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/bluetooth/btmrvl_main.c | |
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/bluetooth/btmrvl_main.c')
-rw-r--r-- | drivers/bluetooth/btmrvl_main.c | 116 |
1 files changed, 116 insertions, 0 deletions
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 | ||