diff options
Diffstat (limited to 'drivers/pinctrl/intel/pinctrl-cherryview.c')
| -rw-r--r-- | drivers/pinctrl/intel/pinctrl-cherryview.c | 97 |
1 files changed, 91 insertions, 6 deletions
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index bf65c948b..bc3150428 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1108,6 +1108,27 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin, return 0; } +static int chv_config_set_oden(struct chv_pinctrl *pctrl, unsigned int pin, + bool enable) +{ + void __iomem *reg = chv_padreg(pctrl, pin, CHV_PADCTRL1); + unsigned long flags; + u32 ctrl1; + + raw_spin_lock_irqsave(&chv_lock, flags); + ctrl1 = readl(reg); + + if (enable) + ctrl1 |= CHV_PADCTRL1_ODEN; + else + ctrl1 &= ~CHV_PADCTRL1_ODEN; + + chv_writel(ctrl1, reg); + raw_spin_unlock_irqrestore(&chv_lock, flags); + + return 0; +} + static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs, unsigned nconfigs) { @@ -1132,6 +1153,18 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin, return ret; break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + ret = chv_config_set_oden(pctrl, pin, false); + if (ret) + return ret; + break; + + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + ret = chv_config_set_oden(pctrl, pin, true); + if (ret) + return ret; + break; + default: return -ENOTSUPP; } @@ -1143,10 +1176,52 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin, return 0; } +static int chv_config_group_get(struct pinctrl_dev *pctldev, + unsigned int group, + unsigned long *config) +{ + const unsigned int *pins; + unsigned int npins; + int ret; + + ret = chv_get_group_pins(pctldev, group, &pins, &npins); + if (ret) + return ret; + + ret = chv_config_get(pctldev, pins[0], config); + if (ret) + return ret; + + return 0; +} + +static int chv_config_group_set(struct pinctrl_dev *pctldev, + unsigned int group, unsigned long *configs, + unsigned int num_configs) +{ + const unsigned int *pins; + unsigned int npins; + int i, ret; + + ret = chv_get_group_pins(pctldev, group, &pins, &npins); + if (ret) + return ret; + + for (i = 0; i < npins; i++) { + ret = chv_config_set(pctldev, pins[i], configs, num_configs); + if (ret) + return ret; + } + + return 0; +} + static const struct pinconf_ops chv_pinconf_ops = { .is_generic = true, .pin_config_set = chv_config_set, .pin_config_get = chv_config_get, + .pin_config_group_get = chv_config_group_get, + .pin_config_group_set = chv_config_group_set, }; static struct pinctrl_desc chv_pinctrl_desc = { @@ -1464,12 +1539,11 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq) offset += range->npins; } - /* Mask and clear all interrupts */ - chv_writel(0, pctrl->regs + CHV_INTMASK); + /* Clear all interrupts */ chv_writel(0xffff, pctrl->regs + CHV_INTSTAT); ret = gpiochip_irqchip_add(chip, &chv_gpio_irqchip, 0, - handle_simple_irq, IRQ_TYPE_NONE); + handle_bad_irq, IRQ_TYPE_NONE); if (ret) { dev_err(pctrl->dev, "failed to add IRQ chip\n"); goto fail; @@ -1560,12 +1634,15 @@ static int chv_pinctrl_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static int chv_pinctrl_suspend(struct device *dev) +static int chv_pinctrl_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct chv_pinctrl *pctrl = platform_get_drvdata(pdev); + unsigned long flags; int i; + raw_spin_lock_irqsave(&chv_lock, flags); + pctrl->saved_intmask = readl(pctrl->regs + CHV_INTMASK); for (i = 0; i < pctrl->community->npins; i++) { @@ -1586,15 +1663,20 @@ static int chv_pinctrl_suspend(struct device *dev) ctx->padctrl1 = readl(reg); } + raw_spin_unlock_irqrestore(&chv_lock, flags); + return 0; } -static int chv_pinctrl_resume(struct device *dev) +static int chv_pinctrl_resume_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct chv_pinctrl *pctrl = platform_get_drvdata(pdev); + unsigned long flags; int i; + raw_spin_lock_irqsave(&chv_lock, flags); + /* * Mask all interrupts before restoring per-pin configuration * registers because we don't know in which state BIOS left them @@ -1639,12 +1721,15 @@ static int chv_pinctrl_resume(struct device *dev) chv_writel(0xffff, pctrl->regs + CHV_INTSTAT); chv_writel(pctrl->saved_intmask, pctrl->regs + CHV_INTMASK); + raw_spin_unlock_irqrestore(&chv_lock, flags); + return 0; } #endif static const struct dev_pm_ops chv_pinctrl_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(chv_pinctrl_suspend, chv_pinctrl_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(chv_pinctrl_suspend_noirq, + chv_pinctrl_resume_noirq) }; static const struct acpi_device_id chv_pinctrl_acpi_match[] = { |
