mux.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * linux/arch/arm/mach-omap/mux.c
  3. *
  4. * Utility to set the Omap MUX and PULL_DWN registers from a table in mux.h
  5. *
  6. * Copyright (C) 2003 Nokia Corporation
  7. *
  8. * Written by Tony Lindgren <tony.lindgren@nokia.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. *
  24. */
  25. #include <linux/config.h>
  26. #include <linux/module.h>
  27. #include <linux/init.h>
  28. #include <asm/system.h>
  29. #include <asm/io.h>
  30. #include <linux/spinlock.h>
  31. #define __MUX_C__
  32. #include <asm/arch/mux.h>
  33. #ifdef CONFIG_OMAP_MUX
  34. /*
  35. * Sets the Omap MUX and PULL_DWN registers based on the table
  36. */
  37. int __init_or_module
  38. omap_cfg_reg(const reg_cfg_t reg_cfg)
  39. {
  40. static DEFINE_SPINLOCK(mux_spin_lock);
  41. unsigned long flags;
  42. reg_cfg_set *cfg;
  43. unsigned int reg_orig = 0, reg = 0, pu_pd_orig = 0, pu_pd = 0,
  44. pull_orig = 0, pull = 0;
  45. unsigned int mask, warn = 0;
  46. if (reg_cfg > ARRAY_SIZE(reg_cfg_table)) {
  47. printk(KERN_ERR "MUX: reg_cfg %d\n", reg_cfg);
  48. return -EINVAL;
  49. }
  50. cfg = &reg_cfg_table[reg_cfg];
  51. /*
  52. * We do a pretty long section here with lock on, but pin muxing
  53. * should only happen on driver init for each driver, so it's not time
  54. * critical.
  55. */
  56. spin_lock_irqsave(&mux_spin_lock, flags);
  57. /* Check the mux register in question */
  58. if (cfg->mux_reg) {
  59. unsigned tmp1, tmp2;
  60. reg_orig = omap_readl(cfg->mux_reg);
  61. /* The mux registers always seem to be 3 bits long */
  62. mask = (0x7 << cfg->mask_offset);
  63. tmp1 = reg_orig & mask;
  64. reg = reg_orig & ~mask;
  65. tmp2 = (cfg->mask << cfg->mask_offset);
  66. reg |= tmp2;
  67. if (tmp1 != tmp2)
  68. warn = 1;
  69. omap_writel(reg, cfg->mux_reg);
  70. }
  71. /* Check for pull up or pull down selection on 1610 */
  72. if (!cpu_is_omap1510()) {
  73. if (cfg->pu_pd_reg && cfg->pull_val) {
  74. pu_pd_orig = omap_readl(cfg->pu_pd_reg);
  75. mask = 1 << cfg->pull_bit;
  76. if (cfg->pu_pd_val) {
  77. if (!(pu_pd_orig & mask))
  78. warn = 1;
  79. /* Use pull up */
  80. pu_pd = pu_pd_orig | mask;
  81. } else {
  82. if (pu_pd_orig & mask)
  83. warn = 1;
  84. /* Use pull down */
  85. pu_pd = pu_pd_orig & ~mask;
  86. }
  87. omap_writel(pu_pd, cfg->pu_pd_reg);
  88. }
  89. }
  90. /* Check for an associated pull down register */
  91. if (cfg->pull_reg) {
  92. pull_orig = omap_readl(cfg->pull_reg);
  93. mask = 1 << cfg->pull_bit;
  94. if (cfg->pull_val) {
  95. if (pull_orig & mask)
  96. warn = 1;
  97. /* Low bit = pull enabled */
  98. pull = pull_orig & ~mask;
  99. } else {
  100. if (!(pull_orig & mask))
  101. warn = 1;
  102. /* High bit = pull disabled */
  103. pull = pull_orig | mask;
  104. }
  105. omap_writel(pull, cfg->pull_reg);
  106. }
  107. if (warn) {
  108. #ifdef CONFIG_OMAP_MUX_WARNINGS
  109. printk(KERN_WARNING "MUX: initialized %s\n", cfg->name);
  110. #endif
  111. }
  112. #ifdef CONFIG_OMAP_MUX_DEBUG
  113. if (cfg->debug || warn) {
  114. printk("MUX: Setting register %s\n", cfg->name);
  115. printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
  116. cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg);
  117. if (!cpu_is_omap1510()) {
  118. if (cfg->pu_pd_reg && cfg->pull_val) {
  119. printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
  120. cfg->pu_pd_name, cfg->pu_pd_reg,
  121. pu_pd_orig, pu_pd);
  122. }
  123. }
  124. if (cfg->pull_reg)
  125. printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
  126. cfg->pull_name, cfg->pull_reg, pull_orig, pull);
  127. }
  128. #endif
  129. spin_unlock_irqrestore(&mux_spin_lock, flags);
  130. #ifdef CONFIG_OMAP_MUX_ERRORS
  131. return warn ? -ETXTBSY : 0;
  132. #else
  133. return 0;
  134. #endif
  135. }
  136. EXPORT_SYMBOL(omap_cfg_reg);
  137. #endif /* CONFIG_OMAP_MUX */