Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Atmel ALSA SoC Audio Class D Amplifier (CLASSD) driver
0003  *
0004  * Copyright (C) 2015 Atmel
0005  *
0006  * Author: Songjun Wu <songjun.wu@atmel.com>
0007  */
0008 
0009 #include <linux/of.h>
0010 #include <linux/clk.h>
0011 #include <linux/module.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/regmap.h>
0014 #include <sound/core.h>
0015 #include <sound/dmaengine_pcm.h>
0016 #include <sound/pcm_params.h>
0017 #include <sound/tlv.h>
0018 #include "atmel-classd.h"
0019 
0020 struct atmel_classd_pdata {
0021     bool non_overlap_enable;
0022     int non_overlap_time;
0023     int pwm_type;
0024     const char *card_name;
0025 };
0026 
0027 struct atmel_classd {
0028     dma_addr_t phy_base;
0029     struct regmap *regmap;
0030     struct clk *pclk;
0031     struct clk *gclk;
0032     struct device *dev;
0033     int irq;
0034     const struct atmel_classd_pdata *pdata;
0035 };
0036 
0037 #ifdef CONFIG_OF
0038 static const struct of_device_id atmel_classd_of_match[] = {
0039     {
0040         .compatible = "atmel,sama5d2-classd",
0041     }, {
0042         /* sentinel */
0043     }
0044 };
0045 MODULE_DEVICE_TABLE(of, atmel_classd_of_match);
0046 
0047 static struct atmel_classd_pdata *atmel_classd_dt_init(struct device *dev)
0048 {
0049     struct device_node *np = dev->of_node;
0050     struct atmel_classd_pdata *pdata;
0051     const char *pwm_type_s;
0052     int ret;
0053 
0054     if (!np) {
0055         dev_err(dev, "device node not found\n");
0056         return ERR_PTR(-EINVAL);
0057     }
0058 
0059     pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
0060     if (!pdata)
0061         return ERR_PTR(-ENOMEM);
0062 
0063     ret = of_property_read_string(np, "atmel,pwm-type", &pwm_type_s);
0064     if ((ret == 0) && (strcmp(pwm_type_s, "diff") == 0))
0065         pdata->pwm_type = CLASSD_MR_PWMTYP_DIFF;
0066     else
0067         pdata->pwm_type = CLASSD_MR_PWMTYP_SINGLE;
0068 
0069     ret = of_property_read_u32(np,
0070             "atmel,non-overlap-time", &pdata->non_overlap_time);
0071     if (ret)
0072         pdata->non_overlap_enable = false;
0073     else
0074         pdata->non_overlap_enable = true;
0075 
0076     ret = of_property_read_string(np, "atmel,model", &pdata->card_name);
0077     if (ret)
0078         pdata->card_name = "CLASSD";
0079 
0080     return pdata;
0081 }
0082 #else
0083 static inline struct atmel_classd_pdata *
0084 atmel_classd_dt_init(struct device *dev)
0085 {
0086     return ERR_PTR(-EINVAL);
0087 }
0088 #endif
0089 
0090 #define ATMEL_CLASSD_RATES (SNDRV_PCM_RATE_8000 \
0091             | SNDRV_PCM_RATE_16000  | SNDRV_PCM_RATE_22050 \
0092             | SNDRV_PCM_RATE_32000  | SNDRV_PCM_RATE_44100 \
0093             | SNDRV_PCM_RATE_48000  | SNDRV_PCM_RATE_88200 \
0094             | SNDRV_PCM_RATE_96000)
0095 
0096 static const struct snd_pcm_hardware atmel_classd_hw = {
0097     .info           = SNDRV_PCM_INFO_MMAP
0098                 | SNDRV_PCM_INFO_MMAP_VALID
0099                 | SNDRV_PCM_INFO_INTERLEAVED
0100                 | SNDRV_PCM_INFO_RESUME
0101                 | SNDRV_PCM_INFO_PAUSE,
0102     .formats        = (SNDRV_PCM_FMTBIT_S16_LE),
0103     .rates          = ATMEL_CLASSD_RATES,
0104     .rate_min       = 8000,
0105     .rate_max       = 96000,
0106     .channels_min       = 1,
0107     .channels_max       = 2,
0108     .buffer_bytes_max   = 64 * 1024,
0109     .period_bytes_min   = 256,
0110     .period_bytes_max   = 32 * 1024,
0111     .periods_min        = 2,
0112     .periods_max        = 256,
0113 };
0114 
0115 #define ATMEL_CLASSD_PREALLOC_BUF_SIZE  (64 * 1024)
0116 
0117 /* cpu dai component */
0118 static int atmel_classd_cpu_dai_startup(struct snd_pcm_substream *substream,
0119                     struct snd_soc_dai *cpu_dai)
0120 {
0121     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0122     struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
0123     int err;
0124 
0125     regmap_write(dd->regmap, CLASSD_THR, 0x0);
0126 
0127     err = clk_prepare_enable(dd->pclk);
0128     if (err)
0129         return err;
0130     err = clk_prepare_enable(dd->gclk);
0131     if (err) {
0132         clk_disable_unprepare(dd->pclk);
0133         return err;
0134     }
0135     return 0;
0136 }
0137 
0138 /* platform */
0139 static int
0140 atmel_classd_platform_configure_dma(struct snd_pcm_substream *substream,
0141     struct snd_pcm_hw_params *params,
0142     struct dma_slave_config *slave_config)
0143 {
0144     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0145     struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
0146 
0147     if (params_physical_width(params) != 16) {
0148         dev_err(dd->dev,
0149             "only supports 16-bit audio data\n");
0150         return -EINVAL;
0151     }
0152 
0153     if (params_channels(params) == 1)
0154         slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
0155     else
0156         slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0157 
0158     slave_config->direction     = DMA_MEM_TO_DEV;
0159     slave_config->dst_addr      = dd->phy_base + CLASSD_THR;
0160     slave_config->dst_maxburst  = 1;
0161     slave_config->src_maxburst  = 1;
0162     slave_config->device_fc     = false;
0163 
0164     return 0;
0165 }
0166 
0167 static const struct snd_dmaengine_pcm_config
0168 atmel_classd_dmaengine_pcm_config = {
0169     .prepare_slave_config   = atmel_classd_platform_configure_dma,
0170     .pcm_hardware       = &atmel_classd_hw,
0171     .prealloc_buffer_size   = ATMEL_CLASSD_PREALLOC_BUF_SIZE,
0172 };
0173 
0174 /* codec */
0175 static const char * const mono_mode_text[] = {
0176     "mix", "sat", "left", "right"
0177 };
0178 
0179 static SOC_ENUM_SINGLE_DECL(classd_mono_mode_enum,
0180             CLASSD_INTPMR, CLASSD_INTPMR_MONO_MODE_SHIFT,
0181             mono_mode_text);
0182 
0183 static const char * const eqcfg_text[] = {
0184     "Treble-12dB", "Treble-6dB",
0185     "Medium-8dB", "Medium-3dB",
0186     "Bass-12dB", "Bass-6dB",
0187     "0 dB",
0188     "Bass+6dB", "Bass+12dB",
0189     "Medium+3dB", "Medium+8dB",
0190     "Treble+6dB", "Treble+12dB",
0191 };
0192 
0193 static const unsigned int eqcfg_value[] = {
0194     CLASSD_INTPMR_EQCFG_T_CUT_12, CLASSD_INTPMR_EQCFG_T_CUT_6,
0195     CLASSD_INTPMR_EQCFG_M_CUT_8, CLASSD_INTPMR_EQCFG_M_CUT_3,
0196     CLASSD_INTPMR_EQCFG_B_CUT_12, CLASSD_INTPMR_EQCFG_B_CUT_6,
0197     CLASSD_INTPMR_EQCFG_FLAT,
0198     CLASSD_INTPMR_EQCFG_B_BOOST_6, CLASSD_INTPMR_EQCFG_B_BOOST_12,
0199     CLASSD_INTPMR_EQCFG_M_BOOST_3, CLASSD_INTPMR_EQCFG_M_BOOST_8,
0200     CLASSD_INTPMR_EQCFG_T_BOOST_6, CLASSD_INTPMR_EQCFG_T_BOOST_12,
0201 };
0202 
0203 static SOC_VALUE_ENUM_SINGLE_DECL(classd_eqcfg_enum,
0204         CLASSD_INTPMR, CLASSD_INTPMR_EQCFG_SHIFT, 0xf,
0205         eqcfg_text, eqcfg_value);
0206 
0207 static const DECLARE_TLV_DB_SCALE(classd_digital_tlv, -7800, 100, 1);
0208 
0209 static const struct snd_kcontrol_new atmel_classd_snd_controls[] = {
0210 SOC_DOUBLE_TLV("Playback Volume", CLASSD_INTPMR,
0211         CLASSD_INTPMR_ATTL_SHIFT, CLASSD_INTPMR_ATTR_SHIFT,
0212         78, 1, classd_digital_tlv),
0213 
0214 SOC_SINGLE("Deemphasis Switch", CLASSD_INTPMR,
0215         CLASSD_INTPMR_DEEMP_SHIFT, 1, 0),
0216 
0217 SOC_SINGLE("Mono Switch", CLASSD_INTPMR, CLASSD_INTPMR_MONO_SHIFT, 1, 0),
0218 
0219 SOC_SINGLE("Swap Switch", CLASSD_INTPMR, CLASSD_INTPMR_SWAP_SHIFT, 1, 0),
0220 
0221 SOC_ENUM("Mono Mode", classd_mono_mode_enum),
0222 
0223 SOC_ENUM("EQ", classd_eqcfg_enum),
0224 };
0225 
0226 static const char * const pwm_type[] = {
0227     "Single ended", "Differential"
0228 };
0229 
0230 static int atmel_classd_component_probe(struct snd_soc_component *component)
0231 {
0232     struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
0233     struct atmel_classd *dd = snd_soc_card_get_drvdata(card);
0234     const struct atmel_classd_pdata *pdata = dd->pdata;
0235     u32 mask, val;
0236 
0237     mask = CLASSD_MR_PWMTYP_MASK;
0238     val = pdata->pwm_type << CLASSD_MR_PWMTYP_SHIFT;
0239 
0240     mask |= CLASSD_MR_NON_OVERLAP_MASK;
0241     if (pdata->non_overlap_enable) {
0242         val |= (CLASSD_MR_NON_OVERLAP_EN
0243             << CLASSD_MR_NON_OVERLAP_SHIFT);
0244 
0245         mask |= CLASSD_MR_NOVR_VAL_MASK;
0246         switch (pdata->non_overlap_time) {
0247         case 5:
0248             val |= (CLASSD_MR_NOVR_VAL_5NS
0249                 << CLASSD_MR_NOVR_VAL_SHIFT);
0250             break;
0251         case 10:
0252             val |= (CLASSD_MR_NOVR_VAL_10NS
0253                 << CLASSD_MR_NOVR_VAL_SHIFT);
0254             break;
0255         case 15:
0256             val |= (CLASSD_MR_NOVR_VAL_15NS
0257                 << CLASSD_MR_NOVR_VAL_SHIFT);
0258             break;
0259         case 20:
0260             val |= (CLASSD_MR_NOVR_VAL_20NS
0261                 << CLASSD_MR_NOVR_VAL_SHIFT);
0262             break;
0263         default:
0264             val |= (CLASSD_MR_NOVR_VAL_10NS
0265                 << CLASSD_MR_NOVR_VAL_SHIFT);
0266             dev_warn(component->dev,
0267                 "non-overlapping value %d is invalid, the default value 10 is specified\n",
0268                 pdata->non_overlap_time);
0269             break;
0270         }
0271     }
0272 
0273     snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
0274 
0275     dev_info(component->dev,
0276         "PWM modulation type is %s, non-overlapping is %s\n",
0277         pwm_type[pdata->pwm_type],
0278         pdata->non_overlap_enable?"enabled":"disabled");
0279 
0280     return 0;
0281 }
0282 
0283 static int atmel_classd_component_resume(struct snd_soc_component *component)
0284 {
0285     struct snd_soc_card *card = snd_soc_component_get_drvdata(component);
0286     struct atmel_classd *dd = snd_soc_card_get_drvdata(card);
0287 
0288     return regcache_sync(dd->regmap);
0289 }
0290 
0291 static int atmel_classd_cpu_dai_mute_stream(struct snd_soc_dai *cpu_dai,
0292                         int mute, int direction)
0293 {
0294     struct snd_soc_component *component = cpu_dai->component;
0295     u32 mask, val;
0296 
0297     mask = CLASSD_MR_LMUTE_MASK | CLASSD_MR_RMUTE_MASK;
0298 
0299     if (mute)
0300         val = mask;
0301     else
0302         val = 0;
0303 
0304     snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
0305 
0306     return 0;
0307 }
0308 
0309 #define CLASSD_GCLK_RATE_11M2896_MPY_8 (112896 * 100 * 8)
0310 #define CLASSD_GCLK_RATE_12M288_MPY_8  (12288 * 1000 * 8)
0311 
0312 static struct {
0313     int rate;
0314     int sample_rate;
0315     int dsp_clk;
0316     unsigned long gclk_rate;
0317 } const sample_rates[] = {
0318     { 8000,  CLASSD_INTPMR_FRAME_8K,
0319     CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_GCLK_RATE_12M288_MPY_8 },
0320     { 16000, CLASSD_INTPMR_FRAME_16K,
0321     CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_GCLK_RATE_12M288_MPY_8 },
0322     { 32000, CLASSD_INTPMR_FRAME_32K,
0323     CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_GCLK_RATE_12M288_MPY_8 },
0324     { 48000, CLASSD_INTPMR_FRAME_48K,
0325     CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_GCLK_RATE_12M288_MPY_8 },
0326     { 96000, CLASSD_INTPMR_FRAME_96K,
0327     CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_GCLK_RATE_12M288_MPY_8 },
0328     { 22050, CLASSD_INTPMR_FRAME_22K,
0329     CLASSD_INTPMR_DSP_CLK_FREQ_11M2896, CLASSD_GCLK_RATE_11M2896_MPY_8 },
0330     { 44100, CLASSD_INTPMR_FRAME_44K,
0331     CLASSD_INTPMR_DSP_CLK_FREQ_11M2896, CLASSD_GCLK_RATE_11M2896_MPY_8 },
0332     { 88200, CLASSD_INTPMR_FRAME_88K,
0333     CLASSD_INTPMR_DSP_CLK_FREQ_11M2896, CLASSD_GCLK_RATE_11M2896_MPY_8 },
0334 };
0335 
0336 static int
0337 atmel_classd_cpu_dai_hw_params(struct snd_pcm_substream *substream,
0338                    struct snd_pcm_hw_params *params,
0339                    struct snd_soc_dai *cpu_dai)
0340 {
0341     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0342     struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
0343     struct snd_soc_component *component = cpu_dai->component;
0344     int fs;
0345     int i, best, best_val, cur_val, ret;
0346     u32 mask, val;
0347 
0348     fs = params_rate(params);
0349 
0350     best = 0;
0351     best_val = abs(fs - sample_rates[0].rate);
0352     for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
0353         /* Closest match */
0354         cur_val = abs(fs - sample_rates[i].rate);
0355         if (cur_val < best_val) {
0356             best = i;
0357             best_val = cur_val;
0358         }
0359     }
0360 
0361     dev_dbg(component->dev,
0362         "Selected SAMPLE_RATE of %dHz, GCLK_RATE of %ldHz\n",
0363         sample_rates[best].rate, sample_rates[best].gclk_rate);
0364 
0365     clk_disable_unprepare(dd->gclk);
0366 
0367     ret = clk_set_rate(dd->gclk, sample_rates[best].gclk_rate);
0368     if (ret)
0369         return ret;
0370 
0371     mask = CLASSD_INTPMR_DSP_CLK_FREQ_MASK | CLASSD_INTPMR_FRAME_MASK;
0372     val = (sample_rates[best].dsp_clk << CLASSD_INTPMR_DSP_CLK_FREQ_SHIFT)
0373     | (sample_rates[best].sample_rate << CLASSD_INTPMR_FRAME_SHIFT);
0374 
0375     snd_soc_component_update_bits(component, CLASSD_INTPMR, mask, val);
0376 
0377     return clk_prepare_enable(dd->gclk);
0378 }
0379 
0380 static void
0381 atmel_classd_cpu_dai_shutdown(struct snd_pcm_substream *substream,
0382                   struct snd_soc_dai *cpu_dai)
0383 {
0384     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0385     struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card);
0386 
0387     clk_disable_unprepare(dd->gclk);
0388 }
0389 
0390 static int atmel_classd_cpu_dai_prepare(struct snd_pcm_substream *substream,
0391                     struct snd_soc_dai *cpu_dai)
0392 {
0393     struct snd_soc_component *component = cpu_dai->component;
0394 
0395     snd_soc_component_update_bits(component, CLASSD_MR,
0396                 CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK,
0397                 (CLASSD_MR_LEN_DIS << CLASSD_MR_LEN_SHIFT)
0398                 |(CLASSD_MR_REN_DIS << CLASSD_MR_REN_SHIFT));
0399 
0400     return 0;
0401 }
0402 
0403 static int atmel_classd_cpu_dai_trigger(struct snd_pcm_substream *substream,
0404                     int cmd, struct snd_soc_dai *cpu_dai)
0405 {
0406     struct snd_soc_component *component = cpu_dai->component;
0407     u32 mask, val;
0408 
0409     mask = CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK;
0410 
0411     switch (cmd) {
0412     case SNDRV_PCM_TRIGGER_START:
0413     case SNDRV_PCM_TRIGGER_RESUME:
0414     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0415         val = mask;
0416         break;
0417     case SNDRV_PCM_TRIGGER_STOP:
0418     case SNDRV_PCM_TRIGGER_SUSPEND:
0419     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0420         val = (CLASSD_MR_LEN_DIS << CLASSD_MR_LEN_SHIFT)
0421             | (CLASSD_MR_REN_DIS << CLASSD_MR_REN_SHIFT);
0422         break;
0423     default:
0424         return -EINVAL;
0425     }
0426 
0427     snd_soc_component_update_bits(component, CLASSD_MR, mask, val);
0428 
0429     return 0;
0430 }
0431 
0432 static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops = {
0433     .startup        = atmel_classd_cpu_dai_startup,
0434     .shutdown       = atmel_classd_cpu_dai_shutdown,
0435     .mute_stream    = atmel_classd_cpu_dai_mute_stream,
0436     .hw_params  = atmel_classd_cpu_dai_hw_params,
0437     .prepare    = atmel_classd_cpu_dai_prepare,
0438     .trigger    = atmel_classd_cpu_dai_trigger,
0439     .no_capture_mute = 1,
0440 };
0441 
0442 static struct snd_soc_dai_driver atmel_classd_cpu_dai = {
0443     .playback = {
0444         .stream_name    = "Playback",
0445         .channels_min   = 1,
0446         .channels_max   = 2,
0447         .rates      = ATMEL_CLASSD_RATES,
0448         .formats    = SNDRV_PCM_FMTBIT_S16_LE,
0449     },
0450     .ops = &atmel_classd_cpu_dai_ops,
0451 };
0452 
0453 static const struct snd_soc_component_driver atmel_classd_cpu_dai_component = {
0454     .name           = "atmel-classd",
0455     .probe          = atmel_classd_component_probe,
0456     .resume         = atmel_classd_component_resume,
0457     .controls       = atmel_classd_snd_controls,
0458     .num_controls       = ARRAY_SIZE(atmel_classd_snd_controls),
0459     .idle_bias_on       = 1,
0460     .use_pmdown_time    = 1,
0461     .legacy_dai_naming  = 1,
0462 };
0463 
0464 /* ASoC sound card */
0465 static int atmel_classd_asoc_card_init(struct device *dev,
0466                     struct snd_soc_card *card)
0467 {
0468     struct snd_soc_dai_link *dai_link;
0469     struct atmel_classd *dd = snd_soc_card_get_drvdata(card);
0470     struct snd_soc_dai_link_component *comp;
0471 
0472     dai_link = devm_kzalloc(dev, sizeof(*dai_link), GFP_KERNEL);
0473     if (!dai_link)
0474         return -ENOMEM;
0475 
0476     comp = devm_kzalloc(dev, 3 * sizeof(*comp), GFP_KERNEL);
0477     if (!comp)
0478         return -ENOMEM;
0479 
0480     dai_link->cpus      = &comp[0];
0481     dai_link->codecs    = &comp[1];
0482     dai_link->platforms = &comp[2];
0483 
0484     dai_link->num_cpus  = 1;
0485     dai_link->num_codecs    = 1;
0486     dai_link->num_platforms = 1;
0487 
0488     dai_link->name          = "CLASSD";
0489     dai_link->stream_name       = "CLASSD PCM";
0490     dai_link->codecs->dai_name  = "snd-soc-dummy-dai";
0491     dai_link->cpus->dai_name    = dev_name(dev);
0492     dai_link->codecs->name      = "snd-soc-dummy";
0493     dai_link->platforms->name   = dev_name(dev);
0494 
0495     card->dai_link  = dai_link;
0496     card->num_links = 1;
0497     card->name  = dd->pdata->card_name;
0498     card->dev   = dev;
0499 
0500     return 0;
0501 };
0502 
0503 /* regmap configuration */
0504 static const struct reg_default atmel_classd_reg_defaults[] = {
0505     { CLASSD_INTPMR,   0x00301212 },
0506 };
0507 
0508 #define ATMEL_CLASSD_REG_MAX    0xE4
0509 static const struct regmap_config atmel_classd_regmap_config = {
0510     .reg_bits   = 32,
0511     .reg_stride = 4,
0512     .val_bits   = 32,
0513     .max_register   = ATMEL_CLASSD_REG_MAX,
0514 
0515     .cache_type     = REGCACHE_FLAT,
0516     .reg_defaults       = atmel_classd_reg_defaults,
0517     .num_reg_defaults   = ARRAY_SIZE(atmel_classd_reg_defaults),
0518 };
0519 
0520 static int atmel_classd_probe(struct platform_device *pdev)
0521 {
0522     struct device *dev = &pdev->dev;
0523     struct atmel_classd *dd;
0524     struct resource *res;
0525     void __iomem *io_base;
0526     const struct atmel_classd_pdata *pdata;
0527     struct snd_soc_card *card;
0528     int ret;
0529 
0530     pdata = dev_get_platdata(dev);
0531     if (!pdata) {
0532         pdata = atmel_classd_dt_init(dev);
0533         if (IS_ERR(pdata))
0534             return PTR_ERR(pdata);
0535     }
0536 
0537     dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
0538     if (!dd)
0539         return -ENOMEM;
0540 
0541     dd->pdata = pdata;
0542 
0543     dd->irq = platform_get_irq(pdev, 0);
0544     if (dd->irq < 0)
0545         return dd->irq;
0546 
0547     dd->pclk = devm_clk_get(dev, "pclk");
0548     if (IS_ERR(dd->pclk)) {
0549         ret = PTR_ERR(dd->pclk);
0550         dev_err(dev, "failed to get peripheral clock: %d\n", ret);
0551         return ret;
0552     }
0553 
0554     dd->gclk = devm_clk_get(dev, "gclk");
0555     if (IS_ERR(dd->gclk)) {
0556         ret = PTR_ERR(dd->gclk);
0557         dev_err(dev, "failed to get GCK clock: %d\n", ret);
0558         return ret;
0559     }
0560 
0561     io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
0562     if (IS_ERR(io_base))
0563         return PTR_ERR(io_base);
0564 
0565     dd->phy_base = res->start;
0566     dd->dev = dev;
0567 
0568     dd->regmap = devm_regmap_init_mmio(dev, io_base,
0569                     &atmel_classd_regmap_config);
0570     if (IS_ERR(dd->regmap)) {
0571         ret = PTR_ERR(dd->regmap);
0572         dev_err(dev, "failed to init register map: %d\n", ret);
0573         return ret;
0574     }
0575 
0576     ret = devm_snd_soc_register_component(dev,
0577                     &atmel_classd_cpu_dai_component,
0578                     &atmel_classd_cpu_dai, 1);
0579     if (ret) {
0580         dev_err(dev, "could not register CPU DAI: %d\n", ret);
0581         return ret;
0582     }
0583 
0584     ret = devm_snd_dmaengine_pcm_register(dev,
0585                     &atmel_classd_dmaengine_pcm_config,
0586                     0);
0587     if (ret) {
0588         dev_err(dev, "could not register platform: %d\n", ret);
0589         return ret;
0590     }
0591 
0592     /* register sound card */
0593     card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
0594     if (!card) {
0595         ret = -ENOMEM;
0596         goto unregister_codec;
0597     }
0598 
0599     snd_soc_card_set_drvdata(card, dd);
0600 
0601     ret = atmel_classd_asoc_card_init(dev, card);
0602     if (ret) {
0603         dev_err(dev, "failed to init sound card\n");
0604         goto unregister_codec;
0605     }
0606 
0607     ret = devm_snd_soc_register_card(dev, card);
0608     if (ret) {
0609         dev_err(dev, "failed to register sound card: %d\n", ret);
0610         goto unregister_codec;
0611     }
0612 
0613     return 0;
0614 
0615 unregister_codec:
0616     return ret;
0617 }
0618 
0619 static int atmel_classd_remove(struct platform_device *pdev)
0620 {
0621     return 0;
0622 }
0623 
0624 static struct platform_driver atmel_classd_driver = {
0625     .driver = {
0626         .name       = "atmel-classd",
0627         .of_match_table = of_match_ptr(atmel_classd_of_match),
0628         .pm     = &snd_soc_pm_ops,
0629     },
0630     .probe  = atmel_classd_probe,
0631     .remove = atmel_classd_remove,
0632 };
0633 module_platform_driver(atmel_classd_driver);
0634 
0635 MODULE_DESCRIPTION("Atmel ClassD driver under ALSA SoC architecture");
0636 MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>");
0637 MODULE_LICENSE("GPL");