Merge branch 'stericsson/cleanup' into next/timer
[pandora-kernel.git] / arch / arm / mach-u300 / padmux.c
1 /*
2  *
3  * arch/arm/mach-u300/padmux.c
4  *
5  *
6  * Copyright (C) 2009 ST-Ericsson AB
7  * License terms: GNU General Public License (GPL) version 2
8  * U300 PADMUX functions
9  * Author: Martin Persson <martin.persson@stericsson.com>
10  */
11
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/device.h>
15 #include <linux/err.h>
16 #include <linux/errno.h>
17 #include <linux/io.h>
18 #include <linux/mutex.h>
19 #include <linux/string.h>
20 #include <linux/bug.h>
21 #include <linux/debugfs.h>
22 #include <linux/seq_file.h>
23 #include <mach/u300-regs.h>
24 #include <mach/syscon.h>
25 #include "padmux.h"
26
27 static DEFINE_MUTEX(pmx_mutex);
28
29 const u32 pmx_registers[] = {
30         (U300_SYSCON_VBASE + U300_SYSCON_PMC1LR),
31         (U300_SYSCON_VBASE + U300_SYSCON_PMC1HR),
32         (U300_SYSCON_VBASE + U300_SYSCON_PMC2R),
33         (U300_SYSCON_VBASE + U300_SYSCON_PMC3R),
34         (U300_SYSCON_VBASE + U300_SYSCON_PMC4R)
35 };
36
37 /* High level functionality */
38
39 /* Lazy dog:
40  * onmask = {
41  *   {"PMC1LR" mask, "PMC1LR" value},
42  *   {"PMC1HR" mask, "PMC1HR" value},
43  *   {"PMC2R"  mask, "PMC2R"  value},
44  *   {"PMC3R"  mask, "PMC3R"  value},
45  *   {"PMC4R"  mask, "PMC4R"  value}
46  * }
47  */
48 static struct pmx mmc_setting = {
49         .setting = U300_APP_PMX_MMC_SETTING,
50         .default_on = false,
51         .activated = false,
52         .name = "MMC",
53         .onmask = {
54                    {U300_SYSCON_PMC1LR_MMCSD_MASK,
55                     U300_SYSCON_PMC1LR_MMCSD_MMCSD},
56                    {0, 0},
57                    {0, 0},
58                    {0, 0},
59                    {U300_SYSCON_PMC4R_APP_MISC_12_MASK,
60                     U300_SYSCON_PMC4R_APP_MISC_12_APP_GPIO}
61                    },
62 };
63
64 static struct pmx spi_setting = {
65         .setting = U300_APP_PMX_SPI_SETTING,
66         .default_on = false,
67         .activated = false,
68         .name = "SPI",
69         .onmask = {{0, 0},
70                    {U300_SYSCON_PMC1HR_APP_SPI_2_MASK |
71                     U300_SYSCON_PMC1HR_APP_SPI_CS_1_MASK |
72                     U300_SYSCON_PMC1HR_APP_SPI_CS_2_MASK,
73                     U300_SYSCON_PMC1HR_APP_SPI_2_SPI |
74                     U300_SYSCON_PMC1HR_APP_SPI_CS_1_SPI |
75                     U300_SYSCON_PMC1HR_APP_SPI_CS_2_SPI},
76                    {0, 0},
77                    {0, 0},
78                    {0, 0}
79                    },
80 };
81
82 /* Available padmux settings */
83 static struct pmx *pmx_settings[] = {
84         &mmc_setting,
85         &spi_setting,
86 };
87
88 static void update_registers(struct pmx *pmx, bool activate)
89 {
90         u16 regval, val, mask;
91         int i;
92
93         for (i = 0; i < ARRAY_SIZE(pmx_registers); i++) {
94                 if (activate)
95                         val = pmx->onmask[i].val;
96                 else
97                         val = 0;
98
99                 mask = pmx->onmask[i].mask;
100                 if (mask != 0) {
101                         regval = readw(pmx_registers[i]);
102                         regval &= ~mask;
103                         regval |= val;
104                         writew(regval, pmx_registers[i]);
105                 }
106         }
107 }
108
109 struct pmx *pmx_get(struct device *dev, enum pmx_settings setting)
110 {
111         int i;
112         struct pmx *pmx = ERR_PTR(-ENOENT);
113
114         if (dev == NULL)
115                 return ERR_PTR(-EINVAL);
116
117         mutex_lock(&pmx_mutex);
118         for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
119
120                 if (setting == pmx_settings[i]->setting) {
121
122                         if (pmx_settings[i]->dev != NULL) {
123                                 WARN(1, "padmux: required setting "
124                                      "in use by another consumer\n");
125                         } else {
126                                 pmx = pmx_settings[i];
127                                 pmx->dev = dev;
128                                 dev_dbg(dev, "padmux: setting nr %d is now "
129                                         "bound to %s and ready to use\n",
130                                         setting, dev_name(dev));
131                                 break;
132                         }
133                 }
134         }
135         mutex_unlock(&pmx_mutex);
136
137         return pmx;
138 }
139 EXPORT_SYMBOL(pmx_get);
140
141 int pmx_put(struct device *dev, struct pmx *pmx)
142 {
143         int i;
144         int ret = -ENOENT;
145
146         if (pmx == NULL || dev == NULL)
147                 return -EINVAL;
148
149         mutex_lock(&pmx_mutex);
150         for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
151
152                 if (pmx->setting == pmx_settings[i]->setting) {
153
154                         if (dev != pmx->dev) {
155                                 WARN(1, "padmux: cannot release handle as "
156                                         "it is bound to another consumer\n");
157                                 ret = -EINVAL;
158                                 break;
159                         } else {
160                                 pmx_settings[i]->dev = NULL;
161                                 ret = 0;
162                                 break;
163                         }
164                 }
165         }
166         mutex_unlock(&pmx_mutex);
167
168         return ret;
169 }
170 EXPORT_SYMBOL(pmx_put);
171
172 int pmx_activate(struct device *dev, struct pmx *pmx)
173 {
174         int i, j, ret;
175         ret = 0;
176
177         if (pmx == NULL || dev == NULL)
178                 return -EINVAL;
179
180         mutex_lock(&pmx_mutex);
181
182         /* Make sure the required bits are not used */
183         for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
184
185                 if (pmx_settings[i]->dev == NULL || pmx_settings[i] == pmx)
186                         continue;
187
188                 for (j = 0; j < ARRAY_SIZE(pmx_registers); j++) {
189
190                         if (pmx_settings[i]->onmask[j].mask & pmx->
191                                 onmask[j].mask) {
192                                 /* More than one entry on the same bits */
193                                 WARN(1, "padmux: cannot activate "
194                                         "setting. Bit conflict with "
195                                         "an active setting\n");
196
197                                 ret = -EUSERS;
198                                 goto exit;
199                         }
200                 }
201         }
202         update_registers(pmx, true);
203         pmx->activated = true;
204         dev_dbg(dev, "padmux: setting nr %d is activated\n",
205                 pmx->setting);
206
207 exit:
208         mutex_unlock(&pmx_mutex);
209         return ret;
210 }
211 EXPORT_SYMBOL(pmx_activate);
212
213 int pmx_deactivate(struct device *dev, struct pmx *pmx)
214 {
215         int i;
216         int ret = -ENOENT;
217
218         if (pmx == NULL || dev == NULL)
219                 return -EINVAL;
220
221         mutex_lock(&pmx_mutex);
222         for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
223
224                 if (pmx_settings[i]->dev == NULL)
225                         continue;
226
227                 if (pmx->setting == pmx_settings[i]->setting) {
228
229                         if (dev != pmx->dev) {
230                                 WARN(1, "padmux: cannot deactivate "
231                                      "pmx setting as it was activated "
232                                      "by another consumer\n");
233
234                                 ret = -EBUSY;
235                                 continue;
236                         } else {
237                                 update_registers(pmx, false);
238                                 pmx_settings[i]->dev = NULL;
239                                 pmx->activated = false;
240                                 ret = 0;
241                                 dev_dbg(dev, "padmux: setting nr %d is deactivated",
242                                         pmx->setting);
243                                 break;
244                         }
245                 }
246         }
247         mutex_unlock(&pmx_mutex);
248
249         return ret;
250 }
251 EXPORT_SYMBOL(pmx_deactivate);
252
253 /*
254  * For internal use only. If it is to be exported,
255  * it should be reentrant. Notice that pmx_activate
256  * (i.e. runtime settings) always override default settings.
257  */
258 static int pmx_set_default(void)
259 {
260         /* Used to identify several entries on the same bits */
261         u16 modbits[ARRAY_SIZE(pmx_registers)];
262
263         int i, j;
264
265         memset(modbits, 0, ARRAY_SIZE(pmx_registers) * sizeof(u16));
266
267         for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
268
269                 if (!pmx_settings[i]->default_on)
270                         continue;
271
272                 for (j = 0; j < ARRAY_SIZE(pmx_registers); j++) {
273
274                         /* Make sure there is only one entry on the same bits */
275                         if (modbits[j] & pmx_settings[i]->onmask[j].mask) {
276                                 BUG();
277                                 return -EUSERS;
278                         }
279                         modbits[j] |= pmx_settings[i]->onmask[j].mask;
280                 }
281                 update_registers(pmx_settings[i], true);
282         }
283         return 0;
284 }
285
286 #if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
287 static int pmx_show(struct seq_file *s, void *data)
288 {
289         int i;
290         seq_printf(s, "-------------------------------------------------\n");
291         seq_printf(s, "SETTING     BOUND TO DEVICE               STATE\n");
292         seq_printf(s, "-------------------------------------------------\n");
293         mutex_lock(&pmx_mutex);
294         for (i = 0; i < ARRAY_SIZE(pmx_settings); i++) {
295                 /* Format pmx and device name nicely */
296                 char cdp[33];
297                 int chars;
298
299                 chars = snprintf(&cdp[0], 17, "%s", pmx_settings[i]->name);
300                 while (chars < 16) {
301                         cdp[chars] = ' ';
302                         chars++;
303                 }
304                 chars = snprintf(&cdp[16], 17, "%s", pmx_settings[i]->dev ?
305                                 dev_name(pmx_settings[i]->dev) : "N/A");
306                 while (chars < 16) {
307                         cdp[chars+16] = ' ';
308                         chars++;
309                 }
310                 cdp[32] = '\0';
311
312                 seq_printf(s,
313                         "%s\t%s\n",
314                         &cdp[0],
315                         pmx_settings[i]->activated ?
316                         "ACTIVATED" : "DEACTIVATED"
317                         );
318
319         }
320         mutex_unlock(&pmx_mutex);
321         return 0;
322 }
323
324 static int pmx_open(struct inode *inode, struct file *file)
325 {
326         return single_open(file, pmx_show, NULL);
327 }
328
329 static const struct file_operations pmx_operations = {
330         .owner          = THIS_MODULE,
331         .open           = pmx_open,
332         .read           = seq_read,
333         .llseek         = seq_lseek,
334         .release        = single_release,
335 };
336
337 static int __init init_pmx_read_debugfs(void)
338 {
339         /* Expose a simple debugfs interface to view pmx settings */
340         (void) debugfs_create_file("padmux", S_IFREG | S_IRUGO,
341                                    NULL, NULL,
342                                    &pmx_operations);
343         return 0;
344 }
345
346 /*
347  * This needs to come in after the core_initcall(),
348  * because debugfs is not available until
349  * the subsystems come up.
350  */
351 module_init(init_pmx_read_debugfs);
352 #endif
353
354 static int __init pmx_init(void)
355 {
356         int ret;
357
358         ret = pmx_set_default();
359
360         if (IS_ERR_VALUE(ret))
361                 pr_crit("padmux: default settings could not be set\n");
362
363         return 0;
364 }
365
366 /* Should be initialized before consumers */
367 core_initcall(pmx_init);