diff options
Diffstat (limited to 'arch/arm/mach-pxa/mfp.c')
-rw-r--r-- | arch/arm/mach-pxa/mfp.c | 261 |
1 files changed, 136 insertions, 125 deletions
diff --git a/arch/arm/mach-pxa/mfp.c b/arch/arm/mach-pxa/mfp.c index 436f96574964..ec1b2d8f61c4 100644 --- a/arch/arm/mach-pxa/mfp.c +++ b/arch/arm/mach-pxa/mfp.c | |||
@@ -17,9 +17,11 @@ | |||
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | #include <linux/sysdev.h> | ||
20 | 21 | ||
21 | #include <asm/hardware.h> | 22 | #include <asm/hardware.h> |
22 | #include <asm/arch/mfp.h> | 23 | #include <asm/arch/mfp.h> |
24 | #include <asm/arch/mfp-pxa3xx.h> | ||
23 | 25 | ||
24 | /* mfp_spin_lock is used to ensure that MFP register configuration | 26 | /* mfp_spin_lock is used to ensure that MFP register configuration |
25 | * (most likely a read-modify-write operation) is atomic, and that | 27 | * (most likely a read-modify-write operation) is atomic, and that |
@@ -28,43 +30,110 @@ | |||
28 | static DEFINE_SPINLOCK(mfp_spin_lock); | 30 | static DEFINE_SPINLOCK(mfp_spin_lock); |
29 | 31 | ||
30 | static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE); | 32 | static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE); |
33 | |||
34 | struct pxa3xx_mfp_pin { | ||
35 | unsigned long config; /* -1 for not configured */ | ||
36 | unsigned long mfpr_off; /* MFPRxx Register offset */ | ||
37 | unsigned long mfpr_run; /* Run-Mode Register Value */ | ||
38 | unsigned long mfpr_lpm; /* Low Power Mode Register Value */ | ||
39 | }; | ||
40 | |||
31 | static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX]; | 41 | static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX]; |
32 | 42 | ||
43 | /* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */ | ||
44 | const static unsigned long mfpr_lpm[] = { | ||
45 | MFPR_LPM_INPUT, | ||
46 | MFPR_LPM_DRIVE_LOW, | ||
47 | MFPR_LPM_DRIVE_HIGH, | ||
48 | MFPR_LPM_PULL_LOW, | ||
49 | MFPR_LPM_PULL_HIGH, | ||
50 | MFPR_LPM_FLOAT, | ||
51 | }; | ||
52 | |||
53 | /* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */ | ||
54 | const static unsigned long mfpr_pull[] = { | ||
55 | MFPR_PULL_NONE, | ||
56 | MFPR_PULL_LOW, | ||
57 | MFPR_PULL_HIGH, | ||
58 | MFPR_PULL_BOTH, | ||
59 | }; | ||
60 | |||
61 | /* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */ | ||
62 | const static unsigned long mfpr_edge[] = { | ||
63 | MFPR_EDGE_NONE, | ||
64 | MFPR_EDGE_RISE, | ||
65 | MFPR_EDGE_FALL, | ||
66 | MFPR_EDGE_BOTH, | ||
67 | }; | ||
68 | |||
33 | #define mfpr_readl(off) \ | 69 | #define mfpr_readl(off) \ |
34 | __raw_readl(mfpr_mmio_base + (off)) | 70 | __raw_readl(mfpr_mmio_base + (off)) |
35 | 71 | ||
36 | #define mfpr_writel(off, val) \ | 72 | #define mfpr_writel(off, val) \ |
37 | __raw_writel(val, mfpr_mmio_base + (off)) | 73 | __raw_writel(val, mfpr_mmio_base + (off)) |
38 | 74 | ||
75 | #define mfp_configured(p) ((p)->config != -1) | ||
76 | |||
39 | /* | 77 | /* |
40 | * perform a read-back of any MFPR register to make sure the | 78 | * perform a read-back of any MFPR register to make sure the |
41 | * previous writings are finished | 79 | * previous writings are finished |
42 | */ | 80 | */ |
43 | #define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0) | 81 | #define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0) |
44 | 82 | ||
45 | static inline void __mfp_config(int pin, unsigned long val) | 83 | static inline void __mfp_config_run(struct pxa3xx_mfp_pin *p) |
46 | { | 84 | { |
47 | unsigned long off = mfp_table[pin].mfpr_off; | 85 | if (mfp_configured(p)) |
86 | mfpr_writel(p->mfpr_off, p->mfpr_run); | ||
87 | } | ||
48 | 88 | ||
49 | mfp_table[pin].mfpr_val = val; | 89 | static inline void __mfp_config_lpm(struct pxa3xx_mfp_pin *p) |
50 | mfpr_writel(off, val); | 90 | { |
91 | if (mfp_configured(p)) { | ||
92 | unsigned long mfpr_clr = (p->mfpr_run & ~MFPR_EDGE_BOTH) | MFPR_EDGE_CLEAR; | ||
93 | if (mfpr_clr != p->mfpr_run) | ||
94 | mfpr_writel(p->mfpr_off, mfpr_clr); | ||
95 | if (p->mfpr_lpm != mfpr_clr) | ||
96 | mfpr_writel(p->mfpr_off, p->mfpr_lpm); | ||
97 | } | ||
51 | } | 98 | } |
52 | 99 | ||
53 | void pxa3xx_mfp_config(mfp_cfg_t *mfp_cfgs, int num) | 100 | void pxa3xx_mfp_config(unsigned long *mfp_cfgs, int num) |
54 | { | 101 | { |
55 | int i, pin; | 102 | unsigned long flags; |
56 | unsigned long val, flags; | 103 | int i; |
57 | mfp_cfg_t *mfp_cfg = mfp_cfgs; | ||
58 | 104 | ||
59 | spin_lock_irqsave(&mfp_spin_lock, flags); | 105 | spin_lock_irqsave(&mfp_spin_lock, flags); |
60 | 106 | ||
61 | for (i = 0; i < num; i++, mfp_cfg++) { | 107 | for (i = 0; i < num; i++, mfp_cfgs++) { |
62 | pin = MFP_CFG_PIN(*mfp_cfg); | 108 | unsigned long tmp, c = *mfp_cfgs; |
63 | val = MFP_CFG_VAL(*mfp_cfg); | 109 | struct pxa3xx_mfp_pin *p; |
110 | int pin, af, drv, lpm, edge, pull; | ||
64 | 111 | ||
112 | pin = MFP_PIN(c); | ||
65 | BUG_ON(pin >= MFP_PIN_MAX); | 113 | BUG_ON(pin >= MFP_PIN_MAX); |
66 | 114 | p = &mfp_table[pin]; | |
67 | __mfp_config(pin, val); | 115 | |
116 | af = MFP_AF(c); | ||
117 | drv = MFP_DS(c); | ||
118 | lpm = MFP_LPM_STATE(c); | ||
119 | edge = MFP_LPM_EDGE(c); | ||
120 | pull = MFP_PULL(c); | ||
121 | |||
122 | /* run-mode pull settings will conflict with MFPR bits of | ||
123 | * low power mode state, calculate mfpr_run and mfpr_lpm | ||
124 | * individually if pull != MFP_PULL_NONE | ||
125 | */ | ||
126 | tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv); | ||
127 | |||
128 | if (likely(pull == MFP_PULL_NONE)) { | ||
129 | p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; | ||
130 | p->mfpr_lpm = p->mfpr_run; | ||
131 | } else { | ||
132 | p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; | ||
133 | p->mfpr_run = tmp | mfpr_pull[pull]; | ||
134 | } | ||
135 | |||
136 | p->config = c; __mfp_config_run(p); | ||
68 | } | 137 | } |
69 | 138 | ||
70 | mfpr_sync(); | 139 | mfpr_sync(); |
@@ -96,140 +165,82 @@ void pxa3xx_mfp_write(int mfp, unsigned long val) | |||
96 | spin_unlock_irqrestore(&mfp_spin_lock, flags); | 165 | spin_unlock_irqrestore(&mfp_spin_lock, flags); |
97 | } | 166 | } |
98 | 167 | ||
99 | void pxa3xx_mfp_set_afds(int mfp, int af, int ds) | 168 | void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map) |
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 | |||
120 | void pxa3xx_mfp_set_rdh(int mfp, int rdh) | ||
121 | { | 169 | { |
122 | uint32_t mfpr_off, mfpr_val; | 170 | struct pxa3xx_mfp_addr_map *p; |
123 | unsigned long flags; | 171 | unsigned long offset, flags; |
124 | 172 | int i; | |
125 | BUG_ON(mfp >= MFP_PIN_MAX); | ||
126 | 173 | ||
127 | spin_lock_irqsave(&mfp_spin_lock, flags); | 174 | spin_lock_irqsave(&mfp_spin_lock, flags); |
128 | 175 | ||
129 | mfpr_off = mfp_table[mfp].mfpr_off; | 176 | for (p = map; p->start != MFP_PIN_INVALID; p++) { |
130 | 177 | offset = p->offset; | |
131 | mfpr_val = mfpr_readl(mfpr_off); | 178 | i = p->start; |
132 | mfpr_val &= ~MFPR_RDH_MASK; | ||
133 | |||
134 | if (likely(rdh)) | ||
135 | mfpr_val |= (1u << MFPR_SS_OFFSET); | ||
136 | 179 | ||
137 | mfpr_writel(mfpr_off, mfpr_val); | 180 | do { |
138 | mfpr_sync(); | 181 | mfp_table[i].mfpr_off = offset; |
182 | mfp_table[i].mfpr_run = 0; | ||
183 | mfp_table[i].mfpr_lpm = 0; | ||
184 | offset += 4; i++; | ||
185 | } while ((i <= p->end) && (p->end != -1)); | ||
186 | } | ||
139 | 187 | ||
140 | spin_unlock_irqrestore(&mfp_spin_lock, flags); | 188 | spin_unlock_irqrestore(&mfp_spin_lock, flags); |
141 | } | 189 | } |
142 | 190 | ||
143 | void pxa3xx_mfp_set_lpm(int mfp, int lpm) | 191 | void __init pxa3xx_init_mfp(void) |
144 | { | 192 | { |
145 | uint32_t mfpr_off, mfpr_val; | 193 | int i; |
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 | 194 | ||
165 | spin_unlock_irqrestore(&mfp_spin_lock, flags); | 195 | for (i = 0; i < ARRAY_SIZE(mfp_table); i++) |
196 | mfp_table[i].config = -1; | ||
166 | } | 197 | } |
167 | 198 | ||
168 | void pxa3xx_mfp_set_pull(int mfp, int pull) | 199 | #ifdef CONFIG_PM |
200 | /* | ||
201 | * Configure the MFPs appropriately for suspend/resume. | ||
202 | * FIXME: this should probably depend on which system state we're | ||
203 | * entering - for instance, we might not want to place MFP pins in | ||
204 | * a pull-down mode if they're an active low chip select, and we're | ||
205 | * just entering standby. | ||
206 | */ | ||
207 | static int pxa3xx_mfp_suspend(struct sys_device *d, pm_message_t state) | ||
169 | { | 208 | { |
170 | uint32_t mfpr_off, mfpr_val; | 209 | int pin; |
171 | unsigned long flags; | ||
172 | |||
173 | BUG_ON(mfp >= MFP_PIN_MAX); | ||
174 | |||
175 | spin_lock_irqsave(&mfp_spin_lock, flags); | ||
176 | 210 | ||
177 | mfpr_off = mfp_table[mfp].mfpr_off; | 211 | for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++) { |
178 | mfpr_val = mfpr_readl(mfpr_off); | 212 | struct pxa3xx_mfp_pin *p = &mfp_table[pin]; |
179 | mfpr_val &= ~MFPR_PULL_MASK; | 213 | __mfp_config_lpm(p); |
180 | mfpr_val |= ((pull & 0x7u) << MFPR_PD_OFFSET); | 214 | } |
181 | 215 | return 0; | |
182 | mfpr_writel(mfpr_off, mfpr_val); | ||
183 | mfpr_sync(); | ||
184 | |||
185 | spin_unlock_irqrestore(&mfp_spin_lock, flags); | ||
186 | } | 216 | } |
187 | 217 | ||
188 | void pxa3xx_mfp_set_edge(int mfp, int edge) | 218 | static int pxa3xx_mfp_resume(struct sys_device *d) |
189 | { | 219 | { |
190 | uint32_t mfpr_off, mfpr_val; | 220 | int pin; |
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 | 221 | ||
204 | mfpr_writel(mfpr_off, mfpr_val); | 222 | for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++) { |
205 | mfpr_sync(); | 223 | struct pxa3xx_mfp_pin *p = &mfp_table[pin]; |
206 | 224 | __mfp_config_run(p); | |
207 | spin_unlock_irqrestore(&mfp_spin_lock, flags); | 225 | } |
226 | return 0; | ||
208 | } | 227 | } |
209 | 228 | ||
210 | void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map) | 229 | static struct sysdev_class mfp_sysclass = { |
211 | { | 230 | set_kset_name("mfp"), |
212 | struct pxa3xx_mfp_addr_map *p; | 231 | .suspend = pxa3xx_mfp_suspend, |
213 | unsigned long offset, flags; | 232 | .resume = pxa3xx_mfp_resume, |
214 | int i; | 233 | }; |
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 | 234 | ||
229 | spin_unlock_irqrestore(&mfp_spin_lock, flags); | 235 | static struct sys_device mfp_device = { |
230 | } | 236 | .id = 0, |
237 | .cls = &mfp_sysclass, | ||
238 | }; | ||
231 | 239 | ||
232 | void __init pxa3xx_init_mfp(void) | 240 | static int __init mfp_init_devicefs(void) |
233 | { | 241 | { |
234 | memset(mfp_table, 0, sizeof(mfp_table)); | 242 | sysdev_class_register(&mfp_sysclass); |
243 | return sysdev_register(&mfp_device); | ||
235 | } | 244 | } |
245 | device_initcall(mfp_init_devicefs); | ||
246 | #endif | ||