mfp.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * linux/arch/arm/mach-pxa/mfp.c
  3. *
  4. * PXA3xx Multi-Function Pin Support
  5. *
  6. * Copyright (C) 2007 Marvell Internation Ltd.
  7. *
  8. * 2007-08-21: eric miao <eric.miao@marvell.com>
  9. * initial version
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License version 2 as
  13. * published by the Free Software Foundation.
  14. */
  15. #include <linux/module.h>
  16. #include <linux/kernel.h>
  17. #include <linux/init.h>
  18. #include <linux/io.h>
  19. #include <asm/hardware.h>
  20. #include <asm/arch/mfp.h>
  21. #include <asm/arch/mfp-pxa3xx.h>
  22. /* mfp_spin_lock is used to ensure that MFP register configuration
  23. * (most likely a read-modify-write operation) is atomic, and that
  24. * mfp_table[] is consistent
  25. */
  26. static DEFINE_SPINLOCK(mfp_spin_lock);
  27. static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE);
  28. struct pxa3xx_mfp_pin {
  29. unsigned long config; /* -1 for not configured */
  30. unsigned long mfpr_off; /* MFPRxx Register offset */
  31. unsigned long mfpr_run; /* Run-Mode Register Value */
  32. unsigned long mfpr_lpm; /* Low Power Mode Register Value */
  33. };
  34. static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX];
  35. /* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */
  36. const static unsigned long mfpr_lpm[] = {
  37. MFPR_LPM_INPUT,
  38. MFPR_LPM_DRIVE_LOW,
  39. MFPR_LPM_DRIVE_HIGH,
  40. MFPR_LPM_PULL_LOW,
  41. MFPR_LPM_PULL_HIGH,
  42. MFPR_LPM_FLOAT,
  43. };
  44. /* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */
  45. const static unsigned long mfpr_pull[] = {
  46. MFPR_PULL_NONE,
  47. MFPR_PULL_LOW,
  48. MFPR_PULL_HIGH,
  49. MFPR_PULL_BOTH,
  50. };
  51. /* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */
  52. const static unsigned long mfpr_edge[] = {
  53. MFPR_EDGE_NONE,
  54. MFPR_EDGE_RISE,
  55. MFPR_EDGE_FALL,
  56. MFPR_EDGE_BOTH,
  57. };
  58. #define mfpr_readl(off) \
  59. __raw_readl(mfpr_mmio_base + (off))
  60. #define mfpr_writel(off, val) \
  61. __raw_writel(val, mfpr_mmio_base + (off))
  62. #define mfp_configured(p) ((p)->config != -1)
  63. /*
  64. * perform a read-back of any MFPR register to make sure the
  65. * previous writings are finished
  66. */
  67. #define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0)
  68. static inline void __mfp_config_run(struct pxa3xx_mfp_pin *p)
  69. {
  70. if (mfp_configured(p))
  71. mfpr_writel(p->mfpr_off, p->mfpr_run);
  72. }
  73. static inline void __mfp_config_lpm(struct pxa3xx_mfp_pin *p)
  74. {
  75. if (mfp_configured(p) && p->mfpr_lpm != p->mfpr_run)
  76. mfpr_writel(p->mfpr_off, p->mfpr_lpm);
  77. }
  78. void pxa3xx_mfp_config(unsigned long *mfp_cfgs, int num)
  79. {
  80. unsigned long flags;
  81. int i;
  82. spin_lock_irqsave(&mfp_spin_lock, flags);
  83. for (i = 0; i < num; i++, mfp_cfgs++) {
  84. unsigned long tmp, c = *mfp_cfgs;
  85. struct pxa3xx_mfp_pin *p;
  86. int pin, af, drv, lpm, edge, pull;
  87. pin = MFP_PIN(c);
  88. BUG_ON(pin >= MFP_PIN_MAX);
  89. p = &mfp_table[pin];
  90. af = MFP_AF(c);
  91. drv = MFP_DS(c);
  92. lpm = MFP_LPM_STATE(c);
  93. edge = MFP_LPM_EDGE(c);
  94. pull = MFP_PULL(c);
  95. /* run-mode pull settings will conflict with MFPR bits of
  96. * low power mode state, calculate mfpr_run and mfpr_lpm
  97. * individually if pull != MFP_PULL_NONE
  98. */
  99. tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv);
  100. if (likely(pull == MFP_PULL_NONE)) {
  101. p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge];
  102. p->mfpr_lpm = p->mfpr_run;
  103. } else {
  104. p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge];
  105. p->mfpr_run = tmp | mfpr_pull[pull];
  106. }
  107. p->config = c; __mfp_config_run(p);
  108. }
  109. mfpr_sync();
  110. spin_unlock_irqrestore(&mfp_spin_lock, flags);
  111. }
  112. unsigned long pxa3xx_mfp_read(int mfp)
  113. {
  114. unsigned long val, flags;
  115. BUG_ON(mfp >= MFP_PIN_MAX);
  116. spin_lock_irqsave(&mfp_spin_lock, flags);
  117. val = mfpr_readl(mfp_table[mfp].mfpr_off);
  118. spin_unlock_irqrestore(&mfp_spin_lock, flags);
  119. return val;
  120. }
  121. void pxa3xx_mfp_write(int mfp, unsigned long val)
  122. {
  123. unsigned long flags;
  124. BUG_ON(mfp >= MFP_PIN_MAX);
  125. spin_lock_irqsave(&mfp_spin_lock, flags);
  126. mfpr_writel(mfp_table[mfp].mfpr_off, val);
  127. mfpr_sync();
  128. spin_unlock_irqrestore(&mfp_spin_lock, flags);
  129. }
  130. void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map)
  131. {
  132. struct pxa3xx_mfp_addr_map *p;
  133. unsigned long offset, flags;
  134. int i;
  135. spin_lock_irqsave(&mfp_spin_lock, flags);
  136. for (p = map; p->start != MFP_PIN_INVALID; p++) {
  137. offset = p->offset;
  138. i = p->start;
  139. do {
  140. mfp_table[i].mfpr_off = offset;
  141. mfp_table[i].mfpr_run = 0;
  142. mfp_table[i].mfpr_lpm = 0;
  143. offset += 4; i++;
  144. } while ((i <= p->end) && (p->end != -1));
  145. }
  146. spin_unlock_irqrestore(&mfp_spin_lock, flags);
  147. }
  148. void __init pxa3xx_init_mfp(void)
  149. {
  150. int i;
  151. for (i = 0; i < ARRAY_SIZE(mfp_table); i++)
  152. mfp_table[i].config = -1;
  153. }