drivers: gpio_cmsdk_ahb: update to use new GPIO API

Update driver code and board files to use new GPIO configuration flags
such as GPIO_ACTIVE_LOW. Also add implementation of new port_* driver
API as well as gpio_pin_interrupt_configure function.

We treat GPIO_INT_MODE_LEVEL as not supported as the hardware doesn't
seem to handle level interrupts as one would expect.  Looking into this
further to determine if its a HW bug or some misconfiguration in the
software.

We don't support dynamic setting of PULL_UP/PULL_DOWN config as this is
handled by pinctrl for the current boards we support the CMSDK AHB
driver on.

Tested on musca-a board.

Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
This commit is contained in:
Kumar Gala 2019-09-17 15:53:16 -05:00 committed by Carles Cufí
commit 9aa1dc11ce

View file

@ -23,6 +23,7 @@
typedef void (*gpio_config_func_t)(struct device *port);
struct gpio_cmsdk_ahb_cfg {
struct gpio_driver_data common;
volatile struct gpio_cmsdk_ahb *port;
gpio_config_func_t gpio_config_func;
/* GPIO Clock control in Active State */
@ -40,50 +41,85 @@ struct gpio_cmsdk_ahb_dev_data {
sys_slist_t gpio_cb;
};
static int gpio_cmsdk_ahb_port_get_raw(struct device *dev, u32_t *value)
{
const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config->config_info;
*value = cfg->port->data;
return 0;
}
static int gpio_cmsdk_ahb_port_set_masked_raw(struct device *dev, u32_t mask,
u32_t value)
{
const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config->config_info;
cfg->port->dataout = (cfg->port->dataout & ~mask) | (mask & value);
return 0;
}
static int gpio_cmsdk_ahb_port_set_bits_raw(struct device *dev, u32_t mask)
{
const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config->config_info;
cfg->port->dataout |= mask;
return 0;
}
static int gpio_cmsdk_ahb_port_clear_bits_raw(struct device *dev, u32_t mask)
{
const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config->config_info;
cfg->port->dataout &= ~mask;
return 0;
}
static int gpio_cmsdk_ahb_port_toggle_bits(struct device *dev, u32_t mask)
{
const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config->config_info;
cfg->port->dataout ^= mask;
return 0;
}
static int cmsdk_ahb_gpio_config(struct device *dev, u32_t mask, int flags)
{
const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config->config_info;
if (((flags & GPIO_INPUT) == 0) && ((flags & GPIO_OUTPUT) == 0)) {
return -ENOTSUP;
}
if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0) {
return -ENOTSUP;
}
if ((flags & GPIO_SINGLE_ENDED) != 0) {
return -ENOTSUP;
}
/*
* Setup the pin direction
* Output Enable:
* 0 - Input
* 1 - Output
*/
if ((flags & GPIO_DIR_MASK) == GPIO_DIR_OUT) {
if ((flags & GPIO_OUTPUT) != 0) {
if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
gpio_cmsdk_ahb_port_set_bits_raw(dev, mask);
} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
gpio_cmsdk_ahb_port_clear_bits_raw(dev, mask);
}
cfg->port->outenableset = mask;
} else {
cfg->port->outenableclr = mask;
}
/* Setup interrupt config */
if (flags & GPIO_INT) {
if (flags & GPIO_INT_DOUBLE_EDGE) {
return -ENOTSUP;
} else {
/*
* Interrupt type:
* 0 - LOW or HIGH level
* 1 - For falling or rising
*/
if (flags & GPIO_INT_EDGE) {
cfg->port->inttypeclr = mask;
} else {
cfg->port->inttypeset = mask;
}
/*
* Interrupt polarity:
* 0 - Low level or falling edge
* 1 - High level or rising edge
*/
if (flags & GPIO_INT_ACTIVE_HIGH) {
cfg->port->intpolset = mask;
} else {
cfg->port->intpolclr = mask;
}
}
}
cfg->port->altfuncclr = mask;
return 0;
@ -202,6 +238,46 @@ static int gpio_cmsdk_ahb_read(struct device *dev, int access_op,
return 0;
}
static int gpio_cmsdk_ahb_pin_interrupt_configure(struct device *dev,
unsigned int pin, enum gpio_int_mode mode,
enum gpio_int_trig trig)
{
const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config->config_info;
if (trig == GPIO_INT_TRIG_BOTH) {
return -ENOTSUP;
}
/* For now treat level interrupts as not supported, as we seem to only
* get a single 'edge' still interrupt rather than continuous
* interrupts until the cause is cleared */
if (mode == GPIO_INT_MODE_LEVEL) {
return -ENOTSUP;
}
if (mode == GPIO_INT_MODE_DISABLED) {
cfg->port->intenclr = BIT(pin);
} else {
if (mode == GPIO_INT_MODE_EDGE) {
cfg->port->inttypeset = BIT(pin);
} else {
/* LEVEL */
cfg->port->inttypeclr = BIT(pin);
}
/* Level High or Edge Risising */
if (trig == GPIO_INT_TRIG_HIGH) {
cfg->port->intpolset = BIT(pin);
} else {
cfg->port->intpolclr = BIT(pin);
}
cfg->port->intclear = BIT(pin);
cfg->port->intenset = BIT(pin);
}
return 0;
}
static void gpio_cmsdk_ahb_isr(void *arg)
{
struct device *dev = (struct device *)arg;
@ -211,10 +287,11 @@ static void gpio_cmsdk_ahb_isr(void *arg)
int_stat = cfg->port->intstatus;
/* clear the port interrupts */
cfg->port->intclear = int_stat;
gpio_fire_callbacks(&data->gpio_cb, dev, int_stat);
/* clear the port interrupts */
cfg->port->intclear = 0xFFFFFFFF;
}
static int gpio_cmsdk_ahb_manage_callback(struct device *dev,
@ -274,6 +351,12 @@ static const struct gpio_driver_api gpio_cmsdk_ahb_drv_api_funcs = {
.config = gpio_cmsdk_ahb_config,
.write = gpio_cmsdk_ahb_write,
.read = gpio_cmsdk_ahb_read,
.port_get_raw = gpio_cmsdk_ahb_port_get_raw,
.port_set_masked_raw = gpio_cmsdk_ahb_port_set_masked_raw,
.port_set_bits_raw = gpio_cmsdk_ahb_port_set_bits_raw,
.port_clear_bits_raw = gpio_cmsdk_ahb_port_clear_bits_raw,
.port_toggle_bits = gpio_cmsdk_ahb_port_toggle_bits,
.pin_interrupt_configure = gpio_cmsdk_ahb_pin_interrupt_configure,
.manage_callback = gpio_cmsdk_ahb_manage_callback,
.enable_callback = gpio_cmsdk_ahb_enable_callback,
.disable_callback = gpio_cmsdk_ahb_disable_callback,