blob: 05f4514048e212b8fcf37010c9052f8ab9c552c6 [file] [log] [blame]
Thomas Gleixner80503b22019-05-24 12:04:09 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Barry Songa1533d92010-03-19 14:48:33 +08002/*
3 * AD193X Audio Codec driver supporting AD1936/7/8/9
4 *
5 * Copyright 2010 Analog Devices Inc.
Barry Songa1533d92010-03-19 14:48:33 +08006 */
7
Barry Songa1533d92010-03-19 14:48:33 +08008#include <linux/module.h>
9#include <linux/kernel.h>
10#include <linux/device.h>
Lars-Peter Clausen6c3d7132014-02-17 13:16:54 +010011#include <linux/regmap.h>
Stephen Rothwell1b132ea2010-03-29 15:32:18 +110012#include <linux/slab.h>
Barry Songa1533d92010-03-19 14:48:33 +080013#include <sound/core.h>
14#include <sound/pcm.h>
15#include <sound/pcm_params.h>
16#include <sound/initval.h>
17#include <sound/soc.h>
18#include <sound/tlv.h>
Lars-Peter Clausen6c3d7132014-02-17 13:16:54 +010019
Barry Songa1533d92010-03-19 14:48:33 +080020#include "ad193x.h"
21
22/* codec private data */
23struct ad193x_priv {
Lars-Peter Clausen30ab1e72011-09-05 20:46:33 +020024 struct regmap *regmap;
Cyrille Pitchene5224f52015-09-29 16:41:43 +020025 enum ad193x_type type;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +000026 int sysclk;
Barry Songa1533d92010-03-19 14:48:33 +080027};
28
Barry Songa1533d92010-03-19 14:48:33 +080029/*
30 * AD193X volume/mute/de-emphasis etc. controls
31 */
Lars-Peter Clausenc4e7a4a2011-11-28 17:28:08 +010032static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
Barry Songa1533d92010-03-19 14:48:33 +080033
Takashi Iwaib6592d82014-02-18 09:55:27 +010034static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1,
35 ad193x_deemp);
Barry Songa1533d92010-03-19 14:48:33 +080036
Lars-Peter Clausen591c0342011-11-28 17:28:07 +010037static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0);
38
Codrin Ciubotariu75c2ecb2019-02-18 16:10:30 +000039static const unsigned int ad193x_sb[] = {32};
40
41static struct snd_pcm_hw_constraint_list constr = {
42 .list = ad193x_sb,
43 .count = ARRAY_SIZE(ad193x_sb),
44};
45
Barry Songa1533d92010-03-19 14:48:33 +080046static const struct snd_kcontrol_new ad193x_snd_controls[] = {
47 /* DAC volume control */
Lars-Peter Clausen591c0342011-11-28 17:28:07 +010048 SOC_DOUBLE_R_TLV("DAC1 Volume", AD193X_DAC_L1_VOL,
49 AD193X_DAC_R1_VOL, 0, 0xFF, 1, adau193x_tlv),
50 SOC_DOUBLE_R_TLV("DAC2 Volume", AD193X_DAC_L2_VOL,
51 AD193X_DAC_R2_VOL, 0, 0xFF, 1, adau193x_tlv),
52 SOC_DOUBLE_R_TLV("DAC3 Volume", AD193X_DAC_L3_VOL,
53 AD193X_DAC_R3_VOL, 0, 0xFF, 1, adau193x_tlv),
54 SOC_DOUBLE_R_TLV("DAC4 Volume", AD193X_DAC_L4_VOL,
55 AD193X_DAC_R4_VOL, 0, 0xFF, 1, adau193x_tlv),
Barry Songa1533d92010-03-19 14:48:33 +080056
Barry Songa1533d92010-03-19 14:48:33 +080057 /* DAC switch control */
58 SOC_DOUBLE("DAC1 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL1_MUTE,
59 AD193X_DACR1_MUTE, 1, 1),
60 SOC_DOUBLE("DAC2 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL2_MUTE,
61 AD193X_DACR2_MUTE, 1, 1),
62 SOC_DOUBLE("DAC3 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL3_MUTE,
63 AD193X_DACR3_MUTE, 1, 1),
64 SOC_DOUBLE("DAC4 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL4_MUTE,
65 AD193X_DACR4_MUTE, 1, 1),
66
Cyrille Pitchene5224f52015-09-29 16:41:43 +020067 /* DAC de-emphasis */
68 SOC_ENUM("Playback Deemphasis", ad193x_deemp_enum),
69};
70
71static const struct snd_kcontrol_new ad193x_adc_snd_controls[] = {
72 /* ADC switch control */
73 SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE,
74 AD193X_ADCR1_MUTE, 1, 1),
75 SOC_DOUBLE("ADC2 Switch", AD193X_ADC_CTRL0, AD193X_ADCL2_MUTE,
76 AD193X_ADCR2_MUTE, 1, 1),
77
Barry Songa1533d92010-03-19 14:48:33 +080078 /* ADC high-pass filter */
79 SOC_SINGLE("ADC High Pass Filter Switch", AD193X_ADC_CTRL0,
80 AD193X_ADC_HIGHPASS_FILTER, 1, 0),
Barry Songa1533d92010-03-19 14:48:33 +080081};
82
83static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
Lars-Peter Clausen1b86a3f2014-11-05 17:19:53 +010084 SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
85 SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0),
Barry Songa1533d92010-03-19 14:48:33 +080086 SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),
Lars-Peter Clausen0718fd22011-11-28 17:28:10 +010087 SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0),
Lars-Peter Clausen1b86a3f2014-11-05 17:19:53 +010088 SND_SOC_DAPM_VMID("VMID"),
Barry Songa1533d92010-03-19 14:48:33 +080089 SND_SOC_DAPM_OUTPUT("DAC1OUT"),
90 SND_SOC_DAPM_OUTPUT("DAC2OUT"),
91 SND_SOC_DAPM_OUTPUT("DAC3OUT"),
92 SND_SOC_DAPM_OUTPUT("DAC4OUT"),
Cyrille Pitchene5224f52015-09-29 16:41:43 +020093};
94
95static const struct snd_soc_dapm_widget ad193x_adc_widgets[] = {
96 SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
97 SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
Barry Songa1533d92010-03-19 14:48:33 +080098 SND_SOC_DAPM_INPUT("ADC1IN"),
99 SND_SOC_DAPM_INPUT("ADC2IN"),
100};
101
Codrin Ciubotariu59529472019-02-18 16:10:36 +0000102static int ad193x_check_pll(struct snd_soc_dapm_widget *source,
103 struct snd_soc_dapm_widget *sink)
104{
105 struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
106 struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
107
108 return !!ad193x->sysclk;
109}
110
Barry Songa1533d92010-03-19 14:48:33 +0800111static const struct snd_soc_dapm_route audio_paths[] = {
Lars-Peter Clausen0718fd22011-11-28 17:28:10 +0100112 { "DAC", NULL, "SYSCLK" },
Lars-Peter Clausen1b86a3f2014-11-05 17:19:53 +0100113 { "DAC Output", NULL, "DAC" },
114 { "DAC Output", NULL, "VMID" },
Lars-Peter Clausen1b86a3f2014-11-05 17:19:53 +0100115 { "DAC1OUT", NULL, "DAC Output" },
116 { "DAC2OUT", NULL, "DAC Output" },
117 { "DAC3OUT", NULL, "DAC Output" },
118 { "DAC4OUT", NULL, "DAC Output" },
Codrin Ciubotariu59529472019-02-18 16:10:36 +0000119 { "SYSCLK", NULL, "PLL_PWR", &ad193x_check_pll },
Barry Songa1533d92010-03-19 14:48:33 +0800120};
121
Cyrille Pitchene5224f52015-09-29 16:41:43 +0200122static const struct snd_soc_dapm_route ad193x_adc_audio_paths[] = {
123 { "ADC", NULL, "SYSCLK" },
124 { "ADC", NULL, "ADC_PWR" },
125 { "ADC", NULL, "ADC1IN" },
126 { "ADC", NULL, "ADC2IN" },
127};
128
129static inline bool ad193x_has_adc(const struct ad193x_priv *ad193x)
130{
131 switch (ad193x->type) {
132 case AD1933:
133 case AD1934:
134 return false;
135 default:
136 break;
137 }
138
139 return true;
140}
141
Barry Songa1533d92010-03-19 14:48:33 +0800142/*
143 * DAI ops entries
144 */
145
146static int ad193x_mute(struct snd_soc_dai *dai, int mute)
147{
Kuninori Morimoto89cea5c2018-01-29 04:25:29 +0000148 struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(dai->component);
Barry Songa1533d92010-03-19 14:48:33 +0800149
Axel Lin54c96cf2011-10-18 06:25:08 +0800150 if (mute)
Lars-Peter Clausen34cbe162011-11-28 17:28:12 +0100151 regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
Axel Lin54c96cf2011-10-18 06:25:08 +0800152 AD193X_DAC_MASTER_MUTE,
153 AD193X_DAC_MASTER_MUTE);
154 else
Lars-Peter Clausen34cbe162011-11-28 17:28:12 +0100155 regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
Axel Lin54c96cf2011-10-18 06:25:08 +0800156 AD193X_DAC_MASTER_MUTE, 0);
Barry Songa1533d92010-03-19 14:48:33 +0800157
158 return 0;
159}
160
161static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
162 unsigned int rx_mask, int slots, int width)
163{
Kuninori Morimoto89cea5c2018-01-29 04:25:29 +0000164 struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(dai->component);
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100165 unsigned int channels;
Barry Songa1533d92010-03-19 14:48:33 +0800166
167 switch (slots) {
168 case 2:
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100169 channels = AD193X_2_CHANNELS;
Barry Songa1533d92010-03-19 14:48:33 +0800170 break;
171 case 4:
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100172 channels = AD193X_4_CHANNELS;
Barry Songa1533d92010-03-19 14:48:33 +0800173 break;
174 case 8:
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100175 channels = AD193X_8_CHANNELS;
Barry Songa1533d92010-03-19 14:48:33 +0800176 break;
177 case 16:
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100178 channels = AD193X_16_CHANNELS;
Barry Songa1533d92010-03-19 14:48:33 +0800179 break;
180 default:
181 return -EINVAL;
182 }
183
Lars-Peter Clausen34cbe162011-11-28 17:28:12 +0100184 regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,
185 AD193X_DAC_CHAN_MASK, channels << AD193X_DAC_CHAN_SHFT);
Cyrille Pitchene5224f52015-09-29 16:41:43 +0200186 if (ad193x_has_adc(ad193x))
187 regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
188 AD193X_ADC_CHAN_MASK,
189 channels << AD193X_ADC_CHAN_SHFT);
Barry Songa1533d92010-03-19 14:48:33 +0800190
191 return 0;
192}
193
194static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
195 unsigned int fmt)
196{
Kuninori Morimoto89cea5c2018-01-29 04:25:29 +0000197 struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(codec_dai->component);
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100198 unsigned int adc_serfmt = 0;
Codrin Ciubotariubccf9c72019-02-18 16:10:34 +0000199 unsigned int dac_serfmt = 0;
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100200 unsigned int adc_fmt = 0;
201 unsigned int dac_fmt = 0;
Barry Songa1533d92010-03-19 14:48:33 +0800202
203 /* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S
Codrin Ciubotariubccf9c72019-02-18 16:10:34 +0000204 * with TDM), ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A) and DAC I2S mode
205 * (SND_SOC_DAIFMT_I2S)
Barry Songa1533d92010-03-19 14:48:33 +0800206 */
207 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
208 case SND_SOC_DAIFMT_I2S:
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100209 adc_serfmt |= AD193X_ADC_SERFMT_TDM;
Codrin Ciubotariubccf9c72019-02-18 16:10:34 +0000210 dac_serfmt |= AD193X_DAC_SERFMT_STEREO;
Barry Songa1533d92010-03-19 14:48:33 +0800211 break;
212 case SND_SOC_DAIFMT_DSP_A:
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100213 adc_serfmt |= AD193X_ADC_SERFMT_AUX;
Codrin Ciubotariubccf9c72019-02-18 16:10:34 +0000214 dac_serfmt |= AD193X_DAC_SERFMT_TDM;
Barry Songa1533d92010-03-19 14:48:33 +0800215 break;
216 default:
Cyrille Pitchene5224f52015-09-29 16:41:43 +0200217 if (ad193x_has_adc(ad193x))
218 return -EINVAL;
Barry Songa1533d92010-03-19 14:48:33 +0800219 }
220
221 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
222 case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
Barry Songa1533d92010-03-19 14:48:33 +0800223 break;
224 case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100225 adc_fmt |= AD193X_ADC_LEFT_HIGH;
226 dac_fmt |= AD193X_DAC_LEFT_HIGH;
Barry Songa1533d92010-03-19 14:48:33 +0800227 break;
228 case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100229 adc_fmt |= AD193X_ADC_BCLK_INV;
230 dac_fmt |= AD193X_DAC_BCLK_INV;
Barry Songa1533d92010-03-19 14:48:33 +0800231 break;
Barry Songa1533d92010-03-19 14:48:33 +0800232 case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100233 adc_fmt |= AD193X_ADC_LEFT_HIGH;
234 adc_fmt |= AD193X_ADC_BCLK_INV;
235 dac_fmt |= AD193X_DAC_LEFT_HIGH;
236 dac_fmt |= AD193X_DAC_BCLK_INV;
Barry Songa1533d92010-03-19 14:48:33 +0800237 break;
238 default:
239 return -EINVAL;
240 }
241
Codrin Ciubotariu90f6e682019-02-18 16:10:32 +0000242 /* For DSP_*, LRCLK's polarity must be inverted */
243 if (fmt & SND_SOC_DAIFMT_DSP_A) {
244 change_bit(ffs(AD193X_DAC_LEFT_HIGH) - 1,
245 (unsigned long *)&dac_fmt);
246 }
247
Barry Songa1533d92010-03-19 14:48:33 +0800248 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
249 case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100250 adc_fmt |= AD193X_ADC_LCR_MASTER;
251 adc_fmt |= AD193X_ADC_BCLK_MASTER;
252 dac_fmt |= AD193X_DAC_LCR_MASTER;
253 dac_fmt |= AD193X_DAC_BCLK_MASTER;
Barry Songa1533d92010-03-19 14:48:33 +0800254 break;
255 case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100256 adc_fmt |= AD193X_ADC_LCR_MASTER;
257 dac_fmt |= AD193X_DAC_LCR_MASTER;
Barry Songa1533d92010-03-19 14:48:33 +0800258 break;
259 case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
Lars-Peter Clausenb82ca572011-11-28 17:28:11 +0100260 adc_fmt |= AD193X_ADC_BCLK_MASTER;
261 dac_fmt |= AD193X_DAC_BCLK_MASTER;
Barry Songa1533d92010-03-19 14:48:33 +0800262 break;
263 case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */
Barry Songa1533d92010-03-19 14:48:33 +0800264 break;
265 default:
266 return -EINVAL;
267 }
268
Cyrille Pitchene5224f52015-09-29 16:41:43 +0200269 if (ad193x_has_adc(ad193x)) {
270 regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
271 AD193X_ADC_SERFMT_MASK, adc_serfmt);
272 regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
273 AD193X_ADC_FMT_MASK, adc_fmt);
274 }
Codrin Ciubotariubccf9c72019-02-18 16:10:34 +0000275 regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL0,
276 AD193X_DAC_SERFMT_MASK, dac_serfmt);
Lars-Peter Clausen34cbe162011-11-28 17:28:12 +0100277 regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,
278 AD193X_DAC_FMT_MASK, dac_fmt);
Barry Songa1533d92010-03-19 14:48:33 +0800279
280 return 0;
281}
282
Barry Songfab90aa2010-05-21 11:57:01 +0800283static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
284 int clk_id, unsigned int freq, int dir)
285{
Kuninori Morimoto89cea5c2018-01-29 04:25:29 +0000286 struct snd_soc_component *component = codec_dai->component;
Codrin Ciubotariu59529472019-02-18 16:10:36 +0000287 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
Kuninori Morimoto89cea5c2018-01-29 04:25:29 +0000288 struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
Codrin Ciubotariu59529472019-02-18 16:10:36 +0000289
290 if (clk_id == AD193X_SYSCLK_MCLK) {
291 /* MCLK must be 512 x fs */
292 if (dir == SND_SOC_CLOCK_OUT || freq != 24576000)
293 return -EINVAL;
294
295 regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL1,
296 AD193X_PLL_SRC_MASK,
297 AD193X_PLL_DAC_SRC_MCLK |
298 AD193X_PLL_CLK_SRC_MCLK);
299
300 snd_soc_dapm_sync(dapm);
301 return 0;
302 }
Barry Songfab90aa2010-05-21 11:57:01 +0800303 switch (freq) {
304 case 12288000:
305 case 18432000:
306 case 24576000:
307 case 36864000:
308 ad193x->sysclk = freq;
309 return 0;
310 }
311 return -EINVAL;
312}
313
Barry Songa1533d92010-03-19 14:48:33 +0800314static int ad193x_hw_params(struct snd_pcm_substream *substream,
315 struct snd_pcm_hw_params *params,
316 struct snd_soc_dai *dai)
317{
Axel Lin54c96cf2011-10-18 06:25:08 +0800318 int word_len = 0, master_rate = 0;
Kuninori Morimoto89cea5c2018-01-29 04:25:29 +0000319 struct snd_soc_component *component = dai->component;
320 struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
Barry Songa1533d92010-03-19 14:48:33 +0800321
322 /* bit size */
Mark Brownd4dd1fd2014-01-08 18:38:20 +0000323 switch (params_width(params)) {
324 case 16:
Barry Songa1533d92010-03-19 14:48:33 +0800325 word_len = 3;
326 break;
Mark Brownd4dd1fd2014-01-08 18:38:20 +0000327 case 20:
Barry Songa1533d92010-03-19 14:48:33 +0800328 word_len = 1;
329 break;
Mark Brownd4dd1fd2014-01-08 18:38:20 +0000330 case 24:
331 case 32:
Barry Songa1533d92010-03-19 14:48:33 +0800332 word_len = 0;
333 break;
334 }
335
Barry Songfab90aa2010-05-21 11:57:01 +0800336 switch (ad193x->sysclk) {
337 case 12288000:
338 master_rate = AD193X_PLL_INPUT_256;
339 break;
340 case 18432000:
341 master_rate = AD193X_PLL_INPUT_384;
342 break;
343 case 24576000:
344 master_rate = AD193X_PLL_INPUT_512;
345 break;
346 case 36864000:
347 master_rate = AD193X_PLL_INPUT_768;
348 break;
349 }
350
Lars-Peter Clausen34cbe162011-11-28 17:28:12 +0100351 regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL0,
Axel Lin54c96cf2011-10-18 06:25:08 +0800352 AD193X_PLL_INPUT_MASK, master_rate);
Barry Songfab90aa2010-05-21 11:57:01 +0800353
Lars-Peter Clausen34cbe162011-11-28 17:28:12 +0100354 regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
Axel Lin54c96cf2011-10-18 06:25:08 +0800355 AD193X_DAC_WORD_LEN_MASK,
356 word_len << AD193X_DAC_WORD_LEN_SHFT);
Barry Songa1533d92010-03-19 14:48:33 +0800357
Cyrille Pitchene5224f52015-09-29 16:41:43 +0200358 if (ad193x_has_adc(ad193x))
359 regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
360 AD193X_ADC_WORD_LEN_MASK, word_len);
Barry Songa1533d92010-03-19 14:48:33 +0800361
362 return 0;
363}
364
Codrin Ciubotariu75c2ecb2019-02-18 16:10:30 +0000365static int ad193x_startup(struct snd_pcm_substream *substream,
366 struct snd_soc_dai *dai)
367{
368 return snd_pcm_hw_constraint_list(substream->runtime, 0,
369 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
370 &constr);
371}
372
Lars-Peter Clausen85e76522011-11-23 11:40:40 +0100373static const struct snd_soc_dai_ops ad193x_dai_ops = {
Codrin Ciubotariu75c2ecb2019-02-18 16:10:30 +0000374 .startup = ad193x_startup,
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000375 .hw_params = ad193x_hw_params,
376 .digital_mute = ad193x_mute,
377 .set_tdm_slot = ad193x_set_tdm_slot,
378 .set_sysclk = ad193x_set_dai_sysclk,
379 .set_fmt = ad193x_set_dai_fmt,
380};
381
382/* codec DAI instance */
383static struct snd_soc_dai_driver ad193x_dai = {
384 .name = "ad193x-hifi",
385 .playback = {
386 .stream_name = "Playback",
387 .channels_min = 2,
388 .channels_max = 8,
389 .rates = SNDRV_PCM_RATE_48000,
390 .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
391 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
392 },
393 .capture = {
394 .stream_name = "Capture",
395 .channels_min = 2,
396 .channels_max = 4,
397 .rates = SNDRV_PCM_RATE_48000,
398 .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
399 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
400 },
401 .ops = &ad193x_dai_ops,
402};
403
Codrin Ciubotariu7aac8d132019-02-18 16:10:28 +0000404/* codec DAI instance for DAC only */
405static struct snd_soc_dai_driver ad193x_no_adc_dai = {
406 .name = "ad193x-hifi",
407 .playback = {
408 .stream_name = "Playback",
409 .channels_min = 2,
410 .channels_max = 8,
411 .rates = SNDRV_PCM_RATE_48000,
412 .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
413 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
414 },
415 .ops = &ad193x_dai_ops,
416};
417
Kuninori Morimoto89cea5c2018-01-29 04:25:29 +0000418static int ad193x_component_probe(struct snd_soc_component *component)
Barry Songa1533d92010-03-19 14:48:33 +0800419{
Kuninori Morimoto89cea5c2018-01-29 04:25:29 +0000420 struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
421 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
Cyrille Pitchene5224f52015-09-29 16:41:43 +0200422 int num, ret;
Barry Songa1533d92010-03-19 14:48:33 +0800423
424 /* default setting for ad193x */
425
426 /* unmute dac channels */
Lars-Peter Clausen34cbe162011-11-28 17:28:12 +0100427 regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0);
Barry Songa1533d92010-03-19 14:48:33 +0800428 /* de-emphasis: 48kHz, powedown dac */
Lars-Peter Clausen34cbe162011-11-28 17:28:12 +0100429 regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A);
Lars-Peter Clausenbdb2c742015-01-12 13:54:13 +0100430 /* dac in tdm mode */
431 regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x40);
Cyrille Pitchene5224f52015-09-29 16:41:43 +0200432
433 /* adc only */
434 if (ad193x_has_adc(ad193x)) {
435 /* high-pass filter enable */
436 regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3);
437 /* sata delay=1, adc aux mode */
438 regmap_write(ad193x->regmap, AD193X_ADC_CTRL1, 0x43);
439 }
440
Barry Songa1533d92010-03-19 14:48:33 +0800441 /* pll input: mclki/xi */
Lars-Peter Clausen34cbe162011-11-28 17:28:12 +0100442 regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
443 regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04);
Barry Songa1533d92010-03-19 14:48:33 +0800444
Cyrille Pitchene5224f52015-09-29 16:41:43 +0200445 /* adc only */
446 if (ad193x_has_adc(ad193x)) {
447 /* add adc controls */
448 num = ARRAY_SIZE(ad193x_adc_snd_controls);
Kuninori Morimoto89cea5c2018-01-29 04:25:29 +0000449 ret = snd_soc_add_component_controls(component,
Cyrille Pitchene5224f52015-09-29 16:41:43 +0200450 ad193x_adc_snd_controls,
451 num);
452 if (ret)
453 return ret;
454
455 /* add adc widgets */
456 num = ARRAY_SIZE(ad193x_adc_widgets);
457 ret = snd_soc_dapm_new_controls(dapm,
458 ad193x_adc_widgets,
459 num);
460 if (ret)
461 return ret;
462
463 /* add adc routes */
464 num = ARRAY_SIZE(ad193x_adc_audio_paths);
465 ret = snd_soc_dapm_add_routes(dapm,
466 ad193x_adc_audio_paths,
467 num);
468 if (ret)
469 return ret;
470 }
471
Xiubo Li5d6be5a2014-03-11 12:43:20 +0800472 return 0;
Barry Songa1533d92010-03-19 14:48:33 +0800473}
474
Kuninori Morimoto89cea5c2018-01-29 04:25:29 +0000475static const struct snd_soc_component_driver soc_component_dev_ad193x = {
476 .probe = ad193x_component_probe,
477 .controls = ad193x_snd_controls,
478 .num_controls = ARRAY_SIZE(ad193x_snd_controls),
479 .dapm_widgets = ad193x_dapm_widgets,
480 .num_dapm_widgets = ARRAY_SIZE(ad193x_dapm_widgets),
481 .dapm_routes = audio_paths,
482 .num_dapm_routes = ARRAY_SIZE(audio_paths),
483 .idle_bias_on = 1,
484 .use_pmdown_time = 1,
485 .endianness = 1,
486 .non_legacy_dai_naming = 1,
Barry Songa1533d92010-03-19 14:48:33 +0800487};
Barry Songa1533d92010-03-19 14:48:33 +0800488
Lars-Peter Clausen6c3d7132014-02-17 13:16:54 +0100489const struct regmap_config ad193x_regmap_config = {
Lars-Peter Clausen34cbe162011-11-28 17:28:12 +0100490 .max_register = AD193X_NUM_REGS - 1,
Lars-Peter Clausen30ab1e72011-09-05 20:46:33 +0200491};
Lars-Peter Clausen6c3d7132014-02-17 13:16:54 +0100492EXPORT_SYMBOL_GPL(ad193x_regmap_config);
Lars-Peter Clausen30ab1e72011-09-05 20:46:33 +0200493
Cyrille Pitchene5224f52015-09-29 16:41:43 +0200494int ad193x_probe(struct device *dev, struct regmap *regmap,
495 enum ad193x_type type)
Barry Songa1533d92010-03-19 14:48:33 +0800496{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000497 struct ad193x_priv *ad193x;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000498
Lars-Peter Clausen6c3d7132014-02-17 13:16:54 +0100499 if (IS_ERR(regmap))
500 return PTR_ERR(regmap);
501
502 ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000503 if (ad193x == NULL)
504 return -ENOMEM;
505
Lars-Peter Clausen6c3d7132014-02-17 13:16:54 +0100506 ad193x->regmap = regmap;
Cyrille Pitchene5224f52015-09-29 16:41:43 +0200507 ad193x->type = type;
Lars-Peter Clausen30ab1e72011-09-05 20:46:33 +0200508
Lars-Peter Clausen6c3d7132014-02-17 13:16:54 +0100509 dev_set_drvdata(dev, ad193x);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000510
Codrin Ciubotariu7aac8d132019-02-18 16:10:28 +0000511 if (ad193x_has_adc(ad193x))
512 return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x,
513 &ad193x_dai, 1);
Kuninori Morimoto89cea5c2018-01-29 04:25:29 +0000514 return devm_snd_soc_register_component(dev, &soc_component_dev_ad193x,
Codrin Ciubotariu7aac8d132019-02-18 16:10:28 +0000515 &ad193x_no_adc_dai, 1);
Barry Songa1533d92010-03-19 14:48:33 +0800516}
Lars-Peter Clausen6c3d7132014-02-17 13:16:54 +0100517EXPORT_SYMBOL_GPL(ad193x_probe);
Barry Songa1533d92010-03-19 14:48:33 +0800518
519MODULE_DESCRIPTION("ASoC ad193x driver");
520MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
521MODULE_LICENSE("GPL");