diff options
Diffstat (limited to 'drivers/pinctrl/intel/pinctrl-intel.c')
-rw-r--r-- | drivers/pinctrl/intel/pinctrl-intel.c | 120 |
1 files changed, 84 insertions, 36 deletions
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index a18d6eefe672..1f13bcd0e4e1 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -8,12 +8,13 @@ */ #include <linux/acpi.h> -#include <linux/module.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> @@ -29,7 +30,6 @@ #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) @@ -71,7 +71,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; @@ -165,7 +165,7 @@ static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, 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; @@ -220,47 +220,71 @@ static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin) return !(readl(hostown) & BIT(gpp_offset)); } -static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int 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 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_is_unlocked(struct intel_pinctrl *pctrl, unsigned int 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_locked(pctrl, 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) @@ -294,7 +318,8 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 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"); @@ -322,11 +347,16 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 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, "]"); @@ -448,11 +478,16 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, 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); intel_gpio_set_gpio_mode(padcfg0); /* Disable TX buffer and enable RX (this will be input) */ @@ -566,7 +601,7 @@ static int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin, 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; } @@ -683,7 +718,7 @@ static int intel_config_set_debounce(struct intel_pinctrl *pctrl, 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; @@ -796,6 +831,29 @@ static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset, return -EINVAL; } +/** + * 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); @@ -1313,15 +1371,12 @@ static int intel_pinctrl_probe(struct platform_device *pdev, 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); @@ -1345,19 +1400,14 @@ static int intel_pinctrl_probe(struct platform_device *pdev, 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) @@ -1421,8 +1471,6 @@ int intel_pinctrl_probe_by_uid(struct platform_device *pdev) table = (const struct intel_pinctrl_soc_data **)id->driver_data; data = table[pdev->id]; } - if (!data) - return -ENODEV; return intel_pinctrl_probe(pdev, data); } @@ -1443,7 +1491,7 @@ static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int * 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; |