1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Texas Instruments PCM186x Universal Audio ADC
4 *
5 * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com
6 *	Andreas Dannenberg <dannenberg@ti.com>
7 *	Andrew F. Davis <afd@ti.com>
8 */
9
10#include <linux/module.h>
11#include <linux/moduleparam.h>
12#include <linux/init.h>
13#include <linux/delay.h>
14#include <linux/pm.h>
15#include <linux/pm_runtime.h>
16#include <linux/regulator/consumer.h>
17#include <linux/regmap.h>
18#include <linux/slab.h>
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/pcm_params.h>
22#include <sound/soc.h>
23#include <sound/jack.h>
24#include <sound/initval.h>
25#include <sound/tlv.h>
26
27#include "pcm186x.h"
28
29static const char * const pcm186x_supply_names[] = {
30	"avdd",		/* Analog power supply. Connect to 3.3-V supply. */
31	"dvdd",		/* Digital power supply. Connect to 3.3-V supply. */
32	"iovdd",	/* I/O power supply. Connect to 3.3-V or 1.8-V. */
33};
34#define PCM186x_NUM_SUPPLIES ARRAY_SIZE(pcm186x_supply_names)
35
36struct pcm186x_priv {
37	struct regmap *regmap;
38	struct regulator_bulk_data supplies[PCM186x_NUM_SUPPLIES];
39	unsigned int sysclk;
40	unsigned int tdm_offset;
41	bool is_tdm_mode;
42	bool is_master_mode;
43};
44
45static const DECLARE_TLV_DB_SCALE(pcm186x_pga_tlv, -1200, 50, 0);
46
47static const struct snd_kcontrol_new pcm1863_snd_controls[] = {
48	SOC_DOUBLE_R_S_TLV("ADC Capture Volume", PCM186X_PGA_VAL_CH1_L,
49			   PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
50			   pcm186x_pga_tlv),
51};
52
53static const struct snd_kcontrol_new pcm1865_snd_controls[] = {
54	SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", PCM186X_PGA_VAL_CH1_L,
55			   PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
56			   pcm186x_pga_tlv),
57	SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", PCM186X_PGA_VAL_CH2_L,
58			   PCM186X_PGA_VAL_CH2_R, 0, -24, 80, 7, 0,
59			   pcm186x_pga_tlv),
60};
61
62static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
63	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
64	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
65	0x10, 0x20, 0x30
66};
67
68static const char * const pcm186x_adcl_input_channel_sel_text[] = {
69	"No Select",
70	"VINL1[SE]",					/* Default for ADC1L */
71	"VINL2[SE]",					/* Default for ADC2L */
72	"VINL2[SE] + VINL1[SE]",
73	"VINL3[SE]",
74	"VINL3[SE] + VINL1[SE]",
75	"VINL3[SE] + VINL2[SE]",
76	"VINL3[SE] + VINL2[SE] + VINL1[SE]",
77	"VINL4[SE]",
78	"VINL4[SE] + VINL1[SE]",
79	"VINL4[SE] + VINL2[SE]",
80	"VINL4[SE] + VINL2[SE] + VINL1[SE]",
81	"VINL4[SE] + VINL3[SE]",
82	"VINL4[SE] + VINL3[SE] + VINL1[SE]",
83	"VINL4[SE] + VINL3[SE] + VINL2[SE]",
84	"VINL4[SE] + VINL3[SE] + VINL2[SE] + VINL1[SE]",
85	"{VIN1P, VIN1M}[DIFF]",
86	"{VIN4P, VIN4M}[DIFF]",
87	"{VIN1P, VIN1M}[DIFF] + {VIN4P, VIN4M}[DIFF]"
88};
89
90static const char * const pcm186x_adcr_input_channel_sel_text[] = {
91	"No Select",
92	"VINR1[SE]",					/* Default for ADC1R */
93	"VINR2[SE]",					/* Default for ADC2R */
94	"VINR2[SE] + VINR1[SE]",
95	"VINR3[SE]",
96	"VINR3[SE] + VINR1[SE]",
97	"VINR3[SE] + VINR2[SE]",
98	"VINR3[SE] + VINR2[SE] + VINR1[SE]",
99	"VINR4[SE]",
100	"VINR4[SE] + VINR1[SE]",
101	"VINR4[SE] + VINR2[SE]",
102	"VINR4[SE] + VINR2[SE] + VINR1[SE]",
103	"VINR4[SE] + VINR3[SE]",
104	"VINR4[SE] + VINR3[SE] + VINR1[SE]",
105	"VINR4[SE] + VINR3[SE] + VINR2[SE]",
106	"VINR4[SE] + VINR3[SE] + VINR2[SE] + VINR1[SE]",
107	"{VIN2P, VIN2M}[DIFF]",
108	"{VIN3P, VIN3M}[DIFF]",
109	"{VIN2P, VIN2M}[DIFF] + {VIN3P, VIN3M}[DIFF]"
110};
111
112static const struct soc_enum pcm186x_adc_input_channel_sel[] = {
113	SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0,
114			      PCM186X_ADC_INPUT_SEL_MASK,
115			      ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
116			      pcm186x_adcl_input_channel_sel_text,
117			      pcm186x_adc_input_channel_sel_value),
118	SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0,
119			      PCM186X_ADC_INPUT_SEL_MASK,
120			      ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
121			      pcm186x_adcr_input_channel_sel_text,
122			      pcm186x_adc_input_channel_sel_value),
123	SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_L, 0,
124			      PCM186X_ADC_INPUT_SEL_MASK,
125			      ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
126			      pcm186x_adcl_input_channel_sel_text,
127			      pcm186x_adc_input_channel_sel_value),
128	SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_R, 0,
129			      PCM186X_ADC_INPUT_SEL_MASK,
130			      ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
131			      pcm186x_adcr_input_channel_sel_text,
132			      pcm186x_adc_input_channel_sel_value),
133};
134
135static const struct snd_kcontrol_new pcm186x_adc_mux_controls[] = {
136	SOC_DAPM_ENUM("ADC1 Left Input", pcm186x_adc_input_channel_sel[0]),
137	SOC_DAPM_ENUM("ADC1 Right Input", pcm186x_adc_input_channel_sel[1]),
138	SOC_DAPM_ENUM("ADC2 Left Input", pcm186x_adc_input_channel_sel[2]),
139	SOC_DAPM_ENUM("ADC2 Right Input", pcm186x_adc_input_channel_sel[3]),
140};
141
142static const struct snd_soc_dapm_widget pcm1863_dapm_widgets[] = {
143	SND_SOC_DAPM_INPUT("VINL1"),
144	SND_SOC_DAPM_INPUT("VINR1"),
145	SND_SOC_DAPM_INPUT("VINL2"),
146	SND_SOC_DAPM_INPUT("VINR2"),
147	SND_SOC_DAPM_INPUT("VINL3"),
148	SND_SOC_DAPM_INPUT("VINR3"),
149	SND_SOC_DAPM_INPUT("VINL4"),
150	SND_SOC_DAPM_INPUT("VINR4"),
151
152	SND_SOC_DAPM_MUX("ADC Left Capture Source", SND_SOC_NOPM, 0, 0,
153			 &pcm186x_adc_mux_controls[0]),
154	SND_SOC_DAPM_MUX("ADC Right Capture Source", SND_SOC_NOPM, 0, 0,
155			 &pcm186x_adc_mux_controls[1]),
156
157	/*
158	 * Put the codec into SLEEP mode when not in use, allowing the
159	 * Energysense mechanism to operate.
160	 */
161	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", PCM186X_POWER_CTRL, 1,  1),
162};
163
164static const struct snd_soc_dapm_widget pcm1865_dapm_widgets[] = {
165	SND_SOC_DAPM_INPUT("VINL1"),
166	SND_SOC_DAPM_INPUT("VINR1"),
167	SND_SOC_DAPM_INPUT("VINL2"),
168	SND_SOC_DAPM_INPUT("VINR2"),
169	SND_SOC_DAPM_INPUT("VINL3"),
170	SND_SOC_DAPM_INPUT("VINR3"),
171	SND_SOC_DAPM_INPUT("VINL4"),
172	SND_SOC_DAPM_INPUT("VINR4"),
173
174	SND_SOC_DAPM_MUX("ADC1 Left Capture Source", SND_SOC_NOPM, 0, 0,
175			 &pcm186x_adc_mux_controls[0]),
176	SND_SOC_DAPM_MUX("ADC1 Right Capture Source", SND_SOC_NOPM, 0, 0,
177			 &pcm186x_adc_mux_controls[1]),
178	SND_SOC_DAPM_MUX("ADC2 Left Capture Source", SND_SOC_NOPM, 0, 0,
179			 &pcm186x_adc_mux_controls[2]),
180	SND_SOC_DAPM_MUX("ADC2 Right Capture Source", SND_SOC_NOPM, 0, 0,
181			 &pcm186x_adc_mux_controls[3]),
182
183	/*
184	 * Put the codec into SLEEP mode when not in use, allowing the
185	 * Energysense mechanism to operate.
186	 */
187	SND_SOC_DAPM_ADC("ADC1", "HiFi Capture 1", PCM186X_POWER_CTRL, 1,  1),
188	SND_SOC_DAPM_ADC("ADC2", "HiFi Capture 2", PCM186X_POWER_CTRL, 1,  1),
189};
190
191static const struct snd_soc_dapm_route pcm1863_dapm_routes[] = {
192	{ "ADC Left Capture Source", NULL, "VINL1" },
193	{ "ADC Left Capture Source", NULL, "VINR1" },
194	{ "ADC Left Capture Source", NULL, "VINL2" },
195	{ "ADC Left Capture Source", NULL, "VINR2" },
196	{ "ADC Left Capture Source", NULL, "VINL3" },
197	{ "ADC Left Capture Source", NULL, "VINR3" },
198	{ "ADC Left Capture Source", NULL, "VINL4" },
199	{ "ADC Left Capture Source", NULL, "VINR4" },
200
201	{ "ADC", NULL, "ADC Left Capture Source" },
202
203	{ "ADC Right Capture Source", NULL, "VINL1" },
204	{ "ADC Right Capture Source", NULL, "VINR1" },
205	{ "ADC Right Capture Source", NULL, "VINL2" },
206	{ "ADC Right Capture Source", NULL, "VINR2" },
207	{ "ADC Right Capture Source", NULL, "VINL3" },
208	{ "ADC Right Capture Source", NULL, "VINR3" },
209	{ "ADC Right Capture Source", NULL, "VINL4" },
210	{ "ADC Right Capture Source", NULL, "VINR4" },
211
212	{ "ADC", NULL, "ADC Right Capture Source" },
213};
214
215static const struct snd_soc_dapm_route pcm1865_dapm_routes[] = {
216	{ "ADC1 Left Capture Source", NULL, "VINL1" },
217	{ "ADC1 Left Capture Source", NULL, "VINR1" },
218	{ "ADC1 Left Capture Source", NULL, "VINL2" },
219	{ "ADC1 Left Capture Source", NULL, "VINR2" },
220	{ "ADC1 Left Capture Source", NULL, "VINL3" },
221	{ "ADC1 Left Capture Source", NULL, "VINR3" },
222	{ "ADC1 Left Capture Source", NULL, "VINL4" },
223	{ "ADC1 Left Capture Source", NULL, "VINR4" },
224
225	{ "ADC1", NULL, "ADC1 Left Capture Source" },
226
227	{ "ADC1 Right Capture Source", NULL, "VINL1" },
228	{ "ADC1 Right Capture Source", NULL, "VINR1" },
229	{ "ADC1 Right Capture Source", NULL, "VINL2" },
230	{ "ADC1 Right Capture Source", NULL, "VINR2" },
231	{ "ADC1 Right Capture Source", NULL, "VINL3" },
232	{ "ADC1 Right Capture Source", NULL, "VINR3" },
233	{ "ADC1 Right Capture Source", NULL, "VINL4" },
234	{ "ADC1 Right Capture Source", NULL, "VINR4" },
235
236	{ "ADC1", NULL, "ADC1 Right Capture Source" },
237
238	{ "ADC2 Left Capture Source", NULL, "VINL1" },
239	{ "ADC2 Left Capture Source", NULL, "VINR1" },
240	{ "ADC2 Left Capture Source", NULL, "VINL2" },
241	{ "ADC2 Left Capture Source", NULL, "VINR2" },
242	{ "ADC2 Left Capture Source", NULL, "VINL3" },
243	{ "ADC2 Left Capture Source", NULL, "VINR3" },
244	{ "ADC2 Left Capture Source", NULL, "VINL4" },
245	{ "ADC2 Left Capture Source", NULL, "VINR4" },
246
247	{ "ADC2", NULL, "ADC2 Left Capture Source" },
248
249	{ "ADC2 Right Capture Source", NULL, "VINL1" },
250	{ "ADC2 Right Capture Source", NULL, "VINR1" },
251	{ "ADC2 Right Capture Source", NULL, "VINL2" },
252	{ "ADC2 Right Capture Source", NULL, "VINR2" },
253	{ "ADC2 Right Capture Source", NULL, "VINL3" },
254	{ "ADC2 Right Capture Source", NULL, "VINR3" },
255	{ "ADC2 Right Capture Source", NULL, "VINL4" },
256	{ "ADC2 Right Capture Source", NULL, "VINR4" },
257
258	{ "ADC2", NULL, "ADC2 Right Capture Source" },
259};
260
261static int pcm186x_hw_params(struct snd_pcm_substream *substream,
262			     struct snd_pcm_hw_params *params,
263			     struct snd_soc_dai *dai)
264{
265	struct snd_soc_component *component = dai->component;
266	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
267	unsigned int rate = params_rate(params);
268	snd_pcm_format_t format = params_format(params);
269	unsigned int width = params_width(params);
270	unsigned int channels = params_channels(params);
271	unsigned int div_lrck;
272	unsigned int div_bck;
273	u8 tdm_tx_sel = 0;
274	u8 pcm_cfg = 0;
275
276	dev_dbg(component->dev, "%s() rate=%u format=0x%x width=%u channels=%u\n",
277		__func__, rate, format, width, channels);
278
279	switch (width) {
280	case 16:
281		pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_16 <<
282			  PCM186X_PCM_CFG_RX_WLEN_SHIFT |
283			  PCM186X_PCM_CFG_TX_WLEN_16 <<
284			  PCM186X_PCM_CFG_TX_WLEN_SHIFT;
285		break;
286	case 20:
287		pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_20 <<
288			  PCM186X_PCM_CFG_RX_WLEN_SHIFT |
289			  PCM186X_PCM_CFG_TX_WLEN_20 <<
290			  PCM186X_PCM_CFG_TX_WLEN_SHIFT;
291		break;
292	case 24:
293		pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_24 <<
294			  PCM186X_PCM_CFG_RX_WLEN_SHIFT |
295			  PCM186X_PCM_CFG_TX_WLEN_24 <<
296			  PCM186X_PCM_CFG_TX_WLEN_SHIFT;
297		break;
298	case 32:
299		pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_32 <<
300			  PCM186X_PCM_CFG_RX_WLEN_SHIFT |
301			  PCM186X_PCM_CFG_TX_WLEN_32 <<
302			  PCM186X_PCM_CFG_TX_WLEN_SHIFT;
303		break;
304	default:
305		return -EINVAL;
306	}
307
308	snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
309			    PCM186X_PCM_CFG_RX_WLEN_MASK |
310			    PCM186X_PCM_CFG_TX_WLEN_MASK,
311			    pcm_cfg);
312
313	div_lrck = width * channels;
314
315	if (priv->is_tdm_mode) {
316		/* Select TDM transmission data */
317		switch (channels) {
318		case 2:
319			tdm_tx_sel = PCM186X_TDM_TX_SEL_2CH;
320			break;
321		case 4:
322			tdm_tx_sel = PCM186X_TDM_TX_SEL_4CH;
323			break;
324		case 6:
325			tdm_tx_sel = PCM186X_TDM_TX_SEL_6CH;
326			break;
327		default:
328			return -EINVAL;
329		}
330
331		snd_soc_component_update_bits(component, PCM186X_TDM_TX_SEL,
332				    PCM186X_TDM_TX_SEL_MASK, tdm_tx_sel);
333
334		/* In DSP/TDM mode, the LRCLK divider must be 256 */
335		div_lrck = 256;
336
337		/* Configure 1/256 duty cycle for LRCK */
338		snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
339				    PCM186X_PCM_CFG_TDM_LRCK_MODE,
340				    PCM186X_PCM_CFG_TDM_LRCK_MODE);
341	}
342
343	/* Only configure clock dividers in master mode. */
344	if (priv->is_master_mode) {
345		div_bck = priv->sysclk / (div_lrck * rate);
346
347		dev_dbg(component->dev,
348			"%s() master_clk=%u div_bck=%u div_lrck=%u\n",
349			__func__, priv->sysclk, div_bck, div_lrck);
350
351		snd_soc_component_write(component, PCM186X_BCK_DIV, div_bck - 1);
352		snd_soc_component_write(component, PCM186X_LRK_DIV, div_lrck - 1);
353	}
354
355	return 0;
356}
357
358static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
359{
360	struct snd_soc_component *component = dai->component;
361	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
362	u8 clk_ctrl = 0;
363	u8 pcm_cfg = 0;
364
365	dev_dbg(component->dev, "%s() format=0x%x\n", __func__, format);
366
367	/* set master/slave audio interface */
368	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
369	case SND_SOC_DAIFMT_CBM_CFM:
370		if (!priv->sysclk) {
371			dev_err(component->dev, "operating in master mode requires sysclock to be configured\n");
372			return -EINVAL;
373		}
374		clk_ctrl |= PCM186X_CLK_CTRL_MST_MODE;
375		priv->is_master_mode = true;
376		break;
377	case SND_SOC_DAIFMT_CBS_CFS:
378		priv->is_master_mode = false;
379		break;
380	default:
381		dev_err(component->dev, "Invalid DAI master/slave interface\n");
382		return -EINVAL;
383	}
384
385	/* set interface polarity */
386	switch (format & SND_SOC_DAIFMT_INV_MASK) {
387	case SND_SOC_DAIFMT_NB_NF:
388		break;
389	default:
390		dev_err(component->dev, "Inverted DAI clocks not supported\n");
391		return -EINVAL;
392	}
393
394	/* set interface format */
395	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
396	case SND_SOC_DAIFMT_I2S:
397		pcm_cfg = PCM186X_PCM_CFG_FMT_I2S;
398		break;
399	case SND_SOC_DAIFMT_LEFT_J:
400		pcm_cfg = PCM186X_PCM_CFG_FMT_LEFTJ;
401		break;
402	case SND_SOC_DAIFMT_DSP_A:
403		priv->tdm_offset += 1;
404		fallthrough;
405		/* DSP_A uses the same basic config as DSP_B
406		 * except we need to shift the TDM output by one BCK cycle
407		 */
408	case SND_SOC_DAIFMT_DSP_B:
409		priv->is_tdm_mode = true;
410		pcm_cfg = PCM186X_PCM_CFG_FMT_TDM;
411		break;
412	default:
413		dev_err(component->dev, "Invalid DAI format\n");
414		return -EINVAL;
415	}
416
417	snd_soc_component_update_bits(component, PCM186X_CLK_CTRL,
418			    PCM186X_CLK_CTRL_MST_MODE, clk_ctrl);
419
420	snd_soc_component_write(component, PCM186X_TDM_TX_OFFSET, priv->tdm_offset);
421
422	snd_soc_component_update_bits(component, PCM186X_PCM_CFG,
423			    PCM186X_PCM_CFG_FMT_MASK, pcm_cfg);
424
425	return 0;
426}
427
428static int pcm186x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
429				unsigned int rx_mask, int slots, int slot_width)
430{
431	struct snd_soc_component *component = dai->component;
432	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
433	unsigned int first_slot, last_slot, tdm_offset;
434
435	dev_dbg(component->dev,
436		"%s() tx_mask=0x%x rx_mask=0x%x slots=%d slot_width=%d\n",
437		__func__, tx_mask, rx_mask, slots, slot_width);
438
439	if (!tx_mask) {
440		dev_err(component->dev, "tdm tx mask must not be 0\n");
441		return -EINVAL;
442	}
443
444	first_slot = __ffs(tx_mask);
445	last_slot = __fls(tx_mask);
446
447	if (last_slot - first_slot != hweight32(tx_mask) - 1) {
448		dev_err(component->dev, "tdm tx mask must be contiguous\n");
449		return -EINVAL;
450	}
451
452	tdm_offset = first_slot * slot_width;
453
454	if (tdm_offset > 255) {
455		dev_err(component->dev, "tdm tx slot selection out of bounds\n");
456		return -EINVAL;
457	}
458
459	priv->tdm_offset = tdm_offset;
460
461	return 0;
462}
463
464static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
465				  unsigned int freq, int dir)
466{
467	struct snd_soc_component *component = dai->component;
468	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
469
470	dev_dbg(component->dev, "%s() clk_id=%d freq=%u dir=%d\n",
471		__func__, clk_id, freq, dir);
472
473	priv->sysclk = freq;
474
475	return 0;
476}
477
478static const struct snd_soc_dai_ops pcm186x_dai_ops = {
479	.set_sysclk = pcm186x_set_dai_sysclk,
480	.set_tdm_slot = pcm186x_set_tdm_slot,
481	.set_fmt = pcm186x_set_fmt,
482	.hw_params = pcm186x_hw_params,
483};
484
485static struct snd_soc_dai_driver pcm1863_dai = {
486	.name = "pcm1863-aif",
487	.capture = {
488		 .stream_name = "Capture",
489		 .channels_min = 1,
490		 .channels_max = 2,
491		 .rates = PCM186X_RATES,
492		 .formats = PCM186X_FORMATS,
493	 },
494	.ops = &pcm186x_dai_ops,
495};
496
497static struct snd_soc_dai_driver pcm1865_dai = {
498	.name = "pcm1865-aif",
499	.capture = {
500		 .stream_name = "Capture",
501		 .channels_min = 1,
502		 .channels_max = 4,
503		 .rates = PCM186X_RATES,
504		 .formats = PCM186X_FORMATS,
505	 },
506	.ops = &pcm186x_dai_ops,
507};
508
509static int pcm186x_power_on(struct snd_soc_component *component)
510{
511	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
512	int ret = 0;
513
514	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
515				    priv->supplies);
516	if (ret)
517		return ret;
518
519	regcache_cache_only(priv->regmap, false);
520	ret = regcache_sync(priv->regmap);
521	if (ret) {
522		dev_err(component->dev, "Failed to restore cache\n");
523		regcache_cache_only(priv->regmap, true);
524		regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
525				       priv->supplies);
526		return ret;
527	}
528
529	snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
530			    PCM186X_PWR_CTRL_PWRDN, 0);
531
532	return 0;
533}
534
535static int pcm186x_power_off(struct snd_soc_component *component)
536{
537	struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
538	int ret;
539
540	snd_soc_component_update_bits(component, PCM186X_POWER_CTRL,
541			    PCM186X_PWR_CTRL_PWRDN, PCM186X_PWR_CTRL_PWRDN);
542
543	regcache_cache_only(priv->regmap, true);
544
545	ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
546				     priv->supplies);
547	if (ret)
548		return ret;
549
550	return 0;
551}
552
553static int pcm186x_set_bias_level(struct snd_soc_component *component,
554				  enum snd_soc_bias_level level)
555{
556	dev_dbg(component->dev, "## %s: %d -> %d\n", __func__,
557		snd_soc_component_get_bias_level(component), level);
558
559	switch (level) {
560	case SND_SOC_BIAS_ON:
561		break;
562	case SND_SOC_BIAS_PREPARE:
563		break;
564	case SND_SOC_BIAS_STANDBY:
565		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
566			pcm186x_power_on(component);
567		break;
568	case SND_SOC_BIAS_OFF:
569		pcm186x_power_off(component);
570		break;
571	}
572
573	return 0;
574}
575
576static struct snd_soc_component_driver soc_codec_dev_pcm1863 = {
577	.set_bias_level		= pcm186x_set_bias_level,
578	.controls		= pcm1863_snd_controls,
579	.num_controls		= ARRAY_SIZE(pcm1863_snd_controls),
580	.dapm_widgets		= pcm1863_dapm_widgets,
581	.num_dapm_widgets	= ARRAY_SIZE(pcm1863_dapm_widgets),
582	.dapm_routes		= pcm1863_dapm_routes,
583	.num_dapm_routes	= ARRAY_SIZE(pcm1863_dapm_routes),
584	.idle_bias_on		= 1,
585	.use_pmdown_time	= 1,
586	.endianness		= 1,
587	.non_legacy_dai_naming	= 1,
588};
589
590static struct snd_soc_component_driver soc_codec_dev_pcm1865 = {
591	.set_bias_level		= pcm186x_set_bias_level,
592	.controls		= pcm1865_snd_controls,
593	.num_controls		= ARRAY_SIZE(pcm1865_snd_controls),
594	.dapm_widgets		= pcm1865_dapm_widgets,
595	.num_dapm_widgets	= ARRAY_SIZE(pcm1865_dapm_widgets),
596	.dapm_routes		= pcm1865_dapm_routes,
597	.num_dapm_routes	= ARRAY_SIZE(pcm1865_dapm_routes),
598	.suspend_bias_off	= 1,
599	.idle_bias_on		= 1,
600	.use_pmdown_time	= 1,
601	.endianness		= 1,
602	.non_legacy_dai_naming	= 1,
603};
604
605static bool pcm186x_volatile(struct device *dev, unsigned int reg)
606{
607	switch (reg) {
608	case PCM186X_PAGE:
609	case PCM186X_DEVICE_STATUS:
610	case PCM186X_FSAMPLE_STATUS:
611	case PCM186X_DIV_STATUS:
612	case PCM186X_CLK_STATUS:
613	case PCM186X_SUPPLY_STATUS:
614	case PCM186X_MMAP_STAT_CTRL:
615	case PCM186X_MMAP_ADDRESS:
616		return true;
617	}
618
619	return false;
620}
621
622static const struct regmap_range_cfg pcm186x_range = {
623	.name = "Pages",
624	.range_max = PCM186X_MAX_REGISTER,
625	.selector_reg = PCM186X_PAGE,
626	.selector_mask = 0xff,
627	.window_len = PCM186X_PAGE_LEN,
628};
629
630const struct regmap_config pcm186x_regmap = {
631	.reg_bits = 8,
632	.val_bits = 8,
633
634	.volatile_reg = pcm186x_volatile,
635
636	.ranges = &pcm186x_range,
637	.num_ranges = 1,
638
639	.max_register = PCM186X_MAX_REGISTER,
640
641	.cache_type = REGCACHE_RBTREE,
642};
643EXPORT_SYMBOL_GPL(pcm186x_regmap);
644
645int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
646		  struct regmap *regmap)
647{
648	struct pcm186x_priv *priv;
649	int i, ret;
650
651	priv = devm_kzalloc(dev, sizeof(struct pcm186x_priv), GFP_KERNEL);
652	if (!priv)
653		return -ENOMEM;
654
655	dev_set_drvdata(dev, priv);
656	priv->regmap = regmap;
657
658	for (i = 0; i < ARRAY_SIZE(priv->supplies); i++)
659		priv->supplies[i].supply = pcm186x_supply_names[i];
660
661	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
662				      priv->supplies);
663	if (ret) {
664		dev_err(dev, "failed to request supplies: %d\n", ret);
665		return ret;
666	}
667
668	ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
669				    priv->supplies);
670	if (ret) {
671		dev_err(dev, "failed enable supplies: %d\n", ret);
672		return ret;
673	}
674
675	/* Reset device registers for a consistent power-on like state */
676	ret = regmap_write(regmap, PCM186X_PAGE, PCM186X_RESET);
677	if (ret) {
678		dev_err(dev, "failed to write device: %d\n", ret);
679		return ret;
680	}
681
682	ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
683				     priv->supplies);
684	if (ret) {
685		dev_err(dev, "failed disable supplies: %d\n", ret);
686		return ret;
687	}
688
689	switch (type) {
690	case PCM1865:
691	case PCM1864:
692		ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1865,
693					     &pcm1865_dai, 1);
694		break;
695	case PCM1863:
696	case PCM1862:
697	default:
698		ret = devm_snd_soc_register_component(dev, &soc_codec_dev_pcm1863,
699					     &pcm1863_dai, 1);
700	}
701	if (ret) {
702		dev_err(dev, "failed to register CODEC: %d\n", ret);
703		return ret;
704	}
705
706	return 0;
707}
708EXPORT_SYMBOL_GPL(pcm186x_probe);
709
710MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
711MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
712MODULE_DESCRIPTION("PCM186x Universal Audio ADC driver");
713MODULE_LICENSE("GPL v2");
714