diff options
author | Mike Rapoport <mike@compulab.co.il> | 2010-11-15 04:48:33 -0500 |
---|---|---|
committer | Nicolas Pitre <nico@fluxnic.net> | 2010-12-15 10:32:30 -0500 |
commit | 5af244fdf2a2405b2181da2a32636f3ca5ef162e (patch) | |
tree | a4da14554797972718439a9a126102756454b783 /arch/arm/mach-dove/mpp.c | |
parent | 8d4ce4cd7480ccd8412d4391d063733d6fc52f5c (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.c | 212 |
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 | |||
26 | struct dove_mpp_grp { | ||
27 | int start; | ||
28 | int end; | ||
29 | }; | ||
30 | |||
31 | static 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 | |||
54 | static 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 | |||
62 | static 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 | |||
82 | static 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 | |||
93 | static 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 | |||
131 | static 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 | |||
143 | void __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 | } | ||