|
@@ -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;
|
|
|
|
|
|
/*
|