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