aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-dove/mpp.c
diff options
context:
space:
mode:
authorMike Rapoport <mike@compulab.co.il>2010-11-15 04:48:33 -0500
committerNicolas Pitre <nico@fluxnic.net>2010-12-15 10:32:30 -0500
commit5af244fdf2a2405b2181da2a32636f3ca5ef162e (patch)
treea4da14554797972718439a9a126102756454b783 /arch/arm/mach-dove/mpp.c
parent8d4ce4cd7480ccd8412d4391d063733d6fc52f5c (diff)
[ARM] Dove: add support for multi-purpose pins configuration
Signed-off-by: Mike Rapoport <mike@compulab.co.il> Acked-by: Saeed Bishara <saeed@marvell.com> Signed-off-by: Nicolas Pitre <nico@fluxnic.net>
Diffstat (limited to 'arch/arm/mach-dove/mpp.c')
-rw-r--r--arch/arm/mach-dove/mpp.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/arch/arm/mach-dove/mpp.c b/arch/arm/mach-dove/mpp.c
new file mode 100644
index 000000000000..71db2bdf2f28
--- /dev/null
+++ b/arch/arm/mach-dove/mpp.c
@@ -0,0 +1,212 @@
1/*
2 * arch/arm/mach-dove/mpp.c
3 *
4 * MPP functions for Marvell Dove SoCs
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 */
10
11#include <linux/kernel.h>
12#include <linux/gpio.h>
13#include <linux/io.h>
14
15#include <mach/dove.h>
16
17#include "mpp.h"
18
19#define MPP_NR_REGS 4
20#define MPP_CTRL(i) ((i) == 3 ? \
21 DOVE_MPP_CTRL4_VIRT_BASE : \
22 DOVE_MPP_VIRT_BASE + (i) * 4)
23#define PMU_SIG_REGS 2
24#define PMU_SIG_CTRL(i) (DOVE_PMU_SIG_CTRL + (i) * 4)
25
26struct dove_mpp_grp {
27 int start;
28 int end;
29};
30
31static struct dove_mpp_grp dove_mpp_grp[] = {
32 [MPP_24_39] = {
33 .start = 24,
34 .end = 39,
35 },
36 [MPP_40_45] = {
37 .start = 40,
38 .end = 45,
39 },
40 [MPP_46_51] = {
41 .start = 40,
42 .end = 45,
43 },
44 [MPP_58_61] = {
45 .start = 58,
46 .end = 61,
47 },
48 [MPP_62_63] = {
49 .start = 62,
50 .end = 63,
51 },
52};
53
54static void dove_mpp_gpio_mode(int start, int end, int gpio_mode)
55{
56 int i;
57
58 for (i = start; i <= end; i++)
59 orion_gpio_set_valid(i, gpio_mode);
60}
61
62static void dove_mpp_dump_regs(void)
63{
64#ifdef DEBUG
65 int i;
66
67 pr_debug("MPP_CTRL regs:");
68 for (i = 0; i < MPP_NR_REGS; i++)
69 printk(" %08x", readl(MPP_CTRL(i)));
70 printk("\n");
71
72 pr_debug("PMU_SIG_CTRL regs:");
73 for (i = 0; i < PMU_SIG_REGS; i++)
74 printk(" %08x", readl(PMU_SIG_CTRL(i)));
75 printk("\n");
76
77 pr_debug("PMU_MPP_GENERAL_CTRL: %08x\n", readl(DOVE_PMU_MPP_GENERAL_CTRL));
78 pr_debug("MPP_GENERAL: %08x\n", readl(DOVE_MPP_GENERAL_VIRT_BASE));
79#endif
80}
81
82static void dove_mpp_cfg_nfc(int sel)
83{
84 u32 mpp_gen_cfg = readl(DOVE_MPP_GENERAL_VIRT_BASE);
85
86 mpp_gen_cfg &= ~0x1;
87 mpp_gen_cfg |= sel;
88 writel(mpp_gen_cfg, DOVE_MPP_GENERAL_VIRT_BASE);
89
90 dove_mpp_gpio_mode(64, 71, GPIO_OUTPUT_OK);
91}
92
93static void dove_mpp_cfg_au1(int sel)
94{
95 u32 mpp_ctrl4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
96 u32 ssp_ctrl1 = readl(DOVE_SSP_CTRL_STATUS_1);
97 u32 mpp_gen_ctrl = readl(DOVE_MPP_GENERAL_VIRT_BASE);
98 u32 global_cfg_2 = readl(DOVE_GLOBAL_CONFIG_2);
99
100 mpp_ctrl4 &= ~(DOVE_AU1_GPIO_SEL);
101 ssp_ctrl1 &= ~(DOVE_SSP_ON_AU1);
102 mpp_gen_ctrl &= ~(DOVE_AU1_SPDIFO_GPIO_EN);
103 global_cfg_2 &= ~(DOVE_TWSI_OPTION3_GPIO);
104
105 if (!sel || sel == 0x2)
106 dove_mpp_gpio_mode(52, 57, 0);
107 else
108 dove_mpp_gpio_mode(52, 57, GPIO_OUTPUT_OK | GPIO_INPUT_OK);
109
110 if (sel & 0x1) {
111 global_cfg_2 |= DOVE_TWSI_OPTION3_GPIO;
112 dove_mpp_gpio_mode(56, 57, 0);
113 }
114 if (sel & 0x2) {
115 mpp_gen_ctrl |= DOVE_AU1_SPDIFO_GPIO_EN;
116 dove_mpp_gpio_mode(57, 57, GPIO_OUTPUT_OK | GPIO_INPUT_OK);
117 }
118 if (sel & 0x4) {
119 ssp_ctrl1 |= DOVE_SSP_ON_AU1;
120 dove_mpp_gpio_mode(52, 55, 0);
121 }
122 if (sel & 0x8)
123 mpp_ctrl4 |= DOVE_AU1_GPIO_SEL;
124
125 writel(mpp_ctrl4, DOVE_MPP_CTRL4_VIRT_BASE);
126 writel(ssp_ctrl1, DOVE_SSP_CTRL_STATUS_1);
127 writel(mpp_gen_ctrl, DOVE_MPP_GENERAL_VIRT_BASE);
128 writel(global_cfg_2, DOVE_GLOBAL_CONFIG_2);
129}
130
131static void dove_mpp_conf_grp(int num, int sel, u32 *mpp_ctrl)
132{
133 int start = dove_mpp_grp[num].start;
134 int end = dove_mpp_grp[num].end;
135 int gpio_mode = sel ? GPIO_OUTPUT_OK | GPIO_INPUT_OK : 0;
136
137 *mpp_ctrl &= ~(0x1 << num);
138 *mpp_ctrl |= sel << num;
139
140 dove_mpp_gpio_mode(start, end, gpio_mode);
141}
142
143void __init dove_mpp_conf(unsigned int *mpp_list)
144{
145 u32 mpp_ctrl[MPP_NR_REGS];
146 u32 pmu_mpp_ctrl = 0;
147 u32 pmu_sig_ctrl[PMU_SIG_REGS];
148 int i;
149
150 /* Initialize gpiolib. */
151 orion_gpio_init();
152
153 for (i = 0; i < MPP_NR_REGS; i++)
154 mpp_ctrl[i] = readl(MPP_CTRL(i));
155
156 for (i = 0; i < PMU_SIG_REGS; i++)
157 pmu_sig_ctrl[i] = readl(PMU_SIG_CTRL(i));
158
159 pmu_mpp_ctrl = readl(DOVE_PMU_MPP_GENERAL_CTRL);
160
161 dove_mpp_dump_regs();
162
163 for ( ; *mpp_list != MPP_END; mpp_list++) {
164 unsigned int num = MPP_NUM(*mpp_list);
165 unsigned int sel = MPP_SEL(*mpp_list);
166 int shift, gpio_mode;
167
168 if (num > MPP_MAX) {
169 pr_err("dove: invalid MPP number (%u)\n", num);
170 continue;
171 }
172
173 if (*mpp_list & MPP_NFC_MASK) {
174 dove_mpp_cfg_nfc(sel);
175 continue;
176 }
177
178 if (*mpp_list & MPP_AU1_MASK) {
179 dove_mpp_cfg_au1(sel);
180 continue;
181 }
182
183 if (*mpp_list & MPP_GRP_MASK) {
184 dove_mpp_conf_grp(num, sel, &mpp_ctrl[3]);
185 continue;
186 }
187
188 shift = (num & 7) << 2;
189 if (*mpp_list & MPP_PMU_MASK) {
190 pmu_mpp_ctrl |= (0x1 << num);
191 pmu_sig_ctrl[num / 8] &= ~(0xf << shift);
192 pmu_sig_ctrl[num / 8] |= 0xf << shift;
193 gpio_mode = 0;
194 } else {
195 mpp_ctrl[num / 8] &= ~(0xf << shift);
196 mpp_ctrl[num / 8] |= sel << shift;
197 gpio_mode = GPIO_OUTPUT_OK | GPIO_INPUT_OK;
198 }
199
200 orion_gpio_set_valid(num, gpio_mode);
201 }
202
203 for (i = 0; i < MPP_NR_REGS; i++)
204 writel(mpp_ctrl[i], MPP_CTRL(i));
205
206 for (i = 0; i < PMU_SIG_REGS; i++)
207 writel(pmu_sig_ctrl[i], PMU_SIG_CTRL(i));
208
209 writel(pmu_mpp_ctrl, DOVE_PMU_MPP_GENERAL_CTRL);
210
211 dove_mpp_dump_regs();
212}