Merge tag 'pinctrl-v3.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 8 Aug 2014 00:20:53 +0000 (17:20 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 8 Aug 2014 00:20:53 +0000 (17:20 -0700)
Pull pinctrl updates from Linus Walleij:
 "This is the bulk pin control changes for the v3.17 merge development
  cycle:

   - get rid of the .disable() callback from the driver callback vtable.

     This callback was abused and counterintuitive since a pin or group
     of pins can be said to always be in some setting, and never really
     disabled.  We now only enable a certain muxing, and move between
     some certain muxings, we never "disable" a mux setting

   - some janitorial moving the MSM, Samsung and Nomadik and drivers to
     their own subdirectories for a clearer view in the subsystem.  This
     will continue

   - kill off the use of the return value from gpiochip_remove(), this
     will be done in parallel in the GPIO subsystem and hopefully not
     trigger too many unchecked return value warnings before we get rid
     of this altogether

   - a huge set of changes and improvements to the Allwinner sunxi
     drivers especially for their latest A23 and A31 SoCs, and some
     ground work for the new sun8i platform family

   - a large set of Rockchip driver improvements adding support for the
     RK3288 SoC

   - advances in migration of older Freescale platforms to pin control,
     especially i.MX1

   - Samsung and Exynos improvements

   - support for the Qualcomm MSM8960 SoC

   - use the gpiolib irqchip helpers for the ST SPEAr and Intel Baytrail
     drivers

   - a bunch of nice janitorial work done with cppcheck"

* tag 'pinctrl-v3.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (61 commits)
  pinctrl: baytrail: Convert to use gpiolib irqchip
  pinctrl: sunxi: number gpio ranges starting from 0
  pinctrl: sunxi: use gpiolib API to mark a GPIO used as an IRQ
  pinctrl: rockchip: add drive-strength control for rk3288
  pinctrl: rockchip: add separate type for rk3288
  pinctrl: rockchip: set is_generic in pinconf_ops
  pinctrl: msm: drop negativity check on unsigned value
  pinctrl: remove all usage of gpio_remove ret val in driver/pinctl
  pinctrl: qcom: Make muxing of gpio function explicit
  pinctrl: nomadik: move all Nomadik drivers to subdir
  pinctrl: samsung: Group all drivers in a sub-dir
  sh-pfc: sh73a0: Introduce the use of devm_regulator_register
  sh-pfc: Add renesas,pfc-r8a7791 to binding documentation
  pinctrl: msm: move all qualcomm drivers to subdir
  pinctrl: msm: Add msm8960 definitions
  pinctrl: samsung: Allow pin value to be initialized using pinfunc
  pinctrl: samsung: Allow grouping multiple pinmux/pinconf nodes
  pinctrl: exynos: Consolidate irq_chips of GPIO and WKUP EINTs
  pinctrl: samsung: Handle GPIO request and free using pinctrl helpers
  pinctrl: samsung: Decouple direction setting from pinctrl
  ...

1  2 
drivers/pinctrl/pinctrl-st.c
drivers/pinctrl/sunxi/pinctrl-sunxi.c

index 9f43916637ca251372fb57efc32bdd82dde4eef1,d0fb44a095e94489c46ac43d1438fd3cdb410d0d..5475374d803fd69bf43c44ad2f8087ad858d92e8
@@@ -930,11 -930,6 +930,6 @@@ static int st_pmx_enable(struct pinctrl
        return 0;
  }
  
- static void st_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
-               unsigned group)
- {
- }
  static int st_pmx_set_gpio_direction(struct pinctrl_dev *pctldev,
                        struct pinctrl_gpio_range *range, unsigned gpio,
                        bool input)
@@@ -957,7 -952,6 +952,6 @@@ static struct pinmux_ops st_pmxops = 
        .get_function_name      = st_pmx_get_fname,
        .get_function_groups    = st_pmx_get_groups,
        .enable                 = st_pmx_enable,
-       .disable                = st_pmx_disable,
        .gpio_set_direction     = st_pmx_set_gpio_direction,
  };
  
