blob: 75d5f155800f20e1d6c0c8312317d0432e48abed [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>
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)) {
630 rc = bt_vregs[i].reg ?
631 PTR_ERR(bt_vregs[i].reg) :
632 -ENODEV;
633 dev_err(&msm_bt_power_device.dev,
634 "%s: invalid regulator handle for %s: %d\n",
635 __func__, bt_vregs[i].name, rc);
636 goto reg_disable;
637 }
638
639 rc = on ? regulator_set_voltage(bt_vregs[i].reg,
640 bt_vregs[i].min_level,
641 bt_vregs[i].max_level) : 0;
642 if (rc) {
643 dev_err(&msm_bt_power_device.dev,
644 "%s: could not set voltage for %s: %d\n",
645 __func__, bt_vregs[i].name, rc);
646 goto reg_disable;
647 }
648
649 rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
650 if (rc) {
651 dev_err(&msm_bt_power_device.dev,
652 "%s: could not %sable regulator %s: %d\n",
653 __func__, "en", bt_vregs[i].name, rc);
654 goto reg_disable;
655 }
656
657 if (bt_vregs[i].is_pin_controlled) {
658 rc = pmapp_vreg_lpm_pincntrl_vote(id,
659 bt_vregs[i].pmapp_id,
660 PMAPP_CLOCK_ID_D1,
661 on ? PMAPP_CLOCK_VOTE_ON :
662 PMAPP_CLOCK_VOTE_OFF);
663 if (rc) {
664 dev_err(&msm_bt_power_device.dev,
665 "%s: pin control failed for %s: %d\n",
666 __func__, bt_vregs[i].name, rc);
667 goto pin_cnt_fail;
668 }
669 }
670 rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
671
672 if (rc) {
673 dev_err(&msm_bt_power_device.dev,
674 "%s: could not %sable regulator %s: %d\n",
675 __func__, "dis", bt_vregs[i].name, rc);
676 goto reg_disable;
677 }
678 }
679
680 return rc;
681pin_cnt_fail:
682 if (on)
683 regulator_disable(bt_vregs[i].reg);
684reg_disable:
685 while (i) {
686 if (on) {
687 i--;
688 regulator_disable(bt_vregs[i].reg);
689 regulator_put(bt_vregs[i].reg);
690 }
691 }
692 return rc;
693}
694
695static struct regulator *reg_s3;
696static unsigned int msm_bahama_setup_power(void)
697{
698 int rc = 0;
699
700 reg_s3 = regulator_get(NULL, "msme1");
701 if (IS_ERR(reg_s3)) {
702 rc = PTR_ERR(reg_s3);
703 pr_err("%s: could not get regulator: %d\n", __func__, rc);
704 goto out;
705 }
706
707 rc = regulator_set_voltage(reg_s3, 1800000, 1800000);
708 if (rc < 0) {
709 pr_err("%s: could not set voltage: %d\n", __func__, rc);
710 goto reg_fail;
711 }
712
713 rc = regulator_enable(reg_s3);
714 if (rc < 0) {
715 pr_err("%s: could not enable regulator: %d\n", __func__, rc);
716 goto reg_fail;
717 }
Rahul Kashyap2a906042012-01-12 19:10:05 +0530718 gpio_tlmm_config(GPIO_CFG(gpio_bt_sys_rest_en, 0,
719 GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
720 GPIO_CFG_2MA), GPIO_CFG_ENABLE);
Chintan Pandya13490c02011-12-20 13:03:36 +0530721
722 /*setup Bahama_sys_reset_n*/
723 rc = gpio_request(gpio_bt_sys_rest_en, "bahama sys_rst_n");
724 if (rc < 0) {
725 pr_err("%s: gpio_request %d = %d\n", __func__,
726 gpio_bt_sys_rest_en, rc);
727 goto reg_disable;
728 }
729
730 rc = bt_set_gpio(1);
731 if (rc < 0) {
732 pr_err("%s: bt_set_gpio %d = %d\n", __func__,
733 gpio_bt_sys_rest_en, rc);
734 goto gpio_fail;
735 }
736
737 return rc;
738
739gpio_fail:
740 gpio_free(gpio_bt_sys_rest_en);
741reg_disable:
742 regulator_disable(reg_s3);
743reg_fail:
744 regulator_put(reg_s3);
745out:
746 reg_s3 = NULL;
747 return rc;
748}
749
750static unsigned int msm_bahama_shutdown_power(int value)
751{
752 int rc = 0;
753
754 if (IS_ERR_OR_NULL(reg_s3)) {
755 rc = reg_s3 ? PTR_ERR(reg_s3) : -ENODEV;
756 goto out;
757 }
758
759 rc = regulator_disable(reg_s3);
760 if (rc) {
761 pr_err("%s: could not disable regulator: %d\n", __func__, rc);
762 goto out;
763 }
764
765 if (value == BAHAMA_ID) {
766 rc = bt_set_gpio(0);
767 if (rc) {
768 pr_err("%s: bt_set_gpio = %d\n",
769 __func__, rc);
770 goto reg_enable;
771 }
772 gpio_free(gpio_bt_sys_rest_en);
773 }
774
775 regulator_put(reg_s3);
776 reg_s3 = NULL;
777
778 return 0;
779
780reg_enable:
781 regulator_enable(reg_s3);
782out:
783 return rc;
784}
785
786static unsigned int msm_bahama_core_config(int type)
787{
788 int rc = 0;
789
790 if (type == BAHAMA_ID) {
791 int i;
792 struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
793 const struct bahama_config_register v20_init[] = {
794 /* reg, value, mask */
795 { 0xF4, 0x84, 0xFF }, /* AREG */
796 { 0xF0, 0x04, 0xFF } /* DREG */
797 };
798 if (marimba_read_bahama_ver(&config) == BAHAMA_VER_2_0) {
799 for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
800 u8 value = v20_init[i].value;
801 rc = marimba_write_bit_mask(&config,
802 v20_init[i].reg,
803 &value,
804 sizeof(v20_init[i].value),
805 v20_init[i].mask);
806 if (rc < 0) {
807 pr_err("%s: reg %d write failed: %d\n",
808 __func__, v20_init[i].reg, rc);
809 return rc;
810 }
811 pr_debug("%s: reg 0x%02x value 0x%02x"
812 " mask 0x%02x\n",
813 __func__, v20_init[i].reg,
814 v20_init[i].value, v20_init[i].mask);
815 }
816 }
817 }
818 rc = bt_set_gpio(0);
819 if (rc) {
820 pr_err("%s: bt_set_gpio = %d\n",
821 __func__, rc);
822 }
823 pr_debug("core type: %d\n", type);
824 return rc;
825}
826
827static int bluetooth_power(int on)
828{
829 int pin, rc = 0;
830 const char *id = "BTPW";
831 int cid = 0;
832
833 cid = adie_get_detected_connectivity_type();
834 if (cid != BAHAMA_ID) {
835 pr_err("%s: unexpected adie connectivity type: %d\n",
836 __func__, cid);
837 return -ENODEV;
838 }
839 if (on) {
840 /*setup power for BT SOC*/
841 rc = bt_set_gpio(on);
842 if (rc) {
843 pr_err("%s: bt_set_gpio = %d\n",
844 __func__, rc);
845 goto exit;
846 }
847 rc = bluetooth_switch_regulators(on);
848 if (rc < 0) {
849 pr_err("%s: bluetooth_switch_regulators rc = %d",
850 __func__, rc);
851 goto exit;
852 }
853 /*setup BT GPIO lines*/
854 for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on);
855 pin++) {
856 rc = gpio_tlmm_config(bt_config_power_on[pin],
857 GPIO_CFG_ENABLE);
858 if (rc < 0) {
859 pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
860 __func__,
861 bt_config_power_on[pin],
862 rc);
863 goto fail_power;
864 }
865 }
866 /*Setup BT clocks*/
867 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
868 PMAPP_CLOCK_VOTE_ON);
869 if (rc < 0) {
870 pr_err("Failed to vote for TCXO_D1 ON\n");
871 goto fail_clock;
872 }
873 msleep(20);
874
875 /*I2C config for Bahama*/
876 rc = bahama_bt(1);
877 if (rc < 0) {
878 pr_err("%s: bahama_bt rc = %d", __func__, rc);
879 goto fail_i2c;
880 }
881 msleep(20);
882
883 /*setup BT PCM lines*/
884 rc = msm_bahama_setup_pcm_i2s(BT_PCM_ON);
885 if (rc < 0) {
886 pr_err("%s: msm_bahama_setup_pcm_i2s , rc =%d\n",
887 __func__, rc);
888 goto fail_power;
889 }
890 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
891 PMAPP_CLOCK_VOTE_PIN_CTRL);
892 if (rc < 0)
893 pr_err("%s:Pin Control Failed, rc = %d",
894 __func__, rc);
895
896 } else {
897 rc = bahama_bt(0);
898 if (rc < 0)
899 pr_err("%s: bahama_bt rc = %d", __func__, rc);
900
Rahul Kashyap387e9532011-12-30 15:57:34 +0530901 rc = msm_bahama_setup_pcm_i2s(BT_PCM_OFF);
902 if (rc < 0) {
903 pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
904 __func__, rc);
905 }
Chintan Pandya13490c02011-12-20 13:03:36 +0530906 rc = bt_set_gpio(on);
907 if (rc) {
908 pr_err("%s: bt_set_gpio = %d\n",
909 __func__, rc);
910 }
911fail_i2c:
912 rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
913 PMAPP_CLOCK_VOTE_OFF);
914 if (rc < 0)
915 pr_err("%s: Failed to vote Off D1\n", __func__);
916fail_clock:
917 for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off);
918 pin++) {
919 rc = gpio_tlmm_config(bt_config_power_off[pin],
920 GPIO_CFG_ENABLE);
921 if (rc < 0) {
922 pr_err("%s:"
923 " gpio_tlmm_config(%#x)=%d\n",
924 __func__,
925 bt_config_power_off[pin], rc);
926 }
927 }
Chintan Pandya13490c02011-12-20 13:03:36 +0530928fail_power:
929 rc = bluetooth_switch_regulators(0);
930 if (rc < 0) {
931 pr_err("%s: switch_regulators : rc = %d",\
932 __func__, rc);
933 goto exit;
934 }
935 }
936 return rc;
937exit:
938 pr_err("%s: failed with rc = %d", __func__, rc);
939 return rc;
940}
941
942static struct marimba_fm_platform_data marimba_fm_pdata = {
943 .fm_setup = fm_radio_setup,
944 .fm_shutdown = fm_radio_shutdown,
945 .irq = MSM_GPIO_TO_INT(FM_GPIO),
946 .vreg_s2 = NULL,
947 .vreg_xo_out = NULL,
948 /* Configuring the FM SoC as I2S Master */
949 .is_fm_soc_i2s_master = true,
950 .config_i2s_gpio = msm_bahama_setup_pcm_i2s,
951};
952
953static struct marimba_platform_data marimba_pdata = {
954 .slave_id[SLAVE_ID_BAHAMA_FM] = BAHAMA_SLAVE_ID_FM_ADDR,
955 .slave_id[SLAVE_ID_BAHAMA_QMEMBIST] = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
956 .bahama_setup = msm_bahama_setup_power,
957 .bahama_shutdown = msm_bahama_shutdown_power,
958 .bahama_core_config = msm_bahama_core_config,
959 .fm = &marimba_fm_pdata,
960};
961
962static struct i2c_board_info bahama_devices[] = {
963{
964 I2C_BOARD_INFO("marimba", 0xc),
965 .platform_data = &marimba_pdata,
966},
967};
968
969void __init msm7627a_bt_power_init(void)
970{
971 int i, rc = 0;
972 struct device *dev;
973
Chintan Pandyab1bad0e2012-02-06 19:04:51 +0530974
Chintan Pandya13490c02011-12-20 13:03:36 +0530975 gpio_bt_config();
976
Taniya Dase3027e22012-02-27 16:32:27 +0530977 rc = i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
978 bahama_devices,
979 ARRAY_SIZE(bahama_devices));
980 if (rc < 0) {
981 pr_err("%s: I2C Register failed\n", __func__);
982 return;
983 }
984
985 rc = platform_device_register(&msm_bt_power_device);
986 if (rc < 0) {
987 pr_err("%s: device register failed\n", __func__);
988 return;
989 }
990
Chintan Pandya13490c02011-12-20 13:03:36 +0530991 dev = &msm_bt_power_device.dev;
992
993 for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
994 bt_vregs[i].reg = regulator_get(dev, bt_vregs[i].name);
995 if (IS_ERR(bt_vregs[i].reg)) {
996 rc = PTR_ERR(bt_vregs[i].reg);
997 dev_err(dev, "%s: could not get regulator %s: %d\n",
998 __func__, bt_vregs[i].name, rc);
999 goto reg_get_fail;
1000 }
1001 }
1002
1003 dev->platform_data = &bluetooth_power;
1004
1005 return;
1006
1007reg_get_fail:
1008 while (i--) {
1009 regulator_put(bt_vregs[i].reg);
1010 bt_vregs[i].reg = NULL;
1011 }
Taniya Dase3027e22012-02-27 16:32:27 +05301012 platform_device_unregister(&msm_bt_power_device);
Chintan Pandya13490c02011-12-20 13:03:36 +05301013}
1014#endif