• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/arm/mach-u300/
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
27static DEFINE_MUTEX(pmx_mutex);
28
29const 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 */
48static 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
64static 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 */
83static struct pmx *pmx_settings[] = {
84	&mmc_setting,
85	&spi_setting,
86};
87
88static 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
109struct 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}
139EXPORT_SYMBOL(pmx_get);
140
141int 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}
170EXPORT_SYMBOL(pmx_put);
171
172int 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
207exit:
208	mutex_unlock(&pmx_mutex);
209	return ret;
210}
211EXPORT_SYMBOL(pmx_activate);
212
213int 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}
251EXPORT_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 */
258static 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))
287static 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
324static int pmx_open(struct inode *inode, struct file *file)
325{
326	return single_open(file, pmx_show, NULL);
327}
328
329static 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
337static 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 */
351module_init(init_pmx_read_debugfs);
352#endif
353
354static 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 */
367core_initcall(pmx_init);
368