|
5 | 5 | // Copyright (C) 2023 Cirrus Logic, Inc. and
|
6 | 6 | // Cirrus Logic International Semiconductor Ltd.
|
7 | 7 |
|
| 8 | +#include <linux/firmware/cirrus/wmfw.h> |
8 | 9 | #include <linux/gpio/consumer.h>
|
9 | 10 | #include <linux/regmap.h>
|
10 | 11 | #include <linux/regulator/consumer.h>
|
11 | 12 | #include <linux/types.h>
|
| 13 | +#include <sound/cs-amp-lib.h> |
12 | 14 |
|
13 | 15 | #include "cs35l56.h"
|
14 | 16 |
|
@@ -36,6 +38,8 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
|
36 | 38 | EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED);
|
37 | 39 |
|
38 | 40 | static const struct reg_default cs35l56_reg_defaults[] = {
|
| 41 | + /* no defaults for OTP_MEM - first read populates cache */ |
| 42 | + |
39 | 43 | { CS35L56_ASP1_ENABLES1, 0x00000000 },
|
40 | 44 | { CS35L56_ASP1_CONTROL1, 0x00000028 },
|
41 | 45 | { CS35L56_ASP1_CONTROL2, 0x18180200 },
|
@@ -91,6 +95,9 @@ static bool cs35l56_readable_reg(struct device *dev, unsigned int reg)
|
91 | 95 | case CS35L56_BLOCK_ENABLES2:
|
92 | 96 | case CS35L56_REFCLK_INPUT:
|
93 | 97 | case CS35L56_GLOBAL_SAMPLE_RATE:
|
| 98 | + case CS35L56_OTP_MEM_53: |
| 99 | + case CS35L56_OTP_MEM_54: |
| 100 | + case CS35L56_OTP_MEM_55: |
94 | 101 | case CS35L56_ASP1_ENABLES1:
|
95 | 102 | case CS35L56_ASP1_CONTROL1:
|
96 | 103 | case CS35L56_ASP1_CONTROL2:
|
@@ -628,6 +635,81 @@ void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_ds
|
628 | 635 | }
|
629 | 636 | EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, SND_SOC_CS35L56_SHARED);
|
630 | 637 |
|
| 638 | +struct cs35l56_pte { |
| 639 | + u8 x; |
| 640 | + u8 wafer_id; |
| 641 | + u8 pte[2]; |
| 642 | + u8 lot[3]; |
| 643 | + u8 y; |
| 644 | + u8 unused[3]; |
| 645 | + u8 dvs; |
| 646 | +} __packed; |
| 647 | +static_assert((sizeof(struct cs35l56_pte) % sizeof(u32)) == 0); |
| 648 | + |
| 649 | +static int cs35l56_read_silicon_uid(struct cs35l56_base *cs35l56_base, u64 *uid) |
| 650 | +{ |
| 651 | + struct cs35l56_pte pte; |
| 652 | + u64 unique_id; |
| 653 | + int ret; |
| 654 | + |
| 655 | + ret = regmap_raw_read(cs35l56_base->regmap, CS35L56_OTP_MEM_53, &pte, sizeof(pte)); |
| 656 | + if (ret) { |
| 657 | + dev_err(cs35l56_base->dev, "Failed to read OTP: %d\n", ret); |
| 658 | + return ret; |
| 659 | + } |
| 660 | + |
| 661 | + unique_id = pte.lot[2] | (pte.lot[1] << 8) | (pte.lot[0] << 16); |
| 662 | + unique_id <<= 32; |
| 663 | + unique_id |= pte.x | (pte.y << 8) | (pte.wafer_id << 16) | (pte.dvs << 24); |
| 664 | + |
| 665 | + dev_dbg(cs35l56_base->dev, "UniqueID = %#llx\n", unique_id); |
| 666 | + |
| 667 | + *uid = unique_id; |
| 668 | + |
| 669 | + return 0; |
| 670 | +} |
| 671 | + |
| 672 | +/* Firmware calibration controls */ |
| 673 | +const struct cirrus_amp_cal_controls cs35l56_calibration_controls = { |
| 674 | + .alg_id = 0x9f210, |
| 675 | + .mem_region = WMFW_ADSP2_YM, |
| 676 | + .ambient = "CAL_AMBIENT", |
| 677 | + .calr = "CAL_R", |
| 678 | + .status = "CAL_STATUS", |
| 679 | + .checksum = "CAL_CHECKSUM", |
| 680 | +}; |
| 681 | +EXPORT_SYMBOL_NS_GPL(cs35l56_calibration_controls, SND_SOC_CS35L56_SHARED); |
| 682 | + |
| 683 | +int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base) |
| 684 | +{ |
| 685 | + u64 silicon_uid; |
| 686 | + int ret; |
| 687 | + |
| 688 | + /* Driver can't apply calibration to a secured part, so skip */ |
| 689 | + if (cs35l56_base->secured) |
| 690 | + return 0; |
| 691 | + |
| 692 | + ret = cs35l56_read_silicon_uid(cs35l56_base, &silicon_uid); |
| 693 | + if (ret < 0) |
| 694 | + return ret; |
| 695 | + |
| 696 | + ret = cs_amp_get_efi_calibration_data(cs35l56_base->dev, silicon_uid, |
| 697 | + cs35l56_base->cal_index, |
| 698 | + &cs35l56_base->cal_data); |
| 699 | + |
| 700 | + /* Only return an error status if probe should be aborted */ |
| 701 | + if ((ret == -ENOENT) || (ret == -EOVERFLOW)) |
| 702 | + return 0; |
| 703 | + |
| 704 | + if (ret < 0) |
| 705 | + return ret; |
| 706 | + |
| 707 | + cs35l56_base->cal_data_valid = true; |
| 708 | + |
| 709 | + return 0; |
| 710 | +} |
| 711 | +EXPORT_SYMBOL_NS_GPL(cs35l56_get_calibration, SND_SOC_CS35L56_SHARED); |
| 712 | + |
631 | 713 | int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
|
632 | 714 | bool *fw_missing, unsigned int *fw_version)
|
633 | 715 | {
|
@@ -922,3 +1004,4 @@ MODULE_DESCRIPTION("ASoC CS35L56 Shared");
|
922 | 1004 | MODULE_AUTHOR( "Richard Fitzgerald <[email protected]>");
|
923 | 1005 | MODULE_AUTHOR( "Simon Trimmer <[email protected]>");
|
924 | 1006 | MODULE_LICENSE("GPL");
|
| 1007 | +MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB); |
0 commit comments