diff options
author | Amitkumar Karwar <akarwar@marvell.com> | 2013-10-01 15:19:15 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2013-10-02 03:36:16 -0400 |
commit | 2cc8689028cd077e3e9cb9a192b1bb524fe38935 (patch) | |
tree | 764174e4b7a05212518d24f4cffbe97769b5ab6f /drivers | |
parent | 4b245722cabc6ee6d56924f10944b14a725ffd61 (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')
-rw-r--r-- | drivers/bluetooth/btmrvl_drv.h | 8 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_main.c | 116 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_sdio.c | 9 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_sdio.h | 2 |
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 { | |||
41 | struct btmrvl_device { | 43 | struct 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 | |||
119 | struct btmrvl_event { | 127 | struct 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 | */ | ||
442 | static 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 | |||
479 | static 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 | |||
508 | static int | ||
509 | btmrvl_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 | |||
527 | static 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 | |||
435 | static int btmrvl_setup(struct hci_dev *hdev) | 548 | static 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 = { | |||
102 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { | 101 | static 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 = { | |||
109 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { | 109 | static 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 = { | |||
116 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { | 117 | static 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 = { | |||
123 | static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { | 125 | static 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"); | |||
1216 | MODULE_FIRMWARE("mrvl/sd8688.bin"); | 1222 | MODULE_FIRMWARE("mrvl/sd8688.bin"); |
1217 | MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); | 1223 | MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); |
1218 | MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); | 1224 | MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); |
1225 | MODULE_FIRMWARE("mrvl/sd8797_caldata.conf"); | ||
1219 | MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin"); | 1226 | MODULE_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 { | |||
94 | struct btmrvl_sdio_device { | 95 | struct 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 | }; |