|
@@ -24,6 +24,7 @@
|
|
|
#include <linux/io.h>
|
|
|
#include <linux/of.h>
|
|
|
#include <linux/of_device.h>
|
|
|
+#include <linux/pinctrl/consumer.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/syscore_ops.h>
|
|
|
#include <linux/slab.h>
|
|
@@ -64,20 +65,11 @@
|
|
|
int pxa_last_gpio;
|
|
|
static int irq_base;
|
|
|
|
|
|
-#ifdef CONFIG_OF
|
|
|
-static struct irq_domain *domain;
|
|
|
-static struct device_node *pxa_gpio_of_node;
|
|
|
-#endif
|
|
|
-
|
|
|
-struct pxa_gpio_chip {
|
|
|
- struct gpio_chip chip;
|
|
|
+struct pxa_gpio_bank {
|
|
|
void __iomem *regbase;
|
|
|
- char label[10];
|
|
|
-
|
|
|
unsigned long irq_mask;
|
|
|
unsigned long irq_edge_rise;
|
|
|
unsigned long irq_edge_fall;
|
|
|
- int (*set_wake)(unsigned int gpio, unsigned int on);
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
|
unsigned long saved_gplr;
|
|
@@ -87,6 +79,17 @@ struct pxa_gpio_chip {
|
|
|
#endif
|
|
|
};
|
|
|
|
|
|
+struct pxa_gpio_chip {
|
|
|
+ struct device *dev;
|
|
|
+ struct gpio_chip chip;
|
|
|
+ struct pxa_gpio_bank *banks;
|
|
|
+ struct irq_domain *irqdomain;
|
|
|
+
|
|
|
+ int irq0;
|
|
|
+ int irq1;
|
|
|
+ int (*set_wake)(unsigned int gpio, unsigned int on);
|
|
|
+};
|
|
|
+
|
|
|
enum pxa_gpio_type {
|
|
|
PXA25X_GPIO = 0,
|
|
|
PXA26X_GPIO,
|
|
@@ -104,9 +107,8 @@ struct pxa_gpio_id {
|
|
|
};
|
|
|
|
|
|
static DEFINE_SPINLOCK(gpio_lock);
|
|
|
-static struct pxa_gpio_chip *pxa_gpio_chips;
|
|
|
+static struct pxa_gpio_chip *pxa_gpio_chip;
|
|
|
static enum pxa_gpio_type gpio_type;
|
|
|
-static void __iomem *gpio_reg_base;
|
|
|
|
|
|
static struct pxa_gpio_id pxa25x_id = {
|
|
|
.type = PXA25X_GPIO,
|
|
@@ -148,17 +150,28 @@ static struct pxa_gpio_id pxa1928_id = {
|
|
|
.gpio_nums = 224,
|
|
|
};
|
|
|
|
|
|
-#define for_each_gpio_chip(i, c) \
|
|
|
- for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++)
|
|
|
+#define for_each_gpio_bank(i, b, pc) \
|
|
|
+ for (i = 0, b = pc->banks; i <= pxa_last_gpio; i += 32, b++)
|
|
|
|
|
|
-static inline void __iomem *gpio_chip_base(struct gpio_chip *c)
|
|
|
+static inline struct pxa_gpio_chip *chip_to_pxachip(struct gpio_chip *c)
|
|
|
{
|
|
|
- return container_of(c, struct pxa_gpio_chip, chip)->regbase;
|
|
|
+ struct pxa_gpio_chip *pxa_chip = gpiochip_get_data(c);
|
|
|
+
|
|
|
+ return pxa_chip;
|
|
|
}
|
|
|
|
|
|
-static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio)
|
|
|
+static inline void __iomem *gpio_bank_base(struct gpio_chip *c, int gpio)
|
|
|
{
|
|
|
- return &pxa_gpio_chips[gpio_to_bank(gpio)];
|
|
|
+ struct pxa_gpio_chip *p = gpiochip_get_data(c);
|
|
|
+ struct pxa_gpio_bank *bank = p->banks + (gpio / 32);
|
|
|
+
|
|
|
+ return bank->regbase;
|
|
|
+}
|
|
|
+
|
|
|
+static inline struct pxa_gpio_bank *gpio_to_pxabank(struct gpio_chip *c,
|
|
|
+ unsigned gpio)
|
|
|
+{
|
|
|
+ return chip_to_pxachip(c)->banks + gpio / 32;
|
|
|
}
|
|
|
|
|
|
static inline int gpio_is_pxa_type(int type)
|
|
@@ -187,15 +200,13 @@ static inline int __gpio_is_inverted(int gpio)
|
|
|
* is attributed as "occupied" here (I know this terminology isn't
|
|
|
* accurate, you are welcome to propose a better one :-)
|
|
|
*/
|
|
|
-static inline int __gpio_is_occupied(unsigned gpio)
|
|
|
+static inline int __gpio_is_occupied(struct pxa_gpio_chip *pchip, unsigned gpio)
|
|
|
{
|
|
|
- struct pxa_gpio_chip *pxachip;
|
|
|
void __iomem *base;
|
|
|
unsigned long gafr = 0, gpdr = 0;
|
|
|
int ret, af = 0, dir = 0;
|
|
|
|
|
|
- pxachip = gpio_to_pxachip(gpio);
|
|
|
- base = gpio_chip_base(&pxachip->chip);
|
|
|
+ base = gpio_bank_base(&pchip->chip, gpio);
|
|
|
gpdr = readl_relaxed(base + GPDR_OFFSET);
|
|
|
|
|
|
switch (gpio_type) {
|
|
@@ -218,21 +229,35 @@ static inline int __gpio_is_occupied(unsigned gpio)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
|
|
+int pxa_irq_to_gpio(int irq)
|
|
|
{
|
|
|
- return chip->base + offset + irq_base;
|
|
|
+ struct pxa_gpio_chip *pchip = pxa_gpio_chip;
|
|
|
+ int irq_gpio0;
|
|
|
+
|
|
|
+ irq_gpio0 = irq_find_mapping(pchip->irqdomain, 0);
|
|
|
+ if (irq_gpio0 > 0)
|
|
|
+ return irq - irq_gpio0;
|
|
|
+
|
|
|
+ return irq_gpio0;
|
|
|
}
|
|
|
|
|
|
-int pxa_irq_to_gpio(int irq)
|
|
|
+static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
|
|
{
|
|
|
- return irq - irq_base;
|
|
|
+ struct pxa_gpio_chip *pchip = chip_to_pxachip(chip);
|
|
|
+
|
|
|
+ return irq_find_mapping(pchip->irqdomain, offset);
|
|
|
}
|
|
|
|
|
|
static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
|
|
{
|
|
|
- void __iomem *base = gpio_chip_base(chip);
|
|
|
- uint32_t value, mask = 1 << offset;
|
|
|
+ void __iomem *base = gpio_bank_base(chip, offset);
|
|
|
+ uint32_t value, mask = GPIO_bit(offset);
|
|
|
unsigned long flags;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = pinctrl_gpio_direction_input(chip->base + offset);
|
|
|
+ if (!ret)
|
|
|
+ return 0;
|
|
|
|
|
|
spin_lock_irqsave(&gpio_lock, flags);
|
|
|
|
|
@@ -250,12 +275,17 @@ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
|
|
static int pxa_gpio_direction_output(struct gpio_chip *chip,
|
|
|
unsigned offset, int value)
|
|
|
{
|
|
|
- void __iomem *base = gpio_chip_base(chip);
|
|
|
- uint32_t tmp, mask = 1 << offset;
|
|
|
+ void __iomem *base = gpio_bank_base(chip, offset);
|
|
|
+ uint32_t tmp, mask = GPIO_bit(offset);
|
|
|
unsigned long flags;
|
|
|
+ int ret;
|
|
|
|
|
|
writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET));
|
|
|
|
|
|
+ ret = pinctrl_gpio_direction_output(chip->base + offset);
|
|
|
+ if (!ret)
|
|
|
+ return 0;
|
|
|
+
|
|
|
spin_lock_irqsave(&gpio_lock, flags);
|
|
|
|
|
|
tmp = readl_relaxed(base + GPDR_OFFSET);
|
|
@@ -271,14 +301,18 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip,
|
|
|
|
|
|
static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|
|
{
|
|
|
- u32 gplr = readl_relaxed(gpio_chip_base(chip) + GPLR_OFFSET);
|
|
|
- return !!(gplr & (1 << offset));
|
|
|
+ void __iomem *base = gpio_bank_base(chip, offset);
|
|
|
+ u32 gplr = readl_relaxed(base + GPLR_OFFSET);
|
|
|
+
|
|
|
+ return !!(gplr & GPIO_bit(offset));
|
|
|
}
|
|
|
|
|
|
static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|
|
{
|
|
|
- writel_relaxed(1 << offset, gpio_chip_base(chip) +
|
|
|
- (value ? GPSR_OFFSET : GPCR_OFFSET));
|
|
|
+ void __iomem *base = gpio_bank_base(chip, offset);
|
|
|
+
|
|
|
+ writel_relaxed(GPIO_bit(offset),
|
|
|
+ base + (value ? GPSR_OFFSET : GPCR_OFFSET));
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_OF_GPIO
|
|
@@ -289,61 +323,61 @@ static int pxa_gpio_of_xlate(struct gpio_chip *gc,
|
|
|
if (gpiospec->args[0] > pxa_last_gpio)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (gc != &pxa_gpio_chips[gpiospec->args[0] / 32].chip)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
if (flags)
|
|
|
*flags = gpiospec->args[1];
|
|
|
|
|
|
- return gpiospec->args[0] % 32;
|
|
|
+ return gpiospec->args[0];
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-static int pxa_init_gpio_chip(int gpio_end,
|
|
|
- int (*set_wake)(unsigned int, unsigned int))
|
|
|
+static int pxa_gpio_request(struct gpio_chip *chip, unsigned int offset)
|
|
|
{
|
|
|
- int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1;
|
|
|
- struct pxa_gpio_chip *chips;
|
|
|
-
|
|
|
- chips = kzalloc(nbanks * sizeof(struct pxa_gpio_chip), GFP_KERNEL);
|
|
|
- if (chips == NULL) {
|
|
|
- pr_err("%s: failed to allocate GPIO chips\n", __func__);
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
+ return pinctrl_request_gpio(chip->base + offset);
|
|
|
+}
|
|
|
|
|
|
- for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
|
|
|
- struct gpio_chip *c = &chips[i].chip;
|
|
|
+static void pxa_gpio_free(struct gpio_chip *chip, unsigned int offset)
|
|
|
+{
|
|
|
+ pinctrl_free_gpio(chip->base + offset);
|
|
|
+}
|
|
|
|
|
|
- sprintf(chips[i].label, "gpio-%d", i);
|
|
|
- chips[i].regbase = gpio_reg_base + BANK_OFF(i);
|
|
|
- chips[i].set_wake = set_wake;
|
|
|
+static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio,
|
|
|
+ struct device_node *np, void __iomem *regbase)
|
|
|
+{
|
|
|
+ int i, gpio, nbanks = DIV_ROUND_UP(ngpio, 32);
|
|
|
+ struct pxa_gpio_bank *bank;
|
|
|
|
|
|
- c->base = gpio;
|
|
|
- c->label = chips[i].label;
|
|
|
+ pchip->banks = devm_kcalloc(pchip->dev, nbanks, sizeof(*pchip->banks),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!pchip->banks)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- c->direction_input = pxa_gpio_direction_input;
|
|
|
- c->direction_output = pxa_gpio_direction_output;
|
|
|
- c->get = pxa_gpio_get;
|
|
|
- c->set = pxa_gpio_set;
|
|
|
- c->to_irq = pxa_gpio_to_irq;
|
|
|
+ pchip->chip.label = "gpio-pxa";
|
|
|
+ pchip->chip.direction_input = pxa_gpio_direction_input;
|
|
|
+ pchip->chip.direction_output = pxa_gpio_direction_output;
|
|
|
+ pchip->chip.get = pxa_gpio_get;
|
|
|
+ pchip->chip.set = pxa_gpio_set;
|
|
|
+ pchip->chip.to_irq = pxa_gpio_to_irq;
|
|
|
+ pchip->chip.ngpio = ngpio;
|
|
|
+ pchip->chip.request = pxa_gpio_request;
|
|
|
+ pchip->chip.free = pxa_gpio_free;
|
|
|
#ifdef CONFIG_OF_GPIO
|
|
|
- c->of_node = pxa_gpio_of_node;
|
|
|
- c->of_xlate = pxa_gpio_of_xlate;
|
|
|
- c->of_gpio_n_cells = 2;
|
|
|
+ pchip->chip.of_node = np;
|
|
|
+ pchip->chip.of_xlate = pxa_gpio_of_xlate;
|
|
|
+ pchip->chip.of_gpio_n_cells = 2;
|
|
|
#endif
|
|
|
|
|
|
- /* number of GPIOs on last bank may be less than 32 */
|
|
|
- c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32;
|
|
|
- gpiochip_add(c);
|
|
|
+ for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
|
|
|
+ bank = pchip->banks + i;
|
|
|
+ bank->regbase = regbase + BANK_OFF(i);
|
|
|
}
|
|
|
- pxa_gpio_chips = chips;
|
|
|
- return 0;
|
|
|
+
|
|
|
+ return gpiochip_add_data(&pchip->chip, pchip);
|
|
|
}
|
|
|
|
|
|
/* Update only those GRERx and GFERx edge detection register bits if those
|
|
|
* bits are set in c->irq_mask
|
|
|
*/
|
|
|
-static inline void update_edge_detect(struct pxa_gpio_chip *c)
|
|
|
+static inline void update_edge_detect(struct pxa_gpio_bank *c)
|
|
|
{
|
|
|
uint32_t grer, gfer;
|
|
|
|
|
@@ -357,12 +391,11 @@ static inline void update_edge_detect(struct pxa_gpio_chip *c)
|
|
|
|
|
|
static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
|
|
|
{
|
|
|
- struct pxa_gpio_chip *c;
|
|
|
- int gpio = pxa_irq_to_gpio(d->irq);
|
|
|
+ struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
|
|
|
+ unsigned int gpio = irqd_to_hwirq(d);
|
|
|
+ struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio);
|
|
|
unsigned long gpdr, mask = GPIO_bit(gpio);
|
|
|
|
|
|
- c = gpio_to_pxachip(gpio);
|
|
|
-
|
|
|
if (type == IRQ_TYPE_PROBE) {
|
|
|
/* Don't mess with enabled GPIOs using preconfigured edges or
|
|
|
* GPIOs set to alternate function or to output during probe
|
|
@@ -370,7 +403,7 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
|
|
|
if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio))
|
|
|
return 0;
|
|
|
|
|
|
- if (__gpio_is_occupied(gpio))
|
|
|
+ if (__gpio_is_occupied(pchip, gpio))
|
|
|
return 0;
|
|
|
|
|
|
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
|
|
@@ -401,20 +434,16 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void pxa_gpio_demux_handler(struct irq_desc *desc)
|
|
|
+static irqreturn_t pxa_gpio_demux_handler(int in_irq, void *d)
|
|
|
{
|
|
|
- struct pxa_gpio_chip *c;
|
|
|
- int loop, gpio, gpio_base, n;
|
|
|
+ int loop, gpio, n, handled = 0;
|
|
|
unsigned long gedr;
|
|
|
- struct irq_chip *chip = irq_desc_get_chip(desc);
|
|
|
-
|
|
|
- chained_irq_enter(chip, desc);
|
|
|
+ struct pxa_gpio_chip *pchip = d;
|
|
|
+ struct pxa_gpio_bank *c;
|
|
|
|
|
|
do {
|
|
|
loop = 0;
|
|
|
- for_each_gpio_chip(gpio, c) {
|
|
|
- gpio_base = c->chip.base;
|
|
|
-
|
|
|
+ for_each_gpio_bank(gpio, c, pchip) {
|
|
|
gedr = readl_relaxed(c->regbase + GEDR_OFFSET);
|
|
|
gedr = gedr & c->irq_mask;
|
|
|
writel_relaxed(gedr, c->regbase + GEDR_OFFSET);
|
|
@@ -422,51 +451,71 @@ static void pxa_gpio_demux_handler(struct irq_desc *desc)
|
|
|
for_each_set_bit(n, &gedr, BITS_PER_LONG) {
|
|
|
loop = 1;
|
|
|
|
|
|
- generic_handle_irq(gpio_to_irq(gpio_base + n));
|
|
|
+ generic_handle_irq(gpio_to_irq(gpio + n));
|
|
|
}
|
|
|
}
|
|
|
+ handled += loop;
|
|
|
} while (loop);
|
|
|
|
|
|
- chained_irq_exit(chip, desc);
|
|
|
+ return handled ? IRQ_HANDLED : IRQ_NONE;
|
|
|
+}
|
|
|
+
|
|
|
+static irqreturn_t pxa_gpio_direct_handler(int in_irq, void *d)
|
|
|
+{
|
|
|
+ struct pxa_gpio_chip *pchip = d;
|
|
|
+
|
|
|
+ if (in_irq == pchip->irq0) {
|
|
|
+ generic_handle_irq(gpio_to_irq(0));
|
|
|
+ } else if (in_irq == pchip->irq1) {
|
|
|
+ generic_handle_irq(gpio_to_irq(1));
|
|
|
+ } else {
|
|
|
+ pr_err("%s() unknown irq %d\n", __func__, in_irq);
|
|
|
+ return IRQ_NONE;
|
|
|
+ }
|
|
|
+ return IRQ_HANDLED;
|
|
|
}
|
|
|
|
|
|
static void pxa_ack_muxed_gpio(struct irq_data *d)
|
|
|
{
|
|
|
- int gpio = pxa_irq_to_gpio(d->irq);
|
|
|
- struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
|
|
|
+ struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
|
|
|
+ unsigned int gpio = irqd_to_hwirq(d);
|
|
|
+ void __iomem *base = gpio_bank_base(&pchip->chip, gpio);
|
|
|
|
|
|
- writel_relaxed(GPIO_bit(gpio), c->regbase + GEDR_OFFSET);
|
|
|
+ writel_relaxed(GPIO_bit(gpio), base + GEDR_OFFSET);
|
|
|
}
|
|
|
|
|
|
static void pxa_mask_muxed_gpio(struct irq_data *d)
|
|
|
{
|
|
|
- int gpio = pxa_irq_to_gpio(d->irq);
|
|
|
- struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
|
|
|
+ struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
|
|
|
+ unsigned int gpio = irqd_to_hwirq(d);
|
|
|
+ struct pxa_gpio_bank *b = gpio_to_pxabank(&pchip->chip, gpio);
|
|
|
+ void __iomem *base = gpio_bank_base(&pchip->chip, gpio);
|
|
|
uint32_t grer, gfer;
|
|
|
|
|
|
- c->irq_mask &= ~GPIO_bit(gpio);
|
|
|
+ b->irq_mask &= ~GPIO_bit(gpio);
|
|
|
|
|
|
- grer = readl_relaxed(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio);
|
|
|
- gfer = readl_relaxed(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio);
|
|
|
- writel_relaxed(grer, c->regbase + GRER_OFFSET);
|
|
|
- writel_relaxed(gfer, c->regbase + GFER_OFFSET);
|
|
|
+ grer = readl_relaxed(base + GRER_OFFSET) & ~GPIO_bit(gpio);
|
|
|
+ gfer = readl_relaxed(base + GFER_OFFSET) & ~GPIO_bit(gpio);
|
|
|
+ writel_relaxed(grer, base + GRER_OFFSET);
|
|
|
+ writel_relaxed(gfer, base + GFER_OFFSET);
|
|
|
}
|
|
|
|
|
|
static int pxa_gpio_set_wake(struct irq_data *d, unsigned int on)
|
|
|
{
|
|
|
- int gpio = pxa_irq_to_gpio(d->irq);
|
|
|
- struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
|
|
|
+ struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
|
|
|
+ unsigned int gpio = irqd_to_hwirq(d);
|
|
|
|
|
|
- if (c->set_wake)
|
|
|
- return c->set_wake(gpio, on);
|
|
|
+ if (pchip->set_wake)
|
|
|
+ return pchip->set_wake(gpio, on);
|
|
|
else
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static void pxa_unmask_muxed_gpio(struct irq_data *d)
|
|
|
{
|
|
|
- int gpio = pxa_irq_to_gpio(d->irq);
|
|
|
- struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
|
|
|
+ struct pxa_gpio_chip *pchip = irq_data_get_irq_chip_data(d);
|
|
|
+ unsigned int gpio = irqd_to_hwirq(d);
|
|
|
+ struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio);
|
|
|
|
|
|
c->irq_mask |= GPIO_bit(gpio);
|
|
|
update_edge_detect(c);
|
|
@@ -506,24 +555,12 @@ static int pxa_gpio_nums(struct platform_device *pdev)
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_OF
|
|
|
-static const struct of_device_id pxa_gpio_dt_ids[] = {
|
|
|
- { .compatible = "intel,pxa25x-gpio", .data = &pxa25x_id, },
|
|
|
- { .compatible = "intel,pxa26x-gpio", .data = &pxa26x_id, },
|
|
|
- { .compatible = "intel,pxa27x-gpio", .data = &pxa27x_id, },
|
|
|
- { .compatible = "intel,pxa3xx-gpio", .data = &pxa3xx_id, },
|
|
|
- { .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, },
|
|
|
- { .compatible = "marvell,mmp-gpio", .data = &mmp_id, },
|
|
|
- { .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, },
|
|
|
- { .compatible = "marvell,pxa1928-gpio", .data = &pxa1928_id, },
|
|
|
- {}
|
|
|
-};
|
|
|
-
|
|
|
static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
|
|
irq_hw_number_t hw)
|
|
|
{
|
|
|
irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
|
|
|
handle_edge_irq);
|
|
|
+ irq_set_chip_data(irq, d->host_data);
|
|
|
irq_set_noprobe(irq);
|
|
|
return 0;
|
|
|
}
|
|
@@ -533,10 +570,23 @@ const struct irq_domain_ops pxa_irq_domain_ops = {
|
|
|
.xlate = irq_domain_xlate_twocell,
|
|
|
};
|
|
|
|
|
|
-static int pxa_gpio_probe_dt(struct platform_device *pdev)
|
|
|
+#ifdef CONFIG_OF
|
|
|
+static const struct of_device_id pxa_gpio_dt_ids[] = {
|
|
|
+ { .compatible = "intel,pxa25x-gpio", .data = &pxa25x_id, },
|
|
|
+ { .compatible = "intel,pxa26x-gpio", .data = &pxa26x_id, },
|
|
|
+ { .compatible = "intel,pxa27x-gpio", .data = &pxa27x_id, },
|
|
|
+ { .compatible = "intel,pxa3xx-gpio", .data = &pxa3xx_id, },
|
|
|
+ { .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, },
|
|
|
+ { .compatible = "marvell,mmp-gpio", .data = &mmp_id, },
|
|
|
+ { .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, },
|
|
|
+ { .compatible = "marvell,pxa1928-gpio", .data = &pxa1928_id, },
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
+static int pxa_gpio_probe_dt(struct platform_device *pdev,
|
|
|
+ struct pxa_gpio_chip *pchip)
|
|
|
{
|
|
|
- int ret = 0, nr_gpios;
|
|
|
- struct device_node *np = pdev->dev.of_node;
|
|
|
+ int nr_gpios;
|
|
|
const struct of_device_id *of_id =
|
|
|
of_match_device(pxa_gpio_dt_ids, &pdev->dev);
|
|
|
const struct pxa_gpio_id *gpio_id;
|
|
@@ -554,57 +604,64 @@ static int pxa_gpio_probe_dt(struct platform_device *pdev)
|
|
|
irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0);
|
|
|
if (irq_base < 0) {
|
|
|
dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
|
|
|
- ret = irq_base;
|
|
|
- goto err;
|
|
|
+ return irq_base;
|
|
|
}
|
|
|
- domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0,
|
|
|
- &pxa_irq_domain_ops, NULL);
|
|
|
- pxa_gpio_of_node = np;
|
|
|
- return 0;
|
|
|
-err:
|
|
|
- iounmap(gpio_reg_base);
|
|
|
- return ret;
|
|
|
+ return irq_base;
|
|
|
}
|
|
|
#else
|
|
|
-#define pxa_gpio_probe_dt(pdev) (-1)
|
|
|
+#define pxa_gpio_probe_dt(pdev, pchip) (-1)
|
|
|
#endif
|
|
|
|
|
|
static int pxa_gpio_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
- struct pxa_gpio_chip *c;
|
|
|
+ struct pxa_gpio_chip *pchip;
|
|
|
+ struct pxa_gpio_bank *c;
|
|
|
struct resource *res;
|
|
|
struct clk *clk;
|
|
|
struct pxa_gpio_platform_data *info;
|
|
|
- int gpio, irq, ret, use_of = 0;
|
|
|
+ void __iomem *gpio_reg_base;
|
|
|
+ int gpio, ret;
|
|
|
int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
|
|
|
|
|
|
+ pchip = devm_kzalloc(&pdev->dev, sizeof(*pchip), GFP_KERNEL);
|
|
|
+ if (!pchip)
|
|
|
+ return -ENOMEM;
|
|
|
+ pchip->dev = &pdev->dev;
|
|
|
+
|
|
|
info = dev_get_platdata(&pdev->dev);
|
|
|
if (info) {
|
|
|
irq_base = info->irq_base;
|
|
|
if (irq_base <= 0)
|
|
|
return -EINVAL;
|
|
|
pxa_last_gpio = pxa_gpio_nums(pdev);
|
|
|
+ pchip->set_wake = info->gpio_set_wake;
|
|
|
} else {
|
|
|
- irq_base = 0;
|
|
|
- use_of = 1;
|
|
|
- ret = pxa_gpio_probe_dt(pdev);
|
|
|
- if (ret < 0)
|
|
|
+ irq_base = pxa_gpio_probe_dt(pdev, pchip);
|
|
|
+ if (irq_base < 0)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
if (!pxa_last_gpio)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ pchip->irqdomain = irq_domain_add_legacy(pdev->dev.of_node,
|
|
|
+ pxa_last_gpio + 1, irq_base,
|
|
|
+ 0, &pxa_irq_domain_ops, pchip);
|
|
|
+ if (!pchip->irqdomain)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
irq0 = platform_get_irq_byname(pdev, "gpio0");
|
|
|
irq1 = platform_get_irq_byname(pdev, "gpio1");
|
|
|
irq_mux = platform_get_irq_byname(pdev, "gpio_mux");
|
|
|
if ((irq0 > 0 && irq1 <= 0) || (irq0 <= 0 && irq1 > 0)
|
|
|
|| (irq_mux <= 0))
|
|
|
return -EINVAL;
|
|
|
+
|
|
|
+ pchip->irq0 = irq0;
|
|
|
+ pchip->irq1 = irq1;
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
- if (!res)
|
|
|
- return -EINVAL;
|
|
|
- gpio_reg_base = ioremap(res->start, resource_size(res));
|
|
|
+ gpio_reg_base = devm_ioremap(&pdev->dev, res->start,
|
|
|
+ resource_size(res));
|
|
|
if (!gpio_reg_base)
|
|
|
return -EINVAL;
|
|
|
|
|
@@ -615,21 +672,24 @@ static int pxa_gpio_probe(struct platform_device *pdev)
|
|
|
if (IS_ERR(clk)) {
|
|
|
dev_err(&pdev->dev, "Error %ld to get gpio clock\n",
|
|
|
PTR_ERR(clk));
|
|
|
- iounmap(gpio_reg_base);
|
|
|
return PTR_ERR(clk);
|
|
|
}
|
|
|
ret = clk_prepare_enable(clk);
|
|
|
if (ret) {
|
|
|
clk_put(clk);
|
|
|
- iounmap(gpio_reg_base);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
/* Initialize GPIO chips */
|
|
|
- pxa_init_gpio_chip(pxa_last_gpio, info ? info->gpio_set_wake : NULL);
|
|
|
+ ret = pxa_init_gpio_chip(pchip, pxa_last_gpio + 1, pdev->dev.of_node,
|
|
|
+ gpio_reg_base);
|
|
|
+ if (ret) {
|
|
|
+ clk_put(clk);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
|
|
|
/* clear all GPIO edge detects */
|
|
|
- for_each_gpio_chip(gpio, c) {
|
|
|
+ for_each_gpio_bank(gpio, c, pchip) {
|
|
|
writel_relaxed(0, c->regbase + GFER_OFFSET);
|
|
|
writel_relaxed(0, c->regbase + GRER_OFFSET);
|
|
|
writel_relaxed(~0, c->regbase + GEDR_OFFSET);
|
|
@@ -638,34 +698,31 @@ static int pxa_gpio_probe(struct platform_device *pdev)
|
|
|
writel_relaxed(~0, c->regbase + ED_MASK_OFFSET);
|
|
|
}
|
|
|
|
|
|
- if (!use_of) {
|
|
|
- if (irq0 > 0) {
|
|
|
- irq = gpio_to_irq(0);
|
|
|
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
|
|
|
- handle_edge_irq);
|
|
|
- irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
|
|
|
- }
|
|
|
- if (irq1 > 0) {
|
|
|
- irq = gpio_to_irq(1);
|
|
|
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
|
|
|
- handle_edge_irq);
|
|
|
- irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
|
|
|
- }
|
|
|
-
|
|
|
- for (irq = gpio_to_irq(gpio_offset);
|
|
|
- irq <= gpio_to_irq(pxa_last_gpio); irq++) {
|
|
|
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
|
|
|
- handle_edge_irq);
|
|
|
- irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
|
|
|
- }
|
|
|
+ if (irq0 > 0) {
|
|
|
+ ret = devm_request_irq(&pdev->dev,
|
|
|
+ irq0, pxa_gpio_direct_handler, 0,
|
|
|
+ "gpio-0", pchip);
|
|
|
+ if (ret)
|
|
|
+ dev_err(&pdev->dev, "request of gpio0 irq failed: %d\n",
|
|
|
+ ret);
|
|
|
}
|
|
|
+ if (irq1 > 0) {
|
|
|
+ ret = devm_request_irq(&pdev->dev,
|
|
|
+ irq1, pxa_gpio_direct_handler, 0,
|
|
|
+ "gpio-1", pchip);
|
|
|
+ if (ret)
|
|
|
+ dev_err(&pdev->dev, "request of gpio1 irq failed: %d\n",
|
|
|
+ ret);
|
|
|
+ }
|
|
|
+ ret = devm_request_irq(&pdev->dev,
|
|
|
+ irq_mux, pxa_gpio_demux_handler, 0,
|
|
|
+ "gpio-mux", pchip);
|
|
|
+ if (ret)
|
|
|
+ dev_err(&pdev->dev, "request of gpio-mux irq failed: %d\n",
|
|
|
+ ret);
|
|
|
|
|
|
- if (irq0 > 0)
|
|
|
- irq_set_chained_handler(irq0, pxa_gpio_demux_handler);
|
|
|
- if (irq1 > 0)
|
|
|
- irq_set_chained_handler(irq1, pxa_gpio_demux_handler);
|
|
|
+ pxa_gpio_chip = pchip;
|
|
|
|
|
|
- irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -690,19 +747,32 @@ static struct platform_driver pxa_gpio_driver = {
|
|
|
.id_table = gpio_id_table,
|
|
|
};
|
|
|
|
|
|
-static int __init pxa_gpio_init(void)
|
|
|
+static int __init pxa_gpio_legacy_init(void)
|
|
|
{
|
|
|
+ if (of_have_populated_dt())
|
|
|
+ return 0;
|
|
|
+
|
|
|
return platform_driver_register(&pxa_gpio_driver);
|
|
|
}
|
|
|
-postcore_initcall(pxa_gpio_init);
|
|
|
+postcore_initcall(pxa_gpio_legacy_init);
|
|
|
+
|
|
|
+static int __init pxa_gpio_dt_init(void)
|
|
|
+{
|
|
|
+ if (of_have_populated_dt())
|
|
|
+ return platform_driver_register(&pxa_gpio_driver);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+device_initcall(pxa_gpio_dt_init);
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
|
static int pxa_gpio_suspend(void)
|
|
|
{
|
|
|
- struct pxa_gpio_chip *c;
|
|
|
+ struct pxa_gpio_chip *pchip = pxa_gpio_chip;
|
|
|
+ struct pxa_gpio_bank *c;
|
|
|
int gpio;
|
|
|
|
|
|
- for_each_gpio_chip(gpio, c) {
|
|
|
+ for_each_gpio_bank(gpio, c, pchip) {
|
|
|
c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET);
|
|
|
c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET);
|
|
|
c->saved_grer = readl_relaxed(c->regbase + GRER_OFFSET);
|
|
@@ -716,10 +786,11 @@ static int pxa_gpio_suspend(void)
|
|
|
|
|
|
static void pxa_gpio_resume(void)
|
|
|
{
|
|
|
- struct pxa_gpio_chip *c;
|
|
|
+ struct pxa_gpio_chip *pchip = pxa_gpio_chip;
|
|
|
+ struct pxa_gpio_bank *c;
|
|
|
int gpio;
|
|
|
|
|
|
- for_each_gpio_chip(gpio, c) {
|
|
|
+ for_each_gpio_bank(gpio, c, pchip) {
|
|
|
/* restore level with set/clear */
|
|
|
writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET);
|
|
|
writel_relaxed(~c->saved_gplr, c->regbase + GPCR_OFFSET);
|