diff options
Diffstat (limited to 'drivers/pinctrl/pinctrl-nomadik.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-nomadik.c | 125 |
1 files changed, 119 insertions, 6 deletions
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 6030a513f3c4..cf82d9ce4dee 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c | |||
@@ -30,6 +30,20 @@ | |||
30 | #include <linux/pinctrl/pinconf.h> | 30 | #include <linux/pinctrl/pinconf.h> |
31 | /* Since we request GPIOs from ourself */ | 31 | /* Since we request GPIOs from ourself */ |
32 | #include <linux/pinctrl/consumer.h> | 32 | #include <linux/pinctrl/consumer.h> |
33 | /* | ||
34 | * For the U8500 archs, use the PRCMU register interface, for the older | ||
35 | * Nomadik, provide some stubs. The functions using these will only be | ||
36 | * called on the U8500 series. | ||
37 | */ | ||
38 | #ifdef CONFIG_ARCH_U8500 | ||
39 | #include <linux/mfd/dbx500-prcmu.h> | ||
40 | #else | ||
41 | static inline u32 prcmu_read(unsigned int reg) { | ||
42 | return 0; | ||
43 | } | ||
44 | static inline void prcmu_write(unsigned int reg, u32 value) {} | ||
45 | static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {} | ||
46 | #endif | ||
33 | 47 | ||
34 | #include <asm/mach/irq.h> | 48 | #include <asm/mach/irq.h> |
35 | 49 | ||
@@ -237,6 +251,89 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) | |||
237 | dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio); | 251 | dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio); |
238 | } | 252 | } |
239 | 253 | ||
254 | static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, | ||
255 | unsigned offset, unsigned alt_num) | ||
256 | { | ||
257 | int i; | ||
258 | u16 reg; | ||
259 | u8 bit; | ||
260 | u8 alt_index; | ||
261 | const struct prcm_gpiocr_altcx_pin_desc *pin_desc; | ||
262 | const u16 *gpiocr_regs; | ||
263 | |||
264 | if (alt_num > PRCM_IDX_GPIOCR_ALTC_MAX) { | ||
265 | dev_err(npct->dev, "PRCM GPIOCR: alternate-C%i is invalid\n", | ||
266 | alt_num); | ||
267 | return; | ||
268 | } | ||
269 | |||
270 | for (i = 0 ; i < npct->soc->npins_altcx ; i++) { | ||
271 | if (npct->soc->altcx_pins[i].pin == offset) | ||
272 | break; | ||
273 | } | ||
274 | if (i == npct->soc->npins_altcx) { | ||
275 | dev_dbg(npct->dev, "PRCM GPIOCR: pin %i is not found\n", | ||
276 | offset); | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | pin_desc = npct->soc->altcx_pins + i; | ||
281 | gpiocr_regs = npct->soc->prcm_gpiocr_registers; | ||
282 | |||
283 | /* | ||
284 | * If alt_num is NULL, just clear current ALTCx selection | ||
285 | * to make sure we come back to a pure ALTC selection | ||
286 | */ | ||
287 | if (!alt_num) { | ||
288 | for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { | ||
289 | if (pin_desc->altcx[i].used == true) { | ||
290 | reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; | ||
291 | bit = pin_desc->altcx[i].control_bit; | ||
292 | if (prcmu_read(reg) & BIT(bit)) { | ||
293 | prcmu_write_masked(reg, BIT(bit), 0); | ||
294 | dev_dbg(npct->dev, | ||
295 | "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", | ||
296 | offset, i+1); | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | return; | ||
301 | } | ||
302 | |||
303 | alt_index = alt_num - 1; | ||
304 | if (pin_desc->altcx[alt_index].used == false) { | ||
305 | dev_warn(npct->dev, | ||
306 | "PRCM GPIOCR: pin %i: alternate-C%i does not exist\n", | ||
307 | offset, alt_num); | ||
308 | return; | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * Check if any other ALTCx functions are activated on this pin | ||
313 | * and disable it first. | ||
314 | */ | ||
315 | for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { | ||
316 | if (i == alt_index) | ||
317 | continue; | ||
318 | if (pin_desc->altcx[i].used == true) { | ||
319 | reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; | ||
320 | bit = pin_desc->altcx[i].control_bit; | ||
321 | if (prcmu_read(reg) & BIT(bit)) { | ||
322 | prcmu_write_masked(reg, BIT(bit), 0); | ||
323 | dev_dbg(npct->dev, | ||
324 | "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", | ||
325 | offset, i+1); | ||
326 | } | ||
327 | } | ||
328 | } | ||
329 | |||
330 | reg = gpiocr_regs[pin_desc->altcx[alt_index].reg_index]; | ||
331 | bit = pin_desc->altcx[alt_index].control_bit; | ||
332 | dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been selected\n", | ||
333 | offset, alt_index+1); | ||
334 | prcmu_write_masked(reg, BIT(bit), BIT(bit)); | ||
335 | } | ||
336 | |||
240 | static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, | 337 | static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, |
241 | pin_cfg_t cfg, bool sleep, unsigned int *slpmregs) | 338 | pin_cfg_t cfg, bool sleep, unsigned int *slpmregs) |
242 | { | 339 | { |
@@ -959,7 +1056,7 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | |||
959 | struct nmk_gpio_chip *nmk_chip = | 1056 | struct nmk_gpio_chip *nmk_chip = |
960 | container_of(chip, struct nmk_gpio_chip, chip); | 1057 | container_of(chip, struct nmk_gpio_chip, chip); |
961 | 1058 | ||
962 | return irq_find_mapping(nmk_chip->domain, offset); | 1059 | return irq_create_mapping(nmk_chip->domain, offset); |
963 | } | 1060 | } |
964 | 1061 | ||
965 | #ifdef CONFIG_DEBUG_FS | 1062 | #ifdef CONFIG_DEBUG_FS |
@@ -1184,6 +1281,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) | |||
1184 | struct clk *clk; | 1281 | struct clk *clk; |
1185 | int secondary_irq; | 1282 | int secondary_irq; |
1186 | void __iomem *base; | 1283 | void __iomem *base; |
1284 | int irq_start = 0; | ||
1187 | int irq; | 1285 | int irq; |
1188 | int ret; | 1286 | int ret; |
1189 | 1287 | ||
@@ -1287,9 +1385,11 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) | |||
1287 | 1385 | ||
1288 | platform_set_drvdata(dev, nmk_chip); | 1386 | platform_set_drvdata(dev, nmk_chip); |
1289 | 1387 | ||
1290 | nmk_chip->domain = irq_domain_add_legacy(np, NMK_GPIO_PER_CHIP, | 1388 | if (!np) |
1291 | NOMADIK_GPIO_TO_IRQ(pdata->first_gpio), | 1389 | irq_start = NOMADIK_GPIO_TO_IRQ(pdata->first_gpio); |
1292 | 0, &nmk_gpio_irq_simple_ops, nmk_chip); | 1390 | nmk_chip->domain = irq_domain_add_simple(np, |
1391 | NMK_GPIO_PER_CHIP, irq_start, | ||
1392 | &nmk_gpio_irq_simple_ops, nmk_chip); | ||
1293 | if (!nmk_chip->domain) { | 1393 | if (!nmk_chip->domain) { |
1294 | dev_err(&dev->dev, "failed to create irqdomain\n"); | 1394 | dev_err(&dev->dev, "failed to create irqdomain\n"); |
1295 | ret = -ENOSYS; | 1395 | ret = -ENOSYS; |
@@ -1441,7 +1541,7 @@ static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, | |||
1441 | * IOFORCE will switch *all* ports to their sleepmode setting to as | 1541 | * IOFORCE will switch *all* ports to their sleepmode setting to as |
1442 | * to avoid glitches. (Not just one port!) | 1542 | * to avoid glitches. (Not just one port!) |
1443 | */ | 1543 | */ |
1444 | glitch = (g->altsetting == NMK_GPIO_ALT_C); | 1544 | glitch = ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C); |
1445 | 1545 | ||
1446 | if (glitch) { | 1546 | if (glitch) { |
1447 | spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); | 1547 | spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); |
@@ -1491,8 +1591,21 @@ static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, | |||
1491 | */ | 1591 | */ |
1492 | nmk_gpio_disable_lazy_irq(nmk_chip, bit); | 1592 | nmk_gpio_disable_lazy_irq(nmk_chip, bit); |
1493 | 1593 | ||
1494 | __nmk_gpio_set_mode_safe(nmk_chip, bit, g->altsetting, glitch); | 1594 | __nmk_gpio_set_mode_safe(nmk_chip, bit, |
1595 | (g->altsetting & NMK_GPIO_ALT_C), glitch); | ||
1495 | clk_disable(nmk_chip->clk); | 1596 | clk_disable(nmk_chip->clk); |
1597 | |||
1598 | /* | ||
1599 | * Call PRCM GPIOCR config function in case ALTC | ||
1600 | * has been selected: | ||
1601 | * - If selection is a ALTCx, some bits in PRCM GPIOCR registers | ||
1602 | * must be set. | ||
1603 | * - If selection is pure ALTC and previous selection was ALTCx, | ||
1604 | * then some bits in PRCM GPIOCR registers must be cleared. | ||
1605 | */ | ||
1606 | if ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C) | ||
1607 | nmk_prcm_altcx_set_mode(npct, g->pins[i], | ||
1608 | g->altsetting >> NMK_GPIO_ALT_CX_SHIFT); | ||
1496 | } | 1609 | } |
1497 | 1610 | ||
1498 | /* When all pins are successfully reconfigured we get here */ | 1611 | /* When all pins are successfully reconfigured we get here */ |