xref: /openbmc/linux/sound/soc/codecs/cs4271.c (revision 2e9688c8)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
267b22517SAlexander Sverdlin /*
367b22517SAlexander Sverdlin  * CS4271 ASoC codec driver
467b22517SAlexander Sverdlin  *
567b22517SAlexander Sverdlin  * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
667b22517SAlexander Sverdlin  *
767b22517SAlexander Sverdlin  * This driver support CS4271 codec being master or slave, working
867b22517SAlexander Sverdlin  * in control port mode, connected either via SPI or I2C.
967b22517SAlexander Sverdlin  * The data format accepted is I2S or left-justified.
1067b22517SAlexander Sverdlin  * DAPM support not implemented.
1167b22517SAlexander Sverdlin  */
1267b22517SAlexander Sverdlin 
1367b22517SAlexander Sverdlin #include <linux/module.h>
1467b22517SAlexander Sverdlin #include <linux/slab.h>
1567b22517SAlexander Sverdlin #include <linux/delay.h>
1667b22517SAlexander Sverdlin #include <linux/gpio.h>
17a7ea1b72SSachin Kamat #include <linux/of.h>
18a31ebc34SDaniel Mack #include <linux/of_device.h>
19a31ebc34SDaniel Mack #include <linux/of_gpio.h>
209a397f47SPascal Huerst #include <linux/regulator/consumer.h>
21a31ebc34SDaniel Mack #include <sound/pcm.h>
22a31ebc34SDaniel Mack #include <sound/soc.h>
23a31ebc34SDaniel Mack #include <sound/tlv.h>
2467b22517SAlexander Sverdlin #include <sound/cs4271.h>
25c973b8a7SAxel Lin #include "cs4271.h"
2667b22517SAlexander Sverdlin 
2767b22517SAlexander Sverdlin #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
2867b22517SAlexander Sverdlin 			    SNDRV_PCM_FMTBIT_S24_LE | \
2967b22517SAlexander Sverdlin 			    SNDRV_PCM_FMTBIT_S32_LE)
30383f8465SAlexander Sverdlin #define CS4271_PCM_RATES SNDRV_PCM_RATE_8000_192000
3167b22517SAlexander Sverdlin 
3267b22517SAlexander Sverdlin /*
3367b22517SAlexander Sverdlin  * CS4271 registers
3467b22517SAlexander Sverdlin  */
351b1861eaSDaniel Mack #define CS4271_MODE1	0x01	/* Mode Control 1 */
361b1861eaSDaniel Mack #define CS4271_DACCTL	0x02	/* DAC Control */
371b1861eaSDaniel Mack #define CS4271_DACVOL	0x03	/* DAC Volume & Mixing Control */
381b1861eaSDaniel Mack #define CS4271_VOLA	0x04	/* DAC Channel A Volume Control */
391b1861eaSDaniel Mack #define CS4271_VOLB	0x05	/* DAC Channel B Volume Control */
401b1861eaSDaniel Mack #define CS4271_ADCCTL	0x06	/* ADC Control */
411b1861eaSDaniel Mack #define CS4271_MODE2	0x07	/* Mode Control 2 */
421b1861eaSDaniel Mack #define CS4271_CHIPID	0x08	/* Chip ID */
4367b22517SAlexander Sverdlin 
4467b22517SAlexander Sverdlin #define CS4271_FIRSTREG	CS4271_MODE1
4567b22517SAlexander Sverdlin #define CS4271_LASTREG	CS4271_MODE2
4667b22517SAlexander Sverdlin #define CS4271_NR_REGS	((CS4271_LASTREG & 0xFF) + 1)
4767b22517SAlexander Sverdlin 
4867b22517SAlexander Sverdlin /* Bit masks for the CS4271 registers */
4967b22517SAlexander Sverdlin #define CS4271_MODE1_MODE_MASK	0xC0
5067b22517SAlexander Sverdlin #define CS4271_MODE1_MODE_1X	0x00
5167b22517SAlexander Sverdlin #define CS4271_MODE1_MODE_2X	0x80
5267b22517SAlexander Sverdlin #define CS4271_MODE1_MODE_4X	0xC0
5367b22517SAlexander Sverdlin 
5467b22517SAlexander Sverdlin #define CS4271_MODE1_DIV_MASK	0x30
5567b22517SAlexander Sverdlin #define CS4271_MODE1_DIV_1	0x00
5667b22517SAlexander Sverdlin #define CS4271_MODE1_DIV_15	0x10
5767b22517SAlexander Sverdlin #define CS4271_MODE1_DIV_2	0x20
5867b22517SAlexander Sverdlin #define CS4271_MODE1_DIV_3	0x30
5967b22517SAlexander Sverdlin 
6067b22517SAlexander Sverdlin #define CS4271_MODE1_MASTER	0x08
6167b22517SAlexander Sverdlin 
6267b22517SAlexander Sverdlin #define CS4271_MODE1_DAC_DIF_MASK	0x07
6367b22517SAlexander Sverdlin #define CS4271_MODE1_DAC_DIF_LJ		0x00
6467b22517SAlexander Sverdlin #define CS4271_MODE1_DAC_DIF_I2S	0x01
6567b22517SAlexander Sverdlin #define CS4271_MODE1_DAC_DIF_RJ16	0x02
6667b22517SAlexander Sverdlin #define CS4271_MODE1_DAC_DIF_RJ24	0x03
6767b22517SAlexander Sverdlin #define CS4271_MODE1_DAC_DIF_RJ20	0x04
6867b22517SAlexander Sverdlin #define CS4271_MODE1_DAC_DIF_RJ18	0x05
6967b22517SAlexander Sverdlin 
7067b22517SAlexander Sverdlin #define CS4271_DACCTL_AMUTE	0x80
7167b22517SAlexander Sverdlin #define CS4271_DACCTL_IF_SLOW	0x40
7267b22517SAlexander Sverdlin 
7367b22517SAlexander Sverdlin #define CS4271_DACCTL_DEM_MASK	0x30
7467b22517SAlexander Sverdlin #define CS4271_DACCTL_DEM_DIS	0x00
7567b22517SAlexander Sverdlin #define CS4271_DACCTL_DEM_441	0x10
7667b22517SAlexander Sverdlin #define CS4271_DACCTL_DEM_48	0x20
7767b22517SAlexander Sverdlin #define CS4271_DACCTL_DEM_32	0x30
7867b22517SAlexander Sverdlin 
7967b22517SAlexander Sverdlin #define CS4271_DACCTL_SVRU	0x08
8067b22517SAlexander Sverdlin #define CS4271_DACCTL_SRD	0x04
8167b22517SAlexander Sverdlin #define CS4271_DACCTL_INVA	0x02
8267b22517SAlexander Sverdlin #define CS4271_DACCTL_INVB	0x01
8367b22517SAlexander Sverdlin 
8467b22517SAlexander Sverdlin #define CS4271_DACVOL_BEQUA	0x40
8567b22517SAlexander Sverdlin #define CS4271_DACVOL_SOFT	0x20
8667b22517SAlexander Sverdlin #define CS4271_DACVOL_ZEROC	0x10
8767b22517SAlexander Sverdlin 
8867b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_MASK	0x0F
8967b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_M_M		0x00
9067b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_M_BR	0x01
9167b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_M_BL	0x02
9267b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_M_BLR2	0x03
9367b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_AR_M	0x04
9467b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_AR_BR	0x05
9567b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_AR_BL	0x06
9667b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_AR_BLR2	0x07
9767b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_AL_M	0x08
9867b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_AL_BR	0x09
9967b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_AL_BL	0x0A
10067b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_AL_BLR2	0x0B
10167b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_ALR2_M	0x0C
10267b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_ALR2_BR	0x0D
10367b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_ALR2_BL	0x0E
10467b22517SAlexander Sverdlin #define CS4271_DACVOL_ATAPI_ALR2_BLR2	0x0F
10567b22517SAlexander Sverdlin 
10667b22517SAlexander Sverdlin #define CS4271_VOLA_MUTE	0x80
10767b22517SAlexander Sverdlin #define CS4271_VOLA_VOL_MASK	0x7F
10867b22517SAlexander Sverdlin #define CS4271_VOLB_MUTE	0x80
10967b22517SAlexander Sverdlin #define CS4271_VOLB_VOL_MASK	0x7F
11067b22517SAlexander Sverdlin 
11167b22517SAlexander Sverdlin #define CS4271_ADCCTL_DITHER16	0x20
11267b22517SAlexander Sverdlin 
11367b22517SAlexander Sverdlin #define CS4271_ADCCTL_ADC_DIF_MASK	0x10
11467b22517SAlexander Sverdlin #define CS4271_ADCCTL_ADC_DIF_LJ	0x00
11567b22517SAlexander Sverdlin #define CS4271_ADCCTL_ADC_DIF_I2S	0x10
11667b22517SAlexander Sverdlin 
11767b22517SAlexander Sverdlin #define CS4271_ADCCTL_MUTEA	0x08
11867b22517SAlexander Sverdlin #define CS4271_ADCCTL_MUTEB	0x04
11967b22517SAlexander Sverdlin #define CS4271_ADCCTL_HPFDA	0x02
12067b22517SAlexander Sverdlin #define CS4271_ADCCTL_HPFDB	0x01
12167b22517SAlexander Sverdlin 
12267b22517SAlexander Sverdlin #define CS4271_MODE2_LOOP	0x10
12367b22517SAlexander Sverdlin #define CS4271_MODE2_MUTECAEQUB	0x08
12467b22517SAlexander Sverdlin #define CS4271_MODE2_FREEZE	0x04
12567b22517SAlexander Sverdlin #define CS4271_MODE2_CPEN	0x02
12667b22517SAlexander Sverdlin #define CS4271_MODE2_PDN	0x01
12767b22517SAlexander Sverdlin 
12867b22517SAlexander Sverdlin #define CS4271_CHIPID_PART_MASK	0xF0
12967b22517SAlexander Sverdlin #define CS4271_CHIPID_REV_MASK	0x0F
13067b22517SAlexander Sverdlin 
13167b22517SAlexander Sverdlin /*
13267b22517SAlexander Sverdlin  * Default CS4271 power-up configuration
13367b22517SAlexander Sverdlin  * Array contains non-existing in hw register at address 0
13467b22517SAlexander Sverdlin  * Array do not include Chip ID, as codec driver does not use
13567b22517SAlexander Sverdlin  * registers read operations at all
13667b22517SAlexander Sverdlin  */
1371b1861eaSDaniel Mack static const struct reg_default cs4271_reg_defaults[] = {
1381b1861eaSDaniel Mack 	{ CS4271_MODE1,		0, },
1391b1861eaSDaniel Mack 	{ CS4271_DACCTL,	CS4271_DACCTL_AMUTE, },
1401b1861eaSDaniel Mack 	{ CS4271_DACVOL,	CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, },
1411b1861eaSDaniel Mack 	{ CS4271_VOLA,		0, },
1421b1861eaSDaniel Mack 	{ CS4271_VOLB,		0, },
1431b1861eaSDaniel Mack 	{ CS4271_ADCCTL,	0, },
1441b1861eaSDaniel Mack 	{ CS4271_MODE2,		0, },
14567b22517SAlexander Sverdlin };
14667b22517SAlexander Sverdlin 
cs4271_volatile_reg(struct device * dev,unsigned int reg)1471b1861eaSDaniel Mack static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)
1481b1861eaSDaniel Mack {
1491b1861eaSDaniel Mack 	return reg == CS4271_CHIPID;
1501b1861eaSDaniel Mack }
1511b1861eaSDaniel Mack 
1529a397f47SPascal Huerst static const char * const supply_names[] = {
1539a397f47SPascal Huerst 	"vd", "vl", "va"
1549a397f47SPascal Huerst };
1559a397f47SPascal Huerst 
15667b22517SAlexander Sverdlin struct cs4271_private {
15767b22517SAlexander Sverdlin 	unsigned int			mclk;
15867b22517SAlexander Sverdlin 	bool				master;
15967b22517SAlexander Sverdlin 	bool				deemph;
1601b1861eaSDaniel Mack 	struct regmap			*regmap;
16167b22517SAlexander Sverdlin 	/* Current sample rate for de-emphasis control */
16267b22517SAlexander Sverdlin 	int				rate;
16367b22517SAlexander Sverdlin 	/* GPIO driving Reset pin, if any */
16467b22517SAlexander Sverdlin 	int				gpio_nreset;
16567b22517SAlexander Sverdlin 	/* GPIO that disable serial bus, if any */
16667b22517SAlexander Sverdlin 	int				gpio_disable;
167fd23fb9fSDaniel Mack 	/* enable soft reset workaround */
168fd23fb9fSDaniel Mack 	bool				enable_soft_reset;
1699a397f47SPascal Huerst 	struct regulator_bulk_data      supplies[ARRAY_SIZE(supply_names)];
17067b22517SAlexander Sverdlin };
17167b22517SAlexander Sverdlin 
1722e7fb942SMark Brown static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {
1732e7fb942SMark Brown SND_SOC_DAPM_INPUT("AINA"),
1742e7fb942SMark Brown SND_SOC_DAPM_INPUT("AINB"),
1752e7fb942SMark Brown 
1762e7fb942SMark Brown SND_SOC_DAPM_OUTPUT("AOUTA+"),
1772e7fb942SMark Brown SND_SOC_DAPM_OUTPUT("AOUTA-"),
1782e7fb942SMark Brown SND_SOC_DAPM_OUTPUT("AOUTB+"),
1792e7fb942SMark Brown SND_SOC_DAPM_OUTPUT("AOUTB-"),
1802e7fb942SMark Brown };
1812e7fb942SMark Brown 
1822e7fb942SMark Brown static const struct snd_soc_dapm_route cs4271_dapm_routes[] = {
1832e7fb942SMark Brown 	{ "Capture", NULL, "AINA" },
1842e7fb942SMark Brown 	{ "Capture", NULL, "AINB" },
1852e7fb942SMark Brown 
1862e7fb942SMark Brown 	{ "AOUTA+", NULL, "Playback" },
1872e7fb942SMark Brown 	{ "AOUTA-", NULL, "Playback" },
1882e7fb942SMark Brown 	{ "AOUTB+", NULL, "Playback" },
1892e7fb942SMark Brown 	{ "AOUTB-", NULL, "Playback" },
1902e7fb942SMark Brown };
1912e7fb942SMark Brown 
19267b22517SAlexander Sverdlin /*
19367b22517SAlexander Sverdlin  * @freq is the desired MCLK rate
19467b22517SAlexander Sverdlin  * MCLK rate should (c) be the sample rate, multiplied by one of the
19567b22517SAlexander Sverdlin  * ratios listed in cs4271_mclk_fs_ratios table
19667b22517SAlexander Sverdlin  */
cs4271_set_dai_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)19767b22517SAlexander Sverdlin static int cs4271_set_dai_sysclk(struct snd_soc_dai *codec_dai,
19867b22517SAlexander Sverdlin 				 int clk_id, unsigned int freq, int dir)
19967b22517SAlexander Sverdlin {
200cac308fcSKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
201cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
20267b22517SAlexander Sverdlin 
20367b22517SAlexander Sverdlin 	cs4271->mclk = freq;
20467b22517SAlexander Sverdlin 	return 0;
20567b22517SAlexander Sverdlin }
20667b22517SAlexander Sverdlin 
cs4271_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int format)20767b22517SAlexander Sverdlin static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
20867b22517SAlexander Sverdlin 			      unsigned int format)
20967b22517SAlexander Sverdlin {
210cac308fcSKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
211cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
21267b22517SAlexander Sverdlin 	unsigned int val = 0;
2130d42e6e7SAlexander Sverdlin 	int ret;
21467b22517SAlexander Sverdlin 
21567b22517SAlexander Sverdlin 	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
21667b22517SAlexander Sverdlin 	case SND_SOC_DAIFMT_CBS_CFS:
2173c17bcfdSPierre-Louis Bossart 		cs4271->master = false;
21867b22517SAlexander Sverdlin 		break;
21967b22517SAlexander Sverdlin 	case SND_SOC_DAIFMT_CBM_CFM:
2203c17bcfdSPierre-Louis Bossart 		cs4271->master = true;
22167b22517SAlexander Sverdlin 		val |= CS4271_MODE1_MASTER;
22267b22517SAlexander Sverdlin 		break;
22367b22517SAlexander Sverdlin 	default:
224cac308fcSKuninori Morimoto 		dev_err(component->dev, "Invalid DAI format\n");
22567b22517SAlexander Sverdlin 		return -EINVAL;
22667b22517SAlexander Sverdlin 	}
22767b22517SAlexander Sverdlin 
22867b22517SAlexander Sverdlin 	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
22967b22517SAlexander Sverdlin 	case SND_SOC_DAIFMT_LEFT_J:
23067b22517SAlexander Sverdlin 		val |= CS4271_MODE1_DAC_DIF_LJ;
2311b1861eaSDaniel Mack 		ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,
23267b22517SAlexander Sverdlin 			CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_LJ);
2330d42e6e7SAlexander Sverdlin 		if (ret < 0)
2340d42e6e7SAlexander Sverdlin 			return ret;
23567b22517SAlexander Sverdlin 		break;
23667b22517SAlexander Sverdlin 	case SND_SOC_DAIFMT_I2S:
23767b22517SAlexander Sverdlin 		val |= CS4271_MODE1_DAC_DIF_I2S;
2381b1861eaSDaniel Mack 		ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,
23967b22517SAlexander Sverdlin 			CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_I2S);
2400d42e6e7SAlexander Sverdlin 		if (ret < 0)
2410d42e6e7SAlexander Sverdlin 			return ret;
24267b22517SAlexander Sverdlin 		break;
24367b22517SAlexander Sverdlin 	default:
244cac308fcSKuninori Morimoto 		dev_err(component->dev, "Invalid DAI format\n");
24567b22517SAlexander Sverdlin 		return -EINVAL;
24667b22517SAlexander Sverdlin 	}
24767b22517SAlexander Sverdlin 
2481b1861eaSDaniel Mack 	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,
24967b22517SAlexander Sverdlin 		CS4271_MODE1_DAC_DIF_MASK | CS4271_MODE1_MASTER, val);
2500d42e6e7SAlexander Sverdlin 	if (ret < 0)
2510d42e6e7SAlexander Sverdlin 		return ret;
25267b22517SAlexander Sverdlin 	return 0;
25367b22517SAlexander Sverdlin }
25467b22517SAlexander Sverdlin 
25567b22517SAlexander Sverdlin static int cs4271_deemph[] = {0, 44100, 48000, 32000};
25667b22517SAlexander Sverdlin 
cs4271_set_deemph(struct snd_soc_component * component)257cac308fcSKuninori Morimoto static int cs4271_set_deemph(struct snd_soc_component *component)
25867b22517SAlexander Sverdlin {
259cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
2600d42e6e7SAlexander Sverdlin 	int i, ret;
26167b22517SAlexander Sverdlin 	int val = CS4271_DACCTL_DEM_DIS;
26267b22517SAlexander Sverdlin 
26367b22517SAlexander Sverdlin 	if (cs4271->deemph) {
26467b22517SAlexander Sverdlin 		/* Find closest de-emphasis freq */
26567b22517SAlexander Sverdlin 		val = 1;
26667b22517SAlexander Sverdlin 		for (i = 2; i < ARRAY_SIZE(cs4271_deemph); i++)
26767b22517SAlexander Sverdlin 			if (abs(cs4271_deemph[i] - cs4271->rate) <
26867b22517SAlexander Sverdlin 			    abs(cs4271_deemph[val] - cs4271->rate))
26967b22517SAlexander Sverdlin 				val = i;
27067b22517SAlexander Sverdlin 		val <<= 4;
27167b22517SAlexander Sverdlin 	}
27267b22517SAlexander Sverdlin 
2731b1861eaSDaniel Mack 	ret = regmap_update_bits(cs4271->regmap, CS4271_DACCTL,
27467b22517SAlexander Sverdlin 		CS4271_DACCTL_DEM_MASK, val);
2750d42e6e7SAlexander Sverdlin 	if (ret < 0)
2760d42e6e7SAlexander Sverdlin 		return ret;
2770d42e6e7SAlexander Sverdlin 	return 0;
27867b22517SAlexander Sverdlin }
27967b22517SAlexander Sverdlin 
cs4271_get_deemph(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)28067b22517SAlexander Sverdlin static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
28167b22517SAlexander Sverdlin 			     struct snd_ctl_elem_value *ucontrol)
28267b22517SAlexander Sverdlin {
283cac308fcSKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
284cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
28567b22517SAlexander Sverdlin 
286e8371aa0STakashi Iwai 	ucontrol->value.integer.value[0] = cs4271->deemph;
28767b22517SAlexander Sverdlin 	return 0;
28867b22517SAlexander Sverdlin }
28967b22517SAlexander Sverdlin 
cs4271_put_deemph(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)29067b22517SAlexander Sverdlin static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,
29167b22517SAlexander Sverdlin 			     struct snd_ctl_elem_value *ucontrol)
29267b22517SAlexander Sverdlin {
293cac308fcSKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
294cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
29567b22517SAlexander Sverdlin 
296e8371aa0STakashi Iwai 	cs4271->deemph = ucontrol->value.integer.value[0];
297cac308fcSKuninori Morimoto 	return cs4271_set_deemph(component);
29867b22517SAlexander Sverdlin }
29967b22517SAlexander Sverdlin 
3005c3a12e9SAlexander Sverdlin struct cs4271_clk_cfg {
3015c3a12e9SAlexander Sverdlin 	bool		master;		/* codec mode */
3025c3a12e9SAlexander Sverdlin 	u8		speed_mode;	/* codec speed mode: 1x, 2x, 4x */
3035c3a12e9SAlexander Sverdlin 	unsigned short	ratio;		/* MCLK / sample rate */
3045c3a12e9SAlexander Sverdlin 	u8		ratio_mask;	/* ratio bit mask for Master mode */
3055c3a12e9SAlexander Sverdlin };
3065c3a12e9SAlexander Sverdlin 
3075c3a12e9SAlexander Sverdlin static struct cs4271_clk_cfg cs4271_clk_tab[] = {
3085c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_1X, 256,  CS4271_MODE1_DIV_1},
3095c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_1X, 384,  CS4271_MODE1_DIV_15},
3105c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_1X, 512,  CS4271_MODE1_DIV_2},
3115c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_1X, 768,  CS4271_MODE1_DIV_3},
3125c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_2X, 128,  CS4271_MODE1_DIV_1},
3135c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_2X, 192,  CS4271_MODE1_DIV_15},
3145c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_2X, 256,  CS4271_MODE1_DIV_2},
3155c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_2X, 384,  CS4271_MODE1_DIV_3},
3165c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_4X, 64,   CS4271_MODE1_DIV_1},
3175c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_4X, 96,   CS4271_MODE1_DIV_15},
3185c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_4X, 128,  CS4271_MODE1_DIV_2},
3195c3a12e9SAlexander Sverdlin 	{1, CS4271_MODE1_MODE_4X, 192,  CS4271_MODE1_DIV_3},
3205c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_1X, 256,  CS4271_MODE1_DIV_1},
3215c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_1X, 384,  CS4271_MODE1_DIV_1},
3225c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_1X, 512,  CS4271_MODE1_DIV_1},
3235c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_1X, 768,  CS4271_MODE1_DIV_2},
3245c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_1X, 1024, CS4271_MODE1_DIV_2},
3255c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_2X, 128,  CS4271_MODE1_DIV_1},
3265c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_2X, 192,  CS4271_MODE1_DIV_1},
3275c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_2X, 256,  CS4271_MODE1_DIV_1},
3285c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_2X, 384,  CS4271_MODE1_DIV_2},
3295c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_2X, 512,  CS4271_MODE1_DIV_2},
3305c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_4X, 64,   CS4271_MODE1_DIV_1},
3315c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_4X, 96,   CS4271_MODE1_DIV_1},
3325c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_4X, 128,  CS4271_MODE1_DIV_1},
3335c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_4X, 192,  CS4271_MODE1_DIV_2},
3345c3a12e9SAlexander Sverdlin 	{0, CS4271_MODE1_MODE_4X, 256,  CS4271_MODE1_DIV_2},
3355c3a12e9SAlexander Sverdlin };
3365c3a12e9SAlexander Sverdlin 
3370c03e37aSChristophe JAILLET #define CS4271_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab)
3385c3a12e9SAlexander Sverdlin 
cs4271_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)33967b22517SAlexander Sverdlin static int cs4271_hw_params(struct snd_pcm_substream *substream,
34067b22517SAlexander Sverdlin 			    struct snd_pcm_hw_params *params,
34167b22517SAlexander Sverdlin 			    struct snd_soc_dai *dai)
34267b22517SAlexander Sverdlin {
343cac308fcSKuninori Morimoto 	struct snd_soc_component *component = dai->component;
344cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
3450d42e6e7SAlexander Sverdlin 	int i, ret;
3460d42e6e7SAlexander Sverdlin 	unsigned int ratio, val;
34767b22517SAlexander Sverdlin 
348fd23fb9fSDaniel Mack 	if (cs4271->enable_soft_reset) {
349fd23fb9fSDaniel Mack 		/*
350fd23fb9fSDaniel Mack 		 * Put the codec in soft reset and back again in case it's not
351fd23fb9fSDaniel Mack 		 * currently streaming data. This way of bringing the codec in
352fd23fb9fSDaniel Mack 		 * sync to the current clocks is not explicitly documented in
353fd23fb9fSDaniel Mack 		 * the data sheet, but it seems to work fine, and in contrast
354fd23fb9fSDaniel Mack 		 * to a read hardware reset, we don't have to sync back all
355fd23fb9fSDaniel Mack 		 * registers every time.
356fd23fb9fSDaniel Mack 		 */
357fd23fb9fSDaniel Mack 
358fd23fb9fSDaniel Mack 		if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
3595e518eddSKuninori Morimoto 		     !snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE)) ||
360fd23fb9fSDaniel Mack 		    (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
3615e518eddSKuninori Morimoto 		     !snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK))) {
3621b1861eaSDaniel Mack 			ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
363fd23fb9fSDaniel Mack 						 CS4271_MODE2_PDN,
364fd23fb9fSDaniel Mack 						 CS4271_MODE2_PDN);
365fd23fb9fSDaniel Mack 			if (ret < 0)
366fd23fb9fSDaniel Mack 				return ret;
367fd23fb9fSDaniel Mack 
3681b1861eaSDaniel Mack 			ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
369fd23fb9fSDaniel Mack 						 CS4271_MODE2_PDN, 0);
370fd23fb9fSDaniel Mack 			if (ret < 0)
371fd23fb9fSDaniel Mack 				return ret;
372fd23fb9fSDaniel Mack 		}
373fd23fb9fSDaniel Mack 	}
374fd23fb9fSDaniel Mack 
37567b22517SAlexander Sverdlin 	cs4271->rate = params_rate(params);
3765c3a12e9SAlexander Sverdlin 
3775c3a12e9SAlexander Sverdlin 	/* Configure DAC */
3785c3a12e9SAlexander Sverdlin 	if (cs4271->rate < 50000)
3795c3a12e9SAlexander Sverdlin 		val = CS4271_MODE1_MODE_1X;
3805c3a12e9SAlexander Sverdlin 	else if (cs4271->rate < 100000)
3815c3a12e9SAlexander Sverdlin 		val = CS4271_MODE1_MODE_2X;
3825c3a12e9SAlexander Sverdlin 	else
3835c3a12e9SAlexander Sverdlin 		val = CS4271_MODE1_MODE_4X;
3845c3a12e9SAlexander Sverdlin 
38567b22517SAlexander Sverdlin 	ratio = cs4271->mclk / cs4271->rate;
3860c03e37aSChristophe JAILLET 	for (i = 0; i < CS4271_NR_RATIOS; i++)
3875c3a12e9SAlexander Sverdlin 		if ((cs4271_clk_tab[i].master == cs4271->master) &&
3885c3a12e9SAlexander Sverdlin 		    (cs4271_clk_tab[i].speed_mode == val) &&
3895c3a12e9SAlexander Sverdlin 		    (cs4271_clk_tab[i].ratio == ratio))
39067b22517SAlexander Sverdlin 			break;
39167b22517SAlexander Sverdlin 
3920c03e37aSChristophe JAILLET 	if (i == CS4271_NR_RATIOS) {
393cac308fcSKuninori Morimoto 		dev_err(component->dev, "Invalid sample rate\n");
39467b22517SAlexander Sverdlin 		return -EINVAL;
39567b22517SAlexander Sverdlin 	}
39667b22517SAlexander Sverdlin 
3975c3a12e9SAlexander Sverdlin 	val |= cs4271_clk_tab[i].ratio_mask;
39867b22517SAlexander Sverdlin 
3991b1861eaSDaniel Mack 	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,
40067b22517SAlexander Sverdlin 		CS4271_MODE1_MODE_MASK | CS4271_MODE1_DIV_MASK, val);
4010d42e6e7SAlexander Sverdlin 	if (ret < 0)
4020d42e6e7SAlexander Sverdlin 		return ret;
40367b22517SAlexander Sverdlin 
404cac308fcSKuninori Morimoto 	return cs4271_set_deemph(component);
40567b22517SAlexander Sverdlin }
40667b22517SAlexander Sverdlin 
cs4271_mute_stream(struct snd_soc_dai * dai,int mute,int stream)407c24a34dbSDaniel Mack static int cs4271_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
40867b22517SAlexander Sverdlin {
409cac308fcSKuninori Morimoto 	struct snd_soc_component *component = dai->component;
410cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
4110d42e6e7SAlexander Sverdlin 	int ret;
41267b22517SAlexander Sverdlin 	int val_a = 0;
41367b22517SAlexander Sverdlin 	int val_b = 0;
41467b22517SAlexander Sverdlin 
415c24a34dbSDaniel Mack 	if (stream != SNDRV_PCM_STREAM_PLAYBACK)
416c24a34dbSDaniel Mack 		return 0;
417c24a34dbSDaniel Mack 
41867b22517SAlexander Sverdlin 	if (mute) {
41967b22517SAlexander Sverdlin 		val_a = CS4271_VOLA_MUTE;
42067b22517SAlexander Sverdlin 		val_b = CS4271_VOLB_MUTE;
42167b22517SAlexander Sverdlin 	}
42267b22517SAlexander Sverdlin 
4231b1861eaSDaniel Mack 	ret = regmap_update_bits(cs4271->regmap, CS4271_VOLA,
4241b1861eaSDaniel Mack 				 CS4271_VOLA_MUTE, val_a);
4250d42e6e7SAlexander Sverdlin 	if (ret < 0)
4260d42e6e7SAlexander Sverdlin 		return ret;
4271b1861eaSDaniel Mack 
4281b1861eaSDaniel Mack 	ret = regmap_update_bits(cs4271->regmap, CS4271_VOLB,
4291b1861eaSDaniel Mack 				 CS4271_VOLB_MUTE, val_b);
4300d42e6e7SAlexander Sverdlin 	if (ret < 0)
4310d42e6e7SAlexander Sverdlin 		return ret;
43267b22517SAlexander Sverdlin 
43367b22517SAlexander Sverdlin 	return 0;
43467b22517SAlexander Sverdlin }
43567b22517SAlexander Sverdlin 
43667b22517SAlexander Sverdlin /* CS4271 controls */
43767b22517SAlexander Sverdlin static DECLARE_TLV_DB_SCALE(cs4271_dac_tlv, -12700, 100, 0);
43867b22517SAlexander Sverdlin 
43967b22517SAlexander Sverdlin static const struct snd_kcontrol_new cs4271_snd_controls[] = {
44067b22517SAlexander Sverdlin 	SOC_DOUBLE_R_TLV("Master Playback Volume", CS4271_VOLA, CS4271_VOLB,
44167b22517SAlexander Sverdlin 		0, 0x7F, 1, cs4271_dac_tlv),
44267b22517SAlexander Sverdlin 	SOC_SINGLE("Digital Loopback Switch", CS4271_MODE2, 4, 1, 0),
44367b22517SAlexander Sverdlin 	SOC_SINGLE("Soft Ramp Switch", CS4271_DACVOL, 5, 1, 0),
44467b22517SAlexander Sverdlin 	SOC_SINGLE("Zero Cross Switch", CS4271_DACVOL, 4, 1, 0),
44567b22517SAlexander Sverdlin 	SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
44667b22517SAlexander Sverdlin 		cs4271_get_deemph, cs4271_put_deemph),
44767b22517SAlexander Sverdlin 	SOC_SINGLE("Auto-Mute Switch", CS4271_DACCTL, 7, 1, 0),
44867b22517SAlexander Sverdlin 	SOC_SINGLE("Slow Roll Off Filter Switch", CS4271_DACCTL, 6, 1, 0),
44967b22517SAlexander Sverdlin 	SOC_SINGLE("Soft Volume Ramp-Up Switch", CS4271_DACCTL, 3, 1, 0),
45067b22517SAlexander Sverdlin 	SOC_SINGLE("Soft Ramp-Down Switch", CS4271_DACCTL, 2, 1, 0),
45167b22517SAlexander Sverdlin 	SOC_SINGLE("Left Channel Inversion Switch", CS4271_DACCTL, 1, 1, 0),
45267b22517SAlexander Sverdlin 	SOC_SINGLE("Right Channel Inversion Switch", CS4271_DACCTL, 0, 1, 0),
45367b22517SAlexander Sverdlin 	SOC_DOUBLE("Master Capture Switch", CS4271_ADCCTL, 3, 2, 1, 1),
45467b22517SAlexander Sverdlin 	SOC_SINGLE("Dither 16-Bit Data Switch", CS4271_ADCCTL, 5, 1, 0),
45567b22517SAlexander Sverdlin 	SOC_DOUBLE("High Pass Filter Switch", CS4271_ADCCTL, 1, 0, 1, 1),
45667b22517SAlexander Sverdlin 	SOC_DOUBLE_R("Master Playback Switch", CS4271_VOLA, CS4271_VOLB,
45767b22517SAlexander Sverdlin 		7, 1, 1),
45867b22517SAlexander Sverdlin };
45967b22517SAlexander Sverdlin 
46085e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops cs4271_dai_ops = {
46167b22517SAlexander Sverdlin 	.hw_params	= cs4271_hw_params,
46267b22517SAlexander Sverdlin 	.set_sysclk	= cs4271_set_dai_sysclk,
46367b22517SAlexander Sverdlin 	.set_fmt	= cs4271_set_dai_fmt,
464c24a34dbSDaniel Mack 	.mute_stream	= cs4271_mute_stream,
46567b22517SAlexander Sverdlin };
46667b22517SAlexander Sverdlin 
46716af7d60SMark Brown static struct snd_soc_dai_driver cs4271_dai = {
46867b22517SAlexander Sverdlin 	.name = "cs4271-hifi",
46967b22517SAlexander Sverdlin 	.playback = {
47067b22517SAlexander Sverdlin 		.stream_name	= "Playback",
47167b22517SAlexander Sverdlin 		.channels_min	= 2,
47267b22517SAlexander Sverdlin 		.channels_max	= 2,
473383f8465SAlexander Sverdlin 		.rates		= CS4271_PCM_RATES,
47467b22517SAlexander Sverdlin 		.formats	= CS4271_PCM_FORMATS,
47567b22517SAlexander Sverdlin 	},
47667b22517SAlexander Sverdlin 	.capture = {
47767b22517SAlexander Sverdlin 		.stream_name	= "Capture",
47867b22517SAlexander Sverdlin 		.channels_min	= 2,
47967b22517SAlexander Sverdlin 		.channels_max	= 2,
480383f8465SAlexander Sverdlin 		.rates		= CS4271_PCM_RATES,
48167b22517SAlexander Sverdlin 		.formats	= CS4271_PCM_FORMATS,
48267b22517SAlexander Sverdlin 	},
48367b22517SAlexander Sverdlin 	.ops = &cs4271_dai_ops,
484260b668cSKuninori Morimoto 	.symmetric_rate = 1,
48567b22517SAlexander Sverdlin };
48667b22517SAlexander Sverdlin 
cs4271_reset(struct snd_soc_component * component)487cac308fcSKuninori Morimoto static int cs4271_reset(struct snd_soc_component *component)
4889a397f47SPascal Huerst {
489cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
4909a397f47SPascal Huerst 
4919a397f47SPascal Huerst 	if (gpio_is_valid(cs4271->gpio_nreset)) {
49249b2e27aSAlexander Sverdlin 		gpio_direction_output(cs4271->gpio_nreset, 0);
4939a397f47SPascal Huerst 		mdelay(1);
4949a397f47SPascal Huerst 		gpio_set_value(cs4271->gpio_nreset, 1);
4959a397f47SPascal Huerst 		mdelay(1);
4969a397f47SPascal Huerst 	}
4979a397f47SPascal Huerst 
4989a397f47SPascal Huerst 	return 0;
4999a397f47SPascal Huerst }
5009a397f47SPascal Huerst 
50167b22517SAlexander Sverdlin #ifdef CONFIG_PM
cs4271_soc_suspend(struct snd_soc_component * component)502cac308fcSKuninori Morimoto static int cs4271_soc_suspend(struct snd_soc_component *component)
50367b22517SAlexander Sverdlin {
5040d42e6e7SAlexander Sverdlin 	int ret;
505cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
5061b1861eaSDaniel Mack 
50767b22517SAlexander Sverdlin 	/* Set power-down bit */
5081b1861eaSDaniel Mack 	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
5091b1861eaSDaniel Mack 				 CS4271_MODE2_PDN, CS4271_MODE2_PDN);
5100d42e6e7SAlexander Sverdlin 	if (ret < 0)
5110d42e6e7SAlexander Sverdlin 		return ret;
5121b1861eaSDaniel Mack 
5139a397f47SPascal Huerst 	regcache_mark_dirty(cs4271->regmap);
5149a397f47SPascal Huerst 	regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
5159a397f47SPascal Huerst 
51667b22517SAlexander Sverdlin 	return 0;
51767b22517SAlexander Sverdlin }
51867b22517SAlexander Sverdlin 
cs4271_soc_resume(struct snd_soc_component * component)519cac308fcSKuninori Morimoto static int cs4271_soc_resume(struct snd_soc_component *component)
52067b22517SAlexander Sverdlin {
5210d42e6e7SAlexander Sverdlin 	int ret;
522cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
5231b1861eaSDaniel Mack 
5249a397f47SPascal Huerst 	ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
5259a397f47SPascal Huerst 				    cs4271->supplies);
5269a397f47SPascal Huerst 	if (ret < 0) {
527cac308fcSKuninori Morimoto 		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
5289a397f47SPascal Huerst 		return ret;
5299a397f47SPascal Huerst 	}
5309a397f47SPascal Huerst 
5319a397f47SPascal Huerst 	/* Do a proper reset after power up */
532cac308fcSKuninori Morimoto 	cs4271_reset(component);
5339a397f47SPascal Huerst 
53467b22517SAlexander Sverdlin 	/* Restore codec state */
5351b1861eaSDaniel Mack 	ret = regcache_sync(cs4271->regmap);
5360d42e6e7SAlexander Sverdlin 	if (ret < 0)
5370d42e6e7SAlexander Sverdlin 		return ret;
5381b1861eaSDaniel Mack 
53967b22517SAlexander Sverdlin 	/* then disable the power-down bit */
5401b1861eaSDaniel Mack 	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
5411b1861eaSDaniel Mack 				 CS4271_MODE2_PDN, 0);
5420d42e6e7SAlexander Sverdlin 	if (ret < 0)
5430d42e6e7SAlexander Sverdlin 		return ret;
5441b1861eaSDaniel Mack 
54567b22517SAlexander Sverdlin 	return 0;
54667b22517SAlexander Sverdlin }
54767b22517SAlexander Sverdlin #else
54867b22517SAlexander Sverdlin #define cs4271_soc_suspend	NULL
54967b22517SAlexander Sverdlin #define cs4271_soc_resume	NULL
55067b22517SAlexander Sverdlin #endif /* CONFIG_PM */
55167b22517SAlexander Sverdlin 
552a31ebc34SDaniel Mack #ifdef CONFIG_OF
553c973b8a7SAxel Lin const struct of_device_id cs4271_dt_ids[] = {
554a31ebc34SDaniel Mack 	{ .compatible = "cirrus,cs4271", },
555a31ebc34SDaniel Mack 	{ }
556a31ebc34SDaniel Mack };
557a31ebc34SDaniel Mack MODULE_DEVICE_TABLE(of, cs4271_dt_ids);
558c973b8a7SAxel Lin EXPORT_SYMBOL_GPL(cs4271_dt_ids);
559a31ebc34SDaniel Mack #endif
560a31ebc34SDaniel Mack 
cs4271_component_probe(struct snd_soc_component * component)561cac308fcSKuninori Morimoto static int cs4271_component_probe(struct snd_soc_component *component)
56267b22517SAlexander Sverdlin {
563cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
564cac308fcSKuninori Morimoto 	struct cs4271_platform_data *cs4271plat = component->dev->platform_data;
56567b22517SAlexander Sverdlin 	int ret;
56626047e2dSDaniel Mack 	bool amutec_eq_bmutec = false;
56767b22517SAlexander Sverdlin 
568a31ebc34SDaniel Mack #ifdef CONFIG_OF
569cac308fcSKuninori Morimoto 	if (of_match_device(cs4271_dt_ids, component->dev)) {
570cac308fcSKuninori Morimoto 		if (of_get_property(component->dev->of_node,
571293750f9SDaniel Mack 				     "cirrus,amutec-eq-bmutec", NULL))
57226047e2dSDaniel Mack 			amutec_eq_bmutec = true;
573fd23fb9fSDaniel Mack 
574cac308fcSKuninori Morimoto 		if (of_get_property(component->dev->of_node,
575fd23fb9fSDaniel Mack 				     "cirrus,enable-soft-reset", NULL))
576fd23fb9fSDaniel Mack 			cs4271->enable_soft_reset = true;
577293750f9SDaniel Mack 	}
578a31ebc34SDaniel Mack #endif
579a31ebc34SDaniel Mack 
5809a397f47SPascal Huerst 	ret = regulator_bulk_enable(ARRAY_SIZE(cs4271->supplies),
5819a397f47SPascal Huerst 				    cs4271->supplies);
5829a397f47SPascal Huerst 	if (ret < 0) {
583cac308fcSKuninori Morimoto 		dev_err(component->dev, "Failed to enable regulators: %d\n", ret);
5849a397f47SPascal Huerst 		return ret;
5859a397f47SPascal Huerst 	}
5869a397f47SPascal Huerst 
587293750f9SDaniel Mack 	if (cs4271plat) {
588293750f9SDaniel Mack 		amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
589fd23fb9fSDaniel Mack 		cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
590293750f9SDaniel Mack 	}
591293750f9SDaniel Mack 
59267b22517SAlexander Sverdlin 	/* Reset codec */
593cac308fcSKuninori Morimoto 	cs4271_reset(component);
5949a397f47SPascal Huerst 
5959a397f47SPascal Huerst 	ret = regcache_sync(cs4271->regmap);
5969a397f47SPascal Huerst 	if (ret < 0)
5979a397f47SPascal Huerst 		return ret;
59867b22517SAlexander Sverdlin 
5991b1861eaSDaniel Mack 	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
600ef0cd470SAxel Lin 				 CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
60167b22517SAlexander Sverdlin 				 CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
6020d42e6e7SAlexander Sverdlin 	if (ret < 0)
6030d42e6e7SAlexander Sverdlin 		return ret;
6041b1861eaSDaniel Mack 	ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
6051b1861eaSDaniel Mack 				 CS4271_MODE2_PDN, 0);
6060d42e6e7SAlexander Sverdlin 	if (ret < 0)
6070d42e6e7SAlexander Sverdlin 		return ret;
60867b22517SAlexander Sverdlin 	/* Power-up sequence requires 85 uS */
60967b22517SAlexander Sverdlin 	udelay(85);
61067b22517SAlexander Sverdlin 
611293750f9SDaniel Mack 	if (amutec_eq_bmutec)
6121b1861eaSDaniel Mack 		regmap_update_bits(cs4271->regmap, CS4271_MODE2,
613293750f9SDaniel Mack 				   CS4271_MODE2_MUTECAEQUB,
614293750f9SDaniel Mack 				   CS4271_MODE2_MUTECAEQUB);
615293750f9SDaniel Mack 
616bad268f3SMark Brown 	return 0;
61767b22517SAlexander Sverdlin }
61867b22517SAlexander Sverdlin 
cs4271_component_remove(struct snd_soc_component * component)619cac308fcSKuninori Morimoto static void cs4271_component_remove(struct snd_soc_component *component)
62067b22517SAlexander Sverdlin {
621cac308fcSKuninori Morimoto 	struct cs4271_private *cs4271 = snd_soc_component_get_drvdata(component);
62267b22517SAlexander Sverdlin 
6235574f774SDaniel Mack 	if (gpio_is_valid(cs4271->gpio_nreset))
62467b22517SAlexander Sverdlin 		/* Set codec to the reset state */
6255574f774SDaniel Mack 		gpio_set_value(cs4271->gpio_nreset, 0);
62667b22517SAlexander Sverdlin 
6279a397f47SPascal Huerst 	regcache_mark_dirty(cs4271->regmap);
6289a397f47SPascal Huerst 	regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
62967b22517SAlexander Sverdlin };
63067b22517SAlexander Sverdlin 
631cac308fcSKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_cs4271 = {
632cac308fcSKuninori Morimoto 	.probe			= cs4271_component_probe,
633cac308fcSKuninori Morimoto 	.remove			= cs4271_component_remove,
63467b22517SAlexander Sverdlin 	.suspend		= cs4271_soc_suspend,
63567b22517SAlexander Sverdlin 	.resume			= cs4271_soc_resume,
636bad268f3SMark Brown 	.controls		= cs4271_snd_controls,
637bad268f3SMark Brown 	.num_controls		= ARRAY_SIZE(cs4271_snd_controls),
6382e7fb942SMark Brown 	.dapm_widgets		= cs4271_dapm_widgets,
6392e7fb942SMark Brown 	.num_dapm_widgets	= ARRAY_SIZE(cs4271_dapm_widgets),
6402e7fb942SMark Brown 	.dapm_routes		= cs4271_dapm_routes,
6412e7fb942SMark Brown 	.num_dapm_routes	= ARRAY_SIZE(cs4271_dapm_routes),
642cac308fcSKuninori Morimoto 	.idle_bias_on		= 1,
643cac308fcSKuninori Morimoto 	.use_pmdown_time	= 1,
644cac308fcSKuninori Morimoto 	.endianness		= 1,
64567b22517SAlexander Sverdlin };
64667b22517SAlexander Sverdlin 
cs4271_common_probe(struct device * dev,struct cs4271_private ** c)647d6cf89eeSDaniel Mack static int cs4271_common_probe(struct device *dev,
648d6cf89eeSDaniel Mack 			       struct cs4271_private **c)
649d6cf89eeSDaniel Mack {
650d6cf89eeSDaniel Mack 	struct cs4271_platform_data *cs4271plat = dev->platform_data;
651d6cf89eeSDaniel Mack 	struct cs4271_private *cs4271;
6529a397f47SPascal Huerst 	int i, ret;
653d6cf89eeSDaniel Mack 
654d6cf89eeSDaniel Mack 	cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL);
655d6cf89eeSDaniel Mack 	if (!cs4271)
656d6cf89eeSDaniel Mack 		return -ENOMEM;
657d6cf89eeSDaniel Mack 
658d6cf89eeSDaniel Mack 	if (of_match_device(cs4271_dt_ids, dev))
659d6cf89eeSDaniel Mack 		cs4271->gpio_nreset =
660d6cf89eeSDaniel Mack 			of_get_named_gpio(dev->of_node, "reset-gpio", 0);
661d6cf89eeSDaniel Mack 
662d6cf89eeSDaniel Mack 	if (cs4271plat)
663d6cf89eeSDaniel Mack 		cs4271->gpio_nreset = cs4271plat->gpio_nreset;
664d6cf89eeSDaniel Mack 
665d6cf89eeSDaniel Mack 	if (gpio_is_valid(cs4271->gpio_nreset)) {
666d6cf89eeSDaniel Mack 		ret = devm_gpio_request(dev, cs4271->gpio_nreset,
667d6cf89eeSDaniel Mack 					"CS4271 Reset");
668d6cf89eeSDaniel Mack 		if (ret < 0)
669d6cf89eeSDaniel Mack 			return ret;
670d6cf89eeSDaniel Mack 	}
671d6cf89eeSDaniel Mack 
6729a397f47SPascal Huerst 	for (i = 0; i < ARRAY_SIZE(supply_names); i++)
6739a397f47SPascal Huerst 		cs4271->supplies[i].supply = supply_names[i];
6749a397f47SPascal Huerst 
6759a397f47SPascal Huerst 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs4271->supplies),
6769a397f47SPascal Huerst 					cs4271->supplies);
6779a397f47SPascal Huerst 
6789a397f47SPascal Huerst 	if (ret < 0) {
6799a397f47SPascal Huerst 		dev_err(dev, "Failed to get regulators: %d\n", ret);
6809a397f47SPascal Huerst 		return ret;
6819a397f47SPascal Huerst 	}
6829a397f47SPascal Huerst 
683d6cf89eeSDaniel Mack 	*c = cs4271;
684d6cf89eeSDaniel Mack 	return 0;
685d6cf89eeSDaniel Mack }
686d6cf89eeSDaniel Mack 
687c973b8a7SAxel Lin const struct regmap_config cs4271_regmap_config = {
6881b1861eaSDaniel Mack 	.max_register = CS4271_LASTREG,
6891b1861eaSDaniel Mack 
6901b1861eaSDaniel Mack 	.reg_defaults = cs4271_reg_defaults,
6911b1861eaSDaniel Mack 	.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
692*2e9688c8SAlexander Sverdlin 	.cache_type = REGCACHE_FLAT,
693*2e9688c8SAlexander Sverdlin 	.val_bits = 8,
6941b1861eaSDaniel Mack 	.volatile_reg = cs4271_volatile_reg,
6951b1861eaSDaniel Mack };
696c973b8a7SAxel Lin EXPORT_SYMBOL_GPL(cs4271_regmap_config);
6971b1861eaSDaniel Mack 
cs4271_probe(struct device * dev,struct regmap * regmap)698c973b8a7SAxel Lin int cs4271_probe(struct device *dev, struct regmap *regmap)
69967b22517SAlexander Sverdlin {
70067b22517SAlexander Sverdlin 	struct cs4271_private *cs4271;
701d6cf89eeSDaniel Mack 	int ret;
70267b22517SAlexander Sverdlin 
703c973b8a7SAxel Lin 	if (IS_ERR(regmap))
704c973b8a7SAxel Lin 		return PTR_ERR(regmap);
705c973b8a7SAxel Lin 
706c973b8a7SAxel Lin 	ret = cs4271_common_probe(dev, &cs4271);
707d6cf89eeSDaniel Mack 	if (ret < 0)
708d6cf89eeSDaniel Mack 		return ret;
70967b22517SAlexander Sverdlin 
710c973b8a7SAxel Lin 	dev_set_drvdata(dev, cs4271);
711c973b8a7SAxel Lin 	cs4271->regmap = regmap;
71267b22517SAlexander Sverdlin 
713cac308fcSKuninori Morimoto 	return devm_snd_soc_register_component(dev, &soc_component_dev_cs4271,
714cac308fcSKuninori Morimoto 					       &cs4271_dai, 1);
71567b22517SAlexander Sverdlin }
716c973b8a7SAxel Lin EXPORT_SYMBOL_GPL(cs4271_probe);
71767b22517SAlexander Sverdlin 
71867b22517SAlexander Sverdlin MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
71967b22517SAlexander Sverdlin MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver");
72067b22517SAlexander Sverdlin MODULE_LICENSE("GPL");
721