xref: /openbmc/linux/sound/soc/codecs/tas2562.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1c173dba4SDan Murphy // SPDX-License-Identifier: GPL-2.0
2c173dba4SDan Murphy //
3c173dba4SDan Murphy // Driver for the Texas Instruments TAS2562 CODEC
4c173dba4SDan Murphy // Copyright (C) 2019 Texas Instruments Inc.
5c173dba4SDan Murphy 
6c173dba4SDan Murphy 
7c173dba4SDan Murphy #include <linux/module.h>
8c173dba4SDan Murphy #include <linux/errno.h>
9c173dba4SDan Murphy #include <linux/device.h>
10c173dba4SDan Murphy #include <linux/i2c.h>
11c173dba4SDan Murphy #include <linux/regmap.h>
12c173dba4SDan Murphy #include <linux/slab.h>
13c173dba4SDan Murphy #include <linux/gpio/consumer.h>
14c173dba4SDan Murphy #include <linux/regulator/consumer.h>
15c173dba4SDan Murphy #include <linux/delay.h>
16c173dba4SDan Murphy 
17c173dba4SDan Murphy #include <sound/pcm.h>
18c173dba4SDan Murphy #include <sound/pcm_params.h>
19c173dba4SDan Murphy #include <sound/soc.h>
20c173dba4SDan Murphy #include <sound/soc-dapm.h>
21c173dba4SDan Murphy #include <sound/tlv.h>
22c173dba4SDan Murphy 
23c173dba4SDan Murphy #include "tas2562.h"
24c173dba4SDan Murphy 
25c173dba4SDan Murphy #define TAS2562_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
26c173dba4SDan Murphy 			 SNDRV_PCM_FORMAT_S32_LE)
27c173dba4SDan Murphy 
28bf726b1cSDan Murphy /* DVC equation involves floating point math
29bf726b1cSDan Murphy  * round(10^(volume in dB/20)*2^30)
30bf726b1cSDan Murphy  * so create a lookup table for 2dB step
31bf726b1cSDan Murphy  */
32bf726b1cSDan Murphy static const unsigned int float_vol_db_lookup[] = {
33bf726b1cSDan Murphy 0x00000d43, 0x000010b2, 0x00001505, 0x00001a67, 0x00002151,
34bf726b1cSDan Murphy 0x000029f1, 0x000034cd, 0x00004279, 0x000053af, 0x0000695b,
35bf726b1cSDan Murphy 0x0000695b, 0x0000a6fa, 0x0000d236, 0x000108a4, 0x00014d2a,
36bf726b1cSDan Murphy 0x0001a36e, 0x00021008, 0x000298c0, 0x000344df, 0x00041d8f,
37bf726b1cSDan Murphy 0x00052e5a, 0x000685c8, 0x00083621, 0x000a566d, 0x000d03a7,
38bf726b1cSDan Murphy 0x0010624d, 0x0014a050, 0x0019f786, 0x0020b0bc, 0x0029279d,
39bf726b1cSDan Murphy 0x0033cf8d, 0x004139d3, 0x00521d50, 0x00676044, 0x0082248a,
40bf726b1cSDan Murphy 0x00a3d70a, 0x00ce4328, 0x0103ab3d, 0x0146e75d, 0x019b8c27,
41bf726b1cSDan Murphy 0x02061b89, 0x028c423f, 0x03352529, 0x0409c2b0, 0x05156d68,
42bf726b1cSDan Murphy 0x080e9f96, 0x0a24b062, 0x0cc509ab, 0x10137987, 0x143d1362,
43bf726b1cSDan Murphy 0x197a967f, 0x2013739e, 0x28619ae9, 0x32d64617, 0x40000000
44bf726b1cSDan Murphy };
45bf726b1cSDan Murphy 
46c173dba4SDan Murphy struct tas2562_data {
47c173dba4SDan Murphy 	struct snd_soc_component *component;
48c173dba4SDan Murphy 	struct gpio_desc *sdz_gpio;
49c173dba4SDan Murphy 	struct regmap *regmap;
50c173dba4SDan Murphy 	struct device *dev;
51c173dba4SDan Murphy 	struct i2c_client *client;
52c173dba4SDan Murphy 	int v_sense_slot;
53c173dba4SDan Murphy 	int i_sense_slot;
54bf726b1cSDan Murphy 	int volume_lvl;
558adcdbe6SDan Murphy 	int model_id;
562848d34cSMartin Povišer 	bool dac_powered;
572848d34cSMartin Povišer 	bool unmuted;
58c173dba4SDan Murphy };
59c173dba4SDan Murphy 
6014f8c8d8SDan Murphy enum tas256x_model {
6114f8c8d8SDan Murphy 	TAS2562,
6214f8c8d8SDan Murphy 	TAS2563,
63534c0f43SDan Murphy 	TAS2564,
648adcdbe6SDan Murphy 	TAS2110,
6514f8c8d8SDan Murphy };
6614f8c8d8SDan Murphy 
tas2562_set_samplerate(struct tas2562_data * tas2562,int samplerate)67c173dba4SDan Murphy static int tas2562_set_samplerate(struct tas2562_data *tas2562, int samplerate)
68c173dba4SDan Murphy {
69c173dba4SDan Murphy 	int samp_rate;
70c173dba4SDan Murphy 	int ramp_rate;
71c173dba4SDan Murphy 
72c173dba4SDan Murphy 	switch (samplerate) {
73c173dba4SDan Murphy 	case 7350:
74c173dba4SDan Murphy 		ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
75c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ;
76c173dba4SDan Murphy 		break;
77c173dba4SDan Murphy 	case 8000:
78c173dba4SDan Murphy 		ramp_rate = 0;
79c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_7305_8KHZ;
80c173dba4SDan Murphy 		break;
81c173dba4SDan Murphy 	case 14700:
82c173dba4SDan Murphy 		ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
83c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ;
84c173dba4SDan Murphy 		break;
85c173dba4SDan Murphy 	case 16000:
86c173dba4SDan Murphy 		ramp_rate = 0;
87c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_14_7_16KHZ;
88c173dba4SDan Murphy 		break;
89c173dba4SDan Murphy 	case 22050:
90c173dba4SDan Murphy 		ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
91c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ;
92c173dba4SDan Murphy 		break;
93c173dba4SDan Murphy 	case 24000:
94c173dba4SDan Murphy 		ramp_rate = 0;
95c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_22_05_24KHZ;
96c173dba4SDan Murphy 		break;
97c173dba4SDan Murphy 	case 29400:
98c173dba4SDan Murphy 		ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
99c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ;
100c173dba4SDan Murphy 		break;
101c173dba4SDan Murphy 	case 32000:
102c173dba4SDan Murphy 		ramp_rate = 0;
103c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_29_4_32KHZ;
104c173dba4SDan Murphy 		break;
105c173dba4SDan Murphy 	case 44100:
106c173dba4SDan Murphy 		ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
107c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ;
108c173dba4SDan Murphy 		break;
109c173dba4SDan Murphy 	case 48000:
110c173dba4SDan Murphy 		ramp_rate = 0;
111c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_44_1_48KHZ;
112c173dba4SDan Murphy 		break;
113c173dba4SDan Murphy 	case 88200:
114c173dba4SDan Murphy 		ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
115c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ;
116c173dba4SDan Murphy 		break;
117c173dba4SDan Murphy 	case 96000:
118c173dba4SDan Murphy 		ramp_rate = 0;
119c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_88_2_96KHZ;
120c173dba4SDan Murphy 		break;
121c173dba4SDan Murphy 	case 176400:
122c173dba4SDan Murphy 		ramp_rate = TAS2562_TDM_CFG0_RAMPRATE_44_1;
123c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ;
124c173dba4SDan Murphy 		break;
125c173dba4SDan Murphy 	case 192000:
126c173dba4SDan Murphy 		ramp_rate = 0;
127c173dba4SDan Murphy 		samp_rate = TAS2562_TDM_CFG0_SAMPRATE_176_4_192KHZ;
128c173dba4SDan Murphy 		break;
129c173dba4SDan Murphy 	default:
130c173dba4SDan Murphy 		dev_info(tas2562->dev, "%s, unsupported sample rate, %d\n",
131c173dba4SDan Murphy 			__func__, samplerate);
132c173dba4SDan Murphy 		return -EINVAL;
133c173dba4SDan Murphy 	}
134c173dba4SDan Murphy 
135c173dba4SDan Murphy 	snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG0,
136c173dba4SDan Murphy 		TAS2562_TDM_CFG0_RAMPRATE_MASK,	ramp_rate);
137c173dba4SDan Murphy 	snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG0,
138c173dba4SDan Murphy 		TAS2562_TDM_CFG0_SAMPRATE_MASK,	samp_rate);
139c173dba4SDan Murphy 
140c173dba4SDan Murphy 	return 0;
141c173dba4SDan Murphy }
142c173dba4SDan Murphy 
tas2562_set_dai_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)143c173dba4SDan Murphy static int tas2562_set_dai_tdm_slot(struct snd_soc_dai *dai,
144c173dba4SDan Murphy 		unsigned int tx_mask, unsigned int rx_mask,
145c173dba4SDan Murphy 		int slots, int slot_width)
146c173dba4SDan Murphy {
147c173dba4SDan Murphy 	struct snd_soc_component *component = dai->component;
148c173dba4SDan Murphy 	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
149d7bd40aeSDan Murphy 	int left_slot, right_slot;
150d7bd40aeSDan Murphy 	int slots_cfg;
151d7bd40aeSDan Murphy 	int ret;
152d7bd40aeSDan Murphy 
153d7bd40aeSDan Murphy 	if (!tx_mask) {
154d7bd40aeSDan Murphy 		dev_err(component->dev, "tx masks must not be 0\n");
155d7bd40aeSDan Murphy 		return -EINVAL;
156d7bd40aeSDan Murphy 	}
157d7bd40aeSDan Murphy 
158d7bd40aeSDan Murphy 	if (slots == 1) {
159d7bd40aeSDan Murphy 		if (tx_mask != 1)
160d7bd40aeSDan Murphy 			return -EINVAL;
161d7bd40aeSDan Murphy 
162d7bd40aeSDan Murphy 		left_slot = 0;
163d7bd40aeSDan Murphy 		right_slot = 0;
164d7bd40aeSDan Murphy 	} else {
165d7bd40aeSDan Murphy 		left_slot = __ffs(tx_mask);
166d7bd40aeSDan Murphy 		tx_mask &= ~(1 << left_slot);
167d7bd40aeSDan Murphy 		if (tx_mask == 0) {
168d7bd40aeSDan Murphy 			right_slot = left_slot;
169d7bd40aeSDan Murphy 		} else {
170d7bd40aeSDan Murphy 			right_slot = __ffs(tx_mask);
171d7bd40aeSDan Murphy 		}
172d7bd40aeSDan Murphy 	}
173d7bd40aeSDan Murphy 
174d7bd40aeSDan Murphy 	slots_cfg = (right_slot << TAS2562_RIGHT_SLOT_SHIFT) | left_slot;
175d7bd40aeSDan Murphy 
176d7bd40aeSDan Murphy 	ret = snd_soc_component_write(component, TAS2562_TDM_CFG3, slots_cfg);
177d7bd40aeSDan Murphy 	if (ret < 0)
178d7bd40aeSDan Murphy 		return ret;
179c173dba4SDan Murphy 
180c173dba4SDan Murphy 	switch (slot_width) {
181c173dba4SDan Murphy 	case 16:
182c173dba4SDan Murphy 		ret = snd_soc_component_update_bits(component,
183c173dba4SDan Murphy 						    TAS2562_TDM_CFG2,
184c173dba4SDan Murphy 						    TAS2562_TDM_CFG2_RXLEN_MASK,
185c173dba4SDan Murphy 						    TAS2562_TDM_CFG2_RXLEN_16B);
186c173dba4SDan Murphy 		break;
187c173dba4SDan Murphy 	case 24:
188c173dba4SDan Murphy 		ret = snd_soc_component_update_bits(component,
189c173dba4SDan Murphy 						    TAS2562_TDM_CFG2,
190c173dba4SDan Murphy 						    TAS2562_TDM_CFG2_RXLEN_MASK,
191c173dba4SDan Murphy 						    TAS2562_TDM_CFG2_RXLEN_24B);
192c173dba4SDan Murphy 		break;
193c173dba4SDan Murphy 	case 32:
194c173dba4SDan Murphy 		ret = snd_soc_component_update_bits(component,
195c173dba4SDan Murphy 						    TAS2562_TDM_CFG2,
196c173dba4SDan Murphy 						    TAS2562_TDM_CFG2_RXLEN_MASK,
197c173dba4SDan Murphy 						    TAS2562_TDM_CFG2_RXLEN_32B);
198c173dba4SDan Murphy 		break;
199c173dba4SDan Murphy 
200c173dba4SDan Murphy 	case 0:
201c173dba4SDan Murphy 		/* Do not change slot width */
202c173dba4SDan Murphy 		break;
203c173dba4SDan Murphy 	default:
204c173dba4SDan Murphy 		dev_err(tas2562->dev, "slot width not supported");
205c173dba4SDan Murphy 		ret = -EINVAL;
206c173dba4SDan Murphy 	}
207c173dba4SDan Murphy 
208c173dba4SDan Murphy 	if (ret < 0)
209c173dba4SDan Murphy 		return ret;
210c173dba4SDan Murphy 
211d7bd40aeSDan Murphy 	ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG5,
212d7bd40aeSDan Murphy 					    TAS2562_TDM_CFG5_VSNS_SLOT_MASK,
213d7bd40aeSDan Murphy 					    tas2562->v_sense_slot);
214d7bd40aeSDan Murphy 	if (ret < 0)
215d7bd40aeSDan Murphy 		return ret;
216d7bd40aeSDan Murphy 
217d7bd40aeSDan Murphy 	ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG6,
218d7bd40aeSDan Murphy 					    TAS2562_TDM_CFG6_ISNS_SLOT_MASK,
219d7bd40aeSDan Murphy 					    tas2562->i_sense_slot);
220d7bd40aeSDan Murphy 	if (ret < 0)
221d7bd40aeSDan Murphy 		return ret;
222d7bd40aeSDan Murphy 
223c173dba4SDan Murphy 	return 0;
224c173dba4SDan Murphy }
225c173dba4SDan Murphy 
tas2562_set_bitwidth(struct tas2562_data * tas2562,int bitwidth)226c173dba4SDan Murphy static int tas2562_set_bitwidth(struct tas2562_data *tas2562, int bitwidth)
227c173dba4SDan Murphy {
228c173dba4SDan Murphy 	int ret;
22909ed395bSDan Murphy 	int val;
23009ed395bSDan Murphy 	int sense_en;
231c173dba4SDan Murphy 
232c173dba4SDan Murphy 	switch (bitwidth) {
233c173dba4SDan Murphy 	case SNDRV_PCM_FORMAT_S16_LE:
234c173dba4SDan Murphy 		snd_soc_component_update_bits(tas2562->component,
235c173dba4SDan Murphy 					      TAS2562_TDM_CFG2,
236c173dba4SDan Murphy 					      TAS2562_TDM_CFG2_RXWLEN_MASK,
237c173dba4SDan Murphy 					      TAS2562_TDM_CFG2_RXWLEN_16B);
238c173dba4SDan Murphy 		break;
239c173dba4SDan Murphy 	case SNDRV_PCM_FORMAT_S24_LE:
240c173dba4SDan Murphy 		snd_soc_component_update_bits(tas2562->component,
241c173dba4SDan Murphy 					      TAS2562_TDM_CFG2,
242c173dba4SDan Murphy 					      TAS2562_TDM_CFG2_RXWLEN_MASK,
243c173dba4SDan Murphy 					      TAS2562_TDM_CFG2_RXWLEN_24B);
244c173dba4SDan Murphy 		break;
245c173dba4SDan Murphy 	case SNDRV_PCM_FORMAT_S32_LE:
246c173dba4SDan Murphy 		snd_soc_component_update_bits(tas2562->component,
247c173dba4SDan Murphy 					      TAS2562_TDM_CFG2,
248c173dba4SDan Murphy 					      TAS2562_TDM_CFG2_RXWLEN_MASK,
249c173dba4SDan Murphy 					      TAS2562_TDM_CFG2_RXWLEN_32B);
250c173dba4SDan Murphy 		break;
251c173dba4SDan Murphy 
252c173dba4SDan Murphy 	default:
253310006caSDan Murphy 		dev_info(tas2562->dev, "Unsupported bitwidth format\n");
254310006caSDan Murphy 		return -EINVAL;
255c173dba4SDan Murphy 	}
256c173dba4SDan Murphy 
25709ed395bSDan Murphy 	val = snd_soc_component_read(tas2562->component, TAS2562_PWR_CTRL);
25809ed395bSDan Murphy 	if (val < 0)
25909ed395bSDan Murphy 		return val;
26009ed395bSDan Murphy 
26109ed395bSDan Murphy 	if (val & (1 << TAS2562_VSENSE_POWER_EN))
26209ed395bSDan Murphy 		sense_en = 0;
26309ed395bSDan Murphy 	else
26409ed395bSDan Murphy 		sense_en = TAS2562_TDM_CFG5_VSNS_EN;
26509ed395bSDan Murphy 
26609ed395bSDan Murphy 	ret = snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG5,
26709ed395bSDan Murphy 		TAS2562_TDM_CFG5_VSNS_EN, sense_en);
268c173dba4SDan Murphy 	if (ret < 0)
269c173dba4SDan Murphy 		return ret;
270c173dba4SDan Murphy 
27109ed395bSDan Murphy 	if (val & (1 << TAS2562_ISENSE_POWER_EN))
27209ed395bSDan Murphy 		sense_en = 0;
27309ed395bSDan Murphy 	else
27409ed395bSDan Murphy 		sense_en = TAS2562_TDM_CFG6_ISNS_EN;
27509ed395bSDan Murphy 
27609ed395bSDan Murphy 	ret = snd_soc_component_update_bits(tas2562->component, TAS2562_TDM_CFG6,
27709ed395bSDan Murphy 		TAS2562_TDM_CFG6_ISNS_EN, sense_en);
278c173dba4SDan Murphy 	if (ret < 0)
279c173dba4SDan Murphy 		return ret;
280c173dba4SDan Murphy 
281c173dba4SDan Murphy 	return 0;
282c173dba4SDan Murphy }
283c173dba4SDan Murphy 
tas2562_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)284c173dba4SDan Murphy static int tas2562_hw_params(struct snd_pcm_substream *substream,
285c173dba4SDan Murphy 			     struct snd_pcm_hw_params *params,
286c173dba4SDan Murphy 			     struct snd_soc_dai *dai)
287c173dba4SDan Murphy {
288c173dba4SDan Murphy 	struct snd_soc_component *component = dai->component;
289c173dba4SDan Murphy 	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
290c173dba4SDan Murphy 	int ret;
291c173dba4SDan Murphy 
292c173dba4SDan Murphy 	ret = tas2562_set_bitwidth(tas2562, params_format(params));
293c173dba4SDan Murphy 	if (ret) {
294c173dba4SDan Murphy 		dev_err(tas2562->dev, "set bitwidth failed, %d\n", ret);
295c173dba4SDan Murphy 		return ret;
296c173dba4SDan Murphy 	}
297c173dba4SDan Murphy 
298c173dba4SDan Murphy 	ret = tas2562_set_samplerate(tas2562, params_rate(params));
299c173dba4SDan Murphy 	if (ret)
30038b6a714SDan Murphy 		dev_err(tas2562->dev, "set sample rate failed, %d\n", ret);
301c173dba4SDan Murphy 
302c173dba4SDan Murphy 	return ret;
303c173dba4SDan Murphy }
304c173dba4SDan Murphy 
tas2562_set_dai_fmt(struct snd_soc_dai * dai,unsigned int fmt)305c173dba4SDan Murphy static int tas2562_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
306c173dba4SDan Murphy {
307c173dba4SDan Murphy 	struct snd_soc_component *component = dai->component;
308c173dba4SDan Murphy 	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
309d7bd40aeSDan Murphy 	u8 asi_cfg_1 = 0;
310d7bd40aeSDan Murphy 	u8 tdm_rx_start_slot = 0;
311c173dba4SDan Murphy 	int ret;
312c173dba4SDan Murphy 
313c173dba4SDan Murphy 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
314c173dba4SDan Murphy 	case SND_SOC_DAIFMT_NB_NF:
315c173dba4SDan Murphy 		asi_cfg_1 = 0;
316c173dba4SDan Murphy 		break;
317c173dba4SDan Murphy 	case SND_SOC_DAIFMT_IB_NF:
318c173dba4SDan Murphy 		asi_cfg_1 |= TAS2562_TDM_CFG1_RX_FALLING;
319c173dba4SDan Murphy 		break;
320c173dba4SDan Murphy 	default:
321c173dba4SDan Murphy 		dev_err(tas2562->dev, "ASI format Inverse is not found\n");
322c173dba4SDan Murphy 		return -EINVAL;
323c173dba4SDan Murphy 	}
324c173dba4SDan Murphy 
325c173dba4SDan Murphy 	ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG1,
326c173dba4SDan Murphy 					    TAS2562_TDM_CFG1_RX_EDGE_MASK,
327c173dba4SDan Murphy 					    asi_cfg_1);
328c173dba4SDan Murphy 	if (ret < 0) {
329c173dba4SDan Murphy 		dev_err(tas2562->dev, "Failed to set RX edge\n");
330c173dba4SDan Murphy 		return ret;
331c173dba4SDan Murphy 	}
332c173dba4SDan Murphy 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
333d7bd40aeSDan Murphy 	case SND_SOC_DAIFMT_LEFT_J:
334d7bd40aeSDan Murphy 	case SND_SOC_DAIFMT_DSP_B:
335c173dba4SDan Murphy 		tdm_rx_start_slot = 0;
336c173dba4SDan Murphy 		break;
337d7bd40aeSDan Murphy 	case SND_SOC_DAIFMT_I2S:
338d7bd40aeSDan Murphy 	case SND_SOC_DAIFMT_DSP_A:
339d7bd40aeSDan Murphy 		tdm_rx_start_slot = 1;
340c173dba4SDan Murphy 		break;
341d7bd40aeSDan Murphy 	default:
342d7bd40aeSDan Murphy 		dev_err(tas2562->dev,
343d7bd40aeSDan Murphy 			"DAI Format is not found, fmt=0x%x\n", fmt);
344d7bd40aeSDan Murphy 		return -EINVAL;
345c173dba4SDan Murphy 	}
346c173dba4SDan Murphy 
347c173dba4SDan Murphy 	ret = snd_soc_component_update_bits(component, TAS2562_TDM_CFG1,
348d7bd40aeSDan Murphy 				TAS2562_RX_OFF_MASK, (tdm_rx_start_slot << 1));
349c173dba4SDan Murphy 	if (ret < 0)
350c173dba4SDan Murphy 		return ret;
351c173dba4SDan Murphy 
352c173dba4SDan Murphy 	return 0;
353c173dba4SDan Murphy }
354c173dba4SDan Murphy 
tas2562_update_pwr_ctrl(struct tas2562_data * tas2562)3552848d34cSMartin Povišer static int tas2562_update_pwr_ctrl(struct tas2562_data *tas2562)
3562848d34cSMartin Povišer {
3572848d34cSMartin Povišer 	struct snd_soc_component *component = tas2562->component;
3582848d34cSMartin Povišer 	unsigned int val;
3592848d34cSMartin Povišer 	int ret;
3602848d34cSMartin Povišer 
3612848d34cSMartin Povišer 	if (tas2562->dac_powered)
3622848d34cSMartin Povišer 		val = tas2562->unmuted ?
3632848d34cSMartin Povišer 			TAS2562_ACTIVE : TAS2562_MUTE;
3642848d34cSMartin Povišer 	else
3652848d34cSMartin Povišer 		val = TAS2562_SHUTDOWN;
3662848d34cSMartin Povišer 
3672848d34cSMartin Povišer 	ret = snd_soc_component_update_bits(component, TAS2562_PWR_CTRL,
3682848d34cSMartin Povišer 					    TAS2562_MODE_MASK, val);
3692848d34cSMartin Povišer 	if (ret < 0)
3702848d34cSMartin Povišer 		return ret;
3712848d34cSMartin Povišer 
3722848d34cSMartin Povišer 	return 0;
3732848d34cSMartin Povišer }
3742848d34cSMartin Povišer 
tas2562_mute(struct snd_soc_dai * dai,int mute,int direction)37538803ce7SKuninori Morimoto static int tas2562_mute(struct snd_soc_dai *dai, int mute, int direction)
376c173dba4SDan Murphy {
3772848d34cSMartin Povišer 	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(dai->component);
378c173dba4SDan Murphy 
3792848d34cSMartin Povišer 	tas2562->unmuted = !mute;
3802848d34cSMartin Povišer 	return tas2562_update_pwr_ctrl(tas2562);
381c173dba4SDan Murphy }
382c173dba4SDan Murphy 
tas2562_codec_probe(struct snd_soc_component * component)383c173dba4SDan Murphy static int tas2562_codec_probe(struct snd_soc_component *component)
384c173dba4SDan Murphy {
385c173dba4SDan Murphy 	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
386c173dba4SDan Murphy 
387c173dba4SDan Murphy 	tas2562->component = component;
388c173dba4SDan Murphy 
389c173dba4SDan Murphy 	if (tas2562->sdz_gpio)
390c173dba4SDan Murphy 		gpiod_set_value_cansleep(tas2562->sdz_gpio, 1);
391c173dba4SDan Murphy 
392c173dba4SDan Murphy 	return 0;
393c173dba4SDan Murphy }
394c173dba4SDan Murphy 
395c173dba4SDan Murphy #ifdef CONFIG_PM
tas2562_suspend(struct snd_soc_component * component)396c173dba4SDan Murphy static int tas2562_suspend(struct snd_soc_component *component)
397c173dba4SDan Murphy {
398c173dba4SDan Murphy 	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
399c173dba4SDan Murphy 
400c173dba4SDan Murphy 	regcache_cache_only(tas2562->regmap, true);
401c173dba4SDan Murphy 	regcache_mark_dirty(tas2562->regmap);
402c173dba4SDan Murphy 
403c173dba4SDan Murphy 	if (tas2562->sdz_gpio)
404c173dba4SDan Murphy 		gpiod_set_value_cansleep(tas2562->sdz_gpio, 0);
405c173dba4SDan Murphy 
406c173dba4SDan Murphy 	return 0;
407c173dba4SDan Murphy }
408c173dba4SDan Murphy 
tas2562_resume(struct snd_soc_component * component)409c173dba4SDan Murphy static int tas2562_resume(struct snd_soc_component *component)
410c173dba4SDan Murphy {
411c173dba4SDan Murphy 	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
412c173dba4SDan Murphy 
413c173dba4SDan Murphy 	if (tas2562->sdz_gpio)
414c173dba4SDan Murphy 		gpiod_set_value_cansleep(tas2562->sdz_gpio, 1);
415c173dba4SDan Murphy 
416c173dba4SDan Murphy 	regcache_cache_only(tas2562->regmap, false);
417c173dba4SDan Murphy 
418c173dba4SDan Murphy 	return regcache_sync(tas2562->regmap);
419c173dba4SDan Murphy }
420c173dba4SDan Murphy #else
421c173dba4SDan Murphy #define tas2562_suspend NULL
422c173dba4SDan Murphy #define tas2562_resume NULL
423c173dba4SDan Murphy #endif
424c173dba4SDan Murphy 
425c173dba4SDan Murphy static const char * const tas2562_ASI1_src[] = {
426c173dba4SDan Murphy 	"I2C offset", "Left", "Right", "LeftRightDiv2",
427c173dba4SDan Murphy };
428c173dba4SDan Murphy 
429c173dba4SDan Murphy static SOC_ENUM_SINGLE_DECL(tas2562_ASI1_src_enum, TAS2562_TDM_CFG2, 4,
430c173dba4SDan Murphy 			    tas2562_ASI1_src);
431c173dba4SDan Murphy 
432c173dba4SDan Murphy static const struct snd_kcontrol_new tas2562_asi1_mux =
433c173dba4SDan Murphy 	SOC_DAPM_ENUM("ASI1 Source", tas2562_ASI1_src_enum);
434c173dba4SDan Murphy 
tas2562_dac_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)435c173dba4SDan Murphy static int tas2562_dac_event(struct snd_soc_dapm_widget *w,
436c173dba4SDan Murphy 			     struct snd_kcontrol *kcontrol, int event)
437c173dba4SDan Murphy {
438c173dba4SDan Murphy 	struct snd_soc_component *component =
439c173dba4SDan Murphy 					snd_soc_dapm_to_component(w->dapm);
440c173dba4SDan Murphy 	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
4413e9a8386SFabio Estevam 	int ret = 0;
442c173dba4SDan Murphy 
443c173dba4SDan Murphy 	switch (event) {
444c173dba4SDan Murphy 	case SND_SOC_DAPM_POST_PMU:
4452848d34cSMartin Povišer 		tas2562->dac_powered = true;
4462848d34cSMartin Povišer 		ret = tas2562_update_pwr_ctrl(tas2562);
447c173dba4SDan Murphy 		break;
448c173dba4SDan Murphy 	case SND_SOC_DAPM_PRE_PMD:
4492848d34cSMartin Povišer 		tas2562->dac_powered = false;
4502848d34cSMartin Povišer 		ret = tas2562_update_pwr_ctrl(tas2562);
451c173dba4SDan Murphy 		break;
452c173dba4SDan Murphy 	default:
45369e53129SDan Murphy 		dev_err(tas2562->dev, "Not supported evevt\n");
45469e53129SDan Murphy 		return -EINVAL;
455c173dba4SDan Murphy 	}
456c173dba4SDan Murphy 
4573e9a8386SFabio Estevam 	return ret;
458c173dba4SDan Murphy }
459c173dba4SDan Murphy 
tas2562_volume_control_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)460bf726b1cSDan Murphy static int tas2562_volume_control_get(struct snd_kcontrol *kcontrol,
461bf726b1cSDan Murphy 				      struct snd_ctl_elem_value *ucontrol)
462bf726b1cSDan Murphy {
463bf726b1cSDan Murphy 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
464bf726b1cSDan Murphy 	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
465bf726b1cSDan Murphy 
466bf726b1cSDan Murphy 	ucontrol->value.integer.value[0] = tas2562->volume_lvl;
467bf726b1cSDan Murphy 	return 0;
468bf726b1cSDan Murphy }
469bf726b1cSDan Murphy 
tas2562_volume_control_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)470bf726b1cSDan Murphy static int tas2562_volume_control_put(struct snd_kcontrol *kcontrol,
471bf726b1cSDan Murphy 				      struct snd_ctl_elem_value *ucontrol)
472bf726b1cSDan Murphy {
473bf726b1cSDan Murphy 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
474bf726b1cSDan Murphy 	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
475bf726b1cSDan Murphy 	int ret;
476bf726b1cSDan Murphy 	u32 reg_val;
477bf726b1cSDan Murphy 
478bf726b1cSDan Murphy 	reg_val = float_vol_db_lookup[ucontrol->value.integer.value[0]/2];
479bf726b1cSDan Murphy 	ret = snd_soc_component_write(component, TAS2562_DVC_CFG4,
480bf726b1cSDan Murphy 				      (reg_val & 0xff));
481bf726b1cSDan Murphy 	if (ret)
482bf726b1cSDan Murphy 		return ret;
483bf726b1cSDan Murphy 	ret = snd_soc_component_write(component, TAS2562_DVC_CFG3,
484bf726b1cSDan Murphy 				      ((reg_val >> 8) & 0xff));
485bf726b1cSDan Murphy 	if (ret)
486bf726b1cSDan Murphy 		return ret;
487bf726b1cSDan Murphy 	ret = snd_soc_component_write(component, TAS2562_DVC_CFG2,
488bf726b1cSDan Murphy 				      ((reg_val >> 16) & 0xff));
489bf726b1cSDan Murphy 	if (ret)
490bf726b1cSDan Murphy 		return ret;
491bf726b1cSDan Murphy 	ret = snd_soc_component_write(component, TAS2562_DVC_CFG1,
492bf726b1cSDan Murphy 				      ((reg_val >> 24) & 0xff));
493bf726b1cSDan Murphy 	if (ret)
494bf726b1cSDan Murphy 		return ret;
495bf726b1cSDan Murphy 
496bf726b1cSDan Murphy 	tas2562->volume_lvl = ucontrol->value.integer.value[0];
497bf726b1cSDan Murphy 
4982e40b21cSPierre-Louis Bossart 	return 0;
499bf726b1cSDan Murphy }
500bf726b1cSDan Murphy 
501bf726b1cSDan Murphy /* Digital Volume Control. From 0 dB to -110 dB in 1 dB steps */
502bf726b1cSDan Murphy static const DECLARE_TLV_DB_SCALE(dvc_tlv, -11000, 100, 0);
503bf726b1cSDan Murphy 
504c173dba4SDan Murphy static DECLARE_TLV_DB_SCALE(tas2562_dac_tlv, 850, 50, 0);
505c173dba4SDan Murphy 
506c173dba4SDan Murphy static const struct snd_kcontrol_new isense_switch =
507c173dba4SDan Murphy 	SOC_DAPM_SINGLE("Switch", TAS2562_PWR_CTRL, TAS2562_ISENSE_POWER_EN,
508c173dba4SDan Murphy 			1, 1);
509c173dba4SDan Murphy 
510c173dba4SDan Murphy static const struct snd_kcontrol_new vsense_switch =
511c173dba4SDan Murphy 	SOC_DAPM_SINGLE("Switch", TAS2562_PWR_CTRL, TAS2562_VSENSE_POWER_EN,
512c173dba4SDan Murphy 			1, 1);
513c173dba4SDan Murphy 
514c173dba4SDan Murphy static const struct snd_kcontrol_new tas2562_snd_controls[] = {
515eedf8a12SJonghwan Choi 	SOC_SINGLE_TLV("Amp Gain Volume", TAS2562_PB_CFG1, 1, 0x1c, 0,
516c173dba4SDan Murphy 		       tas2562_dac_tlv),
517bf726b1cSDan Murphy 	{
518bf726b1cSDan Murphy 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
519bf726b1cSDan Murphy 		.name = "Digital Volume Control",
520bf726b1cSDan Murphy 		.index = 0,
521bf726b1cSDan Murphy 		.tlv.p = dvc_tlv,
522bf726b1cSDan Murphy 		.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,
523bf726b1cSDan Murphy 		.info = snd_soc_info_volsw,
524bf726b1cSDan Murphy 		.get = tas2562_volume_control_get,
525bf726b1cSDan Murphy 		.put = tas2562_volume_control_put,
526bf726b1cSDan Murphy 		.private_value = SOC_SINGLE_VALUE(TAS2562_DVC_CFG1, 0, 110, 0, 0),
527bf726b1cSDan Murphy 	},
528c173dba4SDan Murphy };
529c173dba4SDan Murphy 
5308adcdbe6SDan Murphy static const struct snd_soc_dapm_widget tas2110_dapm_widgets[] = {
5318adcdbe6SDan Murphy 	SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
5328adcdbe6SDan Murphy 	SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2562_asi1_mux),
5338adcdbe6SDan Murphy 	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2562_dac_event,
5348adcdbe6SDan Murphy 			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
5358adcdbe6SDan Murphy 	SND_SOC_DAPM_OUTPUT("OUT"),
5368adcdbe6SDan Murphy };
5378adcdbe6SDan Murphy 
5388adcdbe6SDan Murphy static const struct snd_soc_dapm_route tas2110_audio_map[] = {
5398adcdbe6SDan Murphy 	{"ASI1 Sel", "I2C offset", "ASI1"},
5408adcdbe6SDan Murphy 	{"ASI1 Sel", "Left", "ASI1"},
5418adcdbe6SDan Murphy 	{"ASI1 Sel", "Right", "ASI1"},
5428adcdbe6SDan Murphy 	{"ASI1 Sel", "LeftRightDiv2", "ASI1"},
5438adcdbe6SDan Murphy 	{ "DAC", NULL, "ASI1 Sel" },
5448adcdbe6SDan Murphy 	{ "OUT", NULL, "DAC" },
5458adcdbe6SDan Murphy };
5468adcdbe6SDan Murphy 
5478adcdbe6SDan Murphy static const struct snd_soc_component_driver soc_component_dev_tas2110 = {
5488adcdbe6SDan Murphy 	.probe			= tas2562_codec_probe,
5498adcdbe6SDan Murphy 	.suspend		= tas2562_suspend,
5508adcdbe6SDan Murphy 	.resume			= tas2562_resume,
5518adcdbe6SDan Murphy 	.controls		= tas2562_snd_controls,
5528adcdbe6SDan Murphy 	.num_controls		= ARRAY_SIZE(tas2562_snd_controls),
5538adcdbe6SDan Murphy 	.dapm_widgets		= tas2110_dapm_widgets,
5548adcdbe6SDan Murphy 	.num_dapm_widgets	= ARRAY_SIZE(tas2110_dapm_widgets),
5558adcdbe6SDan Murphy 	.dapm_routes		= tas2110_audio_map,
5568adcdbe6SDan Murphy 	.num_dapm_routes	= ARRAY_SIZE(tas2110_audio_map),
5578adcdbe6SDan Murphy 	.idle_bias_on		= 1,
5588adcdbe6SDan Murphy 	.use_pmdown_time	= 1,
5598adcdbe6SDan Murphy 	.endianness		= 1,
5608adcdbe6SDan Murphy };
5618adcdbe6SDan Murphy 
562c173dba4SDan Murphy static const struct snd_soc_dapm_widget tas2562_dapm_widgets[] = {
563c173dba4SDan Murphy 	SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
564c173dba4SDan Murphy 	SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2562_asi1_mux),
565c173dba4SDan Murphy 	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2562_dac_event,
566c173dba4SDan Murphy 			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
567c173dba4SDan Murphy 	SND_SOC_DAPM_SWITCH("ISENSE", TAS2562_PWR_CTRL, 3, 1, &isense_switch),
568c173dba4SDan Murphy 	SND_SOC_DAPM_SWITCH("VSENSE", TAS2562_PWR_CTRL, 2, 1, &vsense_switch),
569c173dba4SDan Murphy 	SND_SOC_DAPM_SIGGEN("VMON"),
570c173dba4SDan Murphy 	SND_SOC_DAPM_SIGGEN("IMON"),
571c173dba4SDan Murphy 	SND_SOC_DAPM_OUTPUT("OUT"),
572c173dba4SDan Murphy };
573c173dba4SDan Murphy 
574c173dba4SDan Murphy static const struct snd_soc_dapm_route tas2562_audio_map[] = {
575c173dba4SDan Murphy 	{"ASI1 Sel", "I2C offset", "ASI1"},
576c173dba4SDan Murphy 	{"ASI1 Sel", "Left", "ASI1"},
577c173dba4SDan Murphy 	{"ASI1 Sel", "Right", "ASI1"},
578c173dba4SDan Murphy 	{"ASI1 Sel", "LeftRightDiv2", "ASI1"},
57969e53129SDan Murphy 	{ "DAC", NULL, "ASI1 Sel" },
580c173dba4SDan Murphy 	{ "OUT", NULL, "DAC" },
581c173dba4SDan Murphy 	{"ISENSE", "Switch", "IMON"},
582c173dba4SDan Murphy 	{"VSENSE", "Switch", "VMON"},
583c173dba4SDan Murphy };
584c173dba4SDan Murphy 
585c173dba4SDan Murphy static const struct snd_soc_component_driver soc_component_dev_tas2562 = {
586c173dba4SDan Murphy 	.probe			= tas2562_codec_probe,
587c173dba4SDan Murphy 	.suspend		= tas2562_suspend,
588c173dba4SDan Murphy 	.resume			= tas2562_resume,
589c173dba4SDan Murphy 	.controls		= tas2562_snd_controls,
590c173dba4SDan Murphy 	.num_controls		= ARRAY_SIZE(tas2562_snd_controls),
591c173dba4SDan Murphy 	.dapm_widgets		= tas2562_dapm_widgets,
592c173dba4SDan Murphy 	.num_dapm_widgets	= ARRAY_SIZE(tas2562_dapm_widgets),
593c173dba4SDan Murphy 	.dapm_routes		= tas2562_audio_map,
594c173dba4SDan Murphy 	.num_dapm_routes	= ARRAY_SIZE(tas2562_audio_map),
595c173dba4SDan Murphy 	.idle_bias_on		= 1,
596c173dba4SDan Murphy 	.use_pmdown_time	= 1,
597c173dba4SDan Murphy 	.endianness		= 1,
598c173dba4SDan Murphy };
599c173dba4SDan Murphy 
600c173dba4SDan Murphy static const struct snd_soc_dai_ops tas2562_speaker_dai_ops = {
601c173dba4SDan Murphy 	.hw_params	= tas2562_hw_params,
602c173dba4SDan Murphy 	.set_fmt	= tas2562_set_dai_fmt,
603c173dba4SDan Murphy 	.set_tdm_slot	= tas2562_set_dai_tdm_slot,
60438803ce7SKuninori Morimoto 	.mute_stream	= tas2562_mute,
60538803ce7SKuninori Morimoto 	.no_capture_mute = 1,
606c173dba4SDan Murphy };
607c173dba4SDan Murphy 
608c173dba4SDan Murphy static struct snd_soc_dai_driver tas2562_dai[] = {
609c173dba4SDan Murphy 	{
610c173dba4SDan Murphy 		.name = "tas2562-amplifier",
611c173dba4SDan Murphy 		.id = 0,
612c173dba4SDan Murphy 		.playback = {
613c173dba4SDan Murphy 			.stream_name    = "ASI1 Playback",
614c173dba4SDan Murphy 			.channels_min   = 2,
615c173dba4SDan Murphy 			.channels_max   = 2,
616c173dba4SDan Murphy 			.rates      = SNDRV_PCM_RATE_8000_192000,
617c173dba4SDan Murphy 			.formats    = TAS2562_FORMATS,
618c173dba4SDan Murphy 		},
61969e53129SDan Murphy 		.capture = {
62069e53129SDan Murphy 			.stream_name    = "ASI1 Capture",
62169e53129SDan Murphy 			.channels_min   = 0,
62269e53129SDan Murphy 			.channels_max   = 2,
62369e53129SDan Murphy 			.rates		= SNDRV_PCM_RATE_8000_192000,
62469e53129SDan Murphy 			.formats	= TAS2562_FORMATS,
62569e53129SDan Murphy 		},
626c173dba4SDan Murphy 		.ops = &tas2562_speaker_dai_ops,
627c173dba4SDan Murphy 	},
628c173dba4SDan Murphy };
629c173dba4SDan Murphy 
630c173dba4SDan Murphy static const struct regmap_range_cfg tas2562_ranges[] = {
631c173dba4SDan Murphy 	{
632c173dba4SDan Murphy 		.range_min = 0,
633c173dba4SDan Murphy 		.range_max = 5 * 128,
634c173dba4SDan Murphy 		.selector_reg = TAS2562_PAGE_CTRL,
635c173dba4SDan Murphy 		.selector_mask = 0xff,
636c173dba4SDan Murphy 		.selector_shift = 0,
637c173dba4SDan Murphy 		.window_start = 0,
638c173dba4SDan Murphy 		.window_len = 128,
639c173dba4SDan Murphy 	},
640c173dba4SDan Murphy };
641c173dba4SDan Murphy 
642c173dba4SDan Murphy static const struct reg_default tas2562_reg_defaults[] = {
643c173dba4SDan Murphy 	{ TAS2562_PAGE_CTRL, 0x00 },
644c173dba4SDan Murphy 	{ TAS2562_SW_RESET, 0x00 },
645c173dba4SDan Murphy 	{ TAS2562_PWR_CTRL, 0x0e },
646c173dba4SDan Murphy 	{ TAS2562_PB_CFG1, 0x20 },
647c173dba4SDan Murphy 	{ TAS2562_TDM_CFG0, 0x09 },
648c173dba4SDan Murphy 	{ TAS2562_TDM_CFG1, 0x02 },
649bf726b1cSDan Murphy 	{ TAS2562_DVC_CFG1, 0x40 },
650bf726b1cSDan Murphy 	{ TAS2562_DVC_CFG2, 0x40 },
651bf726b1cSDan Murphy 	{ TAS2562_DVC_CFG3, 0x00 },
652bf726b1cSDan Murphy 	{ TAS2562_DVC_CFG4, 0x00 },
653c173dba4SDan Murphy };
654c173dba4SDan Murphy 
655c173dba4SDan Murphy static const struct regmap_config tas2562_regmap_config = {
656c173dba4SDan Murphy 	.reg_bits = 8,
657c173dba4SDan Murphy 	.val_bits = 8,
658c173dba4SDan Murphy 
659c173dba4SDan Murphy 	.max_register = 5 * 128,
660c173dba4SDan Murphy 	.cache_type = REGCACHE_RBTREE,
661c173dba4SDan Murphy 	.reg_defaults = tas2562_reg_defaults,
662c173dba4SDan Murphy 	.num_reg_defaults = ARRAY_SIZE(tas2562_reg_defaults),
663c173dba4SDan Murphy 	.ranges = tas2562_ranges,
664c173dba4SDan Murphy 	.num_ranges = ARRAY_SIZE(tas2562_ranges),
665c173dba4SDan Murphy };
666c173dba4SDan Murphy 
tas2562_parse_dt(struct tas2562_data * tas2562)667c173dba4SDan Murphy static int tas2562_parse_dt(struct tas2562_data *tas2562)
668c173dba4SDan Murphy {
669c173dba4SDan Murphy 	struct device *dev = tas2562->dev;
670c173dba4SDan Murphy 	int ret = 0;
671c173dba4SDan Murphy 
672f78a9700SDan Murphy 	tas2562->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
673f78a9700SDan Murphy 	if (IS_ERR(tas2562->sdz_gpio)) {
674f78a9700SDan Murphy 		if (PTR_ERR(tas2562->sdz_gpio) == -EPROBE_DEFER)
675f78a9700SDan Murphy 			return -EPROBE_DEFER;
676f78a9700SDan Murphy 
677f78a9700SDan Murphy 		tas2562->sdz_gpio = NULL;
678f78a9700SDan Murphy 	}
679f78a9700SDan Murphy 
680f78a9700SDan Murphy 	/*
681f78a9700SDan Murphy 	 * The shut-down property is deprecated but needs to be checked for
682f78a9700SDan Murphy 	 * backwards compatibility.
683f78a9700SDan Murphy 	 */
684f78a9700SDan Murphy 	if (tas2562->sdz_gpio == NULL) {
685bc07b544SDan Murphy 		tas2562->sdz_gpio = devm_gpiod_get_optional(dev, "shut-down",
686c173dba4SDan Murphy 							      GPIOD_OUT_HIGH);
687f78a9700SDan Murphy 		if (IS_ERR(tas2562->sdz_gpio))
688f78a9700SDan Murphy 			if (PTR_ERR(tas2562->sdz_gpio) == -EPROBE_DEFER)
689c173dba4SDan Murphy 				return -EPROBE_DEFER;
690f78a9700SDan Murphy 
691f78a9700SDan Murphy 		tas2562->sdz_gpio = NULL;
692c173dba4SDan Murphy 	}
693c173dba4SDan Murphy 
6948adcdbe6SDan Murphy 	if (tas2562->model_id == TAS2110)
6958adcdbe6SDan Murphy 		return ret;
6968adcdbe6SDan Murphy 
697c173dba4SDan Murphy 	ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no",
698c173dba4SDan Murphy 			&tas2562->i_sense_slot);
69909ed395bSDan Murphy 	if (ret) {
70009ed395bSDan Murphy 		dev_err(dev, "Property %s is missing setting default slot\n",
70109ed395bSDan Murphy 			"ti,imon-slot-no");
70209ed395bSDan Murphy 		tas2562->i_sense_slot = 0;
70309ed395bSDan Murphy 	}
70409ed395bSDan Murphy 
70509ed395bSDan Murphy 
70609ed395bSDan Murphy 	ret = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no",
70709ed395bSDan Murphy 			&tas2562->v_sense_slot);
70809ed395bSDan Murphy 	if (ret) {
70909ed395bSDan Murphy 		dev_info(dev, "Property %s is missing setting default slot\n",
71009ed395bSDan Murphy 			"ti,vmon-slot-no");
71109ed395bSDan Murphy 		tas2562->v_sense_slot = 2;
71209ed395bSDan Murphy 	}
71309ed395bSDan Murphy 
71409ed395bSDan Murphy 	if (tas2562->v_sense_slot < tas2562->i_sense_slot) {
71509ed395bSDan Murphy 		dev_err(dev, "Vsense slot must be greater than Isense slot\n");
71609ed395bSDan Murphy 		return -EINVAL;
71709ed395bSDan Murphy 	}
718c173dba4SDan Murphy 
719c173dba4SDan Murphy 	return ret;
720c173dba4SDan Murphy }
721c173dba4SDan Murphy 
72255116b39SStephen Kitt static const struct i2c_device_id tas2562_id[] = {
72355116b39SStephen Kitt 	{ "tas2562", TAS2562 },
72455116b39SStephen Kitt 	{ "tas2563", TAS2563 },
72555116b39SStephen Kitt 	{ "tas2564", TAS2564 },
72655116b39SStephen Kitt 	{ "tas2110", TAS2110 },
72755116b39SStephen Kitt 	{ }
72855116b39SStephen Kitt };
72955116b39SStephen Kitt MODULE_DEVICE_TABLE(i2c, tas2562_id);
73055116b39SStephen Kitt 
tas2562_probe(struct i2c_client * client)73155116b39SStephen Kitt static int tas2562_probe(struct i2c_client *client)
732c173dba4SDan Murphy {
733c173dba4SDan Murphy 	struct device *dev = &client->dev;
734c173dba4SDan Murphy 	struct tas2562_data *data;
735c173dba4SDan Murphy 	int ret;
73655116b39SStephen Kitt 	const struct i2c_device_id *id;
737c173dba4SDan Murphy 
738c173dba4SDan Murphy 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
739c173dba4SDan Murphy 	if (!data)
740c173dba4SDan Murphy 		return -ENOMEM;
741c173dba4SDan Murphy 
74255116b39SStephen Kitt 	id = i2c_match_id(tas2562_id, client);
743c173dba4SDan Murphy 	data->client = client;
744c173dba4SDan Murphy 	data->dev = &client->dev;
7458adcdbe6SDan Murphy 	data->model_id = id->driver_data;
746c173dba4SDan Murphy 
747c173dba4SDan Murphy 	tas2562_parse_dt(data);
748c173dba4SDan Murphy 
749c173dba4SDan Murphy 	data->regmap = devm_regmap_init_i2c(client, &tas2562_regmap_config);
750c173dba4SDan Murphy 	if (IS_ERR(data->regmap)) {
751c173dba4SDan Murphy 		ret = PTR_ERR(data->regmap);
752c173dba4SDan Murphy 		dev_err(dev, "failed to allocate register map: %d\n", ret);
753c173dba4SDan Murphy 		return ret;
754c173dba4SDan Murphy 	}
755c173dba4SDan Murphy 
756c173dba4SDan Murphy 	dev_set_drvdata(&client->dev, data);
757c173dba4SDan Murphy 
7588adcdbe6SDan Murphy 	if (data->model_id == TAS2110)
7598adcdbe6SDan Murphy 		return devm_snd_soc_register_component(dev,
7608adcdbe6SDan Murphy 						       &soc_component_dev_tas2110,
7618adcdbe6SDan Murphy 						       tas2562_dai,
7628adcdbe6SDan Murphy 						       ARRAY_SIZE(tas2562_dai));
7638adcdbe6SDan Murphy 
764c173dba4SDan Murphy 	return devm_snd_soc_register_component(dev, &soc_component_dev_tas2562,
765c173dba4SDan Murphy 					       tas2562_dai,
766c173dba4SDan Murphy 					       ARRAY_SIZE(tas2562_dai));
767c173dba4SDan Murphy 
768c173dba4SDan Murphy }
769c173dba4SDan Murphy 
77068591e8aSKrzysztof Kozlowski #ifdef CONFIG_OF
771c173dba4SDan Murphy static const struct of_device_id tas2562_of_match[] = {
772c173dba4SDan Murphy 	{ .compatible = "ti,tas2562", },
77314f8c8d8SDan Murphy 	{ .compatible = "ti,tas2563", },
774534c0f43SDan Murphy 	{ .compatible = "ti,tas2564", },
7758adcdbe6SDan Murphy 	{ .compatible = "ti,tas2110", },
776c173dba4SDan Murphy 	{ },
777c173dba4SDan Murphy };
778c173dba4SDan Murphy MODULE_DEVICE_TABLE(of, tas2562_of_match);
77968591e8aSKrzysztof Kozlowski #endif
780c173dba4SDan Murphy 
781c173dba4SDan Murphy static struct i2c_driver tas2562_i2c_driver = {
782c173dba4SDan Murphy 	.driver = {
783c173dba4SDan Murphy 		.name = "tas2562",
784c173dba4SDan Murphy 		.of_match_table = of_match_ptr(tas2562_of_match),
785c173dba4SDan Murphy 	},
786*9abcd240SUwe Kleine-König 	.probe = tas2562_probe,
787c173dba4SDan Murphy 	.id_table = tas2562_id,
788c173dba4SDan Murphy };
789c173dba4SDan Murphy 
790c173dba4SDan Murphy module_i2c_driver(tas2562_i2c_driver);
791c173dba4SDan Murphy 
792c173dba4SDan Murphy MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
793c173dba4SDan Murphy MODULE_DESCRIPTION("TAS2562 Audio amplifier driver");
794c173dba4SDan Murphy MODULE_LICENSE("GPL");
795