Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 1ea3438..83981ad 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -7,11 +7,15 @@
* Mika Westerberg <mika.westerberg@linux.intel.com>
*/
-#include <linux/module.h>
+#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/gpio/driver.h>
#include <linux/log2.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/time.h>
+
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
@@ -26,17 +30,16 @@
#define REVID_MASK GENMASK(31, 16)
#define PADBAR 0x00c
-#define GPI_IS 0x100
#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
@@ -48,7 +51,8 @@
#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_PMODE_GPIO 0
#define PADCFG0_GPIORXDIS BIT(9)
#define PADCFG0_GPIOTXDIS BIT(8)
#define PADCFG0_GPIORXSTATE BIT(1)
@@ -57,7 +61,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
@@ -68,7 +72,7 @@
#define PADCFG2_DEBOUNCE_SHIFT 1
#define PADCFG2_DEBOUNCE_MASK GENMASK(4, 1)
-#define DEBOUNCE_PERIOD 31250 /* ns */
+#define DEBOUNCE_PERIOD_NSEC 31250
struct intel_pad_context {
u32 padcfg0;
@@ -78,6 +82,7 @@
struct intel_community_context {
u32 *intmask;
+ u32 *hostown;
};
struct intel_pinctrl_context {
@@ -92,6 +97,7 @@
* @pctldesc: Pin controller description
* @pctldev: Pointer to the pin controller device
* @chip: GPIO chip in this pin controller
+ * @irqchip: IRQ chip in this pin controller
* @soc: SoC/PCH specific pin configuration data
* @communities: All communities in this pin controller
* @ncommunities: Number of communities in this pin controller
@@ -104,6 +110,7 @@
struct pinctrl_desc pctldesc;
struct pinctrl_dev *pctldev;
struct gpio_chip chip;
+ struct irq_chip irqchip;
const struct intel_pinctrl_soc_data *soc;
struct intel_community *communities;
size_t ncommunities;
@@ -115,7 +122,7 @@
#define padgroup_offset(g, p) ((p) - (g)->base)
static struct intel_community *intel_get_community(struct intel_pinctrl *pctrl,
- unsigned pin)
+ unsigned int pin)
{
struct intel_community *community;
int i;
@@ -133,7 +140,7 @@
static const struct intel_padgroup *
intel_community_get_padgroup(const struct intel_community *community,
- unsigned pin)
+ unsigned int pin)
{
int i;
@@ -147,11 +154,11 @@
return NULL;
}
-static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, unsigned pin,
- unsigned reg)
+static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl,
+ unsigned int pin, unsigned int reg)
{
const struct intel_community *community;
- unsigned padno;
+ unsigned int padno;
size_t nregs;
community = intel_get_community(pctrl, pin);
@@ -161,17 +168,17 @@
padno = pin_to_padno(community, pin);
nregs = (community->features & PINCTRL_FEATURE_DEBOUNCE) ? 4 : 2;
- if (reg == PADCFG2 && !(community->features & PINCTRL_FEATURE_DEBOUNCE))
+ if (reg >= nregs * 4)
return NULL;
return community->pad_regs + reg + padno * nregs * 4;
}
-static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned pin)
+static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned int pin)
{
const struct intel_community *community;
const struct intel_padgroup *padgrp;
- unsigned gpp, offset, gpp_offset;
+ unsigned int gpp, offset, gpp_offset;
void __iomem *padown;
community = intel_get_community(pctrl, pin);
@@ -192,11 +199,11 @@
return !(readl(padown) & PADOWN_MASK(gpp_offset));
}
-static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned pin)
+static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin)
{
const struct intel_community *community;
const struct intel_padgroup *padgrp;
- unsigned offset, gpp_offset;
+ unsigned int offset, gpp_offset;
void __iomem *hostown;
community = intel_get_community(pctrl, pin);
@@ -216,47 +223,71 @@
return !(readl(hostown) & BIT(gpp_offset));
}
-static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned pin)
+/**
+ * enum - Locking variants of the pad configuration
+ *
+ * @PAD_UNLOCKED: pad is fully controlled by the configuration registers
+ * @PAD_LOCKED: pad configuration registers, except TX state, are locked
+ * @PAD_LOCKED_TX: pad configuration TX state is locked
+ * @PAD_LOCKED_FULL: pad configuration registers are locked completely
+ *
+ * Locking is considered as read-only mode for corresponding registers and
+ * their respective fields. That said, TX state bit is locked separately from
+ * the main locking scheme.
+ */
+enum {
+ PAD_UNLOCKED = 0,
+ PAD_LOCKED = 1,
+ PAD_LOCKED_TX = 2,
+ PAD_LOCKED_FULL = PAD_LOCKED | PAD_LOCKED_TX,
+};
+
+static int intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin)
{
struct intel_community *community;
const struct intel_padgroup *padgrp;
- unsigned offset, gpp_offset;
+ unsigned int offset, gpp_offset;
u32 value;
+ int ret = PAD_UNLOCKED;
community = intel_get_community(pctrl, pin);
if (!community)
- return true;
+ return PAD_LOCKED_FULL;
if (!community->padcfglock_offset)
- return false;
+ return PAD_UNLOCKED;
padgrp = intel_community_get_padgroup(community, pin);
if (!padgrp)
- return true;
+ return PAD_LOCKED_FULL;
gpp_offset = padgroup_offset(padgrp, pin);
/*
* If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad,
* the pad is considered unlocked. Any other case means that it is
- * either fully or partially locked and we don't touch it.
+ * either fully or partially locked.
*/
- offset = community->padcfglock_offset + padgrp->reg_num * 8;
+ offset = community->padcfglock_offset + 0 + padgrp->reg_num * 8;
value = readl(community->regs + offset);
if (value & BIT(gpp_offset))
- return true;
+ ret |= PAD_LOCKED;
offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8;
value = readl(community->regs + offset);
if (value & BIT(gpp_offset))
- return true;
+ ret |= PAD_LOCKED_TX;
- return false;
+ return ret;
}
-static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned pin)
+static bool intel_pad_is_unlocked(struct intel_pinctrl *pctrl, unsigned int pin)
{
- return intel_pad_owned_by_host(pctrl, pin) &&
- !intel_pad_locked(pctrl, pin);
+ return (intel_pad_locked(pctrl, pin) & PAD_LOCKED) == PAD_UNLOCKED;
+}
+
+static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin)
+{
+ return intel_pad_owned_by_host(pctrl, pin) && intel_pad_is_unlocked(pctrl, pin);
}
static int intel_get_groups_count(struct pinctrl_dev *pctldev)
@@ -267,15 +298,15 @@
}
static const char *intel_get_group_name(struct pinctrl_dev *pctldev,
- unsigned group)
+ unsigned int group)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->soc->groups[group].name;
}
-static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned group,
- const unsigned **pins, unsigned *npins)
+static int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
+ const unsigned int **pins, unsigned int *npins)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -285,12 +316,13 @@
}
static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
- unsigned pin)
+ unsigned int pin)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
void __iomem *padcfg;
u32 cfg0, cfg1, mode;
- bool locked, acpi;
+ int locked;
+ bool acpi;
if (!intel_pad_owned_by_host(pctrl, pin)) {
seq_puts(s, "not available");
@@ -301,7 +333,7 @@
cfg1 = readl(intel_get_padcfg(pctrl, pin, PADCFG1));
mode = (cfg0 & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT;
- if (!mode)
+ if (mode == PADCFG0_PMODE_GPIO)
seq_puts(s, "GPIO ");
else
seq_printf(s, "mode %d ", mode);
@@ -318,11 +350,16 @@
if (locked || acpi) {
seq_puts(s, " [");
- if (locked) {
+ if (locked)
seq_puts(s, "LOCKED");
- if (acpi)
- seq_puts(s, ", ");
- }
+ if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_TX)
+ seq_puts(s, " tx");
+ else if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_FULL)
+ seq_puts(s, " full");
+
+ if (locked && acpi)
+ seq_puts(s, ", ");
+
if (acpi)
seq_puts(s, "ACPI");
seq_puts(s, "]");
@@ -344,7 +381,7 @@
}
static const char *intel_get_function_name(struct pinctrl_dev *pctldev,
- unsigned function)
+ unsigned int function)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -352,9 +389,9 @@
}
static int intel_get_function_groups(struct pinctrl_dev *pctldev,
- unsigned function,
+ unsigned int function,
const char * const **groups,
- unsigned * const ngroups)
+ unsigned int * const ngroups)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -363,8 +400,8 @@
return 0;
}
-static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
- unsigned group)
+static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int function, unsigned int group)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const struct intel_pingroup *grp = &pctrl->soc->groups[group];
@@ -422,6 +459,11 @@
writel(value, padcfg0);
}
+static int intel_gpio_get_gpio_mode(void __iomem *padcfg0)
+{
+ return (readl(padcfg0) & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT;
+}
+
static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
{
u32 value;
@@ -436,7 +478,7 @@
static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned pin)
+ unsigned int pin)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
void __iomem *padcfg0;
@@ -444,13 +486,31 @@
raw_spin_lock_irqsave(&pctrl->lock, flags);
- if (!intel_pad_usable(pctrl, pin)) {
+ if (!intel_pad_owned_by_host(pctrl, pin)) {
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return -EBUSY;
}
+ if (!intel_pad_is_unlocked(pctrl, pin)) {
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ return 0;
+ }
+
padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
+
+ /*
+ * If pin is already configured in GPIO mode, we assume that
+ * firmware provides correct settings. In such case we avoid
+ * potential glitches on the pin. Otherwise, for the pin in
+ * alternative mode, consumer has to supply respective flags.
+ */
+ if (intel_gpio_get_gpio_mode(padcfg0) == PADCFG0_PMODE_GPIO) {
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ return 0;
+ }
+
intel_gpio_set_gpio_mode(padcfg0);
+
/* Disable TX buffer and enable RX (this will be input) */
__intel_gpio_set_direction(padcfg0, true);
@@ -461,7 +521,7 @@
static int intel_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned pin, bool input)
+ unsigned int pin, bool input)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
void __iomem *padcfg0;
@@ -486,7 +546,7 @@
.gpio_set_direction = intel_gpio_set_direction,
};
-static int intel_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+static int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
@@ -562,7 +622,7 @@
return -EINVAL;
v = (v & PADCFG2_DEBOUNCE_MASK) >> PADCFG2_DEBOUNCE_SHIFT;
- arg = BIT(v) * DEBOUNCE_PERIOD / 1000;
+ arg = BIT(v) * DEBOUNCE_PERIOD_NSEC / NSEC_PER_USEC;
break;
}
@@ -575,11 +635,11 @@
return 0;
}
-static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin,
+static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
unsigned long config)
{
- unsigned param = pinconf_to_config_param(config);
- unsigned arg = pinconf_to_config_argument(config);
+ unsigned int param = pinconf_to_config_param(config);
+ unsigned int arg = pinconf_to_config_argument(config);
const struct intel_community *community;
void __iomem *padcfg1;
unsigned long flags;
@@ -653,8 +713,8 @@
return ret;
}
-static int intel_config_set_debounce(struct intel_pinctrl *pctrl, unsigned pin,
- unsigned debounce)
+static int intel_config_set_debounce(struct intel_pinctrl *pctrl,
+ unsigned int pin, unsigned int debounce)
{
void __iomem *padcfg0, *padcfg2;
unsigned long flags;
@@ -679,7 +739,7 @@
if (debounce) {
unsigned long v;
- v = order_base_2(debounce * 1000 / DEBOUNCE_PERIOD);
+ v = order_base_2(debounce * NSEC_PER_USEC / DEBOUNCE_PERIOD_NSEC);
if (v < 3 || v > 15) {
ret = -EINVAL;
goto exit_unlock;
@@ -700,8 +760,8 @@
return ret;
}
-static int intel_config_set(struct pinctrl_dev *pctldev, unsigned pin,
- unsigned long *configs, unsigned nconfigs)
+static int intel_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int nconfigs)
{
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
int i, ret;
@@ -751,14 +811,14 @@
* 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
+ * @community: 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,
+static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset,
const struct intel_community **community,
const struct intel_padgroup **padgrp)
{
@@ -792,7 +852,30 @@
return -EINVAL;
}
-static int intel_gpio_get(struct gpio_chip *chip, unsigned offset)
+/**
+ * intel_pin_to_gpio() - Translate from pin number to GPIO offset
+ * @pctrl: Pinctrl structure
+ * @pin: pin number
+ *
+ * Translate the pin number of pinctrl to GPIO offset
+ */
+static __maybe_unused int intel_pin_to_gpio(struct intel_pinctrl *pctrl, int pin)
+{
+ const struct intel_community *community;
+ const struct intel_padgroup *padgrp;
+
+ community = intel_get_community(pctrl, pin);
+ if (!community)
+ return -EINVAL;
+
+ padgrp = intel_community_get_padgroup(community, pin);
+ if (!padgrp)
+ return -EINVAL;
+
+ return pin - padgrp->base + padgrp->gpio_base;
+}
+
+static int intel_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
void __iomem *reg;
@@ -814,7 +897,8 @@
return !!(padcfg0 & PADCFG0_GPIORXSTATE);
}
-static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static void intel_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned long flags;
@@ -863,12 +947,12 @@
return !!(padcfg0 & PADCFG0_GPIOTXDIS);
}
-static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
return pinctrl_gpio_direction_input(chip->base + offset);
}
-static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
int value)
{
intel_gpio_set(chip, offset, value);
@@ -897,7 +981,7 @@
pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp);
if (pin >= 0) {
- unsigned gpp, gpp_offset, is_offset;
+ unsigned int gpp, gpp_offset, is_offset;
gpp = padgrp->reg_num;
gpp_offset = padgroup_offset(padgrp, pin);
@@ -909,35 +993,6 @@
}
}
-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 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);
@@ -948,17 +1003,22 @@
pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp);
if (pin >= 0) {
- unsigned gpp, gpp_offset;
+ 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);
@@ -979,11 +1039,11 @@
intel_gpio_irq_mask_unmask(d, false);
}
-static int intel_gpio_irq_type(struct irq_data *d, unsigned type)
+static int intel_gpio_irq_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
- unsigned pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
+ unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
unsigned long flags;
void __iomem *reg;
u32 value;
@@ -1040,7 +1100,7 @@
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
- unsigned pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
+ unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
if (on)
enable_irq_wake(pctrl->irq);
@@ -1100,17 +1160,6 @@
return ret;
}
-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,
- .irq_set_type = intel_gpio_irq_type,
- .irq_set_wake = intel_gpio_irq_wake,
- .flags = IRQCHIP_MASK_ON_SUSPEND,
-};
-
static int intel_gpio_add_pin_ranges(struct intel_pinctrl *pctrl,
const struct intel_community *community)
{
@@ -1135,7 +1184,7 @@
static unsigned intel_gpio_ngpio(const struct intel_pinctrl *pctrl)
{
const struct intel_community *community;
- unsigned ngpio = 0;
+ unsigned int ngpio = 0;
int i, j;
for (i = 0; i < pctrl->ncommunities; i++) {
@@ -1160,12 +1209,22 @@
pctrl->chip = intel_gpio_chip;
+ /* Setup GPIO chip */
pctrl->chip.ngpio = intel_gpio_ngpio(pctrl);
pctrl->chip.label = dev_name(pctrl->dev);
pctrl->chip.parent = pctrl->dev;
pctrl->chip.base = -1;
pctrl->irq = irq;
+ /* Setup IRQ chip */
+ pctrl->irqchip.name = dev_name(pctrl->dev);
+ pctrl->irqchip.irq_ack = intel_gpio_irq_ack;
+ pctrl->irqchip.irq_mask = intel_gpio_irq_mask;
+ pctrl->irqchip.irq_unmask = intel_gpio_irq_unmask;
+ pctrl->irqchip.irq_set_type = intel_gpio_irq_type;
+ pctrl->irqchip.irq_set_wake = intel_gpio_irq_wake;
+ pctrl->irqchip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl);
if (ret) {
dev_err(pctrl->dev, "failed to register gpiochip\n");
@@ -1195,15 +1254,14 @@
return ret;
}
- ret = gpiochip_irqchip_add(&pctrl->chip, &intel_gpio_irqchip, 0,
+ ret = gpiochip_irqchip_add(&pctrl->chip, &pctrl->irqchip, 0,
handle_bad_irq, IRQ_TYPE_NONE);
if (ret) {
dev_err(pctrl->dev, "failed to add irqchip\n");
return ret;
}
- gpiochip_set_chained_irqchip(&pctrl->chip, &intel_gpio_irqchip, irq,
- NULL);
+ gpiochip_set_chained_irqchip(&pctrl->chip, &pctrl->irqchip, irq, NULL);
return 0;
}
@@ -1211,8 +1269,8 @@
struct intel_community *community)
{
struct intel_padgroup *gpps;
- unsigned npins = community->npins;
- unsigned padown_num = 0;
+ unsigned int npins = community->npins;
+ unsigned int padown_num = 0;
size_t ngpps, i;
if (community->gpps)
@@ -1228,7 +1286,7 @@
if (community->gpps) {
gpps[i] = community->gpps[i];
} else {
- unsigned gpp_size = community->gpp_size;
+ unsigned int gpp_size = community->gpp_size;
gpps[i].reg_num = i;
gpps[i].base = community->pin_base + i * gpp_size;
@@ -1280,7 +1338,7 @@
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);
@@ -1288,6 +1346,13 @@
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;
@@ -1297,8 +1362,8 @@
return 0;
}
-int intel_pinctrl_probe(struct platform_device *pdev,
- const struct intel_pinctrl_soc_data *soc_data)
+static int intel_pinctrl_probe(struct platform_device *pdev,
+ const struct intel_pinctrl_soc_data *soc_data)
{
struct intel_pinctrl *pctrl;
int i, ret, irq;
@@ -1326,15 +1391,12 @@
for (i = 0; i < pctrl->ncommunities; i++) {
struct intel_community *community = &pctrl->communities[i];
- struct resource *res;
void __iomem *regs;
u32 padbar;
*community = pctrl->soc->communities[i];
- res = platform_get_resource(pdev, IORESOURCE_MEM,
- community->barno);
- regs = devm_ioremap_resource(&pdev->dev, res);
+ regs = devm_platform_ioremap_resource(pdev, community->barno);
if (IS_ERR(regs))
return PTR_ERR(regs);
@@ -1358,19 +1420,14 @@
community->regs = regs;
community->pad_regs = regs + padbar;
- if (!community->is_offset)
- community->is_offset = GPI_IS;
-
ret = intel_pinctrl_add_padgroups(pctrl, community);
if (ret)
return ret;
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get interrupt number\n");
+ if (irq < 0)
return irq;
- }
ret = intel_pinctrl_pm_init(pctrl);
if (ret)
@@ -1396,10 +1453,51 @@
return 0;
}
-EXPORT_SYMBOL_GPL(intel_pinctrl_probe);
+
+int intel_pinctrl_probe_by_hid(struct platform_device *pdev)
+{
+ const struct intel_pinctrl_soc_data *data;
+
+ data = device_get_match_data(&pdev->dev);
+ return intel_pinctrl_probe(pdev, data);
+}
+EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_hid);
+
+int intel_pinctrl_probe_by_uid(struct platform_device *pdev)
+{
+ const struct intel_pinctrl_soc_data *data = NULL;
+ const struct intel_pinctrl_soc_data **table;
+ struct acpi_device *adev;
+ unsigned int i;
+
+ adev = ACPI_COMPANION(&pdev->dev);
+ if (adev) {
+ const void *match = device_get_match_data(&pdev->dev);
+
+ table = (const struct intel_pinctrl_soc_data **)match;
+ for (i = 0; table[i]; i++) {
+ if (!strcmp(adev->pnp.unique_id, table[i]->uid)) {
+ data = table[i];
+ break;
+ }
+ }
+ } else {
+ const struct platform_device_id *id;
+
+ id = platform_get_device_id(pdev);
+ if (!id)
+ return -ENODEV;
+
+ table = (const struct intel_pinctrl_soc_data **)id->driver_data;
+ data = table[pdev->id];
+ }
+
+ return intel_pinctrl_probe(pdev, data);
+}
+EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_uid);
#ifdef CONFIG_PM_SLEEP
-static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned pin)
+static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin)
{
const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin);
@@ -1413,16 +1511,15 @@
* them alone.
*/
if (pd->mux_owner || pd->gpio_owner ||
- gpiochip_line_is_irq(&pctrl->chip, pin))
+ gpiochip_line_is_irq(&pctrl->chip, intel_pin_to_gpio(pctrl, pin)))
return true;
return false;
}
-int intel_pinctrl_suspend(struct device *dev)
+int intel_pinctrl_suspend_noirq(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct intel_pinctrl *pctrl = platform_get_drvdata(pdev);
+ struct intel_pinctrl *pctrl = dev_get_drvdata(dev);
struct intel_community_context *communities;
struct intel_pad_context *pads;
int i;
@@ -1450,16 +1547,20 @@
for (i = 0; i < pctrl->ncommunities; i++) {
struct intel_community *community = &pctrl->communities[i];
void __iomem *base;
- unsigned gpp;
+ unsigned int gpp;
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)
{
@@ -1468,7 +1569,7 @@
for (i = 0; i < pctrl->ncommunities; i++) {
const struct intel_community *community;
void __iomem *base;
- unsigned gpp;
+ unsigned int gpp;
community = &pctrl->communities[i];
base = community->regs;
@@ -1481,10 +1582,34 @@
}
}
-int intel_pinctrl_resume(struct device *dev)
+static u32
+intel_gpio_is_requested(struct gpio_chip *chip, int base, unsigned int size)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct intel_pinctrl *pctrl = platform_get_drvdata(pdev);
+ 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;
const struct intel_pad_context *pads;
int i;
@@ -1532,7 +1657,7 @@
for (i = 0; i < pctrl->ncommunities; i++) {
struct intel_community *community = &pctrl->communities[i];
void __iomem *base;
- unsigned gpp;
+ unsigned int gpp;
base = community->regs + community->ie_offset;
for (gpp = 0; gpp < community->ngpps; gpp++) {
@@ -1540,11 +1665,30 @@
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>");