1827ed8a0SDan Murphy // SPDX-License-Identifier: GPL-2.0
2827ed8a0SDan Murphy //
3827ed8a0SDan Murphy // Driver for the Texas Instruments TAS2764 CODEC
4827ed8a0SDan Murphy // Copyright (C) 2020 Texas Instruments Inc.
5827ed8a0SDan Murphy
6827ed8a0SDan Murphy #include <linux/module.h>
7827ed8a0SDan Murphy #include <linux/moduleparam.h>
8827ed8a0SDan Murphy #include <linux/err.h>
9827ed8a0SDan Murphy #include <linux/init.h>
10827ed8a0SDan Murphy #include <linux/delay.h>
11827ed8a0SDan Murphy #include <linux/pm.h>
12827ed8a0SDan Murphy #include <linux/i2c.h>
13827ed8a0SDan Murphy #include <linux/gpio.h>
14827ed8a0SDan Murphy #include <linux/gpio/consumer.h>
15827ed8a0SDan Murphy #include <linux/regulator/consumer.h>
16827ed8a0SDan Murphy #include <linux/regmap.h>
17827ed8a0SDan Murphy #include <linux/of.h>
18827ed8a0SDan Murphy #include <linux/of_gpio.h>
19827ed8a0SDan Murphy #include <linux/slab.h>
20827ed8a0SDan Murphy #include <sound/soc.h>
21827ed8a0SDan Murphy #include <sound/pcm.h>
22827ed8a0SDan Murphy #include <sound/pcm_params.h>
23827ed8a0SDan Murphy #include <sound/initval.h>
24827ed8a0SDan Murphy #include <sound/tlv.h>
25827ed8a0SDan Murphy
26827ed8a0SDan Murphy #include "tas2764.h"
27827ed8a0SDan Murphy
28827ed8a0SDan Murphy struct tas2764_priv {
29827ed8a0SDan Murphy struct snd_soc_component *component;
30827ed8a0SDan Murphy struct gpio_desc *reset_gpio;
31827ed8a0SDan Murphy struct gpio_desc *sdz_gpio;
32827ed8a0SDan Murphy struct regmap *regmap;
33827ed8a0SDan Murphy struct device *dev;
34dae191fbSMartin Povišer int irq;
35827ed8a0SDan Murphy
36827ed8a0SDan Murphy int v_sense_slot;
37827ed8a0SDan Murphy int i_sense_slot;
38f5ad67f1SMartin Povišer
39f5ad67f1SMartin Povišer bool dac_powered;
40f5ad67f1SMartin Povišer bool unmuted;
41827ed8a0SDan Murphy };
42827ed8a0SDan Murphy
43dae191fbSMartin Povišer static const char *tas2764_int_ltch0_msgs[8] = {
44dae191fbSMartin Povišer "fault: over temperature", /* INT_LTCH0 & BIT(0) */
45dae191fbSMartin Povišer "fault: over current",
46dae191fbSMartin Povišer "fault: bad TDM clock",
47dae191fbSMartin Povišer "limiter active",
48dae191fbSMartin Povišer "fault: PVDD below limiter inflection point",
49dae191fbSMartin Povišer "fault: limiter max attenuation",
50dae191fbSMartin Povišer "fault: BOP infinite hold",
51dae191fbSMartin Povišer "fault: BOP mute", /* INT_LTCH0 & BIT(7) */
52dae191fbSMartin Povišer };
53dae191fbSMartin Povišer
54dae191fbSMartin Povišer static const unsigned int tas2764_int_readout_regs[6] = {
55dae191fbSMartin Povišer TAS2764_INT_LTCH0,
56dae191fbSMartin Povišer TAS2764_INT_LTCH1,
57dae191fbSMartin Povišer TAS2764_INT_LTCH1_0,
58dae191fbSMartin Povišer TAS2764_INT_LTCH2,
59dae191fbSMartin Povišer TAS2764_INT_LTCH3,
60dae191fbSMartin Povišer TAS2764_INT_LTCH4,
61dae191fbSMartin Povišer };
62dae191fbSMartin Povišer
tas2764_irq(int irq,void * data)63dae191fbSMartin Povišer static irqreturn_t tas2764_irq(int irq, void *data)
64dae191fbSMartin Povišer {
65dae191fbSMartin Povišer struct tas2764_priv *tas2764 = data;
66dae191fbSMartin Povišer u8 latched[6] = {0, 0, 0, 0, 0, 0};
67dae191fbSMartin Povišer int ret = IRQ_NONE;
68dae191fbSMartin Povišer int i;
69dae191fbSMartin Povišer
70dae191fbSMartin Povišer for (i = 0; i < ARRAY_SIZE(latched); i++)
71dae191fbSMartin Povišer latched[i] = snd_soc_component_read(tas2764->component,
72dae191fbSMartin Povišer tas2764_int_readout_regs[i]);
73dae191fbSMartin Povišer
74dae191fbSMartin Povišer for (i = 0; i < 8; i++) {
75dae191fbSMartin Povišer if (latched[0] & BIT(i)) {
76dae191fbSMartin Povišer dev_crit_ratelimited(tas2764->dev, "%s\n",
77dae191fbSMartin Povišer tas2764_int_ltch0_msgs[i]);
78dae191fbSMartin Povišer ret = IRQ_HANDLED;
79dae191fbSMartin Povišer }
80dae191fbSMartin Povišer }
81dae191fbSMartin Povišer
82dae191fbSMartin Povišer if (latched[0]) {
83dae191fbSMartin Povišer dev_err_ratelimited(tas2764->dev, "other context to the fault: %02x,%02x,%02x,%02x,%02x",
84dae191fbSMartin Povišer latched[1], latched[2], latched[3], latched[4], latched[5]);
85dae191fbSMartin Povišer snd_soc_component_update_bits(tas2764->component,
86dae191fbSMartin Povišer TAS2764_INT_CLK_CFG,
87dae191fbSMartin Povišer TAS2764_INT_CLK_CFG_IRQZ_CLR,
88dae191fbSMartin Povišer TAS2764_INT_CLK_CFG_IRQZ_CLR);
89dae191fbSMartin Povišer }
90dae191fbSMartin Povišer
91dae191fbSMartin Povišer return ret;
92dae191fbSMartin Povišer }
93dae191fbSMartin Povišer
tas2764_reset(struct tas2764_priv * tas2764)94827ed8a0SDan Murphy static void tas2764_reset(struct tas2764_priv *tas2764)
95827ed8a0SDan Murphy {
96827ed8a0SDan Murphy if (tas2764->reset_gpio) {
97827ed8a0SDan Murphy gpiod_set_value_cansleep(tas2764->reset_gpio, 0);
98827ed8a0SDan Murphy msleep(20);
99827ed8a0SDan Murphy gpiod_set_value_cansleep(tas2764->reset_gpio, 1);
100cd10bb89SMartin Povišer usleep_range(1000, 2000);
101827ed8a0SDan Murphy }
102827ed8a0SDan Murphy
103827ed8a0SDan Murphy snd_soc_component_write(tas2764->component, TAS2764_SW_RST,
104827ed8a0SDan Murphy TAS2764_RST);
105cd10bb89SMartin Povišer usleep_range(1000, 2000);
106827ed8a0SDan Murphy }
107827ed8a0SDan Murphy
tas2764_update_pwr_ctrl(struct tas2764_priv * tas2764)108f5ad67f1SMartin Povišer static int tas2764_update_pwr_ctrl(struct tas2764_priv *tas2764)
109f5ad67f1SMartin Povišer {
110f5ad67f1SMartin Povišer struct snd_soc_component *component = tas2764->component;
111f5ad67f1SMartin Povišer unsigned int val;
112f5ad67f1SMartin Povišer int ret;
113f5ad67f1SMartin Povišer
114f5ad67f1SMartin Povišer if (tas2764->dac_powered)
115f5ad67f1SMartin Povišer val = tas2764->unmuted ?
116f5ad67f1SMartin Povišer TAS2764_PWR_CTRL_ACTIVE : TAS2764_PWR_CTRL_MUTE;
117f5ad67f1SMartin Povišer else
118f5ad67f1SMartin Povišer val = TAS2764_PWR_CTRL_SHUTDOWN;
119f5ad67f1SMartin Povišer
120f5ad67f1SMartin Povišer ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
121f5ad67f1SMartin Povišer TAS2764_PWR_CTRL_MASK, val);
122f5ad67f1SMartin Povišer if (ret < 0)
123f5ad67f1SMartin Povišer return ret;
124f5ad67f1SMartin Povišer
125f5ad67f1SMartin Povišer return 0;
126f5ad67f1SMartin Povišer }
127f5ad67f1SMartin Povišer
128827ed8a0SDan Murphy #ifdef CONFIG_PM
tas2764_codec_suspend(struct snd_soc_component * component)129827ed8a0SDan Murphy static int tas2764_codec_suspend(struct snd_soc_component *component)
130827ed8a0SDan Murphy {
131827ed8a0SDan Murphy struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
132827ed8a0SDan Murphy int ret;
133827ed8a0SDan Murphy
134827ed8a0SDan Murphy ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
135827ed8a0SDan Murphy TAS2764_PWR_CTRL_MASK,
136827ed8a0SDan Murphy TAS2764_PWR_CTRL_SHUTDOWN);
137827ed8a0SDan Murphy
138827ed8a0SDan Murphy if (ret < 0)
139827ed8a0SDan Murphy return ret;
140827ed8a0SDan Murphy
141827ed8a0SDan Murphy if (tas2764->sdz_gpio)
142827ed8a0SDan Murphy gpiod_set_value_cansleep(tas2764->sdz_gpio, 0);
143827ed8a0SDan Murphy
144827ed8a0SDan Murphy regcache_cache_only(tas2764->regmap, true);
145827ed8a0SDan Murphy regcache_mark_dirty(tas2764->regmap);
146827ed8a0SDan Murphy
147827ed8a0SDan Murphy return 0;
148827ed8a0SDan Murphy }
149827ed8a0SDan Murphy
tas2764_codec_resume(struct snd_soc_component * component)150827ed8a0SDan Murphy static int tas2764_codec_resume(struct snd_soc_component *component)
151827ed8a0SDan Murphy {
152827ed8a0SDan Murphy struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
153827ed8a0SDan Murphy int ret;
154827ed8a0SDan Murphy
155cd10bb89SMartin Povišer if (tas2764->sdz_gpio) {
156827ed8a0SDan Murphy gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
157cd10bb89SMartin Povišer usleep_range(1000, 2000);
158cd10bb89SMartin Povišer }
159827ed8a0SDan Murphy
160f5ad67f1SMartin Povišer ret = tas2764_update_pwr_ctrl(tas2764);
161827ed8a0SDan Murphy
162827ed8a0SDan Murphy if (ret < 0)
163827ed8a0SDan Murphy return ret;
164827ed8a0SDan Murphy
165827ed8a0SDan Murphy regcache_cache_only(tas2764->regmap, false);
166827ed8a0SDan Murphy
167827ed8a0SDan Murphy return regcache_sync(tas2764->regmap);
168827ed8a0SDan Murphy }
169827ed8a0SDan Murphy #else
170827ed8a0SDan Murphy #define tas2764_codec_suspend NULL
171827ed8a0SDan Murphy #define tas2764_codec_resume NULL
172827ed8a0SDan Murphy #endif
173827ed8a0SDan Murphy
174827ed8a0SDan Murphy static const char * const tas2764_ASI1_src[] = {
175827ed8a0SDan Murphy "I2C offset", "Left", "Right", "LeftRightDiv2",
176827ed8a0SDan Murphy };
177827ed8a0SDan Murphy
178827ed8a0SDan Murphy static SOC_ENUM_SINGLE_DECL(
179d1a10f1bSMartin Povišer tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, TAS2764_TDM_CFG2_SCFG_SHIFT,
180d1a10f1bSMartin Povišer tas2764_ASI1_src);
181827ed8a0SDan Murphy
182827ed8a0SDan Murphy static const struct snd_kcontrol_new tas2764_asi1_mux =
183827ed8a0SDan Murphy SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum);
184827ed8a0SDan Murphy
tas2764_dac_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)185827ed8a0SDan Murphy static int tas2764_dac_event(struct snd_soc_dapm_widget *w,
186827ed8a0SDan Murphy struct snd_kcontrol *kcontrol, int event)
187827ed8a0SDan Murphy {
188827ed8a0SDan Murphy struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
189827ed8a0SDan Murphy struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
190827ed8a0SDan Murphy int ret;
191827ed8a0SDan Murphy
192827ed8a0SDan Murphy switch (event) {
193827ed8a0SDan Murphy case SND_SOC_DAPM_POST_PMU:
194f5ad67f1SMartin Povišer tas2764->dac_powered = true;
195f5ad67f1SMartin Povišer ret = tas2764_update_pwr_ctrl(tas2764);
196827ed8a0SDan Murphy break;
197827ed8a0SDan Murphy case SND_SOC_DAPM_PRE_PMD:
198f5ad67f1SMartin Povišer tas2764->dac_powered = false;
199f5ad67f1SMartin Povišer ret = tas2764_update_pwr_ctrl(tas2764);
200827ed8a0SDan Murphy break;
201827ed8a0SDan Murphy default:
202827ed8a0SDan Murphy dev_err(tas2764->dev, "Unsupported event\n");
203827ed8a0SDan Murphy return -EINVAL;
204827ed8a0SDan Murphy }
205827ed8a0SDan Murphy
206827ed8a0SDan Murphy if (ret < 0)
207827ed8a0SDan Murphy return ret;
208827ed8a0SDan Murphy
209827ed8a0SDan Murphy return 0;
210827ed8a0SDan Murphy }
211827ed8a0SDan Murphy
212827ed8a0SDan Murphy static const struct snd_kcontrol_new isense_switch =
213827ed8a0SDan Murphy SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN, 1, 1);
214827ed8a0SDan Murphy static const struct snd_kcontrol_new vsense_switch =
215827ed8a0SDan Murphy SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN, 1, 1);
216827ed8a0SDan Murphy
217827ed8a0SDan Murphy static const struct snd_soc_dapm_widget tas2764_dapm_widgets[] = {
218827ed8a0SDan Murphy SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
219827ed8a0SDan Murphy SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2764_asi1_mux),
220827ed8a0SDan Murphy SND_SOC_DAPM_SWITCH("ISENSE", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN,
221827ed8a0SDan Murphy 1, &isense_switch),
222827ed8a0SDan Murphy SND_SOC_DAPM_SWITCH("VSENSE", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN,
223827ed8a0SDan Murphy 1, &vsense_switch),
224827ed8a0SDan Murphy SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2764_dac_event,
225827ed8a0SDan Murphy SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
226827ed8a0SDan Murphy SND_SOC_DAPM_OUTPUT("OUT"),
227827ed8a0SDan Murphy SND_SOC_DAPM_SIGGEN("VMON"),
228827ed8a0SDan Murphy SND_SOC_DAPM_SIGGEN("IMON")
229827ed8a0SDan Murphy };
230827ed8a0SDan Murphy
231827ed8a0SDan Murphy static const struct snd_soc_dapm_route tas2764_audio_map[] = {
232827ed8a0SDan Murphy {"ASI1 Sel", "I2C offset", "ASI1"},
233827ed8a0SDan Murphy {"ASI1 Sel", "Left", "ASI1"},
234827ed8a0SDan Murphy {"ASI1 Sel", "Right", "ASI1"},
235827ed8a0SDan Murphy {"ASI1 Sel", "LeftRightDiv2", "ASI1"},
236827ed8a0SDan Murphy {"DAC", NULL, "ASI1 Sel"},
237827ed8a0SDan Murphy {"OUT", NULL, "DAC"},
238827ed8a0SDan Murphy {"ISENSE", "Switch", "IMON"},
239827ed8a0SDan Murphy {"VSENSE", "Switch", "VMON"},
240827ed8a0SDan Murphy };
241827ed8a0SDan Murphy
tas2764_mute(struct snd_soc_dai * dai,int mute,int direction)242827ed8a0SDan Murphy static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction)
243827ed8a0SDan Murphy {
244f5ad67f1SMartin Povišer struct tas2764_priv *tas2764 =
245f5ad67f1SMartin Povišer snd_soc_component_get_drvdata(dai->component);
246827ed8a0SDan Murphy
247f5ad67f1SMartin Povišer tas2764->unmuted = !mute;
248f5ad67f1SMartin Povišer return tas2764_update_pwr_ctrl(tas2764);
249827ed8a0SDan Murphy }
250827ed8a0SDan Murphy
tas2764_set_bitwidth(struct tas2764_priv * tas2764,int bitwidth)251827ed8a0SDan Murphy static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth)
252827ed8a0SDan Murphy {
253827ed8a0SDan Murphy struct snd_soc_component *component = tas2764->component;
254827ed8a0SDan Murphy int sense_en;
255827ed8a0SDan Murphy int val;
256827ed8a0SDan Murphy int ret;
257827ed8a0SDan Murphy
258827ed8a0SDan Murphy switch (bitwidth) {
259827ed8a0SDan Murphy case SNDRV_PCM_FORMAT_S16_LE:
260827ed8a0SDan Murphy ret = snd_soc_component_update_bits(component,
261827ed8a0SDan Murphy TAS2764_TDM_CFG2,
262827ed8a0SDan Murphy TAS2764_TDM_CFG2_RXW_MASK,
263827ed8a0SDan Murphy TAS2764_TDM_CFG2_RXW_16BITS);
264827ed8a0SDan Murphy break;
265827ed8a0SDan Murphy case SNDRV_PCM_FORMAT_S24_LE:
266827ed8a0SDan Murphy ret = snd_soc_component_update_bits(component,
267827ed8a0SDan Murphy TAS2764_TDM_CFG2,
268827ed8a0SDan Murphy TAS2764_TDM_CFG2_RXW_MASK,
269827ed8a0SDan Murphy TAS2764_TDM_CFG2_RXW_24BITS);
270827ed8a0SDan Murphy break;
271827ed8a0SDan Murphy case SNDRV_PCM_FORMAT_S32_LE:
272827ed8a0SDan Murphy ret = snd_soc_component_update_bits(component,
273827ed8a0SDan Murphy TAS2764_TDM_CFG2,
274827ed8a0SDan Murphy TAS2764_TDM_CFG2_RXW_MASK,
275827ed8a0SDan Murphy TAS2764_TDM_CFG2_RXW_32BITS);
276827ed8a0SDan Murphy break;
277827ed8a0SDan Murphy
278827ed8a0SDan Murphy default:
279827ed8a0SDan Murphy return -EINVAL;
280827ed8a0SDan Murphy }
281827ed8a0SDan Murphy
282827ed8a0SDan Murphy if (ret < 0)
283827ed8a0SDan Murphy return ret;
284827ed8a0SDan Murphy
285827ed8a0SDan Murphy val = snd_soc_component_read(tas2764->component, TAS2764_PWR_CTRL);
286827ed8a0SDan Murphy if (val < 0)
287827ed8a0SDan Murphy return val;
288827ed8a0SDan Murphy
289827ed8a0SDan Murphy if (val & (1 << TAS2764_VSENSE_POWER_EN))
290827ed8a0SDan Murphy sense_en = 0;
291827ed8a0SDan Murphy else
292827ed8a0SDan Murphy sense_en = TAS2764_TDM_CFG5_VSNS_ENABLE;
293827ed8a0SDan Murphy
294827ed8a0SDan Murphy ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5,
295827ed8a0SDan Murphy TAS2764_TDM_CFG5_VSNS_ENABLE,
296827ed8a0SDan Murphy sense_en);
297827ed8a0SDan Murphy if (ret < 0)
298827ed8a0SDan Murphy return ret;
299827ed8a0SDan Murphy
300827ed8a0SDan Murphy if (val & (1 << TAS2764_ISENSE_POWER_EN))
301827ed8a0SDan Murphy sense_en = 0;
302827ed8a0SDan Murphy else
303827ed8a0SDan Murphy sense_en = TAS2764_TDM_CFG6_ISNS_ENABLE;
304827ed8a0SDan Murphy
305827ed8a0SDan Murphy ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG6,
306827ed8a0SDan Murphy TAS2764_TDM_CFG6_ISNS_ENABLE,
307827ed8a0SDan Murphy sense_en);
308827ed8a0SDan Murphy if (ret < 0)
309827ed8a0SDan Murphy return ret;
310827ed8a0SDan Murphy
311827ed8a0SDan Murphy return 0;
312827ed8a0SDan Murphy }
313827ed8a0SDan Murphy
tas2764_set_samplerate(struct tas2764_priv * tas2764,int samplerate)314827ed8a0SDan Murphy static int tas2764_set_samplerate(struct tas2764_priv *tas2764, int samplerate)
315827ed8a0SDan Murphy {
316827ed8a0SDan Murphy struct snd_soc_component *component = tas2764->component;
317827ed8a0SDan Murphy int ramp_rate_val;
318827ed8a0SDan Murphy int ret;
319827ed8a0SDan Murphy
320827ed8a0SDan Murphy switch (samplerate) {
321827ed8a0SDan Murphy case 48000:
322827ed8a0SDan Murphy ramp_rate_val = TAS2764_TDM_CFG0_SMP_48KHZ |
323827ed8a0SDan Murphy TAS2764_TDM_CFG0_44_1_48KHZ;
324827ed8a0SDan Murphy break;
325827ed8a0SDan Murphy case 44100:
326827ed8a0SDan Murphy ramp_rate_val = TAS2764_TDM_CFG0_SMP_44_1KHZ |
327827ed8a0SDan Murphy TAS2764_TDM_CFG0_44_1_48KHZ;
328827ed8a0SDan Murphy break;
329827ed8a0SDan Murphy case 96000:
330827ed8a0SDan Murphy ramp_rate_val = TAS2764_TDM_CFG0_SMP_48KHZ |
331827ed8a0SDan Murphy TAS2764_TDM_CFG0_88_2_96KHZ;
332827ed8a0SDan Murphy break;
333827ed8a0SDan Murphy case 88200:
334827ed8a0SDan Murphy ramp_rate_val = TAS2764_TDM_CFG0_SMP_44_1KHZ |
335827ed8a0SDan Murphy TAS2764_TDM_CFG0_88_2_96KHZ;
336827ed8a0SDan Murphy break;
337827ed8a0SDan Murphy default:
338827ed8a0SDan Murphy return -EINVAL;
339827ed8a0SDan Murphy }
340827ed8a0SDan Murphy
341827ed8a0SDan Murphy ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0,
342827ed8a0SDan Murphy TAS2764_TDM_CFG0_SMP_MASK |
343827ed8a0SDan Murphy TAS2764_TDM_CFG0_MASK,
344827ed8a0SDan Murphy ramp_rate_val);
345827ed8a0SDan Murphy if (ret < 0)
346827ed8a0SDan Murphy return ret;
347827ed8a0SDan Murphy
348827ed8a0SDan Murphy return 0;
349827ed8a0SDan Murphy }
350827ed8a0SDan Murphy
tas2764_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)351827ed8a0SDan Murphy static int tas2764_hw_params(struct snd_pcm_substream *substream,
352827ed8a0SDan Murphy struct snd_pcm_hw_params *params,
353827ed8a0SDan Murphy struct snd_soc_dai *dai)
354827ed8a0SDan Murphy {
355827ed8a0SDan Murphy struct snd_soc_component *component = dai->component;
356827ed8a0SDan Murphy struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
357827ed8a0SDan Murphy int ret;
358827ed8a0SDan Murphy
359827ed8a0SDan Murphy ret = tas2764_set_bitwidth(tas2764, params_format(params));
360827ed8a0SDan Murphy if (ret < 0)
361827ed8a0SDan Murphy return ret;
362827ed8a0SDan Murphy
363827ed8a0SDan Murphy return tas2764_set_samplerate(tas2764, params_rate(params));
364827ed8a0SDan Murphy }
365827ed8a0SDan Murphy
tas2764_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)366827ed8a0SDan Murphy static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
367827ed8a0SDan Murphy {
368827ed8a0SDan Murphy struct snd_soc_component *component = dai->component;
369827ed8a0SDan Murphy struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
370*08ee4f87SHector Martin u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0, asi_cfg_4 = 0;
371827ed8a0SDan Murphy int ret;
372827ed8a0SDan Murphy
373827ed8a0SDan Murphy switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
374d1a10f1bSMartin Povišer case SND_SOC_DAIFMT_NB_IF:
375d1a10f1bSMartin Povišer asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
376d1a10f1bSMartin Povišer fallthrough;
377827ed8a0SDan Murphy case SND_SOC_DAIFMT_NB_NF:
378827ed8a0SDan Murphy asi_cfg_1 = TAS2764_TDM_CFG1_RX_RISING;
379*08ee4f87SHector Martin asi_cfg_4 = TAS2764_TDM_CFG4_TX_FALLING;
380827ed8a0SDan Murphy break;
381d1a10f1bSMartin Povišer case SND_SOC_DAIFMT_IB_IF:
382d1a10f1bSMartin Povišer asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
383d1a10f1bSMartin Povišer fallthrough;
384827ed8a0SDan Murphy case SND_SOC_DAIFMT_IB_NF:
385827ed8a0SDan Murphy asi_cfg_1 = TAS2764_TDM_CFG1_RX_FALLING;
386*08ee4f87SHector Martin asi_cfg_4 = TAS2764_TDM_CFG4_TX_RISING;
387827ed8a0SDan Murphy break;
388827ed8a0SDan Murphy }
389827ed8a0SDan Murphy
390827ed8a0SDan Murphy ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
391827ed8a0SDan Murphy TAS2764_TDM_CFG1_RX_MASK,
392827ed8a0SDan Murphy asi_cfg_1);
393827ed8a0SDan Murphy if (ret < 0)
394827ed8a0SDan Murphy return ret;
395827ed8a0SDan Murphy
396*08ee4f87SHector Martin ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG4,
397*08ee4f87SHector Martin TAS2764_TDM_CFG4_TX_MASK,
398*08ee4f87SHector Martin asi_cfg_4);
399*08ee4f87SHector Martin if (ret < 0)
400*08ee4f87SHector Martin return ret;
401*08ee4f87SHector Martin
402827ed8a0SDan Murphy switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
403827ed8a0SDan Murphy case SND_SOC_DAIFMT_I2S:
404d1a10f1bSMartin Povišer asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
405d1a10f1bSMartin Povišer fallthrough;
406827ed8a0SDan Murphy case SND_SOC_DAIFMT_DSP_A:
407827ed8a0SDan Murphy tdm_rx_start_slot = 1;
408827ed8a0SDan Murphy break;
409827ed8a0SDan Murphy case SND_SOC_DAIFMT_DSP_B:
410827ed8a0SDan Murphy case SND_SOC_DAIFMT_LEFT_J:
411827ed8a0SDan Murphy tdm_rx_start_slot = 0;
412827ed8a0SDan Murphy break;
413827ed8a0SDan Murphy default:
414827ed8a0SDan Murphy dev_err(tas2764->dev,
415827ed8a0SDan Murphy "DAI Format is not found, fmt=0x%x\n", fmt);
416827ed8a0SDan Murphy return -EINVAL;
417827ed8a0SDan Murphy }
418827ed8a0SDan Murphy
419d1a10f1bSMartin Povišer ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0,
420d1a10f1bSMartin Povišer TAS2764_TDM_CFG0_FRAME_START,
421d1a10f1bSMartin Povišer asi_cfg_0);
422827ed8a0SDan Murphy if (ret < 0)
423827ed8a0SDan Murphy return ret;
424827ed8a0SDan Murphy
425d1a10f1bSMartin Povišer ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
426d1a10f1bSMartin Povišer TAS2764_TDM_CFG1_MASK,
427d1a10f1bSMartin Povišer (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT));
428827ed8a0SDan Murphy if (ret < 0)
429827ed8a0SDan Murphy return ret;
430827ed8a0SDan Murphy
431827ed8a0SDan Murphy return 0;
432827ed8a0SDan Murphy }
433827ed8a0SDan Murphy
434827ed8a0SDan Murphy static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai,
435827ed8a0SDan Murphy unsigned int tx_mask,
436827ed8a0SDan Murphy unsigned int rx_mask,
437827ed8a0SDan Murphy int slots, int slot_width)
438827ed8a0SDan Murphy {
439827ed8a0SDan Murphy struct snd_soc_component *component = dai->component;
440827ed8a0SDan Murphy struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
441827ed8a0SDan Murphy int left_slot, right_slot;
442827ed8a0SDan Murphy int slots_cfg;
443827ed8a0SDan Murphy int slot_size;
444827ed8a0SDan Murphy int ret;
445827ed8a0SDan Murphy
446827ed8a0SDan Murphy if (tx_mask == 0 || rx_mask != 0)
447827ed8a0SDan Murphy return -EINVAL;
448827ed8a0SDan Murphy
449827ed8a0SDan Murphy left_slot = __ffs(tx_mask);
450827ed8a0SDan Murphy tx_mask &= ~(1 << left_slot);
451827ed8a0SDan Murphy if (tx_mask == 0) {
452827ed8a0SDan Murphy right_slot = left_slot;
453827ed8a0SDan Murphy } else {
454827ed8a0SDan Murphy right_slot = __ffs(tx_mask);
455827ed8a0SDan Murphy tx_mask &= ~(1 << right_slot);
456827ed8a0SDan Murphy }
457827ed8a0SDan Murphy
458827ed8a0SDan Murphy if (tx_mask != 0 || left_slot >= slots || right_slot >= slots)
459827ed8a0SDan Murphy return -EINVAL;
460827ed8a0SDan Murphy
461827ed8a0SDan Murphy slots_cfg = (right_slot << TAS2764_TDM_CFG3_RXS_SHIFT) | left_slot;
462827ed8a0SDan Murphy
463827ed8a0SDan Murphy ret = snd_soc_component_write(component, TAS2764_TDM_CFG3, slots_cfg);
464827ed8a0SDan Murphy if (ret)
465827ed8a0SDan Murphy return ret;
466827ed8a0SDan Murphy
467827ed8a0SDan Murphy switch (slot_width) {
468827ed8a0SDan Murphy case 16:
469827ed8a0SDan Murphy slot_size = TAS2764_TDM_CFG2_RXS_16BITS;
470827ed8a0SDan Murphy break;
471827ed8a0SDan Murphy case 24:
472827ed8a0SDan Murphy slot_size = TAS2764_TDM_CFG2_RXS_24BITS;
473827ed8a0SDan Murphy break;
474827ed8a0SDan Murphy case 32:
475827ed8a0SDan Murphy slot_size = TAS2764_TDM_CFG2_RXS_32BITS;
476827ed8a0SDan Murphy break;
477827ed8a0SDan Murphy default:
478827ed8a0SDan Murphy return -EINVAL;
479827ed8a0SDan Murphy }
480827ed8a0SDan Murphy
481827ed8a0SDan Murphy ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG2,
482827ed8a0SDan Murphy TAS2764_TDM_CFG2_RXS_MASK,
483827ed8a0SDan Murphy slot_size);
484827ed8a0SDan Murphy if (ret < 0)
485827ed8a0SDan Murphy return ret;
486827ed8a0SDan Murphy
487827ed8a0SDan Murphy ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG5,
488827ed8a0SDan Murphy TAS2764_TDM_CFG5_50_MASK,
489827ed8a0SDan Murphy tas2764->v_sense_slot);
490827ed8a0SDan Murphy if (ret < 0)
491827ed8a0SDan Murphy return ret;
492827ed8a0SDan Murphy
493827ed8a0SDan Murphy ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG6,
494827ed8a0SDan Murphy TAS2764_TDM_CFG6_50_MASK,
495827ed8a0SDan Murphy tas2764->i_sense_slot);
496827ed8a0SDan Murphy if (ret < 0)
497827ed8a0SDan Murphy return ret;
498827ed8a0SDan Murphy
499827ed8a0SDan Murphy return 0;
500827ed8a0SDan Murphy }
501827ed8a0SDan Murphy
502b186e7c1SYe Bin static const struct snd_soc_dai_ops tas2764_dai_ops = {
503827ed8a0SDan Murphy .mute_stream = tas2764_mute,
504827ed8a0SDan Murphy .hw_params = tas2764_hw_params,
505827ed8a0SDan Murphy .set_fmt = tas2764_set_fmt,
506827ed8a0SDan Murphy .set_tdm_slot = tas2764_set_dai_tdm_slot,
507827ed8a0SDan Murphy .no_capture_mute = 1,
508827ed8a0SDan Murphy };
509827ed8a0SDan Murphy
510827ed8a0SDan Murphy #define TAS2764_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
511827ed8a0SDan Murphy SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
512827ed8a0SDan Murphy
513827ed8a0SDan Murphy #define TAS2764_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
514827ed8a0SDan Murphy SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200)
515827ed8a0SDan Murphy
516827ed8a0SDan Murphy static struct snd_soc_dai_driver tas2764_dai_driver[] = {
517827ed8a0SDan Murphy {
518827ed8a0SDan Murphy .name = "tas2764 ASI1",
519827ed8a0SDan Murphy .id = 0,
520827ed8a0SDan Murphy .playback = {
521827ed8a0SDan Murphy .stream_name = "ASI1 Playback",
52223204d92SMartin Povišer .channels_min = 1,
523827ed8a0SDan Murphy .channels_max = 2,
524827ed8a0SDan Murphy .rates = TAS2764_RATES,
525827ed8a0SDan Murphy .formats = TAS2764_FORMATS,
526827ed8a0SDan Murphy },
527827ed8a0SDan Murphy .capture = {
528827ed8a0SDan Murphy .stream_name = "ASI1 Capture",
529827ed8a0SDan Murphy .channels_min = 0,
530827ed8a0SDan Murphy .channels_max = 2,
tas2764_codec_probe(struct snd_soc_component * component)531827ed8a0SDan Murphy .rates = TAS2764_RATES,
532827ed8a0SDan Murphy .formats = TAS2764_FORMATS,
533827ed8a0SDan Murphy },
534827ed8a0SDan Murphy .ops = &tas2764_dai_ops,
535fa056c07SKuninori Morimoto .symmetric_rate = 1,
536827ed8a0SDan Murphy },
537827ed8a0SDan Murphy };
538827ed8a0SDan Murphy
539827ed8a0SDan Murphy static int tas2764_codec_probe(struct snd_soc_component *component)
540827ed8a0SDan Murphy {
541827ed8a0SDan Murphy struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
542827ed8a0SDan Murphy int ret;
543827ed8a0SDan Murphy
544827ed8a0SDan Murphy tas2764->component = component;
545827ed8a0SDan Murphy
546cd10bb89SMartin Povišer if (tas2764->sdz_gpio) {
547827ed8a0SDan Murphy gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
548cd10bb89SMartin Povišer usleep_range(1000, 2000);
549cd10bb89SMartin Povišer }
550827ed8a0SDan Murphy
551827ed8a0SDan Murphy tas2764_reset(tas2764);
552827ed8a0SDan Murphy
553dae191fbSMartin Povišer if (tas2764->irq) {
554dae191fbSMartin Povišer ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK0, 0xff);
555dae191fbSMartin Povišer if (ret < 0)
556dae191fbSMartin Povišer return ret;
557dae191fbSMartin Povišer
558dae191fbSMartin Povišer ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK1, 0xff);
559dae191fbSMartin Povišer if (ret < 0)
560dae191fbSMartin Povišer return ret;
561dae191fbSMartin Povišer
562dae191fbSMartin Povišer ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK2, 0xff);
563dae191fbSMartin Povišer if (ret < 0)
564dae191fbSMartin Povišer return ret;
565dae191fbSMartin Povišer
566dae191fbSMartin Povišer ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK3, 0xff);
567dae191fbSMartin Povišer if (ret < 0)
568dae191fbSMartin Povišer return ret;
569dae191fbSMartin Povišer
570dae191fbSMartin Povišer ret = snd_soc_component_write(tas2764->component, TAS2764_INT_MASK4, 0xff);
571dae191fbSMartin Povišer if (ret < 0)
572dae191fbSMartin Povišer return ret;
573dae191fbSMartin Povišer
574dae191fbSMartin Povišer ret = devm_request_threaded_irq(tas2764->dev, tas2764->irq, NULL, tas2764_irq,
575dae191fbSMartin Povišer IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
576dae191fbSMartin Povišer "tas2764", tas2764);
577dae191fbSMartin Povišer if (ret)
578dae191fbSMartin Povišer dev_warn(tas2764->dev, "failed to request IRQ: %d\n", ret);
579dae191fbSMartin Povišer }
580dae191fbSMartin Povišer
581827ed8a0SDan Murphy ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5,
582827ed8a0SDan Murphy TAS2764_TDM_CFG5_VSNS_ENABLE, 0);
583827ed8a0SDan Murphy if (ret < 0)
584827ed8a0SDan Murphy return ret;
585827ed8a0SDan Murphy
586827ed8a0SDan Murphy ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG6,
587827ed8a0SDan Murphy TAS2764_TDM_CFG6_ISNS_ENABLE, 0);
588827ed8a0SDan Murphy if (ret < 0)
589827ed8a0SDan Murphy return ret;
590827ed8a0SDan Murphy
591827ed8a0SDan Murphy return 0;
592827ed8a0SDan Murphy }
593827ed8a0SDan Murphy
594827ed8a0SDan Murphy static DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0);
5953e99e569SHector Martin static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10050, 50, 1);
596827ed8a0SDan Murphy
597aca86ec9SMartin Povišer static const char * const tas2764_hpf_texts[] = {
598aca86ec9SMartin Povišer "Disabled", "2 Hz", "50 Hz", "100 Hz", "200 Hz",
599aca86ec9SMartin Povišer "400 Hz", "800 Hz"
600aca86ec9SMartin Povišer };
601aca86ec9SMartin Povišer
602aca86ec9SMartin Povišer static SOC_ENUM_SINGLE_DECL(
603aca86ec9SMartin Povišer tas2764_hpf_enum, TAS2764_DC_BLK0,
604aca86ec9SMartin Povišer TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT, tas2764_hpf_texts);
605aca86ec9SMartin Povišer
606827ed8a0SDan Murphy static const struct snd_kcontrol_new tas2764_snd_controls[] = {
607827ed8a0SDan Murphy SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0,
608827ed8a0SDan Murphy TAS2764_DVC_MAX, 1, tas2764_playback_volume),
6091c4f29ecSHector Martin SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0,
610827ed8a0SDan Murphy tas2764_digital_tlv),
611aca86ec9SMartin Povišer SOC_ENUM("HPF Corner Frequency", tas2764_hpf_enum),
612827ed8a0SDan Murphy };
613827ed8a0SDan Murphy
614827ed8a0SDan Murphy static const struct snd_soc_component_driver soc_component_driver_tas2764 = {
615827ed8a0SDan Murphy .probe = tas2764_codec_probe,
616827ed8a0SDan Murphy .suspend = tas2764_codec_suspend,
617827ed8a0SDan Murphy .resume = tas2764_codec_resume,
618827ed8a0SDan Murphy .controls = tas2764_snd_controls,
619827ed8a0SDan Murphy .num_controls = ARRAY_SIZE(tas2764_snd_controls),
620827ed8a0SDan Murphy .dapm_widgets = tas2764_dapm_widgets,
621827ed8a0SDan Murphy .num_dapm_widgets = ARRAY_SIZE(tas2764_dapm_widgets),
622827ed8a0SDan Murphy .dapm_routes = tas2764_audio_map,
623827ed8a0SDan Murphy .num_dapm_routes = ARRAY_SIZE(tas2764_audio_map),
624827ed8a0SDan Murphy .idle_bias_on = 1,
625827ed8a0SDan Murphy .endianness = 1,
626827ed8a0SDan Murphy };
627827ed8a0SDan Murphy
628827ed8a0SDan Murphy static const struct reg_default tas2764_reg_defaults[] = {
629827ed8a0SDan Murphy { TAS2764_PAGE, 0x00 },
630827ed8a0SDan Murphy { TAS2764_SW_RST, 0x00 },
631827ed8a0SDan Murphy { TAS2764_PWR_CTRL, 0x1a },
632827ed8a0SDan Murphy { TAS2764_DVC, 0x00 },
6331c4f29ecSHector Martin { TAS2764_CHNL_0, 0x28 },
634827ed8a0SDan Murphy { TAS2764_TDM_CFG0, 0x09 },
635827ed8a0SDan Murphy { TAS2764_TDM_CFG1, 0x02 },
636827ed8a0SDan Murphy { TAS2764_TDM_CFG2, 0x0a },
637827ed8a0SDan Murphy { TAS2764_TDM_CFG3, 0x10 },
638827ed8a0SDan Murphy { TAS2764_TDM_CFG5, 0x42 },
639827ed8a0SDan Murphy };
640827ed8a0SDan Murphy
641827ed8a0SDan Murphy static const struct regmap_range_cfg tas2764_regmap_ranges[] = {
642827ed8a0SDan Murphy {
643827ed8a0SDan Murphy .range_min = 0,
644827ed8a0SDan Murphy .range_max = 1 * 128,
tas2764_volatile_register(struct device * dev,unsigned int reg)645827ed8a0SDan Murphy .selector_reg = TAS2764_PAGE,
646827ed8a0SDan Murphy .selector_mask = 0xff,
647827ed8a0SDan Murphy .selector_shift = 0,
648827ed8a0SDan Murphy .window_start = 0,
649827ed8a0SDan Murphy .window_len = 128,
650827ed8a0SDan Murphy },
651827ed8a0SDan Murphy };
652827ed8a0SDan Murphy
653dae191fbSMartin Povišer static bool tas2764_volatile_register(struct device *dev, unsigned int reg)
654dae191fbSMartin Povišer {
655dae191fbSMartin Povišer switch (reg) {
656dae191fbSMartin Povišer case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4:
657dae191fbSMartin Povišer case TAS2764_INT_CLK_CFG:
658dae191fbSMartin Povišer return true;
659dae191fbSMartin Povišer default:
660dae191fbSMartin Povišer return false;
661dae191fbSMartin Povišer }
662dae191fbSMartin Povišer }
663dae191fbSMartin Povišer
664827ed8a0SDan Murphy static const struct regmap_config tas2764_i2c_regmap = {
665827ed8a0SDan Murphy .reg_bits = 8,
666827ed8a0SDan Murphy .val_bits = 8,
667dae191fbSMartin Povišer .volatile_reg = tas2764_volatile_register,
tas2764_parse_dt(struct device * dev,struct tas2764_priv * tas2764)668827ed8a0SDan Murphy .reg_defaults = tas2764_reg_defaults,
669827ed8a0SDan Murphy .num_reg_defaults = ARRAY_SIZE(tas2764_reg_defaults),
670827ed8a0SDan Murphy .cache_type = REGCACHE_RBTREE,
671827ed8a0SDan Murphy .ranges = tas2764_regmap_ranges,
672827ed8a0SDan Murphy .num_ranges = ARRAY_SIZE(tas2764_regmap_ranges),
673827ed8a0SDan Murphy .max_register = 1 * 128,
674827ed8a0SDan Murphy };
675827ed8a0SDan Murphy
676827ed8a0SDan Murphy static int tas2764_parse_dt(struct device *dev, struct tas2764_priv *tas2764)
677827ed8a0SDan Murphy {
678827ed8a0SDan Murphy int ret = 0;
679827ed8a0SDan Murphy
680827ed8a0SDan Murphy tas2764->reset_gpio = devm_gpiod_get_optional(tas2764->dev, "reset",
681827ed8a0SDan Murphy GPIOD_OUT_HIGH);
682827ed8a0SDan Murphy if (IS_ERR(tas2764->reset_gpio)) {
683827ed8a0SDan Murphy if (PTR_ERR(tas2764->reset_gpio) == -EPROBE_DEFER) {
684827ed8a0SDan Murphy tas2764->reset_gpio = NULL;
685827ed8a0SDan Murphy return -EPROBE_DEFER;
686827ed8a0SDan Murphy }
687827ed8a0SDan Murphy }
688827ed8a0SDan Murphy
689827ed8a0SDan Murphy tas2764->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
690827ed8a0SDan Murphy if (IS_ERR(tas2764->sdz_gpio)) {
691827ed8a0SDan Murphy if (PTR_ERR(tas2764->sdz_gpio) == -EPROBE_DEFER)
692827ed8a0SDan Murphy return -EPROBE_DEFER;
693827ed8a0SDan Murphy
694827ed8a0SDan Murphy tas2764->sdz_gpio = NULL;
695827ed8a0SDan Murphy }
696827ed8a0SDan Murphy
697827ed8a0SDan Murphy ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no",
698827ed8a0SDan Murphy &tas2764->i_sense_slot);
699827ed8a0SDan Murphy if (ret)
700827ed8a0SDan Murphy tas2764->i_sense_slot = 0;
701827ed8a0SDan Murphy
tas2764_i2c_probe(struct i2c_client * client)702827ed8a0SDan Murphy ret = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no",
703827ed8a0SDan Murphy &tas2764->v_sense_slot);
704827ed8a0SDan Murphy if (ret)
705827ed8a0SDan Murphy tas2764->v_sense_slot = 2;
706827ed8a0SDan Murphy
707827ed8a0SDan Murphy return 0;
708827ed8a0SDan Murphy }
709827ed8a0SDan Murphy
710ad11678fSStephen Kitt static int tas2764_i2c_probe(struct i2c_client *client)
711827ed8a0SDan Murphy {
712827ed8a0SDan Murphy struct tas2764_priv *tas2764;
713827ed8a0SDan Murphy int result;
714827ed8a0SDan Murphy
715827ed8a0SDan Murphy tas2764 = devm_kzalloc(&client->dev, sizeof(struct tas2764_priv),
716827ed8a0SDan Murphy GFP_KERNEL);
717827ed8a0SDan Murphy if (!tas2764)
718827ed8a0SDan Murphy return -ENOMEM;
719827ed8a0SDan Murphy
720827ed8a0SDan Murphy tas2764->dev = &client->dev;
721dae191fbSMartin Povišer tas2764->irq = client->irq;
722827ed8a0SDan Murphy i2c_set_clientdata(client, tas2764);
723827ed8a0SDan Murphy dev_set_drvdata(&client->dev, tas2764);
724827ed8a0SDan Murphy
725827ed8a0SDan Murphy tas2764->regmap = devm_regmap_init_i2c(client, &tas2764_i2c_regmap);
726827ed8a0SDan Murphy if (IS_ERR(tas2764->regmap)) {
727827ed8a0SDan Murphy result = PTR_ERR(tas2764->regmap);
728827ed8a0SDan Murphy dev_err(&client->dev, "Failed to allocate register map: %d\n",
729827ed8a0SDan Murphy result);
730827ed8a0SDan Murphy return result;
731827ed8a0SDan Murphy }
732827ed8a0SDan Murphy
733827ed8a0SDan Murphy if (client->dev.of_node) {
734827ed8a0SDan Murphy result = tas2764_parse_dt(&client->dev, tas2764);
735827ed8a0SDan Murphy if (result) {
736827ed8a0SDan Murphy dev_err(tas2764->dev, "%s: Failed to parse devicetree\n",
737827ed8a0SDan Murphy __func__);
738827ed8a0SDan Murphy return result;
739827ed8a0SDan Murphy }
740827ed8a0SDan Murphy }
741827ed8a0SDan Murphy
742827ed8a0SDan Murphy return devm_snd_soc_register_component(tas2764->dev,
743827ed8a0SDan Murphy &soc_component_driver_tas2764,
744827ed8a0SDan Murphy tas2764_dai_driver,
745827ed8a0SDan Murphy ARRAY_SIZE(tas2764_dai_driver));
746827ed8a0SDan Murphy }
747827ed8a0SDan Murphy
748827ed8a0SDan Murphy static const struct i2c_device_id tas2764_i2c_id[] = {
749827ed8a0SDan Murphy { "tas2764", 0},
750827ed8a0SDan Murphy { }
751827ed8a0SDan Murphy };
752827ed8a0SDan Murphy MODULE_DEVICE_TABLE(i2c, tas2764_i2c_id);
753827ed8a0SDan Murphy
754827ed8a0SDan Murphy #if defined(CONFIG_OF)
755827ed8a0SDan Murphy static const struct of_device_id tas2764_of_match[] = {
756827ed8a0SDan Murphy { .compatible = "ti,tas2764" },
757827ed8a0SDan Murphy {},
758827ed8a0SDan Murphy };
759827ed8a0SDan Murphy MODULE_DEVICE_TABLE(of, tas2764_of_match);
760827ed8a0SDan Murphy #endif
761827ed8a0SDan Murphy
762827ed8a0SDan Murphy static struct i2c_driver tas2764_i2c_driver = {
763827ed8a0SDan Murphy .driver = {
764827ed8a0SDan Murphy .name = "tas2764",
765827ed8a0SDan Murphy .of_match_table = of_match_ptr(tas2764_of_match),
766827ed8a0SDan Murphy },
7679abcd240SUwe Kleine-König .probe = tas2764_i2c_probe,
768827ed8a0SDan Murphy .id_table = tas2764_i2c_id,
769827ed8a0SDan Murphy };
770827ed8a0SDan Murphy module_i2c_driver(tas2764_i2c_driver);
771827ed8a0SDan Murphy
772827ed8a0SDan Murphy MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
773827ed8a0SDan Murphy MODULE_DESCRIPTION("TAS2764 I2C Smart Amplifier driver");
774827ed8a0SDan Murphy MODULE_LICENSE("GPL v2");
775