brintos

brintos / linux-shallow public Read only

0
0
Text · 15.2 KiB · aea44a1 Raw
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