blob: 644c085584f450f9744d983f4320fdf4b8b3e64a [file] [log] [blame]
Rahul Kashyap2a906042012-01-12 19:10:05 +05301/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Chintan Pandya13490c02011-12-20 13:03:36 +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 <linux/delay.h>
15#include <linux/rfkill.h>
16#include <linux/platform_device.h>
17#include <linux/regulator/consumer.h>
18#include <linux/mfd/marimba.h>
19#include <linux/io.h>
20#include <asm/gpio.h>
21#include <asm/mach-types.h>
22#include <mach/rpc_pmapp.h>
23
24#include "board-msm7627a.h"
25#include "devices-msm7x2xa.h"
26
27#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
28
29
30static struct bt_vreg_info bt_vregs[] = {
31 {"msme1", 2, 1800000, 1800000, 0, NULL},
32 {"bt", 21, 2900000, 3300000, 1, NULL}
33};
34
Taniya Dase3027e22012-02-27 16:32:27 +053035static struct platform_device msm_bt_power_device = {
Chintan Pandya13490c02011-12-20 13:03:36 +053036 .name = "bt_power",
37};
38
39static unsigned bt_config_power_on[] = {
40 /*RFR*/
41 GPIO_CFG(43, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
42 /*CTS*/
43 GPIO_CFG(44, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
44 /*RX*/
45 GPIO_CFG(45, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
46 /*TX*/
47 GPIO_CFG(46, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
48};
49static unsigned bt_config_pcm_on[] = {
50 /*PCM_DOUT*/
51 GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
52 /*PCM_DIN*/
53 GPIO_CFG(69, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
54 /*PCM_SYNC*/
55 GPIO_CFG(70, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
56 /*PCM_CLK*/
57 GPIO_CFG(71, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
58};
59static unsigned bt_config_power_off[] = {
60 /*RFR*/
61 GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
62 /*CTS*/
63 GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
64 /*RX*/
65 GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
66 /*TX*/
67 GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
68};
69static unsigned bt_config_pcm_off[] = {
70 /*PCM_DOUT*/
71 GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
72 /*PCM_DIN*/
73 GPIO_CFG(69, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
74 /*PCM_SYNC*/
75 GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
76 /*PCM_CLK*/
77 GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
78};
79
80static unsigned fm_i2s_config_power_on[] = {
81 /*FM_I2S_SD*/
82 GPIO_CFG(68, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
83 /*FM_I2S_WS*/
84 GPIO_CFG(70, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
85 /*FM_I2S_SCK*/
86 GPIO_CFG(71, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
87};
88
89static unsigned fm_i2s_config_power_off[] = {
90 /*FM_I2S_SD*/
91 GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
92 /*FM_I2S_WS*/
93 GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
94 /*FM_I2S_SCK*/
95 GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
96};
97
98int gpio_bt_sys_rest_en = 133;
99static void gpio_bt_config(void)
100{
101 if (machine_is_msm7627a_qrd1())
102 gpio_bt_sys_rest_en = 114;
Chintan Pandyaf4ad4002012-02-28 19:49:03 +0530103 if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
Rahul Kashyapcfd33102012-01-02 16:56:46 +0530104 gpio_bt_sys_rest_en = 16;
Chintan Pandya13490c02011-12-20 13:03:36 +0530105}
106
107static int bt_set_gpio(int on)
108{
109 int rc = 0;
110 struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
111
112 if (on) {
113 rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
114 msleep(100);
115 } else {
116 if (!marimba_get_fm_status(&config) &&
117 !marimba_get_bt_status(&config)) {
118 gpio_set_value_cansleep(gpio_bt_sys_rest_en, 0);
119 rc = gpio_direction_input(gpio_bt_sys_rest_en);
120 msleep(100);
121 }
122 }
123 if (rc)
124 pr_err("%s: BT sys_reset_en GPIO : Error", __func__);
125
126 return rc;
127}
128
129static struct regulator *fm_regulator;
130static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
131{
132 int rc = 0;
133 const char *id = "FMPW";
134 uint32_t irqcfg;
135 struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
136 u8 value;
137
138 /* Voting for 1.8V Regulator */
139 fm_regulator = regulator_get(NULL , "msme1");
140 if (IS_ERR(fm_regulator)) {
141 rc = PTR_ERR(fm_regulator);
142 pr_err("%s: could not get regulator: %d\n", __func__, rc);
143 goto out;
144 }
145
146 /* Set the voltage level to 1.8V */
147 rc = regulator_set_voltage(fm_regulator, 1800000, 1800000);
148 if (rc < 0) {
149 pr_err("%s: could not set voltage: %d\n", __func__, rc);
150 goto reg_free;
151 }
152
153 /* Enabling the 1.8V regulator */
154 rc = regulator_enable(fm_regulator);
155 if (rc) {
156 pr_err("%s: could not enable regulator: %d\n", __func__, rc);
157 goto reg_free;
158 }
159
160 /* Voting for 19.2MHz clock */
161 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
162 PMAPP_CLOCK_VOTE_ON);
163 if (rc < 0) {
164 pr_err("%s: clock vote failed with :(%d)\n",
165 __func__, rc);
166 goto reg_disable;
167 }
168
169 rc = bt_set_gpio(1);
170 if (rc) {
171 pr_err("%s: bt_set_gpio = %d", __func__, rc);
172 goto gpio_deconfig;
173 }
174 /*re-write FM Slave Id, after reset*/
175 value = BAHAMA_SLAVE_ID_FM_ADDR;
176 rc = marimba_write_bit_mask(&config,
177 BAHAMA_SLAVE_ID_FM_REG, &value, 1, 0xFF);
178 if (rc < 0) {
179 pr_err("%s: FM Slave ID rewrite Failed = %d", __func__, rc);
180 goto gpio_deconfig;
181 }
182 /* Configuring the FM GPIO */
183 irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
184 GPIO_CFG_2MA);
185
186 rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
187 if (rc) {
188 pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
189 __func__, irqcfg, rc);
190 goto gpio_deconfig;
191 }
192
193 return 0;
194
195gpio_deconfig:
196 pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
197 PMAPP_CLOCK_VOTE_OFF);
198 bt_set_gpio(0);
199reg_disable:
200 regulator_disable(fm_regulator);
201reg_free:
202 regulator_put(fm_regulator);
203 fm_regulator = NULL;
204out:
205 return rc;
206};
207
208static void fm_radio_shutdown(struct marimba_fm_platform_data *pdata)
209{
210 int rc;
211 const char *id = "FMPW";
212
213 /* Releasing the GPIO line used by FM */
214 uint32_t irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT,
215 GPIO_CFG_PULL_UP, GPIO_CFG_2MA);
216
217 rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
218 if (rc)
219 pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
220 __func__, irqcfg, rc);
221
222 /* Releasing the 1.8V Regulator */
223 if (!IS_ERR_OR_NULL(fm_regulator)) {
224 rc = regulator_disable(fm_regulator);
225 if (rc)
226 pr_err("%s: could not disable regulator: %d\n",
227 __func__, rc);
228 regulator_put(fm_regulator);
229 fm_regulator = NULL;
230 }
231
232 /* Voting off the clock */
233 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
234 PMAPP_CLOCK_VOTE_OFF);
235 if (rc < 0)
236 pr_err("%s: voting off failed with :(%d)\n",
237 __func__, rc);
238 rc = bt_set_gpio(0);
239 if (rc)
240 pr_err("%s: bt_set_gpio = %d", __func__, rc);
241}
242static int switch_pcm_i2s_reg_mode(int mode)
243{
244 unsigned char reg = 0;
245 int rc = -1;
246 unsigned char set = I2C_PIN_CTL; /*SET PIN CTL mode*/
247 unsigned char unset = I2C_NORMAL; /* UNSET PIN CTL MODE*/
248 struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
249
250 if (mode == 0) {
251 /* as we need to switch path to FM we need to move
252 BT AUX PCM lines to PIN CONTROL mode then move
253 FM to normal mode.*/
254 for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
255 rc = marimba_write(&config, reg, &set, 1);
256 if (rc < 0) {
257 pr_err("pcm pinctl failed = %d", rc);
258 goto err_all;
259 }
260 }
261 for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
262 rc = marimba_write(&config, reg, &unset, 1);
263 if (rc < 0) {
264 pr_err("i2s normal failed = %d", rc);
265 goto err_all;
266 }
267 }
268 } else {
269 /* as we need to switch path to AUXPCM we need to move
270 FM I2S lines to PIN CONTROL mode then move
271 BT AUX_PCM to normal mode.*/
272 for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
273 rc = marimba_write(&config, reg, &set, 1);
274 if (rc < 0) {
275 pr_err("i2s pinctl failed = %d", rc);
276 goto err_all;
277 }
278 }
279 for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
280 rc = marimba_write(&config, reg, &unset, 1);
281 if (rc < 0) {
282 pr_err("pcm normal failed = %d", rc);
283 goto err_all;
284 }
285 }
286 }
287
288 return 0;
289
290err_all:
291 return rc;
292}
293
294
295static void config_pcm_i2s_mode(int mode)
296{
297 void __iomem *cfg_ptr;
298 u8 reg2;
299
300 cfg_ptr = ioremap_nocache(FPGA_MSM_CNTRL_REG2, sizeof(char));
301
302 if (!cfg_ptr)
303 return;
304 if (mode) {
305 /*enable the pcm mode in FPGA*/
306 reg2 = readb_relaxed(cfg_ptr);
307 if (reg2 == 0) {
308 reg2 = 1;
309 writeb_relaxed(reg2, cfg_ptr);
310 }
311 } else {
312 /*enable i2s mode in FPGA*/
313 reg2 = readb_relaxed(cfg_ptr);
314 if (reg2 == 1) {
315 reg2 = 0;
316 writeb_relaxed(reg2, cfg_ptr);
317 }
318 }
319 iounmap(cfg_ptr);
320}
321
322static int config_i2s(int mode)
323{
324 int pin, rc = 0;
325
326 if (mode == FM_I2S_ON) {
Taniya Dase3027e22012-02-27 16:32:27 +0530327 if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
328 || machine_is_msm8625_surf())
Chintan Pandya13490c02011-12-20 13:03:36 +0530329 config_pcm_i2s_mode(0);
330 pr_err("%s mode = FM_I2S_ON", __func__);
331
332 rc = switch_pcm_i2s_reg_mode(0);
333 if (rc) {
334 pr_err("switch mode failed");
335 return rc;
336 }
337 for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_on);
338 pin++) {
339 rc = gpio_tlmm_config(
340 fm_i2s_config_power_on[pin],
341 GPIO_CFG_ENABLE
342 );
343 if (rc < 0)
344 return rc;
345 }
346 } else if (mode == FM_I2S_OFF) {
347 pr_err("%s mode = FM_I2S_OFF", __func__);
348 rc = switch_pcm_i2s_reg_mode(1);
349 if (rc) {
350 pr_err("switch mode failed");
351 return rc;
352 }
353 for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_off);
354 pin++) {
355 rc = gpio_tlmm_config(
356 fm_i2s_config_power_off[pin],
357 GPIO_CFG_ENABLE
358 );
359 if (rc < 0)
360 return rc;
361 }
362 }
363 return rc;
364}
365
366static int config_pcm(int mode)
367{
368 int pin, rc = 0;
369
370 if (mode == BT_PCM_ON) {
Taniya Dase3027e22012-02-27 16:32:27 +0530371 if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
372 || machine_is_msm8625_surf())
Chintan Pandya13490c02011-12-20 13:03:36 +0530373 config_pcm_i2s_mode(1);
374 pr_err("%s mode =BT_PCM_ON", __func__);
375 rc = switch_pcm_i2s_reg_mode(1);
376 if (rc) {
377 pr_err("switch mode failed");
378 return rc;
379 }
380 for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_on);
381 pin++) {
382 rc = gpio_tlmm_config(bt_config_pcm_on[pin],
383 GPIO_CFG_ENABLE);
384 if (rc < 0)
385 return rc;
386 }
387 } else if (mode == BT_PCM_OFF) {
388 pr_err("%s mode =BT_PCM_OFF", __func__);
389 rc = switch_pcm_i2s_reg_mode(0);
390 if (rc) {
391 pr_err("switch mode failed");
392 return rc;
393 }
394 for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_off);
395 pin++) {
396 rc = gpio_tlmm_config(bt_config_pcm_off[pin],
397 GPIO_CFG_ENABLE);
398 if (rc < 0)
399 return rc;
400 }
401
402 }
403
404 return rc;
405}
406
407static int msm_bahama_setup_pcm_i2s(int mode)
408{
409 int fm_state = 0, bt_state = 0;
410 int rc = 0;
411 struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
412
413 fm_state = marimba_get_fm_status(&config);
414 bt_state = marimba_get_bt_status(&config);
415
416 switch (mode) {
417 case BT_PCM_ON:
418 case BT_PCM_OFF:
419 if (!fm_state)
420 rc = config_pcm(mode);
421 break;
422 case FM_I2S_ON:
423 rc = config_i2s(mode);
424 break;
425 case FM_I2S_OFF:
426 if (bt_state)
427 rc = config_pcm(BT_PCM_ON);
428 else
429 rc = config_i2s(mode);
430 break;
431 default:
432 rc = -EIO;
433 pr_err("%s:Unsupported mode", __func__);
434 }
435 return rc;
436}
437
438static int bahama_bt(int on)
439{
440 int rc = 0;
441 int i;
442
443 struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
444
445 struct bahama_variant_register {
446 const size_t size;
447 const struct bahama_config_register *set;
448 };
449
450 const struct bahama_config_register *p;
451
452 u8 version;
453
454 const struct bahama_config_register v10_bt_on[] = {
455 { 0xE9, 0x00, 0xFF },
456 { 0xF4, 0x80, 0xFF },
457 { 0xE4, 0x00, 0xFF },
458 { 0xE5, 0x00, 0x0F },
459#ifdef CONFIG_WLAN
460 { 0xE6, 0x38, 0x7F },
461 { 0xE7, 0x06, 0xFF },
462#endif
463 { 0xE9, 0x21, 0xFF },
464 { 0x01, 0x0C, 0x1F },
465 { 0x01, 0x08, 0x1F },
466 };
467
468 const struct bahama_config_register v20_bt_on_fm_off[] = {
469 { 0x11, 0x0C, 0xFF },
470 { 0x13, 0x01, 0xFF },
471 { 0xF4, 0x80, 0xFF },
472 { 0xF0, 0x00, 0xFF },
473 { 0xE9, 0x00, 0xFF },
474#ifdef CONFIG_WLAN
475 { 0x81, 0x00, 0x7F },
476 { 0x82, 0x00, 0xFF },
477 { 0xE6, 0x38, 0x7F },
478 { 0xE7, 0x06, 0xFF },
479#endif
480 { 0x8E, 0x15, 0xFF },
481 { 0x8F, 0x15, 0xFF },
482 { 0x90, 0x15, 0xFF },
483
484 { 0xE9, 0x21, 0xFF },
485 };
486
487 const struct bahama_config_register v20_bt_on_fm_on[] = {
488 { 0x11, 0x0C, 0xFF },
489 { 0x13, 0x01, 0xFF },
490 { 0xF4, 0x86, 0xFF },
491 { 0xF0, 0x06, 0xFF },
492 { 0xE9, 0x00, 0xFF },
493#ifdef CONFIG_WLAN
494 { 0x81, 0x00, 0x7F },
495 { 0x82, 0x00, 0xFF },
496 { 0xE6, 0x38, 0x7F },
497 { 0xE7, 0x06, 0xFF },
498#endif
499 { 0xE9, 0x21, 0xFF },
500 };
501
502 const struct bahama_config_register v10_bt_off[] = {
503 { 0xE9, 0x00, 0xFF },
504 };
505
506 const struct bahama_config_register v20_bt_off_fm_off[] = {
507 { 0xF4, 0x84, 0xFF },
508 { 0xF0, 0x04, 0xFF },
509 { 0xE9, 0x00, 0xFF }
510 };
511
512 const struct bahama_config_register v20_bt_off_fm_on[] = {
513 { 0xF4, 0x86, 0xFF },
514 { 0xF0, 0x06, 0xFF },
515 { 0xE9, 0x00, 0xFF }
516 };
517
518 const struct bahama_variant_register bt_bahama[2][3] = {
519 {
520 { ARRAY_SIZE(v10_bt_off), v10_bt_off },
521 { ARRAY_SIZE(v20_bt_off_fm_off), v20_bt_off_fm_off },
522 { ARRAY_SIZE(v20_bt_off_fm_on), v20_bt_off_fm_on }
523 },
524 {
525 { ARRAY_SIZE(v10_bt_on), v10_bt_on },
526 { ARRAY_SIZE(v20_bt_on_fm_off), v20_bt_on_fm_off },
527 { ARRAY_SIZE(v20_bt_on_fm_on), v20_bt_on_fm_on }
528 }
529 };
530
531 u8 offset = 0; /* index into bahama configs */
532 on = on ? 1 : 0;
533 version = marimba_read_bahama_ver(&config);
534 if ((int)version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
535 dev_err(&msm_bt_power_device.dev, "%s : Bahama "
536 "version read Error, version = %d\n",
537 __func__, version);
538 return -EIO;
539 }
540
541 if (version == BAHAMA_VER_2_0) {
542 if (marimba_get_fm_status(&config))
543 offset = 0x01;
544 }
545
546 p = bt_bahama[on][version + offset].set;
547
548 dev_info(&msm_bt_power_device.dev,
549 "%s: found version %d\n", __func__, version);
550
551 for (i = 0; i < bt_bahama[on][version + offset].size; i++) {
552 u8 value = (p+i)->value;
553 rc = marimba_write_bit_mask(&config,
554 (p+i)->reg,
555 &value,
556 sizeof((p+i)->value),
557 (p+i)->mask);
558 if (rc < 0) {
559 dev_err(&msm_bt_power_device.dev,
560 "%s: reg %x write failed: %d\n",
561 __func__, (p+i)->reg, rc);
562 return rc;
563 }
564 dev_dbg(&msm_bt_power_device.dev,
565 "%s: reg 0x%02x write value 0x%02x mask 0x%02x\n",
566 __func__, (p+i)->reg,
567 value, (p+i)->mask);
568 value = 0;
569 rc = marimba_read_bit_mask(&config,
570 (p+i)->reg, &value,
571 sizeof((p+i)->value), (p+i)->mask);
572 if (rc < 0)
573 dev_err(&msm_bt_power_device.dev,
574 "%s marimba_read_bit_mask- error",
575 __func__);
576 dev_dbg(&msm_bt_power_device.dev,
577 "%s: reg 0x%02x read value 0x%02x mask 0x%02x\n",
578 __func__, (p+i)->reg,
579 value, (p+i)->mask);
580 }
581 /* Update BT Status */
582 if (on)
583 marimba_set_bt_status(&config, true);
584 else
585 marimba_set_bt_status(&config, false);
586 return rc;
587}
588
589static int bluetooth_switch_regulators(int on)
590{
591 int i, rc = 0;
592 const char *id = "BTPW";
593
594 for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
595 if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
596 rc = bt_vregs[i].reg ?
597 PTR_ERR(bt_vregs[i].reg) :
598 -ENODEV;
599 dev_err(&msm_bt_power_device.dev,
600 "%s: invalid regulator handle for %s: %d\n",
601 __func__, bt_vregs[i].name, rc);
602 goto reg_disable;
603 }
604
605 rc = on ? regulator_set_voltage(bt_vregs[i].reg,
606 bt_vregs[i].min_level,
607 bt_vregs[i].max_level) : 0;
608 if (rc) {
609 dev_err(&msm_bt_power_device.dev,
610 "%s: could not set voltage for %s: %d\n",
611 __func__, bt_vregs[i].name, rc);
612 goto reg_disable;
613 }
614
615 rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
616 if (rc) {
617 dev_err(&msm_bt_power_device.dev,
618 "%s: could not %sable regulator %s: %d\n",
619 __func__, "en", bt_vregs[i].name, rc);
620 goto reg_disable;
621 }
622
623 if (bt_vregs[i].is_pin_controlled) {
624 rc = pmapp_vreg_lpm_pincntrl_vote(id,
625 bt_vregs[i].pmapp_id,
626 PMAPP_CLOCK_ID_D1,
627 on ? PMAPP_CLOCK_VOTE_ON :
628 PMAPP_CLOCK_VOTE_OFF);
629 if (rc) {
630 dev_err(&msm_bt_power_device.dev,
631 "%s: pin control failed for %s: %d\n",
632 __func__, bt_vregs[i].name, rc);
633 goto pin_cnt_fail;
634 }
635 }
636 rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
637
638 if (rc) {
639 dev_err(&msm_bt_power_device.dev,
640 "%s: could not %sable regulator %s: %d\n",
641 __func__, "dis", bt_vregs[i].name, rc);
642 goto reg_disable;
643 }
644 }
645
646 return rc;
647pin_cnt_fail:
648 if (on)
649 regulator_disable(bt_vregs[i].reg);
650reg_disable:
651 while (i) {
652 if (on) {
653 i--;
654 regulator_disable(bt_vregs[i].reg);
655 regulator_put(bt_vregs[i].reg);
656 }
657 }
658 return rc;
659}
660
661static struct regulator *reg_s3;
662static unsigned int msm_bahama_setup_power(void)
663{
664 int rc = 0;
665
666 reg_s3 = regulator_get(NULL, "msme1");
667 if (IS_ERR(reg_s3)) {
668 rc = PTR_ERR(reg_s3);
669 pr_err("%s: could not get regulator: %d\n", __func__, rc);
670 goto out;
671 }
672
673 rc = regulator_set_voltage(reg_s3, 1800000, 1800000);
674 if (rc < 0) {
675 pr_err("%s: could not set voltage: %d\n", __func__, rc);
676 goto reg_fail;
677 }
678
679 rc = regulator_enable(reg_s3);
680 if (rc < 0) {
681 pr_err("%s: could not enable regulator: %d\n", __func__, rc);
682 goto reg_fail;
683 }
Rahul Kashyap2a906042012-01-12 19:10:05 +0530684 gpio_tlmm_config(GPIO_CFG(gpio_bt_sys_rest_en, 0,
685 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
686 GPIO_CFG_2MA), GPIO_CFG_ENABLE);
Chintan Pandya13490c02011-12-20 13:03:36 +0530687
688 /*setup Bahama_sys_reset_n*/
689 rc = gpio_request(gpio_bt_sys_rest_en, "bahama sys_rst_n");
690 if (rc < 0) {
691 pr_err("%s: gpio_request %d = %d\n", __func__,
692 gpio_bt_sys_rest_en, rc);
693 goto reg_disable;
694 }
695
696 rc = bt_set_gpio(1);
697 if (rc < 0) {
698 pr_err("%s: bt_set_gpio %d = %d\n", __func__,
699 gpio_bt_sys_rest_en, rc);
700 goto gpio_fail;
701 }
702
703 return rc;
704
705gpio_fail:
706 gpio_free(gpio_bt_sys_rest_en);
707reg_disable:
708 regulator_disable(reg_s3);
709reg_fail:
710 regulator_put(reg_s3);
711out:
712 reg_s3 = NULL;
713 return rc;
714}
715
716static unsigned int msm_bahama_shutdown_power(int value)
717{
718 int rc = 0;
719
720 if (IS_ERR_OR_NULL(reg_s3)) {
721 rc = reg_s3 ? PTR_ERR(reg_s3) : -ENODEV;
722 goto out;
723 }
724
725 rc = regulator_disable(reg_s3);
726 if (rc) {
727 pr_err("%s: could not disable regulator: %d\n", __func__, rc);
728 goto out;
729 }
730
731 if (value == BAHAMA_ID) {
732 rc = bt_set_gpio(0);
733 if (rc) {
734 pr_err("%s: bt_set_gpio = %d\n",
735 __func__, rc);
736 goto reg_enable;
737 }
738 gpio_free(gpio_bt_sys_rest_en);
739 }
740
741 regulator_put(reg_s3);
742 reg_s3 = NULL;
743
744 return 0;
745
746reg_enable:
747 regulator_enable(reg_s3);
748out:
749 return rc;
750}
751
752static unsigned int msm_bahama_core_config(int type)
753{
754 int rc = 0;
755
756 if (type == BAHAMA_ID) {
757 int i;
758 struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
759 const struct bahama_config_register v20_init[] = {
760 /* reg, value, mask */
761 { 0xF4, 0x84, 0xFF }, /* AREG */
762 { 0xF0, 0x04, 0xFF } /* DREG */
763 };
764 if (marimba_read_bahama_ver(&config) == BAHAMA_VER_2_0) {
765 for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
766 u8 value = v20_init[i].value;
767 rc = marimba_write_bit_mask(&config,
768 v20_init[i].reg,
769 &value,
770 sizeof(v20_init[i].value),
771 v20_init[i].mask);
772 if (rc < 0) {
773 pr_err("%s: reg %d write failed: %d\n",
774 __func__, v20_init[i].reg, rc);
775 return rc;
776 }
777 pr_debug("%s: reg 0x%02x value 0x%02x"
778 " mask 0x%02x\n",
779 __func__, v20_init[i].reg,
780 v20_init[i].value, v20_init[i].mask);
781 }
782 }
783 }
784 rc = bt_set_gpio(0);
785 if (rc) {
786 pr_err("%s: bt_set_gpio = %d\n",
787 __func__, rc);
788 }
789 pr_debug("core type: %d\n", type);
790 return rc;
791}
792
793static int bluetooth_power(int on)
794{
795 int pin, rc = 0;
796 const char *id = "BTPW";
797 int cid = 0;
798
799 cid = adie_get_detected_connectivity_type();
800 if (cid != BAHAMA_ID) {
801 pr_err("%s: unexpected adie connectivity type: %d\n",
802 __func__, cid);
803 return -ENODEV;
804 }
805 if (on) {
806 /*setup power for BT SOC*/
807 rc = bt_set_gpio(on);
808 if (rc) {
809 pr_err("%s: bt_set_gpio = %d\n",
810 __func__, rc);
811 goto exit;
812 }
813 rc = bluetooth_switch_regulators(on);
814 if (rc < 0) {
815 pr_err("%s: bluetooth_switch_regulators rc = %d",
816 __func__, rc);
817 goto exit;
818 }
819 /*setup BT GPIO lines*/
820 for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on);
821 pin++) {
822 rc = gpio_tlmm_config(bt_config_power_on[pin],
823 GPIO_CFG_ENABLE);
824 if (rc < 0) {
825 pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
826 __func__,
827 bt_config_power_on[pin],
828 rc);
829 goto fail_power;
830 }
831 }
832 /*Setup BT clocks*/
833 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
834 PMAPP_CLOCK_VOTE_ON);
835 if (rc < 0) {
836 pr_err("Failed to vote for TCXO_D1 ON\n");
837 goto fail_clock;
838 }
839 msleep(20);
840
841 /*I2C config for Bahama*/
842 rc = bahama_bt(1);
843 if (rc < 0) {
844 pr_err("%s: bahama_bt rc = %d", __func__, rc);
845 goto fail_i2c;
846 }
847 msleep(20);
848
849 /*setup BT PCM lines*/
850 rc = msm_bahama_setup_pcm_i2s(BT_PCM_ON);
851 if (rc < 0) {
852 pr_err("%s: msm_bahama_setup_pcm_i2s , rc =%d\n",
853 __func__, rc);
854 goto fail_power;
855 }
856 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
857 PMAPP_CLOCK_VOTE_PIN_CTRL);
858 if (rc < 0)
859 pr_err("%s:Pin Control Failed, rc = %d",
860 __func__, rc);
861
862 } else {
863 rc = bahama_bt(0);
864 if (rc < 0)
865 pr_err("%s: bahama_bt rc = %d", __func__, rc);
866
Rahul Kashyap387e9532011-12-30 15:57:34 +0530867 rc = msm_bahama_setup_pcm_i2s(BT_PCM_OFF);
868 if (rc < 0) {
869 pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
870 __func__, rc);
871 }
Chintan Pandya13490c02011-12-20 13:03:36 +0530872 rc = bt_set_gpio(on);
873 if (rc) {
874 pr_err("%s: bt_set_gpio = %d\n",
875 __func__, rc);
876 }
877fail_i2c:
878 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
879 PMAPP_CLOCK_VOTE_OFF);
880 if (rc < 0)
881 pr_err("%s: Failed to vote Off D1\n", __func__);
882fail_clock:
883 for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off);
884 pin++) {
885 rc = gpio_tlmm_config(bt_config_power_off[pin],
886 GPIO_CFG_ENABLE);
887 if (rc < 0) {
888 pr_err("%s:"
889 " gpio_tlmm_config(%#x)=%d\n",
890 __func__,
891 bt_config_power_off[pin], rc);
892 }
893 }
Chintan Pandya13490c02011-12-20 13:03:36 +0530894fail_power:
895 rc = bluetooth_switch_regulators(0);
896 if (rc < 0) {
897 pr_err("%s: switch_regulators : rc = %d",\
898 __func__, rc);
899 goto exit;
900 }
901 }
902 return rc;
903exit:
904 pr_err("%s: failed with rc = %d", __func__, rc);
905 return rc;
906}
907
908static struct marimba_fm_platform_data marimba_fm_pdata = {
909 .fm_setup = fm_radio_setup,
910 .fm_shutdown = fm_radio_shutdown,
911 .irq = MSM_GPIO_TO_INT(FM_GPIO),
912 .vreg_s2 = NULL,
913 .vreg_xo_out = NULL,
914 /* Configuring the FM SoC as I2S Master */
915 .is_fm_soc_i2s_master = true,
916 .config_i2s_gpio = msm_bahama_setup_pcm_i2s,
917};
918
919static struct marimba_platform_data marimba_pdata = {
920 .slave_id[SLAVE_ID_BAHAMA_FM] = BAHAMA_SLAVE_ID_FM_ADDR,
921 .slave_id[SLAVE_ID_BAHAMA_QMEMBIST] = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
922 .bahama_setup = msm_bahama_setup_power,
923 .bahama_shutdown = msm_bahama_shutdown_power,
924 .bahama_core_config = msm_bahama_core_config,
925 .fm = &marimba_fm_pdata,
926};
927
928static struct i2c_board_info bahama_devices[] = {
929{
930 I2C_BOARD_INFO("marimba", 0xc),
931 .platform_data = &marimba_pdata,
932},
933};
934
935void __init msm7627a_bt_power_init(void)
936{
937 int i, rc = 0;
938 struct device *dev;
939
Chintan Pandyab1bad0e2012-02-06 19:04:51 +0530940 if (machine_is_msm7627a_qrd3())
941 return;
942
Chintan Pandya13490c02011-12-20 13:03:36 +0530943 gpio_bt_config();
944
Taniya Dase3027e22012-02-27 16:32:27 +0530945 rc = i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
946 bahama_devices,
947 ARRAY_SIZE(bahama_devices));
948 if (rc < 0) {
949 pr_err("%s: I2C Register failed\n", __func__);
950 return;
951 }
952
953 rc = platform_device_register(&msm_bt_power_device);
954 if (rc < 0) {
955 pr_err("%s: device register failed\n", __func__);
956 return;
957 }
958
Chintan Pandya13490c02011-12-20 13:03:36 +0530959 dev = &msm_bt_power_device.dev;
960
961 for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
962 bt_vregs[i].reg = regulator_get(dev, bt_vregs[i].name);
963 if (IS_ERR(bt_vregs[i].reg)) {
964 rc = PTR_ERR(bt_vregs[i].reg);
965 dev_err(dev, "%s: could not get regulator %s: %d\n",
966 __func__, bt_vregs[i].name, rc);
967 goto reg_get_fail;
968 }
969 }
970
971 dev->platform_data = &bluetooth_power;
972
973 return;
974
975reg_get_fail:
976 while (i--) {
977 regulator_put(bt_vregs[i].reg);
978 bt_vregs[i].reg = NULL;
979 }
Taniya Dase3027e22012-02-27 16:32:27 +0530980 platform_device_unregister(&msm_bt_power_device);
Chintan Pandya13490c02011-12-20 13:03:36 +0530981}
982#endif