1 /* Atmel ALSA SoC Audio Class D Amplifier (CLASSD) driver
3 * Copyright (C) 2015 Atmel
5 * Author: Songjun Wu <songjun.wu@atmel.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 or later
9 * as published by the Free Software Foundation.
13 #include <linux/clk.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/regmap.h>
17 #include <sound/core.h>
18 #include <sound/dmaengine_pcm.h>
19 #include <sound/pcm_params.h>
20 #include <sound/tlv.h>
21 #include "atmel-classd.h"
23 struct atmel_classd_pdata
{
24 bool non_overlap_enable
;
27 const char *card_name
;
32 struct regmap
*regmap
;
36 const struct atmel_classd_pdata
*pdata
;
40 static const struct of_device_id atmel_classd_of_match
[] = {
42 .compatible
= "atmel,sama5d2-classd",
47 MODULE_DEVICE_TABLE(of
, atmel_classd_of_match
);
49 static struct atmel_classd_pdata
*atmel_classd_dt_init(struct device
*dev
)
51 struct device_node
*np
= dev
->of_node
;
52 struct atmel_classd_pdata
*pdata
;
57 dev_err(dev
, "device node not found\n");
58 return ERR_PTR(-EINVAL
);
61 pdata
= devm_kzalloc(dev
, sizeof(*pdata
), GFP_KERNEL
);
63 return ERR_PTR(-ENOMEM
);
65 ret
= of_property_read_string(np
, "atmel,pwm-type", &pwm_type
);
66 if ((ret
== 0) && (strcmp(pwm_type
, "diff") == 0))
67 pdata
->pwm_type
= CLASSD_MR_PWMTYP_DIFF
;
69 pdata
->pwm_type
= CLASSD_MR_PWMTYP_SINGLE
;
71 ret
= of_property_read_u32(np
,
72 "atmel,non-overlap-time", &pdata
->non_overlap_time
);
74 pdata
->non_overlap_enable
= false;
76 pdata
->non_overlap_enable
= true;
78 ret
= of_property_read_string(np
, "atmel,model", &pdata
->card_name
);
80 pdata
->card_name
= "CLASSD";
85 static inline struct atmel_classd_pdata
*
86 atmel_classd_dt_init(struct device
*dev
)
88 return ERR_PTR(-EINVAL
);
92 #define ATMEL_CLASSD_RATES (SNDRV_PCM_RATE_8000 \
93 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 \
94 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 \
95 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 \
96 | SNDRV_PCM_RATE_96000)
98 static const struct snd_pcm_hardware atmel_classd_hw
= {
99 .info
= SNDRV_PCM_INFO_MMAP
100 | SNDRV_PCM_INFO_MMAP_VALID
101 | SNDRV_PCM_INFO_INTERLEAVED
102 | SNDRV_PCM_INFO_RESUME
103 | SNDRV_PCM_INFO_PAUSE
,
104 .formats
= (SNDRV_PCM_FMTBIT_S16_LE
),
105 .rates
= ATMEL_CLASSD_RATES
,
110 .buffer_bytes_max
= 64 * 1024,
111 .period_bytes_min
= 256,
112 .period_bytes_max
= 32 * 1024,
117 #define ATMEL_CLASSD_PREALLOC_BUF_SIZE (64 * 1024)
119 /* cpu dai component */
120 static int atmel_classd_cpu_dai_startup(struct snd_pcm_substream
*substream
,
121 struct snd_soc_dai
*cpu_dai
)
123 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
124 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(rtd
->card
);
126 regmap_write(dd
->regmap
, CLASSD_THR
, 0x0);
128 return clk_prepare_enable(dd
->pclk
);
131 static void atmel_classd_cpu_dai_shutdown(struct snd_pcm_substream
*substream
,
132 struct snd_soc_dai
*cpu_dai
)
134 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
135 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(rtd
->card
);
137 clk_disable_unprepare(dd
->pclk
);
140 static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops
= {
141 .startup
= atmel_classd_cpu_dai_startup
,
142 .shutdown
= atmel_classd_cpu_dai_shutdown
,
145 static struct snd_soc_dai_driver atmel_classd_cpu_dai
= {
149 .rates
= ATMEL_CLASSD_RATES
,
150 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,},
151 .ops
= &atmel_classd_cpu_dai_ops
,
154 static const struct snd_soc_component_driver atmel_classd_cpu_dai_component
= {
155 .name
= "atmel-classd",
160 atmel_classd_platform_configure_dma(struct snd_pcm_substream
*substream
,
161 struct snd_pcm_hw_params
*params
,
162 struct dma_slave_config
*slave_config
)
164 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
165 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(rtd
->card
);
167 if (params_physical_width(params
) != 16) {
168 dev_err(rtd
->platform
->dev
,
169 "only supports 16-bit audio data\n");
173 if (params_channels(params
) == 1)
174 slave_config
->dst_addr_width
= DMA_SLAVE_BUSWIDTH_2_BYTES
;
176 slave_config
->dst_addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
178 slave_config
->direction
= DMA_MEM_TO_DEV
;
179 slave_config
->dst_addr
= dd
->phy_base
+ CLASSD_THR
;
180 slave_config
->dst_maxburst
= 1;
181 slave_config
->src_maxburst
= 1;
182 slave_config
->device_fc
= false;
187 static const struct snd_dmaengine_pcm_config
188 atmel_classd_dmaengine_pcm_config
= {
189 .prepare_slave_config
= atmel_classd_platform_configure_dma
,
190 .pcm_hardware
= &atmel_classd_hw
,
191 .prealloc_buffer_size
= ATMEL_CLASSD_PREALLOC_BUF_SIZE
,
195 static const char * const mono_mode_text
[] = {
196 "mix", "sat", "left", "right"
199 static SOC_ENUM_SINGLE_DECL(classd_mono_mode_enum
,
200 CLASSD_INTPMR
, CLASSD_INTPMR_MONO_MODE_SHIFT
,
203 static const char * const eqcfg_text
[] = {
204 "Treble-12dB", "Treble-6dB",
205 "Medium-8dB", "Medium-3dB",
206 "Bass-12dB", "Bass-6dB",
208 "Bass+6dB", "Bass+12dB",
209 "Medium+3dB", "Medium+8dB",
210 "Treble+6dB", "Treble+12dB",
213 static const unsigned int eqcfg_value
[] = {
214 CLASSD_INTPMR_EQCFG_T_CUT_12
, CLASSD_INTPMR_EQCFG_T_CUT_6
,
215 CLASSD_INTPMR_EQCFG_M_CUT_8
, CLASSD_INTPMR_EQCFG_M_CUT_3
,
216 CLASSD_INTPMR_EQCFG_B_CUT_12
, CLASSD_INTPMR_EQCFG_B_CUT_6
,
217 CLASSD_INTPMR_EQCFG_FLAT
,
218 CLASSD_INTPMR_EQCFG_B_BOOST_6
, CLASSD_INTPMR_EQCFG_B_BOOST_12
,
219 CLASSD_INTPMR_EQCFG_M_BOOST_3
, CLASSD_INTPMR_EQCFG_M_BOOST_8
,
220 CLASSD_INTPMR_EQCFG_T_BOOST_6
, CLASSD_INTPMR_EQCFG_T_BOOST_12
,
223 static SOC_VALUE_ENUM_SINGLE_DECL(classd_eqcfg_enum
,
224 CLASSD_INTPMR
, CLASSD_INTPMR_EQCFG_SHIFT
, 0xf,
225 eqcfg_text
, eqcfg_value
);
227 static const DECLARE_TLV_DB_SCALE(classd_digital_tlv
, -7800, 100, 1);
229 static const struct snd_kcontrol_new atmel_classd_snd_controls
[] = {
230 SOC_DOUBLE_TLV("Playback Volume", CLASSD_INTPMR
,
231 CLASSD_INTPMR_ATTL_SHIFT
, CLASSD_INTPMR_ATTR_SHIFT
,
232 78, 1, classd_digital_tlv
),
234 SOC_SINGLE("Deemphasis Switch", CLASSD_INTPMR
,
235 CLASSD_INTPMR_DEEMP_SHIFT
, 1, 0),
237 SOC_SINGLE("Mono Switch", CLASSD_INTPMR
, CLASSD_INTPMR_MONO_SHIFT
, 1, 0),
239 SOC_SINGLE("Swap Switch", CLASSD_INTPMR
, CLASSD_INTPMR_SWAP_SHIFT
, 1, 0),
241 SOC_ENUM("Mono Mode", classd_mono_mode_enum
),
243 SOC_ENUM("EQ", classd_eqcfg_enum
),
246 static const char * const pwm_type
[] = {
247 "Single ended", "Differential"
250 static int atmel_classd_codec_probe(struct snd_soc_codec
*codec
)
252 struct snd_soc_card
*card
= snd_soc_codec_get_drvdata(codec
);
253 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(card
);
254 const struct atmel_classd_pdata
*pdata
= dd
->pdata
;
257 mask
= CLASSD_MR_PWMTYP_MASK
;
258 val
= pdata
->pwm_type
<< CLASSD_MR_PWMTYP_SHIFT
;
260 mask
|= CLASSD_MR_NON_OVERLAP_MASK
;
261 if (pdata
->non_overlap_enable
) {
262 val
|= (CLASSD_MR_NON_OVERLAP_EN
263 << CLASSD_MR_NON_OVERLAP_SHIFT
);
265 mask
|= CLASSD_MR_NOVR_VAL_MASK
;
266 switch (pdata
->non_overlap_time
) {
268 val
|= (CLASSD_MR_NOVR_VAL_5NS
269 << CLASSD_MR_NOVR_VAL_SHIFT
);
272 val
|= (CLASSD_MR_NOVR_VAL_10NS
273 << CLASSD_MR_NOVR_VAL_SHIFT
);
276 val
|= (CLASSD_MR_NOVR_VAL_15NS
277 << CLASSD_MR_NOVR_VAL_SHIFT
);
280 val
|= (CLASSD_MR_NOVR_VAL_20NS
281 << CLASSD_MR_NOVR_VAL_SHIFT
);
284 val
|= (CLASSD_MR_NOVR_VAL_10NS
285 << CLASSD_MR_NOVR_VAL_SHIFT
);
287 "non-overlapping value %d is invalid, the default value 10 is specified\n",
288 pdata
->non_overlap_time
);
293 snd_soc_update_bits(codec
, CLASSD_MR
, mask
, val
);
296 "PWM modulation type is %s, non-overlapping is %s\n",
297 pwm_type
[pdata
->pwm_type
],
298 pdata
->non_overlap_enable
?"enabled":"disabled");
303 static int atmel_classd_codec_resume(struct snd_soc_codec
*codec
)
305 struct snd_soc_card
*card
= snd_soc_codec_get_drvdata(codec
);
306 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(card
);
308 return regcache_sync(dd
->regmap
);
311 static struct snd_soc_codec_driver soc_codec_dev_classd
= {
312 .probe
= atmel_classd_codec_probe
,
313 .resume
= atmel_classd_codec_resume
,
314 .component_driver
= {
315 .controls
= atmel_classd_snd_controls
,
316 .num_controls
= ARRAY_SIZE(atmel_classd_snd_controls
),
320 /* codec dai component */
321 static int atmel_classd_codec_dai_startup(struct snd_pcm_substream
*substream
,
322 struct snd_soc_dai
*codec_dai
)
324 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
325 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(rtd
->card
);
327 return clk_prepare_enable(dd
->gclk
);
330 static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai
*codec_dai
,
333 struct snd_soc_codec
*codec
= codec_dai
->codec
;
336 mask
= CLASSD_MR_LMUTE_MASK
| CLASSD_MR_RMUTE_MASK
;
343 snd_soc_update_bits(codec
, CLASSD_MR
, mask
, val
);
348 #define CLASSD_GCLK_RATE_11M2896_MPY_8 (112896 * 100 * 8)
349 #define CLASSD_GCLK_RATE_12M288_MPY_8 (12288 * 1000 * 8)
355 unsigned long gclk_rate
;
356 } const sample_rates
[] = {
357 { 8000, CLASSD_INTPMR_FRAME_8K
,
358 CLASSD_INTPMR_DSP_CLK_FREQ_12M288
, CLASSD_GCLK_RATE_12M288_MPY_8
},
359 { 16000, CLASSD_INTPMR_FRAME_16K
,
360 CLASSD_INTPMR_DSP_CLK_FREQ_12M288
, CLASSD_GCLK_RATE_12M288_MPY_8
},
361 { 32000, CLASSD_INTPMR_FRAME_32K
,
362 CLASSD_INTPMR_DSP_CLK_FREQ_12M288
, CLASSD_GCLK_RATE_12M288_MPY_8
},
363 { 48000, CLASSD_INTPMR_FRAME_48K
,
364 CLASSD_INTPMR_DSP_CLK_FREQ_12M288
, CLASSD_GCLK_RATE_12M288_MPY_8
},
365 { 96000, CLASSD_INTPMR_FRAME_96K
,
366 CLASSD_INTPMR_DSP_CLK_FREQ_12M288
, CLASSD_GCLK_RATE_12M288_MPY_8
},
367 { 22050, CLASSD_INTPMR_FRAME_22K
,
368 CLASSD_INTPMR_DSP_CLK_FREQ_11M2896
, CLASSD_GCLK_RATE_11M2896_MPY_8
},
369 { 44100, CLASSD_INTPMR_FRAME_44K
,
370 CLASSD_INTPMR_DSP_CLK_FREQ_11M2896
, CLASSD_GCLK_RATE_11M2896_MPY_8
},
371 { 88200, CLASSD_INTPMR_FRAME_88K
,
372 CLASSD_INTPMR_DSP_CLK_FREQ_11M2896
, CLASSD_GCLK_RATE_11M2896_MPY_8
},
376 atmel_classd_codec_dai_hw_params(struct snd_pcm_substream
*substream
,
377 struct snd_pcm_hw_params
*params
,
378 struct snd_soc_dai
*codec_dai
)
380 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
381 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(rtd
->card
);
382 struct snd_soc_codec
*codec
= codec_dai
->codec
;
384 int i
, best
, best_val
, cur_val
, ret
;
387 fs
= params_rate(params
);
390 best_val
= abs(fs
- sample_rates
[0].rate
);
391 for (i
= 1; i
< ARRAY_SIZE(sample_rates
); i
++) {
393 cur_val
= abs(fs
- sample_rates
[i
].rate
);
394 if (cur_val
< best_val
) {
401 "Selected SAMPLE_RATE of %dHz, GCLK_RATE of %ldHz\n",
402 sample_rates
[best
].rate
, sample_rates
[best
].gclk_rate
);
404 clk_disable_unprepare(dd
->gclk
);
406 ret
= clk_set_rate(dd
->gclk
, sample_rates
[best
].gclk_rate
);
410 mask
= CLASSD_INTPMR_DSP_CLK_FREQ_MASK
| CLASSD_INTPMR_FRAME_MASK
;
411 val
= (sample_rates
[best
].dsp_clk
<< CLASSD_INTPMR_DSP_CLK_FREQ_SHIFT
)
412 | (sample_rates
[best
].sample_rate
<< CLASSD_INTPMR_FRAME_SHIFT
);
414 snd_soc_update_bits(codec
, CLASSD_INTPMR
, mask
, val
);
416 return clk_prepare_enable(dd
->gclk
);
420 atmel_classd_codec_dai_shutdown(struct snd_pcm_substream
*substream
,
421 struct snd_soc_dai
*codec_dai
)
423 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
424 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(rtd
->card
);
426 clk_disable_unprepare(dd
->gclk
);
429 static int atmel_classd_codec_dai_prepare(struct snd_pcm_substream
*substream
,
430 struct snd_soc_dai
*codec_dai
)
432 struct snd_soc_codec
*codec
= codec_dai
->codec
;
434 snd_soc_update_bits(codec
, CLASSD_MR
,
435 CLASSD_MR_LEN_MASK
| CLASSD_MR_REN_MASK
,
436 (CLASSD_MR_LEN_DIS
<< CLASSD_MR_LEN_SHIFT
)
437 |(CLASSD_MR_REN_DIS
<< CLASSD_MR_REN_SHIFT
));
442 static int atmel_classd_codec_dai_trigger(struct snd_pcm_substream
*substream
,
443 int cmd
, struct snd_soc_dai
*codec_dai
)
445 struct snd_soc_codec
*codec
= codec_dai
->codec
;
448 mask
= CLASSD_MR_LEN_MASK
| CLASSD_MR_REN_MASK
;
451 case SNDRV_PCM_TRIGGER_START
:
452 case SNDRV_PCM_TRIGGER_RESUME
:
453 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
456 case SNDRV_PCM_TRIGGER_STOP
:
457 case SNDRV_PCM_TRIGGER_SUSPEND
:
458 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
459 val
= (CLASSD_MR_LEN_DIS
<< CLASSD_MR_LEN_SHIFT
)
460 | (CLASSD_MR_REN_DIS
<< CLASSD_MR_REN_SHIFT
);
466 snd_soc_update_bits(codec
, CLASSD_MR
, mask
, val
);
471 static const struct snd_soc_dai_ops atmel_classd_codec_dai_ops
= {
472 .digital_mute
= atmel_classd_codec_dai_digital_mute
,
473 .startup
= atmel_classd_codec_dai_startup
,
474 .shutdown
= atmel_classd_codec_dai_shutdown
,
475 .hw_params
= atmel_classd_codec_dai_hw_params
,
476 .prepare
= atmel_classd_codec_dai_prepare
,
477 .trigger
= atmel_classd_codec_dai_trigger
,
480 #define ATMEL_CLASSD_CODEC_DAI_NAME "atmel-classd-hifi"
482 static struct snd_soc_dai_driver atmel_classd_codec_dai
= {
483 .name
= ATMEL_CLASSD_CODEC_DAI_NAME
,
485 .stream_name
= "Playback",
488 .rates
= ATMEL_CLASSD_RATES
,
489 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
491 .ops
= &atmel_classd_codec_dai_ops
,
494 /* ASoC sound card */
495 static int atmel_classd_asoc_card_init(struct device
*dev
,
496 struct snd_soc_card
*card
)
498 struct snd_soc_dai_link
*dai_link
;
499 struct atmel_classd
*dd
= snd_soc_card_get_drvdata(card
);
501 dai_link
= devm_kzalloc(dev
, sizeof(*dai_link
), GFP_KERNEL
);
505 dai_link
->name
= "CLASSD";
506 dai_link
->stream_name
= "CLASSD PCM";
507 dai_link
->codec_dai_name
= ATMEL_CLASSD_CODEC_DAI_NAME
;
508 dai_link
->cpu_dai_name
= dev_name(dev
);
509 dai_link
->codec_name
= dev_name(dev
);
510 dai_link
->platform_name
= dev_name(dev
);
512 card
->dai_link
= dai_link
;
514 card
->name
= dd
->pdata
->card_name
;
520 /* regmap configuration */
521 static const struct reg_default atmel_classd_reg_defaults
[] = {
522 { CLASSD_INTPMR
, 0x00301212 },
525 #define ATMEL_CLASSD_REG_MAX 0xE4
526 static const struct regmap_config atmel_classd_regmap_config
= {
530 .max_register
= ATMEL_CLASSD_REG_MAX
,
532 .cache_type
= REGCACHE_FLAT
,
533 .reg_defaults
= atmel_classd_reg_defaults
,
534 .num_reg_defaults
= ARRAY_SIZE(atmel_classd_reg_defaults
),
537 static int atmel_classd_probe(struct platform_device
*pdev
)
539 struct device
*dev
= &pdev
->dev
;
540 struct atmel_classd
*dd
;
541 struct resource
*res
;
542 void __iomem
*io_base
;
543 const struct atmel_classd_pdata
*pdata
;
544 struct snd_soc_card
*card
;
547 pdata
= dev_get_platdata(dev
);
549 pdata
= atmel_classd_dt_init(dev
);
551 return PTR_ERR(pdata
);
554 dd
= devm_kzalloc(dev
, sizeof(*dd
), GFP_KERNEL
);
560 dd
->irq
= platform_get_irq(pdev
, 0);
563 dev_err(dev
, "failed to could not get irq: %d\n", ret
);
567 dd
->pclk
= devm_clk_get(dev
, "pclk");
568 if (IS_ERR(dd
->pclk
)) {
569 ret
= PTR_ERR(dd
->pclk
);
570 dev_err(dev
, "failed to get peripheral clock: %d\n", ret
);
574 dd
->gclk
= devm_clk_get(dev
, "gclk");
575 if (IS_ERR(dd
->gclk
)) {
576 ret
= PTR_ERR(dd
->gclk
);
577 dev_err(dev
, "failed to get GCK clock: %d\n", ret
);
581 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
582 io_base
= devm_ioremap_resource(dev
, res
);
583 if (IS_ERR(io_base
)) {
584 ret
= PTR_ERR(io_base
);
585 dev_err(dev
, "failed to remap register memory: %d\n", ret
);
589 dd
->phy_base
= res
->start
;
591 dd
->regmap
= devm_regmap_init_mmio(dev
, io_base
,
592 &atmel_classd_regmap_config
);
593 if (IS_ERR(dd
->regmap
)) {
594 ret
= PTR_ERR(dd
->regmap
);
595 dev_err(dev
, "failed to init register map: %d\n", ret
);
599 ret
= devm_snd_soc_register_component(dev
,
600 &atmel_classd_cpu_dai_component
,
601 &atmel_classd_cpu_dai
, 1);
603 dev_err(dev
, "could not register CPU DAI: %d\n", ret
);
607 ret
= devm_snd_dmaengine_pcm_register(dev
,
608 &atmel_classd_dmaengine_pcm_config
,
611 dev_err(dev
, "could not register platform: %d\n", ret
);
615 ret
= snd_soc_register_codec(dev
, &soc_codec_dev_classd
,
616 &atmel_classd_codec_dai
, 1);
618 dev_err(dev
, "could not register codec: %d\n", ret
);
622 /* register sound card */
623 card
= devm_kzalloc(dev
, sizeof(*card
), GFP_KERNEL
);
626 goto unregister_codec
;
629 snd_soc_card_set_drvdata(card
, dd
);
631 ret
= atmel_classd_asoc_card_init(dev
, card
);
633 dev_err(dev
, "failed to init sound card\n");
634 goto unregister_codec
;
637 ret
= devm_snd_soc_register_card(dev
, card
);
639 dev_err(dev
, "failed to register sound card: %d\n", ret
);
640 goto unregister_codec
;
646 snd_soc_unregister_codec(dev
);
650 static int atmel_classd_remove(struct platform_device
*pdev
)
652 snd_soc_unregister_codec(&pdev
->dev
);
656 static struct platform_driver atmel_classd_driver
= {
658 .name
= "atmel-classd",
659 .of_match_table
= of_match_ptr(atmel_classd_of_match
),
660 .pm
= &snd_soc_pm_ops
,
662 .probe
= atmel_classd_probe
,
663 .remove
= atmel_classd_remove
,
665 module_platform_driver(atmel_classd_driver
);
667 MODULE_DESCRIPTION("Atmel ClassD driver under ALSA SoC architecture");
668 MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>");
669 MODULE_LICENSE("GPL");