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.
master-31012017
Michael LeMay 2016-08-22 15:25:32 -07:00
parent 3043f3956c
commit 2912559061
6 changed files with 195 additions and 48 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -29,10 +29,19 @@
*/
#include "galileo-pinmux.h"
#include <assert.h>
#include "gpio.h"
#include "gpio-pcal9535a.h"
#include "i2c.h"
#include "pwm-pca9685.h"
#include <stdio.h>
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;
}

View File

@ -33,14 +33,51 @@
#include <stdint.h>
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_ */