|
@@ -19,6 +19,7 @@
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/gpio.h>
|
|
|
#include <linux/irq.h>
|
|
|
+#include <linux/irqdomain.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/bitops.h>
|
|
|
#include <linux/mfd/abx500.h>
|
|
@@ -87,20 +88,11 @@
|
|
|
#define AB8540_GPIO_VINSEL_REG 0x47
|
|
|
#define AB8540_GPIO_PULL_UPDOWN_REG 0x48
|
|
|
#define AB8500_GPIO_ALTFUN_REG 0x50
|
|
|
-#define AB8500_NUM_VIR_GPIO_IRQ 16
|
|
|
#define AB8540_GPIO_PULL_UPDOWN_MASK 0x03
|
|
|
#define AB8540_GPIO_VINSEL_MASK 0x03
|
|
|
#define AB8540_GPIOX_VBAT_START 51
|
|
|
#define AB8540_GPIOX_VBAT_END 54
|
|
|
|
|
|
-enum abx500_gpio_action {
|
|
|
- NONE,
|
|
|
- STARTUP,
|
|
|
- SHUTDOWN,
|
|
|
- MASK,
|
|
|
- UNMASK
|
|
|
-};
|
|
|
-
|
|
|
struct abx500_pinctrl {
|
|
|
struct device *dev;
|
|
|
struct pinctrl_dev *pctldev;
|
|
@@ -109,14 +101,8 @@ struct abx500_pinctrl {
|
|
|
struct ab8500 *parent;
|
|
|
struct mutex lock;
|
|
|
u32 irq_base;
|
|
|
- enum abx500_gpio_action irq_action;
|
|
|
- u16 rising;
|
|
|
- u16 falling;
|
|
|
struct abx500_gpio_irq_cluster *irq_cluster;
|
|
|
int irq_cluster_size;
|
|
|
- int irq_gpio_rising_offset;
|
|
|
- int irq_gpio_falling_offset;
|
|
|
- int irq_gpio_factor;
|
|
|
};
|
|
|
|
|
|
/**
|
|
@@ -473,7 +459,6 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s,
|
|
|
struct gpio_chip *chip,
|
|
|
unsigned offset, unsigned gpio)
|
|
|
{
|
|
|
- struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
|
|
|
const char *label = gpiochip_is_requested(chip, offset - 1);
|
|
|
u8 gpio_offset = offset - 1;
|
|
|
int mode = -1;
|
|
@@ -502,25 +487,6 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s,
|
|
|
: "? ")
|
|
|
: (pull ? "pull up" : "pull down"),
|
|
|
(mode < 0) ? "unknown" : modes[mode]);
|
|
|
-
|
|
|
- if (label && !is_out) {
|
|
|
- int irq = gpio_to_irq(gpio);
|
|
|
- struct irq_desc *desc = irq_to_desc(irq);
|
|
|
-
|
|
|
- if (irq >= 0 && desc->action) {
|
|
|
- char *trigger;
|
|
|
- int irq_offset = irq - pct->irq_base;
|
|
|
-
|
|
|
- if (pct->rising & BIT(irq_offset))
|
|
|
- trigger = "edge-rising";
|
|
|
- else if (pct->falling & BIT(irq_offset))
|
|
|
- trigger = "edge-falling";
|
|
|
- else
|
|
|
- trigger = "edge-undefined";
|
|
|
-
|
|
|
- seq_printf(s, " irq-%d %s", irq, trigger);
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|
@@ -574,219 +540,6 @@ static struct gpio_chip abx500gpio_chip = {
|
|
|
.dbg_show = abx500_gpio_dbg_show,
|
|
|
};
|
|
|
|
|
|
-static unsigned int irq_to_rising(unsigned int irq)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = irq_get_chip_data(irq);
|
|
|
- int offset = irq - pct->irq_base;
|
|
|
- int new_irq;
|
|
|
-
|
|
|
- new_irq = offset * pct->irq_gpio_factor
|
|
|
- + pct->irq_gpio_rising_offset
|
|
|
- + pct->parent->irq_base;
|
|
|
-
|
|
|
- return new_irq;
|
|
|
-}
|
|
|
-
|
|
|
-static unsigned int irq_to_falling(unsigned int irq)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = irq_get_chip_data(irq);
|
|
|
- int offset = irq - pct->irq_base;
|
|
|
- int new_irq;
|
|
|
-
|
|
|
- new_irq = offset * pct->irq_gpio_factor
|
|
|
- + pct->irq_gpio_falling_offset
|
|
|
- + pct->parent->irq_base;
|
|
|
- return new_irq;
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-static unsigned int rising_to_irq(unsigned int irq, void *dev)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = dev;
|
|
|
- int offset, new_irq;
|
|
|
-
|
|
|
- offset = irq - pct->irq_gpio_rising_offset
|
|
|
- - pct->parent->irq_base;
|
|
|
- new_irq = (offset / pct->irq_gpio_factor)
|
|
|
- + pct->irq_base;
|
|
|
-
|
|
|
- return new_irq;
|
|
|
-}
|
|
|
-
|
|
|
-static unsigned int falling_to_irq(unsigned int irq, void *dev)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = dev;
|
|
|
- int offset, new_irq;
|
|
|
-
|
|
|
- offset = irq - pct->irq_gpio_falling_offset
|
|
|
- - pct->parent->irq_base;
|
|
|
- new_irq = (offset / pct->irq_gpio_factor)
|
|
|
- + pct->irq_base;
|
|
|
-
|
|
|
- return new_irq;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * IRQ handler
|
|
|
- */
|
|
|
-
|
|
|
-static irqreturn_t handle_rising(int irq, void *dev)
|
|
|
-{
|
|
|
-
|
|
|
- handle_nested_irq(rising_to_irq(irq , dev));
|
|
|
- return IRQ_HANDLED;
|
|
|
-}
|
|
|
-
|
|
|
-static irqreturn_t handle_falling(int irq, void *dev)
|
|
|
-{
|
|
|
-
|
|
|
- handle_nested_irq(falling_to_irq(irq, dev));
|
|
|
- return IRQ_HANDLED;
|
|
|
-}
|
|
|
-
|
|
|
-static void abx500_gpio_irq_lock(struct irq_data *data)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
|
|
|
- mutex_lock(&pct->lock);
|
|
|
-}
|
|
|
-
|
|
|
-static void abx500_gpio_irq_sync_unlock(struct irq_data *data)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
|
|
|
- unsigned int irq = data->irq;
|
|
|
- int offset = irq - pct->irq_base;
|
|
|
- bool rising = pct->rising & BIT(offset);
|
|
|
- bool falling = pct->falling & BIT(offset);
|
|
|
- int ret;
|
|
|
-
|
|
|
- switch (pct->irq_action) {
|
|
|
- case STARTUP:
|
|
|
- if (rising)
|
|
|
- ret = request_threaded_irq(irq_to_rising(irq),
|
|
|
- NULL, handle_rising,
|
|
|
- IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
|
|
|
- "abx500-gpio-r", pct);
|
|
|
- if (falling)
|
|
|
- ret = request_threaded_irq(irq_to_falling(irq),
|
|
|
- NULL, handle_falling,
|
|
|
- IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND,
|
|
|
- "abx500-gpio-f", pct);
|
|
|
- break;
|
|
|
- case SHUTDOWN:
|
|
|
- if (rising)
|
|
|
- free_irq(irq_to_rising(irq), pct);
|
|
|
- if (falling)
|
|
|
- free_irq(irq_to_falling(irq), pct);
|
|
|
- break;
|
|
|
- case MASK:
|
|
|
- if (rising)
|
|
|
- disable_irq(irq_to_rising(irq));
|
|
|
- if (falling)
|
|
|
- disable_irq(irq_to_falling(irq));
|
|
|
- break;
|
|
|
- case UNMASK:
|
|
|
- if (rising)
|
|
|
- enable_irq(irq_to_rising(irq));
|
|
|
- if (falling)
|
|
|
- enable_irq(irq_to_falling(irq));
|
|
|
- break;
|
|
|
- case NONE:
|
|
|
- break;
|
|
|
- }
|
|
|
- pct->irq_action = NONE;
|
|
|
- pct->rising &= ~(BIT(offset));
|
|
|
- pct->falling &= ~(BIT(offset));
|
|
|
- mutex_unlock(&pct->lock);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static void abx500_gpio_irq_mask(struct irq_data *data)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
|
|
|
- pct->irq_action = MASK;
|
|
|
-}
|
|
|
-
|
|
|
-static void abx500_gpio_irq_unmask(struct irq_data *data)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
|
|
|
- pct->irq_action = UNMASK;
|
|
|
-}
|
|
|
-
|
|
|
-static int abx500_gpio_irq_set_type(struct irq_data *data, unsigned int type)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
|
|
|
- unsigned int irq = data->irq;
|
|
|
- int offset = irq - pct->irq_base;
|
|
|
-
|
|
|
- if (type == IRQ_TYPE_EDGE_BOTH) {
|
|
|
- pct->rising = BIT(offset);
|
|
|
- pct->falling = BIT(offset);
|
|
|
- } else if (type == IRQ_TYPE_EDGE_RISING) {
|
|
|
- pct->rising = BIT(offset);
|
|
|
- } else {
|
|
|
- pct->falling = BIT(offset);
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static unsigned int abx500_gpio_irq_startup(struct irq_data *data)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
|
|
|
- pct->irq_action = STARTUP;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void abx500_gpio_irq_shutdown(struct irq_data *data)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
|
|
|
- pct->irq_action = SHUTDOWN;
|
|
|
-}
|
|
|
-
|
|
|
-static struct irq_chip abx500_gpio_irq_chip = {
|
|
|
- .name = "abx500-gpio",
|
|
|
- .irq_startup = abx500_gpio_irq_startup,
|
|
|
- .irq_shutdown = abx500_gpio_irq_shutdown,
|
|
|
- .irq_bus_lock = abx500_gpio_irq_lock,
|
|
|
- .irq_bus_sync_unlock = abx500_gpio_irq_sync_unlock,
|
|
|
- .irq_mask = abx500_gpio_irq_mask,
|
|
|
- .irq_unmask = abx500_gpio_irq_unmask,
|
|
|
- .irq_set_type = abx500_gpio_irq_set_type,
|
|
|
-};
|
|
|
-
|
|
|
-static int abx500_gpio_irq_init(struct abx500_pinctrl *pct)
|
|
|
-{
|
|
|
- u32 base = pct->irq_base;
|
|
|
- int irq;
|
|
|
-
|
|
|
- for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq++) {
|
|
|
- irq_set_chip_data(irq, pct);
|
|
|
- irq_set_chip_and_handler(irq, &abx500_gpio_irq_chip,
|
|
|
- handle_simple_irq);
|
|
|
- irq_set_nested_thread(irq, 1);
|
|
|
-#ifdef CONFIG_ARM
|
|
|
- set_irq_flags(irq, IRQF_VALID);
|
|
|
-#else
|
|
|
- irq_set_noprobe(irq);
|
|
|
-#endif
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void abx500_gpio_irq_remove(struct abx500_pinctrl *pct)
|
|
|
-{
|
|
|
- int base = pct->irq_base;
|
|
|
- int irq;
|
|
|
-
|
|
|
- for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) {
|
|
|
-#ifdef CONFIG_ARM
|
|
|
- set_irq_flags(irq, 0);
|
|
|
-#endif
|
|
|
- irq_set_chip_and_handler(irq, NULL, NULL);
|
|
|
- irq_set_chip_data(irq, NULL);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static int abx500_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
|
|
|
{
|
|
|
struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
|
|
@@ -815,43 +568,6 @@ static int abx500_pmx_get_func_groups(struct pinctrl_dev *pctldev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void abx500_disable_lazy_irq(struct gpio_chip *chip, unsigned gpio)
|
|
|
-{
|
|
|
- struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
|
|
|
- int irq;
|
|
|
- int offset;
|
|
|
- bool rising;
|
|
|
- bool falling;
|
|
|
-
|
|
|
- /*
|
|
|
- * check if gpio has interrupt capability and convert
|
|
|
- * gpio number to irq
|
|
|
- * On ABx5xx, there is no GPIO0, GPIO1 is the
|
|
|
- * first one, so adjust gpio number
|
|
|
- */
|
|
|
- gpio--;
|
|
|
- irq = gpio_to_irq(gpio + chip->base);
|
|
|
- if (irq < 0)
|
|
|
- return;
|
|
|
-
|
|
|
- offset = irq - pct->irq_base;
|
|
|
- rising = pct->rising & BIT(offset);
|
|
|
- falling = pct->falling & BIT(offset);
|
|
|
-
|
|
|
- /* nothing to do ?*/
|
|
|
- if (!rising && !falling)
|
|
|
- return;
|
|
|
-
|
|
|
- if (rising) {
|
|
|
- disable_irq(irq_to_rising(irq));
|
|
|
- free_irq(irq_to_rising(irq), pct);
|
|
|
- }
|
|
|
- if (falling) {
|
|
|
- disable_irq(irq_to_falling(irq));
|
|
|
- free_irq(irq_to_falling(irq), pct);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static int abx500_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
|
|
|
unsigned group)
|
|
|
{
|
|
@@ -871,7 +587,6 @@ static int abx500_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
|
|
|
dev_dbg(pct->dev, "setting pin %d to altsetting %d\n",
|
|
|
g->pins[i], g->altsetting);
|
|
|
|
|
|
- abx500_disable_lazy_irq(chip, g->pins[i]);
|
|
|
ret = abx500_set_mode(pctldev, chip, g->pins[i], g->altsetting);
|
|
|
}
|
|
|
|
|
@@ -1197,18 +912,12 @@ static int abx500_gpio_probe(struct platform_device *pdev)
|
|
|
pct->chip.ngpio = abx500_get_gpio_num(pct->soc);
|
|
|
pct->irq_cluster = pct->soc->gpio_irq_cluster;
|
|
|
pct->irq_cluster_size = pct->soc->ngpio_irq_cluster;
|
|
|
- pct->irq_gpio_rising_offset = pct->soc->irq_gpio_rising_offset;
|
|
|
- pct->irq_gpio_falling_offset = pct->soc->irq_gpio_falling_offset;
|
|
|
- pct->irq_gpio_factor = pct->soc->irq_gpio_factor;
|
|
|
|
|
|
- ret = abx500_gpio_irq_init(pct);
|
|
|
- if (ret)
|
|
|
- goto out_free;
|
|
|
ret = gpiochip_add(&pct->chip);
|
|
|
if (ret) {
|
|
|
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
|
|
|
mutex_destroy(&pct->lock);
|
|
|
- goto out_rem_irq;
|
|
|
+ return ret;
|
|
|
}
|
|
|
dev_info(&pdev->dev, "added gpiochip\n");
|
|
|
|
|
@@ -1243,9 +952,7 @@ out_rem_chip:
|
|
|
err = gpiochip_remove(&pct->chip);
|
|
|
if (err)
|
|
|
dev_info(&pdev->dev, "failed to remove gpiochip\n");
|
|
|
-out_rem_irq:
|
|
|
- abx500_gpio_irq_remove(pct);
|
|
|
-out_free:
|
|
|
+
|
|
|
mutex_destroy(&pct->lock);
|
|
|
return ret;
|
|
|
}
|