diff --git a/include/libopencm3/sam3x/gpio.h b/include/libopencm3/sam3x/gpio.h index f0833ab0..53152d30 100644 --- a/include/libopencm3/sam3x/gpio.h +++ b/include/libopencm3/sam3x/gpio.h @@ -22,6 +22,19 @@ #include +/* flags may be or'd together, but only contain one of + * GPOUTPUT, PERIPHA and PERIPHB */ +enum gpio_flags { + GPIO_FLAG_GPINPUT = 0, + GPIO_FLAG_GPOUTPUT = 1, + GPIO_FLAG_PERIPHA = 2, + GPIO_FLAG_PERIPHB = 3, + GPIO_FLAG_OPEN_DRAIN = 4, + GPIO_FLAG_PULL_UP = 8, +}; + +void gpio_init(u32 gpioport, u32 pins, enum gpio_flags flags); + static inline void gpio_set(u32 gpioport, u32 gpios) { PIO_SODR(gpioport) = gpios; diff --git a/lib/sam3x/gpio.c b/lib/sam3x/gpio.c index b1c5c7c0..e52ac139 100644 --- a/lib/sam3x/gpio.c +++ b/lib/sam3x/gpio.c @@ -19,6 +19,40 @@ #include +void gpio_init(u32 port, u32 pins, enum gpio_flags flags) +{ + switch (flags & 3) { + case GPIO_FLAG_GPINPUT: + /* input mode doesn't really exist, so we make a high + * output in open-drain mode + */ + PIO_SODR(port) = pins; + flags |= GPIO_FLAG_OPEN_DRAIN; + /* fall through */ + case GPIO_FLAG_GPOUTPUT: + PIO_OER(port) = pins; + PIO_PER(port) = pins; + break; + case GPIO_FLAG_PERIPHA: + PIO_ABSR(port) &= ~pins; + PIO_PDR(port) = pins; + break; + case GPIO_FLAG_PERIPHB: + PIO_ABSR(port) |= pins; + PIO_PDR(port) = pins; + } + + if (flags & GPIO_FLAG_OPEN_DRAIN) + PIO_MDER(port) = pins; + else + PIO_MDDR(port) = pins; + + if (flags & GPIO_FLAG_PULL_UP) + PIO_PUER(port) = pins; + else + PIO_PUDR(port) = pins; +} + void gpio_toggle(u32 gpioport, u32 gpios) { u32 odsr = PIO_ODSR(gpioport);