diff options
Diffstat (limited to 'drivers/pinctrl/pinctrl-nomadik.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-nomadik.c | 135 |
1 files changed, 126 insertions, 9 deletions
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 3dde6537adb8..cf82d9ce4dee 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -30,6 +30,20 @@ #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 <asm/mach/irq.h> @@ -237,6 +251,89 @@ 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_prcm_altcx_set_mode(struct nmk_pinctrl *npct, + unsigned offset, unsigned alt_num) +{ + int i; + u16 reg; + u8 bit; + u8 alt_index; + const struct prcm_gpiocr_altcx_pin_desc *pin_desc; + const u16 *gpiocr_regs; + + if (alt_num > PRCM_IDX_GPIOCR_ALTC_MAX) { + dev_err(npct->dev, "PRCM GPIOCR: alternate-C%i is invalid\n", + alt_num); + return; + } + + for (i = 0 ; i < npct->soc->npins_altcx ; i++) { + if (npct->soc->altcx_pins[i].pin == offset) + break; + } + if (i == npct->soc->npins_altcx) { + dev_dbg(npct->dev, "PRCM GPIOCR: pin %i is not found\n", + offset); + return; + } + + pin_desc = npct->soc->altcx_pins + i; + gpiocr_regs = npct->soc->prcm_gpiocr_registers; + + /* + * If alt_num is NULL, just clear current ALTCx selection + * to make sure we come back to a pure ALTC selection + */ + if (!alt_num) { + 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 (prcmu_read(reg) & BIT(bit)) { + prcmu_write_masked(reg, BIT(bit), 0); + dev_dbg(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", + offset, i+1); + } + } + } + return; + } + + alt_index = alt_num - 1; + if (pin_desc->altcx[alt_index].used == false) { + dev_warn(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i does not exist\n", + offset, alt_num); + return; + } + + /* + * Check if any other ALTCx functions are activated on this pin + * and disable it first. + */ + for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { + if (i == alt_index) + continue; + 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); + dev_dbg(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", + offset, i+1); + } + } + } + + reg = gpiocr_regs[pin_desc->altcx[alt_index].reg_index]; + 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)); +} + static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, pin_cfg_t cfg, bool sleep, unsigned int *slpmregs) { @@ -819,6 +916,7 @@ static struct irq_chip nmk_gpio_irq_chip = { .irq_set_wake = nmk_gpio_irq_set_wake, .irq_startup = nmk_gpio_irq_startup, .irq_shutdown = nmk_gpio_irq_shutdown, + .flags = IRQCHIP_MASK_ON_SUSPEND, }; static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, @@ -826,16 +924,14 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, { struct nmk_gpio_chip *nmk_chip; struct irq_chip *host_chip = irq_get_chip(irq); - unsigned int first_irq; chained_irq_enter(host_chip, desc); nmk_chip = irq_get_handler_data(irq); - first_irq = nmk_chip->domain->revmap_data.legacy.first_irq; while (status) { int bit = __ffs(status); - generic_handle_irq(first_irq + bit); + generic_handle_irq(irq_find_mapping(nmk_chip->domain, bit)); status &= ~BIT(bit); } @@ -960,7 +1056,7 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset) struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); - return irq_find_mapping(nmk_chip->domain, offset); + return irq_create_mapping(nmk_chip->domain, offset); } #ifdef CONFIG_DEBUG_FS @@ -1185,6 +1281,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) struct clk *clk; int secondary_irq; void __iomem *base; + int irq_start = 0; int irq; int ret; @@ -1288,9 +1385,11 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) platform_set_drvdata(dev, nmk_chip); - nmk_chip->domain = irq_domain_add_legacy(np, NMK_GPIO_PER_CHIP, - NOMADIK_GPIO_TO_IRQ(pdata->first_gpio), - 0, &nmk_gpio_irq_simple_ops, nmk_chip); + if (!np) + irq_start = NOMADIK_GPIO_TO_IRQ(pdata->first_gpio); + nmk_chip->domain = irq_domain_add_simple(np, + NMK_GPIO_PER_CHIP, irq_start, + &nmk_gpio_irq_simple_ops, nmk_chip); if (!nmk_chip->domain) { dev_err(&dev->dev, "failed to create irqdomain\n"); ret = -ENOSYS; @@ -1442,7 +1541,7 @@ static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, * IOFORCE will switch *all* ports to their sleepmode setting to as * to avoid glitches. (Not just one port!) */ - glitch = (g->altsetting == NMK_GPIO_ALT_C); + glitch = ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C); if (glitch) { spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); @@ -1492,8 +1591,21 @@ static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, */ nmk_gpio_disable_lazy_irq(nmk_chip, bit); - __nmk_gpio_set_mode_safe(nmk_chip, bit, g->altsetting, glitch); + __nmk_gpio_set_mode_safe(nmk_chip, bit, + (g->altsetting & NMK_GPIO_ALT_C), glitch); clk_disable(nmk_chip->clk); + + /* + * Call PRCM GPIOCR config function in case ALTC + * has been selected: + * - If selection is a ALTCx, some bits in PRCM GPIOCR registers + * must be set. + * - If selection is pure ALTC and previous selection was ALTCx, + * then some bits in PRCM GPIOCR registers must be cleared. + */ + if ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C) + nmk_prcm_altcx_set_mode(npct, g->pins[i], + g->altsetting >> NMK_GPIO_ALT_CX_SHIFT); } /* When all pins are successfully reconfigured we get here */ @@ -1720,8 +1832,12 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) of_match_device(nmk_pinctrl_match, &pdev->dev)->data; /* Poke in other ASIC variants here */ + if (version == PINCTRL_NMK_STN8815) + nmk_pinctrl_stn8815_init(&npct->soc); if (version == PINCTRL_NMK_DB8500) nmk_pinctrl_db8500_init(&npct->soc); + if (version == PINCTRL_NMK_DB8540) + nmk_pinctrl_db8540_init(&npct->soc); /* * We need all the GPIO drivers to probe FIRST, or we will not be able @@ -1772,6 +1888,7 @@ static struct platform_driver nmk_gpio_driver = { 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 = { |