1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Atmel ALSA SoC Audio Class D Amplifier (CLASSD) driver
4 * Copyright (C) 2015 Atmel
6 * Author: Songjun Wu <songjun.wu@atmel.com>
10 #include <linux/clk.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/regmap.h>
14 #include <sound/core.h>
15 #include <sound/dmaengine_pcm.h>
16 #include <sound/pcm_params.h>
17 #include <sound/tlv.h>
18 #include "atmel-classd.h"
20 struct atmel_classd_pdata
{
21 bool non_overlap_enable
;
24 const char *card_name
;
29 struct regmap
*regmap
;
34 const struct atmel_classd_pdata
*pdata
;
38 static const struct of_device_id atmel_classd_of_match
[] = {
40 .compatible
= "atmel,sama5d2-classd",
45 MODULE_DEVICE_TABLE(of
, atmel_classd_of_match
);
47 static struct atmel_classd_pdata
*atmel_classd_dt_init(struct device
*dev
)
49 struct device_node
*np
= dev
->of_node
;
50 struct atmel_classd_pdata
*pdata
;
55 dev_err(dev
, "device node not found\n");
56 return ERR_PTR(-EINVAL
);
59 pdata
= devm_kzalloc(dev
, sizeof(*pdata
), GFP_KERNEL
);
61 return ERR_PTR(-ENOMEM
);
63 ret
= of_property_read_string(np
, "atmel,pwm-type", &pwm_type
);
64 if ((ret
== 0) && (strcmp(pwm_type
, "diff") == 0))
65 pdata
->pwm_type
= CLASSD_MR_PWMTYP_DIFF
;
67 pdata
->pwm_type
= CLASSD_MR_PWMTYP_SINGLE
;
69 ret
= of_property_read_u32(np
,
70 "atmel,non-overlap-time", &pdata
->non_overlap_time
);
72 pdata
->non_overlap_enable
= false;
74 pdata
->non_overlap_enable
= true;
76 ret
= of_property_read_string(np
, "atmel,model", &pdata
->card_name
);
78 pdata
->card_name
= "CLASSD";
83 static inline struct atmel_classd_pdata
*
84 atmel_classd_dt_init(struct device
*dev
)
86 return ERR_PTR(-EINVAL
);
90 #define ATMEL_CLASSD_RATES (SNDRV_PCM_RATE_8000 \
91 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 \
92 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 \
93 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 \
94 | SNDRV_PCM_RATE_96000)
96 static const struct snd_pcm_hardware atmel_classd_hw
= {
97 .info
= SNDRV_PCM_INFO_MMAP
98 | SNDRV_PCM_INFO_MMAP_VALID
99 | SNDRV_PCM_INFO_INTERLEAVED
100 | SNDRV_PCM_INFO_RESUME
101 | SNDRV_PCM_INFO_PAUSE
,
102 .formats
= (SNDRV_PCM_FMTBIT_S16_LE
),
103 .rates
= ATMEL_CLASSD_RATES
,
108 .buffer_bytes_max
= 64 * 1024,
109 .period_bytes_min
= 256,
110 .period_bytes_max
= 32 * 1024,
115 #define ATMEL_CLASSD_PREALLOC_BUF_SIZE (64 * 1024)
117 /* cpu dai component */
118 static int atmel_classd_cpu_dai_startup(struct snd_pcm_substream
*substream
,
119 struct snd_soc_dai
*cpu_dai
)
121 struct snd_soc_pcm_runtime
*rtd
= asoc_substream_to_rtd(substream
);
122 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(rtd
->card
);
125 regmap_write(dd
->regmap
, CLASSD_THR
, 0x0);
127 err
= clk_prepare_enable(dd
->pclk
);
130 err
= clk_prepare_enable(dd
->gclk
);
132 clk_disable_unprepare(dd
->pclk
);
140 atmel_classd_platform_configure_dma(struct snd_pcm_substream
*substream
,
141 struct snd_pcm_hw_params
*params
,
142 struct dma_slave_config
*slave_config
)
144 struct snd_soc_pcm_runtime
*rtd
= asoc_substream_to_rtd(substream
);
145 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(rtd
->card
);
147 if (params_physical_width(params
) != 16) {
149 "only supports 16-bit audio data\n");
153 if (params_channels(params
) == 1)
154 slave_config
->dst_addr_width
= DMA_SLAVE_BUSWIDTH_2_BYTES
;
156 slave_config
->dst_addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
158 slave_config
->direction
= DMA_MEM_TO_DEV
;
159 slave_config
->dst_addr
= dd
->phy_base
+ CLASSD_THR
;
160 slave_config
->dst_maxburst
= 1;
161 slave_config
->src_maxburst
= 1;
162 slave_config
->device_fc
= false;
167 static const struct snd_dmaengine_pcm_config
168 atmel_classd_dmaengine_pcm_config
= {
169 .prepare_slave_config
= atmel_classd_platform_configure_dma
,
170 .pcm_hardware
= &atmel_classd_hw
,
171 .prealloc_buffer_size
= ATMEL_CLASSD_PREALLOC_BUF_SIZE
,
175 static const char * const mono_mode_text
[] = {
176 "mix", "sat", "left", "right"
179 static SOC_ENUM_SINGLE_DECL(classd_mono_mode_enum
,
180 CLASSD_INTPMR
, CLASSD_INTPMR_MONO_MODE_SHIFT
,
183 static const char * const eqcfg_text
[] = {
184 "Treble-12dB", "Treble-6dB",
185 "Medium-8dB", "Medium-3dB",
186 "Bass-12dB", "Bass-6dB",
188 "Bass+6dB", "Bass+12dB",
189 "Medium+3dB", "Medium+8dB",
190 "Treble+6dB", "Treble+12dB",
193 static const unsigned int eqcfg_value
[] = {
194 CLASSD_INTPMR_EQCFG_T_CUT_12
, CLASSD_INTPMR_EQCFG_T_CUT_6
,
195 CLASSD_INTPMR_EQCFG_M_CUT_8
, CLASSD_INTPMR_EQCFG_M_CUT_3
,
196 CLASSD_INTPMR_EQCFG_B_CUT_12
, CLASSD_INTPMR_EQCFG_B_CUT_6
,
197 CLASSD_INTPMR_EQCFG_FLAT
,
198 CLASSD_INTPMR_EQCFG_B_BOOST_6
, CLASSD_INTPMR_EQCFG_B_BOOST_12
,
199 CLASSD_INTPMR_EQCFG_M_BOOST_3
, CLASSD_INTPMR_EQCFG_M_BOOST_8
,
200 CLASSD_INTPMR_EQCFG_T_BOOST_6
, CLASSD_INTPMR_EQCFG_T_BOOST_12
,
203 static SOC_VALUE_ENUM_SINGLE_DECL(classd_eqcfg_enum
,
204 CLASSD_INTPMR
, CLASSD_INTPMR_EQCFG_SHIFT
, 0xf,
205 eqcfg_text
, eqcfg_value
);
207 static const DECLARE_TLV_DB_SCALE(classd_digital_tlv
, -7800, 100, 1);
209 static const struct snd_kcontrol_new atmel_classd_snd_controls
[] = {
210 SOC_DOUBLE_TLV("Playback Volume", CLASSD_INTPMR
,
211 CLASSD_INTPMR_ATTL_SHIFT
, CLASSD_INTPMR_ATTR_SHIFT
,
212 78, 1, classd_digital_tlv
),
214 SOC_SINGLE("Deemphasis Switch", CLASSD_INTPMR
,
215 CLASSD_INTPMR_DEEMP_SHIFT
, 1, 0),
217 SOC_SINGLE("Mono Switch", CLASSD_INTPMR
, CLASSD_INTPMR_MONO_SHIFT
, 1, 0),
219 SOC_SINGLE("Swap Switch", CLASSD_INTPMR
, CLASSD_INTPMR_SWAP_SHIFT
, 1, 0),
221 SOC_ENUM("Mono Mode", classd_mono_mode_enum
),
223 SOC_ENUM("EQ", classd_eqcfg_enum
),
226 static const char * const pwm_type
[] = {
227 "Single ended", "Differential"
230 static int atmel_classd_component_probe(struct snd_soc_component
*component
)
232 struct snd_soc_card
*card
= snd_soc_component_get_drvdata(component
);
233 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(card
);
234 const struct atmel_classd_pdata
*pdata
= dd
->pdata
;
237 mask
= CLASSD_MR_PWMTYP_MASK
;
238 val
= pdata
->pwm_type
<< CLASSD_MR_PWMTYP_SHIFT
;
240 mask
|= CLASSD_MR_NON_OVERLAP_MASK
;
241 if (pdata
->non_overlap_enable
) {
242 val
|= (CLASSD_MR_NON_OVERLAP_EN
243 << CLASSD_MR_NON_OVERLAP_SHIFT
);
245 mask
|= CLASSD_MR_NOVR_VAL_MASK
;
246 switch (pdata
->non_overlap_time
) {
248 val
|= (CLASSD_MR_NOVR_VAL_5NS
249 << CLASSD_MR_NOVR_VAL_SHIFT
);
252 val
|= (CLASSD_MR_NOVR_VAL_10NS
253 << CLASSD_MR_NOVR_VAL_SHIFT
);
256 val
|= (CLASSD_MR_NOVR_VAL_15NS
257 << CLASSD_MR_NOVR_VAL_SHIFT
);
260 val
|= (CLASSD_MR_NOVR_VAL_20NS
261 << CLASSD_MR_NOVR_VAL_SHIFT
);
264 val
|= (CLASSD_MR_NOVR_VAL_10NS
265 << CLASSD_MR_NOVR_VAL_SHIFT
);
266 dev_warn(component
->dev
,
267 "non-overlapping value %d is invalid, the default value 10 is specified\n",
268 pdata
->non_overlap_time
);
273 snd_soc_component_update_bits(component
, CLASSD_MR
, mask
, val
);
275 dev_info(component
->dev
,
276 "PWM modulation type is %s, non-overlapping is %s\n",
277 pwm_type
[pdata
->pwm_type
],
278 pdata
->non_overlap_enable
?"enabled":"disabled");
283 static int atmel_classd_component_resume(struct snd_soc_component
*component
)
285 struct snd_soc_card
*card
= snd_soc_component_get_drvdata(component
);
286 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(card
);
288 return regcache_sync(dd
->regmap
);
291 static int atmel_classd_cpu_dai_mute_stream(struct snd_soc_dai
*cpu_dai
,
292 int mute
, int direction
)
294 struct snd_soc_component
*component
= cpu_dai
->component
;
297 mask
= CLASSD_MR_LMUTE_MASK
| CLASSD_MR_RMUTE_MASK
;
304 snd_soc_component_update_bits(component
, CLASSD_MR
, mask
, val
);
309 #define CLASSD_GCLK_RATE_11M2896_MPY_8 (112896 * 100 * 8)
310 #define CLASSD_GCLK_RATE_12M288_MPY_8 (12288 * 1000 * 8)
316 unsigned long gclk_rate
;
317 } const sample_rates
[] = {
318 { 8000, CLASSD_INTPMR_FRAME_8K
,
319 CLASSD_INTPMR_DSP_CLK_FREQ_12M288
, CLASSD_GCLK_RATE_12M288_MPY_8
},
320 { 16000, CLASSD_INTPMR_FRAME_16K
,
321 CLASSD_INTPMR_DSP_CLK_FREQ_12M288
, CLASSD_GCLK_RATE_12M288_MPY_8
},
322 { 32000, CLASSD_INTPMR_FRAME_32K
,
323 CLASSD_INTPMR_DSP_CLK_FREQ_12M288
, CLASSD_GCLK_RATE_12M288_MPY_8
},
324 { 48000, CLASSD_INTPMR_FRAME_48K
,
325 CLASSD_INTPMR_DSP_CLK_FREQ_12M288
, CLASSD_GCLK_RATE_12M288_MPY_8
},
326 { 96000, CLASSD_INTPMR_FRAME_96K
,
327 CLASSD_INTPMR_DSP_CLK_FREQ_12M288
, CLASSD_GCLK_RATE_12M288_MPY_8
},
328 { 22050, CLASSD_INTPMR_FRAME_22K
,
329 CLASSD_INTPMR_DSP_CLK_FREQ_11M2896
, CLASSD_GCLK_RATE_11M2896_MPY_8
},
330 { 44100, CLASSD_INTPMR_FRAME_44K
,
331 CLASSD_INTPMR_DSP_CLK_FREQ_11M2896
, CLASSD_GCLK_RATE_11M2896_MPY_8
},
332 { 88200, CLASSD_INTPMR_FRAME_88K
,
333 CLASSD_INTPMR_DSP_CLK_FREQ_11M2896
, CLASSD_GCLK_RATE_11M2896_MPY_8
},
337 atmel_classd_cpu_dai_hw_params(struct snd_pcm_substream
*substream
,
338 struct snd_pcm_hw_params
*params
,
339 struct snd_soc_dai
*cpu_dai
)
341 struct snd_soc_pcm_runtime
*rtd
= asoc_substream_to_rtd(substream
);
342 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(rtd
->card
);
343 struct snd_soc_component
*component
= cpu_dai
->component
;
345 int i
, best
, best_val
, cur_val
, ret
;
348 fs
= params_rate(params
);
351 best_val
= abs(fs
- sample_rates
[0].rate
);
352 for (i
= 1; i
< ARRAY_SIZE(sample_rates
); i
++) {
354 cur_val
= abs(fs
- sample_rates
[i
].rate
);
355 if (cur_val
< best_val
) {
361 dev_dbg(component
->dev
,
362 "Selected SAMPLE_RATE of %dHz, GCLK_RATE of %ldHz\n",
363 sample_rates
[best
].rate
, sample_rates
[best
].gclk_rate
);
365 clk_disable_unprepare(dd
->gclk
);
367 ret
= clk_set_rate(dd
->gclk
, sample_rates
[best
].gclk_rate
);
371 mask
= CLASSD_INTPMR_DSP_CLK_FREQ_MASK
| CLASSD_INTPMR_FRAME_MASK
;
372 val
= (sample_rates
[best
].dsp_clk
<< CLASSD_INTPMR_DSP_CLK_FREQ_SHIFT
)
373 | (sample_rates
[best
].sample_rate
<< CLASSD_INTPMR_FRAME_SHIFT
);
375 snd_soc_component_update_bits(component
, CLASSD_INTPMR
, mask
, val
);
377 return clk_prepare_enable(dd
->gclk
);
381 atmel_classd_cpu_dai_shutdown(struct snd_pcm_substream
*substream
,
382 struct snd_soc_dai
*cpu_dai
)
384 struct snd_soc_pcm_runtime
*rtd
= asoc_substream_to_rtd(substream
);
385 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(rtd
->card
);
387 clk_disable_unprepare(dd
->gclk
);
390 static int atmel_classd_cpu_dai_prepare(struct snd_pcm_substream
*substream
,
391 struct snd_soc_dai
*cpu_dai
)
393 struct snd_soc_component
*component
= cpu_dai
->component
;
395 snd_soc_component_update_bits(component
, CLASSD_MR
,
396 CLASSD_MR_LEN_MASK
| CLASSD_MR_REN_MASK
,
397 (CLASSD_MR_LEN_DIS
<< CLASSD_MR_LEN_SHIFT
)
398 |(CLASSD_MR_REN_DIS
<< CLASSD_MR_REN_SHIFT
));
403 static int atmel_classd_cpu_dai_trigger(struct snd_pcm_substream
*substream
,
404 int cmd
, struct snd_soc_dai
*cpu_dai
)
406 struct snd_soc_component
*component
= cpu_dai
->component
;
409 mask
= CLASSD_MR_LEN_MASK
| CLASSD_MR_REN_MASK
;
412 case SNDRV_PCM_TRIGGER_START
:
413 case SNDRV_PCM_TRIGGER_RESUME
:
414 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
417 case SNDRV_PCM_TRIGGER_STOP
:
418 case SNDRV_PCM_TRIGGER_SUSPEND
:
419 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
420 val
= (CLASSD_MR_LEN_DIS
<< CLASSD_MR_LEN_SHIFT
)
421 | (CLASSD_MR_REN_DIS
<< CLASSD_MR_REN_SHIFT
);
427 snd_soc_component_update_bits(component
, CLASSD_MR
, mask
, val
);
432 static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops
= {
433 .startup
= atmel_classd_cpu_dai_startup
,
434 .shutdown
= atmel_classd_cpu_dai_shutdown
,
435 .mute_stream
= atmel_classd_cpu_dai_mute_stream
,
436 .hw_params
= atmel_classd_cpu_dai_hw_params
,
437 .prepare
= atmel_classd_cpu_dai_prepare
,
438 .trigger
= atmel_classd_cpu_dai_trigger
,
439 .no_capture_mute
= 1,
442 static struct snd_soc_dai_driver atmel_classd_cpu_dai
= {
444 .stream_name
= "Playback",
447 .rates
= ATMEL_CLASSD_RATES
,
448 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
450 .ops
= &atmel_classd_cpu_dai_ops
,
453 static const struct snd_soc_component_driver atmel_classd_cpu_dai_component
= {
454 .name
= "atmel-classd",
455 .probe
= atmel_classd_component_probe
,
456 .resume
= atmel_classd_component_resume
,
457 .controls
= atmel_classd_snd_controls
,
458 .num_controls
= ARRAY_SIZE(atmel_classd_snd_controls
),
460 .use_pmdown_time
= 1,
464 /* ASoC sound card */
465 static int atmel_classd_asoc_card_init(struct device
*dev
,
466 struct snd_soc_card
*card
)
468 struct snd_soc_dai_link
*dai_link
;
469 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(card
);
470 struct snd_soc_dai_link_component
*comp
;
472 dai_link
= devm_kzalloc(dev
, sizeof(*dai_link
), GFP_KERNEL
);
476 comp
= devm_kzalloc(dev
, 3 * sizeof(*comp
), GFP_KERNEL
);
480 dai_link
->cpus
= &comp
[0];
481 dai_link
->codecs
= &comp
[1];
482 dai_link
->platforms
= &comp
[2];
484 dai_link
->num_cpus
= 1;
485 dai_link
->num_codecs
= 1;
486 dai_link
->num_platforms
= 1;
488 dai_link
->name
= "CLASSD";
489 dai_link
->stream_name
= "CLASSD PCM";
490 dai_link
->codecs
->dai_name
= "snd-soc-dummy-dai";
491 dai_link
->cpus
->dai_name
= dev_name(dev
);
492 dai_link
->codecs
->name
= "snd-soc-dummy";
493 dai_link
->platforms
->name
= dev_name(dev
);
495 card
->dai_link
= dai_link
;
497 card
->name
= dd
->pdata
->card_name
;
503 /* regmap configuration */
504 static const struct reg_default atmel_classd_reg_defaults
[] = {
505 { CLASSD_INTPMR
, 0x00301212 },
508 #define ATMEL_CLASSD_REG_MAX 0xE4
509 static const struct regmap_config atmel_classd_regmap_config
= {
513 .max_register
= ATMEL_CLASSD_REG_MAX
,
515 .cache_type
= REGCACHE_FLAT
,
516 .reg_defaults
= atmel_classd_reg_defaults
,
517 .num_reg_defaults
= ARRAY_SIZE(atmel_classd_reg_defaults
),
520 static int atmel_classd_probe(struct platform_device
*pdev
)
522 struct device
*dev
= &pdev
->dev
;
523 struct atmel_classd
*dd
;
524 struct resource
*res
;
525 void __iomem
*io_base
;
526 const struct atmel_classd_pdata
*pdata
;
527 struct snd_soc_card
*card
;
530 pdata
= dev_get_platdata(dev
);
532 pdata
= atmel_classd_dt_init(dev
);
534 return PTR_ERR(pdata
);
537 dd
= devm_kzalloc(dev
, sizeof(*dd
), GFP_KERNEL
);
543 dd
->irq
= platform_get_irq(pdev
, 0);
547 dd
->pclk
= devm_clk_get(dev
, "pclk");
548 if (IS_ERR(dd
->pclk
)) {
549 ret
= PTR_ERR(dd
->pclk
);
550 dev_err(dev
, "failed to get peripheral clock: %d\n", ret
);
554 dd
->gclk
= devm_clk_get(dev
, "gclk");
555 if (IS_ERR(dd
->gclk
)) {
556 ret
= PTR_ERR(dd
->gclk
);
557 dev_err(dev
, "failed to get GCK clock: %d\n", ret
);
561 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
562 io_base
= devm_ioremap_resource(dev
, res
);
564 return PTR_ERR(io_base
);
566 dd
->phy_base
= res
->start
;
569 dd
->regmap
= devm_regmap_init_mmio(dev
, io_base
,
570 &atmel_classd_regmap_config
);
571 if (IS_ERR(dd
->regmap
)) {
572 ret
= PTR_ERR(dd
->regmap
);
573 dev_err(dev
, "failed to init register map: %d\n", ret
);
577 ret
= devm_snd_soc_register_component(dev
,
578 &atmel_classd_cpu_dai_component
,
579 &atmel_classd_cpu_dai
, 1);
581 dev_err(dev
, "could not register CPU DAI: %d\n", ret
);
585 ret
= devm_snd_dmaengine_pcm_register(dev
,
586 &atmel_classd_dmaengine_pcm_config
,
589 dev_err(dev
, "could not register platform: %d\n", ret
);
593 /* register sound card */
594 card
= devm_kzalloc(dev
, sizeof(*card
), GFP_KERNEL
);
597 goto unregister_codec
;
600 snd_soc_card_set_drvdata(card
, dd
);
602 ret
= atmel_classd_asoc_card_init(dev
, card
);
604 dev_err(dev
, "failed to init sound card\n");
605 goto unregister_codec
;
608 ret
= devm_snd_soc_register_card(dev
, card
);
610 dev_err(dev
, "failed to register sound card: %d\n", ret
);
611 goto unregister_codec
;
620 static int atmel_classd_remove(struct platform_device
*pdev
)
625 static struct platform_driver atmel_classd_driver
= {
627 .name
= "atmel-classd",
628 .of_match_table
= of_match_ptr(atmel_classd_of_match
),
629 .pm
= &snd_soc_pm_ops
,
631 .probe
= atmel_classd_probe
,
632 .remove
= atmel_classd_remove
,
634 module_platform_driver(atmel_classd_driver
);
636 MODULE_DESCRIPTION("Atmel ClassD driver under ALSA SoC architecture");
637 MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>");
638 MODULE_LICENSE("GPL");