diff options
Diffstat (limited to 'drivers/pinctrl/pinctrl-msm.c')
| -rw-r--r-- | drivers/pinctrl/pinctrl-msm.c | 209 |
1 files changed, 79 insertions, 130 deletions
diff --git a/drivers/pinctrl/pinctrl-msm.c b/drivers/pinctrl/pinctrl-msm.c index ef2bf3126da..df6dda4ce80 100644 --- a/drivers/pinctrl/pinctrl-msm.c +++ b/drivers/pinctrl/pinctrl-msm.c @@ -13,7 +13,6 @@ */ #include <linux/err.h> -#include <linux/irqdomain.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> @@ -26,9 +25,6 @@ #include <linux/slab.h> #include <linux/gpio.h> #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" @@ -42,7 +38,6 @@ * struct msm_pinctrl - state for a pinctrl-msm device * @dev: device handle. * @pctrl: pinctrl handle. - * @domain: irqdomain handle. * @chip: gpiochip handle. * @irq: parent irq for the TLMM irq_chip. * @lock: Spinlock to protect register resources as well @@ -50,14 +45,12 @@ * @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. */ struct msm_pinctrl { struct device *dev; struct pinctrl_dev *pctrl; - struct irq_domain *domain; struct gpio_chip chip; int irq; @@ -65,12 +58,16 @@ 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; }; +static inline struct msm_pinctrl *to_msm_pinctrl(struct gpio_chip *gc) +{ + return container_of(gc, struct msm_pinctrl, chip); +} + static int msm_get_groups_count(struct pinctrl_dev *pctldev) { struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); @@ -148,12 +145,12 @@ static int msm_pinmux_enable(struct pinctrl_dev *pctldev, if (WARN_ON(g->mux_bit < 0)) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(g->funcs); i++) { + for (i = 0; i < g->nfuncs; i++) { if (g->funcs[i] == function) break; } - if (WARN_ON(i == ARRAY_SIZE(g->funcs))) + if (WARN_ON(i == g->nfuncs)) return -EINVAL; spin_lock_irqsave(&pctrl->lock, flags); @@ -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); @@ -482,13 +480,6 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) spin_unlock_irqrestore(&pctrl->lock, flags); } -static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct msm_pinctrl *pctrl = container_of(chip, struct msm_pinctrl, chip); - - return irq_find_mapping(pctrl->domain, offset); -} - static int msm_gpio_request(struct gpio_chip *chip, unsigned offset) { int gpio = chip->base + offset; @@ -534,7 +525,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]); } @@ -558,7 +549,6 @@ static struct gpio_chip msm_gpio_template = { .direction_output = msm_gpio_direction_output, .get = msm_gpio_get, .set = msm_gpio_set, - .to_irq = msm_gpio_to_irq, .request = msm_gpio_request, .free = msm_gpio_free, .dbg_show = msm_gpio_dbg_show, @@ -610,15 +600,13 @@ static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl, static void msm_gpio_irq_mask(struct irq_data *d) { + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); const struct msm_pingroup *g; - struct msm_pinctrl *pctrl; unsigned long flags; u32 val; - 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); @@ -633,15 +621,13 @@ static void msm_gpio_irq_mask(struct irq_data *d) static void msm_gpio_irq_unmask(struct irq_data *d) { + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); const struct msm_pingroup *g; - struct msm_pinctrl *pctrl; unsigned long flags; u32 val; - 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); @@ -660,20 +646,21 @@ static void msm_gpio_irq_unmask(struct irq_data *d) static void msm_gpio_irq_ack(struct irq_data *d) { + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); const struct msm_pingroup *g; - struct msm_pinctrl *pctrl; unsigned long flags; u32 val; - 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); val = readl(pctrl->regs + g->intr_status_reg); - val &= ~BIT(g->intr_status_bit); + if (g->intr_ack_high) + val |= BIT(g->intr_status_bit); + else + val &= ~BIT(g->intr_status_bit); writel(val, pctrl->regs + g->intr_status_reg); if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) @@ -686,15 +673,13 @@ static void msm_gpio_irq_ack(struct irq_data *d) static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) { + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); const struct msm_pingroup *g; - struct msm_pinctrl *pctrl; unsigned long flags; u32 val; - 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); @@ -754,6 +739,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) break; case IRQ_TYPE_EDGE_BOTH: val |= BIT(g->intr_detection_bit); + val |= BIT(g->intr_polarity_bit); break; case IRQ_TYPE_LEVEL_LOW: break; @@ -781,50 +767,19 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) { - struct msm_pinctrl *pctrl; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); 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) -{ - 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); - } - msm_gpio_irq_unmask(d); - return 0; -} - -static void msm_gpio_irq_shutdown(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); -} - static struct irq_chip msm_gpio_irq_chip = { .name = "msmgpio", .irq_mask = msm_gpio_irq_mask, @@ -832,14 +787,13 @@ 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, }; static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { + struct gpio_chip *gc = irq_desc_get_handler_data(desc); const struct msm_pingroup *g; - struct msm_pinctrl *pctrl = irq_desc_get_handler_data(desc); + struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); struct irq_chip *chip = irq_get_chip(irq); int irq_pin; int handled = 0; @@ -856,7 +810,7 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) g = &pctrl->soc->groups[i]; val = readl(pctrl->regs + g->intr_status_reg); if (val & BIT(g->intr_status_bit)) { - irq_pin = irq_find_mapping(pctrl->domain, i); + irq_pin = irq_find_mapping(gc->irqdomain, i); generic_handle_irq(irq_pin); handled++; } @@ -872,14 +826,15 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) static int msm_gpio_init(struct msm_pinctrl *pctrl) { struct gpio_chip *chip; - int irq; 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; @@ -897,22 +852,18 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) return ret; } - pctrl->domain = irq_domain_add_linear(pctrl->dev->of_node, chip->ngpio, - &irq_domain_simple_ops, NULL); - if (!pctrl->domain) { - dev_err(pctrl->dev, "Failed to register irq domain\n"); - r = gpiochip_remove(&pctrl->chip); + ret = gpiochip_irqchip_add(chip, + &msm_gpio_irq_chip, + 0, + handle_edge_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n"); return -ENOSYS; } - for (i = 0; i < chip->ngpio; i++) { - irq = irq_create_mapping(pctrl->domain, i); - irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, handle_edge_irq); - irq_set_chip_data(irq, pctrl); - } - - irq_set_handler_data(pctrl->irq, pctrl); - irq_set_chained_handler(pctrl->irq, msm_gpio_irq_handler); + gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip, pctrl->irq, + msm_gpio_irq_handler); return 0; } @@ -980,8 +931,6 @@ int msm_pinctrl_remove(struct platform_device *pdev) return ret; } - irq_set_chained_handler(pctrl->irq, NULL); - irq_domain_remove(pctrl->domain); pinctrl_unregister(pctrl->pctrl); return 0; |
