• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Driver for the Texas Instruments TAS2764 CODEC
4 // Copyright (C) 2020 Texas Instruments Inc.
5 
6 #include <linux/module.h>
7 #include <linux/moduleparam.h>
8 #include <linux/err.h>
9 #include <linux/init.h>
10 #include <linux/delay.h>
11 #include <linux/pm.h>
12 #include <linux/i2c.h>
13 #include <linux/gpio.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/regulator/consumer.h>
16 #include <linux/regmap.h>
17 #include <linux/of.h>
18 #include <linux/of_gpio.h>
19 #include <linux/slab.h>
20 #include <sound/soc.h>
21 #include <sound/pcm.h>
22 #include <sound/pcm_params.h>
23 #include <sound/initval.h>
24 #include <sound/tlv.h>
25 
26 #include "tas2764.h"
27 
28 struct tas2764_priv {
29 	struct snd_soc_component *component;
30 	struct gpio_desc *reset_gpio;
31 	struct gpio_desc *sdz_gpio;
32 	struct regmap *regmap;
33 	struct device *dev;
34 
35 	int v_sense_slot;
36 	int i_sense_slot;
37 
38 	bool dac_powered;
39 	bool unmuted;
40 };
41 
tas2764_reset(struct tas2764_priv * tas2764)42 static void tas2764_reset(struct tas2764_priv *tas2764)
43 {
44 	if (tas2764->reset_gpio) {
45 		gpiod_set_value_cansleep(tas2764->reset_gpio, 0);
46 		msleep(20);
47 		gpiod_set_value_cansleep(tas2764->reset_gpio, 1);
48 		usleep_range(1000, 2000);
49 	}
50 
51 	snd_soc_component_write(tas2764->component, TAS2764_SW_RST,
52 				TAS2764_RST);
53 	usleep_range(1000, 2000);
54 }
55 
tas2764_update_pwr_ctrl(struct tas2764_priv * tas2764)56 static int tas2764_update_pwr_ctrl(struct tas2764_priv *tas2764)
57 {
58 	struct snd_soc_component *component = tas2764->component;
59 	unsigned int val;
60 	int ret;
61 
62 	if (tas2764->dac_powered)
63 		val = tas2764->unmuted ?
64 			TAS2764_PWR_CTRL_ACTIVE : TAS2764_PWR_CTRL_MUTE;
65 	else
66 		val = TAS2764_PWR_CTRL_SHUTDOWN;
67 
68 	ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
69 					    TAS2764_PWR_CTRL_MASK, val);
70 	if (ret < 0)
71 		return ret;
72 
73 	return 0;
74 }
75 
76 #ifdef CONFIG_PM
tas2764_codec_suspend(struct snd_soc_component * component)77 static int tas2764_codec_suspend(struct snd_soc_component *component)
78 {
79 	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
80 	int ret;
81 
82 	ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
83 					    TAS2764_PWR_CTRL_MASK,
84 					    TAS2764_PWR_CTRL_SHUTDOWN);
85 
86 	if (ret < 0)
87 		return ret;
88 
89 	if (tas2764->sdz_gpio)
90 		gpiod_set_value_cansleep(tas2764->sdz_gpio, 0);
91 
92 	regcache_cache_only(tas2764->regmap, true);
93 	regcache_mark_dirty(tas2764->regmap);
94 
95 	return 0;
96 }
97 
tas2764_codec_resume(struct snd_soc_component * component)98 static int tas2764_codec_resume(struct snd_soc_component *component)
99 {
100 	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
101 	int ret;
102 
103 	if (tas2764->sdz_gpio) {
104 		gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
105 		usleep_range(1000, 2000);
106 	}
107 
108 	ret = tas2764_update_pwr_ctrl(tas2764);
109 
110 	if (ret < 0)
111 		return ret;
112 
113 	regcache_cache_only(tas2764->regmap, false);
114 
115 	return regcache_sync(tas2764->regmap);
116 }
117 #else
118 #define tas2764_codec_suspend NULL
119 #define tas2764_codec_resume NULL
120 #endif
121 
122 static const char * const tas2764_ASI1_src[] = {
123 	"I2C offset", "Left", "Right", "LeftRightDiv2",
124 };
125 
126 static SOC_ENUM_SINGLE_DECL(
127 	tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, TAS2764_TDM_CFG2_SCFG_SHIFT,
128 	tas2764_ASI1_src);
129 
130 static const struct snd_kcontrol_new tas2764_asi1_mux =
131 	SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum);
132 
tas2764_dac_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)133 static int tas2764_dac_event(struct snd_soc_dapm_widget *w,
134 			     struct snd_kcontrol *kcontrol, int event)
135 {
136 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
137 	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
138 	int ret;
139 
140 	switch (event) {
141 	case SND_SOC_DAPM_POST_PMU:
142 		tas2764->dac_powered = true;
143 		ret = tas2764_update_pwr_ctrl(tas2764);
144 		break;
145 	case SND_SOC_DAPM_PRE_PMD:
146 		tas2764->dac_powered = false;
147 		ret = tas2764_update_pwr_ctrl(tas2764);
148 		break;
149 	default:
150 		dev_err(tas2764->dev, "Unsupported event\n");
151 		return -EINVAL;
152 	}
153 
154 	if (ret < 0)
155 		return ret;
156 
157 	return 0;
158 }
159 
160 static const struct snd_kcontrol_new isense_switch =
161 	SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN, 1, 1);
162 static const struct snd_kcontrol_new vsense_switch =
163 	SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN, 1, 1);
164 
165 static const struct snd_soc_dapm_widget tas2764_dapm_widgets[] = {
166 	SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
167 	SND_SOC_DAPM_MUX("ASI1 Sel", SND_SOC_NOPM, 0, 0, &tas2764_asi1_mux),
168 	SND_SOC_DAPM_SWITCH("ISENSE", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN,
169 			    1, &isense_switch),
170 	SND_SOC_DAPM_SWITCH("VSENSE", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN,
171 			    1, &vsense_switch),
172 	SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2764_dac_event,
173 			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
174 	SND_SOC_DAPM_OUTPUT("OUT"),
175 	SND_SOC_DAPM_SIGGEN("VMON"),
176 	SND_SOC_DAPM_SIGGEN("IMON")
177 };
178 
179 static const struct snd_soc_dapm_route tas2764_audio_map[] = {
180 	{"ASI1 Sel", "I2C offset", "ASI1"},
181 	{"ASI1 Sel", "Left", "ASI1"},
182 	{"ASI1 Sel", "Right", "ASI1"},
183 	{"ASI1 Sel", "LeftRightDiv2", "ASI1"},
184 	{"DAC", NULL, "ASI1 Sel"},
185 	{"OUT", NULL, "DAC"},
186 	{"ISENSE", "Switch", "IMON"},
187 	{"VSENSE", "Switch", "VMON"},
188 };
189 
tas2764_mute(struct snd_soc_dai * dai,int mute,int direction)190 static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction)
191 {
192 	struct tas2764_priv *tas2764 =
193 			snd_soc_component_get_drvdata(dai->component);
194 
195 	tas2764->unmuted = !mute;
196 	return tas2764_update_pwr_ctrl(tas2764);
197 }
198 
tas2764_set_bitwidth(struct tas2764_priv * tas2764,int bitwidth)199 static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth)
200 {
201 	struct snd_soc_component *component = tas2764->component;
202 	int sense_en;
203 	int val;
204 	int ret;
205 
206 	switch (bitwidth) {
207 	case SNDRV_PCM_FORMAT_S16_LE:
208 		ret = snd_soc_component_update_bits(component,
209 						    TAS2764_TDM_CFG2,
210 						    TAS2764_TDM_CFG2_RXW_MASK,
211 						    TAS2764_TDM_CFG2_RXW_16BITS);
212 		break;
213 	case SNDRV_PCM_FORMAT_S24_LE:
214 		ret = snd_soc_component_update_bits(component,
215 						    TAS2764_TDM_CFG2,
216 						    TAS2764_TDM_CFG2_RXW_MASK,
217 						    TAS2764_TDM_CFG2_RXW_24BITS);
218 		break;
219 	case SNDRV_PCM_FORMAT_S32_LE:
220 		ret = snd_soc_component_update_bits(component,
221 						    TAS2764_TDM_CFG2,
222 						    TAS2764_TDM_CFG2_RXW_MASK,
223 						    TAS2764_TDM_CFG2_RXW_32BITS);
224 		break;
225 
226 	default:
227 		return -EINVAL;
228 	}
229 
230 	if (ret < 0)
231 		return ret;
232 
233 	val = snd_soc_component_read(tas2764->component, TAS2764_PWR_CTRL);
234 	if (val < 0)
235 		return val;
236 
237 	if (val & (1 << TAS2764_VSENSE_POWER_EN))
238 		sense_en = 0;
239 	else
240 		sense_en = TAS2764_TDM_CFG5_VSNS_ENABLE;
241 
242 	ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5,
243 					    TAS2764_TDM_CFG5_VSNS_ENABLE,
244 					    sense_en);
245 	if (ret < 0)
246 		return ret;
247 
248 	if (val & (1 << TAS2764_ISENSE_POWER_EN))
249 		sense_en = 0;
250 	else
251 		sense_en = TAS2764_TDM_CFG6_ISNS_ENABLE;
252 
253 	ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG6,
254 					    TAS2764_TDM_CFG6_ISNS_ENABLE,
255 					    sense_en);
256 	if (ret < 0)
257 		return ret;
258 
259 	return 0;
260 }
261 
tas2764_set_samplerate(struct tas2764_priv * tas2764,int samplerate)262 static int tas2764_set_samplerate(struct tas2764_priv *tas2764, int samplerate)
263 {
264 	struct snd_soc_component *component = tas2764->component;
265 	int ramp_rate_val;
266 	int ret;
267 
268 	switch (samplerate) {
269 	case 48000:
270 		ramp_rate_val = TAS2764_TDM_CFG0_SMP_48KHZ |
271 				TAS2764_TDM_CFG0_44_1_48KHZ;
272 		break;
273 	case 44100:
274 		ramp_rate_val = TAS2764_TDM_CFG0_SMP_44_1KHZ |
275 				TAS2764_TDM_CFG0_44_1_48KHZ;
276 		break;
277 	case 96000:
278 		ramp_rate_val = TAS2764_TDM_CFG0_SMP_48KHZ |
279 				TAS2764_TDM_CFG0_88_2_96KHZ;
280 		break;
281 	case 88200:
282 		ramp_rate_val = TAS2764_TDM_CFG0_SMP_44_1KHZ |
283 				TAS2764_TDM_CFG0_88_2_96KHZ;
284 		break;
285 	default:
286 		return -EINVAL;
287 	}
288 
289 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0,
290 					    TAS2764_TDM_CFG0_SMP_MASK |
291 					    TAS2764_TDM_CFG0_MASK,
292 					    ramp_rate_val);
293 	if (ret < 0)
294 		return ret;
295 
296 	return 0;
297 }
298 
tas2764_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)299 static int tas2764_hw_params(struct snd_pcm_substream *substream,
300 			     struct snd_pcm_hw_params *params,
301 			     struct snd_soc_dai *dai)
302 {
303 	struct snd_soc_component *component = dai->component;
304 	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
305 	int ret;
306 
307 	ret = tas2764_set_bitwidth(tas2764, params_format(params));
308 	if (ret < 0)
309 		return ret;
310 
311 	return tas2764_set_samplerate(tas2764, params_rate(params));
312 }
313 
tas2764_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)314 static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
315 {
316 	struct snd_soc_component *component = dai->component;
317 	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
318 	u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0;
319 	int ret;
320 
321 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
322 	case SND_SOC_DAIFMT_NB_IF:
323 		asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
324 		fallthrough;
325 	case SND_SOC_DAIFMT_NB_NF:
326 		asi_cfg_1 = TAS2764_TDM_CFG1_RX_RISING;
327 		break;
328 	case SND_SOC_DAIFMT_IB_IF:
329 		asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
330 		fallthrough;
331 	case SND_SOC_DAIFMT_IB_NF:
332 		asi_cfg_1 = TAS2764_TDM_CFG1_RX_FALLING;
333 		break;
334 	}
335 
336 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
337 					    TAS2764_TDM_CFG1_RX_MASK,
338 					    asi_cfg_1);
339 	if (ret < 0)
340 		return ret;
341 
342 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
343 	case SND_SOC_DAIFMT_I2S:
344 		asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
345 		fallthrough;
346 	case SND_SOC_DAIFMT_DSP_A:
347 		tdm_rx_start_slot = 1;
348 		break;
349 	case SND_SOC_DAIFMT_DSP_B:
350 	case SND_SOC_DAIFMT_LEFT_J:
351 		tdm_rx_start_slot = 0;
352 		break;
353 	default:
354 		dev_err(tas2764->dev,
355 			"DAI Format is not found, fmt=0x%x\n", fmt);
356 		return -EINVAL;
357 	}
358 
359 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0,
360 					    TAS2764_TDM_CFG0_FRAME_START,
361 					    asi_cfg_0);
362 	if (ret < 0)
363 		return ret;
364 
365 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
366 					    TAS2764_TDM_CFG1_MASK,
367 					    (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT));
368 	if (ret < 0)
369 		return ret;
370 
371 	return 0;
372 }
373 
tas2764_set_dai_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)374 static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai,
375 				unsigned int tx_mask,
376 				unsigned int rx_mask,
377 				int slots, int slot_width)
378 {
379 	struct snd_soc_component *component = dai->component;
380 	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
381 	int left_slot, right_slot;
382 	int slots_cfg;
383 	int slot_size;
384 	int ret;
385 
386 	if (tx_mask == 0 || rx_mask != 0)
387 		return -EINVAL;
388 
389 	left_slot = __ffs(tx_mask);
390 	tx_mask &= ~(1 << left_slot);
391 	if (tx_mask == 0) {
392 		right_slot = left_slot;
393 	} else {
394 		right_slot = __ffs(tx_mask);
395 		tx_mask &= ~(1 << right_slot);
396 	}
397 
398 	if (tx_mask != 0 || left_slot >= slots || right_slot >= slots)
399 		return -EINVAL;
400 
401 	slots_cfg = (right_slot << TAS2764_TDM_CFG3_RXS_SHIFT) | left_slot;
402 
403 	ret = snd_soc_component_write(component, TAS2764_TDM_CFG3, slots_cfg);
404 	if (ret)
405 		return ret;
406 
407 	switch (slot_width) {
408 	case 16:
409 		slot_size = TAS2764_TDM_CFG2_RXS_16BITS;
410 		break;
411 	case 24:
412 		slot_size = TAS2764_TDM_CFG2_RXS_24BITS;
413 		break;
414 	case 32:
415 		slot_size = TAS2764_TDM_CFG2_RXS_32BITS;
416 		break;
417 	default:
418 		return -EINVAL;
419 	}
420 
421 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG2,
422 					    TAS2764_TDM_CFG2_RXS_MASK,
423 					    slot_size);
424 	if (ret < 0)
425 		return ret;
426 
427 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG5,
428 					    TAS2764_TDM_CFG5_50_MASK,
429 					    tas2764->v_sense_slot);
430 	if (ret < 0)
431 		return ret;
432 
433 	ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG6,
434 					    TAS2764_TDM_CFG6_50_MASK,
435 					    tas2764->i_sense_slot);
436 	if (ret < 0)
437 		return ret;
438 
439 	return 0;
440 }
441 
442 static struct snd_soc_dai_ops tas2764_dai_ops = {
443 	.mute_stream = tas2764_mute,
444 	.hw_params  = tas2764_hw_params,
445 	.set_fmt    = tas2764_set_fmt,
446 	.set_tdm_slot = tas2764_set_dai_tdm_slot,
447 	.no_capture_mute = 1,
448 };
449 
450 #define TAS2764_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
451 			 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
452 
453 #define TAS2764_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
454 		       SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200)
455 
456 static struct snd_soc_dai_driver tas2764_dai_driver[] = {
457 	{
458 		.name = "tas2764 ASI1",
459 		.id = 0,
460 		.playback = {
461 			.stream_name    = "ASI1 Playback",
462 			.channels_min   = 1,
463 			.channels_max   = 2,
464 			.rates      = TAS2764_RATES,
465 			.formats    = TAS2764_FORMATS,
466 		},
467 		.capture = {
468 			.stream_name    = "ASI1 Capture",
469 			.channels_min   = 0,
470 			.channels_max   = 2,
471 			.rates = TAS2764_RATES,
472 			.formats = TAS2764_FORMATS,
473 		},
474 		.ops = &tas2764_dai_ops,
475 		.symmetric_rates = 1,
476 	},
477 };
478 
tas2764_codec_probe(struct snd_soc_component * component)479 static int tas2764_codec_probe(struct snd_soc_component *component)
480 {
481 	struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
482 	int ret;
483 
484 	tas2764->component = component;
485 
486 	if (tas2764->sdz_gpio) {
487 		gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
488 		usleep_range(1000, 2000);
489 	}
490 
491 	tas2764_reset(tas2764);
492 
493 	ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG5,
494 					    TAS2764_TDM_CFG5_VSNS_ENABLE, 0);
495 	if (ret < 0)
496 		return ret;
497 
498 	ret = snd_soc_component_update_bits(tas2764->component, TAS2764_TDM_CFG6,
499 					    TAS2764_TDM_CFG6_ISNS_ENABLE, 0);
500 	if (ret < 0)
501 		return ret;
502 
503 	return 0;
504 }
505 
506 static DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0);
507 static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10050, 50, 1);
508 
509 static const struct snd_kcontrol_new tas2764_snd_controls[] = {
510 	SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0,
511 		       TAS2764_DVC_MAX, 1, tas2764_playback_volume),
512 	SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0,
513 		       tas2764_digital_tlv),
514 };
515 
516 static const struct snd_soc_component_driver soc_component_driver_tas2764 = {
517 	.probe			= tas2764_codec_probe,
518 	.suspend		= tas2764_codec_suspend,
519 	.resume			= tas2764_codec_resume,
520 	.controls		= tas2764_snd_controls,
521 	.num_controls		= ARRAY_SIZE(tas2764_snd_controls),
522 	.dapm_widgets		= tas2764_dapm_widgets,
523 	.num_dapm_widgets	= ARRAY_SIZE(tas2764_dapm_widgets),
524 	.dapm_routes		= tas2764_audio_map,
525 	.num_dapm_routes	= ARRAY_SIZE(tas2764_audio_map),
526 	.idle_bias_on		= 1,
527 	.endianness		= 1,
528 	.non_legacy_dai_naming	= 1,
529 };
530 
531 static const struct reg_default tas2764_reg_defaults[] = {
532 	{ TAS2764_PAGE, 0x00 },
533 	{ TAS2764_SW_RST, 0x00 },
534 	{ TAS2764_PWR_CTRL, 0x1a },
535 	{ TAS2764_DVC, 0x00 },
536 	{ TAS2764_CHNL_0, 0x28 },
537 	{ TAS2764_TDM_CFG0, 0x09 },
538 	{ TAS2764_TDM_CFG1, 0x02 },
539 	{ TAS2764_TDM_CFG2, 0x0a },
540 	{ TAS2764_TDM_CFG3, 0x10 },
541 	{ TAS2764_TDM_CFG5, 0x42 },
542 };
543 
544 static const struct regmap_range_cfg tas2764_regmap_ranges[] = {
545 	{
546 		.range_min = 0,
547 		.range_max = 1 * 128,
548 		.selector_reg = TAS2764_PAGE,
549 		.selector_mask = 0xff,
550 		.selector_shift = 0,
551 		.window_start = 0,
552 		.window_len = 128,
553 	},
554 };
555 
556 static const struct regmap_config tas2764_i2c_regmap = {
557 	.reg_bits = 8,
558 	.val_bits = 8,
559 	.reg_defaults = tas2764_reg_defaults,
560 	.num_reg_defaults = ARRAY_SIZE(tas2764_reg_defaults),
561 	.cache_type = REGCACHE_RBTREE,
562 	.ranges = tas2764_regmap_ranges,
563 	.num_ranges = ARRAY_SIZE(tas2764_regmap_ranges),
564 	.max_register = 1 * 128,
565 };
566 
tas2764_parse_dt(struct device * dev,struct tas2764_priv * tas2764)567 static int tas2764_parse_dt(struct device *dev, struct tas2764_priv *tas2764)
568 {
569 	int ret = 0;
570 
571 	tas2764->reset_gpio = devm_gpiod_get_optional(tas2764->dev, "reset",
572 						      GPIOD_OUT_HIGH);
573 	if (IS_ERR(tas2764->reset_gpio)) {
574 		if (PTR_ERR(tas2764->reset_gpio) == -EPROBE_DEFER) {
575 			tas2764->reset_gpio = NULL;
576 			return -EPROBE_DEFER;
577 		}
578 	}
579 
580 	tas2764->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
581 	if (IS_ERR(tas2764->sdz_gpio)) {
582 		if (PTR_ERR(tas2764->sdz_gpio) == -EPROBE_DEFER)
583 			return -EPROBE_DEFER;
584 
585 		tas2764->sdz_gpio = NULL;
586 	}
587 
588 	ret = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no",
589 				       &tas2764->i_sense_slot);
590 	if (ret)
591 		tas2764->i_sense_slot = 0;
592 
593 	ret = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no",
594 				       &tas2764->v_sense_slot);
595 	if (ret)
596 		tas2764->v_sense_slot = 2;
597 
598 	return 0;
599 }
600 
tas2764_i2c_probe(struct i2c_client * client,const struct i2c_device_id * id)601 static int tas2764_i2c_probe(struct i2c_client *client,
602 			const struct i2c_device_id *id)
603 {
604 	struct tas2764_priv *tas2764;
605 	int result;
606 
607 	tas2764 = devm_kzalloc(&client->dev, sizeof(struct tas2764_priv),
608 			       GFP_KERNEL);
609 	if (!tas2764)
610 		return -ENOMEM;
611 
612 	tas2764->dev = &client->dev;
613 	i2c_set_clientdata(client, tas2764);
614 	dev_set_drvdata(&client->dev, tas2764);
615 
616 	tas2764->regmap = devm_regmap_init_i2c(client, &tas2764_i2c_regmap);
617 	if (IS_ERR(tas2764->regmap)) {
618 		result = PTR_ERR(tas2764->regmap);
619 		dev_err(&client->dev, "Failed to allocate register map: %d\n",
620 					result);
621 		return result;
622 	}
623 
624 	if (client->dev.of_node) {
625 		result = tas2764_parse_dt(&client->dev, tas2764);
626 		if (result) {
627 			dev_err(tas2764->dev, "%s: Failed to parse devicetree\n",
628 				__func__);
629 			return result;
630 		}
631 	}
632 
633 	return devm_snd_soc_register_component(tas2764->dev,
634 					       &soc_component_driver_tas2764,
635 					       tas2764_dai_driver,
636 					       ARRAY_SIZE(tas2764_dai_driver));
637 }
638 
639 static const struct i2c_device_id tas2764_i2c_id[] = {
640 	{ "tas2764", 0},
641 	{ }
642 };
643 MODULE_DEVICE_TABLE(i2c, tas2764_i2c_id);
644 
645 #if defined(CONFIG_OF)
646 static const struct of_device_id tas2764_of_match[] = {
647 	{ .compatible = "ti,tas2764" },
648 	{},
649 };
650 MODULE_DEVICE_TABLE(of, tas2764_of_match);
651 #endif
652 
653 static struct i2c_driver tas2764_i2c_driver = {
654 	.driver = {
655 		.name   = "tas2764",
656 		.of_match_table = of_match_ptr(tas2764_of_match),
657 	},
658 	.probe      = tas2764_i2c_probe,
659 	.id_table   = tas2764_i2c_id,
660 };
661 module_i2c_driver(tas2764_i2c_driver);
662 
663 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
664 MODULE_DESCRIPTION("TAS2764 I2C Smart Amplifier driver");
665 MODULE_LICENSE("GPL v2");
666