mfp.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. /* mfp_spin_lock is used to ensure that MFP register configuration
  22. * (most likely a read-modify-write operation) is atomic, and that
  23. * mfp_table[] is consistent
  24. */
  25. static DEFINE_SPINLOCK(mfp_spin_lock);
  26. static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE);
  27. static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX];
  28. #define mfpr_readl(off) \
  29. __raw_readl(mfpr_mmio_base + (off))
  30. #define mfpr_writel(off, val) \
  31. __raw_writel(val, mfpr_mmio_base + (off))
  32. /*
  33. * perform a read-back of any MFPR register to make sure the
  34. * previous writings are finished
  35. */
  36. #define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0)
  37. static inline void __mfp_config(int pin, unsigned long val)
  38. {
  39. unsigned long off = mfp_table[pin].mfpr_off;
  40. mfp_table[pin].mfpr_val = val;
  41. mfpr_writel(off, val);
  42. }
  43. void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num)
  44. {
  45. int i, pin;
  46. unsigned long val, flags;
  47. mfp_cfg_t *mfp_cfg = mfp_cfgs;
  48. spin_lock_irqsave(&mfp_spin_lock, flags);
  49. for (i = 0; i < num; i++, mfp_cfg++) {
  50. pin = MFP_CFG_PIN(*mfp_cfg);
  51. val = MFP_CFG_VAL(*mfp_cfg);
  52. BUG_ON(pin >= MFP_PIN_MAX);
  53. __mfp_config(pin, val);
  54. }
  55. mfpr_sync();
  56. spin_unlock_irqrestore(&mfp_spin_lock, flags);
  57. }
  58. unsigned long pxa3xx_mfp_read(int mfp)
  59. {
  60. unsigned long val, flags;
  61. BUG_ON(mfp >= MFP_PIN_MAX);
  62. spin_lock_irqsave(&mfp_spin_lock, flags);
  63. val = mfpr_readl(mfp_table[mfp].mfpr_off);
  64. spin_unlock_irqrestore(&mfp_spin_lock, flags);
  65. return val;
  66. }
  67. void pxa3xx_mfp_write(int mfp, unsigned long val)
  68. {
  69. unsigned long flags;
  70. BUG_ON(mfp >= MFP_PIN_MAX);
  71. spin_lock_irqsave(&mfp_spin_lock, flags);
  72. mfpr_writel(mfp_table[mfp].mfpr_off, val);
  73. mfpr_sync();
  74. spin_unlock_irqrestore(&mfp_spin_lock, flags);
  75. }
  76. void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map)
  77. {
  78. struct pxa3xx_mfp_addr_map *p;
  79. unsigned long offset, flags;
  80. int i;
  81. spin_lock_irqsave(&mfp_spin_lock, flags);
  82. for (p = map; p->start != MFP_PIN_INVALID; p++) {
  83. offset = p->offset;
  84. i = p->start;
  85. do {
  86. mfp_table[i].mfpr_off = offset;
  87. mfp_table[i].mfpr_val = 0;
  88. offset += 4; i++;
  89. } while ((i <= p->end) && (p->end != -1));
  90. }
  91. spin_unlock_irqrestore(&mfp_spin_lock, flags);
  92. }
  93. void __init pxa3xx_init_mfp(void)
  94. {
  95. memset(mfp_table, 0, sizeof(mfp_table));
  96. }