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