@@@ -1178,9 -1172,7 +1172,7 @@@ static int st_pctl_dt_parse_groups(stru
        const __be32 *list;
        struct property *pp;
        struct st_pinconf *conf;
-       phandle phandle;
        struct device_node *pins;
-       u32 pin;
        int i = 0, npins = 0, nr_props;
  
        pins = of_get_child_by_name(np, "st,pins");
                conf = &grp->pin_conf[i];
  
                /* bank & offset */
-               phandle = be32_to_cpup(list++);
-               pin = be32_to_cpup(list++);
+               be32_to_cpup(list++);
+               be32_to_cpup(list++);
                conf->pin = of_get_named_gpio(pins, pp->name, 0);
                conf->name = pp->name;
                grp->pins[i] = conf->pin;
@@@ -1256,7 -1248,7 +1248,7 @@@ static int st_pctl_parse_functions(stru
        func = &info->functions[index];
        func->name = np->name;
        func->ngroups = of_get_child_count(np);
-       if (func->ngroups <= 0) {
+       if (func->ngroups == 0) {
                dev_err(info->dev, "No groups defined\n");
                return -EINVAL;
        }
@@@ -1431,7 -1423,7 +1423,7 @@@ static void st_gpio_irqmux_handler(unsi
  
        status = readl(info->irqmux_base);
  
 -      for_each_set_bit(n, &status, ST_GPIO_PINS_PER_BANK)
 +      for_each_set_bit(n, &status, info->nbanks)
                __gpio_irq_handler(&info->banks[n]);
  
        chained_irq_exit(chip, desc);
@@@ -1454,6 -1446,7 +1446,7 @@@ static struct irq_chip st_gpio_irqchip 
        .irq_mask       = st_gpio_irq_mask,
        .irq_unmask     = st_gpio_irq_unmask,
        .irq_set_type   = st_gpio_irq_set_type,
+       .flags          = IRQCHIP_SKIP_SET_WAKE,
  };
  
  static int st_gpiolib_register_bank(struct st_pinctrl *info,
index 5f38c7f67834d1cf8bd8bcc2f8d80cd03a76c04a,b24b5ecbe290187b88fb0463e19f84fbec1e9870..3df66e366c8775b25768e079d4febb91c8461b4a
@@@ -31,6 -31,9 +31,9 @@@
  #include "../core.h"
  #include "pinctrl-sunxi.h"
  
+ static struct irq_chip sunxi_pinctrl_edge_irq_chip;
+ static struct irq_chip sunxi_pinctrl_level_irq_chip;
  static struct sunxi_pinctrl_group *
  sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
  {
@@@ -211,10 -214,6 +214,10 @@@ static int sunxi_pctrl_dt_node_to_map(s
                        configlen++;
  
                pinconfig = kzalloc(configlen * sizeof(*pinconfig), GFP_KERNEL);
 +              if (!pinconfig) {
 +                      kfree(*map);
 +                      return -ENOMEM;
 +              }
  
                if (!of_property_read_u32(node, "allwinner,drive", &val)) {
                        u16 strength = (val + 1) * 10;
@@@ -508,7 -507,7 +511,7 @@@ static int sunxi_pinctrl_gpio_of_xlate(
        base = PINS_PER_BANK * gpiospec->args[0];
        pin = base + gpiospec->args[1];
  
-       if (pin > (gc->base + gc->ngpio))
+       if (pin > gc->ngpio)
                return -EINVAL;
  
        if (flags)
@@@ -521,25 -520,61 +524,61 @@@ static int sunxi_pinctrl_gpio_to_irq(st
  {
        struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
        struct sunxi_desc_function *desc;
+       unsigned pinnum = pctl->desc->pin_base + offset;
+       unsigned irqnum;
  
        if (offset >= chip->ngpio)
                return -ENXIO;
  
-       desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, "irq");
+       desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pinnum, "irq");
        if (!desc)
                return -EINVAL;
  
+       irqnum = desc->irqbank * IRQ_PER_BANK + desc->irqnum;
        dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
-               chip->label, offset + chip->base, desc->irqnum);
+               chip->label, offset + chip->base, irqnum);
  
-       return irq_find_mapping(pctl->domain, desc->irqnum);
+       return irq_find_mapping(pctl->domain, irqnum);
  }
  
+ static int sunxi_pinctrl_irq_request_resources(struct irq_data *d)
+ {
+       struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+       struct sunxi_desc_function *func;
+       int ret;
+       func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
+                                       pctl->irq_array[d->hwirq], "irq");
+       if (!func)
+               return -EINVAL;
+       ret = gpio_lock_as_irq(pctl->chip,
+                       pctl->irq_array[d->hwirq] - pctl->desc->pin_base);
+       if (ret) {
+               dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n",
+                       irqd_to_hwirq(d));
+               return ret;
+       }
+       /* Change muxing to INT mode */
+       sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
  
- static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
-                                     unsigned int type)
+       return 0;
+ }
+ static void sunxi_pinctrl_irq_release_resources(struct irq_data *d)
+ {
+       struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+       gpio_unlock_as_irq(pctl->chip,
+                          pctl->irq_array[d->hwirq] - pctl->desc->pin_base);
+ }
+ 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;
                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);
  
        regval = readl(pctl->membase + reg);
        return 0;
  }
  
