cc3200: Add a GPIO driver for the TI CC3200 LaunchXL
The pinmux configuration is done during board initialization. This was validated using the following Zephyr apps: - samples/basic/blinky - samples/basic/disco - samples/basic/button All 4 GPIO ports are supported. Change-Id: If8599a23c1d56cfd678a6e2e5339f7e093c6061a Signed-off-by: Gil Pitney <gil.pitney@linaro.org>
This commit is contained in:
parent
429bea5381
commit
f18cced2c1
@ -34,4 +34,23 @@ config UART_CC32XX_IRQ_PRI
|
||||
default 3
|
||||
endif # UART_CC32XX
|
||||
|
||||
if GPIO
|
||||
|
||||
config GPIO_CC32XX
|
||||
def_bool y
|
||||
|
||||
config GPIO_CC32XX_A0
|
||||
default n
|
||||
|
||||
config GPIO_CC32XX_A1
|
||||
default y
|
||||
|
||||
config GPIO_CC32XX_A2
|
||||
default y
|
||||
|
||||
config GPIO_CC32XX_A3
|
||||
default n
|
||||
|
||||
endif # GPIO
|
||||
|
||||
endif # SOC_CC3200
|
||||
|
||||
@ -63,4 +63,6 @@ source "drivers/gpio/Kconfig.nrf5"
|
||||
|
||||
source "drivers/gpio/Kconfig.cmsdk_ahb"
|
||||
|
||||
source "drivers/gpio/Kconfig.cc32xx"
|
||||
|
||||
endif # GPIO
|
||||
|
||||
93
drivers/gpio/Kconfig.cc32xx
Normal file
93
drivers/gpio/Kconfig.cc32xx
Normal file
@ -0,0 +1,93 @@
|
||||
# Kconfig.cc32xx- CC32XX GPIO configuration options
|
||||
#
|
||||
|
||||
menuconfig GPIO_CC32XX
|
||||
bool "TI CC32XX GPIO driver"
|
||||
depends on GPIO && SOC_FAMILY_TISIMPLELINK
|
||||
default n
|
||||
help
|
||||
Enable the GPIO driver on TI SimpleLink CC32xx boards
|
||||
|
||||
if GPIO_CC32XX
|
||||
|
||||
config GPIO_CC32XX_A0
|
||||
bool "GPIO block A0"
|
||||
depends on GPIO_CC32XX
|
||||
default n
|
||||
help
|
||||
Include support for the GPIO port A0.
|
||||
|
||||
config GPIO_CC32XX_A0_NAME
|
||||
string "Driver name"
|
||||
depends on GPIO_CC32XX_A0
|
||||
default "GPIO_A0"
|
||||
|
||||
config GPIO_CC32XX_A0_IRQ_PRI
|
||||
int "GPIO A0 interrupt priority"
|
||||
depends on GPIO_CC32XX_A0
|
||||
range 0 5
|
||||
default 1
|
||||
help
|
||||
CC32XX GPIO A0 IRQ priority.
|
||||
|
||||
config GPIO_CC32XX_A1
|
||||
bool "GPIO block A1"
|
||||
depends on GPIO_CC32XX
|
||||
default n
|
||||
help
|
||||
Include support for the GPIO port A1.
|
||||
|
||||
config GPIO_CC32XX_A1_NAME
|
||||
string "Driver name"
|
||||
depends on GPIO_CC32XX_A1
|
||||
default "GPIO_A1"
|
||||
|
||||
config GPIO_CC32XX_A1_IRQ_PRI
|
||||
int "GPIO A1 interrupt priority"
|
||||
depends on GPIO_CC32XX_A1
|
||||
range 0 5
|
||||
default 1
|
||||
help
|
||||
CC32XX GPIO A1 IRQ priority.
|
||||
|
||||
config GPIO_CC32XX_A2
|
||||
bool "GPIO block A2"
|
||||
depends on GPIO_CC32XX
|
||||
default n
|
||||
help
|
||||
Include support for the GPIO port A2.
|
||||
|
||||
config GPIO_CC32XX_A2_NAME
|
||||
string "Driver name"
|
||||
depends on GPIO_CC32XX_A2
|
||||
default "GPIO_A2"
|
||||
|
||||
config GPIO_CC32XX_A2_IRQ_PRI
|
||||
int "GPIO A2 interrupt priority"
|
||||
depends on GPIO_CC32XX_A2
|
||||
range 0 5
|
||||
default 1
|
||||
help
|
||||
CC32XX GPIO A2 IRQ priority.
|
||||
|
||||
config GPIO_CC32XX_A3
|
||||
bool "GPIO block A3"
|
||||
depends on GPIO_CC32XX
|
||||
default n
|
||||
help
|
||||
Include support for the GPIO port A3.
|
||||
|
||||
config GPIO_CC32XX_A3_NAME
|
||||
string "Driver name"
|
||||
depends on GPIO_CC32XX_A3
|
||||
default "GPIO_A3"
|
||||
|
||||
config GPIO_CC32XX_A3_IRQ_PRI
|
||||
int "GPIO A3 interrupt priority"
|
||||
depends on GPIO_CC32XX_A3
|
||||
range 0 5
|
||||
default 1
|
||||
help
|
||||
CC32XX GPIO A3 IRQ priority.
|
||||
|
||||
endif # GPIO_CC32XX
|
||||
@ -10,3 +10,4 @@ obj-$(CONFIG_GPIO_K64) += gpio_k64.o
|
||||
obj-$(CONFIG_GPIO_STM32) += gpio_stm32.o
|
||||
obj-$(CONFIG_GPIO_NRF5) += gpio_nrf5.o
|
||||
obj-$(CONFIG_GPIO_CMSDK_AHB) += gpio_cmsdk_ahb.o
|
||||
obj-$(CONFIG_GPIO_CC32XX) += gpio_cc32xx.o
|
||||
|
||||
335
drivers/gpio/gpio_cc32xx.c
Normal file
335
drivers/gpio/gpio_cc32xx.c
Normal file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Texas Instruments Incorporated
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
||||
#include <device.h>
|
||||
#include <gpio.h>
|
||||
#include <init.h>
|
||||
#include <nanokernel.h>
|
||||
#include <sys_io.h>
|
||||
|
||||
/* Driverlib includes */
|
||||
#include <inc/hw_types.h>
|
||||
#include <inc/hw_memmap.h>
|
||||
#include <inc/hw_ints.h>
|
||||
#include <inc/hw_gpio.h>
|
||||
#include <driverlib/rom.h>
|
||||
#include <driverlib/pin.h>
|
||||
#undef __GPIO_H__ /* Zephyr and CC3200SDK gpio.h conflict */
|
||||
#include <driverlib/gpio.h>
|
||||
#include <driverlib/rom_map.h>
|
||||
#include <driverlib/interrupt.h>
|
||||
|
||||
#include "gpio_utils.h"
|
||||
|
||||
/* Note: Zephyr uses exception numbers, vs the IRQ #s used by the CC3200 SDK */
|
||||
#define EXCEPTION_GPIOA0 0 /* (INT_GPIOA0 - 16) = (16-16) */
|
||||
#define EXCEPTION_GPIOA1 1 /* (INT_GPIOA1 - 16) = (17-16) */
|
||||
#define EXCEPTION_GPIOA2 2 /* (INT_GPIOA2 - 16) = (18-16) */
|
||||
#define EXCEPTION_GPIOA3 3 /* (INT_GPIOA3 - 16) = (19-16) */
|
||||
|
||||
struct gpio_cc32xx_config {
|
||||
/* base address of GPIO port */
|
||||
unsigned long port_base;
|
||||
/* GPIO IRQ number */
|
||||
unsigned long irq_num;
|
||||
};
|
||||
|
||||
struct gpio_cc32xx_data {
|
||||
/* list of registered callbacks */
|
||||
sys_slist_t callbacks;
|
||||
/* callback enable pin bitmask */
|
||||
uint32_t pin_callback_enables;
|
||||
};
|
||||
|
||||
#define DEV_CFG(dev) \
|
||||
((const struct gpio_cc32xx_config *)(dev)->config->config_info)
|
||||
#define DEV_DATA(dev) \
|
||||
((struct gpio_cc32xx_data *)(dev)->driver_data)
|
||||
|
||||
static inline int gpio_cc32xx_config(struct device *port,
|
||||
int access_op, uint32_t pin, int flags)
|
||||
{
|
||||
const struct gpio_cc32xx_config *gpio_config = DEV_CFG(port);
|
||||
unsigned long port_base = gpio_config->port_base;
|
||||
unsigned long int_type;
|
||||
|
||||
/*
|
||||
* See pinmux_initialize(): which leverages TI's recommended
|
||||
* method of using the PinMux utility for most pin configuration.
|
||||
*/
|
||||
|
||||
if (access_op == GPIO_ACCESS_BY_PIN) {
|
||||
/* Just handle runtime interrupt type config here: */
|
||||
if (flags & GPIO_INT) {
|
||||
if (flags & GPIO_INT_EDGE) {
|
||||
if (flags & GPIO_INT_ACTIVE_HIGH) {
|
||||
int_type = GPIO_RISING_EDGE;
|
||||
} else if (flags & GPIO_INT_DOUBLE_EDGE) {
|
||||
int_type = GPIO_BOTH_EDGES;
|
||||
} else {
|
||||
int_type = GPIO_FALLING_EDGE;
|
||||
}
|
||||
} else { /* GPIO_INT_LEVEL */
|
||||
if (flags & GPIO_INT_ACTIVE_HIGH) {
|
||||
int_type = GPIO_HIGH_LEVEL;
|
||||
} else {
|
||||
int_type = GPIO_LOW_LEVEL;
|
||||
}
|
||||
}
|
||||
MAP_GPIOIntTypeSet(port_base, (1 << pin), int_type);
|
||||
MAP_GPIOIntClear(port_base, (1 << pin));
|
||||
MAP_GPIOIntEnable(port_base, (1 << pin));
|
||||
}
|
||||
} else {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int gpio_cc32xx_write(struct device *port,
|
||||
int access_op, uint32_t pin, uint32_t value)
|
||||
{
|
||||
const struct gpio_cc32xx_config *gpio_config = DEV_CFG(port);
|
||||
unsigned long port_base = gpio_config->port_base;
|
||||
|
||||
if (access_op == GPIO_ACCESS_BY_PIN) {
|
||||
value = value << pin;
|
||||
/* Bitpack external GPIO pin number for GPIOPinWrite API: */
|
||||
pin = 1 << pin;
|
||||
|
||||
MAP_GPIOPinWrite(port_base, (unsigned char)pin, value);
|
||||
} else {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int gpio_cc32xx_read(struct device *port,
|
||||
int access_op, uint32_t pin, uint32_t *value)
|
||||
{
|
||||
const struct gpio_cc32xx_config *gpio_config = DEV_CFG(port);
|
||||
unsigned long port_base = gpio_config->port_base;
|
||||
long status;
|
||||
unsigned char pin_packed;
|
||||
|
||||
if (access_op == GPIO_ACCESS_BY_PIN) {
|
||||
/* Bitpack external GPIO pin number for GPIOPinRead API: */
|
||||
pin_packed = 1 << pin;
|
||||
status = MAP_GPIOPinRead(port_base, pin_packed);
|
||||
*value = status >> pin;
|
||||
} else {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_cc32xx_manage_callback(struct device *dev,
|
||||
struct gpio_callback *callback, bool set)
|
||||
{
|
||||
struct gpio_cc32xx_data *data = DEV_DATA(dev);
|
||||
|
||||
_gpio_manage_callback(&data->callbacks, callback, set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int gpio_cc32xx_enable_callback(struct device *dev,
|
||||
int access_op, uint32_t pin)
|
||||
{
|
||||
struct gpio_cc32xx_data *data = DEV_DATA(dev);
|
||||
|
||||
if (access_op == GPIO_ACCESS_BY_PIN) {
|
||||
data->pin_callback_enables |= (1 << pin);
|
||||
} else {
|
||||
data->pin_callback_enables = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int gpio_cc32xx_disable_callback(struct device *dev,
|
||||
int access_op, uint32_t pin)
|
||||
{
|
||||
struct gpio_cc32xx_data *data = DEV_DATA(dev);
|
||||
|
||||
if (access_op == GPIO_ACCESS_BY_PIN) {
|
||||
data->pin_callback_enables &= ~(1 << pin);
|
||||
} else {
|
||||
data->pin_callback_enables = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpio_cc32xx_port_isr(void *arg)
|
||||
{
|
||||
struct device *dev = arg;
|
||||
const struct gpio_cc32xx_config *config = DEV_CFG(dev);
|
||||
struct gpio_cc32xx_data *data = DEV_DATA(dev);
|
||||
uint32_t enabled_int, int_status;
|
||||
|
||||
/* See which interrupts triggered: */
|
||||
int_status = (uint32_t)MAP_GPIOIntStatus(config->port_base, 1);
|
||||
|
||||
enabled_int = int_status & data->pin_callback_enables;
|
||||
|
||||
/* Clear and Disable GPIO Interrupt */
|
||||
MAP_GPIOIntDisable(config->port_base, int_status);
|
||||
MAP_GPIOIntClear(config->port_base, int_status);
|
||||
|
||||
/* Call the registered callbacks */
|
||||
_gpio_fire_callbacks(&data->callbacks, (struct device *)dev,
|
||||
enabled_int);
|
||||
|
||||
/* Re-enable the interrupts */
|
||||
MAP_GPIOIntEnable(config->port_base, int_status);
|
||||
}
|
||||
|
||||
static const struct gpio_driver_api api_funcs = {
|
||||
.config = gpio_cc32xx_config,
|
||||
.write = gpio_cc32xx_write,
|
||||
.read = gpio_cc32xx_read,
|
||||
.manage_callback = gpio_cc32xx_manage_callback,
|
||||
.enable_callback = gpio_cc32xx_enable_callback,
|
||||
.disable_callback = gpio_cc32xx_disable_callback,
|
||||
|
||||
};
|
||||
|
||||
#ifdef CONFIG_GPIO_CC32XX_A0
|
||||
static const struct gpio_cc32xx_config gpio_cc32xx_a0_config = {
|
||||
.port_base = GPIOA0_BASE,
|
||||
.irq_num = INT_GPIOA0,
|
||||
};
|
||||
|
||||
static struct device DEVICE_NAME_GET(gpio_cc32xx_a0);
|
||||
static struct gpio_cc32xx_data gpio_cc32xx_a0_data;
|
||||
|
||||
static int gpio_cc32xx_a0_init(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
IRQ_CONNECT(EXCEPTION_GPIOA0, CONFIG_GPIO_CC32XX_A0_IRQ_PRI,
|
||||
gpio_cc32xx_port_isr, DEVICE_GET(gpio_cc32xx_a0), 0);
|
||||
|
||||
MAP_IntPendClear(INT_GPIOA0);
|
||||
irq_enable(EXCEPTION_GPIOA0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEVICE_AND_API_INIT(gpio_cc32xx_a0, CONFIG_GPIO_CC32XX_A0_NAME,
|
||||
&gpio_cc32xx_a0_init, &gpio_cc32xx_a0_data,
|
||||
&gpio_cc32xx_a0_config,
|
||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
||||
&api_funcs);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GPIO_CC32XX_A1
|
||||
static const struct gpio_cc32xx_config gpio_cc32xx_a1_config = {
|
||||
.port_base = GPIOA1_BASE,
|
||||
.irq_num = INT_GPIOA1,
|
||||
};
|
||||
|
||||
static struct device DEVICE_NAME_GET(gpio_cc32xx_a1);
|
||||
static struct gpio_cc32xx_data gpio_cc32xx_a1_data;
|
||||
|
||||
static int gpio_cc32xx_a1_init(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
IRQ_CONNECT(EXCEPTION_GPIOA1, CONFIG_GPIO_CC32XX_A1_IRQ_PRI,
|
||||
gpio_cc32xx_port_isr, DEVICE_GET(gpio_cc32xx_a1), 0);
|
||||
|
||||
MAP_IntPendClear(INT_GPIOA1);
|
||||
irq_enable(EXCEPTION_GPIOA1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEVICE_AND_API_INIT(gpio_cc32xx_a1, CONFIG_GPIO_CC32XX_A1_NAME,
|
||||
&gpio_cc32xx_a1_init, &gpio_cc32xx_a1_data,
|
||||
&gpio_cc32xx_a1_config,
|
||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
||||
&api_funcs);
|
||||
|
||||
#endif /* CONFIG_GPIO_CC32XX_A1 */
|
||||
|
||||
#ifdef CONFIG_GPIO_CC32XX_A2
|
||||
static const struct gpio_cc32xx_config gpio_cc32xx_a2_config = {
|
||||
.port_base = GPIOA2_BASE,
|
||||
.irq_num = INT_GPIOA2,
|
||||
};
|
||||
|
||||
static struct device DEVICE_NAME_GET(gpio_cc32xx_a2);
|
||||
static struct gpio_cc32xx_data gpio_cc32xx_a2_data;
|
||||
|
||||
static int gpio_cc32xx_a2_init(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
IRQ_CONNECT(EXCEPTION_GPIOA2, CONFIG_GPIO_CC32XX_A2_IRQ_PRI,
|
||||
gpio_cc32xx_port_isr, DEVICE_GET(gpio_cc32xx_a2), 0);
|
||||
|
||||
MAP_IntPendClear(INT_GPIOA2);
|
||||
irq_enable(EXCEPTION_GPIOA2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEVICE_AND_API_INIT(gpio_cc32xx_a2, CONFIG_GPIO_CC32XX_A2_NAME,
|
||||
&gpio_cc32xx_a2_init, &gpio_cc32xx_a2_data,
|
||||
&gpio_cc32xx_a2_config,
|
||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
||||
&api_funcs);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GPIO_CC32XX_A3
|
||||
static const struct gpio_cc32xx_config gpio_cc32xx_a3_config = {
|
||||
.port_base = GPIOA3_BASE,
|
||||
.irq_num = INT_GPIOA3,
|
||||
};
|
||||
|
||||
static struct device DEVICE_NAME_GET(gpio_cc32xx_a3);
|
||||
static struct gpio_cc32xx_data gpio_cc32xx_a3_data;
|
||||
|
||||
static int gpio_cc32xx_a3_init(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
IRQ_CONNECT(EXCEPTION_GPIOA3, CONFIG_GPIO_CC32XX_A3_IRQ_PRI,
|
||||
gpio_cc32xx_port_isr, DEVICE_GET(gpio_cc32xx_a3), 0);
|
||||
|
||||
MAP_IntPendClear(INT_GPIOA3);
|
||||
irq_enable(EXCEPTION_GPIOA3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEVICE_AND_API_INIT(gpio_cc32xx_a3, CONFIG_GPIO_CC32XX_A3_NAME,
|
||||
&gpio_cc32xx_a3_init, &gpio_cc32xx_a3_data,
|
||||
&gpio_cc32xx_a3_config,
|
||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
||||
&api_funcs);
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user