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