aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/mmc-twl4030.c
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@nokia.com>2010-02-15 13:03:34 -0500
committerTony Lindgren <tony@atomide.com>2010-02-15 13:03:34 -0500
commitdb0fefc5119e2cfaa8f57565331e0abe47f0801e (patch)
tree367d86d4784322e3b8156f187f68667680ce497a /arch/arm/mach-omap2/mmc-twl4030.c
parent88c8460ac32283e2a25e36e4670ff5ab02f3b521 (diff)
omap_hsmmc: Move gpio and regulator control from board file
This patch moves the setup code for GPIO's and Voltage Regulators from the board file mmc-twl4030.c to the driver omap_hsmmc.c. PBIAS and other system control configuration remains in the board file. Moving GPIO code to the driver makes the board initialisation code independent of when GPIO's are defined. That makes the board initialisation now entirely independent of its original twl4030 roots. Moving Voltage Regulator code to the driver allows for further development of regulator support in the core MMC code. It also permits the MMC core to be compiled as a module, because the board code no longer calls MMC core functions. Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/mmc-twl4030.c')
-rw-r--r--arch/arm/mach-omap2/mmc-twl4030.c352
1 files changed, 31 insertions, 321 deletions
diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c
index 8afe9dd3f15..6f8f29e99ff 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.c
+++ b/arch/arm/mach-omap2/mmc-twl4030.c
@@ -9,26 +9,17 @@
9 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation. 10 * published by the Free Software Foundation.
11 */ 11 */
12#include <linux/err.h> 12#include <linux/kernel.h>
13#include <linux/io.h> 13#include <linux/slab.h>
14#include <linux/module.h> 14#include <linux/string.h>
15#include <linux/platform_device.h>
16#include <linux/interrupt.h>
17#include <linux/delay.h> 15#include <linux/delay.h>
18#include <linux/gpio.h>
19#include <linux/mmc/host.h>
20#include <linux/regulator/consumer.h>
21
22#include <mach/hardware.h> 16#include <mach/hardware.h>
23#include <plat/control.h> 17#include <plat/control.h>
24#include <plat/mmc.h> 18#include <plat/mmc.h>
25#include <plat/board.h>
26 19
27#include "mmc-twl4030.h" 20#include "mmc-twl4030.h"
28 21
29 22#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
30#if defined(CONFIG_REGULATOR) && \
31 (defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE))
32 23
33static u16 control_pbias_offset; 24static u16 control_pbias_offset;
34static u16 control_devconf1_offset; 25static u16 control_devconf1_offset;
@@ -36,168 +27,9 @@ static u16 control_devconf1_offset;
36#define HSMMC_NAME_LEN 9 27#define HSMMC_NAME_LEN 9
37 28
38static struct twl_mmc_controller { 29static struct twl_mmc_controller {
39 struct omap_mmc_platform_data *mmc;
40 /* Vcc == configured supply
41 * Vcc_alt == optional
42 * - MMC1, supply for DAT4..DAT7
43 * - MMC2/MMC2, external level shifter voltage supply, for
44 * chip (SDIO, eMMC, etc) or transceiver (MMC2 only)
45 */
46 struct regulator *vcc;
47 struct regulator *vcc_aux;
48 char name[HSMMC_NAME_LEN + 1]; 30 char name[HSMMC_NAME_LEN + 1];
49} hsmmc[OMAP34XX_NR_MMC]; 31} hsmmc[OMAP34XX_NR_MMC];
50 32
51static int twl_mmc_card_detect(int irq)
52{
53 unsigned i;
54
55 for (i = 0; i < ARRAY_SIZE(hsmmc); i++) {
56 struct omap_mmc_platform_data *mmc;
57
58 mmc = hsmmc[i].mmc;
59 if (!mmc)
60 continue;
61 if (irq != mmc->slots[0].card_detect_irq)
62 continue;
63
64 /* NOTE: assumes card detect signal is active-low */
65 return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
66 }
67 return -ENOSYS;
68}
69
70static int twl_mmc_get_ro(struct device *dev, int slot)
71{
72 struct omap_mmc_platform_data *mmc = dev->platform_data;
73
74 /* NOTE: assumes write protect signal is active-high */
75 return gpio_get_value_cansleep(mmc->slots[0].gpio_wp);
76}
77
78static int twl_mmc_get_cover_state(struct device *dev, int slot)
79{
80 struct omap_mmc_platform_data *mmc = dev->platform_data;
81
82 /* NOTE: assumes card detect signal is active-low */
83 return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
84}
85
86/*
87 * MMC Slot Initialization.
88 */
89static int twl_mmc_late_init(struct device *dev)
90{
91 struct omap_mmc_platform_data *mmc = dev->platform_data;
92 int ret = 0;
93 int i;
94
95 /* MMC/SD/SDIO doesn't require a card detect switch */
96 if (gpio_is_valid(mmc->slots[0].switch_pin)) {
97 ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd");
98 if (ret)
99 goto done;
100 ret = gpio_direction_input(mmc->slots[0].switch_pin);
101 if (ret)
102 goto err;
103 }
104
105 /* require at least main regulator */
106 for (i = 0; i < ARRAY_SIZE(hsmmc); i++) {
107 if (hsmmc[i].name == mmc->slots[0].name) {
108 struct regulator *reg;
109
110 hsmmc[i].mmc = mmc;
111
112 reg = regulator_get(dev, "vmmc");
113 if (IS_ERR(reg)) {
114 dev_dbg(dev, "vmmc regulator missing\n");
115 /* HACK: until fixed.c regulator is usable,
116 * we don't require a main regulator
117 * for MMC2 or MMC3
118 */
119 if (i != 0)
120 break;
121 ret = PTR_ERR(reg);
122 hsmmc[i].vcc = NULL;
123 goto err;
124 }
125 hsmmc[i].vcc = reg;
126 mmc->slots[0].ocr_mask = mmc_regulator_get_ocrmask(reg);
127
128 /* allow an aux regulator */
129 reg = regulator_get(dev, "vmmc_aux");
130 hsmmc[i].vcc_aux = IS_ERR(reg) ? NULL : reg;
131
132 /* UGLY HACK: workaround regulator framework bugs.
133 * When the bootloader leaves a supply active, it's
134 * initialized with zero usecount ... and we can't
135 * disable it without first enabling it. Until the
136 * framework is fixed, we need a workaround like this
137 * (which is safe for MMC, but not in general).
138 */
139 if (regulator_is_enabled(hsmmc[i].vcc) > 0) {
140 regulator_enable(hsmmc[i].vcc);
141 regulator_disable(hsmmc[i].vcc);
142 }
143 if (hsmmc[i].vcc_aux) {
144 if (regulator_is_enabled(reg) > 0) {
145 regulator_enable(reg);
146 regulator_disable(reg);
147 }
148 }
149
150 break;
151 }
152 }
153
154 return 0;
155
156err:
157 gpio_free(mmc->slots[0].switch_pin);
158done:
159 mmc->slots[0].card_detect_irq = 0;
160 mmc->slots[0].card_detect = NULL;
161
162 dev_err(dev, "err %d configuring card detect\n", ret);
163 return ret;
164}
165
166static void twl_mmc_cleanup(struct device *dev)
167{
168 struct omap_mmc_platform_data *mmc = dev->platform_data;
169 int i;
170
171 gpio_free(mmc->slots[0].switch_pin);
172 for(i = 0; i < ARRAY_SIZE(hsmmc); i++) {
173 regulator_put(hsmmc[i].vcc);
174 regulator_put(hsmmc[i].vcc_aux);
175 }
176}
177
178#ifdef CONFIG_PM
179
180static int twl_mmc_suspend(struct device *dev, int slot)
181{
182 struct omap_mmc_platform_data *mmc = dev->platform_data;
183
184 disable_irq(mmc->slots[0].card_detect_irq);
185 return 0;
186}
187
188static int twl_mmc_resume(struct device *dev, int slot)
189{
190 struct omap_mmc_platform_data *mmc = dev->platform_data;
191
192 enable_irq(mmc->slots[0].card_detect_irq);
193 return 0;
194}
195
196#else
197#define twl_mmc_suspend NULL
198#define twl_mmc_resume NULL
199#endif
200
201#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) 33#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
202 34
203static int twl4030_mmc_get_context_loss(struct device *dev) 35static int twl4030_mmc_get_context_loss(struct device *dev)
@@ -210,12 +42,10 @@ static int twl4030_mmc_get_context_loss(struct device *dev)
210#define twl4030_mmc_get_context_loss NULL 42#define twl4030_mmc_get_context_loss NULL
211#endif 43#endif
212 44
213static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, 45static void hsmmc1_before_set_reg(struct device *dev, int slot,
214 int vdd) 46 int power_on, int vdd)
215{ 47{
216 u32 reg, prog_io; 48 u32 reg, prog_io;
217 int ret = 0;
218 struct twl_mmc_controller *c = &hsmmc[0];
219 struct omap_mmc_platform_data *mmc = dev->platform_data; 49 struct omap_mmc_platform_data *mmc = dev->platform_data;
220 50
221 /* 51 /*
@@ -255,11 +85,22 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
255 } 85 }
256 reg &= ~OMAP2_PBIASLITEPWRDNZ0; 86 reg &= ~OMAP2_PBIASLITEPWRDNZ0;
257 omap_ctrl_writel(reg, control_pbias_offset); 87 omap_ctrl_writel(reg, control_pbias_offset);
88 } else {
89 reg = omap_ctrl_readl(control_pbias_offset);
90 reg &= ~OMAP2_PBIASLITEPWRDNZ0;
91 omap_ctrl_writel(reg, control_pbias_offset);
92 }
93}
94
95static void hsmmc1_after_set_reg(struct device *dev, int slot,
96 int power_on, int vdd)
97{
98 u32 reg;
258 99
259 ret = mmc_regulator_set_ocr(c->vcc, vdd); 100 /* 100ms delay required for PBIAS configuration */
101 msleep(100);
260 102
261 /* 100ms delay required for PBIAS configuration */ 103 if (power_on) {
262 msleep(100);
263 reg = omap_ctrl_readl(control_pbias_offset); 104 reg = omap_ctrl_readl(control_pbias_offset);
264 reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0); 105 reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0);
265 if ((1 << vdd) <= MMC_VDD_165_195) 106 if ((1 << vdd) <= MMC_VDD_165_195)
@@ -269,60 +110,19 @@ static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
269 omap_ctrl_writel(reg, control_pbias_offset); 110 omap_ctrl_writel(reg, control_pbias_offset);
270 } else { 111 } else {
271 reg = omap_ctrl_readl(control_pbias_offset); 112 reg = omap_ctrl_readl(control_pbias_offset);
272 reg &= ~OMAP2_PBIASLITEPWRDNZ0;
273 omap_ctrl_writel(reg, control_pbias_offset);
274
275 ret = mmc_regulator_set_ocr(c->vcc, 0);
276
277 /* 100ms delay required for PBIAS configuration */
278 msleep(100);
279 reg = omap_ctrl_readl(control_pbias_offset);
280 reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 | 113 reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 |
281 OMAP2_PBIASLITEVMODE0); 114 OMAP2_PBIASLITEVMODE0);
282 omap_ctrl_writel(reg, control_pbias_offset); 115 omap_ctrl_writel(reg, control_pbias_offset);
283 } 116 }
284
285 return ret;
286} 117}
287 118
288static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int vdd) 119static void hsmmc23_before_set_reg(struct device *dev, int slot,
120 int power_on, int vdd)
289{ 121{
290 int ret = 0;
291 struct twl_mmc_controller *c = NULL;
292 struct omap_mmc_platform_data *mmc = dev->platform_data; 122 struct omap_mmc_platform_data *mmc = dev->platform_data;
293 int i;
294
295 for (i = 1; i < ARRAY_SIZE(hsmmc); i++) {
296 if (mmc == hsmmc[i].mmc) {
297 c = &hsmmc[i];
298 break;
299 }
300 }
301
302 if (c == NULL)
303 return -ENODEV;
304
305 /* If we don't see a Vcc regulator, assume it's a fixed
306 * voltage always-on regulator.
307 */
308 if (!c->vcc)
309 return 0;
310 123
311 /*
312 * Assume Vcc regulator is used only to power the card ... OMAP
313 * VDDS is used to power the pins, optionally with a transceiver to
314 * support cards using voltages other than VDDS (1.8V nominal). When a
315 * transceiver is used, DAT3..7 are muxed as transceiver control pins.
316 *
317 * In some cases this regulator won't support enable/disable;
318 * e.g. it's a fixed rail for a WLAN chip.
319 *
320 * In other cases vcc_aux switches interface power. Example, for
321 * eMMC cards it represents VccQ. Sometimes transceivers or SDIO
322 * chips/cards need an interface voltage rail too.
323 */
324 if (power_on) { 124 if (power_on) {
325 /* only MMC2 supports a CLKIN */ 125 /* Only MMC2 supports a CLKIN */
326 if (mmc->slots[0].internal_clock) { 126 if (mmc->slots[0].internal_clock) {
327 u32 reg; 127 u32 reg;
328 128
@@ -330,76 +130,7 @@ static int twl_mmc23_set_power(struct device *dev, int slot, int power_on, int v
330 reg |= OMAP2_MMCSDIO2ADPCLKISEL; 130 reg |= OMAP2_MMCSDIO2ADPCLKISEL;
331 omap_ctrl_writel(reg, control_devconf1_offset); 131 omap_ctrl_writel(reg, control_devconf1_offset);
332 } 132 }
333 ret = mmc_regulator_set_ocr(c->vcc, vdd);
334 /* enable interface voltage rail, if needed */
335 if (ret == 0 && c->vcc_aux) {
336 ret = regulator_enable(c->vcc_aux);
337 if (ret < 0)
338 ret = mmc_regulator_set_ocr(c->vcc, 0);
339 }
340 } else {
341 if (c->vcc_aux && (ret = regulator_is_enabled(c->vcc_aux)) > 0)
342 ret = regulator_disable(c->vcc_aux);
343 if (ret == 0)
344 ret = mmc_regulator_set_ocr(c->vcc, 0);
345 }
346
347 return ret;
348}
349
350static int twl_mmc1_set_sleep(struct device *dev, int slot, int sleep, int vdd,
351 int cardsleep)
352{
353 struct twl_mmc_controller *c = &hsmmc[0];
354 int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
355
356 return regulator_set_mode(c->vcc, mode);
357}
358
359static int twl_mmc23_set_sleep(struct device *dev, int slot, int sleep, int vdd,
360 int cardsleep)
361{
362 struct twl_mmc_controller *c = NULL;
363 struct omap_mmc_platform_data *mmc = dev->platform_data;
364 int i, err, mode;
365
366 for (i = 1; i < ARRAY_SIZE(hsmmc); i++) {
367 if (mmc == hsmmc[i].mmc) {
368 c = &hsmmc[i];
369 break;
370 }
371 } 133 }
372
373 if (c == NULL)
374 return -ENODEV;
375
376 /*
377 * If we don't see a Vcc regulator, assume it's a fixed
378 * voltage always-on regulator.
379 */
380 if (!c->vcc)
381 return 0;
382
383 mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
384
385 if (!c->vcc_aux)
386 return regulator_set_mode(c->vcc, mode);
387
388 if (cardsleep) {
389 /* VCC can be turned off if card is asleep */
390 struct regulator *vcc_aux = c->vcc_aux;
391
392 c->vcc_aux = NULL;
393 if (sleep)
394 err = twl_mmc23_set_power(dev, slot, 0, 0);
395 else
396 err = twl_mmc23_set_power(dev, slot, 1, vdd);
397 c->vcc_aux = vcc_aux;
398 } else
399 err = regulator_set_mode(c->vcc, mode);
400 if (err)
401 return err;
402 return regulator_set_mode(c->vcc_aux, mode);
403} 134}
404 135
405static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; 136static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata;
@@ -413,7 +144,6 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
413 if (cpu_is_omap2430()) { 144 if (cpu_is_omap2430()) {
414 control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE; 145 control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE;
415 control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1; 146 control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1;
416 nr_hsmmc = 2;
417 } else { 147 } else {
418 control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE; 148 control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE;
419 control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1; 149 control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1;
@@ -448,35 +178,15 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
448 mmc->slots[0].wires = c->wires; 178 mmc->slots[0].wires = c->wires;
449 mmc->slots[0].internal_clock = !c->ext_clock; 179 mmc->slots[0].internal_clock = !c->ext_clock;
450 mmc->dma_mask = 0xffffffff; 180 mmc->dma_mask = 0xffffffff;
451 mmc->init = twl_mmc_late_init;
452
453 /* note: twl4030 card detect GPIOs can disable VMMCx ... */
454 if (gpio_is_valid(c->gpio_cd)) {
455 mmc->cleanup = twl_mmc_cleanup;
456 mmc->suspend = twl_mmc_suspend;
457 mmc->resume = twl_mmc_resume;
458
459 mmc->slots[0].switch_pin = c->gpio_cd;
460 mmc->slots[0].card_detect_irq = gpio_to_irq(c->gpio_cd);
461 if (c->cover_only)
462 mmc->slots[0].get_cover_state = twl_mmc_get_cover_state;
463 else
464 mmc->slots[0].card_detect = twl_mmc_card_detect;
465 } else
466 mmc->slots[0].switch_pin = -EINVAL;
467 181
468 mmc->get_context_loss_count = 182 mmc->get_context_loss_count =
469 twl4030_mmc_get_context_loss; 183 twl4030_mmc_get_context_loss;
470 184
471 /* write protect normally uses an OMAP gpio */ 185 mmc->slots[0].switch_pin = c->gpio_cd;
472 if (gpio_is_valid(c->gpio_wp)) { 186 mmc->slots[0].gpio_wp = c->gpio_wp;
473 gpio_request(c->gpio_wp, "mmc_wp");
474 gpio_direction_input(c->gpio_wp);
475 187
476 mmc->slots[0].gpio_wp = c->gpio_wp; 188 if (c->cover_only)
477 mmc->slots[0].get_ro = twl_mmc_get_ro; 189 mmc->slots[0].cover = 1;
478 } else
479 mmc->slots[0].gpio_wp = -EINVAL;
480 190
481 if (c->nonremovable) 191 if (c->nonremovable)
482 mmc->slots[0].nonremovable = 1; 192 mmc->slots[0].nonremovable = 1;
@@ -495,8 +205,8 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
495 switch (c->mmc) { 205 switch (c->mmc) {
496 case 1: 206 case 1:
497 /* on-chip level shifting via PBIAS0/PBIAS1 */ 207 /* on-chip level shifting via PBIAS0/PBIAS1 */
498 mmc->slots[0].set_power = twl_mmc1_set_power; 208 mmc->slots[0].before_set_reg = hsmmc1_before_set_reg;
499 mmc->slots[0].set_sleep = twl_mmc1_set_sleep; 209 mmc->slots[0].after_set_reg = hsmmc1_after_set_reg;
500 210
501 /* Omap3630 HSMMC1 supports only 4-bit */ 211 /* Omap3630 HSMMC1 supports only 4-bit */
502 if (cpu_is_omap3630() && c->wires > 4) { 212 if (cpu_is_omap3630() && c->wires > 4) {
@@ -512,8 +222,8 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
512 /* FALLTHROUGH */ 222 /* FALLTHROUGH */
513 case 3: 223 case 3:
514 /* off-chip level shifting, or none */ 224 /* off-chip level shifting, or none */
515 mmc->slots[0].set_power = twl_mmc23_set_power; 225 mmc->slots[0].before_set_reg = hsmmc23_before_set_reg;
516 mmc->slots[0].set_sleep = twl_mmc23_set_sleep; 226 mmc->slots[0].after_set_reg = NULL;
517 break; 227 break;
518 default: 228 default:
519 pr_err("MMC%d configuration not supported!\n", c->mmc); 229 pr_err("MMC%d configuration not supported!\n", c->mmc);