diff options
Diffstat (limited to 'drivers/pinctrl/intel/pinctrl-intel.c')
| -rw-r--r-- | drivers/pinctrl/intel/pinctrl-intel.c | 88 |
1 files changed, 73 insertions, 15 deletions
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 52ecd66ce357..cc3aaba24188 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -14,12 +14,17 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> +#include <linux/seq_file.h> +#include <linux/string_helpers.h> #include <linux/time.h> -#include <linux/pinctrl/pinctrl.h> -#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> + +#include <linux/platform_data/x86/pwm-lpss.h> #include "../core.h" #include "pinctrl-intel.h" @@ -46,6 +51,8 @@ #define PADOWN_MASK(p) (GENMASK(3, 0) << PADOWN_SHIFT(p)) #define PADOWN_GPP(p) ((p) / 8) +#define PWMC 0x204 + /* Offset from pad_regs */ #define PADCFG0 0x000 #define PADCFG0_RXEVCFG_SHIFT 25 @@ -436,9 +443,14 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input) writel(value, padcfg0); } +static int __intel_gpio_get_gpio_mode(u32 value) +{ + return (value & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; +} + static int intel_gpio_get_gpio_mode(void __iomem *padcfg0) { - return (readl(padcfg0) & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; + return __intel_gpio_get_gpio_mode(readl(padcfg0)); } static void intel_gpio_set_gpio_mode(void __iomem *padcfg0) @@ -1165,7 +1177,7 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on) else disable_irq_wake(pctrl->irq); - dev_dbg(pctrl->dev, "%sable wake for pin %u\n", on ? "en" : "dis", pin); + dev_dbg(pctrl->dev, "%s wake for pin %u\n", str_enable_disable(on), pin); return 0; } @@ -1499,17 +1511,39 @@ static int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl) return 0; } +static int intel_pinctrl_probe_pwm(struct intel_pinctrl *pctrl, + struct intel_community *community) +{ + static const struct pwm_lpss_boardinfo info = { + .clk_rate = 19200000, + .npwm = 1, + .base_unit_bits = 22, + .bypass = true, + }; + struct pwm_lpss_chip *pwm; + + if (!(community->features & PINCTRL_FEATURE_PWM)) + return 0; + + if (!IS_REACHABLE(CONFIG_PWM_LPSS)) + return 0; + + pwm = devm_pwm_lpss_probe(pctrl->dev, community->regs + PWMC, &info); + return PTR_ERR_OR_ZERO(pwm); +} + static int intel_pinctrl_probe(struct platform_device *pdev, const struct intel_pinctrl_soc_data *soc_data) { + struct device *dev = &pdev->dev; struct intel_pinctrl *pctrl; int i, ret, irq; - pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); if (!pctrl) return -ENOMEM; - pctrl->dev = &pdev->dev; + pctrl->dev = dev; pctrl->soc = soc_data; raw_spin_lock_init(&pctrl->lock); @@ -1518,8 +1552,8 @@ static int intel_pinctrl_probe(struct platform_device *pdev, * to the registers. */ pctrl->ncommunities = pctrl->soc->ncommunities; - pctrl->communities = devm_kcalloc(&pdev->dev, pctrl->ncommunities, - sizeof(*pctrl->communities), GFP_KERNEL); + pctrl->communities = devm_kcalloc(dev, pctrl->ncommunities, + sizeof(*pctrl->communities), GFP_KERNEL); if (!pctrl->communities) return -ENOMEM; @@ -1570,7 +1604,7 @@ static int intel_pinctrl_probe(struct platform_device *pdev, offset = (value & CAPLIST_NEXT_MASK) >> CAPLIST_NEXT_SHIFT; } while (offset); - dev_dbg(&pdev->dev, "Community%d features: %#08x\n", i, community->features); + dev_dbg(dev, "Community%d features: %#08x\n", i, community->features); /* Read offset of the pad configuration registers */ offset = readl(regs + PADBAR); @@ -1584,6 +1618,10 @@ static int intel_pinctrl_probe(struct platform_device *pdev, ret = intel_pinctrl_add_padgroups_by_size(pctrl, community); if (ret) return ret; + + ret = intel_pinctrl_probe_pwm(pctrl, community); + if (ret) + return ret; } irq = platform_get_irq(pdev, 0); @@ -1595,14 +1633,13 @@ static int intel_pinctrl_probe(struct platform_device *pdev, return ret; pctrl->pctldesc = intel_pinctrl_desc; - pctrl->pctldesc.name = dev_name(&pdev->dev); + pctrl->pctldesc.name = dev_name(dev); pctrl->pctldesc.pins = pctrl->soc->pins; pctrl->pctldesc.npins = pctrl->soc->npins; - pctrl->pctldev = devm_pinctrl_register(&pdev->dev, &pctrl->pctldesc, - pctrl); + pctrl->pctldev = devm_pinctrl_register(dev, &pctrl->pctldesc, pctrl); if (IS_ERR(pctrl->pctldev)) { - dev_err(&pdev->dev, "failed to register pinctrl driver\n"); + dev_err(dev, "failed to register pinctrl driver\n"); return PTR_ERR(pctrl->pctldev); } @@ -1643,10 +1680,11 @@ const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_ { const struct intel_pinctrl_soc_data * const *table; const struct intel_pinctrl_soc_data *data = NULL; + struct device *dev = &pdev->dev; - table = device_get_match_data(&pdev->dev); + table = device_get_match_data(dev); if (table) { - struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); + struct acpi_device *adev = ACPI_COMPANION(dev); unsigned int i; for (i = 0; table[i]; i++) { @@ -1674,6 +1712,7 @@ EXPORT_SYMBOL_GPL(intel_pinctrl_get_soc_data); static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin) { const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin); + u32 value; if (!pd || !intel_pad_usable(pctrl, pin)) return false; @@ -1688,6 +1727,25 @@ static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int gpiochip_line_is_irq(&pctrl->chip, intel_pin_to_gpio(pctrl, pin))) return true; + /* + * The firmware on some systems may configure GPIO pins to be + * an interrupt source in so called "direct IRQ" mode. In such + * cases the GPIO controller driver has no idea if those pins + * are being used or not. At the same time, there is a known bug + * in the firmwares that don't restore the pin settings correctly + * after suspend, i.e. by an unknown reason the Rx value becomes + * inverted. + * + * Hence, let's save and restore the pins that are configured + * as GPIOs in the input mode with GPIROUTIOXAPIC bit set. + * + * See https://bugzilla.kernel.org/show_bug.cgi?id=214749. + */ + value = readl(intel_get_padcfg(pctrl, pin, PADCFG0)); + if ((value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) && + (__intel_gpio_get_gpio_mode(value) == PADCFG0_PMODE_GPIO)) + return true; + return false; } |