2 * tas2552.c - ALSA SoC Texas Instruments TAS2552 Mono Audio Amplifier
4 * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
6 * Author: Dan Murphy <dmurphy@ti.com>
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.
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.
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>
28 #include <linux/gpio/consumer.h>
29 #include <linux/regulator/consumer.h>
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>
40 static struct reg_default tas2552_reg_defs
[] = {
41 {TAS2552_CFG_1
, 0x22},
42 {TAS2552_CFG_3
, 0x80},
44 {TAS2552_OUTPUT_DATA
, 0xc0},
45 {TAS2552_PDM_CFG
, 0x01},
46 {TAS2552_PGA_GAIN
, 0x00},
47 {TAS2552_BOOST_PT_CTRL
, 0x0f},
48 {TAS2552_RESERVED_0D
, 0x00},
49 {TAS2552_LIMIT_RATE_HYS
, 0x08},
50 {TAS2552_CFG_2
, 0xef},
51 {TAS2552_SER_CTRL_1
, 0x00},
52 {TAS2552_SER_CTRL_2
, 0x00},
53 {TAS2552_PLL_CTRL_1
, 0x10},
54 {TAS2552_PLL_CTRL_2
, 0x00},
55 {TAS2552_PLL_CTRL_3
, 0x00},
57 {TAS2552_BTS_CTRL
, 0x80},
58 {TAS2552_LIMIT_RELEASE
, 0x04},
59 {TAS2552_LIMIT_INT_COUNT
, 0x00},
60 {TAS2552_EDGE_RATE_CTRL
, 0x40},
61 {TAS2552_VBAT_DATA
, 0x00},
64 #define TAS2552_NUM_SUPPLIES 3
65 static const char *tas2552_supply_names
[TAS2552_NUM_SUPPLIES
] = {
66 "vbat", /* vbat voltage */
67 "iovdd", /* I/O Voltage */
68 "avdd", /* Analog DAC Voltage */
72 struct snd_soc_codec
*codec
;
73 struct regmap
*regmap
;
74 struct i2c_client
*tas2552_client
;
75 struct regulator_bulk_data supplies
[TAS2552_NUM_SUPPLIES
];
76 struct gpio_desc
*enable_gpio
;
77 unsigned char regs
[TAS2552_VBAT_DATA
];
81 /* Input mux controls */
82 static const char *tas2552_input_texts
[] = {
86 static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum
, TAS2552_CFG_3
, 7,
89 static const struct snd_kcontrol_new tas2552_input_mux_control
[] = {
90 SOC_DAPM_ENUM("Input selection", tas2552_input_mux_enum
)
93 static const struct snd_soc_dapm_widget tas2552_dapm_widgets
[] =
95 SND_SOC_DAPM_INPUT("IN"),
98 SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM
, 0, 0,
99 tas2552_input_mux_control
),
101 SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM
, 0, 0),
102 SND_SOC_DAPM_DAC("DAC", NULL
, SND_SOC_NOPM
, 0, 0),
103 SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2
, 7, 0, NULL
, 0),
104 SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2
, 3, 0, NULL
, 0),
106 SND_SOC_DAPM_OUTPUT("OUT")
109 static const struct snd_soc_dapm_route tas2552_audio_map
[] = {
110 {"DAC", NULL
, "DAC IN"},
111 {"Input selection", "Digital", "DAC"},
112 {"Input selection", "Analog", "IN"},
113 {"ClassD", NULL
, "Input selection"},
114 {"OUT", NULL
, "ClassD"},
115 {"ClassD", NULL
, "PLL"},
119 static void tas2552_sw_shutdown(struct tas2552_data
*tas_data
, int sw_shutdown
)
126 cfg1_reg
= TAS2552_SWS_MASK
;
128 snd_soc_update_bits(tas_data
->codec
, TAS2552_CFG_1
,
129 TAS2552_SWS_MASK
, cfg1_reg
);
133 static int tas2552_hw_params(struct snd_pcm_substream
*substream
,
134 struct snd_pcm_hw_params
*params
,
135 struct snd_soc_dai
*dai
)
137 struct snd_soc_codec
*codec
= dai
->codec
;
138 struct tas2552_data
*tas2552
= dev_get_drvdata(codec
->dev
);
139 int sample_rate
, pll_clk
;
146 snd_soc_update_bits(codec
, TAS2552_CFG_2
, TAS2552_PLL_ENABLE
, 0);
148 if (tas2552
->mclk
== TAS2552_245MHZ_CLK
||
149 tas2552
->mclk
== TAS2552_225MHZ_CLK
) {
150 /* By pass the PLL configuration */
151 snd_soc_update_bits(codec
, TAS2552_PLL_CTRL_2
,
152 TAS2552_PLL_BYPASS_MASK
,
155 /* Fill in the PLL control registers for J & D
156 * PLL_CLK = (.5 * freq * J.D) / 2^p
157 * Need to fill in J and D here based on incoming freq
159 p
= snd_soc_read(codec
, TAS2552_PLL_CTRL_1
);
161 sample_rate
= params_rate(params
);
163 if (sample_rate
== 48000)
164 pll_clk
= TAS2552_245MHZ_CLK
;
165 else if (sample_rate
== 44100)
166 pll_clk
= TAS2552_225MHZ_CLK
;
168 dev_vdbg(codec
->dev
, "Substream sample rate is not found %i\n",
169 params_rate(params
));
173 j
= (pll_clk
* 2 * (1 << p
)) / tas2552
->mclk
;
174 d
= (pll_clk
* 2 * (1 << p
)) % tas2552
->mclk
;
176 snd_soc_update_bits(codec
, TAS2552_PLL_CTRL_1
,
177 TAS2552_PLL_J_MASK
, j
);
178 snd_soc_write(codec
, TAS2552_PLL_CTRL_2
,
179 (d
>> 7) & TAS2552_PLL_D_UPPER_MASK
);
180 snd_soc_write(codec
, TAS2552_PLL_CTRL_3
,
181 d
& TAS2552_PLL_D_LOWER_MASK
);
188 static int tas2552_set_dai_fmt(struct snd_soc_dai
*dai
, unsigned int fmt
)
190 struct snd_soc_codec
*codec
= dai
->codec
;
192 u8 serial_control_mask
;
194 switch (fmt
& SND_SOC_DAIFMT_MASTER_MASK
) {
195 case SND_SOC_DAIFMT_CBS_CFS
:
196 serial_format
= 0x00;
198 case SND_SOC_DAIFMT_CBS_CFM
:
199 serial_format
= TAS2552_WORD_CLK_MASK
;
201 case SND_SOC_DAIFMT_CBM_CFS
:
202 serial_format
= TAS2552_BIT_CLK_MASK
;
204 case SND_SOC_DAIFMT_CBM_CFM
:
205 serial_format
= (TAS2552_BIT_CLK_MASK
| TAS2552_WORD_CLK_MASK
);
208 dev_vdbg(codec
->dev
, "DAI Format master is not found\n");
212 serial_control_mask
= TAS2552_BIT_CLK_MASK
| TAS2552_WORD_CLK_MASK
;
214 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
215 case SND_SOC_DAIFMT_I2S
:
216 serial_format
&= TAS2552_DAIFMT_I2S_MASK
;
218 case SND_SOC_DAIFMT_DSP_A
:
219 serial_format
|= TAS2552_DAIFMT_DSP
;
221 case SND_SOC_DAIFMT_RIGHT_J
:
222 serial_format
|= TAS2552_DAIFMT_RIGHT_J
;
224 case SND_SOC_DAIFMT_LEFT_J
:
225 serial_format
|= TAS2552_DAIFMT_LEFT_J
;
228 dev_vdbg(codec
->dev
, "DAI Format is not found\n");
232 if (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
)
233 serial_control_mask
|= TAS2552_DATA_FORMAT_MASK
;
235 snd_soc_update_bits(codec
, TAS2552_SER_CTRL_1
, serial_control_mask
,
241 static int tas2552_set_dai_sysclk(struct snd_soc_dai
*dai
, int clk_id
,
242 unsigned int freq
, int dir
)
244 struct snd_soc_codec
*codec
= dai
->codec
;
245 struct tas2552_data
*tas2552
= dev_get_drvdata(codec
->dev
);
247 tas2552
->mclk
= freq
;
252 static int tas2552_mute(struct snd_soc_dai
*dai
, int mute
)
255 struct snd_soc_codec
*codec
= dai
->codec
;
258 cfg1_reg
= TAS2552_MUTE_MASK
;
260 cfg1_reg
= ~TAS2552_MUTE_MASK
;
262 snd_soc_update_bits(codec
, TAS2552_CFG_1
, TAS2552_MUTE_MASK
, cfg1_reg
);
268 static int tas2552_runtime_suspend(struct device
*dev
)
270 struct tas2552_data
*tas2552
= dev_get_drvdata(dev
);
272 tas2552_sw_shutdown(tas2552
, 0);
274 regcache_cache_only(tas2552
->regmap
, true);
275 regcache_mark_dirty(tas2552
->regmap
);
277 if (tas2552
->enable_gpio
)
278 gpiod_set_value(tas2552
->enable_gpio
, 0);
283 static int tas2552_runtime_resume(struct device
*dev
)
285 struct tas2552_data
*tas2552
= dev_get_drvdata(dev
);
287 if (tas2552
->enable_gpio
)
288 gpiod_set_value(tas2552
->enable_gpio
, 1);
290 tas2552_sw_shutdown(tas2552
, 1);
292 regcache_cache_only(tas2552
->regmap
, false);
293 regcache_sync(tas2552
->regmap
);
299 static const struct dev_pm_ops tas2552_pm
= {
300 SET_RUNTIME_PM_OPS(tas2552_runtime_suspend
, tas2552_runtime_resume
,
304 static struct snd_soc_dai_ops tas2552_speaker_dai_ops
= {
305 .hw_params
= tas2552_hw_params
,
306 .set_sysclk
= tas2552_set_dai_sysclk
,
307 .set_fmt
= tas2552_set_dai_fmt
,
308 .digital_mute
= tas2552_mute
,
311 /* Formats supported by TAS2552 driver. */
312 #define TAS2552_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
313 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
315 /* TAS2552 dai structure. */
316 static struct snd_soc_dai_driver tas2552_dai
[] = {
318 .name
= "tas2552-amplifier",
320 .stream_name
= "Playback",
323 .rates
= SNDRV_PCM_RATE_8000_192000
,
324 .formats
= TAS2552_FORMATS
,
326 .ops
= &tas2552_speaker_dai_ops
,
331 * DAC digital volumes. From -7 to 24 dB in 1 dB steps
333 static DECLARE_TLV_DB_SCALE(dac_tlv
, -7, 100, 24);
335 static const struct snd_kcontrol_new tas2552_snd_controls
[] = {
336 SOC_SINGLE_TLV("Speaker Driver Playback Volume",
337 TAS2552_PGA_GAIN
, 0, 0x1f, 1, dac_tlv
),
338 SOC_DAPM_SINGLE("Playback AMP", SND_SOC_NOPM
, 0, 1, 0),
341 static const struct reg_default tas2552_init_regs
[] = {
342 { TAS2552_RESERVED_0D
, 0xc0 },
345 static int tas2552_codec_probe(struct snd_soc_codec
*codec
)
347 struct tas2552_data
*tas2552
= snd_soc_codec_get_drvdata(codec
);
350 tas2552
->codec
= codec
;
352 ret
= regulator_bulk_enable(ARRAY_SIZE(tas2552
->supplies
),
356 dev_err(codec
->dev
, "Failed to enable supplies: %d\n",
361 if (tas2552
->enable_gpio
)
362 gpiod_set_value(tas2552
->enable_gpio
, 1);
364 ret
= pm_runtime_get_sync(codec
->dev
);
366 dev_err(codec
->dev
, "Enabling device failed: %d\n",
371 snd_soc_write(codec
, TAS2552_CFG_1
, TAS2552_MUTE_MASK
|
372 TAS2552_PLL_SRC_BCLK
);
373 snd_soc_write(codec
, TAS2552_CFG_3
, TAS2552_I2S_OUT_SEL
|
374 TAS2552_DIN_SRC_SEL_AVG_L_R
| TAS2552_88_96KHZ
);
375 snd_soc_write(codec
, TAS2552_DOUT
, TAS2552_PDM_DATA_I
);
376 snd_soc_write(codec
, TAS2552_OUTPUT_DATA
, TAS2552_PDM_DATA_V_I
| 0x8);
377 snd_soc_write(codec
, TAS2552_PDM_CFG
, TAS2552_PDM_BCLK_SEL
);
378 snd_soc_write(codec
, TAS2552_BOOST_PT_CTRL
, TAS2552_APT_DELAY_200
|
379 TAS2552_APT_THRESH_2_1_7
);
381 ret
= regmap_register_patch(tas2552
->regmap
, tas2552_init_regs
,
382 ARRAY_SIZE(tas2552_init_regs
));
384 dev_err(codec
->dev
, "Failed to write init registers: %d\n",
389 snd_soc_write(codec
, TAS2552_CFG_2
, TAS2552_BOOST_EN
|
390 TAS2552_APT_EN
| TAS2552_LIM_EN
);
395 pm_runtime_put(codec
->dev
);
397 if (tas2552
->enable_gpio
)
398 gpiod_set_value(tas2552
->enable_gpio
, 0);
400 regulator_bulk_disable(ARRAY_SIZE(tas2552
->supplies
),
405 static int tas2552_codec_remove(struct snd_soc_codec
*codec
)
407 struct tas2552_data
*tas2552
= snd_soc_codec_get_drvdata(codec
);
409 pm_runtime_put(codec
->dev
);
411 if (tas2552
->enable_gpio
)
412 gpiod_set_value(tas2552
->enable_gpio
, 0);
418 static int tas2552_suspend(struct snd_soc_codec
*codec
)
420 struct tas2552_data
*tas2552
= snd_soc_codec_get_drvdata(codec
);
423 ret
= regulator_bulk_disable(ARRAY_SIZE(tas2552
->supplies
),
427 dev_err(codec
->dev
, "Failed to disable supplies: %d\n",
432 static int tas2552_resume(struct snd_soc_codec
*codec
)
434 struct tas2552_data
*tas2552
= snd_soc_codec_get_drvdata(codec
);
437 ret
= regulator_bulk_enable(ARRAY_SIZE(tas2552
->supplies
),
441 dev_err(codec
->dev
, "Failed to enable supplies: %d\n",
448 #define tas2552_suspend NULL
449 #define tas2552_resume NULL
452 static struct snd_soc_codec_driver soc_codec_dev_tas2552
= {
453 .probe
= tas2552_codec_probe
,
454 .remove
= tas2552_codec_remove
,
455 .suspend
= tas2552_suspend
,
456 .resume
= tas2552_resume
,
457 .controls
= tas2552_snd_controls
,
458 .num_controls
= ARRAY_SIZE(tas2552_snd_controls
),
459 .dapm_widgets
= tas2552_dapm_widgets
,
460 .num_dapm_widgets
= ARRAY_SIZE(tas2552_dapm_widgets
),
461 .dapm_routes
= tas2552_audio_map
,
462 .num_dapm_routes
= ARRAY_SIZE(tas2552_audio_map
),
465 static const struct regmap_config tas2552_regmap_config
= {
469 .max_register
= TAS2552_MAX_REG
,
470 .reg_defaults
= tas2552_reg_defs
,
471 .num_reg_defaults
= ARRAY_SIZE(tas2552_reg_defs
),
472 .cache_type
= REGCACHE_RBTREE
,
475 static int tas2552_probe(struct i2c_client
*client
,
476 const struct i2c_device_id
*id
)
479 struct tas2552_data
*data
;
484 data
= devm_kzalloc(&client
->dev
, sizeof(*data
), GFP_KERNEL
);
488 data
->enable_gpio
= devm_gpiod_get(dev
, "enable", GPIOD_OUT_LOW
);
489 if (IS_ERR(data
->enable_gpio
))
490 return PTR_ERR(data
->enable_gpio
);
492 data
->tas2552_client
= client
;
493 data
->regmap
= devm_regmap_init_i2c(client
, &tas2552_regmap_config
);
494 if (IS_ERR(data
->regmap
)) {
495 ret
= PTR_ERR(data
->regmap
);
496 dev_err(&client
->dev
, "Failed to allocate register map: %d\n",
501 for (i
= 0; i
< ARRAY_SIZE(data
->supplies
); i
++)
502 data
->supplies
[i
].supply
= tas2552_supply_names
[i
];
504 ret
= devm_regulator_bulk_get(dev
, ARRAY_SIZE(data
->supplies
),
507 dev_err(dev
, "Failed to request supplies: %d\n", ret
);
511 pm_runtime_set_active(&client
->dev
);
512 pm_runtime_set_autosuspend_delay(&client
->dev
, 1000);
513 pm_runtime_use_autosuspend(&client
->dev
);
514 pm_runtime_enable(&client
->dev
);
515 pm_runtime_mark_last_busy(&client
->dev
);
516 pm_runtime_put_sync_autosuspend(&client
->dev
);
518 dev_set_drvdata(&client
->dev
, data
);
520 ret
= snd_soc_register_codec(&client
->dev
,
521 &soc_codec_dev_tas2552
,
522 tas2552_dai
, ARRAY_SIZE(tas2552_dai
));
524 dev_err(&client
->dev
, "Failed to register codec: %d\n", ret
);
529 static int tas2552_i2c_remove(struct i2c_client
*client
)
531 snd_soc_unregister_codec(&client
->dev
);
535 static const struct i2c_device_id tas2552_id
[] = {
539 MODULE_DEVICE_TABLE(i2c
, tas2552_id
);
541 #if IS_ENABLED(CONFIG_OF)
542 static const struct of_device_id tas2552_of_match
[] = {
543 { .compatible
= "ti,tas2552", },
546 MODULE_DEVICE_TABLE(of
, tas2552_of_match
);
549 static struct i2c_driver tas2552_i2c_driver
= {
552 .owner
= THIS_MODULE
,
553 .of_match_table
= of_match_ptr(tas2552_of_match
),
556 .probe
= tas2552_probe
,
557 .remove
= tas2552_i2c_remove
,
558 .id_table
= tas2552_id
,
561 module_i2c_driver(tas2552_i2c_driver
);
563 MODULE_AUTHOR("Dan Muprhy <dmurphy@ti.com>");
564 MODULE_DESCRIPTION("TAS2552 Audio amplifier driver");
565 MODULE_LICENSE("GPL");