From 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 13 May 2024 10:30:14 +0000 Subject: [PATCH] modify sin led gpio --- kernel/drivers/gpio/gpio-dwapb.c | 509 ++++++++++++++++++++++++++------------------------------ 1 files changed, 239 insertions(+), 270 deletions(-) diff --git a/kernel/drivers/gpio/gpio-dwapb.c b/kernel/drivers/gpio/gpio-dwapb.c index 2a56efc..ea2e261 100644 --- a/kernel/drivers/gpio/gpio-dwapb.c +++ b/kernel/drivers/gpio/gpio-dwapb.c @@ -1,9 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011 Jamie Iles - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. * * All enquiries to support@picochip.com */ @@ -16,7 +13,6 @@ #include <linux/io.h> #include <linux/ioport.h> #include <linux/irq.h> -#include <linux/irqdomain.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> @@ -30,6 +26,7 @@ #include <linux/slab.h> #include "gpiolib.h" +#include "gpiolib-acpi.h" #define GPIO_SWPORTA_DR 0x00 #define GPIO_SWPORTA_DDR 0x04 @@ -66,6 +63,8 @@ #define GPIO_INTSTATUS_V2 0x3c #define GPIO_PORTA_EOI_V2 0x40 +#define DWAPB_NR_CLOCKS 2 + struct dwapb_gpio; #ifdef CONFIG_PM_SLEEP @@ -83,25 +82,32 @@ }; #endif +struct dwapb_gpio_port_irqchip { + struct irq_chip irqchip; + unsigned int nr_irqs; + unsigned int irq[DWAPB_MAX_GPIOS]; +}; + struct dwapb_gpio_port { struct gpio_chip gc; - bool is_registered; + struct dwapb_gpio_port_irqchip *pirq; struct dwapb_gpio *gpio; #ifdef CONFIG_PM_SLEEP struct dwapb_context *ctx; #endif unsigned int idx; }; +#define to_dwapb_gpio(_gc) \ + (container_of(_gc, struct dwapb_gpio_port, gc)->gpio) struct dwapb_gpio { struct device *dev; void __iomem *regs; struct dwapb_gpio_port *ports; unsigned int nr_ports; - struct irq_domain *domain; unsigned int flags; struct reset_control *rst; - struct clk *clk; + struct clk_bulk_data clks[DWAPB_NR_CLOCKS]; }; static inline u32 gpio_reg_v2_convert(unsigned int offset) @@ -147,14 +153,6 @@ gc->write_reg(reg_base + gpio_reg_convert(gpio, offset), val); } -static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct dwapb_gpio_port *port = gpiochip_get_data(gc); - struct dwapb_gpio *gpio = port->gpio; - - return irq_find_mapping(gpio->domain, offset); -} - static struct dwapb_gpio_port *dwapb_offs_to_port(struct dwapb_gpio *gpio, unsigned int offs) { struct dwapb_gpio_port *port; @@ -162,7 +160,7 @@ for (i = 0; i < gpio->nr_ports; i++) { port = &gpio->ports[i]; - if (port->idx == offs / 32) + if (port->idx == offs / DWAPB_MAX_GPIOS) return port; } @@ -182,7 +180,7 @@ pol = dwapb_read(gpio, GPIO_INT_POLARITY); /* Just read the current value right out of the data register */ - val = gc->get(gc, offs % 32); + val = gc->get(gc, offs % DWAPB_MAX_GPIOS); if (val) pol &= ~BIT(offs); else @@ -193,22 +191,22 @@ static u32 dwapb_do_irq(struct dwapb_gpio *gpio) { - u32 irq_status = dwapb_read(gpio, GPIO_INTSTATUS); - u32 ret = irq_status; + struct gpio_chip *gc = &gpio->ports[0].gc; + unsigned long irq_status; + irq_hw_number_t hwirq; - while (irq_status) { - int hwirq = fls(irq_status) - 1; - int gpio_irq = irq_find_mapping(gpio->domain, hwirq); + irq_status = dwapb_read(gpio, GPIO_INTSTATUS); + for_each_set_bit(hwirq, &irq_status, DWAPB_MAX_GPIOS) { + int gpio_irq = irq_find_mapping(gc->irq.domain, hwirq); + u32 irq_type = irq_get_trigger_type(gpio_irq); generic_handle_irq(gpio_irq); - irq_status &= ~BIT(hwirq); - if ((irq_get_trigger_type(gpio_irq) & IRQ_TYPE_SENSE_MASK) - == IRQ_TYPE_EDGE_BOTH) + if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) dwapb_toggle_trigger(gpio, hwirq); } - return ret; + return irq_status; } static void dwapb_irq_handler(struct irq_desc *desc) @@ -216,77 +214,90 @@ struct dwapb_gpio *gpio = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); + chained_irq_enter(chip, desc); dwapb_do_irq(gpio); + chained_irq_exit(chip, desc); +} - if (chip->irq_eoi) - chip->irq_eoi(irq_desc_get_irq_data(desc)); +static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id) +{ + return IRQ_RETVAL(dwapb_do_irq(dev_id)); +} + +static void dwapb_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = to_dwapb_gpio(gc); + u32 val = BIT(irqd_to_hwirq(d)); + unsigned long flags; + + spin_lock_irqsave(&gc->bgpio_lock, flags); + dwapb_write(gpio, GPIO_PORTA_EOI, val); + spin_unlock_irqrestore(&gc->bgpio_lock, flags); +} + +static void dwapb_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = to_dwapb_gpio(gc); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gc->bgpio_lock, flags); + val = dwapb_read(gpio, GPIO_INTMASK) | BIT(irqd_to_hwirq(d)); + dwapb_write(gpio, GPIO_INTMASK, val); + spin_unlock_irqrestore(&gc->bgpio_lock, flags); +} + +static void dwapb_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = to_dwapb_gpio(gc); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gc->bgpio_lock, flags); + val = dwapb_read(gpio, GPIO_INTMASK) & ~BIT(irqd_to_hwirq(d)); + dwapb_write(gpio, GPIO_INTMASK, val); + spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void dwapb_irq_enable(struct irq_data *d) { - struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); - struct dwapb_gpio *gpio = igc->private; - struct gpio_chip *gc = &gpio->ports[0].gc; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = to_dwapb_gpio(gc); unsigned long flags; u32 val; spin_lock_irqsave(&gc->bgpio_lock, flags); val = dwapb_read(gpio, GPIO_INTEN); - val |= BIT(d->hwirq); + val |= BIT(irqd_to_hwirq(d)); dwapb_write(gpio, GPIO_INTEN, val); spin_unlock_irqrestore(&gc->bgpio_lock, flags); } static void dwapb_irq_disable(struct irq_data *d) { - struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); - struct dwapb_gpio *gpio = igc->private; - struct gpio_chip *gc = &gpio->ports[0].gc; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = to_dwapb_gpio(gc); unsigned long flags; u32 val; spin_lock_irqsave(&gc->bgpio_lock, flags); val = dwapb_read(gpio, GPIO_INTEN); - val &= ~BIT(d->hwirq); + val &= ~BIT(irqd_to_hwirq(d)); dwapb_write(gpio, GPIO_INTEN, val); spin_unlock_irqrestore(&gc->bgpio_lock, flags); } -static int dwapb_irq_reqres(struct irq_data *d) -{ - struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); - struct dwapb_gpio *gpio = igc->private; - struct gpio_chip *gc = &gpio->ports[0].gc; - int ret; - - ret = gpiochip_lock_as_irq(gc, irqd_to_hwirq(d)); - if (ret) { - dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n", - irqd_to_hwirq(d)); - return ret; - } - return 0; -} - -static void dwapb_irq_relres(struct irq_data *d) -{ - struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); - struct dwapb_gpio *gpio = igc->private; - struct gpio_chip *gc = &gpio->ports[0].gc; - - gpiochip_unlock_as_irq(gc, irqd_to_hwirq(d)); -} - static int dwapb_irq_set_type(struct irq_data *d, u32 type) { - struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); - struct dwapb_gpio *gpio = igc->private; - struct gpio_chip *gc = &gpio->ports[0].gc; - int bit = d->hwirq; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = to_dwapb_gpio(gc); + irq_hw_number_t bit = irqd_to_hwirq(d); unsigned long level, polarity, flags; - if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | - IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) + if (type & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; spin_lock_irqsave(&gc->bgpio_lock, flags); @@ -316,7 +327,10 @@ break; } - irq_setup_alt_chip(d, type); + if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_handler_locked(d, handle_level_irq); + else if (type & IRQ_TYPE_EDGE_BOTH) + irq_set_handler_locked(d, handle_edge_irq); dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level); if (type != IRQ_TYPE_EDGE_BOTH) @@ -329,14 +343,15 @@ #ifdef CONFIG_PM_SLEEP static int dwapb_irq_set_wake(struct irq_data *d, unsigned int enable) { - struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); - struct dwapb_gpio *gpio = igc->private; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = to_dwapb_gpio(gc); struct dwapb_context *ctx = gpio->ports[0].ctx; + irq_hw_number_t bit = irqd_to_hwirq(d); if (enable) - ctx->wake_en |= BIT(d->hwirq); + ctx->wake_en |= BIT(bit); else - ctx->wake_en &= ~BIT(d->hwirq); + ctx->wake_en &= ~BIT(bit); return 0; } @@ -354,9 +369,10 @@ val_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE); if (debounce) - dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb | mask); + val_deb |= mask; else - dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb & ~mask); + val_deb &= ~mask; + dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb); spin_unlock_irqrestore(&gc->bgpio_lock, flags); @@ -375,84 +391,67 @@ return dwapb_gpio_set_debounce(gc, offset, debounce); } -static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id) +static int dwapb_convert_irqs(struct dwapb_gpio_port_irqchip *pirq, + struct dwapb_port_property *pp) { - u32 worked; - struct dwapb_gpio *gpio = dev_id; + int i; - worked = dwapb_do_irq(gpio); + /* Group all available IRQs into an array of parental IRQs. */ + for (i = 0; i < pp->ngpio; ++i) { + if (!pp->irq[i]) + continue; - return worked ? IRQ_HANDLED : IRQ_NONE; + pirq->irq[pirq->nr_irqs++] = pp->irq[i]; + } + + return pirq->nr_irqs ? 0 : -ENOENT; } static void dwapb_configure_irqs(struct dwapb_gpio *gpio, struct dwapb_gpio_port *port, struct dwapb_port_property *pp) { + struct dwapb_gpio_port_irqchip *pirq; struct gpio_chip *gc = &port->gc; - struct fwnode_handle *fwnode = pp->fwnode; - struct irq_chip_generic *irq_gc = NULL; - unsigned int hwirq, ngpio = gc->ngpio; - struct irq_chip_type *ct; - int err, i; + struct gpio_irq_chip *girq; + int err; - gpio->domain = irq_domain_create_linear(fwnode, ngpio, - &irq_generic_chip_ops, gpio); - if (!gpio->domain) + pirq = devm_kzalloc(gpio->dev, sizeof(*pirq), GFP_KERNEL); + if (!pirq) return; - err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 2, - DWAPB_DRIVER_NAME, handle_level_irq, - IRQ_NOREQUEST, 0, - IRQ_GC_INIT_NESTED_LOCK); - if (err) { - dev_info(gpio->dev, "irq_alloc_domain_generic_chips failed\n"); - irq_domain_remove(gpio->domain); - gpio->domain = NULL; - return; + if (dwapb_convert_irqs(pirq, pp)) { + dev_warn(gpio->dev, "no IRQ for port%d\n", pp->idx); + goto err_kfree_pirq; } - irq_gc = irq_get_domain_generic_chip(gpio->domain, 0); - if (!irq_gc) { - irq_domain_remove(gpio->domain); - gpio->domain = NULL; - return; - } + girq = &gc->irq; + girq->handler = handle_bad_irq; + girq->default_type = IRQ_TYPE_NONE; - irq_gc->reg_base = gpio->regs; - irq_gc->private = gpio; - - for (i = 0; i < 2; i++) { - ct = &irq_gc->chip_types[i]; - ct->chip.irq_ack = irq_gc_ack_set_bit; - ct->chip.irq_mask = irq_gc_mask_set_bit; - ct->chip.irq_unmask = irq_gc_mask_clr_bit; - ct->chip.irq_set_type = dwapb_irq_set_type; - ct->chip.irq_enable = dwapb_irq_enable; - ct->chip.irq_disable = dwapb_irq_disable; - ct->chip.irq_request_resources = dwapb_irq_reqres; - ct->chip.irq_release_resources = dwapb_irq_relres; + port->pirq = pirq; + pirq->irqchip.name = DWAPB_DRIVER_NAME; + pirq->irqchip.irq_ack = dwapb_irq_ack; + pirq->irqchip.irq_mask = dwapb_irq_mask; + pirq->irqchip.irq_unmask = dwapb_irq_unmask; + pirq->irqchip.irq_set_type = dwapb_irq_set_type; + pirq->irqchip.irq_enable = dwapb_irq_enable; + pirq->irqchip.irq_disable = dwapb_irq_disable; #ifdef CONFIG_PM_SLEEP - ct->chip.irq_set_wake = dwapb_irq_set_wake; + pirq->irqchip.irq_set_wake = dwapb_irq_set_wake; #endif - ct->regs.ack = gpio_reg_convert(gpio, GPIO_PORTA_EOI); - ct->regs.mask = gpio_reg_convert(gpio, GPIO_INTMASK); - ct->type = IRQ_TYPE_LEVEL_MASK; - } - - irq_gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK; - irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; - irq_gc->chip_types[1].handler = handle_edge_irq; if (!pp->irq_shared) { - int i; - - for (i = 0; i < pp->ngpio; i++) { - if (pp->irq[i] >= 0) - irq_set_chained_handler_and_data(pp->irq[i], - dwapb_irq_handler, gpio); - } + girq->num_parents = pirq->nr_irqs; + girq->parents = pirq->irq; + girq->parent_handler_data = gpio; + girq->parent_handler = dwapb_irq_handler; } else { + /* This will let us handle the parent IRQ in the driver */ + girq->num_parents = 0; + girq->parents = NULL; + girq->parent_handler = NULL; + /* * Request a shared IRQ since where MFD would have devices * using the same irq pin @@ -462,33 +461,16 @@ IRQF_SHARED, DWAPB_DRIVER_NAME, gpio); if (err) { dev_err(gpio->dev, "error requesting IRQ\n"); - irq_domain_remove(gpio->domain); - gpio->domain = NULL; - return; + goto err_kfree_pirq; } } - for (hwirq = 0 ; hwirq < ngpio ; hwirq++) - irq_create_mapping(gpio->domain, hwirq); + girq->chip = &pirq->irqchip; - port->gc.to_irq = dwapb_gpio_to_irq; -} + return; -static void dwapb_irq_teardown(struct dwapb_gpio *gpio) -{ - struct dwapb_gpio_port *port = &gpio->ports[0]; - struct gpio_chip *gc = &port->gc; - unsigned int ngpio = gc->ngpio; - irq_hw_number_t hwirq; - - if (!gpio->domain) - return; - - for (hwirq = 0 ; hwirq < ngpio ; hwirq++) - irq_dispose_mapping(irq_find_mapping(gpio->domain, hwirq)); - - irq_domain_remove(gpio->domain); - gpio->domain = NULL; +err_kfree_pirq: + devm_kfree(gpio->dev, pirq); } static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, @@ -509,10 +491,9 @@ return -ENOMEM; #endif - dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_STRIDE); - set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_STRIDE); - dirout = gpio->regs + GPIO_SWPORTA_DDR + - (pp->idx * GPIO_SWPORT_DDR_STRIDE); + dat = gpio->regs + GPIO_EXT_PORTA + pp->idx * GPIO_EXT_PORT_STRIDE; + set = gpio->regs + GPIO_SWPORTA_DR + pp->idx * GPIO_SWPORT_DR_STRIDE; + dirout = gpio->regs + GPIO_SWPORTA_DDR + pp->idx * GPIO_SWPORT_DDR_STRIDE; /* This registers 32 GPIO lines per port */ err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout, @@ -533,47 +514,46 @@ if (pp->idx == 0) port->gc.set_config = dwapb_gpio_set_config; - if (pp->has_irq) + /* Only port A can provide interrupts in all configurations of the IP */ + if (pp->idx == 0) dwapb_configure_irqs(gpio, port, pp); - err = gpiochip_add_data(&port->gc, port); + err = devm_gpiochip_add_data(gpio->dev, &port->gc, port); if (err) { dev_err(gpio->dev, "failed to register gpiochip for port%d\n", port->idx); return err; } - /* Add GPIO-signaled ACPI event support */ - acpi_gpiochip_request_interrupts(&port->gc); - - port->is_registered = true; - return 0; } -static void dwapb_gpio_unregister(struct dwapb_gpio *gpio) +static void dwapb_get_irq(struct device *dev, struct fwnode_handle *fwnode, + struct dwapb_port_property *pp) { - unsigned int m; + struct device_node *np = NULL; + int irq = -ENXIO, j; - for (m = 0; m < gpio->nr_ports; ++m) { - struct dwapb_gpio_port *port = &gpio->ports[m]; + if (fwnode_property_read_bool(fwnode, "interrupt-controller")) + np = to_of_node(fwnode); - if (!port->is_registered) - continue; - - acpi_gpiochip_free_interrupts(&port->gc); - gpiochip_remove(&port->gc); + for (j = 0; j < pp->ngpio; j++) { + if (np) + irq = of_irq_get(np, j); + else if (has_acpi_companion(dev)) + irq = platform_get_irq_optional(to_platform_device(dev), j); + if (irq > 0) + pp->irq[j] = irq; } } -static struct dwapb_platform_data * -dwapb_gpio_get_pdata(struct device *dev) +static struct dwapb_platform_data *dwapb_gpio_get_pdata(struct device *dev) { struct fwnode_handle *fwnode; struct dwapb_platform_data *pdata; struct dwapb_port_property *pp; int nports; - int i, j; + int i; nports = device_get_child_node_count(dev); if (nports == 0) @@ -591,8 +571,6 @@ i = 0; device_for_each_child_node(dev, fwnode) { - struct device_node *np = NULL; - pp = &pdata->properties[i++]; pp->fwnode = fwnode; @@ -604,12 +582,12 @@ return ERR_PTR(-EINVAL); } - if (fwnode_property_read_u32(fwnode, "snps,nr-gpios", - &pp->ngpio)) { + if (fwnode_property_read_u32(fwnode, "ngpios", &pp->ngpio) && + fwnode_property_read_u32(fwnode, "snps,nr-gpios", &pp->ngpio)) { dev_info(dev, "failed to get number of gpios for port%d\n", i); - pp->ngpio = 32; + pp->ngpio = DWAPB_MAX_GPIOS; } pp->irq_shared = false; @@ -619,31 +597,66 @@ * Only port A can provide interrupts in all configurations of * the IP. */ - if (pp->idx != 0) - continue; - - if (dev->of_node && fwnode_property_read_bool(fwnode, - "interrupt-controller")) { - np = to_of_node(fwnode); - } - - for (j = 0; j < pp->ngpio; j++) { - pp->irq[j] = -ENXIO; - - if (np) - pp->irq[j] = of_irq_get(np, j); - else if (has_acpi_companion(dev)) - pp->irq[j] = platform_get_irq(to_platform_device(dev), j); - - if (pp->irq[j] >= 0) - pp->has_irq = true; - } - - if (!pp->has_irq) - dev_warn(dev, "no irq for port%d\n", pp->idx); + if (pp->idx == 0) + dwapb_get_irq(dev, fwnode, pp); } return pdata; +} + +static void dwapb_assert_reset(void *data) +{ + struct dwapb_gpio *gpio = data; + + reset_control_assert(gpio->rst); +} + +static int dwapb_get_reset(struct dwapb_gpio *gpio) +{ + int err; + + gpio->rst = devm_reset_control_get_optional_shared(gpio->dev, NULL); + if (IS_ERR(gpio->rst)) { + dev_err(gpio->dev, "Cannot get reset descriptor\n"); + return PTR_ERR(gpio->rst); + } + + err = reset_control_deassert(gpio->rst); + if (err) { + dev_err(gpio->dev, "Cannot deassert reset lane\n"); + return err; + } + + return devm_add_action_or_reset(gpio->dev, dwapb_assert_reset, gpio); +} + +static void dwapb_disable_clks(void *data) +{ + struct dwapb_gpio *gpio = data; + + clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks); +} + +static int dwapb_get_clks(struct dwapb_gpio *gpio) +{ + int err; + + /* Optional bus and debounce clocks */ + gpio->clks[0].id = "bus"; + gpio->clks[1].id = "db"; + err = devm_clk_bulk_get_optional(gpio->dev, DWAPB_NR_CLOCKS, + gpio->clks); + if (err) + return dev_err_probe(gpio->dev, err, + "Cannot get APB/Debounce clocks\n"); + + err = clk_bulk_prepare_enable(DWAPB_NR_CLOCKS, gpio->clks); + if (err) { + dev_err(gpio->dev, "Cannot enable APB/Debounce clocks\n"); + return err; + } + + return devm_add_action_or_reset(gpio->dev, dwapb_disable_clks, gpio); } static const struct of_device_id dwapb_of_match[] = { @@ -664,7 +677,6 @@ static int dwapb_gpio_probe(struct platform_device *pdev) { unsigned int i; - struct resource *res; struct dwapb_gpio *gpio; int err; struct device *dev = &pdev->dev; @@ -686,70 +698,32 @@ gpio->dev = &pdev->dev; gpio->nr_ports = pdata->nports; - gpio->rst = devm_reset_control_get_optional_shared(dev, NULL); - if (IS_ERR(gpio->rst)) - return PTR_ERR(gpio->rst); - - reset_control_deassert(gpio->rst); + err = dwapb_get_reset(gpio); + if (err) + return err; gpio->ports = devm_kcalloc(&pdev->dev, gpio->nr_ports, sizeof(*gpio->ports), GFP_KERNEL); if (!gpio->ports) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - gpio->regs = devm_ioremap_resource(&pdev->dev, res); + gpio->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(gpio->regs)) return PTR_ERR(gpio->regs); - /* Optional bus clock */ - gpio->clk = devm_clk_get(&pdev->dev, "bus"); - if (!IS_ERR(gpio->clk)) { - err = clk_prepare_enable(gpio->clk); - if (err) { - dev_info(&pdev->dev, "Cannot enable clock\n"); - return err; - } - } + err = dwapb_get_clks(gpio); + if (err) + return err; - gpio->flags = 0; - if (dev->of_node) { - gpio->flags = (uintptr_t)of_device_get_match_data(dev); - } else if (has_acpi_companion(dev)) { - const struct acpi_device_id *acpi_id; - - acpi_id = acpi_match_device(dwapb_acpi_match, dev); - if (acpi_id) { - if (acpi_id->driver_data) - gpio->flags = acpi_id->driver_data; - } - } + gpio->flags = (uintptr_t)device_get_match_data(dev); for (i = 0; i < gpio->nr_ports; i++) { err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i); if (err) - goto out_unregister; + return err; } + platform_set_drvdata(pdev, gpio); - - return 0; - -out_unregister: - dwapb_gpio_unregister(gpio); - dwapb_irq_teardown(gpio); - clk_disable_unprepare(gpio->clk); - - return err; -} - -static int dwapb_gpio_remove(struct platform_device *pdev) -{ - struct dwapb_gpio *gpio = platform_get_drvdata(pdev); - - dwapb_gpio_unregister(gpio); - dwapb_irq_teardown(gpio); - reset_control_assert(gpio->rst); - clk_disable_unprepare(gpio->clk); return 0; } @@ -757,8 +731,7 @@ #ifdef CONFIG_PM_SLEEP static int dwapb_gpio_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct dwapb_gpio *gpio = platform_get_drvdata(pdev); + struct dwapb_gpio *gpio = dev_get_drvdata(dev); struct gpio_chip *gc = &gpio->ports[0].gc; unsigned long flags; int i; @@ -768,8 +741,6 @@ unsigned int offset; unsigned int idx = gpio->ports[i].idx; struct dwapb_context *ctx = gpio->ports[i].ctx; - - BUG_ON(!ctx); offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_STRIDE; ctx->dir = dwapb_read(gpio, offset); @@ -789,35 +760,34 @@ ctx->int_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE); /* Mask out interrupts */ - dwapb_write(gpio, GPIO_INTMASK, - 0xffffffff & ~ctx->wake_en); + dwapb_write(gpio, GPIO_INTMASK, ~ctx->wake_en); } } spin_unlock_irqrestore(&gc->bgpio_lock, flags); - clk_disable_unprepare(gpio->clk); + clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks); return 0; } static int dwapb_gpio_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct dwapb_gpio *gpio = platform_get_drvdata(pdev); + struct dwapb_gpio *gpio = dev_get_drvdata(dev); struct gpio_chip *gc = &gpio->ports[0].gc; unsigned long flags; - int i; + int i, err; - if (!IS_ERR(gpio->clk)) - clk_prepare_enable(gpio->clk); + err = clk_bulk_prepare_enable(DWAPB_NR_CLOCKS, gpio->clks); + if (err) { + dev_err(gpio->dev, "Cannot reenable APB/Debounce clocks\n"); + return err; + } spin_lock_irqsave(&gc->bgpio_lock, flags); for (i = 0; i < gpio->nr_ports; i++) { unsigned int offset; unsigned int idx = gpio->ports[i].idx; struct dwapb_context *ctx = gpio->ports[i].ctx; - - BUG_ON(!ctx); offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_STRIDE; dwapb_write(gpio, offset, ctx->data); @@ -853,11 +823,10 @@ .driver = { .name = DWAPB_DRIVER_NAME, .pm = &dwapb_gpio_pm_ops, - .of_match_table = of_match_ptr(dwapb_of_match), - .acpi_match_table = ACPI_PTR(dwapb_acpi_match), + .of_match_table = dwapb_of_match, + .acpi_match_table = dwapb_acpi_match, }, .probe = dwapb_gpio_probe, - .remove = dwapb_gpio_remove, }; module_platform_driver(dwapb_gpio_driver); -- Gitblit v1.6.2