ARM: tegra: pm269: sdhci: Support for PM269
[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         .clk_id = NULL,
80         .force_hs = 0,
81         .cd_gpio = -1,
82         .wp_gpio = -1,
83         .power_gpio = -1,
84         .tap_delay = 6,
85         .is_voltage_switch_supported = false,
86         .vdd_rail_name = NULL,
87         .slot_rail_name = NULL,
88         .vdd_max_uv = -1,
89         .vdd_min_uv = -1,
90         .max_clk = 0,
91         .is_8bit_supported = false,
92 };
93
94 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
95         .clk_id = NULL,
96         .force_hs = 1,
97         .cd_gpio = -1,
98         .wp_gpio = -1,
99         .power_gpio = -1,
100         .tap_delay = 6,
101         .is_voltage_switch_supported = true,
102         .vdd_rail_name = "vddio_sdmmc1",
103         .slot_rail_name = "vddio_sd_slot",
104         .vdd_max_uv = 3320000,
105         .vdd_min_uv = 3280000,
106         .max_clk = 208000000,
107         .is_8bit_supported = false,
108 };
109
110 static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
111         .clk_id = NULL,
112         .force_hs = 0,
113         .cd_gpio = -1,
114         .wp_gpio = -1,
115         .power_gpio = -1,
116         .tap_delay = 6,
117         .is_voltage_switch_supported = false,
118         .vdd_rail_name = NULL,
119         .slot_rail_name = NULL,
120         .vdd_max_uv = -1,
121         .vdd_min_uv = -1,
122         .max_clk = 48000000,
123         .is_8bit_supported = true,
124 };
125
126 static struct platform_device tegra_sdhci_device0 = {
127         .name           = "sdhci-tegra",
128         .id             = 0,
129         .resource       = sdhci_resource0,
130         .num_resources  = ARRAY_SIZE(sdhci_resource0),
131         .dev = {
132                 .platform_data = &tegra_sdhci_platform_data0,
133         },
134 };
135
136 static struct platform_device tegra_sdhci_device2 = {
137         .name           = "sdhci-tegra",
138         .id             = 2,
139         .resource       = sdhci_resource2,
140         .num_resources  = ARRAY_SIZE(sdhci_resource2),
141         .dev = {
142                 .platform_data = &tegra_sdhci_platform_data2,
143         },
144 };
145
146 static struct platform_device tegra_sdhci_device3 = {
147         .name           = "sdhci-tegra",
148         .id             = 3,
149         .resource       = sdhci_resource3,
150         .num_resources  = ARRAY_SIZE(sdhci_resource3),
151         .dev = {
152                 .platform_data = &tegra_sdhci_platform_data3,
153         },
154 };
155
156 static int cardhu_sd_cd_gpio_init(void)
157 {
158         unsigned int rc = 0;
159
160         rc = gpio_request(CARDHU_SD_CD, "card_detect");
161         if (rc) {
162                 pr_err("Card detect gpio request failed:%d\n", rc);
163                 return rc;
164         }
165
166         tegra_gpio_enable(CARDHU_SD_CD);
167
168         rc = gpio_direction_input(CARDHU_SD_CD);
169         if (rc) {
170                 pr_err("Unable to configure direction for card detect gpio:%d\n", rc);
171                 return rc;
172         }
173
174         return 0;
175 }
176
177 static int cardhu_sd_wp_gpio_init(void)
178 {
179         unsigned int rc = 0;
180
181         rc = gpio_request(CARDHU_SD_WP, "write_protect");
182         if (rc) {
183                 pr_err("Write protect gpio request failed:%d\n", rc);
184                 return rc;
185         }
186
187         tegra_gpio_enable(CARDHU_SD_WP);
188
189         rc = gpio_direction_input(CARDHU_SD_WP);
190         if (rc) {
191                 pr_err("Unable to configure direction for write protect gpio:%d\n", rc);
192                 return rc;
193         }
194
195         return 0;
196 }
197
198 static int pm269_sd_wp_gpio_init(void)
199 {
200         unsigned int rc = 0;
201
202         rc = gpio_request(PM269_SD_WP, "write_protect");
203         if (rc) {
204                 pr_err("Write protect gpio request failed:%d\n", rc);
205                 return rc;
206         }
207
208         tegra_gpio_enable(PM269_SD_WP);
209
210         rc = gpio_direction_input(PM269_SD_WP);
211         if (rc) {
212                 pr_err("Unable to configure direction for write protect gpio:%d\n", rc);
213                 return rc;
214         }
215
216         return 0;
217 }
218
219 int __init cardhu_sdhci_init(void)
220 {
221         unsigned int rc = 0;
222         struct board_info board_info;
223         tegra_get_board_info(&board_info);
224         if (board_info.board_id == BOARD_PM269) {
225                 tegra_sdhci_platform_data2.max_clk = 12000000;
226                 rc = pm269_sd_wp_gpio_init();
227                 if (!rc) {
228                         tegra_sdhci_platform_data0.wp_gpio = PM269_SD_WP;
229                         tegra_sdhci_platform_data0.wp_gpio_polarity = 1;
230                 }
231         } else {
232                 tegra_sdhci_platform_data2.max_clk = 48000000;
233                 rc = cardhu_sd_wp_gpio_init();
234                 if (!rc) {
235                         tegra_sdhci_platform_data0.wp_gpio = CARDHU_SD_WP;
236                         tegra_sdhci_platform_data0.wp_gpio_polarity = 1;
237                 }
238         }
239
240         platform_device_register(&tegra_sdhci_device3);
241         platform_device_register(&tegra_sdhci_device2);
242
243         /* Fix ME: The gpios have to enabled for hot plug support */
244         rc = cardhu_sd_cd_gpio_init();
245         if (!rc) {
246                 tegra_sdhci_platform_data0.cd_gpio = CARDHU_SD_CD;
247                 tegra_sdhci_platform_data0.cd_gpio_polarity = 0;
248         }
249
250
251
252         platform_device_register(&tegra_sdhci_device0);
253
254         return 0;
255 }