diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 11:21:33 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 11:21:33 -0800 |
commit | 505cbedab9c7c565957e64af6348e5d84acd510e (patch) | |
tree | 4855caf82c434629432e22f03c96892d73383ba2 /drivers/pinctrl/pinctrl-nomadik.c | |
parent | a8936db7c2d9ef7f8e080d629301e448291f3b75 (diff) | |
parent | 7c8f86a451fe8c010eb93c62d4d69727ccdbe435 (diff) |
Merge tag 'pinctrl-for-v3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pinctrl changes from Linus Walleij:
"These are the first and major pinctrl changes for the v3.8 merge
cycle. Some of this is used as merge base for other trees so I better
be early on the trigger.
As can be seen from the diffstat the major changes are:
- A big conversion of the AT91 pinctrl driver and the associated ACKed
platform changes under arch/arm/max-at91 and its device trees. This
has been coordinated with the AT91 maintainers to go in through the
pinctrl tree.
- A larger chunk of changes to the SPEAr drivers and the addition of
the "plgpio" driver for the SPEAr as well.
- The removal of the remnants of the Nomadik driver from the arch/arm
tree and fusion of that into the Nomadik driver and platform data
header files.
- Some local movement in the Marvell MVEBU drivers, these now have
their own subdirectory.
- The addition of a chunk of code to gpiolib under drivers/gpio to
register gpio-to-pin range mappings from the GPIO side of things.
This has been requested by Grant Likely and is now implemented, it
is particularly useful for device tree work.
Then we have incremental updates all over the place, many of these are
cleanups and fixes from Axel Lin who has done a great job of removing
minor mistakes and compilation annoyances."
* tag 'pinctrl-for-v3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (114 commits)
ARM: mmp: select PINCTRL for ARCH_MMP
pinctrl: Drop selecting PINCONF for MMP2, PXA168 and PXA910
pinctrl: pinctrl-single: Fix error check condition
pinctrl: SPEAr: Update error check for unsigned variables
gpiolib: Fix use after free in gpiochip_add_pin_range
gpiolib: rename pin range arguments
pinctrl: single: support gpio request and free
pinctrl: generic: add input schmitt disable parameter
pinctrl/u300/coh901: stop spawning pinctrl from GPIO
pinctrl/u300/coh901: let the gpio_chip register the range
pinctrl: add function to retrieve range from pin
gpiolib: return any error code from range creation
pinctrl: make range registration defer properly
gpiolib: rename find_pinctrl_*
gpiolib: let gpiochip_add_pin_range() specify offset
ARM: at91: pm9g45: add mmc support
ARM: at91: Animeo IP: add mmc support
ARM: at91: dt: add mmc pinctrl for Atmel reference boards
ARM: at91: dt: at91sam9: add mmc pinctrl support
ARM: at91/dts: add nodes for atmel hsmci controllers for atmel boards
...
Diffstat (limited to 'drivers/pinctrl/pinctrl-nomadik.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-nomadik.c | 152 |
1 files changed, 104 insertions, 48 deletions
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index cf82d9ce4de..8ef3e85cb01 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -30,26 +30,10 @@ #include <linux/pinctrl/pinconf.h> /* Since we request GPIOs from ourself */ #include <linux/pinctrl/consumer.h> -/* - * For the U8500 archs, use the PRCMU register interface, for the older - * Nomadik, provide some stubs. The functions using these will only be - * called on the U8500 series. - */ -#ifdef CONFIG_ARCH_U8500 -#include <linux/mfd/dbx500-prcmu.h> -#else -static inline u32 prcmu_read(unsigned int reg) { - return 0; -} -static inline void prcmu_write(unsigned int reg, u32 value) {} -static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {} -#endif +#include <linux/platform_data/pinctrl-nomadik.h> #include <asm/mach/irq.h> -#include <plat/pincfg.h> -#include <plat/gpio-nomadik.h> - #include "pinctrl-nomadik.h" /* @@ -60,8 +44,6 @@ static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {} * Symbols in this file are called "nmk_gpio" for "nomadik gpio" */ -#define NMK_GPIO_PER_CHIP 32 - struct nmk_gpio_chip { struct gpio_chip chip; struct irq_domain *domain; @@ -86,10 +68,18 @@ struct nmk_gpio_chip { u32 lowemi; }; +/** + * struct nmk_pinctrl - state container for the Nomadik pin controller + * @dev: containing device pointer + * @pctl: corresponding pin controller device + * @soc: SoC data for this specific chip + * @prcm_base: PRCM register range virtual base + */ struct nmk_pinctrl { struct device *dev; struct pinctrl_dev *pctl; const struct nmk_pinctrl_soc_data *soc; + void __iomem *prcm_base; }; static struct nmk_gpio_chip * @@ -251,6 +241,15 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio); } +static void nmk_write_masked(void __iomem *reg, u32 mask, u32 value) +{ + u32 val; + + val = readl(reg); + val = ((val & ~mask) | (value & mask)); + writel(val, reg); +} + static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, unsigned offset, unsigned alt_num) { @@ -289,8 +288,8 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, if (pin_desc->altcx[i].used == true) { reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; bit = pin_desc->altcx[i].control_bit; - if (prcmu_read(reg) & BIT(bit)) { - prcmu_write_masked(reg, BIT(bit), 0); + if (readl(npct->prcm_base + reg) & BIT(bit)) { + nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0); dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", offset, i+1); @@ -318,8 +317,8 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, if (pin_desc->altcx[i].used == true) { reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; bit = pin_desc->altcx[i].control_bit; - if (prcmu_read(reg) & BIT(bit)) { - prcmu_write_masked(reg, BIT(bit), 0); + if (readl(npct->prcm_base + reg) & BIT(bit)) { + nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0); dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", offset, i+1); @@ -331,7 +330,7 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, bit = pin_desc->altcx[alt_index].control_bit; dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been selected\n", offset, alt_index+1); - prcmu_write_masked(reg, BIT(bit), BIT(bit)); + nmk_write_masked(npct->prcm_base + reg, BIT(bit), BIT(bit)); } static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, @@ -536,7 +535,7 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep) * and its sleep mode based on the specified configuration. The @cfg is * usually one of the SoC specific macros defined in mach/<soc>-pins.h. These * are constructed using, and can be further enhanced with, the macros in - * plat/pincfg.h. + * <linux/platform_data/pinctrl-nomadik.h> * * If a pin's mode is set to GPIO, it is configured as an input to avoid * side-effects. The gpio can be manipulated later using standard GPIO API @@ -675,6 +674,35 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode) } EXPORT_SYMBOL(nmk_gpio_set_mode); +static int nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio) +{ + int i; + u16 reg; + u8 bit; + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + const struct prcm_gpiocr_altcx_pin_desc *pin_desc; + const u16 *gpiocr_regs; + + for (i = 0; i < npct->soc->npins_altcx; i++) { + if (npct->soc->altcx_pins[i].pin == gpio) + break; + } + if (i == npct->soc->npins_altcx) + return NMK_GPIO_ALT_C; + + pin_desc = npct->soc->altcx_pins + i; + gpiocr_regs = npct->soc->prcm_gpiocr_registers; + for (i = 0; i < PRCM_IDX_GPIOCR_ALTC_MAX; i++) { + if (pin_desc->altcx[i].used == true) { + reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; + bit = pin_desc->altcx[i].control_bit; + if (readl(npct->prcm_base + reg) & BIT(bit)) + return NMK_GPIO_ALT_C+i+1; + } + } + return NMK_GPIO_ALT_C; +} + int nmk_gpio_get_mode(int gpio) { struct nmk_gpio_chip *nmk_chip; @@ -1063,8 +1091,9 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset) #include <linux/seq_file.h> -static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip, - unsigned offset, unsigned gpio) +static void nmk_gpio_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, struct gpio_chip *chip, + unsigned offset, unsigned gpio) { const char *label = gpiochip_is_requested(chip, offset); struct nmk_gpio_chip *nmk_chip = @@ -1078,12 +1107,18 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip, [NMK_GPIO_ALT_A] = "altA", [NMK_GPIO_ALT_B] = "altB", [NMK_GPIO_ALT_C] = "altC", + [NMK_GPIO_ALT_C+1] = "altC1", + [NMK_GPIO_ALT_C+2] = "altC2", + [NMK_GPIO_ALT_C+3] = "altC3", + [NMK_GPIO_ALT_C+4] = "altC4", }; clk_enable(nmk_chip->clk); is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & bit); pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit); mode = nmk_gpio_get_mode(gpio); + if ((mode == NMK_GPIO_ALT_C) && pctldev) + mode = nmk_prcm_gpiocr_get_mode(pctldev, gpio); seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s", gpio, label ?: "(none)", @@ -1127,13 +1162,14 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) unsigned gpio = chip->base; for (i = 0; i < chip->ngpio; i++, gpio++) { - nmk_gpio_dbg_show_one(s, chip, i, gpio); + nmk_gpio_dbg_show_one(s, NULL, chip, i, gpio); seq_printf(s, "\n"); } } #else static inline void nmk_gpio_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, struct gpio_chip *chip, unsigned offset, unsigned gpio) { @@ -1250,8 +1286,8 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up) } } -int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) +static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { struct nmk_gpio_chip *nmk_chip = d->host_data; @@ -1464,7 +1500,7 @@ static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, return; } chip = range->gc; - nmk_gpio_dbg_show_one(s, chip, offset - chip->base, offset); + nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset); } static struct pinctrl_ops nmk_pinctrl_ops = { @@ -1635,9 +1671,9 @@ static void nmk_pmx_disable(struct pinctrl_dev *pctldev, dev_dbg(npct->dev, "disable group %s, %u pins\n", g->name, g->npins); } -int nmk_gpio_request_enable(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned offset) +static int nmk_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) { struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); struct nmk_gpio_chip *nmk_chip; @@ -1666,9 +1702,9 @@ int nmk_gpio_request_enable(struct pinctrl_dev *pctldev, return 0; } -void nmk_gpio_disable_free(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned offset) +static void nmk_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) { struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); @@ -1686,17 +1722,15 @@ static struct pinmux_ops nmk_pinmux_ops = { .gpio_disable_free = nmk_gpio_disable_free, }; -int nmk_pin_config_get(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *config) +static int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long *config) { /* Not implemented */ return -EINVAL; } -int nmk_pin_config_set(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long config) +static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long config) { static const char *pullnames[] = { [NMK_GPIO_PULL_NONE] = "none", @@ -1818,6 +1852,7 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) const struct platform_device_id *platid = platform_get_device_id(pdev); struct device_node *np = pdev->dev.of_node; struct nmk_pinctrl *npct; + struct resource *res; unsigned int version = 0; int i; @@ -1827,9 +1862,14 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) if (platid) version = platid->driver_data; - else if (np) - version = (unsigned int) - of_match_device(nmk_pinctrl_match, &pdev->dev)->data; + else if (np) { + const struct of_device_id *match; + + match = of_match_device(nmk_pinctrl_match, &pdev->dev); + if (!match) + return -ENODEV; + version = (unsigned int) match->data; + } /* Poke in other ASIC variants here */ if (version == PINCTRL_NMK_STN8815) @@ -1839,22 +1879,37 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) if (version == PINCTRL_NMK_DB8540) nmk_pinctrl_db8540_init(&npct->soc); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + npct->prcm_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!npct->prcm_base) { + dev_err(&pdev->dev, + "failed to ioremap PRCM registers\n"); + return -ENOMEM; + } + } else { + dev_info(&pdev->dev, + "No PRCM base, assume no ALT-Cx control is available\n"); + } + /* * We need all the GPIO drivers to probe FIRST, or we will not be able * to obtain references to the struct gpio_chip * for them, and we * need this to proceed. */ for (i = 0; i < npct->soc->gpio_num_ranges; i++) { - if (!nmk_gpio_chips[i]) { + if (!nmk_gpio_chips[npct->soc->gpio_ranges[i].id]) { dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i); return -EPROBE_DEFER; } - npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip; + npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[npct->soc->gpio_ranges[i].id]->chip; } nmk_pinctrl_desc.pins = npct->soc->pins; nmk_pinctrl_desc.npins = npct->soc->npins; npct->dev = &pdev->dev; + npct->pctl = pinctrl_register(&nmk_pinctrl_desc, &pdev->dev, npct); if (!npct->pctl) { dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n"); @@ -1889,6 +1944,7 @@ static const struct platform_device_id nmk_pinctrl_id[] = { { "pinctrl-stn8815", PINCTRL_NMK_STN8815 }, { "pinctrl-db8500", PINCTRL_NMK_DB8500 }, { "pinctrl-db8540", PINCTRL_NMK_DB8540 }, + { } }; static struct platform_driver nmk_pinctrl_driver = { |