diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 12a1af45acb98557de6184e934360dc056fbc01a..4c2369a8d926cd92c1e61ec36490d282ca43490c 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -806,22 +806,63 @@ static const struct gpio_chip intel_gpio_chip = { .set_config = gpiochip_generic_config, }; +/** + * intel_gpio_to_pin() - Translate from GPIO offset to pin number + * @pctrl: Pinctrl structure + * @offset: GPIO offset from gpiolib + * @commmunity: Community is filled here if not %NULL + * @padgrp: Pad group is filled here if not %NULL + * + * When coming through gpiolib irqchip, the GPIO offset is not + * automatically translated to pinctrl pin number. This function can be + * used to find out the corresponding pinctrl pin. + */ +static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned offset, + const struct intel_community **community, + const struct intel_padgroup **padgrp) +{ + int i; + + for (i = 0; i < pctrl->ncommunities; i++) { + const struct intel_community *comm = &pctrl->communities[i]; + int j; + + for (j = 0; j < comm->ngpps; j++) { + const struct intel_padgroup *pgrp = &comm->gpps[j]; + + if (pgrp->gpio_base < 0) + continue; + + if (offset >= pgrp->gpio_base && + offset < pgrp->gpio_base + pgrp->size) { + int pin; + + pin = pgrp->base + offset - pgrp->gpio_base; + if (community) + *community = comm; + if (padgrp) + *padgrp = pgrp; + + return pin; + } + } + } + + return -EINVAL; +} + static void intel_gpio_irq_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); const struct intel_community *community; - unsigned pin = irqd_to_hwirq(d); + const struct intel_padgroup *padgrp; + int pin; - community = intel_get_community(pctrl, pin); - if (community) { - const struct intel_padgroup *padgrp; + pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); + if (pin >= 0) { unsigned gpp, gpp_offset, is_offset; - padgrp = intel_community_get_padgroup(community, pin); - if (!padgrp) - return; - gpp = padgrp->reg_num; gpp_offset = padgroup_offset(padgrp, pin); is_offset = community->is_offset + gpp * 4; @@ -837,19 +878,15 @@ static void intel_gpio_irq_enable(struct irq_data *d) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); const struct intel_community *community; - unsigned pin = irqd_to_hwirq(d); + const struct intel_padgroup *padgrp; + int pin; - community = intel_get_community(pctrl, pin); - if (community) { - const struct intel_padgroup *padgrp; + pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); + if (pin >= 0) { unsigned gpp, gpp_offset, is_offset; unsigned long flags; u32 value; - padgrp = intel_community_get_padgroup(community, pin); - if (!padgrp) - return; - gpp = padgrp->reg_num; gpp_offset = padgroup_offset(padgrp, pin); is_offset = community->is_offset + gpp * 4; @@ -870,20 +907,16 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); const struct intel_community *community; - unsigned pin = irqd_to_hwirq(d); + const struct intel_padgroup *padgrp; + int pin; - community = intel_get_community(pctrl, pin); - if (community) { - const struct intel_padgroup *padgrp; + pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); + if (pin >= 0) { unsigned gpp, gpp_offset; unsigned long flags; void __iomem *reg; u32 value; - padgrp = intel_community_get_padgroup(community, pin); - if (!padgrp) - return; - gpp = padgrp->reg_num; gpp_offset = padgroup_offset(padgrp, pin); @@ -914,7 +947,7 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); - unsigned pin = irqd_to_hwirq(d); + unsigned pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); unsigned long flags; void __iomem *reg; u32 value; @@ -969,7 +1002,7 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct intel_pinctrl *pctrl = gpiochip_get_data(gc); - unsigned pin = irqd_to_hwirq(d); + unsigned pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL); if (on) enable_irq_wake(pctrl->irq); @@ -1000,14 +1033,10 @@ static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl, pending &= enabled; for_each_set_bit(gpp_offset, &pending, padgrp->size) { - unsigned padno, irq; - - padno = padgrp->base - community->pin_base + gpp_offset; - if (padno >= community->npins) - break; + unsigned irq; irq = irq_find_mapping(gc->irq.domain, - community->pin_base + padno); + padgrp->gpio_base + gpp_offset); generic_handle_irq(irq); ret |= IRQ_HANDLED; @@ -1044,13 +1073,56 @@ static struct irq_chip intel_gpio_irqchip = { .flags = IRQCHIP_MASK_ON_SUSPEND, }; +static int intel_gpio_add_pin_ranges(struct intel_pinctrl *pctrl, + const struct intel_community *community) +{ + int ret, i; + + for (i = 0; i < community->ngpps; i++) { + const struct intel_padgroup *gpp = &community->gpps[i]; + + if (gpp->gpio_base < 0) + continue; + + ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), + gpp->gpio_base, gpp->base, + gpp->size); + if (ret) + return ret; + } + + return ret; +} + +static unsigned intel_gpio_ngpio(const struct intel_pinctrl *pctrl) +{ + const struct intel_community *community; + unsigned ngpio = 0; + int i, j; + + for (i = 0; i < pctrl->ncommunities; i++) { + community = &pctrl->communities[i]; + for (j = 0; j < community->ngpps; j++) { + const struct intel_padgroup *gpp = &community->gpps[j]; + + if (gpp->gpio_base < 0) + continue; + + if (gpp->gpio_base + gpp->size > ngpio) + ngpio = gpp->gpio_base + gpp->size; + } + } + + return ngpio; +} + static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) { - int ret; + int ret, i; pctrl->chip = intel_gpio_chip; - pctrl->chip.ngpio = pctrl->soc->npins; + pctrl->chip.ngpio = intel_gpio_ngpio(pctrl); pctrl->chip.label = dev_name(pctrl->dev); pctrl->chip.parent = pctrl->dev; pctrl->chip.base = -1; @@ -1062,11 +1134,14 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq) return ret; } - ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), - 0, 0, pctrl->soc->npins); - if (ret) { - dev_err(pctrl->dev, "failed to add GPIO pin range\n"); - return ret; + for (i = 0; i < pctrl->ncommunities; i++) { + struct intel_community *community = &pctrl->communities[i]; + + ret = intel_gpio_add_pin_ranges(pctrl, community); + if (ret) { + dev_err(pctrl->dev, "failed to add GPIO pin range\n"); + return ret; + } } /* @@ -1126,6 +1201,9 @@ static int intel_pinctrl_add_padgroups(struct intel_pinctrl *pctrl, if (gpps[i].size > 32) return -EINVAL; + if (!gpps[i].gpio_base) + gpps[i].gpio_base = gpps[i].base; + gpps[i].padown_num = padown_num; /* diff --git a/drivers/pinctrl/intel/pinctrl-intel.h b/drivers/pinctrl/intel/pinctrl-intel.h index 13b0bd6eb2a25441b1a29d9ff87931351f1125ce..98fdf9adf6236a1fcdebf1f24c26ced8aec65700 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.h +++ b/drivers/pinctrl/intel/pinctrl-intel.h @@ -51,6 +51,8 @@ struct intel_function { * @reg_num: GPI_IS register number * @base: Starting pin of this group * @size: Size of this group (maximum is 32). + * @gpio_base: Starting GPIO base of this group (%0 if matches with @base, + * and %-1 if no GPIO mapping should be created) * @padown_num: PAD_OWN register number (assigned by the core driver) * * If pad groups of a community are not the same size, use this structure @@ -60,6 +62,7 @@ struct intel_padgroup { unsigned reg_num; unsigned base; unsigned size; + int gpio_base; unsigned padown_num; };