cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cs42xx8.c (20415B)


      1/*
      2 * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
      3 *
      4 * Copyright (C) 2014 Freescale Semiconductor, Inc.
      5 *
      6 * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
      7 *
      8 * This file is licensed under the terms of the GNU General Public License
      9 * version 2. This program is licensed "as is" without any warranty of any
     10 * kind, whether express or implied.
     11 */
     12
     13#include <linux/clk.h>
     14#include <linux/delay.h>
     15#include <linux/module.h>
     16#include <linux/of_device.h>
     17#include <linux/gpio/consumer.h>
     18#include <linux/pm_runtime.h>
     19#include <linux/regulator/consumer.h>
     20#include <sound/pcm_params.h>
     21#include <sound/soc.h>
     22#include <sound/tlv.h>
     23
     24#include "cs42xx8.h"
     25
     26#define CS42XX8_NUM_SUPPLIES 4
     27static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {
     28	"VA",
     29	"VD",
     30	"VLS",
     31	"VLC",
     32};
     33
     34#define CS42XX8_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
     35			 SNDRV_PCM_FMTBIT_S20_3LE | \
     36			 SNDRV_PCM_FMTBIT_S24_LE | \
     37			 SNDRV_PCM_FMTBIT_S32_LE)
     38
     39/* codec private data */
     40struct cs42xx8_priv {
     41	struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];
     42	const struct cs42xx8_driver_data *drvdata;
     43	struct regmap *regmap;
     44	struct clk *clk;
     45
     46	bool slave_mode;
     47	unsigned long sysclk;
     48	u32 tx_channels;
     49	struct gpio_desc *gpiod_reset;
     50	u32 rate[2];
     51};
     52
     53/* -127.5dB to 0dB with step of 0.5dB */
     54static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
     55/* -64dB to 24dB with step of 0.5dB */
     56static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
     57
     58static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };
     59static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",
     60					"Soft Ramp", "Soft Ramp on Zero Cross" };
     61
     62static const struct soc_enum adc1_single_enum =
     63	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);
     64static const struct soc_enum adc2_single_enum =
     65	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);
     66static const struct soc_enum adc3_single_enum =
     67	SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);
     68static const struct soc_enum dac_szc_enum =
     69	SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);
     70static const struct soc_enum adc_szc_enum =
     71	SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);
     72
     73static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {
     74	SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,
     75			 CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),
     76	SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,
     77			 CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),
     78	SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,
     79			 CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),
     80	SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,
     81			 CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),
     82	SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,
     83			   CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
     84	SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,
     85			   CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
     86	SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),
     87	SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),
     88	SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),
     89	SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),
     90	SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),
     91	SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),
     92	SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),
     93	SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),
     94	SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),
     95	SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),
     96	SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),
     97	SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
     98	SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),
     99	SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),
    100	SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),
    101	SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),
    102};
    103
    104static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {
    105	SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,
    106			   CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),
    107	SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),
    108	SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),
    109};
    110
    111static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {
    112	SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),
    113	SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),
    114	SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),
    115	SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),
    116
    117	SND_SOC_DAPM_OUTPUT("AOUT1L"),
    118	SND_SOC_DAPM_OUTPUT("AOUT1R"),
    119	SND_SOC_DAPM_OUTPUT("AOUT2L"),
    120	SND_SOC_DAPM_OUTPUT("AOUT2R"),
    121	SND_SOC_DAPM_OUTPUT("AOUT3L"),
    122	SND_SOC_DAPM_OUTPUT("AOUT3R"),
    123	SND_SOC_DAPM_OUTPUT("AOUT4L"),
    124	SND_SOC_DAPM_OUTPUT("AOUT4R"),
    125
    126	SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),
    127	SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),
    128
    129	SND_SOC_DAPM_INPUT("AIN1L"),
    130	SND_SOC_DAPM_INPUT("AIN1R"),
    131	SND_SOC_DAPM_INPUT("AIN2L"),
    132	SND_SOC_DAPM_INPUT("AIN2R"),
    133
    134	SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),
    135};
    136
    137static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {
    138	SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),
    139
    140	SND_SOC_DAPM_INPUT("AIN3L"),
    141	SND_SOC_DAPM_INPUT("AIN3R"),
    142};
    143
    144static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {
    145	/* Playback */
    146	{ "AOUT1L", NULL, "DAC1" },
    147	{ "AOUT1R", NULL, "DAC1" },
    148	{ "DAC1", NULL, "PWR" },
    149
    150	{ "AOUT2L", NULL, "DAC2" },
    151	{ "AOUT2R", NULL, "DAC2" },
    152	{ "DAC2", NULL, "PWR" },
    153
    154	{ "AOUT3L", NULL, "DAC3" },
    155	{ "AOUT3R", NULL, "DAC3" },
    156	{ "DAC3", NULL, "PWR" },
    157
    158	{ "AOUT4L", NULL, "DAC4" },
    159	{ "AOUT4R", NULL, "DAC4" },
    160	{ "DAC4", NULL, "PWR" },
    161
    162	/* Capture */
    163	{ "ADC1", NULL, "AIN1L" },
    164	{ "ADC1", NULL, "AIN1R" },
    165	{ "ADC1", NULL, "PWR" },
    166
    167	{ "ADC2", NULL, "AIN2L" },
    168	{ "ADC2", NULL, "AIN2R" },
    169	{ "ADC2", NULL, "PWR" },
    170};
    171
    172static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
    173	/* Capture */
    174	{ "ADC3", NULL, "AIN3L" },
    175	{ "ADC3", NULL, "AIN3R" },
    176	{ "ADC3", NULL, "PWR" },
    177};
    178
    179struct cs42xx8_ratios {
    180	unsigned int mfreq;
    181	unsigned int min_mclk;
    182	unsigned int max_mclk;
    183	unsigned int ratio[3];
    184};
    185
    186/*
    187 * According to reference mannual, define the cs42xx8_ratio struct
    188 * MFreq2 | MFreq1 | MFreq0 |     Description     | SSM | DSM | QSM |
    189 * 0      | 0      | 0      |1.029MHz to 12.8MHz  | 256 | 128 |  64 |
    190 * 0      | 0      | 1      |1.536MHz to 19.2MHz  | 384 | 192 |  96 |
    191 * 0      | 1      | 0      |2.048MHz to 25.6MHz  | 512 | 256 | 128 |
    192 * 0      | 1      | 1      |3.072MHz to 38.4MHz  | 768 | 384 | 192 |
    193 * 1      | x      | x      |4.096MHz to 51.2MHz  |1024 | 512 | 256 |
    194 */
    195static const struct cs42xx8_ratios cs42xx8_ratios[] = {
    196	{ 0, 1029000, 12800000, {256, 128, 64} },
    197	{ 2, 1536000, 19200000, {384, 192, 96} },
    198	{ 4, 2048000, 25600000, {512, 256, 128} },
    199	{ 6, 3072000, 38400000, {768, 384, 192} },
    200	{ 8, 4096000, 51200000, {1024, 512, 256} },
    201};
    202
    203static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
    204				  int clk_id, unsigned int freq, int dir)
    205{
    206	struct snd_soc_component *component = codec_dai->component;
    207	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
    208
    209	cs42xx8->sysclk = freq;
    210
    211	return 0;
    212}
    213
    214static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
    215			       unsigned int format)
    216{
    217	struct snd_soc_component *component = codec_dai->component;
    218	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
    219	u32 val;
    220
    221	/* Set DAI format */
    222	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
    223	case SND_SOC_DAIFMT_LEFT_J:
    224		val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;
    225		break;
    226	case SND_SOC_DAIFMT_I2S:
    227		val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;
    228		break;
    229	case SND_SOC_DAIFMT_RIGHT_J:
    230		val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
    231		break;
    232	case SND_SOC_DAIFMT_DSP_A:
    233		val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;
    234		break;
    235	default:
    236		dev_err(component->dev, "unsupported dai format\n");
    237		return -EINVAL;
    238	}
    239
    240	regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,
    241			   CS42XX8_INTF_DAC_DIF_MASK |
    242			   CS42XX8_INTF_ADC_DIF_MASK, val);
    243
    244	/* Set master/slave audio interface */
    245	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
    246	case SND_SOC_DAIFMT_CBS_CFS:
    247		cs42xx8->slave_mode = true;
    248		break;
    249	case SND_SOC_DAIFMT_CBM_CFM:
    250		cs42xx8->slave_mode = false;
    251		break;
    252	default:
    253		dev_err(component->dev, "unsupported master/slave mode\n");
    254		return -EINVAL;
    255	}
    256
    257	return 0;
    258}
    259
    260static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
    261			     struct snd_pcm_hw_params *params,
    262			     struct snd_soc_dai *dai)
    263{
    264	struct snd_soc_component *component = dai->component;
    265	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
    266	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
    267	u32 ratio[2];
    268	u32 rate[2];
    269	u32 fm[2];
    270	u32 i, val, mask;
    271	bool condition1, condition2;
    272
    273	if (tx)
    274		cs42xx8->tx_channels = params_channels(params);
    275
    276	rate[tx]  = params_rate(params);
    277	rate[!tx] = cs42xx8->rate[!tx];
    278
    279	ratio[tx] = rate[tx] > 0 ? cs42xx8->sysclk / rate[tx] : 0;
    280	ratio[!tx] = rate[!tx] > 0 ? cs42xx8->sysclk / rate[!tx] : 0;
    281
    282	/* Get functional mode for tx and rx according to rate */
    283	for (i = 0; i < 2; i++) {
    284		if (cs42xx8->slave_mode) {
    285			fm[i] = CS42XX8_FM_AUTO;
    286		} else {
    287			if (rate[i] < 50000) {
    288				fm[i] = CS42XX8_FM_SINGLE;
    289			} else if (rate[i] > 50000 && rate[i] < 100000) {
    290				fm[i] = CS42XX8_FM_DOUBLE;
    291			} else if (rate[i] > 100000 && rate[i] < 200000) {
    292				fm[i] = CS42XX8_FM_QUAD;
    293			} else {
    294				dev_err(component->dev,
    295					"unsupported sample rate\n");
    296				return -EINVAL;
    297			}
    298		}
    299	}
    300
    301	for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
    302		/* Is the ratio[tx] valid ? */
    303		condition1 = ((fm[tx] == CS42XX8_FM_AUTO) ?
    304			(cs42xx8_ratios[i].ratio[0] == ratio[tx] ||
    305			cs42xx8_ratios[i].ratio[1] == ratio[tx] ||
    306			cs42xx8_ratios[i].ratio[2] == ratio[tx]) :
    307			(cs42xx8_ratios[i].ratio[fm[tx]] == ratio[tx])) &&
    308			cs42xx8->sysclk >= cs42xx8_ratios[i].min_mclk &&
    309			cs42xx8->sysclk <= cs42xx8_ratios[i].max_mclk;
    310
    311		if (!ratio[tx])
    312			condition1 = true;
    313
    314		/* Is the ratio[!tx] valid ? */
    315		condition2 = ((fm[!tx] == CS42XX8_FM_AUTO) ?
    316			(cs42xx8_ratios[i].ratio[0] == ratio[!tx] ||
    317			cs42xx8_ratios[i].ratio[1] == ratio[!tx] ||
    318			cs42xx8_ratios[i].ratio[2] == ratio[!tx]) :
    319			(cs42xx8_ratios[i].ratio[fm[!tx]] == ratio[!tx]));
    320
    321		if (!ratio[!tx])
    322			condition2 = true;
    323
    324		/*
    325		 * Both ratio[tx] and ratio[!tx] is valid, then we get
    326		 * a proper MFreq.
    327		 */
    328		if (condition1 && condition2)
    329			break;
    330	}
    331
    332	if (i == ARRAY_SIZE(cs42xx8_ratios)) {
    333		dev_err(component->dev, "unsupported sysclk ratio\n");
    334		return -EINVAL;
    335	}
    336
    337	cs42xx8->rate[tx] = params_rate(params);
    338
    339	mask = CS42XX8_FUNCMOD_MFREQ_MASK;
    340	val = cs42xx8_ratios[i].mfreq;
    341
    342	regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
    343			   CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
    344			   CS42XX8_FUNCMOD_xC_FM(tx, fm[tx]) | val);
    345
    346	return 0;
    347}
    348
    349static int cs42xx8_hw_free(struct snd_pcm_substream *substream,
    350			   struct snd_soc_dai *dai)
    351{
    352	struct snd_soc_component *component = dai->component;
    353	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
    354	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
    355
    356	/* Clear stored rate */
    357	cs42xx8->rate[tx] = 0;
    358
    359	regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
    360			   CS42XX8_FUNCMOD_xC_FM_MASK(tx),
    361			   CS42XX8_FUNCMOD_xC_FM(tx, CS42XX8_FM_AUTO));
    362	return 0;
    363}
    364
    365static int cs42xx8_mute(struct snd_soc_dai *dai, int mute, int direction)
    366{
    367	struct snd_soc_component *component = dai->component;
    368	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
    369	u8 dac_unmute = cs42xx8->tx_channels ?
    370		        ~((0x1 << cs42xx8->tx_channels) - 1) : 0;
    371
    372	regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE,
    373		     mute ? CS42XX8_DACMUTE_ALL : dac_unmute);
    374
    375	return 0;
    376}
    377
    378static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
    379	.set_fmt	= cs42xx8_set_dai_fmt,
    380	.set_sysclk	= cs42xx8_set_dai_sysclk,
    381	.hw_params	= cs42xx8_hw_params,
    382	.hw_free	= cs42xx8_hw_free,
    383	.mute_stream	= cs42xx8_mute,
    384	.no_capture_mute = 1,
    385};
    386
    387static struct snd_soc_dai_driver cs42xx8_dai = {
    388	.playback = {
    389		.stream_name = "Playback",
    390		.channels_min = 1,
    391		.channels_max = 8,
    392		.rates = SNDRV_PCM_RATE_8000_192000,
    393		.formats = CS42XX8_FORMATS,
    394	},
    395	.capture = {
    396		.stream_name = "Capture",
    397		.channels_min = 1,
    398		.rates = SNDRV_PCM_RATE_8000_192000,
    399		.formats = CS42XX8_FORMATS,
    400	},
    401	.ops = &cs42xx8_dai_ops,
    402};
    403
    404static const struct reg_default cs42xx8_reg[] = {
    405	{ 0x02, 0x00 },   /* Power Control */
    406	{ 0x03, 0xF0 },   /* Functional Mode */
    407	{ 0x04, 0x46 },   /* Interface Formats */
    408	{ 0x05, 0x00 },   /* ADC Control & DAC De-Emphasis */
    409	{ 0x06, 0x10 },   /* Transition Control */
    410	{ 0x07, 0x00 },   /* DAC Channel Mute */
    411	{ 0x08, 0x00 },   /* Volume Control AOUT1 */
    412	{ 0x09, 0x00 },   /* Volume Control AOUT2 */
    413	{ 0x0a, 0x00 },   /* Volume Control AOUT3 */
    414	{ 0x0b, 0x00 },   /* Volume Control AOUT4 */
    415	{ 0x0c, 0x00 },   /* Volume Control AOUT5 */
    416	{ 0x0d, 0x00 },   /* Volume Control AOUT6 */
    417	{ 0x0e, 0x00 },   /* Volume Control AOUT7 */
    418	{ 0x0f, 0x00 },   /* Volume Control AOUT8 */
    419	{ 0x10, 0x00 },   /* DAC Channel Invert */
    420	{ 0x11, 0x00 },   /* Volume Control AIN1 */
    421	{ 0x12, 0x00 },   /* Volume Control AIN2 */
    422	{ 0x13, 0x00 },   /* Volume Control AIN3 */
    423	{ 0x14, 0x00 },   /* Volume Control AIN4 */
    424	{ 0x15, 0x00 },   /* Volume Control AIN5 */
    425	{ 0x16, 0x00 },   /* Volume Control AIN6 */
    426	{ 0x17, 0x00 },   /* ADC Channel Invert */
    427	{ 0x18, 0x00 },   /* Status Control */
    428	{ 0x1a, 0x00 },   /* Status Mask */
    429	{ 0x1b, 0x00 },   /* MUTEC Pin Control */
    430};
    431
    432static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)
    433{
    434	switch (reg) {
    435	case CS42XX8_STATUS:
    436		return true;
    437	default:
    438		return false;
    439	}
    440}
    441
    442static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)
    443{
    444	switch (reg) {
    445	case CS42XX8_CHIPID:
    446	case CS42XX8_STATUS:
    447		return false;
    448	default:
    449		return true;
    450	}
    451}
    452
    453const struct regmap_config cs42xx8_regmap_config = {
    454	.reg_bits = 8,
    455	.val_bits = 8,
    456
    457	.max_register = CS42XX8_LASTREG,
    458	.reg_defaults = cs42xx8_reg,
    459	.num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
    460	.volatile_reg = cs42xx8_volatile_register,
    461	.writeable_reg = cs42xx8_writeable_register,
    462	.cache_type = REGCACHE_RBTREE,
    463};
    464EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
    465
    466static int cs42xx8_component_probe(struct snd_soc_component *component)
    467{
    468	struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component);
    469	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
    470
    471	switch (cs42xx8->drvdata->num_adcs) {
    472	case 3:
    473		snd_soc_add_component_controls(component, cs42xx8_adc3_snd_controls,
    474					ARRAY_SIZE(cs42xx8_adc3_snd_controls));
    475		snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
    476					ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
    477		snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,
    478					ARRAY_SIZE(cs42xx8_adc3_dapm_routes));
    479		break;
    480	default:
    481		break;
    482	}
    483
    484	/* Mute all DAC channels */
    485	regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);
    486
    487	return 0;
    488}
    489
    490static const struct snd_soc_component_driver cs42xx8_driver = {
    491	.probe			= cs42xx8_component_probe,
    492	.controls		= cs42xx8_snd_controls,
    493	.num_controls		= ARRAY_SIZE(cs42xx8_snd_controls),
    494	.dapm_widgets		= cs42xx8_dapm_widgets,
    495	.num_dapm_widgets	= ARRAY_SIZE(cs42xx8_dapm_widgets),
    496	.dapm_routes		= cs42xx8_dapm_routes,
    497	.num_dapm_routes	= ARRAY_SIZE(cs42xx8_dapm_routes),
    498	.use_pmdown_time	= 1,
    499	.endianness		= 1,
    500	.non_legacy_dai_naming	= 1,
    501};
    502
    503const struct cs42xx8_driver_data cs42448_data = {
    504	.name = "cs42448",
    505	.num_adcs = 3,
    506};
    507EXPORT_SYMBOL_GPL(cs42448_data);
    508
    509const struct cs42xx8_driver_data cs42888_data = {
    510	.name = "cs42888",
    511	.num_adcs = 2,
    512};
    513EXPORT_SYMBOL_GPL(cs42888_data);
    514
    515const struct of_device_id cs42xx8_of_match[] = {
    516	{ .compatible = "cirrus,cs42448", .data = &cs42448_data, },
    517	{ .compatible = "cirrus,cs42888", .data = &cs42888_data, },
    518	{ /* sentinel */ }
    519};
    520MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
    521EXPORT_SYMBOL_GPL(cs42xx8_of_match);
    522
    523int cs42xx8_probe(struct device *dev, struct regmap *regmap)
    524{
    525	const struct of_device_id *of_id;
    526	struct cs42xx8_priv *cs42xx8;
    527	int ret, val, i;
    528
    529	if (IS_ERR(regmap)) {
    530		ret = PTR_ERR(regmap);
    531		dev_err(dev, "failed to allocate regmap: %d\n", ret);
    532		return ret;
    533	}
    534
    535	cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
    536	if (cs42xx8 == NULL)
    537		return -ENOMEM;
    538
    539	cs42xx8->regmap = regmap;
    540	dev_set_drvdata(dev, cs42xx8);
    541
    542	of_id = of_match_device(cs42xx8_of_match, dev);
    543	if (of_id)
    544		cs42xx8->drvdata = of_id->data;
    545
    546	if (!cs42xx8->drvdata) {
    547		dev_err(dev, "failed to find driver data\n");
    548		return -EINVAL;
    549	}
    550
    551	cs42xx8->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
    552							GPIOD_OUT_HIGH);
    553	if (IS_ERR(cs42xx8->gpiod_reset))
    554		return PTR_ERR(cs42xx8->gpiod_reset);
    555
    556	gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);
    557
    558	cs42xx8->clk = devm_clk_get(dev, "mclk");
    559	if (IS_ERR(cs42xx8->clk)) {
    560		dev_err(dev, "failed to get the clock: %ld\n",
    561				PTR_ERR(cs42xx8->clk));
    562		return -EINVAL;
    563	}
    564
    565	cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
    566
    567	for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)
    568		cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];
    569
    570	ret = devm_regulator_bulk_get(dev,
    571			ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);
    572	if (ret) {
    573		dev_err(dev, "failed to request supplies: %d\n", ret);
    574		return ret;
    575	}
    576
    577	ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
    578				    cs42xx8->supplies);
    579	if (ret) {
    580		dev_err(dev, "failed to enable supplies: %d\n", ret);
    581		return ret;
    582	}
    583
    584	/* Make sure hardware reset done */
    585	msleep(5);
    586
    587	/* Validate the chip ID */
    588	ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
    589	if (ret < 0) {
    590		dev_err(dev, "failed to get device ID, ret = %d", ret);
    591		goto err_enable;
    592	}
    593
    594	/* The top four bits of the chip ID should be 0000 */
    595	if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) {
    596		dev_err(dev, "unmatched chip ID: %d\n",
    597			(val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4);
    598		ret = -EINVAL;
    599		goto err_enable;
    600	}
    601
    602	dev_info(dev, "found device, revision %X\n",
    603			val & CS42XX8_CHIPID_REV_ID_MASK);
    604
    605	cs42xx8_dai.name = cs42xx8->drvdata->name;
    606
    607	/* Each adc supports stereo input */
    608	cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
    609
    610	ret = devm_snd_soc_register_component(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
    611	if (ret) {
    612		dev_err(dev, "failed to register component:%d\n", ret);
    613		goto err_enable;
    614	}
    615
    616	regcache_cache_only(cs42xx8->regmap, true);
    617
    618err_enable:
    619	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
    620			       cs42xx8->supplies);
    621
    622	return ret;
    623}
    624EXPORT_SYMBOL_GPL(cs42xx8_probe);
    625
    626#ifdef CONFIG_PM
    627static int cs42xx8_runtime_resume(struct device *dev)
    628{
    629	struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
    630	int ret;
    631
    632	ret = clk_prepare_enable(cs42xx8->clk);
    633	if (ret) {
    634		dev_err(dev, "failed to enable mclk: %d\n", ret);
    635		return ret;
    636	}
    637
    638	gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 0);
    639
    640	ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
    641				    cs42xx8->supplies);
    642	if (ret) {
    643		dev_err(dev, "failed to enable supplies: %d\n", ret);
    644		goto err_clk;
    645	}
    646
    647	/* Make sure hardware reset done */
    648	msleep(5);
    649
    650	regcache_cache_only(cs42xx8->regmap, false);
    651	regcache_mark_dirty(cs42xx8->regmap);
    652
    653	ret = regcache_sync(cs42xx8->regmap);
    654	if (ret) {
    655		dev_err(dev, "failed to sync regmap: %d\n", ret);
    656		goto err_bulk;
    657	}
    658
    659	return 0;
    660
    661err_bulk:
    662	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
    663			       cs42xx8->supplies);
    664err_clk:
    665	clk_disable_unprepare(cs42xx8->clk);
    666
    667	return ret;
    668}
    669
    670static int cs42xx8_runtime_suspend(struct device *dev)
    671{
    672	struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
    673
    674	regcache_cache_only(cs42xx8->regmap, true);
    675
    676	regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
    677			       cs42xx8->supplies);
    678
    679	gpiod_set_value_cansleep(cs42xx8->gpiod_reset, 1);
    680
    681	clk_disable_unprepare(cs42xx8->clk);
    682
    683	return 0;
    684}
    685#endif
    686
    687const struct dev_pm_ops cs42xx8_pm = {
    688	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
    689				pm_runtime_force_resume)
    690	SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
    691};
    692EXPORT_SYMBOL_GPL(cs42xx8_pm);
    693
    694MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
    695MODULE_AUTHOR("Freescale Semiconductor, Inc.");
    696MODULE_LICENSE("GPL");