diff options
Diffstat (limited to 'sound/soc/atmel')
| -rw-r--r-- | sound/soc/atmel/Kconfig | 29 | ||||
| -rw-r--r-- | sound/soc/atmel/Makefile | 4 | ||||
| -rw-r--r-- | sound/soc/atmel/atmel-pcm-dma.c | 134 | ||||
| -rw-r--r-- | sound/soc/atmel/atmel-pcm-pdc.c | 68 | ||||
| -rw-r--r-- | sound/soc/atmel/atmel-pcm.c | 15 | ||||
| -rw-r--r-- | sound/soc/atmel/atmel-pcm.h | 6 | ||||
| -rw-r--r-- | sound/soc/atmel/atmel_ssc_dai.c | 145 | ||||
| -rw-r--r-- | sound/soc/atmel/atmel_wm8904.c | 246 | ||||
| -rw-r--r-- | sound/soc/atmel/sam9g20_wm8731.c | 37 | ||||
| -rw-r--r-- | sound/soc/atmel/sam9x5_wm8731.c | 208 | ||||
| -rw-r--r-- | sound/soc/atmel/snd-soc-afeb9260.c | 12 |
11 files changed, 633 insertions, 271 deletions
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index d1b691bf8e2..27e3fc4a536 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -1,6 +1,6 @@ config SND_ATMEL_SOC tristate "SoC Audio for the Atmel System-on-Chip" - depends on ARCH_AT91 + depends on HAS_IOMEM help Say Y or M if you want to add support for codecs attached to the ATMEL SSC interface. You will also need @@ -13,6 +13,7 @@ config SND_ATMEL_SOC_PDC config SND_ATMEL_SOC_DMA tristate depends on SND_ATMEL_SOC + select SND_SOC_GENERIC_DMAENGINE_PCM config SND_ATMEL_SOC_SSC tristate @@ -24,7 +25,7 @@ config SND_ATMEL_SOC_SSC config SND_AT91_SOC_SAM9G20_WM8731 tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" - depends on ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS + depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC select SND_ATMEL_SOC_PDC select SND_ATMEL_SOC_SSC select SND_SOC_WM8731 @@ -32,11 +33,31 @@ config SND_AT91_SOC_SAM9G20_WM8731 Say Y if you want to add support for SoC audio on WM8731-based AT91sam9g20 evaluation board. +config SND_ATMEL_SOC_WM8904 + tristate "Atmel ASoC driver for boards using WM8904 codec" + depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC && I2C + select SND_ATMEL_SOC_SSC + select SND_ATMEL_SOC_DMA + select SND_SOC_WM8904 + help + Say Y if you want to add support for Atmel ASoC driver for boards using + WM8904 codec. + +config SND_AT91_SOC_SAM9X5_WM8731 + tristate "SoC Audio support for WM8731-based at91sam9x5 board" + depends on ATMEL_SSC && SND_ATMEL_SOC && SOC_AT91SAM9X5 + select SND_ATMEL_SOC_SSC + select SND_ATMEL_SOC_DMA + select SND_SOC_WM8731 + help + Say Y if you want to add support for audio SoC on an + at91sam9x5 based board that is using WM8731 codec. + config SND_AT91_SOC_AFEB9260 tristate "SoC Audio support for AFEB9260 board" - depends on ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC + depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC select SND_ATMEL_SOC_PDC select SND_ATMEL_SOC_SSC - select SND_SOC_TLV320AIC23 + select SND_SOC_TLV320AIC23_I2C help Say Y here to support sound on AFEB9260 board. diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index 41967ccb6f4..5baabc8bde3 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -11,6 +11,10 @@ obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o # AT91 Machine Support snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o +snd-atmel-soc-wm8904-objs := atmel_wm8904.o +snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o +obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o +obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c index 30184a4a147..b79a2a86451 100644 --- a/sound/soc/atmel/atmel-pcm-dma.c +++ b/sound/soc/atmel/atmel-pcm-dma.c @@ -50,7 +50,6 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = { SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_PAUSE, - .formats = SNDRV_PCM_FMTBIT_S16_LE, .period_bytes_min = 256, /* lighting DMA overhead */ .period_bytes_max = 2 * 0xffff, /* if 2 bytes format */ .periods_min = 8, @@ -67,9 +66,10 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = { static void atmel_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; struct atmel_pcm_dma_params *prtd; - prtd = snd_dmaengine_pcm_get_data(substream); + prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (ssc_sr & prtd->mask->ssc_error) { if (snd_pcm_running(substream)) @@ -80,7 +80,9 @@ static void atmel_pcm_dma_irq(u32 ssc_sr, /* stop RX and capture: will be enabled again at restart */ ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_disable); + snd_pcm_stream_lock(substream); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(substream); /* now drain RHR and read status to remove xrun condition */ ssc_readx(prtd->ssc->regs, SSC_RHR); @@ -88,150 +90,52 @@ static void atmel_pcm_dma_irq(u32 ssc_sr, } } -/*--------------------------------------------------------------------------*\ - * DMAENGINE operations -\*--------------------------------------------------------------------------*/ -static bool filter(struct dma_chan *chan, void *slave) -{ - struct at_dma_slave *sl = slave; - - if (sl->dma_dev == chan->device->dev) { - chan->private = sl; - return true; - } else { - return false; - } -} - static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; struct atmel_pcm_dma_params *prtd; struct ssc_device *ssc; - struct dma_chan *dma_chan; - struct dma_slave_config slave_config; int ret; - prtd = snd_dmaengine_pcm_get_data(substream); + prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); ssc = prtd->ssc; - ret = snd_hwparams_to_dma_slave_config(substream, params, - &slave_config); + ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config); if (ret) { pr_err("atmel-pcm: hwparams to dma slave configure failed\n"); return ret; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - slave_config.dst_addr = (dma_addr_t)ssc->phybase + SSC_THR; - slave_config.dst_maxburst = 1; + slave_config->dst_addr = ssc->phybase + SSC_THR; + slave_config->dst_maxburst = 1; } else { - slave_config.src_addr = (dma_addr_t)ssc->phybase + SSC_RHR; - slave_config.src_maxburst = 1; - } - - slave_config.device_fc = false; - - dma_chan = snd_dmaengine_pcm_get_chan(substream); - if (dmaengine_slave_config(dma_chan, &slave_config)) { - pr_err("atmel-pcm: failed to configure dma channel\n"); - ret = -EBUSY; - return ret; - } - - return 0; -} - -static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct atmel_pcm_dma_params *prtd; - struct ssc_device *ssc; - struct at_dma_slave *sdata = NULL; - int ret; - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - - prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - ssc = prtd->ssc; - if (ssc->pdev) - sdata = ssc->pdev->dev.platform_data; - - ret = snd_dmaengine_pcm_open(substream, filter, sdata); - if (ret) { - pr_err("atmel-pcm: dmaengine pcm open failed\n"); - return -EINVAL; - } - - snd_dmaengine_pcm_set_data(substream, prtd); - - ret = atmel_pcm_configure_dma(substream, params); - if (ret) { - pr_err("atmel-pcm: failed to configure dmai\n"); - goto err; + slave_config->src_addr = ssc->phybase + SSC_RHR; + slave_config->src_maxburst = 1; } prtd->dma_intr_handler = atmel_pcm_dma_irq; return 0; -err: - snd_dmaengine_pcm_close(substream); - return ret; -} - -static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream) -{ - struct atmel_pcm_dma_params *prtd; - - prtd = snd_dmaengine_pcm_get_data(substream); - - ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error); - ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable); - - return 0; -} - -static int atmel_pcm_open(struct snd_pcm_substream *substream) -{ - snd_soc_set_runtime_hwparams(substream, &atmel_pcm_dma_hardware); - - return 0; } -static int atmel_pcm_close(struct snd_pcm_substream *substream) -{ - snd_dmaengine_pcm_close(substream); - - return 0; -} - -static struct snd_pcm_ops atmel_pcm_ops = { - .open = atmel_pcm_open, - .close = atmel_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = atmel_pcm_hw_params, - .prepare = atmel_pcm_dma_prepare, - .trigger = snd_dmaengine_pcm_trigger, - .pointer = snd_dmaengine_pcm_pointer_no_residue, - .mmap = atmel_pcm_mmap, -}; - -static struct snd_soc_platform_driver atmel_soc_platform = { - .ops = &atmel_pcm_ops, - .pcm_new = atmel_pcm_new, - .pcm_free = atmel_pcm_free, +static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = { + .prepare_slave_config = atmel_pcm_configure_dma, + .pcm_hardware = &atmel_pcm_dma_hardware, + .prealloc_buffer_size = ATMEL_SSC_DMABUF_SIZE, }; int atmel_pcm_dma_platform_register(struct device *dev) { - return snd_soc_register_platform(dev, &atmel_soc_platform); + return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config, + SND_DMAENGINE_PCM_FLAG_NO_RESIDUE); } EXPORT_SYMBOL(atmel_pcm_dma_platform_register); void atmel_pcm_dma_platform_unregister(struct device *dev) { - snd_soc_unregister_platform(dev); + snd_dmaengine_pcm_unregister(dev); } EXPORT_SYMBOL(atmel_pcm_dma_platform_unregister); diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c index 6a293c713a3..a366b3503c2 100644 --- a/sound/soc/atmel/atmel-pcm-pdc.c +++ b/sound/soc/atmel/atmel-pcm-pdc.c @@ -58,7 +58,6 @@ static const struct snd_pcm_hardware atmel_pcm_hardware = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE, - .formats = SNDRV_PCM_FMTBIT_S16_LE, .period_bytes_min = 32, .period_bytes_max = 8192, .periods_min = 2, @@ -77,12 +76,6 @@ struct atmel_runtime_data { size_t period_size; dma_addr_t period_ptr; /* physical address of next period */ - - /* PDC register save */ - u32 pdc_xpr_save; - u32 pdc_xcr_save; - u32 pdc_xnpr_save; - u32 pdc_xncr_save; }; /*--------------------------------------------------------------------------*\ @@ -159,7 +152,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, pr_debug("atmel-pcm: " "hw_params: DMA for %s initialized " - "(dma_bytes=%u, period_size=%u)\n", + "(dma_bytes=%zu, period_size=%zu)\n", prtd->params->name, runtime->dma_bytes, prtd->period_size); @@ -201,7 +194,7 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream, int ret = 0; pr_debug("atmel-pcm:buffer_size = %ld," - "dma_area = %p, dma_bytes = %u\n", + "dma_area = %p, dma_bytes = %zu\n", rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); switch (cmd) { @@ -321,67 +314,10 @@ static struct snd_pcm_ops atmel_pcm_ops = { .mmap = atmel_pcm_mmap, }; - -/*--------------------------------------------------------------------------*\ - * ASoC platform driver -\*--------------------------------------------------------------------------*/ -#ifdef CONFIG_PM -static int atmel_pcm_suspend(struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct atmel_runtime_data *prtd; - struct atmel_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* disable the PDC and save the PDC registers */ - - ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); - - prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); - prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); - prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); - prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); - - return 0; -} - -static int atmel_pcm_resume(struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct atmel_runtime_data *prtd; - struct atmel_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* restore the PDC registers and enable the PDC */ - ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); - ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); - ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); - ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); - - ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); - return 0; -} -#else -#define atmel_pcm_suspend NULL -#define atmel_pcm_resume NULL -#endif - static struct snd_soc_platform_driver atmel_soc_platform = { .ops = &atmel_pcm_ops, .pcm_new = atmel_pcm_new, .pcm_free = atmel_pcm_free, - .suspend = atmel_pcm_suspend, - .resume = atmel_pcm_resume, }; int atmel_pcm_pdc_platform_register(struct device *dev) diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index e99f1811300..8ae3fa5ac60 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -49,8 +49,8 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, buf->private_data = NULL; buf->area = dma_alloc_coherent(pcm->card->dev, size, &buf->addr, GFP_KERNEL); - pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%d\n", - (void *)buf->area, (void *)buf->addr, size); + pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n", + (void *)buf->area, (void *)(long)buf->addr, size); if (!buf->area) return -ENOMEM; @@ -68,18 +68,15 @@ int atmel_pcm_mmap(struct snd_pcm_substream *substream, } EXPORT_SYMBOL_GPL(atmel_pcm_mmap); -static u64 atmel_pcm_dmamask = DMA_BIT_MASK(32); - int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; struct snd_pcm *pcm = rtd->pcm; - int ret = 0; + int ret; - if (!card->dev->dma_mask) - card->dev->dma_mask = &atmel_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = DMA_BIT_MASK(32); + ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n"); diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h index bb45d20e725..12ae814eff2 100644 --- a/sound/soc/atmel/atmel-pcm.h +++ b/sound/soc/atmel/atmel-pcm.h @@ -88,7 +88,8 @@ void atmel_pcm_free(struct snd_pcm *pcm); int atmel_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); -#ifdef CONFIG_SND_ATMEL_SOC_PDC +#if defined(CONFIG_SND_ATMEL_SOC_PDC) || \ + defined(CONFIG_SND_ATMEL_SOC_PDC_MODULE) int atmel_pcm_pdc_platform_register(struct device *dev); void atmel_pcm_pdc_platform_unregister(struct device *dev); #else @@ -101,7 +102,8 @@ static inline void atmel_pcm_pdc_platform_unregister(struct device *dev) } #endif -#ifdef CONFIG_SND_ATMEL_SOC_DMA +#if defined(CONFIG_SND_ATMEL_SOC_DMA) || \ + defined(CONFIG_SND_ATMEL_SOC_DMA_MODULE) int atmel_pcm_dma_platform_register(struct device *dev); void atmel_pcm_dma_platform_unregister(struct device *dev); #else diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 1c766342205..de433cfd044 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -42,8 +42,6 @@ #include <sound/initval.h> #include <sound/soc.h> -#include <mach/hardware.h> - #include "atmel-pcm.h" #include "atmel_ssc_dai.h" @@ -75,6 +73,7 @@ static struct atmel_ssc_mask ssc_tx_mask = { .ssc_disable = SSC_BIT(CR_TXDIS), .ssc_endx = SSC_BIT(SR_ENDTX), .ssc_endbuf = SSC_BIT(SR_TXBUFE), + .ssc_error = SSC_BIT(SR_OVRUN), .pdc_enable = ATMEL_PDC_TXTEN, .pdc_disable = ATMEL_PDC_TXTDIS, }; @@ -84,6 +83,7 @@ static struct atmel_ssc_mask ssc_rx_mask = { .ssc_disable = SSC_BIT(CR_RXDIS), .ssc_endx = SSC_BIT(SR_ENDRX), .ssc_endbuf = SSC_BIT(SR_RXBUFF), + .ssc_error = SSC_BIT(SR_OVRUN), .pdc_enable = ATMEL_PDC_RXTEN, .pdc_disable = ATMEL_PDC_RXTDIS, }; @@ -198,15 +198,27 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; - int dir_mask; + struct atmel_pcm_dma_params *dma_params; + int dir, dir_mask; pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", ssc_readl(ssc_p->ssc->regs, SR)); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dir = 0; dir_mask = SSC_DIR_MASK_PLAYBACK; - else + } else { + dir = 1; dir_mask = SSC_DIR_MASK_CAPTURE; + } + + dma_params = &ssc_dma_params[dai->id][dir]; + dma_params->ssc = ssc_p->ssc; + dma_params->substream = substream; + + ssc_p->dma_params[dir] = dma_params; + + snd_soc_dai_set_dma_data(dai, substream, dma_params); spin_lock_irq(&ssc_p->lock); if (ssc_p->dir_mask & dir_mask) { @@ -327,9 +339,9 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); int id = dai->id; struct atmel_ssc_info *ssc_p = &ssc_info[id]; + struct ssc_device *ssc = ssc_p->ssc; struct atmel_pcm_dma_params *dma_params; int dir, channels, bits; u32 tfmr, rfmr, tcmr, rcmr; @@ -346,19 +358,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, else dir = 1; - dma_params = &ssc_dma_params[id][dir]; - dma_params->ssc = ssc_p->ssc; - dma_params->substream = substream; - - ssc_p->dma_params[dir] = dma_params; - - /* - * The snd_soc_pcm_stream->dma_data field is only used to communicate - * the appropriate DMA parameters to the pcm driver hw_params() - * function. It should not be used for other purposes - * as it is common to all substreams. - */ - snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params); + dma_params = ssc_p->dma_params[dir]; channels = params_channels(params); @@ -467,7 +467,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(RCMR_START, start_event) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK); + | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_PIN : SSC_CKS_CLOCK); rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) @@ -482,7 +483,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(TCMR_START, start_event) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(TCMR_CKS, SSC_CKS_PIN); + | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_CLOCK : SSC_CKS_PIN); tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | SSC_BF(TFMR_FSDEN, 0) @@ -535,6 +537,51 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, break; case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + /* + * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks. + * + * The SSC transmit clock is obtained from the BCLK signal on + * on the TK line, and the SSC receive clock is + * generated from the transmit clock. + * + * Data is transferred on first BCLK after LRC pulse rising + * edge.If stereo, the right channel data is contiguous with + * the left channel data. + */ + rcmr = SSC_BF(RCMR_PERIOD, 0) + | SSC_BF(RCMR_STTDLY, START_DELAY) + | SSC_BF(RCMR_START, SSC_START_RISING_RF) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE) + | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_PIN : SSC_CKS_CLOCK); + + rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(RFMR_FSLEN, 0) + | SSC_BF(RFMR_DATNB, (channels - 1)) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tcmr = SSC_BF(TCMR_PERIOD, 0) + | SSC_BF(TCMR_STTDLY, START_DELAY) + | SSC_BF(TCMR_START, SSC_START_RISING_RF) + | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) + | SSC_BF(TCMR_CKO, SSC_CKO_NONE) + | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? + SSC_CKS_CLOCK : SSC_CKS_PIN); + + tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(TFMR_FSLEN, 0) + | SSC_BF(TFMR_DATNB, (channels - 1)) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + break; + default: printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", ssc_p->daifmt); @@ -606,7 +653,8 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream, dma_params = ssc_p->dma_params[dir]; - ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable); + ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable); + ssc_writel(ssc_p->ssc->regs, IDR, dma_params->mask->ssc_error); pr_debug("%s enabled SSC_SR=0x%08x\n", dir ? "receive" : "transmit", @@ -614,6 +662,33 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream, return 0; } +static int atmel_ssc_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; + struct atmel_pcm_dma_params *dma_params; + int dir; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dir = 0; + else + dir = 1; + + dma_params = ssc_p->dma_params[dir]; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable); + break; + default: + ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable); + break; + } + + return 0; +} #ifdef CONFIG_PM static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) @@ -679,15 +754,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) # define atmel_ssc_resume NULL #endif /* CONFIG_PM */ -static int atmel_ssc_probe(struct snd_soc_dai *dai) -{ - struct atmel_ssc_info *ssc_p = &ssc_info[dai->id]; - - snd_soc_dai_set_drvdata(dai, ssc_p); - - return 0; -} - #define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ @@ -697,13 +763,13 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { .startup = atmel_ssc_startup, .shutdown = atmel_ssc_shutdown, .prepare = atmel_ssc_prepare, + .trigger = atmel_ssc_trigger, .hw_params = atmel_ssc_hw_params, .set_fmt = atmel_ssc_set_dai_fmt, .set_clkdiv = atmel_ssc_set_dai_clkdiv, }; static struct snd_soc_dai_driver atmel_ssc_dai = { - .probe = atmel_ssc_probe, .suspend = atmel_ssc_suspend, .resume = atmel_ssc_resume, .playback = { @@ -719,13 +785,18 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { .ops = &atmel_ssc_dai_ops, }; +static const struct snd_soc_component_driver atmel_ssc_component = { + .name = "atmel-ssc", +}; + static int asoc_ssc_init(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct ssc_device *ssc = platform_get_drvdata(pdev); int ret; - ret = snd_soc_register_dai(dev, &atmel_ssc_dai); + ret = snd_soc_register_component(dev, &atmel_ssc_component, + &atmel_ssc_dai, 1); if (ret) { dev_err(dev, "Could not register DAI: %d\n", ret); goto err; @@ -739,12 +810,12 @@ static int asoc_ssc_init(struct device *dev) if (ret) { dev_err(dev, "Could not register PCM: %d\n", ret); goto err_unregister_dai; - }; + } return 0; err_unregister_dai: - snd_soc_unregister_dai(dev); + snd_soc_unregister_component(dev); err: return ret; } @@ -759,7 +830,7 @@ static void asoc_ssc_exit(struct device *dev) else atmel_pcm_pdc_platform_unregister(dev); - snd_soc_unregister_dai(dev); + snd_soc_unregister_component(dev); } /** @@ -790,8 +861,8 @@ void atmel_ssc_put_audio(int ssc_id) { struct ssc_device *ssc = ssc_info[ssc_id].ssc; - ssc_free(ssc); asoc_ssc_exit(&ssc->pdev->dev); + ssc_free(ssc); } EXPORT_SYMBOL_GPL(atmel_ssc_put_audio); diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c new file mode 100644 index 00000000000..b4e36901a40 --- /dev/null +++ b/sound/soc/atmel/atmel_wm8904.c @@ -0,0 +1,246 @@ +/* + * atmel_wm8904 - Atmel ASoC driver for boards with WM8904 codec. + * + * Copyright (C) 2012 Atmel + * + * Author: Bo Shen <voice.shen@atmel.com> + * + * GPLv2 or later + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> + +#include <sound/soc.h> + +#include "../codecs/wm8904.h" +#include "atmel_ssc_dai.h" + +#define MCLK_RATE 32768 + +static struct clk *mclk; + +static const struct snd_soc_dapm_widget atmel_asoc_wm8904_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic", NULL), + SND_SOC_DAPM_LINE("Line In Jack", NULL), +}; + +static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_pll(codec_dai, WM8904_FLL_MCLK, WM8904_FLL_MCLK, + 32768, params_rate(params) * 256); + if (ret < 0) { + pr_err("%s - failed to set wm8904 codec PLL.", __func__); + return ret; + } + + /* + * As here wm8904 use FLL output as its system clock + * so calling set_sysclk won't care freq parameter + * then we pass 0 + */ + ret = snd_soc_dai_set_sysclk(codec_dai, WM8904_CLK_FLL, + 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + pr_err("%s -failed to set wm8904 SYSCLK\n", __func__); + return ret; + } + + return 0; +} + +static struct snd_soc_ops atmel_asoc_wm8904_ops = { + .hw_params = atmel_asoc_wm8904_hw_params, +}; + +static int atmel_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { + switch (level) { + case SND_SOC_BIAS_PREPARE: + clk_prepare_enable(mclk); + break; + case SND_SOC_BIAS_OFF: + clk_disable_unprepare(mclk); + break; + default: + break; + } + } + + return 0; +}; + +static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = { + .name = "WM8904", + .stream_name = "WM8904 PCM", + .codec_dai_name = "wm8904-hifi", + .dai_fmt = SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .ops = &atmel_asoc_wm8904_ops, +}; + +static struct snd_soc_card atmel_asoc_wm8904_card = { + .name = "atmel_asoc_wm8904", + .owner = THIS_MODULE, + .set_bias_level = atmel_set_bias_level, + .dai_link = &atmel_asoc_wm8904_dailink, + .num_links = 1, + .dapm_widgets = atmel_asoc_wm8904_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(atmel_asoc_wm8904_dapm_widgets), + .fully_routed = true, +}; + +static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *codec_np, *cpu_np; + struct snd_soc_card *card = &atmel_asoc_wm8904_card; + struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; + int ret; + + if (!np) { + dev_err(&pdev->dev, "only device tree supported\n"); + return -EINVAL; + } + + ret = snd_soc_of_parse_card_name(card, "atmel,model"); + if (ret) { + dev_err(&pdev->dev, "failed to parse card name\n"); + return ret; + } + + ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing"); + if (ret) { + dev_err(&pdev->dev, "failed to parse audio routing\n"); + return ret; + } + + cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "failed to get dai and pcm info\n"); + ret = -EINVAL; + return ret; + } + dailink->cpu_of_node = cpu_np; + dailink->platform_of_node = cpu_np; + of_node_put(cpu_np); + + codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "failed to get codec info\n"); + ret = -EINVAL; + return ret; + } + dailink->codec_of_node = codec_np; + of_node_put(codec_np); + + return 0; +} + +static int atmel_asoc_wm8904_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &atmel_asoc_wm8904_card; + struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; + struct clk *clk_src; + int id, ret; + + card->dev = &pdev->dev; + ret = atmel_asoc_wm8904_dt_init(pdev); + if (ret) { + dev_err(&pdev->dev, "failed to init dt info\n"); + return ret; + } + + id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc"); + ret = atmel_ssc_set_audio(id); + if (ret != 0) { + dev_err(&pdev->dev, "failed to set SSC %d for audio\n", id); + return ret; + } + + mclk = clk_get(NULL, "pck0"); + if (IS_ERR(mclk)) { + dev_err(&pdev->dev, "failed to get pck0\n"); + ret = PTR_ERR(mclk); + goto err_set_audio; + } + + clk_src = clk_get(NULL, "clk32k"); + if (IS_ERR(clk_src)) { + dev_err(&pdev->dev, "failed to get clk32k\n"); + ret = PTR_ERR(clk_src); + goto err_set_audio; + } + + ret = clk_set_parent(mclk, clk_src); + clk_put(clk_src); + if (ret != 0) { + dev_err(&pdev->dev, "failed to set MCLK parent\n"); + goto err_set_audio; + } + + dev_info(&pdev->dev, "setting pck0 to %dHz\n", MCLK_RATE); + clk_set_rate(mclk, MCLK_RATE); + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed\n"); + goto err_set_audio; + } + + return 0; + +err_set_audio: + atmel_ssc_put_audio(id); + return ret; +} + +static int atmel_asoc_wm8904_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink; + int id; + + id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc"); + + snd_soc_unregister_card(card); + atmel_ssc_put_audio(id); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id atmel_asoc_wm8904_dt_ids[] = { + { .compatible = "atmel,asoc-wm8904", }, + { } +}; +#endif + +static struct platform_driver atmel_asoc_wm8904_driver = { + .driver = { + .name = "atmel-wm8904-audio", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(atmel_asoc_wm8904_dt_ids), + }, + .probe = atmel_asoc_wm8904_probe, + .remove = atmel_asoc_wm8904_remove, +}; + +module_platform_driver(atmel_asoc_wm8904_driver); + +/* Module information */ +MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>"); +MODULE_DESCRIPTION("ALSA SoC machine driver for Atmel EK with WM8904 codec"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index da976291da9..bb1149126c5 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -37,8 +37,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/i2c.h> - -#include <linux/pinctrl/consumer.h> +#include <linux/of.h> #include <linux/atmel-ssc.h> @@ -49,7 +48,6 @@ #include <asm/mach-types.h> #include <mach/hardware.h> -#include <mach/gpio.h> #include "../codecs/wm8731.h" #include "atmel-pcm.h" @@ -156,25 +154,14 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) return ret; } - /* Add specific widgets */ - snd_soc_dapm_new_controls(dapm, at91sam9g20ek_dapm_widgets, - ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); - /* Set up specific audio path interconnects */ - snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); - /* not connected */ snd_soc_dapm_nc_pin(dapm, "RLINEIN"); snd_soc_dapm_nc_pin(dapm, "LLINEIN"); -#ifdef ENABLE_MIC_INPUT - snd_soc_dapm_enable_pin(dapm, "Int Mic"); -#else - snd_soc_dapm_nc_pin(dapm, "Int Mic"); +#ifndef ENABLE_MIC_INPUT + snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic"); #endif - /* always connected */ - snd_soc_dapm_enable_pin(dapm, "Ext Spk"); - return 0; } @@ -195,6 +182,11 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = { .dai_link = &at91sam9g20ek_dai, .num_links = 1, .set_bias_level = at91sam9g20ek_set_bias_level, + + .dapm_widgets = at91sam9g20ek_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets), + .dapm_routes = intercon, + .num_dapm_routes = ARRAY_SIZE(intercon), }; static int at91sam9g20ek_audio_probe(struct platform_device *pdev) @@ -203,15 +195,8 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev) struct device_node *codec_np, *cpu_np; struct clk *pllb; struct snd_soc_card *card = &snd_soc_at91sam9g20ek; - struct pinctrl *pinctrl; int ret; - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) { - dev_err(&pdev->dev, "Failed to request pinctrl for mck\n"); - return PTR_ERR(pinctrl); - } - if (!np) { if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc())) @@ -305,10 +290,10 @@ static int at91sam9g20ek_audio_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - atmel_ssc_put_audio(0); - snd_soc_unregister_card(card); - clk_put(mclk); + clk_disable(mclk); mclk = NULL; + snd_soc_unregister_card(card); + atmel_ssc_put_audio(0); return 0; } diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c new file mode 100644 index 00000000000..3188036a18f --- /dev/null +++ b/sound/soc/atmel/sam9x5_wm8731.c @@ -0,0 +1,208 @@ +/* + * sam9x5_wm8731 -- SoC audio for AT91SAM9X5-based boards + * that are using WM8731 as codec. + * + * Copyright (C) 2011 Atmel, + * Nicolas Ferre <nicolas.ferre@atmel.com> + * + * Copyright (C) 2013 Paratronic, + * Richard Genoud <richard.genoud@gmail.com> + * + * Based on sam9g20_wm8731.c by: + * Sedji Gaouaou <sedji.gaouaou@atmel.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/of.h> +#include <linux/export.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/device.h> + +#include <sound/soc.h> +#include <sound/soc-dai.h> +#include <sound/soc-dapm.h> + +#include "../codecs/wm8731.h" +#include "atmel_ssc_dai.h" + + +#define MCLK_RATE 12288000 + +#define DRV_NAME "sam9x5-snd-wm8731" + +struct sam9x5_drvdata { + int ssc_id; +}; + +/* + * Logic for a wm8731 as connected on a at91sam9x5ek based board. + */ +static int sam9x5_wm8731_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct device *dev = rtd->dev; + int ret; + + dev_dbg(dev, "ASoC: %s called\n", __func__); + + /* set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, + MCLK_RATE, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(dev, "ASoC: Failed to set WM8731 SYSCLK: %d\n", ret); + return ret; + } + + return 0; +} + +/* + * Audio paths on at91sam9x5ek board: + * + * |A| ------------> | | ---R----> Headphone Jack + * |T| <----\ | WM | ---L--/ + * |9| ---> CLK <--> | 8731 | <--R----- Line In Jack + * |1| <------------ | | <--L--/ + */ +static const struct snd_soc_dapm_widget sam9x5_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_LINE("Line In Jack", NULL), +}; + +static int sam9x5_wm8731_driver_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *codec_np, *cpu_np; + struct snd_soc_card *card; + struct snd_soc_dai_link *dai; + struct sam9x5_drvdata *priv; + int ret; + + if (!np) { + dev_err(&pdev->dev, "No device node supplied\n"); + return -EINVAL; + } + + card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL); + if (!dai || !card || !priv) { + ret = -ENOMEM; + goto out; + } + + snd_soc_card_set_drvdata(card, priv); + + card->dev = &pdev->dev; + card->owner = THIS_MODULE; + card->dai_link = dai; + card->num_links = 1; + card->dapm_widgets = sam9x5_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sam9x5_dapm_widgets); + dai->name = "WM8731"; + dai->stream_name = "WM8731 PCM"; + dai->codec_dai_name = "wm8731-hifi"; + dai->init = sam9x5_wm8731_init; + dai->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM; + + ret = snd_soc_of_parse_card_name(card, "atmel,model"); + if (ret) { + dev_err(&pdev->dev, "atmel,model node missing\n"); + goto out; + } + + ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing"); + if (ret) { + dev_err(&pdev->dev, "atmel,audio-routing node missing\n"); + goto out; + } + + codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "atmel,audio-codec node missing\n"); + ret = -EINVAL; + goto out; + } + + dai->codec_of_node = codec_np; + + cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "atmel,ssc-controller node missing\n"); + ret = -EINVAL; + goto out; + } + dai->cpu_of_node = cpu_np; + dai->platform_of_node = cpu_np; + + priv->ssc_id = of_alias_get_id(cpu_np, "ssc"); + + ret = atmel_ssc_set_audio(priv->ssc_id); + if (ret != 0) { + dev_err(&pdev->dev, + "ASoC: Failed to set SSC %d for audio: %d\n", + ret, priv->ssc_id); + goto out; + } + + of_node_put(codec_np); + of_node_put(cpu_np); + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, + "ASoC: Platform device allocation failed\n"); + goto out_put_audio; + } + + dev_dbg(&pdev->dev, "ASoC: %s ok\n", __func__); + + return ret; + +out_put_audio: + atmel_ssc_put_audio(priv->ssc_id); +out: + return ret; +} + +static int sam9x5_wm8731_driver_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct sam9x5_drvdata *priv = card->drvdata; + + snd_soc_unregister_card(card); + atmel_ssc_put_audio(priv->ssc_id); + + return 0; +} + +static const struct of_device_id sam9x5_wm8731_of_match[] = { + { .compatible = "atmel,sam9x5-wm8731-audio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, sam9x5_wm8731_of_match); + +static struct platform_driver sam9x5_wm8731_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sam9x5_wm8731_of_match), + }, + .probe = sam9x5_wm8731_driver_probe, + .remove = sam9x5_wm8731_driver_remove, +}; +module_platform_driver(sam9x5_wm8731_driver); + +/* Module information */ +MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>"); +MODULE_AUTHOR("Richard Genoud <richard.genoud@gmail.com>"); +MODULE_DESCRIPTION("ALSA SoC machine driver for AT91SAM9x5 - WM8731"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c index f65f08beac3..9579799ace5 100644 --- a/sound/soc/atmel/snd-soc-afeb9260.c +++ b/sound/soc/atmel/snd-soc-afeb9260.c @@ -80,17 +80,6 @@ static const struct snd_soc_dapm_route afeb9260_audio_map[] = { {"MICIN", NULL, "Mic Jack"}, }; -static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); - snd_soc_dapm_enable_pin(dapm, "Line In"); - snd_soc_dapm_enable_pin(dapm, "Mic Jack"); - - return 0; -} /* Digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link afeb9260_dai = { @@ -100,7 +89,6 @@ static struct snd_soc_dai_link afeb9260_dai = { .codec_dai_name = "tlv320aic23-hifi", .platform_name = "atmel_pcm-audio", .codec_name = "tlv320aic23-codec.0-001a", - .init = afeb9260_tlv320aic23_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBM_CFM, .ops = &afeb9260_ops, |
