aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-pxa/mfp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-pxa/mfp.c')
-rw-r--r--arch/arm/mach-pxa/mfp.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/mfp.c b/arch/arm/mach-pxa/mfp.c
new file mode 100644
index 000000000000..5cd3cadbbd10
--- /dev/null
+++ b/arch/arm/mach-pxa/mfp.c
@@ -0,0 +1,235 @@
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.y.miao@gmail.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
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/io.h>
20
21#include <asm/hardware.h>
22#include <asm/arch/mfp.h>
23
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
27 */
28static DEFINE_SPINLOCK(mfp_spin_lock);
29
30static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE);
31static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX];
32
33#define mfpr_readl(off) \
34 __raw_readl(mfpr_mmio_base + (off))
35
36#define mfpr_writel(off, val) \
37 __raw_writel(val, mfpr_mmio_base + (off))
38
39/*
40 * perform a read-back of any MFPR register to make sure the
41 * previous writings are finished
42 */
43#define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0)
44
45static inline void __mfp_config(int pin, unsigned long val)
46{
47 unsigned long off = mfp_table[pin].mfpr_off;
48
49 mfp_table[pin].mfpr_val = val;
50 mfpr_writel(off, val);
51}
52
53void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num)
54{
55 int i, pin;
56 unsigned long val, flags;
57 mfp_cfg_t *mfp_cfg = mfp_cfgs;
58
59 spin_lock_irqsave(&mfp_spin_lock, flags);
60
61 for (i = 0; i < num; i++, mfp_cfg++) {
62 pin = MFP_CFG_PIN(*mfp_cfg);
63 val = MFP_CFG_VAL(*mfp_cfg);
64
65 BUG_ON(pin >= MFP_PIN_MAX);
66
67 __mfp_config(pin, val);
68 }
69
70 mfpr_sync();
71 spin_unlock_irqrestore(&mfp_spin_lock, flags);
72}
73
74unsigned long pxa3xx_mfp_read(int mfp)
75{
76 unsigned long val, flags;
77
78 BUG_ON(mfp >= MFP_PIN_MAX);
79
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);
83
84 return val;
85}
86
87void pxa3xx_mfp_write(int mfp, unsigned long val)
88{
89 unsigned long flags;
90
91 BUG_ON(mfp >= MFP_PIN_MAX);
92
93 spin_lock_irqsave(&mfp_spin_lock, flags);
94 mfpr_writel(mfp_table[mfp].mfpr_off, val);
95 mfpr_sync();
96 spin_unlock_irqrestore(&mfp_spin_lock, flags);
97}
98
99void pxa3xx_mfp_set_afds(int mfp, int af, int ds)
100{
101 uint32_t mfpr_off, mfpr_val;
102 unsigned long flags;
103
104 BUG_ON(mfp >= MFP_PIN_MAX);
105
106 spin_lock_irqsave(&mfp_spin_lock, flags);
107 mfpr_off = mfp_table[mfp].mfpr_off;
108
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));
113
114 mfpr_writel(mfpr_off, mfpr_val);
115 mfpr_sync();
116
117 spin_unlock_irqrestore(&mfp_spin_lock, flags);
118}
119
120void pxa3xx_mfp_set_rdh(int mfp, int rdh)
121{
122 uint32_t mfpr_off, mfpr_val;
123 unsigned long flags;
124
125 BUG_ON(mfp >= MFP_PIN_MAX);
126
127 spin_lock_irqsave(&mfp_spin_lock, flags);
128
129 mfpr_off = mfp_table[mfp].mfpr_off;
130
131 mfpr_val = mfpr_readl(mfpr_off);
132 mfpr_val &= ~MFPR_RDH_MASK;
133
134 if (likely(rdh))
135 mfpr_val |= (1u << MFPR_SS_OFFSET);
136
137 mfpr_writel(mfpr_off, mfpr_val);
138 mfpr_sync();
139
140 spin_unlock_irqrestore(&mfp_spin_lock, flags);
141}
142
143void pxa3xx_mfp_set_lpm(int mfp, int lpm)
144{
145 uint32_t mfpr_off, mfpr_val;
146 unsigned long flags;
147
148 BUG_ON(mfp >= MFP_PIN_MAX);
149
150 spin_lock_irqsave(&mfp_spin_lock, flags);
151
152 mfpr_off = mfp_table[mfp].mfpr_off;
153 mfpr_val = mfpr_readl(mfpr_off);
154 mfpr_val &= ~MFPR_LPM_MASK;
155
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;
161
162 mfpr_writel(mfpr_off, mfpr_val);
163 mfpr_sync();
164
165 spin_unlock_irqrestore(&mfp_spin_lock, flags);
166}
167
168void pxa3xx_mfp_set_pull(int mfp, int pull)
169{
170 uint32_t mfpr_off, mfpr_val;
171 unsigned long flags;
172
173 BUG_ON(mfp >= MFP_PIN_MAX);
174
175 spin_lock_irqsave(&mfp_spin_lock, flags);
176
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);
181
182 mfpr_writel(mfpr_off, mfpr_val);
183 mfpr_sync();
184
185 spin_unlock_irqrestore(&mfp_spin_lock, flags);
186}
187
188void pxa3xx_mfp_set_edge(int mfp, int edge)
189{
190 uint32_t mfpr_off, mfpr_val;
191 unsigned long flags;
192
193 BUG_ON(mfp >= MFP_PIN_MAX);
194
195 spin_lock_irqsave(&mfp_spin_lock, flags);
196
197 mfpr_off = mfp_table[mfp].mfpr_off;
198 mfpr_val = mfpr_readl(mfpr_off);
199
200 mfpr_val &= ~MFPR_EDGE_MASK;
201 mfpr_val |= (edge & 0x3u) << MFPR_ERE_OFFSET;
202 mfpr_val |= (!edge & 0x1) << MFPR_EC_OFFSET;
203
204 mfpr_writel(mfpr_off, mfpr_val);
205 mfpr_sync();
206
207 spin_unlock_irqrestore(&mfp_spin_lock, flags);
208}
209
210void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map)
211{
212 struct pxa3xx_mfp_addr_map *p;
213 unsigned long offset, flags;
214 int i;
215
216 spin_lock_irqsave(&mfp_spin_lock, flags);
217
218 for (p = map; p->start != MFP_PIN_INVALID; p++) {
219 offset = p->offset;
220 i = p->start;
221
222 do {
223 mfp_table[i].mfpr_off = offset;
224 mfp_table[i].mfpr_val = 0;
225 offset += 4; i++;
226 } while ((i <= p->end) && (p->end != -1));
227 }
228
229 spin_unlock_irqrestore(&mfp_spin_lock, flags);
230}
231
232void __init pxa3xx_init_mfp(void)
233{
234 memset(mfp_table, 0, sizeof(mfp_table));
235}