ODROID-COMMON: pwm: improve pwm API & Update missing M1/N2 codes.
the missing commit: 8fceae1
Signed-off-by: steve.jeong <jkhpro1003@gmail.com>
Change-Id: I1092e044a0e500944fc36e38c6d991e7e9bdde5c
diff --git a/wiringPi/odroidc4.c b/wiringPi/odroidc4.c
index 0a7b42d..8da29df 100644
--- a/wiringPi/odroidc4.c
+++ b/wiringPi/odroidc4.c
@@ -416,6 +416,7 @@
}
pwmPin = pinToPwmNum[pin];
+ pwmClock = C4_PWM_INTERNAL_CLK;
sprintf(pwmExport, "%d", (pwmPin % 2));
sprintf(pwmPinPath[pwmPin], "%s/pwm%d", sysPwmPath, (pwmPin % 2));
strncpy(setupedPwmPinPath, pwmPinPath[pwmPin], (sizeof(setupedPwmPinPath) - 1));
@@ -426,8 +427,7 @@
#endif
inputToSysNode(sysPwmPath, "export", pwmExport);
system(cmd);
- inputToSysNode(pwmPinPath[pwmPin], "polarity", "normal");
- inputToSysNode(pwmPinPath[pwmPin], "enable", "1");
+ printf("PWM/pin%d: Don't change to gpio mode with overlay registered.\n", pin);
return 0;
}
@@ -436,12 +436,10 @@
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;
}
@@ -718,8 +716,7 @@
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");
+ printf("warn : pwm range value is greater than or equal pwmWrite's\n");
return -1;
}
@@ -861,14 +858,14 @@
return;
if (pwmClock < 2) {
- printf("Set \'pwmSetClock\' valied value.\n");
- printf("pwm freq: %dMHz / (pwmSetClock's value) >= 2\n", (C4_PWM_INTERNAL_CLK / 1000000));
+ printf("error : 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");
+ printf("error : invalied value. ( < pwm freq)\n");
return;
}
@@ -881,6 +878,8 @@
}
inputToSysNode(setupedPwmPinPath, "period", pwmPeriod);
+ inputToSysNode(setupedPwmPinPath, "polarity", "normal");
+ inputToSysNode(setupedPwmPinPath, "enable", "1");
}
@@ -892,7 +891,12 @@
static void _pwmSetClock (int divisor)
{
- pwmClock = (C4_PWM_INTERNAL_CLK / divisor);
+ if (pwmClock > 0)
+ pwmClock = (pwmClock / divisor);
+ else {
+ printf("error : pwm mode error\n");
+ return;
+ }
}
/*----------------------------------------------------------------------------*/
diff --git a/wiringPi/odroidm1.c b/wiringPi/odroidm1.c
index 07504ea..bad8086 100644
--- a/wiringPi/odroidm1.c
+++ b/wiringPi/odroidm1.c
@@ -21,6 +21,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
+#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -31,6 +32,7 @@
#include <sys/ioctl.h>
#include <asm/ioctl.h>
#include <sys/mman.h>
+#include <sys/stat.h>
/*----------------------------------------------------------------------------*/
#include "softPwm.h"
#include "softTone.h"
@@ -74,30 +76,6 @@
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 48...63
};
-static const int pinToPwm[64] = {
- // wiringPi number to pwm idx number
- -1, -1, // 0 | 1 : GPIO0_C0, GPIO3_D0
- -1, 9, // 2 | 3 : GPIO0_C1, GPIO3_B2(PWM9) /* To be added */
- -1, -1, // 4 | 5 : GPIO3_C6, GPIO3_C7
- -1, 2, // 6 | 7 : GPIO3_D1, GPIO0_B6(PWM2)
- -1, -1, // 8 | 9 : GPIO3_B6, GPIO3_B5
- -1, -1, // 10 | 11 : GPIO2_D2, GPIO3_D2
- -1, -1, // 12 | 13 : GPIO2_D1, GPIO2_D0
- -1, -1, // 14 | 15 : GPIO2_D3, GPIO3_D6
- -1, -1, // 16 | 17 : GPIO3_D7
- -1, -1, // 18 | 19 :
- -1, -1, // 20 | 21 : , GPIO4_C1
- -1, 1, // 22 | 23 : GPIO4_B6, GPIO0_B5(PWM1)
- -1, -1, // 24 | 25 : GPIO3_D5,
- -1, -1, // 26 | 27 : GPIO3_D3, GPIO3_D4
- -1, -1, // 28 | 29 :
- -1, -1, // 30 | 31 : GPIO0_B4, GPIO0_B3
-
- // 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 const int phyToGpio[64] = {
// physical header pin number to native gpio number
-1, // 0
@@ -128,15 +106,61 @@
-1, -1, -1, -1, -1, -1, -1 // 57...63
};
-static int pwmPinToRange[10] = {
- -1,
- 0, 0,
- -1, -1,
- -1, -1,
- -1, -1,
- 0
+static const char *pinToPwm[64] = {
+ // wiringPi number to pwm group number
+ "None", "None",// 0 | 1 : GPIO0_C0, GPIO3_D0
+ "None", "fe6f0010", // 2 | 3 : GPIO0_C1, GPIO3_B2(PWM9)
+ "None", "None", // 4 | 5 : GPIO3_C6, GPIO3_C7
+ "None", "fdd70020", // 6 | 7 : GPIO3_D1, GPIO0_B6(PWM2)
+ "None", "None", // 8 | 9 : GPIO3_B6, GPIO3_B5
+ "None", "None", // 10 | 11 : GPIO2_D2, GPIO3_D2
+ "None", "None", // 12 | 13 : GPIO2_D1, GPIO2_D0
+ "None", "None", // 14 | 15 : GPIO2_D3, GPIO3_D6
+ "None", "None", // 16 | 17 : GPIO3_D7
+ "None", "None", // 18 | 19 :
+ "None", "None", // 20 | 21 : , GPIO4_C1
+ "None", "fdd70010", // 22 | 23 : GPIO4_B6, GPIO0_B5(PWM1)
+ "None", "None", // 24 | 25 : GPIO3_D5,
+ "None", "None", // 26 | 27 : GPIO3_D3, GPIO3_D4
+ "None", "None", // 28 | 29 :
+ "None", "None", // 30 | 31 : GPIO0_B4, GPIO0_B3
+ // 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
+ -1, -1, // 0 | 1 : GPIO0_C0, GPIO3_D0
+ -1, 2, // 2 | 3 : GPIO0_C1, GPIO3_B2(PWM9)
+ -1, -1, // 4 | 5 : GPIO3_C6, GPIO3_C7
+ -1, 1, // 6 | 7 : GPIO3_D1, GPIO0_B6(PWM2)
+ -1, -1, // 8 | 9 : GPIO3_B6, GPIO3_B5
+ -1, -1, // 10 | 11 : GPIO2_D2, GPIO3_D2
+ -1, -1, // 12 | 13 : GPIO2_D1, GPIO2_D0
+ -1, -1, // 14 | 15 : GPIO2_D3, GPIO3_D6
+ -1, -1, // 16 | 17 : GPIO3_D7
+ -1, -1, // 18 | 19 :
+ -1, -1, // 20 | 21 : , GPIO4_C1
+ -1, 0, // 22 | 23 : GPIO4_B6, GPIO0_B5(PWM1)
+ -1, -1, // 24 | 25 : GPIO3_D5,
+ -1, -1, // 26 | 27 : GPIO3_D3, GPIO3_D4
+ -1, -1, // 28 | 29 :
+ -1, -1, // 30 | 31 : GPIO0_B4, GPIO0_B3
+ // 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","None","None","None"
+};
+
+static char setupedPwmPinPath[BLOCK_SIZE];
/*----------------------------------------------------------------------------*/
//
// Global variable define
@@ -145,9 +169,6 @@
/* ADC file descriptor */
static int adcFds[2];
-/* GPIO mmap control. Actual PWM bank number. */
-static volatile uint32_t *pwm[2];
-
/* GPIO mmap control. Actual GPIO bank number. */
static volatile uint32_t *gpio[5];
@@ -160,6 +181,17 @@
/* 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
/*----------------------------------------------------------------------------*/
@@ -168,6 +200,12 @@
static void setClkState (int pin, int state);
static int setIomuxMode (int pin, int mode);
/*----------------------------------------------------------------------------*/
+// Function of pwm define
+/*----------------------------------------------------------------------------*/
+static int pinToSysPwmPath (int pin);
+static int pwmSetup (int pin);
+static int pwmRelease (int pin);
+/*----------------------------------------------------------------------------*/
// wiringPi core function
/*----------------------------------------------------------------------------*/
static int _getModeToGpio (int mode, int pin);
@@ -222,6 +260,114 @@
return pin % 16;
}
/*----------------------------------------------------------------------------*/
+//
+// 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];
+ if (pwmPin == 2)
+ pwmClock = M1_PWM_INTERNAL_CLK;
+ else
+ pwmClock = (M1_PWM_INTERNAL_CLK / 2);
+ sprintf(pwmExport, "%d", 0);
+ sprintf(pwmPinPath[pwmPin], "%s/pwm%d", sysPwmPath, 0);
+ 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);
+ printf("PWM/pin%d: Don't change to gpio mode with overlay registered.\n", pin);
+
+ return 0;
+}
+
+static int pwmRelease (int pin) {
+ int pwmPin, ret;
+
+ if ((ret = pinToSysPwmPath(pin)) < 0) {
+ return ret;
+ }
+
+ if (strstr(sysPwmPath, "pwmchip") == NULL) {
+ 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)
{
if (pin > 255)
@@ -375,11 +521,9 @@
bitNum = pin - (bank * GPIO_SIZE);
offset = bitNum / 16 == 0 ? M1_GPIO_DIR_OFFSET : M1_GPIO_DIR_OFFSET + 0x4;
+ pwmRelease (origPin);
softPwmStop(pin);
softToneStop(pin);
- *(pwm[0] + (M1_PWM1_CTRL_OFFSET >> 2)) = M1_PWM_LOCK;
- *(pwm[0] + (M1_PWM2_CTRL_OFFSET >> 2)) = M1_PWM_LOCK;
-// *(pwm[1] + (M1_PWM9_CTRL_OFFSET >> 2)) = M1_PWM_LOCK;
target = *(gpio[bank] + (offset >> 2));
target |= (1 << (gpioToShiftRegBy16(pin) + 16));
@@ -414,19 +558,8 @@
case SOFT_TONE_OUTPUT:
softToneCreate(origPin);
break;
- case PWM_OUTPUT:
- setIomuxMode(origPin, M1_FUNC_PWM);
-
-#ifndef ANDROID
- /**
- * PWM1,2 clk: [12MHz] PWM9 clk: [24MHz]
- *
- * frequency of PWM: 400 Hz
- * period of PWM: 2500 us
- */
- _pwmSetClock(30);
- _pwmSetRange(1000);
-#endif
+ case PWM_OUTPUT:
+ pwmSetup(origPin);
break;
default:
msg(MSG_WARN, "%s : Unknown Mode %d\n", __func__, mode);
@@ -1007,52 +1140,24 @@
__attribute__ ((unused))static int _pwmWrite (int pin, int value)
{
+ unsigned int duty;
int pwmPin;
- uint16_t range;
- uint32_t target;
- float duty_rate;
+
+ memset(pwmDuty, 0, sizeof(pwmDuty));
if (lib->mode == MODE_GPIO_SYS)
return -1;
- if (((pwmPin = pinToPwm[pin]) < 0))
- return -1;
-
- range = pwmPinToRange[pwmPin];
- if (range <= 0) {
- printf("you didn't set pwm range\n");
+ if (((unsigned int)value > pwmRange) || (pwmRange <= 0)) {
+ printf("warn : pwm range value is greater than or equal pwmWrite's\n");
return -1;
}
- if (value > range)
- value = range;
- duty_rate = ((value * 100) / range);
+ pwmPin = pinToPwmNum[pin];
+ duty = ((value * 100) / pwmRange);
+ sprintf(pwmDuty, "%d", ((atoi(pwmPeriod) * duty) / 100));
- switch (pwmPin) {
- case 1:
- target = *(pwm[0] + (M1_PWM1_CTRL_OFFSET >> 2));
- target &= ~M1_PWM_READY;
- target |= M1_PWM_EN;
- *(pwm[0] + (M1_PWM1_CTRL_OFFSET >> 2)) = target;
- *(pwm[0] + (M1_PWM1_DUTY_OFFSET >> 2)) = ((*(pwm[0] + (M1_PWM1_PERIOD_OFFSET >> 2)) * (uint8_t)duty_rate) / 100);
- break;
- case 2:
- target = *(pwm[0] + (M1_PWM2_CTRL_OFFSET >> 2));
- target &= ~M1_PWM_READY;
- target |= M1_PWM_EN;
- *(pwm[0] + (M1_PWM2_CTRL_OFFSET >> 2)) = target;
- *(pwm[0] + (M1_PWM2_DUTY_OFFSET >> 2)) = ((*(pwm[0] + (M1_PWM2_PERIOD_OFFSET >> 2)) * (uint8_t)duty_rate) / 100);
- break;
- /*
- case 9:
- target = *(pwm[1] + (M1_PWM9_CTRL_OFFSET >> 2));
- target &= ~M1_PWM_READY;
- target |= M1_PWM_EN;
- *(pwm[1] + (M1_PWM9_CTRL_OFFSET >> 2)) = target;
- *(pwm[1] + (M1_PWM9_DUTY_OFFSET >> 2)) = ((*(pwm[1] + (M1_PWM9_PERIOD_OFFSET >> 2)) * (uint8_t)duty_rate) / 100);
- break;
- */
- }
+ inputToSysNode(pwmPinPath[pwmPin], "duty_cycle", pwmDuty);
return 0;
}
@@ -1318,21 +1423,38 @@
/*----------------------------------------------------------------------------*/
static void _pwmSetRange (unsigned int range)
{
- if ((*(pwm[0] + (M1_PWM1_CTRL_OFFSET >> 2)) == 0) ||
-// (*(pwm[1] + (M1_PWM9_CTRL_OFFSET >> 2)) == 0) ||
- (*(pwm[0] + (M1_PWM2_CTRL_OFFSET >> 2)) == 0)) {
- printf("you didn't set clock\n");
+ unsigned int freq, period;
+
+ memset(pwmPeriod, 0, sizeof(pwmPeriod));
+
+ if (lib->mode == MODE_GPIO_SYS)
+ return;
+
+ if (pwmClock < 2) {
+ printf("error : pwm1 or pwm2 freq: %dMHz / (pwmSetClock's value) >= 2\n",
+ (M1_PWM_INTERNAL_CLK / 2000000));
+ printf("error : pwm9 freq: %dMHz / (pwmSetClock's value) >= 2\n",
+ (M1_PWM_INTERNAL_CLK / 1000000));
return;
}
- range = range & 0xFFFFFFFF;
- pwmPinToRange[1] = range;
- pwmPinToRange[2] = range;
-// pwmPinToRange[9] = range;
+ pwmRange = range;
+ if ((pwmRange < 1) || (pwmRange >= pwmClock)) {
+ printf("error : invalid value. ( < pwm freq)\n");
+ return;
+ }
- *(pwm[0] + (M1_PWM1_PERIOD_OFFSET >> 2)) = range;
- *(pwm[0] + (M1_PWM2_PERIOD_OFFSET >> 2)) = range;
-// *(pwm[1] + (M1_PWM9_PERIOD_OFFSET >> 2)) = range;
+ 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);
+ inputToSysNode(setupedPwmPinPath, "polarity", "normal");
+ inputToSysNode(setupedPwmPinPath, "enable", "1");
}
/*----------------------------------------------------------------------------*/
@@ -1342,31 +1464,19 @@
/*----------------------------------------------------------------------------*/
static void _pwmSetClock (int divisor)
{
- uint8_t scale;
- uint32_t pwmScale, target;
-
- if ((divisor % 2 != 0)) {
- printf("clk divisor must be set to an even number.\n");
+ if (pwmClock > 0)
+ pwmClock = (pwmClock / divisor);
+ else {
+ printf("error : pwm mode error\n");
return;
}
-
- divisor = divisor / 2;
- scale = (uint8_t)(divisor & 0xFF);
- pwmScale = (scale << 16);
-
- target = pwmScale; // if scale == 0, It changes to the maximum value(256).
- target |= (1 << 9); // scaled clock is selected
- target |= M1_PWM_READY;
- *(pwm[0] + (M1_PWM1_CTRL_OFFSET >> 2)) = target;
- *(pwm[0] + (M1_PWM2_CTRL_OFFSET >> 2)) = target;
-// *(pwm[1] + (M1_PWM9_CTRL_OFFSET >> 2)) = target;
}
/*----------------------------------------------------------------------------*/
static void init_gpio_mmap (void)
{
int fd = -1;
- void *mapped_cru[2], *mapped_grf[2], *mapped_gpio[5], *mapped_pwm[2];
+ void *mapped_cru[2], *mapped_grf[2], *mapped_gpio[5];
/* GPIO mmap setup */
if (!getuid()) {
@@ -1401,9 +1511,6 @@
mapped_gpio[4] = mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, M1_GPIO_4_BASE);
mapped_gpio[3] = mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, M1_GPIO_3_BASE);
- mapped_pwm[0] = mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, M1_PWM_BASE);
- mapped_pwm[1] = mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, M1_PWM9_BASE);
-
if ((mapped_cru[0] == MAP_FAILED) || (mapped_cru[1] == MAP_FAILED)) {
msg (MSG_ERR,"wiringPiSetup: mmap (CRU) failed: %s\n",strerror (errno));
} else {
@@ -1433,15 +1540,6 @@
gpio[3] = (uint32_t *) mapped_gpio[3];
gpio[4] = (uint32_t *) mapped_gpio[4];
}
-
- if ((mapped_pwm[0] == MAP_FAILED) || (mapped_pwm[1] == MAP_FAILED)) {
- msg (MSG_ERR,
- "wiringPiSetup: mmap (PWM) failed: %s\n",
- strerror (errno));
- } else {
- pwm[0] = (uint32_t *) mapped_pwm[0];
- pwm[1] = (uint32_t *) mapped_pwm[1];
- }
}
}
/*----------------------------------------------------------------------------*/
diff --git a/wiringPi/odroidm1.h b/wiringPi/odroidm1.h
index b631f71..2676fa6 100644
--- a/wiringPi/odroidm1.h
+++ b/wiringPi/odroidm1.h
@@ -108,6 +108,8 @@
#define CONSUMER "consumer"
+#define M1_PWM_INTERNAL_CLK 24000000 // 24MHz
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/wiringPi/odroidn2.c b/wiringPi/odroidn2.c
index 8652b65..6189d62 100644
--- a/wiringPi/odroidn2.c
+++ b/wiringPi/odroidn2.c
@@ -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"
@@ -79,81 +81,61 @@
-1, -1, -1, -1, -1, -1, -1 // 57...63
};
-static int16_t _gpioTophysPin [] = {
- // (native gpio number - N2_GPIOA_PIN_START) to physical header pin number
- -1, // 0 + N2_GPIOA_PIN_START(460)
- -1, -1, // 1 | 2
- -1, 26, // 3 | 4 GPIOA.4(SPI_CE1)
- -1, -1, // 5 | 6
- -1, -1, // 7 | 8
- -1, -1, // 9 | 10
- -1, 32, // 11 | 12 GPIOA.12
- 7, 27, // GPIOA.13 13 | 14 GPIOA.14(I2C-3_SDA)
- 28, 16, // GPIOA.15(I2C-3_SCL) 15 | 16 GPIOX.0
- 18, 22, // GPIOX.1 17 | 18 GPIOX.2
- 11, 13, // GPIOX.3 19 | 20 GPIOX.4
- 33, 35, // GPIOX.5(PWM_C) 21 | 22 GPIOX.6(PWM_D)
- 15, 19, // GPIOX.7(PWM_F) 23 | 24 GPIOX.8(SPI_MOSI)
- 21, 24, // GPIOX.9(SPI_MISO) 25 | 26 GPIOX.10(SPI_CE0)
- 23, 8, // GPIOX.11(SPI_SCLK) 27 | 28 GPIOX.12(UART_TX_B)
- 10, 29, // GPIOX.13(UART_RX_B) 29 | 30 GPIOX.14
- 31, 12, // GPIOX.15 31 | 32 GPIOX.16(PWM_E)
- 3, 5, // GPIOX.17(I2C-2_SDA) 33 | 34 GPIOX.18(I2C-2_SCL)
- 36, -1, // GPIOX.19 35 | 36
- -1, -1, // 37 | 38
- -1, -1, // 39 | 40
- // Not used
- -1, -1, -1, -1, -1, -1, -1, -1, // 41...48
- -1, -1, -1, -1, -1, -1, -1, -1, // 49...56
- -1, -1, -1, -1, -1, -1, -1 // 57...63
+static const char *pinToPwm[64] = {
+ // wiringPi number to pwm group number
+ "None", "ffd19000", // GPIOX.3 0 | 1 GPIOX.16(PWM_E)
+ "None", "ffd19000", // GPIOX.4 2 | 3 GPIOX.7(PWM_F)
+ "None", "None", // GPIOX.0 4 | 5 GPIOX.1
+ "None", "None", // GPIOX.2 6 | 7 GPIOA.13
+ "None", "None", // GPIOX.17(I2C-2_SDA) 8 | 9 GPIOX.18(I2C-2_SCL)
+ "None", "None", // GPIOX.10 10 | 11 GPIOA.4
+ "None", "None", // GPIOX.8 12 | 13 GPIOX.9
+ "None", "None", // GPIOX.11 14 | 15 GPIOX.12
+ "None", "None", // GPIOX.13 16 | 17
+ "None", "None", // 18 | 19
+ "None", "None", // 20 | 21 GPIOX.14
+ "None", "ffd1a000", // GPIOX.15 22 | 23 GPIOX.5(PWM_C)
+ "ffd1a000", "None", // GPIOX.6(PWM_D) 24 | 25 ADC.AIN3
+ "None", "None", // GPIOA.12 26 | 27 GPIOX.19
+ "None", "None", // REF1.8V OUT 28 | 29 ADC.AIN2
+ "None", "None", // GPIOA.14(I2C-3_SDA) 30 | 31 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 int8_t _gpioToPwmPin [] = {
- // (native gpio number - N2_GPIOA_PIN_START) to PWM pin number
- -1, // 0 + N2_GPIOA_PIN_START(460)
- -1, -1, // 1 | 2
- -1, -1, // 3 | 4 GPIOA.4(SPI_CE1)
- -1, -1, // 5 | 6
- -1, -1, // 7 | 8
- -1, -1, // 9 | 10
- -1, -1, // 11 | 12 GPIOA.12
- -1, -1, // GPIOA.13 13 | 14 GPIOA.14(I2C-3_SDA)
- -1, -1, // GPIOA.15(I2C-3_SCL) 15 | 16 GPIOX.0
- -1, -1, // GPIOX.1 17 | 18 GPIOX.2
- -1, -1, // GPIOX.3 19 | 20 GPIOX.4
- 2, 3, // GPIOX.5(PWM_C) 21 | 22 GPIOX.6(PWM_D)
- 5, -1, // GPIOX.7(PWM_F) 23 | 24 GPIOX.8(SPI_MOSI)
- -1, -1, // GPIOX.9(SPI_MISO) 25 | 26 GPIOX.10(SPI_CE0)
- -1, -1, // GPIOX.11(SPI_SCLK) 27 | 28 GPIOX.12(UART_TX_B)
- -1, -1, // GPIOX.13(UART_RX_B) 29 | 30 GPIOX.14
- -1, 4, // GPIOX.15 31 | 32 GPIOX.16(PWM_E)
- -1, -1, // GPIOX.17(I2C-2_SDA) 33 | 34 GPIOX.18(I2C-2_SCL)
- -1, -1, // GPIOX.19 35 | 36
- -1, -1, // 37 | 38
- -1, -1, // 39 | 40
- // Not used
- -1, -1, -1, -1, -1, -1, -1, -1, // 41...48
- -1, -1, -1, -1, -1, -1, -1, -1, // 49...56
- -1, -1, -1, -1, -1, -1, -1 // 57...63
+static const int pinToPwmNum[64] = {
+ // wiringPi number to pwm pin number
+ -1, 2, // GPIOX.3 0 | 1 GPIOX.16(PWM_E)
+ -1, 3, // GPIOX.4 2 | 3 GPIOX.7(PWM_F)
+ -1, -1, // GPIOX.0 4 | 5 GPIOX.1
+ -1, -1, // GPIOX.2 6 | 7 GPIOA.13
+ -1, -1, // GPIOX.17(I2C-2_SDA) 8 | 9 GPIOX.18(I2C-2_SCL)
+ -1, -1, // GPIOX.10 10 | 11 GPIOA.4
+ -1, -1, // GPIOX.8 12 | 13 GPIOX.9
+ -1, -1, // GPIOX.11 14 | 15 GPIOX.12
+ -1, -1, // GPIOX.13 16 | 17
+ -1, -1, // 18 | 19
+ -1, -1, // 20 | 21 GPIOX.14
+ -1, 0, // GPIOX.15 22 | 23 GPIOX.5(PWM_C)
+ 1, -1, // GPIOX.6(PWM_D) 24 | 25 ADC.AIN3
+ -1, -1, // GPIOA.12 26 | 27 GPIOX.19
+ -1, -1, // REF1.8V OUT 28 | 29 ADC.AIN2
+ -1, -1, // GPIOA.14(I2C-3_SDA) 30 | 31 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 uint16_t pwmPinToALT [] = {
- 0, 0, // A, B
- 4, 4, // C 481 GPIOX.5 , D 482 GPIOX.6
- 1, 1 // E 492 GPIOX.16, F 483 GPIOX.7
+static char pwmPinPath[10][(BLOCK_SIZE)] = {
+ "","",
+ "","",
+ // Padding:
+ "None","None",
+ "None","None","None","None"
};
-static uint16_t pwmPinToRange [] = {
- 0, 0, // A, B
- 0, 0, // C 481 GPIOX.5 , D 482 GPIOX.6
- 0, 0 // E 492 GPIOX.16, F 483 GPIOX.7
-};
-
-static uint16_t pwmPinToDutyOffset [] = {
- N2_PWM_0_DUTY_CYCLE_OFFSET, N2_PWM_1_DUTY_CYCLE_OFFSET, // A, B
- N2_PWM_0_DUTY_CYCLE_OFFSET, N2_PWM_1_DUTY_CYCLE_OFFSET, // C 481 GPIOX.5 , D 482 GPIOX.6
- N2_PWM_0_DUTY_CYCLE_OFFSET, N2_PWM_1_DUTY_CYCLE_OFFSET // E 492 GPIOX.16, F 483 GPIOX.7
-};
+static char setupedPwmPinPath[BLOCK_SIZE];
/*----------------------------------------------------------------------------*/
//
@@ -169,11 +151,21 @@
/* GPIO mmap control */
static volatile uint32_t *gpio;
-static volatile uint32_t *pwm[3];
/* 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
/*----------------------------------------------------------------------------*/
@@ -185,9 +177,12 @@
static int gpioToGPFSELReg (int pin);
static int gpioToDSReg (int pin);
static int gpioToMuxReg (int pin);
-static int gpioToPwmPin (int pin);
-static int gpioTophysPin (int pin) UNU;
-
+/*----------------------------------------------------------------------------*/
+// Function of pwm define
+/*----------------------------------------------------------------------------*/
+static int pinToSysPwmPath (int pin);
+static int pwmSetup (int pin);
+static int pwmRelease (int pin);
/*----------------------------------------------------------------------------*/
// wiringPi core function
/*----------------------------------------------------------------------------*/
@@ -340,15 +335,109 @@
}
/*----------------------------------------------------------------------------*/
-static int gpioToPwmPin (int pin)
+//
+// config pwm sys path. "/sys/class/pwm/pwmchip?"
+//
+/*----------------------------------------------------------------------------*/
+static int pinToSysPwmPath (int pin)
{
- return _gpioToPwmPin[pin - N2_GPIOA_PIN_START];
+ 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 gpioTophysPin (int pin)
-{
- return _gpioTophysPin[pin - N2_GPIOA_PIN_START];
+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];
+ pwmClock = N2_PWM_INTERNAL_CLK;
+ 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);
+ printf("PWM/pin%d: Don't change to gpio mode with overlay registered.\n", pin);
+
+ return 0;
+}
+
+static int pwmRelease (int pin) {
+ int pwmPin, ret;
+
+ if ((ret = pinToSysPwmPath(pin)) < 0) {
+ return ret;
+ }
+
+ if (strstr(sysPwmPath, "pwmchip") == NULL) {
+ 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;
}
/*----------------------------------------------------------------------------*/
@@ -432,10 +521,10 @@
if (lib->mode == MODE_GPIO_SYS)
return -1;
-
if ((pin = _getModeToGpio(lib->mode, pin)) < 0)
return -1;
+ pwmRelease (origPin);
softPwmStop (origPin);
softToneStop (origPin);
@@ -471,29 +560,7 @@
softToneCreate (origPin);
break;
case PWM_OUTPUT:
- usingGpiomemCheck("pinMode PWM");
-
- int pwm_pin, alt;
- pwm_pin = gpioToPwmPin(pin);
- if( pwm_pin == -1 )
- {
- msg(MSG_WARN, "%s : This pin does not support hardware PWM mode.\n", __func__);
- return -1;
- }
-
- alt = pwmPinToALT[pwm_pin];
- *(gpio + mux) = (*(gpio + mux) & ~(0xF << target)) | (alt << target);
-
-#ifndef ANDROID
- /**
- * 24 MHz / 120
- * 200 kHz / 500
- * frequency of PWM: 400 Hz
- * period of PWM: 2500 us
- */
- _pwmSetClock(120);
- _pwmSetRange(500);
-#endif
+ pwmSetup(origPin);
break;
default:
msg(MSG_WARN, "%s : Unknown Mode %d\n", __func__, mode);
@@ -639,29 +706,27 @@
/*----------------------------------------------------------------------------*/
static int _pwmWrite (int pin, int value)
{
- /**
- * @todo Add node
- * struct wiringPiNodeStruct *node = wiringPiNodes;
- */
+ unsigned int duty;
+ int pwmPin;
+
+ memset(pwmDuty, 0, sizeof(pwmDuty));
if (lib->mode == MODE_GPIO_SYS)
return -1;
- if ((pin = _getModeToGpio(lib->mode, pin)) < 0)
+ if (((unsigned int)value > pwmRange) || (pwmRange <= 0)) {
+ printf("warn : pwm range value is greater than or equal pwmWrite's\n");
return -1;
-
- int pwm_pin = gpioToPwmPin(pin);
- uint16_t range = pwmPinToRange[pwm_pin];
-
- if( value > range ) {
- value = range;
}
- *(pwm[pwm_pin/2] + pwmPinToDutyOffset[pwm_pin]) = (value << 16) | (range - value);
+ 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)
{
@@ -743,11 +808,36 @@
/*----------------------------------------------------------------------------*/
static void _pwmSetRange (unsigned int range)
{
- range = range & 0xFFFF;
- for( int i = 0; i < 6; ++i )
- {
- pwmPinToRange[i] = range;
+ unsigned int freq, period;
+
+ memset(pwmPeriod, 0, sizeof(pwmPeriod));
+
+ if (lib->mode == MODE_GPIO_SYS)
+ return;
+
+ if (pwmClock < 2) {
+ printf("error : pwm freq: %dMHz / (pwmSetClock's value) >= 2\n",
+ (N2_PWM_INTERNAL_CLK / 1000000));
+ return;
}
+
+ pwmRange = range;
+ if ((pwmRange < 1) || (pwmRange >= pwmClock)) {
+ printf("error : invalied 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);
+ inputToSysNode(setupedPwmPinPath, "polarity", "normal");
+ inputToSysNode(setupedPwmPinPath, "enable", "1");
}
/*----------------------------------------------------------------------------*/
@@ -757,28 +847,18 @@
/*----------------------------------------------------------------------------*/
static void _pwmSetClock (int divisor)
{
- if((divisor < 1) || (divisor > 128))
- {
- msg(MSG_ERR,
- "Set the clock prescaler (divisor) to 1 or more and 128 or less.: %s\n",
- strerror (errno));
- }
- divisor = (divisor - 1);
-
- for(uint16_t i = 1; i < 3; ++i) {
- *( pwm[i] + N2_PWM_MISC_REG_01_OFFSET ) = \
- (1 << N2_PWM_1_CLK_EN) \
- | ( divisor << N2_PWM_1_CLK_DIV0) \
- | (1 << N2_PWM_0_CLK_EN) \
- | ( divisor << N2_PWM_0_CLK_DIV0) \
- | (0 << N2_PWM_1_CLK_SEL0) \
- | (0 << N2_PWM_0_CLK_SEL0) \
- | (1 << N2_PWM_1_EN) \
- | (1 << N2_PWM_0_EN);
+ if (pwmClock > 0)
+ pwmClock = (pwmClock / divisor);
+ else {
+ printf("error : pwm mode error\n");
+ return;
}
}
/*----------------------------------------------------------------------------*/
+
+
+/*----------------------------------------------------------------------------*/
static unsigned int _digitalReadByte (void)
{
return -1;
@@ -826,12 +906,6 @@
msg(MSG_ERR, "wiringPiSetup: mmap (GPIO) failed: %s \n", strerror (errno));
else
gpio = (uint32_t *) mapped;
-
- for(uint16_t i = 1; i < 3; ++i) {
- pwm[i] = ( uint32_t * )mmap( 0, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, N2_GPIO_PWM_BASE + (0x1000 * (2 - i)) );
- if( ( void * )pwm == MAP_FAILED )
- msg(MSG_ERR, "wiringPiSetup: mmap (PWM) failed: %s \n", strerror (errno));
- }
}
}
diff --git a/wiringPi/odroidn2.h b/wiringPi/odroidn2.h
index d363230..54c0e75 100644
--- a/wiringPi/odroidn2.h
+++ b/wiringPi/odroidn2.h
@@ -62,6 +62,8 @@
#define N2_PWM_1_EN ( 1 )
#define N2_PWM_0_EN ( 0 )
+#define N2_PWM_INTERNAL_CLK 24000000 // 24MHz
+
#ifdef __cplusplus
extern "C" {
#endif