b732209de1b31a4bf15eecdb682f45b393ebc176
[linux-2.6.git] / arch / arm / mach-tegra / board-cardhu-sdhci.c
1 /*
2  * arch/arm/mach-tegra/board-harmony-sdhci.c
3  *
4  * Copyright (C) 2010 Google, Inc.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/resource.h>
18 #include <linux/platform_device.h>
19 #include <linux/delay.h>
20 #include <linux/gpio.h>
21 #include <linux/clk.h>
22 #include <linux/err.h>
23 #include <linux/mmc/host.h>
24
25 #include <asm/mach-types.h>
26 #include <mach/irqs.h>
27 #include <mach/iomap.h>
28 #include <mach/sdhci.h>
29
30 #include "gpio-names.h"
31 #include "board.h"
32 #include "board-cardhu.h"
33
34 #define CARDHU_SD_CD TEGRA_GPIO_PI5
35 #define CARDHU_SD_WP TEGRA_GPIO_PT3
36 #define PM269_SD_WP TEGRA_GPIO_PZ4
37
38 static struct resource sdhci_resource0[] = {
39         [0] = {
40                 .start  = INT_SDMMC1,
41                 .end    = INT_SDMMC1,
42                 .flags  = IORESOURCE_IRQ,
43         },
44         [1] = {
45                 .start  = TEGRA_SDMMC1_BASE,
46                 .end    = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1,
47                 .flags  = IORESOURCE_MEM,
48         },
49 };
50
51 static struct resource sdhci_resource2[] = {
52         [0] = {
53                 .start  = INT_SDMMC3,
54                 .end    = INT_SDMMC3,
55                 .flags  = IORESOURCE_IRQ,
56         },
57         [1] = {
58                 .start  = TEGRA_SDMMC3_BASE,
59                 .end    = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1,
60                 .flags  = IORESOURCE_MEM,
61         },
62 };
63
64 static struct resource sdhci_resource3[] = {
65         [0] = {
66                 .start  = INT_SDMMC4,
67                 .end    = INT_SDMMC4,
68                 .flags  = IORESOURCE_IRQ,
69         },
70         [1] = {
71                 .start  = TEGRA_SDMMC4_BASE,
72                 .end    = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1,
73                 .flags  = IORESOURCE_MEM,
74         },
75 };
76
77
78 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = {
79         .cd_gpio = -1,
80         .wp_gpio = -1,
81         .power_gpio = -1,
82         .tap_delay = 6,
83         .is_voltage_switch_supported = false,
84         .vdd_rail_name = NULL,
85         .slot_rail_name = NULL,
86         .vdd_max_uv = -1,
87         .vdd_min_uv = -1,
88         .max_clk = 0,
89         .is_8bit_supported = false,
90 };
91
92 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
93         .cd_gpio = -1,
94         .wp_gpio = -1,
95         .power_gpio = -1,
96         .tap_delay = 6,
97         .is_voltage_switch_supported = true,
98         .vdd_rail_name = "vddio_sdmmc1",
99         .slot_rail_name = "vddio_sd_slot",
100         .vdd_max_uv = 3320000,
101         .vdd_min_uv = 3280000,
102         .max_clk = 208000000,
103         .is_8bit_supported = false,
104 };
105
106 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
107         .cd_gpio = -1,
108         .wp_gpio = -1,
109         .power_gpio = -1,
110         .tap_delay = 6,
111         .is_voltage_switch_supported = false,
112         .vdd_rail_name = NULL,
113         .slot_rail_name = NULL,
114         .vdd_max_uv = -1,
115         .vdd_min_uv = -1,
116         .max_clk = 48000000,
117         .is_8bit_supported = true,
118 };
119
120 static struct platform_device tegra_sdhci_device0 = {
121         .name           = "sdhci-tegra",
122         .id             = 0,
123         .resource       = sdhci_resource0,
124         .num_resources  = ARRAY_SIZE(sdhci_resource0),
125         .dev = {
126                 .platform_data = &tegra_sdhci_platform_data0,
127         },
128 };
129
130 static struct platform_device tegra_sdhci_device2 = {
131         .name           = "sdhci-tegra",
132         .id             = 2,
133         .resource       = sdhci_resource2,
134         .num_resources  = ARRAY_SIZE(sdhci_resource2),
135         .dev = {
136                 .platform_data = &tegra_sdhci_platform_data2,
137         },
138 };
139
140 static struct platform_device tegra_sdhci_device3 = {
141         .name           = "sdhci-tegra",
142         .id             = 3,
143         .resource       = sdhci_resource3,
144         .num_resources  = ARRAY_SIZE(sdhci_resource3),
145         .dev = {
146                 .platform_data = &tegra_sdhci_platform_data3,
147         },
148 };
149
150 static int cardhu_sd_cd_gpio_init(void)
151 {
152         unsigned int rc = 0;
153
154         rc = gpio_request(CARDHU_SD_CD, "card_detect");
155         if (rc) {
156                 pr_err("Card detect gpio request failed:%d\n", rc);
157                 return rc;
158         }
159
160         tegra_gpio_enable(CARDHU_SD_CD);
161
162         rc = gpio_direction_input(CARDHU_SD_CD);
163         if (rc) {
164                 pr_err("Unable to configure direction for card detect gpio:%d\n", rc);
165                 return rc;
166         }
167
168         return 0;
169 }
170
171 static int cardhu_sd_wp_gpio_init(void)
172 {
173         unsigned int rc = 0;
174
175         rc = gpio_request(CARDHU_SD_WP, "write_protect");
176         if (rc) {
177                 pr_err("Write protect gpio request failed:%d\n", rc);
178                 return rc;
179         }
180
181         tegra_gpio_enable(CARDHU_SD_WP);
182
183         rc = gpio_direction_input(CARDHU_SD_WP);
184         if (rc) {
185                 pr_err("Unable to configure direction for write protect gpio:%d\n", rc);
186                 return rc;
187         }
188
189         return 0;
190 }
191
192 static int pm269_sd_wp_gpio_init(void)
193 {
194         unsigned int rc = 0;
195
196         rc = gpio_request(PM269_SD_WP, "write_protect");
197         if (rc) {
198                 pr_err("Write protect gpio request failed:%d\n", rc);
199                 return rc;
200         }
201
202         tegra_gpio_enable(PM269_SD_WP);
203
204         rc = gpio_direction_input(PM269_SD_WP);
205         if (rc) {
206                 pr_err("Unable to configure direction for write protect gpio:%d\n", rc);
207                 return rc;
208         }
209
210         return 0;
211 }
212
213 int __init cardhu_sdhci_init(void)
214 {
215         unsigned int rc = 0;
216         struct board_info board_info;
217         tegra_get_board_info(&board_info);
218         if (board_info.board_id == BOARD_PM269) {
219                 tegra_sdhci_platform_data2.max_clk = 12000000;
220                 rc = pm269_sd_wp_gpio_init();
221                 if (!rc) {
222                         tegra_sdhci_platform_data0.wp_gpio = PM269_SD_WP;
223                         tegra_sdhci_platform_data0.wp_gpio_polarity = 1;
224                 }
225         } else {
226                 tegra_sdhci_platform_data2.max_clk = 48000000;
227                 rc = cardhu_sd_wp_gpio_init();
228                 if (!rc) {
229                         tegra_sdhci_platform_data0.wp_gpio = CARDHU_SD_WP;
230                         tegra_sdhci_platform_data0.wp_gpio_polarity = 1;
231                 }
232         }
233
234         platform_device_register(&tegra_sdhci_device3);
235         platform_device_register(&tegra_sdhci_device2);
236
237         /* Fix ME: The gpios have to enabled for hot plug support */
238         rc = cardhu_sd_cd_gpio_init();
239         if (!rc) {
240                 tegra_sdhci_platform_data0.cd_gpio = CARDHU_SD_CD;
241                 tegra_sdhci_platform_data0.cd_gpio_polarity = 0;
242         }
243
244
245
246         platform_device_register(&tegra_sdhci_device0);
247
248         return 0;
249 }