blob: 963b1a3e33df31e6c567619ef003959acf29af27 [file] [log] [blame]
Anantha Krishnan0f498fd2012-12-19 17:26:42 +05301/* Copyright (c) 2011-2013, Linux Foundation. All rights reserved.
Ankit Verma6fe41b02012-09-13 16:12:11 +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 <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
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530124 int version;
Ankit Verma6fe41b02012-09-13 16:12:11 +0530125
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);
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530206 if (version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
Ankit Verma6fe41b02012-09-13 16:12:11 +0530207 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;
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530240 if (marimba_read_bit_mask(&config,
Ankit Verma6fe41b02012-09-13 16:12:11 +0530241 (p+i)->reg, &value,
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530242 sizeof((p+i)->value), (p+i)->mask) < 0)
Ankit Verma6fe41b02012-09-13 16:12:11 +0530243 dev_err(&msm_bt_power_device.dev,
244 "%s marimba_read_bit_mask- error",
245 __func__);
246 dev_dbg(&msm_bt_power_device.dev,
247 "%s: reg 0x%02x read value 0x%02x mask 0x%02x\n",
248 __func__, (p+i)->reg,
249 value, (p+i)->mask);
250 }
251 /* Update BT Status */
252 if (on)
253 marimba_set_bt_status(&config, true);
254 else
255 marimba_set_bt_status(&config, false);
256 return rc;
257}
258
259static int bluetooth_switch_regulators(int on)
260{
261 int i, rc = 0;
262
263 for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
264 if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
265 bt_vregs[i].reg =
266 regulator_get(&msm_bt_power_device.dev,
267 bt_vregs[i].name);
268 if (IS_ERR(bt_vregs[i].reg)) {
269 rc = PTR_ERR(bt_vregs[i].reg);
270 dev_err(&msm_bt_power_device.dev,
271 "%s: invalid regulator handle for %s: %d\n",
272 __func__, bt_vregs[i].name, rc);
273 goto reg_disable;
274 }
275 }
276 rc = on ? regulator_set_voltage(bt_vregs[i].reg,
277 bt_vregs[i].min_level,
278 bt_vregs[i].max_level) : 0;
279 if (rc) {
280 dev_err(&msm_bt_power_device.dev,
281 "%s: could not set voltage for %s: %d\n",
282 __func__, bt_vregs[i].name, rc);
283 goto reg_disable;
284 }
285
286 rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
287 if (rc) {
288 dev_err(&msm_bt_power_device.dev,
289 "%s: could not %sable regulator %s: %d\n",
290 __func__, "en", bt_vregs[i].name, rc);
291 goto reg_disable;
292 }
293
294 rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
295
296 if (rc) {
297 dev_err(&msm_bt_power_device.dev,
298 "%s: could not %sable regulator %s: %d\n",
299 __func__, "dis", bt_vregs[i].name, rc);
Ankit Verma6fe41b02012-09-13 16:12:11 +0530300 }
301 }
302
303 return rc;
304reg_disable:
305 pr_err("bluetooth_switch_regulators - FAIL!!!!\n");
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530306 if (on) {
307 while (i) {
Ankit Verma6fe41b02012-09-13 16:12:11 +0530308 i--;
309 regulator_disable(bt_vregs[i].reg);
310 regulator_put(bt_vregs[i].reg);
311 bt_vregs[i].reg = NULL;
312 }
313 }
314 return rc;
315}
316
317static unsigned int msm_bahama_setup_power(void)
318{
319 int rc = 0;
320 int i;
321
322 for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
323 bt_vregs[i].reg = regulator_get(&msm_bt_power_device.dev,
324 bt_vregs[i].name);
325 if (IS_ERR(bt_vregs[i].reg)) {
326 rc = PTR_ERR(bt_vregs[i].reg);
327 pr_err("%s: could not get regulator %s: %d\n",
328 __func__, bt_vregs[i].name, rc);
329 goto reg_fail;
330 }
331 rc = regulator_set_voltage(bt_vregs[i].reg,
332 bt_vregs[i].min_level,
333 bt_vregs[i].max_level);
334 if (rc) {
335 pr_err("%s: could not set voltage for %s: %d\n",
336 __func__, bt_vregs[i].name, rc);
337 goto reg_fail;
338 }
339 rc = regulator_enable(bt_vregs[i].reg);
340 if (rc) {
341 pr_err("%s: could not enable regulator %s: %d\n",
342 __func__, bt_vregs[i].name, rc);
343 goto reg_fail;
344 }
345 }
346 return rc;
347reg_fail:
348 pr_err("msm_bahama_setup_power FAILED !!!\n");
349
350 while (i) {
351 i--;
352 regulator_disable(bt_vregs[i].reg);
353 regulator_put(bt_vregs[i].reg);
354 bt_vregs[i].reg = NULL;
355 }
356 return rc;
357}
358
359static unsigned int msm_bahama_shutdown_power(int value)
360{
361 int rc = 0;
362 int i;
363
364 for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
365 rc = regulator_disable(bt_vregs[i].reg);
366
367 if (rc < 0) {
368 pr_err("%s: could not disable regulator %s: %d\n",
369 __func__, bt_vregs[i].name, rc);
370 goto out;
371 }
372
373 regulator_put(bt_vregs[i].reg);
374 bt_vregs[i].reg = NULL;
375 }
376out:
377 return rc;
378}
379
380static unsigned int msm_bahama_core_config(int type)
381{
382 int rc = 0;
383
384 if (type == BAHAMA_ID) {
385 int i;
386 struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
387 const struct bahama_config_register v20_init[] = {
388 /* reg, value, mask */
389 { 0xF4, 0x84, 0xFF }, /* AREG */
390 { 0xF0, 0x04, 0xFF } /* DREG */
391 };
392 if (marimba_read_bahama_ver(&config) == BAHAMA_VER_2_0) {
393 for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
394 u8 value = v20_init[i].value;
395 rc = marimba_write_bit_mask(&config,
396 v20_init[i].reg,
397 &value,
398 sizeof(v20_init[i].value),
399 v20_init[i].mask);
400 if (rc < 0) {
401 pr_err("%s: reg %d write failed: %d\n",
402 __func__, v20_init[i].reg, rc);
403 return rc;
404 }
405 pr_debug("%s: reg 0x%02x value 0x%02x mask 0x%02x\n",
406 __func__, v20_init[i].reg,
407 v20_init[i].value, v20_init[i].mask);
408 }
409 }
410 }
411 pr_debug("core type: %d\n", type);
412 return rc;
413}
414
415static int bluetooth_power(int on)
416{
417 int rc = 0;
418 const char *id = "BTPW";
419 int cid = 0;
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530420 int bt_state = 0;
421 struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
Ankit Verma6fe41b02012-09-13 16:12:11 +0530422
Ankit Verma6fe41b02012-09-13 16:12:11 +0530423 cid = adie_get_detected_connectivity_type();
424 if (cid != BAHAMA_ID) {
425 pr_err("%s: unexpected adie connectivity type: %d\n",
426 __func__, cid);
427 return -ENODEV;
428 }
429
430 if (on) {
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530431 pr_debug("%s: Powering up the BT module.\n", __func__);
Ankit Verma6fe41b02012-09-13 16:12:11 +0530432 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*/
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530440 pr_debug("%s: Voting for the 19.2MHz clock\n", __func__);
Ankit Verma6fe41b02012-09-13 16:12:11 +0530441 bt_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
442 if (IS_ERR(bt_clock)) {
443 rc = PTR_ERR(bt_clock);
444 pr_err("%s: failed to get the handle for A2(%d)\n",
445 __func__, rc);
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530446 goto fail_power;
Ankit Verma6fe41b02012-09-13 16:12:11 +0530447 }
448 rc = msm_xo_mode_vote(bt_clock, MSM_XO_MODE_ON);
449 if (rc < 0) {
450 pr_err("%s: Failed to vote for TCXO_A2 ON\n", __func__);
451 goto fail_xo_vote;
452 }
453 msleep(20);
454
455 /*I2C config for Bahama*/
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530456 pr_debug("%s: BT Turn On sequence in-progress.\n", __func__);
Ankit Verma6fe41b02012-09-13 16:12:11 +0530457 rc = bahama_bt(1);
458 if (rc < 0) {
459 pr_err("%s: bahama_bt rc = %d", __func__, rc);
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530460 goto fail_xo_vote;
Ankit Verma6fe41b02012-09-13 16:12:11 +0530461 }
462 msleep(20);
463
464 /*setup BT PCM lines*/
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530465 pr_debug("%s: Configuring PCM lines.\n", __func__);
Ankit Verma6fe41b02012-09-13 16:12:11 +0530466 rc = config_pcm(BT_PCM_ON);
467 if (rc < 0) {
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530468 pr_err("%s: config_pcm , rc = %d\n",
Ankit Verma6fe41b02012-09-13 16:12:11 +0530469 __func__, rc);
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530470 goto fail_i2c;
Ankit Verma6fe41b02012-09-13 16:12:11 +0530471 }
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530472 pr_debug("%s: BT Turn On complete.\n", __func__);
Ankit Verma6fe41b02012-09-13 16:12:11 +0530473 /* TO DO - Enable PIN CTRL */
474 /*
475 rc = msm_xo_mode_vote(bt_clock, MSM_XO_MODE_PIN_CTRL);
476 if (rc < 0) {
477 pr_err("%s: Failed to vote for TCXO_A2 in PIN_CTRL\n",
478 __func__);
479 goto fail_xo_vote;
480 } */
481 } else {
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530482 pr_debug("%s: Turning BT Off.\n", __func__);
483 bt_state = marimba_get_bt_status(&config);
484 if (!bt_state) {
485 pr_err("%s: BT is already turned OFF.\n", __func__);
486 return 0;
487 }
Ankit Verma6fe41b02012-09-13 16:12:11 +0530488
489 rc = config_pcm(BT_PCM_OFF);
490 if (rc < 0) {
491 pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
492 __func__, rc);
493 }
494fail_i2c:
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530495 rc = bahama_bt(0);
496 if (rc < 0)
497 pr_err("%s: bahama_bt rc = %d", __func__, rc);
Ankit Verma6fe41b02012-09-13 16:12:11 +0530498fail_xo_vote:
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530499 pr_debug("%s: Voting off the 19.2MHz clk\n", __func__);
Ankit Verma6fe41b02012-09-13 16:12:11 +0530500 msm_xo_put(bt_clock);
501fail_power:
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530502 pr_debug("%s: Switching off voltage regulators.\n", __func__);
Ankit Verma6fe41b02012-09-13 16:12:11 +0530503 rc = bluetooth_switch_regulators(0);
504 if (rc < 0) {
505 pr_err("%s: switch_regulators : rc = %d",\
506 __func__, rc);
507 goto exit;
508 }
Anantha Krishnan0f498fd2012-12-19 17:26:42 +0530509 pr_debug("%s: BT Power Off complete.\n", __func__);
Ankit Verma6fe41b02012-09-13 16:12:11 +0530510 }
511 return rc;
512exit:
513 pr_err("%s: failed with rc = %d", __func__, rc);
514 return rc;
515}
516
517static struct marimba_platform_data marimba_pdata = {
518 .slave_id[SLAVE_ID_BAHAMA_FM] = BAHAMA_SLAVE_ID_FM_ADDR,
519 .slave_id[SLAVE_ID_BAHAMA_QMEMBIST] = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
520 .bahama_setup = msm_bahama_setup_power,
521 .bahama_shutdown = msm_bahama_shutdown_power,
522 .bahama_core_config = msm_bahama_core_config,
523 .fm = NULL,
524};
525
526static struct i2c_board_info bahama_devices[] = {
527{
528 I2C_BOARD_INFO("marimba", 0xc),
529 .platform_data = &marimba_pdata,
530},
531};
532
533void __init apq8064_bt_power_init(void)
534{
535 int rc = 0;
536 struct device *dev;
537
538 rc = i2c_register_board_info(APQ_8064_GSBI5_QUP_I2C_BUS_ID,
539 bahama_devices,
540 ARRAY_SIZE(bahama_devices));
541 if (rc < 0) {
542 pr_err("%s: I2C Register failed\n", __func__);
543 return;
544 }
545 rc = platform_device_register(&msm_bt_power_device);
546 if (rc < 0) {
547 pr_err("%s: device register failed\n", __func__);
548 platform_device_unregister(&msm_bt_power_device);
549 return;
550 }
551
552 dev = &msm_bt_power_device.dev;
553 dev->platform_data = &bluetooth_power;
554
555 return;
556}
557#endif