- static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d)
+ static void sunxi_pinctrl_irq_ack(struct irq_data *d)
  {
        struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       u32 ctrl_reg = sunxi_irq_ctrl_reg(d->hwirq);
-       u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq);
        u32 status_reg = sunxi_irq_status_reg(d->hwirq);
        u8 status_idx = sunxi_irq_status_offset(d->hwirq);
-       unsigned long flags;
-       u32 val;
-       spin_lock_irqsave(&pctl->lock, flags);
-       /* Mask the IRQ */
-       val = readl(pctl->membase + ctrl_reg);
-       writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg);
  
        /* Clear the IRQ */
        writel(1 << status_idx, pctl->membase + status_reg);
-       spin_unlock_irqrestore(&pctl->lock, flags);
  }
  
  static void sunxi_pinctrl_irq_mask(struct irq_data *d)
  static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
  {
        struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       struct sunxi_desc_function *func;
        u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
        u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
        unsigned long flags;
        u32 val;
  
-       func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
-                                                      pctl->irq_array[d->hwirq],
-                                                      "irq");
-       /* Change muxing to INT mode */
-       sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
        spin_lock_irqsave(&pctl->lock, flags);
  
        /* Unmask the IRQ */
        spin_unlock_irqrestore(&pctl->lock, flags);
  }
  
