blob: 564c59df0906fe43411bd11a75ff59122769e3f0 [file] [log] [blame]
Taniya Dasc868a2e2012-01-03 10:18:47 +05301/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Chintan Pandyacf467fc2011-12-01 17:11:11 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <asm/mach-types.h>
15#include <asm/mach/mmc.h>
16#include <linux/regulator/consumer.h>
17#include <mach/gpio.h>
18#include <mach/gpiomux.h>
19#include <mach/board.h>
20
21#include "devices.h"
Sujit Reddy Thummaca0c1062012-02-24 14:47:05 +053022#include "pm.h"
Chintan Pandyacf467fc2011-12-01 17:11:11 +053023#include "board-msm7627a.h"
24
25#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
26 || defined(CONFIG_MMC_MSM_SDC2_SUPPORT)\
27 || defined(CONFIG_MMC_MSM_SDC3_SUPPORT)\
28 || defined(CONFIG_MMC_MSM_SDC4_SUPPORT))
29
Sujit Reddy Thumma464a1792012-02-17 15:54:13 +053030#define MAX_SDCC_CONTROLLER 4
Chintan Pandyacf467fc2011-12-01 17:11:11 +053031static unsigned long vreg_sts, gpio_sts;
32
33struct sdcc_gpio {
34 struct msm_gpio *cfg_data;
35 uint32_t size;
36 struct msm_gpio *sleep_cfg_data;
37};
38
39/**
40 * Due to insufficient drive strengths for SDC GPIO lines some old versioned
41 * SD/MMC cards may cause data CRC errors. Hence, set optimal values
42 * for SDC slots based on timing closure and marginality. SDC1 slot
43 * require higher value since it should handle bad signal quality due
44 * to size of T-flash adapters.
45 */
46static struct msm_gpio sdc1_cfg_data[] = {
47 {GPIO_CFG(51, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
48 "sdc1_dat_3"},
49 {GPIO_CFG(52, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
50 "sdc1_dat_2"},
51 {GPIO_CFG(53, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
52 "sdc1_dat_1"},
53 {GPIO_CFG(54, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
54 "sdc1_dat_0"},
55 {GPIO_CFG(55, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_14MA),
56 "sdc1_cmd"},
57 {GPIO_CFG(56, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_14MA),
58 "sdc1_clk"},
59};
60
61static struct msm_gpio sdc2_cfg_data[] = {
62 {GPIO_CFG(62, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
63 "sdc2_clk"},
64 {GPIO_CFG(63, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
65 "sdc2_cmd"},
66 {GPIO_CFG(64, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
67 "sdc2_dat_3"},
68 {GPIO_CFG(65, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
69 "sdc2_dat_2"},
70 {GPIO_CFG(66, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
71 "sdc2_dat_1"},
72 {GPIO_CFG(67, 2, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
73 "sdc2_dat_0"},
74};
75
76static struct msm_gpio sdc2_sleep_cfg_data[] = {
Sujit Reddy Thumma4a6d84b2012-02-15 19:40:45 +053077 {GPIO_CFG(62, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
Chintan Pandyacf467fc2011-12-01 17:11:11 +053078 "sdc2_clk"},
Sujit Reddy Thumma4a6d84b2012-02-15 19:40:45 +053079 {GPIO_CFG(63, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
Chintan Pandyacf467fc2011-12-01 17:11:11 +053080 "sdc2_cmd"},
Sujit Reddy Thumma4a6d84b2012-02-15 19:40:45 +053081 {GPIO_CFG(64, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
Chintan Pandyacf467fc2011-12-01 17:11:11 +053082 "sdc2_dat_3"},
Sujit Reddy Thumma4a6d84b2012-02-15 19:40:45 +053083 {GPIO_CFG(65, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
Chintan Pandyacf467fc2011-12-01 17:11:11 +053084 "sdc2_dat_2"},
Sujit Reddy Thumma4a6d84b2012-02-15 19:40:45 +053085 {GPIO_CFG(66, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
Chintan Pandyacf467fc2011-12-01 17:11:11 +053086 "sdc2_dat_1"},
Sujit Reddy Thumma4a6d84b2012-02-15 19:40:45 +053087 {GPIO_CFG(67, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
Chintan Pandyacf467fc2011-12-01 17:11:11 +053088 "sdc2_dat_0"},
89};
90static struct msm_gpio sdc3_cfg_data[] = {
91 {GPIO_CFG(88, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
92 "sdc3_clk"},
93 {GPIO_CFG(89, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
94 "sdc3_cmd"},
95 {GPIO_CFG(90, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
96 "sdc3_dat_3"},
97 {GPIO_CFG(91, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
98 "sdc3_dat_2"},
99 {GPIO_CFG(92, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
100 "sdc3_dat_1"},
101 {GPIO_CFG(93, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
102 "sdc3_dat_0"},
103#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
104 {GPIO_CFG(19, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
105 "sdc3_dat_7"},
106 {GPIO_CFG(20, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
107 "sdc3_dat_6"},
108 {GPIO_CFG(21, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
109 "sdc3_dat_5"},
110 {GPIO_CFG(108, 3, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
111 "sdc3_dat_4"},
112#endif
113};
114
115static struct msm_gpio sdc4_cfg_data[] = {
116 {GPIO_CFG(19, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
117 "sdc4_dat_3"},
118 {GPIO_CFG(20, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
119 "sdc4_dat_2"},
120 {GPIO_CFG(21, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
121 "sdc4_dat_1"},
122 {GPIO_CFG(107, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
123 "sdc4_cmd"},
124 {GPIO_CFG(108, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_10MA),
125 "sdc4_dat_0"},
126 {GPIO_CFG(109, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
127 "sdc4_clk"},
128};
129
130static struct sdcc_gpio sdcc_cfg_data[] = {
131 {
132 .cfg_data = sdc1_cfg_data,
133 .size = ARRAY_SIZE(sdc1_cfg_data),
134 },
135 {
136 .cfg_data = sdc2_cfg_data,
137 .size = ARRAY_SIZE(sdc2_cfg_data),
138 .sleep_cfg_data = sdc2_sleep_cfg_data,
139 },
140 {
141 .cfg_data = sdc3_cfg_data,
142 .size = ARRAY_SIZE(sdc3_cfg_data),
143 },
144 {
145 .cfg_data = sdc4_cfg_data,
146 .size = ARRAY_SIZE(sdc4_cfg_data),
147 },
148};
149
150static int gpio_sdc1_hw_det = 85;
151static void gpio_sdc1_config(void)
152{
Chintan Pandyaf4ad4002012-02-28 19:49:03 +0530153 if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
Aparna Mallavarapu80c9bcf2012-04-03 13:51:48 +0530154 || machine_is_msm8625_evb()
155 || machine_is_msm7627a_qrd3()
156 || machine_is_msm8625_qrd7())
Chintan Pandyacf467fc2011-12-01 17:11:11 +0530157 gpio_sdc1_hw_det = 42;
158}
159
Sujit Reddy Thumma464a1792012-02-17 15:54:13 +0530160static struct regulator *sdcc_vreg_data[MAX_SDCC_CONTROLLER];
Chintan Pandyacf467fc2011-12-01 17:11:11 +0530161static int msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
162{
163 int rc = 0;
164 struct sdcc_gpio *curr;
165
166 curr = &sdcc_cfg_data[dev_id - 1];
167 if (!(test_bit(dev_id, &gpio_sts)^enable))
168 return rc;
169
170 if (enable) {
171 set_bit(dev_id, &gpio_sts);
172 rc = msm_gpios_request_enable(curr->cfg_data, curr->size);
173 if (rc)
174 pr_err("%s: Failed to turn on GPIOs for slot %d\n",
175 __func__, dev_id);
176 } else {
177 clear_bit(dev_id, &gpio_sts);
178 if (curr->sleep_cfg_data) {
179 rc = msm_gpios_enable(curr->sleep_cfg_data, curr->size);
180 msm_gpios_free(curr->sleep_cfg_data, curr->size);
181 return rc;
182 }
183 msm_gpios_disable_free(curr->cfg_data, curr->size);
184 }
185 return rc;
186}
187
188static int msm_sdcc_setup_vreg(int dev_id, unsigned int enable)
189{
190 int rc = 0;
191 struct regulator *curr = sdcc_vreg_data[dev_id - 1];
192
193 if (test_bit(dev_id, &vreg_sts) == enable)
194 return 0;
195
196 if (!curr)
197 return -ENODEV;
198
199 if (IS_ERR(curr))
200 return PTR_ERR(curr);
201
202 if (enable) {
203 set_bit(dev_id, &vreg_sts);
204
205 rc = regulator_enable(curr);
206 if (rc)
207 pr_err("%s: could not enable regulator: %d\n",
208 __func__, rc);
209 } else {
210 clear_bit(dev_id, &vreg_sts);
211
212 rc = regulator_disable(curr);
213 if (rc)
214 pr_err("%s: could not disable regulator: %d\n",
215 __func__, rc);
216 }
217 return rc;
218}
219
220static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd)
221{
222 int rc = 0;
223 struct platform_device *pdev;
224
225 pdev = container_of(dv, struct platform_device, dev);
226
227 rc = msm_sdcc_setup_gpio(pdev->id, !!vdd);
228 if (rc)
229 goto out;
230
231 rc = msm_sdcc_setup_vreg(pdev->id, !!vdd);
232out:
233 return rc;
234}
235
236#if defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
237 && defined(CONFIG_MMC_MSM_CARD_HW_DETECTION)
238static unsigned int msm7627a_sdcc_slot_status(struct device *dev)
239{
240 int status;
241
242 status = gpio_tlmm_config(GPIO_CFG(gpio_sdc1_hw_det, 2, GPIO_CFG_INPUT,
243 GPIO_CFG_PULL_UP, GPIO_CFG_8MA),
244 GPIO_CFG_ENABLE);
245 if (status)
246 pr_err("%s:Failed to configure tlmm for GPIO %d\n", __func__,
247 gpio_sdc1_hw_det);
248
249 status = gpio_request(gpio_sdc1_hw_det, "SD_HW_Detect");
250 if (status) {
251 pr_err("%s:Failed to request GPIO %d\n", __func__,
252 gpio_sdc1_hw_det);
253 } else {
254 status = gpio_direction_input(gpio_sdc1_hw_det);
255 if (!status) {
Taniya Dasc868a2e2012-01-03 10:18:47 +0530256 if (machine_is_msm7627a_qrd1() ||
Chintan Pandyaf4ad4002012-02-28 19:49:03 +0530257 machine_is_msm7627a_evb() ||
Aparna Mallavarapu80c9bcf2012-04-03 13:51:48 +0530258 machine_is_msm8625_evb() ||
259 machine_is_msm7627a_qrd3() ||
260 machine_is_msm8625_qrd7())
Chintan Pandyacf467fc2011-12-01 17:11:11 +0530261 status = !gpio_get_value(gpio_sdc1_hw_det);
262 else
263 status = gpio_get_value(gpio_sdc1_hw_det);
264 }
265 gpio_free(gpio_sdc1_hw_det);
266 }
267 return status;
268}
269#endif
270
271#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
272static struct mmc_platform_data sdc1_plat_data = {
273 .ocr_mask = MMC_VDD_28_29,
274 .translate_vdd = msm_sdcc_setup_power,
275 .mmc_bus_width = MMC_CAP_4_BIT_DATA,
276 .msmsdcc_fmin = 144000,
277 .msmsdcc_fmid = 24576000,
278 .msmsdcc_fmax = 49152000,
279#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
280 .status = msm7627a_sdcc_slot_status,
281 .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
282#endif
283};
284#endif
285
286#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
287static struct mmc_platform_data sdc2_plat_data = {
288 /*
289 * SDC2 supports only 1.8V, claim for 2.85V range is just
290 * for allowing buggy cards who advertise 2.8V even though
291 * they can operate at 1.8V supply.
292 */
293 .ocr_mask = MMC_VDD_28_29 | MMC_VDD_165_195,
294 .translate_vdd = msm_sdcc_setup_power,
295 .mmc_bus_width = MMC_CAP_4_BIT_DATA,
296#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
297 .sdiowakeup_irq = MSM_GPIO_TO_INT(66),
298#endif
299 .msmsdcc_fmin = 144000,
300 .msmsdcc_fmid = 24576000,
301 .msmsdcc_fmax = 49152000,
302#ifdef CONFIG_MMC_MSM_SDC2_DUMMY52_REQUIRED
303 .dummy52_required = 1,
304#endif
305};
306#endif
307
308#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
309static struct mmc_platform_data sdc3_plat_data = {
310 .ocr_mask = MMC_VDD_28_29,
311 .translate_vdd = msm_sdcc_setup_power,
312#ifdef CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT
313 .mmc_bus_width = MMC_CAP_8_BIT_DATA,
314#else
315 .mmc_bus_width = MMC_CAP_4_BIT_DATA,
316#endif
317 .msmsdcc_fmin = 144000,
318 .msmsdcc_fmid = 24576000,
319 .msmsdcc_fmax = 49152000,
320 .nonremovable = 1,
321};
322#endif
323
324#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
325 && !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
326static struct mmc_platform_data sdc4_plat_data = {
327 .ocr_mask = MMC_VDD_28_29,
328 .translate_vdd = msm_sdcc_setup_power,
329 .mmc_bus_width = MMC_CAP_4_BIT_DATA,
330 .msmsdcc_fmin = 144000,
331 .msmsdcc_fmid = 24576000,
332 .msmsdcc_fmax = 49152000,
333};
334#endif
335
336static int __init mmc_regulator_init(int sdcc_no, const char *supply, int uV)
337{
338 int rc;
339
340 BUG_ON(sdcc_no < 1 || sdcc_no > 4);
341
342 sdcc_no--;
343
344 sdcc_vreg_data[sdcc_no] = regulator_get(NULL, supply);
345
346 if (IS_ERR(sdcc_vreg_data[sdcc_no])) {
347 rc = PTR_ERR(sdcc_vreg_data[sdcc_no]);
348 pr_err("%s: could not get regulator \"%s\": %d\n",
349 __func__, supply, rc);
350 goto out;
351 }
352
353 rc = regulator_set_voltage(sdcc_vreg_data[sdcc_no], uV, uV);
354
355 if (rc) {
356 pr_err("%s: could not set voltage for \"%s\" to %d uV: %d\n",
357 __func__, supply, uV, rc);
358 goto reg_free;
359 }
360
361 return rc;
362
363reg_free:
364 regulator_put(sdcc_vreg_data[sdcc_no]);
365out:
366 sdcc_vreg_data[sdcc_no] = NULL;
367 return rc;
368}
369
370void __init msm7627a_init_mmc(void)
371{
372 /* eMMC slot */
373#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
Aparna Mallavarapu80c9bcf2012-04-03 13:51:48 +0530374
375 /* There is no eMMC on SDC3 for QRD3 based devices */
376 if (!(machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())) {
377 if (mmc_regulator_init(3, "emmc", 3000000))
378 return;
379 sdc3_plat_data.swfi_latency = msm7627a_power_collapse_latency(
Sujit Reddy Thummaca0c1062012-02-24 14:47:05 +0530380 MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT);
Aparna Mallavarapu80c9bcf2012-04-03 13:51:48 +0530381 msm_add_sdcc(3, &sdc3_plat_data);
382 }
Chintan Pandyacf467fc2011-12-01 17:11:11 +0530383#endif
384 /* Micro-SD slot */
385#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
386 gpio_sdc1_config();
387 if (mmc_regulator_init(1, "mmc", 2850000))
388 return;
389 sdc1_plat_data.status_irq = MSM_GPIO_TO_INT(gpio_sdc1_hw_det);
Sujit Reddy Thummaca0c1062012-02-24 14:47:05 +0530390 sdc1_plat_data.swfi_latency = msm7627a_power_collapse_latency(
391 MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT);
Chintan Pandyacf467fc2011-12-01 17:11:11 +0530392 msm_add_sdcc(1, &sdc1_plat_data);
393#endif
394 /* SDIO WLAN slot */
395#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
Sujit Reddy Thumma464a1792012-02-17 15:54:13 +0530396 if (mmc_regulator_init(2, "smps3", 1800000))
Chintan Pandyacf467fc2011-12-01 17:11:11 +0530397 return;
398 msm_add_sdcc(2, &sdc2_plat_data);
399#endif
400 /* Not Used */
401#if (defined(CONFIG_MMC_MSM_SDC4_SUPPORT)\
402 && !defined(CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT))
Aparna Mallavarapu80c9bcf2012-04-03 13:51:48 +0530403 /* There is no SDC4 for QRD3/7 based devices */
404 if (!(machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())) {
405 if (mmc_regulator_init(4, "smps3", 1800000))
406 return;
407 msm_add_sdcc(4, &sdc4_plat_data);
408 }
Chintan Pandyacf467fc2011-12-01 17:11:11 +0530409#endif
410}
411#endif