162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// aw88395.c -- ALSA SoC AW88395 codec support 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (c) 2022-2023 AWINIC Technology CO., LTD 662306a36Sopenharmony_ci// 762306a36Sopenharmony_ci// Author: Bruce zhao <zhaolei@awinic.com> 862306a36Sopenharmony_ci// Author: Weidong Wang <wangweidong.a@awinic.com> 962306a36Sopenharmony_ci// 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/firmware.h> 1362306a36Sopenharmony_ci#include <linux/of_gpio.h> 1462306a36Sopenharmony_ci#include <linux/regmap.h> 1562306a36Sopenharmony_ci#include <sound/soc.h> 1662306a36Sopenharmony_ci#include "aw88395.h" 1762306a36Sopenharmony_ci#include "aw88395_device.h" 1862306a36Sopenharmony_ci#include "aw88395_lib.h" 1962306a36Sopenharmony_ci#include "aw88395_reg.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic const struct regmap_config aw88395_remap_config = { 2262306a36Sopenharmony_ci .val_bits = 16, 2362306a36Sopenharmony_ci .reg_bits = 8, 2462306a36Sopenharmony_ci .max_register = AW88395_REG_MAX - 1, 2562306a36Sopenharmony_ci .reg_format_endian = REGMAP_ENDIAN_LITTLE, 2662306a36Sopenharmony_ci .val_format_endian = REGMAP_ENDIAN_BIG, 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic void aw88395_start_pa(struct aw88395 *aw88395) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci int ret, i; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci for (i = 0; i < AW88395_START_RETRIES; i++) { 3462306a36Sopenharmony_ci ret = aw88395_dev_start(aw88395->aw_pa); 3562306a36Sopenharmony_ci if (ret) { 3662306a36Sopenharmony_ci dev_err(aw88395->aw_pa->dev, "aw88395 device start failed. retry = %d", i); 3762306a36Sopenharmony_ci ret = aw88395_dev_fw_update(aw88395->aw_pa, AW88395_DSP_FW_UPDATE_ON, true); 3862306a36Sopenharmony_ci if (ret < 0) { 3962306a36Sopenharmony_ci dev_err(aw88395->aw_pa->dev, "fw update failed"); 4062306a36Sopenharmony_ci continue; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci } else { 4362306a36Sopenharmony_ci dev_info(aw88395->aw_pa->dev, "start success\n"); 4462306a36Sopenharmony_ci break; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic void aw88395_startup_work(struct work_struct *work) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct aw88395 *aw88395 = 5262306a36Sopenharmony_ci container_of(work, struct aw88395, start_work.work); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci mutex_lock(&aw88395->lock); 5562306a36Sopenharmony_ci aw88395_start_pa(aw88395); 5662306a36Sopenharmony_ci mutex_unlock(&aw88395->lock); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void aw88395_start(struct aw88395 *aw88395, bool sync_start) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci int ret; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (aw88395->aw_pa->fw_status != AW88395_DEV_FW_OK) 6462306a36Sopenharmony_ci return; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (aw88395->aw_pa->status == AW88395_DEV_PW_ON) 6762306a36Sopenharmony_ci return; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci ret = aw88395_dev_fw_update(aw88395->aw_pa, AW88395_DSP_FW_UPDATE_OFF, true); 7062306a36Sopenharmony_ci if (ret < 0) { 7162306a36Sopenharmony_ci dev_err(aw88395->aw_pa->dev, "fw update failed."); 7262306a36Sopenharmony_ci return; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (sync_start == AW88395_SYNC_START) 7662306a36Sopenharmony_ci aw88395_start_pa(aw88395); 7762306a36Sopenharmony_ci else 7862306a36Sopenharmony_ci queue_delayed_work(system_wq, 7962306a36Sopenharmony_ci &aw88395->start_work, 8062306a36Sopenharmony_ci AW88395_START_WORK_DELAY_MS); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic struct snd_soc_dai_driver aw88395_dai[] = { 8462306a36Sopenharmony_ci { 8562306a36Sopenharmony_ci .name = "aw88395-aif", 8662306a36Sopenharmony_ci .id = 1, 8762306a36Sopenharmony_ci .playback = { 8862306a36Sopenharmony_ci .stream_name = "Speaker_Playback", 8962306a36Sopenharmony_ci .channels_min = 1, 9062306a36Sopenharmony_ci .channels_max = 2, 9162306a36Sopenharmony_ci .rates = AW88395_RATES, 9262306a36Sopenharmony_ci .formats = AW88395_FORMATS, 9362306a36Sopenharmony_ci }, 9462306a36Sopenharmony_ci .capture = { 9562306a36Sopenharmony_ci .stream_name = "Speaker_Capture", 9662306a36Sopenharmony_ci .channels_min = 1, 9762306a36Sopenharmony_ci .channels_max = 2, 9862306a36Sopenharmony_ci .rates = AW88395_RATES, 9962306a36Sopenharmony_ci .formats = AW88395_FORMATS, 10062306a36Sopenharmony_ci }, 10162306a36Sopenharmony_ci }, 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int aw88395_get_fade_in_time(struct snd_kcontrol *kcontrol, 10562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 10862306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component); 10962306a36Sopenharmony_ci struct aw_device *aw_dev = aw88395->aw_pa; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ucontrol->value.integer.value[0] = aw_dev->fade_in_time; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int aw88395_set_fade_in_time(struct snd_kcontrol *kcontrol, 11762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 12062306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component); 12162306a36Sopenharmony_ci struct soc_mixer_control *mc = 12262306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 12362306a36Sopenharmony_ci struct aw_device *aw_dev = aw88395->aw_pa; 12462306a36Sopenharmony_ci int time; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci time = ucontrol->value.integer.value[0]; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (time < mc->min || time > mc->max) 12962306a36Sopenharmony_ci return -EINVAL; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (time != aw_dev->fade_in_time) { 13262306a36Sopenharmony_ci aw_dev->fade_in_time = time; 13362306a36Sopenharmony_ci return 1; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic int aw88395_get_fade_out_time(struct snd_kcontrol *kcontrol, 14062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 14362306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component); 14462306a36Sopenharmony_ci struct aw_device *aw_dev = aw88395->aw_pa; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = aw_dev->fade_out_time; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return 0; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic int aw88395_set_fade_out_time(struct snd_kcontrol *kcontrol, 15262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 15562306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component); 15662306a36Sopenharmony_ci struct soc_mixer_control *mc = 15762306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 15862306a36Sopenharmony_ci struct aw_device *aw_dev = aw88395->aw_pa; 15962306a36Sopenharmony_ci int time; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci time = ucontrol->value.integer.value[0]; 16262306a36Sopenharmony_ci if (time < mc->min || time > mc->max) 16362306a36Sopenharmony_ci return -EINVAL; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (time != aw_dev->fade_out_time) { 16662306a36Sopenharmony_ci aw_dev->fade_out_time = time; 16762306a36Sopenharmony_ci return 1; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int aw88395_profile_info(struct snd_kcontrol *kcontrol, 17462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 17762306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec); 17862306a36Sopenharmony_ci const char *prof_name; 17962306a36Sopenharmony_ci char *name; 18062306a36Sopenharmony_ci int count; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 18362306a36Sopenharmony_ci uinfo->count = 1; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci count = aw88395_dev_get_profile_count(aw88395->aw_pa); 18662306a36Sopenharmony_ci if (count <= 0) { 18762306a36Sopenharmony_ci uinfo->value.enumerated.items = 0; 18862306a36Sopenharmony_ci return 0; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci uinfo->value.enumerated.items = count; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (uinfo->value.enumerated.item >= count) 19462306a36Sopenharmony_ci uinfo->value.enumerated.item = count - 1; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci name = uinfo->value.enumerated.name; 19762306a36Sopenharmony_ci count = uinfo->value.enumerated.item; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci prof_name = aw88395_dev_get_prof_name(aw88395->aw_pa, count); 20062306a36Sopenharmony_ci if (!prof_name) { 20162306a36Sopenharmony_ci strscpy(uinfo->value.enumerated.name, "null", 20262306a36Sopenharmony_ci strlen("null") + 1); 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name)); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int aw88395_profile_get(struct snd_kcontrol *kcontrol, 21262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 21562306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ucontrol->value.integer.value[0] = aw88395_dev_get_profile_index(aw88395->aw_pa); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return 0; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic int aw88395_profile_set(struct snd_kcontrol *kcontrol, 22362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 22662306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec); 22762306a36Sopenharmony_ci int ret; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* pa stop or stopping just set profile */ 23062306a36Sopenharmony_ci mutex_lock(&aw88395->lock); 23162306a36Sopenharmony_ci ret = aw88395_dev_set_profile_index(aw88395->aw_pa, ucontrol->value.integer.value[0]); 23262306a36Sopenharmony_ci if (ret < 0) { 23362306a36Sopenharmony_ci dev_dbg(codec->dev, "profile index does not change"); 23462306a36Sopenharmony_ci mutex_unlock(&aw88395->lock); 23562306a36Sopenharmony_ci return 0; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (aw88395->aw_pa->status) { 23962306a36Sopenharmony_ci aw88395_dev_stop(aw88395->aw_pa); 24062306a36Sopenharmony_ci aw88395_start(aw88395, AW88395_SYNC_START); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci mutex_unlock(&aw88395->lock); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci return 1; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int aw88395_volume_get(struct snd_kcontrol *kcontrol, 24962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 25262306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec); 25362306a36Sopenharmony_ci struct aw_volume_desc *vol_desc = &aw88395->aw_pa->volume_desc; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci ucontrol->value.integer.value[0] = vol_desc->ctl_volume; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return 0; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int aw88395_volume_set(struct snd_kcontrol *kcontrol, 26162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 26462306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec); 26562306a36Sopenharmony_ci struct aw_volume_desc *vol_desc = &aw88395->aw_pa->volume_desc; 26662306a36Sopenharmony_ci struct soc_mixer_control *mc = 26762306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 26862306a36Sopenharmony_ci int value; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci value = ucontrol->value.integer.value[0]; 27162306a36Sopenharmony_ci if (value < mc->min || value > mc->max) 27262306a36Sopenharmony_ci return -EINVAL; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (vol_desc->ctl_volume != value) { 27562306a36Sopenharmony_ci vol_desc->ctl_volume = value; 27662306a36Sopenharmony_ci aw88395_dev_set_volume(aw88395->aw_pa, vol_desc->ctl_volume); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return 1; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int aw88395_get_fade_step(struct snd_kcontrol *kcontrol, 28562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 28862306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = aw88395->aw_pa->fade_step; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic int aw88395_set_fade_step(struct snd_kcontrol *kcontrol, 29662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 29962306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec); 30062306a36Sopenharmony_ci struct soc_mixer_control *mc = 30162306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 30262306a36Sopenharmony_ci int value; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci value = ucontrol->value.integer.value[0]; 30562306a36Sopenharmony_ci if (value < mc->min || value > mc->max) 30662306a36Sopenharmony_ci return -EINVAL; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (aw88395->aw_pa->fade_step != value) { 30962306a36Sopenharmony_ci aw88395->aw_pa->fade_step = value; 31062306a36Sopenharmony_ci return 1; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic int aw88395_re_get(struct snd_kcontrol *kcontrol, 31762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 32062306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec); 32162306a36Sopenharmony_ci struct aw_device *aw_dev = aw88395->aw_pa; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci ucontrol->value.integer.value[0] = aw_dev->cali_desc.cali_re; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic int aw88395_re_set(struct snd_kcontrol *kcontrol, 32962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); 33262306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec); 33362306a36Sopenharmony_ci struct soc_mixer_control *mc = 33462306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 33562306a36Sopenharmony_ci struct aw_device *aw_dev = aw88395->aw_pa; 33662306a36Sopenharmony_ci int value; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci value = ucontrol->value.integer.value[0]; 33962306a36Sopenharmony_ci if (value < mc->min || value > mc->max) 34062306a36Sopenharmony_ci return -EINVAL; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (aw_dev->cali_desc.cali_re != value) { 34362306a36Sopenharmony_ci aw_dev->cali_desc.cali_re = value; 34462306a36Sopenharmony_ci return 1; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic const struct snd_kcontrol_new aw88395_controls[] = { 35162306a36Sopenharmony_ci SOC_SINGLE_EXT("PCM Playback Volume", AW88395_SYSCTRL2_REG, 35262306a36Sopenharmony_ci 6, AW88395_MUTE_VOL, 0, aw88395_volume_get, 35362306a36Sopenharmony_ci aw88395_volume_set), 35462306a36Sopenharmony_ci SOC_SINGLE_EXT("Fade Step", 0, 0, AW88395_MUTE_VOL, 0, 35562306a36Sopenharmony_ci aw88395_get_fade_step, aw88395_set_fade_step), 35662306a36Sopenharmony_ci SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, 35762306a36Sopenharmony_ci aw88395_get_fade_in_time, aw88395_set_fade_in_time), 35862306a36Sopenharmony_ci SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, 35962306a36Sopenharmony_ci aw88395_get_fade_out_time, aw88395_set_fade_out_time), 36062306a36Sopenharmony_ci SOC_SINGLE_EXT("Calib", 0, 0, 100, 0, 36162306a36Sopenharmony_ci aw88395_re_get, aw88395_re_set), 36262306a36Sopenharmony_ci AW88395_PROFILE_EXT("Profile Set", aw88395_profile_info, 36362306a36Sopenharmony_ci aw88395_profile_get, aw88395_profile_set), 36462306a36Sopenharmony_ci}; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int aw88395_playback_event(struct snd_soc_dapm_widget *w, 36762306a36Sopenharmony_ci struct snd_kcontrol *k, int event) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 37062306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci mutex_lock(&aw88395->lock); 37362306a36Sopenharmony_ci switch (event) { 37462306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 37562306a36Sopenharmony_ci aw88395_start(aw88395, AW88395_ASYNC_START); 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 37862306a36Sopenharmony_ci aw88395_dev_stop(aw88395->aw_pa); 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci default: 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci mutex_unlock(&aw88395->lock); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget aw88395_dapm_widgets[] = { 38962306a36Sopenharmony_ci /* playback */ 39062306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, 0, 0, 0, 39162306a36Sopenharmony_ci aw88395_playback_event, 39262306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 39362306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("DAC Output"), 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* capture */ 39662306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0), 39762306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("ADC Input"), 39862306a36Sopenharmony_ci}; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic const struct snd_soc_dapm_route aw88395_audio_map[] = { 40162306a36Sopenharmony_ci {"DAC Output", NULL, "AIF_RX"}, 40262306a36Sopenharmony_ci {"AIF_TX", NULL, "ADC Input"}, 40362306a36Sopenharmony_ci}; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int aw88395_codec_probe(struct snd_soc_component *component) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 40862306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component); 40962306a36Sopenharmony_ci int ret; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci INIT_DELAYED_WORK(&aw88395->start_work, aw88395_startup_work); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* add widgets */ 41462306a36Sopenharmony_ci ret = snd_soc_dapm_new_controls(dapm, aw88395_dapm_widgets, 41562306a36Sopenharmony_ci ARRAY_SIZE(aw88395_dapm_widgets)); 41662306a36Sopenharmony_ci if (ret < 0) 41762306a36Sopenharmony_ci return ret; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* add route */ 42062306a36Sopenharmony_ci ret = snd_soc_dapm_add_routes(dapm, aw88395_audio_map, 42162306a36Sopenharmony_ci ARRAY_SIZE(aw88395_audio_map)); 42262306a36Sopenharmony_ci if (ret < 0) 42362306a36Sopenharmony_ci return ret; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci ret = snd_soc_add_component_controls(component, aw88395_controls, 42662306a36Sopenharmony_ci ARRAY_SIZE(aw88395_controls)); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return ret; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic void aw88395_codec_remove(struct snd_soc_component *aw_codec) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct aw88395 *aw88395 = snd_soc_component_get_drvdata(aw_codec); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci cancel_delayed_work_sync(&aw88395->start_work); 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_codec_dev_aw88395 = { 43962306a36Sopenharmony_ci .probe = aw88395_codec_probe, 44062306a36Sopenharmony_ci .remove = aw88395_codec_remove, 44162306a36Sopenharmony_ci}; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic struct aw88395 *aw88395_malloc_init(struct i2c_client *i2c) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct aw88395 *aw88395 = devm_kzalloc(&i2c->dev, 44662306a36Sopenharmony_ci sizeof(struct aw88395), GFP_KERNEL); 44762306a36Sopenharmony_ci if (!aw88395) 44862306a36Sopenharmony_ci return NULL; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci mutex_init(&aw88395->lock); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return aw88395; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic void aw88395_hw_reset(struct aw88395 *aw88395) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci if (aw88395->reset_gpio) { 45862306a36Sopenharmony_ci gpiod_set_value_cansleep(aw88395->reset_gpio, 0); 45962306a36Sopenharmony_ci usleep_range(AW88395_1000_US, AW88395_1000_US + 10); 46062306a36Sopenharmony_ci gpiod_set_value_cansleep(aw88395->reset_gpio, 1); 46162306a36Sopenharmony_ci usleep_range(AW88395_1000_US, AW88395_1000_US + 10); 46262306a36Sopenharmony_ci } else { 46362306a36Sopenharmony_ci dev_err(aw88395->aw_pa->dev, "%s failed", __func__); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic int aw88395_request_firmware_file(struct aw88395 *aw88395) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci const struct firmware *cont = NULL; 47062306a36Sopenharmony_ci int ret; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci aw88395->aw_pa->fw_status = AW88395_DEV_FW_FAILED; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci ret = request_firmware(&cont, AW88395_ACF_FILE, aw88395->aw_pa->dev); 47562306a36Sopenharmony_ci if ((ret < 0) || (!cont)) { 47662306a36Sopenharmony_ci dev_err(aw88395->aw_pa->dev, "load [%s] failed!", AW88395_ACF_FILE); 47762306a36Sopenharmony_ci return ret; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci dev_info(aw88395->aw_pa->dev, "loaded %s - size: %zu\n", 48162306a36Sopenharmony_ci AW88395_ACF_FILE, cont ? cont->size : 0); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci aw88395->aw_cfg = devm_kzalloc(aw88395->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL); 48462306a36Sopenharmony_ci if (!aw88395->aw_cfg) { 48562306a36Sopenharmony_ci release_firmware(cont); 48662306a36Sopenharmony_ci return -ENOMEM; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci aw88395->aw_cfg->len = (int)cont->size; 48962306a36Sopenharmony_ci memcpy(aw88395->aw_cfg->data, cont->data, cont->size); 49062306a36Sopenharmony_ci release_firmware(cont); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci ret = aw88395_dev_load_acf_check(aw88395->aw_pa, aw88395->aw_cfg); 49362306a36Sopenharmony_ci if (ret < 0) { 49462306a36Sopenharmony_ci dev_err(aw88395->aw_pa->dev, "Load [%s] failed ....!", AW88395_ACF_FILE); 49562306a36Sopenharmony_ci return ret; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci dev_dbg(aw88395->aw_pa->dev, "%s : bin load success\n", __func__); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci mutex_lock(&aw88395->lock); 50162306a36Sopenharmony_ci /* aw device init */ 50262306a36Sopenharmony_ci ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg); 50362306a36Sopenharmony_ci if (ret < 0) 50462306a36Sopenharmony_ci dev_err(aw88395->aw_pa->dev, "dev init failed"); 50562306a36Sopenharmony_ci mutex_unlock(&aw88395->lock); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return ret; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic int aw88395_i2c_probe(struct i2c_client *i2c) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct aw88395 *aw88395; 51362306a36Sopenharmony_ci int ret; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { 51662306a36Sopenharmony_ci dev_err(&i2c->dev, "check_functionality failed"); 51762306a36Sopenharmony_ci return -EIO; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci aw88395 = aw88395_malloc_init(i2c); 52162306a36Sopenharmony_ci if (!aw88395) { 52262306a36Sopenharmony_ci dev_err(&i2c->dev, "malloc aw88395 failed"); 52362306a36Sopenharmony_ci return -ENOMEM; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci i2c_set_clientdata(i2c, aw88395); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci aw88395->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); 52862306a36Sopenharmony_ci if (IS_ERR(aw88395->reset_gpio)) 52962306a36Sopenharmony_ci dev_info(&i2c->dev, "reset gpio not defined\n"); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* hardware reset */ 53262306a36Sopenharmony_ci aw88395_hw_reset(aw88395); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci aw88395->regmap = devm_regmap_init_i2c(i2c, &aw88395_remap_config); 53562306a36Sopenharmony_ci if (IS_ERR(aw88395->regmap)) { 53662306a36Sopenharmony_ci ret = PTR_ERR(aw88395->regmap); 53762306a36Sopenharmony_ci dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); 53862306a36Sopenharmony_ci return ret; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* aw pa init */ 54262306a36Sopenharmony_ci ret = aw88395_init(&aw88395->aw_pa, i2c, aw88395->regmap); 54362306a36Sopenharmony_ci if (ret < 0) 54462306a36Sopenharmony_ci return ret; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ret = aw88395_request_firmware_file(aw88395); 54762306a36Sopenharmony_ci if (ret < 0) { 54862306a36Sopenharmony_ci dev_err(&i2c->dev, "%s failed\n", __func__); 54962306a36Sopenharmony_ci return ret; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&i2c->dev, 55362306a36Sopenharmony_ci &soc_codec_dev_aw88395, 55462306a36Sopenharmony_ci aw88395_dai, ARRAY_SIZE(aw88395_dai)); 55562306a36Sopenharmony_ci if (ret < 0) { 55662306a36Sopenharmony_ci dev_err(&i2c->dev, "failed to register aw88395: %d", ret); 55762306a36Sopenharmony_ci return ret; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic const struct i2c_device_id aw88395_i2c_id[] = { 56462306a36Sopenharmony_ci { AW88395_I2C_NAME, 0 }, 56562306a36Sopenharmony_ci { } 56662306a36Sopenharmony_ci}; 56762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, aw88395_i2c_id); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic struct i2c_driver aw88395_i2c_driver = { 57062306a36Sopenharmony_ci .driver = { 57162306a36Sopenharmony_ci .name = AW88395_I2C_NAME, 57262306a36Sopenharmony_ci }, 57362306a36Sopenharmony_ci .probe = aw88395_i2c_probe, 57462306a36Sopenharmony_ci .id_table = aw88395_i2c_id, 57562306a36Sopenharmony_ci}; 57662306a36Sopenharmony_cimodule_i2c_driver(aw88395_i2c_driver); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC AW88395 Smart PA Driver"); 57962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 580