[PATCH V5 0/8] ASoC: codecs: Add aw87390 amplifier driver
From: Weidong Wang wangweidong.a@awinic.com
The awinic aw87390 is a new high efficiency, low noise, constant large volume, 6th Smart K audio amplifier.
Add a DT schema for describing awinic aw87390 audio amplifiers. They are controlled using I2C.
v4 -> v5: Adjust the order and context of the patch
Weidong Wang (8): ASoC: dt-bindings: awinic,aw88395: Add properties for multiple PA support ASoC: dt-bindings: Add schema for "awinic,aw87390" ASoC: codecs: Modify the code related to the property ASoC: codecs: Modify the transmission method of parameters ASoC: codecs: Add code for bin parsing compatible with aw87390 ASoC: codecs: Modify the code related to the property ASoC: codecs: Modify the transmission mode of function parameters ASoC: codecs: Add aw87390 amplifier driver
.../bindings/sound/awinic,aw87390.yaml | 58 +++ .../bindings/sound/awinic,aw88395.yaml | 16 + sound/soc/codecs/Kconfig | 15 +- sound/soc/codecs/Makefile | 2 + sound/soc/codecs/aw87390.c | 462 ++++++++++++++++++ sound/soc/codecs/aw87390.h | 85 ++++ sound/soc/codecs/aw88261.c | 27 +- sound/soc/codecs/aw88261.h | 4 +- sound/soc/codecs/aw88395/aw88395.c | 9 +- sound/soc/codecs/aw88395/aw88395.h | 2 +- sound/soc/codecs/aw88395/aw88395_device.c | 47 +- sound/soc/codecs/aw88395/aw88395_device.h | 6 +- sound/soc/codecs/aw88395/aw88395_lib.c | 25 +- sound/soc/codecs/aw88395/aw88395_reg.h | 1 + 14 files changed, 685 insertions(+), 74 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/awinic,aw87390.yaml create mode 100644 sound/soc/codecs/aw87390.c create mode 100644 sound/soc/codecs/aw87390.h
base-commit: 0e945134b680040b8613e962f586d91b6d40292d
From: Weidong Wang wangweidong.a@awinic.com
Add two properties, the "awinic,audio-channel" property and the "awinic,sync-flag". The "awinic,audio-channel" is used to make different PA load different configurations, the "awinic,sync-flag" is used to synchronize the phases of multiple PA. These two properties will be read by the corresponding driver, allowing multi-PA to achieve better playback effect.
Signed-off-by: Weidong Wang wangweidong.a@awinic.com Acked-by: Rob Herring robh@kernel.org --- .../bindings/sound/awinic,aw88395.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml index 4051c2538caf..b977d3de87cb 100644 --- a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml +++ b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml @@ -32,11 +32,25 @@ properties: reset-gpios: maxItems: 1
+ awinic,audio-channel: + description: + It is used to distinguish multiple PA devices, so that different + configurations can be loaded to different PA devices + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 7 + + awinic,sync-flag: + description: + Flag bit used to keep the phase synchronized in the case of multiple PA + $ref: /schemas/types.yaml#/definitions/flag + required: - compatible - reg - '#sound-dai-cells' - reset-gpios + - awinic,audio-channel
unevaluatedProperties: false
@@ -51,5 +65,7 @@ examples: reg = <0x34>; #sound-dai-cells = <0>; reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>; + awinic,audio-channel = <0>; + awinic,sync-flag; }; };
From: Weidong Wang wangweidong.a@awinic.com
Add a DT schema for describing awinic aw87390 audio amplifiers. They are controlled using I2C.
Signed-off-by: Weidong Wang wangweidong.a@awinic.com Reviewed-by: Rob Herring robh@kernel.org --- .../bindings/sound/awinic,aw87390.yaml | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/awinic,aw87390.yaml
diff --git a/Documentation/devicetree/bindings/sound/awinic,aw87390.yaml b/Documentation/devicetree/bindings/sound/awinic,aw87390.yaml new file mode 100644 index 000000000000..ba9d8767c5d5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/awinic,aw87390.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/awinic,aw87390.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Awinic Aw87390 Audio Amplifier + +maintainers: + - Weidong Wang wangweidong.a@awinic.com + +description: + The awinic aw87390 is specifically designed to improve + the musical output dynamic range, enhance the overall + sound quallity, which is a new high efficiency, low + noise, constant large volume, 6th Smart K audio amplifier. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: awinic,aw87390 + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + + awinic,audio-channel: + description: + It is used to distinguish multiple PA devices, so that different + configurations can be loaded to different PA devices + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 7 + +required: + - compatible + - reg + - "#sound-dai-cells" + - awinic,audio-channel + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + audio-codec@58 { + compatible = "awinic,aw87390"; + reg = <0x58>; + #sound-dai-cells = <0>; + awinic,audio-channel = <0>; + }; + };
From: Weidong Wang wangweidong.a@awinic.com
Remove the "fade-enable" property because other properties already implement this functionality. Rename "sound-channel" to "awinic,audio-channel", this is to be consistent with the "awinic,aw88395.yaml" file
Signed-off-by: Weidong Wang wangweidong.a@awinic.com --- sound/soc/codecs/aw88395/aw88395_device.c | 35 ++--------------------- sound/soc/codecs/aw88395/aw88395_device.h | 4 +-- 2 files changed, 4 insertions(+), 35 deletions(-)
diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c index 33eda3741464..5ca4172cb788 100644 --- a/sound/soc/codecs/aw88395/aw88395_device.c +++ b/sound/soc/codecs/aw88395/aw88395_device.c @@ -297,9 +297,6 @@ static void aw_dev_fade_in(struct aw_device *aw_dev) int fade_step = aw_dev->fade_step; int i;
- if (!aw_dev->fade_en) - return; - if (fade_step == 0 || aw_dev->fade_in_time == 0) { aw_dev_set_volume(aw_dev, fade_in_vol); return; @@ -320,9 +317,6 @@ static void aw_dev_fade_out(struct aw_device *aw_dev) int fade_step = aw_dev->fade_step; int i;
- if (!aw_dev->fade_en) - return; - if (fade_step == 0 || aw_dev->fade_out_time == 0) { aw_dev_set_volume(aw_dev, AW88395_MUTE_VOL); return; @@ -1062,10 +1056,6 @@ static int aw_dev_update_reg_container(struct aw_device *aw_dev, aw_dev_set_volume(aw_dev, vol_desc->ctl_volume); }
- /* keep min volume */ - if (aw_dev->fade_en) - aw_dev_set_volume(aw_dev, AW88395_MUTE_VOL); - aw_dev_get_dsp_config(aw_dev, &aw_dev->dsp_cfg);
return ret; @@ -1594,37 +1584,19 @@ static void aw88395_parse_channel_dt(struct aw_device *aw_dev) u32 channel_value; int ret;
- ret = of_property_read_u32(np, "sound-channel", &channel_value); + ret = of_property_read_u32(np, "awinic,audio-channel", &channel_value); if (ret) { dev_dbg(aw_dev->dev, - "read sound-channel failed,use default 0"); + "read audio-channel failed,use default 0"); aw_dev->channel = AW88395_DEV_DEFAULT_CH; return; }
- dev_dbg(aw_dev->dev, "read sound-channel value is: %d", + dev_dbg(aw_dev->dev, "read audio-channel value is: %d", channel_value); aw_dev->channel = channel_value; }
-static void aw88395_parse_fade_enable_dt(struct aw_device *aw_dev) -{ - struct device_node *np = aw_dev->dev->of_node; - u32 fade_en; - int ret; - - ret = of_property_read_u32(np, "fade-enable", &fade_en); - if (ret) { - dev_dbg(aw_dev->dev, - "read fade-enable failed, close fade_in_out"); - fade_en = AW88395_FADE_IN_OUT_DEFAULT; - } - - dev_dbg(aw_dev->dev, "read fade-enable value is: %d", fade_en); - - aw_dev->fade_en = fade_en; -} - static int aw_dev_init(struct aw_device *aw_dev) { aw_dev->chip_id = AW88395_CHIP_ID; @@ -1639,7 +1611,6 @@ static int aw_dev_init(struct aw_device *aw_dev) aw_dev->fade_step = AW88395_VOLUME_STEP_DB; aw_dev->volume_desc.ctl_volume = AW88395_VOL_DEFAULT_VALUE; aw88395_parse_channel_dt(aw_dev); - aw88395_parse_fade_enable_dt(aw_dev);
return 0; } diff --git a/sound/soc/codecs/aw88395/aw88395_device.h b/sound/soc/codecs/aw88395/aw88395_device.h index caf730753167..d32d16c89509 100644 --- a/sound/soc/codecs/aw88395/aw88395_device.h +++ b/sound/soc/codecs/aw88395/aw88395_device.h @@ -141,6 +141,7 @@ struct aw_device { unsigned char prof_cur; unsigned char prof_index; unsigned char dsp_crc_st; + unsigned char dsp_cfg; u16 chip_id;
unsigned int channel; @@ -151,9 +152,6 @@ struct aw_device { struct regmap *regmap; char *acf;
- u32 fade_en; - unsigned char dsp_cfg; - u32 dsp_fw_len; u32 dsp_cfg_len; u8 platform;
On Wed, Sep 27, 2023 at 08:16:29PM +0800, wangweidong.a@awinic.com wrote:
From: Weidong Wang wangweidong.a@awinic.com
Remove the "fade-enable" property because other properties already implement this functionality. Rename "sound-channel" to "awinic,audio-channel", this is to be consistent with the "awinic,aw88395.yaml" file
This feels like it should be split into two patches.
patch 4/9: remove the "fade-enable property". Btw, which other properties implement this. Can you add that to the commit message?
patch 5/9: Rename "sound-channel" to "awinic,audio-channel".
regards, dan carpenter
From: Weidong Wang wangweidong.a@awinic.com
Change the transmission mode of the "aw88395_dev_get_prof_name" function parameter and change the name of the i2c driver, this is to be consistent with the "awinic,aw88395.yaml" file
Signed-off-by: Weidong Wang wangweidong.a@awinic.com --- sound/soc/codecs/aw88395/aw88395.c | 9 ++++----- sound/soc/codecs/aw88395/aw88395.h | 2 +- sound/soc/codecs/aw88395/aw88395_device.c | 12 ++++++++---- sound/soc/codecs/aw88395/aw88395_device.h | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c index 9dcd75dd799a..77227c8f01f6 100644 --- a/sound/soc/codecs/aw88395/aw88395.c +++ b/sound/soc/codecs/aw88395/aw88395.c @@ -175,9 +175,8 @@ static int aw88395_profile_info(struct snd_kcontrol *kcontrol, { struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec); - const char *prof_name; - char *name; - int count; + char *prof_name, *name; + int count, ret;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -196,8 +195,8 @@ static int aw88395_profile_info(struct snd_kcontrol *kcontrol, name = uinfo->value.enumerated.name; count = uinfo->value.enumerated.item;
- prof_name = aw88395_dev_get_prof_name(aw88395->aw_pa, count); - if (!prof_name) { + ret = aw88395_dev_get_prof_name(aw88395->aw_pa, count, &prof_name); + if (ret) { strscpy(uinfo->value.enumerated.name, "null", strlen("null") + 1); return 0; diff --git a/sound/soc/codecs/aw88395/aw88395.h b/sound/soc/codecs/aw88395/aw88395.h index 8036ba27f68d..c2a4f0cb8cd5 100644 --- a/sound/soc/codecs/aw88395/aw88395.h +++ b/sound/soc/codecs/aw88395/aw88395.h @@ -16,7 +16,7 @@
#define AW88395_DSP_16_DATA_MASK (0x0000ffff)
-#define AW88395_I2C_NAME "aw88395_smartpa" +#define AW88395_I2C_NAME "aw88395"
#define AW88395_RATES (SNDRV_PCM_RATE_8000_48000 | \ SNDRV_PCM_RATE_96000) diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c index 5ca4172cb788..fd1f67d5f22f 100644 --- a/sound/soc/codecs/aw88395/aw88395_device.c +++ b/sound/soc/codecs/aw88395/aw88395_device.c @@ -1296,7 +1296,9 @@ int aw88395_dev_fw_update(struct aw_device *aw_dev, bool up_dsp_fw_en, bool forc return -EPERM; }
- prof_name = aw88395_dev_get_prof_name(aw_dev, aw_dev->prof_index); + ret = aw88395_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); + if (ret) + return ret;
dev_dbg(aw_dev->dev, "start update %s", prof_name);
@@ -1644,7 +1646,7 @@ int aw88395_dev_set_profile_index(struct aw_device *aw_dev, int index) } EXPORT_SYMBOL_GPL(aw88395_dev_set_profile_index);
-char *aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index) +int aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) { struct aw_prof_info *prof_info = &aw_dev->prof_info; struct aw_prof_desc *prof_desc; @@ -1652,12 +1654,14 @@ char *aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index) if ((index >= aw_dev->prof_info.count) || (index < 0)) { dev_err(aw_dev->dev, "index[%d] overflow count[%d]", index, aw_dev->prof_info.count); - return NULL; + return -EINVAL; }
prof_desc = &aw_dev->prof_info.prof_desc[index];
- return prof_info->prof_name_list[prof_desc->id]; + *prof_name = prof_info->prof_name_list[prof_desc->id]; + + return 0; } EXPORT_SYMBOL_GPL(aw88395_dev_get_prof_name);
diff --git a/sound/soc/codecs/aw88395/aw88395_device.h b/sound/soc/codecs/aw88395/aw88395_device.h index d32d16c89509..791c8c106557 100644 --- a/sound/soc/codecs/aw88395/aw88395_device.h +++ b/sound/soc/codecs/aw88395/aw88395_device.h @@ -181,7 +181,7 @@ int aw88395_dev_fw_update(struct aw_device *aw_dev, bool up_dsp_fw_en, bool forc void aw88395_dev_set_volume(struct aw_device *aw_dev, unsigned short set_vol); int aw88395_dev_get_prof_data(struct aw_device *aw_dev, int index, struct aw_prof_desc **prof_desc); -char *aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index); +int aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name); int aw88395_dev_set_profile_index(struct aw_device *aw_dev, int index); int aw88395_dev_get_profile_index(struct aw_device *aw_dev); int aw88395_dev_get_profile_count(struct aw_device *aw_dev);
From: Weidong Wang wangweidong.a@awinic.com
Add aw87390 compatible code to the aw88395_lib.c file so that it can parse aw87390's bin file Modify the function return value
Signed-off-by: Weidong Wang wangweidong.a@awinic.com --- sound/soc/codecs/aw88395/aw88395_lib.c | 25 +++++++++++++++---------- sound/soc/codecs/aw88395/aw88395_reg.h | 1 + 2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c index 87dd0ccade4c..a0a429ca9768 100644 --- a/sound/soc/codecs/aw88395/aw88395_lib.c +++ b/sound/soc/codecs/aw88395/aw88395_lib.c @@ -456,10 +456,12 @@ static int aw_dev_parse_reg_bin_with_hdr(struct aw_device *aw_dev, goto parse_bin_failed; }
- if (aw_bin->header_info[0].valid_data_len % 4) { - dev_err(aw_dev->dev, "bin data len get error!"); - ret = -EINVAL; - goto parse_bin_failed; + if (aw_dev->chip_id == AW88261_CHIP_ID) { + if (aw_bin->header_info[0].valid_data_len % 4) { + dev_err(aw_dev->dev, "bin data len get error!"); + ret = -EINVAL; + goto parse_bin_failed; + } }
prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data = @@ -581,9 +583,9 @@ static int aw_dev_parse_dev_default_type(struct aw_device *aw_dev, }
static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev, - struct aw_all_prof_info all_prof_info) + struct aw_all_prof_info *all_prof_info) { - struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; + struct aw_prof_desc *prof_desc = all_prof_info->prof_desc; struct aw_prof_info *prof_info = &aw_dev->prof_info; int num = 0; int i; @@ -623,9 +625,9 @@ static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev, }
static int aw88395_dev_cfg_get_valid_prof(struct aw_device *aw_dev, - struct aw_all_prof_info all_prof_info) + struct aw_all_prof_info *all_prof_info) { - struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; + struct aw_prof_desc *prof_desc = all_prof_info->prof_desc; struct aw_prof_info *prof_info = &aw_dev->prof_info; struct aw_sec_data_desc *sec_desc; int num = 0; @@ -703,12 +705,13 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev,
switch (aw_dev->chip_id) { case AW88395_CHIP_ID: - ret = aw88395_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); + ret = aw88395_dev_cfg_get_valid_prof(aw_dev, all_prof_info); if (ret < 0) goto exit; break; case AW88261_CHIP_ID: - ret = aw88261_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); + case AW87390_CHIP_ID: + ret = aw88261_dev_cfg_get_valid_prof(aw_dev, all_prof_info); if (ret < 0) goto exit; break; @@ -801,6 +804,7 @@ static int aw_get_dev_scene_count_v1(struct aw_device *aw_dev, struct aw_contain ret = 0; break; case AW88261_CHIP_ID: + case AW87390_CHIP_ID: for (i = 0; i < cfg_hdr->ddt_num; ++i) { if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && @@ -841,6 +845,7 @@ static int aw_get_default_scene_count_v1(struct aw_device *aw_dev, ret = 0; break; case AW88261_CHIP_ID: + case AW87390_CHIP_ID: for (i = 0; i < cfg_hdr->ddt_num; ++i) { if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && diff --git a/sound/soc/codecs/aw88395/aw88395_reg.h b/sound/soc/codecs/aw88395/aw88395_reg.h index e7a7c02efaf3..d0a273387313 100644 --- a/sound/soc/codecs/aw88395/aw88395_reg.h +++ b/sound/soc/codecs/aw88395/aw88395_reg.h @@ -97,6 +97,7 @@ enum aw88395_id { AW88395_CHIP_ID = 0x2049, AW88261_CHIP_ID = 0x2113, + AW87390_CHIP_ID = 0x76, };
#define AW88395_REG_MAX (0x7D)
From: Weidong Wang wangweidong.a@awinic.com
Change "sound-channel" to "awinic,audio-channel". Change "aw88261_smartpa" to "aw88261". Change "sync-flag" to "awinic,sync-flag". These changes are made to align with yaml files.
Signed-off-by: Weidong Wang wangweidong.a@awinic.com --- sound/soc/codecs/aw88261.c | 6 ++---- sound/soc/codecs/aw88261.h | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c index a697b5006b45..61179e235fbf 100644 --- a/sound/soc/codecs/aw88261.c +++ b/sound/soc/codecs/aw88261.c @@ -1187,13 +1187,11 @@ static void aw88261_parse_channel_dt(struct aw88261 *aw88261) struct aw_device *aw_dev = aw88261->aw_pa; struct device_node *np = aw_dev->dev->of_node; u32 channel_value = AW88261_DEV_DEFAULT_CH; - u32 sync_enable = false;
- of_property_read_u32(np, "sound-channel", &channel_value); - of_property_read_u32(np, "sync-flag", &sync_enable); + of_property_read_u32(np, "awinic,audio-channel", &channel_value); + aw88261->phase_sync = of_property_read_bool(np, "awinic,sync-flag");
aw_dev->channel = channel_value; - aw88261->phase_sync = sync_enable; }
static int aw88261_init(struct aw88261 **aw88261, struct i2c_client *i2c, struct regmap *regmap) diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h index 4f3dbf438510..734d0f93ced9 100644 --- a/sound/soc/codecs/aw88261.h +++ b/sound/soc/codecs/aw88261.h @@ -370,7 +370,7 @@ #define AW88261_START_RETRIES (5) #define AW88261_START_WORK_DELAY_MS (0)
-#define AW88261_I2C_NAME "aw88261_smartpa" +#define AW88261_I2C_NAME "aw88261"
#define AW88261_RATES (SNDRV_PCM_RATE_8000_48000 | \ SNDRV_PCM_RATE_96000) @@ -453,7 +453,7 @@ struct aw88261 { unsigned int mute_st; unsigned int amppd_st;
- unsigned char phase_sync; + bool phase_sync; };
#endif
On Wed, Sep 27, 2023 at 08:16:32PM +0800, wangweidong.a@awinic.com wrote:
From: Weidong Wang wangweidong.a@awinic.com
Change "sound-channel" to "awinic,audio-channel".
I'm not super happy that we are doing part of the sound-channel rename as part of this patch instead of all at once in the same patch.
Change "aw88261_smartpa" to "aw88261". Change "sync-flag" to "awinic,sync-flag". These changes are made to align with yaml files.
Signed-off-by: Weidong Wang wangweidong.a@awinic.com
regards, dan carpenter
From: Weidong Wang wangweidong.a@awinic.com
Change the transmission mode of the "aw88261_dev_get_prof_name" function parameter
Signed-off-by: Weidong Wang wangweidong.a@awinic.com --- sound/soc/codecs/aw88261.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c index 61179e235fbf..45eaf931a69c 100644 --- a/sound/soc/codecs/aw88261.c +++ b/sound/soc/codecs/aw88261.c @@ -477,7 +477,7 @@ static int aw88261_dev_reg_update(struct aw88261 *aw88261, return ret; }
-static char *aw88261_dev_get_prof_name(struct aw_device *aw_dev, int index) +static int aw88261_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) { struct aw_prof_info *prof_info = &aw_dev->prof_info; struct aw_prof_desc *prof_desc; @@ -485,12 +485,14 @@ static char *aw88261_dev_get_prof_name(struct aw_device *aw_dev, int index) if ((index >= aw_dev->prof_info.count) || (index < 0)) { dev_err(aw_dev->dev, "index[%d] overflow count[%d]", index, aw_dev->prof_info.count); - return NULL; + return -EINVAL; }
prof_desc = &aw_dev->prof_info.prof_desc[index];
- return prof_info->prof_name_list[prof_desc->id]; + *prof_name = prof_info->prof_name_list[prof_desc->id]; + + return 0; }
static int aw88261_dev_get_prof_data(struct aw_device *aw_dev, int index, @@ -515,8 +517,8 @@ static int aw88261_dev_fw_update(struct aw88261 *aw88261) char *prof_name; int ret;
- prof_name = aw88261_dev_get_prof_name(aw_dev, aw_dev->prof_index); - if (!prof_name) { + ret = aw88261_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); + if (ret) { dev_err(aw_dev->dev, "get prof name failed"); return -EINVAL; } @@ -818,9 +820,8 @@ static int aw88261_profile_info(struct snd_kcontrol *kcontrol, { struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); - const char *prof_name; - char *name; - int count; + char *prof_name, *name; + int count, ret;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -839,8 +840,8 @@ static int aw88261_profile_info(struct snd_kcontrol *kcontrol, name = uinfo->value.enumerated.name; count = uinfo->value.enumerated.item;
- prof_name = aw88261_dev_get_prof_name(aw88261->aw_pa, count); - if (!prof_name) { + ret = aw88261_dev_get_prof_name(aw88261->aw_pa, count, &prof_name); + if (ret) { strscpy(uinfo->value.enumerated.name, "null", strlen("null") + 1); return 0;
From: Weidong Wang wangweidong.a@awinic.com
Add i2c and amplifier registration for aw87390 and their associated operation functions.
Signed-off-by: Weidong Wang wangweidong.a@awinic.com --- sound/soc/codecs/Kconfig | 15 +- sound/soc/codecs/Makefile | 2 + sound/soc/codecs/aw87390.c | 462 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/aw87390.h | 85 +++++++ 4 files changed, 562 insertions(+), 2 deletions(-) create mode 100644 sound/soc/codecs/aw87390.c create mode 100644 sound/soc/codecs/aw87390.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f1e1dbc509f6..8c101919259f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -54,6 +54,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_ALC5632 imply SND_SOC_AUDIO_IIO_AUX imply SND_SOC_AW8738 + imply SND_SOC_AW87390 imply SND_SOC_AW88395 imply SND_SOC_AW88261 imply SND_SOC_BT_SCO @@ -638,12 +639,12 @@ config SND_SOC_AW8738 operation mode using the Awinic-specific one-wire pulse control.
config SND_SOC_AW88395_LIB + select CRC8 tristate
config SND_SOC_AW88395 tristate "Soc Audio for awinic aw88395" depends on I2C - select CRC8 select CRC32 select REGMAP_I2C select GPIOLIB @@ -657,7 +658,6 @@ config SND_SOC_AW88395 config SND_SOC_AW88261 tristate "Soc Audio for awinic aw88261" depends on I2C - select CRC8 select REGMAP_I2C select GPIOLIB select SND_SOC_AW88395_LIB @@ -668,6 +668,17 @@ config SND_SOC_AW88261 boost converter can be adjusted smartly according to the input amplitude.
+config SND_SOC_AW87390 + tristate "Soc Audio for awinic aw87390" + depends on I2C + select REGMAP_I2C + select SND_SOC_AW88395_LIB + help + The awinic aw87390 is specifically designed to improve + the musical output dynamic range, enhance the overall + sound quallity, which is a new high efficiency, low + noise, constant large volume, 6th Smart K audio amplifier. + config SND_SOC_BD28623 tristate "ROHM BD28623 CODEC" help diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index a87e56938ce5..60df97b67c01 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -47,6 +47,7 @@ snd-soc-ak5558-objs := ak5558.o snd-soc-arizona-objs := arizona.o arizona-jack.o snd-soc-audio-iio-aux-objs := audio-iio-aux.o snd-soc-aw8738-objs := aw8738.o +snd-soc-aw87390-objs := aw87390.o snd-soc-aw88395-lib-objs := aw88395/aw88395_lib.o snd-soc-aw88395-objs := aw88395/aw88395.o \ aw88395/aw88395_device.o @@ -434,6 +435,7 @@ obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o obj-$(CONFIG_SND_SOC_AUDIO_IIO_AUX) += snd-soc-audio-iio-aux.o obj-$(CONFIG_SND_SOC_AW8738) += snd-soc-aw8738.o +obj-$(CONFIG_SND_SOC_AW87390) += snd-soc-aw87390.o obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c new file mode 100644 index 000000000000..8efae3b73eea --- /dev/null +++ b/sound/soc/codecs/aw87390.c @@ -0,0 +1,462 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw87390.c -- AW87390 ALSA SoC Audio driver +// +// Copyright (c) 2023 awinic Technology CO., LTD +// +// Author: Weidong Wang wangweidong.a@awinic.com +// + +#include <linux/i2c.h> +#include <linux/firmware.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include "aw87390.h" +#include "aw88395/aw88395_data_type.h" +#include "aw88395/aw88395_device.h" + +static const struct regmap_config aw87390_remap_config = { + .val_bits = 8, + .reg_bits = 8, + .max_register = AW87390_REG_MAX, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static int aw87390_dev_reg_update(struct aw_device *aw_dev, + unsigned char *data, unsigned int len) +{ + int i, ret; + + if (!data) { + dev_err(aw_dev->dev, "data is NULL\n"); + return -EINVAL; + } + + for (i = 0; i < len; i = i + 2) { + if (data[i] == AW87390_DELAY_REG_ADDR) { + usleep_range(data[i + 1] * AW87390_REG_DELAY_TIME, + data[i + 1] * AW87390_REG_DELAY_TIME + 10); + continue; + } + ret = regmap_write(aw_dev->regmap, data[i], data[i + 1]); + if (ret) + return ret; + } + + return 0; +} + +static int aw87390_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_prof_desc *prof_desc; + + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "index[%d] overflow count[%d]\n", + index, aw_dev->prof_info.count); + return -EINVAL; + } + + prof_desc = &aw_dev->prof_info.prof_desc[index]; + + *prof_name = prof_info->prof_name_list[prof_desc->id]; + + return 0; +} + +static int aw87390_dev_get_prof_data(struct aw_device *aw_dev, int index, + struct aw_prof_desc **prof_desc) +{ + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", + __func__, index, aw_dev->prof_info.count); + return -EINVAL; + } + + *prof_desc = &aw_dev->prof_info.prof_desc[index]; + + return 0; +} + +static int aw87390_dev_fw_update(struct aw_device *aw_dev) +{ + struct aw_prof_desc *prof_index_desc; + struct aw_sec_data_desc *sec_desc; + char *prof_name; + int ret; + + ret = aw87390_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); + if (ret) { + dev_err(aw_dev->dev, "get prof name failed\n"); + return -EINVAL; + } + + dev_dbg(aw_dev->dev, "start update %s", prof_name); + + ret = aw87390_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); + if (ret) { + dev_err(aw_dev->dev, "aw87390_dev_get_prof_data failed\n"); + return ret; + } + + /* update reg */ + sec_desc = prof_index_desc->sec_desc; + ret = aw87390_dev_reg_update(aw_dev, sec_desc[AW88395_DATA_TYPE_REG].data, + sec_desc[AW88395_DATA_TYPE_REG].len); + if (ret) { + dev_err(aw_dev->dev, "update reg failed\n"); + return ret; + } + + aw_dev->prof_cur = aw_dev->prof_index; + + return ret; +} + +static int aw87390_power_off(struct aw_device *aw_dev) +{ + int ret; + + if (aw_dev->status == AW87390_DEV_PW_OFF) { + dev_info(aw_dev->dev, "already power off\n"); + return 0; + } + + ret = regmap_write(aw_dev->regmap, AW87390_SYSCTRL_REG, AW87390_POWER_DOWN_VALUE); + if (ret) + return ret; + aw_dev->status = AW87390_DEV_PW_OFF; + + return ret; +} + +static int aw87390_power_on(struct aw_device *aw_dev) +{ + int ret; + + if (aw_dev->status == AW87390_DEV_PW_ON) { + dev_info(aw_dev->dev, "already power on\n"); + return 0; + } + + if (!aw_dev->fw_status) { + dev_err(aw_dev->dev, "fw not load\n"); + return -EINVAL; + } + + ret = regmap_write(aw_dev->regmap, AW87390_SYSCTRL_REG, AW87390_POWER_DOWN_VALUE); + if (ret) + return ret; + + ret = aw87390_dev_fw_update(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "%s load profile failed\n", __func__); + return ret; + } + aw_dev->status = AW87390_DEV_PW_ON; + + return ret; +} + +static int aw87390_dev_set_profile_index(struct aw_device *aw_dev, int index) +{ + if ((index >= aw_dev->prof_info.count) || (index < 0)) + return -EINVAL; + + if (aw_dev->prof_index == index) + return -EPERM; + + aw_dev->prof_index = index; + + return 0; +} + +static int aw87390_profile_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec); + char *prof_name, *name; + int count, ret; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + count = aw87390->aw_pa->prof_info.count; + if (count <= 0) { + uinfo->value.enumerated.items = 0; + return 0; + } + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + name = uinfo->value.enumerated.name; + count = uinfo->value.enumerated.item; + + ret = aw87390_dev_get_prof_name(aw87390->aw_pa, count, &prof_name); + if (ret) { + strscpy(uinfo->value.enumerated.name, "null", + strlen("null") + 1); + return 0; + } + + strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name)); + + return 0; +} + +static int aw87390_profile_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw87390->aw_pa->prof_index; + + return 0; +} + +static int aw87390_profile_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec); + int ret; + + mutex_lock(&aw87390->lock); + ret = aw87390_dev_set_profile_index(aw87390->aw_pa, ucontrol->value.integer.value[0]); + if (ret) { + dev_dbg(codec->dev, "profile index does not change\n"); + mutex_unlock(&aw87390->lock); + return 0; + } + + if (aw87390->aw_pa->status == AW87390_DEV_PW_ON) { + aw87390_power_off(aw87390->aw_pa); + aw87390_power_on(aw87390->aw_pa); + } + + mutex_unlock(&aw87390->lock); + + return 1; +} + +static const struct snd_kcontrol_new aw87390_controls[] = { + AW87390_PROFILE_EXT("AW87390 Profile Set", aw87390_profile_info, + aw87390_profile_get, aw87390_profile_set), +}; + +static int aw87390_request_firmware_file(struct aw87390 *aw87390) +{ + const struct firmware *cont = NULL; + int ret; + + aw87390->aw_pa->fw_status = AW87390_DEV_FW_FAILED; + + ret = request_firmware(&cont, AW87390_ACF_FILE, aw87390->aw_pa->dev); + if (ret) + return dev_err_probe(aw87390->aw_pa->dev, ret, + "load [%s] failed!\n", AW87390_ACF_FILE); + + dev_dbg(aw87390->aw_pa->dev, "loaded %s - size: %zu\n", + AW87390_ACF_FILE, cont ? cont->size : 0); + + aw87390->aw_cfg = devm_kzalloc(aw87390->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL); + if (!aw87390->aw_cfg) { + release_firmware(cont); + return -ENOMEM; + } + + aw87390->aw_cfg->len = (int)cont->size; + memcpy(aw87390->aw_cfg->data, cont->data, cont->size); + release_firmware(cont); + + ret = aw88395_dev_load_acf_check(aw87390->aw_pa, aw87390->aw_cfg); + if (ret) { + dev_err(aw87390->aw_pa->dev, "load [%s] failed !\n", AW87390_ACF_FILE); + return ret; + } + + mutex_lock(&aw87390->lock); + + ret = aw88395_dev_cfg_load(aw87390->aw_pa, aw87390->aw_cfg); + if (ret) + dev_err(aw87390->aw_pa->dev, "aw_dev acf parse failed\n"); + + mutex_unlock(&aw87390->lock); + + return ret; +} + +static int aw87390_drv_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct aw87390 *aw87390 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw87390->aw_pa; + int ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = aw87390_power_on(aw_dev); + break; + case SND_SOC_DAPM_POST_PMD: + ret = aw87390_power_off(aw_dev); + break; + default: + dev_err(aw_dev->dev, "%s: invalid event %d\n", __func__, event); + ret = -EINVAL; + } + + return ret; +} + +static const struct snd_soc_dapm_widget aw87390_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("IN"), + SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM, 0, 0, NULL, 0, aw87390_drv_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUTPUT("OUT"), +}; + +static const struct snd_soc_dapm_route aw87390_dapm_routes[] = { + { "SPK PA", NULL, "IN" }, + { "OUT", NULL, "SPK PA" }, +}; + +static int aw87390_codec_probe(struct snd_soc_component *component) +{ + struct aw87390 *aw87390 = snd_soc_component_get_drvdata(component); + int ret; + + ret = aw87390_request_firmware_file(aw87390); + if (ret) + return dev_err_probe(aw87390->aw_pa->dev, ret, + "aw87390_request_firmware_file failed\n"); + + return 0; +} + +static const struct snd_soc_component_driver soc_codec_dev_aw87390 = { + .probe = aw87390_codec_probe, + .dapm_widgets = aw87390_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aw87390_dapm_widgets), + .dapm_routes = aw87390_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(aw87390_dapm_routes), + .controls = aw87390_controls, + .num_controls = ARRAY_SIZE(aw87390_controls), +}; + +static void aw87390_parse_channel_dt(struct aw87390 *aw87390) +{ + struct aw_device *aw_dev = aw87390->aw_pa; + struct device_node *np = aw_dev->dev->of_node; + u32 channel_value = AW87390_DEV_DEFAULT_CH; + + of_property_read_u32(np, "awinic,audio-channel", &channel_value); + + aw_dev->channel = channel_value; +} + +static int aw87390_init(struct aw87390 **aw87390, struct i2c_client *i2c, struct regmap *regmap) +{ + struct aw_device *aw_dev; + unsigned int chip_id; + int ret; + + /* read chip id */ + ret = regmap_read(regmap, AW87390_ID_REG, &chip_id); + if (ret) { + dev_err(&i2c->dev, "%s read chipid error. ret = %d\n", __func__, ret); + return ret; + } + + if (chip_id != AW87390_CHIP_ID) { + dev_err(&i2c->dev, "unsupported device\n"); + return -ENXIO; + } + + dev_info(&i2c->dev, "chip id = 0x%x\n", chip_id); + + aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); + if (!aw_dev) + return -ENOMEM; + + (*aw87390)->aw_pa = aw_dev; + aw_dev->i2c = i2c; + aw_dev->regmap = regmap; + aw_dev->dev = &i2c->dev; + aw_dev->chip_id = AW87390_CHIP_ID; + aw_dev->acf = NULL; + aw_dev->prof_info.prof_desc = NULL; + aw_dev->prof_info.count = 0; + aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; + aw_dev->channel = AW87390_DEV_DEFAULT_CH; + aw_dev->fw_status = AW87390_DEV_FW_FAILED; + aw_dev->prof_index = AW87390_INIT_PROFILE; + aw_dev->status = AW87390_DEV_PW_OFF; + + aw87390_parse_channel_dt(*aw87390); + + return ret; +} + +static int aw87390_i2c_probe(struct i2c_client *i2c) +{ + struct aw87390 *aw87390; + int ret; + + ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C); + if (!ret) + return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed\n"); + + aw87390 = devm_kzalloc(&i2c->dev, sizeof(*aw87390), GFP_KERNEL); + if (!aw87390) + return -ENOMEM; + + mutex_init(&aw87390->lock); + + i2c_set_clientdata(i2c, aw87390); + + aw87390->regmap = devm_regmap_init_i2c(i2c, &aw87390_remap_config); + if (IS_ERR(aw87390->regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(aw87390->regmap), + "failed to init regmap\n"); + + /* aw pa init */ + ret = aw87390_init(&aw87390, i2c, aw87390->regmap); + if (ret) + return ret; + + ret = regmap_write(aw87390->regmap, AW87390_ID_REG, AW87390_SOFT_RESET_VALUE); + if (ret) + return ret; + + ret = devm_snd_soc_register_component(&i2c->dev, + &soc_codec_dev_aw87390, NULL, 0); + if (ret) + dev_err(&i2c->dev, "failed to register aw87390: %d\n", ret); + + return ret; +} + +static const struct i2c_device_id aw87390_i2c_id[] = { + { AW87390_I2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw87390_i2c_id); + +static struct i2c_driver aw87390_i2c_driver = { + .driver = { + .name = AW87390_I2C_NAME, + }, + .probe = aw87390_i2c_probe, + .id_table = aw87390_i2c_id, +}; +module_i2c_driver(aw87390_i2c_driver); + +MODULE_DESCRIPTION("ASoC AW87390 PA Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/aw87390.h b/sound/soc/codecs/aw87390.h new file mode 100644 index 000000000000..54c268c18e72 --- /dev/null +++ b/sound/soc/codecs/aw87390.h @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw87390.h -- aw87390 ALSA SoC Audio driver +// +// Copyright (c) 2023 awinic Technology CO., LTD +// +// Author: Weidong Wang wangweidong.a@awinic.com +// + +#ifndef __AW87390_H__ +#define __AW87390_H__ + +#define AW87390_ID_REG (0x00) +#define AW87390_SYSCTRL_REG (0x01) +#define AW87390_MDCTRL_REG (0x02) +#define AW87390_CPOVP_REG (0x03) +#define AW87390_CPP_REG (0x04) +#define AW87390_PAG_REG (0x05) +#define AW87390_AGC3P_REG (0x06) +#define AW87390_AGC3PA_REG (0x07) +#define AW87390_AGC2P_REG (0x08) +#define AW87390_AGC2PA_REG (0x09) +#define AW87390_AGC1PA_REG (0x0A) +#define AW87390_SYSST_REG (0x59) +#define AW87390_SYSINT_REG (0x60) +#define AW87390_DFT_SYSCTRL_REG (0x61) +#define AW87390_DFT_MDCTRL_REG (0x62) +#define AW87390_DFT_CPADP_REG (0x63) +#define AW87390_DFT_AGCPA_REG (0x64) +#define AW87390_DFT_POFR_REG (0x65) +#define AW87390_DFT_OC_REG (0x66) +#define AW87390_DFT_ADP1_REG (0x67) +#define AW87390_DFT_REF_REG (0x68) +#define AW87390_DFT_LDO_REG (0x69) +#define AW87390_ADP1_REG (0x70) +#define AW87390_ADP2_REG (0x71) +#define AW87390_NG1_REG (0x72) +#define AW87390_NG2_REG (0x73) +#define AW87390_NG3_REG (0x74) +#define AW87390_CP_REG (0x75) +#define AW87390_AB_REG (0x76) +#define AW87390_TEST_REG (0x77) +#define AW87390_ENCR_REG (0x78) +#define AW87390_DELAY_REG_ADDR (0xFE) + +#define AW87390_SOFT_RESET_VALUE (0xAA) +#define AW87390_POWER_DOWN_VALUE (0x00) +#define AW87390_REG_MAX (0xFF) +#define AW87390_DEV_DEFAULT_CH (0) +#define AW87390_INIT_PROFILE (0) +#define AW87390_REG_DELAY_TIME (1000) +#define AW87390_I2C_NAME "aw87390" +#define AW87390_ACF_FILE "aw87390_acf.bin" + +#define AW87390_PROFILE_EXT(xname, profile_info, profile_get, profile_set) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = profile_info, \ + .get = profile_get, \ + .put = profile_set, \ +} + +enum aw87390_id { + AW87390_CHIP_ID = 0x76, +}; + +enum { + AW87390_DEV_FW_FAILED = 0, + AW87390_DEV_FW_OK, +}; + +enum { + AW87390_DEV_PW_OFF = 0, + AW87390_DEV_PW_ON, +}; + +struct aw87390 { + struct aw_device *aw_pa; + struct mutex lock; + struct regmap *regmap; + struct aw_container *aw_cfg; +}; + +#endif
I just had a few nits. Sorry to complain about such minor things in a v5 patch.
On Wed, Sep 27, 2023 at 08:16:34PM +0800, wangweidong.a@awinic.com wrote:
@@ -668,6 +668,17 @@ config SND_SOC_AW88261 boost converter can be adjusted smartly according to the input amplitude.
+config SND_SOC_AW87390
- tristate "Soc Audio for awinic aw87390"
Capitalize A in Awinic.
- depends on I2C
- select REGMAP_I2C
- select SND_SOC_AW88395_LIB
- help
The awinic aw87390 is specifically designed to improve
the musical output dynamic range, enhance the overall
sound quallity, which is a new high efficiency, low
s/quallity/quality/.
noise, constant large volume, 6th Smart K audio amplifier.
config SND_SOC_BD28623 tristate "ROHM BD28623 CODEC" help
[ snip ]
diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c new file mode 100644 index 000000000000..8efae3b73eea --- /dev/null +++ b/sound/soc/codecs/aw87390.c @@ -0,0 +1,462 @@ +// SPDX-License-Identifier: GPL-2.0-only
Checkpatch complains about this. It should just be GPL-2.0, the "only" is assumed unless there is a + as in "GPL-2.0+". You might want to run scripts/checkpatch.pl --strict on your patch.
+// +// aw87390.c -- AW87390 ALSA SoC Audio driver +// +// Copyright (c) 2023 awinic Technology CO., LTD +// +// Author: Weidong Wang wangweidong.a@awinic.com +//
+#include <linux/i2c.h> +#include <linux/firmware.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include "aw87390.h" +#include "aw88395/aw88395_data_type.h" +#include "aw88395/aw88395_device.h"
+static const struct regmap_config aw87390_remap_config = {
- .val_bits = 8,
- .reg_bits = 8,
- .max_register = AW87390_REG_MAX,
- .reg_format_endian = REGMAP_ENDIAN_LITTLE,
- .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+static int aw87390_dev_reg_update(struct aw_device *aw_dev,
unsigned char *data, unsigned int len)
+{
- int i, ret;
- if (!data) {
dev_err(aw_dev->dev, "data is NULL\n");
return -EINVAL;
- }
- for (i = 0; i < len; i = i + 2) {
if (data[i] == AW87390_DELAY_REG_ADDR) {
usleep_range(data[i + 1] * AW87390_REG_DELAY_TIME,
data[i + 1] * AW87390_REG_DELAY_TIME + 10);
continue;
}
ret = regmap_write(aw_dev->regmap, data[i], data[i + 1]);
This assumes that len is an even number... Maybe write it as:
for (i = 0; i < len - 1; i += 2) {
Although that assumes len can't be zero so maybe it's not a win...
if (ret)
return ret;
- }
- return 0;
+}
+static int aw87390_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) +{
- struct aw_prof_info *prof_info = &aw_dev->prof_info;
- struct aw_prof_desc *prof_desc;
- if ((index >= aw_dev->prof_info.count) || (index < 0)) {
dev_err(aw_dev->dev, "index[%d] overflow count[%d]\n",
index, aw_dev->prof_info.count);
return -EINVAL;
- }
- prof_desc = &aw_dev->prof_info.prof_desc[index];
- *prof_name = prof_info->prof_name_list[prof_desc->id];
- return 0;
+}
+static int aw87390_dev_get_prof_data(struct aw_device *aw_dev, int index,
struct aw_prof_desc **prof_desc)
+{
- if ((index >= aw_dev->prof_info.count) || (index < 0)) {
dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n",
__func__, index, aw_dev->prof_info.count);
return -EINVAL;
- }
- *prof_desc = &aw_dev->prof_info.prof_desc[index];
- return 0;
+}
+static int aw87390_dev_fw_update(struct aw_device *aw_dev) +{
- struct aw_prof_desc *prof_index_desc;
- struct aw_sec_data_desc *sec_desc;
- char *prof_name;
- int ret;
- ret = aw87390_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
- if (ret) {
dev_err(aw_dev->dev, "get prof name failed\n");
return -EINVAL;
- }
- dev_dbg(aw_dev->dev, "start update %s", prof_name);
- ret = aw87390_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc);
- if (ret) {
dev_err(aw_dev->dev, "aw87390_dev_get_prof_data failed\n");
return ret;
- }
- /* update reg */
- sec_desc = prof_index_desc->sec_desc;
- ret = aw87390_dev_reg_update(aw_dev, sec_desc[AW88395_DATA_TYPE_REG].data,
sec_desc[AW88395_DATA_TYPE_REG].len);
- if (ret) {
dev_err(aw_dev->dev, "update reg failed\n");
return ret;
- }
- aw_dev->prof_cur = aw_dev->prof_index;
- return ret;
Just "return 0;" here. It's the same but zero is more clear.
+}
+static int aw87390_power_off(struct aw_device *aw_dev) +{
- int ret;
- if (aw_dev->status == AW87390_DEV_PW_OFF) {
dev_info(aw_dev->dev, "already power off\n");
return 0;
- }
- ret = regmap_write(aw_dev->regmap, AW87390_SYSCTRL_REG, AW87390_POWER_DOWN_VALUE);
- if (ret)
return ret;
- aw_dev->status = AW87390_DEV_PW_OFF;
- return ret;
return 0;
+}
+static int aw87390_power_on(struct aw_device *aw_dev) +{
- int ret;
- if (aw_dev->status == AW87390_DEV_PW_ON) {
dev_info(aw_dev->dev, "already power on\n");
Change this dev_info() to dev_dbg().
return 0;
- }
- if (!aw_dev->fw_status) {
dev_err(aw_dev->dev, "fw not load\n");
return -EINVAL;
- }
- ret = regmap_write(aw_dev->regmap, AW87390_SYSCTRL_REG, AW87390_POWER_DOWN_VALUE);
- if (ret)
return ret;
- ret = aw87390_dev_fw_update(aw_dev);
- if (ret) {
dev_err(aw_dev->dev, "%s load profile failed\n", __func__);
return ret;
- }
- aw_dev->status = AW87390_DEV_PW_ON;
- return ret;
return 0;
+}
+static int aw87390_dev_set_profile_index(struct aw_device *aw_dev, int index) +{
- if ((index >= aw_dev->prof_info.count) || (index < 0))
return -EINVAL;
- if (aw_dev->prof_index == index)
return -EPERM;
- aw_dev->prof_index = index;
- return 0;
+}
+static int aw87390_profile_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
+{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
- struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec);
- char *prof_name, *name;
- int count, ret;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- count = aw87390->aw_pa->prof_info.count;
- if (count <= 0) {
uinfo->value.enumerated.items = 0;
return 0;
- }
- uinfo->value.enumerated.items = count;
- if (uinfo->value.enumerated.item >= count)
uinfo->value.enumerated.item = count - 1;
- name = uinfo->value.enumerated.name;
- count = uinfo->value.enumerated.item;
- ret = aw87390_dev_get_prof_name(aw87390->aw_pa, count, &prof_name);
- if (ret) {
strscpy(uinfo->value.enumerated.name, "null",
strlen("null") + 1);
return 0;
- }
- strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name));
- return 0;
+}
+static int aw87390_profile_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
+{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
- struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec);
- ucontrol->value.integer.value[0] = aw87390->aw_pa->prof_index;
- return 0;
+}
+static int aw87390_profile_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
+{
- struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
- struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec);
- int ret;
- mutex_lock(&aw87390->lock);
- ret = aw87390_dev_set_profile_index(aw87390->aw_pa, ucontrol->value.integer.value[0]);
- if (ret) {
dev_dbg(codec->dev, "profile index does not change\n");
mutex_unlock(&aw87390->lock);
return 0;
- }
- if (aw87390->aw_pa->status == AW87390_DEV_PW_ON) {
aw87390_power_off(aw87390->aw_pa);
aw87390_power_on(aw87390->aw_pa);
- }
- mutex_unlock(&aw87390->lock);
- return 1;
+}
+static const struct snd_kcontrol_new aw87390_controls[] = {
- AW87390_PROFILE_EXT("AW87390 Profile Set", aw87390_profile_info,
aw87390_profile_get, aw87390_profile_set),
+};
+static int aw87390_request_firmware_file(struct aw87390 *aw87390) +{
- const struct firmware *cont = NULL;
- int ret;
- aw87390->aw_pa->fw_status = AW87390_DEV_FW_FAILED;
- ret = request_firmware(&cont, AW87390_ACF_FILE, aw87390->aw_pa->dev);
- if (ret)
return dev_err_probe(aw87390->aw_pa->dev, ret,
"load [%s] failed!\n", AW87390_ACF_FILE);
- dev_dbg(aw87390->aw_pa->dev, "loaded %s - size: %zu\n",
AW87390_ACF_FILE, cont ? cont->size : 0);
- aw87390->aw_cfg = devm_kzalloc(aw87390->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL);
Use struct_size().
aw87390->aw_cfg = devm_kzalloc(aw87390->aw_pa->dev, struct_size(aw87390->aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw87390->aw_cfg) {
release_firmware(cont);
return -ENOMEM;
- }
- aw87390->aw_cfg->len = (int)cont->size;
No need for this scary looking cast.
- memcpy(aw87390->aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
- ret = aw88395_dev_load_acf_check(aw87390->aw_pa, aw87390->aw_cfg);
- if (ret) {
dev_err(aw87390->aw_pa->dev, "load [%s] failed !\n", AW87390_ACF_FILE);
No space before !.
return ret;
- }
- mutex_lock(&aw87390->lock);
- ret = aw88395_dev_cfg_load(aw87390->aw_pa, aw87390->aw_cfg);
- if (ret)
dev_err(aw87390->aw_pa->dev, "aw_dev acf parse failed\n");
- mutex_unlock(&aw87390->lock);
- return ret;
+}
+static int aw87390_drv_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
+{
- struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
- struct aw87390 *aw87390 = snd_soc_component_get_drvdata(component);
- struct aw_device *aw_dev = aw87390->aw_pa;
- int ret;
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
ret = aw87390_power_on(aw_dev);
break;
- case SND_SOC_DAPM_POST_PMD:
ret = aw87390_power_off(aw_dev);
break;
- default:
dev_err(aw_dev->dev, "%s: invalid event %d\n", __func__, event);
ret = -EINVAL;
- }
- return ret;
+}
+static const struct snd_soc_dapm_widget aw87390_dapm_widgets[] = {
- SND_SOC_DAPM_INPUT("IN"),
- SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM, 0, 0, NULL, 0, aw87390_drv_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_OUTPUT("OUT"),
+};
+static const struct snd_soc_dapm_route aw87390_dapm_routes[] = {
- { "SPK PA", NULL, "IN" },
- { "OUT", NULL, "SPK PA" },
+};
+static int aw87390_codec_probe(struct snd_soc_component *component) +{
- struct aw87390 *aw87390 = snd_soc_component_get_drvdata(component);
- int ret;
- ret = aw87390_request_firmware_file(aw87390);
- if (ret)
return dev_err_probe(aw87390->aw_pa->dev, ret,
"aw87390_request_firmware_file failed\n");
- return 0;
+}
+static const struct snd_soc_component_driver soc_codec_dev_aw87390 = {
- .probe = aw87390_codec_probe,
- .dapm_widgets = aw87390_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(aw87390_dapm_widgets),
- .dapm_routes = aw87390_dapm_routes,
- .num_dapm_routes = ARRAY_SIZE(aw87390_dapm_routes),
- .controls = aw87390_controls,
- .num_controls = ARRAY_SIZE(aw87390_controls),
+};
+static void aw87390_parse_channel_dt(struct aw87390 *aw87390) +{
- struct aw_device *aw_dev = aw87390->aw_pa;
- struct device_node *np = aw_dev->dev->of_node;
- u32 channel_value = AW87390_DEV_DEFAULT_CH;
- of_property_read_u32(np, "awinic,audio-channel", &channel_value);
- aw_dev->channel = channel_value;
+}
+static int aw87390_init(struct aw87390 **aw87390, struct i2c_client *i2c, struct regmap *regmap) +{
- struct aw_device *aw_dev;
- unsigned int chip_id;
- int ret;
- /* read chip id */
- ret = regmap_read(regmap, AW87390_ID_REG, &chip_id);
- if (ret) {
dev_err(&i2c->dev, "%s read chipid error. ret = %d\n", __func__, ret);
return ret;
- }
- if (chip_id != AW87390_CHIP_ID) {
dev_err(&i2c->dev, "unsupported device\n");
return -ENXIO;
- }
- dev_info(&i2c->dev, "chip id = 0x%x\n", chip_id);
Make this dev_dbg().
- aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
- if (!aw_dev)
return -ENOMEM;
- (*aw87390)->aw_pa = aw_dev;
- aw_dev->i2c = i2c;
- aw_dev->regmap = regmap;
- aw_dev->dev = &i2c->dev;
- aw_dev->chip_id = AW87390_CHIP_ID;
- aw_dev->acf = NULL;
- aw_dev->prof_info.prof_desc = NULL;
- aw_dev->prof_info.count = 0;
- aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
- aw_dev->channel = AW87390_DEV_DEFAULT_CH;
- aw_dev->fw_status = AW87390_DEV_FW_FAILED;
- aw_dev->prof_index = AW87390_INIT_PROFILE;
- aw_dev->status = AW87390_DEV_PW_OFF;
- aw87390_parse_channel_dt(*aw87390);
- return ret;
return 0;
+}
+static int aw87390_i2c_probe(struct i2c_client *i2c) +{
- struct aw87390 *aw87390;
- int ret;
- ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C);
- if (!ret)
return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed\n");
- aw87390 = devm_kzalloc(&i2c->dev, sizeof(*aw87390), GFP_KERNEL);
- if (!aw87390)
return -ENOMEM;
- mutex_init(&aw87390->lock);
- i2c_set_clientdata(i2c, aw87390);
- aw87390->regmap = devm_regmap_init_i2c(i2c, &aw87390_remap_config);
- if (IS_ERR(aw87390->regmap))
return dev_err_probe(&i2c->dev, PTR_ERR(aw87390->regmap),
"failed to init regmap\n");
- /* aw pa init */
- ret = aw87390_init(&aw87390, i2c, aw87390->regmap);
- if (ret)
return ret;
- ret = regmap_write(aw87390->regmap, AW87390_ID_REG, AW87390_SOFT_RESET_VALUE);
- if (ret)
return ret;
- ret = devm_snd_soc_register_component(&i2c->dev,
&soc_codec_dev_aw87390, NULL, 0);
- if (ret)
dev_err(&i2c->dev, "failed to register aw87390: %d\n", ret);
- return ret;
+}
+static const struct i2c_device_id aw87390_i2c_id[] = {
- { AW87390_I2C_NAME, 0 },
- { }
+}; +MODULE_DEVICE_TABLE(i2c, aw87390_i2c_id);
+static struct i2c_driver aw87390_i2c_driver = {
- .driver = {
.name = AW87390_I2C_NAME,
- },
- .probe = aw87390_i2c_probe,
- .id_table = aw87390_i2c_id,
+}; +module_i2c_driver(aw87390_i2c_driver);
+MODULE_DESCRIPTION("ASoC AW87390 PA Driver"); +MODULE_LICENSE("GPL v2");
This is another checkpatch thing. It should just be MODULE_LICENSE("GPL");
regards, dan carpenter
Thank you very much for your review, but I have some questions I would like to discuss with you
On Wed, Sep 27, 2023 at 08:16:34PM +0800, wangweidong.a@awinic.com wrote:
@@ -668,6 +668,17 @@ config SND_SOC_AW88261 boost converter can be adjusted smartly according to the input amplitude.
+config SND_SOC_AW87390
- tristate "Soc Audio for awinic aw87390"
Capitalize A in Awinic.
Thank you very much, but our company prefers to use awinic rather than Awinic
- depends on I2C
- select REGMAP_I2C
- select SND_SOC_AW88395_LIB
- help
The awinic aw87390 is specifically designed to improve
the musical output dynamic range, enhance the overall
sound quallity, which is a new high efficiency, low
s/quallity/quality/.
Thank you very much. I'll correct it
noise, constant large volume, 6th Smart K audio amplifier.
config SND_SOC_BD28623 tristate "ROHM BD28623 CODEC" help
[ snip ]
diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c new file mode 100644 index 000000000000..8efae3b73eea --- /dev/null +++ b/sound/soc/codecs/aw87390.c @@ -0,0 +1,462 @@ +// SPDX-License-Identifier: GPL-2.0-only
Checkpatch complains about this. It should just be GPL-2.0, the "only" is assumed unless there is a + as in "GPL-2.0+". You might want to run scripts/checkpatch.pl --strict on your patch.
Thank you very much. Our company uses the GPL-2.0-only all the time, and I see a lot of GPL-2.0-only in other drivers.
+// +// aw87390.c -- AW87390 ALSA SoC Audio driver +// +// Copyright (c) 2023 awinic Technology CO., LTD +// +// Author: Weidong Wang wangweidong.a@awinic.com +//
+#include <linux/i2c.h> +#include <linux/firmware.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include "aw87390.h" +#include "aw88395/aw88395_data_type.h" +#include "aw88395/aw88395_device.h"
+static const struct regmap_config aw87390_remap_config = {
- .val_bits = 8,
- .reg_bits = 8,
- .max_register = AW87390_REG_MAX,
- .reg_format_endian = REGMAP_ENDIAN_LITTLE,
- .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+static int aw87390_dev_reg_update(struct aw_device *aw_dev,
unsigned char *data, unsigned int len)
+{
- int i, ret;
- if (!data) {
dev_err(aw_dev->dev, "data is NULL\n");
return -EINVAL;
- }
- for (i = 0; i < len; i = i + 2) {
if (data[i] == AW87390_DELAY_REG_ADDR) {
usleep_range(data[i + 1] * AW87390_REG_DELAY_TIME,
data[i + 1] * AW87390_REG_DELAY_TIME + 10);
continue;
}
ret = regmap_write(aw_dev->regmap, data[i], data[i + 1]);
This assumes that len is an even number... Maybe write it as:
for (i = 0; i < len - 1; i += 2) {
Although that assumes len can't be zero so maybe it's not a win...
Thank you very much. I will modify it.
if (ret)
return ret;
- }
- return 0;
+}
+static int aw87390_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) +{
- struct aw_prof_info *prof_info = &aw_dev->prof_info;
- struct aw_prof_desc *prof_desc;
- if ((index >= aw_dev->prof_info.count) || (index < 0)) {
dev_err(aw_dev->dev, "index[%d] overflow count[%d]\n",
index, aw_dev->prof_info.count);
...
- /* update reg */
- sec_desc = prof_index_desc->sec_desc;
- ret = aw87390_dev_reg_update(aw_dev, sec_desc[AW88395_DATA_TYPE_REG].data,
sec_desc[AW88395_DATA_TYPE_REG].len);
- if (ret) {
dev_err(aw_dev->dev, "update reg failed\n");
return ret;
- }
- aw_dev->prof_cur = aw_dev->prof_index;
- return ret;
Just "return 0;" here. It's the same but zero is more clear.
Thank you very much. I will modify it.
+}
+static int aw87390_power_off(struct aw_device *aw_dev) +{
- int ret;
- if (aw_dev->status == AW87390_DEV_PW_OFF) {
dev_info(aw_dev->dev, "already power off\n");
return 0;
- }
- ret = regmap_write(aw_dev->regmap, AW87390_SYSCTRL_REG, AW87390_POWER_DOWN_VALUE);
- if (ret)
return ret;
- aw_dev->status = AW87390_DEV_PW_OFF;
- return ret;
return 0;
Thank you very much. I will modify it.
+}
+static int aw87390_power_on(struct aw_device *aw_dev) +{
- int ret;
- if (aw_dev->status == AW87390_DEV_PW_ON) {
dev_info(aw_dev->dev, "already power on\n");
Change this dev_info() to dev_dbg().
Thank you very much. I will modify it.
return 0;
- }
- if (!aw_dev->fw_status) {
dev_err(aw_dev->dev, "fw not load\n");
return -EINVAL;
- }
- ret = regmap_write(aw_dev->regmap, AW87390_SYSCTRL_REG, AW87390_POWER_DOWN_VALUE);
- if (ret)
return ret;
- ret = aw87390_dev_fw_update(aw_dev);
- if (ret) {
dev_err(aw_dev->dev, "%s load profile failed\n", __func__);
return ret;
- }
- aw_dev->status = AW87390_DEV_PW_ON;
- return ret;
return 0;
Thank you very much. I will modify it.
+}
+static int aw87390_dev_set_profile_index(struct aw_device *aw_dev, int index) +{
- if ((index >= aw_dev->prof_info.count) || (index < 0))
return -EINVAL;
- if (aw_dev->prof_index == index)
return -EPERM;
- aw_dev->prof_index = index;
- return 0;
+}
...
+static const struct snd_kcontrol_new aw87390_controls[] = {
- AW87390_PROFILE_EXT("AW87390 Profile Set", aw87390_profile_info,
aw87390_profile_get, aw87390_profile_set),
+};
+static int aw87390_request_firmware_file(struct aw87390 *aw87390) +{
- const struct firmware *cont = NULL;
- int ret;
- aw87390->aw_pa->fw_status = AW87390_DEV_FW_FAILED;
- ret = request_firmware(&cont, AW87390_ACF_FILE, aw87390->aw_pa->dev);
- if (ret)
return dev_err_probe(aw87390->aw_pa->dev, ret,
"load [%s] failed!\n", AW87390_ACF_FILE);
- dev_dbg(aw87390->aw_pa->dev, "loaded %s - size: %zu\n",
AW87390_ACF_FILE, cont ? cont->size : 0);
- aw87390->aw_cfg = devm_kzalloc(aw87390->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL);
Use struct_size().
aw87390->aw_cfg = devm_kzalloc(aw87390->aw_pa->dev, struct_size(aw87390->aw_cfg, data, cont->size), GFP_KERNEL);
Thank you very much. I will modify it.
- if (!aw87390->aw_cfg) {
release_firmware(cont);
return -ENOMEM;
- }
- aw87390->aw_cfg->len = (int)cont->size;
No need for this scary looking cast.
Thank you very much. I will modify it to "aw87390->aw_cfg->len = cont->size;"
- memcpy(aw87390->aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
- ret = aw88395_dev_load_acf_check(aw87390->aw_pa, aw87390->aw_cfg);
- if (ret) {
dev_err(aw87390->aw_pa->dev, "load [%s] failed !\n", AW87390_ACF_FILE);
No space before !.
Thank you very much. I will modify it.
return ret;
- }
- mutex_lock(&aw87390->lock);
- ret = aw88395_dev_cfg_load(aw87390->aw_pa, aw87390->aw_cfg);
...
+static int aw87390_init(struct aw87390 **aw87390, struct i2c_client *i2c, struct regmap *regmap) +{
- struct aw_device *aw_dev;
- unsigned int chip_id;
- int ret;
- /* read chip id */
- ret = regmap_read(regmap, AW87390_ID_REG, &chip_id);
- if (ret) {
dev_err(&i2c->dev, "%s read chipid error. ret = %d\n", __func__, ret);
return ret;
- }
- if (chip_id != AW87390_CHIP_ID) {
dev_err(&i2c->dev, "unsupported device\n");
return -ENXIO;
- }
- dev_info(&i2c->dev, "chip id = 0x%x\n", chip_id);
Make this dev_dbg().
Thank you very much. I will modify it.
- aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
- if (!aw_dev)
return -ENOMEM;
- (*aw87390)->aw_pa = aw_dev;
- aw_dev->i2c = i2c;
- aw_dev->regmap = regmap;
- aw_dev->dev = &i2c->dev;
- aw_dev->chip_id = AW87390_CHIP_ID;
- aw_dev->acf = NULL;
- aw_dev->prof_info.prof_desc = NULL;
- aw_dev->prof_info.count = 0;
- aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
- aw_dev->channel = AW87390_DEV_DEFAULT_CH;
- aw_dev->fw_status = AW87390_DEV_FW_FAILED;
- aw_dev->prof_index = AW87390_INIT_PROFILE;
- aw_dev->status = AW87390_DEV_PW_OFF;
- aw87390_parse_channel_dt(*aw87390);
- return ret;
return 0;
Thank you very much. I will modify it.
+}
+static int aw87390_i2c_probe(struct i2c_client *i2c) +{
- struct aw87390 *aw87390;
- int ret;
...
+static const struct i2c_device_id aw87390_i2c_id[] = {
- { AW87390_I2C_NAME, 0 },
- { }
+}; +MODULE_DEVICE_TABLE(i2c, aw87390_i2c_id);
+static struct i2c_driver aw87390_i2c_driver = {
- .driver = {
.name = AW87390_I2C_NAME,
- },
- .probe = aw87390_i2c_probe,
- .id_table = aw87390_i2c_id,
+}; +module_i2c_driver(aw87390_i2c_driver);
+MODULE_DESCRIPTION("ASoC AW87390 PA Driver"); +MODULE_LICENSE("GPL v2");
This is another checkpatch thing. It should just be MODULE_LICENSE("GPL");
Thank you very much, but our company follows the "GPL v2" So I want to still use it
Best regards, Weidong Wang
On Thu, Sep 28, 2023 at 02:43:30PM +0800, wangweidong.a@awinic.com wrote:
Thank you very much for your review, but I have some questions I would like to discuss with you
On Wed, Sep 27, 2023 at 08:16:34PM +0800, wangweidong.a@awinic.com wrote:
@@ -668,6 +668,17 @@ config SND_SOC_AW88261 boost converter can be adjusted smartly according to the input amplitude.
+config SND_SOC_AW87390
- tristate "Soc Audio for awinic aw87390"
Capitalize A in Awinic.
Thank you very much, but our company prefers to use awinic rather than Awinic
Ah. Fine. I did Google the company name but hadn't scrolled down far enough.
regards, dan carpenter
On Wed, 27 Sep 2023 20:16:26 +0800, wangweidong.a@awinic.com wrote:
The awinic aw87390 is a new high efficiency, low noise, constant large volume, 6th Smart K audio amplifier.
Add a DT schema for describing awinic aw87390 audio amplifiers. They are controlled using I2C.
v4 -> v5: Adjust the order and context of the patch
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/8] ASoC: dt-bindings: awinic,aw88395: Add properties for multiple PA support commit: b99d8d8adfda1f9220dd2ee9bdb96ba02dc62bd7 [2/8] ASoC: dt-bindings: Add schema for "awinic,aw87390" commit: 457b6587c112e162d3bec871c7b93359168d5c0a [3/8] ASoC: codecs: Modify the code related to the property (no commit info) [4/8] ASoC: codecs: Modify the transmission method of parameters commit: e83219c94abb4ad977f6b2b8be7d466ef0c2248f [5/8] ASoC: codecs: Add code for bin parsing compatible with aw87390 commit: b116c832c9e84843c64eed087271e29b3bc6c1b8 [6/8] ASoC: codecs: Modify the code related to the property (no commit info) [7/8] ASoC: codecs: Modify the transmission mode of function parameters commit: f83287a72551833a6fe2fc96f334b26e6eba77e8 [8/8] ASoC: codecs: Add aw87390 amplifier driver commit: 37b4346ed8681660ae60de4facc3d499d8e5cf2a
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
participants (3)
-
Dan Carpenter
-
Mark Brown
-
wangweidong.a@awinic.com