From: Linus Torvalds Date: Fri, 8 Aug 2014 00:20:53 +0000 (-0700) Subject: Merge tag 'pinctrl-v3.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw... X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=e0b8b78651350e8dcf9cc60a959ccbcfc5bc3061;hp=-c;p=deliverable%2Flinux.git Merge tag 'pinctrl-v3.17-1' of git://git./linux/kernel/git/linusw/linux-pinctrl 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 ... --- e0b8b78651350e8dcf9cc60a959ccbcfc5bc3061 diff --combined drivers/pinctrl/pinctrl-st.c index 9f43916637ca,d0fb44a095e9..5475374d803f --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@@ -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"); @@@ -1218,8 -1210,8 +1210,8 @@@ 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, diff --combined drivers/pinctrl/sunxi/pinctrl-sunxi.c index 5f38c7f67834,b24b5ecbe290..3df66e366c87 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@@ -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; @@@ -566,6 -601,14 +605,14 @@@ 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); @@@ -577,26 -620,14 +624,14 @@@ 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) @@@ -619,19 -650,11 +654,11 @@@ 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 */ @@@ -641,28 -664,60 +668,60 @@@ 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, ®, 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); @@@ -869,7 -934,7 +938,7 @@@ 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; @@@ -885,30 -950,51 +954,51 @@@ 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"); @@@ -917,8 -1003,7 +1007,7 @@@ 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;