From 3043f3956cfc1d4533bf0fff4eedcf6bc8444369 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Mon, 22 Aug 2016 10:29:04 -0700 Subject: [PATCH 1/4] galileo: Simplify pinmux configuration This patch refactors the pinmux configuration code for Intel Galileo to simplify it. This patch also corrects an off-by-one error in how the pin number is checked in galileo_pinmux_set_pin. --- platform/galileo/drivers/galileo-pinmux.c | 79 +++++++++++------------ 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/platform/galileo/drivers/galileo-pinmux.c b/platform/galileo/drivers/galileo-pinmux.c index 3059bdb36..a6b0e6888 100644 --- a/platform/galileo/drivers/galileo-pinmux.c +++ b/platform/galileo/drivers/galileo-pinmux.c @@ -63,26 +63,26 @@ struct pin_config { }; static struct pin_config default_pinmux_config[PINMUX_NUM_PINS] = { - { 0, GALILEO_PINMUX_FUNC_C }, /* UART0_RXD */ - { 1, GALILEO_PINMUX_FUNC_C }, /* UART0_TXD */ - { 2, GALILEO_PINMUX_FUNC_A }, /* GPIO5(out) */ - { 3, GALILEO_PINMUX_FUNC_B }, /* GPIO6(in) */ - { 4, GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS4 (in) */ - { 5, GALILEO_PINMUX_FUNC_B }, /* GPIO8 (in) */ - { 6, GALILEO_PINMUX_FUNC_B }, /* GPIO9 (in) */ - { 7, GALILEO_PINMUX_FUNC_B }, /* EXP1.P0_6 (in) */ - { 8, GALILEO_PINMUX_FUNC_B }, /* EXP1.P1_0 (in) */ - { 9, GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS2 (in) */ - { 10, GALILEO_PINMUX_FUNC_A }, /* GPIO2 (out) */ - { 11, GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS3 (in) */ - { 12, GALILEO_PINMUX_FUNC_B }, /* GPIO7 (in) */ - { 13, GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS5(in) */ - { 14, GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_0 (in)/ADC.IN0 */ - { 15, GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_2 (in)/ADC.IN1 */ - { 16, GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_4 (in)/ADC.IN2 */ - { 17, GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_6 (in)/ADC.IN3 */ - { 18, GALILEO_PINMUX_FUNC_C }, /* I2C_SDA */ - { 19, GALILEO_PINMUX_FUNC_C }, /* I2C_SCL */ + { GALILEO_PINMUX_FUNC_C }, /* UART0_RXD */ + { GALILEO_PINMUX_FUNC_C }, /* UART0_TXD */ + { GALILEO_PINMUX_FUNC_A }, /* GPIO5(out) */ + { GALILEO_PINMUX_FUNC_B }, /* GPIO6(in) */ + { GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS4 (in) */ + { GALILEO_PINMUX_FUNC_B }, /* GPIO8 (in) */ + { GALILEO_PINMUX_FUNC_B }, /* GPIO9 (in) */ + { GALILEO_PINMUX_FUNC_B }, /* EXP1.P0_6 (in) */ + { GALILEO_PINMUX_FUNC_B }, /* EXP1.P1_0 (in) */ + { GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS2 (in) */ + { GALILEO_PINMUX_FUNC_A }, /* GPIO2 (out) */ + { GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS3 (in) */ + { GALILEO_PINMUX_FUNC_B }, /* GPIO7 (in) */ + { GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS5(in) */ + { GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_0 (in)/ADC.IN0 */ + { GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_2 (in)/ADC.IN1 */ + { GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_4 (in)/ADC.IN2 */ + { GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_6 (in)/ADC.IN3 */ + { GALILEO_PINMUX_FUNC_C }, /* I2C_SDA */ + { GALILEO_PINMUX_FUNC_C }, /* I2C_SCL */ }; struct mux_pin { @@ -535,7 +535,7 @@ galileo_pinmux_set_pin(uint8_t pin, GALILEO_PINMUX_FUNC func) struct mux_path *mux_path; uint8_t index, i; - if(pin > PINMUX_NUM_PINS) { + if(pin >= PINMUX_NUM_PINS) { return -1; } @@ -545,38 +545,33 @@ galileo_pinmux_set_pin(uint8_t pin, GALILEO_PINMUX_FUNC func) mux_path = &galileo_pinmux_paths[index]; for(i = 0; i < PINMUX_NUM_PATHS; i++) { + struct gpio_pcal9535a_data *exp = NULL; switch(mux_path->path[i].chip) { case EXP0: - if(gpio_pcal9535a_write(&data.exp0, mux_path->path[i].pin, mux_path->path[i].level) < 0) { - return -1; - } - if(gpio_pcal9535a_config(&data.exp0, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) { - return -1; - } + exp = &data.exp0; break; case EXP1: - if(gpio_pcal9535a_write(&data.exp1, mux_path->path[i].pin, mux_path->path[i].level) < 0) { - return -1; - } - if(gpio_pcal9535a_config(&data.exp1, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) { - return -1; - } + exp = &data.exp1; break; case EXP2: - if(gpio_pcal9535a_write(&data.exp2, mux_path->path[i].pin, mux_path->path[i].level) < 0) { - return -1; - } - if(gpio_pcal9535a_config(&data.exp2, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) { - return -1; - } + exp = &data.exp2; break; case PWM0: if(pwm_pca9685_set_duty_cycle(&data.pwm0, mux_path->path[i].pin, mux_path->path[i].level ? 100 : 0) < 0) { return -1; } - break; + continue; case NONE: - break; + continue; + } + + assert(exp != NULL); + + if(gpio_pcal9535a_write(exp, mux_path->path[i].pin, mux_path->path[i].level) < 0) { + return -1; + } + if(gpio_pcal9535a_config(exp, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) { + return -1; } } @@ -609,7 +604,7 @@ galileo_pinmux_initialize(void) } for(i = 0; i < PINMUX_NUM_PINS; i++) { - if(galileo_pinmux_set_pin(default_pinmux_config[i].pin_num, default_pinmux_config[i].func) < 0) { + if(galileo_pinmux_set_pin(i, default_pinmux_config[i].func) < 0) { return -1; } } From 2912559061d29cdaf896d00b1915e86c316e0ce3 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Mon, 22 Aug 2016 15:25:32 -0700 Subject: [PATCH 2/4] galileo: Revise pinmux API to be more intuitive This patch replaces the pinmux APIs that require users to look up an arbitrary function number for the desired function of each pin. The replacement API functions have intuitive names and permit users to pass board-level IO port numbers. The API functions internally convert those to CPU-level port numbers when necessary. Furthermore, when configuring a pin to be a digital input or output, those API functions also perform the corresponding configuration operation on the CPU-level GPIO port. The revised APIs halt when users attempt to configure a currently-unsupported GPIO, specifically those in the GPIO_SUS port range and those implemented on the expander chip EXP2. This also means that such ports are left unconfigured during initialization, whereas the pinmuxing for them was setup by the old implementation. --- examples/galileo/gpio-input.c | 3 - examples/galileo/gpio-interrupt.c | 1 - examples/galileo/gpio-output.c | 2 - platform/galileo/contiki-main.c | 6 +- platform/galileo/drivers/galileo-pinmux.c | 180 ++++++++++++++++++---- platform/galileo/drivers/galileo-pinmux.h | 51 +++++- 6 files changed, 195 insertions(+), 48 deletions(-) diff --git a/examples/galileo/gpio-input.c b/examples/galileo/gpio-input.c index 196ea9193..077055a69 100644 --- a/examples/galileo/gpio-input.c +++ b/examples/galileo/gpio-input.c @@ -67,9 +67,6 @@ PROCESS_THREAD(gpio_input_process, ev, data) { PROCESS_BEGIN(); - quarkX1000_gpio_config(PIN_OUTPUT, QUARKX1000_GPIO_OUT); - quarkX1000_gpio_config(PIN_INPUT, QUARKX1000_GPIO_IN); - quarkX1000_gpio_clock_enable(); ctimer_set(&timer, CLOCK_SECOND / 2, timeout, NULL); diff --git a/examples/galileo/gpio-interrupt.c b/examples/galileo/gpio-interrupt.c index 04fb4cc1b..ca4606266 100644 --- a/examples/galileo/gpio-interrupt.c +++ b/examples/galileo/gpio-interrupt.c @@ -63,7 +63,6 @@ PROCESS_THREAD(gpio_interrupt_process, ev, data) { PROCESS_BEGIN(); - quarkX1000_gpio_config(PIN_OUTPUT, QUARKX1000_GPIO_OUT); quarkX1000_gpio_config(PIN_INTR, QUARKX1000_GPIO_INT | QUARKX1000_GPIO_ACTIVE_HIGH | QUARKX1000_GPIO_EDGE); quarkX1000_gpio_set_callback(callback); diff --git a/examples/galileo/gpio-output.c b/examples/galileo/gpio-output.c index 4dad7d684..4cc50597e 100644 --- a/examples/galileo/gpio-output.c +++ b/examples/galileo/gpio-output.c @@ -57,8 +57,6 @@ PROCESS_THREAD(gpio_output_process, ev, data) { PROCESS_BEGIN(); - quarkX1000_gpio_config(PIN, QUARKX1000_GPIO_OUT); - quarkX1000_gpio_clock_enable(); ctimer_set(&timer, CLOCK_SECOND / 2, timeout, NULL); diff --git a/platform/galileo/contiki-main.c b/platform/galileo/contiki-main.c index 5e95c4902..5b8f50a7e 100644 --- a/platform/galileo/contiki-main.c +++ b/platform/galileo/contiki-main.c @@ -99,11 +99,15 @@ main(void) quarkX1000_i2c_init(); quarkX1000_i2c_configure(QUARKX1000_I2C_SPEED_STANDARD, QUARKX1000_I2C_ADDR_MODE_7BIT); + /* The GPIO subsystem must be initialized prior to configuring pinmux, because + * the pinmux configuration automatically performs GPIO configuration for the + * relevant pins. + */ + quarkX1000_gpio_init(); /* use default pinmux configuration */ if(galileo_pinmux_initialize() < 0) { fprintf(stderr, "Failed to initialize pinmux\n"); } - quarkX1000_gpio_init(); shared_isr_init(); /* The ability to remap interrupts is not needed after this point and should diff --git a/platform/galileo/drivers/galileo-pinmux.c b/platform/galileo/drivers/galileo-pinmux.c index a6b0e6888..c99ccd6c2 100644 --- a/platform/galileo/drivers/galileo-pinmux.c +++ b/platform/galileo/drivers/galileo-pinmux.c @@ -29,10 +29,19 @@ */ #include "galileo-pinmux.h" +#include #include "gpio.h" #include "gpio-pcal9535a.h" #include "i2c.h" #include "pwm-pca9685.h" +#include + +typedef enum { + GALILEO_PINMUX_FUNC_A, + GALILEO_PINMUX_FUNC_B, + GALILEO_PINMUX_FUNC_C, + GALILEO_PINMUX_FUNC_D +} GALILEO_PINMUX_FUNC; #define GPIO_PCAL9535A_0_I2C_ADDR 0x25 #define GPIO_PCAL9535A_1_I2C_ADDR 0x26 @@ -41,7 +50,6 @@ #define PINMUX_NUM_FUNCS 4 #define PINMUX_NUM_PATHS 4 -#define PINMUX_NUM_PINS 20 typedef enum { NONE, @@ -62,29 +70,6 @@ struct pin_config { GALILEO_PINMUX_FUNC func; }; -static struct pin_config default_pinmux_config[PINMUX_NUM_PINS] = { - { GALILEO_PINMUX_FUNC_C }, /* UART0_RXD */ - { GALILEO_PINMUX_FUNC_C }, /* UART0_TXD */ - { GALILEO_PINMUX_FUNC_A }, /* GPIO5(out) */ - { GALILEO_PINMUX_FUNC_B }, /* GPIO6(in) */ - { GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS4 (in) */ - { GALILEO_PINMUX_FUNC_B }, /* GPIO8 (in) */ - { GALILEO_PINMUX_FUNC_B }, /* GPIO9 (in) */ - { GALILEO_PINMUX_FUNC_B }, /* EXP1.P0_6 (in) */ - { GALILEO_PINMUX_FUNC_B }, /* EXP1.P1_0 (in) */ - { GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS2 (in) */ - { GALILEO_PINMUX_FUNC_A }, /* GPIO2 (out) */ - { GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS3 (in) */ - { GALILEO_PINMUX_FUNC_B }, /* GPIO7 (in) */ - { GALILEO_PINMUX_FUNC_B }, /* GPIO_SUS5(in) */ - { GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_0 (in)/ADC.IN0 */ - { GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_2 (in)/ADC.IN1 */ - { GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_4 (in)/ADC.IN2 */ - { GALILEO_PINMUX_FUNC_B }, /* EXP2.P0_6 (in)/ADC.IN3 */ - { GALILEO_PINMUX_FUNC_C }, /* I2C_SDA */ - { GALILEO_PINMUX_FUNC_C }, /* I2C_SCL */ -}; - struct mux_pin { MUX_CHIP chip; uint8_t pin; @@ -107,7 +92,7 @@ struct pinmux_internal_data { static struct pinmux_internal_data data; -static struct mux_path galileo_pinmux_paths[PINMUX_NUM_PINS * PINMUX_NUM_FUNCS] = { +static struct mux_path galileo_pinmux_paths[GALILEO_NUM_PINS * PINMUX_NUM_FUNCS] = { {0, GALILEO_PINMUX_FUNC_A, { { EXP1, 0, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* GPIO3 out */ { EXP1, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }, @@ -529,13 +514,13 @@ static struct mux_path galileo_pinmux_paths[PINMUX_NUM_PINS * PINMUX_NUM_FUNCS] { NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}}, }; -int +static int galileo_pinmux_set_pin(uint8_t pin, GALILEO_PINMUX_FUNC func) { struct mux_path *mux_path; uint8_t index, i; - if(pin >= PINMUX_NUM_PINS) { + if(pin >= GALILEO_NUM_PINS) { return -1; } @@ -577,11 +562,120 @@ galileo_pinmux_set_pin(uint8_t pin, GALILEO_PINMUX_FUNC func) return 0; } +static void +flatten_pin_num(galileo_pin_group_t grp, unsigned *pin) +{ + if(grp == GALILEO_PIN_GRP_ANALOG) { + *pin += GALILEO_NUM_DIGITAL_PINS; + } + + assert(*pin < GALILEO_NUM_PINS); +} +/* Map a board-level GPIO pin number to the corresponding CPU GPIO pin number. + */ +static int +brd_to_cpu_gpio_pin(unsigned pin, bool *sus) +{ + static const int SUS = 0x100; + unsigned pins[GALILEO_NUM_PINS] = { + 3, 4, 5, 6, + SUS | 4, 8, 9, SUS | 0, + SUS | 1, SUS | 2, 2, SUS | 3, + 7, SUS | 5 + }; + int cpu_pin; + + /* GPIOs in the analog pin space are implemented by EXP2, not the CPU. */ + assert(pin < GALILEO_NUM_DIGITAL_PINS); + cpu_pin = pins[pin]; + + *sus = (cpu_pin & SUS) == SUS; + + return cpu_pin & ~SUS; +} +void +galileo_pinmux_select_din(galileo_pin_group_t grp, unsigned pin) +{ + bool sus; + int cpu_pin; + + flatten_pin_num(grp, &pin); + + assert(galileo_pinmux_set_pin(pin, GALILEO_PINMUX_FUNC_B) == 0); + + cpu_pin = brd_to_cpu_gpio_pin(pin, &sus); + /* GPIO_SUS pins are currently unsupported. */ + assert(!sus); + quarkX1000_gpio_config(cpu_pin, QUARKX1000_GPIO_IN); +} +void +galileo_pinmux_select_dout(galileo_pin_group_t grp, unsigned pin) +{ + bool sus; + int cpu_pin; + + flatten_pin_num(grp, &pin); + + assert(galileo_pinmux_set_pin(pin, GALILEO_PINMUX_FUNC_A) == 0); + + cpu_pin = brd_to_cpu_gpio_pin(pin, &sus); + /* GPIO_SUS pins are currently unsupported. */ + assert(!sus); + quarkX1000_gpio_config(cpu_pin, QUARKX1000_GPIO_OUT); +} +void +galileo_pinmux_select_pwm(unsigned pin) +{ + GALILEO_PINMUX_FUNC func = GALILEO_PINMUX_FUNC_C; + switch(pin) { + case 3: + func = GALILEO_PINMUX_FUNC_D; + break; + case 5: + case 6: + case 9: + case 10: + case 11: + break; + default: + fprintf(stderr, "%s: invalid pin: %d.\n", __FUNCTION__, pin); + halt(); + } + + assert(galileo_pinmux_set_pin(pin, func) == 0); +} +void +galileo_pinmux_select_serial(unsigned pin) +{ + assert(pin < 4); + + assert(galileo_pinmux_set_pin(pin, GALILEO_PINMUX_FUNC_C) == 0); +} +void +galileo_pinmux_select_i2c(void) +{ + assert(galileo_pinmux_set_pin(18, GALILEO_PINMUX_FUNC_C) == 0); + assert(galileo_pinmux_set_pin(19, GALILEO_PINMUX_FUNC_C) == 0); +} +void +galileo_pinmux_select_spi(void) +{ + assert(galileo_pinmux_set_pin(11, GALILEO_PINMUX_FUNC_D) == 0); + assert(galileo_pinmux_set_pin(12, GALILEO_PINMUX_FUNC_C) == 0); + assert(galileo_pinmux_set_pin(13, GALILEO_PINMUX_FUNC_C) == 0); +} +void +galileo_pinmux_select_analog(unsigned pin) +{ + assert(pin < GALILEO_NUM_ANALOG_PINS); + + pin += GALILEO_NUM_DIGITAL_PINS; + + assert(galileo_pinmux_set_pin(pin, GALILEO_PINMUX_FUNC_B) == 0); +} int galileo_pinmux_initialize(void) { - uint8_t i; - /* has to init after I2C master */ if(!quarkX1000_i2c_is_available()) { return -1; @@ -603,11 +697,29 @@ galileo_pinmux_initialize(void) return -1; } - for(i = 0; i < PINMUX_NUM_PINS; i++) { - if(galileo_pinmux_set_pin(i, default_pinmux_config[i].func) < 0) { - return -1; - } - } + /* Activate default pinmux configuration. */ + /* Some of the following lines are commented out due to the GPIO_SUS pins + * being currently unsupported. + */ + galileo_pinmux_select_serial(0); + galileo_pinmux_select_serial(1); + galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 2); + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 3); + /*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 4);*/ + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 5); + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 6); + /*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 7);*/ + /*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 8);*/ + /*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 9);*/ + galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 10); + /*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 11);*/ + galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 12); + /*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 13);*/ + galileo_pinmux_select_analog(0); + galileo_pinmux_select_analog(1); + galileo_pinmux_select_analog(2); + galileo_pinmux_select_analog(3); + galileo_pinmux_select_i2c(); return 0; } diff --git a/platform/galileo/drivers/galileo-pinmux.h b/platform/galileo/drivers/galileo-pinmux.h index f7d4fa39e..022a43cf6 100644 --- a/platform/galileo/drivers/galileo-pinmux.h +++ b/platform/galileo/drivers/galileo-pinmux.h @@ -33,14 +33,51 @@ #include -typedef enum { - GALILEO_PINMUX_FUNC_A, - GALILEO_PINMUX_FUNC_B, - GALILEO_PINMUX_FUNC_C, - GALILEO_PINMUX_FUNC_D -} GALILEO_PINMUX_FUNC; +typedef enum galileo_pin_group { + GALILEO_PIN_GRP_ANALOG, + GALILEO_PIN_GRP_DIGITAL +} galileo_pin_group_t; + +#define GALILEO_NUM_ANALOG_PINS 6 +#define GALILEO_NUM_DIGITAL_PINS 14 +#define GALILEO_NUM_PINS (GALILEO_NUM_ANALOG_PINS + GALILEO_NUM_DIGITAL_PINS) int galileo_pinmux_initialize(void); -int galileo_pinmux_set_pin(uint8_t pin, GALILEO_PINMUX_FUNC func); + +/** + * \brief Set the indicated pin to be a digital input. + * \param grp Indicates whether the pin is in the analog or digital group. + * \param pin Index of pin within group. + */ +void galileo_pinmux_select_din(galileo_pin_group_t grp, unsigned pin); +/** + * \brief Set the indicated pin to be a digital output. + */ +void galileo_pinmux_select_dout(galileo_pin_group_t grp, unsigned pin); +/** + * \brief Set the indicated pin to be a PWM pin. Only a subset of the pins + * support PWM output. This implicitly operates on the digital pin + * group. + */ +void galileo_pinmux_select_pwm(unsigned pin); +/** + * \brief Connect the indicated pin to a serial port. This implicitly operates + * on the digital pin group. Galileo Gen. 2 supports UART0 on pins 0 and + * 1 and UART1 on pins 2 and 3. + */ +void galileo_pinmux_select_serial(unsigned pin); +/** + * \brief Connect analog pins 4 (SDA) and 5 (SCL) to I2C. + */ +void galileo_pinmux_select_i2c(void); +/** + * \brief Connect digital pins 11 (MOSI), 12 (MISO), and 13 (CLK) to SPI. + */ +void galileo_pinmux_select_spi(void); +/** + * \brief Set the indicated pin to be an ADC input. This implicitly operates + * on the analog pin group. + */ +void galileo_pinmux_select_analog(unsigned pin); #endif /* CPU_X86_DRIVERS_GALILEO_PINMUX_H_ */ From b17a936bf75f62e677fbc9d7360800c42dbca1d5 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Mon, 22 Aug 2016 16:28:58 -0700 Subject: [PATCH 3/4] galileo: Add board-level abstraction layer for GPIO This patch adds a HAL for GPIOs so that users of the API can specify board-level IO pin numbers rather than CPU-level pin numbers. --- examples/galileo/gpio-input.c | 9 +-- examples/galileo/gpio-interrupt.c | 11 ++-- examples/galileo/gpio-output.c | 5 +- platform/galileo/Makefile.galileo | 2 +- platform/galileo/drivers/galileo-gpio.c | 72 +++++++++++++++++++++++ platform/galileo/drivers/galileo-gpio.h | 40 +++++++++++++ platform/galileo/drivers/galileo-pinmux.c | 11 ++-- 7 files changed, 132 insertions(+), 18 deletions(-) create mode 100644 platform/galileo/drivers/galileo-gpio.c create mode 100644 platform/galileo/drivers/galileo-gpio.h diff --git a/examples/galileo/gpio-input.c b/examples/galileo/gpio-input.c index 077055a69..804c9a86e 100644 --- a/examples/galileo/gpio-input.c +++ b/examples/galileo/gpio-input.c @@ -33,10 +33,11 @@ #include "contiki.h" #include "sys/ctimer.h" +#include "galileo-gpio.h" #include "gpio.h" -#define PIN_OUTPUT 5 -#define PIN_INPUT 6 +#define PIN_OUTPUT 2 +#define PIN_INPUT 3 static uint32_t value; static struct ctimer timer; @@ -51,9 +52,9 @@ timeout(void *data) /* toggle pin state */ value = !value; - quarkX1000_gpio_write(PIN_OUTPUT, value); + galileo_gpio_write(PIN_OUTPUT, value); - quarkX1000_gpio_read(PIN_INPUT, &value_in); + galileo_gpio_read(PIN_INPUT, &value_in); if (value == value_in) printf("GPIO pin value match!\n"); diff --git a/examples/galileo/gpio-interrupt.c b/examples/galileo/gpio-interrupt.c index ca4606266..6289fe4f1 100644 --- a/examples/galileo/gpio-interrupt.c +++ b/examples/galileo/gpio-interrupt.c @@ -33,10 +33,11 @@ #include "contiki.h" #include "sys/ctimer.h" +#include "galileo-gpio.h" #include "gpio.h" -#define PIN_OUTPUT 5 -#define PIN_INTR 6 +#define PIN_OUTPUT 2 +#define PIN_INTR 3 static struct ctimer timer; @@ -47,8 +48,8 @@ static void timeout(void *data) { /* emulate an interrupt */ - quarkX1000_gpio_write(PIN_OUTPUT, 0); - quarkX1000_gpio_write(PIN_OUTPUT, 1); + galileo_gpio_write(PIN_OUTPUT, 0); + galileo_gpio_write(PIN_OUTPUT, 1); ctimer_reset(&timer); } @@ -63,7 +64,7 @@ PROCESS_THREAD(gpio_interrupt_process, ev, data) { PROCESS_BEGIN(); - quarkX1000_gpio_config(PIN_INTR, QUARKX1000_GPIO_INT | QUARKX1000_GPIO_ACTIVE_HIGH | QUARKX1000_GPIO_EDGE); + galileo_gpio_config(PIN_INTR, QUARKX1000_GPIO_INT | QUARKX1000_GPIO_ACTIVE_HIGH | QUARKX1000_GPIO_EDGE); quarkX1000_gpio_set_callback(callback); diff --git a/examples/galileo/gpio-output.c b/examples/galileo/gpio-output.c index 4cc50597e..33a1159da 100644 --- a/examples/galileo/gpio-output.c +++ b/examples/galileo/gpio-output.c @@ -33,9 +33,10 @@ #include "contiki.h" #include "sys/ctimer.h" +#include "galileo-gpio.h" #include "gpio.h" -#define PIN 5 /* IO2 */ +#define PIN 2 static uint32_t value; static struct ctimer timer; @@ -48,7 +49,7 @@ timeout(void *data) { /* toggle pin state */ value = !value; - quarkX1000_gpio_write(PIN, value); + galileo_gpio_write(PIN, value); ctimer_reset(&timer); } diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index daada587a..d0ff4b0a8 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -5,7 +5,7 @@ LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) CONTIKI_TARGET_DIRS = . core/sys/ drivers/ net/ CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c gpio-pcal9535a.c pwm-pca9685.c galileo-pinmux.c eth-proc.c eth-conf.c +CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c gpio-pcal9535a.c pwm-pca9685.c galileo-pinmux.c eth-proc.c eth-conf.c galileo-gpio.c ifeq ($(CONTIKI_WITH_IPV6),1) CONTIKI_SOURCEFILES += nbr-table.c packetbuf.c linkaddr.c link-stats.c diff --git a/platform/galileo/drivers/galileo-gpio.c b/platform/galileo/drivers/galileo-gpio.c new file mode 100644 index 000000000..593f7acda --- /dev/null +++ b/platform/galileo/drivers/galileo-gpio.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "galileo-gpio.h" +#include +#include "gpio.h" + +/* Must be implemented in board-specific pinmux file to map a board-level GPIO + * pin number to the corresponding CPU GPIO pin number. + * + * The return value should always be a positive number. An assertion within the + * function should check the validity of the pin number. + */ +int galileo_brd_to_cpu_gpio_pin(unsigned pin, bool *sus); + +static int +brd_to_cpu_pin(unsigned pin) +{ + int cpu_pin; + bool sus; + + cpu_pin = galileo_brd_to_cpu_gpio_pin(pin, &sus); + assert(!sus); + + return cpu_pin; +} + +void galileo_gpio_config(uint8_t pin, int flags) +{ + assert(quarkX1000_gpio_config(brd_to_cpu_pin(pin), flags) == 0); +} + +/** + * \brief Read from GPIO. + * \param pin Board-level IO pin number. + */ +void galileo_gpio_read(uint8_t pin, uint8_t *value) +{ + assert(quarkX1000_gpio_read(brd_to_cpu_pin(pin), value) == 0); +} + +void galileo_gpio_write(uint8_t pin, uint8_t value) +{ + assert(quarkX1000_gpio_write(brd_to_cpu_pin(pin), value) == 0); +} diff --git a/platform/galileo/drivers/galileo-gpio.h b/platform/galileo/drivers/galileo-gpio.h new file mode 100644 index 000000000..07dbc1082 --- /dev/null +++ b/platform/galileo/drivers/galileo-gpio.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PLATFORM_GALILEO_DRIVERS_GALILEO_GPIO_H_ +#define PLATFORM_GALILEO_DRIVERS_GALILEO_GPIO_H_ + +#include + +void galileo_gpio_config(uint8_t pin, int flags); +void galileo_gpio_read(uint8_t pin, uint8_t *value); +void galileo_gpio_write(uint8_t pin, uint8_t value); + +#endif /* PLATFORM_GALILEO_DRIVERS_GALILEO_GPIO_H_ */ diff --git a/platform/galileo/drivers/galileo-pinmux.c b/platform/galileo/drivers/galileo-pinmux.c index c99ccd6c2..f4ea5be30 100644 --- a/platform/galileo/drivers/galileo-pinmux.c +++ b/platform/galileo/drivers/galileo-pinmux.c @@ -571,10 +571,9 @@ flatten_pin_num(galileo_pin_group_t grp, unsigned *pin) assert(*pin < GALILEO_NUM_PINS); } -/* Map a board-level GPIO pin number to the corresponding CPU GPIO pin number. - */ -static int -brd_to_cpu_gpio_pin(unsigned pin, bool *sus) +/* See galileo-gpio.c for the declaration of this function. */ +int +galileo_brd_to_cpu_gpio_pin(unsigned pin, bool *sus) { static const int SUS = 0x100; unsigned pins[GALILEO_NUM_PINS] = { @@ -603,7 +602,7 @@ galileo_pinmux_select_din(galileo_pin_group_t grp, unsigned pin) assert(galileo_pinmux_set_pin(pin, GALILEO_PINMUX_FUNC_B) == 0); - cpu_pin = brd_to_cpu_gpio_pin(pin, &sus); + cpu_pin = galileo_brd_to_cpu_gpio_pin(pin, &sus); /* GPIO_SUS pins are currently unsupported. */ assert(!sus); quarkX1000_gpio_config(cpu_pin, QUARKX1000_GPIO_IN); @@ -618,7 +617,7 @@ galileo_pinmux_select_dout(galileo_pin_group_t grp, unsigned pin) assert(galileo_pinmux_set_pin(pin, GALILEO_PINMUX_FUNC_A) == 0); - cpu_pin = brd_to_cpu_gpio_pin(pin, &sus); + cpu_pin = galileo_brd_to_cpu_gpio_pin(pin, &sus); /* GPIO_SUS pins are currently unsupported. */ assert(!sus); quarkX1000_gpio_config(cpu_pin, QUARKX1000_GPIO_OUT); From 418117998545a77e0c6f219e7e97eea7db032f84 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Mon, 22 Aug 2016 16:54:49 -0700 Subject: [PATCH 4/4] galileo: Add support for Gen. 1 pinmux and GPIO This patch adds support for IO pinmuxing and GPIO on first generation Intel Galileo boards. --- platform/galileo/Makefile.galileo | 12 +- platform/galileo/README.md | 8 +- platform/galileo/drivers/cy8c9540a.c | 131 ++++++++ platform/galileo/drivers/cy8c9540a.h | 72 +++++ .../galileo/drivers/galileo-gen1-pinmux.c | 282 ++++++++++++++++++ ...galileo-pinmux.c => galileo-gen2-pinmux.c} | 0 platform/galileo/drivers/galileo-gpio.c | 36 ++- 7 files changed, 536 insertions(+), 5 deletions(-) create mode 100644 platform/galileo/drivers/cy8c9540a.c create mode 100644 platform/galileo/drivers/cy8c9540a.h create mode 100644 platform/galileo/drivers/galileo-gen1-pinmux.c rename platform/galileo/drivers/{galileo-pinmux.c => galileo-gen2-pinmux.c} (100%) diff --git a/platform/galileo/Makefile.galileo b/platform/galileo/Makefile.galileo index d0ff4b0a8..35a4ad825 100644 --- a/platform/galileo/Makefile.galileo +++ b/platform/galileo/Makefile.galileo @@ -5,7 +5,17 @@ LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion) CONTIKI_TARGET_DIRS = . core/sys/ drivers/ net/ CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} -CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c gpio-pcal9535a.c pwm-pca9685.c galileo-pinmux.c eth-proc.c eth-conf.c galileo-gpio.c +CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c eth-proc.c eth-conf.c galileo-gpio.c + +GALILEO_GEN ?= 2 +CFLAGS += -DGALILEO_GEN=$(GALILEO_GEN) +CONTIKI_SOURCEFILES += galileo-gen$(GALILEO_GEN)-pinmux.c + +ifeq ($(GALILEO_GEN),2) +CONTIKI_SOURCEFILES += gpio-pcal9535a.c pwm-pca9685.c +else +CONTIKI_SOURCEFILES += cy8c9540a.c +endif ifeq ($(CONTIKI_WITH_IPV6),1) CONTIKI_SOURCEFILES += nbr-table.c packetbuf.c linkaddr.c link-stats.c diff --git a/platform/galileo/README.md b/platform/galileo/README.md index 529739ea8..e32799e3b 100644 --- a/platform/galileo/README.md +++ b/platform/galileo/README.md @@ -141,6 +141,9 @@ specify X86_CONF_RESTRICT_DMA=1 as a command-line argument to the make command that is used to build the image. This will configure and lock the IMRs. +Galileo Gen. 2 is targeted by default. Specify GALILEO_GEN=1 on the build +command line to target first generation boards. + Running ------- @@ -193,7 +196,8 @@ $ cp examples/hello-world/hello-world.galileo.efi /mnt/sdcard/efi/boot/bootia32. ### Connect to the console output -Connect the serial cable to your computer as shown in [2]. +Connect the serial cable to your computer as shown in [8] for first generation +boards and [2] for second generation boards. Choose a terminal emulator such as PuTTY. Make sure you use the SCO keyboard mode (on PuTTY that option is at Terminal -> Keyboard, on the left menu). @@ -277,3 +281,5 @@ References [6] https://docs.docker.com/docker-for-windows/#/shared-drives [7] https://docs.docker.com/engine/understanding-docker/ + +[8] https://software.intel.com/en-us/articles/intel-galileo-gen-1-board-assembly-using-eclipse-and-intel-xdk-iot-edition diff --git a/platform/galileo/drivers/cy8c9540a.c b/platform/galileo/drivers/cy8c9540a.c new file mode 100644 index 000000000..e042f9e23 --- /dev/null +++ b/platform/galileo/drivers/cy8c9540a.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cy8c9540a.h" + +#include +#include "i2c.h" +#include + +/* Change this to 0x21 if J2 is set to 1-2 + * (covering the pin marked with the white triangle). */ +#define I2C_ADDR 0x20 + +#define REG_PORT_SEL 0x18 +#define REG_PORT_DIR 0x1C + +#define PORT_CNT 6 + +/* Cache the current state of each port to obviate the need for reading before + * writing to output ports when simply updating a single pin. + */ +static uint8_t out_cache[PORT_CNT]; + +/*---------------------------------------------------------------------------*/ +static void +write_reg(uint8_t reg, uint8_t data) +{ + uint8_t pkt[] = { reg, data }; + assert(quarkX1000_i2c_polling_write(pkt, sizeof(pkt), I2C_ADDR) == 0); +} +/*---------------------------------------------------------------------------*/ +static uint8_t +read_reg(uint8_t reg) +{ + uint8_t data; + assert(quarkX1000_i2c_polling_write(®, 1, I2C_ADDR) == 0); + assert(quarkX1000_i2c_polling_read(&data, 1, I2C_ADDR) == 0); + return data; +} +/*---------------------------------------------------------------------------*/ +void +cy8c9540a_init(void) +{ + uint8_t status; + + /* has to init after I2C master */ + assert(quarkX1000_i2c_is_available()); + + status = read_reg(0x2E); + if((status >> 4) != 4) { + fprintf(stderr, "Failed to communicate with CY8C9540A. Perhaps jumper J2 " + "is not set to 2-3? Halting.\n"); + halt(); + } +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Set the direction (in or out) for the indicated GPIO pin. + */ +void +cy8c9540a_set_port_dir(cy8c9540a_bit_addr_t addr, cy8c9540a_port_dir_t dir) +{ + uint8_t mask; + + assert(addr.port < PORT_CNT); + + write_reg(REG_PORT_SEL, addr.port); + mask = read_reg(REG_PORT_DIR); + mask &= ~(1 << addr.pin); + mask |= ((uint8_t)dir) << addr.pin; + write_reg(REG_PORT_DIR, mask); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Set the drive mode for the indicated GPIO pin. + */ +void +cy8c9540a_set_drive_mode(cy8c9540a_bit_addr_t addr, + cy8c9540a_drive_mode_t drv_mode) +{ + assert(addr.port < PORT_CNT); + + write_reg(REG_PORT_SEL, addr.port); + write_reg((uint8_t)drv_mode, 1 << addr.pin); +} +/*---------------------------------------------------------------------------*/ +bool +cy8c9540a_read(cy8c9540a_bit_addr_t addr) +{ + assert(addr.port < PORT_CNT); + + return ((read_reg(addr.port) >> addr.pin) & 1) == 1; +} +/*---------------------------------------------------------------------------*/ +void +cy8c9540a_write(cy8c9540a_bit_addr_t addr, bool val) +{ + assert(addr.port < PORT_CNT); + + out_cache[addr.port] &= ~(1 << addr.pin); + out_cache[addr.port] |= ((uint8_t)val) << addr.pin; + write_reg(8 + addr.port, out_cache[addr.port]); +} +/*---------------------------------------------------------------------------*/ diff --git a/platform/galileo/drivers/cy8c9540a.h b/platform/galileo/drivers/cy8c9540a.h new file mode 100644 index 000000000..a9c31a484 --- /dev/null +++ b/platform/galileo/drivers/cy8c9540a.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PLATFORM_GALILEO_DRIVERS_CY8C9540A_H_ +#define PLATFORM_GALILEO_DRIVERS_CY8C9540A_H_ + +#include +#include + +/* Driver for Cypress Semiconductors CY8C9540A device used for GPIO, PWM, and + * pinmuxing on the first generation Intel Galileo. + */ + +/* The numeric value of each drive mode corresponds to the device register + * address for selecting that mode. Only a subset of the available modes are + * listed here. + */ +typedef enum cy8c9540a_drive_mode { + CY8C9540A_DRIVE_PULL_UP = 0x1D, + CY8C9540A_DRIVE_PULL_DOWN = 0x1E, + CY8C9540A_DRIVE_STRONG = 0x21, + CY8C9540A_DRIVE_HI_Z = 0x23 +} cy8c9540a_drive_mode_t; + +typedef enum cy8c9540a_port_dir { + CY8C9540A_PORT_DIR_OUT = 0, + CY8C9540A_PORT_DIR_IN = 1 +} cy8c9540a_port_dir_t; + +typedef struct cy8c9540a_bit_addr { + uint8_t port; + int pin; +} cy8c9540a_bit_addr_t; + +#define CY8C9540A_BIT_ADDR_INVALID_PORT 0xFF + +void cy8c9540a_init(void); +void cy8c9540a_set_port_dir(cy8c9540a_bit_addr_t addr, + cy8c9540a_port_dir_t dir); +void cy8c9540a_set_drive_mode(cy8c9540a_bit_addr_t addr, + cy8c9540a_drive_mode_t drv_mode); +bool cy8c9540a_read(cy8c9540a_bit_addr_t addr); +void cy8c9540a_write(cy8c9540a_bit_addr_t addr, bool val); + +#endif /* PLATFORM_GALILEO_DRIVERS_CY8C9540A_H_ */ diff --git a/platform/galileo/drivers/galileo-gen1-pinmux.c b/platform/galileo/drivers/galileo-gen1-pinmux.c new file mode 100644 index 000000000..fc94ab5ca --- /dev/null +++ b/platform/galileo/drivers/galileo-gen1-pinmux.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "galileo-pinmux.h" + +#include +#include "cy8c9540a.h" +#include "gpio.h" +#include + +static cy8c9540a_bit_addr_t mux_bit_addrs[] = { + { 3, 4 }, /* IO0 */ + { 3, 5 }, /* IO1 */ + { 1, 7 }, /* IO2 */ + { 1, 6 }, /* IO3 */ + { CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO4 */ + { CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO5 */ + { CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO6 */ + { CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO7 */ + { CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO8 */ + { CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO9 */ + { 3, 6 }, /* IO10 */ + { 3, 7 }, /* IO11 */ + { 5, 2 }, /* IO12 */ + { 5, 3 }, /* IO13 */ + { 3, 1 }, /* A0 */ + { 3, 0 }, /* A1 */ + { 0, 7 }, /* A2 */ + { 0, 6 }, /* A3 */ + { 0, 5 }, /* A4 (also controlled by I2C mux) */ + { 0, 4 }, /* A5 (also controlled by I2C mux) */ +}; + +static cy8c9540a_bit_addr_t i2c_mux_bit_addr = { 1, 5 }; + +/*---------------------------------------------------------------------------*/ +static void +flatten_pin_num(galileo_pin_group_t grp, unsigned *pin) +{ + if(grp == GALILEO_PIN_GRP_ANALOG) { + *pin += GALILEO_NUM_DIGITAL_PINS; + } + + assert(*pin < GALILEO_NUM_PINS); +} +/*---------------------------------------------------------------------------*/ +/* See galileo-gpio.c for the declaration of this function. */ +int +galileo_brd_to_cpu_gpio_pin(unsigned pin, bool *sus) +{ + assert(pin < GALILEO_NUM_PINS); + *sus = false; + switch(pin) { + case 2: + return 6; + case 3: + return 7; + case 10: + return 2; + default: + return -1; /* GPIO pin may be connected to the CY8C9540A chip, but not the + CPU. */ + } +} +/*---------------------------------------------------------------------------*/ +static cy8c9540a_bit_addr_t cy8c9540a_gpio_mapping[] = { + { 4, 6 }, + { 4, 7 }, + { CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, + { CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, + { 1, 4 }, + { 0, 1 }, + { 1, 0 }, + { 1, 3 }, + { 1, 2 }, + { 0, 3 }, + { 0, 0 }, /* This driver configures IO10 to connect to CPU GPIO when setting + IO10 to a digital mode, but hardware exists to alternately + connect it to this pin of the CY8C9540A chip. */ + { 1, 1 }, + { 3, 2 }, + { 3, 3 }, + { 4, 0 }, + { 4, 1 }, + { 4, 2 }, + { 4, 3 }, + { 4, 4 }, + { 4, 5 } +}; +/* Map a board-level GPIO pin number to the address of the CY8C9540A pin that + * implements it. + */ +cy8c9540a_bit_addr_t +galileo_brd_to_cy8c9540a_gpio_pin(unsigned pin) +{ + assert(pin < GALILEO_NUM_PINS); + return cy8c9540a_gpio_mapping[pin]; +} +/*---------------------------------------------------------------------------*/ +/* The I2C mux control must be set high to be able to access A4 and A5. + */ +static void +set_i2c_mux(bool val) +{ + cy8c9540a_write(i2c_mux_bit_addr, val); +} +/*---------------------------------------------------------------------------*/ +static void +select_gpio_pwm(unsigned flat_pin, bool pwm) +{ + bool mux_val; + cy8c9540a_bit_addr_t mux_bit_addr; + mux_bit_addr = mux_bit_addrs[flat_pin]; + if(mux_bit_addr.port != CY8C9540A_BIT_ADDR_INVALID_PORT) { + mux_val = pwm || !(flat_pin == 2 || flat_pin == 3 || flat_pin == 10); + cy8c9540a_write(mux_bit_addr, mux_val); + } + if((GALILEO_NUM_DIGITAL_PINS + 4) <= flat_pin) { + /* This single control switches away from both I2C pins. */ + set_i2c_mux(true); + } +} +/*---------------------------------------------------------------------------*/ +static void +select_gpio(galileo_pin_group_t grp, unsigned pin, bool out) +{ + bool sus; + int cpu_pin; + cy8c9540a_bit_addr_t gpio_bit_addr; + + flatten_pin_num(grp, &pin); + select_gpio_pwm(pin, false); + + cpu_pin = galileo_brd_to_cpu_gpio_pin(pin, &sus); + if(cpu_pin == -1) { + gpio_bit_addr = galileo_brd_to_cy8c9540a_gpio_pin(pin); + cy8c9540a_set_port_dir(gpio_bit_addr, + out? + CY8C9540A_PORT_DIR_OUT : + CY8C9540A_PORT_DIR_IN); + cy8c9540a_set_drive_mode(gpio_bit_addr, + out? + CY8C9540A_DRIVE_STRONG : + CY8C9540A_DRIVE_HI_Z); + } else { + quarkX1000_gpio_config(cpu_pin, + out? QUARKX1000_GPIO_OUT : QUARKX1000_GPIO_IN); + } +} +/*---------------------------------------------------------------------------*/ +void +galileo_pinmux_select_din(galileo_pin_group_t grp, unsigned pin) +{ + select_gpio(grp, pin, false); +} +/*---------------------------------------------------------------------------*/ +void galileo_pinmux_select_dout(galileo_pin_group_t grp, unsigned pin) +{ + select_gpio(grp, pin, true); +} +/*---------------------------------------------------------------------------*/ +void galileo_pinmux_select_pwm(unsigned pin) +{ + switch(pin) { + case 3: + case 5: + case 6: + case 9: + case 10: + case 11: + break; + default: + fprintf(stderr, "%s: invalid pin: %d.\n", __FUNCTION__, pin); + halt(); + } + + select_gpio_pwm(pin, true); +} +/*---------------------------------------------------------------------------*/ +void galileo_pinmux_select_serial(unsigned pin) +{ + assert(pin == 0 || pin == 1); + + cy8c9540a_write(mux_bit_addrs[pin], false); +} +/*---------------------------------------------------------------------------*/ +void galileo_pinmux_select_i2c(void) +{ + set_i2c_mux(false); +} +/*---------------------------------------------------------------------------*/ +void galileo_pinmux_select_spi(void) +{ + unsigned pin; + for(pin = 11; pin <= 13; pin++) { + cy8c9540a_write(mux_bit_addrs[pin], false); + } +} +/*---------------------------------------------------------------------------*/ +void galileo_pinmux_select_analog(unsigned pin) +{ + assert(pin < GALILEO_NUM_ANALOG_PINS); + pin += GALILEO_NUM_DIGITAL_PINS; + + cy8c9540a_write(mux_bit_addrs[pin], false); + + if(4 <= pin) { + /* This single control switches away from both I2C pins. */ + set_i2c_mux(true); + } +} +/*---------------------------------------------------------------------------*/ +int +galileo_pinmux_initialize(void) +{ + int i; + + cy8c9540a_init(); + + /* Configure all mux control pins as outputs. */ + for(i = 0; i < GALILEO_NUM_PINS; i++) { + if(mux_bit_addrs[i].port == CY8C9540A_BIT_ADDR_INVALID_PORT) { + continue; + } + + cy8c9540a_set_port_dir(mux_bit_addrs[i], CY8C9540A_PORT_DIR_OUT); + cy8c9540a_set_drive_mode(mux_bit_addrs[i], CY8C9540A_DRIVE_STRONG); + } + cy8c9540a_set_port_dir(i2c_mux_bit_addr, CY8C9540A_PORT_DIR_OUT); + cy8c9540a_set_drive_mode(i2c_mux_bit_addr, CY8C9540A_DRIVE_STRONG); + + /* Activate default pinmux configuration. */ + galileo_pinmux_select_serial(0); + galileo_pinmux_select_serial(1); + galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 2); + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 3); + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 4); + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 5); + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 6); + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 7); + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 8); + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 9); + galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 10); + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 11); + galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 12); + galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 13); + galileo_pinmux_select_analog(0); + galileo_pinmux_select_analog(1); + galileo_pinmux_select_analog(2); + galileo_pinmux_select_analog(3); + galileo_pinmux_select_i2c(); + + return 0; +} +/*---------------------------------------------------------------------------*/ diff --git a/platform/galileo/drivers/galileo-pinmux.c b/platform/galileo/drivers/galileo-gen2-pinmux.c similarity index 100% rename from platform/galileo/drivers/galileo-pinmux.c rename to platform/galileo/drivers/galileo-gen2-pinmux.c diff --git a/platform/galileo/drivers/galileo-gpio.c b/platform/galileo/drivers/galileo-gpio.c index 593f7acda..a6cee8b65 100644 --- a/platform/galileo/drivers/galileo-gpio.c +++ b/platform/galileo/drivers/galileo-gpio.c @@ -31,14 +31,22 @@ #include "galileo-gpio.h" #include #include "gpio.h" +#if GALILEO_GEN == 1 +#include "cy8c9540a.h" +#endif /* Must be implemented in board-specific pinmux file to map a board-level GPIO * pin number to the corresponding CPU GPIO pin number. * - * The return value should always be a positive number. An assertion within the + * For gen. 1 boards, the value -1 may be returned to indicate that the + * specified GPIO pin is not connected to any CPU pin. For gen. 2 boards, the + * return value should always be a positive number. An assertion within the * function should check the validity of the pin number. */ int galileo_brd_to_cpu_gpio_pin(unsigned pin, bool *sus); +#if GALILEO_GEN == 1 +cy8c9540a_bit_addr_t galileo_brd_to_cy8c9540a_gpio_pin(unsigned pin); +#endif static int brd_to_cpu_pin(unsigned pin) @@ -63,10 +71,32 @@ void galileo_gpio_config(uint8_t pin, int flags) */ void galileo_gpio_read(uint8_t pin, uint8_t *value) { - assert(quarkX1000_gpio_read(brd_to_cpu_pin(pin), value) == 0); +#if GALILEO_GEN == 1 + cy8c9540a_bit_addr_t bit_addr; +#endif + int cpu_pin = brd_to_cpu_pin(pin); +#if GALILEO_GEN == 1 + if(cpu_pin == -1) { + bit_addr = galileo_brd_to_cy8c9540a_gpio_pin(pin); + *value = cy8c9540a_read(bit_addr); + return; + } +#endif + assert(quarkX1000_gpio_read(cpu_pin, value) == 0); } void galileo_gpio_write(uint8_t pin, uint8_t value) { - assert(quarkX1000_gpio_write(brd_to_cpu_pin(pin), value) == 0); +#if GALILEO_GEN == 1 + cy8c9540a_bit_addr_t bit_addr; +#endif + int cpu_pin = brd_to_cpu_pin(pin); +#if GALILEO_GEN == 1 + if(cpu_pin == -1) { + bit_addr = galileo_brd_to_cy8c9540a_gpio_pin(pin); + cy8c9540a_write(bit_addr, value); + return; + } +#endif + assert(quarkX1000_gpio_write(cpu_pin, value) == 0); }