2 * linux/arch/arm/mach-pxa/mfp.c
4 * PXA3xx Multi-Function Pin Support
6 * Copyright (C) 2007 Marvell Internation Ltd.
8 * 2007-08-21: eric miao <eric.miao@marvell.com>
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.
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/init.h>
21 #include <asm/hardware.h>
22 #include <asm/arch/mfp.h>
24 /* mfp_spin_lock is used to ensure that MFP register configuration
25 * (most likely a read-modify-write operation) is atomic, and that
26 * mfp_table[] is consistent
28 static DEFINE_SPINLOCK(mfp_spin_lock);
30 static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE);
31 static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX];
33 #define mfpr_readl(off) \
34 __raw_readl(mfpr_mmio_base + (off))
36 #define mfpr_writel(off, val) \
37 __raw_writel(val, mfpr_mmio_base + (off))
40 * perform a read-back of any MFPR register to make sure the
41 * previous writings are finished
43 #define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0)
45 static inline void __mfp_config(int pin, unsigned long val)
47 unsigned long off = mfp_table[pin].mfpr_off;
49 mfp_table[pin].mfpr_val = val;
50 mfpr_writel(off, val);
53 void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num)
56 unsigned long val, flags;
57 mfp_cfg_t *mfp_cfg = mfp_cfgs;
59 spin_lock_irqsave(&mfp_spin_lock, flags);
61 for (i = 0; i < num; i++, mfp_cfg++) {
62 pin = MFP_CFG_PIN(*mfp_cfg);
63 val = MFP_CFG_VAL(*mfp_cfg);
65 BUG_ON(pin >= MFP_PIN_MAX);
67 __mfp_config(pin, val);
71 spin_unlock_irqrestore(&mfp_spin_lock, flags);
74 unsigned long pxa3xx_mfp_read(int mfp)
76 unsigned long val, flags;
78 BUG_ON(mfp >= MFP_PIN_MAX);
80 spin_lock_irqsave(&mfp_spin_lock, flags);
81 val = mfpr_readl(mfp_table[mfp].mfpr_off);
82 spin_unlock_irqrestore(&mfp_spin_lock, flags);
87 void pxa3xx_mfp_write(int mfp, unsigned long val)
91 BUG_ON(mfp >= MFP_PIN_MAX);
93 spin_lock_irqsave(&mfp_spin_lock, flags);
94 mfpr_writel(mfp_table[mfp].mfpr_off, val);
96 spin_unlock_irqrestore(&mfp_spin_lock, flags);
99 void pxa3xx_mfp_set_afds(int mfp, int af, int ds)
101 uint32_t mfpr_off, mfpr_val;
104 BUG_ON(mfp >= MFP_PIN_MAX);
106 spin_lock_irqsave(&mfp_spin_lock, flags);
107 mfpr_off = mfp_table[mfp].mfpr_off;
109 mfpr_val = mfpr_readl(mfpr_off);
110 mfpr_val &= ~(MFPR_AF_MASK | MFPR_DRV_MASK);
111 mfpr_val |= (((af & 0x7) << MFPR_ALT_OFFSET) |
112 ((ds & 0x7) << MFPR_DRV_OFFSET));
114 mfpr_writel(mfpr_off, mfpr_val);
117 spin_unlock_irqrestore(&mfp_spin_lock, flags);
120 void pxa3xx_mfp_set_rdh(int mfp, int rdh)
122 uint32_t mfpr_off, mfpr_val;
125 BUG_ON(mfp >= MFP_PIN_MAX);
127 spin_lock_irqsave(&mfp_spin_lock, flags);
129 mfpr_off = mfp_table[mfp].mfpr_off;
131 mfpr_val = mfpr_readl(mfpr_off);
132 mfpr_val &= ~MFPR_RDH_MASK;
135 mfpr_val |= (1u << MFPR_SS_OFFSET);
137 mfpr_writel(mfpr_off, mfpr_val);
140 spin_unlock_irqrestore(&mfp_spin_lock, flags);
143 void pxa3xx_mfp_set_lpm(int mfp, int lpm)
145 uint32_t mfpr_off, mfpr_val;
148 BUG_ON(mfp >= MFP_PIN_MAX);
150 spin_lock_irqsave(&mfp_spin_lock, flags);
152 mfpr_off = mfp_table[mfp].mfpr_off;
153 mfpr_val = mfpr_readl(mfpr_off);
154 mfpr_val &= ~MFPR_LPM_MASK;
156 if (lpm & 0x1) mfpr_val |= 1u << MFPR_SON_OFFSET;
157 if (lpm & 0x2) mfpr_val |= 1u << MFPR_SD_OFFSET;
158 if (lpm & 0x4) mfpr_val |= 1u << MFPR_PU_OFFSET;
159 if (lpm & 0x8) mfpr_val |= 1u << MFPR_PD_OFFSET;
160 if (lpm &0x10) mfpr_val |= 1u << MFPR_PS_OFFSET;
162 mfpr_writel(mfpr_off, mfpr_val);
165 spin_unlock_irqrestore(&mfp_spin_lock, flags);
168 void pxa3xx_mfp_set_pull(int mfp, int pull)
170 uint32_t mfpr_off, mfpr_val;
173 BUG_ON(mfp >= MFP_PIN_MAX);
175 spin_lock_irqsave(&mfp_spin_lock, flags);
177 mfpr_off = mfp_table[mfp].mfpr_off;
178 mfpr_val = mfpr_readl(mfpr_off);
179 mfpr_val &= ~MFPR_PULL_MASK;
180 mfpr_val |= ((pull & 0x7u) << MFPR_PD_OFFSET);
182 mfpr_writel(mfpr_off, mfpr_val);
185 spin_unlock_irqrestore(&mfp_spin_lock, flags);
188 void pxa3xx_mfp_set_edge(int mfp, int edge)
190 uint32_t mfpr_off, mfpr_val;
193 BUG_ON(mfp >= MFP_PIN_MAX);
195 spin_lock_irqsave(&mfp_spin_lock, flags);
197 mfpr_off = mfp_table[mfp].mfpr_off;
198 mfpr_val = mfpr_readl(mfpr_off);
200 mfpr_val &= ~MFPR_EDGE_MASK;
201 mfpr_val |= (edge & 0x3u) << MFPR_ERE_OFFSET;
202 mfpr_val |= (!edge & 0x1) << MFPR_EC_OFFSET;
204 mfpr_writel(mfpr_off, mfpr_val);
207 spin_unlock_irqrestore(&mfp_spin_lock, flags);
210 void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map)
212 struct pxa3xx_mfp_addr_map *p;
213 unsigned long offset, flags;
216 spin_lock_irqsave(&mfp_spin_lock, flags);
218 for (p = map; p->start != MFP_PIN_INVALID; p++) {
223 mfp_table[i].mfpr_off = offset;
224 mfp_table[i].mfpr_val = 0;
226 } while ((i <= p->end) && (p->end != -1));
229 spin_unlock_irqrestore(&mfp_spin_lock, flags);
232 void __init pxa3xx_init_mfp(void)
234 memset(mfp_table, 0, sizeof(mfp_table));