diff options
Diffstat (limited to 'kernel/drivers/pinctrl/sunxi/pinctrl-sunxi.c')
-rw-r--r-- | kernel/drivers/pinctrl/sunxi/pinctrl-sunxi.c | 86 |
1 files changed, 54 insertions, 32 deletions
diff --git a/kernel/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/kernel/drivers/pinctrl/sunxi/pinctrl-sunxi.c index f8e171b76..dead97dac 100644 --- a/kernel/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/kernel/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -446,16 +446,6 @@ static const struct pinmux_ops sunxi_pmx_ops = { .gpio_set_direction = sunxi_pmx_gpio_set_direction, }; -static int sunxi_pinctrl_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - return pinctrl_request_gpio(chip->base + offset); -} - -static void sunxi_pinctrl_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - pinctrl_free_gpio(chip->base + offset); -} - static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { @@ -588,7 +578,6 @@ static void sunxi_pinctrl_irq_release_resources(struct irq_data *d) static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) { struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); - struct irq_desc *desc = container_of(d, struct irq_desc, irq_data); u32 reg = sunxi_irq_cfg_reg(d->hwirq); u8 index = sunxi_irq_cfg_offset(d->hwirq); unsigned long flags; @@ -615,16 +604,15 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - if (type & IRQ_TYPE_LEVEL_MASK) { - d->chip = &sunxi_pinctrl_level_irq_chip; - desc->handle_irq = handle_fasteoi_irq; - } else { - d->chip = &sunxi_pinctrl_edge_irq_chip; - desc->handle_irq = handle_edge_irq; - } - spin_lock_irqsave(&pctl->lock, flags); + if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_level_irq_chip, + handle_fasteoi_irq, NULL); + else + irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_edge_irq_chip, + handle_edge_irq, NULL); + regval = readl(pctl->membase + reg); regval &= ~(IRQ_CFG_IRQ_MASK << index); writel(regval | (mode << index), pctl->membase + reg); @@ -685,6 +673,7 @@ static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d) } static struct irq_chip sunxi_pinctrl_edge_irq_chip = { + .name = "sunxi_pio_edge", .irq_ack = sunxi_pinctrl_irq_ack, .irq_mask = sunxi_pinctrl_irq_mask, .irq_unmask = sunxi_pinctrl_irq_unmask, @@ -695,6 +684,7 @@ static struct irq_chip sunxi_pinctrl_edge_irq_chip = { }; static struct irq_chip sunxi_pinctrl_level_irq_chip = { + .name = "sunxi_pio_level", .irq_eoi = sunxi_pinctrl_irq_ack, .irq_mask = sunxi_pinctrl_irq_mask, .irq_unmask = sunxi_pinctrl_irq_unmask, @@ -709,10 +699,42 @@ static struct irq_chip sunxi_pinctrl_level_irq_chip = { IRQCHIP_EOI_IF_HANDLED, }; -static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc) +static int sunxi_pinctrl_irq_of_xlate(struct irq_domain *d, + struct device_node *node, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) { - struct irq_chip *chip = irq_get_chip(irq); - struct sunxi_pinctrl *pctl = irq_get_handler_data(irq); + struct sunxi_pinctrl *pctl = d->host_data; + struct sunxi_desc_function *desc; + int pin, base; + + if (intsize < 3) + return -EINVAL; + + base = PINS_PER_BANK * intspec[0]; + pin = pctl->desc->pin_base + base + intspec[1]; + + desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pin, "irq"); + if (!desc) + return -EINVAL; + + *out_hwirq = desc->irqbank * PINS_PER_BANK + desc->irqnum; + *out_type = intspec[2]; + + return 0; +} + +static struct irq_domain_ops sunxi_pinctrl_irq_domain_ops = { + .xlate = sunxi_pinctrl_irq_of_xlate, +}; + +static void sunxi_pinctrl_irq_handler(struct irq_desc *desc) +{ + unsigned int irq = irq_desc_get_irq(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc); unsigned long bank, reg, val; for (bank = 0; bank < pctl->desc->irq_banks; bank++) @@ -911,9 +933,9 @@ int sunxi_pinctrl_init(struct platform_device *pdev, pctl->pctl_dev = pinctrl_register(pctrl_desc, &pdev->dev, pctl); - if (!pctl->pctl_dev) { + if (IS_ERR(pctl->pctl_dev)) { dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); - return -EINVAL; + return PTR_ERR(pctl->pctl_dev); } pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL); @@ -924,8 +946,8 @@ int sunxi_pinctrl_init(struct platform_device *pdev, last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number; pctl->chip->owner = THIS_MODULE; - pctl->chip->request = sunxi_pinctrl_gpio_request, - pctl->chip->free = sunxi_pinctrl_gpio_free, + pctl->chip->request = gpiochip_generic_request, + pctl->chip->free = gpiochip_generic_free, pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input, pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output, pctl->chip->get = sunxi_pinctrl_gpio_get, @@ -983,8 +1005,8 @@ int sunxi_pinctrl_init(struct platform_device *pdev, pctl->domain = irq_domain_add_linear(node, pctl->desc->irq_banks * IRQ_PER_BANK, - &irq_domain_simple_ops, - NULL); + &sunxi_pinctrl_irq_domain_ops, + pctl); if (!pctl->domain) { dev_err(&pdev->dev, "Couldn't register IRQ domain\n"); ret = -ENOMEM; @@ -997,7 +1019,7 @@ int sunxi_pinctrl_init(struct platform_device *pdev, irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip, handle_edge_irq); irq_set_chip_data(irqno, pctl); - }; + } for (i = 0; i < pctl->desc->irq_banks; i++) { /* Mask and clear all IRQs before registering a handler */ @@ -1005,9 +1027,9 @@ int sunxi_pinctrl_init(struct platform_device *pdev, writel(0xffffffff, pctl->membase + sunxi_irq_status_reg_from_bank(i)); - irq_set_chained_handler(pctl->irq[i], - sunxi_pinctrl_irq_handler); - irq_set_handler_data(pctl->irq[i], pctl); + irq_set_chained_handler_and_data(pctl->irq[i], + sunxi_pinctrl_irq_handler, + pctl); } dev_info(&pdev->dev, "initialized sunXi PIO driver\n"); |