ODROID-C5: Add odroid-c5 wiring-pi support
- Rev. 20250106
- Warning: Use only GPIO functions.
Signed-off-by: YoungSoo Shin <shinys000114@gmail.com>
Change-Id: I02623a284c047c6b5e485d28c9714ed8e65025df
diff --git a/Android.bp b/Android.bp
index 7aa17ea..bf09a74 100644
--- a/Android.bp
+++ b/Android.bp
@@ -29,6 +29,7 @@
"wiringPi/odroidm1.c",
"wiringPi/odroidm1s.c",
"wiringPi/odroidm2.c",
+ "wiringPi/odroidc5.c",
"wiringPi/drcSerial.c",
"wiringPi/mcp23s08.c",
"wiringPi/odroidn1.c",
diff --git a/debian/changelog b/debian/changelog
index 1d6559f..705803e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+odroid-wiringpi (3.17.1) stable; urgency=medium
+
+ * ODROID-C5: New Support for ODROID-C5
+ * ODROID: Change binary installation path
+
+ -- Bob Shin <shinys000114@gmail.com> Thu, 29 Oct 2024 06:07:00 +0000
+
odroid-wiringpi (3.17.0) stable; urgency=medium
* ODROID-M2: New Support for ODROID-M2
diff --git a/gpio/readall.c b/gpio/readall.c
index 515ed6a..01d175c 100644
--- a/gpio/readall.c
+++ b/gpio/readall.c
@@ -779,6 +779,69 @@
};
/*----------------------------------------------------------------------------*/
+static const char *physNamesOdroidC5All [64] =
+{
+ NULL,
+
+ " 3.3V", "5V ",
+ " SDA.0", "5V ",
+ " SCL.0", "GND(0V) ",
+ "GPIOX_17", "TxD.0 ",
+ " GND(0V)", "RxD.0 ",
+ " GPIOX_5", "GPIOX_14",
+ "GPIOX_15", "GND(0V) ",
+ " GPIOX_4", "GPIODV_1",
+ " 3.3V", "GPIODV_2",
+ " MOSI", "GND(0V) ",
+ " MISO", "GPIOX_6 ",
+ " SLCK", "SS ",
+ " GND(0V)", "GPIOX_7 ",
+ " SDA.1", "SCL.1 ",
+ " GPIOH_4", "GND(0V) ",
+ " GPIOH_5", "GPIOX_2 ",
+ " GPIOX_0", "GND(0V) ",
+ " GPIOX_1", "GPIOX_3 ",
+ " AIN.1", "1V8 ",
+ " GND(0V)", "AIN.0 ",
+
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,
+};
+
+/*----------------------------------------------------------------------------*/
+static const char *physNamesOdroidC5 [64] =
+{
+ NULL,
+
+ " 3.3V", "5V ",
+ " SDA.0", "5V ",
+ " SCL.0", "0V ",
+ " IO_D4", "TxD1 ",
+ " 0V", "RxD1 ",
+ " IO_X5", "IO_X14 ",
+ " IO_X15", "0V ",
+ " IO_X4", "IO_DV1 ",
+ " 3.3V", "IO_DV2 ",
+ " MOSI", "0V ",
+ " MISO", "IOX_6 ",
+ " SLCK", "SS ",
+ " 0V", "IOX_7 ",
+ " SDA.1", "SCL.1 ",
+ " IO_H4", "0V ",
+ " IO_H5", "IOX_2 ",
+ " IO_X0", "0V ",
+ " IO_X1", "IOX_3 ",
+ " AIN.1", "1V8 ",
+ " 0V", "AIN.0 ",
+
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ NULL,NULL,NULL,
+};
+
+/*----------------------------------------------------------------------------*/
+
static void readallPhys(int model, int UNU rev, int physPin, const char *physNames[], int isAll) {
int pin ;
@@ -834,6 +897,7 @@
case MODEL_ODROID_M1:
case MODEL_ODROID_M1S:
case MODEL_ODROID_M2:
+ case MODEL_ODROID_C5:
printf (" | %2d | %5s", getDrive(pin), pupd[getPUPD(pin)]);
break;
default:
@@ -878,6 +942,7 @@
case MODEL_ODROID_M1:
case MODEL_ODROID_M1S:
case MODEL_ODROID_M2:
+ case MODEL_ODROID_C5:
printf (" | %-5s | %-2d", pupd[getPUPD(pin)], getDrive(pin));
break;
default:
@@ -1108,6 +1173,10 @@
headerName = (isAll == FALSE) ? "--- M2 ---" : "---- Model ODROID-M2 ----";
physNames = (char *) ((isAll == FALSE) ? physNamesOdroidM2 : physNamesOdroidM2All);
break;
+ case MODEL_ODROID_C5:
+ headerName = (isAll == FALSE) ? "--- C5 ---" : "---- Model ODROID-C5 ----";
+ physNames = (char *) ((isAll == FALSE) ? physNamesOdroidC5 : physNamesOdroidC5All);
+ break;
default:
printf("Oops - unknown model: %d\n", model);
return;
diff --git a/wiringPi/Makefile.am b/wiringPi/Makefile.am
index 35eb930..75d35e6 100644
--- a/wiringPi/Makefile.am
+++ b/wiringPi/Makefile.am
@@ -21,6 +21,7 @@
odroidc1.c \
odroidc2.c \
odroidc4.c \
+ odroidc5.c \
odroidhc4.c \
odroidm1.c \
odroidm1s.c \
diff --git a/wiringPi/odroidc5.c b/wiringPi/odroidc5.c
new file mode 100644
index 0000000..4d97071
--- /dev/null
+++ b/wiringPi/odroidc5.c
@@ -0,0 +1,1005 @@
+/*----------------------------------------------------------------------------*/
+//
+//
+// WiringPi ODROID-C4 Board Control file (AMLogic 64Bits Platform)
+//
+//
+/*----------------------------------------------------------------------------*/
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+/*----------------------------------------------------------------------------*/
+#include "softPwm.h"
+#include "softTone.h"
+
+/*----------------------------------------------------------------------------*/
+#include "wiringPi.h"
+#include "odroidc5.h"
+
+/*----------------------------------------------------------------------------*/
+// wiringPi gpio map define
+/*----------------------------------------------------------------------------*/
+static const int pinToGpio[64] = {
+ // wiringPi number to native gpio number
+ 481, 490, // 0 | 1
+ 491, 480, // 2 | 3
+ 458, 459, // 4 | 5
+ 482, 456, // 6 | 7
+ 493, 494, // 8 | 9
+ 486, 483, // 10 | 11
+ 484, 485, // 12 | 13
+ 487, 488, // 14 | 15
+ 489, -1, // 16 | 17
+ -1, -1, // 18 | 19
+ -1, 468, // 20 | 21
+ 469, 476, // 22 | 23
+ 477, -1, // 24 | 25
+ 478, 479, // 26 | 27
+ -1, -1, // 28 | 29
+ 455, 454, // 30 | 31
+ // 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
+ -1, -1, // 1 | 2
+ 493, -1, // 3 | 4
+ 494, -1, // 5 | 6
+ 456, 488, // 7 | 8
+ -1, 489, // 9 | 10
+ 481, 490, // 11 | 12
+ 491, -1, // 13 | 14
+ 480, 458, // 15 | 16
+ -1, 459, // 17 | 18
+ 484, -1, // 19 | 20
+ 485, 482, // 21 | 22
+ 487, 486, // 23 | 24
+ -1, 433, // 25 | 26
+ 455, 454, // 27 | 28
+ 468, -1, // 29 | 30
+ 469, 478, // 31 | 32
+ 476, -1, // 33 | 34
+ 477, 479, // 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", "None", // 0 | 1
+ "None", "None", // 2 | 3
+ "None", "None", // 4 | 5
+ "fe058000", "fe058200", // 6 | 7 : PWM_A, PWM_B
+ "None", "None", // 8 | 9
+ "None", "fe058a00", // 10 | 11 : , PWM_F
+ "None", "None", // 12 | 13
+ "None", "None", // 14 | 15
+ "None", "None", // 16 | 17
+ "None", "None", // 18 | 19
+ "None", "None", // 20 | 21
+ "None", "None", // 22 | 23
+ "None", "None", // 24 | 25
+ "None", "None", // 26 | 27
+ "None", "None", // 28 | 29
+ "None", "fe058400", // 30 | 31 : , PWM_C
+ // 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
+ -1, -1, // 2 | 3
+ -1, -1, // 4 | 5
+ 0, 1, // 6 | 7 : PWM_A, PWM_B
+ -1, -1, // 8 | 9
+ -1, 4, // 10 | 11 : , PWM_F
+ -1, -1, // 12 | 13
+ -1, -1, // 14 | 15
+ -1, -1, // 16 | 17
+ -1, -1, // 18 | 19
+ -1, -1, // 20 | 21
+ -1, -1, // 22 | 23
+ 1, -1, // 24 | 25
+ -1, -1, // 26 | 27
+ -1, -1, // 28 | 29
+ -1, 2, // 30 | 31 : , PWM_C
+ // 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[10][BLOCK_SIZE] = {
+ "None","None",
+ "None","None",
+ "None","None",
+ "None","None",
+ "None","None"
+};
+
+/*----------------------------------------------------------------------------*/
+//
+// Global variable define
+//
+/*----------------------------------------------------------------------------*/
+// wiringPi Pinmap control arrary
+/*----------------------------------------------------------------------------*/
+/* ADC file descriptor */
+static int adcFds[2];
+
+/* GPIO mmap control */
+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
+/*----------------------------------------------------------------------------*/
+static int gpioToOffset(int pin);
+static int gpioToInputReg (int pin);
+static int gpioToOutputReg (int pin);
+static int gpioToPullEnReg (int pin);
+static int gpioToPullDirReg (int pin);
+static int gpioToDirectionReg (int pin);
+static int gpioToShiftReg (int pin);
+static int gpioToDSReg (int pin);
+static int gpioToDSShift (int pin);
+static int gpioToMuxReg (int pin);
+static int gpioToMuxShift (int pin);
+/*----------------------------------------------------------------------------*/
+// 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);
+static int _setDrive (int pin, int value);
+static int _getDrive (int pin);
+static int _pinMode (int pin, int mode);
+static int _getAlt (int pin);
+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
+/*----------------------------------------------------------------------------*/
+static void init_gpio_mmap (void);
+static void init_adc_fds (void);
+
+/*----------------------------------------------------------------------------*/
+
+/**
+ * Offset to the GPIO base offset
+ * @param pin gpio number
+ * @return Base register or -1
+ */
+static int gpioToOffset(int pin) {
+ if (C5_IS_GPIO_X(pin))
+ return C5_GPIO_X_OFFSET;
+ if (C5_IS_GPIO_D(pin))
+ return C5_GPIO_D_OFFSET;
+ if (C5_IS_GPIO_H(pin))
+ return C5_GPIO_H_OFFSET;
+ if (C5_IS_GPIO_DV(pin))
+ return C5_GPIO_DV_OFFSET;
+ return -1;
+}
+
+/**
+ * Offset to the GPIO output value register
+ * @param pin gpio number
+ * @return Output value register or -1
+ */
+static int gpioToOutputReg (int pin)
+{
+ int ret = gpioToOffset(pin);
+ if (ret == -1) return -1;
+
+ return ret + C5_GPIO_O_OFFSET;
+}
+
+/**
+ * Offset to the GPIO input value register
+ * @param pin gpio number
+ * @return Input value register or -1
+ */
+static int gpioToInputReg (int pin)
+{
+ int ret = gpioToOffset(pin);
+ if (ret == -1) return -1;
+
+ return ret + C5_GPIO_I_OFFSET;
+}
+
+/**
+ * Offset to the GPIO Pull up/down enable register
+ * @param pin gpio number
+ * @return Pull enable register or -1
+ */
+static int gpioToPullEnReg (int pin)
+{
+ int ret = gpioToOffset(pin);
+ if (ret == -1) return -1;
+
+ return ret + C5_GPIO_PULL_EN_OFFSET;
+}
+
+/**
+ * Offset to the GPIO Pull up/down direction register
+ * @param pin gpio number
+ * @return Pull direction register or -1
+ */
+static int gpioToPullDirReg (int pin)
+{
+ int ret = gpioToOffset(pin);
+ if (ret == -1) return -1;
+
+ return ret + C5_GPIO_PULL_UP_OFFSET;
+}
+
+/**
+ * Offset to the GPIO Direction register
+ * @param pin gpio number
+ * @return Direction register offset or -1
+ */
+static int gpioToDirectionReg (int pin)
+{
+ int ret = gpioToOffset(pin);
+ if (ret == -1) return -1;
+
+ return ret + C5_GPIO_OEN_OFFSET;
+}
+
+/**
+ * Offset to the GPIO bit
+ * @param pin gpio number
+ * @return
+ */
+static int gpioToShiftReg (int pin)
+{
+ if (C5_IS_GPIO_X(pin))
+ return pin - C5_GPIO_X_WPI_START;
+ if (C5_IS_GPIO_D(pin))
+ return pin - C5_GPIO_D_WPI_START;
+ if (C5_IS_GPIO_H(pin))
+ return pin - C5_GPIO_H_WPI_START;
+ if (C5_IS_GPIO_DV(pin))
+ return pin - C5_GPIO_DV_WPI_START;
+ return -1;
+}
+
+/**
+ * Offset to the GPIO DS register
+ * @param pin gpio number
+ * @return DS register or -1
+ */
+static int gpioToDSReg (int pin)
+{
+ int x = gpioToOffset(pin);
+ if (x == -1) return -1;
+
+ if (C5_IS_GPIO_X_EXT(pin))
+ return x + C5_GPIO_DS_EXT_OFFSET;
+
+ return x + C5_GPIO_DS_OFFSET;
+}
+
+/**
+ * Offset to the GPIO DS shift
+ * @param pin gpio number
+ * @return DS register or -1
+ */
+static int gpioToDSShift (int pin)
+{
+ if (C5_IS_GPIO_X_EXT(pin))
+ return pin - C5_GPIO_X(16);
+ return gpioToShiftReg(pin);
+}
+
+/**
+ * Offset to the pin mux register
+ * @param pin gpio number
+ * @return Pin mux register or -1
+ */
+static int gpioToMuxReg (int pin)
+{
+ if (pin == C5_GPIO_DV(1) || pin == C5_GPIO_DV(2))
+ return C5_PIN_MUX_REG2_OFFSET;
+ if (pin >= C5_GPIO_X(0) && pin <= C5_GPIO_X(7))
+ return C5_PIN_MUX_REG3_OFFSET;
+ if ((pin >= C5_GPIO_X(8) && pin <= C5_GPIO_X(15)))
+ return C5_PIN_MUX_REG4_OFFSET;
+ if (pin >= C5_GPIO_X(17) && pin <= C5_GPIO_X(18))
+ return C5_PIN_MUX_REG5_OFFSET;
+ if (pin >= C5_GPIO_H(4) && pin <= C5_GPIO_H(5))
+ return C5_PIN_MUX_REGB_OFFSET;
+ if (pin >= C5_GPIO_D(2) && pin <= C5_GPIO_D(4))
+ return C5_PIN_MUX_REGG_OFFSET;
+
+ return -1;
+}
+
+/**
+ * Offset to the pin mux shift
+ * @param pin gpio number
+ * @return Pin mux shift or -1
+ */
+static int gpioToMuxShift (int pin)
+{
+ if (pin == C5_GPIO_DV(1) || pin == C5_GPIO_DV(2))
+ return pin - C5_GPIO_DV(0);
+ if (pin >= C5_GPIO_X(0) && pin <= C5_GPIO_X(7))
+ return pin - C5_GPIO_X(0);
+ if ((pin >= C5_GPIO_X(8) && pin <= C5_GPIO_X(15)))
+ return pin - C5_GPIO_X(8);
+ if (pin >= C5_GPIO_X(17) && pin <= C5_GPIO_X(18))
+ return pin - C5_GPIO_X(16);
+ if (pin >= C5_GPIO_H(4) && pin <= C5_GPIO_H(5))
+ return pin - C5_GPIO_H(0);
+ if (pin >= C5_GPIO_D(2) && pin <= C5_GPIO_D(4))
+ return pin - C5_GPIO_D(0);
+
+ return -1;
+}
+
+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];
+ pwmClock = C5_PWM_INTERNAL_CLK;
+ sprintf(pwmExport, "%d", 0);
+ sprintf(pwmPinPath[pwmPin], "%s/pwm%d", sysPwmPath, 0);
+ strncpy(setupedPwmPinPath[pwmPin], pwmPinPath[pwmPin], (BLOCK_SIZE - 1));
+#ifdef ANDROID
+ sprintf(cmd, "su -s sh -c %s %s", SYS_ACCESS_SCRIPT, pwmPinPath[pwmPin]);
+#else
+ sprintf(cmd, "sudo sh %s %s", SYS_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", 0);
+ sprintf(pwmPinPath[pwmPin], "%s/pwm%d", sysPwmPath, 0);
+ 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)
+{
+ int retPin = -1;
+
+ switch (mode) {
+ /* Native gpio number */
+ case MODE_GPIO:
+ retPin = pin;
+ break;
+ /* Native gpio number for sysfs */
+ case MODE_GPIO_SYS:
+ retPin = lib->sysFds[pin] != -1 ? pin : -1;
+ break;
+ /* wiringPi number */
+ case MODE_PINS:
+ retPin = pin < 64 ? pinToGpio[pin] : -1;
+ break;
+ /* header pin number */
+ case MODE_PHYS:
+ retPin = pin < 64 ? phyToGpio[pin] : -1;
+ break;
+ default :
+ msg(MSG_WARN, "%s : Unknown Mode %d\n", __func__, mode);
+ return -1;
+ }
+
+ return retPin;
+}
+
+/*----------------------------------------------------------------------------*/
+static int _setDrive (int pin, int value)
+{
+ int ds, shift;
+
+ if (lib->mode == MODE_GPIO_SYS)
+ return -1;
+
+ if ((pin = _getModeToGpio(lib->mode, pin)) < 0)
+ return -1;
+
+ if (value < 0 || value > 3) {
+ msg(MSG_WARN, "%s : Invalid value %d (Must be 0 ~ 3)\n", __func__, value);
+ return -1;
+ }
+
+ ds = gpioToDSReg(pin);
+ shift = gpioToDSShift(pin);
+
+ *(gpio + ds) &= ~(0b11 << shift);
+ *(gpio + ds) |= (value << shift);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+static int _getDrive (int pin)
+{
+ int ds, shift;
+
+ if (lib->mode == MODE_GPIO_SYS)
+ return -1;
+
+ if ((pin = _getModeToGpio(lib->mode, pin)) < 0)
+ return -1;
+
+ ds = gpioToDSReg(pin);
+ shift = gpioToDSShift(pin);
+
+ return (*(gpio + ds) >> shift) & 0b11;
+}
+
+/*----------------------------------------------------------------------------*/
+static int _pinMode (int pin, int mode)
+{
+ int dir, shift, origPin = pin;
+
+ if (lib->mode == MODE_GPIO_SYS)
+ return -1;
+
+ if ((pin = _getModeToGpio(lib->mode, pin)) < 0)
+ return -1;
+
+ pwmRelease (origPin);
+ softPwmStop (origPin);
+ softToneStop (origPin);
+
+ dir = gpioToDirectionReg(pin);
+ shift = gpioToShiftReg (pin);
+
+ switch (mode) {
+ case INPUT:
+ *(gpio + dir) = (*(gpio + dir) | (1 << shift));
+ break;
+ case OUTPUT:
+ *(gpio + dir) = (*(gpio + dir) & ~(1 << shift));
+ break;
+ case SOFT_PWM_OUTPUT:
+ softPwmCreate (pin, 0, 100);
+ break;
+ 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;
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+static int _getAlt (int pin)
+{
+ int dir, mux, shift, target, mode;
+
+ if (lib->mode == MODE_GPIO_SYS)
+ return -1;
+
+ if ((pin = _getModeToGpio(lib->mode, pin)) < 0)
+ return -1;
+
+ dir = gpioToDirectionReg(pin);
+ mux = gpioToMuxReg(pin);
+ shift = gpioToShiftReg (pin);
+ target = gpioToMuxShift(pin);
+
+ while (target >= 8) {
+ target -= 8;
+ }
+
+ mode = (*(gpio + mux) >> (target * 4)) & 0xF;
+ return mode ? mode + 1 : (*(gpio + dir) & (1 << shift)) ? 0 : 1;
+}
+
+/*----------------------------------------------------------------------------*/
+static int _getPUPD (int pin)
+{
+ int puen, pupd, shift;
+
+ if (lib->mode == MODE_GPIO_SYS)
+ return -1;
+
+ if ((pin = _getModeToGpio(lib->mode, pin)) < 0)
+ return -1;
+
+ puen = gpioToPullEnReg(pin);
+ pupd = gpioToPullDirReg(pin);
+ shift = gpioToShiftReg(pin);
+
+ if (*(gpio + puen) & (1 << shift)) return *(gpio + pupd) & (1 << shift) ? 1 : 2;
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+static int _pullUpDnControl (int pin, int pud)
+{
+ int shift = 0;
+
+ if (lib->mode == MODE_GPIO_SYS)
+ return -1;
+
+ if ((pin = _getModeToGpio(lib->mode, pin)) < 0)
+ return -1;
+
+ shift = gpioToShiftReg(pin);
+
+ if (pud) {
+ // Enable Pull/Pull-down resister
+ *(gpio + gpioToPullEnReg(pin)) =
+ (*(gpio + gpioToPullEnReg(pin)) | (1 << shift));
+
+ if (pud == PUD_UP)
+ *(gpio + gpioToPullDirReg(pin)) =
+ (*(gpio + gpioToPullDirReg(pin)) | (1 << shift));
+ else
+ *(gpio + gpioToPullDirReg(pin)) =
+ (*(gpio + gpioToPullDirReg(pin)) & ~(1 << shift));
+ } else // Disable Pull/Pull-down resister
+ *(gpio + gpioToPullEnReg(pin)) =
+ (*(gpio + gpioToPullEnReg(pin)) & ~(1 << shift));
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+static int _digitalRead (int pin)
+{
+ char c ;
+
+ if (lib->mode == MODE_GPIO_SYS) {
+ if (lib->sysFds[pin] == -1)
+ return -1;
+
+ lseek (lib->sysFds[pin], 0L, SEEK_SET);
+ if (read(lib->sysFds[pin], &c, 1) < 0) {
+ msg(MSG_WARN, "%s: Failed with reading from sysfs GPIO node. \n", __func__);
+ return -1;
+ }
+
+ return (c == '0') ? LOW : HIGH;
+ }
+
+ if ((pin = _getModeToGpio(lib->mode, pin)) < 0)
+ return -1;
+
+ if ((*(gpio + gpioToInputReg(pin)) & (1 << gpioToShiftReg(pin))) != 0)
+ return HIGH ;
+ else
+ return LOW ;
+}
+
+/*----------------------------------------------------------------------------*/
+static int _digitalWrite (int pin, int value)
+{
+ if (lib->mode == MODE_GPIO_SYS) {
+ if (lib->sysFds[pin] != -1) {
+ if (value == LOW) {
+ if (write(lib->sysFds[pin], "0\n", 2) < 0)
+ msg(MSG_WARN, "%s: Failed with reading from sysfs GPIO node. \n", __func__);
+ } else {
+ if (write(lib->sysFds[pin], "1\n", 2) < 0)
+ msg(MSG_WARN, "%s: Failed with reading from sysfs GPIO node. \n", __func__);
+ }
+ }
+ return -1;
+ }
+
+ if ((pin = _getModeToGpio(lib->mode, pin)) < 0)
+ return -1;
+
+ if (value == LOW)
+ *(gpio + gpioToOutputReg(pin)) &= ~(1 << gpioToShiftReg(pin));
+ else
+ *(gpio + gpioToOutputReg(pin)) |= (1 << gpioToShiftReg(pin));
+
+ return 0;
+}
+
+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("warn : pwm range 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)
+{
+ char value[5] = {0,};
+
+ if (lib->mode == MODE_GPIO_SYS)
+ return -1;
+
+ /* wiringPi ADC number = pin 25, pin 29 */
+ switch (pin) {
+#if defined(ARDUINO)
+ /* To work with physical analog channel numbering */
+ case 2: case 25:
+ pin = 0;
+ break;
+ case 0: case 29:
+ pin = 1;
+ break;
+#else
+ case 0: case 25:
+ pin = 0;
+ break;
+ case 1: case 29:
+ pin = 1;
+ break;
+#endif
+ default:
+ return 0;
+ }
+ if (adcFds [pin] == -1)
+ return 0;
+
+ lseek (adcFds [pin], 0L, SEEK_SET);
+ if (read(adcFds [pin], &value[0], 4) < 0) {
+ msg(MSG_WARN, "%s: Error occurs when it reads from ADC file descriptor. \n", __func__);
+ return -1;
+ }
+
+ return atoi(value);
+}
+
+/*----------------------------------------------------------------------------*/
+static int _digitalWriteByte (const unsigned int value)
+{
+ union reg_bitfield gpiox;
+ union reg_bitfield gpiod;
+
+ if (lib->mode == MODE_GPIO_SYS)
+ return -1;
+
+ gpiox.wvalue = *(gpio + C5_GPIO_X_OFFSET + C5_GPIO_I_OFFSET);
+ gpiod.wvalue = *(gpio + C5_GPIO_D_OFFSET + C5_GPIO_I_OFFSET);
+
+ /* Wiring PI GPIO0 = C5 GPIOX.5 */
+ gpiox.bits.bit5 = (value & 0x01);
+ /* Wiring PI GPIO1 = C5 GPIOX.16 */
+ gpiox.bits.bit16 = (value & 0x02);
+ /* Wiring PI GPIO2 = C5 GPIOX.15 */
+ gpiox.bits.bit15 = (value & 0x04);
+ /* Wiring PI GPIO3 = C5 GPIOX.4 */
+ gpiox.bits.bit4 = (value & 0x08);
+ /* Wiring PI GPIO4 = C5 GPIOD.2 */
+ gpiod.bits.bit2 = (value & 0x10);
+ /* Wiring PI GPIO5 = C5 GPIOD.3 */
+ gpiod.bits.bit3 = (value & 0x20);
+ /* Wiring PI GPIO6 = C5 GPIOX.6 */
+ gpiox.bits.bit6 = (value & 0x40);
+ /* Wiring PI GPIO7 = C5 GPIOD.4 */
+ gpiod.bits.bit4 = (value & 0x80);
+
+ *(gpio + C5_GPIO_X_OFFSET + C5_GPIO_O_OFFSET) = gpiox.wvalue;
+ *(gpio + C5_GPIO_D_OFFSET + C5_GPIO_O_OFFSET) = gpiod.wvalue;
+
+ return 0;
+}
+
+static unsigned int _digitalReadByte (void)
+{
+ union reg_bitfield gpiox;
+ union reg_bitfield gpiod;
+
+ unsigned int value = 0;
+
+ if (lib->mode == MODE_GPIO_SYS)
+ return -1;
+
+ gpiox.wvalue = *(gpio + C5_GPIO_X_OFFSET + C5_GPIO_I_OFFSET);
+ gpiod.wvalue = *(gpio + C5_GPIO_D_OFFSET + C5_GPIO_I_OFFSET);
+
+ /* Wiring PI GPIO0 = C5 GPIOX.5 */
+ if (gpiox.bits.bit5)
+ value |= 0x01;
+ /* Wiring PI GPIO1 = C5 GPIOX.16 */
+ if (gpiox.bits.bit16)
+ value |= 0x02;
+ /* Wiring PI GPIO2 = C5 GPIOX.15 */
+ if (gpiox.bits.bit15)
+ value |= 0x04;
+ /* Wiring PI GPIO3 = C5 GPIOX.4 */
+ if (gpiox.bits.bit4)
+ value |= 0x08;
+ /* Wiring PI GPIO4 = C5 GPIOD.2 */
+ if (gpiod.bits.bit2)
+ value |= 0x10;
+ /* Wiring PI GPIO5 = C5 GPIOD.3 */
+ if (gpiod.bits.bit3)
+ value |= 0x20;
+ /* Wiring PI GPIO6 = C5 GPIOX.6 */
+ if (gpiox.bits.bit6)
+ value |= 0x40;
+ /* Wiring PI GPIO7 = C5 GPIOD.4 */
+ if (gpiod.bits.bit4)
+ value |= 0x80;
+
+ return value;
+}
+
+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("error : pwm freq: %dMHz / (pwmSetClock's value) >= 2\n",
+ (C5_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);
+
+ for (int i = 0; i < 10; i++) {
+ if (strstr(setupedPwmPinPath[i], "None") != NULL)
+ continue;
+ inputToSysNode(setupedPwmPinPath[i], "period", pwmPeriod);
+ inputToSysNode(setupedPwmPinPath[i], "polarity", "normal");
+ inputToSysNode(setupedPwmPinPath[i], "enable", "1");
+ }
+}
+
+static void _pwmSetClock (int divisor)
+{
+ if (pwmClock > 0)
+ pwmClock = (pwmClock / divisor);
+ else {
+ printf("error : pwm mode error\n");
+ return;
+ }
+}
+
+static void init_gpio_mmap (void)
+{
+ int fd = -1;
+ void *mapped;
+
+ /* GPIO mmap setup */
+ if (!getuid()) {
+ if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0)
+ msg (MSG_ERR,
+ "wiringPiSetup: Unable to open /dev/mem: %s\n",
+ strerror (errno));
+ } else {
+ if (access("/dev/gpiomem",0) == 0) {
+ if ((fd = open ("/dev/gpiomem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0)
+ msg (MSG_ERR,
+ "wiringPiSetup: Unable to open /dev/gpiomem: %s\n",
+ strerror (errno));
+ setUsingGpiomem(TRUE);
+ } else
+ msg (MSG_ERR,
+ "wiringPiSetup: /dev/gpiomem doesn't exist. Please try again with sudo.\n");
+ }
+
+ if (fd < 0) {
+ msg(MSG_ERR, "wiringPiSetup: Cannot open memory area for GPIO use. \n");
+ } else {
+ // #define C4_GPIO_BASE 0xff634000
+#ifdef ANDROID
+#if defined(__aarch64__)
+ mapped = mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, C5_GPIO_BASE);
+#else
+ mapped = mmap64(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off64_t)C5_GPIO_BASE);
+#endif
+#else
+ mapped = mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, C5_GPIO_BASE);
+#endif
+
+ if (mapped == MAP_FAILED)
+ msg(MSG_ERR, "wiringPiSetup: mmap (GPIO) failed: %s \n", strerror (errno));
+ else
+ gpio = (uint32_t *) mapped;
+ }
+}
+
+static void init_adc_fds (void)
+{
+ const char *AIN25_NODE, *AIN29_NODE;
+
+ /* ADC node setup */
+ AIN25_NODE = "/sys/bus/iio/devices/iio:device0/in_voltage0_raw";
+ AIN29_NODE = "/sys/bus/iio/devices/iio:device0/in_voltage1_raw";
+
+ adcFds[0] = open(AIN25_NODE, O_RDONLY);
+ adcFds[1] = open(AIN29_NODE, O_RDONLY);
+}
+
+/*----------------------------------------------------------------------------*/
+void init_odroidc5 (struct libodroid *libwiring)
+{
+ init_gpio_mmap();
+
+ init_adc_fds();
+
+ /* wiringPi Core function initialize */
+ libwiring->getModeToGpio = _getModeToGpio;
+ libwiring->setDrive = _setDrive;
+ libwiring->getDrive = _getDrive;
+ libwiring->pinMode = _pinMode;
+ libwiring->getAlt = _getAlt;
+ libwiring->getPUPD = _getPUPD;
+ 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 = C5_GPIO_D_WPI_START;
+
+ /* global variable setup */
+ lib = libwiring;
+}
diff --git a/wiringPi/odroidc5.h b/wiringPi/odroidc5.h
new file mode 100644
index 0000000..671abf9
--- /dev/null
+++ b/wiringPi/odroidc5.h
@@ -0,0 +1,68 @@
+/*----------------------------------------------------------------------------*/
+/*
+
+ WiringPi ODROID-C5 Board Header file
+
+ */
+/*----------------------------------------------------------------------------*/
+#ifndef __ODROID_C5_H__
+#define __ODROID_C5_H__
+
+/*----------------------------------------------------------------------------*/
+
+#define C5_PWM_INTERNAL_CLK 24000000
+
+#define C5_GPIO_BASE 0xfe004000
+
+#define C5_GPIO_D_WPI_START 452
+#define C5_GPIO_DV_WPI_START 457
+#define C5_GPIO_H_WPI_START 464
+#define C5_GPIO_X_WPI_START 476
+
+#define C5_GPIO_D(REG) (REG + C5_GPIO_D_WPI_START)
+#define C5_GPIO_DV(REG) (REG + C5_GPIO_DV_WPI_START)
+#define C5_GPIO_H(REG) (REG + C5_GPIO_H_WPI_START)
+#define C5_GPIO_X(REG) (REG + C5_GPIO_X_WPI_START)
+
+#define C5_IS_GPIO_D(W) (W >= C5_GPIO_D(2) && W <= C5_GPIO_D(4))
+#define C5_IS_GPIO_DV(W) (W >= C5_GPIO_DV(1) && W <= C5_GPIO_DV(2))
+#define C5_IS_GPIO_H(W) (W >= C5_GPIO_H(4) && W <= C5_GPIO_H(5))
+#define C5_IS_GPIO_X(W) (W >= C5_GPIO_X(0) && W <= C5_GPIO_X(18) && W != C5_GPIO_X(16))
+#define C5_IS_GPIO_X_EXT(W) (W >= C5_GPIO_X(16) && W <= C5_GPIO_X(18))
+
+#define C5_PIN_MUX_REG2_OFFSET 0x02
+#define C5_PIN_MUX_REG3_OFFSET 0x03
+#define C5_PIN_MUX_REG4_OFFSET 0x04
+#define C5_PIN_MUX_REG5_OFFSET 0x05
+#define C5_PIN_MUX_REGB_OFFSET 0x0b
+#define C5_PIN_MUX_REGG_OFFSET 0x10
+
+#define C5_GPIO_X_OFFSET 0x40
+#define C5_GPIO_H_OFFSET 0x50
+#define C5_GPIO_D_OFFSET 0x60
+#define C5_GPIO_DV_OFFSET 0xa0
+
+#define C5_GPIO_I_OFFSET 0x00
+#define C5_GPIO_O_OFFSET 0x01
+#define C5_GPIO_OEN_OFFSET 0x02
+#define C5_GPIO_PULL_EN_OFFSET 0x03
+#define C5_GPIO_PULL_UP_OFFSET 0x04
+#define C5_GPIO_DS_OFFSET 0x07
+#define C5_GPIO_DS_EXT_OFFSET 0x08
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void init_odroidc5 (struct libodroid *libwiring);
+
+#ifdef __cplusplus
+}
+#endif
+
+/*----------------------------------------------------------------------------*/
+#endif /* __ODROID_C5_H__ */
+/*----------------------------------------------------------------------------*/
+/*----------------------------------------------------------------------------*/
diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c
index 6737de5..f889ac9 100644
--- a/wiringPi/wiringPi.c
+++ b/wiringPi/wiringPi.c
@@ -47,6 +47,7 @@
#include "odroidc4.h"
#include "odroidm1.h"
#include "odroidm2.h"
+#include "odroidc5.h"
/*----------------------------------------------------------------------------*/
// Const string define
@@ -67,6 +68,7 @@
"ODROID-M1",
"ODROID-M1S",
"ODROID-M2",
+ "ODROID-C5",
};
const char *piRevisionNames [16] =
@@ -551,6 +553,11 @@
libwiring.mem = 5;
libwiring.rev = 1;
break;
+ case MODEL_ODROID_C5:
+ libwiring.maker = MAKER_AMLOGIC;
+ libwiring.mem = 4;
+ libwiring.rev = 1;
+ break;
case MODEL_UNKNOWN:
default:
libwiring.model = MAKER_UNKNOWN;
@@ -1279,6 +1286,9 @@
case MODEL_ODROID_M2:
init_odroidm2(&libwiring);
break;
+ case MODEL_ODROID_C5:
+ init_odroidc5(&libwiring);
+ break;
default:
return wiringPiFailure (WPI_ALMOST,
"wiringPiSetup: Unknown model\n");
diff --git a/wiringPi/wiringPi.h b/wiringPi/wiringPi.h
index 067b543..c4dd59c 100644
--- a/wiringPi/wiringPi.h
+++ b/wiringPi/wiringPi.h
@@ -63,6 +63,7 @@
#define MODEL_ODROID_M1 8
#define MODEL_ODROID_M1S 9
#define MODEL_ODROID_M2 10
+#define MODEL_ODROID_C5 11
#define MAKER_UNKNOWN 0
#define MAKER_AMLOGIC 1
diff --git a/wiringPi/wiringPiI2C.c b/wiringPi/wiringPiI2C.c
index 7a843e5..9bc099b 100644
--- a/wiringPi/wiringPiI2C.c
+++ b/wiringPi/wiringPiI2C.c
@@ -270,6 +270,8 @@
case MODEL_ODROID_M1S:
case MODEL_ODROID_M2:
device = "/dev/i2c-0";
+ case MODEL_ODROID_C5:
+ device = "/dev/i2c-0";
break;
}
diff --git a/wiringPi/wiringPiSPI.c b/wiringPi/wiringPiSPI.c
index 9c1c4ef..131f2b9 100644
--- a/wiringPi/wiringPiSPI.c
+++ b/wiringPi/wiringPiSPI.c
@@ -151,6 +151,7 @@
case MODEL_ODROID_M1:
case MODEL_ODROID_M1S:
case MODEL_ODROID_M2:
+ case MODEL_ODROID_C5:
sprintf(device, "%s%d", spiDevType0, channel);
break;
case MODEL_ODROID_XU3: