drivers: gpio: Add support for AON GPIO to QMSI driver

This adds support to the AON GPIO controller using the QMSI driver.

In order to enable it, the following configuration options must be set:
CONFIG_QMSI_DRIVERS=y
CONFIG_QMSI_INSTALL_PATH="PATH TO LIBQMSI"
CONFIG_GPIO_QMSI=y
CONFIG_GPIO_QMSI_AON=y

Change-Id: I5a1a232d97741ad7fdbf40d8aea5a835e5b4e724
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
This commit is contained in:
Vinicius Costa Gomes 2016-01-26 12:04:38 -02:00 committed by Gerrit Code Review
commit 821212c3df
3 changed files with 121 additions and 25 deletions

View file

@ -124,6 +124,14 @@ config GPIO_QMSI_0_IRQ
default 8 default 8
config GPIO_QMSI_0_PRI config GPIO_QMSI_0_PRI
default 2 default 2
config GPIO_QMSI_AON
def_bool n
config GPIO_QMSI_AON_NAME
default "gpio_aon"
config GPIO_QMSI_AON_IRQ
default 31
config GPIO_QMSI_AON_PRI
default 2
endif endif
endif endif
endif endif

View file

@ -633,6 +633,32 @@ config GPIO_QMSI_0_PRI
help help
IRQ priority IRQ priority
config GPIO_QMSI_AON
bool "QMSI GPIO block AON"
depends on GPIO_QMSI
default n
help
Include support for the GPIO AON (always on) port using QMSI.
config GPIO_QMSI_AON_NAME
string "Driver name"
depends on GPIO_QMSI_AON
default "gpio_aon"
config GPIO_QMSI_AON_IRQ
int "Controller interrupt number"
depends on GPIO_QMSI_AON
default 0
help
IRQ number for the controller
config GPIO_QMSI_AON_PRI
int "Controller interrupt priority"
depends on GPIO_QMSI_AON
default 2
help
IRQ priority
config GPIO_SCH config GPIO_SCH
bool "SCH GPIO controller" bool "SCH GPIO controller"
depends on GPIO depends on GPIO

View file

