blob: a8ae9fa6e8d0930dff8a6d88b7b22b522554d1e6 [file] [log] [blame]
Ankit Verma6fe41b02012-09-13 16:12:11 +05301/* Copyright (c) 2011-2012, Linux Foundation. All rights reserved.
2 *
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 <linux/gpio.h>
21#include <asm/mach-types.h>
22#include <mach/rpc_pmapp.h>
23#include <mach/msm_xo.h>
24#include <mach/socinfo.h>
25
26#include "board-8064.h"
27
28#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
29
30#define BAHAMA_SLAVE_ID_FM_ADDR 0x2A
31#define BAHAMA_SLAVE_ID_QMEMBIST_ADDR 0x7B
32
33struct bt_vreg_info {
34 const char *name;
35 unsigned int pmapp_id;
36 unsigned int min_level;
37 unsigned int max_level;
38 unsigned int is_pin_controlled;
39 struct regulator *reg;
40};
41
42struct bahama_config_register {
43 u8 reg;
44 u8 value;
45 u8 mask;
46};
47static struct bt_vreg_info bt_vregs[] = {
48 {"bha_vddxo", 2, 1800000, 1800000, 0, NULL},
49 {"bha_vddpx", 21, 1800000, 1800000, 0, NULL},
50 {"bha_vddpa", 21, 2900000, 3300000, 0, NULL}
51};
52
53static struct msm_xo_voter *bt_clock;
54
55static struct platform_device msm_bt_power_device = {
56 .name = "bt_power",
57 .id = -1,
58};
59
60static unsigned bt_config_pcm_on[] = {
61 /*PCM_DOUT*/
62 GPIO_CFG(43, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
63 /*PCM_DIN*/
64 GPIO_CFG(44, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
65 /*PCM_SYNC*/
66 GPIO_CFG(45, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
67 /*PCM_CLK*/
68 GPIO_CFG(46, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
69};
70
71static unsigned bt_config_pcm_off[] = {
72 /*PCM_DOUT*/
73 GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
74 /*PCM_DIN*/
75 GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
76 /*PCM_SYNC*/
77 GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
78 /*PCM_CLK*/
79 GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
80};
81
82static int config_pcm(int mode)
83{
84 int pin, rc = 0;
85
86 if (mode == BT_PCM_ON) {
87 pr_err("%s mode =BT_PCM_ON", __func__);
88 for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_on);
89 pin++) {
90 rc = gpio_tlmm_config(bt_config_pcm_on[pin],
91 GPIO_CFG_ENABLE);
92 if (rc < 0)
93 return rc;
94 }
95 } else if (mode == BT_PCM_OFF) {
96 pr_err("%s mode =BT_PCM_OFF", __func__);
97 for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_off);
98 pin++) {
99 rc = gpio_tlmm_config(bt_config_pcm_off[pin],
100 GPIO_CFG_ENABLE);
101 if (rc < 0)
102 return rc;
103 }
104
105 }
106
107 return rc;
108}
109
110static int bahama_bt(int on)
111{
112 int rc = 0;
113 int i;
114
115 struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
116
117 struct bahama_variant_register {
118 const size_t size;
119 const struct bahama_config_register *set;
120 };
121
122 const struct bahama_config_register *p;
123
124 u8 version;
125
126 const struct bahama_config_register v10_bt_on[] = {
127 { 0xE9, 0x00, 0xFF },
128 { 0xF4, 0x80, 0xFF },
129 { 0xE4, 0x00, 0xFF },
130 { 0xE5, 0x00, 0x0F },
131#ifdef CONFIG_WLAN
132 { 0xE6, 0x38, 0x7F },
133 { 0xE7, 0x06, 0xFF },
134#endif
135 { 0xE9, 0x21, 0xFF },
136 { 0x01, 0x0C, 0x1F },
137 { 0x01, 0x08, 0x1F },
138 };
139
140 const struct bahama_config_register v20_bt_on_fm_off[] = {
141 { 0x11, 0x0C, 0xFF },
142 { 0x13, 0x01, 0xFF },
143 { 0xF4, 0x80, 0xFF },
144 { 0xF0, 0x00, 0xFF },
145 { 0xE9, 0x00, 0xFF },
146#ifdef CONFIG_WLAN
147 { 0x81, 0x00, 0x7F },
148 { 0x82, 0x00, 0xFF },
149 { 0xE6, 0x38, 0x7F },
150 { 0xE7, 0x06, 0xFF },
151#endif
152 { 0x8E, 0x15, 0xFF },
153 { 0x8F, 0x15, 0xFF },
154 { 0x90, 0x15, 0xFF },
155
156 { 0xE9, 0x21, 0xFF },
157 };
158
159 const struct bahama_config_register v20_bt_on_fm_on[] = {
160 { 0x11, 0x0C, 0xFF },
161 { 0x13, 0x01, 0xFF },
162 { 0xF4, 0x86, 0xFF },
163 { 0xF0, 0x06, 0xFF },
164 { 0xE9, 0x00, 0xFF },
165#ifdef CONFIG_WLAN
166 { 0x81, 0x00, 0x7F },
167 { 0x82, 0x00, 0xFF },
168 { 0xE6, 0x38, 0x7F },
169 { 0xE7, 0x06, 0xFF },
170#endif
171 { 0xE9, 0x21, 0xFF },
172 };
173
174 const struct bahama_config_register v10_bt_off[] = {
175 { 0xE9, 0x00, 0xFF },
176 };
177
178 const struct bahama_config_register v20_bt_off_fm_off[] = {
179 { 0xF4, 0x84, 0xFF },
180 { 0xF0, 0x04, 0xFF },
181 { 0xE9, 0x00, 0xFF }
182 };
183
184 const struct bahama_config_register v20_bt_off_fm_on[] = {
185 { 0xF4, 0x86, 0xFF },
186 { 0xF0, 0x06, 0xFF },
187 { 0xE9, 0x00, 0xFF }
188 };
189
190 const struct bahama_variant_register bt_bahama[2][3] = {
191 {
192 { ARRAY_SIZE(v10_bt_off), v10_bt_off },
193 { ARRAY_SIZE(v20_bt_off_fm_off), v20_bt_off_fm_off },
194 { ARRAY_SIZE(v20_bt_off_fm_on), v20_bt_off_fm_on }
195 },
196 {
197 { ARRAY_SIZE(v10_bt_on), v10_bt_on },
198 { ARRAY_SIZE(v20_bt_on_fm_off), v20_bt_on_fm_off },
199 { ARRAY_SIZE(v20_bt_on_fm_on), v20_bt_on_fm_on }
200 }
201 };
202
203 u8 offset = 0; /* index into bahama configs */
204 on = on ? 1 : 0;
205 version = marimba_read_bahama_ver(&config);
206 if ((int)version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
207 dev_err(&msm_bt_power_device.dev,
208 "%s : Bahama version read Error, version = %d\n",
209 __func__, version);
210 return -EIO;
211 }
212 if (version == BAHAMA_VER_2_0) {
213 if (marimba_get_fm_status(&config))
214 offset = 0x01;
215 }
216
217 p = bt_bahama[on][version + offset].set;
218
219 dev_dbg(&msm_bt_power_device.dev,
220 "%s: found version %d\n", __func__, version);
221
222 for (i = 0; i < bt_bahama[on][version + offset].size; i++) {
223 u8 value = (p+i)->value;
224 rc = marimba_write_bit_mask(&config,
225 (p+i)->reg,
226 &value,
227 sizeof((p+i)->value),
228 (p+i)->mask);
229 if (rc < 0) {
230 dev_err(&msm_bt_power_device.dev,
231 "%s: reg %x write failed: %d\n",
232 __func__, (p+i)->reg, rc);
233 return rc;
234 }
235 dev_dbg(&msm_bt_power_device.dev,
236 "%s: reg 0x%02x write value 0x%02x mask 0x%02x\n",
237 __func__, (p+i)->reg,
238 value, (p+i)->mask);
239 value = 0;
240 rc = marimba_read_bit_mask(&config,
241 (p+i)->reg, &value,
242 sizeof((p+i)->value), (p+i)->mask);
243 if (rc < 0)
244 dev_err(&msm_bt_power_device.dev,
245 "%s marimba_read_bit_mask- error",
246 __func__);
247 dev_dbg(&msm_bt_power_device.dev,
248 "%s: reg 0x%02x read value 0x%02x mask 0x%02x\n",
249 __func__, (p+i)->reg,
250 value, (p+i)->mask);
251 }
252 /* Update BT Status */
253 if (on)
254 marimba_set_bt_status(&config, true);
255 else
256 marimba_set_bt_status(&config, false);
257 return rc;
258}
259
260static int bluetooth_switch_regulators(int on)
261{
262 int i, rc = 0;
263
264 for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
265 if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
266 bt_vregs[i].reg =
267 regulator_get(&msm_bt_power_device.dev,
268 bt_vregs[i].name);
269 if (IS_ERR(bt_vregs[i].reg)) {
270 rc = PTR_ERR(bt_vregs[i].reg);
271 dev_err(&msm_bt_power_device.dev,
272 "%s: invalid regulator handle for %s: %d\n",
273 __func__, bt_vregs[i].name, rc);
274 goto reg_disable;
275 }
276 }
277 rc = on ? regulator_set_voltage(bt_vregs[i].reg,
278 bt_vregs[i].min_level,
279 bt_vregs[i].max_level) : 0;
280 if (rc) {
281 dev_err(&msm_bt_power_device.dev,
282 "%s: could not set voltage for %s: %d\n",
283 __func__, bt_vregs[i].name, rc);
284 goto reg_disable;
285 }
286
287 rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
288 if (rc) {
289 dev_err(&msm_bt_power_device.dev,
290 "%s: could not %sable regulator %s: %d\n",
291 __func__, "en", bt_vregs[i].name, rc);
292 goto reg_disable;
293 }
294
295 rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
296
297 if (rc) {
298 dev_err(&msm_bt_power_device.dev,
299 "%s: could not %sable regulator %s: %d\n",
300 __func__, "dis", bt_vregs[i].name, rc);
301 goto reg_disable;
302 }
303 }
304
305 return rc;
306reg_disable:
307 pr_err("bluetooth_switch_regulators - FAIL!!!!\n");
308 while (i) {
309 if (on) {
310 i--;
311 regulator_disable(bt_vregs[i].reg);
312 regulator_put(bt_vregs[i].reg);
313 bt_vregs[i].reg = NULL;
314 }
315 }
316 return rc;
317}
318
319static unsigned int msm_bahama_setup_power(void)
320{
321 int rc = 0;
322 int i;
323
324 for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
325 bt_vregs[i].reg = regulator_get(&msm_bt_power_device.dev,
326 bt_vregs[i].name);
327 if (IS_ERR(bt_vregs[i].reg)) {
328 rc = PTR_ERR(bt_vregs[i].reg);
329 pr_err("%s: could not get regulator %s: %d\n",
330 __func__, bt_vregs[i].name, rc);
331 goto reg_fail;
332 }
333 rc = regulator_set_voltage(bt_vregs[i].reg,
334 bt_vregs[i].min_level,
335 bt_vregs[i].max_level);
336 if (rc) {
337 pr_err("%s: could not set voltage for %s: %d\n",
338 __func__, bt_vregs[i].name, rc);
339 goto reg_fail;
340 }
341 rc = regulator_enable(bt_vregs[i].reg);
342 if (rc) {
343 pr_err("%s: could not enable regulator %s: %d\n",
344 __func__, bt_vregs[i].name, rc);
345 goto reg_fail;
346 }
347 }
348 return rc;
349reg_fail:
350 pr_err("msm_bahama_setup_power FAILED !!!\n");
351
352 while (i) {
353 i--;
354 regulator_disable(bt_vregs[i].reg);
355 regulator_put(bt_vregs[i].reg);
356 bt_vregs[i].reg = NULL;
357 }
358 return rc;
359}
360
361static unsigned int msm_bahama_shutdown_power(int value)
362{
363 int rc = 0;
364 int i;
365
366 for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
367 rc = regulator_disable(bt_vregs[i].reg);
368
369 if (rc < 0) {
370 pr_err("%s: could not disable regulator %s: %d\n",
371 __func__, bt_vregs[i].name, rc);
372 goto out;
373 }
374
375 regulator_put(bt_vregs[i].reg);
376 bt_vregs[i].reg = NULL;
377 }
378out:
379 return rc;
380}
381
382static unsigned int msm_bahama_core_config(int type)
383{
384 int rc = 0;
385
386 if (type == BAHAMA_ID) {
387 int i;
388 struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
389 const struct bahama_config_register v20_init[] = {
390 /* reg, value, mask */
391 { 0xF4, 0x84, 0xFF }, /* AREG */
392 { 0xF0, 0x04, 0xFF } /* DREG */
393 };
394 if (marimba_read_bahama_ver(&config) == BAHAMA_VER_2_0) {
395 for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
396 u8 value = v20_init[i].value;
397 rc = marimba_write_bit_mask(&config,
398 v20_init[i].reg,
399 &value,
400 sizeof(v20_init[i].value),
401 v20_init[i].mask);
402 if (rc < 0) {
403 pr_err("%s: reg %d write failed: %d\n",
404 __func__, v20_init[i].reg, rc);
405 return rc;
406 }
407 pr_debug("%s: reg 0x%02x value 0x%02x mask 0x%02x\n",
408 __func__, v20_init[i].reg,
409 v20_init[i].value, v20_init[i].mask);
410 }
411 }
412 }
413 pr_debug("core type: %d\n", type);
414 return rc;
415}
416
417static int bluetooth_power(int on)
418{
419 int rc = 0;
420 const char *id = "BTPW";
421 int cid = 0;
422
423 pr_debug("bluetooth_power entered....\n");
424 cid = adie_get_detected_connectivity_type();
425 if (cid != BAHAMA_ID) {
426 pr_err("%s: unexpected adie connectivity type: %d\n",
427 __func__, cid);
428 return -ENODEV;
429 }
430
431 if (on) {
432 rc = bluetooth_switch_regulators(on);
433 if (rc < 0) {
434 pr_err("%s: bluetooth_switch_regulators rc = %d",
435 __func__, rc);
436 goto exit;
437 }
438 /* UART GPIO configuration to be done by by UART module*/
439 /*Setup BT clocks*/
440 bt_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
441 if (IS_ERR(bt_clock)) {
442 rc = PTR_ERR(bt_clock);
443 pr_err("%s: failed to get the handle for A2(%d)\n",
444 __func__, rc);
445 }
446 rc = msm_xo_mode_vote(bt_clock, MSM_XO_MODE_ON);
447 if (rc < 0) {
448 pr_err("%s: Failed to vote for TCXO_A2 ON\n", __func__);
449 goto fail_xo_vote;
450 }
451 msleep(20);
452
453 /*I2C config for Bahama*/
454 rc = bahama_bt(1);
455 if (rc < 0) {
456 pr_err("%s: bahama_bt rc = %d", __func__, rc);
457 goto fail_i2c;
458 }
459 msleep(20);
460
461 /*setup BT PCM lines*/
462 rc = config_pcm(BT_PCM_ON);
463 if (rc < 0) {
464 pr_err("%s: config_pcm , rc =%d\n",
465 __func__, rc);
466 goto fail_power;
467 }
468 /* TO DO - Enable PIN CTRL */
469 /*
470 rc = msm_xo_mode_vote(bt_clock, MSM_XO_MODE_PIN_CTRL);
471 if (rc < 0) {
472 pr_err("%s: Failed to vote for TCXO_A2 in PIN_CTRL\n",
473 __func__);
474 goto fail_xo_vote;
475 } */
476 } else {
477 rc = bahama_bt(0);
478 if (rc < 0)
479 pr_err("%s: bahama_bt rc = %d", __func__, rc);
480
481 rc = config_pcm(BT_PCM_OFF);
482 if (rc < 0) {
483 pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
484 __func__, rc);
485 }
486fail_i2c:
487 pr_err("bluetooth_power...FAIL_I2C\n");
488
489fail_xo_vote:
490 pr_err("bluetooth_power...FAIL_XO_VOTE\n");
491 msm_xo_put(bt_clock);
492fail_power:
493 pr_err("bluetooth_power...FAIL POWER\n");
494 rc = bluetooth_switch_regulators(0);
495 if (rc < 0) {
496 pr_err("%s: switch_regulators : rc = %d",\
497 __func__, rc);
498 goto exit;
499 }
500 }
501 return rc;
502exit:
503 pr_err("%s: failed with rc = %d", __func__, rc);
504 return rc;
505}
506
507static struct marimba_platform_data marimba_pdata = {
508 .slave_id[SLAVE_ID_BAHAMA_FM] = BAHAMA_SLAVE_ID_FM_ADDR,
509 .slave_id[SLAVE_ID_BAHAMA_QMEMBIST] = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
510 .bahama_setup = msm_bahama_setup_power,
511 .bahama_shutdown = msm_bahama_shutdown_power,
512 .bahama_core_config = msm_bahama_core_config,
513 .fm = NULL,
514};
515
516static struct i2c_board_info bahama_devices[] = {
517{
518 I2C_BOARD_INFO("marimba", 0xc),
519 .platform_data = &marimba_pdata,
520},
521};
522
523void __init apq8064_bt_power_init(void)
524{
525 int rc = 0;
526 struct device *dev;
527
528 rc = i2c_register_board_info(APQ_8064_GSBI5_QUP_I2C_BUS_ID,
529 bahama_devices,
530 ARRAY_SIZE(bahama_devices));
531 if (rc < 0) {
532 pr_err("%s: I2C Register failed\n", __func__);
533 return;
534 }
535 rc = platform_device_register(&msm_bt_power_device);
536 if (rc < 0) {
537 pr_err("%s: device register failed\n", __func__);
538 platform_device_unregister(&msm_bt_power_device);
539 return;
540 }
541
542 dev = &msm_bt_power_device.dev;
543 dev->platform_data = &bluetooth_power;
544
545 return;
546}
547#endif