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