pinctrl: nomadik: convert driver to use gpiolib irqchip
This converts the Nomadik pin control driver to register its chained irq handler and irqchip using the helpers in the gpiolib core. Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
8d5b24bd30
commit
e0bc34a3da
2 changed files with 36 additions and 90 deletions
|
@ -235,6 +235,9 @@ config PINCTRL_NOMADIK
|
||||||
depends on ARCH_U8500 || ARCH_NOMADIK
|
depends on ARCH_U8500 || ARCH_NOMADIK
|
||||||
select PINMUX
|
select PINMUX
|
||||||
select PINCONF
|
select PINCONF
|
||||||
|
select GPIOLIB
|
||||||
|
select OF_GPIO
|
||||||
|
select GPIOLIB_IRQCHIP
|
||||||
|
|
||||||
config PINCTRL_STN8815
|
config PINCTRL_STN8815
|
||||||
bool "STN8815 pin controller driver"
|
bool "STN8815 pin controller driver"
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irq.h>
|
|
||||||
#include <linux/irqdomain.h>
|
|
||||||
#include <linux/irqchip/chained_irq.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
@ -248,7 +245,6 @@ enum nmk_gpio_slpm {
|
||||||
|
|
||||||
struct nmk_gpio_chip {
|
struct nmk_gpio_chip {
|
||||||
struct gpio_chip chip;
|
struct gpio_chip chip;
|
||||||
struct irq_domain *domain;
|
|
||||||
void __iomem *addr;
|
void __iomem *addr;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
unsigned int bank;
|
unsigned int bank;
|
||||||
|
@ -419,7 +415,7 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
|
||||||
u32 falling = nmk_chip->fimsc & BIT(offset);
|
u32 falling = nmk_chip->fimsc & BIT(offset);
|
||||||
u32 rising = nmk_chip->rimsc & BIT(offset);
|
u32 rising = nmk_chip->rimsc & BIT(offset);
|
||||||
int gpio = nmk_chip->chip.base + offset;
|
int gpio = nmk_chip->chip.base + offset;
|
||||||
int irq = irq_find_mapping(nmk_chip->domain, offset);
|
int irq = irq_find_mapping(nmk_chip->chip.irqdomain, offset);
|
||||||
struct irq_data *d = irq_get_irq_data(irq);
|
struct irq_data *d = irq_get_irq_data(irq);
|
||||||
|
|
||||||
if (!rising && !falling)
|
if (!rising && !falling)
|
||||||
|
@ -647,11 +643,8 @@ static inline int nmk_gpio_get_bitmask(int gpio)
|
||||||
|
|
||||||
static void nmk_gpio_irq_ack(struct irq_data *d)
|
static void nmk_gpio_irq_ack(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct nmk_gpio_chip *nmk_chip;
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||||
|
struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
|
||||||
nmk_chip = irq_data_get_irq_chip_data(d);
|
|
||||||
if (!nmk_chip)
|
|
||||||
return;
|
|
||||||
|
|
||||||
clk_enable(nmk_chip->clk);
|
clk_enable(nmk_chip->clk);
|
||||||
writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC);
|
writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC);
|
||||||
|
@ -848,26 +841,6 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d)
|
||||||
clk_disable(nmk_chip->clk);
|
clk_disable(nmk_chip->clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nmk_gpio_irq_reqres(struct irq_data *d)
|
|
||||||
{
|
|
||||||
struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
|
|
||||||
|
|
||||||
if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq)) {
|
|
||||||
dev_err(nmk_chip->chip.dev,
|
|
||||||
"unable to lock HW IRQ %lu for IRQ\n",
|
|
||||||
d->hwirq);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nmk_gpio_irq_relres(struct irq_data *d)
|
|
||||||
{
|
|
||||||
struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
|
|
||||||
|
|
||||||
gpio_unlock_as_irq(&nmk_chip->chip, d->hwirq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct irq_chip nmk_gpio_irq_chip = {
|
static struct irq_chip nmk_gpio_irq_chip = {
|
||||||
.name = "Nomadik-GPIO",
|
.name = "Nomadik-GPIO",
|
||||||
.irq_ack = nmk_gpio_irq_ack,
|
.irq_ack = nmk_gpio_irq_ack,
|
||||||
|
@ -877,24 +850,21 @@ static struct irq_chip nmk_gpio_irq_chip = {
|
||||||
.irq_set_wake = nmk_gpio_irq_set_wake,
|
.irq_set_wake = nmk_gpio_irq_set_wake,
|
||||||
.irq_startup = nmk_gpio_irq_startup,
|
.irq_startup = nmk_gpio_irq_startup,
|
||||||
.irq_shutdown = nmk_gpio_irq_shutdown,
|
.irq_shutdown = nmk_gpio_irq_shutdown,
|
||||||
.irq_request_resources = nmk_gpio_irq_reqres,
|
|
||||||
.irq_release_resources = nmk_gpio_irq_relres,
|
|
||||||
.flags = IRQCHIP_MASK_ON_SUSPEND,
|
.flags = IRQCHIP_MASK_ON_SUSPEND,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
|
static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
|
||||||
u32 status)
|
u32 status)
|
||||||
{
|
{
|
||||||
struct nmk_gpio_chip *nmk_chip;
|
|
||||||
struct irq_chip *host_chip = irq_get_chip(irq);
|
struct irq_chip *host_chip = irq_get_chip(irq);
|
||||||
|
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
|
||||||
|
|
||||||
chained_irq_enter(host_chip, desc);
|
chained_irq_enter(host_chip, desc);
|
||||||
|
|
||||||
nmk_chip = irq_get_handler_data(irq);
|
|
||||||
while (status) {
|
while (status) {
|
||||||
int bit = __ffs(status);
|
int bit = __ffs(status);
|
||||||
|
|
||||||
generic_handle_irq(irq_find_mapping(nmk_chip->domain, bit));
|
generic_handle_irq(irq_find_mapping(chip->irqdomain, bit));
|
||||||
status &= ~BIT(bit);
|
status &= ~BIT(bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -903,9 +873,11 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
|
||||||
|
|
||||||
static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
{
|
{
|
||||||
struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
|
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
|
||||||
|
struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
|
||||||
u32 status;
|
u32 status;
|
||||||
|
|
||||||
|
pr_err("PLONK IRQ %d\n", irq);
|
||||||
clk_enable(nmk_chip->clk);
|
clk_enable(nmk_chip->clk);
|
||||||
status = readl(nmk_chip->addr + NMK_GPIO_IS);
|
status = readl(nmk_chip->addr + NMK_GPIO_IS);
|
||||||
clk_disable(nmk_chip->clk);
|
clk_disable(nmk_chip->clk);
|
||||||
|
@ -916,26 +888,13 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
static void nmk_gpio_latent_irq_handler(unsigned int irq,
|
static void nmk_gpio_latent_irq_handler(unsigned int irq,
|
||||||
struct irq_desc *desc)
|
struct irq_desc *desc)
|
||||||
{
|
{
|
||||||
struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
|
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
|
||||||
|
struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
|
||||||
u32 status = nmk_chip->get_latent_status(nmk_chip->bank);
|
u32 status = nmk_chip->get_latent_status(nmk_chip->bank);
|
||||||
|
|
||||||
__nmk_gpio_irq_handler(irq, desc, status);
|
__nmk_gpio_irq_handler(irq, desc, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
|
|
||||||
{
|
|
||||||
irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler);
|
|
||||||
irq_set_handler_data(nmk_chip->parent_irq, nmk_chip);
|
|
||||||
|
|
||||||
if (nmk_chip->latent_parent_irq >= 0) {
|
|
||||||
irq_set_chained_handler(nmk_chip->latent_parent_irq,
|
|
||||||
nmk_gpio_latent_irq_handler);
|
|
||||||
irq_set_handler_data(nmk_chip->latent_parent_irq, nmk_chip);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* I/O Functions */
|
/* I/O Functions */
|
||||||
|
|
||||||
static int nmk_gpio_request(struct gpio_chip *chip, unsigned offset)
|
static int nmk_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||||
|
@ -1014,14 +973,6 @@ static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
|
||||||
{
|
|
||||||
struct nmk_gpio_chip *nmk_chip =
|
|
||||||
container_of(chip, struct nmk_gpio_chip, chip);
|
|
||||||
|
|
||||||
return irq_create_mapping(nmk_chip->domain, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
@ -1120,7 +1071,6 @@ static struct gpio_chip nmk_gpio_template = {
|
||||||
.get = nmk_gpio_get_input,
|
.get = nmk_gpio_get_input,
|
||||||
.direction_output = nmk_gpio_make_output,
|
.direction_output = nmk_gpio_make_output,
|
||||||
.set = nmk_gpio_set_output,
|
.set = nmk_gpio_set_output,
|
||||||
.to_irq = nmk_gpio_to_irq,
|
|
||||||
.dbg_show = nmk_gpio_dbg_show,
|
.dbg_show = nmk_gpio_dbg_show,
|
||||||
.can_sleep = false,
|
.can_sleep = false,
|
||||||
};
|
};
|
||||||
|
@ -1221,27 +1171,6 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
|
|
||||||
irq_hw_number_t hwirq)
|
|
||||||
{
|
|
||||||
struct nmk_gpio_chip *nmk_chip = d->host_data;
|
|
||||||
|
|
||||||
if (!nmk_chip)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
irq_set_chip_and_handler(irq, &nmk_gpio_irq_chip, handle_edge_irq);
|
|
||||||
set_irq_flags(irq, IRQF_VALID);
|
|
||||||
irq_set_chip_data(irq, nmk_chip);
|
|
||||||
irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct irq_domain_ops nmk_gpio_irq_simple_ops = {
|
|
||||||
.map = nmk_gpio_irq_map,
|
|
||||||
.xlate = irq_domain_xlate_twocell,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int nmk_gpio_probe(struct platform_device *dev)
|
static int nmk_gpio_probe(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
struct device_node *np = dev->dev.of_node;
|
struct device_node *np = dev->dev.of_node;
|
||||||
|
@ -1321,17 +1250,31 @@ static int nmk_gpio_probe(struct platform_device *dev)
|
||||||
|
|
||||||
platform_set_drvdata(dev, nmk_chip);
|
platform_set_drvdata(dev, nmk_chip);
|
||||||
|
|
||||||
nmk_chip->domain = irq_domain_add_simple(np,
|
/*
|
||||||
NMK_GPIO_PER_CHIP, 0,
|
* Let the generic code handle this edge IRQ, the the chained
|
||||||
&nmk_gpio_irq_simple_ops, nmk_chip);
|
* handler will perform the actual work of handling the parent
|
||||||
if (!nmk_chip->domain) {
|
* interrupt.
|
||||||
dev_err(&dev->dev, "failed to create irqdomain\n");
|
*/
|
||||||
/* Just do this, no matter if it fails */
|
ret = gpiochip_irqchip_add(&nmk_chip->chip,
|
||||||
|
&nmk_gpio_irq_chip,
|
||||||
|
0,
|
||||||
|
handle_edge_irq,
|
||||||
|
IRQ_TYPE_EDGE_FALLING);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&dev->dev, "could not add irqchip\n");
|
||||||
ret = gpiochip_remove(&nmk_chip->chip);
|
ret = gpiochip_remove(&nmk_chip->chip);
|
||||||
return -ENOSYS;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
/* Then register the chain on the parent IRQ */
|
||||||
nmk_gpio_init_irq(nmk_chip);
|
gpiochip_set_chained_irqchip(&nmk_chip->chip,
|
||||||
|
&nmk_gpio_irq_chip,
|
||||||
|
nmk_chip->parent_irq,
|
||||||
|
nmk_gpio_irq_handler);
|
||||||
|
if (nmk_chip->latent_parent_irq > 0)
|
||||||
|
gpiochip_set_chained_irqchip(&nmk_chip->chip,
|
||||||
|
&nmk_gpio_irq_chip,
|
||||||
|
nmk_chip->latent_parent_irq,
|
||||||
|
nmk_gpio_latent_irq_handler);
|
||||||
|
|
||||||
dev_info(&dev->dev, "at address %p\n", nmk_chip->addr);
|
dev_info(&dev->dev, "at address %p\n", nmk_chip->addr);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue