diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index bce99182578b..540b2115f741 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -69,15 +69,11 @@ 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 +83,16 @@ struct pxa_gpio_chip { #endif }; +struct pxa_gpio_chip { + struct device *dev; + struct gpio_chip chip; + struct pxa_gpio_bank *banks; + + int irq0; + int irq1; + int (*set_wake)(unsigned int gpio, unsigned int on); +}; + enum pxa_gpio_type { PXA25X_GPIO = 0, PXA26X_GPIO, @@ -104,9 +110,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 +153,27 @@ 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 = + container_of(c, struct pxa_gpio_chip, chip); + + return pxa_chip; +} +static inline void __iomem *gpio_bank_base(struct gpio_chip *c, int gpio) +{ + struct pxa_gpio_bank *bank = chip_to_pxachip(c)->banks + (gpio / 32); + + return bank->regbase; } -static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio) +static inline struct pxa_gpio_bank *gpio_to_pxabank(struct gpio_chip *c, + unsigned gpio) { - return &pxa_gpio_chips[gpio_to_bank(gpio)]; + return chip_to_pxachip(c)->banks + gpio / 32; } static inline int gpio_is_pxa_type(int type) @@ -187,15 +202,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) { @@ -220,7 +233,7 @@ static inline int __gpio_is_occupied(unsigned gpio) static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - return chip->base + offset + irq_base; + return offset + irq_base; } int pxa_irq_to_gpio(int irq) @@ -230,8 +243,8 @@ int pxa_irq_to_gpio(int irq) 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; spin_lock_irqsave(&gpio_lock, flags); @@ -250,8 +263,8 @@ 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; writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); @@ -271,14 +284,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 +306,49 @@ 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_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio, + void __iomem *regbase) { - int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1; - struct pxa_gpio_chip *chips; + int i, gpio, nbanks = DIV_ROUND_UP(ngpio, 32); + struct pxa_gpio_bank *bank; - chips = kzalloc(nbanks * sizeof(struct pxa_gpio_chip), GFP_KERNEL); - if (chips == NULL) { - pr_err("%s: failed to allocate GPIO chips\n", __func__); + pchip->banks = devm_kcalloc(pchip->dev, nbanks, sizeof(*pchip->banks), + GFP_KERNEL); + if (!pchip->banks) return -ENOMEM; - } - for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) { - struct gpio_chip *c = &chips[i].chip; - - sprintf(chips[i].label, "gpio-%d", i); - chips[i].regbase = gpio_reg_base + BANK_OFF(i); - chips[i].set_wake = set_wake; - - c->base = gpio; - c->label = chips[i].label; - - 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; #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 = pxa_gpio_of_node; + 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(&pchip->chip); } /* 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 +362,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; + struct pxa_gpio_chip *pchip = pxa_gpio_chip; int gpio = pxa_irq_to_gpio(d->irq); + 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 +374,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; @@ -403,18 +407,17 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type) static void pxa_gpio_demux_handler(struct irq_desc *desc) { - 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); + struct pxa_gpio_chip *pchip = pxa_gpio_chip; + struct pxa_gpio_bank *c; chained_irq_enter(chip, desc); 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,7 +425,7 @@ 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)); } } } while (loop); @@ -432,41 +435,45 @@ static void pxa_gpio_demux_handler(struct irq_desc *desc) static void pxa_ack_muxed_gpio(struct irq_data *d) { + struct pxa_gpio_chip *pchip = pxa_gpio_chip; int gpio = pxa_irq_to_gpio(d->irq); - struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); + 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) { + struct pxa_gpio_chip *pchip = pxa_gpio_chip; int gpio = pxa_irq_to_gpio(d->irq); - struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); + 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 = pxa_gpio_chip; - 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) { + struct pxa_gpio_chip *pchip = pxa_gpio_chip; int gpio = pxa_irq_to_gpio(d->irq); - struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); + struct pxa_gpio_bank *c = gpio_to_pxabank(&pchip->chip, gpio); c->irq_mask |= GPIO_bit(gpio); update_edge_detect(c); @@ -533,9 +540,10 @@ const struct irq_domain_ops pxa_irq_domain_ops = { .xlate = irq_domain_xlate_twocell, }; -static int pxa_gpio_probe_dt(struct platform_device *pdev) +static int pxa_gpio_probe_dt(struct platform_device *pdev, + struct pxa_gpio_chip *pchip) { - int ret = 0, nr_gpios; + int nr_gpios; struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(pxa_gpio_dt_ids, &pdev->dev); @@ -554,40 +562,44 @@ 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_irq_domain_ops, pchip); pxa_gpio_of_node = np; return 0; -err: - iounmap(gpio_reg_base); - return ret; } #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; + void __iomem *gpio_reg_base; int gpio, irq, ret, use_of = 0; 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); + ret = pxa_gpio_probe_dt(pdev, pchip); if (ret < 0) return -EINVAL; } @@ -626,10 +638,14 @@ static int pxa_gpio_probe(struct platform_device *pdev) } /* 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, 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); @@ -664,6 +680,7 @@ static int pxa_gpio_probe(struct platform_device *pdev) 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; @@ -711,10 +728,11 @@ 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); @@ -728,10 +746,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);