diff options
Diffstat (limited to 'drivers/pinctrl/intel/pinctrl-intel.c')
-rw-r--r-- | drivers/pinctrl/intel/pinctrl-intel.c | 111 |
1 files changed, 71 insertions, 40 deletions
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 3b1818184207..a18d6eefe672 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -33,13 +33,13 @@ #define PADOWN_BITS 4 #define PADOWN_SHIFT(p) ((p) % 8 * PADOWN_BITS) -#define PADOWN_MASK(p) (0xf << PADOWN_SHIFT(p)) +#define PADOWN_MASK(p) (GENMASK(3, 0) << PADOWN_SHIFT(p)) #define PADOWN_GPP(p) ((p) / 8) /* Offset from pad_regs */ #define PADCFG0 0x000 #define PADCFG0_RXEVCFG_SHIFT 25 -#define PADCFG0_RXEVCFG_MASK (3 << PADCFG0_RXEVCFG_SHIFT) +#define PADCFG0_RXEVCFG_MASK GENMASK(26, 25) #define PADCFG0_RXEVCFG_LEVEL 0 #define PADCFG0_RXEVCFG_EDGE 1 #define PADCFG0_RXEVCFG_DISABLED 2 @@ -51,7 +51,7 @@ #define PADCFG0_GPIROUTSMI BIT(18) #define PADCFG0_GPIROUTNMI BIT(17) #define PADCFG0_PMODE_SHIFT 10 -#define PADCFG0_PMODE_MASK (0xf << PADCFG0_PMODE_SHIFT) +#define PADCFG0_PMODE_MASK GENMASK(13, 10) #define PADCFG0_GPIORXDIS BIT(9) #define PADCFG0_GPIOTXDIS BIT(8) #define PADCFG0_GPIORXSTATE BIT(1) @@ -60,7 +60,7 @@ #define PADCFG1 0x004 #define PADCFG1_TERM_UP BIT(13) #define PADCFG1_TERM_SHIFT 10 -#define PADCFG1_TERM_MASK (7 << PADCFG1_TERM_SHIFT) +#define PADCFG1_TERM_MASK GENMASK(12, 10) #define PADCFG1_TERM_20K 4 #define PADCFG1_TERM_2K 3 #define PADCFG1_TERM_5K 2 @@ -81,6 +81,7 @@ struct intel_pad_context { struct intel_community_context { u32 *intmask; + u32 *hostown; }; struct intel_pinctrl_context { @@ -913,35 +914,6 @@ static void intel_gpio_irq_ack(struct irq_data *d) } } -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; - const struct intel_padgroup *padgrp; - int pin; - - pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp); - if (pin >= 0) { - unsigned int gpp, gpp_offset, is_offset; - unsigned long flags; - u32 value; - - gpp = padgrp->reg_num; - gpp_offset = padgroup_offset(padgrp, pin); - is_offset = community->is_offset + gpp * 4; - - raw_spin_lock_irqsave(&pctrl->lock, flags); - /* Clear interrupt status first to avoid unexpected interrupt */ - writel(BIT(gpp_offset), community->regs + is_offset); - - value = readl(community->regs + community->ie_offset + gpp * 4); - value |= BIT(gpp_offset); - writel(value, community->regs + community->ie_offset + gpp * 4); - raw_spin_unlock_irqrestore(&pctrl->lock, flags); - } -} - static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); @@ -954,15 +926,20 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask) if (pin >= 0) { unsigned int gpp, gpp_offset; unsigned long flags; - void __iomem *reg; + void __iomem *reg, *is; u32 value; gpp = padgrp->reg_num; gpp_offset = padgroup_offset(padgrp, pin); reg = community->regs + community->ie_offset + gpp * 4; + is = community->regs + community->is_offset + gpp * 4; raw_spin_lock_irqsave(&pctrl->lock, flags); + + /* Clear interrupt status first to avoid unexpected interrupt */ + writel(BIT(gpp_offset), is); + value = readl(reg); if (mask) value &= ~BIT(gpp_offset); @@ -1106,7 +1083,6 @@ static irqreturn_t intel_gpio_irq(int irq, void *data) static struct irq_chip intel_gpio_irqchip = { .name = "intel-gpio", - .irq_enable = intel_gpio_irq_enable, .irq_ack = intel_gpio_irq_ack, .irq_mask = intel_gpio_irq_mask, .irq_unmask = intel_gpio_irq_unmask, @@ -1284,7 +1260,7 @@ static int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl) for (i = 0; i < pctrl->ncommunities; i++) { struct intel_community *community = &pctrl->communities[i]; - u32 *intmask; + u32 *intmask, *hostown; intmask = devm_kcalloc(pctrl->dev, community->ngpps, sizeof(*intmask), GFP_KERNEL); @@ -1292,6 +1268,13 @@ static int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl) return -ENOMEM; communities[i].intmask = intmask; + + hostown = devm_kcalloc(pctrl->dev, community->ngpps, + sizeof(*hostown), GFP_KERNEL); + if (!hostown) + return -ENOMEM; + + communities[i].hostown = hostown; } pctrl->context.pads = pads; @@ -1466,7 +1449,7 @@ static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int return false; } -int intel_pinctrl_suspend(struct device *dev) +int intel_pinctrl_suspend_noirq(struct device *dev) { struct intel_pinctrl *pctrl = dev_get_drvdata(dev); struct intel_community_context *communities; @@ -1501,11 +1484,15 @@ int intel_pinctrl_suspend(struct device *dev) base = community->regs + community->ie_offset; for (gpp = 0; gpp < community->ngpps; gpp++) communities[i].intmask[gpp] = readl(base + gpp * 4); + + base = community->regs + community->hostown_offset; + for (gpp = 0; gpp < community->ngpps; gpp++) + communities[i].hostown[gpp] = readl(base + gpp * 4); } return 0; } -EXPORT_SYMBOL_GPL(intel_pinctrl_suspend); +EXPORT_SYMBOL_GPL(intel_pinctrl_suspend_noirq); static void intel_gpio_irq_init(struct intel_pinctrl *pctrl) { @@ -1527,7 +1514,32 @@ static void intel_gpio_irq_init(struct intel_pinctrl *pctrl) } } -int intel_pinctrl_resume(struct device *dev) +static u32 +intel_gpio_is_requested(struct gpio_chip *chip, int base, unsigned int size) +{ + u32 requested = 0; + unsigned int i; + + for (i = 0; i < size; i++) + if (gpiochip_is_requested(chip, base + i)) + requested |= BIT(i); + + return requested; +} + +static u32 +intel_gpio_update_pad_mode(void __iomem *hostown, u32 mask, u32 value) +{ + u32 curr, updated; + + curr = readl(hostown); + updated = (curr & ~mask) | (value & mask); + writel(updated, hostown); + + return curr; +} + +int intel_pinctrl_resume_noirq(struct device *dev) { struct intel_pinctrl *pctrl = dev_get_drvdata(dev); const struct intel_community_context *communities; @@ -1585,11 +1597,30 @@ int intel_pinctrl_resume(struct device *dev) dev_dbg(dev, "restored mask %d/%u %#08x\n", i, gpp, readl(base + gpp * 4)); } + + base = community->regs + community->hostown_offset; + for (gpp = 0; gpp < community->ngpps; gpp++) { + const struct intel_padgroup *padgrp = &community->gpps[gpp]; + u32 requested = 0, value = 0; + u32 saved = communities[i].hostown[gpp]; + + if (padgrp->gpio_base < 0) + continue; + + requested = intel_gpio_is_requested(&pctrl->chip, + padgrp->gpio_base, padgrp->size); + value = intel_gpio_update_pad_mode(base + gpp * 4, + requested, saved); + if ((value ^ saved) & requested) { + dev_warn(dev, "restore hostown %d/%u %#8x->%#8x\n", + i, gpp, value, saved); + } + } } return 0; } -EXPORT_SYMBOL_GPL(intel_pinctrl_resume); +EXPORT_SYMBOL_GPL(intel_pinctrl_resume_noirq); #endif MODULE_AUTHOR("Mathias Nyman <mathias.nyman@linux.intel.com>"); |