aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2013-10-01 15:19:15 -0400
committerMarcel Holtmann <marcel@holtmann.org>2013-10-02 03:36:16 -0400
commit2cc8689028cd077e3e9cb9a192b1bb524fe38935 (patch)
tree764174e4b7a05212518d24f4cffbe97769b5ab6f /drivers/bluetooth
parent4b245722cabc6ee6d56924f10944b14a725ffd61 (diff)
Bluetooth: btmrvl: add calibration data download support
A text file containing calibration data in hex format can be provided at following path: /lib/firmware/mrvl/sd8797_caldata.conf The data will be downloaded to firmware during initialization. Reviewed-by: Mike Frysinger <vapier@chromium.org> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: Hyuckjoo Lee <hyuckjoo.lee@samsung.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r--drivers/bluetooth/btmrvl_drv.h8
-rw-r--r--drivers/bluetooth/btmrvl_main.c116
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c9
-rw-r--r--drivers/bluetooth/btmrvl_sdio.h2
4 files changed, 134 insertions, 1 deletions
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index 42f7028d3890..f9d183387f45 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -23,6 +23,8 @@
23#include <linux/bitops.h> 23#include <linux/bitops.h>
24#include <linux/slab.h> 24#include <linux/slab.h>
25#include <net/bluetooth/bluetooth.h> 25#include <net/bluetooth/bluetooth.h>
26#include <linux/ctype.h>
27#include <linux/firmware.h>
26 28
27#define BTM_HEADER_LEN 4 29#define BTM_HEADER_LEN 4
28#define BTM_UPLD_SIZE 2312 30#define BTM_UPLD_SIZE 2312
@@ -41,6 +43,8 @@ struct btmrvl_thread {
41struct btmrvl_device { 43struct btmrvl_device {
42 void *card; 44 void *card;
43 struct hci_dev *hcidev; 45 struct hci_dev *hcidev;
46 struct device *dev;
47 const char *cal_data;
44 48
45 u8 dev_type; 49 u8 dev_type;
46 50
@@ -91,6 +95,7 @@ struct btmrvl_private {
91#define BT_CMD_HOST_SLEEP_CONFIG 0x59 95#define BT_CMD_HOST_SLEEP_CONFIG 0x59
92#define BT_CMD_HOST_SLEEP_ENABLE 0x5A 96#define BT_CMD_HOST_SLEEP_ENABLE 0x5A
93#define BT_CMD_MODULE_CFG_REQ 0x5B 97#define BT_CMD_MODULE_CFG_REQ 0x5B
98#define BT_CMD_LOAD_CONFIG_DATA 0x61
94 99
95/* Sub-commands: Module Bringup/Shutdown Request/Response */ 100/* Sub-commands: Module Bringup/Shutdown Request/Response */
96#define MODULE_BRINGUP_REQ 0xF1 101#define MODULE_BRINGUP_REQ 0xF1
@@ -116,6 +121,9 @@ struct btmrvl_private {
116#define PS_SLEEP 0x01 121#define PS_SLEEP 0x01
117#define PS_AWAKE 0x00 122#define PS_AWAKE 0x00
118 123
124#define BT_CMD_DATA_SIZE 32
125#define BT_CAL_DATA_SIZE 28
126
119struct btmrvl_event { 127struct btmrvl_event {
120 u8 ec; /* event counter */ 128 u8 ec; /* event counter */
121 u8 length; 129 u8 length;
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index e0ae1f4ea406..6e7bd4e4adbb 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -432,12 +432,128 @@ static int btmrvl_open(struct hci_dev *hdev)
432 return 0; 432 return 0;
433} 433}
434 434
435/*
436 * This function parses provided calibration data input. It should contain
437 * hex bytes separated by space or new line character. Here is an example.
438 * 00 1C 01 37 FF FF FF FF 02 04 7F 01
439 * CE BA 00 00 00 2D C6 C0 00 00 00 00
440 * 00 F0 00 00
441 */
442static int btmrvl_parse_cal_cfg(const u8 *src, u32 len, u8 *dst, u32 dst_size)
443{
444 const u8 *s = src;
445 u8 *d = dst;
446 int ret;
447 u8 tmp[3];
448
449 tmp[2] = '\0';
450 while ((s - src) <= len - 2) {
451 if (isspace(*s)) {
452 s++;
453 continue;
454 }
455
456 if (isxdigit(*s)) {
457 if ((d - dst) >= dst_size) {
458 BT_ERR("calibration data file too big!!!");
459 return -EINVAL;
460 }
461
462 memcpy(tmp, s, 2);
463
464 ret = kstrtou8(tmp, 16, d++);
465 if (ret < 0)
466 return ret;
467
468 s += 2;
469 } else {
470 return -EINVAL;
471 }
472 }
473 if (d == dst)
474 return -EINVAL;
475
476 return 0;
477}
478
479static int btmrvl_load_cal_data(struct btmrvl_private *priv,
480 u8 *config_data)
481{
482 int i, ret;
483 u8 data[BT_CMD_DATA_SIZE];
484
485 data[0] = 0x00;
486 data[1] = 0x00;
487 data[2] = 0x00;
488 data[3] = BT_CMD_DATA_SIZE - 4;
489
490 /* Swap cal-data bytes. Each four bytes are swapped. Considering 4
491 * byte SDIO header offset, mapping of input and output bytes will be
492 * {3, 2, 1, 0} -> {0+4, 1+4, 2+4, 3+4},
493 * {7, 6, 5, 4} -> {4+4, 5+4, 6+4, 7+4} */
494 for (i = 4; i < BT_CMD_DATA_SIZE; i++)
495 data[i] = config_data[(i / 4) * 8 - 1 - i];
496
497 print_hex_dump_bytes("Calibration data: ",
498 DUMP_PREFIX_OFFSET, data, BT_CMD_DATA_SIZE);
499
500 ret = btmrvl_send_sync_cmd(priv, BT_CMD_LOAD_CONFIG_DATA, data,
501 BT_CMD_DATA_SIZE);
502 if (ret)
503 BT_ERR("Failed to download caibration data\n");
504
505 return 0;
506}
507
508static int
509btmrvl_process_cal_cfg(struct btmrvl_private *priv, u8 *data, u32 size)
510{
511 u8 cal_data[BT_CAL_DATA_SIZE];
512 int ret;
513
514 ret = btmrvl_parse_cal_cfg(data, size, cal_data, sizeof(cal_data));
515 if (ret)
516 return ret;
517
518 ret = btmrvl_load_cal_data(priv, cal_data);
519 if (ret) {
520 BT_ERR("Fail to load calibrate data");
521 return ret;
522 }
523
524 return 0;
525}
526
527static int btmrvl_cal_data_config(struct btmrvl_private *priv)
528{
529 const struct firmware *cfg;
530 int ret;
531 const char *cal_data = priv->btmrvl_dev.cal_data;
532
533 if (!cal_data)
534 return 0;
535
536 ret = request_firmware(&cfg, cal_data, priv->btmrvl_dev.dev);
537 if (ret < 0) {
538 BT_DBG("Failed to get %s file, skipping cal data download",
539 cal_data);
540 return 0;
541 }
542
543 ret = btmrvl_process_cal_cfg(priv, (u8 *)cfg->data, cfg->size);
544 release_firmware(cfg);
545 return ret;
546}
547
435static int btmrvl_setup(struct hci_dev *hdev) 548static int btmrvl_setup(struct hci_dev *hdev)
436{ 549{
437 struct btmrvl_private *priv = hci_get_drvdata(hdev); 550 struct btmrvl_private *priv = hci_get_drvdata(hdev);
438 551
439 btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ); 552 btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
440 553
554 if (btmrvl_cal_data_config(priv))
555 BT_ERR("Set cal data failed");
556
441 priv->btmrvl_dev.psmode = 1; 557 priv->btmrvl_dev.psmode = 1;
442 btmrvl_enable_ps(priv); 558 btmrvl_enable_ps(priv);
443 559
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 5b70bcb38a5e..332475e400cf 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -18,7 +18,6 @@
18 * this warranty disclaimer. 18 * this warranty disclaimer.
19 **/ 19 **/
20 20
21#include <linux/firmware.h>
22#include <linux/slab.h> 21#include <linux/slab.h>
23 22
24#include <linux/mmc/sdio_ids.h> 23#include <linux/mmc/sdio_ids.h>
@@ -102,6 +101,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
102static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { 101static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
103 .helper = "mrvl/sd8688_helper.bin", 102 .helper = "mrvl/sd8688_helper.bin",
104 .firmware = "mrvl/sd8688.bin", 103 .firmware = "mrvl/sd8688.bin",
104 .cal_data = NULL,
105 .reg = &btmrvl_reg_8688, 105 .reg = &btmrvl_reg_8688,
106 .sd_blksz_fw_dl = 64, 106 .sd_blksz_fw_dl = 64,
107}; 107};
@@ -109,6 +109,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
109static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { 109static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
110 .helper = NULL, 110 .helper = NULL,
111 .firmware = "mrvl/sd8787_uapsta.bin", 111 .firmware = "mrvl/sd8787_uapsta.bin",
112 .cal_data = NULL,
112 .reg = &btmrvl_reg_87xx, 113 .reg = &btmrvl_reg_87xx,
113 .sd_blksz_fw_dl = 256, 114 .sd_blksz_fw_dl = 256,
114}; 115};
@@ -116,6 +117,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
116static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { 117static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
117 .helper = NULL, 118 .helper = NULL,
118 .firmware = "mrvl/sd8797_uapsta.bin", 119 .firmware = "mrvl/sd8797_uapsta.bin",
120 .cal_data = "mrvl/sd8797_caldata.conf",
119 .reg = &btmrvl_reg_87xx, 121 .reg = &btmrvl_reg_87xx,
120 .sd_blksz_fw_dl = 256, 122 .sd_blksz_fw_dl = 256,
121}; 123};
@@ -123,6 +125,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
123static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { 125static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
124 .helper = NULL, 126 .helper = NULL,
125 .firmware = "mrvl/sd8897_uapsta.bin", 127 .firmware = "mrvl/sd8897_uapsta.bin",
128 .cal_data = NULL,
126 .reg = &btmrvl_reg_88xx, 129 .reg = &btmrvl_reg_88xx,
127 .sd_blksz_fw_dl = 256, 130 .sd_blksz_fw_dl = 256,
128}; 131};
@@ -1006,6 +1009,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
1006 struct btmrvl_sdio_device *data = (void *) id->driver_data; 1009 struct btmrvl_sdio_device *data = (void *) id->driver_data;
1007 card->helper = data->helper; 1010 card->helper = data->helper;
1008 card->firmware = data->firmware; 1011 card->firmware = data->firmware;
1012 card->cal_data = data->cal_data;
1009 card->reg = data->reg; 1013 card->reg = data->reg;
1010 card->sd_blksz_fw_dl = data->sd_blksz_fw_dl; 1014 card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
1011 } 1015 }
@@ -1034,6 +1038,8 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
1034 } 1038 }
1035 1039
1036 card->priv = priv; 1040 card->priv = priv;
1041 priv->btmrvl_dev.dev = &card->func->dev;
1042 priv->btmrvl_dev.cal_data = card->cal_data;
1037 1043
1038 /* Initialize the interface specific function pointers */ 1044 /* Initialize the interface specific function pointers */
1039 priv->hw_host_to_card = btmrvl_sdio_host_to_card; 1045 priv->hw_host_to_card = btmrvl_sdio_host_to_card;
@@ -1216,4 +1222,5 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
1216MODULE_FIRMWARE("mrvl/sd8688.bin"); 1222MODULE_FIRMWARE("mrvl/sd8688.bin");
1217MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); 1223MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
1218MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); 1224MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
1225MODULE_FIRMWARE("mrvl/sd8797_caldata.conf");
1219MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin"); 1226MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h
index 43d35a609ca9..6872d9ecac07 100644
--- a/drivers/bluetooth/btmrvl_sdio.h
+++ b/drivers/bluetooth/btmrvl_sdio.h
@@ -85,6 +85,7 @@ struct btmrvl_sdio_card {
85 u32 ioport; 85 u32 ioport;
86 const char *helper; 86 const char *helper;
87 const char *firmware; 87 const char *firmware;
88 const char *cal_data;
88 const struct btmrvl_sdio_card_reg *reg; 89 const struct btmrvl_sdio_card_reg *reg;
89 u16 sd_blksz_fw_dl; 90 u16 sd_blksz_fw_dl;
90 u8 rx_unit; 91 u8 rx_unit;
@@ -94,6 +95,7 @@ struct btmrvl_sdio_card {
94struct btmrvl_sdio_device { 95struct btmrvl_sdio_device {
95 const char *helper; 96 const char *helper;
96 const char *firmware; 97 const char *firmware;
98 const char *cal_data;
97 const struct btmrvl_sdio_card_reg *reg; 99 const struct btmrvl_sdio_card_reg *reg;
98 u16 sd_blksz_fw_dl; 100 u16 sd_blksz_fw_dl;
99}; 101};