MIPS: Yosemite, Emma: Fix off-by-two in arcs_cmdline buffer size check
[linux-2.6/linux-mips.git] / arch / arm / plat-spear / padmux.c
blob555eec6dc1cbfd14a4e750205217132d63cbb9f5
1 /*
2 * arch/arm/plat-spear/include/plat/padmux.c
4 * SPEAr platform specific gpio pads muxing source file
6 * Copyright (C) 2009 ST Microelectronics
7 * Viresh Kumar<viresh.kumar@st.com>
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
14 #include <linux/err.h>
15 #include <linux/io.h>
16 #include <linux/slab.h>
17 #include <plat/padmux.h>
20 * struct pmx: pmx definition structure
22 * base: base address of configuration registers
23 * mode_reg: mode configurations
24 * mux_reg: muxing configurations
25 * active_mode: pointer to current active mode
27 struct pmx {
28 u32 base;
29 struct pmx_reg mode_reg;
30 struct pmx_reg mux_reg;
31 struct pmx_mode *active_mode;
34 static struct pmx *pmx;
36 /**
37 * pmx_mode_set - Enables an multiplexing mode
38 * @mode - pointer to pmx mode
40 * It will set mode of operation in hardware.
41 * Returns -ve on Err otherwise 0
43 static int pmx_mode_set(struct pmx_mode *mode)
45 u32 val;
47 if (!mode->name)
48 return -EFAULT;
50 pmx->active_mode = mode;
52 val = readl(pmx->base + pmx->mode_reg.offset);
53 val &= ~pmx->mode_reg.mask;
54 val |= mode->mask & pmx->mode_reg.mask;
55 writel(val, pmx->base + pmx->mode_reg.offset);
57 return 0;
60 /**
61 * pmx_devs_enable - Enables list of devices
62 * @devs - pointer to pmx device array
63 * @count - number of devices to enable
65 * It will enable pads for all required peripherals once and only once.
66 * If peripheral is not supported by current mode then request is rejected.
67 * Conflicts between peripherals are not handled and peripherals will be
68 * enabled in the order they are present in pmx_dev array.
69 * In case of conflicts last peripheral enabled will be present.
70 * Returns -ve on Err otherwise 0
72 static int pmx_devs_enable(struct pmx_dev **devs, u8 count)
74 u32 val, i, mask;
76 if (!count)
77 return -EINVAL;
79 val = readl(pmx->base + pmx->mux_reg.offset);
80 for (i = 0; i < count; i++) {
81 u8 j = 0;
83 if (!devs[i]->name || !devs[i]->modes) {
84 printk(KERN_ERR "padmux: dev name or modes is null\n");
85 continue;
87 /* check if peripheral exists in active mode */
88 if (pmx->active_mode) {
89 bool found = false;
90 for (j = 0; j < devs[i]->mode_count; j++) {
91 if (devs[i]->modes[j].ids &
92 pmx->active_mode->id) {
93 found = true;
94 break;
97 if (found == false) {
98 printk(KERN_ERR "%s device not available in %s"\
99 "mode\n", devs[i]->name,
100 pmx->active_mode->name);
101 continue;
105 /* enable peripheral */
106 mask = devs[i]->modes[j].mask & pmx->mux_reg.mask;
107 if (devs[i]->enb_on_reset)
108 val &= ~mask;
109 else
110 val |= mask;
112 devs[i]->is_active = true;
114 writel(val, pmx->base + pmx->mux_reg.offset);
115 kfree(pmx);
117 /* this will ensure that multiplexing can't be changed now */
118 pmx = (struct pmx *)-1;
120 return 0;
124 * pmx_register - registers a platform requesting pad mux feature
125 * @driver - pointer to driver structure containing driver specific parameters
127 * Also this must be called only once. This will allocate memory for pmx
128 * structure, will call pmx_mode_set, will call pmx_devs_enable.
129 * Returns -ve on Err otherwise 0
131 int pmx_register(struct pmx_driver *driver)
133 int ret = 0;
135 if (pmx)
136 return -EPERM;
137 if (!driver->base || !driver->devs)
138 return -EFAULT;
140 pmx = kzalloc(sizeof(*pmx), GFP_KERNEL);
141 if (!pmx)
142 return -ENOMEM;
144 pmx->base = (u32)driver->base;
145 pmx->mode_reg.offset = driver->mode_reg.offset;
146 pmx->mode_reg.mask = driver->mode_reg.mask;
147 pmx->mux_reg.offset = driver->mux_reg.offset;
148 pmx->mux_reg.mask = driver->mux_reg.mask;
150 /* choose mode to enable */
151 if (driver->mode) {
152 ret = pmx_mode_set(driver->mode);
153 if (ret)
154 goto pmx_fail;
156 ret = pmx_devs_enable(driver->devs, driver->devs_count);
157 if (ret)
158 goto pmx_fail;
160 return 0;
162 pmx_fail:
163 return ret;