ASoC: tas2552: Implement startup/stop sequence as per TRM
[deliverable/linux.git] / sound / soc / codecs / tas2552.c
CommitLineData
5df7f71d
DM
1/*
2 * tas2552.c - ALSA SoC Texas Instruments TAS2552 Mono Audio Amplifier
3 *
4 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
5 *
6 * Author: Dan Murphy <dmurphy@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 */
17
18#include <linux/module.h>
19#include <linux/errno.h>
20#include <linux/device.h>
21#include <linux/i2c.h>
22#include <linux/gpio.h>
23#include <linux/of_gpio.h>
24#include <linux/pm_runtime.h>
25#include <linux/regmap.h>
26#include <linux/slab.h>
27
28#include <linux/gpio/consumer.h>
29#include <linux/regulator/consumer.h>
30
31#include <sound/pcm.h>
32#include <sound/pcm_params.h>
33#include <sound/soc.h>
34#include <sound/soc-dapm.h>
35#include <sound/tlv.h>
36#include <sound/tas2552-plat.h>
9d87a888 37#include <dt-bindings/sound/tas2552.h>
5df7f71d
DM
38
39#include "tas2552.h"
40
41static struct reg_default tas2552_reg_defs[] = {
42 {TAS2552_CFG_1, 0x22},
43 {TAS2552_CFG_3, 0x80},
44 {TAS2552_DOUT, 0x00},
45 {TAS2552_OUTPUT_DATA, 0xc0},
46 {TAS2552_PDM_CFG, 0x01},
47 {TAS2552_PGA_GAIN, 0x00},
48 {TAS2552_BOOST_PT_CTRL, 0x0f},
7d785025 49 {TAS2552_RESERVED_0D, 0xbe},
5df7f71d
DM
50 {TAS2552_LIMIT_RATE_HYS, 0x08},
51 {TAS2552_CFG_2, 0xef},
52 {TAS2552_SER_CTRL_1, 0x00},
53 {TAS2552_SER_CTRL_2, 0x00},
54 {TAS2552_PLL_CTRL_1, 0x10},
55 {TAS2552_PLL_CTRL_2, 0x00},
56 {TAS2552_PLL_CTRL_3, 0x00},
57 {TAS2552_BTIP, 0x8f},
58 {TAS2552_BTS_CTRL, 0x80},
59 {TAS2552_LIMIT_RELEASE, 0x04},
60 {TAS2552_LIMIT_INT_COUNT, 0x00},
61 {TAS2552_EDGE_RATE_CTRL, 0x40},
62 {TAS2552_VBAT_DATA, 0x00},
63};
64
65#define TAS2552_NUM_SUPPLIES 3
66static const char *tas2552_supply_names[TAS2552_NUM_SUPPLIES] = {
67 "vbat", /* vbat voltage */
68 "iovdd", /* I/O Voltage */
69 "avdd", /* Analog DAC Voltage */
70};
71
72struct tas2552_data {
73 struct snd_soc_codec *codec;
74 struct regmap *regmap;
75 struct i2c_client *tas2552_client;
76 struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES];
77 struct gpio_desc *enable_gpio;
78 unsigned char regs[TAS2552_VBAT_DATA];
16bd3952 79 unsigned int pll_clkin;
9d87a888 80 unsigned int pdm_clk;
3f747a81
PU
81
82 unsigned int dai_fmt;
83 unsigned int tdm_delay;
5df7f71d
DM
84};
85
7d785025
PU
86static int tas2552_post_event(struct snd_soc_dapm_widget *w,
87 struct snd_kcontrol *kcontrol, int event)
88{
89 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
90
91 switch (event) {
92 case SND_SOC_DAPM_POST_PMU:
93 snd_soc_write(codec, TAS2552_RESERVED_0D, 0xc0);
94 snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5),
95 (1 << 5));
96 snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 0);
97 snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS, 0);
98 break;
99 case SND_SOC_DAPM_POST_PMD:
100 snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS,
101 TAS2552_SWS);
102 snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 1);
103 snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5), 0);
104 snd_soc_write(codec, TAS2552_RESERVED_0D, 0xbe);
105 break;
106 }
107 return 0;
108}
a7a8e994 109
609e7131
PU
110/* Input mux controls */
111static const char * const tas2552_input_texts[] = {
112 "Digital", "Analog" };
a7a8e994
DM
113static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7,
114 tas2552_input_texts);
115
609e7131
PU
116static const struct snd_kcontrol_new tas2552_input_mux_control =
117 SOC_DAPM_ENUM("Route", tas2552_input_mux_enum);
a7a8e994
DM
118
119static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
120{
121 SND_SOC_DAPM_INPUT("IN"),
122
123 /* MUX Controls */
124 SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0,
609e7131 125 &tas2552_input_mux_control),
a7a8e994
DM
126
127 SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
128 SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
129 SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0),
130 SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0),
7d785025 131 SND_SOC_DAPM_POST("Post Event", tas2552_post_event),
a7a8e994
DM
132
133 SND_SOC_DAPM_OUTPUT("OUT")
134};
135
136static const struct snd_soc_dapm_route tas2552_audio_map[] = {
137 {"DAC", NULL, "DAC IN"},
138 {"Input selection", "Digital", "DAC"},
139 {"Input selection", "Analog", "IN"},
140 {"ClassD", NULL, "Input selection"},
141 {"OUT", NULL, "ClassD"},
142 {"ClassD", NULL, "PLL"},
143};
144
641d334b 145#ifdef CONFIG_PM
5df7f71d
DM
146static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown)
147{
dd6e3053 148 u8 cfg1_reg = 0;
5df7f71d 149
80ba2669
PU
150 if (!tas_data->codec)
151 return;
152
5df7f71d 153 if (sw_shutdown)
7de544fd 154 cfg1_reg = TAS2552_SWS;
5df7f71d 155
7de544fd
PU
156 snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1, TAS2552_SWS,
157 cfg1_reg);
5df7f71d 158}
be1aa3ea 159#endif
5df7f71d
DM
160
161static int tas2552_hw_params(struct snd_pcm_substream *substream,
162 struct snd_pcm_hw_params *params,
163 struct snd_soc_dai *dai)
164{
165 struct snd_soc_codec *codec = dai->codec;
166 struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
167 int sample_rate, pll_clk;
168 int d;
169 u8 p, j;
170
16bd3952 171 if (!tas2552->pll_clkin)
5df7f71d
DM
172 return -EINVAL;
173
174 snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
175
16bd3952
PU
176 if (tas2552->pll_clkin == TAS2552_245MHZ_CLK ||
177 tas2552->pll_clkin == TAS2552_225MHZ_CLK) {
5df7f71d
DM
178 /* By pass the PLL configuration */
179 snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
180 TAS2552_PLL_BYPASS_MASK,
181 TAS2552_PLL_BYPASS);
182 } else {
183 /* Fill in the PLL control registers for J & D
184 * PLL_CLK = (.5 * freq * J.D) / 2^p
185 * Need to fill in J and D here based on incoming freq
186 */
187 p = snd_soc_read(codec, TAS2552_PLL_CTRL_1);
188 p = (p >> 7);
189 sample_rate = params_rate(params);
190
191 if (sample_rate == 48000)
192 pll_clk = TAS2552_245MHZ_CLK;
193 else if (sample_rate == 44100)
194 pll_clk = TAS2552_225MHZ_CLK;
195 else {
196 dev_vdbg(codec->dev, "Substream sample rate is not found %i\n",
197 params_rate(params));
198 return -EINVAL;
199 }
200
16bd3952
PU
201 j = (pll_clk * 2 * (1 << p)) / tas2552->pll_clkin;
202 d = (pll_clk * 2 * (1 << p)) % tas2552->pll_clkin;
5df7f71d
DM
203
204 snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1,
205 TAS2552_PLL_J_MASK, j);
206 snd_soc_write(codec, TAS2552_PLL_CTRL_2,
207 (d >> 7) & TAS2552_PLL_D_UPPER_MASK);
208 snd_soc_write(codec, TAS2552_PLL_CTRL_3,
209 d & TAS2552_PLL_D_LOWER_MASK);
210
211 }
212
5df7f71d
DM
213 return 0;
214}
215
1b68c7dc
PU
216#define TAS2552_DAI_FMT_MASK (TAS2552_BCLKDIR | \
217 TAS2552_WCLKDIR | \
218 TAS2552_DATAFORMAT_MASK)
3f747a81
PU
219static int tas2552_prepare(struct snd_pcm_substream *substream,
220 struct snd_soc_dai *dai)
221{
222 struct snd_soc_codec *codec = dai->codec;
223 struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
224 int delay = 0;
225
226 /* TDM slot selection only valid in DSP_A/_B mode */
227 if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_A)
228 delay += (tas2552->tdm_delay + 1);
229 else if (tas2552->dai_fmt == SND_SOC_DAIFMT_DSP_B)
230 delay += tas2552->tdm_delay;
231
232 /* Configure data delay */
233 snd_soc_write(codec, TAS2552_SER_CTRL_2, delay);
234
235 return 0;
236}
237
5df7f71d
DM
238static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
239{
240 struct snd_soc_codec *codec = dai->codec;
3f747a81 241 struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
5df7f71d 242 u8 serial_format;
5df7f71d
DM
243
244 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
245 case SND_SOC_DAIFMT_CBS_CFS:
246 serial_format = 0x00;
247 break;
248 case SND_SOC_DAIFMT_CBS_CFM:
1b68c7dc 249 serial_format = TAS2552_WCLKDIR;
5df7f71d
DM
250 break;
251 case SND_SOC_DAIFMT_CBM_CFS:
1b68c7dc 252 serial_format = TAS2552_BCLKDIR;
5df7f71d
DM
253 break;
254 case SND_SOC_DAIFMT_CBM_CFM:
1b68c7dc 255 serial_format = (TAS2552_BCLKDIR | TAS2552_WCLKDIR);
5df7f71d
DM
256 break;
257 default:
258 dev_vdbg(codec->dev, "DAI Format master is not found\n");
259 return -EINVAL;
260 }
261
4c331373
PU
262 switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
263 SND_SOC_DAIFMT_INV_MASK)) {
264 case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
5df7f71d 265 break;
4c331373 266 case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF):
4c331373 267 case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF):
1b68c7dc 268 serial_format |= TAS2552_DATAFORMAT_DSP;
5df7f71d 269 break;
4c331373 270 case (SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF):
1b68c7dc 271 serial_format |= TAS2552_DATAFORMAT_RIGHT_J;
5df7f71d 272 break;
4c331373 273 case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
1b68c7dc 274 serial_format |= TAS2552_DATAFORMAT_LEFT_J;
5df7f71d
DM
275 break;
276 default:
277 dev_vdbg(codec->dev, "DAI Format is not found\n");
278 return -EINVAL;
279 }
3f747a81 280 tas2552->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
5df7f71d 281
4c331373
PU
282 snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, TAS2552_DAI_FMT_MASK,
283 serial_format);
5df7f71d
DM
284 return 0;
285}
286
287static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
288 unsigned int freq, int dir)
289{
290 struct snd_soc_codec *codec = dai->codec;
291 struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
9d87a888
PU
292 u8 reg, mask, val;
293
294 switch (clk_id) {
295 case TAS2552_PLL_CLKIN_MCLK:
296 case TAS2552_PLL_CLKIN_BCLK:
297 case TAS2552_PLL_CLKIN_IVCLKIN:
298 case TAS2552_PLL_CLKIN_1_8_FIXED:
299 mask = TAS2552_PLL_SRC_MASK;
300 val = (clk_id << 3) & mask; /* bit 4:5 in the register */
301 reg = TAS2552_CFG_1;
302 tas2552->pll_clkin = freq;
303 break;
304 case TAS2552_PDM_CLK_PLL:
305 case TAS2552_PDM_CLK_IVCLKIN:
306 case TAS2552_PDM_CLK_BCLK:
307 case TAS2552_PDM_CLK_MCLK:
308 mask = TAS2552_PDM_CLK_SEL_MASK;
309 val = (clk_id >> 1) & mask; /* bit 0:1 in the register */
310 reg = TAS2552_PDM_CFG;
311 tas2552->pdm_clk = freq;
312 break;
313 default:
314 dev_err(codec->dev, "Invalid clk id: %d\n", clk_id);
315 return -EINVAL;
316 }
5df7f71d 317
9d87a888 318 snd_soc_update_bits(codec, reg, mask, val);
5df7f71d
DM
319
320 return 0;
321}
322
3f747a81
PU
323static int tas2552_set_dai_tdm_slot(struct snd_soc_dai *dai,
324 unsigned int tx_mask, unsigned int rx_mask,
325 int slots, int slot_width)
326{
327 struct snd_soc_codec *codec = dai->codec;
328 struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
329 unsigned int lsb;
330
331 if (unlikely(!tx_mask)) {
332 dev_err(codec->dev, "tx masks need to be non 0\n");
333 return -EINVAL;
334 }
335
336 /* TDM based on DSP mode requires slots to be adjacent */
337 lsb = __ffs(tx_mask);
338 if ((lsb + 1) != __fls(tx_mask)) {
339 dev_err(codec->dev, "Invalid mask, slots must be adjacent\n");
340 return -EINVAL;
341 }
342
343 tas2552->tdm_delay = lsb * slot_width;
344
345 /* DOUT in high-impedance on inactive bit clocks */
346 snd_soc_update_bits(codec, TAS2552_DOUT,
347 TAS2552_SDOUT_TRISTATE, TAS2552_SDOUT_TRISTATE);
348
349 return 0;
350}
351
5df7f71d
DM
352static int tas2552_mute(struct snd_soc_dai *dai, int mute)
353{
e3606aa4 354 u8 cfg1_reg = 0;
5df7f71d
DM
355 struct snd_soc_codec *codec = dai->codec;
356
357 if (mute)
e3606aa4 358 cfg1_reg |= TAS2552_MUTE;
5df7f71d 359
7de544fd 360 snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, cfg1_reg);
5df7f71d
DM
361
362 return 0;
363}
364
641d334b 365#ifdef CONFIG_PM
5df7f71d
DM
366static int tas2552_runtime_suspend(struct device *dev)
367{
368 struct tas2552_data *tas2552 = dev_get_drvdata(dev);
369
dd6e3053 370 tas2552_sw_shutdown(tas2552, 1);
5df7f71d 371
5df7f71d
DM
372 regcache_cache_only(tas2552->regmap, true);
373 regcache_mark_dirty(tas2552->regmap);
374
e295a4a4
DM
375 if (tas2552->enable_gpio)
376 gpiod_set_value(tas2552->enable_gpio, 0);
377
5df7f71d
DM
378 return 0;
379}
380
381static int tas2552_runtime_resume(struct device *dev)
382{
383 struct tas2552_data *tas2552 = dev_get_drvdata(dev);
384
385 if (tas2552->enable_gpio)
386 gpiod_set_value(tas2552->enable_gpio, 1);
387
dd6e3053 388 tas2552_sw_shutdown(tas2552, 0);
5df7f71d
DM
389
390 regcache_cache_only(tas2552->regmap, false);
391 regcache_sync(tas2552->regmap);
392
393 return 0;
394}
395#endif
396
397static const struct dev_pm_ops tas2552_pm = {
398 SET_RUNTIME_PM_OPS(tas2552_runtime_suspend, tas2552_runtime_resume,
399 NULL)
400};
401
5df7f71d
DM
402static struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
403 .hw_params = tas2552_hw_params,
3f747a81 404 .prepare = tas2552_prepare,
5df7f71d
DM
405 .set_sysclk = tas2552_set_dai_sysclk,
406 .set_fmt = tas2552_set_dai_fmt,
3f747a81 407 .set_tdm_slot = tas2552_set_dai_tdm_slot,
5df7f71d
DM
408 .digital_mute = tas2552_mute,
409};
410
411/* Formats supported by TAS2552 driver. */
412#define TAS2552_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
413 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
414
415/* TAS2552 dai structure. */
416static struct snd_soc_dai_driver tas2552_dai[] = {
417 {
418 .name = "tas2552-amplifier",
419 .playback = {
a7a8e994 420 .stream_name = "Playback",
5df7f71d
DM
421 .channels_min = 2,
422 .channels_max = 2,
423 .rates = SNDRV_PCM_RATE_8000_192000,
424 .formats = TAS2552_FORMATS,
425 },
426 .ops = &tas2552_speaker_dai_ops,
427 },
428};
429
430/*
431 * DAC digital volumes. From -7 to 24 dB in 1 dB steps
432 */
dd6ae3bc 433static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 0);
5df7f71d
DM
434
435static const struct snd_kcontrol_new tas2552_snd_controls[] = {
436 SOC_SINGLE_TLV("Speaker Driver Playback Volume",
dd6ae3bc 437 TAS2552_PGA_GAIN, 0, 0x1f, 0, dac_tlv),
5df7f71d
DM
438};
439
5df7f71d
DM
440static int tas2552_codec_probe(struct snd_soc_codec *codec)
441{
442 struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
443 int ret;
444
445 tas2552->codec = codec;
446
447 ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies),
448 tas2552->supplies);
449
450 if (ret != 0) {
451 dev_err(codec->dev, "Failed to enable supplies: %d\n",
452 ret);
453 return ret;
454 }
455
456 if (tas2552->enable_gpio)
457 gpiod_set_value(tas2552->enable_gpio, 1);
458
459 ret = pm_runtime_get_sync(codec->dev);
460 if (ret < 0) {
461 dev_err(codec->dev, "Enabling device failed: %d\n",
462 ret);
463 goto probe_fail;
464 }
465
7d785025 466 snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, TAS2552_MUTE);
5df7f71d
DM
467 snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL |
468 TAS2552_DIN_SRC_SEL_AVG_L_R | TAS2552_88_96KHZ);
469 snd_soc_write(codec, TAS2552_DOUT, TAS2552_PDM_DATA_I);
470 snd_soc_write(codec, TAS2552_OUTPUT_DATA, TAS2552_PDM_DATA_V_I | 0x8);
5df7f71d
DM
471 snd_soc_write(codec, TAS2552_BOOST_PT_CTRL, TAS2552_APT_DELAY_200 |
472 TAS2552_APT_THRESH_2_1_7);
473
a7a8e994
DM
474 snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN |
475 TAS2552_APT_EN | TAS2552_LIM_EN);
476
5df7f71d
DM
477 return 0;
478
5df7f71d
DM
479probe_fail:
480 if (tas2552->enable_gpio)
481 gpiod_set_value(tas2552->enable_gpio, 0);
482
483 regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies),
484 tas2552->supplies);
485 return -EIO;
486}
487
488static int tas2552_codec_remove(struct snd_soc_codec *codec)
489{
490 struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
491
e295a4a4
DM
492 pm_runtime_put(codec->dev);
493
5df7f71d
DM
494 if (tas2552->enable_gpio)
495 gpiod_set_value(tas2552->enable_gpio, 0);
496
497 return 0;
498};
499
500#ifdef CONFIG_PM
501static int tas2552_suspend(struct snd_soc_codec *codec)
502{
503 struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
504 int ret;
505
506 ret = regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies),
507 tas2552->supplies);
508
509 if (ret != 0)
510 dev_err(codec->dev, "Failed to disable supplies: %d\n",
511 ret);
512 return 0;
513}
514
515static int tas2552_resume(struct snd_soc_codec *codec)
516{
517 struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
518 int ret;
519
520 ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies),
521 tas2552->supplies);
522
523 if (ret != 0) {
524 dev_err(codec->dev, "Failed to enable supplies: %d\n",
525 ret);
526 }
527
528 return 0;
529}
530#else
531#define tas2552_suspend NULL
532#define tas2552_resume NULL
533#endif
534
535static struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
536 .probe = tas2552_codec_probe,
537 .remove = tas2552_codec_remove,
538 .suspend = tas2552_suspend,
539 .resume = tas2552_resume,
7d785025
PU
540 .ignore_pmdown_time = true,
541
5df7f71d
DM
542 .controls = tas2552_snd_controls,
543 .num_controls = ARRAY_SIZE(tas2552_snd_controls),
e3f1ff31
LPC
544 .dapm_widgets = tas2552_dapm_widgets,
545 .num_dapm_widgets = ARRAY_SIZE(tas2552_dapm_widgets),
546 .dapm_routes = tas2552_audio_map,
547 .num_dapm_routes = ARRAY_SIZE(tas2552_audio_map),
5df7f71d
DM
548};
549
550static const struct regmap_config tas2552_regmap_config = {
551 .reg_bits = 8,
552 .val_bits = 8,
553
554 .max_register = TAS2552_MAX_REG,
555 .reg_defaults = tas2552_reg_defs,
556 .num_reg_defaults = ARRAY_SIZE(tas2552_reg_defs),
557 .cache_type = REGCACHE_RBTREE,
558};
559
560static int tas2552_probe(struct i2c_client *client,
561 const struct i2c_device_id *id)
562{
563 struct device *dev;
564 struct tas2552_data *data;
565 int ret;
566 int i;
567
568 dev = &client->dev;
569 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
570 if (data == NULL)
571 return -ENOMEM;
572
34d7c390 573 data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
ea178d14
PU
574 if (IS_ERR(data->enable_gpio)) {
575 if (PTR_ERR(data->enable_gpio) == -EPROBE_DEFER)
576 return -EPROBE_DEFER;
577
578 data->enable_gpio = NULL;;
579 }
5df7f71d
DM
580
581 data->tas2552_client = client;
582 data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);
583 if (IS_ERR(data->regmap)) {
584 ret = PTR_ERR(data->regmap);
585 dev_err(&client->dev, "Failed to allocate register map: %d\n",
586 ret);
587 return ret;
588 }
589
590 for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
591 data->supplies[i].supply = tas2552_supply_names[i];
592
593 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
594 data->supplies);
c62f9d8f 595 if (ret != 0) {
5df7f71d 596 dev_err(dev, "Failed to request supplies: %d\n", ret);
c62f9d8f
AL
597 return ret;
598 }
5df7f71d
DM
599
600 pm_runtime_set_active(&client->dev);
601 pm_runtime_set_autosuspend_delay(&client->dev, 1000);
602 pm_runtime_use_autosuspend(&client->dev);
603 pm_runtime_enable(&client->dev);
604 pm_runtime_mark_last_busy(&client->dev);
605 pm_runtime_put_sync_autosuspend(&client->dev);
606
607 dev_set_drvdata(&client->dev, data);
608
609 ret = snd_soc_register_codec(&client->dev,
610 &soc_codec_dev_tas2552,
611 tas2552_dai, ARRAY_SIZE(tas2552_dai));
612 if (ret < 0)
613 dev_err(&client->dev, "Failed to register codec: %d\n", ret);
614
c62f9d8f 615 return ret;
5df7f71d
DM
616}
617
618static int tas2552_i2c_remove(struct i2c_client *client)
619{
620 snd_soc_unregister_codec(&client->dev);
621 return 0;
622}
623
624static const struct i2c_device_id tas2552_id[] = {
625 { "tas2552", 0 },
626 { }
627};
628MODULE_DEVICE_TABLE(i2c, tas2552_id);
629
630#if IS_ENABLED(CONFIG_OF)
631static const struct of_device_id tas2552_of_match[] = {
632 { .compatible = "ti,tas2552", },
633 {},
634};
635MODULE_DEVICE_TABLE(of, tas2552_of_match);
636#endif
637
638static struct i2c_driver tas2552_i2c_driver = {
639 .driver = {
640 .name = "tas2552",
641 .owner = THIS_MODULE,
642 .of_match_table = of_match_ptr(tas2552_of_match),
643 .pm = &tas2552_pm,
644 },
645 .probe = tas2552_probe,
646 .remove = tas2552_i2c_remove,
647 .id_table = tas2552_id,
648};
649
650module_i2c_driver(tas2552_i2c_driver);
651
652MODULE_AUTHOR("Dan Muprhy <dmurphy@ti.com>");
653MODULE_DESCRIPTION("TAS2552 Audio amplifier driver");
654MODULE_LICENSE("GPL");
This page took 0.075313 seconds and 5 git commands to generate.