@ -40,15 +40,46 @@ struct gpio_qmsi_runtime {
uint32_t pin_callbacks; uint32_t pin_callbacks;
uint8_t port_callback; uint8_t port_callback;
}; };
int gpio_qmsi_init(struct device *dev);
#ifdef CONFIG_GPIO_QMSI_0
static struct gpio_qmsi_config gpio_0_config = {
.gpio = QM_GPIO_0,
.addr = &QM_GPIO[0],
.num_pins = QM_NUM_GPIO_PINS,
};
static struct gpio_qmsi_runtime gpio_0_runtime;
DEVICE_INIT(gpio_0, CONFIG_GPIO_QMSI_0_NAME, &gpio_qmsi_init,
&gpio_0_runtime, &gpio_0_config,
SECONDARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
#endif /* CONFIG_GPIO_QMSI_0 */
#ifdef CONFIG_GPIO_QMSI_AON
static struct gpio_qmsi_config gpio_aon_config = {
.gpio = QM_AON_GPIO_0,
.addr = (qm_gpio_reg_t *) QM_AON_GPIO_BASE,
.num_pins = QM_NUM_AON_GPIO_PINS,
};
static struct gpio_qmsi_runtime gpio_aon_runtime;
DEVICE_INIT(gpio_aon, CONFIG_GPIO_QMSI_AON_NAME, &gpio_qmsi_init,
&gpio_aon_runtime, &gpio_aon_config,
SECONDARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
#endif /* CONFIG_GPIO_QMSI_AON */
/* /*
* TODO: Zephyr's API is not clear about the behavior of the this * TODO: Zephyr's API is not clear about the behavior of the this
* application callback. This topic is currently under * application callback. This topic is currently under
* discussion, so this implementation will be fixed as soon as a * discussion, so this implementation will be fixed as soon as a
* decision is made. * decision is made.
*/ */
static void gpio_qmsi_0_int_callback(uint32_t status) static void gpio_qmsi_callback(struct device *port, uint32_t status)
{ {
struct device *port = device_get_binding(CONFIG_GPIO_QMSI_0_NAME);
struct gpio_qmsi_config *config = port->config->config_info; struct gpio_qmsi_config *config = port->config->config_info;
struct gpio_qmsi_runtime *context = port->driver_data; struct gpio_qmsi_runtime *context = port->driver_data;
const uint32_t enabled_mask = context->pin_callbacks & status; const uint32_t enabled_mask = context->pin_callbacks & status;
@ -72,6 +103,28 @@ static void gpio_qmsi_0_int_callback(uint32_t status)
} }
} }
static void gpio_qmsi_0_int_callback(uint32_t status)
{
#ifndef CONFIG_GPIO_QMSI_0
return;
#else
struct device *port = DEVICE_GET(gpio_0);
gpio_qmsi_callback(port, status);
#endif
}
static void gpio_qmsi_aon_int_callback(uint32_t status)
{
#ifndef CONFIG_GPIO_QMSI_AON
return;
#else
struct device *port = DEVICE_GET(gpio_aon);
gpio_qmsi_callback(port, status);
#endif
}
static void qmsi_write_bit(uint32_t *target, uint8_t bit, uint8_t value) static void qmsi_write_bit(uint32_t *target, uint8_t bit, uint8_t value)
{ {
if (value) { if (value) {
@ -108,8 +161,17 @@ static inline void qmsi_pin_config(struct device *port, uint32_t pin, int flags)
qmsi_write_bit(&cfg.int_en, pin, 1); qmsi_write_bit(&cfg.int_en, pin, 1);
} }
/* FIXME: for multiple GPIO ports */ switch (gpio) {
cfg.callback = gpio_qmsi_0_int_callback; case QM_GPIO_0:
cfg.callback = gpio_qmsi_0_int_callback;
break;
case QM_AON_GPIO_0:
cfg.callback = gpio_qmsi_aon_int_callback;
break;
default:
return;
}
qm_gpio_set_config(gpio, &cfg); qm_gpio_set_config(gpio, &cfg);
/* Recover the original interrupt mask for this port. */ /* Recover the original interrupt mask for this port. */
@ -250,33 +312,33 @@ int gpio_qmsi_init(struct device *port)
struct gpio_qmsi_config *gpio_config = port->config->config_info; struct gpio_qmsi_config *gpio_config = port->config->config_info;
uint32_t reg = (uint32_t) gpio_config->addr; uint32_t reg = (uint32_t) gpio_config->addr;
clk_periph_enable(CLK_PERIPH_GPIO_REGISTER | switch (gpio_config->gpio) {
CLK_PERIPH_GPIO_INTERRUPT | CLK_PERIPH_GPIO_DB); case QM_GPIO_0:
clk_periph_enable(CLK_PERIPH_GPIO_REGISTER |
CLK_PERIPH_GPIO_INTERRUPT |
CLK_PERIPH_GPIO_DB);
IRQ_CONNECT(CONFIG_GPIO_QMSI_0_IRQ,
CONFIG_GPIO_QMSI_0_PRI, qm_gpio_isr_0,
0, IOAPIC_LEVEL | IOAPIC_HIGH);
irq_enable(CONFIG_GPIO_QMSI_0_IRQ);
QM_SCSS_INT->int_gpio_mask &= ~BIT(0);
break;
case QM_AON_GPIO_0:
IRQ_CONNECT(CONFIG_GPIO_QMSI_AON_IRQ,
CONFIG_GPIO_QMSI_AON_PRI, qm_aon_gpio_isr_0,
0, IOAPIC_LEVEL | IOAPIC_HIGH);
irq_enable(CONFIG_GPIO_QMSI_AON_IRQ);
QM_SCSS_INT->int_aon_gpio_mask &= ~BIT(0);
break;
default:
return DEV_FAIL;
}
/* mask and disable interrupts */ /* mask and disable interrupts */
sys_write32(~(0), reg + INTMASK); sys_write32(~(0), reg + INTMASK);
sys_write32(0, reg + INTEN); sys_write32(0, reg + INTEN);
sys_write32(~(0), reg + PORTA_EOI); sys_write32(~(0), reg + PORTA_EOI);
IRQ_CONNECT(CONFIG_GPIO_QMSI_0_IRQ, CONFIG_GPIO_QMSI_0_PRI, qm_gpio_isr_0,
0, IOAPIC_LEVEL | IOAPIC_HIGH);
/* Enable GPIO IRQ and unmask interrupts for Lakemont. */
sys_clear_bit(QM_SCSS_INT_BASE + INT_GPIO_MASK, 0);
irq_enable(CONFIG_GPIO_QMSI_0_IRQ);
port->driver_api = &api_funcs; port->driver_api = &api_funcs;
return DEV_OK; return DEV_OK;
} }
static struct gpio_qmsi_config gpio_0_config = {
.gpio = QM_GPIO_0,
.addr = &QM_GPIO[0],
.num_pins = QM_NUM_GPIO_PINS,
};
static struct gpio_qmsi_runtime gpio_0_runtime;
DEVICE_INIT(gpio_0, CONFIG_GPIO_QMSI_0_NAME, &gpio_qmsi_init,
&gpio_0_runtime, &gpio_0_config,
SECONDARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);