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