579 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// aw88395.c -- ALSA SoC AW88395 codec support4//5// Copyright (c) 2022-2023 AWINIC Technology CO., LTD6//7// Author: Bruce zhao <zhaolei@awinic.com>8// Author: Weidong Wang <wangweidong.a@awinic.com>9//10 11#include <linux/gpio/consumer.h>12#include <linux/i2c.h>13#include <linux/firmware.h>14#include <linux/regmap.h>15#include <sound/soc.h>16#include "aw88395.h"17#include "aw88395_device.h"18#include "aw88395_lib.h"19#include "aw88395_reg.h"20 21static const struct regmap_config aw88395_remap_config = {22 .val_bits = 16,23 .reg_bits = 8,24 .max_register = AW88395_REG_MAX - 1,25 .reg_format_endian = REGMAP_ENDIAN_LITTLE,26 .val_format_endian = REGMAP_ENDIAN_BIG,27};28 29static void aw88395_start_pa(struct aw88395 *aw88395)30{31 int ret, i;32 33 for (i = 0; i < AW88395_START_RETRIES; i++) {34 ret = aw88395_dev_start(aw88395->aw_pa);35 if (ret) {36 dev_err(aw88395->aw_pa->dev, "aw88395 device start failed. retry = %d", i);37 ret = aw88395_dev_fw_update(aw88395->aw_pa, AW88395_DSP_FW_UPDATE_ON, true);38 if (ret < 0) {39 dev_err(aw88395->aw_pa->dev, "fw update failed");40 continue;41 }42 } else {43 dev_info(aw88395->aw_pa->dev, "start success\n");44 break;45 }46 }47}48 49static void aw88395_startup_work(struct work_struct *work)50{51 struct aw88395 *aw88395 =52 container_of(work, struct aw88395, start_work.work);53 54 mutex_lock(&aw88395->lock);55 aw88395_start_pa(aw88395);56 mutex_unlock(&aw88395->lock);57}58 59static void aw88395_start(struct aw88395 *aw88395, bool sync_start)60{61 int ret;62 63 if (aw88395->aw_pa->fw_status != AW88395_DEV_FW_OK)64 return;65 66 if (aw88395->aw_pa->status == AW88395_DEV_PW_ON)67 return;68 69 ret = aw88395_dev_fw_update(aw88395->aw_pa, AW88395_DSP_FW_UPDATE_OFF, true);70 if (ret < 0) {71 dev_err(aw88395->aw_pa->dev, "fw update failed.");72 return;73 }74 75 if (sync_start == AW88395_SYNC_START)76 aw88395_start_pa(aw88395);77 else78 queue_delayed_work(system_wq,79 &aw88395->start_work,80 AW88395_START_WORK_DELAY_MS);81}82 83static struct snd_soc_dai_driver aw88395_dai[] = {84 {85 .name = "aw88395-aif",86 .id = 1,87 .playback = {88 .stream_name = "Speaker_Playback",89 .channels_min = 1,90 .channels_max = 2,91 .rates = AW88395_RATES,92 .formats = AW88395_FORMATS,93 },94 .capture = {95 .stream_name = "Speaker_Capture",96 .channels_min = 1,97 .channels_max = 2,98 .rates = AW88395_RATES,99 .formats = AW88395_FORMATS,100 },101 },102};103 104static int aw88395_get_fade_in_time(struct snd_kcontrol *kcontrol,105 struct snd_ctl_elem_value *ucontrol)106{107 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);108 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);109 struct aw_device *aw_dev = aw88395->aw_pa;110 111 ucontrol->value.integer.value[0] = aw_dev->fade_in_time;112 113 return 0;114}115 116static int aw88395_set_fade_in_time(struct snd_kcontrol *kcontrol,117 struct snd_ctl_elem_value *ucontrol)118{119 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);120 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);121 struct soc_mixer_control *mc =122 (struct soc_mixer_control *)kcontrol->private_value;123 struct aw_device *aw_dev = aw88395->aw_pa;124 int time;125 126 time = ucontrol->value.integer.value[0];127 128 if (time < mc->min || time > mc->max)129 return -EINVAL;130 131 if (time != aw_dev->fade_in_time) {132 aw_dev->fade_in_time = time;133 return 1;134 }135 136 return 0;137}138 139static int aw88395_get_fade_out_time(struct snd_kcontrol *kcontrol,140 struct snd_ctl_elem_value *ucontrol)141{142 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);143 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);144 struct aw_device *aw_dev = aw88395->aw_pa;145 146 ucontrol->value.integer.value[0] = aw_dev->fade_out_time;147 148 return 0;149}150 151static int aw88395_set_fade_out_time(struct snd_kcontrol *kcontrol,152 struct snd_ctl_elem_value *ucontrol)153{154 struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);155 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);156 struct soc_mixer_control *mc =157 (struct soc_mixer_control *)kcontrol->private_value;158 struct aw_device *aw_dev = aw88395->aw_pa;159 int time;160 161 time = ucontrol->value.integer.value[0];162 if (time < mc->min || time > mc->max)163 return -EINVAL;164 165 if (time != aw_dev->fade_out_time) {166 aw_dev->fade_out_time = time;167 return 1;168 }169 170 return 0;171}172 173static int aw88395_profile_info(struct snd_kcontrol *kcontrol,174 struct snd_ctl_elem_info *uinfo)175{176 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);177 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);178 char *prof_name, *name;179 int count, ret;180 181 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;182 uinfo->count = 1;183 184 count = aw88395_dev_get_profile_count(aw88395->aw_pa);185 if (count <= 0) {186 uinfo->value.enumerated.items = 0;187 return 0;188 }189 190 uinfo->value.enumerated.items = count;191 192 if (uinfo->value.enumerated.item >= count)193 uinfo->value.enumerated.item = count - 1;194 195 name = uinfo->value.enumerated.name;196 count = uinfo->value.enumerated.item;197 198 ret = aw88395_dev_get_prof_name(aw88395->aw_pa, count, &prof_name);199 if (ret) {200 strscpy(uinfo->value.enumerated.name, "null",201 strlen("null") + 1);202 return 0;203 }204 205 strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name));206 207 return 0;208}209 210static int aw88395_profile_get(struct snd_kcontrol *kcontrol,211 struct snd_ctl_elem_value *ucontrol)212{213 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);214 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);215 216 ucontrol->value.integer.value[0] = aw88395_dev_get_profile_index(aw88395->aw_pa);217 218 return 0;219}220 221static int aw88395_profile_set(struct snd_kcontrol *kcontrol,222 struct snd_ctl_elem_value *ucontrol)223{224 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);225 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);226 int ret;227 228 /* pa stop or stopping just set profile */229 mutex_lock(&aw88395->lock);230 ret = aw88395_dev_set_profile_index(aw88395->aw_pa, ucontrol->value.integer.value[0]);231 if (ret < 0) {232 dev_dbg(codec->dev, "profile index does not change");233 mutex_unlock(&aw88395->lock);234 return 0;235 }236 237 if (aw88395->aw_pa->status) {238 aw88395_dev_stop(aw88395->aw_pa);239 aw88395_start(aw88395, AW88395_SYNC_START);240 }241 242 mutex_unlock(&aw88395->lock);243 244 return 1;245}246 247static int aw88395_volume_get(struct snd_kcontrol *kcontrol,248 struct snd_ctl_elem_value *ucontrol)249{250 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);251 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);252 struct aw_volume_desc *vol_desc = &aw88395->aw_pa->volume_desc;253 254 ucontrol->value.integer.value[0] = vol_desc->ctl_volume;255 256 return 0;257}258 259static int aw88395_volume_set(struct snd_kcontrol *kcontrol,260 struct snd_ctl_elem_value *ucontrol)261{262 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);263 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);264 struct aw_volume_desc *vol_desc = &aw88395->aw_pa->volume_desc;265 struct soc_mixer_control *mc =266 (struct soc_mixer_control *)kcontrol->private_value;267 int value;268 269 value = ucontrol->value.integer.value[0];270 if (value < mc->min || value > mc->max)271 return -EINVAL;272 273 if (vol_desc->ctl_volume != value) {274 vol_desc->ctl_volume = value;275 aw88395_dev_set_volume(aw88395->aw_pa, vol_desc->ctl_volume);276 277 return 1;278 }279 280 return 0;281}282 283static int aw88395_get_fade_step(struct snd_kcontrol *kcontrol,284 struct snd_ctl_elem_value *ucontrol)285{286 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);287 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);288 289 ucontrol->value.integer.value[0] = aw88395->aw_pa->fade_step;290 291 return 0;292}293 294static int aw88395_set_fade_step(struct snd_kcontrol *kcontrol,295 struct snd_ctl_elem_value *ucontrol)296{297 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);298 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);299 struct soc_mixer_control *mc =300 (struct soc_mixer_control *)kcontrol->private_value;301 int value;302 303 value = ucontrol->value.integer.value[0];304 if (value < mc->min || value > mc->max)305 return -EINVAL;306 307 if (aw88395->aw_pa->fade_step != value) {308 aw88395->aw_pa->fade_step = value;309 return 1;310 }311 312 return 0;313}314 315static int aw88395_re_get(struct snd_kcontrol *kcontrol,316 struct snd_ctl_elem_value *ucontrol)317{318 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);319 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);320 struct aw_device *aw_dev = aw88395->aw_pa;321 322 ucontrol->value.integer.value[0] = aw_dev->cali_desc.cali_re;323 324 return 0;325}326 327static int aw88395_re_set(struct snd_kcontrol *kcontrol,328 struct snd_ctl_elem_value *ucontrol)329{330 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);331 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(codec);332 struct soc_mixer_control *mc =333 (struct soc_mixer_control *)kcontrol->private_value;334 struct aw_device *aw_dev = aw88395->aw_pa;335 int value;336 337 value = ucontrol->value.integer.value[0];338 if (value < mc->min || value > mc->max)339 return -EINVAL;340 341 if (aw_dev->cali_desc.cali_re != value) {342 aw_dev->cali_desc.cali_re = value;343 return 1;344 }345 346 return 0;347}348 349static const struct snd_kcontrol_new aw88395_controls[] = {350 SOC_SINGLE_EXT("PCM Playback Volume", AW88395_SYSCTRL2_REG,351 6, AW88395_MUTE_VOL, 0, aw88395_volume_get,352 aw88395_volume_set),353 SOC_SINGLE_EXT("Fade Step", 0, 0, AW88395_MUTE_VOL, 0,354 aw88395_get_fade_step, aw88395_set_fade_step),355 SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,356 aw88395_get_fade_in_time, aw88395_set_fade_in_time),357 SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,358 aw88395_get_fade_out_time, aw88395_set_fade_out_time),359 SOC_SINGLE_EXT("Calib", 0, 0, AW88395_CALI_RE_MAX, 0,360 aw88395_re_get, aw88395_re_set),361 AW88395_PROFILE_EXT("Profile Set", aw88395_profile_info,362 aw88395_profile_get, aw88395_profile_set),363};364 365static int aw88395_playback_event(struct snd_soc_dapm_widget *w,366 struct snd_kcontrol *k, int event)367{368 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);369 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);370 371 mutex_lock(&aw88395->lock);372 switch (event) {373 case SND_SOC_DAPM_PRE_PMU:374 aw88395_start(aw88395, AW88395_ASYNC_START);375 break;376 case SND_SOC_DAPM_POST_PMD:377 aw88395_dev_stop(aw88395->aw_pa);378 break;379 default:380 break;381 }382 mutex_unlock(&aw88395->lock);383 384 return 0;385}386 387static const struct snd_soc_dapm_widget aw88395_dapm_widgets[] = {388 /* playback */389 SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, 0, 0, 0,390 aw88395_playback_event,391 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),392 SND_SOC_DAPM_OUTPUT("DAC Output"),393 394 /* capture */395 SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0),396 SND_SOC_DAPM_INPUT("ADC Input"),397};398 399static const struct snd_soc_dapm_route aw88395_audio_map[] = {400 {"DAC Output", NULL, "AIF_RX"},401 {"AIF_TX", NULL, "ADC Input"},402};403 404static int aw88395_codec_probe(struct snd_soc_component *component)405{406 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);407 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);408 int ret;409 410 INIT_DELAYED_WORK(&aw88395->start_work, aw88395_startup_work);411 412 /* add widgets */413 ret = snd_soc_dapm_new_controls(dapm, aw88395_dapm_widgets,414 ARRAY_SIZE(aw88395_dapm_widgets));415 if (ret < 0)416 return ret;417 418 /* add route */419 ret = snd_soc_dapm_add_routes(dapm, aw88395_audio_map,420 ARRAY_SIZE(aw88395_audio_map));421 if (ret < 0)422 return ret;423 424 ret = snd_soc_add_component_controls(component, aw88395_controls,425 ARRAY_SIZE(aw88395_controls));426 427 return ret;428}429 430static void aw88395_codec_remove(struct snd_soc_component *aw_codec)431{432 struct aw88395 *aw88395 = snd_soc_component_get_drvdata(aw_codec);433 434 cancel_delayed_work_sync(&aw88395->start_work);435}436 437static const struct snd_soc_component_driver soc_codec_dev_aw88395 = {438 .probe = aw88395_codec_probe,439 .remove = aw88395_codec_remove,440};441 442static struct aw88395 *aw88395_malloc_init(struct i2c_client *i2c)443{444 struct aw88395 *aw88395 = devm_kzalloc(&i2c->dev,445 sizeof(struct aw88395), GFP_KERNEL);446 if (!aw88395)447 return NULL;448 449 mutex_init(&aw88395->lock);450 451 return aw88395;452}453 454static void aw88395_hw_reset(struct aw88395 *aw88395)455{456 if (aw88395->reset_gpio) {457 gpiod_set_value_cansleep(aw88395->reset_gpio, 0);458 usleep_range(AW88395_1000_US, AW88395_1000_US + 10);459 gpiod_set_value_cansleep(aw88395->reset_gpio, 1);460 usleep_range(AW88395_1000_US, AW88395_1000_US + 10);461 } else {462 dev_err(aw88395->aw_pa->dev, "%s failed", __func__);463 }464}465 466static int aw88395_request_firmware_file(struct aw88395 *aw88395)467{468 const struct firmware *cont = NULL;469 int ret;470 471 aw88395->aw_pa->fw_status = AW88395_DEV_FW_FAILED;472 473 ret = request_firmware(&cont, AW88395_ACF_FILE, aw88395->aw_pa->dev);474 if ((ret < 0) || (!cont)) {475 dev_err(aw88395->aw_pa->dev, "load [%s] failed!", AW88395_ACF_FILE);476 return ret;477 }478 479 dev_info(aw88395->aw_pa->dev, "loaded %s - size: %zu\n",480 AW88395_ACF_FILE, cont ? cont->size : 0);481 482 aw88395->aw_cfg = devm_kzalloc(aw88395->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL);483 if (!aw88395->aw_cfg) {484 release_firmware(cont);485 return -ENOMEM;486 }487 aw88395->aw_cfg->len = (int)cont->size;488 memcpy(aw88395->aw_cfg->data, cont->data, cont->size);489 release_firmware(cont);490 491 ret = aw88395_dev_load_acf_check(aw88395->aw_pa, aw88395->aw_cfg);492 if (ret < 0) {493 dev_err(aw88395->aw_pa->dev, "Load [%s] failed ....!", AW88395_ACF_FILE);494 return ret;495 }496 497 dev_dbg(aw88395->aw_pa->dev, "%s : bin load success\n", __func__);498 499 mutex_lock(&aw88395->lock);500 /* aw device init */501 ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg);502 if (ret < 0)503 dev_err(aw88395->aw_pa->dev, "dev init failed");504 mutex_unlock(&aw88395->lock);505 506 return ret;507}508 509static int aw88395_i2c_probe(struct i2c_client *i2c)510{511 struct aw88395 *aw88395;512 int ret;513 514 if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) {515 dev_err(&i2c->dev, "check_functionality failed");516 return -EIO;517 }518 519 aw88395 = aw88395_malloc_init(i2c);520 if (!aw88395) {521 dev_err(&i2c->dev, "malloc aw88395 failed");522 return -ENOMEM;523 }524 i2c_set_clientdata(i2c, aw88395);525 526 aw88395->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW);527 if (IS_ERR(aw88395->reset_gpio))528 dev_info(&i2c->dev, "reset gpio not defined\n");529 530 /* hardware reset */531 aw88395_hw_reset(aw88395);532 533 aw88395->regmap = devm_regmap_init_i2c(i2c, &aw88395_remap_config);534 if (IS_ERR(aw88395->regmap)) {535 ret = PTR_ERR(aw88395->regmap);536 dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);537 return ret;538 }539 540 /* aw pa init */541 ret = aw88395_init(&aw88395->aw_pa, i2c, aw88395->regmap);542 if (ret < 0)543 return ret;544 545 ret = aw88395_request_firmware_file(aw88395);546 if (ret < 0) {547 dev_err(&i2c->dev, "%s failed\n", __func__);548 return ret;549 }550 551 ret = devm_snd_soc_register_component(&i2c->dev,552 &soc_codec_dev_aw88395,553 aw88395_dai, ARRAY_SIZE(aw88395_dai));554 if (ret < 0) {555 dev_err(&i2c->dev, "failed to register aw88395: %d", ret);556 return ret;557 }558 559 return 0;560}561 562static const struct i2c_device_id aw88395_i2c_id[] = {563 { AW88395_I2C_NAME },564 { }565};566MODULE_DEVICE_TABLE(i2c, aw88395_i2c_id);567 568static struct i2c_driver aw88395_i2c_driver = {569 .driver = {570 .name = AW88395_I2C_NAME,571 },572 .probe = aw88395_i2c_probe,573 .id_table = aw88395_i2c_id,574};575module_i2c_driver(aw88395_i2c_driver);576 577MODULE_DESCRIPTION("ASoC AW88395 Smart PA Driver");578MODULE_LICENSE("GPL v2");579