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