diff options
Diffstat (limited to 'arch/arm/mach-tegra/board-kai-sdhci.c')
-rw-r--r-- | arch/arm/mach-tegra/board-kai-sdhci.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/board-kai-sdhci.c b/arch/arm/mach-tegra/board-kai-sdhci.c new file mode 100644 index 00000000000..3e489927108 --- /dev/null +++ b/arch/arm/mach-tegra/board-kai-sdhci.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-tegra/board-kai-sdhci.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Copyright (C) 2012 NVIDIA Corporation. | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/resource.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <linux/mmc/host.h> | ||
25 | #include <linux/wl12xx.h> | ||
26 | |||
27 | #include <asm/mach-types.h> | ||
28 | #include <mach/irqs.h> | ||
29 | #include <mach/iomap.h> | ||
30 | #include <mach/sdhci.h> | ||
31 | |||
32 | #include "gpio-names.h" | ||
33 | #include "board.h" | ||
34 | #include "board-kai.h" | ||
35 | |||
36 | #define KAI_SD_CD TEGRA_GPIO_PI5 | ||
37 | #define KAI_WLAN_EN TEGRA_GPIO_PD3 | ||
38 | #define KAI_WLAN_IRQ TEGRA_GPIO_PV1 | ||
39 | |||
40 | static void (*wifi_status_cb)(int card_present, void *dev_id); | ||
41 | static void *wifi_status_cb_devid; | ||
42 | static int kai_wifi_power(int power_on); | ||
43 | static int kai_wifi_set_carddetect(int val); | ||
44 | |||
45 | static int kai_wifi_status_register( | ||
46 | void (*callback)(int card_present, void *dev_id), | ||
47 | void *dev_id) | ||
48 | { | ||
49 | if (wifi_status_cb) | ||
50 | return -EAGAIN; | ||
51 | wifi_status_cb = callback; | ||
52 | wifi_status_cb_devid = dev_id; | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | |||
57 | static struct wl12xx_platform_data kai_wlan_data __initdata = { | ||
58 | .irq = TEGRA_GPIO_TO_IRQ(KAI_WLAN_IRQ), | ||
59 | .board_ref_clock = WL12XX_REFCLOCK_26, | ||
60 | .board_tcxo_clock = 1, | ||
61 | .set_power = kai_wifi_power, | ||
62 | .set_carddetect = kai_wifi_set_carddetect, | ||
63 | }; | ||
64 | |||
65 | static struct resource sdhci_resource0[] = { | ||
66 | [0] = { | ||
67 | .start = INT_SDMMC1, | ||
68 | .end = INT_SDMMC1, | ||
69 | .flags = IORESOURCE_IRQ, | ||
70 | }, | ||
71 | [1] = { | ||
72 | .start = TEGRA_SDMMC1_BASE, | ||
73 | .end = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1, | ||
74 | .flags = IORESOURCE_MEM, | ||
75 | }, | ||
76 | }; | ||
77 | |||
78 | static struct resource sdhci_resource2[] = { | ||
79 | [0] = { | ||
80 | .start = INT_SDMMC3, | ||
81 | .end = INT_SDMMC3, | ||
82 | .flags = IORESOURCE_IRQ, | ||
83 | }, | ||
84 | [1] = { | ||
85 | .start = TEGRA_SDMMC3_BASE, | ||
86 | .end = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1, | ||
87 | .flags = IORESOURCE_MEM, | ||
88 | }, | ||
89 | }; | ||
90 | |||
91 | static struct resource sdhci_resource3[] = { | ||
92 | [0] = { | ||
93 | .start = INT_SDMMC4, | ||
94 | .end = INT_SDMMC4, | ||
95 | .flags = IORESOURCE_IRQ, | ||
96 | }, | ||
97 | [1] = { | ||
98 | .start = TEGRA_SDMMC4_BASE, | ||
99 | .end = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1, | ||
100 | .flags = IORESOURCE_MEM, | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | static struct embedded_sdio_data embedded_sdio_data2 = { | ||
105 | .cccr = { | ||
106 | .sdio_vsn = 2, | ||
107 | .multi_block = 1, | ||
108 | .low_speed = 0, | ||
109 | .wide_bus = 0, | ||
110 | .high_power = 1, | ||
111 | .high_speed = 1, | ||
112 | }, | ||
113 | .cis = { | ||
114 | .vendor = 0x0097, | ||
115 | .device = 0x4076, | ||
116 | }, | ||
117 | }; | ||
118 | |||
119 | static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = { | ||
120 | .mmc_data = { | ||
121 | .register_status_notify = kai_wifi_status_register, | ||
122 | /* .embedded_sdio = &embedded_sdio_data2, */ | ||
123 | .built_in = 1, | ||
124 | }, | ||
125 | .cd_gpio = -1, | ||
126 | .wp_gpio = -1, | ||
127 | .power_gpio = -1, | ||
128 | /* .tap_delay = 6, | ||
129 | .is_voltage_switch_supported = false, | ||
130 | .vdd_rail_name = NULL, | ||
131 | .slot_rail_name = NULL, | ||
132 | .vdd_max_uv = -1, | ||
133 | .vdd_min_uv = -1, | ||
134 | .max_clk = 0, | ||
135 | .is_8bit_supported = false, */ | ||
136 | /* .max_clk = 25000000, */ | ||
137 | }; | ||
138 | |||
139 | static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = { | ||
140 | .cd_gpio = KAI_SD_CD, | ||
141 | .wp_gpio = -1, | ||
142 | .power_gpio = -1, | ||
143 | /* .tap_delay = 6, | ||
144 | .is_voltage_switch_supported = true, | ||
145 | .vdd_rail_name = "vddio_sdmmc1", | ||
146 | .slot_rail_name = "vddio_sd_slot", | ||
147 | .vdd_max_uv = 3320000, | ||
148 | .vdd_min_uv = 3280000, | ||
149 | .max_clk = 208000000, | ||
150 | .is_8bit_supported = false, */ | ||
151 | }; | ||
152 | |||
153 | static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = { | ||
154 | .cd_gpio = -1, | ||
155 | .wp_gpio = -1, | ||
156 | .power_gpio = -1, | ||
157 | .is_8bit = 1, | ||
158 | .tap_delay = 0x0F, | ||
159 | .mmc_data = { | ||
160 | .built_in = 1, | ||
161 | } | ||
162 | /* .tap_delay = 6, | ||
163 | .is_voltage_switch_supported = false, | ||
164 | .vdd_rail_name = NULL, | ||
165 | .slot_rail_name = NULL, | ||
166 | .vdd_max_uv = -1, | ||
167 | .vdd_min_uv = -1, | ||
168 | .max_clk = 48000000, | ||
169 | .is_8bit_supported = true, */ | ||
170 | }; | ||
171 | |||
172 | static struct platform_device tegra_sdhci_device0 = { | ||
173 | .name = "sdhci-tegra", | ||
174 | .id = 0, | ||
175 | .resource = sdhci_resource0, | ||
176 | .num_resources = ARRAY_SIZE(sdhci_resource0), | ||
177 | .dev = { | ||
178 | .platform_data = &tegra_sdhci_platform_data0, | ||
179 | }, | ||
180 | }; | ||
181 | |||
182 | static struct platform_device tegra_sdhci_device2 = { | ||
183 | .name = "sdhci-tegra", | ||
184 | .id = 2, | ||
185 | .resource = sdhci_resource2, | ||
186 | .num_resources = ARRAY_SIZE(sdhci_resource2), | ||
187 | .dev = { | ||
188 | .platform_data = &tegra_sdhci_platform_data2, | ||
189 | }, | ||
190 | }; | ||
191 | |||
192 | static struct platform_device tegra_sdhci_device3 = { | ||
193 | .name = "sdhci-tegra", | ||
194 | .id = 3, | ||
195 | .resource = sdhci_resource3, | ||
196 | .num_resources = ARRAY_SIZE(sdhci_resource3), | ||
197 | .dev = { | ||
198 | .platform_data = &tegra_sdhci_platform_data3, | ||
199 | }, | ||
200 | }; | ||
201 | |||
202 | static int kai_wifi_set_carddetect(int val) | ||
203 | { | ||
204 | pr_debug("%s: %d\n", __func__, val); | ||
205 | if (wifi_status_cb) | ||
206 | wifi_status_cb(val, wifi_status_cb_devid); | ||
207 | else | ||
208 | pr_warning("%s: Nobody to notify\n", __func__); | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int kai_wifi_power(int power_on) | ||
213 | { | ||
214 | pr_err("Powering %s wifi\n", (power_on ? "on" : "off")); | ||
215 | |||
216 | if (power_on) { | ||
217 | gpio_set_value(KAI_WLAN_EN, 1); | ||
218 | mdelay(15); | ||
219 | gpio_set_value(KAI_WLAN_EN, 0); | ||
220 | mdelay(1); | ||
221 | gpio_set_value(KAI_WLAN_EN, 1); | ||
222 | mdelay(70); | ||
223 | } else { | ||
224 | gpio_set_value(KAI_WLAN_EN, 0); | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int __init kai_wifi_init(void) | ||
231 | { | ||
232 | int rc; | ||
233 | |||
234 | rc = gpio_request(KAI_WLAN_EN, "wl12xx"); | ||
235 | if (rc) | ||
236 | pr_err("WLAN_EN gpio request failed:%d\n", rc); | ||
237 | |||
238 | rc = gpio_request(KAI_WLAN_IRQ, "wl12xx"); | ||
239 | if (rc) | ||
240 | pr_err("WLAN_IRQ gpio request failed:%d\n", rc); | ||
241 | |||
242 | tegra_gpio_enable(KAI_WLAN_EN); | ||
243 | tegra_gpio_enable(KAI_WLAN_IRQ); | ||
244 | |||
245 | rc = gpio_direction_output(KAI_WLAN_EN, 0); | ||
246 | if (rc) | ||
247 | pr_err("WLAN_EN gpio direction configuration failed:%d\n", rc); | ||
248 | |||
249 | rc = gpio_direction_input(KAI_WLAN_IRQ); | ||
250 | if (rc) | ||
251 | pr_err("WLAN_IRQ gpio direction configuration failed:%d\n", rc); | ||
252 | |||
253 | if (wl12xx_set_platform_data(&kai_wlan_data)) | ||
254 | pr_err("Error setting wl12xx data\n"); | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | int __init kai_sdhci_init(void) | ||
260 | { | ||
261 | platform_device_register(&tegra_sdhci_device3); | ||
262 | platform_device_register(&tegra_sdhci_device2); | ||
263 | platform_device_register(&tegra_sdhci_device0); | ||
264 | |||
265 | kai_wifi_init(); | ||
266 | return 0; | ||
267 | } | ||