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