Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: codecs: Add aw87390 amplifier driver

Merge series from wangweidong.a@awinic.com:

The awinic aw87390 is a new high efficiency, low noise,
constant large volume, 6th Smart K audio amplifier.

+686 -74
+58
Documentation/devicetree/bindings/sound/awinic,aw87390.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/sound/awinic,aw87390.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Awinic Aw87390 Audio Amplifier 8 + 9 + maintainers: 10 + - Weidong Wang <wangweidong.a@awinic.com> 11 + 12 + description: 13 + The awinic aw87390 is specifically designed to improve 14 + the musical output dynamic range, enhance the overall 15 + sound quallity, which is a new high efficiency, low 16 + noise, constant large volume, 6th Smart K audio amplifier. 17 + 18 + allOf: 19 + - $ref: dai-common.yaml# 20 + 21 + properties: 22 + compatible: 23 + const: awinic,aw87390 24 + 25 + reg: 26 + maxItems: 1 27 + 28 + "#sound-dai-cells": 29 + const: 0 30 + 31 + awinic,audio-channel: 32 + description: 33 + It is used to distinguish multiple PA devices, so that different 34 + configurations can be loaded to different PA devices 35 + $ref: /schemas/types.yaml#/definitions/uint32 36 + minimum: 0 37 + maximum: 7 38 + 39 + required: 40 + - compatible 41 + - reg 42 + - "#sound-dai-cells" 43 + - awinic,audio-channel 44 + 45 + unevaluatedProperties: false 46 + 47 + examples: 48 + - | 49 + i2c { 50 + #address-cells = <1>; 51 + #size-cells = <0>; 52 + audio-codec@58 { 53 + compatible = "awinic,aw87390"; 54 + reg = <0x58>; 55 + #sound-dai-cells = <0>; 56 + awinic,audio-channel = <0>; 57 + }; 58 + };
+16
Documentation/devicetree/bindings/sound/awinic,aw88395.yaml
··· 32 32 reset-gpios: 33 33 maxItems: 1 34 34 35 + awinic,audio-channel: 36 + description: 37 + It is used to distinguish multiple PA devices, so that different 38 + configurations can be loaded to different PA devices 39 + $ref: /schemas/types.yaml#/definitions/uint32 40 + minimum: 0 41 + maximum: 7 42 + 43 + awinic,sync-flag: 44 + description: 45 + Flag bit used to keep the phase synchronized in the case of multiple PA 46 + $ref: /schemas/types.yaml#/definitions/flag 47 + 35 48 required: 36 49 - compatible 37 50 - reg 38 51 - '#sound-dai-cells' 39 52 - reset-gpios 53 + - awinic,audio-channel 40 54 41 55 unevaluatedProperties: false 42 56 ··· 65 51 reg = <0x34>; 66 52 #sound-dai-cells = <0>; 67 53 reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>; 54 + awinic,audio-channel = <0>; 55 + awinic,sync-flag; 68 56 }; 69 57 };
+13 -2
sound/soc/codecs/Kconfig
··· 54 54 imply SND_SOC_ALC5632 55 55 imply SND_SOC_AUDIO_IIO_AUX 56 56 imply SND_SOC_AW8738 57 + imply SND_SOC_AW87390 57 58 imply SND_SOC_AW88395 58 59 imply SND_SOC_AW88261 59 60 imply SND_SOC_BT_SCO ··· 640 639 operation mode using the Awinic-specific one-wire pulse control. 641 640 642 641 config SND_SOC_AW88395_LIB 642 + select CRC8 643 643 tristate 644 644 645 645 config SND_SOC_AW88395 646 646 tristate "Soc Audio for awinic aw88395" 647 647 depends on I2C 648 - select CRC8 649 648 select CRC32 650 649 select REGMAP_I2C 651 650 select GPIOLIB ··· 659 658 config SND_SOC_AW88261 660 659 tristate "Soc Audio for awinic aw88261" 661 660 depends on I2C 662 - select CRC8 663 661 select REGMAP_I2C 664 662 select GPIOLIB 665 663 select SND_SOC_AW88395_LIB ··· 668 668 digital Smart K audio amplifier. The output voltage of 669 669 boost converter can be adjusted smartly according to 670 670 the input amplitude. 671 + 672 + config SND_SOC_AW87390 673 + tristate "Soc Audio for awinic aw87390" 674 + depends on I2C 675 + select REGMAP_I2C 676 + select SND_SOC_AW88395_LIB 677 + help 678 + The awinic aw87390 is specifically designed to improve 679 + the musical output dynamic range, enhance the overall 680 + sound quality, which is a new high efficiency, low 681 + noise, constant large volume, 6th Smart K audio amplifier. 671 682 672 683 config SND_SOC_BD28623 673 684 tristate "ROHM BD28623 CODEC"
+2
sound/soc/codecs/Makefile
··· 47 47 snd-soc-arizona-objs := arizona.o arizona-jack.o 48 48 snd-soc-audio-iio-aux-objs := audio-iio-aux.o 49 49 snd-soc-aw8738-objs := aw8738.o 50 + snd-soc-aw87390-objs := aw87390.o 50 51 snd-soc-aw88395-lib-objs := aw88395/aw88395_lib.o 51 52 snd-soc-aw88395-objs := aw88395/aw88395.o \ 52 53 aw88395/aw88395_device.o ··· 436 435 obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o 437 436 obj-$(CONFIG_SND_SOC_AUDIO_IIO_AUX) += snd-soc-audio-iio-aux.o 438 437 obj-$(CONFIG_SND_SOC_AW8738) += snd-soc-aw8738.o 438 + obj-$(CONFIG_SND_SOC_AW87390) += snd-soc-aw87390.o 439 439 obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o 440 440 obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o 441 441 obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o
+463
sound/soc/codecs/aw87390.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + // 3 + // aw87390.c -- AW87390 ALSA SoC Audio driver 4 + // 5 + // Copyright (c) 2023 awinic Technology CO., LTD 6 + // 7 + // Author: Weidong Wang <wangweidong.a@awinic.com> 8 + // 9 + 10 + #include <linux/i2c.h> 11 + #include <linux/firmware.h> 12 + #include <linux/regmap.h> 13 + #include <sound/soc.h> 14 + #include "aw87390.h" 15 + #include "aw88395/aw88395_data_type.h" 16 + #include "aw88395/aw88395_device.h" 17 + 18 + static const struct regmap_config aw87390_remap_config = { 19 + .val_bits = 8, 20 + .reg_bits = 8, 21 + .max_register = AW87390_REG_MAX, 22 + .reg_format_endian = REGMAP_ENDIAN_LITTLE, 23 + .val_format_endian = REGMAP_ENDIAN_BIG, 24 + }; 25 + 26 + static int aw87390_dev_reg_update(struct aw_device *aw_dev, 27 + unsigned char *data, unsigned int len) 28 + { 29 + int i, ret; 30 + 31 + if (!data) { 32 + dev_err(aw_dev->dev, "data is NULL\n"); 33 + return -EINVAL; 34 + } 35 + 36 + for (i = 0; i < len-1; i += 2) { 37 + if (data[i] == AW87390_DELAY_REG_ADDR) { 38 + usleep_range(data[i + 1] * AW87390_REG_DELAY_TIME, 39 + data[i + 1] * AW87390_REG_DELAY_TIME + 10); 40 + continue; 41 + } 42 + ret = regmap_write(aw_dev->regmap, data[i], data[i + 1]); 43 + if (ret) 44 + return ret; 45 + } 46 + 47 + return 0; 48 + } 49 + 50 + static int aw87390_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) 51 + { 52 + struct aw_prof_info *prof_info = &aw_dev->prof_info; 53 + struct aw_prof_desc *prof_desc; 54 + 55 + if ((index >= aw_dev->prof_info.count) || (index < 0)) { 56 + dev_err(aw_dev->dev, "index[%d] overflow count[%d]\n", 57 + index, aw_dev->prof_info.count); 58 + return -EINVAL; 59 + } 60 + 61 + prof_desc = &aw_dev->prof_info.prof_desc[index]; 62 + 63 + *prof_name = prof_info->prof_name_list[prof_desc->id]; 64 + 65 + return 0; 66 + } 67 + 68 + static int aw87390_dev_get_prof_data(struct aw_device *aw_dev, int index, 69 + struct aw_prof_desc **prof_desc) 70 + { 71 + if ((index >= aw_dev->prof_info.count) || (index < 0)) { 72 + dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", 73 + __func__, index, aw_dev->prof_info.count); 74 + return -EINVAL; 75 + } 76 + 77 + *prof_desc = &aw_dev->prof_info.prof_desc[index]; 78 + 79 + return 0; 80 + } 81 + 82 + static int aw87390_dev_fw_update(struct aw_device *aw_dev) 83 + { 84 + struct aw_prof_desc *prof_index_desc; 85 + struct aw_sec_data_desc *sec_desc; 86 + char *prof_name; 87 + int ret; 88 + 89 + ret = aw87390_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); 90 + if (ret) { 91 + dev_err(aw_dev->dev, "get prof name failed\n"); 92 + return -EINVAL; 93 + } 94 + 95 + dev_dbg(aw_dev->dev, "start update %s", prof_name); 96 + 97 + ret = aw87390_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); 98 + if (ret) { 99 + dev_err(aw_dev->dev, "aw87390_dev_get_prof_data failed\n"); 100 + return ret; 101 + } 102 + 103 + /* update reg */ 104 + sec_desc = prof_index_desc->sec_desc; 105 + ret = aw87390_dev_reg_update(aw_dev, sec_desc[AW88395_DATA_TYPE_REG].data, 106 + sec_desc[AW88395_DATA_TYPE_REG].len); 107 + if (ret) { 108 + dev_err(aw_dev->dev, "update reg failed\n"); 109 + return ret; 110 + } 111 + 112 + aw_dev->prof_cur = aw_dev->prof_index; 113 + 114 + return 0; 115 + } 116 + 117 + static int aw87390_power_off(struct aw_device *aw_dev) 118 + { 119 + int ret; 120 + 121 + if (aw_dev->status == AW87390_DEV_PW_OFF) { 122 + dev_dbg(aw_dev->dev, "already power off\n"); 123 + return 0; 124 + } 125 + 126 + ret = regmap_write(aw_dev->regmap, AW87390_SYSCTRL_REG, AW87390_POWER_DOWN_VALUE); 127 + if (ret) 128 + return ret; 129 + aw_dev->status = AW87390_DEV_PW_OFF; 130 + 131 + return 0; 132 + } 133 + 134 + static int aw87390_power_on(struct aw_device *aw_dev) 135 + { 136 + int ret; 137 + 138 + if (aw_dev->status == AW87390_DEV_PW_ON) { 139 + dev_dbg(aw_dev->dev, "already power on\n"); 140 + return 0; 141 + } 142 + 143 + if (!aw_dev->fw_status) { 144 + dev_err(aw_dev->dev, "fw not load\n"); 145 + return -EINVAL; 146 + } 147 + 148 + ret = regmap_write(aw_dev->regmap, AW87390_SYSCTRL_REG, AW87390_POWER_DOWN_VALUE); 149 + if (ret) 150 + return ret; 151 + 152 + ret = aw87390_dev_fw_update(aw_dev); 153 + if (ret) { 154 + dev_err(aw_dev->dev, "%s load profile failed\n", __func__); 155 + return ret; 156 + } 157 + aw_dev->status = AW87390_DEV_PW_ON; 158 + 159 + return 0; 160 + } 161 + 162 + static int aw87390_dev_set_profile_index(struct aw_device *aw_dev, int index) 163 + { 164 + if ((index >= aw_dev->prof_info.count) || (index < 0)) 165 + return -EINVAL; 166 + 167 + if (aw_dev->prof_index == index) 168 + return -EPERM; 169 + 170 + aw_dev->prof_index = index; 171 + 172 + return 0; 173 + } 174 + 175 + static int aw87390_profile_info(struct snd_kcontrol *kcontrol, 176 + struct snd_ctl_elem_info *uinfo) 177 + { 178 + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 179 + struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec); 180 + char *prof_name, *name; 181 + int count, ret; 182 + 183 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 184 + uinfo->count = 1; 185 + 186 + count = aw87390->aw_pa->prof_info.count; 187 + if (count <= 0) { 188 + uinfo->value.enumerated.items = 0; 189 + return 0; 190 + } 191 + 192 + uinfo->value.enumerated.items = count; 193 + 194 + if (uinfo->value.enumerated.item >= count) 195 + uinfo->value.enumerated.item = count - 1; 196 + 197 + name = uinfo->value.enumerated.name; 198 + count = uinfo->value.enumerated.item; 199 + 200 + ret = aw87390_dev_get_prof_name(aw87390->aw_pa, count, &prof_name); 201 + if (ret) { 202 + strscpy(uinfo->value.enumerated.name, "null", 203 + strlen("null") + 1); 204 + return 0; 205 + } 206 + 207 + strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name)); 208 + 209 + return 0; 210 + } 211 + 212 + static int aw87390_profile_get(struct snd_kcontrol *kcontrol, 213 + struct snd_ctl_elem_value *ucontrol) 214 + { 215 + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 216 + struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec); 217 + 218 + ucontrol->value.integer.value[0] = aw87390->aw_pa->prof_index; 219 + 220 + return 0; 221 + } 222 + 223 + static int aw87390_profile_set(struct snd_kcontrol *kcontrol, 224 + struct snd_ctl_elem_value *ucontrol) 225 + { 226 + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 227 + struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec); 228 + int ret; 229 + 230 + mutex_lock(&aw87390->lock); 231 + ret = aw87390_dev_set_profile_index(aw87390->aw_pa, ucontrol->value.integer.value[0]); 232 + if (ret) { 233 + dev_dbg(codec->dev, "profile index does not change\n"); 234 + mutex_unlock(&aw87390->lock); 235 + return 0; 236 + } 237 + 238 + if (aw87390->aw_pa->status == AW87390_DEV_PW_ON) { 239 + aw87390_power_off(aw87390->aw_pa); 240 + aw87390_power_on(aw87390->aw_pa); 241 + } 242 + 243 + mutex_unlock(&aw87390->lock); 244 + 245 + return 1; 246 + } 247 + 248 + static const struct snd_kcontrol_new aw87390_controls[] = { 249 + AW87390_PROFILE_EXT("AW87390 Profile Set", aw87390_profile_info, 250 + aw87390_profile_get, aw87390_profile_set), 251 + }; 252 + 253 + static int aw87390_request_firmware_file(struct aw87390 *aw87390) 254 + { 255 + const struct firmware *cont = NULL; 256 + int ret; 257 + 258 + aw87390->aw_pa->fw_status = AW87390_DEV_FW_FAILED; 259 + 260 + ret = request_firmware(&cont, AW87390_ACF_FILE, aw87390->aw_pa->dev); 261 + if (ret) 262 + return dev_err_probe(aw87390->aw_pa->dev, ret, 263 + "load [%s] failed!\n", AW87390_ACF_FILE); 264 + 265 + dev_dbg(aw87390->aw_pa->dev, "loaded %s - size: %zu\n", 266 + AW87390_ACF_FILE, cont ? cont->size : 0); 267 + 268 + aw87390->aw_cfg = devm_kzalloc(aw87390->aw_pa->dev, 269 + struct_size(aw87390->aw_cfg, data, cont->size), GFP_KERNEL); 270 + if (!aw87390->aw_cfg) { 271 + release_firmware(cont); 272 + return -ENOMEM; 273 + } 274 + 275 + aw87390->aw_cfg->len = cont->size; 276 + memcpy(aw87390->aw_cfg->data, cont->data, cont->size); 277 + release_firmware(cont); 278 + 279 + ret = aw88395_dev_load_acf_check(aw87390->aw_pa, aw87390->aw_cfg); 280 + if (ret) { 281 + dev_err(aw87390->aw_pa->dev, "load [%s] failed!\n", AW87390_ACF_FILE); 282 + return ret; 283 + } 284 + 285 + mutex_lock(&aw87390->lock); 286 + 287 + ret = aw88395_dev_cfg_load(aw87390->aw_pa, aw87390->aw_cfg); 288 + if (ret) 289 + dev_err(aw87390->aw_pa->dev, "aw_dev acf parse failed\n"); 290 + 291 + mutex_unlock(&aw87390->lock); 292 + 293 + return ret; 294 + } 295 + 296 + static int aw87390_drv_event(struct snd_soc_dapm_widget *w, 297 + struct snd_kcontrol *kcontrol, int event) 298 + { 299 + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 300 + struct aw87390 *aw87390 = snd_soc_component_get_drvdata(component); 301 + struct aw_device *aw_dev = aw87390->aw_pa; 302 + int ret; 303 + 304 + switch (event) { 305 + case SND_SOC_DAPM_PRE_PMU: 306 + ret = aw87390_power_on(aw_dev); 307 + break; 308 + case SND_SOC_DAPM_POST_PMD: 309 + ret = aw87390_power_off(aw_dev); 310 + break; 311 + default: 312 + dev_err(aw_dev->dev, "%s: invalid event %d\n", __func__, event); 313 + ret = -EINVAL; 314 + } 315 + 316 + return ret; 317 + } 318 + 319 + static const struct snd_soc_dapm_widget aw87390_dapm_widgets[] = { 320 + SND_SOC_DAPM_INPUT("IN"), 321 + SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM, 0, 0, NULL, 0, aw87390_drv_event, 322 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 323 + SND_SOC_DAPM_OUTPUT("OUT"), 324 + }; 325 + 326 + static const struct snd_soc_dapm_route aw87390_dapm_routes[] = { 327 + { "SPK PA", NULL, "IN" }, 328 + { "OUT", NULL, "SPK PA" }, 329 + }; 330 + 331 + static int aw87390_codec_probe(struct snd_soc_component *component) 332 + { 333 + struct aw87390 *aw87390 = snd_soc_component_get_drvdata(component); 334 + int ret; 335 + 336 + ret = aw87390_request_firmware_file(aw87390); 337 + if (ret) 338 + return dev_err_probe(aw87390->aw_pa->dev, ret, 339 + "aw87390_request_firmware_file failed\n"); 340 + 341 + return 0; 342 + } 343 + 344 + static const struct snd_soc_component_driver soc_codec_dev_aw87390 = { 345 + .probe = aw87390_codec_probe, 346 + .dapm_widgets = aw87390_dapm_widgets, 347 + .num_dapm_widgets = ARRAY_SIZE(aw87390_dapm_widgets), 348 + .dapm_routes = aw87390_dapm_routes, 349 + .num_dapm_routes = ARRAY_SIZE(aw87390_dapm_routes), 350 + .controls = aw87390_controls, 351 + .num_controls = ARRAY_SIZE(aw87390_controls), 352 + }; 353 + 354 + static void aw87390_parse_channel_dt(struct aw87390 *aw87390) 355 + { 356 + struct aw_device *aw_dev = aw87390->aw_pa; 357 + struct device_node *np = aw_dev->dev->of_node; 358 + u32 channel_value = AW87390_DEV_DEFAULT_CH; 359 + 360 + of_property_read_u32(np, "awinic,audio-channel", &channel_value); 361 + 362 + aw_dev->channel = channel_value; 363 + } 364 + 365 + static int aw87390_init(struct aw87390 **aw87390, struct i2c_client *i2c, struct regmap *regmap) 366 + { 367 + struct aw_device *aw_dev; 368 + unsigned int chip_id; 369 + int ret; 370 + 371 + /* read chip id */ 372 + ret = regmap_read(regmap, AW87390_ID_REG, &chip_id); 373 + if (ret) { 374 + dev_err(&i2c->dev, "%s read chipid error. ret = %d\n", __func__, ret); 375 + return ret; 376 + } 377 + 378 + if (chip_id != AW87390_CHIP_ID) { 379 + dev_err(&i2c->dev, "unsupported device\n"); 380 + return -ENXIO; 381 + } 382 + 383 + dev_dbg(&i2c->dev, "chip id = 0x%x\n", chip_id); 384 + 385 + aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); 386 + if (!aw_dev) 387 + return -ENOMEM; 388 + 389 + (*aw87390)->aw_pa = aw_dev; 390 + aw_dev->i2c = i2c; 391 + aw_dev->regmap = regmap; 392 + aw_dev->dev = &i2c->dev; 393 + aw_dev->chip_id = AW87390_CHIP_ID; 394 + aw_dev->acf = NULL; 395 + aw_dev->prof_info.prof_desc = NULL; 396 + aw_dev->prof_info.count = 0; 397 + aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; 398 + aw_dev->channel = AW87390_DEV_DEFAULT_CH; 399 + aw_dev->fw_status = AW87390_DEV_FW_FAILED; 400 + aw_dev->prof_index = AW87390_INIT_PROFILE; 401 + aw_dev->status = AW87390_DEV_PW_OFF; 402 + 403 + aw87390_parse_channel_dt(*aw87390); 404 + 405 + return 0; 406 + } 407 + 408 + static int aw87390_i2c_probe(struct i2c_client *i2c) 409 + { 410 + struct aw87390 *aw87390; 411 + int ret; 412 + 413 + ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C); 414 + if (!ret) 415 + return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed\n"); 416 + 417 + aw87390 = devm_kzalloc(&i2c->dev, sizeof(*aw87390), GFP_KERNEL); 418 + if (!aw87390) 419 + return -ENOMEM; 420 + 421 + mutex_init(&aw87390->lock); 422 + 423 + i2c_set_clientdata(i2c, aw87390); 424 + 425 + aw87390->regmap = devm_regmap_init_i2c(i2c, &aw87390_remap_config); 426 + if (IS_ERR(aw87390->regmap)) 427 + return dev_err_probe(&i2c->dev, PTR_ERR(aw87390->regmap), 428 + "failed to init regmap\n"); 429 + 430 + /* aw pa init */ 431 + ret = aw87390_init(&aw87390, i2c, aw87390->regmap); 432 + if (ret) 433 + return ret; 434 + 435 + ret = regmap_write(aw87390->regmap, AW87390_ID_REG, AW87390_SOFT_RESET_VALUE); 436 + if (ret) 437 + return ret; 438 + 439 + ret = devm_snd_soc_register_component(&i2c->dev, 440 + &soc_codec_dev_aw87390, NULL, 0); 441 + if (ret) 442 + dev_err(&i2c->dev, "failed to register aw87390: %d\n", ret); 443 + 444 + return ret; 445 + } 446 + 447 + static const struct i2c_device_id aw87390_i2c_id[] = { 448 + { AW87390_I2C_NAME, 0 }, 449 + { } 450 + }; 451 + MODULE_DEVICE_TABLE(i2c, aw87390_i2c_id); 452 + 453 + static struct i2c_driver aw87390_i2c_driver = { 454 + .driver = { 455 + .name = AW87390_I2C_NAME, 456 + }, 457 + .probe = aw87390_i2c_probe, 458 + .id_table = aw87390_i2c_id, 459 + }; 460 + module_i2c_driver(aw87390_i2c_driver); 461 + 462 + MODULE_DESCRIPTION("ASoC AW87390 PA Driver"); 463 + MODULE_LICENSE("GPL v2");
+85
sound/soc/codecs/aw87390.h
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + // 3 + // aw87390.h -- aw87390 ALSA SoC Audio driver 4 + // 5 + // Copyright (c) 2023 awinic Technology CO., LTD 6 + // 7 + // Author: Weidong Wang <wangweidong.a@awinic.com> 8 + // 9 + 10 + #ifndef __AW87390_H__ 11 + #define __AW87390_H__ 12 + 13 + #define AW87390_ID_REG (0x00) 14 + #define AW87390_SYSCTRL_REG (0x01) 15 + #define AW87390_MDCTRL_REG (0x02) 16 + #define AW87390_CPOVP_REG (0x03) 17 + #define AW87390_CPP_REG (0x04) 18 + #define AW87390_PAG_REG (0x05) 19 + #define AW87390_AGC3P_REG (0x06) 20 + #define AW87390_AGC3PA_REG (0x07) 21 + #define AW87390_AGC2P_REG (0x08) 22 + #define AW87390_AGC2PA_REG (0x09) 23 + #define AW87390_AGC1PA_REG (0x0A) 24 + #define AW87390_SYSST_REG (0x59) 25 + #define AW87390_SYSINT_REG (0x60) 26 + #define AW87390_DFT_SYSCTRL_REG (0x61) 27 + #define AW87390_DFT_MDCTRL_REG (0x62) 28 + #define AW87390_DFT_CPADP_REG (0x63) 29 + #define AW87390_DFT_AGCPA_REG (0x64) 30 + #define AW87390_DFT_POFR_REG (0x65) 31 + #define AW87390_DFT_OC_REG (0x66) 32 + #define AW87390_DFT_ADP1_REG (0x67) 33 + #define AW87390_DFT_REF_REG (0x68) 34 + #define AW87390_DFT_LDO_REG (0x69) 35 + #define AW87390_ADP1_REG (0x70) 36 + #define AW87390_ADP2_REG (0x71) 37 + #define AW87390_NG1_REG (0x72) 38 + #define AW87390_NG2_REG (0x73) 39 + #define AW87390_NG3_REG (0x74) 40 + #define AW87390_CP_REG (0x75) 41 + #define AW87390_AB_REG (0x76) 42 + #define AW87390_TEST_REG (0x77) 43 + #define AW87390_ENCR_REG (0x78) 44 + #define AW87390_DELAY_REG_ADDR (0xFE) 45 + 46 + #define AW87390_SOFT_RESET_VALUE (0xAA) 47 + #define AW87390_POWER_DOWN_VALUE (0x00) 48 + #define AW87390_REG_MAX (0xFF) 49 + #define AW87390_DEV_DEFAULT_CH (0) 50 + #define AW87390_INIT_PROFILE (0) 51 + #define AW87390_REG_DELAY_TIME (1000) 52 + #define AW87390_I2C_NAME "aw87390" 53 + #define AW87390_ACF_FILE "aw87390_acf.bin" 54 + 55 + #define AW87390_PROFILE_EXT(xname, profile_info, profile_get, profile_set) \ 56 + { \ 57 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 58 + .name = xname, \ 59 + .info = profile_info, \ 60 + .get = profile_get, \ 61 + .put = profile_set, \ 62 + } 63 + 64 + enum aw87390_id { 65 + AW87390_CHIP_ID = 0x76, 66 + }; 67 + 68 + enum { 69 + AW87390_DEV_FW_FAILED = 0, 70 + AW87390_DEV_FW_OK, 71 + }; 72 + 73 + enum { 74 + AW87390_DEV_PW_OFF = 0, 75 + AW87390_DEV_PW_ON, 76 + }; 77 + 78 + struct aw87390 { 79 + struct aw_device *aw_pa; 80 + struct mutex lock; 81 + struct regmap *regmap; 82 + struct aw_container *aw_cfg; 83 + }; 84 + 85 + #endif
+13 -14
sound/soc/codecs/aw88261.c
··· 477 477 return ret; 478 478 } 479 479 480 - static char *aw88261_dev_get_prof_name(struct aw_device *aw_dev, int index) 480 + static int aw88261_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) 481 481 { 482 482 struct aw_prof_info *prof_info = &aw_dev->prof_info; 483 483 struct aw_prof_desc *prof_desc; ··· 485 485 if ((index >= aw_dev->prof_info.count) || (index < 0)) { 486 486 dev_err(aw_dev->dev, "index[%d] overflow count[%d]", 487 487 index, aw_dev->prof_info.count); 488 - return NULL; 488 + return -EINVAL; 489 489 } 490 490 491 491 prof_desc = &aw_dev->prof_info.prof_desc[index]; 492 492 493 - return prof_info->prof_name_list[prof_desc->id]; 493 + *prof_name = prof_info->prof_name_list[prof_desc->id]; 494 + 495 + return 0; 494 496 } 495 497 496 498 static int aw88261_dev_get_prof_data(struct aw_device *aw_dev, int index, ··· 517 515 char *prof_name; 518 516 int ret; 519 517 520 - prof_name = aw88261_dev_get_prof_name(aw_dev, aw_dev->prof_index); 521 - if (!prof_name) { 518 + ret = aw88261_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); 519 + if (ret) { 522 520 dev_err(aw_dev->dev, "get prof name failed"); 523 521 return -EINVAL; 524 522 } ··· 820 818 { 821 819 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 822 820 struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); 823 - const char *prof_name; 824 - char *name; 825 - int count; 821 + char *prof_name, *name; 822 + int count, ret; 826 823 827 824 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 828 825 uinfo->count = 1; ··· 840 839 name = uinfo->value.enumerated.name; 841 840 count = uinfo->value.enumerated.item; 842 841 843 - prof_name = aw88261_dev_get_prof_name(aw88261->aw_pa, count); 844 - if (!prof_name) { 842 + ret = aw88261_dev_get_prof_name(aw88261->aw_pa, count, &prof_name); 843 + if (ret) { 845 844 strscpy(uinfo->value.enumerated.name, "null", 846 845 strlen("null") + 1); 847 846 return 0; ··· 1188 1187 struct aw_device *aw_dev = aw88261->aw_pa; 1189 1188 struct device_node *np = aw_dev->dev->of_node; 1190 1189 u32 channel_value = AW88261_DEV_DEFAULT_CH; 1191 - u32 sync_enable = false; 1192 1190 1193 - of_property_read_u32(np, "sound-channel", &channel_value); 1194 - of_property_read_u32(np, "sync-flag", &sync_enable); 1191 + of_property_read_u32(np, "awinic,audio-channel", &channel_value); 1192 + aw88261->phase_sync = of_property_read_bool(np, "awinic,sync-flag"); 1195 1193 1196 1194 aw_dev->channel = channel_value; 1197 - aw88261->phase_sync = sync_enable; 1198 1195 } 1199 1196 1200 1197 static int aw88261_init(struct aw88261 **aw88261, struct i2c_client *i2c, struct regmap *regmap)
+2 -2
sound/soc/codecs/aw88261.h
··· 370 370 #define AW88261_START_RETRIES (5) 371 371 #define AW88261_START_WORK_DELAY_MS (0) 372 372 373 - #define AW88261_I2C_NAME "aw88261_smartpa" 373 + #define AW88261_I2C_NAME "aw88261" 374 374 375 375 #define AW88261_RATES (SNDRV_PCM_RATE_8000_48000 | \ 376 376 SNDRV_PCM_RATE_96000) ··· 453 453 unsigned int mute_st; 454 454 unsigned int amppd_st; 455 455 456 - unsigned char phase_sync; 456 + bool phase_sync; 457 457 }; 458 458 459 459 #endif
+4 -5
sound/soc/codecs/aw88395/aw88395.c
··· 175 175 { 176 176 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 177 177 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec); 178 - const char *prof_name; 179 - char *name; 180 - int count; 178 + char *prof_name, *name; 179 + int count, ret; 181 180 182 181 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 183 182 uinfo->count = 1; ··· 195 196 name = uinfo->value.enumerated.name; 196 197 count = uinfo->value.enumerated.item; 197 198 198 - prof_name = aw88395_dev_get_prof_name(aw88395->aw_pa, count); 199 - if (!prof_name) { 199 + ret = aw88395_dev_get_prof_name(aw88395->aw_pa, count, &prof_name); 200 + if (ret) { 200 201 strscpy(uinfo->value.enumerated.name, "null", 201 202 strlen("null") + 1); 202 203 return 0;
+1 -1
sound/soc/codecs/aw88395/aw88395.h
··· 16 16 17 17 #define AW88395_DSP_16_DATA_MASK (0x0000ffff) 18 18 19 - #define AW88395_I2C_NAME "aw88395_smartpa" 19 + #define AW88395_I2C_NAME "aw88395" 20 20 21 21 #define AW88395_RATES (SNDRV_PCM_RATE_8000_48000 | \ 22 22 SNDRV_PCM_RATE_96000)
+11 -36
sound/soc/codecs/aw88395/aw88395_device.c
··· 297 297 int fade_step = aw_dev->fade_step; 298 298 int i; 299 299 300 - if (!aw_dev->fade_en) 301 - return; 302 - 303 300 if (fade_step == 0 || aw_dev->fade_in_time == 0) { 304 301 aw_dev_set_volume(aw_dev, fade_in_vol); 305 302 return; ··· 316 319 struct aw_volume_desc *desc = &aw_dev->volume_desc; 317 320 int fade_step = aw_dev->fade_step; 318 321 int i; 319 - 320 - if (!aw_dev->fade_en) 321 - return; 322 322 323 323 if (fade_step == 0 || aw_dev->fade_out_time == 0) { 324 324 aw_dev_set_volume(aw_dev, AW88395_MUTE_VOL); ··· 1056 1062 aw_dev_set_volume(aw_dev, vol_desc->ctl_volume); 1057 1063 } 1058 1064 1059 - /* keep min volume */ 1060 - if (aw_dev->fade_en) 1061 - aw_dev_set_volume(aw_dev, AW88395_MUTE_VOL); 1062 - 1063 1065 aw_dev_get_dsp_config(aw_dev, &aw_dev->dsp_cfg); 1064 1066 1065 1067 return ret; ··· 1296 1306 return -EPERM; 1297 1307 } 1298 1308 1299 - prof_name = aw88395_dev_get_prof_name(aw_dev, aw_dev->prof_index); 1309 + ret = aw88395_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); 1310 + if (ret) 1311 + return ret; 1300 1312 1301 1313 dev_dbg(aw_dev->dev, "start update %s", prof_name); 1302 1314 ··· 1586 1594 u32 channel_value; 1587 1595 int ret; 1588 1596 1589 - ret = of_property_read_u32(np, "sound-channel", &channel_value); 1597 + ret = of_property_read_u32(np, "awinic,audio-channel", &channel_value); 1590 1598 if (ret) { 1591 1599 dev_dbg(aw_dev->dev, 1592 - "read sound-channel failed,use default 0"); 1600 + "read audio-channel failed,use default 0"); 1593 1601 aw_dev->channel = AW88395_DEV_DEFAULT_CH; 1594 1602 return; 1595 1603 } 1596 1604 1597 - dev_dbg(aw_dev->dev, "read sound-channel value is: %d", 1605 + dev_dbg(aw_dev->dev, "read audio-channel value is: %d", 1598 1606 channel_value); 1599 1607 aw_dev->channel = channel_value; 1600 - } 1601 - 1602 - static void aw88395_parse_fade_enable_dt(struct aw_device *aw_dev) 1603 - { 1604 - struct device_node *np = aw_dev->dev->of_node; 1605 - u32 fade_en; 1606 - int ret; 1607 - 1608 - ret = of_property_read_u32(np, "fade-enable", &fade_en); 1609 - if (ret) { 1610 - dev_dbg(aw_dev->dev, 1611 - "read fade-enable failed, close fade_in_out"); 1612 - fade_en = AW88395_FADE_IN_OUT_DEFAULT; 1613 - } 1614 - 1615 - dev_dbg(aw_dev->dev, "read fade-enable value is: %d", fade_en); 1616 - 1617 - aw_dev->fade_en = fade_en; 1618 1608 } 1619 1609 1620 1610 static int aw_dev_init(struct aw_device *aw_dev) ··· 1613 1639 aw_dev->fade_step = AW88395_VOLUME_STEP_DB; 1614 1640 aw_dev->volume_desc.ctl_volume = AW88395_VOL_DEFAULT_VALUE; 1615 1641 aw88395_parse_channel_dt(aw_dev); 1616 - aw88395_parse_fade_enable_dt(aw_dev); 1617 1642 1618 1643 return 0; 1619 1644 } ··· 1646 1673 } 1647 1674 EXPORT_SYMBOL_GPL(aw88395_dev_set_profile_index); 1648 1675 1649 - char *aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index) 1676 + int aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) 1650 1677 { 1651 1678 struct aw_prof_info *prof_info = &aw_dev->prof_info; 1652 1679 struct aw_prof_desc *prof_desc; ··· 1654 1681 if ((index >= aw_dev->prof_info.count) || (index < 0)) { 1655 1682 dev_err(aw_dev->dev, "index[%d] overflow count[%d]", 1656 1683 index, aw_dev->prof_info.count); 1657 - return NULL; 1684 + return -EINVAL; 1658 1685 } 1659 1686 1660 1687 prof_desc = &aw_dev->prof_info.prof_desc[index]; 1661 1688 1662 - return prof_info->prof_name_list[prof_desc->id]; 1689 + *prof_name = prof_info->prof_name_list[prof_desc->id]; 1690 + 1691 + return 0; 1663 1692 } 1664 1693 EXPORT_SYMBOL_GPL(aw88395_dev_get_prof_name); 1665 1694
+2 -4
sound/soc/codecs/aw88395/aw88395_device.h
··· 141 141 unsigned char prof_cur; 142 142 unsigned char prof_index; 143 143 unsigned char dsp_crc_st; 144 + unsigned char dsp_cfg; 144 145 u16 chip_id; 145 146 146 147 unsigned int channel; ··· 151 150 struct device *dev; 152 151 struct regmap *regmap; 153 152 char *acf; 154 - 155 - u32 fade_en; 156 - unsigned char dsp_cfg; 157 153 158 154 u32 dsp_fw_len; 159 155 u32 dsp_cfg_len; ··· 181 183 void aw88395_dev_set_volume(struct aw_device *aw_dev, unsigned short set_vol); 182 184 int aw88395_dev_get_prof_data(struct aw_device *aw_dev, int index, 183 185 struct aw_prof_desc **prof_desc); 184 - char *aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index); 186 + int aw88395_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name); 185 187 int aw88395_dev_set_profile_index(struct aw_device *aw_dev, int index); 186 188 int aw88395_dev_get_profile_index(struct aw_device *aw_dev); 187 189 int aw88395_dev_get_profile_count(struct aw_device *aw_dev);
+15 -10
sound/soc/codecs/aw88395/aw88395_lib.c
··· 456 456 goto parse_bin_failed; 457 457 } 458 458 459 - if (aw_bin->header_info[0].valid_data_len % 4) { 460 - dev_err(aw_dev->dev, "bin data len get error!"); 461 - ret = -EINVAL; 462 - goto parse_bin_failed; 459 + if (aw_dev->chip_id == AW88261_CHIP_ID) { 460 + if (aw_bin->header_info[0].valid_data_len % 4) { 461 + dev_err(aw_dev->dev, "bin data len get error!"); 462 + ret = -EINVAL; 463 + goto parse_bin_failed; 464 + } 463 465 } 464 466 465 467 prof_desc->sec_desc[AW88395_DATA_TYPE_REG].data = ··· 583 581 } 584 582 585 583 static int aw88261_dev_cfg_get_valid_prof(struct aw_device *aw_dev, 586 - struct aw_all_prof_info all_prof_info) 584 + struct aw_all_prof_info *all_prof_info) 587 585 { 588 - struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; 586 + struct aw_prof_desc *prof_desc = all_prof_info->prof_desc; 589 587 struct aw_prof_info *prof_info = &aw_dev->prof_info; 590 588 int num = 0; 591 589 int i; ··· 625 623 } 626 624 627 625 static int aw88395_dev_cfg_get_valid_prof(struct aw_device *aw_dev, 628 - struct aw_all_prof_info all_prof_info) 626 + struct aw_all_prof_info *all_prof_info) 629 627 { 630 - struct aw_prof_desc *prof_desc = all_prof_info.prof_desc; 628 + struct aw_prof_desc *prof_desc = all_prof_info->prof_desc; 631 629 struct aw_prof_info *prof_info = &aw_dev->prof_info; 632 630 struct aw_sec_data_desc *sec_desc; 633 631 int num = 0; ··· 705 703 706 704 switch (aw_dev->chip_id) { 707 705 case AW88395_CHIP_ID: 708 - ret = aw88395_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); 706 + ret = aw88395_dev_cfg_get_valid_prof(aw_dev, all_prof_info); 709 707 if (ret < 0) 710 708 goto exit; 711 709 break; 712 710 case AW88261_CHIP_ID: 713 - ret = aw88261_dev_cfg_get_valid_prof(aw_dev, *all_prof_info); 711 + case AW87390_CHIP_ID: 712 + ret = aw88261_dev_cfg_get_valid_prof(aw_dev, all_prof_info); 714 713 if (ret < 0) 715 714 goto exit; 716 715 break; ··· 804 801 ret = 0; 805 802 break; 806 803 case AW88261_CHIP_ID: 804 + case AW87390_CHIP_ID: 807 805 for (i = 0; i < cfg_hdr->ddt_num; ++i) { 808 806 if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || 809 807 (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) && ··· 845 841 ret = 0; 846 842 break; 847 843 case AW88261_CHIP_ID: 844 + case AW87390_CHIP_ID: 848 845 for (i = 0; i < cfg_hdr->ddt_num; ++i) { 849 846 if (((cfg_dde[i].data_type == ACF_SEC_TYPE_REG) || 850 847 (cfg_dde[i].data_type == ACF_SEC_TYPE_HDR_REG)) &&
+1
sound/soc/codecs/aw88395/aw88395_reg.h
··· 97 97 enum aw88395_id { 98 98 AW88395_CHIP_ID = 0x2049, 99 99 AW88261_CHIP_ID = 0x2113, 100 + AW87390_CHIP_ID = 0x76, 100 101 }; 101 102 102 103 #define AW88395_REG_MAX (0x7D)