brintos

brintos / linux-shallow public Read only

0
0
Text · 19.7 KiB · e864188 Raw
698 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * CS4271 ASoC codec driver4 *5 * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>6 *7 * This driver support CS4271 codec being master or slave, working8 * in control port mode, connected either via SPI or I2C.9 * The data format accepted is I2S or left-justified.10 * DAPM support not implemented.11 */12 13#include <linux/module.h>14#include <linux/slab.h>15#include <linux/delay.h>16#include <linux/gpio/consumer.h>17#include <linux/of.h>18#include <linux/regulator/consumer.h>19#include <sound/pcm.h>20#include <sound/soc.h>21#include <sound/tlv.h>22#include <sound/cs4271.h>23#include "cs4271.h"24 25#define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \26			    SNDRV_PCM_FMTBIT_S24_LE | \27			    SNDRV_PCM_FMTBIT_S32_LE)28#define CS4271_PCM_RATES SNDRV_PCM_RATE_8000_19200029 30/*31 * CS4271 registers32 */33#define CS4271_MODE1	0x01	/* Mode Control 1 */34#define CS4271_DACCTL	0x02	/* DAC Control */35#define CS4271_DACVOL	0x03	/* DAC Volume & Mixing Control */36#define CS4271_VOLA	0x04	/* DAC Channel A Volume Control */37#define CS4271_VOLB	0x05	/* DAC Channel B Volume Control */38#define CS4271_ADCCTL	0x06	/* ADC Control */39#define CS4271_MODE2	0x07	/* Mode Control 2 */40#define CS4271_CHIPID	0x08	/* Chip ID */41 42#define CS4271_FIRSTREG	CS4271_MODE143#define CS4271_LASTREG	CS4271_MODE244#define CS4271_NR_REGS	((CS4271_LASTREG & 0xFF) + 1)45 46/* Bit masks for the CS4271 registers */47#define CS4271_MODE1_MODE_MASK	0xC048#define CS4271_MODE1_MODE_1X	0x0049#define CS4271_MODE1_MODE_2X	0x8050#define CS4271_MODE1_MODE_4X	0xC051 52#define CS4271_MODE1_DIV_MASK	0x3053#define CS4271_MODE1_DIV_1	0x0054#define CS4271_MODE1_DIV_15	0x1055#define CS4271_MODE1_DIV_2	0x2056#define CS4271_MODE1_DIV_3	0x3057 58#define CS4271_MODE1_MASTER	0x0859 60#define CS4271_MODE1_DAC_DIF_MASK	0x0761#define CS4271_MODE1_DAC_DIF_LJ		0x0062#define CS4271_MODE1_DAC_DIF_I2S	0x0163#define CS4271_MODE1_DAC_DIF_RJ16	0x0264#define CS4271_MODE1_DAC_DIF_RJ24	0x0365#define CS4271_MODE1_DAC_DIF_RJ20	0x0466#define CS4271_MODE1_DAC_DIF_RJ18	0x0567 68#define CS4271_DACCTL_AMUTE	0x8069#define CS4271_DACCTL_IF_SLOW	0x4070 71#define CS4271_DACCTL_DEM_MASK	0x3072#define CS4271_DACCTL_DEM_DIS	0x0073#define CS4271_DACCTL_DEM_441	0x1074#define CS4271_DACCTL_DEM_48	0x2075#define CS4271_DACCTL_DEM_32	0x3076 77#define CS4271_DACCTL_SVRU	0x0878#define CS4271_DACCTL_SRD	0x0479#define CS4271_DACCTL_INVA	0x0280#define CS4271_DACCTL_INVB	0x0181 82#define CS4271_DACVOL_BEQUA	0x4083#define CS4271_DACVOL_SOFT	0x2084#define CS4271_DACVOL_ZEROC	0x1085 86#define CS4271_DACVOL_ATAPI_MASK	0x0F87#define CS4271_DACVOL_ATAPI_M_M		0x0088#define CS4271_DACVOL_ATAPI_M_BR	0x0189#define CS4271_DACVOL_ATAPI_M_BL	0x0290#define CS4271_DACVOL_ATAPI_M_BLR2	0x0391#define CS4271_DACVOL_ATAPI_AR_M	0x0492#define CS4271_DACVOL_ATAPI_AR_BR	0x0593#define CS4271_DACVOL_ATAPI_AR_BL	0x0694#define CS4271_DACVOL_ATAPI_AR_BLR2	0x0795#define CS4271_DACVOL_ATAPI_AL_M	0x0896#define CS4271_DACVOL_ATAPI_AL_BR	0x0997#define CS4271_DACVOL_ATAPI_AL_BL	0x0A98#define CS4271_DACVOL_ATAPI_AL_BLR2	0x0B99#define CS4271_DACVOL_ATAPI_ALR2_M	0x0C100#define CS4271_DACVOL_ATAPI_ALR2_BR	0x0D101#define CS4271_DACVOL_ATAPI_ALR2_BL	0x0E102#define CS4271_DACVOL_ATAPI_ALR2_BLR2	0x0F103 104#define CS4271_VOLA_MUTE	0x80105#define CS4271_VOLA_VOL_MASK	0x7F106#define CS4271_VOLB_MUTE	0x80107#define CS4271_VOLB_VOL_MASK	0x7F108 109#define CS4271_ADCCTL_DITHER16	0x20110 111#define CS4271_ADCCTL_ADC_DIF_MASK	0x10112#define CS4271_ADCCTL_ADC_DIF_LJ	0x00113#define CS4271_ADCCTL_ADC_DIF_I2S	0x10114 115#define CS4271_ADCCTL_MUTEA	0x08116#define CS4271_ADCCTL_MUTEB	0x04117#define CS4271_ADCCTL_HPFDA	0x02118#define CS4271_ADCCTL_HPFDB	0x01119 120#define CS4271_MODE2_LOOP	0x10121#define CS4271_MODE2_MUTECAEQUB	0x08122#define CS4271_MODE2_FREEZE	0x04123#define CS4271_MODE2_CPEN	0x02124#define CS4271_MODE2_PDN	0x01125 126#define CS4271_CHIPID_PART_MASK	0xF0127#define CS4271_CHIPID_REV_MASK	0x0F128 129/*130 * Default CS4271 power-up configuration131 * Array contains non-existing in hw register at address 0132 * Array do not include Chip ID, as codec driver does not use133 * registers read operations at all134 */135static const struct reg_default cs4271_reg_defaults[] = {136	{ CS4271_MODE1,		0, },137	{ CS4271_DACCTL,	CS4271_DACCTL_AMUTE, },138	{ CS4271_DACVOL,	CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, },139	{ CS4271_VOLA,		0, },140	{ CS4271_VOLB,		0, },141	{ CS4271_ADCCTL,	0, },142	{ CS4271_MODE2,		0, },143};144 145static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)146{147	return reg == CS4271_CHIPID;148}149 150static const char * const supply_names[] = {151	"vd", "vl", "va"152};153 154struct cs4271_private {155	unsigned int			mclk;156	bool				master;157	bool				deemph;158	struct regmap			*regmap;159	/* Current sample rate for de-emphasis control */160	int				rate;161	/* GPIO driving Reset pin, if any */162	struct gpio_desc		*reset;163	/* enable soft reset workaround */164	bool				enable_soft_reset;165	struct regulator_bulk_data      supplies[ARRAY_SIZE(supply_names)];166};167 168static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {169SND_SOC_DAPM_INPUT("AINA"),170SND_SOC_DAPM_INPUT("AINB"),171 172SND_SOC_DAPM_OUTPUT("AOUTA+"),173SND_SOC_DAPM_OUTPUT("AOUTA-"),174SND_SOC_DAPM_OUTPUT("AOUTB+"),175SND_SOC_DAPM_OUTPUT("AOUTB-"),176};177 178static const struct snd_soc_dapm_route cs4271_dapm_routes[] = {179	{ "Capture", NULL, "AINA" },180	{ "Capture", NULL, "AINB" },181 182	{ "AOUTA+", NULL, "Playback" },183	{ "AOUTA-", NULL, "Playback" },184	{ "AOUTB+", NULL, "Playback" },185	{ "AOUTB-", NULL, "Playback" },186};187 188/*189 * @freq is the desired MCLK rate190 * MCLK rate should (c) be the sample rate, multiplied by one of the191 * ratios listed in cs4271_mclk_fs_ratios table192 */193static int cs4271_set_dai_sysclk(struct snd_soc_dai *codec_dai,194				 int clk_id, unsigned int freq, int dir)195{196	struct snd_soc_component *component = codec_dai->component;197	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);198 199	cs4271->mclk = freq;200	return 0;201}202 203static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,204			      unsigned int format)205{206	struct snd_soc_component *component = codec_dai->component;207	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);208	unsigned int val = 0;209	int ret;210 211	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {212	case SND_SOC_DAIFMT_CBS_CFS:213		cs4271->master = false;214		break;215	case SND_SOC_DAIFMT_CBM_CFM:216		cs4271->master = true;217		val |= CS4271_MODE1_MASTER;218		break;219	default:220		dev_err(component->dev, "Invalid DAI format\n");221		return -EINVAL;222	}223 224	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {225	case SND_SOC_DAIFMT_LEFT_J:226		val |= CS4271_MODE1_DAC_DIF_LJ;227		ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,228			CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_LJ);229		if (ret < 0)230			return ret;231		break;232	case SND_SOC_DAIFMT_I2S:233		val |= CS4271_MODE1_DAC_DIF_I2S;234		ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,235			CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_I2S);236		if (ret < 0)237			return ret;238		break;239	default:240		dev_err(component->dev, "Invalid DAI format\n");241		return -EINVAL;242	}243 244	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,245		CS4271_MODE1_DAC_DIF_MASK | CS4271_MODE1_MASTER, val);246	if (ret < 0)247		return ret;248	return 0;249}250 251static int cs4271_deemph[] = {0, 44100, 48000, 32000};252 253static int cs4271_set_deemph(struct snd_soc_component *component)254{255	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);256	int i, ret;257	int val = CS4271_DACCTL_DEM_DIS;258 259	if (cs4271->deemph) {260		/* Find closest de-emphasis freq */261		val = 1;262		for (i = 2; i < ARRAY_SIZE(cs4271_deemph); i++)263			if (abs(cs4271_deemph[i] - cs4271->rate) <264			    abs(cs4271_deemph[val] - cs4271->rate))265				val = i;266		val <<= 4;267	}268 269	ret = regmap_update_bits(cs4271->regmap, CS4271_DACCTL,270		CS4271_DACCTL_DEM_MASK, val);271	if (ret < 0)272		return ret;273	return 0;274}275 276static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,277			     struct snd_ctl_elem_value *ucontrol)278{279	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);280	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);281 282	ucontrol->value.integer.value[0] = cs4271->deemph;283	return 0;284}285 286static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,287			     struct snd_ctl_elem_value *ucontrol)288{289	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);290	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);291 292	cs4271->deemph = ucontrol->value.integer.value[0];293	return cs4271_set_deemph(component);294}295 296struct cs4271_clk_cfg {297	bool		master;		/* codec mode */298	u8		speed_mode;	/* codec speed mode: 1x, 2x, 4x */299	unsigned short	ratio;		/* MCLK / sample rate */300	u8		ratio_mask;	/* ratio bit mask for Master mode */301};302 303static struct cs4271_clk_cfg cs4271_clk_tab[] = {304	{1, CS4271_MODE1_MODE_1X, 256,  CS4271_MODE1_DIV_1},305	{1, CS4271_MODE1_MODE_1X, 384,  CS4271_MODE1_DIV_15},306	{1, CS4271_MODE1_MODE_1X, 512,  CS4271_MODE1_DIV_2},307	{1, CS4271_MODE1_MODE_1X, 768,  CS4271_MODE1_DIV_3},308	{1, CS4271_MODE1_MODE_2X, 128,  CS4271_MODE1_DIV_1},309	{1, CS4271_MODE1_MODE_2X, 192,  CS4271_MODE1_DIV_15},310	{1, CS4271_MODE1_MODE_2X, 256,  CS4271_MODE1_DIV_2},311	{1, CS4271_MODE1_MODE_2X, 384,  CS4271_MODE1_DIV_3},312	{1, CS4271_MODE1_MODE_4X, 64,   CS4271_MODE1_DIV_1},313	{1, CS4271_MODE1_MODE_4X, 96,   CS4271_MODE1_DIV_15},314	{1, CS4271_MODE1_MODE_4X, 128,  CS4271_MODE1_DIV_2},315	{1, CS4271_MODE1_MODE_4X, 192,  CS4271_MODE1_DIV_3},316	{0, CS4271_MODE1_MODE_1X, 256,  CS4271_MODE1_DIV_1},317	{0, CS4271_MODE1_MODE_1X, 384,  CS4271_MODE1_DIV_1},318	{0, CS4271_MODE1_MODE_1X, 512,  CS4271_MODE1_DIV_1},319	{0, CS4271_MODE1_MODE_1X, 768,  CS4271_MODE1_DIV_2},320	{0, CS4271_MODE1_MODE_1X, 1024, CS4271_MODE1_DIV_2},321	{0, CS4271_MODE1_MODE_2X, 128,  CS4271_MODE1_DIV_1},322	{0, CS4271_MODE1_MODE_2X, 192,  CS4271_MODE1_DIV_1},323	{0, CS4271_MODE1_MODE_2X, 256,  CS4271_MODE1_DIV_1},324	{0, CS4271_MODE1_MODE_2X, 384,  CS4271_MODE1_DIV_2},325	{0, CS4271_MODE1_MODE_2X, 512,  CS4271_MODE1_DIV_2},326	{0, CS4271_MODE1_MODE_4X, 64,   CS4271_MODE1_DIV_1},327	{0, CS4271_MODE1_MODE_4X, 96,   CS4271_MODE1_DIV_1},328	{0, CS4271_MODE1_MODE_4X, 128,  CS4271_MODE1_DIV_1},329	{0, CS4271_MODE1_MODE_4X, 192,  CS4271_MODE1_DIV_2},330	{0, CS4271_MODE1_MODE_4X, 256,  CS4271_MODE1_DIV_2},331};332 333#define CS4271_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab)334 335static int cs4271_hw_params(struct snd_pcm_substream *substream,336			    struct snd_pcm_hw_params *params,337			    struct snd_soc_dai *dai)338{339	struct snd_soc_component *component = dai->component;340	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);341	int i, ret;342	unsigned int ratio, val;343 344	if (cs4271->enable_soft_reset) {345		/*346		 * Put the codec in soft reset and back again in case it's not347		 * currently streaming data. This way of bringing the codec in348		 * sync to the current clocks is not explicitly documented in349		 * the data sheet, but it seems to work fine, and in contrast350		 * to a read hardware reset, we don't have to sync back all351		 * registers every time.352		 */353 354		if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&355		     !snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE)) ||356		    (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&357		     !snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK))) {358			ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,359						 CS4271_MODE2_PDN,360						 CS4271_MODE2_PDN);361			if (ret < 0)362				return ret;363 364			ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,365						 CS4271_MODE2_PDN, 0);366			if (ret < 0)367				return ret;368		}369	}370 371	cs4271->rate = params_rate(params);372 373	/* Configure DAC */374	if (cs4271->rate < 50000)375		val = CS4271_MODE1_MODE_1X;376	else if (cs4271->rate < 100000)377		val = CS4271_MODE1_MODE_2X;378	else379		val = CS4271_MODE1_MODE_4X;380 381	ratio = cs4271->mclk / cs4271->rate;382	for (i = 0; i < CS4271_NR_RATIOS; i++)383		if ((cs4271_clk_tab[i].master == cs4271->master) &&384		    (cs4271_clk_tab[i].speed_mode == val) &&385		    (cs4271_clk_tab[i].ratio == ratio))386			break;387 388	if (i == CS4271_NR_RATIOS) {389		dev_err(component->dev, "Invalid sample rate\n");390		return -EINVAL;391	}392 393	val |= cs4271_clk_tab[i].ratio_mask;394 395	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,396		CS4271_MODE1_MODE_MASK | CS4271_MODE1_DIV_MASK, val);397	if (ret < 0)398		return ret;399 400	return cs4271_set_deemph(component);401}402 403static int cs4271_mute_stream(struct snd_soc_dai *dai, int mute, int stream)404{405	struct snd_soc_component *component = dai->component;406	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);407	int ret;408	int val_a = 0;409	int val_b = 0;410 411	if (stream != SNDRV_PCM_STREAM_PLAYBACK)412		return 0;413 414	if (mute) {415		val_a = CS4271_VOLA_MUTE;416		val_b = CS4271_VOLB_MUTE;417	}418 419	ret = regmap_update_bits(cs4271->regmap, CS4271_VOLA,420				 CS4271_VOLA_MUTE, val_a);421	if (ret < 0)422		return ret;423 424	ret = regmap_update_bits(cs4271->regmap, CS4271_VOLB,425				 CS4271_VOLB_MUTE, val_b);426	if (ret < 0)427		return ret;428 429	return 0;430}431 432/* CS4271 controls */433static DECLARE_TLV_DB_SCALE(cs4271_dac_tlv, -12700, 100, 0);434 435static const struct snd_kcontrol_new cs4271_snd_controls[] = {436	SOC_DOUBLE_R_TLV("Master Playback Volume", CS4271_VOLA, CS4271_VOLB,437		0, 0x7F, 1, cs4271_dac_tlv),438	SOC_SINGLE("Digital Loopback Switch", CS4271_MODE2, 4, 1, 0),439	SOC_SINGLE("Soft Ramp Switch", CS4271_DACVOL, 5, 1, 0),440	SOC_SINGLE("Zero Cross Switch", CS4271_DACVOL, 4, 1, 0),441	SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,442		cs4271_get_deemph, cs4271_put_deemph),443	SOC_SINGLE("Auto-Mute Switch", CS4271_DACCTL, 7, 1, 0),444	SOC_SINGLE("Slow Roll Off Filter Switch", CS4271_DACCTL, 6, 1, 0),445	SOC_SINGLE("Soft Volume Ramp-Up Switch", CS4271_DACCTL, 3, 1, 0),446	SOC_SINGLE("Soft Ramp-Down Switch", CS4271_DACCTL, 2, 1, 0),447	SOC_SINGLE("Left Channel Inversion Switch", CS4271_DACCTL, 1, 1, 0),448	SOC_SINGLE("Right Channel Inversion Switch", CS4271_DACCTL, 0, 1, 0),449	SOC_DOUBLE("Master Capture Switch", CS4271_ADCCTL, 3, 2, 1, 1),450	SOC_SINGLE("Dither 16-Bit Data Switch", CS4271_ADCCTL, 5, 1, 0),451	SOC_DOUBLE("High Pass Filter Switch", CS4271_ADCCTL, 1, 0, 1, 1),452	SOC_DOUBLE_R("Master Playback Switch", CS4271_VOLA, CS4271_VOLB,453		7, 1, 1),454};455 456static const struct snd_soc_dai_ops cs4271_dai_ops = {457	.hw_params	= cs4271_hw_params,458	.set_sysclk	= cs4271_set_dai_sysclk,459	.set_fmt	= cs4271_set_dai_fmt,460	.mute_stream	= cs4271_mute_stream,461};462 463static struct snd_soc_dai_driver cs4271_dai = {464	.name = "cs4271-hifi",465	.playback = {466		.stream_name	= "Playback",467		.channels_min	= 2,468		.channels_max	= 2,469		.rates		= CS4271_PCM_RATES,470		.formats	= CS4271_PCM_FORMATS,471	},472	.capture = {473		.stream_name	= "Capture",474		.channels_min	= 2,475		.channels_max	= 2,476		.rates		= CS4271_PCM_RATES,477		.formats	= CS4271_PCM_FORMATS,478	},479	.ops = &cs4271_dai_ops,480	.symmetric_rate = 1,481};482 483static int cs4271_reset(struct snd_soc_component *component)484{485	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);486 487	gpiod_direction_output(cs4271->reset, 1);488	mdelay(1);489	gpiod_set_value(cs4271->reset, 0);490	mdelay(1);491 492	return 0;493}494 495#ifdef CONFIG_PM496static int cs4271_soc_suspend(struct snd_soc_component *component)497{498	int ret;499	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);500 501	/* Set power-down bit */502	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,503				 CS4271_MODE2_PDN, CS4271_MODE2_PDN);504	if (ret < 0)505		return ret;506 507	regcache_mark_dirty(cs4271->regmap);508	regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);509 510	return 0;511}512 513static int cs4271_soc_resume(struct snd_soc_component *component)514{515	int ret;516	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);517 518	ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),519				    cs4271->supplies);520	if (ret < 0) {521		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);522		return ret;523	}524 525	/* Do a proper reset after power up */526	cs4271_reset(component);527 528	/* Restore codec state */529	ret = regcache_sync(cs4271->regmap);530	if (ret < 0)531		return ret;532 533	/* then disable the power-down bit */534	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,535				 CS4271_MODE2_PDN, 0);536	if (ret < 0)537		return ret;538 539	return 0;540}541#else542#define cs4271_soc_suspend	NULL543#define cs4271_soc_resume	NULL544#endif /* CONFIG_PM */545 546#ifdef CONFIG_OF547const struct of_device_id cs4271_dt_ids[] = {548	{ .compatible = "cirrus,cs4271", },549	{ }550};551MODULE_DEVICE_TABLE(of, cs4271_dt_ids);552EXPORT_SYMBOL_GPL(cs4271_dt_ids);553#endif554 555static int cs4271_component_probe(struct snd_soc_component *component)556{557	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);558	struct cs4271_platform_data *cs4271plat = component->dev->platform_data;559	int ret;560	bool amutec_eq_bmutec;561 562	amutec_eq_bmutec = of_property_read_bool(component->dev->of_node,563						 "cirrus,amutec-eq-bmutec");564	cs4271->enable_soft_reset = of_property_read_bool(component->dev->of_node,565							  "cirrus,enable-soft-reset");566 567	ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),568				    cs4271->supplies);569	if (ret < 0) {570		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);571		return ret;572	}573 574	if (cs4271plat) {575		amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;576		cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;577	}578 579	/* Reset codec */580	cs4271_reset(component);581 582	ret = regcache_sync(cs4271->regmap);583	if (ret < 0)584		return ret;585 586	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,587				 CS4271_MODE2_PDN | CS4271_MODE2_CPEN,588				 CS4271_MODE2_PDN | CS4271_MODE2_CPEN);589	if (ret < 0)590		return ret;591	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,592				 CS4271_MODE2_PDN, 0);593	if (ret < 0)594		return ret;595	/* Power-up sequence requires 85 uS */596	udelay(85);597 598	if (amutec_eq_bmutec)599		regmap_update_bits(cs4271->regmap, CS4271_MODE2,600				   CS4271_MODE2_MUTECAEQUB,601				   CS4271_MODE2_MUTECAEQUB);602 603	return 0;604}605 606static void cs4271_component_remove(struct snd_soc_component *component)607{608	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);609 610	/* Set codec to the reset state */611	gpiod_set_value(cs4271->reset, 1);612 613	regcache_mark_dirty(cs4271->regmap);614	regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);615};616 617static const struct snd_soc_component_driver soc_component_dev_cs4271 = {618	.probe			= cs4271_component_probe,619	.remove			= cs4271_component_remove,620	.suspend		= cs4271_soc_suspend,621	.resume			= cs4271_soc_resume,622	.controls		= cs4271_snd_controls,623	.num_controls		= ARRAY_SIZE(cs4271_snd_controls),624	.dapm_widgets		= cs4271_dapm_widgets,625	.num_dapm_widgets	= ARRAY_SIZE(cs4271_dapm_widgets),626	.dapm_routes		= cs4271_dapm_routes,627	.num_dapm_routes	= ARRAY_SIZE(cs4271_dapm_routes),628	.idle_bias_on		= 1,629	.use_pmdown_time	= 1,630	.endianness		= 1,631};632 633static int cs4271_common_probe(struct device *dev,634			       struct cs4271_private **c)635{636	struct cs4271_private *cs4271;637	int i, ret;638 639	cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL);640	if (!cs4271)641		return -ENOMEM;642 643	cs4271->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS);644	if (IS_ERR(cs4271->reset))645		return dev_err_probe(dev, PTR_ERR(cs4271->reset),646				     "error retrieving RESET GPIO\n");647	gpiod_set_consumer_name(cs4271->reset, "CS4271 Reset");648 649	for (i = 0; i < ARRAY_SIZE(supply_names); i++)650		cs4271->supplies[i].supply = supply_names[i];651 652	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs4271->supplies),653					cs4271->supplies);654 655	if (ret < 0) {656		dev_err(dev, "Failed to get regulators: %d\n", ret);657		return ret;658	}659 660	*c = cs4271;661	return 0;662}663 664const struct regmap_config cs4271_regmap_config = {665	.max_register = CS4271_LASTREG,666 667	.reg_defaults = cs4271_reg_defaults,668	.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),669	.cache_type = REGCACHE_FLAT,670	.val_bits = 8,671	.volatile_reg = cs4271_volatile_reg,672};673EXPORT_SYMBOL_GPL(cs4271_regmap_config);674 675int cs4271_probe(struct device *dev, struct regmap *regmap)676{677	struct cs4271_private *cs4271;678	int ret;679 680	if (IS_ERR(regmap))681		return PTR_ERR(regmap);682 683	ret = cs4271_common_probe(dev, &cs4271);684	if (ret < 0)685		return ret;686 687	dev_set_drvdata(dev, cs4271);688	cs4271->regmap = regmap;689 690	return devm_snd_soc_register_component(dev, &soc_component_dev_cs4271,691					       &cs4271_dai, 1);692}693EXPORT_SYMBOL_GPL(cs4271_probe);694 695MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");696MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver");697MODULE_LICENSE("GPL");698