debian: update package version 3.14.1

ODROID-COMMON: support hardware PWM with sysnode.
Support pwm with gpiomem mode. not sys mode.

ANDROID: Add Android.mk for android.

Signed-off-by: steve.jeong <jkhpro1003@gmail.com>
Change-Id: Ic6005c0cb81586c9f945b9b6c75f904fa79e3915
This commit is contained in:
steve.jeong
2022-11-17 12:37:24 +09:00
parent ae8438fb70
commit 8fceae15a1
11 changed files with 334 additions and 2 deletions

8
Android.mk Normal file
View File

@@ -0,0 +1,8 @@
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := odroid-wpi-pwm.sh
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_SRC_FILES := etc/$(LOCAL_MODULE)
include $(BUILD_PREBUILT)

7
debian/changelog vendored
View File

@@ -1,3 +1,10 @@
odroid-wiringpi (3.14.1) stable; urgency=medium
* ODROID-COMMON: allow permission pwm sys nodes and use with gpiomem mode.
* ANDROID: Add Android.mk for android.
-- steve <jkhpro1003@gmail.com> Wed, 23 Nov 2022 10:41:05 +0900
odroid-wiringpi (3.14.0) stable; urgency=medium
* ODROID-N2L: new support ODROID-N2L

View File

@@ -1 +1,2 @@
udev/rules.d/* usr/lib/udev/rules.d/
etc/* etc/

View File

@@ -5,6 +5,8 @@ set -e
case "$1" in
purge)
rm -f /etc/udev/rules.d/99-odroid-wiringpi-*
rm -f /etc/odroid-wpi-pwm.sh
rm -f /etc/sudoers.d/odroid-wpi-sudoers
;;
remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)

18
etc/odroid-wpi-pwm.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
# /etc/odroid-wpi-pwm.sh
# written by steve.jeong <jkhpro1003@gmail.com>
#
# allow access pwm sys node (with odroid-wiringpi gpiomem).
# udev rules: 99-odroid-wiringpi-pwm.rules
# param: "/sys/class/pwm/pwmchip*" default.
cutoff=0
while [ ! -d "$1" ]; do
cutoff=$(expr ${cutoff} + 1)
[ ${cutoff} -gt 5 ] && break
sleep .1
done
chmod -R ugo+rw $1

View File

@@ -0,0 +1,2 @@
# Allow members of the odroid group change permission of wpi
%odroid ALL = (ALL) NOPASSWD: /usr/bin/sh /etc/odroid-wpi-pwm.sh*

View File

@@ -0,0 +1 @@
ACTION=="add", KERNEL=="pwmchip*", SUBSYSTEM=="pwm", RUN+="/bin/sh /etc/odroid-wpi-pwm.sh /sys/class/pwm/pwmchip*"

View File

@@ -5,6 +5,7 @@
//
//
/*----------------------------------------------------------------------------*/
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -15,6 +16,7 @@
#include <sys/ioctl.h>
#include <asm/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
/*----------------------------------------------------------------------------*/
#include "softPwm.h"
@@ -47,7 +49,7 @@ static const int pinToGpio[64] = {
474, 475, // 30 | 31 : GPIOA.14(I2C-3_SDA), GPIOA.15(I2C-3_SCL)
// Padding:
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32...47
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 48...63
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 48...63
};
static const int phyToGpio[64] = {
@@ -79,6 +81,62 @@ static const int phyToGpio[64] = {
-1, -1, -1, -1, -1, -1, -1 // 57...63
};
static const char *pinToPwm[64] = {
// wiringPi number to pwm group number
"ffd1a000", "ffd19000", // 0 | 1 : GPIOX.3(PWM_CD), GPIOX.16(PWM_EF)
"None", "ffd19000", // 2 | 3 : GPIOX.4, GPIOX.7(PWM_EF)
"None", "None", // 4 | 5 : GPIOX.0, GPIOX.1
"None", "ffd1a000", // 6 | 7 : GPIOX.2, GPIOX.5(PWM_CD)
"None", "None", // 8 | 9 : GPIOX.17(I2C-2_SDA), GPIOX.18(I2C-2_SCL)
"None", "None", // 10 | 11 : GPIOX.10(SPI_SS), GPIOH.6
"None", "None", // 12 | 13 : GPIOX.8(SPI_MOSI), GPIOX.9(SPI_MISO)
"None", "None", // 14 | 15 : GPIOX.11(SPI_CLK), GPIOX.12(UART_TX_B)
"None", "None", // 16 | 17 : GPIOX.13(UART_RX_B),
"None", "None", // 18 | 19 :
"None", "None", // 20 | 21 : , GPIOX.14
"None", "ffd1b000", // 22 | 23 : GPIOX.15, GPIOX.6(PWM_AB)
"ffd1b000", "None", // 24 | 25 : GPIOX.19(PWM_AB), ADC.AIN3
"None", "None", // 26 | 27 : GPIOH.7, GPIOH.5
"None", "None", // 28 | 29 : REF1.8V OUT, ADC.AIC4
"None", "None", // 30 | 31 : GPIOA.14(I2C-3_SDA), GPIOA.15(I2C-3_SCL)
// Padding:
"None","None","None","None","None","None","None","None","None","None","None","None","None","None","None","None", // 32...47
"None","None","None","None","None","None","None","None","None","None","None","None","None","None","None","None" // 48...63
};
static const int pinToPwmNum[64] = {
// wiringPi number to pwm pin number
3, 4, // 0 | 1 : GPIOX.3(PWM_D), GPIOX.16(PWM_E)
-1, 5, // 2 | 3 : GPIOX.4, GPIOX.7(PWM_F)
-1, -1, // 4 | 5 : GPIOX.0, GPIOX.1
-1, 2, // 6 | 7 : GPIOX.2, GPIOX.5(PWM_C)
-1, -1, // 8 | 9 : GPIOX.17(I2C-2_SDA), GPIOX.18(I2C-2_SCL)
-1, -1, // 10 | 11 : GPIOX.10(SPI_SS), GPIOH.6
-1, -1, // 12 | 13 : GPIOX.8(SPI_MOSI), GPIOX.9(SPI_MISO)
-1, -1, // 14 | 15 : GPIOX.11(SPI_CLK), GPIOX.12(UART_TX_B)
-1, -1, // 16 | 17 : GPIOX.13(UART_RX_B),
-1, -1, // 18 | 19 :
-1, -1, // 20 | 21 : , GPIOX.14
-1, 0, // 22 | 23 : GPIOX.15, GPIOX.6(PWM_A)
1, -1, // 24 | 25 : GPIOX.19(PWM_B), ADC.AIN3
-1, -1, // 26 | 27 : GPIOH.7, GPIOH.5
-1, -1, // 28 | 29 : REF1.8V OUT, ADC.AIC4
-1, -1, // 30 | 31 : GPIOA.14(I2C-3_SDA), GPIOA.15(I2C-3_SCL)
// Padding:
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32...47
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 48...63
};
static char pwmPinPath[10][(BLOCK_SIZE)] = {
"","",
"","",
"","",
// Padding:
"None","None","None","None"
};
static char setupedPwmPinPath[BLOCK_SIZE];
/*----------------------------------------------------------------------------*/
//
// Global variable define
@@ -95,6 +153,18 @@ static volatile uint32_t *gpio;
/* wiringPi Global library */
static struct libodroid *lib = NULL;
/* pwm sysnode */
static DIR *pwm;
static struct dirent *pwmchip;
/* pwm params */
static char sysPwmPath[(BLOCK_SIZE / 4)];
static char pwmExport[(BLOCK_SIZE / 16)];
static char pwmUnexport[(BLOCK_SIZE / 16)];
static char pwmPeriod[(BLOCK_SIZE / 16)];
static char pwmDuty[(BLOCK_SIZE / 16)];
static unsigned int pwmClock;
static unsigned int pwmRange;
/*----------------------------------------------------------------------------*/
// Function prototype define
/*----------------------------------------------------------------------------*/
@@ -106,7 +176,12 @@ static int gpioToShiftReg (int pin);
static int gpioToGPFSELReg (int pin);
static int gpioToDSReg (int pin);
static int gpioToMuxReg (int pin);
/*----------------------------------------------------------------------------*/
// Function of pwm define
/*----------------------------------------------------------------------------*/
static int pinToSysPwmPath (int pin);
static int pwmSetup (int pin);
static int pwmRelease (int pin);
/*----------------------------------------------------------------------------*/
// wiringPi core function
/*----------------------------------------------------------------------------*/
@@ -119,9 +194,12 @@ static int _getPUPD (int pin);
static int _pullUpDnControl (int pin, int pud);
static int _digitalRead (int pin);
static int _digitalWrite (int pin, int value);
static int _pwmWrite (int pin, int value);
static int _analogRead (int pin);
static int _digitalWriteByte (const unsigned int value);
static unsigned int _digitalReadByte (void);
static void _pwmSetRange (unsigned int range);
static void _pwmSetClock (int divisor);
/*----------------------------------------------------------------------------*/
// board init function
@@ -271,6 +349,114 @@ static int gpioToMuxReg (int pin)
}
}
/*----------------------------------------------------------------------------*/
//
// config pwm sys path. "/sys/class/pwm/pwmchip?"
//
/*----------------------------------------------------------------------------*/
static int pinToSysPwmPath (int pin)
{
const char *pwmGroup;
char pwmLinkSrc[(BLOCK_SIZE / 8)];
char pwmPath[(BLOCK_SIZE / 8)];
int sz_link;
memset(pwmLinkSrc, 0, sizeof(pwmLinkSrc));
memset(pwmPath, 0, sizeof(pwmPath));
pwmGroup = pinToPwm[pin];
pwm = opendir("/sys/class/pwm");
if (pwm == NULL) {
printf("need to set device: pwm\n");
return -1;
}
while (1) {
pwmchip = readdir(pwm);
if (pwmchip == NULL) {
break;
}
if (strlen(pwmchip->d_name) <= 2)
continue;
sprintf(pwmPath, "%s/%s", "/sys/class/pwm", pwmchip->d_name);
sz_link = readlink(pwmPath, pwmLinkSrc, sizeof(pwmLinkSrc));
if (sz_link < 0) {
perror("Read symbolic link fail");
return sz_link;
}
if (strstr(pwmLinkSrc, pwmGroup) != NULL) {
strncpy(sysPwmPath, pwmPath, (sizeof(sysPwmPath) - 1));
break;
}
}
closedir(pwm);
return 0;
}
static int pwmSetup (int pin) {
char cmd[(BLOCK_SIZE * 2)];
int pwmPin, ret;
memset(cmd, 0, sizeof(cmd));
memset(pwmExport, 0, sizeof(pwmExport));
if ((ret = pinToSysPwmPath(pin)) < 0) {
perror("set pwm dtb overlays");
return ret;
}
if (strstr(sysPwmPath, "pwmchip") == NULL) {
printf("config pwm dtb overlays\n");
return -1;
}
pwmPin = pinToPwmNum[pin];
sprintf(pwmExport, "%d", (pwmPin % 2));
sprintf(pwmPinPath[pwmPin], "%s/pwm%d", sysPwmPath, (pwmPin % 2));
strncpy(setupedPwmPinPath, pwmPinPath[pwmPin], (sizeof(setupedPwmPinPath) - 1));
#ifdef ANDROID
sprintf(cmd, "su -s sh -c %s %s", PWM_ACCESS_SCRIPT, pwmPinPath[pwmPin]);
#else
sprintf(cmd, "sudo sh %s %s", PWM_ACCESS_SCRIPT, pwmPinPath[pwmPin]);
#endif
inputToSysNode(sysPwmPath, "export", pwmExport);
system(cmd);
inputToSysNode(pwmPinPath[pwmPin], "polarity", "normal");
inputToSysNode(pwmPinPath[pwmPin], "enable", "1");
return 0;
}
static int pwmRelease (int pin) {
int pwmPin, ret;
if ((ret = pinToSysPwmPath(pin)) < 0) {
perror("set pwm dtb overlays");
return ret;
}
if (strstr(sysPwmPath, "pwmchip") == NULL) {
printf("config pwm dtb overlays\n");
return -1;
}
pwmPin = pinToPwmNum[pin];
sprintf(pwmUnexport, "%d", (pwmPin % 2));
sprintf(pwmPinPath[pwmPin], "%s/pwm%d", sysPwmPath, (pwmPin % 2));
if ((pwm = opendir(pwmPinPath[pwmPin])) != NULL) {
inputToSysNode(pwmPinPath[pwmPin], "enable", "0");
inputToSysNode(sysPwmPath, "unexport", pwmUnexport);
closedir(pwm);
}
return 0;
}
/*----------------------------------------------------------------------------*/
static int _getModeToGpio (int mode, int pin)
{
@@ -356,6 +542,7 @@ static int _pinMode (int pin, int mode)
if ((pin = _getModeToGpio(lib->mode, pin)) < 0)
return -1;
pwmRelease (origPin);
softPwmStop (origPin);
softToneStop (origPin);
@@ -375,6 +562,9 @@ static int _pinMode (int pin, int mode)
case SOFT_TONE_OUTPUT:
softToneCreate (pin);
break;
case PWM_OUTPUT:
pwmSetup(origPin);
break;
default:
msg(MSG_WARN, "%s : Unknown Mode %d\n", __func__, mode);
return -1;
@@ -512,6 +702,36 @@ static int _digitalWrite (int pin, int value)
return 0;
}
/*----------------------------------------------------------------------------*/
// PWM signal ___-----------___________---------------_______-----_
// <--value--> <----value---->
// <-------range--------><-------range-------->
/*----------------------------------------------------------------------------*/
static int _pwmWrite (int pin, int value)
{
unsigned int duty;
int pwmPin;
memset(pwmDuty, 0, sizeof(pwmDuty));
if (lib->mode == MODE_GPIO_SYS)
return -1;
if (((unsigned int)value > pwmRange) || (pwmRange <= 0)) {
printf("Set \'pwmWrite\' valied value. ( < pwm range)\n");
printf("pwmSetRange value is greater than or equal pwmWrite's\n");
return -1;
}
pwmPin = pinToPwmNum[pin];
duty = ((value * 100) / pwmRange);
sprintf(pwmDuty, "%d", ((atoi(pwmPeriod) * duty) / 100));
inputToSysNode(pwmPinPath[pwmPin], "duty_cycle", pwmDuty);
return 0;
}
/*----------------------------------------------------------------------------*/
static int _analogRead (int pin)
{
@@ -624,6 +844,57 @@ static unsigned int _digitalReadByte (void)
return value;
}
/*----------------------------------------------------------------------------*/
// PWM signal ___-----------___________---------------_______-----_
// <--value--> <----value---->
// <-------range--------><-------range-------->
// PWM frequency == (PWM clock) / range
/*----------------------------------------------------------------------------*/
static void _pwmSetRange (unsigned int range)
{
unsigned int freq, period;
memset(pwmPeriod, 0, sizeof(pwmPeriod));
if (lib->mode == MODE_GPIO_SYS)
return;
if (pwmClock < 2) {
printf("Set \'pwmSetClock\' valied value.\n");
printf("pwm freq: %dMHz / (pwmSetClock's value) >= 2\n", (C4_PWM_INTERNAL_CLK / 1000000));
return;
}
pwmRange = range;
if ((pwmRange < 1) || (pwmRange >= pwmClock)) {
printf("Set \'pwmSetRange\' valied value. ( < pwm freq)\n");
return;
}
freq = (pwmClock / pwmRange);
period = (1000000000 / freq); // period: s to ns.
sprintf(pwmPeriod, "%d", period);
if (strstr(setupedPwmPinPath, "pwm") == NULL) {
printf("Not setuped pwm target.\n");
return;
}
inputToSysNode(setupedPwmPinPath, "period", pwmPeriod);
}
/*----------------------------------------------------------------------------*/
// Internal clock == 24MHz
// PWM clock == (Internal clock) / divisor
// PWM frequency == (PWM clock) / range
/*----------------------------------------------------------------------------*/
static void _pwmSetClock (int divisor)
{
pwmClock = (C4_PWM_INTERNAL_CLK / divisor);
}
/*----------------------------------------------------------------------------*/
static void init_gpio_mmap (void)
{
@@ -706,9 +977,12 @@ void init_odroidc4 (struct libodroid *libwiring)
libwiring->pullUpDnControl = _pullUpDnControl;
libwiring->digitalRead = _digitalRead;
libwiring->digitalWrite = _digitalWrite;
libwiring->pwmWrite = _pwmWrite;
libwiring->analogRead = _analogRead;
libwiring->digitalWriteByte = _digitalWriteByte;
libwiring->digitalReadByte = _digitalReadByte;
libwiring->pwmSetRange = _pwmSetRange;
libwiring->pwmSetClock = _pwmSetClock;
/* specify pin base number */
libwiring->pinBase = C4_GPIO_PIN_BASE;

View File

@@ -49,6 +49,8 @@
#define C4_GPIOX_MUX_4_REG_OFFSET 0x1B4
#define C4_GPIOX_MUX_5_REG_OFFSET 0x1B5
#define C4_PWM_INTERNAL_CLK 24000000 // 24MHz
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -1311,6 +1311,20 @@ int wiringPiSetupPhys (void)
* Initialisation (again), however this time we are using the /sys/class/gpio
* interface to the GPIO systems - slightly slower, but always usable as
* a non-root user, assuming the devices are already exported and setup correctly.
*
* -----------------------------------------------------------------------------
* Applies from "odroid-wiringpi" 3.14.1 and later.
*
* [The odroid hardware pwm uses sysnode, but it is separate from it.]
* I decided to use the wiringpi service as gpiomem base for odroid,
* but the pwm is using sysnode.
*
* In addition, i designed the API in common so that devices such as gpio as well as pwm
* can be directly accessed and used by sysnode.
*
* "inputToSysNode" is what it is.
*
* Authored by steve.jeong <jkhpro1003@gmail.com>, <steve.jeong@hardkernel.com>
*/
/*----------------------------------------------------------------------------*/
int wiringPiSetupSys (void)

View File

@@ -102,6 +102,9 @@
// Module names
#define AML_MODULE_I2C "aml_i2c"
// syspwm
#define PWM_ACCESS_SCRIPT "/etc/odroid-wpi-pwm.sh"
// Threads
#define PI_THREAD(X) void *X (UNU void *dummy)