diff options
author | Scott Wood <scottwood@freescale.com> | 2014-04-07 23:49:35 (GMT) |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2014-04-07 23:49:35 (GMT) |
commit | 62b8c978ee6b8d135d9e7953221de58000dba986 (patch) | |
tree | 683b04b2e627f6710c22c151b23c8cc9a165315e /drivers/pinctrl/pinctrl-single.c | |
parent | 78fd82238d0e5716578c326404184a27ba67fd6e (diff) | |
download | linux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz |
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'drivers/pinctrl/pinctrl-single.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-single.c | 384 |
1 files changed, 9 insertions, 375 deletions
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 829b98c..a82ace4 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -15,21 +15,15 @@ #include <linux/slab.h> #include <linux/err.h> #include <linux/list.h> -#include <linux/interrupt.h> - -#include <linux/irqchip/chained_irq.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_address.h> -#include <linux/of_irq.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> #include <linux/pinctrl/pinconf-generic.h> -#include <linux/platform_data/pinctrl-single.h> - #include "core.h" #include "pinconf.h" @@ -156,36 +150,19 @@ struct pcs_name { }; /** - * struct pcs_soc_data - SoC specific settings - * @flags: initial SoC specific PCS_FEAT_xxx values - * @irq: optional interrupt for the controller - * @irq_enable_mask: optional SoC specific interrupt enable mask - * @irq_status_mask: optional SoC specific interrupt status mask - * @rearm: optional SoC specific wake-up rearm function - */ -struct pcs_soc_data { - unsigned flags; - int irq; - unsigned irq_enable_mask; - unsigned irq_status_mask; - void (*rearm)(void); -}; - -/** * struct pcs_device - pinctrl device instance * @res: resources * @base: virtual address of the controller * @size: size of the ioremapped area * @dev: device entry * @pctl: pin controller device - * @flags: mask of PCS_FEAT_xxx values - * @lock: spinlock for register access * @mutex: mutex protecting the lists * @width: bits per mux register * @fmask: function register mask * @fshift: function register shift * @foff: value to turn mux off * @fmax: max number of functions in fmask + * @is_pinconf: whether supports pinconf * @bits_per_pin:number of bits per pin * @names: array of register names for pins * @pins: physical pins on the SoC @@ -194,9 +171,6 @@ struct pcs_soc_data { * @pingroups: list of pingroups * @functions: list of functions * @gpiofuncs: list of gpio functions - * @irqs: list of interrupt registers - * @chip: chip container for this instance - * @domain: IRQ domain for this instance * @ngroups: number of pingroups * @nfuncs: number of functions * @desc: pin controller descriptor @@ -209,12 +183,6 @@ struct pcs_device { unsigned size; struct device *dev; struct pinctrl_dev *pctl; - unsigned flags; -#define PCS_QUIRK_SHARED_IRQ (1 << 2) -#define PCS_FEAT_IRQ (1 << 1) -#define PCS_FEAT_PINCONF (1 << 0) - struct pcs_soc_data socdata; - raw_spinlock_t lock; struct mutex mutex; unsigned width; unsigned fmask; @@ -222,6 +190,7 @@ struct pcs_device { unsigned foff; unsigned fmax; bool bits_per_mux; + bool is_pinconf; unsigned bits_per_pin; struct pcs_name *names; struct pcs_data pins; @@ -230,9 +199,6 @@ struct pcs_device { struct list_head pingroups; struct list_head functions; struct list_head gpiofuncs; - struct list_head irqs; - struct irq_chip chip; - struct irq_domain *domain; unsigned ngroups; unsigned nfuncs; struct pinctrl_desc desc; @@ -240,10 +206,6 @@ struct pcs_device { void (*write)(unsigned val, void __iomem *reg); }; -#define PCS_QUIRK_HAS_SHARED_IRQ (pcs->flags & PCS_QUIRK_SHARED_IRQ) -#define PCS_HAS_IRQ (pcs->flags & PCS_FEAT_IRQ) -#define PCS_HAS_PINCONF (pcs->flags & PCS_FEAT_PINCONF) - static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config); static int pcs_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, @@ -467,11 +429,9 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector, for (i = 0; i < func->nvals; i++) { struct pcs_func_vals *vals; - unsigned long flags; unsigned val, mask; vals = &func->vals[i]; - raw_spin_lock_irqsave(&pcs->lock, flags); val = pcs->read(vals->reg); if (pcs->bits_per_mux) @@ -482,7 +442,6 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector, val &= ~mask; val |= (vals->val & mask); pcs->write(val, vals->reg); - raw_spin_unlock_irqrestore(&pcs->lock, flags); } return 0; @@ -524,16 +483,13 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector, for (i = 0; i < func->nvals; i++) { struct pcs_func_vals *vals; - unsigned long flags; unsigned val; vals = &func->vals[i]; - raw_spin_lock_irqsave(&pcs->lock, flags); val = pcs->read(vals->reg); val &= ~pcs->fmask; val |= pcs->foff << pcs->fshift; pcs->write(val, vals->reg); - raw_spin_unlock_irqrestore(&pcs->lock, flags); } } @@ -1104,7 +1060,7 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np, }; /* If pinconf isn't supported, don't parse properties in below. */ - if (!PCS_HAS_PINCONF) + if (!pcs->is_pinconf) return 0; /* cacluate how much properties are supported in current node */ @@ -1228,7 +1184,7 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, (*map)->data.mux.group = np->name; (*map)->data.mux.function = np->name; - if (PCS_HAS_PINCONF) { + if (pcs->is_pinconf) { res = pcs_parse_pinconf(pcs, np, function, map); if (res) goto free_pingroups; @@ -1349,7 +1305,7 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs, (*map)->data.mux.group = np->name; (*map)->data.mux.function = np->name; - if (PCS_HAS_PINCONF) { + if (pcs->is_pinconf) { dev_err(pcs->dev, "pinconf not supported\n"); goto free_pingroups; } @@ -1484,33 +1440,11 @@ static void pcs_free_pingroups(struct pcs_device *pcs) } /** - * pcs_irq_free() - free interrupt - * @pcs: pcs driver instance - */ -static void pcs_irq_free(struct pcs_device *pcs) -{ - struct pcs_soc_data *pcs_soc = &pcs->socdata; - - if (pcs_soc->irq < 0) - return; - - if (pcs->domain) - irq_domain_remove(pcs->domain); - - if (PCS_QUIRK_HAS_SHARED_IRQ) - free_irq(pcs_soc->irq, pcs_soc); - else - irq_set_chained_handler(pcs_soc->irq, NULL); -} - -/** * pcs_free_resources() - free memory used by this driver * @pcs: pcs driver instance */ static void pcs_free_resources(struct pcs_device *pcs) { - pcs_irq_free(pcs); - if (pcs->pctl) pinctrl_unregister(pcs->pctl); @@ -1559,264 +1493,6 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs) } return ret; } -/** - * @reg: virtual address of interrupt register - * @hwirq: hardware irq number - * @irq: virtual irq number - * @node: list node - */ -struct pcs_interrupt { - void __iomem *reg; - irq_hw_number_t hwirq; - unsigned int irq; - struct list_head node; -}; - -/** - * pcs_irq_set() - enables or disables an interrupt - * - * Note that this currently assumes one interrupt per pinctrl - * register that is typically used for wake-up events. - */ -static inline void pcs_irq_set(struct pcs_soc_data *pcs_soc, - int irq, const bool enable) -{ - struct pcs_device *pcs; - struct list_head *pos; - unsigned mask; - - pcs = container_of(pcs_soc, struct pcs_device, socdata); - list_for_each(pos, &pcs->irqs) { - struct pcs_interrupt *pcswi; - unsigned soc_mask; - - pcswi = list_entry(pos, struct pcs_interrupt, node); - if (irq != pcswi->irq) - continue; - - soc_mask = pcs_soc->irq_enable_mask; - raw_spin_lock(&pcs->lock); - mask = pcs->read(pcswi->reg); - if (enable) - mask |= soc_mask; - else - mask &= ~soc_mask; - pcs->write(mask, pcswi->reg); - raw_spin_unlock(&pcs->lock); - } - - if (pcs_soc->rearm) - pcs_soc->rearm(); -} - -/** - * pcs_irq_mask() - mask pinctrl interrupt - * @d: interrupt data - */ -static void pcs_irq_mask(struct irq_data *d) -{ - struct pcs_soc_data *pcs_soc = irq_data_get_irq_chip_data(d); - - pcs_irq_set(pcs_soc, d->irq, false); -} - -/** - * pcs_irq_unmask() - unmask pinctrl interrupt - * @d: interrupt data - */ -static void pcs_irq_unmask(struct irq_data *d) -{ - struct pcs_soc_data *pcs_soc = irq_data_get_irq_chip_data(d); - - pcs_irq_set(pcs_soc, d->irq, true); -} - -/** - * pcs_irq_set_wake() - toggle the suspend and resume wake up - * @d: interrupt data - * @state: wake-up state - * - * Note that this should be called only for suspend and resume. - * For runtime PM, the wake-up events should be enabled by default. - */ -static int pcs_irq_set_wake(struct irq_data *d, unsigned int state) -{ - if (state) - pcs_irq_unmask(d); - else - pcs_irq_mask(d); - - return 0; -} - -/** - * pcs_irq_handle() - common interrupt handler - * @pcs_irq: interrupt data - * - * Note that this currently assumes we have one interrupt bit per - * mux register. This interrupt is typically used for wake-up events. - * For more complex interrupts different handlers can be specified. - */ -static int pcs_irq_handle(struct pcs_soc_data *pcs_soc) -{ - struct pcs_device *pcs; - struct list_head *pos; - int count = 0; - - pcs = container_of(pcs_soc, struct pcs_device, socdata); - list_for_each(pos, &pcs->irqs) { - struct pcs_interrupt *pcswi; - unsigned mask; - - pcswi = list_entry(pos, struct pcs_interrupt, node); - raw_spin_lock(&pcs->lock); - mask = pcs->read(pcswi->reg); - raw_spin_unlock(&pcs->lock); - if (mask & pcs_soc->irq_status_mask) { - generic_handle_irq(irq_find_mapping(pcs->domain, - pcswi->hwirq)); - count++; - } - } - - return count; -} - -/** - * pcs_irq_handler() - handler for the shared interrupt case - * @irq: interrupt - * @d: data - * - * Use this for cases where multiple instances of - * pinctrl-single share a single interrupt like on omaps. - */ -static irqreturn_t pcs_irq_handler(int irq, void *d) -{ - struct pcs_soc_data *pcs_soc = d; - - return pcs_irq_handle(pcs_soc) ? IRQ_HANDLED : IRQ_NONE; -} - -/** - * pcs_irq_handle() - handler for the dedicated chained interrupt case - * @irq: interrupt - * @desc: interrupt descriptor - * - * Use this if you have a separate interrupt for each - * pinctrl-single instance. - */ -static void pcs_irq_chain_handler(unsigned int irq, struct irq_desc *desc) -{ - struct pcs_soc_data *pcs_soc = irq_desc_get_handler_data(desc); - struct irq_chip *chip; - int res; - - chip = irq_get_chip(irq); - chained_irq_enter(chip, desc); - res = pcs_irq_handle(pcs_soc); - /* REVISIT: export and add handle_bad_irq(irq, desc)? */ - chained_irq_exit(chip, desc); - - return; -} - -static int pcs_irqdomain_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct pcs_soc_data *pcs_soc = d->host_data; - struct pcs_device *pcs; - struct pcs_interrupt *pcswi; - - pcs = container_of(pcs_soc, struct pcs_device, socdata); - pcswi = devm_kzalloc(pcs->dev, sizeof(*pcswi), GFP_KERNEL); - if (!pcswi) - return -ENOMEM; - - pcswi->reg = pcs->base + hwirq; - pcswi->hwirq = hwirq; - pcswi->irq = irq; - - mutex_lock(&pcs->mutex); - list_add_tail(&pcswi->node, &pcs->irqs); - mutex_unlock(&pcs->mutex); - - irq_set_chip_data(irq, pcs_soc); - irq_set_chip_and_handler(irq, &pcs->chip, - handle_level_irq); - -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - - return 0; -} - -static struct irq_domain_ops pcs_irqdomain_ops = { - .map = pcs_irqdomain_map, - .xlate = irq_domain_xlate_onecell, -}; - -/** - * pcs_irq_init_chained_handler() - set up a chained interrupt handler - * @pcs: pcs driver instance - * @np: device node pointer - */ -static int pcs_irq_init_chained_handler(struct pcs_device *pcs, - struct device_node *np) -{ - struct pcs_soc_data *pcs_soc = &pcs->socdata; - const char *name = "pinctrl"; - int num_irqs; - - if (!pcs_soc->irq_enable_mask || - !pcs_soc->irq_status_mask) { - pcs_soc->irq = -1; - return -EINVAL; - } - - INIT_LIST_HEAD(&pcs->irqs); - pcs->chip.name = name; - pcs->chip.irq_ack = pcs_irq_mask; - pcs->chip.irq_mask = pcs_irq_mask; - pcs->chip.irq_unmask = pcs_irq_unmask; - pcs->chip.irq_set_wake = pcs_irq_set_wake; - - if (PCS_QUIRK_HAS_SHARED_IRQ) { - int res; - - res = request_irq(pcs_soc->irq, pcs_irq_handler, - IRQF_SHARED | IRQF_NO_SUSPEND, - name, pcs_soc); - if (res) { - pcs_soc->irq = -1; - return res; - } - } else { - irq_set_handler_data(pcs_soc->irq, pcs_soc); - irq_set_chained_handler(pcs_soc->irq, - pcs_irq_chain_handler); - } - - /* - * We can use the register offset as the hardirq - * number as irq_domain_add_simple maps them lazily. - * This way we can easily support more than one - * interrupt per function if needed. - */ - num_irqs = pcs->size; - - pcs->domain = irq_domain_add_simple(np, num_irqs, 0, - &pcs_irqdomain_ops, - pcs_soc); - if (!pcs->domain) { - irq_set_chained_handler(pcs_soc->irq, NULL); - return -EINVAL; - } - - return 0; -} #ifdef CONFIG_PM static int pinctrl_single_suspend(struct platform_device *pdev, @@ -1847,10 +1523,8 @@ static int pcs_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; const struct of_device_id *match; - struct pcs_pdata *pdata; struct resource *res; struct pcs_device *pcs; - const struct pcs_soc_data *soc; int ret; match = of_match_device(pcs_of_match, &pdev->dev); @@ -1863,14 +1537,11 @@ static int pcs_probe(struct platform_device *pdev) return -ENOMEM; } pcs->dev = &pdev->dev; - raw_spin_lock_init(&pcs->lock); mutex_init(&pcs->mutex); INIT_LIST_HEAD(&pcs->pingroups); INIT_LIST_HEAD(&pcs->functions); INIT_LIST_HEAD(&pcs->gpiofuncs); - soc = match->data; - pcs->flags = soc->flags; - memcpy(&pcs->socdata, soc, sizeof(*soc)); + pcs->is_pinconf = match->data; PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width, "register width not specified\n"); @@ -1939,7 +1610,7 @@ static int pcs_probe(struct platform_device *pdev) pcs->desc.name = DRIVER_NAME; pcs->desc.pctlops = &pcs_pinctrl_ops; pcs->desc.pmxops = &pcs_pinmux_ops; - if (PCS_HAS_PINCONF) + if (pcs->is_pinconf) pcs->desc.confops = &pcs_pinconf_ops; pcs->desc.owner = THIS_MODULE; @@ -1958,27 +1629,6 @@ static int pcs_probe(struct platform_device *pdev) if (ret < 0) goto free; - pcs->socdata.irq = irq_of_parse_and_map(np, 0); - if (pcs->socdata.irq) - pcs->flags |= PCS_FEAT_IRQ; - - /* We still need auxdata for some omaps for PRM interrupts */ - pdata = dev_get_platdata(&pdev->dev); - if (pdata) { - if (pdata->rearm) - pcs->socdata.rearm = pdata->rearm; - if (pdata->irq) { - pcs->socdata.irq = pdata->irq; - pcs->flags |= PCS_FEAT_IRQ; - } - } - - if (PCS_HAS_IRQ) { - ret = pcs_irq_init_chained_handler(pcs, np); - if (ret < 0) - dev_warn(pcs->dev, "initialized with no interrupts\n"); - } - dev_info(pcs->dev, "%i pins at pa %p size %u\n", pcs->desc.npins, pcs->base, pcs->size); @@ -2002,25 +1652,9 @@ static int pcs_remove(struct platform_device *pdev) return 0; } -static const struct pcs_soc_data pinctrl_single_omap_wkup = { - .flags = PCS_QUIRK_SHARED_IRQ, - .irq_enable_mask = (1 << 14), /* OMAP_WAKEUP_EN */ - .irq_status_mask = (1 << 15), /* OMAP_WAKEUP_EVENT */ -}; - -static const struct pcs_soc_data pinctrl_single = { -}; - -static const struct pcs_soc_data pinconf_single = { - .flags = PCS_FEAT_PINCONF, -}; - static struct of_device_id pcs_of_match[] = { - { .compatible = "ti,omap3-padconf", .data = &pinctrl_single_omap_wkup }, - { .compatible = "ti,omap4-padconf", .data = &pinctrl_single_omap_wkup }, - { .compatible = "ti,omap5-padconf", .data = &pinctrl_single_omap_wkup }, - { .compatible = "pinctrl-single", .data = &pinctrl_single }, - { .compatible = "pinconf-single", .data = &pinconf_single }, + { .compatible = "pinctrl-single", .data = (void *)false }, + { .compatible = "pinconf-single", .data = (void *)true }, { }, }; MODULE_DEVICE_TABLE(of, pcs_of_match); |