diff options
Diffstat (limited to 'drivers/pinctrl/pinctrl-msm.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-msm.c | 124 |
1 files changed, 57 insertions, 67 deletions
diff --git a/drivers/pinctrl/pinctrl-msm.c b/drivers/pinctrl/pinctrl-msm.c index ef2bf3126da..38d579b47f3 100644 --- a/drivers/pinctrl/pinctrl-msm.c +++ b/drivers/pinctrl/pinctrl-msm.c @@ -28,7 +28,6 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqchip/chained_irq.h> -#include <linux/of_irq.h> #include <linux/spinlock.h> #include "core.h" @@ -50,7 +49,6 @@ * @enabled_irqs: Bitmap of currently enabled irqs. * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge * detection. - * @wake_irqs: Bitmap of irqs with requested as wakeup source. * @soc; Reference to soc_data of platform specific data. * @regs: Base address for the TLMM register map. */ @@ -65,7 +63,6 @@ struct msm_pinctrl { DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); - DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO); const struct msm_pinctrl_soc_data *soc; void __iomem *regs; @@ -203,42 +200,29 @@ static const struct pinmux_ops msm_pinmux_ops = { static int msm_config_reg(struct msm_pinctrl *pctrl, const struct msm_pingroup *g, unsigned param, - s16 *reg, unsigned *mask, unsigned *bit) { switch (param) { case PIN_CONFIG_BIAS_DISABLE: - *reg = g->ctl_reg; - *bit = g->pull_bit; - *mask = 3; - break; case PIN_CONFIG_BIAS_PULL_DOWN: - *reg = g->ctl_reg; - *bit = g->pull_bit; - *mask = 3; - break; case PIN_CONFIG_BIAS_PULL_UP: - *reg = g->ctl_reg; *bit = g->pull_bit; *mask = 3; break; case PIN_CONFIG_DRIVE_STRENGTH: - *reg = g->ctl_reg; *bit = g->drv_bit; *mask = 7; break; + case PIN_CONFIG_OUTPUT: + *bit = g->oe_bit; + *mask = 1; + break; default: dev_err(pctrl->dev, "Invalid config param %04x\n", param); return -ENOTSUPP; } - if (*reg < 0) { - dev_err(pctrl->dev, "Config param %04x not supported on group %s\n", - param, g->name); - return -ENOTSUPP; - } - return 0; } @@ -261,8 +245,10 @@ static int msm_config_set(struct pinctrl_dev *pctldev, unsigned int pin, #define MSM_PULL_DOWN 1 #define MSM_PULL_UP 3 -static const unsigned msm_regval_to_drive[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; -static const unsigned msm_drive_to_regval[] = { -1, -1, 0, -1, 1, -1, 2, -1, 3, -1, 4, -1, 5, -1, 6, -1, 7 }; +static unsigned msm_regval_to_drive(u32 val) +{ + return (val + 1) * 2; +} static int msm_config_group_get(struct pinctrl_dev *pctldev, unsigned int group, @@ -274,17 +260,16 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev, unsigned mask; unsigned arg; unsigned bit; - s16 reg; int ret; u32 val; g = &pctrl->soc->groups[group]; - ret = msm_config_reg(pctrl, g, param, ®, &mask, &bit); + ret = msm_config_reg(pctrl, g, param, &mask, &bit); if (ret < 0) return ret; - val = readl(pctrl->regs + reg); + val = readl(pctrl->regs + g->ctl_reg); arg = (val >> bit) & mask; /* Convert register value to pinconf value */ @@ -299,7 +284,15 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev, arg = arg == MSM_PULL_UP; break; case PIN_CONFIG_DRIVE_STRENGTH: - arg = msm_regval_to_drive[arg]; + arg = msm_regval_to_drive(arg); + break; + case PIN_CONFIG_OUTPUT: + /* Pin is not output */ + if (!arg) + return -EINVAL; + + val = readl(pctrl->regs + g->io_reg); + arg = !!(val & BIT(g->in_bit)); break; default: dev_err(pctrl->dev, "Unsupported config parameter: %x\n", @@ -324,7 +317,6 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev, unsigned mask; unsigned arg; unsigned bit; - s16 reg; int ret; u32 val; int i; @@ -335,7 +327,7 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev, param = pinconf_to_config_param(configs[i]); arg = pinconf_to_config_argument(configs[i]); - ret = msm_config_reg(pctrl, g, param, ®, &mask, &bit); + ret = msm_config_reg(pctrl, g, param, &mask, &bit); if (ret < 0) return ret; @@ -352,10 +344,24 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev, break; case PIN_CONFIG_DRIVE_STRENGTH: /* Check for invalid values */ - if (arg >= ARRAY_SIZE(msm_drive_to_regval)) + if (arg > 16 || arg < 2 || (arg % 2) != 0) arg = -1; else - arg = msm_drive_to_regval[arg]; + arg = (arg / 2) - 1; + break; + case PIN_CONFIG_OUTPUT: + /* set output value */ + spin_lock_irqsave(&pctrl->lock, flags); + val = readl(pctrl->regs + g->io_reg); + if (arg) + val |= BIT(g->out_bit); + else + val &= ~BIT(g->out_bit); + writel(val, pctrl->regs + g->io_reg); + spin_unlock_irqrestore(&pctrl->lock, flags); + + /* enable output */ + arg = 1; break; default: dev_err(pctrl->dev, "Unsupported config parameter: %x\n", @@ -370,10 +376,10 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev, } spin_lock_irqsave(&pctrl->lock, flags); - val = readl(pctrl->regs + reg); + val = readl(pctrl->regs + g->ctl_reg); val &= ~(mask << bit); val |= arg << bit; - writel(val, pctrl->regs + reg); + writel(val, pctrl->regs + g->ctl_reg); spin_unlock_irqrestore(&pctrl->lock, flags); } @@ -402,8 +408,6 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset) u32 val; g = &pctrl->soc->groups[offset]; - if (WARN_ON(g->io_reg < 0)) - return -EINVAL; spin_lock_irqsave(&pctrl->lock, flags); @@ -424,8 +428,6 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in u32 val; g = &pctrl->soc->groups[offset]; - if (WARN_ON(g->io_reg < 0)) - return -EINVAL; spin_lock_irqsave(&pctrl->lock, flags); @@ -452,8 +454,6 @@ static int msm_gpio_get(struct gpio_chip *chip, unsigned offset) u32 val; g = &pctrl->soc->groups[offset]; - if (WARN_ON(g->io_reg < 0)) - return -EINVAL; val = readl(pctrl->regs + g->io_reg); return !!(val & BIT(g->in_bit)); @@ -467,8 +467,6 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) u32 val; g = &pctrl->soc->groups[offset]; - if (WARN_ON(g->io_reg < 0)) - return; spin_lock_irqsave(&pctrl->lock, flags); @@ -534,7 +532,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s, pull = (ctl_reg >> g->pull_bit) & 3; seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func); - seq_printf(s, " %dmA", msm_regval_to_drive[drive]); + seq_printf(s, " %dmA", msm_regval_to_drive(drive)); seq_printf(s, " %s", pulls[pull]); } @@ -617,8 +615,6 @@ static void msm_gpio_irq_mask(struct irq_data *d) pctrl = irq_data_get_irq_chip_data(d); g = &pctrl->soc->groups[d->hwirq]; - if (WARN_ON(g->intr_cfg_reg < 0)) - return; spin_lock_irqsave(&pctrl->lock, flags); @@ -640,8 +636,6 @@ static void msm_gpio_irq_unmask(struct irq_data *d) pctrl = irq_data_get_irq_chip_data(d); g = &pctrl->soc->groups[d->hwirq]; - if (WARN_ON(g->intr_status_reg < 0)) - return; spin_lock_irqsave(&pctrl->lock, flags); @@ -667,8 +661,6 @@ static void msm_gpio_irq_ack(struct irq_data *d) pctrl = irq_data_get_irq_chip_data(d); g = &pctrl->soc->groups[d->hwirq]; - if (WARN_ON(g->intr_status_reg < 0)) - return; spin_lock_irqsave(&pctrl->lock, flags); @@ -693,8 +685,6 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) pctrl = irq_data_get_irq_chip_data(d); g = &pctrl->soc->groups[d->hwirq]; - if (WARN_ON(g->intr_cfg_reg < 0)) - return -EINVAL; spin_lock_irqsave(&pctrl->lock, flags); @@ -783,45 +773,34 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) { struct msm_pinctrl *pctrl; unsigned long flags; - unsigned ngpio; pctrl = irq_data_get_irq_chip_data(d); - ngpio = pctrl->chip.ngpio; spin_lock_irqsave(&pctrl->lock, flags); - if (on) { - if (bitmap_empty(pctrl->wake_irqs, ngpio)) - enable_irq_wake(pctrl->irq); - set_bit(d->hwirq, pctrl->wake_irqs); - } else { - clear_bit(d->hwirq, pctrl->wake_irqs); - if (bitmap_empty(pctrl->wake_irqs, ngpio)) - disable_irq_wake(pctrl->irq); - } + irq_set_irq_wake(pctrl->irq, on); spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } -static unsigned int msm_gpio_irq_startup(struct irq_data *d) +static int msm_gpio_irq_reqres(struct irq_data *d) { struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); if (gpio_lock_as_irq(&pctrl->chip, d->hwirq)) { dev_err(pctrl->dev, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); + return -EINVAL; } - msm_gpio_irq_unmask(d); return 0; } -static void msm_gpio_irq_shutdown(struct irq_data *d) +static void msm_gpio_irq_relres(struct irq_data *d) { struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); - msm_gpio_irq_mask(d); gpio_unlock_as_irq(&pctrl->chip, d->hwirq); } @@ -832,8 +811,8 @@ static struct irq_chip msm_gpio_irq_chip = { .irq_ack = msm_gpio_irq_ack, .irq_set_type = msm_gpio_irq_set_type, .irq_set_wake = msm_gpio_irq_set_wake, - .irq_startup = msm_gpio_irq_startup, - .irq_shutdown = msm_gpio_irq_shutdown, + .irq_request_resources = msm_gpio_irq_reqres, + .irq_release_resources = msm_gpio_irq_relres, }; static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) @@ -869,6 +848,12 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + static int msm_gpio_init(struct msm_pinctrl *pctrl) { struct gpio_chip *chip; @@ -876,10 +861,14 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) int ret; int i; int r; + unsigned ngpio = pctrl->soc->ngpios; + + if (WARN_ON(ngpio > MAX_NR_GPIO)) + return -EINVAL; chip = &pctrl->chip; chip->base = 0; - chip->ngpio = pctrl->soc->ngpios; + chip->ngpio = ngpio; chip->label = dev_name(pctrl->dev); chip->dev = pctrl->dev; chip->owner = THIS_MODULE; @@ -907,6 +896,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) for (i = 0; i < chip->ngpio; i++) { irq = irq_create_mapping(pctrl->domain, i); + irq_set_lockdep_class(irq, &gpio_lock_class); irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, handle_edge_irq); irq_set_chip_data(irq, pctrl); } |