- static struct irq_chip sunxi_pinctrl_irq_chip = {
+ static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d)
+ {
+       sunxi_pinctrl_irq_ack(d);
+       sunxi_pinctrl_irq_unmask(d);
+ }
+ static struct irq_chip sunxi_pinctrl_edge_irq_chip = {
+       .irq_ack        = sunxi_pinctrl_irq_ack,
+       .irq_mask       = sunxi_pinctrl_irq_mask,
+       .irq_unmask     = sunxi_pinctrl_irq_unmask,
+       .irq_request_resources = sunxi_pinctrl_irq_request_resources,
+       .irq_release_resources = sunxi_pinctrl_irq_release_resources,
+       .irq_set_type   = sunxi_pinctrl_irq_set_type,
+       .flags          = IRQCHIP_SKIP_SET_WAKE,
+ };
+ static struct irq_chip sunxi_pinctrl_level_irq_chip = {
+       .irq_eoi        = sunxi_pinctrl_irq_ack,
        .irq_mask       = sunxi_pinctrl_irq_mask,
-       .irq_mask_ack   = sunxi_pinctrl_irq_mask_ack,
        .irq_unmask     = sunxi_pinctrl_irq_unmask,
+       /* Define irq_enable / disable to avoid spurious irqs for drivers
+        * using these to suppress irqs while they clear the irq source */
+       .irq_enable     = sunxi_pinctrl_irq_ack_unmask,
+       .irq_disable    = sunxi_pinctrl_irq_mask,
+       .irq_request_resources = sunxi_pinctrl_irq_request_resources,
+       .irq_release_resources = sunxi_pinctrl_irq_release_resources,
        .irq_set_type   = sunxi_pinctrl_irq_set_type,
+       .flags          = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_EOI_THREADED |
+                         IRQCHIP_EOI_IF_HANDLED,
  };
  
  static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
  {
        struct irq_chip *chip = irq_get_chip(irq);
        struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
-       const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
+       unsigned long bank, reg, val;
+       for (bank = 0; bank < pctl->desc->irq_banks; bank++)
+               if (irq == pctl->irq[bank])
+                       break;
+       if (bank == pctl->desc->irq_banks)
+               return;
  
-       /* Clear all interrupts */
-       writel(reg, pctl->membase + IRQ_STATUS_REG);
+       reg = sunxi_irq_status_reg_from_bank(bank);
+       val = readl(pctl->membase + reg);
  
-       if (reg) {
+       if (val) {
                int irqoffset;
  
                chained_irq_enter(chip, desc);
-               for_each_set_bit(irqoffset, &reg, SUNXI_IRQ_NUMBER) {
-                       int pin_irq = irq_find_mapping(pctl->domain, irqoffset);
+               for_each_set_bit(irqoffset, &val, IRQ_PER_BANK) {
+                       int pin_irq = irq_find_mapping(pctl->domain,
+                                                      bank * IRQ_PER_BANK + irqoffset);
                        generic_handle_irq(pin_irq);
                }
                chained_irq_exit(chip, desc);
@@@ -730,8 -785,11 +789,11 @@@ static int sunxi_pinctrl_build_state(st
  
                while (func->name) {
                        /* Create interrupt mapping while we're at it */
-                       if (!strcmp(func->name, "irq"))
-                               pctl->irq_array[func->irqnum] = pin->pin.number;
+                       if (!strcmp(func->name, "irq")) {
+                               int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK;
+                               pctl->irq_array[irqnum] = pin->pin.number;
+                       }
                        sunxi_pinctrl_add_function(pctl, func->name);
                        func++;
                }
@@@ -801,6 -859,13 +863,13 @@@ int sunxi_pinctrl_init(struct platform_
        pctl->dev = &pdev->dev;
        pctl->desc = desc;
  
+       pctl->irq_array = devm_kcalloc(&pdev->dev,
+                                      IRQ_PER_BANK * pctl->desc->irq_banks,
+                                      sizeof(*pctl->irq_array),
+                                      GFP_KERNEL);
+       if (!pctl->irq_array)
+               return -ENOMEM;
        ret = sunxi_pinctrl_build_state(pdev);
        if (ret) {
                dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
                const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
  
                ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),
-                                            pin->pin.number,
+                                            pin->pin.number - pctl->desc->pin_base,
                                             pin->pin.number, 1);
                if (ret)
                        goto gpiochip_error;
        if (ret)
                goto gpiochip_error;
  
-       pctl->irq = irq_of_parse_and_map(node, 0);
+       pctl->irq = devm_kcalloc(&pdev->dev,
+                                pctl->desc->irq_banks,
+                                sizeof(*pctl->irq),
+                                GFP_KERNEL);
        if (!pctl->irq) {
-               ret = -EINVAL;
+               ret = -ENOMEM;
                goto clk_error;
        }
  
-       pctl->domain = irq_domain_add_linear(node, SUNXI_IRQ_NUMBER,
-                                            &irq_domain_simple_ops, NULL);
+       for (i = 0; i < pctl->desc->irq_banks; i++) {
+               pctl->irq[i] = platform_get_irq(pdev, i);
+               if (pctl->irq[i] < 0) {
+                       ret = pctl->irq[i];
+                       goto clk_error;
+               }
+       }
+       pctl->domain = irq_domain_add_linear(node,
+                                            pctl->desc->irq_banks * IRQ_PER_BANK,
+                                            &irq_domain_simple_ops,
+                                            NULL);
        if (!pctl->domain) {
                dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
                ret = -ENOMEM;
                goto clk_error;
        }
  
-       for (i = 0; i < SUNXI_IRQ_NUMBER; i++) {
+       for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) {
                int irqno = irq_create_mapping(pctl->domain, i);
  
-               irq_set_chip_and_handler(irqno, &sunxi_pinctrl_irq_chip,
-                                        handle_simple_irq);
+               irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip,
+                                        handle_edge_irq);
                irq_set_chip_data(irqno, pctl);
        };
  
-       irq_set_chained_handler(pctl->irq, sunxi_pinctrl_irq_handler);
-       irq_set_handler_data(pctl->irq, pctl);
+       for (i = 0; i < pctl->desc->irq_banks; i++) {
+               /* Mask and clear all IRQs before registering a handler */
+               writel(0, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i));
+               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);
+       }
  
        dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
  
  clk_error:
        clk_disable_unprepare(clk);
  gpiochip_error:
-       if (gpiochip_remove(pctl->chip))
-               dev_err(&pdev->dev, "failed to remove gpio chip\n");
+       gpiochip_remove(pctl->chip);
  pinctrl_error:
        pinctrl_unregister(pctl->pctl_dev);
        return ret;
This page took 0.035966 seconds and 5 git commands to generate.