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