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