aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pinctrl/intel/pinctrl-cherryview.c34
1 files changed, 33 insertions, 1 deletions
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 0fe8fad25e4d..d23be3a2fb35 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -134,6 +134,7 @@ struct chv_gpio_pinrange {
* @gpio_ranges: An array of GPIO ranges in this community
* @ngpio_ranges: Number of GPIO ranges
* @ngpios: Total number of GPIOs in this community
+ * @nirqs: Total number of IRQs this community can generate
*/
struct chv_community {
const char *uid;
@@ -146,6 +147,7 @@ struct chv_community {
const struct chv_gpio_pinrange *gpio_ranges;
size_t ngpio_ranges;
size_t ngpios;
+ size_t nirqs;
};
struct chv_pin_context {
@@ -396,6 +398,12 @@ static const struct chv_community southwest_community = {
.gpio_ranges = southwest_gpio_ranges,
.ngpio_ranges = ARRAY_SIZE(southwest_gpio_ranges),
.ngpios = ARRAY_SIZE(southwest_pins),
+ /*
+ * Southwest community can benerate GPIO interrupts only for the
+ * first 8 interrupts. The upper half (8-15) can only be used to
+ * trigger GPEs.
+ */
+ .nirqs = 8,
};
static const struct pinctrl_pin_desc north_pins[] = {
@@ -479,6 +487,12 @@ static const struct chv_community north_community = {
.gpio_ranges = north_gpio_ranges,
.ngpio_ranges = ARRAY_SIZE(north_gpio_ranges),
.ngpios = ARRAY_SIZE(north_pins),
+ /*
+ * North community can benerate GPIO interrupts only for the first
+ * 8 interrupts. The upper half (8-15) can only be used to trigger
+ * GPEs.
+ */
+ .nirqs = 8,
};
static const struct pinctrl_pin_desc east_pins[] = {
@@ -521,6 +535,7 @@ static const struct chv_community east_community = {
.gpio_ranges = east_gpio_ranges,
.ngpio_ranges = ARRAY_SIZE(east_gpio_ranges),
.ngpios = ARRAY_SIZE(east_pins),
+ .nirqs = 16,
};
static const struct pinctrl_pin_desc southeast_pins[] = {
@@ -646,6 +661,7 @@ static const struct chv_community southeast_community = {
.gpio_ranges = southeast_gpio_ranges,
.ngpio_ranges = ARRAY_SIZE(southeast_gpio_ranges),
.ngpios = ARRAY_SIZE(southeast_pins),
+ .nirqs = 16,
};
static const struct chv_community *chv_communities[] = {
@@ -1497,7 +1513,7 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
chained_irq_enter(chip, desc);
pending = readl(pctrl->regs + CHV_INTSTAT);
- for_each_set_bit(intr_line, &pending, 16) {
+ for_each_set_bit(intr_line, &pending, pctrl->community->nirqs) {
unsigned irq, offset;
offset = pctrl->intr_lines[intr_line];
@@ -1520,6 +1536,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
chip->label = dev_name(pctrl->dev);
chip->parent = pctrl->dev;
chip->base = -1;
+ chip->irq_need_valid_mask = true;
ret = gpiochip_add_data(chip, pctrl);
if (ret) {
@@ -1539,6 +1556,21 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
offset += range->npins;
}
+ /* Do not add GPIOs that can only generate GPEs to the IRQ domain */
+ for (i = 0; i < pctrl->community->npins; i++) {
+ const struct pinctrl_pin_desc *desc;
+ u32 intsel;
+
+ desc = &pctrl->community->pins[i];
+
+ intsel = readl(chv_padreg(pctrl, desc->number, CHV_PADCTRL0));
+ intsel &= CHV_PADCTRL0_INTSEL_MASK;
+ intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
+
+ if (intsel >= pctrl->community->nirqs)
+ clear_bit(i, chip->irq_valid_mask);
+ }
+
/* Clear all interrupts */
chv_writel(0xffff, pctrl->regs + CHV_INTSTAT);