From b99cbc570b1782a273b949b2e6397c10d564daf5 Mon Sep 17 00:00:00 2001 From: YoungSoo Shin Date: Fri, 11 Oct 2024 12:17:15 +0900 Subject: [PATCH] ODROID-C5: Add odroid-c5 wiring-pi support - Rev. 20250106 - Warning: Use only GPIO functions. Signed-off-by: YoungSoo Shin Change-Id: I02623a284c047c6b5e485d28c9714ed8e65025df --- Android.bp | 1 + debian/changelog | 7 + gpio/readall.c | 69 +++ wiringPi/Makefile.am | 1 + wiringPi/odroidc5.c | 1005 ++++++++++++++++++++++++++++++++++++++++ wiringPi/odroidc5.h | 68 +++ wiringPi/wiringPi.c | 10 + wiringPi/wiringPi.h | 1 + wiringPi/wiringPiI2C.c | 2 + wiringPi/wiringPiSPI.c | 1 + 10 files changed, 1165 insertions(+) create mode 100644 wiringPi/odroidc5.c create mode 100644 wiringPi/odroidc5.h diff --git a/Android.bp b/Android.bp index 7aa17ea..bf09a74 100644 --- a/Android.bp +++ b/Android.bp @@ -29,6 +29,7 @@ cc_library_shared { "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 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 *physNamesOdroidM2 [64] = }; /*----------------------------------------------------------------------------*/ +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 @@ static void readallPhys(int model, int UNU rev, int physPin, const char *physNam 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 @@ static void readallPhys(int model, int UNU rev, int physPin, const char *physNam 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 @@ void doReadall(int argc, char *argv[]) { 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 @@ libwiringPi_la_SOURCES = \ 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*----------------------------------------------------------------------------*/ +#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 @@ const char *piModelNames [16] = "ODROID-M1", "ODROID-M1S", "ODROID-M2", + "ODROID-C5", }; const char *piRevisionNames [16] = @@ -551,6 +553,11 @@ int piGpioLayout (void) { 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 @@ int wiringPiSetup (void) 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 @@ int wiringPiI2CSetup (const int devId) 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 @@ int wiringPiSPISetupMode (int channel, int speed, int mode) 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: