diff options
Diffstat (limited to 'arch/arm/mach-tegra/pinmux.c')
-rw-r--r-- | arch/arm/mach-tegra/pinmux.c | 163 |
1 files changed, 132 insertions, 31 deletions
diff --git a/arch/arm/mach-tegra/pinmux.c b/arch/arm/mach-tegra/pinmux.c index f80d507671bc..1d201650d7a4 100644 --- a/arch/arm/mach-tegra/pinmux.c +++ b/arch/arm/mach-tegra/pinmux.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
21 | #include <linux/spinlock.h> | 21 | #include <linux/spinlock.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/platform_device.h> | ||
23 | 24 | ||
24 | #include <mach/iomap.h> | 25 | #include <mach/iomap.h> |
25 | #include <mach/pinmux.h> | 26 | #include <mach/pinmux.h> |
@@ -169,15 +170,17 @@ static const char *pupd_name(unsigned long val) | |||
169 | } | 170 | } |
170 | } | 171 | } |
171 | 172 | ||
173 | static int nbanks; | ||
174 | static void __iomem **regs; | ||
172 | 175 | ||
173 | static inline unsigned long pg_readl(unsigned long offset) | 176 | static inline u32 pg_readl(u32 bank, u32 reg) |
174 | { | 177 | { |
175 | return readl(IO_TO_VIRT(TEGRA_APB_MISC_BASE + offset)); | 178 | return readl(regs[bank] + reg); |
176 | } | 179 | } |
177 | 180 | ||
178 | static inline void pg_writel(unsigned long value, unsigned long offset) | 181 | static inline void pg_writel(u32 val, u32 bank, u32 reg) |
179 | { | 182 | { |
180 | writel(value, IO_TO_VIRT(TEGRA_APB_MISC_BASE + offset)); | 183 | writel(val, regs[bank] + reg); |
181 | } | 184 | } |
182 | 185 | ||
183 | static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config) | 186 | static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config) |
@@ -217,10 +220,10 @@ static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config) | |||
217 | 220 | ||
218 | spin_lock_irqsave(&mux_lock, flags); | 221 | spin_lock_irqsave(&mux_lock, flags); |
219 | 222 | ||
220 | reg = pg_readl(pingroups[pg].mux_reg); | 223 | reg = pg_readl(pingroups[pg].mux_bank, pingroups[pg].mux_reg); |
221 | reg &= ~(0x3 << pingroups[pg].mux_bit); | 224 | reg &= ~(0x3 << pingroups[pg].mux_bit); |
222 | reg |= mux << pingroups[pg].mux_bit; | 225 | reg |= mux << pingroups[pg].mux_bit; |
223 | pg_writel(reg, pingroups[pg].mux_reg); | 226 | pg_writel(reg, pingroups[pg].mux_bank, pingroups[pg].mux_reg); |
224 | 227 | ||
225 | spin_unlock_irqrestore(&mux_lock, flags); | 228 | spin_unlock_irqrestore(&mux_lock, flags); |
226 | 229 | ||
@@ -241,11 +244,11 @@ int tegra_pinmux_set_tristate(enum tegra_pingroup pg, | |||
241 | 244 | ||
242 | spin_lock_irqsave(&mux_lock, flags); | 245 | spin_lock_irqsave(&mux_lock, flags); |
243 | 246 | ||
244 | reg = pg_readl(pingroups[pg].tri_reg); | 247 | reg = pg_readl(pingroups[pg].tri_bank, pingroups[pg].tri_reg); |
245 | reg &= ~(0x1 << pingroups[pg].tri_bit); | 248 | reg &= ~(0x1 << pingroups[pg].tri_bit); |
246 | if (tristate) | 249 | if (tristate) |
247 | reg |= 1 << pingroups[pg].tri_bit; | 250 | reg |= 1 << pingroups[pg].tri_bit; |
248 | pg_writel(reg, pingroups[pg].tri_reg); | 251 | pg_writel(reg, pingroups[pg].tri_bank, pingroups[pg].tri_reg); |
249 | 252 | ||
250 | spin_unlock_irqrestore(&mux_lock, flags); | 253 | spin_unlock_irqrestore(&mux_lock, flags); |
251 | 254 | ||
@@ -272,10 +275,10 @@ int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg, | |||
272 | 275 | ||
273 | spin_lock_irqsave(&mux_lock, flags); | 276 | spin_lock_irqsave(&mux_lock, flags); |
274 | 277 | ||
275 | reg = pg_readl(pingroups[pg].pupd_reg); | 278 | reg = pg_readl(pingroups[pg].pupd_bank, pingroups[pg].pupd_reg); |
276 | reg &= ~(0x3 << pingroups[pg].pupd_bit); | 279 | reg &= ~(0x3 << pingroups[pg].pupd_bit); |
277 | reg |= pupd << pingroups[pg].pupd_bit; | 280 | reg |= pupd << pingroups[pg].pupd_bit; |
278 | pg_writel(reg, pingroups[pg].pupd_reg); | 281 | pg_writel(reg, pingroups[pg].pupd_bank, pingroups[pg].pupd_reg); |
279 | 282 | ||
280 | spin_unlock_irqrestore(&mux_lock, flags); | 283 | spin_unlock_irqrestore(&mux_lock, flags); |
281 | 284 | ||
@@ -362,12 +365,12 @@ static int tegra_drive_pinmux_set_hsm(enum tegra_drive_pingroup pg, | |||
362 | 365 | ||
363 | spin_lock_irqsave(&mux_lock, flags); | 366 | spin_lock_irqsave(&mux_lock, flags); |
364 | 367 | ||
365 | reg = pg_readl(drive_pingroups[pg].reg); | 368 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
366 | if (hsm == TEGRA_HSM_ENABLE) | 369 | if (hsm == TEGRA_HSM_ENABLE) |
367 | reg |= (1 << 2); | 370 | reg |= (1 << 2); |
368 | else | 371 | else |
369 | reg &= ~(1 << 2); | 372 | reg &= ~(1 << 2); |
370 | pg_writel(reg, drive_pingroups[pg].reg); | 373 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
371 | 374 | ||
372 | spin_unlock_irqrestore(&mux_lock, flags); | 375 | spin_unlock_irqrestore(&mux_lock, flags); |
373 | 376 | ||
@@ -387,12 +390,12 @@ static int tegra_drive_pinmux_set_schmitt(enum tegra_drive_pingroup pg, | |||
387 | 390 | ||
388 | spin_lock_irqsave(&mux_lock, flags); | 391 | spin_lock_irqsave(&mux_lock, flags); |
389 | 392 | ||
390 | reg = pg_readl(drive_pingroups[pg].reg); | 393 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
391 | if (schmitt == TEGRA_SCHMITT_ENABLE) | 394 | if (schmitt == TEGRA_SCHMITT_ENABLE) |
392 | reg |= (1 << 3); | 395 | reg |= (1 << 3); |
393 | else | 396 | else |
394 | reg &= ~(1 << 3); | 397 | reg &= ~(1 << 3); |
395 | pg_writel(reg, drive_pingroups[pg].reg); | 398 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
396 | 399 | ||
397 | spin_unlock_irqrestore(&mux_lock, flags); | 400 | spin_unlock_irqrestore(&mux_lock, flags); |
398 | 401 | ||
@@ -412,10 +415,10 @@ static int tegra_drive_pinmux_set_drive(enum tegra_drive_pingroup pg, | |||
412 | 415 | ||
413 | spin_lock_irqsave(&mux_lock, flags); | 416 | spin_lock_irqsave(&mux_lock, flags); |
414 | 417 | ||
415 | reg = pg_readl(drive_pingroups[pg].reg); | 418 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
416 | reg &= ~(0x3 << 4); | 419 | reg &= ~(0x3 << 4); |
417 | reg |= drive << 4; | 420 | reg |= drive << 4; |
418 | pg_writel(reg, drive_pingroups[pg].reg); | 421 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
419 | 422 | ||
420 | spin_unlock_irqrestore(&mux_lock, flags); | 423 | spin_unlock_irqrestore(&mux_lock, flags); |
421 | 424 | ||
@@ -435,10 +438,10 @@ static int tegra_drive_pinmux_set_pull_down(enum tegra_drive_pingroup pg, | |||
435 | 438 | ||
436 | spin_lock_irqsave(&mux_lock, flags); | 439 | spin_lock_irqsave(&mux_lock, flags); |
437 | 440 | ||
438 | reg = pg_readl(drive_pingroups[pg].reg); | 441 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
439 | reg &= ~(0x1f << 12); | 442 | reg &= ~(0x1f << 12); |
440 | reg |= pull_down << 12; | 443 | reg |= pull_down << 12; |
441 | pg_writel(reg, drive_pingroups[pg].reg); | 444 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
442 | 445 | ||
443 | spin_unlock_irqrestore(&mux_lock, flags); | 446 | spin_unlock_irqrestore(&mux_lock, flags); |
444 | 447 | ||
@@ -458,10 +461,10 @@ static int tegra_drive_pinmux_set_pull_up(enum tegra_drive_pingroup pg, | |||
458 | 461 | ||
459 | spin_lock_irqsave(&mux_lock, flags); | 462 | spin_lock_irqsave(&mux_lock, flags); |
460 | 463 | ||
461 | reg = pg_readl(drive_pingroups[pg].reg); | 464 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
462 | reg &= ~(0x1f << 12); | 465 | reg &= ~(0x1f << 12); |
463 | reg |= pull_up << 12; | 466 | reg |= pull_up << 12; |
464 | pg_writel(reg, drive_pingroups[pg].reg); | 467 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
465 | 468 | ||
466 | spin_unlock_irqrestore(&mux_lock, flags); | 469 | spin_unlock_irqrestore(&mux_lock, flags); |
467 | 470 | ||
@@ -481,10 +484,10 @@ static int tegra_drive_pinmux_set_slew_rising(enum tegra_drive_pingroup pg, | |||
481 | 484 | ||
482 | spin_lock_irqsave(&mux_lock, flags); | 485 | spin_lock_irqsave(&mux_lock, flags); |
483 | 486 | ||
484 | reg = pg_readl(drive_pingroups[pg].reg); | 487 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
485 | reg &= ~(0x3 << 28); | 488 | reg &= ~(0x3 << 28); |
486 | reg |= slew_rising << 28; | 489 | reg |= slew_rising << 28; |
487 | pg_writel(reg, drive_pingroups[pg].reg); | 490 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
488 | 491 | ||
489 | spin_unlock_irqrestore(&mux_lock, flags); | 492 | spin_unlock_irqrestore(&mux_lock, flags); |
490 | 493 | ||
@@ -504,10 +507,10 @@ static int tegra_drive_pinmux_set_slew_falling(enum tegra_drive_pingroup pg, | |||
504 | 507 | ||
505 | spin_lock_irqsave(&mux_lock, flags); | 508 | spin_lock_irqsave(&mux_lock, flags); |
506 | 509 | ||
507 | reg = pg_readl(drive_pingroups[pg].reg); | 510 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
508 | reg &= ~(0x3 << 30); | 511 | reg &= ~(0x3 << 30); |
509 | reg |= slew_falling << 30; | 512 | reg |= slew_falling << 30; |
510 | pg_writel(reg, drive_pingroups[pg].reg); | 513 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); |
511 | 514 | ||
512 | spin_unlock_irqrestore(&mux_lock, flags); | 515 | spin_unlock_irqrestore(&mux_lock, flags); |
513 | 516 | ||
@@ -665,6 +668,99 @@ void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *co | |||
665 | } | 668 | } |
666 | } | 669 | } |
667 | 670 | ||
671 | static int __devinit tegra_pinmux_probe(struct platform_device *pdev) | ||
672 | { | ||
673 | struct resource *res; | ||
674 | int i; | ||
675 | int config_bad = 0; | ||
676 | |||
677 | for (i = 0; ; i++) { | ||
678 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
679 | if (!res) | ||
680 | break; | ||
681 | } | ||
682 | nbanks = i; | ||
683 | |||
684 | for (i = 0; i < TEGRA_MAX_PINGROUP; i++) { | ||
685 | if (pingroups[i].tri_bank >= nbanks) { | ||
686 | dev_err(&pdev->dev, "pingroup %d: bad tri_bank\n", i); | ||
687 | config_bad = 1; | ||
688 | } | ||
689 | |||
690 | if (pingroups[i].mux_bank >= nbanks) { | ||
691 | dev_err(&pdev->dev, "pingroup %d: bad mux_bank\n", i); | ||
692 | config_bad = 1; | ||
693 | } | ||
694 | |||
695 | if (pingroups[i].pupd_bank >= nbanks) { | ||
696 | dev_err(&pdev->dev, "pingroup %d: bad pupd_bank\n", i); | ||
697 | config_bad = 1; | ||
698 | } | ||
699 | } | ||
700 | |||
701 | for (i = 0; i < TEGRA_MAX_DRIVE_PINGROUP; i++) { | ||
702 | if (drive_pingroups[i].reg_bank >= nbanks) { | ||
703 | dev_err(&pdev->dev, | ||
704 | "drive pingroup %d: bad reg_bank\n", i); | ||
705 | config_bad = 1; | ||
706 | } | ||
707 | } | ||
708 | |||
709 | if (config_bad) | ||
710 | return -ENODEV; | ||
711 | |||
712 | regs = devm_kzalloc(&pdev->dev, nbanks * sizeof(*regs), GFP_KERNEL); | ||
713 | if (!regs) { | ||
714 | dev_err(&pdev->dev, "Can't alloc regs pointer\n"); | ||
715 | return -ENODEV; | ||
716 | } | ||
717 | |||
718 | for (i = 0; i < nbanks; i++) { | ||
719 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
720 | if (!res) { | ||
721 | dev_err(&pdev->dev, "Missing MEM resource\n"); | ||
722 | return -ENODEV; | ||
723 | } | ||
724 | |||
725 | if (!devm_request_mem_region(&pdev->dev, res->start, | ||
726 | resource_size(res), | ||
727 | dev_name(&pdev->dev))) { | ||
728 | dev_err(&pdev->dev, | ||
729 | "Couldn't request MEM resource %d\n", i); | ||
730 | return -ENODEV; | ||
731 | } | ||
732 | |||
733 | regs[i] = devm_ioremap(&pdev->dev, res->start, | ||
734 | resource_size(res)); | ||
735 | if (!regs) { | ||
736 | dev_err(&pdev->dev, "Couldn't ioremap regs %d\n", i); | ||
737 | return -ENODEV; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | return 0; | ||
742 | } | ||
743 | |||
744 | static struct of_device_id tegra_pinmux_of_match[] __devinitdata = { | ||
745 | { .compatible = "nvidia,tegra20-pinmux", }, | ||
746 | { }, | ||
747 | }; | ||
748 | |||
749 | static struct platform_driver tegra_pinmux_driver = { | ||
750 | .driver = { | ||
751 | .name = "tegra-pinmux", | ||
752 | .owner = THIS_MODULE, | ||
753 | .of_match_table = tegra_pinmux_of_match, | ||
754 | }, | ||
755 | .probe = tegra_pinmux_probe, | ||
756 | }; | ||
757 | |||
758 | static int __init tegra_pinmux_init(void) | ||
759 | { | ||
760 | return platform_driver_register(&tegra_pinmux_driver); | ||
761 | } | ||
762 | postcore_initcall(tegra_pinmux_init); | ||
763 | |||
668 | #ifdef CONFIG_DEBUG_FS | 764 | #ifdef CONFIG_DEBUG_FS |
669 | 765 | ||
670 | #include <linux/debugfs.h> | 766 | #include <linux/debugfs.h> |
@@ -684,6 +780,7 @@ static int dbg_pinmux_show(struct seq_file *s, void *unused) | |||
684 | int len; | 780 | int len; |
685 | 781 | ||
686 | for (i = 0; i < TEGRA_MAX_PINGROUP; i++) { | 782 | for (i = 0; i < TEGRA_MAX_PINGROUP; i++) { |
783 | unsigned long reg; | ||
687 | unsigned long tri; | 784 | unsigned long tri; |
688 | unsigned long mux; | 785 | unsigned long mux; |
689 | unsigned long pupd; | 786 | unsigned long pupd; |
@@ -696,8 +793,9 @@ static int dbg_pinmux_show(struct seq_file *s, void *unused) | |||
696 | seq_printf(s, "TEGRA_MUX_NONE"); | 793 | seq_printf(s, "TEGRA_MUX_NONE"); |
697 | len = strlen("NONE"); | 794 | len = strlen("NONE"); |
698 | } else { | 795 | } else { |
699 | mux = (pg_readl(pingroups[i].mux_reg) >> | 796 | reg = pg_readl(pingroups[i].mux_bank, |
700 | pingroups[i].mux_bit) & 0x3; | 797 | pingroups[i].mux_reg); |
798 | mux = (reg >> pingroups[i].mux_bit) & 0x3; | ||
701 | if (pingroups[i].funcs[mux] == TEGRA_MUX_RSVD) { | 799 | if (pingroups[i].funcs[mux] == TEGRA_MUX_RSVD) { |
702 | seq_printf(s, "TEGRA_MUX_RSVD%1lu", mux+1); | 800 | seq_printf(s, "TEGRA_MUX_RSVD%1lu", mux+1); |
703 | len = 5; | 801 | len = 5; |
@@ -713,8 +811,9 @@ static int dbg_pinmux_show(struct seq_file *s, void *unused) | |||
713 | seq_printf(s, "TEGRA_PUPD_NORMAL"); | 811 | seq_printf(s, "TEGRA_PUPD_NORMAL"); |
714 | len = strlen("NORMAL"); | 812 | len = strlen("NORMAL"); |
715 | } else { | 813 | } else { |
716 | pupd = (pg_readl(pingroups[i].pupd_reg) >> | 814 | reg = pg_readl(pingroups[i].pupd_bank, |
717 | pingroups[i].pupd_bit) & 0x3; | 815 | pingroups[i].pupd_reg); |
816 | pupd = (reg >> pingroups[i].pupd_bit) & 0x3; | ||
718 | seq_printf(s, "TEGRA_PUPD_%s", pupd_name(pupd)); | 817 | seq_printf(s, "TEGRA_PUPD_%s", pupd_name(pupd)); |
719 | len = strlen(pupd_name(pupd)); | 818 | len = strlen(pupd_name(pupd)); |
720 | } | 819 | } |
@@ -723,8 +822,9 @@ static int dbg_pinmux_show(struct seq_file *s, void *unused) | |||
723 | if (pingroups[i].tri_reg < 0) { | 822 | if (pingroups[i].tri_reg < 0) { |
724 | seq_printf(s, "TEGRA_TRI_NORMAL"); | 823 | seq_printf(s, "TEGRA_TRI_NORMAL"); |
725 | } else { | 824 | } else { |
726 | tri = (pg_readl(pingroups[i].tri_reg) >> | 825 | reg = pg_readl(pingroups[i].tri_bank, |
727 | pingroups[i].tri_bit) & 0x1; | 826 | pingroups[i].tri_reg); |
827 | tri = (reg >> pingroups[i].tri_bit) & 0x1; | ||
728 | 828 | ||
729 | seq_printf(s, "TEGRA_TRI_%s", tri_name(tri)); | 829 | seq_printf(s, "TEGRA_TRI_%s", tri_name(tri)); |
730 | } | 830 | } |
@@ -759,7 +859,8 @@ static int dbg_drive_pinmux_show(struct seq_file *s, void *unused) | |||
759 | dbg_pad_field(s, 7 - len); | 859 | dbg_pad_field(s, 7 - len); |
760 | 860 | ||
761 | 861 | ||
762 | reg = pg_readl(drive_pingroups[i].reg); | 862 | reg = pg_readl(drive_pingroups[i].reg_bank, |
863 | drive_pingroups[i].reg); | ||
763 | if (HSM_EN(reg)) { | 864 | if (HSM_EN(reg)) { |
764 | seq_printf(s, "TEGRA_HSM_ENABLE"); | 865 | seq_printf(s, "TEGRA_HSM_ENABLE"); |
765 | len = 16; | 866 | len = 16; |