]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/mach-omap2/hsmmc.c
c6ff49010244cda6038ee026dcea5360e8541681
[linux-2.6-omap-h63xx.git] / arch / arm / mach-omap2 / hsmmc.c
1 /*
2  * linux/arch/arm/mach-omap2/board-sdp-hsmmc.c
3  *
4  * Copyright (C) 2007-2008 Texas Instruments
5  * Copyright (C) 2008 Nokia Corporation
6  * Author: Texas Instruments
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 #include <linux/err.h>
13 #include <linux/io.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/interrupt.h>
17 #include <linux/delay.h>
18 #include <linux/i2c/twl4030.h>
19 #include <mach/hardware.h>
20 #include <mach/mmc.h>
21 #include <mach/board.h>
22
23 #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
24
25 #define VMMC1_DEV_GRP           0x27
26 #define P1_DEV_GRP              0x20
27 #define VMMC1_DEDICATED         0x2A
28 #define VSEL_3V                 0x02
29 #define VSEL_18V                0x00
30 #define TWL_GPIO_IMR1A          0x1C
31 #define TWL_GPIO_ISR1A          0x19
32 #define LDO_CLR                 0x00
33 #define VSEL_S2_CLR             0x40
34 #define GPIO_0_BIT_POS          (1 << 0)
35 #define MMC1_CD_IRQ             0
36 #define MMC2_CD_IRQ             1
37
38 #define OMAP2_CONTROL_DEVCONF0  0x48002274
39 #define OMAP2_CONTROL_DEVCONF1  0x490022E8
40
41 #define OMAP2_CONTROL_DEVCONF0_LBCLK    (1 << 24)
42 #define OMAP2_CONTROL_DEVCONF1_ACTOV    (1 << 31)
43
44 #define OMAP2_CONTROL_PBIAS_VMODE       (1 << 0)
45 #define OMAP2_CONTROL_PBIAS_PWRDNZ      (1 << 1)
46 #define OMAP2_CONTROL_PBIAS_SCTRL       (1 << 2)
47
48 static int hsmmc_card_detect(int irq)
49 {
50         return twl4030_get_gpio_datain(irq - TWL4030_GPIO_IRQ_BASE);
51 }
52
53 /*
54  * MMC Slot Initialization.
55  */
56 static int hsmmc_late_init(struct device *dev)
57 {
58         int ret = 0;
59
60         /*
61          * Configure TWL4030 GPIO parameters for MMC hotplug irq
62          */
63         ret = twl4030_request_gpio(MMC1_CD_IRQ);
64         if (ret)
65                 goto err;
66
67         ret = twl4030_set_gpio_debounce(MMC1_CD_IRQ, TWL4030_GPIO_IS_ENABLE);
68         if (ret)
69                 goto err;
70
71         return ret;
72
73 err:
74         dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
75         return ret;
76 }
77
78 static void hsmmc_cleanup(struct device *dev)
79 {
80         int ret = 0;
81
82         ret = twl4030_free_gpio(MMC1_CD_IRQ);
83         if (ret)
84                 dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
85 }
86
87 #ifdef CONFIG_PM
88
89 /*
90  * To mask and unmask MMC Card Detect Interrupt
91  * mask : 1
92  * unmask : 0
93  */
94 static int mask_cd_interrupt(int mask)
95 {
96         u8 reg = 0, ret = 0;
97
98         ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &reg, TWL_GPIO_IMR1A);
99         if (ret)
100                 goto err;
101
102         reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
103
104         ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_IMR1A);
105         if (ret)
106                 goto err;
107
108         ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &reg, TWL_GPIO_ISR1A);
109         if (ret)
110                 goto err;
111
112         reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
113
114         ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_ISR1A);
115         if (ret)
116                 goto err;
117
118 err:
119         return ret;
120 }
121
122 static int hsmmc_suspend(struct device *dev, int slot)
123 {
124         int ret = 0;
125
126         disable_irq(TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ));
127         ret = mask_cd_interrupt(1);
128
129         return ret;
130 }
131
132 static int hsmmc_resume(struct device *dev, int slot)
133 {
134         int ret = 0;
135
136         enable_irq(TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ));
137         ret = mask_cd_interrupt(0);
138
139         return ret;
140 }
141
142 #endif
143
144 static int hsmmc_set_power(struct device *dev, int slot, int power_on,
145                                 int vdd)
146 {
147         u32 vdd_sel = 0, devconf = 0, reg = 0;
148         int ret = 0;
149
150         /* REVISIT: Using address directly till the control.h defines
151          * are settled.
152          */
153 #if defined(CONFIG_ARCH_OMAP2430)
154         #define OMAP2_CONTROL_PBIAS 0x490024A0
155 #else
156         #define OMAP2_CONTROL_PBIAS 0x48002520
157 #endif
158
159         if (power_on) {
160                 if (cpu_is_omap24xx())
161                         devconf = omap_readl(OMAP2_CONTROL_DEVCONF1);
162                 else
163                         devconf = omap_readl(OMAP2_CONTROL_DEVCONF0);
164
165                 switch (1 << vdd) {
166                 case MMC_VDD_33_34:
167                 case MMC_VDD_32_33:
168                         vdd_sel = VSEL_3V;
169                         if (cpu_is_omap24xx())
170                                 devconf |= OMAP2_CONTROL_DEVCONF1_ACTOV;
171                         break;
172                 case MMC_VDD_165_195:
173                         vdd_sel = VSEL_18V;
174                         if (cpu_is_omap24xx())
175                                 devconf &= ~OMAP2_CONTROL_DEVCONF1_ACTOV;
176                 }
177
178                 if (cpu_is_omap24xx())
179                         omap_writel(devconf, OMAP2_CONTROL_DEVCONF1);
180                 else
181                         omap_writel(devconf | OMAP2_CONTROL_DEVCONF0_LBCLK,
182                                     OMAP2_CONTROL_DEVCONF0);
183
184                 reg = omap_readl(OMAP2_CONTROL_PBIAS);
185                 reg |= OMAP2_CONTROL_PBIAS_SCTRL;
186                 omap_writel(reg, OMAP2_CONTROL_PBIAS);
187
188                 reg = omap_readl(OMAP2_CONTROL_PBIAS);
189                 reg &= ~OMAP2_CONTROL_PBIAS_PWRDNZ;
190                 omap_writel(reg, OMAP2_CONTROL_PBIAS);
191
192                 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
193                                                 P1_DEV_GRP, VMMC1_DEV_GRP);
194                 if (ret)
195                         goto err;
196
197                 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
198                                                 vdd_sel, VMMC1_DEDICATED);
199                 if (ret)
200                         goto err;
201
202                 msleep(100);
203                 reg = omap_readl(OMAP2_CONTROL_PBIAS);
204                 reg |= (OMAP2_CONTROL_PBIAS_SCTRL |
205                         OMAP2_CONTROL_PBIAS_PWRDNZ);
206                 if (vdd_sel == VSEL_18V)
207                         reg &= ~OMAP2_CONTROL_PBIAS_VMODE;
208                 else
209                         reg |= OMAP2_CONTROL_PBIAS_VMODE;
210                 omap_writel(reg, OMAP2_CONTROL_PBIAS);
211
212                 return ret;
213
214         } else {
215                 /* Power OFF */
216
217                 /* For MMC1, Toggle PBIAS before every power up sequence */
218                 reg = omap_readl(OMAP2_CONTROL_PBIAS);
219                 reg &= ~OMAP2_CONTROL_PBIAS_PWRDNZ;
220                 omap_writel(reg, OMAP2_CONTROL_PBIAS);
221
222                 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
223                                                 LDO_CLR, VMMC1_DEV_GRP);
224                 if (ret)
225                         goto err;
226
227                 ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
228                                                 VSEL_S2_CLR, VMMC1_DEDICATED);
229                 if (ret)
230                         goto err;
231
232                 /* 100ms delay required for PBIAS configuration */
233                 msleep(100);
234                 reg = omap_readl(OMAP2_CONTROL_PBIAS);
235                 reg |= (OMAP2_CONTROL_PBIAS_VMODE |
236                         OMAP2_CONTROL_PBIAS_PWRDNZ |
237                         OMAP2_CONTROL_PBIAS_SCTRL);
238                 omap_writel(reg, OMAP2_CONTROL_PBIAS);
239         }
240
241         return 0;
242
243 err:
244         return 1;
245 }
246
247 static struct omap_mmc_platform_data mmc1_data = {
248         .nr_slots                       = 1,
249         .init                           = hsmmc_late_init,
250         .cleanup                        = hsmmc_cleanup,
251 #ifdef CONFIG_PM
252         .suspend                        = hsmmc_suspend,
253         .resume                         = hsmmc_resume,
254 #endif
255         .dma_mask                       = 0xffffffff,
256         .slots[0] = {
257                 .wire4                  = 1,
258                 .set_power              = hsmmc_set_power,
259                 .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34 |
260                                                 MMC_VDD_165_195,
261                 .name                   = "first slot",
262
263                 .card_detect_irq        = TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ),
264                 .card_detect            = hsmmc_card_detect,
265         },
266 };
267
268 static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC];
269
270 void __init hsmmc_init(void)
271 {
272         hsmmc_data[0] = &mmc1_data;
273         omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC);
274 }
275
276 #else
277
278 void __init hsmmc_init(void)
279 {
280
281 }
282
283 #endif