diff options
Diffstat (limited to 'sound/soc')
126 files changed, 3937 insertions, 10307 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 615ebf0b76e7..4dfda6674bec 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -23,7 +23,8 @@ config SND_SOC_AC97_BUS bool # All the supported Soc's -source "sound/soc/atmel/Kconfig" +source "sound/soc/at32/Kconfig" +source "sound/soc/at91/Kconfig" source "sound/soc/au1x/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 4d475c3ceb91..d849349f2c66 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ atmel/ pxa/ s3c24xx/ sh/ fsl/ davinci/ +obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/ diff --git a/sound/soc/at32/Kconfig b/sound/soc/at32/Kconfig new file mode 100644 index 000000000000..b0765e86c085 --- /dev/null +++ b/sound/soc/at32/Kconfig @@ -0,0 +1,34 @@ +config SND_AT32_SOC + tristate "SoC Audio for the Atmel AT32 System-on-a-Chip" + depends on AVR32 && SND_SOC + help + Say Y or M if you want to add support for codecs attached to + the AT32 SSC interface. You will also need to + to select the audio interfaces to support below. + + +config SND_AT32_SOC_SSC + tristate + + + +config SND_AT32_SOC_PLAYPAQ + tristate "SoC Audio support for PlayPaq with WM8510" + depends on SND_AT32_SOC && BOARD_PLAYPAQ + select SND_AT32_SOC_SSC + select SND_SOC_WM8510 + help + Say Y or M here if you want to add support for SoC audio + on the LRS PlayPaq. + + + +config SND_AT32_SOC_PLAYPAQ_SLAVE + bool "Run CODEC on PlayPaq in slave mode" + depends on SND_AT32_SOC_PLAYPAQ + default n + help + Say Y if you want to run with the AT32 SSC generating the BCLK + and FRAME signals on the PlayPaq. Unless you want to play + with the AT32 as the SSC master, you probably want to say N here, + as this will give you better sound quality. diff --git a/sound/soc/at32/Makefile b/sound/soc/at32/Makefile new file mode 100644 index 000000000000..c03e55ececeb --- /dev/null +++ b/sound/soc/at32/Makefile @@ -0,0 +1,11 @@ +# AT32 Platform Support +snd-soc-at32-objs := at32-pcm.o +snd-soc-at32-ssc-objs := at32-ssc.o + +obj-$(CONFIG_SND_AT32_SOC) += snd-soc-at32.o +obj-$(CONFIG_SND_AT32_SOC_SSC) += snd-soc-at32-ssc.o + +# AT32 Machine Support +snd-soc-playpaq-objs := playpaq_wm8510.o + +obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o diff --git a/sound/soc/at32/at32-pcm.c b/sound/soc/at32/at32-pcm.c new file mode 100644 index 000000000000..c83584f989a9 --- /dev/null +++ b/sound/soc/at32/at32-pcm.c @@ -0,0 +1,492 @@ +/* sound/soc/at32/at32-pcm.c + * ASoC PCM interface for Atmel AT32 SoC + * + * Copyright (C) 2008 Long Range Systems + * Geoffrey Wossum <gwossum@acm.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Note that this is basically a port of the sound/soc/at91-pcm.c to + * the AVR32 kernel. Thanks to Frank Mandarino for that code. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include "at32-pcm.h" + + + +/*--------------------------------------------------------------------------*\ + * Hardware definition +\*--------------------------------------------------------------------------*/ +/* TODO: These values were taken from the AT91 platform driver, check + * them against real values for AT32 + */ +static const struct snd_pcm_hardware at32_pcm_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE), + + .formats = SNDRV_PCM_FMTBIT_S16, + .period_bytes_min = 32, + .period_bytes_max = 8192, /* 512 frames * 16 bytes / frame */ + .periods_min = 2, + .periods_max = 1024, + .buffer_bytes_max = 32 * 1024, +}; + + + +/*--------------------------------------------------------------------------*\ + * Data types +\*--------------------------------------------------------------------------*/ +struct at32_runtime_data { + struct at32_pcm_dma_params *params; + dma_addr_t dma_buffer; /* physical address of DMA buffer */ + dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ + size_t period_size; + + dma_addr_t period_ptr; /* physical address of next period */ + int periods; /* period index of period_ptr */ + + /* Save PDC registers (for power management) */ + u32 pdc_xpr_save; + u32 pdc_xcr_save; + u32 pdc_xnpr_save; + u32 pdc_xncr_save; +}; + + + +/*--------------------------------------------------------------------------*\ + * Helper functions +\*--------------------------------------------------------------------------*/ +static int at32_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *dmabuf = &substream->dma_buffer; + size_t size = at32_pcm_hardware.buffer_bytes_max; + + dmabuf->dev.type = SNDRV_DMA_TYPE_DEV; + dmabuf->dev.dev = pcm->card->dev; + dmabuf->private_data = NULL; + dmabuf->area = dma_alloc_coherent(pcm->card->dev, size, + &dmabuf->addr, GFP_KERNEL); + pr_debug("at32_pcm: preallocate_dma_buffer: " + "area=%p, addr=%p, size=%ld\n", + (void *)dmabuf->area, (void *)dmabuf->addr, size); + + if (!dmabuf->area) + return -ENOMEM; + + dmabuf->bytes = size; + return 0; +} + + + +/*--------------------------------------------------------------------------*\ + * ISR +\*--------------------------------------------------------------------------*/ +static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *rtd = substream->runtime; + struct at32_runtime_data *prtd = rtd->private_data; + struct at32_pcm_dma_params *params = prtd->params; + static int count; + + count++; + if (ssc_sr & params->mask->ssc_endbuf) { + pr_warning("at32-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + "underrun" : "overrun", params->name, ssc_sr, count); + + /* re-start the PDC */ + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) + prtd->period_ptr = prtd->dma_buffer; + + + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_enable); + } + + + if (ssc_sr & params->mask->ssc_endx) { + /* Load the PDC next pointer and counter registers */ + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) + prtd->period_ptr = prtd->dma_buffer; + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + } + + + snd_pcm_period_elapsed(substream); +} + + + +/*--------------------------------------------------------------------------*\ + * PCM operations +\*--------------------------------------------------------------------------*/ +static int at32_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at32_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* this may get called several times by oss emulation + * with different params + */ + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params->dma_intr_handler = at32_pcm_dma_irq; + + prtd->dma_buffer = runtime->dma_addr; + prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; + prtd->period_size = params_period_bytes(params); + + pr_debug("hw_params: DMA for %s initialized " + "(dma_bytes=%ld, period_size=%ld)\n", + prtd->params->name, runtime->dma_bytes, prtd->period_size); + + return 0; +} + + + +static int at32_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct at32_runtime_data *prtd = substream->runtime->private_data; + struct at32_pcm_dma_params *params = prtd->params; + + if (params != NULL) { + ssc_writex(params->ssc->regs, SSC_PDC_PTCR, + params->mask->pdc_disable); + prtd->params->dma_intr_handler = NULL; + } + + return 0; +} + + + +static int at32_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct at32_runtime_data *prtd = substream->runtime->private_data; + struct at32_pcm_dma_params *params = prtd->params; + + ssc_writex(params->ssc->regs, SSC_IDR, + params->mask->ssc_endx | params->mask->ssc_endbuf); + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + + return 0; +} + + +static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *rtd = substream->runtime; + struct at32_runtime_data *prtd = rtd->private_data; + struct at32_pcm_dma_params *params = prtd->params; + int ret = 0; + + pr_debug("at32_pcm_trigger: buffer_size = %ld, " + "dma_area = %p, dma_bytes = %ld\n", + rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->period_ptr = prtd->dma_buffer; + + ssc_writex(params->ssc->regs, params->pdc->xpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + prtd->period_ptr += prtd->period_size; + ssc_writex(params->ssc->regs, params->pdc->xnpr, + prtd->period_ptr); + ssc_writex(params->ssc->regs, params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + + pr_debug("trigger: period_ptr=%lx, xpr=%x, " + "xcr=%d, xnpr=%x, xncr=%d\n", + (unsigned long)prtd->period_ptr, + ssc_readx(params->ssc->regs, params->pdc->xpr), + ssc_readx(params->ssc->regs, params->pdc->xcr), + ssc_readx(params->ssc->regs, params->pdc->xnpr), + ssc_readx(params->ssc->regs, params->pdc->xncr)); + + ssc_writex(params->ssc->regs, SSC_IER, + params->mask->ssc_endx | params->mask->ssc_endbuf); + ssc_writex(params->ssc->regs, SSC_PDC_PTCR, + params->mask->pdc_enable); + + pr_debug("sr=%x, imr=%x\n", + ssc_readx(params->ssc->regs, SSC_SR), + ssc_readx(params->ssc->regs, SSC_IER)); + break; /* SNDRV_PCM_TRIGGER_START */ + + + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_disable); + break; + + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, + params->mask->pdc_enable); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + + + +static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at32_runtime_data *prtd = runtime->private_data; + struct at32_pcm_dma_params *params = prtd->params; + dma_addr_t ptr; + snd_pcm_uframes_t x; + + ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); + x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); + + if (x == runtime->buffer_size) + x = 0; + + return x; +} + + + +static int at32_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at32_runtime_data *prtd; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &at32_pcm_hardware); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + runtime->private_data = prtd; + + +out: + return ret; +} + + + +static int at32_pcm_close(struct snd_pcm_substream *substream) +{ + struct at32_runtime_data *prtd = substream->runtime->private_data; + + kfree(prtd); + return 0; +} + + +static int at32_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + return remap_pfn_range(vma, vma->vm_start, + substream->dma_buffer.addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot); +} + + + +static struct snd_pcm_ops at32_pcm_ops = { + .open = at32_pcm_open, + .close = at32_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = at32_pcm_hw_params, + .hw_free = at32_pcm_hw_free, + .prepare = at32_pcm_prepare, + .trigger = at32_pcm_trigger, + .pointer = at32_pcm_pointer, + .mmap = at32_pcm_mmap, +}; + + + +/*--------------------------------------------------------------------------*\ + * ASoC platform driver +\*--------------------------------------------------------------------------*/ +static u64 at32_pcm_dmamask = 0xffffffff; + +static int at32_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &at32_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = at32_pcm_preallocate_dma_buffer( + pcm, SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + pr_debug("at32-pcm: Allocating PCM capture DMA buffer\n"); + ret = at32_pcm_preallocate_dma_buffer( + pcm, SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + + +out: + return ret; +} + + + +static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (substream == NULL) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + dma_free_coherent(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + + + +#ifdef CONFIG_PM +static int at32_pcm_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at32_runtime_data *prtd; + struct at32_pcm_dma_params *params; + + if (runtime == NULL) + return 0; + prtd = runtime->private_data; + params = prtd->params; + + /* Disable the PDC and save the PDC registers */ + ssc_writex(params->ssc->regs, ATMEL_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 at32_pcm_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at32_runtime_data *prtd; + struct at32_pcm_dma_params *params; + + if (runtime == NULL) + 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_writex(params->ssc->regs, ATMEL_PDC_PTCR, params->mask->pdc_enable); + return 0; +} +#else /* CONFIG_PM */ +# define at32_pcm_suspend NULL +# define at32_pcm_resume NULL +#endif /* CONFIG_PM */ + + + +struct snd_soc_platform at32_soc_platform = { + .name = "at32-audio", + .pcm_ops = &at32_pcm_ops, + .pcm_new = at32_pcm_new, + .pcm_free = at32_pcm_free_dma_buffers, + .suspend = at32_pcm_suspend, + .resume = at32_pcm_resume, +}; +EXPORT_SYMBOL_GPL(at32_soc_platform); + + + +MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); +MODULE_DESCRIPTION("Atmel AT32 PCM module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/at32/at32-pcm.h b/sound/soc/at32/at32-pcm.h new file mode 100644 index 000000000000..2a52430417da --- /dev/null +++ b/sound/soc/at32/at32-pcm.h @@ -0,0 +1,79 @@ +/* sound/soc/at32/at32-pcm.h + * ASoC PCM interface for Atmel AT32 SoC + * + * Copyright (C) 2008 Long Range Systems + * Geoffrey Wossum <gwossum@acm.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __SOUND_SOC_AT32_AT32_PCM_H +#define __SOUND_SOC_AT32_AT32_PCM_H __FILE__ + +#include <linux/atmel-ssc.h> + + +/* + * Registers and status bits that are required by the PCM driver + * TODO: Is ptcr really used? + */ +struct at32_pdc_regs { + u32 xpr; /* PDC RX/TX pointer */ + u32 xcr; /* PDC RX/TX counter */ + u32 xnpr; /* PDC next RX/TX pointer */ + u32 xncr; /* PDC next RX/TX counter */ + u32 ptcr; /* PDC transfer control */ +}; + + + +/* + * SSC mask info + */ +struct at32_ssc_mask { + u32 ssc_enable; /* SSC RX/TX enable */ + u32 ssc_disable; /* SSC RX/TX disable */ + u32 ssc_endx; /* SSC ENDTX or ENDRX */ + u32 ssc_endbuf; /* SSC TXBUFF or RXBUFF */ + u32 pdc_enable; /* PDC RX/TX enable */ + u32 pdc_disable; /* PDC RX/TX disable */ +}; + + + +/* + * This structure, shared between the PCM driver and the interface, + * contains all information required by the PCM driver to perform the + * PDC DMA operation. All fields except dma_intr_handler() are initialized + * by the interface. The dms_intr_handler() pointer is set by the PCM + * driver and called by the interface SSC interrupt handler if it is + * non-NULL. + */ +struct at32_pcm_dma_params { + char *name; /* stream identifier */ + int pdc_xfer_size; /* PDC counter increment in bytes */ + struct ssc_device *ssc; /* SSC device for stream */ + struct at32_pdc_regs *pdc; /* PDC register info */ + struct at32_ssc_mask *mask; /* SSC mask info */ + struct snd_pcm_substream *substream; + void (*dma_intr_handler) (u32, struct snd_pcm_substream *); +}; + + + +/* + * The AT32 ASoC platform driver + */ +extern struct snd_soc_platform at32_soc_platform; + + + +/* + * SSC register access (since ssc_writel() / ssc_readl() require literal name) + */ +#define ssc_readx(base, reg) (__raw_readl((base) + (reg))) +#define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) + +#endif /* __SOUND_SOC_AT32_AT32_PCM_H */ diff --git a/sound/soc/at32/at32-ssc.c b/sound/soc/at32/at32-ssc.c new file mode 100644 index 000000000000..4ef6492c902e --- /dev/null +++ b/sound/soc/at32/at32-ssc.c @@ -0,0 +1,849 @@ +/* sound/soc/at32/at32-ssc.c + * ASoC platform driver for AT32 using SSC as DAI + * + * Copyright (C) 2008 Long Range Systems + * Geoffrey Wossum <gwossum@acm.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Note that this is basically a port of the sound/soc/at91-ssc.c to + * the AVR32 kernel. Thanks to Frank Mandarino for that code. + */ + +/* #define DEBUG */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/atmel_pdc.h> +#include <linux/atmel-ssc.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#include "at32-pcm.h" +#include "at32-ssc.h" + + + +/*-------------------------------------------------------------------------*\ + * Constants +\*-------------------------------------------------------------------------*/ +#define NUM_SSC_DEVICES 3 + +/* + * SSC direction masks + */ +#define SSC_DIR_MASK_UNUSED 0 +#define SSC_DIR_MASK_PLAYBACK 1 +#define SSC_DIR_MASK_CAPTURE 2 + +/* + * SSC register values that Atmel left out of <linux/atmel-ssc.h>. These + * are expected to be used with SSC_BF + */ +/* START bit field values */ +#define SSC_START_CONTINUOUS 0 +#define SSC_START_TX_RX 1 +#define SSC_START_LOW_RF 2 +#define SSC_START_HIGH_RF 3 +#define SSC_START_FALLING_RF 4 +#define SSC_START_RISING_RF 5 +#define SSC_START_LEVEL_RF 6 +#define SSC_START_EDGE_RF 7 +#define SSS_START_COMPARE_0 8 + +/* CKI bit field values */ +#define SSC_CKI_FALLING 0 +#define SSC_CKI_RISING 1 + +/* CKO bit field values */ +#define SSC_CKO_NONE 0 +#define SSC_CKO_CONTINUOUS 1 +#define SSC_CKO_TRANSFER 2 + +/* CKS bit field values */ +#define SSC_CKS_DIV 0 +#define SSC_CKS_CLOCK 1 +#define SSC_CKS_PIN 2 + +/* FSEDGE bit field values */ +#define SSC_FSEDGE_POSITIVE 0 +#define SSC_FSEDGE_NEGATIVE 1 + +/* FSOS bit field values */ +#define SSC_FSOS_NONE 0 +#define SSC_FSOS_NEGATIVE 1 +#define SSC_FSOS_POSITIVE 2 +#define SSC_FSOS_LOW 3 +#define SSC_FSOS_HIGH 4 +#define SSC_FSOS_TOGGLE 5 + +#define START_DELAY 1 + + + +/*-------------------------------------------------------------------------*\ + * Module data +\*-------------------------------------------------------------------------*/ +/* + * SSC PDC registered required by the PCM DMA engine + */ +static struct at32_pdc_regs pdc_tx_reg = { + .xpr = SSC_PDC_TPR, + .xcr = SSC_PDC_TCR, + .xnpr = SSC_PDC_TNPR, + .xncr = SSC_PDC_TNCR, +}; + + + +static struct at32_pdc_regs pdc_rx_reg = { + .xpr = SSC_PDC_RPR, + .xcr = SSC_PDC_RCR, + .xnpr = SSC_PDC_RNPR, + .xncr = SSC_PDC_RNCR, +}; + + + +/* + * SSC and PDC status bits for transmit and receive + */ +static struct at32_ssc_mask ssc_tx_mask = { + .ssc_enable = SSC_BIT(CR_TXEN), + .ssc_disable = SSC_BIT(CR_TXDIS), + .ssc_endx = SSC_BIT(SR_ENDTX), + .ssc_endbuf = SSC_BIT(SR_TXBUFE), + .pdc_enable = SSC_BIT(PDC_PTCR_TXTEN), + .pdc_disable = SSC_BIT(PDC_PTCR_TXTDIS), +}; + + + +static struct at32_ssc_mask ssc_rx_mask = { + .ssc_enable = SSC_BIT(CR_RXEN), + .ssc_disable = SSC_BIT(CR_RXDIS), + .ssc_endx = SSC_BIT(SR_ENDRX), + .ssc_endbuf = SSC_BIT(SR_RXBUFF), + .pdc_enable = SSC_BIT(PDC_PTCR_RXTEN), + .pdc_disable = SSC_BIT(PDC_PTCR_RXTDIS), +}; + + + +/* + * DMA parameters for each SSC + */ +static struct at32_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { + { + { + .name = "SSC0 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC0 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }, + }, + { + { + .name = "SSC1 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC1 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }, + }, + { + { + .name = "SSC2 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC2 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }, + }, +}; + + + +static struct at32_ssc_info ssc_info[NUM_SSC_DEVICES] = { + { + .name = "ssc0", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, + { + .name = "ssc1", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, + { + .name = "ssc2", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, +}; + + + + +/*-------------------------------------------------------------------------*\ + * ISR +\*-------------------------------------------------------------------------*/ +/* + * SSC interrupt handler. Passes PDC interrupts to the DMA interrupt + * handler in the PCM driver. + */ +static irqreturn_t at32_ssc_interrupt(int irq, void *dev_id) +{ + struct at32_ssc_info *ssc_p = dev_id; + struct at32_pcm_dma_params *dma_params; + u32 ssc_sr; + u32 ssc_substream_mask; + int i; + + ssc_sr = (ssc_readl(ssc_p->ssc->regs, SR) & + ssc_readl(ssc_p->ssc->regs, IMR)); + + /* + * Loop through substreams attached to this SSC. If a DMA-related + * interrupt occured on that substream, call the DMA interrupt + * handler function, if one has been registered in the dma_param + * structure by the PCM driver. + */ + for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { + dma_params = ssc_p->dma_params[i]; + + if ((dma_params != NULL) && + (dma_params->dma_intr_handler != NULL)) { + ssc_substream_mask = (dma_params->mask->ssc_endx | + dma_params->mask->ssc_endbuf); + if (ssc_sr & ssc_substream_mask) { + dma_params->dma_intr_handler(ssc_sr, + dma_params-> + substream); + } + } + } + + + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*\ + * DAI functions +\*-------------------------------------------------------------------------*/ +/* + * Startup. Only that one substream allowed in each direction. + */ +static int at32_ssc_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + int dir_mask; + + dir_mask = ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? + SSC_DIR_MASK_PLAYBACK : SSC_DIR_MASK_CAPTURE); + + spin_lock_irq(&ssc_p->lock); + if (ssc_p->dir_mask & dir_mask) { + spin_unlock_irq(&ssc_p->lock); + return -EBUSY; + } + ssc_p->dir_mask |= dir_mask; + spin_unlock_irq(&ssc_p->lock); + + return 0; +} + + + +/* + * Shutdown. Clear DMA parameters and shutdown the SSC if there + * are no other substreams open. + */ +static void at32_ssc_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct at32_pcm_dma_params *dma_params; + int dir_mask; + + dma_params = ssc_p->dma_params[substream->stream]; + + if (dma_params != NULL) { + ssc_writel(dma_params->ssc->regs, CR, + dma_params->mask->ssc_disable); + pr_debug("%s disabled SSC_SR=0x%08x\n", + (substream->stream ? "receiver" : "transmit"), + ssc_readl(ssc_p->ssc->regs, SR)); + + dma_params->ssc = NULL; + dma_params->substream = NULL; + ssc_p->dma_params[substream->stream] = NULL; + } + + + dir_mask = 1 << substream->stream; + spin_lock_irq(&ssc_p->lock); + ssc_p->dir_mask &= ~dir_mask; + if (!ssc_p->dir_mask) { + /* Shutdown the SSC clock */ + pr_debug("at32-ssc: Stopping user %d clock\n", + ssc_p->ssc->user); + clk_disable(ssc_p->ssc->clk); + + if (ssc_p->initialized) { + free_irq(ssc_p->ssc->irq, ssc_p); + ssc_p->initialized = 0; + } + + /* Reset the SSC */ + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); + + /* clear the SSC dividers */ + ssc_p->cmr_div = 0; + ssc_p->tcmr_period = 0; + ssc_p->rcmr_period = 0; + } + spin_unlock_irq(&ssc_p->lock); +} + + + +/* + * Set the SSC system clock rate + */ +static int at32_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + /* TODO: What the heck do I do here? */ + return 0; +} + + + +/* + * Record DAI format for use by hw_params() + */ +static int at32_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + ssc_p->daifmt = fmt; + return 0; +} + + + +/* + * Record SSC clock dividers for use in hw_params() + */ +static int at32_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + switch (div_id) { + case AT32_SSC_CMR_DIV: + /* + * The same master clock divider is used for both + * transmit and receive, so if a value has already + * been set, it must match this value + */ + if (ssc_p->cmr_div == 0) + ssc_p->cmr_div = div; + else if (div != ssc_p->cmr_div) + return -EBUSY; + break; + + case AT32_SSC_TCMR_PERIOD: + ssc_p->tcmr_period = div; + break; + + case AT32_SSC_RCMR_PERIOD: + ssc_p->rcmr_period = div; + break; + + default: + return -EINVAL; + } + + return 0; +} + + + +/* + * Configure the SSC + */ +static int at32_ssc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int id = rtd->dai->cpu_dai->id; + struct at32_ssc_info *ssc_p = &ssc_info[id]; + struct at32_pcm_dma_params *dma_params; + int channels, bits; + u32 tfmr, rfmr, tcmr, rcmr; + int start_event; + int ret; + + + /* + * Currently, there is only one set of dma_params for each direction. + * If more are added, this code will have to be changed to select + * the proper set + */ + dma_params = &ssc_dma_params[id][substream->stream]; + dma_params->ssc = ssc_p->ssc; + dma_params->substream = substream; + + ssc_p->dma_params[substream->stream] = dma_params; + + + /* + * The cpu_dai->dma_data field is only used to communicate the + * appropriate DMA parameters to the PCM driver's hw_params() + * function. It should not be used for other purposes as it + * is common to all substreams. + */ + rtd->dai->cpu_dai->dma_data = dma_params; + + channels = params_channels(params); + + + /* + * Determine sample size in bits and the PDC increment + */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + bits = 8; + dma_params->pdc_xfer_size = 1; + break; + + case SNDRV_PCM_FORMAT_S16: + bits = 16; + dma_params->pdc_xfer_size = 2; + break; + + case SNDRV_PCM_FORMAT_S24: + bits = 24; + dma_params->pdc_xfer_size = 4; + break; + + case SNDRV_PCM_FORMAT_S32: + bits = 32; + dma_params->pdc_xfer_size = 4; + break; + + default: + pr_warning("at32-ssc: Unsupported PCM format %d", + params_format(params)); + return -EINVAL; + } + pr_debug("at32-ssc: bits = %d, pdc_xfer_size = %d, channels = %d\n", + bits, dma_params->pdc_xfer_size, channels); + + + /* + * The SSC only supports up to 16-bit samples in I2S format, due + * to the size of the Frame Mode Register FSLEN field. + */ + if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) + if (bits > 16) { + pr_warning("at32-ssc: " + "sample size %d is too large for I2S\n", + bits); + return -EINVAL; + } + + + /* + * Compute the SSC register settings + */ + switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK | + SND_SOC_DAIFMT_MASTER_MASK)) { + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + /* + * I2S format, SSC provides BCLK and LRS clocks. + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output on the SSC TK line + */ + pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME master\n"); + rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | + SSC_BF(RCMR_STTDLY, START_DELAY) | + SSC_BF(RCMR_START, SSC_START_FALLING_RF) | + SSC_BF(RCMR_CKI, SSC_CKI_RISING) | + SSC_BF(RCMR_CKO, SSC_CKO_NONE) | + SSC_BF(RCMR_CKS, SSC_CKS_DIV)); + + rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) | + SSC_BF(RFMR_FSLEN, bits - 1) | + SSC_BF(RFMR_DATNB, channels - 1) | + SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); + + tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | + SSC_BF(TCMR_STTDLY, START_DELAY) | + SSC_BF(TCMR_START, SSC_START_FALLING_RF) | + SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | + SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | + SSC_BF(TCMR_CKS, SSC_CKS_DIV)); + + tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) | + SSC_BF(TFMR_FSLEN, bits - 1) | + SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) | + SSC_BF(TFMR_DATLEN, bits - 1)); + break; + + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + /* + * I2S format, CODEC supplies BCLK and LRC clock. + * + * The SSC transmit clock is obtained from the BCLK signal + * on the TK line, and the SSC receive clock is generated from + * the transmit clock. + * + * For single channel data, one sample is transferred on the + * falling edge of the LRC clock. For two channel data, one + * sample is transferred on both edges of the LRC clock. + */ + pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME slave\n"); + start_event = ((channels == 1) ? + SSC_START_FALLING_RF : SSC_START_EDGE_RF); + + rcmr = (SSC_BF(RCMR_STTDLY, START_DELAY) | + 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)); + + rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | + SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); + + tcmr = (SSC_BF(TCMR_STTDLY, START_DELAY) | + 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)); + + tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | + SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); + break; + + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: + /* + * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output on the SSC TK line + */ + pr_debug("at32-ssc: SSC mode is DSP A BCLK / FRAME master\n"); + rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | + SSC_BF(RCMR_STTDLY, 1) | + 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_CKS_DIV)); + + rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) | + SSC_BF(RFMR_DATNB, channels - 1) | + SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); + + tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | + SSC_BF(TCMR_STTDLY, 1) | + SSC_BF(TCMR_START, SSC_START_RISING_RF) | + SSC_BF(TCMR_CKI, SSC_CKI_RISING) | + SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | + SSC_BF(TCMR_CKS, SSC_CKS_DIV)); + + tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | + SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) | + SSC_BF(TFMR_DATNB, channels - 1) | + SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); + break; + + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + default: + pr_warning("at32-ssc: unsupported DAI format 0x%x\n", + ssc_p->daifmt); + return -EINVAL; + break; + } + pr_debug("at32-ssc: RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", + rcmr, rfmr, tcmr, tfmr); + + + if (!ssc_p->initialized) { + /* enable peripheral clock */ + pr_debug("at32-ssc: Starting clock\n"); + clk_enable(ssc_p->ssc->clk); + + /* Reset the SSC and its PDC registers */ + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); + + ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); + + ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); + + ret = request_irq(ssc_p->ssc->irq, at32_ssc_interrupt, 0, + ssc_p->name, ssc_p); + if (ret < 0) { + pr_warning("at32-ssc: request irq failed (%d)\n", ret); + pr_debug("at32-ssc: Stopping clock\n"); + clk_disable(ssc_p->ssc->clk); + return ret; + } + + ssc_p->initialized = 1; + } + + /* Set SSC clock mode register */ + ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); + + /* set receive clock mode and format */ + ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); + ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); + + /* set transmit clock mode and format */ + ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); + ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); + + pr_debug("at32-ssc: SSC initialized\n"); + return 0; +} + + + +static int at32_ssc_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct at32_pcm_dma_params *dma_params; + + dma_params = ssc_p->dma_params[substream->stream]; + + ssc_writel(dma_params->ssc->regs, CR, dma_params->mask->ssc_enable); + + return 0; +} + + + +#ifdef CONFIG_PM +static int at32_ssc_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct at32_ssc_info *ssc_p; + + if (!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + /* Save the status register before disabling transmit and receive */ + ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS)); + + /* Save the current interrupt mask, then disable unmasked interrupts */ + ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR); + ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr); + + ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR); + ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR); + ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR); + ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); + ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); + + return 0; +} + + + +static int at32_ssc_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct at32_ssc_info *ssc_p; + u32 cr; + + if (!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + /* restore SSC register settings */ + ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); + ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); + ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr); + ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr); + ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr); + + /* re-enable interrupts */ + ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); + + /* Re-enable recieve and transmit as appropriate */ + cr = 0; + cr |= + (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; + cr |= + (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0; + ssc_writel(ssc_p->ssc->regs, CR, cr); + + return 0; +} +#else /* CONFIG_PM */ +# define at32_ssc_suspend NULL +# define at32_ssc_resume NULL +#endif /* CONFIG_PM */ + + +#define AT32_SSC_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + + +#define AT32_SSC_FORMATS \ + (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16 | \ + SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32) + + +struct snd_soc_dai at32_ssc_dai[NUM_SSC_DEVICES] = { + { + .name = "at32-ssc0", + .id = 0, + .type = SND_SOC_DAI_PCM, + .suspend = at32_ssc_suspend, + .resume = at32_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .ops = { + .startup = at32_ssc_startup, + .shutdown = at32_ssc_shutdown, + .prepare = at32_ssc_prepare, + .hw_params = at32_ssc_hw_params, + }, + .dai_ops = { + .set_sysclk = at32_ssc_set_dai_sysclk, + .set_fmt = at32_ssc_set_dai_fmt, + .set_clkdiv = at32_ssc_set_dai_clkdiv, + }, + .private_data = &ssc_info[0], + }, + { + .name = "at32-ssc1", + .id = 1, + .type = SND_SOC_DAI_PCM, + .suspend = at32_ssc_suspend, + .resume = at32_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .ops = { + .startup = at32_ssc_startup, + .shutdown = at32_ssc_shutdown, + .prepare = at32_ssc_prepare, + .hw_params = at32_ssc_hw_params, + }, + .dai_ops = { + .set_sysclk = at32_ssc_set_dai_sysclk, + .set_fmt = at32_ssc_set_dai_fmt, + .set_clkdiv = at32_ssc_set_dai_clkdiv, + }, + .private_data = &ssc_info[1], + }, + { + .name = "at32-ssc2", + .id = 2, + .type = SND_SOC_DAI_PCM, + .suspend = at32_ssc_suspend, + .resume = at32_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT32_SSC_RATES, + .formats = AT32_SSC_FORMATS, + }, + .ops = { + .startup = at32_ssc_startup, + .shutdown = at32_ssc_shutdown, + .prepare = at32_ssc_prepare, + .hw_params = at32_ssc_hw_params, + }, + .dai_ops = { + .set_sysclk = at32_ssc_set_dai_sysclk, + .set_fmt = at32_ssc_set_dai_fmt, + .set_clkdiv = at32_ssc_set_dai_clkdiv, + }, + .private_data = &ssc_info[2], + }, +}; +EXPORT_SYMBOL_GPL(at32_ssc_dai); + + +MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); +MODULE_DESCRIPTION("AT32 SSC ASoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/at32/at32-ssc.h b/sound/soc/at32/at32-ssc.h new file mode 100644 index 000000000000..3c052dbbe460 --- /dev/null +++ b/sound/soc/at32/at32-ssc.h @@ -0,0 +1,59 @@ +/* sound/soc/at32/at32-ssc.h + * ASoC SSC interface for Atmel AT32 SoC + * + * Copyright (C) 2008 Long Range Systems + * Geoffrey Wossum <gwossum@acm.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __SOUND_SOC_AT32_AT32_SSC_H +#define __SOUND_SOC_AT32_AT32_SSC_H __FILE__ + +#include <linux/types.h> +#include <linux/atmel-ssc.h> + +#include "at32-pcm.h" + + + +struct at32_ssc_state { + u32 ssc_cmr; + u32 ssc_rcmr; + u32 ssc_rfmr; + u32 ssc_tcmr; + u32 ssc_tfmr; + u32 ssc_sr; + u32 ssc_imr; +}; + + + +struct at32_ssc_info { + char *name; + struct ssc_device *ssc; + spinlock_t lock; /* lock for dir_mask */ + unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ + unsigned short initialized; /* true if SSC has been initialized */ + unsigned short daifmt; + unsigned short cmr_div; + unsigned short tcmr_period; + unsigned short rcmr_period; + struct at32_pcm_dma_params *dma_params[2]; + struct at32_ssc_state ssc_state; +}; + + +/* SSC divider ids */ +#define AT32_SSC_CMR_DIV 0 /* MCK divider for BCLK */ +#define AT32_SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ +#define AT32_SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ + + +extern struct snd_soc_dai at32_ssc_dai[]; + + + +#endif /* __SOUND_SOC_AT32_AT32_SSC_H */ diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/at32/playpaq_wm8510.c index 43dd8cee83c6..b1966e4dfcd3 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/at32/playpaq_wm8510.c @@ -22,6 +22,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/version.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/clk.h> @@ -39,8 +40,8 @@ #include <mach/portmux.h> #include "../codecs/wm8510.h" -#include "atmel-pcm.h" -#include "atmel_ssc_dai.h" +#include "at32-pcm.h" +#include "at32-ssc.h" /*-------------------------------------------------------------------------*\ @@ -361,9 +362,8 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = { -static struct snd_soc_card snd_soc_playpaq = { +static struct snd_soc_machine snd_soc_machine_playpaq = { .name = "LRS_PlayPaq_WM8510", - .platform = &at32_soc_platform, .dai_link = &playpaq_wm8510_dai, .num_links = 1, }; @@ -378,7 +378,8 @@ static struct wm8510_setup_data playpaq_wm8510_setup = { static struct snd_soc_device playpaq_wm8510_snd_devdata = { - .card = &snd_soc_playpaq, + .machine = &snd_soc_machine_playpaq, + .platform = &at32_soc_platform, .codec_dev = &soc_codec_dev_wm8510, .codec_data = &playpaq_wm8510_setup, }; diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig new file mode 100644 index 000000000000..85a883299c2e --- /dev/null +++ b/sound/soc/at91/Kconfig @@ -0,0 +1,10 @@ +config SND_AT91_SOC + tristate "SoC Audio for the Atmel AT91 System-on-Chip" + depends on ARCH_AT91 + help + Say Y or M if you want to add support for codecs attached to + the AT91 SSC interface. You will also need + to select the audio interfaces to support below. + +config SND_AT91_SOC_SSC + tristate diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile new file mode 100644 index 000000000000..b817f11df286 --- /dev/null +++ b/sound/soc/at91/Makefile @@ -0,0 +1,6 @@ +# AT91 Platform Support +snd-soc-at91-objs := at91-pcm.o +snd-soc-at91-ssc-objs := at91-ssc.o + +obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o +obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c new file mode 100644 index 000000000000..7ab48bd25e4c --- /dev/null +++ b/sound/soc/at91/at91-pcm.c @@ -0,0 +1,434 @@ +/* + * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC + * + * Author: Frank Mandarino <fmandarino@endrelia.com> + * Endrelia Technologies Inc. + * Created: Mar 3, 2006 + * + * Based on pxa2xx-pcm.c by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: (C) 2004 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/atmel_pdc.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#include <mach/hardware.h> +#include <mach/at91_ssc.h> + +#include "at91-pcm.h" + +#if 0 +#define DBG(x...) printk(KERN_INFO "at91-pcm: " x) +#else +#define DBG(x...) +#endif + +static const struct snd_pcm_hardware at91_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + 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, + .periods_max = 1024, + .buffer_bytes_max = 32 * 1024, +}; + +struct at91_runtime_data { + struct at91_pcm_dma_params *params; + dma_addr_t dma_buffer; /* physical address of dma buffer */ + dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ + size_t period_size; + dma_addr_t period_ptr; /* physical address of next period */ + u32 pdc_xpr_save; /* PDC register save */ + u32 pdc_xcr_save; + u32 pdc_xnpr_save; + u32 pdc_xncr_save; +}; + +static void at91_pcm_dma_irq(u32 ssc_sr, + struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + static int count = 0; + + count++; + + if (ssc_sr & params->mask->ssc_endbuf) { + + printk(KERN_WARNING + "at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", + substream->stream == SNDRV_PCM_STREAM_PLAYBACK + ? "underrun" : "overrun", + params->name, ssc_sr, count); + + /* re-start the PDC */ + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); + + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) { + prtd->period_ptr = prtd->dma_buffer; + } + + at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); + } + + if (ssc_sr & params->mask->ssc_endx) { + + /* Load the PDC next pointer and counter registers */ + prtd->period_ptr += prtd->period_size; + if (prtd->period_ptr >= prtd->dma_buffer_end) { + prtd->period_ptr = prtd->dma_buffer; + } + at91_ssc_write(params->ssc_base + params->pdc->xnpr, + prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + } + + snd_pcm_period_elapsed(substream); +} + +static int at91_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at91_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + + /* this may get called several times by oss emulation + * with different params */ + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + prtd->params = rtd->dai->cpu_dai->dma_data; + prtd->params->dma_intr_handler = at91_pcm_dma_irq; + + prtd->dma_buffer = runtime->dma_addr; + prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; + prtd->period_size = params_period_bytes(params); + + DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n", + prtd->params->name, runtime->dma_bytes, prtd->period_size); + return 0; +} + +static int at91_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + + if (params != NULL) { + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); + prtd->params->dma_intr_handler = NULL; + } + + return 0; +} + +static int at91_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + + at91_ssc_write(params->ssc_base + AT91_SSC_IDR, + params->mask->ssc_endx | params->mask->ssc_endbuf); + + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); + return 0; +} + +static int at91_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->period_ptr = prtd->dma_buffer; + + at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xcr, + prtd->period_size / params->pdc_xfer_size); + + prtd->period_ptr += prtd->period_size; + at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr); + at91_ssc_write(params->ssc_base + params->pdc->xncr, + prtd->period_size / params->pdc_xfer_size); + + DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n", + (unsigned long) prtd->period_ptr, + at91_ssc_read(params->ssc_base + params->pdc->xpr), + at91_ssc_read(params->ssc_base + params->pdc->xcr), + at91_ssc_read(params->ssc_base + params->pdc->xnpr), + at91_ssc_read(params->ssc_base + params->pdc->xncr)); + + at91_ssc_write(params->ssc_base + AT91_SSC_IER, + params->mask->ssc_endx | params->mask->ssc_endbuf); + + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, + params->mask->pdc_enable); + + DBG("sr=%lx imr=%lx\n", + at91_ssc_read(params->ssc_base + AT91_SSC_SR), + at91_ssc_read(params->ssc_base + AT91_SSC_IMR)); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); + break; + + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t at91_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at91_runtime_data *prtd = runtime->private_data; + struct at91_pcm_dma_params *params = prtd->params; + dma_addr_t ptr; + snd_pcm_uframes_t x; + + ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr); + x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); + + if (x == runtime->buffer_size) + x = 0; + return x; +} + +static int at91_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct at91_runtime_data *prtd; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware); + + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + + prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL); + if (prtd == NULL) { + ret = -ENOMEM; + goto out; + } + runtime->private_data = prtd; + + out: + return ret; +} + +static int at91_pcm_close(struct snd_pcm_substream *substream) +{ + struct at91_runtime_data *prtd = substream->runtime->private_data; + + kfree(prtd); + return 0; +} + +static int at91_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +struct snd_pcm_ops at91_pcm_ops = { + .open = at91_pcm_open, + .close = at91_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = at91_pcm_hw_params, + .hw_free = at91_pcm_hw_free, + .prepare = at91_pcm_prepare, + .trigger = at91_pcm_trigger, + .pointer = at91_pcm_pointer, + .mmap = at91_pcm_mmap, +}; + +static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = at91_pcm_hardware.buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + + DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", + (void *) buf->area, + (void *) buf->addr, + size); + + if (!buf->area) + return -ENOMEM; + + buf->bytes = size; + return 0; +} + +static u64 at91_pcm_dmamask = 0xffffffff; + +static int at91_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) +{ + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &at91_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = 0xffffffff; + + if (dai->playback.channels_min) { + ret = at91_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = at91_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + out: + return ret; +} + +static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +#ifdef CONFIG_PM +static int at91_pcm_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at91_runtime_data *prtd; + struct at91_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* disable the PDC and save the PDC registers */ + + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); + + prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr); + prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr); + prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr); + prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr); + + return 0; +} + +static int at91_pcm_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct snd_pcm_runtime *runtime = dai->runtime; + struct at91_runtime_data *prtd; + struct at91_pcm_dma_params *params; + + if (!runtime) + return 0; + + prtd = runtime->private_data; + params = prtd->params; + + /* restore the PDC registers and enable the PDC */ + at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->pdc_xpr_save); + at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->pdc_xcr_save); + at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save); + at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save); + + at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); + return 0; +} +#else +#define at91_pcm_suspend NULL +#define at91_pcm_resume NULL +#endif + +struct snd_soc_platform at91_soc_platform = { + .name = "at91-audio", + .pcm_ops = &at91_pcm_ops, + .pcm_new = at91_pcm_new, + .pcm_free = at91_pcm_free_dma_buffers, + .suspend = at91_pcm_suspend, + .resume = at91_pcm_resume, +}; + +EXPORT_SYMBOL_GPL(at91_soc_platform); + +MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>"); +MODULE_DESCRIPTION("Atmel AT91 PCM module"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h new file mode 100644 index 000000000000..e5aada2cb102 --- /dev/null +++ b/sound/soc/at91/at91-pcm.h @@ -0,0 +1,72 @@ +/* + * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC + * + * Author: Frank Mandarino <fmandarino@endrelia.com> + * Endrelia Technologies Inc. + * Created: Mar 3, 2006 + * + * Based on pxa2xx-pcm.h by: + * + * Author: Nicolas Pitre + * Created: Nov 30, 2004 + * Copyright: MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _AT91_PCM_H +#define _AT91_PCM_H + +#include <mach/hardware.h> + +struct at91_ssc_periph { + void __iomem *base; + u32 pid; +}; + +/* + * Registers and status bits that are required by the PCM driver. + */ +struct at91_pdc_regs { + unsigned int xpr; /* PDC recv/trans pointer */ + unsigned int xcr; /* PDC recv/trans counter */ + unsigned int xnpr; /* PDC next recv/trans pointer */ + unsigned int xncr; /* PDC next recv/trans counter */ + unsigned int ptcr; /* PDC transfer control */ +}; + +struct at91_ssc_mask { + u32 ssc_enable; /* SSC recv/trans enable */ + u32 ssc_disable; /* SSC recv/trans disable */ + u32 ssc_endx; /* SSC ENDTX or ENDRX */ + u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ + u32 pdc_enable; /* PDC recv/trans enable */ + u32 pdc_disable; /* PDC recv/trans disable */ +}; + +/* + * This structure, shared between the PCM driver and the interface, + * contains all information required by the PCM driver to perform the + * PDC DMA operation. All fields except dma_intr_handler() are initialized + * by the interface. The dms_intr_handler() pointer is set by the PCM + * driver and called by the interface SSC interrupt handler if it is + * non-NULL. + */ +struct at91_pcm_dma_params { + char *name; /* stream identifier */ + int pdc_xfer_size; /* PDC counter increment in bytes */ + void __iomem *ssc_base; /* SSC base address */ + struct at91_pdc_regs *pdc; /* PDC receive or transmit registers */ + struct at91_ssc_mask *mask;/* SSC & PDC status bits */ + struct snd_pcm_substream *substream; + void (*dma_intr_handler)(u32, struct snd_pcm_substream *); +}; + +extern struct snd_soc_platform at91_soc_platform; + +#define at91_ssc_read(a) ((unsigned long) __raw_readl(a)) +#define at91_ssc_write(a,v) __raw_writel((v),(a)) + +#endif /* _AT91_PCM_H */ diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c new file mode 100644 index 000000000000..1b61cc461261 --- /dev/null +++ b/sound/soc/at91/at91-ssc.c @@ -0,0 +1,791 @@ +/* + * at91-ssc.c -- ALSA SoC AT91 SSC Audio Layer Platform driver + * + * Author: Frank Mandarino <fmandarino@endrelia.com> + * Endrelia Technologies Inc. + * + * Based on pxa2xx Platform drivers by + * Liam Girdwood <lrg@slimlogic.co.uk> + * + * 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/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/atmel_pdc.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> + +#include <mach/hardware.h> +#include <mach/at91_pmc.h> +#include <mach/at91_ssc.h> + +#include "at91-pcm.h" +#include "at91-ssc.h" + +#if 0 +#define DBG(x...) printk(KERN_DEBUG "at91-ssc:" x) +#else +#define DBG(x...) +#endif + +#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) +#define NUM_SSC_DEVICES 1 +#else +#define NUM_SSC_DEVICES 3 +#endif + + +/* + * SSC PDC registers required by the PCM DMA engine. + */ +static struct at91_pdc_regs pdc_tx_reg = { + .xpr = ATMEL_PDC_TPR, + .xcr = ATMEL_PDC_TCR, + .xnpr = ATMEL_PDC_TNPR, + .xncr = ATMEL_PDC_TNCR, +}; + +static struct at91_pdc_regs pdc_rx_reg = { + .xpr = ATMEL_PDC_RPR, + .xcr = ATMEL_PDC_RCR, + .xnpr = ATMEL_PDC_RNPR, + .xncr = ATMEL_PDC_RNCR, +}; + +/* + * SSC & PDC status bits for transmit and receive. + */ +static struct at91_ssc_mask ssc_tx_mask = { + .ssc_enable = AT91_SSC_TXEN, + .ssc_disable = AT91_SSC_TXDIS, + .ssc_endx = AT91_SSC_ENDTX, + .ssc_endbuf = AT91_SSC_TXBUFE, + .pdc_enable = ATMEL_PDC_TXTEN, + .pdc_disable = ATMEL_PDC_TXTDIS, +}; + +static struct at91_ssc_mask ssc_rx_mask = { + .ssc_enable = AT91_SSC_RXEN, + .ssc_disable = AT91_SSC_RXDIS, + .ssc_endx = AT91_SSC_ENDRX, + .ssc_endbuf = AT91_SSC_RXBUFF, + .pdc_enable = ATMEL_PDC_RXTEN, + .pdc_disable = ATMEL_PDC_RXTDIS, +}; + + +/* + * DMA parameters. + */ +static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { + {{ + .name = "SSC0 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC0 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }}, +#if NUM_SSC_DEVICES == 3 + {{ + .name = "SSC1 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC1 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }}, + {{ + .name = "SSC2 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC2 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + }}, +#endif +}; + +struct at91_ssc_state { + u32 ssc_cmr; + u32 ssc_rcmr; + u32 ssc_rfmr; + u32 ssc_tcmr; + u32 ssc_tfmr; + u32 ssc_sr; + u32 ssc_imr; +}; + +static struct at91_ssc_info { + char *name; + struct at91_ssc_periph ssc; + spinlock_t lock; /* lock for dir_mask */ + unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ + unsigned short initialized; /* 1=SSC has been initialized */ + unsigned short daifmt; + unsigned short cmr_div; + unsigned short tcmr_period; + unsigned short rcmr_period; + struct at91_pcm_dma_params *dma_params[2]; + struct at91_ssc_state ssc_state; + +} ssc_info[NUM_SSC_DEVICES] = { + { + .name = "ssc0", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), + .dir_mask = 0, + .initialized = 0, + }, +#if NUM_SSC_DEVICES == 3 + { + .name = "ssc1", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), + .dir_mask = 0, + .initialized = 0, + }, + { + .name = "ssc2", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), + .dir_mask = 0, + .initialized = 0, + }, +#endif +}; + +static unsigned int at91_ssc_sysclk; + +/* + * SSC interrupt handler. Passes PDC interrupts to the DMA + * interrupt handler in the PCM driver. + */ +static irqreturn_t at91_ssc_interrupt(int irq, void *dev_id) +{ + struct at91_ssc_info *ssc_p = dev_id; + struct at91_pcm_dma_params *dma_params; + u32 ssc_sr; + int i; + + ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR) + & at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); + + /* + * Loop through the substreams attached to this SSC. If + * a DMA-related interrupt occurred on that substream, call + * the DMA interrupt handler function, if one has been + * registered in the dma_params structure by the PCM driver. + */ + for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { + dma_params = ssc_p->dma_params[i]; + + if (dma_params != NULL && dma_params->dma_intr_handler != NULL && + (ssc_sr & + (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf))) + + dma_params->dma_intr_handler(ssc_sr, dma_params->substream); + } + + return IRQ_HANDLED; +} + +/* + * Startup. Only that one substream allowed in each direction. + */ +static int at91_ssc_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + int dir_mask; + + DBG("ssc_startup: SSC_SR=0x%08lx\n", + at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); + dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2; + + spin_lock_irq(&ssc_p->lock); + if (ssc_p->dir_mask & dir_mask) { + spin_unlock_irq(&ssc_p->lock); + return -EBUSY; + } + ssc_p->dir_mask |= dir_mask; + spin_unlock_irq(&ssc_p->lock); + + return 0; +} + +/* + * Shutdown. Clear DMA parameters and shutdown the SSC if there + * are no other substreams open. + */ +static void at91_ssc_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct at91_pcm_dma_params *dma_params; + int dir, dir_mask; + + dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + dma_params = ssc_p->dma_params[dir]; + + if (dma_params != NULL) { + at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, + dma_params->mask->ssc_disable); + DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"), + at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); + + dma_params->ssc_base = NULL; + dma_params->substream = NULL; + ssc_p->dma_params[dir] = NULL; + } + + dir_mask = 1 << dir; + + spin_lock_irq(&ssc_p->lock); + ssc_p->dir_mask &= ~dir_mask; + if (!ssc_p->dir_mask) { + /* Shutdown the SSC clock. */ + DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); + at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid); + + if (ssc_p->initialized) { + free_irq(ssc_p->ssc.pid, ssc_p); + ssc_p->initialized = 0; + } + + /* Reset the SSC */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); + + /* Clear the SSC dividers */ + ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; + } + spin_unlock_irq(&ssc_p->lock); +} + +/* + * Record the SSC system clock rate. + */ +static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + /* + * The only clock supplied to the SSC is the AT91 master clock, + * which is only used if the SSC is generating BCLK and/or + * LRC clocks. + */ + switch (clk_id) { + case AT91_SYSCLK_MCK: + at91_ssc_sysclk = freq; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + * Record the DAI format for use in hw_params(). + */ +static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + ssc_p->daifmt = fmt; + return 0; +} + +/* + * Record SSC clock dividers for use in hw_params(). + */ +static int at91_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + switch (div_id) { + case AT91SSC_CMR_DIV: + /* + * The same master clock divider is used for both + * transmit and receive, so if a value has already + * been set, it must match this value. + */ + if (ssc_p->cmr_div == 0) + ssc_p->cmr_div = div; + else + if (div != ssc_p->cmr_div) + return -EBUSY; + break; + + case AT91SSC_TCMR_PERIOD: + ssc_p->tcmr_period = div; + break; + + case AT91SSC_RCMR_PERIOD: + ssc_p->rcmr_period = div; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * Configure the SSC. + */ +static int at91_ssc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int id = rtd->dai->cpu_dai->id; + struct at91_ssc_info *ssc_p = &ssc_info[id]; + struct at91_pcm_dma_params *dma_params; + int dir, channels, bits; + u32 tfmr, rfmr, tcmr, rcmr; + int start_event; + int ret; + + /* + * Currently, there is only one set of dma params for + * each direction. If more are added, this code will + * have to be changed to select the proper set. + */ + dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + + dma_params = &ssc_dma_params[id][dir]; + dma_params->ssc_base = ssc_p->ssc.base; + dma_params->substream = substream; + + ssc_p->dma_params[dir] = dma_params; + + /* + * The cpu_dai->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. + */ + rtd->dai->cpu_dai->dma_data = dma_params; + + channels = params_channels(params); + + /* + * Determine sample size in bits and the PDC increment. + */ + switch(params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + bits = 8; + dma_params->pdc_xfer_size = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + bits = 16; + dma_params->pdc_xfer_size = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + bits = 24; + dma_params->pdc_xfer_size = 4; + break; + case SNDRV_PCM_FORMAT_S32_LE: + bits = 32; + dma_params->pdc_xfer_size = 4; + break; + default: + printk(KERN_WARNING "at91-ssc: unsupported PCM format\n"); + return -EINVAL; + } + + /* + * The SSC only supports up to 16-bit samples in I2S format, due + * to the size of the Frame Mode Register FSLEN field. + */ + if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S + && bits > 16) { + printk(KERN_WARNING + "at91-ssc: sample size %d is too large for I2S\n", bits); + return -EINVAL; + } + + /* + * Compute SSC register settings. + */ + switch (ssc_p->daifmt + & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + /* + * I2S format, SSC provides BCLK and LRC clocks. + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output on the SSC TK line. + */ + rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) + | (((bits - 1) << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_LOOP) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( 0 << 23) & AT91_SSC_FSDEN) + | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) + | (((bits - 1) << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_DATDEF) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + break; + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + /* + * I2S 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. + * + * For single channel data, one sample is transferred on the falling + * edge of the LRC clock. For two channel data, one sample is + * transferred on both edges of the LRC clock. + */ + start_event = channels == 1 + ? AT91_SSC_START_FALLING_RF + : AT91_SSC_START_EDGE_RF; + + rcmr = (( 0 << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( start_event ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS); + + rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (( 0 << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_LOOP) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + tcmr = (( 0 << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( start_event ) & AT91_SSC_START) + | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_PIN ) & AT91_SSC_CKS); + + tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( 0 << 23) & AT91_SSC_FSDEN) + | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (( 0 << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_DATDEF) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + break; + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: + /* + * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output on the SSC TK line. + */ + rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_RISING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( AT91_SSC_FSOS_POSITIVE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_LOOP) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD) + | (( 1 << 16) & AT91_SSC_STTDLY) + | (( AT91_SSC_START_RISING_RF ) & AT91_SSC_START) + | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) + | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) + | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); + + tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) + | (( 0 << 23) & AT91_SSC_FSDEN) + | (( AT91_SSC_FSOS_POSITIVE ) & AT91_SSC_FSOS) + | (( 0 << 16) & AT91_SSC_FSLEN) + | (((channels - 1) << 8) & AT91_SSC_DATNB) + | (( 1 << 7) & AT91_SSC_MSBF) + | (( 0 << 5) & AT91_SSC_DATDEF) + | (((bits - 1) << 0) & AT91_SSC_DATALEN); + + + + break; + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + default: + printk(KERN_WARNING "at91-ssc: unsupported DAI format 0x%x.\n", + ssc_p->daifmt); + return -EINVAL; + break; + } + DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr); + + if (!ssc_p->initialized) { + + /* Enable PMC peripheral clock for this SSC */ + DBG("Starting pid %d clock\n", ssc_p->ssc.pid); + at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid); + + /* Reset the SSC and its PDC registers */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); + + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RCR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNCR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TCR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNPR, 0); + at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNCR, 0); + + if ((ret = request_irq(ssc_p->ssc.pid, at91_ssc_interrupt, + 0, ssc_p->name, ssc_p)) < 0) { + printk(KERN_WARNING "at91-ssc: request_irq failure\n"); + + DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); + at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid); + return ret; + } + + ssc_p->initialized = 1; + } + + /* set SSC clock mode register */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div); + + /* set receive clock mode and format */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr); + + /* set transmit clock mode and format */ + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr); + + DBG("hw_params: SSC initialized\n"); + return 0; +} + + +static int at91_ssc_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct at91_pcm_dma_params *dma_params; + int dir; + + dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + dma_params = ssc_p->dma_params[dir]; + + at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, + dma_params->mask->ssc_enable); + + DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit", + at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR)); + return 0; +} + + +#ifdef CONFIG_PM +static int at91_ssc_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct at91_ssc_info *ssc_p; + + if(!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + /* Save the status register before disabling transmit and receive. */ + ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, + AT91_SSC_TXDIS | AT91_SSC_RXDIS); + + /* Save the current interrupt mask, then disable unmasked interrupts. */ + ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr); + + ssc_p->ssc_state.ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR); + ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); + ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR); + ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR); + ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR); + + return 0; +} + +static int at91_ssc_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct at91_ssc_info *ssc_p; + + if(!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr); + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->ssc_state.ssc_cmr); + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->ssc_state.ssc_imr); + + at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, + ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | + ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); + + return 0; +} + +#else +#define at91_ssc_suspend NULL +#define at91_ssc_resume NULL +#endif + +#define AT91_SSC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000) + +#define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +struct snd_soc_dai at91_ssc_dai[NUM_SSC_DEVICES] = { + { .name = "at91-ssc0", + .id = 0, + .type = SND_SOC_DAI_PCM, + .suspend = at91_ssc_suspend, + .resume = at91_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .ops = { + .startup = at91_ssc_startup, + .shutdown = at91_ssc_shutdown, + .prepare = at91_ssc_prepare, + .hw_params = at91_ssc_hw_params,}, + .dai_ops = { + .set_sysclk = at91_ssc_set_dai_sysclk, + .set_fmt = at91_ssc_set_dai_fmt, + .set_clkdiv = at91_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[0].ssc, + }, +#if NUM_SSC_DEVICES == 3 + { .name = "at91-ssc1", + .id = 1, + .type = SND_SOC_DAI_PCM, + .suspend = at91_ssc_suspend, + .resume = at91_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .ops = { + .startup = at91_ssc_startup, + .shutdown = at91_ssc_shutdown, + .prepare = at91_ssc_prepare, + .hw_params = at91_ssc_hw_params,}, + .dai_ops = { + .set_sysclk = at91_ssc_set_dai_sysclk, + .set_fmt = at91_ssc_set_dai_fmt, + .set_clkdiv = at91_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[1].ssc, + }, + { .name = "at91-ssc2", + .id = 2, + .type = SND_SOC_DAI_PCM, + .suspend = at91_ssc_suspend, + .resume = at91_ssc_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = AT91_SSC_RATES, + .formats = AT91_SSC_FORMATS,}, + .ops = { + .startup = at91_ssc_startup, + .shutdown = at91_ssc_shutdown, + .prepare = at91_ssc_prepare, + .hw_params = at91_ssc_hw_params,}, + .dai_ops = { + .set_sysclk = at91_ssc_set_dai_sysclk, + .set_fmt = at91_ssc_set_dai_fmt, + .set_clkdiv = at91_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[2].ssc, + }, +#endif +}; + +EXPORT_SYMBOL_GPL(at91_ssc_dai); + +/* Module information */ +MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com"); +MODULE_DESCRIPTION("AT91 SSC ASoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91-ssc.h b/sound/soc/at91/at91-ssc.h new file mode 100644 index 000000000000..6b7bf382d06f --- /dev/null +++ b/sound/soc/at91/at91-ssc.h @@ -0,0 +1,27 @@ +/* + * at91-ssc.h - ALSA SSC interface for the Atmel AT91 SoC + * + * Author: Frank Mandarino <fmandarino@endrelia.com> + * Endrelia Technologies Inc. + * Created: Jan 9, 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _AT91_SSC_H +#define _AT91_SSC_H + +/* SSC system clock ids */ +#define AT91_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */ + +/* SSC divider ids */ +#define AT91SSC_CMR_DIV 0 /* MCK divider for BCLK */ +#define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ +#define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ + +extern struct snd_soc_dai at91_ssc_dai[]; + +#endif /* _AT91_SSC_H */ + diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig deleted file mode 100644 index a608d7009dbd..000000000000 --- a/sound/soc/atmel/Kconfig +++ /dev/null @@ -1,43 +0,0 @@ -config SND_ATMEL_SOC - tristate "SoC Audio for the Atmel System-on-Chip" - depends on ARCH_AT91 || AVR32 - help - Say Y or M if you want to add support for codecs attached to - the ATMEL SSC interface. You will also need - to select the audio interfaces to support below. - -config SND_ATMEL_SOC_SSC - tristate - depends on SND_ATMEL_SOC - help - Say Y or M if you want to add support for codecs the - ATMEL SSC interface. You will also needs to select the individual - machine drivers to support below. - -config SND_AT91_SOC_SAM9G20_WM8731 - tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" - depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC - select SND_ATMEL_SOC_SSC - select SND_SOC_WM8731 - help - Say Y if you want to add support for SoC audio on WM8731-based - AT91sam9g20 evaluation board. - -config SND_AT32_SOC_PLAYPAQ - tristate "SoC Audio support for PlayPaq with WM8510" - depends on SND_ATMEL_SOC && BOARD_PLAYPAQ - select SND_ATMEL_SOC_SSC - select SND_SOC_WM8510 - help - Say Y or M here if you want to add support for SoC audio - on the LRS PlayPaq. - -config SND_AT32_SOC_PLAYPAQ_SLAVE - bool "Run CODEC on PlayPaq in slave mode" - depends on SND_AT32_SOC_PLAYPAQ - default n - help - Say Y if you want to run with the AT32 SSC generating the BCLK - and FRAME signals on the PlayPaq. Unless you want to play - with the AT32 as the SSC master, you probably want to say N here, - as this will give you better sound quality. diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile deleted file mode 100644 index f54a7cc68e66..000000000000 --- a/sound/soc/atmel/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# AT91 Platform Support -snd-soc-atmel-pcm-objs := atmel-pcm.o -snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o - -obj-$(CONFIG_SND_ATMEL_SOC) += snd-soc-atmel-pcm.o -obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o - -# AT91 Machine Support -snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o - -# AT32 Machine Support -snd-soc-playpaq-objs := playpaq_wm8510.o - -obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o -obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c deleted file mode 100644 index 027eb13f9dd0..000000000000 --- a/sound/soc/atmel/atmel-pcm.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * atmel-pcm.c -- ALSA PCM interface for the Atmel atmel SoC. - * - * Copyright (C) 2005 SAN People - * Copyright (C) 2008 Atmel - * - * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> - * - * Based on at91-pcm. by: - * Frank Mandarino <fmandarino@endrelia.com> - * Copyright 2006 Endrelia Technologies Inc. - * - * Based on pxa2xx-pcm.c by: - * - * Author: Nicolas Pitre - * Created: Nov 30, 2004 - * Copyright: (C) 2004 MontaVista Software, Inc. - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/dma-mapping.h> -#include <linux/atmel_pdc.h> -#include <linux/atmel-ssc.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include <mach/hardware.h> - -#include "atmel-pcm.h" - - -/*--------------------------------------------------------------------------*\ - * Hardware definition -\*--------------------------------------------------------------------------*/ -/* TODO: These values were taken from the AT91 platform driver, check - * them against real values for AT32 - */ -static const struct snd_pcm_hardware atmel_pcm_hardware = { - .info = SNDRV_PCM_INFO_MMAP | - 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, - .periods_max = 1024, - .buffer_bytes_max = 32 * 1024, -}; - - -/*--------------------------------------------------------------------------*\ - * Data types -\*--------------------------------------------------------------------------*/ -struct atmel_runtime_data { - struct atmel_pcm_dma_params *params; - dma_addr_t dma_buffer; /* physical address of dma buffer */ - dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ - size_t period_size; - - dma_addr_t period_ptr; /* physical address of next period */ - int periods; /* period index of period_ptr */ - - /* PDC register save */ - u32 pdc_xpr_save; - u32 pdc_xcr_save; - u32 pdc_xnpr_save; - u32 pdc_xncr_save; -}; - - -/*--------------------------------------------------------------------------*\ - * Helper functions -\*--------------------------------------------------------------------------*/ -static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, - int stream) -{ - struct snd_pcm_substream *substream = pcm->streams[stream].substream; - struct snd_dma_buffer *buf = &substream->dma_buffer; - size_t size = atmel_pcm_hardware.buffer_bytes_max; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - buf->area = dma_alloc_coherent(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - pr_debug("atmel-pcm:" - "preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", - (void *) buf->area, - (void *) buf->addr, - size); - - if (!buf->area) - return -ENOMEM; - - buf->bytes = size; - return 0; -} -/*--------------------------------------------------------------------------*\ - * ISR -\*--------------------------------------------------------------------------*/ -static void atmel_pcm_dma_irq(u32 ssc_sr, - struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - static int count; - - count++; - - if (ssc_sr & params->mask->ssc_endbuf) { - pr_warning("atmel-pcm: buffer %s on %s" - " (SSC_SR=%#x, count=%d)\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK - ? "underrun" : "overrun", - params->name, ssc_sr, count); - - /* re-start the PDC */ - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - } - - if (ssc_sr & params->mask->ssc_endx) { - /* Load the PDC next pointer and counter registers */ - prtd->period_ptr += prtd->period_size; - if (prtd->period_ptr >= prtd->dma_buffer_end) - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - } - - snd_pcm_period_elapsed(substream); -} - - -/*--------------------------------------------------------------------------*\ - * PCM operations -\*--------------------------------------------------------------------------*/ -static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd = runtime->private_data; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - - /* this may get called several times by oss emulation - * with different params */ - - snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); - runtime->dma_bytes = params_buffer_bytes(params); - - prtd->params = rtd->dai->cpu_dai->dma_data; - prtd->params->dma_intr_handler = atmel_pcm_dma_irq; - - prtd->dma_buffer = runtime->dma_addr; - prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; - prtd->period_size = params_period_bytes(params); - - pr_debug("atmel-pcm: " - "hw_params: DMA for %s initialized " - "(dma_bytes=%u, period_size=%u)\n", - prtd->params->name, - runtime->dma_bytes, - prtd->period_size); - return 0; -} - -static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - - if (params != NULL) { - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_disable); - prtd->params->dma_intr_handler = NULL; - } - - return 0; -} - -static int atmel_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - - ssc_writex(params->ssc->regs, SSC_IDR, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - return 0; -} - -static int atmel_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct snd_pcm_runtime *rtd = substream->runtime; - struct atmel_runtime_data *prtd = rtd->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - int ret = 0; - - pr_debug("atmel-pcm:buffer_size = %ld," - "dma_area = %p, dma_bytes = %u\n", - rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->period_ptr = prtd->dma_buffer; - - ssc_writex(params->ssc->regs, params->pdc->xpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - prtd->period_ptr += prtd->period_size; - ssc_writex(params->ssc->regs, params->pdc->xnpr, - prtd->period_ptr); - ssc_writex(params->ssc->regs, params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - - pr_debug("atmel-pcm: trigger: " - "period_ptr=%lx, xpr=%u, " - "xcr=%u, xnpr=%u, xncr=%u\n", - (unsigned long)prtd->period_ptr, - ssc_readx(params->ssc->regs, params->pdc->xpr), - ssc_readx(params->ssc->regs, params->pdc->xcr), - ssc_readx(params->ssc->regs, params->pdc->xnpr), - ssc_readx(params->ssc->regs, params->pdc->xncr)); - - ssc_writex(params->ssc->regs, SSC_IER, - params->mask->ssc_endx | params->mask->ssc_endbuf); - ssc_writex(params->ssc->regs, SSC_PDC_PTCR, - params->mask->pdc_enable); - - pr_debug("sr=%u imr=%u\n", - ssc_readx(params->ssc->regs, SSC_SR), - ssc_readx(params->ssc->regs, SSC_IER)); - break; /* SNDRV_PCM_TRIGGER_START */ - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); - break; - - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_enable); - break; - - default: - ret = -EINVAL; - } - - return ret; -} - -static snd_pcm_uframes_t atmel_pcm_pointer( - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd = runtime->private_data; - struct atmel_pcm_dma_params *params = prtd->params; - dma_addr_t ptr; - snd_pcm_uframes_t x; - - ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); - x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); - - if (x == runtime->buffer_size) - x = 0; - - return x; -} - -static int atmel_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct atmel_runtime_data *prtd; - int ret = 0; - - snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); - - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - goto out; - - prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; - goto out; - } - runtime->private_data = prtd; - - out: - return ret; -} - -static int atmel_pcm_close(struct snd_pcm_substream *substream) -{ - struct atmel_runtime_data *prtd = substream->runtime->private_data; - - kfree(prtd); - return 0; -} - -static int atmel_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - return remap_pfn_range(vma, vma->vm_start, - substream->dma_buffer.addr >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot); -} - -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, - .hw_free = atmel_pcm_hw_free, - .prepare = atmel_pcm_prepare, - .trigger = atmel_pcm_trigger, - .pointer = atmel_pcm_pointer, - .mmap = atmel_pcm_mmap, -}; - - -/*--------------------------------------------------------------------------*\ - * ASoC platform driver -\*--------------------------------------------------------------------------*/ -static u64 atmel_pcm_dmamask = 0xffffffff; - -static int atmel_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) -{ - int ret = 0; - - if (!card->dev->dma_mask) - card->dev->dma_mask = &atmel_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (dai->playback.channels_min) { - ret = atmel_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - goto out; - } - - if (dai->capture.channels_min) { - pr_debug("at32-pcm:" - "Allocating PCM capture DMA buffer\n"); - ret = atmel_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) - goto out; - } - out: - return ret; -} - -static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (!substream) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - dma_free_coherent(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} - -#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 - -struct snd_soc_platform atmel_soc_platform = { - .name = "atmel-audio", - .pcm_ops = &atmel_pcm_ops, - .pcm_new = atmel_pcm_new, - .pcm_free = atmel_pcm_free_dma_buffers, - .suspend = atmel_pcm_suspend, - .resume = atmel_pcm_resume, -}; -EXPORT_SYMBOL_GPL(atmel_soc_platform); - -static int __devinit atmel_pcm_modinit(void) -{ - return snd_soc_register_platform(&atmel_soc_platform); -} -module_init(atmel_pcm_modinit); - -static void __exit atmel_pcm_modexit(void) -{ - snd_soc_unregister_platform(&atmel_soc_platform); -} -module_exit(atmel_pcm_modexit); - -MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); -MODULE_DESCRIPTION("Atmel PCM module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h deleted file mode 100644 index ec9b2824b663..000000000000 --- a/sound/soc/atmel/atmel-pcm.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC. - * - * Copyright (C) 2005 SAN People - * Copyright (C) 2008 Atmel - * - * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> - * - * Based on at91-pcm. by: - * Frank Mandarino <fmandarino@endrelia.com> - * Copyright 2006 Endrelia Technologies Inc. - * - * Based on pxa2xx-pcm.c by: - * - * Author: Nicolas Pitre - * Created: Nov 30, 2004 - * Copyright: (C) 2004 MontaVista Software, Inc. - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ATMEL_PCM_H -#define _ATMEL_PCM_H - -#include <linux/atmel-ssc.h> - -/* - * Registers and status bits that are required by the PCM driver. - */ -struct atmel_pdc_regs { - unsigned int xpr; /* PDC recv/trans pointer */ - unsigned int xcr; /* PDC recv/trans counter */ - unsigned int xnpr; /* PDC next recv/trans pointer */ - unsigned int xncr; /* PDC next recv/trans counter */ - unsigned int ptcr; /* PDC transfer control */ -}; - -struct atmel_ssc_mask { - u32 ssc_enable; /* SSC recv/trans enable */ - u32 ssc_disable; /* SSC recv/trans disable */ - u32 ssc_endx; /* SSC ENDTX or ENDRX */ - u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ - u32 pdc_enable; /* PDC recv/trans enable */ - u32 pdc_disable; /* PDC recv/trans disable */ -}; - -/* - * This structure, shared between the PCM driver and the interface, - * contains all information required by the PCM driver to perform the - * PDC DMA operation. All fields except dma_intr_handler() are initialized - * by the interface. The dms_intr_handler() pointer is set by the PCM - * driver and called by the interface SSC interrupt handler if it is - * non-NULL. - */ -struct atmel_pcm_dma_params { - char *name; /* stream identifier */ - int pdc_xfer_size; /* PDC counter increment in bytes */ - struct ssc_device *ssc; /* SSC device for stream */ - struct atmel_pdc_regs *pdc; /* PDC receive or transmit registers */ - struct atmel_ssc_mask *mask; /* SSC & PDC status bits */ - struct snd_pcm_substream *substream; - void (*dma_intr_handler)(u32, struct snd_pcm_substream *); -}; - -extern struct snd_soc_platform atmel_soc_platform; - - -/* - * SSC register access (since ssc_writel() / ssc_readl() require literal name) - */ -#define ssc_readx(base, reg) (__raw_readl((base) + (reg))) -#define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) - -#endif /* _ATMEL_PCM_H */ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c deleted file mode 100644 index 87904b6ab8c2..000000000000 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ /dev/null @@ -1,790 +0,0 @@ -/* - * atmel_ssc_dai.c -- ALSA SoC ATMEL SSC Audio Layer Platform driver - * - * Copyright (C) 2005 SAN People - * Copyright (C) 2008 Atmel - * - * Author: Sedji Gaouaou <sedji.gaouaou@atmel.com> - * ATMEL CORP. - * - * Based on at91-ssc.c by - * Frank Mandarino <fmandarino@endrelia.com> - * Based on pxa2xx Platform drivers by - * Liam Girdwood <liam.girdwood@wolfsonmicro.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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/device.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/atmel_pdc.h> - -#include <linux/atmel-ssc.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/initval.h> -#include <sound/soc.h> - -#include <mach/hardware.h> - -#include "atmel-pcm.h" -#include "atmel_ssc_dai.h" - - -#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) -#define NUM_SSC_DEVICES 1 -#else -#define NUM_SSC_DEVICES 3 -#endif - -/* - * SSC PDC registers required by the PCM DMA engine. - */ -static struct atmel_pdc_regs pdc_tx_reg = { - .xpr = ATMEL_PDC_TPR, - .xcr = ATMEL_PDC_TCR, - .xnpr = ATMEL_PDC_TNPR, - .xncr = ATMEL_PDC_TNCR, -}; - -static struct atmel_pdc_regs pdc_rx_reg = { - .xpr = ATMEL_PDC_RPR, - .xcr = ATMEL_PDC_RCR, - .xnpr = ATMEL_PDC_RNPR, - .xncr = ATMEL_PDC_RNCR, -}; - -/* - * SSC & PDC status bits for transmit and receive. - */ -static struct atmel_ssc_mask ssc_tx_mask = { - .ssc_enable = SSC_BIT(CR_TXEN), - .ssc_disable = SSC_BIT(CR_TXDIS), - .ssc_endx = SSC_BIT(SR_ENDTX), - .ssc_endbuf = SSC_BIT(SR_TXBUFE), - .pdc_enable = ATMEL_PDC_TXTEN, - .pdc_disable = ATMEL_PDC_TXTDIS, -}; - -static struct atmel_ssc_mask ssc_rx_mask = { - .ssc_enable = SSC_BIT(CR_RXEN), - .ssc_disable = SSC_BIT(CR_RXDIS), - .ssc_endx = SSC_BIT(SR_ENDRX), - .ssc_endbuf = SSC_BIT(SR_RXBUFF), - .pdc_enable = ATMEL_PDC_RXTEN, - .pdc_disable = ATMEL_PDC_RXTDIS, -}; - - -/* - * DMA parameters. - */ -static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { - {{ - .name = "SSC0 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC0 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - } }, -#if NUM_SSC_DEVICES == 3 - {{ - .name = "SSC1 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC1 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - } }, - {{ - .name = "SSC2 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC2 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - } }, -#endif -}; - - -static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = { - { - .name = "ssc0", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, -#if NUM_SSC_DEVICES == 3 - { - .name = "ssc1", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, - { - .name = "ssc2", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, -#endif -}; - - -/* - * SSC interrupt handler. Passes PDC interrupts to the DMA - * interrupt handler in the PCM driver. - */ -static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) -{ - struct atmel_ssc_info *ssc_p = dev_id; - struct atmel_pcm_dma_params *dma_params; - u32 ssc_sr; - u32 ssc_substream_mask; - int i; - - ssc_sr = (unsigned long)ssc_readl(ssc_p->ssc->regs, SR) - & (unsigned long)ssc_readl(ssc_p->ssc->regs, IMR); - - /* - * Loop through the substreams attached to this SSC. If - * a DMA-related interrupt occurred on that substream, call - * the DMA interrupt handler function, if one has been - * registered in the dma_params structure by the PCM driver. - */ - for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { - dma_params = ssc_p->dma_params[i]; - - if ((dma_params != NULL) && - (dma_params->dma_intr_handler != NULL)) { - ssc_substream_mask = (dma_params->mask->ssc_endx | - dma_params->mask->ssc_endbuf); - if (ssc_sr & ssc_substream_mask) { - dma_params->dma_intr_handler(ssc_sr, - dma_params-> - substream); - } - } - } - - return IRQ_HANDLED; -} - - -/*-------------------------------------------------------------------------*\ - * DAI functions -\*-------------------------------------------------------------------------*/ -/* - * Startup. Only that one substream allowed in each direction. - */ -static int atmel_ssc_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - int 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) - dir_mask = SSC_DIR_MASK_PLAYBACK; - else - dir_mask = SSC_DIR_MASK_CAPTURE; - - spin_lock_irq(&ssc_p->lock); - if (ssc_p->dir_mask & dir_mask) { - spin_unlock_irq(&ssc_p->lock); - return -EBUSY; - } - ssc_p->dir_mask |= dir_mask; - spin_unlock_irq(&ssc_p->lock); - - return 0; -} - -/* - * Shutdown. Clear DMA parameters and shutdown the SSC if there - * are no other substreams open. - */ -static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct atmel_pcm_dma_params *dma_params; - int dir, dir_mask; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dir = 0; - else - dir = 1; - - dma_params = ssc_p->dma_params[dir]; - - if (dma_params != NULL) { - ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable); - pr_debug("atmel_ssc_shutdown: %s disabled SSC_SR=0x%08x\n", - (dir ? "receive" : "transmit"), - ssc_readl(ssc_p->ssc->regs, SR)); - - dma_params->ssc = NULL; - dma_params->substream = NULL; - ssc_p->dma_params[dir] = NULL; - } - - dir_mask = 1 << dir; - - spin_lock_irq(&ssc_p->lock); - ssc_p->dir_mask &= ~dir_mask; - if (!ssc_p->dir_mask) { - if (ssc_p->initialized) { - /* Shutdown the SSC clock. */ - pr_debug("atmel_ssc_dau: Stopping clock\n"); - clk_disable(ssc_p->ssc->clk); - - free_irq(ssc_p->ssc->irq, ssc_p); - ssc_p->initialized = 0; - } - - /* Reset the SSC */ - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); - /* Clear the SSC dividers */ - ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; - } - spin_unlock_irq(&ssc_p->lock); -} - - -/* - * Record the DAI format for use in hw_params(). - */ -static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - ssc_p->daifmt = fmt; - return 0; -} - -/* - * Record SSC clock dividers for use in hw_params(). - */ -static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - switch (div_id) { - case ATMEL_SSC_CMR_DIV: - /* - * The same master clock divider is used for both - * transmit and receive, so if a value has already - * been set, it must match this value. - */ - if (ssc_p->cmr_div == 0) - ssc_p->cmr_div = div; - else - if (div != ssc_p->cmr_div) - return -EBUSY; - break; - - case ATMEL_SSC_TCMR_PERIOD: - ssc_p->tcmr_period = div; - break; - - case ATMEL_SSC_RCMR_PERIOD: - ssc_p->rcmr_period = div; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * Configure the SSC. - */ -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 = rtd->dai->cpu_dai->id; - struct atmel_ssc_info *ssc_p = &ssc_info[id]; - struct atmel_pcm_dma_params *dma_params; - int dir, channels, bits; - u32 tfmr, rfmr, tcmr, rcmr; - int start_event; - int ret; - - /* - * Currently, there is only one set of dma params for - * each direction. If more are added, this code will - * have to be changed to select the proper set. - */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dir = 0; - 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 cpu_dai->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. - */ - rtd->dai->cpu_dai->dma_data = dma_params; - - channels = params_channels(params); - - /* - * Determine sample size in bits and the PDC increment. - */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - bits = 8; - dma_params->pdc_xfer_size = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - bits = 16; - dma_params->pdc_xfer_size = 2; - break; - case SNDRV_PCM_FORMAT_S24_LE: - bits = 24; - dma_params->pdc_xfer_size = 4; - break; - case SNDRV_PCM_FORMAT_S32_LE: - bits = 32; - dma_params->pdc_xfer_size = 4; - break; - default: - printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format"); - return -EINVAL; - } - - /* - * The SSC only supports up to 16-bit samples in I2S format, due - * to the size of the Frame Mode Register FSLEN field. - */ - if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S - && bits > 16) { - printk(KERN_WARNING - "atmel_ssc_dai: sample size %d" - "is too large for I2S\n", bits); - return -EINVAL; - } - - /* - * Compute SSC register settings. - */ - switch (ssc_p->daifmt - & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { - - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: - /* - * I2S format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated - * from the MCK divider, and the BCLK signal - * is output on the SSC TK line. - */ - rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | SSC_BF(RCMR_START, SSC_START_FALLING_RF) - | SSC_BF(RCMR_CKI, SSC_CKI_RISING) - | SSC_BF(RCMR_CKO, SSC_CKO_NONE) - | SSC_BF(RCMR_CKS, SSC_CKS_DIV); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(RFMR_FSLEN, (bits - 1)) - | 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, ssc_p->tcmr_period) - | SSC_BF(TCMR_STTDLY, START_DELAY) - | SSC_BF(TCMR_START, SSC_START_FALLING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) - | SSC_BF(TCMR_CKS, SSC_CKS_DIV); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) - | SSC_BF(TFMR_FSLEN, (bits - 1)) - | SSC_BF(TFMR_DATNB, (channels - 1)) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; - - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - /* - * I2S 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. - * - * For single channel data, one sample is transferred - * on the falling edge of the LRC clock. - * For two channel data, one sample is - * transferred on both edges of the LRC clock. - */ - start_event = ((channels == 1) - ? SSC_START_FALLING_RF - : SSC_START_EDGE_RF); - - rcmr = SSC_BF(RCMR_PERIOD, 0) - | SSC_BF(RCMR_STTDLY, START_DELAY) - | 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); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) - | SSC_BF(RFMR_FSLEN, 0) - | SSC_BF(RFMR_DATNB, 0) - | 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, start_event) - | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) - | SSC_BF(TCMR_CKO, SSC_CKO_NONE) - | SSC_BF(TCMR_CKS, 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, 0) - | SSC_BIT(TFMR_MSBF) - | SSC_BF(TFMR_DATDEF, 0) - | SSC_BF(TFMR_DATLEN, (bits - 1)); - break; - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - /* - * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output - * on the SSC TK line. - */ - rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) - | SSC_BF(RCMR_STTDLY, 1) - | 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_CKS_DIV); - - rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) - | 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, ssc_p->tcmr_period) - | SSC_BF(TCMR_STTDLY, 1) - | SSC_BF(TCMR_START, SSC_START_RISING_RF) - | SSC_BF(TCMR_CKI, SSC_CKI_RISING) - | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) - | SSC_BF(TCMR_CKS, SSC_CKS_DIV); - - tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) - | SSC_BF(TFMR_FSDEN, 0) - | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) - | 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; - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: - default: - printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", - ssc_p->daifmt); - return -EINVAL; - break; - } - pr_debug("atmel_ssc_hw_params: " - "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", - rcmr, rfmr, tcmr, tfmr); - - if (!ssc_p->initialized) { - - /* Enable PMC peripheral clock for this SSC */ - pr_debug("atmel_ssc_dai: Starting clock\n"); - clk_enable(ssc_p->ssc->clk); - - /* Reset the SSC and its PDC registers */ - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); - - ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); - - ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); - - ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0, - ssc_p->name, ssc_p); - if (ret < 0) { - printk(KERN_WARNING - "atmel_ssc_dai: request_irq failure\n"); - pr_debug("Atmel_ssc_dai: Stoping clock\n"); - clk_disable(ssc_p->ssc->clk); - return ret; - } - - ssc_p->initialized = 1; - } - - /* set SSC clock mode register */ - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); - - /* set receive clock mode and format */ - ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); - ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); - - /* set transmit clock mode and format */ - ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); - ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); - - pr_debug("atmel_ssc_dai,hw_params: SSC initialized\n"); - return 0; -} - - -static int atmel_ssc_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_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]; - - ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable); - - pr_debug("%s enabled SSC_SR=0x%08x\n", - dir ? "receive" : "transmit", - ssc_readl(ssc_p->ssc->regs, SR)); - return 0; -} - - -#ifdef CONFIG_PM -static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) -{ - struct atmel_ssc_info *ssc_p; - - if (!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* Save the status register before disabling transmit and receive */ - ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS)); - - /* Save the current interrupt mask, then disable unmasked interrupts */ - ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR); - ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr); - - ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR); - ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR); - ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR); - ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); - ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); - - return 0; -} - - - -static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) -{ - struct atmel_ssc_info *ssc_p; - u32 cr; - - if (!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* restore SSC register settings */ - ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); - ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); - ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr); - ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr); - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr); - - /* re-enable interrupts */ - ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); - - /* Re-enable recieve and transmit as appropriate */ - cr = 0; - cr |= - (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; - cr |= - (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0; - ssc_writel(ssc_p->ssc->regs, CR, cr); - - return 0; -} -#else /* CONFIG_PM */ -# define atmel_ssc_suspend NULL -# define atmel_ssc_resume NULL -#endif /* CONFIG_PM */ - - -#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) - -#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { - { .name = "atmel-ssc0", - .id = 0, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = { - .startup = atmel_ssc_startup, - .shutdown = atmel_ssc_shutdown, - .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params, - .set_fmt = atmel_ssc_set_dai_fmt, - .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[0], - }, -#if NUM_SSC_DEVICES == 3 - { .name = "atmel-ssc1", - .id = 1, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = { - .startup = atmel_ssc_startup, - .shutdown = atmel_ssc_shutdown, - .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params, - .set_fmt = atmel_ssc_set_dai_fmt, - .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[1], - }, - { .name = "atmel-ssc2", - .id = 2, - .suspend = atmel_ssc_suspend, - .resume = atmel_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ATMEL_SSC_RATES, - .formats = ATMEL_SSC_FORMATS,}, - .ops = { - .startup = atmel_ssc_startup, - .shutdown = atmel_ssc_shutdown, - .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params, - .set_fmt = atmel_ssc_set_dai_fmt, - .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[2], - }, -#endif -}; -EXPORT_SYMBOL_GPL(atmel_ssc_dai); - -static int __devinit atmel_ssc_modinit(void) -{ - return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); -} -module_init(atmel_ssc_modinit); - -static void __exit atmel_ssc_modexit(void) -{ - snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); -} -module_exit(atmel_ssc_modexit); - -/* Module information */ -MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"); -MODULE_DESCRIPTION("ATMEL SSC ASoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h deleted file mode 100644 index a828746e8a2f..000000000000 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * atmel_ssc_dai.h - ALSA SSC interface for the Atmel SoC - * - * Copyright (C) 2005 SAN People - * Copyright (C) 2008 Atmel - * - * Author: Sedji Gaouaou <sedji.gaouaou@atmel.com> - * ATMEL CORP. - * - * Based on at91-ssc.c by - * Frank Mandarino <fmandarino@endrelia.com> - * Based on pxa2xx Platform drivers by - * Liam Girdwood <liam.girdwood@wolfsonmicro.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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ATMEL_SSC_DAI_H -#define _ATMEL_SSC_DAI_H - -#include <linux/types.h> -#include <linux/atmel-ssc.h> - -#include "atmel-pcm.h" - -/* SSC system clock ids */ -#define ATMEL_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */ - -/* SSC divider ids */ -#define ATMEL_SSC_CMR_DIV 0 /* MCK divider for BCLK */ -#define ATMEL_SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ -#define ATMEL_SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ -/* - * SSC direction masks - */ -#define SSC_DIR_MASK_UNUSED 0 -#define SSC_DIR_MASK_PLAYBACK 1 -#define SSC_DIR_MASK_CAPTURE 2 - -/* - * SSC register values that Atmel left out of <linux/atmel-ssc.h>. These - * are expected to be used with SSC_BF - */ -/* START bit field values */ -#define SSC_START_CONTINUOUS 0 -#define SSC_START_TX_RX 1 -#define SSC_START_LOW_RF 2 -#define SSC_START_HIGH_RF 3 -#define SSC_START_FALLING_RF 4 -#define SSC_START_RISING_RF 5 -#define SSC_START_LEVEL_RF 6 -#define SSC_START_EDGE_RF 7 -#define SSS_START_COMPARE_0 8 - -/* CKI bit field values */ -#define SSC_CKI_FALLING 0 -#define SSC_CKI_RISING 1 - -/* CKO bit field values */ -#define SSC_CKO_NONE 0 -#define SSC_CKO_CONTINUOUS 1 -#define SSC_CKO_TRANSFER 2 - -/* CKS bit field values */ -#define SSC_CKS_DIV 0 -#define SSC_CKS_CLOCK 1 -#define SSC_CKS_PIN 2 - -/* FSEDGE bit field values */ -#define SSC_FSEDGE_POSITIVE 0 -#define SSC_FSEDGE_NEGATIVE 1 - -/* FSOS bit field values */ -#define SSC_FSOS_NONE 0 -#define SSC_FSOS_NEGATIVE 1 -#define SSC_FSOS_POSITIVE 2 -#define SSC_FSOS_LOW 3 -#define SSC_FSOS_HIGH 4 -#define SSC_FSOS_TOGGLE 5 - -#define START_DELAY 1 - -struct atmel_ssc_state { - u32 ssc_cmr; - u32 ssc_rcmr; - u32 ssc_rfmr; - u32 ssc_tcmr; - u32 ssc_tfmr; - u32 ssc_sr; - u32 ssc_imr; -}; - - -struct atmel_ssc_info { - char *name; - struct ssc_device *ssc; - spinlock_t lock; /* lock for dir_mask */ - unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ - unsigned short initialized; /* true if SSC has been initialized */ - unsigned short daifmt; - unsigned short cmr_div; - unsigned short tcmr_period; - unsigned short rcmr_period; - struct atmel_pcm_dma_params *dma_params[2]; - struct atmel_ssc_state ssc_state; -}; -extern struct snd_soc_dai atmel_ssc_dai[]; - -#endif /* _AT91_SSC_DAI_H */ diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c deleted file mode 100644 index 1fb59a9d3719..000000000000 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * sam9g20_wm8731 -- SoC audio for AT91SAM9G20-based - * ATMEL AT91SAM9G20ek board. - * - * Copyright (C) 2005 SAN People - * Copyright (C) 2008 Atmel - * - * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> - * - * Based on ati_b1_wm8731.c by: - * Frank Mandarino <fmandarino@endrelia.com> - * Copyright 2006 Endrelia Technologies Inc. - * Based on corgi.c by: - * Copyright 2005 Wolfson Microelectronics PLC. - * Copyright 2005 Openedhand Ltd. - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/clk.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> - -#include <linux/atmel-ssc.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <mach/hardware.h> -#include <mach/gpio.h> - -#include "../codecs/wm8731.h" -#include "atmel-pcm.h" -#include "atmel_ssc_dai.h" - - -static int at91sam9g20ek_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - int ret; - - /* codec system clock is supplied by PCK0, set to 12MHz */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, - 12000000, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - return 0; -} - -static void at91sam9g20ek_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - - dev_dbg(rtd->socdev->dev, "shutdown"); -} - -static int at91sam9g20ek_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->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct atmel_ssc_info *ssc_p = cpu_dai->private_data; - struct ssc_device *ssc = ssc_p->ssc; - int ret; - - unsigned int rate; - int cmr_div, period; - - if (ssc == NULL) { - printk(KERN_INFO "at91sam9g20ek_hw_params: ssc is NULL!\n"); - return -EINVAL; - } - - /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - /* - * The SSC clock dividers depend on the sample rate. The CMR.DIV - * field divides the system master clock MCK to drive the SSC TK - * signal which provides the codec BCLK. The TCMR.PERIOD and - * RCMR.PERIOD fields further divide the BCLK signal to drive - * the SSC TF and RF signals which provide the codec DACLRC and - * ADCLRC clocks. - * - * The dividers were determined through trial and error, where a - * CMR.DIV value is chosen such that the resulting BCLK value is - * divisible, or almost divisible, by (2 * sample rate), and then - * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1. - */ - rate = params_rate(params); - - switch (rate) { - case 8000: - cmr_div = 55; /* BCLK = 133MHz/(2*55) = 1.209MHz */ - period = 74; /* LRC = BCLK/(2*(74+1)) ~= 8060,6Hz */ - break; - case 11025: - cmr_div = 67; /* BCLK = 133MHz/(2*60) = 1.108MHz */ - period = 45; /* LRC = BCLK/(2*(49+1)) = 11083,3Hz */ - break; - case 16000: - cmr_div = 63; /* BCLK = 133MHz/(2*63) = 1.055MHz */ - period = 32; /* LRC = BCLK/(2*(32+1)) = 15993,2Hz */ - break; - case 22050: - cmr_div = 52; /* BCLK = 133MHz/(2*52) = 1.278MHz */ - period = 28; /* LRC = BCLK/(2*(28+1)) = 22049Hz */ - break; - case 32000: - cmr_div = 66; /* BCLK = 133MHz/(2*66) = 1.007MHz */ - period = 15; /* LRC = BCLK/(2*(15+1)) = 31486,742Hz */ - break; - case 44100: - cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */ - period = 25; /* LRC = BCLK/(2*(25+1)) = 44098Hz */ - break; - case 48000: - cmr_div = 33; /* BCLK = 133MHz/(2*33) = 2.015MHz */ - period = 20; /* LRC = BCLK/(2*(20+1)) = 47979,79Hz */ - break; - case 88200: - cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */ - period = 12; /* LRC = BCLK/(2*(12+1)) = 88196Hz */ - break; - case 96000: - cmr_div = 23; /* BCLK = 133MHz/(2*23) = 2.891MHz */ - period = 14; /* LRC = BCLK/(2*(14+1)) = 96376Hz */ - break; - default: - printk(KERN_WARNING "unsupported rate %d" - " on at91sam9g20ek board\n", rate); - return -EINVAL; - } - - /* set the MCK divider for BCLK */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cmr_div); - if (ret < 0) - return ret; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* set the BCLK divider for DACLRC */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, - ATMEL_SSC_TCMR_PERIOD, period); - } else { - /* set the BCLK divider for ADCLRC */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, - ATMEL_SSC_RCMR_PERIOD, period); - } - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops at91sam9g20ek_ops = { - .startup = at91sam9g20ek_startup, - .hw_params = at91sam9g20ek_hw_params, - .shutdown = at91sam9g20ek_shutdown, -}; - - -static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = { - SND_SOC_DAPM_MIC("Int Mic", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), -}; - -static const struct snd_soc_dapm_route intercon[] = { - - /* speaker connected to LHPOUT */ - {"Ext Spk", NULL, "LHPOUT"}, - - /* mic is connected to Mic Jack, with WM8731 Mic Bias */ - {"MICIN", NULL, "Mic Bias"}, - {"Mic Bias", NULL, "Int Mic"}, -}; - -/* - * Logic for a wm8731 as connected on a at91sam9g20ek board. - */ -static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec) -{ - printk(KERN_DEBUG - "at91sam9g20ek_wm8731 " - ": at91sam9g20ek_wm8731_init() called\n"); - - /* Add specific widgets */ - snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets, - ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); - /* Set up specific audio path interconnects */ - snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - - /* not connected */ - snd_soc_dapm_disable_pin(codec, "RLINEIN"); - snd_soc_dapm_disable_pin(codec, "LLINEIN"); - - /* always connected */ - snd_soc_dapm_enable_pin(codec, "Int Mic"); - snd_soc_dapm_enable_pin(codec, "Ext Spk"); - - snd_soc_dapm_sync(codec); - - return 0; -} - -static struct snd_soc_dai_link at91sam9g20ek_dai = { - .name = "WM8731", - .stream_name = "WM8731 PCM", - .cpu_dai = &atmel_ssc_dai[0], - .codec_dai = &wm8731_dai, - .init = at91sam9g20ek_wm8731_init, - .ops = &at91sam9g20ek_ops, -}; - -static struct snd_soc_card snd_soc_at91sam9g20ek = { - .name = "WM8731", - .platform = &atmel_soc_platform, - .dai_link = &at91sam9g20ek_dai, - .num_links = 1, -}; - -static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = { - .i2c_bus = 0, - .i2c_address = 0x1b, -}; - -static struct snd_soc_device at91sam9g20ek_snd_devdata = { - .card = &snd_soc_at91sam9g20ek, - .codec_dev = &soc_codec_dev_wm8731, - .codec_data = &at91sam9g20ek_wm8731_setup, -}; - -static struct platform_device *at91sam9g20ek_snd_device; - -static int __init at91sam9g20ek_init(void) -{ - struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data; - struct ssc_device *ssc = NULL; - int ret; - - /* - * Request SSC device - */ - ssc = ssc_request(0); - if (IS_ERR(ssc)) { - ret = PTR_ERR(ssc); - ssc = NULL; - goto err_ssc; - } - ssc_p->ssc = ssc; - - at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1); - if (!at91sam9g20ek_snd_device) { - printk(KERN_DEBUG - "platform device allocation failed\n"); - ret = -ENOMEM; - } - - platform_set_drvdata(at91sam9g20ek_snd_device, - &at91sam9g20ek_snd_devdata); - at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev; - - ret = platform_device_add(at91sam9g20ek_snd_device); - if (ret) { - printk(KERN_DEBUG - "platform device allocation failed\n"); - platform_device_put(at91sam9g20ek_snd_device); - } - - return ret; - -err_ssc: - return ret; -} - -static void __exit at91sam9g20ek_exit(void) -{ - struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data; - struct ssc_device *ssc; - - if (ssc_p != NULL) { - ssc = ssc_p->ssc; - if (ssc != NULL) - ssc_free(ssc); - ssc_p->ssc = NULL; - } - - platform_device_unregister(at91sam9g20ek_snd_device); - at91sam9g20ek_snd_device = NULL; -} - -module_init(at91sam9g20ek_init); -module_exit(at91sam9g20ek_exit); - -/* Module information */ -MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); -MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 74c823d60f91..1466d9328800 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -406,12 +406,11 @@ static int __init au1xpsc_audio_dbdma_init(void) { au1xpsc_audio_pcmdma[PCM_TX] = NULL; au1xpsc_audio_pcmdma[PCM_RX] = NULL; - return snd_soc_register_platform(&au1xpsc_soc_platform); + return 0; } static void __exit au1xpsc_audio_dbdma_exit(void) { - snd_soc_unregister_platform(&au1xpsc_soc_platform); } module_init(au1xpsc_audio_dbdma_init); diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index f0e30aec7f23..57facbad6825 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -160,8 +160,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; @@ -211,7 +210,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, } static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) + int cmd) { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; @@ -314,7 +313,8 @@ static void au1xpsc_ac97_remove(struct platform_device *pdev, au1xpsc_ac97_workdata = NULL; } -static int au1xpsc_ac97_suspend(struct snd_soc_dai *dai) +static int au1xpsc_ac97_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) { /* save interesting registers and disable PSC */ au1xpsc_ac97_workdata->pm[0] = @@ -328,7 +328,8 @@ static int au1xpsc_ac97_suspend(struct snd_soc_dai *dai) return 0; } -static int au1xpsc_ac97_resume(struct snd_soc_dai *dai) +static int au1xpsc_ac97_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { /* restore PSC clock config */ au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE, @@ -344,7 +345,7 @@ static int au1xpsc_ac97_resume(struct snd_soc_dai *dai) struct snd_soc_dai au1xpsc_ac97_dai = { .name = "au1xpsc_ac97", - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .probe = au1xpsc_ac97_probe, .remove = au1xpsc_ac97_remove, .suspend = au1xpsc_ac97_suspend, @@ -371,12 +372,11 @@ EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai); static int __init au1xpsc_ac97_init(void) { au1xpsc_ac97_workdata = NULL; - return snd_soc_register_dai(&au1xpsc_ac97_dai); + return 0; } static void __exit au1xpsc_ac97_exit(void) { - snd_soc_unregister_dai(&au1xpsc_ac97_dai); } module_init(au1xpsc_ac97_init); diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index f916de4400ed..9384702c7ebd 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -116,8 +116,7 @@ out: } static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; @@ -241,8 +240,7 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype) return 0; } -static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; int ret, stype = SUBSTREAM_TYPE(substream); @@ -339,7 +337,8 @@ static void au1xpsc_i2s_remove(struct platform_device *pdev, au1xpsc_i2s_workdata = NULL; } -static int au1xpsc_i2s_suspend(struct snd_soc_dai *cpu_dai) +static int au1xpsc_i2s_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) { /* save interesting register and disable PSC */ au1xpsc_i2s_workdata->pm[0] = @@ -353,7 +352,8 @@ static int au1xpsc_i2s_suspend(struct snd_soc_dai *cpu_dai) return 0; } -static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai) +static int au1xpsc_i2s_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) { /* select I2S mode and PSC clock */ au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); @@ -369,6 +369,7 @@ static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai) struct snd_soc_dai au1xpsc_i2s_dai = { .name = "au1xpsc_i2s", + .type = SND_SOC_DAI_I2S, .probe = au1xpsc_i2s_probe, .remove = au1xpsc_i2s_remove, .suspend = au1xpsc_i2s_suspend, @@ -388,6 +389,8 @@ struct snd_soc_dai au1xpsc_i2s_dai = { .ops = { .trigger = au1xpsc_i2s_trigger, .hw_params = au1xpsc_i2s_hw_params, + }, + .dai_ops = { .set_fmt = au1xpsc_i2s_set_fmt, }, }; @@ -396,12 +399,11 @@ EXPORT_SYMBOL(au1xpsc_i2s_dai); static int __init au1xpsc_i2s_init(void) { au1xpsc_i2s_workdata = NULL; - return snd_soc_register_dai(&au1xpsc_i2s_dai); + return 0; } static void __exit au1xpsc_i2s_exit(void) { - snd_soc_unregister_dai(&au1xpsc_i2s_dai); } module_init(au1xpsc_i2s_init); diff --git a/sound/soc/au1x/sample-ac97.c b/sound/soc/au1x/sample-ac97.c index 27683eb7905e..f75ae7f62c3d 100644 --- a/sound/soc/au1x/sample-ac97.c +++ b/sound/soc/au1x/sample-ac97.c @@ -42,14 +42,14 @@ static struct snd_soc_dai_link au1xpsc_sample_ac97_dai = { .ops = NULL, }; -static struct snd_soc_card au1xpsc_sample_ac97_machine = { +static struct snd_soc_machine au1xpsc_sample_ac97_machine = { .name = "Au1xxx PSC AC97 Audio", .dai_link = &au1xpsc_sample_ac97_dai, .num_links = 1, }; static struct snd_soc_device au1xpsc_sample_ac97_devdata = { - .card = &au1xpsc_sample_ac97_machine, + .machine = &au1xpsc_sample_ac97_machine, .platform = &au1xpsc_soc_platform, /* see dbdma2.c */ .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 0a2f8f9eff53..dc006206f622 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -1,6 +1,6 @@ config SND_BF5XX_I2S tristate "SoC I2S Audio for the ADI BF5xx chip" - depends on BLACKFIN + depends on BLACKFIN && SND_SOC help Say Y or M if you want to add support for codecs attached to the Blackfin SPORT (synchronous serial ports) interface in I2S @@ -13,6 +13,7 @@ config SND_BF5XX_SOC_SSM2602 select SND_BF5XX_SOC_I2S select SND_SOC_SSM2602 select I2C + select I2C_BLACKFIN_TWI help Say Y if you want to add support for SoC audio on BF527-EZKIT. @@ -34,7 +35,7 @@ config SND_BFIN_AD73311_SE config SND_BF5XX_AC97 tristate "SoC AC97 Audio for the ADI BF5xx chip" - depends on BLACKFIN + depends on BLACKFIN && SND_SOC help Say Y or M if you want to add support for codecs attached to the Blackfin SPORT (synchronous serial ports) interface in slot 16 @@ -46,7 +47,7 @@ config SND_BF5XX_AC97 properly with this driver. This driver is known to work with the Analog Devices line of AC97 codecs. -config SND_BF5XX_MMAP_SUPPORT +config SND_MMAP_SUPPORT bool "Enable MMAP Support" depends on SND_BF5XX_AC97 default y @@ -54,17 +55,9 @@ config SND_BF5XX_MMAP_SUPPORT Say y if you want AC97 driver to support mmap mode. We introduce an intermediate buffer to simulate mmap. -config SND_BF5XX_MULTICHAN_SUPPORT - bool "Enable Multichannel Support" - depends on SND_BF5XX_AC97 - default n - help - Say y if you want AC97 driver to support up to 5.1 channel audio. - this mode will consume much more memory for DMA. - config SND_BF5XX_SOC_SPORT tristate - + config SND_BF5XX_SOC_I2S tristate select SND_BF5XX_SOC_SPORT @@ -87,7 +80,7 @@ config SND_BF5XX_SPORT_NUM int "Set a SPORT for Sound chip" depends on (SND_BF5XX_I2S || SND_BF5XX_AC97) range 0 3 if BF54x - range 0 1 if !BF54x + range 0 1 if (BF53x || BF561) default 0 help Set the correct SPORT for sound chip. @@ -97,13 +90,12 @@ config SND_BF5XX_HAVE_COLD_RESET depends on SND_BF5XX_AC97 default y if BFIN548_EZKIT default n if !BFIN548_EZKIT - + config SND_BF5XX_RESET_GPIO_NUM int "Set a GPIO for cold reset" depends on SND_BF5XX_HAVE_COLD_RESET range 0 159 default 19 if BFIN548_EZKIT default 5 if BFIN537_STAMP - default 0 help Set the correct GPIO for RESET the sound chip. diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 5b27e0d9d0ec..25e50d2ea1ec 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -43,34 +43,24 @@ #include "bf5xx-ac97.h" #include "bf5xx-sport.h" -static unsigned int ac97_chan_mask[] = { - SP_FL, /* Mono */ - SP_STEREO, /* Stereo */ - SP_2DOT1, /* 2.1*/ - SP_QUAD,/*Quadraquic*/ - SP_FL | SP_FR | SP_FC | SP_SL | SP_SR,/*5 channels */ - SP_5DOT1, /* 5.1 */ -}; - -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, snd_pcm_uframes_t count) { struct snd_pcm_runtime *runtime = substream->runtime; struct sport_device *sport = runtime->private_data; - unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1]; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - bf5xx_pcm_to_ac97((struct ac97_frame *)sport->tx_dma_buf + - sport->tx_pos, (__u16 *)runtime->dma_area + sport->tx_pos * - runtime->channels, count, chan_mask); + bf5xx_pcm_to_ac97( + (struct ac97_frame *)sport->tx_dma_buf + sport->tx_pos, + (__u32 *)runtime->dma_area + sport->tx_pos, count); sport->tx_pos += runtime->period_size; if (sport->tx_pos >= runtime->buffer_size) sport->tx_pos %= runtime->buffer_size; sport->tx_delay_pos = sport->tx_pos; } else { - bf5xx_ac97_to_pcm((struct ac97_frame *)sport->rx_dma_buf + - sport->rx_pos, (__u16 *)runtime->dma_area + sport->rx_pos * - runtime->channels, count); + bf5xx_ac97_to_pcm( + (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, + (__u32 *)runtime->dma_area + sport->rx_pos, count); sport->rx_pos += runtime->period_size; if (sport->rx_pos >= runtime->buffer_size) sport->rx_pos %= runtime->buffer_size; @@ -81,7 +71,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, static void bf5xx_dma_irq(void *data) { struct snd_pcm_substream *pcm = data; -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) struct snd_pcm_runtime *runtime = pcm->runtime; struct sport_device *sport = runtime->private_data; bf5xx_mmap_copy(pcm, runtime->period_size); @@ -100,14 +90,17 @@ static void bf5xx_dma_irq(void *data) * The total rx/tx buffer is for ac97 frame to hold all pcm data * is 0x20000 * sizeof(struct ac97_frame) / 4. */ +#ifdef CONFIG_SND_MMAP_SUPPORT static const struct snd_pcm_hardware bf5xx_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | -#endif SNDRV_PCM_INFO_BLOCK_TRANSFER, - +#else +static const struct snd_pcm_hardware bf5xx_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, +#endif .formats = SNDRV_PCM_FMTBIT_S16_LE, .period_bytes_min = 32, .period_bytes_max = 0x10000, @@ -130,20 +123,10 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) { -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) struct snd_pcm_runtime *runtime = substream->runtime; - struct sport_device *sport = runtime->private_data; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - sport->once = 0; - if (runtime->dma_area) - memset(runtime->dma_area, 0, runtime->buffer_size); - memset(sport->tx_dma_buf, 0, runtime->buffer_size * - sizeof(struct ac97_frame)); - } else - memset(sport->rx_dma_buf, 0, runtime->buffer_size * - sizeof(struct ac97_frame)); -#endif + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + memset(runtime->dma_area, 0, runtime->buffer_size); snd_pcm_lib_free_pages(substream); return 0; } @@ -156,7 +139,7 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) /* An intermediate buffer is introduced for implementing mmap for * SPORT working in TMD mode(include AC97). */ -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { sport_set_tx_callback(sport, bf5xx_dma_irq, substream); sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, @@ -190,24 +173,24 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) bf5xx_mmap_copy(substream, runtime->period_size); + snd_pcm_period_elapsed(substream); sport->tx_delay_pos = 0; -#endif sport_tx_start(sport); - } else + } + else sport_rx_start(sport); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) sport->tx_pos = 0; #endif sport_tx_stop(sport); } else { -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) sport->rx_pos = 0; #endif sport_rx_stop(sport); @@ -225,7 +208,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) struct sport_device *sport = runtime->private_data; unsigned int curr; -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) curr = sport->tx_delay_pos; else @@ -266,7 +249,22 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) return ret; } -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +static int bf5xx_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sport_device *sport = runtime->private_data; + + pr_debug("%s enter\n", __func__); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + sport->once = 0; + memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + } else + memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + + return 0; +} + +#ifdef CONFIG_SND_MMAP_SUPPORT static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { @@ -283,29 +281,32 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, void __user *buf, snd_pcm_uframes_t count) { struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1]; + pr_debug("%s copy pos:0x%lx count:0x%lx\n", substream->stream ? "Capture" : "Playback", pos, count); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - bf5xx_pcm_to_ac97((struct ac97_frame *)runtime->dma_area + pos, - (__u16 *)buf, count, chan_mask); + bf5xx_pcm_to_ac97( + (struct ac97_frame *)runtime->dma_area + pos, + buf, count); else - bf5xx_ac97_to_pcm((struct ac97_frame *)runtime->dma_area + pos, - (__u16 *)buf, count); + bf5xx_ac97_to_pcm( + (struct ac97_frame *)runtime->dma_area + pos, + buf, count); return 0; } #endif struct snd_pcm_ops bf5xx_pcm_ac97_ops = { .open = bf5xx_pcm_open, + .close = bf5xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = bf5xx_pcm_hw_params, .hw_free = bf5xx_pcm_hw_free, .prepare = bf5xx_pcm_prepare, .trigger = bf5xx_pcm_trigger, .pointer = bf5xx_pcm_pointer, -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#ifdef CONFIG_SND_MMAP_SUPPORT .mmap = bf5xx_pcm_mmap, #else .copy = bf5xx_pcm_copy, @@ -343,7 +344,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) * Need to allocate local buffer when enable * MMAP for SPORT working in TMD mode (include AC97). */ -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (!sport_handle->tx_dma_buf) { sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \ @@ -380,7 +381,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; int stream; -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) size_t size = bf5xx_pcm_hardware.buffer_bytes_max * sizeof(struct ac97_frame) / 4; #endif @@ -394,7 +395,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) continue; dma_free_coherent(NULL, buf->bytes, buf->area, 0); buf->area = NULL; -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) +#if defined(CONFIG_SND_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (sport_handle->tx_dma_buf) dma_free_coherent(NULL, size, \ @@ -451,18 +452,6 @@ struct snd_soc_platform bf5xx_ac97_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform); -static int __devinit bfin_ac97_init(void) -{ - return snd_soc_register_platform(&bf5xx_ac97_soc_platform); -} -module_init(bfin_ac97_init); - -static void __exit bfin_ac97_exit(void) -{ - snd_soc_unregister_platform(&bf5xx_ac97_soc_platform); -} -module_exit(bfin_ac97_exit); - MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index ad3efeeb6d44..5e5aafb6485f 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -54,103 +54,71 @@ static int *cmd_count; static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; -static u16 sport_req[][7] = { - PIN_REQ_SPORT_0, -#ifdef PIN_REQ_SPORT_1 - PIN_REQ_SPORT_1, -#endif -#ifdef PIN_REQ_SPORT_2 - PIN_REQ_SPORT_2, -#endif -#ifdef PIN_REQ_SPORT_3 - PIN_REQ_SPORT_3, -#endif - }; - +#if defined(CONFIG_BF54x) static struct sport_param sport_params[4] = { { .dma_rx_chan = CH_SPORT0_RX, .dma_tx_chan = CH_SPORT0_TX, - .err_irq = IRQ_SPORT0_ERROR, + .err_irq = IRQ_SPORT0_ERR, .regs = (struct sport_register *)SPORT0_TCR1, }, -#ifdef PIN_REQ_SPORT_1 { .dma_rx_chan = CH_SPORT1_RX, .dma_tx_chan = CH_SPORT1_TX, - .err_irq = IRQ_SPORT1_ERROR, + .err_irq = IRQ_SPORT1_ERR, .regs = (struct sport_register *)SPORT1_TCR1, }, -#endif -#ifdef PIN_REQ_SPORT_2 { .dma_rx_chan = CH_SPORT2_RX, .dma_tx_chan = CH_SPORT2_TX, - .err_irq = IRQ_SPORT2_ERROR, + .err_irq = IRQ_SPORT2_ERR, .regs = (struct sport_register *)SPORT2_TCR1, }, -#endif -#ifdef PIN_REQ_SPORT_3 { .dma_rx_chan = CH_SPORT3_RX, .dma_tx_chan = CH_SPORT3_TX, - .err_irq = IRQ_SPORT3_ERROR, + .err_irq = IRQ_SPORT3_ERR, .regs = (struct sport_register *)SPORT3_TCR1, } -#endif }; +#else +static struct sport_param sport_params[2] = { + { + .dma_rx_chan = CH_SPORT0_RX, + .dma_tx_chan = CH_SPORT0_TX, + .err_irq = IRQ_SPORT0_ERROR, + .regs = (struct sport_register *)SPORT0_TCR1, + }, + { + .dma_rx_chan = CH_SPORT1_RX, + .dma_tx_chan = CH_SPORT1_TX, + .err_irq = IRQ_SPORT1_ERROR, + .regs = (struct sport_register *)SPORT1_TCR1, + } +}; +#endif -void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, - size_t count, unsigned int chan_mask) +void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ + size_t count) { while (count--) { - dst->ac97_tag = TAG_VALID; - if (chan_mask & SP_FL) { - dst->ac97_pcm_r = *src++; - dst->ac97_tag |= TAG_PCM_RIGHT; - } - if (chan_mask & SP_FR) { - dst->ac97_pcm_l = *src++; - dst->ac97_tag |= TAG_PCM_LEFT; - - } -#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) - if (chan_mask & SP_SR) { - dst->ac97_sl = *src++; - dst->ac97_tag |= TAG_PCM_SL; - } - if (chan_mask & SP_SL) { - dst->ac97_sr = *src++; - dst->ac97_tag |= TAG_PCM_SR; - } - if (chan_mask & SP_LFE) { - dst->ac97_lfe = *src++; - dst->ac97_tag |= TAG_PCM_LFE; - } - if (chan_mask & SP_FC) { - dst->ac97_center = *src++; - dst->ac97_tag |= TAG_PCM_CENTER; - } -#endif - dst++; + dst->ac97_tag = TAG_VALID | TAG_PCM; + (dst++)->ac97_pcm = *src++; } } EXPORT_SYMBOL(bf5xx_pcm_to_ac97); -void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, +void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ size_t count) { - while (count--) { - *(dst++) = src->ac97_pcm_l; - *(dst++) = src->ac97_pcm_r; - src++; - } + while (count--) + *(dst++) = (src++)->ac97_pcm; } EXPORT_SYMBOL(bf5xx_ac97_to_pcm); static unsigned int sport_tx_curr_frag(struct sport_device *sport) { - return sport->tx_curr_frag = sport_curr_offset_tx(sport) / + return sport->tx_curr_frag = sport_curr_offset_tx(sport) / \ sport->tx_fragsize; } @@ -162,7 +130,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) sport_incfrag(sport, &nextfrag, 1); - nextwrite = (struct ac97_frame *)(sport->tx_buf + + nextwrite = (struct ac97_frame *)(sport->tx_buf + \ nextfrag * sport->tx_fragsize); pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n", sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]); @@ -269,7 +237,8 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); #ifdef CONFIG_PM -static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) +static int bf5xx_ac97_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) { struct sport_device *sport = (struct sport_device *)dai->private_data; @@ -284,7 +253,8 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) return 0; } -static int bf5xx_ac97_resume(struct snd_soc_dai *dai) +static int bf5xx_ac97_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { int ret; struct sport_device *sport = @@ -327,15 +297,20 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai) static int bf5xx_ac97_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { - int ret = 0; + int ret; +#if defined(CONFIG_BF54x) + u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1, + PIN_REQ_SPORT_2, PIN_REQ_SPORT_3}; +#else + u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1}; +#endif cmd_count = (int *)get_zeroed_page(GFP_KERNEL); if (cmd_count == NULL) return -ENOMEM; if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { pr_err("Requesting Peripherals failed\n"); - ret = -EFAULT; - goto peripheral_err; + return -EFAULT; } #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET @@ -343,54 +318,54 @@ static int bf5xx_ac97_probe(struct platform_device *pdev, if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) { pr_err("Failed to request GPIO_%d for reset\n", CONFIG_SND_BF5XX_RESET_GPIO_NUM); - ret = -1; - goto gpio_err; + peripheral_free_list(&sport_req[sport_num][0]); + return -1; } gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); #endif sport_handle = sport_init(&sport_params[sport_num], 2, \ sizeof(struct ac97_frame), NULL); if (!sport_handle) { - ret = -ENODEV; - goto sport_err; + peripheral_free_list(&sport_req[sport_num][0]); +#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET + gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); +#endif + return -ENODEV; } /*SPORT works in TDM mode to simulate AC97 transfers*/ ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); if (ret) { pr_err("SPORT is busy!\n"); - ret = -EBUSY; - goto sport_config_err; + kfree(sport_handle); + peripheral_free_list(&sport_req[sport_num][0]); +#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET + gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); +#endif + return -EBUSY; } ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1)); if (ret) { pr_err("SPORT is busy!\n"); - ret = -EBUSY; - goto sport_config_err; + kfree(sport_handle); + peripheral_free_list(&sport_req[sport_num][0]); +#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET + gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); +#endif + return -EBUSY; } ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1)); if (ret) { pr_err("SPORT is busy!\n"); - ret = -EBUSY; - goto sport_config_err; - } - - return 0; - -sport_config_err: - kfree(sport_handle); -sport_err: + kfree(sport_handle); + peripheral_free_list(&sport_req[sport_num][0]); #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET - gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); + gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); #endif -gpio_err: - peripheral_free_list(&sport_req[sport_num][0]); -peripheral_err: - free_page((unsigned long)cmd_count); - cmd_count = NULL; - - return ret; + return -EBUSY; + } + return 0; } static void bf5xx_ac97_remove(struct platform_device *pdev, @@ -398,7 +373,6 @@ static void bf5xx_ac97_remove(struct platform_device *pdev, { free_page((unsigned long)cmd_count); cmd_count = NULL; - peripheral_free_list(&sport_req[sport_num][0]); #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); #endif @@ -407,7 +381,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev, struct snd_soc_dai bfin_ac97_dai = { .name = "bf5xx-ac97", .id = 0, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .probe = bf5xx_ac97_probe, .remove = bf5xx_ac97_remove, .suspend = bf5xx_ac97_suspend, @@ -415,11 +389,7 @@ struct snd_soc_dai bfin_ac97_dai = { .playback = { .stream_name = "AC97 Playback", .channels_min = 2, -#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) - .channels_max = 6, -#else .channels_max = 2, -#endif .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { @@ -431,18 +401,6 @@ struct snd_soc_dai bfin_ac97_dai = { }; EXPORT_SYMBOL_GPL(bfin_ac97_dai); -static int __devinit bfin_ac97_init(void) -{ - return snd_soc_register_dai(&bfin_ac97_dai); -} -module_init(bfin_ac97_init); - -static void __exit bfin_ac97_exit(void) -{ - snd_soc_unregister_dai(&bfin_ac97_dai); -} -module_exit(bfin_ac97_exit); - MODULE_AUTHOR("Roy Huang"); MODULE_DESCRIPTION("AC97 driver for ADI Blackfin"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h index 3f2a911fe0cb..3f77cc558dc0 100644 --- a/sound/soc/blackfin/bf5xx-ac97.h +++ b/sound/soc/blackfin/bf5xx-ac97.h @@ -16,46 +16,21 @@ struct ac97_frame { u16 ac97_tag; /* slot 0 */ u16 ac97_addr; /* slot 1 */ u16 ac97_data; /* slot 2 */ - u16 ac97_pcm_l; /*slot 3:front left*/ - u16 ac97_pcm_r; /*slot 4:front left*/ -#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) - u16 ac97_mdm_l1; - u16 ac97_center; /*slot 6:center*/ - u16 ac97_sl; /*slot 7:surround left*/ - u16 ac97_sr; /*slot 8:surround right*/ - u16 ac97_lfe; /*slot 9:lfe*/ -#endif + u32 ac97_pcm; /* slot 3 and 4: left and right pcm data */ } __attribute__ ((packed)); -/* Speaker location */ -#define SP_FL 0x0001 -#define SP_FR 0x0010 -#define SP_FC 0x0002 -#define SP_LFE 0x0020 -#define SP_SL 0x0004 -#define SP_SR 0x0040 - -#define SP_STEREO (SP_FL | SP_FR) -#define SP_2DOT1 (SP_FL | SP_FR | SP_LFE) -#define SP_QUAD (SP_FL | SP_FR | SP_SL | SP_SR) -#define SP_5DOT1 (SP_FL | SP_FR | SP_FC | SP_LFE | SP_SL | SP_SR) - #define TAG_VALID 0x8000 #define TAG_CMD 0x6000 #define TAG_PCM_LEFT 0x1000 #define TAG_PCM_RIGHT 0x0800 -#define TAG_PCM_MDM_L1 0x0400 -#define TAG_PCM_CENTER 0x0200 -#define TAG_PCM_SL 0x0100 -#define TAG_PCM_SR 0x0080 -#define TAG_PCM_LFE 0x0040 +#define TAG_PCM (TAG_PCM_LEFT | TAG_PCM_RIGHT) extern struct snd_soc_dai bfin_ac97_dai; -void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \ - size_t count, unsigned int chan_mask); +void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ + size_t count); -void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, \ +void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ size_t count); #endif diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c index d8f591273778..124425d22320 100644 --- a/sound/soc/blackfin/bf5xx-ad1980.c +++ b/sound/soc/blackfin/bf5xx-ad1980.c @@ -43,7 +43,7 @@ #include "bf5xx-ac97-pcm.h" #include "bf5xx-ac97.h" -static struct snd_soc_card bf5xx_board; +static struct snd_soc_machine bf5xx_board; static int bf5xx_board_startup(struct snd_pcm_substream *substream) { @@ -67,15 +67,15 @@ static struct snd_soc_dai_link bf5xx_board_dai = { .ops = &bf5xx_board_ops, }; -static struct snd_soc_card bf5xx_board = { +static struct snd_soc_machine bf5xx_board = { .name = "bf5xx-board", - .platform = &bf5xx_ac97_soc_platform, .dai_link = &bf5xx_board_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_board_snd_devdata = { - .card = &bf5xx_board, + .machine = &bf5xx_board, + .platform = &bf5xx_ac97_soc_platform, .codec_dev = &soc_codec_dev_ad1980, }; diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index 7f2a5e199075..622c9b909532 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -65,7 +65,7 @@ #define GPIO_SE CONFIG_SND_BFIN_AD73311_SE -static struct snd_soc_card bf5xx_ad73311; +static struct snd_soc_machine bf5xx_ad73311; static int snd_ad73311_startup(void) { @@ -168,7 +168,7 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream, params_format(params)); /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; @@ -190,16 +190,16 @@ static struct snd_soc_dai_link bf5xx_ad73311_dai = { .ops = &bf5xx_ad73311_ops, }; -static struct snd_soc_card bf5xx_ad73311 = { +static struct snd_soc_machine bf5xx_ad73311 = { .name = "bf5xx_ad73311", - .platform = &bf5xx_i2s_soc_platform, .probe = bf5xx_probe, .dai_link = &bf5xx_ad73311_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_ad73311_snd_devdata = { - .card = &bf5xx_ad73311, + .machine = &bf5xx_ad73311, + .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ad73311, }; diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index c58b12a44870..61fccf925192 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -283,18 +283,6 @@ struct snd_soc_platform bf5xx_i2s_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform); -static int __devinit bfin_i2s_init(void) -{ - return snd_soc_register_platform(&bf5xx_i2s_soc_platform); -} -module_init(bfin_i2s_init); - -static void __exit bfin_i2s_exit(void) -{ - snd_soc_unregister_platform(&bf5xx_i2s_soc_platform); -} -module_exit(bfin_i2s_exit); - MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 0d58d2b6db6a..e020c160ee44 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -132,8 +132,7 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return ret; } -static int bf5xx_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int bf5xx_i2s_startup(struct snd_pcm_substream *substream) { pr_debug("%s enter\n", __func__); @@ -143,8 +142,7 @@ static int bf5xx_i2s_startup(struct snd_pcm_substream *substream, } static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { int ret = 0; @@ -195,8 +193,7 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream) { pr_debug("%s enter\n", __func__); bf5xx_i2s.counter--; @@ -222,14 +219,16 @@ static int bf5xx_i2s_probe(struct platform_device *pdev, return 0; } -static void bf5xx_i2s_remove(struct snd_soc_dai *dai) +static void bf5xx_i2s_remove(struct platform_device *pdev, + struct snd_soc_dai *dai) { pr_debug("%s enter\n", __func__); peripheral_free_list(&sport_req[sport_num][0]); } #ifdef CONFIG_PM -static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) +static int bf5xx_i2s_suspend(struct platform_device *dev, + struct snd_soc_dai *dai) { struct sport_device *sport = (struct sport_device *)dai->private_data; @@ -290,6 +289,7 @@ static int bf5xx_i2s_resume(struct platform_device *pdev, struct snd_soc_dai bf5xx_i2s_dai = { .name = "bf5xx-i2s", .id = 0, + .type = SND_SOC_DAI_I2S, .probe = bf5xx_i2s_probe, .remove = bf5xx_i2s_remove, .suspend = bf5xx_i2s_suspend, @@ -307,24 +307,13 @@ struct snd_soc_dai bf5xx_i2s_dai = { .ops = { .startup = bf5xx_i2s_startup, .shutdown = bf5xx_i2s_shutdown, - .hw_params = bf5xx_i2s_hw_params, + .hw_params = bf5xx_i2s_hw_params,}, + .dai_ops = { .set_fmt = bf5xx_i2s_set_dai_fmt, }, }; EXPORT_SYMBOL_GPL(bf5xx_i2s_dai); -static int __devinit bfin_i2s_init(void) -{ - return snd_soc_register_dai(&bfin_i2s_dai); -} -module_init(bfin_i2s_init); - -static void __exit bfin_i2s_exit(void) -{ - snd_soc_unregister_dai(&bfin_i2s_dai); -} -module_exit(bfin_i2s_exit); - /* Module information */ MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("I2S driver for ADI Blackfin"); diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h index 2e63dea73e9c..fcadcc081f7f 100644 --- a/sound/soc/blackfin/bf5xx-sport.h +++ b/sound/soc/blackfin/bf5xx-sport.h @@ -116,7 +116,7 @@ struct sport_device { void *err_data; unsigned char *tx_dma_buf; unsigned char *rx_dma_buf; -#ifdef CONFIG_SND_BF5XX_MMAP_SUPPORT +#ifdef CONFIG_SND_MMAP_SUPPORT dma_addr_t tx_dma_phy; dma_addr_t rx_dma_phy; int tx_pos;/*pcm sample count*/ diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index bc0cdded7116..e15f67fd7769 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c @@ -44,7 +44,7 @@ #include "bf5xx-i2s-pcm.h" #include "bf5xx-i2s.h" -static struct snd_soc_card bf5xx_ssm2602; +static struct snd_soc_machine bf5xx_ssm2602; static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream) { @@ -92,17 +92,17 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream, */ /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; - ret = snd_soc_dai_set_sysclk(codec_dai, SSM2602_SYSCLK, clk, + ret = codec_dai->dai_ops.set_sysclk(codec_dai, SSM2602_SYSCLK, clk, SND_SOC_CLOCK_IN); if (ret < 0) return ret; @@ -135,15 +135,15 @@ static struct ssm2602_setup_data bf5xx_ssm2602_setup = { .i2c_address = 0x1b, }; -static struct snd_soc_card bf5xx_ssm2602 = { +static struct snd_soc_machine bf5xx_ssm2602 = { .name = "bf5xx_ssm2602", - .platform = &bf5xx_i2s_soc_platform, .dai_link = &bf5xx_ssm2602_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_ssm2602_snd_devdata = { - .card = &bf5xx_ssm2602, + .machine = &bf5xx_ssm2602, + .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ssm2602, .codec_data = &bf5xx_ssm2602_setup, }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index bf68052d6924..38a0e3b620a7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1,39 +1,31 @@ config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" - select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS - select SND_SOC_AD1980 if SND_SOC_AC97_BUS - select SND_SOC_AD73311 if I2C - select SND_SOC_AK4535 if I2C - select SND_SOC_CS4270 if I2C - select SND_SOC_PCM3008 - select SND_SOC_SSM2602 if I2C - select SND_SOC_TLV320AIC23 if I2C - select SND_SOC_TLV320AIC26 if SPI_MASTER - select SND_SOC_TLV320AIC3X if I2C - select SND_SOC_TWL4030 if TWL4030_CORE - select SND_SOC_UDA134X - select SND_SOC_UDA1380 if I2C - select SND_SOC_WM8510 if (I2C || SPI_MASTER) - select SND_SOC_WM8580 if I2C - select SND_SOC_WM8728 if (I2C || SPI_MASTER) - select SND_SOC_WM8731 if (I2C || SPI_MASTER) - select SND_SOC_WM8750 if (I2C || SPI_MASTER) - select SND_SOC_WM8753 if (I2C || SPI_MASTER) - select SND_SOC_WM8900 if I2C - select SND_SOC_WM8903 if I2C - select SND_SOC_WM8971 if I2C - select SND_SOC_WM8990 if I2C - select SND_SOC_WM9712 if SND_SOC_AC97_BUS - select SND_SOC_WM9713 if SND_SOC_AC97_BUS + depends on I2C + select SPI + select SPI_MASTER + select SND_SOC_AD73311 + select SND_SOC_AK4535 + select SND_SOC_CS4270 + select SND_SOC_SSM2602 + select SND_SOC_TLV320AIC23 + select SND_SOC_TLV320AIC26 + select SND_SOC_TLV320AIC3X + select SND_SOC_UDA1380 + select SND_SOC_WM8510 + select SND_SOC_WM8580 + select SND_SOC_WM8731 + select SND_SOC_WM8750 + select SND_SOC_WM8753 + select SND_SOC_WM8900 + select SND_SOC_WM8903 + select SND_SOC_WM8971 + select SND_SOC_WM8990 help Normally ASoC codec drivers are only built if a machine driver which uses them is also built since they are only usable with a machine driver. Selecting this option will allow these drivers to be built without an explicit machine driver for test and development purposes. - Support for the bus types used to access the codecs to be built must - be selected separately. - If unsure select "N". @@ -68,12 +60,6 @@ config SND_SOC_CS4270_VD33_ERRATA bool depends on SND_SOC_CS4270 -config SND_SOC_L3 - tristate - -config SND_SOC_PCM3008 - tristate - config SND_SOC_SSM2602 tristate @@ -89,14 +75,6 @@ config SND_SOC_TLV320AIC3X tristate depends on I2C -config SND_SOC_TWL4030 - tristate - depends on TWL4030_CORE - -config SND_SOC_UDA134X - tristate - select SND_SOC_L3 - config SND_SOC_UDA1380 tristate @@ -106,9 +84,6 @@ config SND_SOC_WM8510 config SND_SOC_WM8580 tristate -config SND_SOC_WM8728 - tristate - config SND_SOC_WM8731 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9a20fddd09c7..90f0a585fc70 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -3,18 +3,13 @@ snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o snd-soc-ak4535-objs := ak4535.o snd-soc-cs4270-objs := cs4270.o -snd-soc-l3-objs := l3.o -snd-soc-pcm3008-objs := pcm3008.o snd-soc-ssm2602-objs := ssm2602.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o -snd-soc-twl4030-objs := twl4030.o -snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8580-objs := wm8580.o -snd-soc-wm8728-objs := wm8728.o snd-soc-wm8731-objs := wm8731.o snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o @@ -30,18 +25,13 @@ obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o -obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o -obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o -obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o -obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o -obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index fb53e6511af2..bd1ebdc6c86c 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -24,8 +24,7 @@ #define AC97_VERSION "0.6" -static int ac97_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ac97_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -43,7 +42,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai ac97_dai = { .name = "AC97 HiFi", - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .playback = { .stream_name = "AC97 Playback", .channels_min = 1, @@ -114,7 +113,7 @@ static int ac97_soc_probe(struct platform_device *pdev) if (ret < 0) goto bus_err; - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) goto bus_err; return 0; diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 73fdbb4d4a3d..1397b8e06c0b 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -85,9 +85,6 @@ SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0), SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), -SOC_DOUBLE("Center/LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 0, 31, 1), -SOC_DOUBLE("Center/LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 7, 1, 1), - SOC_ENUM("Capture Source", ad1980_cap_src), SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), @@ -145,11 +142,10 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, struct snd_soc_dai ad1980_dai = { .name = "AC97", - .ac97_control = 1, .playback = { .stream_name = "Playback", .channels_min = 2, - .channels_max = 6, + .channels_max = 2, .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { @@ -196,7 +192,6 @@ static int ad1980_soc_probe(struct platform_device *pdev) struct snd_soc_codec *codec; int ret = 0; u16 vendor_id2; - u16 ext_status; printk(KERN_INFO "AD1980 SoC Audio Codec\n"); @@ -239,7 +234,7 @@ static int ad1980_soc_probe(struct platform_device *pdev) ret = ad1980_reset(codec, 0); if (ret < 0) { - printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n"); + printk(KERN_ERR "AC97 link error\n"); goto reset_err; } @@ -258,19 +253,12 @@ static int ad1980_soc_probe(struct platform_device *pdev) "supported\n"); } - /* unmute captures and playbacks volume */ - ac97_write(codec, AC97_MASTER, 0x0000); - ac97_write(codec, AC97_PCM, 0x0000); - ac97_write(codec, AC97_REC_GAIN, 0x0000); - ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); - ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); - - /*power on LFE/CENTER/Surround DACs*/ - ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); - ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); + ac97_write(codec, AC97_MASTER, 0x0000); /* unmute line out volume */ + ac97_write(codec, AC97_PCM, 0x0000); /* unmute PCM out volume */ + ac97_write(codec, AC97_REC_GAIN, 0x0000);/* unmute record volume */ ad1980_add_controls(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "ad1980: failed to register card\n"); goto reset_err; diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index e32f55034e64..37af8607b00a 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -8,10 +8,14 @@ * 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. + * + * Revision history + * 25th Sep 2008 Initial version. */ #include <linux/init.h> #include <linux/module.h> +#include <linux/version.h> #include <linux/kernel.h> #include <linux/device.h> #include <sound/core.h> @@ -64,7 +68,7 @@ static int ad73311_soc_probe(struct platform_device *pdev) goto pcm_err; } - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "ad73311: failed to register card\n"); goto register_err; @@ -98,18 +102,6 @@ struct snd_soc_codec_device soc_codec_dev_ad73311 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311); -static int __devinit ad73311_init(void) -{ - return snd_soc_register_dai(&ad73311_dai); -} -module_init(ad73311_init); - -static void __exit ad73311_exit(void) -{ - snd_soc_unregister_dai(&ad73311_dai); -} -module_exit(ad73311_exit); - MODULE_DESCRIPTION("ASoC ad73311 driver"); MODULE_AUTHOR("Cliff Cai "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 94148fba9119..2a89b5888e11 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -339,8 +339,7 @@ static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, } static int ak4535_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -452,6 +451,8 @@ struct snd_soc_dai ak4535_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .hw_params = ak4535_hw_params, + }, + .dai_ops = { .set_fmt = ak4535_set_dai_fmt, .digital_mute = ak4535_mute, .set_sysclk = ak4535_set_dai_sysclk, @@ -512,7 +513,7 @@ static int ak4535_init(struct snd_soc_device *socdev) ak4535_add_controls(codec); ak4535_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "ak4535: failed to register card\n"); goto card_err; @@ -688,18 +689,6 @@ struct snd_soc_codec_device soc_codec_dev_ak4535 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); -static int __devinit ak4535_modinit(void) -{ - return snd_soc_register_dai(&ak4535_dai); -} -module_init(ak4535_modinit); - -static void __exit ak4535_exit(void) -{ - snd_soc_unregister_dai(&ak4535_dai); -} -module_exit(ak4535_exit); - MODULE_DESCRIPTION("Soc AK4535 driver"); MODULE_AUTHOR("Richard Purdie"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 73aaf249d782..0bbd94501d7e 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -360,14 +360,13 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, /* * Program the CS4270 with the given hardware parameters. * - * The .ops functions are used to provide board-specific data, like + * The .dai_ops functions are used to provide board-specific data, like * input frequencies, to this driver. This function takes that information, * combines it with the hardware parameters provided, and programs the * hardware accordingly. */ static int cs4270_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -451,19 +450,6 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, return ret; } - /* Disable automatic volume control. It's enabled by default, and - * it causes volume change commands to be delayed, sometimes until - * after playback has started. - */ - - reg = cs4270_read_reg_cache(codec, CS4270_TRANS); - reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO); - ret = cs4270_i2c_write(codec, CS4270_TRANS, reg); - if (ret < 0) { - printk(KERN_ERR "I2C write failed\n"); - return ret; - } - /* Thaw and power-up the codec */ ret = snd_soc_write(codec, CS4270_PWRCTL, 0); @@ -711,10 +697,10 @@ static int cs4270_probe(struct platform_device *pdev) if (codec->control_data) { /* Initialize codec ops */ cs4270_dai.ops.hw_params = cs4270_hw_params; - cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk; - cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt; + cs4270_dai.dai_ops.set_sysclk = cs4270_set_dai_sysclk; + cs4270_dai.dai_ops.set_fmt = cs4270_set_dai_fmt; #ifdef CONFIG_SND_SOC_CS4270_HWMUTE - cs4270_dai.ops.digital_mute = cs4270_mute; + cs4270_dai.dai_ops.digital_mute = cs4270_mute; #endif } else printk(KERN_INFO "cs4270: no I2C device found, " @@ -723,7 +709,7 @@ static int cs4270_probe(struct platform_device *pdev) printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n"); #endif - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "cs4270: failed to register card\n"); goto error_del_driver; @@ -774,18 +760,6 @@ struct snd_soc_codec_device soc_codec_device_cs4270 = { }; EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); -static int __devinit cs4270_init(void) -{ - return snd_soc_register_dai(&cs4270_dai); -} -module_init(cs4270_init); - -static void __exit cs4270_exit(void) -{ - snd_soc_unregister_dai(&cs4270_dai); -} -module_exit(cs4270_exit); - MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c deleted file mode 100644 index 5353af58862c..000000000000 --- a/sound/soc/codecs/l3.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * L3 code - * - * Copyright (C) 2008, Christian Pellegrin <chripell@evolware.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * - * based on: - * - * L3 bus algorithm module. - * - * Copyright (C) 2001 Russell King, All Rights Reserved. - * - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> - -#include <sound/l3.h> - -/* - * Send one byte of data to the chip. Data is latched into the chip on - * the rising edge of the clock. - */ -static void sendbyte(struct l3_pins *adap, unsigned int byte) -{ - int i; - - for (i = 0; i < 8; i++) { - adap->setclk(0); - udelay(adap->data_hold); - adap->setdat(byte & 1); - udelay(adap->data_setup); - adap->setclk(1); - udelay(adap->clock_high); - byte >>= 1; - } -} - -/* - * Send a set of bytes to the chip. We need to pulse the MODE line - * between each byte, but never at the start nor at the end of the - * transfer. - */ -static void sendbytes(struct l3_pins *adap, const u8 *buf, - int len) -{ - int i; - - for (i = 0; i < len; i++) { - if (i) { - udelay(adap->mode_hold); - adap->setmode(0); - udelay(adap->mode); - } - adap->setmode(1); - udelay(adap->mode_setup); - sendbyte(adap, buf[i]); - } -} - -int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len) -{ - adap->setclk(1); - adap->setdat(1); - adap->setmode(1); - udelay(adap->mode); - - adap->setmode(0); - udelay(adap->mode_setup); - sendbyte(adap, addr); - udelay(adap->mode_hold); - - sendbytes(adap, data, len); - - adap->setclk(1); - adap->setdat(1); - adap->setmode(0); - - return len; -} -EXPORT_SYMBOL_GPL(l3_write); - -MODULE_DESCRIPTION("L3 bit-banging driver"); -MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c deleted file mode 100644 index f333e88ee255..000000000000 --- a/sound/soc/codecs/pcm3008.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * ALSA Soc PCM3008 codec support - * - * Author: Hugo Villeneuve - * Copyright (C) 2008 Lyrtech inc - * - * Based on AC97 Soc codec, original copyright follow: - * Copyright 2005 Wolfson Microelectronics PLC. - * - * 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. - * - * Generic PCM3008 support. - */ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/gpio.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/initval.h> -#include <sound/soc.h> - -#include "pcm3008.h" - -#define PCM3008_VERSION "0.2" - -#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000) - -struct snd_soc_dai pcm3008_dai = { - .name = "PCM3008 HiFi", - .playback = { - .stream_name = "PCM3008 Playback", - .channels_min = 1, - .channels_max = 2, - .rates = PCM3008_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "PCM3008 Capture", - .channels_min = 1, - .channels_max = 2, - .rates = PCM3008_RATES, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}; -EXPORT_SYMBOL_GPL(pcm3008_dai); - -static void pcm3008_gpio_free(struct pcm3008_setup_data *setup) -{ - gpio_free(setup->dem0_pin); - gpio_free(setup->dem1_pin); - gpio_free(setup->pdad_pin); - gpio_free(setup->pdda_pin); -} - -static int pcm3008_soc_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - struct pcm3008_setup_data *setup = socdev->codec_data; - int ret = 0; - - printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION); - - socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (!socdev->codec) - return -ENOMEM; - - codec = socdev->codec; - mutex_init(&codec->mutex); - - codec->name = "PCM3008"; - codec->owner = THIS_MODULE; - codec->dai = &pcm3008_dai; - codec->num_dai = 1; - codec->write = NULL; - codec->read = NULL; - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - /* Register PCMs. */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "pcm3008: failed to create pcms\n"); - goto pcm_err; - } - - /* Register Card. */ - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "pcm3008: failed to register card\n"); - goto card_err; - } - - /* DEM1 DEM0 DE-EMPHASIS_MODE - * Low Low De-emphasis 44.1 kHz ON - * Low High De-emphasis OFF - * High Low De-emphasis 48 kHz ON - * High High De-emphasis 32 kHz ON - */ - - /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */ - ret = gpio_request(setup->dem0_pin, "codec_dem0"); - if (ret == 0) - ret = gpio_direction_output(setup->dem0_pin, 1); - if (ret != 0) - goto gpio_err; - - /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */ - ret = gpio_request(setup->dem1_pin, "codec_dem1"); - if (ret == 0) - ret = gpio_direction_output(setup->dem1_pin, 0); - if (ret != 0) - goto gpio_err; - - /* Configure PDAD GPIO. */ - ret = gpio_request(setup->pdad_pin, "codec_pdad"); - if (ret == 0) - ret = gpio_direction_output(setup->pdad_pin, 1); - if (ret != 0) - goto gpio_err; - - /* Configure PDDA GPIO. */ - ret = gpio_request(setup->pdda_pin, "codec_pdda"); - if (ret == 0) - ret = gpio_direction_output(setup->pdda_pin, 1); - if (ret != 0) - goto gpio_err; - - return ret; - -gpio_err: - pcm3008_gpio_free(setup); -card_err: - snd_soc_free_pcms(socdev); -pcm_err: - kfree(socdev->codec); - - return ret; -} - -static int pcm3008_soc_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - struct pcm3008_setup_data *setup = socdev->codec_data; - - if (!codec) - return 0; - - pcm3008_gpio_free(setup); - snd_soc_free_pcms(socdev); - kfree(socdev->codec); - - return 0; -} - -#ifdef CONFIG_PM -static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct pcm3008_setup_data *setup = socdev->codec_data; - - gpio_set_value(setup->pdad_pin, 0); - gpio_set_value(setup->pdda_pin, 0); - - return 0; -} - -static int pcm3008_soc_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct pcm3008_setup_data *setup = socdev->codec_data; - - gpio_set_value(setup->pdad_pin, 1); - gpio_set_value(setup->pdda_pin, 1); - - return 0; -} -#else -#define pcm3008_soc_suspend NULL -#define pcm3008_soc_resume NULL -#endif - -struct snd_soc_codec_device soc_codec_dev_pcm3008 = { - .probe = pcm3008_soc_probe, - .remove = pcm3008_soc_remove, - .suspend = pcm3008_soc_suspend, - .resume = pcm3008_soc_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008); - -static int __devinit pcm3008_init(void) -{ - return snd_soc_register_dai(&pcm3008_dai); -} -module_init(pcm3008_init); - -static void __exit pcm3008_exit(void) -{ - snd_soc_unregister_dai(&pcm3008_dai); -} -module_exit(pcm3008_exit); - -MODULE_DESCRIPTION("Soc PCM3008 driver"); -MODULE_AUTHOR("Hugo Villeneuve"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm3008.h b/sound/soc/codecs/pcm3008.h deleted file mode 100644 index d04e87d3c060..000000000000 --- a/sound/soc/codecs/pcm3008.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * PCM3008 ALSA SoC Layer - * - * Author: Hugo Villeneuve - * Copyright (C) 2008 Lyrtech inc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __LINUX_SND_SOC_PCM3008_H -#define __LINUX_SND_SOC_PCM3008_H - -struct pcm3008_setup_data { - unsigned dem0_pin; - unsigned dem1_pin; - unsigned pdad_pin; - unsigned pdda_pin; -}; - -extern struct snd_soc_codec_device soc_codec_dev_pcm3008; -extern struct snd_soc_dai pcm3008_dai; - -#endif diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 77fdcb4b9a1b..44ef0dacd564 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -285,23 +285,16 @@ static inline int get_coeff(int mclk, int rate) } static int ssm2602_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { u16 srate; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; struct ssm2602_priv *ssm2602 = codec->private_data; - struct i2c_client *i2c = codec->control_data; u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; int i = get_coeff(ssm2602->sysclk, params_rate(params)); - if (substream == ssm2602->slave_substream) { - dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); - return 0; - } - /*no match is found*/ if (i == ARRAY_SIZE(coeff_div)) return -EINVAL; @@ -331,26 +324,19 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, return 0; } -static int ssm2602_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ssm2602_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; struct ssm2602_priv *ssm2602 = codec->private_data; - struct i2c_client *i2c = codec->control_data; struct snd_pcm_runtime *master_runtime; /* The DAI has shared clocks so if we already have a playback or * capture going then constrain this substream to match it. - * TODO: the ssm2602 allows pairs of non-matching PB/REC rates */ if (ssm2602->master_substream) { master_runtime = ssm2602->master_substream->runtime; - dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n", - master_runtime->sample_bits, - master_runtime->rate); - snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, master_runtime->rate, @@ -368,8 +354,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream, return 0; } -static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -380,21 +365,14 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream, return 0; } -static void ssm2602_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void ssm2602_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - struct ssm2602_priv *ssm2602 = codec->private_data; /* deactivate */ if (!codec->active) ssm2602_write(codec, SSM2602_ACTIVE, 0); - - if (ssm2602->master_substream == substream) - ssm2602->master_substream = ssm2602->slave_substream; - - ssm2602->slave_substream = NULL; } static int ssm2602_mute(struct snd_soc_dai *dai, int mute) @@ -518,9 +496,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000) -#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - struct snd_soc_dai ssm2602_dai = { .name = "SSM2602", .playback = { @@ -528,18 +503,20 @@ struct snd_soc_dai ssm2602_dai = { .channels_min = 2, .channels_max = 2, .rates = SSM2602_RATES, - .formats = SSM2602_FORMATS,}, + .formats = SNDRV_PCM_FMTBIT_S32_LE,}, .capture = { .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SSM2602_RATES, - .formats = SSM2602_FORMATS,}, + .formats = SNDRV_PCM_FMTBIT_S32_LE,}, .ops = { .startup = ssm2602_startup, .prepare = ssm2602_pcm_prepare, .hw_params = ssm2602_hw_params, .shutdown = ssm2602_shutdown, + }, + .dai_ops = { .digital_mute = ssm2602_mute, .set_sysclk = ssm2602_set_dai_sysclk, .set_fmt = ssm2602_set_dai_fmt, @@ -624,7 +601,7 @@ static int ssm2602_init(struct snd_soc_device *socdev) ssm2602_add_controls(codec); ssm2602_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { pr_err("ssm2602: failed to register card\n"); goto card_err; @@ -793,18 +770,6 @@ struct snd_soc_codec_device soc_codec_dev_ssm2602 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602); -static int __devinit ssm2602_modinit(void) -{ - return snd_soc_register_dai(&ssm2602_dai); -} -module_init(ssm2602_modinit); - -static void __exit ssm2602_exit(void) -{ - snd_soc_unregister_dai(&ssm2602_dai); -} -module_exit(ssm2602_exit); - MODULE_DESCRIPTION("ASoC ssm2602 driver"); MODULE_AUTHOR("Cliff Cai"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index eac449b92bd5..44308dac9e18 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -37,6 +37,12 @@ #define AIC23_VERSION "0.1" +struct tlv320aic23_srate_reg_info { + u32 sample_rate; + u8 control; /* SR3, SR2, SR1, SR0 and BOSR */ + u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */ +}; + /* * AIC23 register cache */ @@ -255,156 +261,20 @@ static const struct snd_soc_dapm_route intercon[] = { }; -/* AIC23 driver data */ -struct aic23 { - struct snd_soc_codec codec; - int mclk; - int requested_adc; - int requested_dac; -}; - -/* - * Common Crystals used - * 11.2896 Mhz /128 = *88.2k /192 = 58.8k - * 12.0000 Mhz /125 = *96k /136 = 88.235K - * 12.2880 Mhz /128 = *96k /192 = 64k - * 16.9344 Mhz /128 = 132.3k /192 = *88.2k - * 18.4320 Mhz /128 = 144k /192 = *96k - */ - -/* - * Normal BOSR 0-256/2 = 128, 1-384/2 = 192 - * USB BOSR 0-250/2 = 125, 1-272/2 = 136 - */ -static const int bosr_usb_divisor_table[] = { - 128, 125, 192, 136 -}; -#define LOWER_GROUP ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<6) | (1<<7)) -#define UPPER_GROUP ((1<<8) | (1<<9) | (1<<10) | (1<<11) | (1<<15)) -static const unsigned short sr_valid_mask[] = { - LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 0*/ - LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 1*/ - LOWER_GROUP, /* Usb, bosr - 0*/ - UPPER_GROUP, /* Usb, bosr - 1*/ -}; -/* - * Every divisor is a factor of 11*12 - */ -#define SR_MULT (11*12) -#define A(x) (x) ? (SR_MULT/x) : 0 -static const unsigned char sr_adc_mult_table[] = { - A(2), A(2), A(12), A(12), A(0), A(0), A(3), A(1), - A(2), A(2), A(11), A(11), A(0), A(0), A(0), A(1) -}; -static const unsigned char sr_dac_mult_table[] = { - A(2), A(12), A(2), A(12), A(0), A(0), A(3), A(1), - A(2), A(11), A(2), A(11), A(0), A(0), A(0), A(1) +/* tlv320aic23 related */ +static const struct tlv320aic23_srate_reg_info srate_reg_info[] = { + {4000, 0x06, 1}, /* 4000 */ + {8000, 0x06, 0}, /* 8000 */ + {16000, 0x0C, 1}, /* 16000 */ + {22050, 0x11, 1}, /* 22050 */ + {24000, 0x00, 1}, /* 24000 */ + {32000, 0x0C, 0}, /* 32000 */ + {44100, 0x11, 0}, /* 44100 */ + {48000, 0x00, 0}, /* 48000 */ + {88200, 0x1F, 0}, /* 88200 */ + {96000, 0x0E, 0}, /* 96000 */ }; -static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc, - int dac, int dac_l, int dac_h, int need_dac) -{ - if ((adc >= adc_l) && (adc <= adc_h) && - (dac >= dac_l) && (dac <= dac_h)) { - int diff_adc = need_adc - adc; - int diff_dac = need_dac - dac; - return abs(diff_adc) + abs(diff_dac); - } - return UINT_MAX; -} - -static int find_rate(int mclk, u32 need_adc, u32 need_dac) -{ - int i, j; - int best_i = -1; - int best_j = -1; - int best_div = 0; - unsigned best_score = UINT_MAX; - int adc_l, adc_h, dac_l, dac_h; - - need_adc *= SR_MULT; - need_dac *= SR_MULT; - /* - * rates given are +/- 1/32 - */ - adc_l = need_adc - (need_adc >> 5); - adc_h = need_adc + (need_adc >> 5); - dac_l = need_dac - (need_dac >> 5); - dac_h = need_dac + (need_dac >> 5); - for (i = 0; i < ARRAY_SIZE(bosr_usb_divisor_table); i++) { - int base = mclk / bosr_usb_divisor_table[i]; - int mask = sr_valid_mask[i]; - for (j = 0; j < ARRAY_SIZE(sr_adc_mult_table); - j++, mask >>= 1) { - int adc; - int dac; - int score; - if ((mask & 1) == 0) - continue; - adc = base * sr_adc_mult_table[j]; - dac = base * sr_dac_mult_table[j]; - score = get_score(adc, adc_l, adc_h, need_adc, - dac, dac_l, dac_h, need_dac); - if (best_score > score) { - best_score = score; - best_i = i; - best_j = j; - best_div = 0; - } - score = get_score((adc >> 1), adc_l, adc_h, need_adc, - (dac >> 1), dac_l, dac_h, need_dac); - /* prefer to have a /2 */ - if ((score != UINT_MAX) && (best_score >= score)) { - best_score = score; - best_i = i; - best_j = j; - best_div = 1; - } - } - } - return (best_j << 2) | best_i | (best_div << TLV320AIC23_CLKIN_SHIFT); -} - -#ifdef DEBUG -static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk, - u32 *sample_rate_adc, u32 *sample_rate_dac) -{ - int src = tlv320aic23_read_reg_cache(codec, TLV320AIC23_SRATE); - int sr = (src >> 2) & 0x0f; - int val = (mclk / bosr_usb_divisor_table[src & 3]); - int adc = (val * sr_adc_mult_table[sr]) / SR_MULT; - int dac = (val * sr_dac_mult_table[sr]) / SR_MULT; - if (src & TLV320AIC23_CLKIN_HALF) { - adc >>= 1; - dac >>= 1; - } - *sample_rate_adc = adc; - *sample_rate_dac = dac; -} -#endif - -static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk, - u32 sample_rate_adc, u32 sample_rate_dac) -{ - /* Search for the right sample rate */ - int data = find_rate(mclk, sample_rate_adc, sample_rate_dac); - if (data < 0) { - printk(KERN_ERR "%s:Invalid rate %u,%u requested\n", - __func__, sample_rate_adc, sample_rate_dac); - return -EINVAL; - } - tlv320aic23_write(codec, TLV320AIC23_SRATE, data); -#ifdef DEBUG - { - u32 adc, dac; - get_current_sample_rates(codec, mclk, &adc, &dac); - printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n", - adc, dac, data); - } -#endif - return 0; -} - static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) { snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, @@ -418,36 +288,32 @@ static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) } static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - u16 iface_reg; - int ret; - struct aic23 *aic23 = container_of(codec, struct aic23, codec); - u32 sample_rate_adc = aic23->requested_adc; - u32 sample_rate_dac = aic23->requested_dac; - u32 sample_rate = params_rate(params); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - aic23->requested_dac = sample_rate_dac = sample_rate; - if (!sample_rate_adc) - sample_rate_adc = sample_rate; - } else { - aic23->requested_adc = sample_rate_adc = sample_rate; - if (!sample_rate_dac) - sample_rate_dac = sample_rate; - } - ret = set_sample_rate_control(codec, aic23->mclk, sample_rate_adc, - sample_rate_dac); - if (ret < 0) - return ret; + u16 iface_reg, data; + u8 count = 0; iface_reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & ~(0x03 << 2); + + /* Search for the right sample rate */ + /* Verify what happens if the rate is not supported + * now it goes to 96Khz */ + while ((srate_reg_info[count].sample_rate != params_rate(params)) && + (count < ARRAY_SIZE(srate_reg_info))) { + count++; + } + + data = (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) | + (srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) | + TLV320AIC23_USB_CLK_ON; + + tlv320aic23_write(codec, TLV320AIC23_SRATE, data); + switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; @@ -466,8 +332,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, return 0; } -static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -479,23 +344,17 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream, return 0; } -static void tlv320aic23_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void tlv320aic23_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - struct aic23 *aic23 = container_of(codec, struct aic23, codec); /* deactivate */ if (!codec->active) { udelay(50); tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - aic23->requested_dac = 0; - else - aic23->requested_adc = 0; } static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute) @@ -563,9 +422,12 @@ static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; - struct aic23 *aic23 = container_of(codec, struct aic23, codec); - aic23->mclk = freq; - return 0; + + switch (freq) { + case 12000000: + return 0; + } + return -EINVAL; } static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, @@ -616,10 +478,12 @@ struct snd_soc_dai tlv320aic23_dai = { .prepare = tlv320aic23_pcm_prepare, .hw_params = tlv320aic23_hw_params, .shutdown = tlv320aic23_shutdown, - .digital_mute = tlv320aic23_mute, - .set_fmt = tlv320aic23_set_dai_fmt, - .set_sysclk = tlv320aic23_set_dai_sysclk, - } + }, + .dai_ops = { + .digital_mute = tlv320aic23_mute, + .set_fmt = tlv320aic23_set_dai_fmt, + .set_sysclk = tlv320aic23_set_dai_sysclk, + } }; EXPORT_SYMBOL_GPL(tlv320aic23_dai); @@ -720,7 +584,7 @@ static int tlv320aic23_init(struct snd_soc_device *socdev) tlv320aic23_add_controls(codec); tlv320aic23_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "tlv320aic23: failed to register card\n"); goto card_err; @@ -795,15 +659,14 @@ static int tlv320aic23_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec; - struct aic23 *aic23; int ret = 0; printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION); - aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL); - if (aic23 == NULL) + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) return -ENOMEM; - codec = &aic23->codec; + socdev->codec = codec; mutex_init(&codec->mutex); INIT_LIST_HEAD(&codec->dapm_widgets); @@ -824,7 +687,6 @@ static int tlv320aic23_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->codec; - struct aic23 *aic23 = container_of(codec, struct aic23, codec); if (codec->control_data) tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); @@ -835,7 +697,7 @@ static int tlv320aic23_remove(struct platform_device *pdev) i2c_del_driver(&tlv320aic23_i2c_driver); #endif kfree(codec->reg_cache); - kfree(aic23); + kfree(codec); return 0; } @@ -847,18 +709,6 @@ struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23); -static int __devinit tlv320aic23_modinit(void) -{ - return snd_soc_register_dai(&tlv320aic23_dai); -} -module_init(tlv320aic23_modinit); - -static void __exit tlv320aic23_exit(void) -{ - snd_soc_unregister_dai(&tlv320aic23_dai); -} -module_exit(tlv320aic23_exit); - MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 29f2f1a017fd..bed8a9e63ddc 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -125,8 +125,7 @@ static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg, * Digital Audio Interface Operations */ static int aic26_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -288,6 +287,8 @@ struct snd_soc_dai aic26_dai = { }, .ops = { .hw_params = aic26_hw_params, + }, + .dai_ops = { .digital_mute = aic26_mute, .set_sysclk = aic26_set_sysclk, .set_fmt = aic26_set_fmt, @@ -359,7 +360,7 @@ static int aic26_probe(struct platform_device *pdev) /* CODEC is setup, we can register the card now */ dev_dbg(&pdev->dev, "Registering card\n"); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { dev_err(&pdev->dev, "aic26: failed to register card\n"); goto card_err; @@ -426,7 +427,7 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set); static int aic26_spi_probe(struct spi_device *spi) { struct aic26 *aic26; - int ret, i, reg; + int rc, i, reg; dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n"); @@ -456,14 +457,6 @@ static int aic26_spi_probe(struct spi_device *spi) aic26->codec.reg_cache_size = AIC26_NUM_REGS; aic26->codec.reg_cache = aic26->reg_cache; - aic26_dai.dev = &spi->dev; - ret = snd_soc_register_dai(&aic26_dai); - if (ret != 0) { - dev_err(&spi->dev, "Failed to register DAI: %d\n", ret); - kfree(aic26); - return ret; - } - /* Reset the codec to power on defaults */ aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00); @@ -482,8 +475,8 @@ static int aic26_spi_probe(struct spi_device *spi) /* Register the sysfs files for debugging */ /* Create SysFS files */ - ret = device_create_file(&spi->dev, &dev_attr_keyclick); - if (ret) + rc = device_create_file(&spi->dev, &dev_attr_keyclick); + if (rc) dev_info(&spi->dev, "error creating sysfs files\n"); #if defined(CONFIG_SND_SOC_OF_SIMPLE) @@ -500,7 +493,6 @@ static int aic26_spi_remove(struct spi_device *spi) { struct aic26 *aic26 = dev_get_drvdata(&spi->dev); - snd_soc_unregister_dai(&aic26_dai); kfree(aic26); return 0; diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index ccd575961869..cff276ee261e 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -253,17 +253,11 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL, 0, 0x7f, 1), - SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0), - SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0), - SOC_DOUBLE_R("LineL DAC Playback Volume", DACL1_2_LLOPM_VOL, - DACR1_2_LLOPM_VOL, 0, 0x7f, 1), - SOC_SINGLE("LineL Left PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, - 0, 0x7f, 1), - SOC_SINGLE("LineR Right PGA Bypass Playback Volume", PGAR_2_RLOPM_VOL, - 0, 0x7f, 1), - SOC_DOUBLE_R("LineL Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, - LINE2R_2_LLOPM_VOL, 0, 0x7f, 1), - SOC_DOUBLE_R("LineR Line2 Bypass Playback Volume", LINE2L_2_RLOPM_VOL, + SOC_DOUBLE_R("Line DAC Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3, + 0x01, 0), + SOC_DOUBLE_R("Line PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, + PGAR_2_RLOPM_VOL, 0, 0x7f, 1), + SOC_DOUBLE_R("Line Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL, @@ -278,12 +272,8 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACR1_2_HPROUT_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, 0x01, 0), - SOC_DOUBLE_R("HP Right PGA Bypass Playback Volume", PGAR_2_HPLOUT_VOL, + SOC_DOUBLE_R("HP PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL, 0, 0x7f, 1), - SOC_SINGLE("HPL PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, - 0, 0x7f, 1), - SOC_SINGLE("HPR PGA Bypass Playback Volume", PGAL_2_HPROUT_VOL, - 0, 0x7f, 1), SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, 0, 0x7f, 1), @@ -291,10 +281,8 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACR1_2_HPRCOM_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, 0x01, 0), - SOC_SINGLE("HPLCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, - 0, 0x7f, 1), - SOC_SINGLE("HPRCOM PGA Bypass Playback Volume", PGAL_2_HPRCOM_VOL, - 0, 0x7f, 1), + SOC_DOUBLE_R("HPCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, + PGAR_2_HPRCOM_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1), @@ -345,8 +333,7 @@ SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); /* Left DAC_L1 Mixer */ static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), @@ -354,8 +341,7 @@ static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { /* Right DAC_R1 Mixer */ static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0), @@ -364,18 +350,14 @@ static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { /* Left PGA Mixer */ static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = { SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1), - SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1), - SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1), }; /* Right PGA Mixer */ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1), - SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1), - SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1), SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1), }; @@ -397,42 +379,34 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); /* Left PGA Bypass Mixer */ static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HP Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), }; /* Right PGA Bypass Mixer */ static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HP Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), }; /* Left Line2 Bypass Mixer */ static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), }; /* Right Line2 Bypass Mixer */ static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("Line Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), }; static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { @@ -465,26 +439,22 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { /* Mono Output */ SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0), - /* Inputs to Left ADC */ + /* Left Inputs to Left ADC */ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0), SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, &aic3x_left_pga_mixer_controls[0], ARRAY_SIZE(aic3x_left_pga_mixer_controls)), SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line1_mux_controls), - SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0, - &aic3x_left_line1_mux_controls), SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line2_mux_controls), - /* Inputs to Right ADC */ + /* Right Inputs to Right ADC */ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", LINE1R_2_RADC_CTRL, 2, 0), SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, &aic3x_right_pga_mixer_controls[0], ARRAY_SIZE(aic3x_right_pga_mixer_controls)), - SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0, - &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, @@ -561,8 +531,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left DAC Mux", "DAC_L2", "Left DAC"}, {"Left DAC Mux", "DAC_L3", "Left DAC"}, - {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"}, - {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"}, + {"Left DAC_L1 Mixer", "Line Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"}, @@ -588,8 +557,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right DAC Mux", "DAC_R2", "Right DAC"}, {"Right DAC Mux", "DAC_R3", "Right DAC"}, - {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"}, - {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"}, + {"Right DAC_R1 Mixer", "Line Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"}, @@ -624,10 +592,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left Line2L Mux", "differential", "LINE2L"}, {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"}, - {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"}, {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, - {"Left PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Left ADC", NULL, "Left PGA Mixer"}, {"Left ADC", NULL, "GPIO1 dmic modclk"}, @@ -639,23 +605,18 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right Line2R Mux", "single-ended", "LINE2R"}, {"Right Line2R Mux", "differential", "LINE2R"}, - {"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"}, {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"}, {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"}, - {"Right PGA Mixer", "Mic3L Switch", "MIC3L"}, {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Right ADC", NULL, "Right PGA Mixer"}, {"Right ADC", NULL, "GPIO1 dmic modclk"}, /* Left PGA Bypass */ - {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HP Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HPCOM Switch", "Left PGA Mixer"}, {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"}, {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"}, @@ -666,13 +627,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left HP Out", NULL, "Left PGA Bypass Mixer"}, /* Right PGA Bypass */ - {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "Line Switch", "Right PGA Mixer"}, {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HP Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HPCOM Switch", "Right PGA Mixer"}, {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"}, {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"}, @@ -685,11 +643,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right HP Out", NULL, "Right PGA Bypass Mixer"}, /* Left Line2 Bypass */ - {"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"}, - {"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"}, + {"Left Line2 Bypass Mixer", "Line Switch", "Left Line2L Mux"}, {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"}, {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"}, - {"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"}, + {"Left Line2 Bypass Mixer", "HPCOM Switch", "Left Line2L Mux"}, {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"}, {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"}, @@ -700,11 +657,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left HP Out", NULL, "Left Line2 Bypass Mixer"}, /* Right Line2 Bypass */ - {"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"}, - {"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"}, + {"Right Line2 Bypass Mixer", "Line Switch", "Right Line2R Mux"}, {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"}, {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"}, - {"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"}, + {"Right Line2 Bypass Mixer", "HPCOM Switch", "Right Line2R Mux"}, {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"}, {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"}, @@ -738,8 +694,7 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec) } static int aic3x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1026,41 +981,14 @@ int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) } EXPORT_SYMBOL_GPL(aic3x_get_gpio); -void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, - int headset_debounce, int button_debounce) -{ - u8 val; - - val = ((detect & AIC3X_HEADSET_DETECT_MASK) - << AIC3X_HEADSET_DETECT_SHIFT) | - ((headset_debounce & AIC3X_HEADSET_DEBOUNCE_MASK) - << AIC3X_HEADSET_DEBOUNCE_SHIFT) | - ((button_debounce & AIC3X_BUTTON_DEBOUNCE_MASK) - << AIC3X_BUTTON_DEBOUNCE_SHIFT); - - if (detect & AIC3X_HEADSET_DETECT_MASK) - val |= AIC3X_HEADSET_DETECT_ENABLED; - - aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); -} -EXPORT_SYMBOL_GPL(aic3x_set_headset_detection); - int aic3x_headset_detected(struct snd_soc_codec *codec) { u8 val; - aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); - return (val >> 4) & 1; + aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val); + return (val >> 2) & 1; } EXPORT_SYMBOL_GPL(aic3x_headset_detected); -int aic3x_button_pressed(struct snd_soc_codec *codec) -{ - u8 val; - aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); - return (val >> 5) & 1; -} -EXPORT_SYMBOL_GPL(aic3x_button_pressed); - #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) @@ -1081,6 +1009,8 @@ struct snd_soc_dai aic3x_dai = { .formats = AIC3X_FORMATS,}, .ops = { .hw_params = aic3x_hw_params, + }, + .dai_ops = { .digital_mute = aic3x_mute, .set_sysclk = aic3x_set_dai_sysclk, .set_fmt = aic3x_set_dai_fmt, @@ -1222,7 +1152,7 @@ static int aic3x_init(struct snd_soc_device *socdev) aic3x_add_controls(codec); aic3x_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "aic3x: failed to register card\n"); goto card_err; @@ -1411,18 +1341,6 @@ struct snd_soc_codec_device soc_codec_dev_aic3x = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); -static int __devinit aic3x_modinit(void) -{ - return snd_soc_register_dai(&aic3x_dai); -} -module_init(aic3x_modinit); - -static void __exit aic3x_exit(void) -{ - snd_soc_unregister_dai(&aic3x_dai); -} -module_exit(aic3x_exit); - MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); MODULE_AUTHOR("Vladimir Barinov"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 73e35b6ec929..00a195aa02e4 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -39,9 +39,7 @@ #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 /* Audio codec digital filter control register */ #define AIC3X_CODEC_DFILT_CTRL 12 -/* Headset/button press detection register */ -#define AIC3X_HEADSET_DETECT_CTRL_A 13 -#define AIC3X_HEADSET_DETECT_CTRL_B 14 + /* ADC PGA Gain control registers */ #define LADC_VOL 15 #define RADC_VOL 16 @@ -50,9 +48,7 @@ #define MIC3LR_2_RADC_CTRL 18 /* Line1 Input control registers */ #define LINE1L_2_LADC_CTRL 19 -#define LINE1R_2_LADC_CTRL 21 #define LINE1R_2_RADC_CTRL 22 -#define LINE1L_2_RADC_CTRL 24 /* Line2 Input control registers */ #define LINE2L_2_LADC_CTRL 20 #define LINE2R_2_RADC_CTRL 23 @@ -83,8 +79,6 @@ #define LINE2L_2_HPLOUT_VOL 45 #define LINE2R_2_HPROUT_VOL 62 #define PGAL_2_HPLOUT_VOL 46 -#define PGAL_2_HPROUT_VOL 60 -#define PGAR_2_HPLOUT_VOL 49 #define PGAR_2_HPROUT_VOL 63 #define DACL1_2_HPLOUT_VOL 47 #define DACR1_2_HPROUT_VOL 64 @@ -94,8 +88,6 @@ #define LINE2L_2_HPLCOM_VOL 52 #define LINE2R_2_HPRCOM_VOL 69 #define PGAL_2_HPLCOM_VOL 53 -#define PGAR_2_HPLCOM_VOL 56 -#define PGAL_2_HPRCOM_VOL 67 #define PGAR_2_HPRCOM_VOL 70 #define DACL1_2_HPLCOM_VOL 54 #define DACR1_2_HPRCOM_VOL 71 @@ -111,17 +103,11 @@ #define MONOLOPM_CTRL 79 /* Line Output Plus/Minus control registers */ #define LINE2L_2_LLOPM_VOL 80 -#define LINE2L_2_RLOPM_VOL 87 -#define LINE2R_2_LLOPM_VOL 83 #define LINE2R_2_RLOPM_VOL 90 #define PGAL_2_LLOPM_VOL 81 -#define PGAL_2_RLOPM_VOL 88 -#define PGAR_2_LLOPM_VOL 84 #define PGAR_2_RLOPM_VOL 91 #define DACL1_2_LLOPM_VOL 82 -#define DACL1_2_RLOPM_VOL 89 #define DACR1_2_RLOPM_VOL 92 -#define DACR1_2_LLOPM_VOL 85 #define LLOPM_CTRL 86 #define RLOPM_CTRL 93 /* GPIO/IRQ registers */ @@ -235,49 +221,7 @@ enum { void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state); int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio); - -/* headset detection / button API */ - -/* The AIC3x supports detection of stereo headsets (GND + left + right signal) - * and cellular headsets (GND + speaker output + microphone input). - * It is recommended to enable MIC bias for this function to work properly. - * For more information, please refer to the datasheet. */ -enum { - AIC3X_HEADSET_DETECT_OFF = 0, - AIC3X_HEADSET_DETECT_STEREO = 1, - AIC3X_HEADSET_DETECT_CELLULAR = 2, - AIC3X_HEADSET_DETECT_BOTH = 3 -}; - -enum { - AIC3X_HEADSET_DEBOUNCE_16MS = 0, - AIC3X_HEADSET_DEBOUNCE_32MS = 1, - AIC3X_HEADSET_DEBOUNCE_64MS = 2, - AIC3X_HEADSET_DEBOUNCE_128MS = 3, - AIC3X_HEADSET_DEBOUNCE_256MS = 4, - AIC3X_HEADSET_DEBOUNCE_512MS = 5 -}; - -enum { - AIC3X_BUTTON_DEBOUNCE_0MS = 0, - AIC3X_BUTTON_DEBOUNCE_8MS = 1, - AIC3X_BUTTON_DEBOUNCE_16MS = 2, - AIC3X_BUTTON_DEBOUNCE_32MS = 3 -}; - -#define AIC3X_HEADSET_DETECT_ENABLED 0x80 -#define AIC3X_HEADSET_DETECT_SHIFT 5 -#define AIC3X_HEADSET_DETECT_MASK 3 -#define AIC3X_HEADSET_DEBOUNCE_SHIFT 2 -#define AIC3X_HEADSET_DEBOUNCE_MASK 7 -#define AIC3X_BUTTON_DEBOUNCE_SHIFT 0 -#define AIC3X_BUTTON_DEBOUNCE_MASK 3 - -/* see the enums above for valid parameters to this function */ -void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, - int headset_debounce, int button_debounce); int aic3x_headset_detected(struct snd_soc_codec *codec); -int aic3x_button_pressed(struct snd_soc_codec *codec); struct aic3x_setup_data { int i2c_bus; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c deleted file mode 100644 index 373daa486cea..000000000000 --- a/sound/soc/codecs/twl4030.c +++ /dev/null @@ -1,1292 +0,0 @@ -/* - * ALSA SoC TWL4030 codec driver - * - * Author: Steve Sakoman, <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/i2c.h> -#include <linux/platform_device.h> -#include <linux/i2c/twl4030.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/initval.h> -#include <sound/tlv.h> - -#include "twl4030.h" - -/* - * twl4030 register cache & default register settings - */ -static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { - 0x00, /* this register not used */ - 0x93, /* REG_CODEC_MODE (0x1) */ - 0xc3, /* REG_OPTION (0x2) */ - 0x00, /* REG_UNKNOWN (0x3) */ - 0x00, /* REG_MICBIAS_CTL (0x4) */ - 0x20, /* REG_ANAMICL (0x5) */ - 0x00, /* REG_ANAMICR (0x6) */ - 0x00, /* REG_AVADC_CTL (0x7) */ - 0x00, /* REG_ADCMICSEL (0x8) */ - 0x00, /* REG_DIGMIXING (0x9) */ - 0x0c, /* REG_ATXL1PGA (0xA) */ - 0x0c, /* REG_ATXR1PGA (0xB) */ - 0x00, /* REG_AVTXL2PGA (0xC) */ - 0x00, /* REG_AVTXR2PGA (0xD) */ - 0x01, /* REG_AUDIO_IF (0xE) */ - 0x00, /* REG_VOICE_IF (0xF) */ - 0x00, /* REG_ARXR1PGA (0x10) */ - 0x00, /* REG_ARXL1PGA (0x11) */ - 0x6c, /* REG_ARXR2PGA (0x12) */ - 0x6c, /* REG_ARXL2PGA (0x13) */ - 0x00, /* REG_VRXPGA (0x14) */ - 0x00, /* REG_VSTPGA (0x15) */ - 0x00, /* REG_VRX2ARXPGA (0x16) */ - 0x0c, /* REG_AVDAC_CTL (0x17) */ - 0x00, /* REG_ARX2VTXPGA (0x18) */ - 0x00, /* REG_ARXL1_APGA_CTL (0x19) */ - 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */ - 0x4b, /* REG_ARXL2_APGA_CTL (0x1B) */ - 0x4b, /* REG_ARXR2_APGA_CTL (0x1C) */ - 0x00, /* REG_ATX2ARXPGA (0x1D) */ - 0x00, /* REG_BT_IF (0x1E) */ - 0x00, /* REG_BTPGA (0x1F) */ - 0x00, /* REG_BTSTPGA (0x20) */ - 0x00, /* REG_EAR_CTL (0x21) */ - 0x24, /* REG_HS_SEL (0x22) */ - 0x0a, /* REG_HS_GAIN_SET (0x23) */ - 0x00, /* REG_HS_POPN_SET (0x24) */ - 0x00, /* REG_PREDL_CTL (0x25) */ - 0x00, /* REG_PREDR_CTL (0x26) */ - 0x00, /* REG_PRECKL_CTL (0x27) */ - 0x00, /* REG_PRECKR_CTL (0x28) */ - 0x00, /* REG_HFL_CTL (0x29) */ - 0x00, /* REG_HFR_CTL (0x2A) */ - 0x00, /* REG_ALC_CTL (0x2B) */ - 0x00, /* REG_ALC_SET1 (0x2C) */ - 0x00, /* REG_ALC_SET2 (0x2D) */ - 0x00, /* REG_BOOST_CTL (0x2E) */ - 0x00, /* REG_SOFTVOL_CTL (0x2F) */ - 0x00, /* REG_DTMF_FREQSEL (0x30) */ - 0x00, /* REG_DTMF_TONEXT1H (0x31) */ - 0x00, /* REG_DTMF_TONEXT1L (0x32) */ - 0x00, /* REG_DTMF_TONEXT2H (0x33) */ - 0x00, /* REG_DTMF_TONEXT2L (0x34) */ - 0x00, /* REG_DTMF_TONOFF (0x35) */ - 0x00, /* REG_DTMF_WANONOFF (0x36) */ - 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ - 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ - 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ - 0x16, /* REG_APLL_CTL (0x3A) */ - 0x00, /* REG_DTMF_CTL (0x3B) */ - 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */ - 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */ - 0x00, /* REG_MISC_SET_1 (0x3E) */ - 0x00, /* REG_PCMBTMUX (0x3F) */ - 0x00, /* not used (0x40) */ - 0x00, /* not used (0x41) */ - 0x00, /* not used (0x42) */ - 0x00, /* REG_RX_PATH_SEL (0x43) */ - 0x00, /* REG_VDL_APGA_CTL (0x44) */ - 0x00, /* REG_VIBRA_CTL (0x45) */ - 0x00, /* REG_VIBRA_SET (0x46) */ - 0x00, /* REG_VIBRA_PWM_SET (0x47) */ - 0x00, /* REG_ANAMIC_GAIN (0x48) */ - 0x00, /* REG_MISC_SET_2 (0x49) */ -}; - -/* - * read twl4030 register cache - */ -static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u8 *cache = codec->reg_cache; - - return cache[reg]; -} - -/* - * write twl4030 register cache - */ -static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec, - u8 reg, u8 value) -{ - u8 *cache = codec->reg_cache; - - if (reg >= TWL4030_CACHEREGNUM) - return; - cache[reg] = value; -} - -/* - * write to the twl4030 register space - */ -static int twl4030_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - twl4030_write_reg_cache(codec, reg, value); - return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); -} - -static void twl4030_clear_codecpdz(struct snd_soc_codec *codec) -{ - u8 mode; - - mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); - twl4030_write(codec, TWL4030_REG_CODEC_MODE, - mode & ~TWL4030_CODECPDZ); - - /* REVISIT: this delay is present in TI sample drivers */ - /* but there seems to be no TRM requirement for it */ - udelay(10); -} - -static void twl4030_set_codecpdz(struct snd_soc_codec *codec) -{ - u8 mode; - - mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); - twl4030_write(codec, TWL4030_REG_CODEC_MODE, - mode | TWL4030_CODECPDZ); - - /* REVISIT: this delay is present in TI sample drivers */ - /* but there seems to be no TRM requirement for it */ - udelay(10); -} - -static void twl4030_init_chip(struct snd_soc_codec *codec) -{ - int i; - - /* clear CODECPDZ prior to setting register defaults */ - twl4030_clear_codecpdz(codec); - - /* set all audio section registers to reasonable defaults */ - for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) - twl4030_write(codec, i, twl4030_reg[i]); - -} - -/* Earpiece */ -static const char *twl4030_earpiece_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", - "DACR1"}; - -static const struct soc_enum twl4030_earpiece_enum = - SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, - ARRAY_SIZE(twl4030_earpiece_texts), - twl4030_earpiece_texts); - -static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = -SOC_DAPM_ENUM("Route", twl4030_earpiece_enum); - -/* PreDrive Left */ -static const char *twl4030_predrivel_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", - "DACR2"}; - -static const struct soc_enum twl4030_predrivel_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, - ARRAY_SIZE(twl4030_predrivel_texts), - twl4030_predrivel_texts); - -static const struct snd_kcontrol_new twl4030_dapm_predrivel_control = -SOC_DAPM_ENUM("Route", twl4030_predrivel_enum); - -/* PreDrive Right */ -static const char *twl4030_predriver_texts[] = - {"Off", "DACR1", "DACR2", "Invalid", - "DACL2"}; - -static const struct soc_enum twl4030_predriver_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, - ARRAY_SIZE(twl4030_predriver_texts), - twl4030_predriver_texts); - -static const struct snd_kcontrol_new twl4030_dapm_predriver_control = -SOC_DAPM_ENUM("Route", twl4030_predriver_enum); - -/* Headset Left */ -static const char *twl4030_hsol_texts[] = - {"Off", "DACL1", "DACL2"}; - -static const struct soc_enum twl4030_hsol_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 1, - ARRAY_SIZE(twl4030_hsol_texts), - twl4030_hsol_texts); - -static const struct snd_kcontrol_new twl4030_dapm_hsol_control = -SOC_DAPM_ENUM("Route", twl4030_hsol_enum); - -/* Headset Right */ -static const char *twl4030_hsor_texts[] = - {"Off", "DACR1", "DACR2"}; - -static const struct soc_enum twl4030_hsor_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 4, - ARRAY_SIZE(twl4030_hsor_texts), - twl4030_hsor_texts); - -static const struct snd_kcontrol_new twl4030_dapm_hsor_control = -SOC_DAPM_ENUM("Route", twl4030_hsor_enum); - -/* Carkit Left */ -static const char *twl4030_carkitl_texts[] = - {"Off", "DACL1", "DACL2"}; - -static const struct soc_enum twl4030_carkitl_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PRECKL_CTL, 1, - ARRAY_SIZE(twl4030_carkitl_texts), - twl4030_carkitl_texts); - -static const struct snd_kcontrol_new twl4030_dapm_carkitl_control = -SOC_DAPM_ENUM("Route", twl4030_carkitl_enum); - -/* Carkit Right */ -static const char *twl4030_carkitr_texts[] = - {"Off", "DACR1", "DACR2"}; - -static const struct soc_enum twl4030_carkitr_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PRECKR_CTL, 1, - ARRAY_SIZE(twl4030_carkitr_texts), - twl4030_carkitr_texts); - -static const struct snd_kcontrol_new twl4030_dapm_carkitr_control = -SOC_DAPM_ENUM("Route", twl4030_carkitr_enum); - -/* Handsfree Left */ -static const char *twl4030_handsfreel_texts[] = - {"Voice", "DACL1", "DACL2", "DACR2"}; - -static const struct soc_enum twl4030_handsfreel_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0, - ARRAY_SIZE(twl4030_handsfreel_texts), - twl4030_handsfreel_texts); - -static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control = -SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum); - -/* Handsfree Right */ -static const char *twl4030_handsfreer_texts[] = - {"Voice", "DACR1", "DACR2", "DACL2"}; - -static const struct soc_enum twl4030_handsfreer_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0, - ARRAY_SIZE(twl4030_handsfreer_texts), - twl4030_handsfreer_texts); - -static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control = -SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); - -static int outmixer_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int ret = 0; - int val; - - switch (e->reg) { - case TWL4030_REG_PREDL_CTL: - case TWL4030_REG_PREDR_CTL: - case TWL4030_REG_EAR_CTL: - val = w->value >> e->shift_l; - if (val == 3) { - printk(KERN_WARNING - "Invalid MUX setting for register 0x%02x (%d)\n", - e->reg, val); - ret = -1; - } - break; - } - - return ret; -} - -/* - * Some of the gain controls in TWL (mostly those which are associated with - * the outputs) are implemented in an interesting way: - * 0x0 : Power down (mute) - * 0x1 : 6dB - * 0x2 : 0 dB - * 0x3 : -6 dB - * Inverting not going to help with these. - * Custom volsw and volsw_2r get/put functions to handle these gain bits. - */ -#define SOC_DOUBLE_TLV_TWL4030(xname, xreg, shift_left, shift_right, xmax,\ - xinvert, tlv_array) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_READWRITE,\ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw, \ - .get = snd_soc_get_volsw_twl4030, \ - .put = snd_soc_put_volsw_twl4030, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = xreg, .shift = shift_left, .rshift = shift_right,\ - .max = xmax, .invert = xinvert} } -#define SOC_DOUBLE_R_TLV_TWL4030(xname, reg_left, reg_right, xshift, xmax,\ - xinvert, tlv_array) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_READWRITE,\ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw_2r, \ - .get = snd_soc_get_volsw_r2_twl4030,\ - .put = snd_soc_put_volsw_r2_twl4030, \ - .private_value = (unsigned long)&(struct soc_mixer_control) \ - {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ - .rshift = xshift, .max = xmax, .invert = xinvert} } -#define SOC_SINGLE_TLV_TWL4030(xname, xreg, xshift, xmax, xinvert, tlv_array) \ - SOC_DOUBLE_TLV_TWL4030(xname, xreg, xshift, xshift, xmax, \ - xinvert, tlv_array) - -static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg = mc->reg; - unsigned int shift = mc->shift; - unsigned int rshift = mc->rshift; - int max = mc->max; - int mask = (1 << fls(max)) - 1; - - ucontrol->value.integer.value[0] = - (snd_soc_read(codec, reg) >> shift) & mask; - if (ucontrol->value.integer.value[0]) - ucontrol->value.integer.value[0] = - max + 1 - ucontrol->value.integer.value[0]; - - if (shift != rshift) { - ucontrol->value.integer.value[1] = - (snd_soc_read(codec, reg) >> rshift) & mask; - if (ucontrol->value.integer.value[1]) - ucontrol->value.integer.value[1] = - max + 1 - ucontrol->value.integer.value[1]; - } - - return 0; -} - -static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg = mc->reg; - unsigned int shift = mc->shift; - unsigned int rshift = mc->rshift; - int max = mc->max; - int mask = (1 << fls(max)) - 1; - unsigned short val, val2, val_mask; - - val = (ucontrol->value.integer.value[0] & mask); - - val_mask = mask << shift; - if (val) - val = max + 1 - val; - val = val << shift; - if (shift != rshift) { - val2 = (ucontrol->value.integer.value[1] & mask); - val_mask |= mask << rshift; - if (val2) - val2 = max + 1 - val2; - val |= val2 << rshift; - } - return snd_soc_update_bits(codec, reg, val_mask, val); -} - -static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - int max = mc->max; - int mask = (1<<fls(max))-1; - - ucontrol->value.integer.value[0] = - (snd_soc_read(codec, reg) >> shift) & mask; - ucontrol->value.integer.value[1] = - (snd_soc_read(codec, reg2) >> shift) & mask; - - if (ucontrol->value.integer.value[0]) - ucontrol->value.integer.value[0] = - max + 1 - ucontrol->value.integer.value[0]; - if (ucontrol->value.integer.value[1]) - ucontrol->value.integer.value[1] = - max + 1 - ucontrol->value.integer.value[1]; - - return 0; -} - -static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - int max = mc->max; - int mask = (1 << fls(max)) - 1; - int err; - unsigned short val, val2, val_mask; - - val_mask = mask << shift; - val = (ucontrol->value.integer.value[0] & mask); - val2 = (ucontrol->value.integer.value[1] & mask); - - if (val) - val = max + 1 - val; - if (val2) - val2 = max + 1 - val2; - - val = val << shift; - val2 = val2 << shift; - - err = snd_soc_update_bits(codec, reg, val_mask, val); - if (err < 0) - return err; - - err = snd_soc_update_bits(codec, reg2, val_mask, val2); - return err; -} - -static int twl4030_get_left_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); - int result = 0; - - /* one bit must be set a time */ - reg &= TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN - | TWL4030_MAINMIC_EN; - if (reg != 0) { - result++; - while ((reg & 1) == 0) { - result++; - reg >>= 1; - } - } - - ucontrol->value.integer.value[0] = result; - return 0; -} - -static int twl4030_put_left_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - int value = ucontrol->value.integer.value[0]; - u8 anamicl, micbias, avadc_ctl; - - anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); - anamicl &= ~(TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN - | TWL4030_MAINMIC_EN); - micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); - micbias &= ~(TWL4030_HSMICBIAS_EN | TWL4030_MICBIAS1_EN); - avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); - - switch (value) { - case 1: - anamicl |= TWL4030_MAINMIC_EN; - micbias |= TWL4030_MICBIAS1_EN; - break; - case 2: - anamicl |= TWL4030_HSMIC_EN; - micbias |= TWL4030_HSMICBIAS_EN; - break; - case 3: - anamicl |= TWL4030_AUXL_EN; - break; - case 4: - anamicl |= TWL4030_CKMIC_EN; - break; - default: - break; - } - - /* If some input is selected, enable amp and ADC */ - if (value != 0) { - anamicl |= TWL4030_MICAMPL_EN; - avadc_ctl |= TWL4030_ADCL_EN; - } else { - anamicl &= ~TWL4030_MICAMPL_EN; - avadc_ctl &= ~TWL4030_ADCL_EN; - } - - twl4030_write(codec, TWL4030_REG_ANAMICL, anamicl); - twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); - twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); - - return 1; -} - -static int twl4030_get_right_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); - int value = 0; - - reg &= TWL4030_SUBMIC_EN|TWL4030_AUXR_EN; - switch (reg) { - case TWL4030_SUBMIC_EN: - value = 1; - break; - case TWL4030_AUXR_EN: - value = 2; - break; - default: - break; - } - - ucontrol->value.integer.value[0] = value; - return 0; -} - -static int twl4030_put_right_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - int value = ucontrol->value.integer.value[0]; - u8 anamicr, micbias, avadc_ctl; - - anamicr = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); - anamicr &= ~(TWL4030_SUBMIC_EN|TWL4030_AUXR_EN); - micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); - micbias &= ~TWL4030_MICBIAS2_EN; - avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); - - switch (value) { - case 1: - anamicr |= TWL4030_SUBMIC_EN; - micbias |= TWL4030_MICBIAS2_EN; - break; - case 2: - anamicr |= TWL4030_AUXR_EN; - break; - default: - break; - } - - if (value != 0) { - anamicr |= TWL4030_MICAMPR_EN; - avadc_ctl |= TWL4030_ADCR_EN; - } else { - anamicr &= ~TWL4030_MICAMPR_EN; - avadc_ctl &= ~TWL4030_ADCR_EN; - } - - twl4030_write(codec, TWL4030_REG_ANAMICR, anamicr); - twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); - twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); - - return 1; -} - -static const char *twl4030_left_in_sel[] = { - "None", - "Main Mic", - "Headset Mic", - "Line In", - "Carkit Mic", -}; - -static const char *twl4030_right_in_sel[] = { - "None", - "Sub Mic", - "Line In", -}; - -static const struct soc_enum twl4030_left_input_mux = - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_left_in_sel), - twl4030_left_in_sel); - -static const struct soc_enum twl4030_right_input_mux = - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_right_in_sel), - twl4030_right_in_sel); - -/* - * FGAIN volume control: - * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) - */ -static DECLARE_TLV_DB_SCALE(digital_fine_tlv, -6300, 100, 1); - -/* - * CGAIN volume control: - * 0 dB to 12 dB in 6 dB steps - * value 2 and 3 means 12 dB - */ -static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0); - -/* - * Analog playback gain - * -24 dB to 12 dB in 2 dB steps - */ -static DECLARE_TLV_DB_SCALE(analog_tlv, -2400, 200, 0); - -/* - * Gain controls tied to outputs - * -6 dB to 6 dB in 6 dB steps (mute instead of -12) - */ -static DECLARE_TLV_DB_SCALE(output_tvl, -1200, 600, 1); - -/* - * Capture gain after the ADCs - * from 0 dB to 31 dB in 1 dB steps - */ -static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); - -/* - * Gain control for input amplifiers - * 0 dB to 30 dB in 6 dB steps - */ -static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); - -static const struct snd_kcontrol_new twl4030_snd_controls[] = { - /* Common playback gain controls */ - SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", - TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA, - 0, 0x3f, 0, digital_fine_tlv), - SOC_DOUBLE_R_TLV("DAC2 Digital Fine Playback Volume", - TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 0, 0x3f, 0, digital_fine_tlv), - - SOC_DOUBLE_R_TLV("DAC1 Digital Coarse Playback Volume", - TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA, - 6, 0x2, 0, digital_coarse_tlv), - SOC_DOUBLE_R_TLV("DAC2 Digital Coarse Playback Volume", - TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 6, 0x2, 0, digital_coarse_tlv), - - SOC_DOUBLE_R_TLV("DAC1 Analog Playback Volume", - TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL, - 3, 0x12, 1, analog_tlv), - SOC_DOUBLE_R_TLV("DAC2 Analog Playback Volume", - TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, - 3, 0x12, 1, analog_tlv), - SOC_DOUBLE_R("DAC1 Analog Playback Switch", - TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL, - 1, 1, 0), - SOC_DOUBLE_R("DAC2 Analog Playback Switch", - TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, - 1, 1, 0), - - /* Separate output gain controls */ - SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume", - TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL, - 4, 3, 0, output_tvl), - - SOC_DOUBLE_TLV_TWL4030("Headset Playback Volume", - TWL4030_REG_HS_GAIN_SET, 0, 2, 3, 0, output_tvl), - - SOC_DOUBLE_R_TLV_TWL4030("Carkit Playback Volume", - TWL4030_REG_PRECKL_CTL, TWL4030_REG_PRECKR_CTL, - 4, 3, 0, output_tvl), - - SOC_SINGLE_TLV_TWL4030("Earpiece Playback Volume", - TWL4030_REG_EAR_CTL, 4, 3, 0, output_tvl), - - /* Common capture gain controls */ - SOC_DOUBLE_R_TLV("Capture Volume", - TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, - 0, 0x1f, 0, digital_capture_tlv), - - SOC_DOUBLE_TLV("Input Boost Volume", TWL4030_REG_ANAMIC_GAIN, - 0, 3, 5, 0, input_gain_tlv), - - /* Input source controls */ - SOC_ENUM_EXT("Left Input Source", twl4030_left_input_mux, - twl4030_get_left_input, twl4030_put_left_input), - SOC_ENUM_EXT("Right Input Source", twl4030_right_input_mux, - twl4030_get_right_input, twl4030_put_right_input), -}; - -/* add non dapm controls */ -static int twl4030_add_controls(struct snd_soc_codec *codec) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(twl4030_snd_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&twl4030_snd_controls[i], - codec, NULL)); - if (err < 0) - return err; - } - - return 0; -} - -static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("INL"), - SND_SOC_DAPM_INPUT("INR"), - - SND_SOC_DAPM_OUTPUT("OUTL"), - SND_SOC_DAPM_OUTPUT("OUTR"), - SND_SOC_DAPM_OUTPUT("EARPIECE"), - SND_SOC_DAPM_OUTPUT("PREDRIVEL"), - SND_SOC_DAPM_OUTPUT("PREDRIVER"), - SND_SOC_DAPM_OUTPUT("HSOL"), - SND_SOC_DAPM_OUTPUT("HSOR"), - SND_SOC_DAPM_OUTPUT("HFL"), - SND_SOC_DAPM_OUTPUT("HFR"), - - /* DACs */ - SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", - TWL4030_REG_AVDAC_CTL, 0, 0), - SND_SOC_DAPM_DAC("DACL1", "Left Front Playback", - TWL4030_REG_AVDAC_CTL, 1, 0), - SND_SOC_DAPM_DAC("DACR2", "Right Rear Playback", - TWL4030_REG_AVDAC_CTL, 2, 0), - SND_SOC_DAPM_DAC("DACL2", "Left Rear Playback", - TWL4030_REG_AVDAC_CTL, 3, 0), - - /* Analog PGAs */ - SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL, - 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ARXL1_APGA", TWL4030_REG_ARXL1_APGA_CTL, - 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ARXR2_APGA", TWL4030_REG_ARXR2_APGA_CTL, - 0, 0, NULL, 0), - SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL, - 0, 0, NULL, 0), - - /* Output MUX controls */ - /* Earpiece */ - SND_SOC_DAPM_MUX_E("Earpiece Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_earpiece_control, outmixer_event, - SND_SOC_DAPM_PRE_REG), - /* PreDrivL/R */ - SND_SOC_DAPM_MUX_E("PredriveL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predrivel_control, outmixer_event, - SND_SOC_DAPM_PRE_REG), - SND_SOC_DAPM_MUX_E("PredriveR Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predriver_control, outmixer_event, - SND_SOC_DAPM_PRE_REG), - /* HeadsetL/R */ - SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_hsol_control), - SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_hsor_control), - /* CarkitL/R */ - SND_SOC_DAPM_MUX("CarkitL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_carkitl_control), - SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_carkitr_control), - /* HandsfreeL/R */ - SND_SOC_DAPM_MUX("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0, - &twl4030_dapm_handsfreel_control), - SND_SOC_DAPM_MUX("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0, - &twl4030_dapm_handsfreer_control), - - SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), -}; - -static const struct snd_soc_dapm_route intercon[] = { - {"ARXL1_APGA", NULL, "DACL1"}, - {"ARXR1_APGA", NULL, "DACR1"}, - {"ARXL2_APGA", NULL, "DACL2"}, - {"ARXR2_APGA", NULL, "DACR2"}, - - /* Internal playback routings */ - /* Earpiece */ - {"Earpiece Mux", "DACL1", "ARXL1_APGA"}, - {"Earpiece Mux", "DACL2", "ARXL2_APGA"}, - {"Earpiece Mux", "DACR1", "ARXR1_APGA"}, - /* PreDrivL */ - {"PredriveL Mux", "DACL1", "ARXL1_APGA"}, - {"PredriveL Mux", "DACL2", "ARXL2_APGA"}, - {"PredriveL Mux", "DACR2", "ARXR2_APGA"}, - /* PreDrivR */ - {"PredriveR Mux", "DACR1", "ARXR1_APGA"}, - {"PredriveR Mux", "DACR2", "ARXR2_APGA"}, - {"PredriveR Mux", "DACL2", "ARXL2_APGA"}, - /* HeadsetL */ - {"HeadsetL Mux", "DACL1", "ARXL1_APGA"}, - {"HeadsetL Mux", "DACL2", "ARXL2_APGA"}, - /* HeadsetR */ - {"HeadsetR Mux", "DACR1", "ARXR1_APGA"}, - {"HeadsetR Mux", "DACR2", "ARXR2_APGA"}, - /* CarkitL */ - {"CarkitL Mux", "DACL1", "ARXL1_APGA"}, - {"CarkitL Mux", "DACL2", "ARXL2_APGA"}, - /* CarkitR */ - {"CarkitR Mux", "DACR1", "ARXR1_APGA"}, - {"CarkitR Mux", "DACR2", "ARXR2_APGA"}, - /* HandsfreeL */ - {"HandsfreeL Mux", "DACL1", "ARXL1_APGA"}, - {"HandsfreeL Mux", "DACL2", "ARXL2_APGA"}, - {"HandsfreeL Mux", "DACR2", "ARXR2_APGA"}, - /* HandsfreeR */ - {"HandsfreeR Mux", "DACR1", "ARXR1_APGA"}, - {"HandsfreeR Mux", "DACR2", "ARXR2_APGA"}, - {"HandsfreeR Mux", "DACL2", "ARXL2_APGA"}, - - /* outputs */ - {"OUTL", NULL, "ARXL2_APGA"}, - {"OUTR", NULL, "ARXR2_APGA"}, - {"EARPIECE", NULL, "Earpiece Mux"}, - {"PREDRIVEL", NULL, "PredriveL Mux"}, - {"PREDRIVER", NULL, "PredriveR Mux"}, - {"HSOL", NULL, "HeadsetL Mux"}, - {"HSOR", NULL, "HeadsetR Mux"}, - {"CARKITL", NULL, "CarkitL Mux"}, - {"CARKITR", NULL, "CarkitR Mux"}, - {"HFL", NULL, "HandsfreeL Mux"}, - {"HFR", NULL, "HandsfreeR Mux"}, - - /* inputs */ - {"ADCL", NULL, "INL"}, - {"ADCR", NULL, "INR"}, -}; - -static int twl4030_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_dapm_new_controls(codec, twl4030_dapm_widgets, - ARRAY_SIZE(twl4030_dapm_widgets)); - - snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - - snd_soc_dapm_new_widgets(codec); - return 0; -} - -static void twl4030_power_up(struct snd_soc_codec *codec) -{ - u8 anamicl, regmisc1, byte, popn; - int i = 0; - - /* set CODECPDZ to turn on codec */ - twl4030_set_codecpdz(codec); - - /* initiate offset cancellation */ - anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); - twl4030_write(codec, TWL4030_REG_ANAMICL, - anamicl | TWL4030_CNCL_OFFSET_START); - - /* wait for offset cancellation to complete */ - do { - /* this takes a little while, so don't slam i2c */ - udelay(2000); - twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, - TWL4030_REG_ANAMICL); - } while ((i++ < 100) && - ((byte & TWL4030_CNCL_OFFSET_START) == - TWL4030_CNCL_OFFSET_START)); - - /* anti-pop when changing analog gain */ - regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); - twl4030_write(codec, TWL4030_REG_MISC_SET_1, - regmisc1 | TWL4030_SMOOTH_ANAVOL_EN); - - /* toggle CODECPDZ as per TRM */ - twl4030_clear_codecpdz(codec); - twl4030_set_codecpdz(codec); - - /* program anti-pop with bias ramp delay */ - popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); - popn &= TWL4030_RAMP_DELAY; - popn |= TWL4030_RAMP_DELAY_645MS; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - popn |= TWL4030_VMID_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - - /* enable anti-pop ramp */ - popn |= TWL4030_RAMP_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); -} - -static void twl4030_power_down(struct snd_soc_codec *codec) -{ - u8 popn; - - /* disable anti-pop ramp */ - popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); - popn &= ~TWL4030_RAMP_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - - /* disable bias out */ - popn &= ~TWL4030_VMID_EN; - twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - - /* power down */ - twl4030_clear_codecpdz(codec); -} - -static int twl4030_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - switch (level) { - case SND_SOC_BIAS_ON: - twl4030_power_up(codec); - break; - case SND_SOC_BIAS_PREPARE: - /* TODO: develop a twl4030_prepare function */ - break; - case SND_SOC_BIAS_STANDBY: - /* TODO: develop a twl4030_standby function */ - twl4030_power_down(codec); - break; - case SND_SOC_BIAS_OFF: - twl4030_power_down(codec); - break; - } - codec->bias_level = level; - - return 0; -} - -static int twl4030_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - u8 mode, old_mode, format, old_format; - - - /* bit rate */ - old_mode = twl4030_read_reg_cache(codec, - TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; - mode = old_mode & ~TWL4030_APLL_RATE; - - switch (params_rate(params)) { - case 8000: - mode |= TWL4030_APLL_RATE_8000; - break; - case 11025: - mode |= TWL4030_APLL_RATE_11025; - break; - case 12000: - mode |= TWL4030_APLL_RATE_12000; - break; - case 16000: - mode |= TWL4030_APLL_RATE_16000; - break; - case 22050: - mode |= TWL4030_APLL_RATE_22050; - break; - case 24000: - mode |= TWL4030_APLL_RATE_24000; - break; - case 32000: - mode |= TWL4030_APLL_RATE_32000; - break; - case 44100: - mode |= TWL4030_APLL_RATE_44100; - break; - case 48000: - mode |= TWL4030_APLL_RATE_48000; - break; - default: - printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n", - params_rate(params)); - return -EINVAL; - } - - if (mode != old_mode) { - /* change rate and set CODECPDZ */ - twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); - twl4030_set_codecpdz(codec); - } - - /* sample size */ - old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); - format = old_format; - format &= ~TWL4030_DATA_WIDTH; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - format |= TWL4030_DATA_WIDTH_16S_16W; - break; - case SNDRV_PCM_FORMAT_S24_LE: - format |= TWL4030_DATA_WIDTH_32S_24W; - break; - default: - printk(KERN_ERR "TWL4030 hw params: unknown format %d\n", - params_format(params)); - return -EINVAL; - } - - if (format != old_format) { - - /* clear CODECPDZ before changing format (codec requirement) */ - twl4030_clear_codecpdz(codec); - - /* change format */ - twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); - - /* set CODECPDZ afterwards */ - twl4030_set_codecpdz(codec); - } - return 0; -} - -static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u8 infreq; - - switch (freq) { - case 19200000: - infreq = TWL4030_APLL_INFREQ_19200KHZ; - break; - case 26000000: - infreq = TWL4030_APLL_INFREQ_26000KHZ; - break; - case 38400000: - infreq = TWL4030_APLL_INFREQ_38400KHZ; - break; - default: - printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n", - freq); - return -EINVAL; - } - - infreq |= TWL4030_APLL_EN; - twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq); - - return 0; -} - -static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u8 old_format, format; - - /* get format */ - old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); - format = old_format; - - /* set master/slave audio interface */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - format &= ~(TWL4030_AIF_SLAVE_EN); - format &= ~(TWL4030_CLK256FS_EN); - break; - case SND_SOC_DAIFMT_CBS_CFS: - format |= TWL4030_AIF_SLAVE_EN; - format |= TWL4030_CLK256FS_EN; - break; - default: - return -EINVAL; - } - - /* interface format */ - format &= ~TWL4030_AIF_FORMAT; - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - format |= TWL4030_AIF_FORMAT_CODEC; - break; - default: - return -EINVAL; - } - - if (format != old_format) { - - /* clear CODECPDZ before changing format (codec requirement) */ - twl4030_clear_codecpdz(codec); - - /* change format */ - twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); - - /* set CODECPDZ afterwards */ - twl4030_set_codecpdz(codec); - } - - return 0; -} - -#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) -#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) - -struct snd_soc_dai twl4030_dai = { - .name = "twl4030", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, - .rates = TWL4030_RATES, - .formats = TWL4030_FORMATS,}, - .capture = { - .stream_name = "Capture", - .channels_min = 2, - .channels_max = 2, - .rates = TWL4030_RATES, - .formats = TWL4030_FORMATS,}, - .ops = { - .hw_params = twl4030_hw_params, - .set_sysclk = twl4030_set_dai_sysclk, - .set_fmt = twl4030_set_dai_fmt, - } -}; -EXPORT_SYMBOL_GPL(twl4030_dai); - -static int twl4030_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int twl4030_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - twl4030_set_bias_level(codec, codec->suspend_bias_level); - return 0; -} - -/* - * initialize the driver - * register the mixer and dsp interfaces with the kernel - */ - -static int twl4030_init(struct snd_soc_device *socdev) -{ - struct snd_soc_codec *codec = socdev->codec; - int ret = 0; - - printk(KERN_INFO "TWL4030 Audio Codec init \n"); - - codec->name = "twl4030"; - codec->owner = THIS_MODULE; - codec->read = twl4030_read_reg_cache; - codec->write = twl4030_write; - codec->set_bias_level = twl4030_set_bias_level; - codec->dai = &twl4030_dai; - codec->num_dai = 1; - codec->reg_cache_size = sizeof(twl4030_reg); - codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), - GFP_KERNEL); - if (codec->reg_cache == NULL) - return -ENOMEM; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "twl4030: failed to create pcms\n"); - goto pcm_err; - } - - twl4030_init_chip(codec); - - /* power on device */ - twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - twl4030_add_controls(codec); - twl4030_add_widgets(codec); - - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "twl4030: failed to register card\n"); - goto card_err; - } - - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - return ret; -} - -static struct snd_soc_device *twl4030_socdev; - -static int twl4030_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - socdev->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - twl4030_socdev = socdev; - twl4030_init(socdev); - - return 0; -} - -static int twl4030_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - printk(KERN_INFO "TWL4030 Audio Codec remove\n"); - kfree(codec); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_twl4030 = { - .probe = twl4030_probe, - .remove = twl4030_remove, - .suspend = twl4030_suspend, - .resume = twl4030_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); - -static int __devinit twl4030_init(void) -{ - return snd_soc_register_dai(&twl4030_dai); -} -module_init(twl4030_init); - -static void __exit twl4030_exit(void) -{ - snd_soc_unregister_dai(&twl4030_dai); -} -module_exit(twl4030_exit); - -MODULE_DESCRIPTION("ASoC TWL4030 codec driver"); -MODULE_AUTHOR("Steve Sakoman"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h deleted file mode 100644 index a2065d417c2e..000000000000 --- a/sound/soc/codecs/twl4030.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * ALSA SoC TWL4030 codec driver - * - * Author: Steve Sakoman <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef __TWL4030_AUDIO_H__ -#define __TWL4030_AUDIO_H__ - -#define TWL4030_REG_CODEC_MODE 0x1 -#define TWL4030_REG_OPTION 0x2 -#define TWL4030_REG_UNKNOWN 0x3 -#define TWL4030_REG_MICBIAS_CTL 0x4 -#define TWL4030_REG_ANAMICL 0x5 -#define TWL4030_REG_ANAMICR 0x6 -#define TWL4030_REG_AVADC_CTL 0x7 -#define TWL4030_REG_ADCMICSEL 0x8 -#define TWL4030_REG_DIGMIXING 0x9 -#define TWL4030_REG_ATXL1PGA 0xA -#define TWL4030_REG_ATXR1PGA 0xB -#define TWL4030_REG_AVTXL2PGA 0xC -#define TWL4030_REG_AVTXR2PGA 0xD -#define TWL4030_REG_AUDIO_IF 0xE -#define TWL4030_REG_VOICE_IF 0xF -#define TWL4030_REG_ARXR1PGA 0x10 -#define TWL4030_REG_ARXL1PGA 0x11 -#define TWL4030_REG_ARXR2PGA 0x12 -#define TWL4030_REG_ARXL2PGA 0x13 -#define TWL4030_REG_VRXPGA 0x14 -#define TWL4030_REG_VSTPGA 0x15 -#define TWL4030_REG_VRX2ARXPGA 0x16 -#define TWL4030_REG_AVDAC_CTL 0x17 -#define TWL4030_REG_ARX2VTXPGA 0x18 -#define TWL4030_REG_ARXL1_APGA_CTL 0x19 -#define TWL4030_REG_ARXR1_APGA_CTL 0x1A -#define TWL4030_REG_ARXL2_APGA_CTL 0x1B -#define TWL4030_REG_ARXR2_APGA_CTL 0x1C -#define TWL4030_REG_ATX2ARXPGA 0x1D -#define TWL4030_REG_BT_IF 0x1E -#define TWL4030_REG_BTPGA 0x1F -#define TWL4030_REG_BTSTPGA 0x20 -#define TWL4030_REG_EAR_CTL 0x21 -#define TWL4030_REG_HS_SEL 0x22 -#define TWL4030_REG_HS_GAIN_SET 0x23 -#define TWL4030_REG_HS_POPN_SET 0x24 -#define TWL4030_REG_PREDL_CTL 0x25 -#define TWL4030_REG_PREDR_CTL 0x26 -#define TWL4030_REG_PRECKL_CTL 0x27 -#define TWL4030_REG_PRECKR_CTL 0x28 -#define TWL4030_REG_HFL_CTL 0x29 -#define TWL4030_REG_HFR_CTL 0x2A -#define TWL4030_REG_ALC_CTL 0x2B -#define TWL4030_REG_ALC_SET1 0x2C -#define TWL4030_REG_ALC_SET2 0x2D -#define TWL4030_REG_BOOST_CTL 0x2E -#define TWL4030_REG_SOFTVOL_CTL 0x2F -#define TWL4030_REG_DTMF_FREQSEL 0x30 -#define TWL4030_REG_DTMF_TONEXT1H 0x31 -#define TWL4030_REG_DTMF_TONEXT1L 0x32 -#define TWL4030_REG_DTMF_TONEXT2H 0x33 -#define TWL4030_REG_DTMF_TONEXT2L 0x34 -#define TWL4030_REG_DTMF_TONOFF 0x35 -#define TWL4030_REG_DTMF_WANONOFF 0x36 -#define TWL4030_REG_I2S_RX_SCRAMBLE_H 0x37 -#define TWL4030_REG_I2S_RX_SCRAMBLE_M 0x38 -#define TWL4030_REG_I2S_RX_SCRAMBLE_L 0x39 -#define TWL4030_REG_APLL_CTL 0x3A -#define TWL4030_REG_DTMF_CTL 0x3B -#define TWL4030_REG_DTMF_PGA_CTL2 0x3C -#define TWL4030_REG_DTMF_PGA_CTL1 0x3D -#define TWL4030_REG_MISC_SET_1 0x3E -#define TWL4030_REG_PCMBTMUX 0x3F -#define TWL4030_REG_RX_PATH_SEL 0x43 -#define TWL4030_REG_VDL_APGA_CTL 0x44 -#define TWL4030_REG_VIBRA_CTL 0x45 -#define TWL4030_REG_VIBRA_SET 0x46 -#define TWL4030_REG_VIBRA_PWM_SET 0x47 -#define TWL4030_REG_ANAMIC_GAIN 0x48 -#define TWL4030_REG_MISC_SET_2 0x49 - -#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1) - -/* Bitfield Definitions */ - -/* TWL4030_CODEC_MODE (0x01) Fields */ - -#define TWL4030_APLL_RATE 0xF0 -#define TWL4030_APLL_RATE_8000 0x00 -#define TWL4030_APLL_RATE_11025 0x10 -#define TWL4030_APLL_RATE_12000 0x20 -#define TWL4030_APLL_RATE_16000 0x40 -#define TWL4030_APLL_RATE_22050 0x50 -#define TWL4030_APLL_RATE_24000 0x60 -#define TWL4030_APLL_RATE_32000 0x80 -#define TWL4030_APLL_RATE_44100 0x90 -#define TWL4030_APLL_RATE_48000 0xA0 -#define TWL4030_SEL_16K 0x04 -#define TWL4030_CODECPDZ 0x02 -#define TWL4030_OPT_MODE 0x01 - -/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */ - -#define TWL4030_MICBIAS2_CTL 0x40 -#define TWL4030_MICBIAS1_CTL 0x20 -#define TWL4030_HSMICBIAS_EN 0x04 -#define TWL4030_MICBIAS2_EN 0x02 -#define TWL4030_MICBIAS1_EN 0x01 - -/* ANAMICL (0x05) Fields */ - -#define TWL4030_CNCL_OFFSET_START 0x80 -#define TWL4030_OFFSET_CNCL_SEL 0x60 -#define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00 -#define TWL4030_OFFSET_CNCL_SEL_ARX2 0x20 -#define TWL4030_OFFSET_CNCL_SEL_VRX 0x40 -#define TWL4030_OFFSET_CNCL_SEL_ALL 0x60 -#define TWL4030_MICAMPL_EN 0x10 -#define TWL4030_CKMIC_EN 0x08 -#define TWL4030_AUXL_EN 0x04 -#define TWL4030_HSMIC_EN 0x02 -#define TWL4030_MAINMIC_EN 0x01 - -/* ANAMICR (0x06) Fields */ - -#define TWL4030_MICAMPR_EN 0x10 -#define TWL4030_AUXR_EN 0x04 -#define TWL4030_SUBMIC_EN 0x01 - -/* AVADC_CTL (0x07) Fields */ - -#define TWL4030_ADCL_EN 0x08 -#define TWL4030_AVADC_CLK_PRIORITY 0x04 -#define TWL4030_ADCR_EN 0x02 - -/* AUDIO_IF (0x0E) Fields */ - -#define TWL4030_AIF_SLAVE_EN 0x80 -#define TWL4030_DATA_WIDTH 0x60 -#define TWL4030_DATA_WIDTH_16S_16W 0x00 -#define TWL4030_DATA_WIDTH_32S_16W 0x40 -#define TWL4030_DATA_WIDTH_32S_24W 0x60 -#define TWL4030_AIF_FORMAT 0x18 -#define TWL4030_AIF_FORMAT_CODEC 0x00 -#define TWL4030_AIF_FORMAT_LEFT 0x08 -#define TWL4030_AIF_FORMAT_RIGHT 0x10 -#define TWL4030_AIF_FORMAT_TDM 0x18 -#define TWL4030_AIF_TRI_EN 0x04 -#define TWL4030_CLK256FS_EN 0x02 -#define TWL4030_AIF_EN 0x01 - -/* HS_GAIN_SET (0x23) Fields */ - -#define TWL4030_HSR_GAIN 0x0C -#define TWL4030_HSR_GAIN_PWR_DOWN 0x00 -#define TWL4030_HSR_GAIN_PLUS_6DB 0x04 -#define TWL4030_HSR_GAIN_0DB 0x08 -#define TWL4030_HSR_GAIN_MINUS_6DB 0x0C -#define TWL4030_HSL_GAIN 0x03 -#define TWL4030_HSL_GAIN_PWR_DOWN 0x00 -#define TWL4030_HSL_GAIN_PLUS_6DB 0x01 -#define TWL4030_HSL_GAIN_0DB 0x02 -#define TWL4030_HSL_GAIN_MINUS_6DB 0x03 - -/* HS_POPN_SET (0x24) Fields */ - -#define TWL4030_VMID_EN 0x40 -#define TWL4030_EXTMUTE 0x20 -#define TWL4030_RAMP_DELAY 0x1C -#define TWL4030_RAMP_DELAY_20MS 0x00 -#define TWL4030_RAMP_DELAY_40MS 0x04 -#define TWL4030_RAMP_DELAY_81MS 0x08 -#define TWL4030_RAMP_DELAY_161MS 0x0C -#define TWL4030_RAMP_DELAY_323MS 0x10 -#define TWL4030_RAMP_DELAY_645MS 0x14 -#define TWL4030_RAMP_DELAY_1291MS 0x18 -#define TWL4030_RAMP_DELAY_2581MS 0x1C -#define TWL4030_RAMP_EN 0x02 - -/* APLL_CTL (0x3A) Fields */ - -#define TWL4030_APLL_EN 0x10 -#define TWL4030_APLL_INFREQ 0x0F -#define TWL4030_APLL_INFREQ_19200KHZ 0x05 -#define TWL4030_APLL_INFREQ_26000KHZ 0x06 -#define TWL4030_APLL_INFREQ_38400KHZ 0x0F - -/* REG_MISC_SET_1 (0x3E) Fields */ - -#define TWL4030_CLK64_EN 0x80 -#define TWL4030_SCRAMBLE_EN 0x40 -#define TWL4030_FMLOOP_EN 0x20 -#define TWL4030_SMOOTH_ANAVOL_EN 0x02 -#define TWL4030_DIGMIC_LR_SWAP_EN 0x01 - -extern struct snd_soc_dai twl4030_dai; -extern struct snd_soc_codec_device soc_codec_dev_twl4030; - -#endif /* End of __TWL4030_AUDIO_H__ */ diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c deleted file mode 100644 index 8e035b5d733f..000000000000 --- a/sound/soc/codecs/uda134x.c +++ /dev/null @@ -1,668 +0,0 @@ -/* - * uda134x.c -- UDA134X ALSA SoC Codec driver - * - * Modifications by Christian Pellegrin <chripell@evolware.org> - * - * Copyright 2007 Dension Audio Systems Ltd. - * Author: Zoltan Devai - * - * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/initval.h> - -#include <sound/uda134x.h> -#include <sound/l3.h> - -#include "uda134x.h" - - -#define POWER_OFF_ON_STANDBY 1 -/* - ALSA SOC usually puts the device in standby mode when it's not used - for sometime. If you define POWER_OFF_ON_STANDBY the driver will - turn off the ADC/DAC when this callback is invoked and turn it back - on when needed. Unfortunately this will result in a very light bump - (it can be audible only with good earphones). If this bothers you - just comment this line, you will have slightly higher power - consumption . Please note that sending the L3 command for ADC is - enough to make the bump, so it doesn't make difference if you - completely take off power from the codec. - */ - -#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000 -#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) - -struct uda134x_priv { - int sysclk; - int dai_fmt; - - struct snd_pcm_substream *master_substream; - struct snd_pcm_substream *slave_substream; -}; - -/* In-data addresses are hard-coded into the reg-cache values */ -static const char uda134x_reg[UDA134X_REGS_NUM] = { - /* Extended address registers */ - 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Status, data regs */ - 0x00, 0x83, 0x00, 0x40, 0x80, 0x00, -}; - -/* - * The codec has no support for reading its registers except for peak level... - */ -static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u8 *cache = codec->reg_cache; - - if (reg >= UDA134X_REGS_NUM) - return -1; - return cache[reg]; -} - -/* - * Write the register cache - */ -static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec, - u8 reg, unsigned int value) -{ - u8 *cache = codec->reg_cache; - - if (reg >= UDA134X_REGS_NUM) - return; - cache[reg] = value; -} - -/* - * Write to the uda134x registers - * - */ -static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - int ret; - u8 addr; - u8 data = value; - struct uda134x_platform_data *pd = codec->control_data; - - pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value); - - if (reg >= UDA134X_REGS_NUM) { - printk(KERN_ERR "%s unkown register: reg: %d", - __func__, reg); - return -EINVAL; - } - - uda134x_write_reg_cache(codec, reg, value); - - switch (reg) { - case UDA134X_STATUS0: - case UDA134X_STATUS1: - addr = UDA134X_STATUS_ADDR; - break; - case UDA134X_DATA000: - case UDA134X_DATA001: - case UDA134X_DATA010: - addr = UDA134X_DATA0_ADDR; - break; - case UDA134X_DATA1: - addr = UDA134X_DATA1_ADDR; - break; - default: - /* It's an extended address register */ - addr = (reg | UDA134X_EXTADDR_PREFIX); - - ret = l3_write(&pd->l3, - UDA134X_DATA0_ADDR, &addr, 1); - if (ret != 1) - return -EIO; - - addr = UDA134X_DATA0_ADDR; - data = (value | UDA134X_EXTDATA_PREFIX); - break; - } - - ret = l3_write(&pd->l3, - addr, &data, 1); - if (ret != 1) - return -EIO; - - return 0; -} - -static inline void uda134x_reset(struct snd_soc_codec *codec) -{ - u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0); - uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6)); - msleep(1); - uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6)); -} - -static int uda134x_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010); - - pr_debug("%s mute: %d\n", __func__, mute); - - if (mute) - mute_reg |= (1<<2); - else - mute_reg &= ~(1<<2); - - uda134x_write(codec, UDA134X_DATA010, mute_reg & ~(1<<2)); - - return 0; -} - -static int uda134x_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - struct uda134x_priv *uda134x = codec->private_data; - struct snd_pcm_runtime *master_runtime; - - if (uda134x->master_substream) { - master_runtime = uda134x->master_substream->runtime; - - pr_debug("%s constraining to %d bits at %d\n", __func__, - master_runtime->sample_bits, - master_runtime->rate); - - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_RATE, - master_runtime->rate, - master_runtime->rate); - - snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS, - master_runtime->sample_bits, - master_runtime->sample_bits); - - uda134x->slave_substream = substream; - } else - uda134x->master_substream = substream; - - return 0; -} - -static void uda134x_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - struct uda134x_priv *uda134x = codec->private_data; - - if (uda134x->master_substream == substream) - uda134x->master_substream = uda134x->slave_substream; - - uda134x->slave_substream = NULL; -} - -static int uda134x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - struct uda134x_priv *uda134x = codec->private_data; - u8 hw_params; - - if (substream == uda134x->slave_substream) { - pr_debug("%s ignoring hw_params for slave substream\n", - __func__); - return 0; - } - - hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0); - hw_params &= STATUS0_SYSCLK_MASK; - hw_params &= STATUS0_DAIFMT_MASK; - - pr_debug("%s sysclk: %d, rate:%d\n", __func__, - uda134x->sysclk, params_rate(params)); - - /* set SYSCLK / fs ratio */ - switch (uda134x->sysclk / params_rate(params)) { - case 512: - break; - case 384: - hw_params |= (1<<4); - break; - case 256: - hw_params |= (1<<5); - break; - default: - printk(KERN_ERR "%s unsupported fs\n", __func__); - return -EINVAL; - } - - pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__, - uda134x->dai_fmt, params_format(params)); - - /* set DAI format and word length */ - switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - break; - case SND_SOC_DAIFMT_RIGHT_J: - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - hw_params |= (1<<1); - break; - case SNDRV_PCM_FORMAT_S18_3LE: - hw_params |= (1<<2); - break; - case SNDRV_PCM_FORMAT_S20_3LE: - hw_params |= ((1<<2) | (1<<1)); - break; - default: - printk(KERN_ERR "%s unsupported format (right)\n", - __func__); - return -EINVAL; - } - break; - case SND_SOC_DAIFMT_LEFT_J: - hw_params |= (1<<3); - break; - default: - printk(KERN_ERR "%s unsupported format\n", __func__); - return -EINVAL; - } - - uda134x_write(codec, UDA134X_STATUS0, hw_params); - - return 0; -} - -static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct uda134x_priv *uda134x = codec->private_data; - - pr_debug("%s clk_id: %d, freq: %d, dir: %d\n", __func__, - clk_id, freq, dir); - - /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable - because the codec is slave. Of course limitations of the clock - master (the IIS controller) apply. - We'll error out on set_hw_params if it's not OK */ - if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { - uda134x->sysclk = freq; - return 0; - } - - printk(KERN_ERR "%s unsupported sysclk\n", __func__); - return -EINVAL; -} - -static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct uda134x_priv *uda134x = codec->private_data; - - pr_debug("%s fmt: %08X\n", __func__, fmt); - - /* codec supports only full slave mode */ - if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { - printk(KERN_ERR "%s unsupported slave mode\n", __func__); - return -EINVAL; - } - - /* no support for clock inversion */ - if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) { - printk(KERN_ERR "%s unsupported clock inversion\n", __func__); - return -EINVAL; - } - - /* We can't setup DAI format here as it depends on the word bit num */ - /* so let's just store the value for later */ - uda134x->dai_fmt = fmt; - - return 0; -} - -static int uda134x_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - u8 reg; - struct uda134x_platform_data *pd = codec->control_data; - int i; - u8 *cache = codec->reg_cache; - - pr_debug("%s bias level %d\n", __func__, level); - - switch (level) { - case SND_SOC_BIAS_ON: - /* ADC, DAC on */ - reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); - uda134x_write(codec, UDA134X_STATUS1, reg | 0x03); - break; - case SND_SOC_BIAS_PREPARE: - /* power on */ - if (pd->power) { - pd->power(1); - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++) - codec->write(codec, i, *cache++); - } - break; - case SND_SOC_BIAS_STANDBY: - /* ADC, DAC power off */ - reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); - uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03)); - break; - case SND_SOC_BIAS_OFF: - /* power off */ - if (pd->power) - pd->power(0); - break; - } - codec->bias_level = level; - return 0; -} - -static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1", - "Minimum2", "Maximum"}; -static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; -static const char *uda134x_mixmode[] = {"Differential", "Analog1", - "Analog2", "Both"}; - -static const struct soc_enum uda134x_mixer_enum[] = { -SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting), -SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph), -SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode), -}; - -static const struct snd_kcontrol_new uda1341_snd_controls[] = { -SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), -SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0), -SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1), -SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1), - -SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0), -SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0), - -SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), -SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), - -SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), -SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), -SOC_ENUM("Input Mux", uda134x_mixer_enum[2]), - -SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0), -SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1), -SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0), - -SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0), -SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0), -SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0), -SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0), -SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0), -SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), -}; - -static const struct snd_kcontrol_new uda1340_snd_controls[] = { -SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), - -SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), -SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), - -SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), -SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), - -SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), -}; - -static int uda134x_add_controls(struct snd_soc_codec *codec) -{ - int err, i, n; - const struct snd_kcontrol_new *ctrls; - struct uda134x_platform_data *pd = codec->control_data; - - switch (pd->model) { - case UDA134X_UDA1340: - case UDA134X_UDA1344: - n = ARRAY_SIZE(uda1340_snd_controls); - ctrls = uda1340_snd_controls; - break; - case UDA134X_UDA1341: - n = ARRAY_SIZE(uda1341_snd_controls); - ctrls = uda1341_snd_controls; - break; - default: - printk(KERN_ERR "%s unkown codec type: %d", - __func__, pd->model); - return -EINVAL; - } - - for (i = 0; i < n; i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&ctrls[i], - codec, NULL)); - if (err < 0) - return err; - } - - return 0; -} - -struct snd_soc_dai uda134x_dai = { - .name = "UDA134X", - /* playback capabilities */ - .playback = { - .stream_name = "Playback", - .channels_min = 1, - .channels_max = 2, - .rates = UDA134X_RATES, - .formats = UDA134X_FORMATS, - }, - /* capture capabilities */ - .capture = { - .stream_name = "Capture", - .channels_min = 1, - .channels_max = 2, - .rates = UDA134X_RATES, - .formats = UDA134X_FORMATS, - }, - /* pcm operations */ - .ops = { - .startup = uda134x_startup, - .shutdown = uda134x_shutdown, - .hw_params = uda134x_hw_params, - .digital_mute = uda134x_mute, - .set_sysclk = uda134x_set_dai_sysclk, - .set_fmt = uda134x_set_dai_fmt, - } -}; -EXPORT_SYMBOL(uda134x_dai); - - -static int uda134x_soc_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec; - struct uda134x_priv *uda134x; - void *codec_setup_data = socdev->codec_data; - int ret = -ENOMEM; - struct uda134x_platform_data *pd; - - printk(KERN_INFO "UDA134X SoC Audio Codec\n"); - - if (!codec_setup_data) { - printk(KERN_ERR "UDA134X SoC codec: " - "missing L3 bitbang function\n"); - return -ENODEV; - } - - pd = codec_setup_data; - switch (pd->model) { - case UDA134X_UDA1340: - case UDA134X_UDA1341: - case UDA134X_UDA1344: - break; - default: - printk(KERN_ERR "UDA134X SoC codec: " - "unsupported model %d\n", - pd->model); - return -EINVAL; - } - - socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (socdev->codec == NULL) - return ret; - - codec = socdev->codec; - - uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL); - if (uda134x == NULL) - goto priv_err; - codec->private_data = uda134x; - - codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg), - GFP_KERNEL); - if (codec->reg_cache == NULL) - goto reg_err; - - mutex_init(&codec->mutex); - - codec->reg_cache_size = sizeof(uda134x_reg); - codec->reg_cache_step = 1; - - codec->name = "UDA134X"; - codec->owner = THIS_MODULE; - codec->dai = &uda134x_dai; - codec->num_dai = 1; - codec->read = uda134x_read_reg_cache; - codec->write = uda134x_write; -#ifdef POWER_OFF_ON_STANDBY - codec->set_bias_level = uda134x_set_bias_level; -#endif - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - codec->control_data = codec_setup_data; - - if (pd->power) - pd->power(1); - - uda134x_reset(codec); - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "UDA134X: failed to register pcms\n"); - goto pcm_err; - } - - ret = uda134x_add_controls(codec); - if (ret < 0) { - printk(KERN_ERR "UDA134X: failed to register controls\n"); - goto pcm_err; - } - - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "UDA134X: failed to register card\n"); - goto card_err; - } - - return 0; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); -reg_err: - kfree(codec->private_data); -priv_err: - kfree(codec); - return ret; -} - -/* power down chip */ -static int uda134x_soc_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - - kfree(codec->private_data); - kfree(codec->reg_cache); - kfree(codec); - - return 0; -} - -#if defined(CONFIG_PM) -static int uda134x_soc_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int uda134x_soc_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); - return 0; -} -#else -#define uda134x_soc_suspend NULL -#define uda134x_soc_resume NULL -#endif /* CONFIG_PM */ - -struct snd_soc_codec_device soc_codec_dev_uda134x = { - .probe = uda134x_soc_probe, - .remove = uda134x_soc_remove, - .suspend = uda134x_soc_suspend, - .resume = uda134x_soc_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x); - -static int __devinit uda134x_init(void) -{ - return snd_soc_register_dai(&uda134x_dai); -} -module_init(uda134x_init); - -static void __exit uda134x_exit(void) -{ - snd_soc_unregister_dai(&uda134x_dai); -} -module_exit(uda134x_exit); - -MODULE_DESCRIPTION("UDA134X ALSA soc codec driver"); -MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h deleted file mode 100644 index 94f440490b31..000000000000 --- a/sound/soc/codecs/uda134x.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _UDA134X_CODEC_H -#define _UDA134X_CODEC_H - -#define UDA134X_L3ADDR 5 -#define UDA134X_DATA0_ADDR ((UDA134X_L3ADDR << 2) | 0) -#define UDA134X_DATA1_ADDR ((UDA134X_L3ADDR << 2) | 1) -#define UDA134X_STATUS_ADDR ((UDA134X_L3ADDR << 2) | 2) - -#define UDA134X_EXTADDR_PREFIX 0xC0 -#define UDA134X_EXTDATA_PREFIX 0xE0 - -/* UDA134X registers */ -#define UDA134X_EA000 0 -#define UDA134X_EA001 1 -#define UDA134X_EA010 2 -#define UDA134X_EA011 3 -#define UDA134X_EA100 4 -#define UDA134X_EA101 5 -#define UDA134X_EA110 6 -#define UDA134X_EA111 7 -#define UDA134X_STATUS0 8 -#define UDA134X_STATUS1 9 -#define UDA134X_DATA000 10 -#define UDA134X_DATA001 11 -#define UDA134X_DATA010 12 -#define UDA134X_DATA1 13 - -#define UDA134X_REGS_NUM 14 - -#define STATUS0_DAIFMT_MASK (~(7<<1)) -#define STATUS0_SYSCLK_MASK (~(3<<4)) - -extern struct snd_soc_dai uda134x_dai; -extern struct snd_soc_codec_device soc_codec_dev_uda134x; - -#endif diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 55a99b6a68a1..a69ee72a7af5 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -407,8 +407,7 @@ static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, * when the DAI is being clocked by the CPU DAI. It's up to the * machine and cpu DAI driver to do this before we are called. */ -static int uda1380_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -440,8 +439,7 @@ static int uda1380_pcm_prepare(struct snd_pcm_substream *substream, } static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -479,8 +477,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -563,6 +560,8 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, + }, + .dai_ops = { .digital_mute = uda1380_mute, .set_fmt = uda1380_set_dai_fmt, }, @@ -580,6 +579,8 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, + }, + .dai_ops = { .digital_mute = uda1380_mute, .set_fmt = uda1380_set_dai_fmt, }, @@ -597,6 +598,8 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, + }, + .dai_ops = { .set_fmt = uda1380_set_dai_fmt, }, }, @@ -677,7 +680,7 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) /* uda1380 init */ uda1380_add_controls(codec); uda1380_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { pr_err("uda1380: failed to register card\n"); goto card_err; @@ -841,18 +844,6 @@ struct snd_soc_codec_device soc_codec_dev_uda1380 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); -static int __devinit uda1380_modinit(void) -{ - return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); -} -module_init(uda1380_modinit); - -static void __exit uda1380_exit(void) -{ - snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); -} -module_exit(uda1380_exit); - MODULE_AUTHOR("Giorgio Padrin"); MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index a2af04bb4e9f..d8ca2da8d634 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -463,8 +463,7 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -586,6 +585,8 @@ struct snd_soc_dai wm8510_dai = { .formats = WM8510_FORMATS,}, .ops = { .hw_params = wm8510_pcm_hw_params, + }, + .dai_ops = { .digital_mute = wm8510_mute, .set_fmt = wm8510_set_dai_fmt, .set_clkdiv = wm8510_set_dai_clkdiv, @@ -658,7 +659,7 @@ static int wm8510_init(struct snd_soc_device *socdev) wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8510_add_controls(codec); wm8510_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8510: failed to register card\n"); goto card_err; @@ -889,18 +890,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8510 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); -static int __devinit wm8510_modinit(void) -{ - return snd_soc_register_dai(&wm8510_dai); -} -module_init(wm8510_modinit); - -static void __exit wm8510_exit(void) -{ - snd_soc_unregister_dai(&wm8510_dai); -} -module_exit(wm8510_exit); - MODULE_DESCRIPTION("ASoC WM8510 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 391ec2978aed..627ebfb4209b 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -548,13 +548,13 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *dai = rtd->dai; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id); + u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->codec_dai->id); paifb &= ~WM8580_AIF_LENGTH_MASK; /* bit size */ @@ -574,7 +574,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - wm8580_write(codec, WM8580_PAIF3 + dai->id, paifb); + wm8580_write(codec, WM8580_PAIF3 + dai->codec_dai->id, paifb); return 0; } @@ -798,6 +798,8 @@ struct snd_soc_dai wm8580_dai[] = { }, .ops = { .hw_params = wm8580_paif_hw_params, + }, + .dai_ops = { .set_fmt = wm8580_set_paif_dai_fmt, .set_clkdiv = wm8580_set_dai_clkdiv, .set_pll = wm8580_set_dai_pll, @@ -816,6 +818,8 @@ struct snd_soc_dai wm8580_dai[] = { }, .ops = { .hw_params = wm8580_paif_hw_params, + }, + .dai_ops = { .set_fmt = wm8580_set_paif_dai_fmt, .set_clkdiv = wm8580_set_dai_clkdiv, .set_pll = wm8580_set_dai_pll, @@ -869,7 +873,7 @@ static int wm8580_init(struct snd_soc_device *socdev) wm8580_add_controls(codec); wm8580_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8580: failed to register card\n"); goto card_err; @@ -896,85 +900,85 @@ static struct snd_soc_device *wm8580_socdev; * low = 0x1a * high = 0x1b */ +static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; + +/* Magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; -static int wm8580_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static struct i2c_driver wm8580_i2c_driver; +static struct i2c_client client_template; + +static int wm8580_codec_probe(struct i2c_adapter *adap, int addr, int kind) { struct snd_soc_device *socdev = wm8580_socdev; + struct wm8580_setup_data *setup = socdev->codec_data; struct snd_soc_codec *codec = socdev->codec; + struct i2c_client *i2c; int ret; + if (addr != setup->i2c_address) + return -ENODEV; + + client_template.adapter = adap; + client_template.addr = addr; + + i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); + if (i2c == NULL) { + kfree(codec); + return -ENOMEM; + } i2c_set_clientdata(i2c, codec); codec->control_data = i2c; + ret = i2c_attach_client(i2c); + if (ret < 0) { + dev_err(&i2c->dev, "failed to attach codec at addr %x\n", addr); + goto err; + } + ret = wm8580_init(socdev); - if (ret < 0) + if (ret < 0) { dev_err(&i2c->dev, "failed to initialise WM8580\n"); + goto err; + } + + return ret; + +err: + kfree(codec); + kfree(i2c); return ret; } -static int wm8580_i2c_remove(struct i2c_client *client) +static int wm8580_i2c_detach(struct i2c_client *client) { struct snd_soc_codec *codec = i2c_get_clientdata(client); + i2c_detach_client(client); kfree(codec->reg_cache); + kfree(client); return 0; } -static const struct i2c_device_id wm8580_i2c_id[] = { - { "wm8580", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); +static int wm8580_i2c_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, wm8580_codec_probe); +} +/* corgi i2c codec control layer */ static struct i2c_driver wm8580_i2c_driver = { .driver = { .name = "WM8580 I2C Codec", .owner = THIS_MODULE, }, - .probe = wm8580_i2c_probe, - .remove = wm8580_i2c_remove, - .id_table = wm8580_i2c_id, + .attach_adapter = wm8580_i2c_attach, + .detach_client = wm8580_i2c_detach, + .command = NULL, }; -static int wm8580_add_i2c_device(struct platform_device *pdev, - const struct wm8580_setup_data *setup) -{ - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; - int ret; - - ret = i2c_add_driver(&wm8580_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = setup->i2c_address; - strlcpy(info.type, "wm8580", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "can't get i2c adapter %d\n", - setup->i2c_bus); - goto err_driver; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - goto err_driver; - } - - return 0; - -err_driver: - i2c_del_driver(&wm8580_i2c_driver); - return -ENODEV; -} +static struct i2c_client client_template = { + .name = "WM8580", + .driver = &wm8580_i2c_driver, +}; #endif static int wm8580_probe(struct platform_device *pdev) @@ -1007,8 +1011,11 @@ static int wm8580_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { + normal_i2c[0] = setup->i2c_address; codec->hw_write = (hw_write_t)i2c_master_send; - ret = wm8580_add_i2c_device(pdev, setup); + ret = i2c_add_driver(&wm8580_i2c_driver); + if (ret != 0) + printk(KERN_ERR "can't add i2c driver"); } #else /* Add other interfaces here */ @@ -1027,7 +1034,6 @@ static int wm8580_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_unregister_device(codec->control_data); i2c_del_driver(&wm8580_i2c_driver); #endif kfree(codec->private_data); @@ -1042,18 +1048,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8580 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); -static int __devinit wm8580_modinit(void) -{ - return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); -} -module_init(wm8580_modinit); - -static void __exit wm8580_exit(void) -{ - snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); -} -module_exit(wm8580_exit); - MODULE_DESCRIPTION("ASoC WM8580 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h index 09e4422f6f2f..589ddaba21d7 100644 --- a/sound/soc/codecs/wm8580.h +++ b/sound/soc/codecs/wm8580.h @@ -29,7 +29,6 @@ #define WM8580_CLKSRC_NONE 5 struct wm8580_setup_data { - int i2c_bus; unsigned short i2c_address; }; diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c deleted file mode 100644 index d905e25b1a93..000000000000 --- a/sound/soc/codecs/wm8728.c +++ /dev/null @@ -1,585 +0,0 @@ -/* - * wm8728.c -- WM8728 ALSA SoC Audio driver - * - * Copyright 2008 Wolfson Microelectronics plc - * - * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/i2c.h> -#include <linux/platform_device.h> -#include <linux/spi/spi.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/initval.h> -#include <sound/tlv.h> - -#include "wm8728.h" - -struct snd_soc_codec_device soc_codec_dev_wm8728; - -/* - * We can't read the WM8728 register space so we cache them instead. - * Note that the defaults here aren't the physical defaults, we latch - * the volume update bits, mute the output and enable infinite zero - * detect. - */ -static const u16 wm8728_reg_defaults[] = { - 0x1ff, - 0x1ff, - 0x001, - 0x100, -}; - -static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); - return cache[reg]; -} - -static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec, - u16 reg, unsigned int value) -{ - u16 *cache = codec->reg_cache; - BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); - cache[reg] = value; -} - -/* - * write to the WM8728 register space - */ -static int wm8728_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - /* data is - * D15..D9 WM8728 register offset - * D8...D0 register data - */ - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - wm8728_write_reg_cache(codec, reg, value); - - if (codec->hw_write(codec->control_data, data, 2) == 2) - return 0; - else - return -EIO; -} - -static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); - -static const struct snd_kcontrol_new wm8728_snd_controls[] = { - -SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL, - 0, 255, 0, wm8728_tlv), - -SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0), -}; - -static int wm8728_add_controls(struct snd_soc_codec *codec) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(wm8728_snd_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&wm8728_snd_controls[i], - codec, NULL)); - if (err < 0) - return err; - } - - return 0; -} - -/* - * DAPM controls. - */ -static const struct snd_soc_dapm_widget wm8728_dapm_widgets[] = { -SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_OUTPUT("VOUTL"), -SND_SOC_DAPM_OUTPUT("VOUTR"), -}; - -static const struct snd_soc_dapm_route intercon[] = { - {"VOUTL", NULL, "DAC"}, - {"VOUTR", NULL, "DAC"}, -}; - -static int wm8728_add_widgets(struct snd_soc_codec *codec) -{ - snd_soc_dapm_new_controls(codec, wm8728_dapm_widgets, - ARRAY_SIZE(wm8728_dapm_widgets)); - - snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); - - snd_soc_dapm_new_widgets(codec); - - return 0; -} - -static int wm8728_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); - - if (mute) - wm8728_write(codec, WM8728_DACCTL, mute_reg | 1); - else - wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1); - - return 0; -} - -static int wm8728_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; - u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL); - - dac &= ~0x18; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - break; - case SNDRV_PCM_FORMAT_S20_3LE: - dac |= 0x10; - break; - case SNDRV_PCM_FORMAT_S24_LE: - dac |= 0x08; - break; - default: - return -EINVAL; - } - - wm8728_write(codec, WM8728_DACCTL, dac); - - return 0; -} - -static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = wm8728_read_reg_cache(codec, WM8728_IFCTL); - - /* Currently only I2S is supported by the driver, though the - * hardware is more flexible. - */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - iface |= 1; - break; - default: - return -EINVAL; - } - - /* The hardware only support full slave mode */ - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - iface &= ~0x22; - break; - case SND_SOC_DAIFMT_IB_NF: - iface |= 0x20; - iface &= ~0x02; - break; - case SND_SOC_DAIFMT_NB_IF: - iface |= 0x02; - iface &= ~0x20; - break; - case SND_SOC_DAIFMT_IB_IF: - iface |= 0x22; - break; - default: - return -EINVAL; - } - - wm8728_write(codec, WM8728_IFCTL, iface); - return 0; -} - -static int wm8728_set_bias_level(struct snd_soc_codec *codec, - enum snd_soc_bias_level level) -{ - u16 reg; - int i; - - switch (level) { - case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: - case SND_SOC_BIAS_STANDBY: - if (codec->bias_level == SND_SOC_BIAS_OFF) { - /* Power everything up... */ - reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); - wm8728_write(codec, WM8728_DACCTL, reg & ~0x4); - - /* ..then sync in the register cache. */ - for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++) - wm8728_write(codec, i, - wm8728_read_reg_cache(codec, i)); - } - break; - - case SND_SOC_BIAS_OFF: - reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); - wm8728_write(codec, WM8728_DACCTL, reg | 0x4); - break; - } - codec->bias_level = level; - return 0; -} - -#define WM8728_RATES (SNDRV_PCM_RATE_8000_192000) - -#define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S24_LE) - -struct snd_soc_dai wm8728_dai = { - .name = "WM8728", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, - .rates = WM8728_RATES, - .formats = WM8728_FORMATS, - }, - .ops = { - .hw_params = wm8728_hw_params, - .digital_mute = wm8728_mute, - .set_fmt = wm8728_set_dai_fmt, - } -}; -EXPORT_SYMBOL_GPL(wm8728_dai); - -static int wm8728_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int wm8728_resume(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - wm8728_set_bias_level(codec, codec->suspend_bias_level); - - return 0; -} - -/* - * initialise the WM8728 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8728_init(struct snd_soc_device *socdev) -{ - struct snd_soc_codec *codec = socdev->codec; - int ret = 0; - - codec->name = "WM8728"; - codec->owner = THIS_MODULE; - codec->read = wm8728_read_reg_cache; - codec->write = wm8728_write; - codec->set_bias_level = wm8728_set_bias_level; - codec->dai = &wm8728_dai; - codec->num_dai = 1; - codec->bias_level = SND_SOC_BIAS_OFF; - codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults); - codec->reg_cache = kmemdup(wm8728_reg_defaults, - sizeof(wm8728_reg_defaults), - GFP_KERNEL); - if (codec->reg_cache == NULL) - return -ENOMEM; - - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - printk(KERN_ERR "wm8728: failed to create pcms\n"); - goto pcm_err; - } - - /* power on device */ - wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - wm8728_add_controls(codec); - wm8728_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - printk(KERN_ERR "wm8728: failed to register card\n"); - goto card_err; - } - - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - return ret; -} - -static struct snd_soc_device *wm8728_socdev; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -/* - * WM8728 2 wire address is determined by GPIO5 - * state during powerup. - * low = 0x1a - * high = 0x1b - */ - -static int wm8728_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct snd_soc_device *socdev = wm8728_socdev; - struct snd_soc_codec *codec = socdev->codec; - int ret; - - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - - ret = wm8728_init(socdev); - if (ret < 0) - pr_err("failed to initialise WM8728\n"); - - return ret; -} - -static int wm8728_i2c_remove(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); - return 0; -} - -static const struct i2c_device_id wm8728_i2c_id[] = { - { "wm8728", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id); - -static struct i2c_driver wm8728_i2c_driver = { - .driver = { - .name = "WM8728 I2C Codec", - .owner = THIS_MODULE, - }, - .probe = wm8728_i2c_probe, - .remove = wm8728_i2c_remove, - .id_table = wm8728_i2c_id, -}; - -static int wm8728_add_i2c_device(struct platform_device *pdev, - const struct wm8728_setup_data *setup) -{ - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; - int ret; - - ret = i2c_add_driver(&wm8728_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = setup->i2c_address; - strlcpy(info.type, "wm8728", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "can't get i2c adapter %d\n", - setup->i2c_bus); - goto err_driver; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - goto err_driver; - } - - return 0; - -err_driver: - i2c_del_driver(&wm8728_i2c_driver); - return -ENODEV; -} -#endif - -#if defined(CONFIG_SPI_MASTER) -static int __devinit wm8728_spi_probe(struct spi_device *spi) -{ - struct snd_soc_device *socdev = wm8728_socdev; - struct snd_soc_codec *codec = socdev->codec; - int ret; - - codec->control_data = spi; - - ret = wm8728_init(socdev); - if (ret < 0) - dev_err(&spi->dev, "failed to initialise WM8728\n"); - - return ret; -} - -static int __devexit wm8728_spi_remove(struct spi_device *spi) -{ - return 0; -} - -static struct spi_driver wm8728_spi_driver = { - .driver = { - .name = "wm8728", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - .probe = wm8728_spi_probe, - .remove = __devexit_p(wm8728_spi_remove), -}; - -static int wm8728_spi_write(struct spi_device *spi, const char *data, int len) -{ - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} -#endif /* CONFIG_SPI_MASTER */ - -static int wm8728_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8728_setup_data *setup; - struct snd_soc_codec *codec; - int ret = 0; - - setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - socdev->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - - wm8728_socdev = socdev; - ret = -ENODEV; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - codec->hw_write = (hw_write_t)i2c_master_send; - ret = wm8728_add_i2c_device(pdev, setup); - } -#endif -#if defined(CONFIG_SPI_MASTER) - if (setup->spi) { - codec->hw_write = (hw_write_t)wm8728_spi_write; - ret = spi_register_driver(&wm8728_spi_driver); - if (ret != 0) - printk(KERN_ERR "can't add spi driver"); - } -#endif - - if (ret != 0) - kfree(codec); - - return ret; -} - -/* power down chip */ -static int wm8728_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - if (codec->control_data) - wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); - - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_unregister_device(codec->control_data); - i2c_del_driver(&wm8728_i2c_driver); -#endif -#if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&wm8728_spi_driver); -#endif - kfree(codec); - - return 0; -} - -struct snd_soc_codec_device soc_codec_dev_wm8728 = { - .probe = wm8728_probe, - .remove = wm8728_remove, - .suspend = wm8728_suspend, - .resume = wm8728_resume, -}; -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728); - -static int __devinit wm8728_modinit(void) -{ - return snd_soc_register_dai(&wm8728_dai); -} -module_init(wm8728_modinit); - -static void __exit wm8728_exit(void) -{ - snd_soc_unregister_dai(&wm8728_dai); -} -module_exit(wm8728_exit); - -MODULE_DESCRIPTION("ASoC WM8728 driver"); -MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8728.h b/sound/soc/codecs/wm8728.h deleted file mode 100644 index d269c132474b..000000000000 --- a/sound/soc/codecs/wm8728.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * wm8728.h -- WM8728 ASoC codec driver - * - * Copyright 2008 Wolfson Microelectronics plc - * - * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _WM8728_H -#define _WM8728_H - -#define WM8728_DACLVOL 0x00 -#define WM8728_DACRVOL 0x01 -#define WM8728_DACCTL 0x02 -#define WM8728_IFCTL 0x03 - -struct wm8728_setup_data { - int spi; - int i2c_bus; - unsigned short i2c_address; -}; - -extern struct snd_soc_dai wm8728_dai; -extern struct snd_soc_codec_device soc_codec_dev_wm8728; - -#endif diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 7b455a60d719..7f8a7e36b33e 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -264,8 +264,7 @@ static inline int get_coeff(int mclk, int rate) } static int wm8731_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -294,8 +293,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, return 0; } -static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -307,8 +305,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, return 0; } -static void wm8731_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void wm8731_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -464,6 +461,8 @@ struct snd_soc_dai wm8731_dai = { .prepare = wm8731_pcm_prepare, .hw_params = wm8731_hw_params, .shutdown = wm8731_shutdown, + }, + .dai_ops = { .digital_mute = wm8731_mute, .set_sysclk = wm8731_set_dai_sysclk, .set_fmt = wm8731_set_dai_fmt, @@ -545,7 +544,7 @@ static int wm8731_init(struct snd_soc_device *socdev) wm8731_add_controls(codec); wm8731_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8731: failed to register card\n"); goto card_err; @@ -793,18 +792,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8731 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); -static int __devinit wm8731_modinit(void) -{ - return snd_soc_register_dai(&wm8731_dai); -} -module_init(wm8731_modinit); - -static void __exit wm8731_exit(void) -{ - snd_soc_unregister_dai(&wm8731_dai); -} -module_exit(wm8731_exit); - MODULE_DESCRIPTION("ASoC WM8731 driver"); MODULE_AUTHOR("Richard Purdie"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 84a6307de907..9b7296ee5b08 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -614,8 +614,7 @@ static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -710,6 +709,8 @@ struct snd_soc_dai wm8750_dai = { .formats = WM8750_FORMATS,}, .ops = { .hw_params = wm8750_pcm_hw_params, + }, + .dai_ops = { .digital_mute = wm8750_mute, .set_fmt = wm8750_set_dai_fmt, .set_sysclk = wm8750_set_dai_sysclk, @@ -818,7 +819,7 @@ static int wm8750_init(struct snd_soc_device *socdev) wm8750_add_controls(codec); wm8750_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8750: failed to register card\n"); goto card_err; @@ -1085,18 +1086,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8750 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); -static int __devinit wm8750_modinit(void) -{ - return snd_soc_register_dai(&wm8750_dai); -} -module_init(wm8750_modinit); - -static void __exit wm8750_exit(void) -{ - snd_soc_unregister_dai(&wm8750_dai); -} -module_exit(wm8750_exit); - MODULE_DESCRIPTION("ASoC WM8750 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 1caca30d0812..d426eaa22185 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -922,8 +922,7 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1156,8 +1155,7 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1325,15 +1323,16 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .channels_min = 1, .channels_max = 2, .rates = WM8753_RATES, - .formats = WM8753_FORMATS}, + .formats = WM8753_FORMATS,}, .capture = { /* dummy for fast DAI switching */ .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = WM8753_RATES, - .formats = WM8753_FORMATS}, + .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_i2s_hw_params, + .hw_params = wm8753_i2s_hw_params,}, + .dai_ops = { .digital_mute = wm8753_mute, .set_fmt = wm8753_mode1h_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1357,7 +1356,8 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_pcm_hw_params, + .hw_params = wm8753_pcm_hw_params,}, + .dai_ops = { .digital_mute = wm8753_mute, .set_fmt = wm8753_mode1v_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1385,7 +1385,8 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_pcm_hw_params, + .hw_params = wm8753_pcm_hw_params,}, + .dai_ops = { .digital_mute = wm8753_mute, .set_fmt = wm8753_mode2_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1409,7 +1410,8 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_i2s_hw_params, + .hw_params = wm8753_i2s_hw_params,}, + .dai_ops = { .digital_mute = wm8753_mute, .set_fmt = wm8753_mode3_4_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1437,7 +1439,8 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_i2s_hw_params, + .hw_params = wm8753_i2s_hw_params,}, + .dai_ops = { .digital_mute = wm8753_mute, .set_fmt = wm8753_mode3_4_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1605,7 +1608,7 @@ static int wm8753_init(struct snd_soc_device *socdev) wm8753_add_controls(codec); wm8753_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8753: failed to register card\n"); goto card_err; @@ -1874,18 +1877,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8753 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); -static int __devinit wm8753_modinit(void) -{ - return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); -} -module_init(wm8753_modinit); - -static void __exit wm8753_exit(void) -{ - snd_soc_unregister_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); -} -module_exit(wm8753_exit); - MODULE_DESCRIPTION("ASoC WM8753 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 34e58af0c65a..3b326c9b5586 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -727,8 +727,7 @@ static int wm8900_add_widgets(struct snd_soc_codec *codec) } static int wm8900_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1118,6 +1117,8 @@ struct snd_soc_dai wm8900_dai = { }, .ops = { .hw_params = wm8900_hw_params, + }, + .dai_ops = { .set_clkdiv = wm8900_set_dai_clkdiv, .set_pll = wm8900_set_dai_pll, .set_fmt = wm8900_set_dai_fmt, @@ -1365,7 +1366,7 @@ static int wm8900_init(struct snd_soc_device *socdev) wm8900_add_controls(codec); wm8900_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { dev_err(&i2c_client->dev, "Failed to register card\n"); goto card_err; @@ -1382,51 +1383,105 @@ priv_err: return ret; } -static struct i2c_client *wm8900_client; +static struct snd_soc_device *wm8900_socdev; + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + +static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; -static int wm8900_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +/* Magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver wm8900_i2c_driver; +static struct i2c_client client_template; + +/* If the i2c layer weren't so broken, we could pass this kind of data + around */ +static int wm8900_codec_probe(struct i2c_adapter *adap, int addr, int kind) { - wm8900_client = i2c; - wm8900_dai.dev = &i2c->dev; - return snd_soc_register_dai(&wm8900_dai); + struct snd_soc_device *socdev = wm8900_socdev; + struct wm8900_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec = socdev->codec; + struct i2c_client *i2c; + int ret; + + if (addr != setup->i2c_address) + return -ENODEV; + + dev_err(&adap->dev, "Probe on %x\n", addr); + + client_template.adapter = adap; + client_template.addr = addr; + + i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); + if (i2c == NULL) { + kfree(codec); + return -ENOMEM; + } + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + ret = i2c_attach_client(i2c); + if (ret < 0) { + dev_err(&adap->dev, + "failed to attach codec at addr %x\n", addr); + goto err; + } + + ret = wm8900_init(socdev); + if (ret < 0) { + dev_err(&adap->dev, "failed to initialise WM8900\n"); + goto err; + } + return ret; + +err: + kfree(codec); + kfree(i2c); + return ret; } -static int wm8900_i2c_remove(struct i2c_client *client) +static int wm8900_i2c_detach(struct i2c_client *client) { - snd_soc_unregister_dai(&wm8900_dai); - wm8900_dai.dev = NULL; - wm8900_client = NULL; + struct snd_soc_codec *codec = i2c_get_clientdata(client); + i2c_detach_client(client); + kfree(codec->reg_cache); + kfree(client); return 0; } -static const struct i2c_device_id wm8900_i2c_id[] = { - { "wm8900", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id); +static int wm8900_i2c_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, wm8900_codec_probe); +} +/* corgi i2c codec control layer */ static struct i2c_driver wm8900_i2c_driver = { .driver = { .name = "WM8900 I2C codec", .owner = THIS_MODULE, }, - .probe = wm8900_i2c_probe, - .remove = wm8900_i2c_remove, - .id_table = wm8900_i2c_id, + .attach_adapter = wm8900_i2c_attach, + .detach_client = wm8900_i2c_detach, + .command = NULL, }; +static struct i2c_client client_template = { + .name = "WM8900", + .driver = &wm8900_i2c_driver, +}; +#endif + static int wm8900_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct wm8900_setup_data *setup; struct snd_soc_codec *codec; int ret = 0; - if (!wm8900_client) { - dev_err(&pdev->dev, "I2C client not yet instantiated\n"); - return -ENODEV; - } + dev_info(&pdev->dev, "WM8900 Audio Codec\n"); + setup = socdev->codec_data; codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); if (codec == NULL) return -ENOMEM; @@ -1439,13 +1494,18 @@ static int wm8900_probe(struct platform_device *pdev) codec->set_bias_level = wm8900_set_bias_level; - codec->hw_write = (hw_write_t)i2c_master_send; - codec->control_data = wm8900_client; - - ret = wm8900_init(socdev); - if (ret != 0) - kfree(codec); - + wm8900_socdev = socdev; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + if (setup->i2c_address) { + normal_i2c[0] = setup->i2c_address; + codec->hw_write = (hw_write_t)i2c_master_send; + ret = i2c_add_driver(&wm8900_i2c_driver); + if (ret != 0) + printk(KERN_ERR "can't add i2c driver"); + } +#else +#error Non-I2C interfaces not yet supported +#endif return ret; } @@ -1460,6 +1520,9 @@ static int wm8900_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&wm8900_i2c_driver); +#endif kfree(codec); return 0; @@ -1473,18 +1536,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8900 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); -static int __devinit wm8900_modinit(void) -{ - return i2c_add_driver(&wm8900_i2c_driver); -} -module_init(wm8900_modinit); - -static void __exit wm8900_exit(void) -{ - i2c_del_driver(&wm8900_i2c_driver); -} -module_exit(wm8900_exit); - MODULE_DESCRIPTION("ASoC WM8900 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h index 2249a446ad37..ba450d99e902 100644 --- a/sound/soc/codecs/wm8900.h +++ b/sound/soc/codecs/wm8900.h @@ -55,7 +55,6 @@ #define WM8900_ struct wm8900_setup_data { - int i2c_bus; unsigned short i2c_address; }; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 5d8fe7e1571e..ce40d7877605 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -773,14 +773,14 @@ static const struct snd_kcontrol_new left_output_mixer[] = { SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0), SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), -SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 0, 1, 0), +SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), }; static const struct snd_kcontrol_new right_output_mixer[] = { SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 2, 1, 0), SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), -SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 0, 1, 0), +SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), }; static const struct snd_kcontrol_new left_speaker_mixer[] = { @@ -788,7 +788,7 @@ SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 2, 1, 0), SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 1, 1, 0), SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, - 0, 1, 0), + 1, 1, 0), }; static const struct snd_kcontrol_new right_speaker_mixer[] = { @@ -797,7 +797,7 @@ SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 2, 1, 0), SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 1, 1, 0), SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, - 0, 1, 0), + 1, 1, 0), }; static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = { @@ -1257,8 +1257,7 @@ static struct { { 0, 0 }, }; -static int wm8903_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int wm8903_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1299,8 +1298,7 @@ static int wm8903_startup(struct snd_pcm_substream *substream, return 0; } -static void wm8903_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void wm8903_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1319,8 +1317,7 @@ static void wm8903_shutdown(struct snd_pcm_substream *substream, } static int wm8903_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1518,6 +1515,8 @@ struct snd_soc_dai wm8903_dai = { .startup = wm8903_startup, .shutdown = wm8903_shutdown, .hw_params = wm8903_hw_params, + }, + .dai_ops = { .digital_mute = wm8903_digital_mute, .set_fmt = wm8903_set_dai_fmt, .set_sysclk = wm8903_set_dai_sysclk @@ -1648,7 +1647,7 @@ static int wm8903_init(struct snd_soc_device *socdev) wm8903_add_controls(codec); wm8903_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { dev_err(&i2c->dev, "wm8903: failed to register card\n"); goto card_err; @@ -1809,18 +1808,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8903 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903); -static int __devinit wm8903_modinit(void) -{ - return snd_soc_register_dai(&wm8903_dai); -} -module_init(wm8903_modinit); - -static void __exit wm8903_exit(void) -{ - snd_soc_unregister_dai(&wm8903_dai); -} -module_exit(wm8903_exit); - MODULE_DESCRIPTION("ASoC WM8903 driver"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 2979fc4f44f1..f41a578ddd4f 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -541,8 +541,7 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -635,6 +634,8 @@ struct snd_soc_dai wm8971_dai = { .formats = WM8971_FORMATS,}, .ops = { .hw_params = wm8971_pcm_hw_params, + }, + .dai_ops = { .digital_mute = wm8971_mute, .set_fmt = wm8971_set_dai_fmt, .set_sysclk = wm8971_set_dai_sysclk, @@ -747,7 +748,7 @@ static int wm8971_init(struct snd_soc_device *socdev) wm8971_add_controls(codec); wm8971_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8971: failed to register card\n"); goto card_err; @@ -935,18 +936,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8971 = { EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971); -static int __devinit wm8971_modinit(void) -{ - return snd_soc_register_dai(&wm8971_dai); -} -module_init(wm8971_modinit); - -static void __exit wm8971_exit(void) -{ - snd_soc_unregister_dai(&wm8971_dai); -} -module_exit(wm8971_exit); - MODULE_DESCRIPTION("ASoC WM8971 driver"); MODULE_AUTHOR("Lab126"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 53e71aafe6c6..572d22b0880b 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -106,7 +106,6 @@ static const u16 wm8990_reg[] = { 0x0008, /* R60 - PLL1 */ 0x0031, /* R61 - PLL2 */ 0x0026, /* R62 - PLL3 */ - 0x0000, /* R63 - Driver internal */ }; /* @@ -127,9 +126,10 @@ static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u16 *cache = codec->reg_cache; + BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); - /* Reset register and reserved registers are uncached */ - if (reg == 0 || reg > ARRAY_SIZE(wm8990_reg) - 1) + /* Reset register is uncached */ + if (reg == 0) return; cache[reg] = value; @@ -1172,8 +1172,7 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8990_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1223,14 +1222,8 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: break; - case SND_SOC_BIAS_PREPARE: - /* VMID=2*50k */ - val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & - ~WM8990_VMID_MODE_MASK; - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2); break; - case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Enable all output discharge bits */ @@ -1279,17 +1272,10 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); + } else { + /* ON -> standby */ - /* Enable workaround for ADC clocking issue. */ - wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2); - wm8990_write(codec, WM8990_EXT_CTL1, 0xa003); - wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0); } - - /* VMID=2*250k */ - val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & - ~WM8990_VMID_MODE_MASK; - wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4); break; case SND_SOC_BIAS_OFF: @@ -1363,7 +1349,8 @@ struct snd_soc_dai wm8990_dai = { .rates = WM8990_RATES, .formats = WM8990_FORMATS,}, .ops = { - .hw_params = wm8990_hw_params, + .hw_params = wm8990_hw_params,}, + .dai_ops = { .digital_mute = wm8990_mute, .set_fmt = wm8990_set_dai_fmt, .set_clkdiv = wm8990_set_dai_clkdiv, @@ -1462,7 +1449,7 @@ static int wm8990_init(struct snd_soc_device *socdev) wm8990_add_controls(codec); wm8990_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8990: failed to register card\n"); goto card_err; @@ -1643,18 +1630,6 @@ struct snd_soc_codec_device soc_codec_dev_wm8990 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); -static int __devinit wm8990_modinit(void) -{ - return snd_soc_register_dai(&wm8990_dai); -} -module_init(wm8990_modinit); - -static void __exit wm8990_exit(void) -{ - snd_soc_unregister_dai(&wm8990_dai); -} -module_exit(wm8990_exit); - MODULE_DESCRIPTION("ASoC WM8990 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h index 7114ddc88b4b..0e192f3b0788 100644 --- a/sound/soc/codecs/wm8990.h +++ b/sound/soc/codecs/wm8990.h @@ -80,8 +80,8 @@ #define WM8990_PLL3 0x3E #define WM8990_INTDRIVBITS 0x3F -#define WM8990_EXT_ACCESS_ENA 0x75 -#define WM8990_EXT_CTL1 0x7a +#define WM8990_REGISTER_COUNT 60 +#define WM8990_MAX_REGISTER 0x3F /* * Field Definitions. diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index af83d629078a..ffb471e420e2 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -487,8 +487,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, return 0; } -static int ac97_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ac97_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -508,8 +507,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream, return ac97_write(codec, reg, runtime->rate); } -static int ac97_aux_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ac97_aux_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -535,7 +533,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai wm9712_dai[] = { { .name = "AC97 HiFi", - .ac97_control = 1, + .type = SND_SOC_DAI_AC97_BUS, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, @@ -690,7 +688,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) ret = wm9712_reset(codec, 0); if (ret < 0) { - printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n"); + printk(KERN_ERR "AC97 link error\n"); goto reset_err; } @@ -700,7 +698,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm9712_add_controls(codec); wm9712_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) { printk(KERN_ERR "wm9712: failed to register card\n"); goto reset_err; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index f3ca8aaf0139..945b32ed9884 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -928,10 +928,11 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { - struct snd_soc_codec *codec = dai->codec; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xfff3; switch (params_format(params)) { @@ -953,10 +954,11 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) { - struct snd_soc_codec *codec = dai->codec; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; u16 status; /* Gracefully shut down the voice interface. */ @@ -967,11 +969,12 @@ static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, ac97_write(codec, AC97_EXTENDED_MID, status); } -static int ac97_hifi_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ac97_hifi_prepare(struct snd_pcm_substream *substream) { - struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; int reg; u16 vra; @@ -986,11 +989,12 @@ static int ac97_hifi_prepare(struct snd_pcm_substream *substream, return ac97_write(codec, reg, runtime->rate); } -static int ac97_aux_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ac97_aux_prepare(struct snd_pcm_substream *substream) { - struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; u16 vra, xsle; vra = ac97_read(codec, AC97_EXTENDED_STATUS); @@ -1024,7 +1028,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai wm9713_dai[] = { { .name = "AC97 HiFi", - .ac97_control = 1, + .type = SND_SOC_DAI_AC97_BUS, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, @@ -1038,7 +1042,8 @@ struct snd_soc_dai wm9713_dai[] = { .rates = WM9713_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { - .prepare = ac97_hifi_prepare, + .prepare = ac97_hifi_prepare,}, + .dai_ops = { .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll,}, }, @@ -1051,7 +1056,8 @@ struct snd_soc_dai wm9713_dai[] = { .rates = WM9713_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { - .prepare = ac97_aux_prepare, + .prepare = ac97_aux_prepare,}, + .dai_ops = { .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll,}, }, @@ -1071,7 +1077,8 @@ struct snd_soc_dai wm9713_dai[] = { .formats = WM9713_PCM_FORMATS,}, .ops = { .hw_params = wm9713_pcm_hw_params, - .shutdown = wm9713_voiceshutdown, + .shutdown = wm9713_voiceshutdown,}, + .dai_ops = { .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll, .set_fmt = wm9713_set_dai_fmt, @@ -1090,8 +1097,6 @@ int wm9713_reset(struct snd_soc_codec *codec, int try_warm) } soc_ac97_ops.reset(codec->ac97); - if (soc_ac97_ops.warm_reset) - soc_ac97_ops.warm_reset(codec->ac97); if (ac97_read(codec, 0) != wm9713_reg[0]) return -EIO; return 0; @@ -1235,7 +1240,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) wm9713_reset(codec, 0); ret = wm9713_reset(codec, 1); if (ret < 0) { - printk(KERN_ERR "Failed to reset WM9713: AC97 link error\n"); + printk(KERN_ERR "AC97 link error\n"); goto reset_err; } @@ -1247,7 +1252,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) wm9713_add_controls(codec); wm9713_add_widgets(codec); - ret = snd_soc_init_card(socdev); + ret = snd_soc_register_card(socdev); if (ret < 0) goto reset_err; return 0; @@ -1283,6 +1288,7 @@ static int wm9713_soc_remove(struct platform_device *pdev) snd_soc_free_ac97_codec(codec); kfree(codec->private_data); kfree(codec->reg_cache); + kfree(codec->dai); kfree(codec); return 0; } diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index b502741692d6..8f7e33834902 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -17,13 +17,3 @@ config SND_DAVINCI_SOC_EVM help Say Y if you want to add support for SoC audio on TI DaVinci EVM platform. - -config SND_DAVINCI_SOC_SFFSDR - tristate "SoC Audio support for SFFSDR" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_SFFSDR - select SND_DAVINCI_SOC_I2S - select SND_SOC_PCM3008 - select SFFSDR_FPGA - help - Say Y if you want to add support for SoC audio on - Lyrtech SFFSDR board. diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index ca8bae1fc3f6..ca772e5b4637 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -7,7 +7,5 @@ obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o # DAVINCI Machine Support snd-soc-evm-objs := davinci-evm.o -snd-soc-sffsdr-objs := davinci-sffsdr.o obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o -obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index d87b91179cc8..9e6062cd6b59 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -128,9 +128,8 @@ static struct snd_soc_dai_link evm_dai = { }; /* davinci-evm audio machine driver */ -static struct snd_soc_card snd_soc_card_evm = { +static struct snd_soc_machine snd_soc_machine_evm = { .name = "DaVinci EVM", - .platform = &davinci_soc_platform, .dai_link = &evm_dai, .num_links = 1, }; @@ -143,7 +142,8 @@ static struct aic3x_setup_data evm_aic3x_setup = { /* evm audio subsystem */ static struct snd_soc_device evm_snd_devdata = { - .card = &snd_soc_card_evm, + .machine = &snd_soc_machine_evm, + .platform = &davinci_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &evm_aic3x_setup, }; diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index d89fc2f009ab..abb5fedb0b1e 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -59,7 +59,6 @@ #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) #define DAVINCI_MCBSP_PCR_FSRP (1 << 2) #define DAVINCI_MCBSP_PCR_FSXP (1 << 3) -#define DAVINCI_MCBSP_PCR_SCLKME (1 << 7) #define DAVINCI_MCBSP_PCR_CLKRM (1 << 8) #define DAVINCI_MCBSP_PCR_CLKXM (1 << 9) #define DAVINCI_MCBSP_PCR_FSRM (1 << 10) @@ -111,59 +110,16 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_platform *platform = socdev->card->platform; u32 w; - int ret; /* Start the sample generator and enable transmitter/receiver */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* Stop the DMA to avoid data loss */ - /* while the transmitter is out of reset to handle XSYNCERR */ - if (platform->pcm_ops->trigger) { - ret = platform->pcm_ops->trigger(substream, - SNDRV_PCM_TRIGGER_STOP); - if (ret < 0) - printk(KERN_DEBUG "Playback DMA stop failed\n"); - } - - /* Enable the transmitter */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - - /* wait for any unexpected frame sync error to occur */ - udelay(100); - - /* Disable the transmitter to clear any outstanding XSYNCERR */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - - /* Restart the DMA */ - if (platform->pcm_ops->trigger) { - ret = platform->pcm_ops->trigger(substream, - SNDRV_PCM_TRIGGER_START); - if (ret < 0) - printk(KERN_DEBUG "Playback DMA start failed\n"); - } - /* Enable the transmitter */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - - } else { - - /* Enable the reciever */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + else MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - } - + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); /* Start frame sync */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); @@ -188,8 +144,7 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); } -static int davinci_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int davinci_i2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -216,16 +171,6 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, DAVINCI_MCBSP_SRGR_FSGM); break; - case SND_SOC_DAIFMT_CBM_CFS: - /* McBSP CLKR pin is the input for the Sample Rate Generator. - * McBSP FSR and FSX are driven by the Sample Rate Generator. */ - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, - DAVINCI_MCBSP_PCR_SCLKME | - DAVINCI_MCBSP_PCR_FSXM | - DAVINCI_MCBSP_PCR_FSRM); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, - DAVINCI_MCBSP_SRGR_FSGM); - break; case SND_SOC_DAIFMT_CBM_CFM: davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0); break; @@ -260,34 +205,11 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_RIGHT_J: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, - DAVINCI_MCBSP_RCR_RFRLEN1(1) | - DAVINCI_MCBSP_RCR_RDATDLY(0)); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, - DAVINCI_MCBSP_XCR_XFRLEN1(1) | - DAVINCI_MCBSP_XCR_XDATDLY(0) | - DAVINCI_MCBSP_XCR_XFIG); - break; - case SND_SOC_DAIFMT_I2S: - default: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, - DAVINCI_MCBSP_RCR_RFRLEN1(1) | - DAVINCI_MCBSP_RCR_RDATDLY(1)); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, - DAVINCI_MCBSP_XCR_XFRLEN1(1) | - DAVINCI_MCBSP_XCR_XDATDLY(1) | - DAVINCI_MCBSP_XCR_XFIG); - break; - } - return 0; } static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; @@ -297,14 +219,17 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, u32 w; /* general line settings */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - w |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - } else { - w |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); - } + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, + DAVINCI_MCBSP_SPCR_RINTM(3) | + DAVINCI_MCBSP_SPCR_XINTM(3) | + DAVINCI_MCBSP_SPCR_FREE); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, + DAVINCI_MCBSP_RCR_RFRLEN1(1) | + DAVINCI_MCBSP_RCR_RDATDLY(1)); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, + DAVINCI_MCBSP_XCR_XFRLEN1(1) | + DAVINCI_MCBSP_XCR_XDATDLY(1) | + DAVINCI_MCBSP_XCR_XFIG); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); @@ -335,24 +260,20 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); - } else { - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); - } return 0; } -static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { int ret = 0; @@ -378,8 +299,8 @@ static int davinci_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev; struct resource *mem, *ioarea; struct evm_snd_platform_data *pdata; @@ -440,8 +361,8 @@ static void davinci_i2s_remove(struct platform_device *pdev, struct snd_soc_dai *dai) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev = cpu_dai->private_data; struct resource *mem; @@ -460,6 +381,7 @@ static void davinci_i2s_remove(struct platform_device *pdev, struct snd_soc_dai davinci_i2s_dai = { .name = "davinci-i2s", .id = 0, + .type = SND_SOC_DAI_I2S, .probe = davinci_i2s_probe, .remove = davinci_i2s_remove, .playback = { @@ -475,24 +397,13 @@ struct snd_soc_dai davinci_i2s_dai = { .ops = { .startup = davinci_i2s_startup, .trigger = davinci_i2s_trigger, - .hw_params = davinci_i2s_hw_params, + .hw_params = davinci_i2s_hw_params,}, + .dai_ops = { .set_fmt = davinci_i2s_set_dai_fmt, }, }; EXPORT_SYMBOL_GPL(davinci_i2s_dai); -static int __devinit davinci_i2s_init(void) -{ - return snd_soc_register_dai(&davinci_i2s_dai); -} -module_init(davinci_i2s_init); - -static void __exit davinci_i2s_exit(void) -{ - snd_soc_unregister_dai(&davinci_i2s_dai); -} -module_exit(davinci_i2s_exit); - MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index f1b6e02d24ed..76feaa657375 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -384,18 +384,6 @@ struct snd_soc_platform davinci_soc_platform = { }; EXPORT_SYMBOL_GPL(davinci_soc_platform); -static int __devinit davinci_soc_platform_init(void) -{ - return snd_soc_register_platform(&davinci_soc_platform); -} -module_init(davinci_soc_platform_init); - -static void __exit davinci_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&davinci_soc_platform); -} -module_exit(davinci_soc_platform_exit); - MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c deleted file mode 100644 index f67579d52765..000000000000 --- a/sound/soc/davinci/davinci-sffsdr.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * ASoC driver for Lyrtech SFFSDR board. - * - * Author: Hugo Villeneuve - * Copyright (C) 2008 Lyrtech inc - * - * Based on ASoC driver for TI DAVINCI EVM platform, original copyright follow: - * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/gpio.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/dma.h> -#include <asm/plat-sffsdr/sffsdr-fpga.h> - -#include <mach/mcbsp.h> -#include <mach/edma.h> - -#include "../codecs/pcm3008.h" -#include "davinci-pcm.h" -#include "davinci-i2s.h" - -static int sffsdr_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int fs; - int ret = 0; - - /* Set cpu DAI configuration: - * CLKX and CLKR are the inputs for the Sample Rate Generator. - * FSX and FSR are outputs, driven by the sample Rate Generator. */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_RIGHT_J | - SND_SOC_DAIFMT_CBM_CFS | - SND_SOC_DAIFMT_IB_NF); - if (ret < 0) - return ret; - - /* Fsref can be 32000, 44100 or 48000. */ - fs = params_rate(params); - - pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); - - return sffsdr_fpga_set_codec_fs(fs); -} - -static struct snd_soc_ops sffsdr_ops = { - .hw_params = sffsdr_hw_params, -}; - -/* davinci-sffsdr digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link sffsdr_dai = { - .name = "PCM3008", /* Codec name */ - .stream_name = "PCM3008 HiFi", - .cpu_dai = &davinci_i2s_dai, - .codec_dai = &pcm3008_dai, - .ops = &sffsdr_ops, -}; - -/* davinci-sffsdr audio machine driver */ -static struct snd_soc_card snd_soc_sffsdr = { - .name = "DaVinci SFFSDR", - .platform = &davinci_soc_platform, - .dai_link = &sffsdr_dai, - .num_links = 1, -}; - -/* sffsdr audio private data */ -static struct pcm3008_setup_data sffsdr_pcm3008_setup = { - .dem0_pin = GPIO(45), - .dem1_pin = GPIO(46), - .pdad_pin = GPIO(47), - .pdda_pin = GPIO(38), -}; - -/* sffsdr audio subsystem */ -static struct snd_soc_device sffsdr_snd_devdata = { - .card = &snd_soc_sffsdr, - .codec_dev = &soc_codec_dev_pcm3008, - .codec_data = &sffsdr_pcm3008_setup, -}; - -static struct resource sffsdr_snd_resources[] = { - { - .start = DAVINCI_MCBSP_BASE, - .end = DAVINCI_MCBSP_BASE + SZ_8K - 1, - .flags = IORESOURCE_MEM, - }, -}; - -static struct evm_snd_platform_data sffsdr_snd_data = { - .tx_dma_ch = DAVINCI_DMA_MCBSP_TX, - .rx_dma_ch = DAVINCI_DMA_MCBSP_RX, -}; - -static struct platform_device *sffsdr_snd_device; - -static int __init sffsdr_init(void) -{ - int ret; - - sffsdr_snd_device = platform_device_alloc("soc-audio", 0); - if (!sffsdr_snd_device) { - printk(KERN_ERR "platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata); - sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev; - sffsdr_snd_device->dev.platform_data = &sffsdr_snd_data; - - ret = platform_device_add_resources(sffsdr_snd_device, - sffsdr_snd_resources, - ARRAY_SIZE(sffsdr_snd_resources)); - if (ret) { - printk(KERN_ERR "platform device add ressources failed\n"); - goto error; - } - - ret = platform_device_add(sffsdr_snd_device); - if (ret) - goto error; - - return ret; - -error: - platform_device_put(sffsdr_snd_device); - return ret; -} - -static void __exit sffsdr_exit(void) -{ - platform_device_unregister(sffsdr_snd_device); -} - -module_init(sffsdr_init); -module_exit(sffsdr_exit); - -MODULE_AUTHOR("Hugo Villeneuve"); -MODULE_DESCRIPTION("Lyrtech SFFSDR ASoC driver"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 95c12b26fe37..8d73edc56102 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -20,7 +20,7 @@ config SND_SOC_MPC8610_HPCD config SND_SOC_MPC5200_I2S tristate "Freescale MPC5200 PSC in I2S mode driver" - depends on PPC_MPC52xx && PPC_BESTCOMM + depends on SND_SOC && PPC_MPC52xx && PPC_BESTCOMM select SND_SOC_OF_SIMPLE select PPC_BESTCOMM_GEN_BD help diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 646c807163ab..d2d3da9729f2 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -284,7 +284,7 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) * fsl_dma_new: initialize this PCM driver. * * This function is called when the codec driver calls snd_soc_new_pcms(), - * once for each .dai_link in the machine driver's snd_soc_card + * once for each .dai_link in the machine driver's snd_soc_machine * structure. */ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, @@ -853,18 +853,6 @@ int fsl_dma_configure(struct fsl_dma_info *dma_info) } EXPORT_SYMBOL_GPL(fsl_dma_configure); -static int __devinit fsl_soc_platform_init(void) -{ - return snd_soc_register_platform(&fsl_soc_platform); -} -module_init(fsl_soc_platform_init); - -static void __exit fsl_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&fsl_soc_platform); -} -module_exit(fsl_soc_platform_exit); - MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c6d6eb71dc1d..157a7895ffa1 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -266,8 +266,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) * If this is the first stream open, then grab the IRQ and program most of * the SSI registers. */ -static int fsl_ssi_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int fsl_ssi_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -412,8 +411,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the * clock master. */ -static int fsl_ssi_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int fsl_ssi_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -443,8 +441,7 @@ static int fsl_ssi_prepare(struct snd_pcm_substream *substream, * The DMA channel is in external master start and pause mode, which * means the SSI completely controls the flow of data. */ -static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -493,8 +490,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, * * Shutdown the SSI if there are no other substreams open. */ -static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void fsl_ssi_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -582,6 +578,8 @@ static struct snd_soc_dai fsl_ssi_dai_template = { .prepare = fsl_ssi_prepare, .shutdown = fsl_ssi_shutdown, .trigger = fsl_ssi_trigger, + }, + .dai_ops = { .set_sysclk = fsl_ssi_set_sysclk, .set_fmt = fsl_ssi_set_fmt, }, @@ -673,14 +671,6 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) fsl_ssi_dai->private_data = ssi_private; fsl_ssi_dai->name = ssi_private->name; fsl_ssi_dai->id = ssi_info->id; - fsl_ssi_dai->dev = ssi_info->dev; - - ret = snd_soc_register_dai(fsl_ssi_dai); - if (ret != 0) { - dev_err(ssi_info->dev, "failed to register DAI: %d\n", ret); - kfree(fsl_ssi_dai); - return NULL; - } return fsl_ssi_dai; } @@ -698,8 +688,6 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai) device_remove_file(ssi_private->dev, &ssi_private->dev_attr); - snd_soc_unregister_dai(&ssi_private->cpu_dai); - kfree(ssi_private); } EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 9eb1ce185bd0..94a02eaa4825 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -187,8 +187,7 @@ static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream) * If this is the first stream open, then grab the IRQ and program most of * the PSC registers. */ -static int psc_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int psc_i2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -221,8 +220,7 @@ static int psc_i2s_startup(struct snd_pcm_substream *substream, } static int psc_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -258,8 +256,7 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int psc_i2s_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int psc_i2s_hw_free(struct snd_pcm_substream *substream) { snd_pcm_set_runtime_buffer(substream, NULL); return 0; @@ -271,8 +268,7 @@ static int psc_i2s_hw_free(struct snd_pcm_substream *substream, * This function is called by ALSA to start, stop, pause, and resume the DMA * transfer of data. */ -static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -387,8 +383,7 @@ static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, * * Shutdown the PSC if there are no other substreams open. */ -static void psc_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void psc_i2s_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -469,6 +464,7 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) * psc_i2s_dai_template: template CPU Digital Audio Interface */ static struct snd_soc_dai psc_i2s_dai_template = { + .type = SND_SOC_DAI_I2S, .playback = { .channels_min = 2, .channels_max = 2, @@ -487,6 +483,8 @@ static struct snd_soc_dai psc_i2s_dai_template = { .hw_free = psc_i2s_hw_free, .shutdown = psc_i2s_shutdown, .trigger = psc_i2s_trigger, + }, + .dai_ops = { .set_sysclk = psc_i2s_set_sysclk, .set_fmt = psc_i2s_set_fmt, }, @@ -828,8 +826,6 @@ static int __devinit psc_i2s_of_probe(struct of_device *op, if (rc) dev_info(psc_i2s->dev, "error creating sysfs files\n"); - snd_soc_register_platform(&psc_i2s_pcm_soc_platform); - /* Tell the ASoC OF helpers about it */ of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node, &psc_i2s->dai); @@ -843,8 +839,6 @@ static int __devexit psc_i2s_of_remove(struct of_device *op) dev_dbg(&op->dev, "psc_i2s_remove()\n"); - snd_soc_unregister_platform(&psc_i2s_pcm_soc_platform); - bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task); bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task); diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index bcec3f60bad9..94f89debde1f 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -29,7 +29,7 @@ struct mpc8610_hpcd_data { struct snd_soc_device sound_devdata; struct snd_soc_dai_link dai; - struct snd_soc_card machine; + struct snd_soc_machine machine; unsigned int dai_format; unsigned int codec_clk_direction; unsigned int cpu_clk_direction; @@ -185,7 +185,7 @@ static struct snd_soc_ops mpc8610_hpcd_ops = { /** * mpc8610_hpcd_machine: ASoC machine data */ -static struct snd_soc_card mpc8610_hpcd_machine = { +static struct snd_soc_machine mpc8610_hpcd_machine = { .probe = mpc8610_hpcd_machine_probe, .remove = mpc8610_hpcd_machine_remove, .name = "MPC8610 HPCD", @@ -465,9 +465,9 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, goto error; } - machine_data->sound_devdata.card = &mpc8610_hpcd_machine; + machine_data->sound_devdata.machine = &mpc8610_hpcd_machine; machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270; - machine_data->machine.platform = &fsl_soc_platform; + machine_data->sound_devdata.platform = &fsl_soc_platform; sound_device->dev.platform_data = machine_data; diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c index 8bc5cd9e972f..0382fdac51cd 100644 --- a/sound/soc/fsl/soc-of-simple.c +++ b/sound/soc/fsl/soc-of-simple.c @@ -31,7 +31,7 @@ struct of_snd_soc_device { int id; struct list_head list; struct snd_soc_device device; - struct snd_soc_card card; + struct snd_soc_machine machine; struct snd_soc_dai_link dai_link; struct platform_device *pdev; struct device_node *platform_node; @@ -58,9 +58,9 @@ of_snd_soc_get_device(struct device_node *codec_node) /* Initialize the structure and add it to the global list */ of_soc->codec_node = codec_node; of_soc->id = of_snd_soc_next_index++; - of_soc->card.dai_link = &of_soc->dai_link; - of_soc->card.num_links = 1; - of_soc->device.card = &of_soc->card; + of_soc->machine.dai_link = &of_soc->dai_link; + of_soc->machine.num_links = 1; + of_soc->device.machine = &of_soc->machine; of_soc->dai_link.ops = &of_snd_soc_ops; list_add(&of_soc->list, &of_snd_soc_device_list); @@ -158,8 +158,8 @@ int of_snd_soc_register_platform(struct snd_soc_platform *platform, of_soc->platform_node = node; of_soc->dai_link.cpu_dai = cpu_dai; - of_soc->card.platform = platform; - of_soc->card.name = of_soc->dai_link.cpu_dai->name; + of_soc->device.platform = platform; + of_soc->machine.name = of_soc->dai_link.cpu_dai->name; /* Now try to register the SoC device */ of_snd_soc_register_device(of_soc); diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index a7b1d77b2105..8b7766b998d7 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -1,6 +1,6 @@ config SND_OMAP_SOC tristate "SoC Audio for the Texas Instruments OMAP chips" - depends on ARCH_OMAP + depends on ARCH_OMAP && SND_SOC config SND_OMAP_SOC_MCBSP tristate @@ -21,36 +21,3 @@ config SND_OMAP_SOC_OSK5912 select SND_SOC_TLV320AIC23 help Say Y if you want to add support for SoC audio on osk5912. - -config SND_OMAP_SOC_OVERO - tristate "SoC Audio support for Gumstix Overo" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OVERO - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on the Gumstix Overo. - -config SND_OMAP_SOC_OMAP2EVM - tristate "SoC Audio support for OMAP2EVM board" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP2EVM - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on the omap2evm board. - -config SND_OMAP_SOC_SDP3430 - tristate "SoC Audio support for Texas Instruments SDP3430" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on Texas Instruments - SDP3430. - -config SND_OMAP_SOC_OMAP3_PANDORA - tristate "SoC Audio support for OMAP3 Pandora" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on the OMAP3 Pandora. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 76fedd96e365..e09d1f297f64 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -8,14 +8,6 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o # OMAP Machine Support snd-soc-n810-objs := n810.o snd-soc-osk5912-objs := osk5912.o -snd-soc-overo-objs := overo.o -snd-soc-omap2evm-objs := omap2evm.o -snd-soc-sdp3430-objs := sdp3430.o -snd-soc-omap3pandora-objs := omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o -obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o -obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o -obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o -obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 25593fee9121..fae3ad36e0bf 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -70,13 +70,9 @@ static void n810_ext_control(struct snd_soc_codec *codec) static int n810_startup(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->socdev->codec; - snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); - n810_ext_control(codec); return clk_enable(sys_clkout2); } @@ -286,9 +282,8 @@ static struct snd_soc_dai_link n810_dai = { }; /* Audio machine driver */ -static struct snd_soc_card snd_soc_n810 = { +static struct snd_soc_machine snd_soc_machine_n810 = { .name = "N810", - .platform = &omap_soc_platform, .dai_link = &n810_dai, .num_links = 1, }; @@ -303,7 +298,8 @@ static struct aic3x_setup_data n810_aic33_setup = { /* Audio subsystem */ static struct snd_soc_device n810_snd_devdata = { - .card = &snd_soc_n810, + .machine = &snd_soc_machine_n810, + .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &n810_aic33_setup, }; diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 41cab2034163..8485a8a9d0ff 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -36,7 +36,9 @@ #include "omap-mcbsp.h" #include "omap-pcm.h" -#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) +#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_KNOT) struct omap_mcbsp_data { unsigned int bus_id; @@ -138,8 +140,7 @@ static const unsigned long omap34xx_mcbsp_port[][2] = { static const unsigned long omap34xx_mcbsp_port[][2] = {}; #endif -static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -152,8 +153,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, return err; } -static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -165,8 +165,7 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, } } -static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -195,15 +194,14 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, } static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; - int wlen, channels; + int wlen; unsigned long port; if (cpu_class_is_omap1()) { @@ -232,17 +230,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, return 0; } - channels = params_channels(params); - switch (channels) { + switch (params_channels(params)) { case 2: - /* Use dual-phase frames */ - regs->rcr2 |= RPHASE; - regs->xcr2 |= XPHASE; - case 1: - /* Set 1 word per (McBSP) frame */ - regs->rcr2 |= RFRLEN2(1 - 1); + /* Set 1 word per (McBPSP) frame and use dual-phase frames */ + regs->rcr2 |= RFRLEN2(1 - 1) | RPHASE; regs->rcr1 |= RFRLEN1(1 - 1); - regs->xcr2 |= XFRLEN2(1 - 1); + regs->xcr2 |= XFRLEN2(1 - 1) | XPHASE; regs->xcr1 |= XFRLEN1(1 - 1); break; default: @@ -271,8 +264,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, regs->srgr1 |= FWID(wlen - 1); break; case SND_SOC_DAIFMT_DSP_A: - regs->srgr2 |= FPER(wlen * channels - 1); - regs->srgr1 |= FWID(wlen * channels - 2); + regs->srgr2 |= FPER(wlen * 2 - 1); + regs->srgr1 |= FWID(wlen * 2 - 2); break; } @@ -459,16 +452,17 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, #define OMAP_MCBSP_DAI_BUILDER(link_id) \ { \ - .name = "omap-mcbsp-dai-"#link_id, \ + .name = "omap-mcbsp-dai-(link_id)", \ .id = (link_id), \ + .type = SND_SOC_DAI_I2S, \ .playback = { \ - .channels_min = 1, \ + .channels_min = 2, \ .channels_max = 2, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ .capture = { \ - .channels_min = 1, \ + .channels_min = 2, \ .channels_max = 2, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ @@ -478,6 +472,8 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, .shutdown = omap_mcbsp_dai_shutdown, \ .trigger = omap_mcbsp_dai_trigger, \ .hw_params = omap_mcbsp_dai_hw_params, \ + }, \ + .dai_ops = { \ .set_fmt = omap_mcbsp_dai_set_dai_fmt, \ .set_clkdiv = omap_mcbsp_dai_set_clkdiv, \ .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, \ @@ -499,19 +495,6 @@ struct snd_soc_dai omap_mcbsp_dai[] = { EXPORT_SYMBOL_GPL(omap_mcbsp_dai); -static int __devinit omap_mcbsp_init(void) -{ - return snd_soc_register_dais(omap_mcbsp_dai, - ARRAY_SIZE(omap_mcbsp_dai)); -} -module_init(omap_mcbsp_init); - -static void __exit omap_mcbsp_exit(void) -{ - snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai)); -} -module_exit(omap_mcbsp_exit); - MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>"); MODULE_DESCRIPTION("OMAP I2S SoC Interface"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 9940de296316..e9084fdd2082 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -354,18 +354,6 @@ struct snd_soc_platform omap_soc_platform = { }; EXPORT_SYMBOL_GPL(omap_soc_platform); -static int __devinit omap_soc_platform_init(void) -{ - return snd_soc_register_platform(&omap_soc_platform); -} -module_init(omap_soc_platform_init); - -static void __exit omap_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&omap_soc_platform); -} -module_exit(omap_soc_platform_exit); - MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>"); MODULE_DESCRIPTION("OMAP PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c deleted file mode 100644 index 0c2322dcf02a..000000000000 --- a/sound/soc/omap/omap2evm.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * omap2evm.c -- SoC audio machine driver for omap2evm board - * - * Author: Arun KS <arunks@mistralsolutions.com> - * - * Based on sound/soc/omap/overo.c by Steve Sakoman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <mach/mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" -#include "../codecs/twl4030.h" - -static int omap2evm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops omap2evm_ops = { - .hw_params = omap2evm_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap2evm_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, - .ops = &omap2evm_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_omap2evm = { - .name = "omap2evm", - .platform = &omap_soc_platform, - .dai_link = &omap2evm_dai, - .num_links = 1, -}; - -/* Audio subsystem */ -static struct snd_soc_device omap2evm_snd_devdata = { - .card = &snd_soc_omap2evm, - .codec_dev = &soc_codec_dev_twl4030, -}; - -static struct platform_device *omap2evm_snd_device; - -static int __init omap2evm_soc_init(void) -{ - int ret; - - if (!machine_is_omap2evm()) { - pr_debug("Not omap2evm!\n"); - return -ENODEV; - } - printk(KERN_INFO "omap2evm SoC init\n"); - - omap2evm_snd_device = platform_device_alloc("soc-audio", -1); - if (!omap2evm_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(omap2evm_snd_device, &omap2evm_snd_devdata); - omap2evm_snd_devdata.dev = &omap2evm_snd_device->dev; - *(unsigned int *)omap2evm_dai.cpu_dai->private_data = 1; /* McBSP2 */ - - ret = platform_device_add(omap2evm_snd_device); - if (ret) - goto err1; - - return 0; - -err1: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(omap2evm_snd_device); - - return ret; -} -module_init(omap2evm_soc_init); - -static void __exit omap2evm_soc_exit(void) -{ - platform_device_unregister(omap2evm_snd_device); -} -module_exit(omap2evm_soc_exit); - -MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); -MODULE_DESCRIPTION("ALSA SoC omap2evm"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c deleted file mode 100644 index fd24a4acd2f5..000000000000 --- a/sound/soc/omap/omap3beagle.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * omap3beagle.c -- SoC audio for OMAP3 Beagle - * - * Author: Steve Sakoman <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <mach/mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" -#include "../codecs/twl4030.h" - -static int omap3beagle_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->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops omap3beagle_ops = { - .hw_params = omap3beagle_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap3beagle_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, - .ops = &omap3beagle_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_omap3beagle = { - .name = "omap3beagle", - .platform = &omap_soc_platform, - .dai_link = &omap3beagle_dai, - .num_links = 1, -}; - -/* Audio subsystem */ -static struct snd_soc_device omap3beagle_snd_devdata = { - .card = &snd_soc_omap3beagle, - .codec_dev = &soc_codec_dev_twl4030, -}; - -static struct platform_device *omap3beagle_snd_device; - -static int __init omap3beagle_soc_init(void) -{ - int ret; - - if (!machine_is_omap3_beagle()) { - pr_debug("Not OMAP3 Beagle!\n"); - return -ENODEV; - } - pr_info("OMAP3 Beagle SoC init\n"); - - omap3beagle_snd_device = platform_device_alloc("soc-audio", -1); - if (!omap3beagle_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(omap3beagle_snd_device, &omap3beagle_snd_devdata); - omap3beagle_snd_devdata.dev = &omap3beagle_snd_device->dev; - *(unsigned int *)omap3beagle_dai.cpu_dai->private_data = 1; /* McBSP2 */ - - ret = platform_device_add(omap3beagle_snd_device); - if (ret) - goto err1; - - return 0; - -err1: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(omap3beagle_snd_device); - - return ret; -} - -static void __exit omap3beagle_soc_exit(void) -{ - platform_device_unregister(omap3beagle_snd_device); -} - -module_init(omap3beagle_soc_init); -module_exit(omap3beagle_soc_exit); - -MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>"); -MODULE_DESCRIPTION("ALSA SoC OMAP3 Beagle"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c deleted file mode 100644 index bd91594496b1..000000000000 --- a/sound/soc/omap/omap3pandora.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * omap3pandora.c -- SoC audio for Pandora Handheld Console - * - * Author: Gražvydas Ignotas <notasas@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/gpio.h> -#include <linux/delay.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" -#include "../codecs/twl4030.h" - -#define OMAP3_PANDORA_DAC_POWER_GPIO 118 -#define OMAP3_PANDORA_AMP_POWER_GPIO 14 - -#define PREFIX "ASoC omap3pandora: " - -static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai, - struct snd_soc_dai *cpu_dai, unsigned int fmt) -{ - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, fmt); - if (ret < 0) { - pr_err(PREFIX "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); - if (ret < 0) { - pr_err(PREFIX "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - pr_err(PREFIX "can't set codec system clock\n"); - return ret; - } - - /* Set McBSP clock to external */ - ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, 0, - SND_SOC_CLOCK_IN); - if (ret < 0) { - pr_err(PREFIX "can't set cpu system clock\n"); - return ret; - } - - ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8); - if (ret < 0) { - pr_err(PREFIX "can't set SRG clock divider\n"); - return ret; - } - - return 0; -} - -static int omap3pandora_out_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->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - - return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBS_CFS); -} - -static int omap3pandora_in_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->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - - return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS); -} - -static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - if (SND_SOC_DAPM_EVENT_ON(event)) { - gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1); - gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1); - } else { - gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0); - mdelay(1); - gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0); - } - - return 0; -} - -/* - * Audio paths on Pandora board: - * - * |O| ---> PCM DAC +-> AMP -> Headphone Jack - * |M| A +--------> Line Out - * |A| <~~clk~~+ - * |P| <--- TWL4030 <--------- Line In and MICs - */ -static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { - SND_SOC_DAPM_DAC("PCM DAC", "Playback", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM, - 0, 0, NULL, 0, omap3pandora_hp_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), -}; - -static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = { - SND_SOC_DAPM_MIC("Mic (Internal)", NULL), - SND_SOC_DAPM_MIC("Mic (external)", NULL), - SND_SOC_DAPM_LINE("Line In", NULL), -}; - -static const struct snd_soc_dapm_route omap3pandora_out_map[] = { - {"Headphone Amplifier", NULL, "PCM DAC"}, - {"Line Out", NULL, "PCM DAC"}, - {"Headphone Jack", NULL, "Headphone Amplifier"}, -}; - -static const struct snd_soc_dapm_route omap3pandora_in_map[] = { - {"INL", NULL, "Line In"}, - {"INR", NULL, "Line In"}, - {"INL", NULL, "Mic (Internal)"}, - {"INR", NULL, "Mic (external)"}, -}; - -static int omap3pandora_out_init(struct snd_soc_codec *codec) -{ - int ret; - - ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets, - ARRAY_SIZE(omap3pandora_out_dapm_widgets)); - if (ret < 0) - return ret; - - snd_soc_dapm_add_routes(codec, omap3pandora_out_map, - ARRAY_SIZE(omap3pandora_out_map)); - - return snd_soc_dapm_sync(codec); -} - -static int omap3pandora_in_init(struct snd_soc_codec *codec) -{ - int ret; - - ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets, - ARRAY_SIZE(omap3pandora_in_dapm_widgets)); - if (ret < 0) - return ret; - - snd_soc_dapm_add_routes(codec, omap3pandora_in_map, - ARRAY_SIZE(omap3pandora_in_map)); - - return snd_soc_dapm_sync(codec); -} - -static struct snd_soc_ops omap3pandora_out_ops = { - .hw_params = omap3pandora_out_hw_params, -}; - -static struct snd_soc_ops omap3pandora_in_ops = { - .hw_params = omap3pandora_in_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link omap3pandora_dai[] = { - { - .name = "PCM1773", - .stream_name = "HiFi Out", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, - .ops = &omap3pandora_out_ops, - .init = omap3pandora_out_init, - }, { - .name = "TWL4030", - .stream_name = "Line/Mic In", - .cpu_dai = &omap_mcbsp_dai[1], - .codec_dai = &twl4030_dai, - .ops = &omap3pandora_in_ops, - .init = omap3pandora_in_init, - } -}; - -/* SoC card */ -static struct snd_soc_card snd_soc_card_omap3pandora = { - .name = "omap3pandora", - .platform = &omap_soc_platform, - .dai_link = omap3pandora_dai, - .num_links = ARRAY_SIZE(omap3pandora_dai), -}; - -/* Audio subsystem */ -static struct snd_soc_device omap3pandora_snd_data = { - .card = &snd_soc_card_omap3pandora, - .codec_dev = &soc_codec_dev_twl4030, -}; - -static struct platform_device *omap3pandora_snd_device; - -static int __init omap3pandora_soc_init(void) -{ - int ret; - - if (!machine_is_omap3_pandora()) { - pr_debug(PREFIX "Not OMAP3 Pandora\n"); - return -ENODEV; - } - pr_info("OMAP3 Pandora SoC init\n"); - - ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power"); - if (ret) { - pr_err(PREFIX "Failed to get DAC power GPIO\n"); - return ret; - } - - ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0); - if (ret) { - pr_err(PREFIX "Failed to set DAC power GPIO direction\n"); - goto fail0; - } - - ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power"); - if (ret) { - pr_err(PREFIX "Failed to get amp power GPIO\n"); - goto fail0; - } - - ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0); - if (ret) { - pr_err(PREFIX "Failed to set amp power GPIO direction\n"); - goto fail1; - } - - omap3pandora_snd_device = platform_device_alloc("soc-audio", -1); - if (omap3pandora_snd_device == NULL) { - pr_err(PREFIX "Platform device allocation failed\n"); - ret = -ENOMEM; - goto fail1; - } - - platform_set_drvdata(omap3pandora_snd_device, &omap3pandora_snd_data); - omap3pandora_snd_data.dev = &omap3pandora_snd_device->dev; - *(unsigned int *)omap_mcbsp_dai[0].private_data = 1; /* McBSP2 */ - *(unsigned int *)omap_mcbsp_dai[1].private_data = 3; /* McBSP4 */ - - ret = platform_device_add(omap3pandora_snd_device); - if (ret) { - pr_err(PREFIX "Unable to add platform device\n"); - goto fail2; - } - - return 0; - -fail2: - platform_device_put(omap3pandora_snd_device); -fail1: - gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); -fail0: - gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); - return ret; -} -module_init(omap3pandora_soc_init); - -static void __exit omap3pandora_soc_exit(void) -{ - platform_device_unregister(omap3pandora_snd_device); - gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); - gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); -} -module_exit(omap3pandora_soc_exit); - -MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>"); -MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index 845bf41335b9..0fe733796898 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -143,16 +143,16 @@ static struct snd_soc_dai_link osk_dai = { }; /* Audio machine driver */ -static struct snd_soc_card snd_soc_card_osk = { +static struct snd_soc_machine snd_soc_machine_osk = { .name = "OSK5912", - .platform = &omap_soc_platform, .dai_link = &osk_dai, .num_links = 1, }; /* Audio subsystem */ static struct snd_soc_device osk_snd_devdata = { - .card = &snd_soc_card_osk, + .machine = &snd_soc_machine_osk, + .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_tlv320aic23, }; diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c deleted file mode 100644 index a72dc4e159e5..000000000000 --- a/sound/soc/omap/overo.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * overo.c -- SoC audio for Gumstix Overo - * - * Author: Steve Sakoman <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <mach/mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" -#include "../codecs/twl4030.h" - -static int overo_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->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops overo_ops = { - .hw_params = overo_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link overo_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, - .ops = &overo_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_card snd_soc_card_overo = { - .name = "overo", - .platform = &omap_soc_platform, - .dai_link = &overo_dai, - .num_links = 1, -}; - -/* Audio subsystem */ -static struct snd_soc_device overo_snd_devdata = { - .card = &snd_soc_card_overo, - .codec_dev = &soc_codec_dev_twl4030, -}; - -static struct platform_device *overo_snd_device; - -static int __init overo_soc_init(void) -{ - int ret; - - if (!machine_is_overo()) { - pr_debug("Not Overo!\n"); - return -ENODEV; - } - printk(KERN_INFO "overo SoC init\n"); - - overo_snd_device = platform_device_alloc("soc-audio", -1); - if (!overo_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(overo_snd_device, &overo_snd_devdata); - overo_snd_devdata.dev = &overo_snd_device->dev; - *(unsigned int *)overo_dai.cpu_dai->private_data = 1; /* McBSP2 */ - - ret = platform_device_add(overo_snd_device); - if (ret) - goto err1; - - return 0; - -err1: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(overo_snd_device); - - return ret; -} -module_init(overo_soc_init); - -static void __exit overo_soc_exit(void) -{ - platform_device_unregister(overo_snd_device); -} -module_exit(overo_soc_exit); - -MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>"); -MODULE_DESCRIPTION("ALSA SoC overo"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c deleted file mode 100644 index ad97836818b1..000000000000 --- a/sound/soc/omap/sdp3430.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * sdp3430.c -- SoC audio for TI OMAP3430 SDP - * - * Author: Misael Lopez Cruz <x0052729@ti.com> - * - * Based on: - * Author: Steve Sakoman <steve@sakoman.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> -#include <mach/hardware.h> -#include <mach/gpio.h> -#include <mach/mcbsp.h> - -#include "omap-mcbsp.h" -#include "omap-pcm.h" -#include "../codecs/twl4030.h" - -static int sdp3430_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->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret; - - /* Set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set codec DAI configuration\n"); - return ret; - } - - /* Set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM); - if (ret < 0) { - printk(KERN_ERR "can't set cpu DAI configuration\n"); - return ret; - } - - /* Set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, - SND_SOC_CLOCK_IN); - if (ret < 0) { - printk(KERN_ERR "can't set codec system clock\n"); - return ret; - } - - return 0; -} - -static struct snd_soc_ops sdp3430_ops = { - .hw_params = sdp3430_hw_params, -}; - -/* Digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link sdp3430_dai = { - .name = "TWL4030", - .stream_name = "TWL4030", - .cpu_dai = &omap_mcbsp_dai[0], - .codec_dai = &twl4030_dai, - .ops = &sdp3430_ops, -}; - -/* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_sdp3430 = { - .name = "SDP3430", - .platform = &omap_soc_platform, - .dai_link = &sdp3430_dai, - .num_links = 1, -}; - -/* Audio subsystem */ -static struct snd_soc_device sdp3430_snd_devdata = { - .machine = &snd_soc_machine_sdp3430, - .codec_dev = &soc_codec_dev_twl4030, -}; - -static struct platform_device *sdp3430_snd_device; - -static int __init sdp3430_soc_init(void) -{ - int ret; - - if (!machine_is_omap_3430sdp()) { - pr_debug("Not SDP3430!\n"); - return -ENODEV; - } - printk(KERN_INFO "SDP3430 SoC init\n"); - - sdp3430_snd_device = platform_device_alloc("soc-audio", -1); - if (!sdp3430_snd_device) { - printk(KERN_ERR "Platform device allocation failed\n"); - return -ENOMEM; - } - - platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata); - sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev; - *(unsigned int *)sdp3430_dai.cpu_dai->private_data = 1; /* McBSP2 */ - - ret = platform_device_add(sdp3430_snd_device); - if (ret) - goto err1; - - return 0; - -err1: - printk(KERN_ERR "Unable to add platform device\n"); - platform_device_put(sdp3430_snd_device); - - return ret; -} -module_init(sdp3430_soc_init); - -static void __exit sdp3430_soc_exit(void) -{ - platform_device_unregister(sdp3430_snd_device); -} -module_exit(sdp3430_soc_exit); - -MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>"); -MODULE_DESCRIPTION("ALSA SoC SDP3430"); -MODULE_LICENSE("GPL"); - diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index f82e10699471..f8c1cdd940ac 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -21,9 +21,6 @@ config SND_PXA2XX_SOC_AC97 config SND_PXA2XX_SOC_I2S tristate -config SND_PXA_SOC_SSP - tristate - config SND_PXA2XX_SOC_CORGI tristate "SoC Audio support for Sharp Zaurus SL-C7x0" depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx @@ -78,22 +75,3 @@ config SND_PXA2XX_SOC_EM_X270 help Say Y if you want to add support for SoC audio on CompuLab EM-x270. - -config SND_PXA2XX_SOC_PALM27X - bool "SoC Audio support for Palm T|X, T5 and LifeDrive" - depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || MACH_PALMT5) - select SND_PXA2XX_SOC_AC97 - select SND_SOC_WM9712 - help - Say Y if you want to add support for SoC audio on - Palm T|X, T5 or LifeDrive handheld computer. - -config SND_SOC_ZYLONITE - tristate "SoC Audio support for Marvell Zylonite" - depends on SND_PXA2XX_SOC && MACH_ZYLONITE - select SND_PXA2XX_SOC_AC97 - select SND_PXA_SOC_SSP - select SND_SOC_WM9713 - help - Say Y if you want to add support for SoC audio on the - Marvell Zylonite reference platform. diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 08a9f2797729..5bc8edf9dca9 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -2,12 +2,10 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o -snd-soc-pxa-ssp-objs := pxa-ssp.o obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o -obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o # PXA Machine Support snd-soc-corgi-objs := corgi.o @@ -16,8 +14,6 @@ snd-soc-tosa-objs := tosa.o snd-soc-e800-objs := e800_wm9712.o snd-soc-spitz-objs := spitz.o snd-soc-em-x270-objs := em-x270.o -snd-soc-palm27x-objs := palm27x.o -snd-soc-zylonite-objs := zylonite.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o @@ -25,5 +21,3 @@ obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o -obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o -obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 1ba25a559524..2718eaf7895f 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -108,11 +108,15 @@ static int corgi_startup(struct snd_pcm_substream *substream) } /* we need to unmute the HP at shutdown as the mute burns power on corgi */ -static void corgi_shutdown(struct snd_pcm_substream *substream) +static int corgi_shutdown(struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + /* set = unmute headphone */ gpio_set_value(CORGI_GPIO_MUTE_L, 1); gpio_set_value(CORGI_GPIO_MUTE_R, 1); + return 0; } static int corgi_hw_params(struct snd_pcm_substream *substream, @@ -310,9 +314,8 @@ static struct snd_soc_dai_link corgi_dai = { }; /* corgi audio machine driver */ -static struct snd_soc_card snd_soc_corgi = { +static struct snd_soc_machine snd_soc_machine_corgi = { .name = "Corgi", - .platform = &pxa2xx_soc_platform, .dai_link = &corgi_dai, .num_links = 1, }; @@ -325,7 +328,8 @@ static struct wm8731_setup_data corgi_wm8731_setup = { /* corgi audio subsystem */ static struct snd_soc_device corgi_snd_devdata = { - .card = &snd_soc_corgi, + .machine = &snd_soc_machine_corgi, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &corgi_wm8731_setup, }; diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 2e3386dfa0f0..6781c5be242f 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -29,7 +29,7 @@ #include "pxa2xx-pcm.h" #include "pxa2xx-ac97.h" -static struct snd_soc_card e800; +static struct snd_soc_machine e800; static struct snd_soc_dai_link e800_dai[] = { { @@ -40,15 +40,15 @@ static struct snd_soc_dai_link e800_dai[] = { }, }; -static struct snd_soc_card e800 = { +static struct snd_soc_machine e800 = { .name = "Toshiba e800", - .platform = &pxa2xx_soc_platform, .dai_link = e800_dai, .num_links = ARRAY_SIZE(e800_dai), }; static struct snd_soc_device e800_snd_devdata = { - .card = &e800, + .machine = &e800, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index fe4a729ea648..e6ff6929ab4b 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -23,6 +23,7 @@ #include <linux/moduleparam.h> #include <linux/device.h> +#include <sound/driver.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/soc.h> @@ -52,15 +53,15 @@ static struct snd_soc_dai_link em_x270_dai[] = { }, }; -static struct snd_soc_card em_x270 = { +static struct snd_soc_machine em_x270 = { .name = "EM-X270", - .platform = &pxa2xx_soc_platform, .dai_link = em_x270_dai, .num_links = ARRAY_SIZE(em_x270_dai), }; static struct snd_soc_device em_x270_snd_devdata = { - .card = &em_x270, + .machine = &em_x270, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c deleted file mode 100644 index 4a9cf3083af0..000000000000 --- a/sound/soc/pxa/palm27x.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * linux/sound/soc/pxa/palm27x.c - * - * SoC Audio driver for Palm T|X, T5 and LifeDrive - * - * based on tosa.c - * - * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/device.h> -#include <linux/gpio.h> -#include <linux/interrupt.h> -#include <linux/irq.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include <asm/mach-types.h> -#include <mach/audio.h> -#include <mach/palmasoc.h> - -#include "../codecs/wm9712.h" -#include "pxa2xx-pcm.h" -#include "pxa2xx-ac97.h" - -static int palm27x_jack_func = 1; -static int palm27x_spk_func = 1; -static int palm27x_ep_gpio = -1; - -static void palm27x_ext_control(struct snd_soc_codec *codec) -{ - if (!palm27x_spk_func) - snd_soc_dapm_enable_pin(codec, "Speaker"); - else - snd_soc_dapm_disable_pin(codec, "Speaker"); - - if (!palm27x_jack_func) - snd_soc_dapm_enable_pin(codec, "Headphone Jack"); - else - snd_soc_dapm_disable_pin(codec, "Headphone Jack"); - - snd_soc_dapm_sync(codec); -} - -static int palm27x_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->socdev->codec; - - /* check the jack status at stream startup */ - palm27x_ext_control(codec); - return 0; -} - -static struct snd_soc_ops palm27x_ops = { - .startup = palm27x_startup, -}; - -static irqreturn_t palm27x_interrupt(int irq, void *v) -{ - palm27x_spk_func = gpio_get_value(palm27x_ep_gpio); - palm27x_jack_func = !palm27x_spk_func; - return IRQ_HANDLED; -} - -static int palm27x_get_jack(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = palm27x_jack_func; - return 0; -} - -static int palm27x_set_jack(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - - if (palm27x_jack_func == ucontrol->value.integer.value[0]) - return 0; - - palm27x_jack_func = ucontrol->value.integer.value[0]; - palm27x_ext_control(codec); - return 1; -} - -static int palm27x_get_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.integer.value[0] = palm27x_spk_func; - return 0; -} - -static int palm27x_set_spk(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - - if (palm27x_spk_func == ucontrol->value.integer.value[0]) - return 0; - - palm27x_spk_func = ucontrol->value.integer.value[0]; - palm27x_ext_control(codec); - return 1; -} - -/* PalmTX machine dapm widgets */ -static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -/* PalmTX audio map */ -static const struct snd_soc_dapm_route audio_map[] = { - /* headphone connected to HPOUTL, HPOUTR */ - {"Headphone Jack", NULL, "HPOUTL"}, - {"Headphone Jack", NULL, "HPOUTR"}, - - /* ext speaker connected to ROUT2, LOUT2 */ - {"Speaker", NULL, "LOUT2"}, - {"Speaker", NULL, "ROUT2"}, -}; - -static const char *jack_function[] = {"Headphone", "Off"}; -static const char *spk_function[] = {"On", "Off"}; -static const struct soc_enum palm27x_enum[] = { - SOC_ENUM_SINGLE_EXT(2, jack_function), - SOC_ENUM_SINGLE_EXT(2, spk_function), -}; - -static const struct snd_kcontrol_new palm27x_controls[] = { - SOC_ENUM_EXT("Jack Function", palm27x_enum[0], palm27x_get_jack, - palm27x_set_jack), - SOC_ENUM_EXT("Speaker Function", palm27x_enum[1], palm27x_get_spk, - palm27x_set_spk), -}; - -static int palm27x_ac97_init(struct snd_soc_codec *codec) -{ - int i, err; - - snd_soc_dapm_nc_pin(codec, "OUT3"); - snd_soc_dapm_nc_pin(codec, "MONOOUT"); - - /* add palm27x specific controls */ - for (i = 0; i < ARRAY_SIZE(palm27x_controls); i++) { - err = snd_ctl_add(codec->card, - snd_soc_cnew(&palm27x_controls[i], - codec, NULL)); - if (err < 0) - return err; - } - - /* add palm27x specific widgets */ - snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets, - ARRAY_SIZE(palm27x_dapm_widgets)); - - /* set up palm27x specific audio path audio_map */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - snd_soc_dapm_sync(codec); - return 0; -} - -static struct snd_soc_dai_link palm27x_dai[] = { -{ - .name = "AC97 HiFi", - .stream_name = "AC97 HiFi", - .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], - .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], - .init = palm27x_ac97_init, - .ops = &palm27x_ops, -}, -{ - .name = "AC97 Aux", - .stream_name = "AC97 Aux", - .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], - .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], - .ops = &palm27x_ops, -}, -}; - -static struct snd_soc_card palm27x_asoc = { - .name = "Palm/PXA27x", - .platform = &pxa2xx_soc_platform, - .dai_link = palm27x_dai, - .num_links = ARRAY_SIZE(palm27x_dai), -}; - -static struct snd_soc_device palm27x_snd_devdata = { - .card = &palm27x_asoc, - .codec_dev = &soc_codec_dev_wm9712, -}; - -static struct platform_device *palm27x_snd_device; - -static int __init palm27x_asoc_init(void) -{ - int ret; - - if (!(machine_is_palmtx() || machine_is_palmt5() || - machine_is_palmld())) - return -ENODEV; - - ret = gpio_request(palm27x_ep_gpio, "Headphone Jack"); - if (ret) - return ret; - ret = gpio_direction_input(palm27x_ep_gpio); - if (ret) - goto err_alloc; - - if (request_irq(gpio_to_irq(palm27x_ep_gpio), palm27x_interrupt, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "Headphone jack", NULL)) - goto err_alloc; - - palm27x_snd_device = platform_device_alloc("soc-audio", -1); - if (!palm27x_snd_device) { - ret = -ENOMEM; - goto err_dev; - } - - platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata); - palm27x_snd_devdata.dev = &palm27x_snd_device->dev; - ret = platform_device_add(palm27x_snd_device); - - if (ret != 0) - goto put_device; - - return 0; - -put_device: - platform_device_put(palm27x_snd_device); -err_dev: - free_irq(gpio_to_irq(palm27x_ep_gpio), NULL); -err_alloc: - gpio_free(palm27x_ep_gpio); - - return ret; -} - -static void __exit palm27x_asoc_exit(void) -{ - free_irq(gpio_to_irq(palm27x_ep_gpio), NULL); - gpio_free(palm27x_ep_gpio); - platform_device_unregister(palm27x_snd_device); -} - -void __init palm27x_asoc_set_pdata(struct palm27x_asoc_info *data) -{ - palm27x_ep_gpio = data->jack_gpio; -} - -module_init(palm27x_asoc_init); -module_exit(palm27x_asoc_exit); - -/* Module information */ -MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); -MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 6e9827189fff..4d9930c52789 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -276,9 +276,8 @@ static struct snd_soc_dai_link poodle_dai = { }; /* poodle audio machine driver */ -static struct snd_soc_card snd_soc_poodle = { +static struct snd_soc_machine snd_soc_machine_poodle = { .name = "Poodle", - .platform = &pxa2xx_soc_platform, .dai_link = &poodle_dai, .num_links = 1, }; @@ -291,7 +290,8 @@ static struct wm8731_setup_data poodle_wm8731_setup = { /* poodle audio subsystem */ static struct snd_soc_device poodle_snd_devdata = { - .card = &snd_soc_poodle, + .machine = &snd_soc_machine_poodle, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &poodle_wm8731_setup, }; diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c deleted file mode 100644 index 3587f2fae5f1..000000000000 --- a/sound/soc/pxa/pxa-ssp.c +++ /dev/null @@ -1,931 +0,0 @@ -#define DEBUG -/* - * pxa-ssp.c -- ALSA Soc Audio Layer - * - * Copyright 2005,2008 Wolfson Microelectronics PLC. - * Author: Liam Girdwood - * Mark Brown <broonie@opensource.wolfsonmicro.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. - * - * TODO: - * o Test network mode for > 16bit sample size - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/initval.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/pxa2xx-lib.h> - -#include <mach/hardware.h> -#include <mach/pxa-regs.h> -#include <mach/regs-ssp.h> -#include <mach/audio.h> -#include <mach/ssp.h> - -#include "pxa2xx-pcm.h" -#include "pxa-ssp.h" - -/* - * SSP audio private data - */ -struct ssp_priv { - struct ssp_dev dev; - unsigned int sysclk; - int dai_fmt; -#ifdef CONFIG_PM - struct ssp_state state; -#endif -}; - -#define PXA2xx_SSP1_BASE 0x41000000 -#define PXA27x_SSP2_BASE 0x41700000 -#define PXA27x_SSP3_BASE 0x41900000 -#define PXA3xx_SSP4_BASE 0x41a00000 - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_out = { - .name = "SSP1 PCM Mono out", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(14), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_in = { - .name = "SSP1 PCM Mono in", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(13), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_out = { - .name = "SSP1 PCM Stereo out", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(14), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_in = { - .name = "SSP1 PCM Stereo in", - .dev_addr = PXA2xx_SSP1_BASE + SSDR, - .drcmr = &DRCMR(13), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_out = { - .name = "SSP2 PCM Mono out", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(16), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_in = { - .name = "SSP2 PCM Mono in", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(15), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_out = { - .name = "SSP2 PCM Stereo out", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(16), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_in = { - .name = "SSP2 PCM Stereo in", - .dev_addr = PXA27x_SSP2_BASE + SSDR, - .drcmr = &DRCMR(15), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_out = { - .name = "SSP3 PCM Mono out", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_in = { - .name = "SSP3 PCM Mono in", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_out = { - .name = "SSP3 PCM Stereo out", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_in = { - .name = "SSP3 PCM Stereo in", - .dev_addr = PXA27x_SSP3_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_out = { - .name = "SSP4 PCM Mono out", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_in = { - .name = "SSP4 PCM Mono in", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH2, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_out = { - .name = "SSP4 PCM Stereo out", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(67), - .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_in = { - .name = "SSP4 PCM Stereo in", - .dev_addr = PXA3xx_SSP4_BASE + SSDR, - .drcmr = &DRCMR(66), - .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | - DCMD_BURST16 | DCMD_WIDTH4, -}; - -static void dump_registers(struct ssp_device *ssp) -{ - dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n", - ssp_read_reg(ssp, SSCR0), ssp_read_reg(ssp, SSCR1), - ssp_read_reg(ssp, SSTO)); - - dev_dbg(&ssp->pdev->dev, "SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x\n", - ssp_read_reg(ssp, SSPSP), ssp_read_reg(ssp, SSSR), - ssp_read_reg(ssp, SSACD)); -} - -static struct pxa2xx_pcm_dma_params *ssp_dma_params[4][4] = { - { - &pxa_ssp1_pcm_mono_out, &pxa_ssp1_pcm_mono_in, - &pxa_ssp1_pcm_stereo_out, &pxa_ssp1_pcm_stereo_in, - }, - { - &pxa_ssp2_pcm_mono_out, &pxa_ssp2_pcm_mono_in, - &pxa_ssp2_pcm_stereo_out, &pxa_ssp2_pcm_stereo_in, - }, - { - &pxa_ssp3_pcm_mono_out, &pxa_ssp3_pcm_mono_in, - &pxa_ssp3_pcm_stereo_out, &pxa_ssp3_pcm_stereo_in, - }, - { - &pxa_ssp4_pcm_mono_out, &pxa_ssp4_pcm_mono_in, - &pxa_ssp4_pcm_stereo_out, &pxa_ssp4_pcm_stereo_in, - }, -}; - -static int pxa_ssp_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct ssp_priv *priv = cpu_dai->private_data; - int ret = 0; - - if (!cpu_dai->active) { - ret = ssp_init(&priv->dev, cpu_dai->id + 1, SSP_NO_IRQ); - if (ret < 0) - return ret; - ssp_disable(&priv->dev); - } - return ret; -} - -static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct ssp_priv *priv = cpu_dai->private_data; - - if (!cpu_dai->active) { - ssp_disable(&priv->dev); - ssp_exit(&priv->dev); - } -} - -#ifdef CONFIG_PM - -static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) -{ - struct ssp_priv *priv = cpu_dai->private_data; - - if (!cpu_dai->active) - return 0; - - ssp_save_state(&priv->dev, &priv->state); - clk_disable(priv->dev.ssp->clk); - return 0; -} - -static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) -{ - struct ssp_priv *priv = cpu_dai->private_data; - - if (!cpu_dai->active) - return 0; - - clk_enable(priv->dev.ssp->clk); - ssp_restore_state(&priv->dev, &priv->state); - ssp_enable(&priv->dev); - - return 0; -} - -#else -#define pxa_ssp_suspend NULL -#define pxa_ssp_resume NULL -#endif - -/** - * ssp_set_clkdiv - set SSP clock divider - * @div: serial clock rate divider - */ -static void ssp_set_scr(struct ssp_dev *dev, u32 div) -{ - struct ssp_device *ssp = dev->ssp; - u32 sscr0 = ssp_read_reg(dev->ssp, SSCR0) & ~SSCR0_SCR; - - ssp_write_reg(ssp, SSCR0, (sscr0 | SSCR0_SerClkDiv(div))); -} - -/* - * Set the SSP ports SYSCLK. - */ -static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - int val; - - u32 sscr0 = ssp_read_reg(ssp, SSCR0) & - ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); - - dev_dbg(&ssp->pdev->dev, - "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n", - cpu_dai->id, clk_id, freq); - - switch (clk_id) { - case PXA_SSP_CLK_NET_PLL: - sscr0 |= SSCR0_MOD; - break; - case PXA_SSP_CLK_PLL: - /* Internal PLL is fixed */ - if (cpu_is_pxa25x()) - priv->sysclk = 1843200; - else - priv->sysclk = 13000000; - break; - case PXA_SSP_CLK_EXT: - priv->sysclk = freq; - sscr0 |= SSCR0_ECS; - break; - case PXA_SSP_CLK_NET: - priv->sysclk = freq; - sscr0 |= SSCR0_NCS | SSCR0_MOD; - break; - case PXA_SSP_CLK_AUDIO: - priv->sysclk = 0; - ssp_set_scr(&priv->dev, 1); - sscr0 |= SSCR0_ADC; - break; - default: - return -ENODEV; - } - - /* The SSP clock must be disabled when changing SSP clock mode - * on PXA2xx. On PXA3xx it must be enabled when doing so. */ - if (!cpu_is_pxa3xx()) - clk_disable(priv->dev.ssp->clk); - val = ssp_read_reg(ssp, SSCR0) | sscr0; - ssp_write_reg(ssp, SSCR0, val); - if (!cpu_is_pxa3xx()) - clk_enable(priv->dev.ssp->clk); - - return 0; -} - -/* - * Set the SSP clock dividers. - */ -static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - int val; - - switch (div_id) { - case PXA_SSP_AUDIO_DIV_ACDS: - val = (ssp_read_reg(ssp, SSACD) & ~0x7) | SSACD_ACDS(div); - ssp_write_reg(ssp, SSACD, val); - break; - case PXA_SSP_AUDIO_DIV_SCDB: - val = ssp_read_reg(ssp, SSACD); - val &= ~SSACD_SCDB; -#if defined(CONFIG_PXA3xx) - if (cpu_is_pxa3xx()) - val &= ~SSACD_SCDX8; -#endif - switch (div) { - case PXA_SSP_CLK_SCDB_1: - val |= SSACD_SCDB; - break; - case PXA_SSP_CLK_SCDB_4: - break; -#if defined(CONFIG_PXA3xx) - case PXA_SSP_CLK_SCDB_8: - if (cpu_is_pxa3xx()) - val |= SSACD_SCDX8; - else - return -EINVAL; - break; -#endif - default: - return -EINVAL; - } - ssp_write_reg(ssp, SSACD, val); - break; - case PXA_SSP_DIV_SCR: - ssp_set_scr(&priv->dev, div); - break; - default: - return -ENODEV; - } - - return 0; -} - -/* - * Configure the PLL frequency pxa27x and (afaik - pxa320 only) - */ -static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - u32 ssacd = ssp_read_reg(ssp, SSACD) & ~0x70; - -#if defined(CONFIG_PXA3xx) - if (cpu_is_pxa3xx()) - ssp_write_reg(ssp, SSACDD, 0); -#endif - - switch (freq_out) { - case 5622000: - break; - case 11345000: - ssacd |= (0x1 << 4); - break; - case 12235000: - ssacd |= (0x2 << 4); - break; - case 14857000: - ssacd |= (0x3 << 4); - break; - case 32842000: - ssacd |= (0x4 << 4); - break; - case 48000000: - ssacd |= (0x5 << 4); - break; - case 0: - /* Disable */ - break; - - default: -#ifdef CONFIG_PXA3xx - /* PXA3xx has a clock ditherer which can be used to generate - * a wider range of frequencies - calculate a value for it. - */ - if (cpu_is_pxa3xx()) { - u32 val; - u64 tmp = 19968; - tmp *= 1000000; - do_div(tmp, freq_out); - val = tmp; - - val = (val << 16) | 64;; - ssp_write_reg(ssp, SSACDD, val); - - ssacd |= (0x6 << 4); - - dev_dbg(&ssp->pdev->dev, - "Using SSACDD %x to supply %dHz\n", - val, freq_out); - break; - } -#endif - - return -EINVAL; - } - - ssp_write_reg(ssp, SSACD, ssacd); - - return 0; -} - -/* - * Set the active slots in TDM/Network mode - */ -static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, - unsigned int mask, int slots) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - u32 sscr0; - - sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7); - - /* set number of active slots */ - sscr0 |= SSCR0_SlotsPerFrm(slots); - ssp_write_reg(ssp, SSCR0, sscr0); - - /* set active slot mask */ - ssp_write_reg(ssp, SSTSA, mask); - ssp_write_reg(ssp, SSRSA, mask); - return 0; -} - -/* - * Tristate the SSP DAI lines - */ -static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai, - int tristate) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - u32 sscr1; - - sscr1 = ssp_read_reg(ssp, SSCR1); - if (tristate) - sscr1 &= ~SSCR1_TTE; - else - sscr1 |= SSCR1_TTE; - ssp_write_reg(ssp, SSCR1, sscr1); - - return 0; -} - -/* - * Set up the SSP DAI format. - * The SSP Port must be inactive before calling this function as the - * physical interface format is changed. - */ -static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - u32 sscr0; - u32 sscr1; - u32 sspsp; - - /* reset port settings */ - sscr0 = ssp_read_reg(ssp, SSCR0) & - (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); - sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7); - sspsp = 0; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR; - break; - case SND_SOC_DAIFMT_CBM_CFS: - sscr1 |= SSCR1_SCLKDIR; - break; - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } - - ssp_write_reg(ssp, SSCR0, sscr0); - ssp_write_reg(ssp, SSCR1, sscr1); - ssp_write_reg(ssp, SSPSP, sspsp); - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - sscr0 |= SSCR0_MOD | SSCR0_PSP; - sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - sspsp |= SSPSP_FSRT; - break; - case SND_SOC_DAIFMT_NB_IF: - sspsp |= SSPSP_SFRMP | SSPSP_FSRT; - break; - case SND_SOC_DAIFMT_IB_IF: - sspsp |= SSPSP_SFRMP; - break; - default: - return -EINVAL; - } - break; - - case SND_SOC_DAIFMT_DSP_A: - sspsp |= SSPSP_FSRT; - case SND_SOC_DAIFMT_DSP_B: - sscr0 |= SSCR0_MOD | SSCR0_PSP; - sscr1 |= SSCR1_TRAIL | SSCR1_RWOT; - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - sspsp |= SSPSP_SFRMP; - break; - case SND_SOC_DAIFMT_IB_IF: - break; - default: - return -EINVAL; - } - break; - - default: - return -EINVAL; - } - - ssp_write_reg(ssp, SSCR0, sscr0); - ssp_write_reg(ssp, SSCR1, sscr1); - ssp_write_reg(ssp, SSPSP, sspsp); - - dump_registers(ssp); - - /* Since we are configuring the timings for the format by hand - * we have to defer some things until hw_params() where we - * know parameters like the sample size. - */ - priv->dai_fmt = fmt; - - return 0; -} - -/* - * Set the SSP audio DMA parameters and sample size. - * Can be called multiple times by oss emulation. - */ -static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - int dma = 0, chn = params_channels(params); - u32 sscr0; - u32 sspsp; - int width = snd_pcm_format_physical_width(params_format(params)); - - /* select correct DMA params */ - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - dma = 1; /* capture DMA offset is 1,3 */ - if (chn == 2) - dma += 2; /* stereo DMA offset is 2, mono is 0 */ - cpu_dai->dma_data = ssp_dma_params[cpu_dai->id][dma]; - - dev_dbg(&ssp->pdev->dev, "pxa_ssp_hw_params: dma %d\n", dma); - - /* we can only change the settings if the port is not in use */ - if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) - return 0; - - /* clear selected SSP bits */ - sscr0 = ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS); - ssp_write_reg(ssp, SSCR0, sscr0); - - /* bit size */ - sscr0 = ssp_read_reg(ssp, SSCR0); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: -#ifdef CONFIG_PXA3xx - if (cpu_is_pxa3xx()) - sscr0 |= SSCR0_FPCKE; -#endif - sscr0 |= SSCR0_DataSize(16); - if (params_channels(params) > 1) - sscr0 |= SSCR0_EDSS; - break; - case SNDRV_PCM_FORMAT_S24_LE: - sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8)); - /* we must be in network mode (2 slots) for 24 bit stereo */ - break; - case SNDRV_PCM_FORMAT_S32_LE: - sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16)); - /* we must be in network mode (2 slots) for 32 bit stereo */ - break; - } - ssp_write_reg(ssp, SSCR0, sscr0); - - switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - /* Cleared when the DAI format is set */ - sspsp = ssp_read_reg(ssp, SSPSP) | SSPSP_SFRMWDTH(width); - ssp_write_reg(ssp, SSPSP, sspsp); - break; - default: - break; - } - - /* We always use a network mode so we always require TDM slots - * - complain loudly and fail if they've not been set up yet. - */ - if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) { - dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); - return -EINVAL; - } - - dump_registers(ssp); - - return 0; -} - -static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - int ret = 0; - struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; - int val; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: - ssp_enable(&priv->dev); - break; - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - val = ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= SSCR1_TSRE; - else - val |= SSCR1_RSRE; - ssp_write_reg(ssp, SSCR1, val); - val = ssp_read_reg(ssp, SSSR); - ssp_write_reg(ssp, SSSR, val); - break; - case SNDRV_PCM_TRIGGER_START: - val = ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= SSCR1_TSRE; - else - val |= SSCR1_RSRE; - ssp_write_reg(ssp, SSCR1, val); - ssp_enable(&priv->dev); - break; - case SNDRV_PCM_TRIGGER_STOP: - val = ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val &= ~SSCR1_TSRE; - else - val &= ~SSCR1_RSRE; - ssp_write_reg(ssp, SSCR1, val); - break; - case SNDRV_PCM_TRIGGER_SUSPEND: - ssp_disable(&priv->dev); - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - val = ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val &= ~SSCR1_TSRE; - else - val &= ~SSCR1_RSRE; - ssp_write_reg(ssp, SSCR1, val); - break; - - default: - ret = -EINVAL; - } - - dump_registers(ssp); - - return ret; -} - -static int pxa_ssp_probe(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct ssp_priv *priv; - int ret; - - priv = kzalloc(sizeof(struct ssp_priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->dev.ssp = ssp_request(dai->id, "SoC audio"); - if (priv->dev.ssp == NULL) { - ret = -ENODEV; - goto err_priv; - } - - dai->private_data = priv; - - return 0; - -err_priv: - kfree(priv); - return ret; -} - -static void pxa_ssp_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct ssp_priv *priv = dai->private_data; - ssp_free(priv->dev.ssp); -} - -#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) - -#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) - -struct snd_soc_dai pxa_ssp_dai[] = { - { - .name = "pxa2xx-ssp1", - .id = 0, - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, - .suspend = pxa_ssp_suspend, - .resume = pxa_ssp_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .ops = { - .startup = pxa_ssp_startup, - .shutdown = pxa_ssp_shutdown, - .trigger = pxa_ssp_trigger, - .hw_params = pxa_ssp_hw_params, - .set_sysclk = pxa_ssp_set_dai_sysclk, - .set_clkdiv = pxa_ssp_set_dai_clkdiv, - .set_pll = pxa_ssp_set_dai_pll, - .set_fmt = pxa_ssp_set_dai_fmt, - .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, - .set_tristate = pxa_ssp_set_dai_tristate, - }, - }, - { .name = "pxa2xx-ssp2", - .id = 1, - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, - .suspend = pxa_ssp_suspend, - .resume = pxa_ssp_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .ops = { - .startup = pxa_ssp_startup, - .shutdown = pxa_ssp_shutdown, - .trigger = pxa_ssp_trigger, - .hw_params = pxa_ssp_hw_params, - .set_sysclk = pxa_ssp_set_dai_sysclk, - .set_clkdiv = pxa_ssp_set_dai_clkdiv, - .set_pll = pxa_ssp_set_dai_pll, - .set_fmt = pxa_ssp_set_dai_fmt, - .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, - .set_tristate = pxa_ssp_set_dai_tristate, - }, - }, - { - .name = "pxa2xx-ssp3", - .id = 2, - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, - .suspend = pxa_ssp_suspend, - .resume = pxa_ssp_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .ops = { - .startup = pxa_ssp_startup, - .shutdown = pxa_ssp_shutdown, - .trigger = pxa_ssp_trigger, - .hw_params = pxa_ssp_hw_params, - .set_sysclk = pxa_ssp_set_dai_sysclk, - .set_clkdiv = pxa_ssp_set_dai_clkdiv, - .set_pll = pxa_ssp_set_dai_pll, - .set_fmt = pxa_ssp_set_dai_fmt, - .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, - .set_tristate = pxa_ssp_set_dai_tristate, - }, - }, - { - .name = "pxa2xx-ssp4", - .id = 3, - .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, - .suspend = pxa_ssp_suspend, - .resume = pxa_ssp_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = PXA_SSP_RATES, - .formats = PXA_SSP_FORMATS, - }, - .ops = { - .startup = pxa_ssp_startup, - .shutdown = pxa_ssp_shutdown, - .trigger = pxa_ssp_trigger, - .hw_params = pxa_ssp_hw_params, - .set_sysclk = pxa_ssp_set_dai_sysclk, - .set_clkdiv = pxa_ssp_set_dai_clkdiv, - .set_pll = pxa_ssp_set_dai_pll, - .set_fmt = pxa_ssp_set_dai_fmt, - .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, - .set_tristate = pxa_ssp_set_dai_tristate, - }, - }, -}; -EXPORT_SYMBOL_GPL(pxa_ssp_dai); - -static int __devinit pxa_ssp_init(void) -{ - return snd_soc_register_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai)); -} -module_init(pxa_ssp_init); - -static void __exit pxa_ssp_exit(void) -{ - snd_soc_unregister_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai)); -} -module_exit(pxa_ssp_exit); - -/* Module information */ -MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); -MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa-ssp.h b/sound/soc/pxa/pxa-ssp.h deleted file mode 100644 index 91deadd55675..000000000000 --- a/sound/soc/pxa/pxa-ssp.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ASoC PXA SSP port support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _PXA_SSP_H -#define _PXA_SSP_H - -/* pxa DAI SSP IDs */ -#define PXA_DAI_SSP1 0 -#define PXA_DAI_SSP2 1 -#define PXA_DAI_SSP3 2 -#define PXA_DAI_SSP4 3 - -/* SSP clock sources */ -#define PXA_SSP_CLK_PLL 0 -#define PXA_SSP_CLK_EXT 1 -#define PXA_SSP_CLK_NET 2 -#define PXA_SSP_CLK_AUDIO 3 -#define PXA_SSP_CLK_NET_PLL 4 - -/* SSP audio dividers */ -#define PXA_SSP_AUDIO_DIV_ACDS 0 -#define PXA_SSP_AUDIO_DIV_SCDB 1 -#define PXA_SSP_DIV_SCR 2 - -/* SSP ACDS audio dividers values */ -#define PXA_SSP_CLK_AUDIO_DIV_1 0 -#define PXA_SSP_CLK_AUDIO_DIV_2 1 -#define PXA_SSP_CLK_AUDIO_DIV_4 2 -#define PXA_SSP_CLK_AUDIO_DIV_8 3 -#define PXA_SSP_CLK_AUDIO_DIV_16 4 -#define PXA_SSP_CLK_AUDIO_DIV_32 5 - -/* SSP divider bypass */ -#define PXA_SSP_CLK_SCDB_4 0 -#define PXA_SSP_CLK_SCDB_1 1 -#define PXA_SSP_CLK_SCDB_8 2 - -#define PXA_SSP_PLL_OUT 0 - -extern struct snd_soc_dai pxa_ssp_dai[4]; - -#endif diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 2574d323ae51..5e727393cfd4 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -88,12 +88,14 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { }; #ifdef CONFIG_PM -static int pxa2xx_ac97_suspend(struct snd_soc_dai *dai) +static int pxa2xx_ac97_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) { return pxa2xx_ac97_hw_suspend(); } -static int pxa2xx_ac97_resume(struct snd_soc_dai *dai) +static int pxa2xx_ac97_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { return pxa2xx_ac97_hw_resume(); } @@ -116,8 +118,7 @@ static void pxa2xx_ac97_remove(struct platform_device *pdev, } static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -131,8 +132,7 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, } static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -146,8 +146,7 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, } static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -172,7 +171,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97", .id = 0, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .probe = pxa2xx_ac97_probe, .remove = pxa2xx_ac97_remove, .suspend = pxa2xx_ac97_suspend, @@ -195,7 +194,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97-aux", .id = 1, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .playback = { .stream_name = "AC97 Aux Playback", .channels_min = 1, @@ -214,7 +213,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97-mic", .id = 2, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .capture = { .stream_name = "AC97 Mic Capture", .channels_min = 1, @@ -229,18 +228,6 @@ struct snd_soc_dai pxa_ac97_dai[] = { EXPORT_SYMBOL_GPL(pxa_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); -static int __devinit pxa_ac97_init(void) -{ - return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); -} -module_init(pxa_ac97_init); - -static void __exit pxa_ac97_exit(void) -{ - snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); -} -module_exit(pxa_ac97_exit); - MODULE_AUTHOR("Nicolas Pitre"); MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 517991fb1099..e758034db5c3 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -121,8 +121,7 @@ static struct pxa2xx_gpio gpio_bus[] = { }, }; -static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -188,8 +187,7 @@ static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, } static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -250,8 +248,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { int ret = 0; @@ -272,8 +269,7 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } -static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { SACR1 |= SACR1_DRPL; @@ -293,7 +289,8 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, } #ifdef CONFIG_PM -static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) +static int pxa2xx_i2s_suspend(struct platform_device *dev, + struct snd_soc_dai *dai) { if (!dai->active) return 0; @@ -310,7 +307,8 @@ static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) return 0; } -static int pxa2xx_i2s_resume(struct snd_soc_dai *dai) +static int pxa2xx_i2s_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { if (!dai->active) return 0; @@ -338,6 +336,7 @@ static int pxa2xx_i2s_resume(struct snd_soc_dai *dai) struct snd_soc_dai pxa_i2s_dai = { .name = "pxa2xx-i2s", .id = 0, + .type = SND_SOC_DAI_I2S, .suspend = pxa2xx_i2s_suspend, .resume = pxa2xx_i2s_resume, .playback = { @@ -354,7 +353,8 @@ struct snd_soc_dai pxa_i2s_dai = { .startup = pxa2xx_i2s_startup, .shutdown = pxa2xx_i2s_shutdown, .trigger = pxa2xx_i2s_trigger, - .hw_params = pxa2xx_i2s_hw_params, + .hw_params = pxa2xx_i2s_hw_params,}, + .dai_ops = { .set_fmt = pxa2xx_i2s_set_dai_fmt, .set_sysclk = pxa2xx_i2s_set_dai_sysclk, }, @@ -364,23 +364,12 @@ EXPORT_SYMBOL_GPL(pxa_i2s_dai); static int pxa2xx_i2s_probe(struct platform_device *dev) { - int ret; - clk_i2s = clk_get(&dev->dev, "I2SCLK"); - if (IS_ERR(clk_i2s)) - return PTR_ERR(clk_i2s); - - pxa_i2s_dai.dev = &dev->dev; - ret = snd_soc_register_dai(&pxa_i2s_dai); - if (ret != 0) - clk_put(clk_i2s); - - return ret; + return IS_ERR(clk_i2s) ? PTR_ERR(clk_i2s) : 0; } static int __devexit pxa2xx_i2s_remove(struct platform_device *dev) { - snd_soc_unregister_dai(&pxa_i2s_dai); clk_put(clk_i2s); clk_i2s = ERR_PTR(-ENOENT); return 0; diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 4fa1578f5d47..afcd892cd2fa 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -69,7 +69,7 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -static struct snd_pcm_ops pxa2xx_pcm_ops = { +struct snd_pcm_ops pxa2xx_pcm_ops = { .open = __pxa2xx_pcm_open, .close = __pxa2xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, @@ -118,18 +118,6 @@ struct snd_soc_platform pxa2xx_soc_platform = { }; EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); -static int __devinit pxa2xx_soc_platform_init(void) -{ - return snd_soc_register_platform(&pxa2xx_soc_platform); -} -module_init(pxa2xx_soc_platform_init); - -static void __exit pxa2xx_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&pxa2xx_soc_platform); -} -module_exit(pxa2xx_soc_platform_exit); - MODULE_AUTHOR("Nicolas Pitre"); MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index a3b9e6bdf979..d307b6757e95 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -319,9 +319,8 @@ static struct snd_soc_dai_link spitz_dai = { }; /* spitz audio machine driver */ -static struct snd_soc_card snd_soc_spitz = { +static struct snd_soc_machine snd_soc_machine_spitz = { .name = "Spitz", - .platform = &pxa2xx_soc_platform, .dai_link = &spitz_dai, .num_links = 1, }; @@ -334,7 +333,8 @@ static struct wm8750_setup_data spitz_wm8750_setup = { /* spitz audio subsystem */ static struct snd_soc_device spitz_snd_devdata = { - .card = &snd_soc_spitz, + .machine = &snd_soc_machine_spitz, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8750, .codec_data = &spitz_wm8750_setup, }; diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index c77194f74c9b..afefe41b8c46 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -38,7 +38,7 @@ #include "pxa2xx-pcm.h" #include "pxa2xx-ac97.h" -static struct snd_soc_card tosa; +static struct snd_soc_machine tosa; #define TOSA_HP 0 #define TOSA_MIC_INT 1 @@ -230,37 +230,15 @@ static struct snd_soc_dai_link tosa_dai[] = { }, }; -static int tosa_probe(struct platform_device *dev) -{ - int ret; - - ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack"); - if (ret) - return ret; - ret = gpio_direction_output(TOSA_GPIO_L_MUTE, 0); - if (ret) - gpio_free(TOSA_GPIO_L_MUTE); - - return ret; -} - -static int tosa_remove(struct platform_device *dev) -{ - gpio_free(TOSA_GPIO_L_MUTE); - return 0; -} - -static struct snd_soc_card tosa = { +static struct snd_soc_machine tosa = { .name = "Tosa", - .platform = &pxa2xx_soc_platform, .dai_link = tosa_dai, .num_links = ARRAY_SIZE(tosa_dai), - .probe = tosa_probe, - .remove = tosa_remove, }; static struct snd_soc_device tosa_snd_devdata = { - .card = &tosa, + .machine = &tosa, + .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; @@ -273,6 +251,11 @@ static int __init tosa_init(void) if (!machine_is_tosa()) return -ENODEV; + ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack"); + if (ret) + return ret; + gpio_direction_output(TOSA_GPIO_L_MUTE, 0); + tosa_snd_device = platform_device_alloc("soc-audio", -1); if (!tosa_snd_device) { ret = -ENOMEM; @@ -289,12 +272,15 @@ static int __init tosa_init(void) platform_device_put(tosa_snd_device); err_alloc: + gpio_free(TOSA_GPIO_L_MUTE); + return ret; } static void __exit tosa_exit(void) { platform_device_unregister(tosa_snd_device); + gpio_free(TOSA_GPIO_L_MUTE); } module_init(tosa_init); diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c deleted file mode 100644 index f8e9ecd589d3..000000000000 --- a/sound/soc/pxa/zylonite.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * zylonite.c -- SoC audio for Zylonite - * - * Copyright 2008 Wolfson Microelectronics PLC. - * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/module.h> -#include <linux/moduleparam.h> -#include <linux/device.h> -#include <linux/i2c.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> - -#include "../codecs/wm9713.h" -#include "pxa2xx-pcm.h" -#include "pxa2xx-ac97.h" -#include "pxa-ssp.h" - -static struct snd_soc_card zylonite; - -static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Microphone", NULL), - SND_SOC_DAPM_MIC("Handset Microphone", NULL), - SND_SOC_DAPM_SPK("Multiactor", NULL), - SND_SOC_DAPM_SPK("Headset Earpiece", NULL), -}; - -/* Currently supported audio map */ -static const struct snd_soc_dapm_route audio_map[] = { - - /* Headphone output connected to HPL/HPR */ - { "Headphone", NULL, "HPL" }, - { "Headphone", NULL, "HPR" }, - - /* On-board earpiece */ - { "Headset Earpiece", NULL, "OUT3" }, - - /* Headphone mic */ - { "MIC2A", NULL, "Mic Bias" }, - { "Mic Bias", NULL, "Headset Microphone" }, - - /* On-board mic */ - { "MIC1", NULL, "Mic Bias" }, - { "Mic Bias", NULL, "Handset Microphone" }, - - /* Multiactor differentially connected over SPKL/SPKR */ - { "Multiactor", NULL, "SPKL" }, - { "Multiactor", NULL, "SPKR" }, -}; - -static int zylonite_wm9713_init(struct snd_soc_codec *codec) -{ - /* Currently we only support use of the AC97 clock here. If - * CLK_POUT is selected by SW15 then the clock API will need - * to be used to request and enable it here. - */ - - snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, - ARRAY_SIZE(zylonite_dapm_widgets)); - - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - - /* Static setup for now */ - snd_soc_dapm_enable_pin(codec, "Headphone"); - snd_soc_dapm_enable_pin(codec, "Headset Earpiece"); - - snd_soc_dapm_sync(codec); - return 0; -} - -static int zylonite_voice_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->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - unsigned int pll_out = 0; - unsigned int acds = 0; - unsigned int wm9713_div = 0; - int ret = 0; - - switch (params_rate(params)) { - case 8000: - wm9713_div = 12; - pll_out = 2048000; - break; - case 16000: - wm9713_div = 6; - pll_out = 4096000; - break; - case 48000: - default: - wm9713_div = 2; - pll_out = 12288000; - acds = 1; - break; - } - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_tdm_slot(cpu_dai, - params_channels(params), - params_channels(params)); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, pll_out); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_AUDIO_DIV_ACDS, acds); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); - if (ret < 0) - return ret; - - /* Note that if the PLL is in use the WM9713_PCMCLK_PLL_DIV needs - * to be set instead. - */ - ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, - WM9713_PCMDIV(wm9713_div)); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops zylonite_voice_ops = { - .hw_params = zylonite_voice_hw_params, -}; - -static struct snd_soc_dai_link zylonite_dai[] = { -{ - .name = "AC97", - .stream_name = "AC97 HiFi", - .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], - .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI], - .init = zylonite_wm9713_init, -}, -{ - .name = "AC97 Aux", - .stream_name = "AC97 Aux", - .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], - .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX], -}, -{ - .name = "WM9713 Voice", - .stream_name = "WM9713 Voice", - .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP3], - .codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE], - .ops = &zylonite_voice_ops, -}, -}; - -static struct snd_soc_card zylonite = { - .name = "Zylonite", - .platform = &pxa2xx_soc_platform, - .dai_link = zylonite_dai, - .num_links = ARRAY_SIZE(zylonite_dai), -}; - -static struct snd_soc_device zylonite_snd_ac97_devdata = { - .card = &zylonite, - .codec_dev = &soc_codec_dev_wm9713, -}; - -static struct platform_device *zylonite_snd_ac97_device; - -static int __init zylonite_init(void) -{ - int ret; - - zylonite_snd_ac97_device = platform_device_alloc("soc-audio", -1); - if (!zylonite_snd_ac97_device) - return -ENOMEM; - - platform_set_drvdata(zylonite_snd_ac97_device, - &zylonite_snd_ac97_devdata); - zylonite_snd_ac97_devdata.dev = &zylonite_snd_ac97_device->dev; - - ret = platform_device_add(zylonite_snd_ac97_device); - if (ret != 0) - platform_device_put(zylonite_snd_ac97_device); - - return ret; -} - -static void __exit zylonite_exit(void) -{ - platform_device_unregister(zylonite_snd_ac97_device); -} - -module_init(zylonite_init); -module_exit(zylonite_exit); - -MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); -MODULE_DESCRIPTION("ALSA SoC WM9713 Zylonite"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index fcd03acf10f6..b9f2353effeb 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -44,8 +44,3 @@ config SND_S3C24XX_SOC_LN2440SBC_ALC650 Say Y if you want to add support for SoC audio on ln2440sbc with the ALC650. -config SND_S3C24XX_SOC_S3C24XX_UDA134X - tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" - depends on SND_S3C24XX_SOC - select SND_S3C24XX_SOC_I2S - select SND_SOC_UDA134X diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 96b3f3f617d4..0aa5fb0b9700 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -13,9 +13,7 @@ obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o -snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o -obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c index 12c71482d258..4eab2c19c454 100644 --- a/sound/soc/s3c24xx/ln2440sbc_alc650.c +++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c @@ -27,7 +27,7 @@ #include "s3c24xx-pcm.h" #include "s3c24xx-ac97.h" -static struct snd_soc_card ln2440sbc; +static struct snd_soc_machine ln2440sbc; static struct snd_soc_dai_link ln2440sbc_dai[] = { { @@ -38,15 +38,15 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = { }, }; -static struct snd_soc_card ln2440sbc = { +static struct snd_soc_machine ln2440sbc = { .name = "LN2440SBC", - .platform = &s3c24xx_soc_platform, .dai_link = ln2440sbc_dai, .num_links = ARRAY_SIZE(ln2440sbc_dai), }; static struct snd_soc_device ln2440sbc_snd_ac97_devdata = { - .card = &ln2440sbc, + .machine = &ln2440sbc, + .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 45bb12e8ea44..87ddfefcc2fb 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -59,7 +59,7 @@ #define NEO_CAPTURE_HEADSET 7 #define NEO_CAPTURE_BLUETOOTH 8 -static struct snd_soc_card neo1973; +static struct snd_soc_machine neo1973; static struct i2c_client *i2c; static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, @@ -548,6 +548,7 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) static struct snd_soc_dai bt_dai = { .name = "Bluetooth", .id = 0, + .type = SND_SOC_DAI_PCM, .playback = { .channels_min = 1, .channels_max = 1, @@ -578,9 +579,8 @@ static struct snd_soc_dai_link neo1973_dai[] = { }, }; -static struct snd_soc_card neo1973 = { +static struct snd_soc_machine neo1973 = { .name = "neo1973", - .platform = &s3c24xx_soc_platform, .dai_link = neo1973_dai, .num_links = ARRAY_SIZE(neo1973_dai), }; @@ -591,7 +591,8 @@ static struct wm8753_setup_data neo1973_wm8753_setup = { }; static struct snd_soc_device neo1973_snd_devdata = { - .card = &neo1973, + .machine = &neo1973, + .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_wm8753, .codec_data = &neo1973_wm8753_setup, }; diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 2cf050791562..ded7d995a922 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -343,8 +343,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; u32 iismod; @@ -374,8 +373,7 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); unsigned long irqs; @@ -649,7 +647,8 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, } #ifdef CONFIG_PM -static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) +static int s3c2412_i2s_suspend(struct platform_device *dev, + struct snd_soc_dai *dai) { struct s3c2412_i2s_info *i2s = &s3c2412_i2s; u32 iismod; @@ -664,24 +663,25 @@ static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) iismod = readl(i2s->regs + S3C2412_IISMOD); if (iismod & S3C2412_IISCON_RXDMA_ACTIVE) - pr_warning("%s: RXDMA active?\n", __func__); + dev_warn(&dev->dev, "%s: RXDMA active?\n", __func__); if (iismod & S3C2412_IISCON_TXDMA_ACTIVE) - pr_warning("%s: TXDMA active?\n", __func__); + dev_warn(&dev->dev, "%s: TXDMA active?\n", __func__); if (iismod & S3C2412_IISCON_IIS_ACTIVE) - pr_warning("%s: IIS active\n", __func__); + dev_warn(&dev->dev, "%s: IIS active\n", __func__); } return 0; } -static int s3c2412_i2s_resume(struct snd_soc_dai *dai) +static int s3c2412_i2s_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { struct s3c2412_i2s_info *i2s = &s3c2412_i2s; - pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n", - dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); + dev_info(&pdev->dev, "dai_active %d, IISMOD %08x, IISCON %08x\n", + dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); if (dai->active) { writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON); @@ -711,6 +711,7 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai) struct snd_soc_dai s3c2412_i2s_dai = { .name = "s3c2412-i2s", .id = 0, + .type = SND_SOC_DAI_I2S, .probe = s3c2412_i2s_probe, .suspend = s3c2412_i2s_suspend, .resume = s3c2412_i2s_resume, @@ -729,6 +730,8 @@ struct snd_soc_dai s3c2412_i2s_dai = { .ops = { .trigger = s3c2412_i2s_trigger, .hw_params = s3c2412_i2s_hw_params, + }, + .dai_ops = { .set_fmt = s3c2412_i2s_set_fmt, .set_clkdiv = s3c2412_i2s_set_clkdiv, .set_sysclk = s3c2412_i2s_set_sysclk, @@ -736,19 +739,6 @@ struct snd_soc_dai s3c2412_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); -static int __devinit s3c2412_i2s_init(void) -{ - return snd_soc_register_dai(&s3c2412_i2s_dai); -} -module_init(s3c2412_i2s_init); - -static void __exit s3c2412_i2s_exit(void) -{ - snd_soc_unregister_dai(&s3c2412_i2s_dai); -} -module_exit(s3c2412_i2s_exit); - - /* Module information */ MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index aa99e1615eff..c473a3b97b55 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -271,8 +271,7 @@ static void s3c2443_ac97_remove(struct platform_device *pdev, } static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -285,8 +284,7 @@ static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd) { u32 ac_glbctrl; @@ -315,8 +313,7 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, } static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -330,7 +327,7 @@ static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, } static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) + int cmd) { u32 ac_glbctrl; @@ -359,7 +356,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { { .name = "s3c2443-ac97", .id = 0, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .probe = s3c2443_ac97_probe, .remove = s3c2443_ac97_remove, .playback = { @@ -381,7 +378,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { { .name = "pxa2xx-ac97-mic", .id = 1, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .capture = { .stream_name = "AC97 Mic Capture", .channels_min = 1, @@ -396,19 +393,6 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); -static int __devinit s3c2443_ac97_init(void) -{ - return snd_soc_register_dai(&s3c2443_ac97_dai); -} -module_init(s3c2443_ac97_init); - -static void __exit s3c2443_ac97_exit(void) -{ - snd_soc_unregister_dai(&s3c2443_ac97_dai); -} -module_exit(s3c2443_ac97_exit); - - MODULE_AUTHOR("Graeme Gregory"); MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 897b1ac92cef..ba4476b55fbc 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -243,8 +243,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; u32 iismod; @@ -262,17 +261,10 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: - iismod &= ~S3C2410_IISMOD_16BIT; - ((struct s3c24xx_pcm_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size = 1; break; case SNDRV_PCM_FORMAT_S16_LE: iismod |= S3C2410_IISMOD_16BIT; - ((struct s3c24xx_pcm_dma_params *) - rtd->dai->cpu_dai->dma_data)->dma_size = 2; break; - default: - return -EINVAL; } writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); @@ -280,8 +272,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) { int ret = 0; @@ -419,7 +410,8 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev, } #ifdef CONFIG_PM -static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) +static int s3c24xx_i2s_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) { DBG("Entered %s\n", __func__); @@ -433,7 +425,8 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) return 0; } -static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) +static int s3c24xx_i2s_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) { DBG("Entered %s\n", __func__); clk_enable(s3c24xx_i2s.iis_clk); @@ -459,6 +452,7 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) struct snd_soc_dai s3c24xx_i2s_dai = { .name = "s3c24xx-i2s", .id = 0, + .type = SND_SOC_DAI_I2S, .probe = s3c24xx_i2s_probe, .suspend = s3c24xx_i2s_suspend, .resume = s3c24xx_i2s_resume, @@ -474,7 +468,8 @@ struct snd_soc_dai s3c24xx_i2s_dai = { .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .trigger = s3c24xx_i2s_trigger, - .hw_params = s3c24xx_i2s_hw_params, + .hw_params = s3c24xx_i2s_hw_params,}, + .dai_ops = { .set_fmt = s3c24xx_i2s_set_fmt, .set_clkdiv = s3c24xx_i2s_set_clkdiv, .set_sysclk = s3c24xx_i2s_set_sysclk, @@ -482,18 +477,6 @@ struct snd_soc_dai s3c24xx_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai); -static int __devinit s3c24xx_i2s_init(void) -{ - return snd_soc_register_dai(&s3c24xx_i2s_dai); -} -module_init(s3c24xx_i2s_init); - -static void __exit s3c24xx_i2s_exit(void) -{ - snd_soc_unregister_dai(&s3c24xx_i2s_dai); -} -module_exit(s3c24xx_i2s_exit); - /* Module information */ MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_DESCRIPTION("s3c24xx I2S SoC Interface"); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index ea5a9caec13e..e13e614bada9 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -465,18 +465,6 @@ struct snd_soc_platform s3c24xx_soc_platform = { }; EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); -static int __devinit s3c24xx_soc_platform_init(void) -{ - return snd_soc_register_platform(&s3c24xx_soc_platform); -} -module_init(s3c24xx_soc_platform_init); - -static void __exit s3c24xx_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&s3c24xx_soc_platform); -} -module_exit(s3c24xx_soc_platform_exit); - MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_DESCRIPTION("Samsung S3C24XX PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c deleted file mode 100644 index a0a4d1832a14..000000000000 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Modifications by Christian Pellegrin <chripell@evolware.org> - * - * s3c24xx_uda134x.c -- S3C24XX_UDA134X ALSA SoC Audio board driver - * - * Copyright 2007 Dension Audio Systems Ltd. - * Author: Zoltan Devai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/clk.h> -#include <linux/mutex.h> -#include <linux/gpio.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dapm.h> -#include <sound/s3c24xx_uda134x.h> -#include <sound/uda134x.h> - -#include <asm/plat-s3c24xx/regs-iis.h> - -#include "s3c24xx-pcm.h" -#include "s3c24xx-i2s.h" -#include "../codecs/uda134x.h" - - -/* #define ENFORCE_RATES 1 */ -/* - Unfortunately the S3C24XX in master mode has a limited capacity of - generating the clock for the codec. If you define this only rates - that are really available will be enforced. But be careful, most - user level application just want the usual sampling frequencies (8, - 11.025, 22.050, 44.1 kHz) and anyway resampling is a costly - operation for embedded systems. So if you aren't very lucky or your - hardware engineer wasn't very forward-looking it's better to leave - this undefined. If you do so an approximate value for the requested - sampling rate in the range -/+ 5% will be chosen. If this in not - possible an error will be returned. -*/ - -static struct clk *xtal; -static struct clk *pclk; -/* this is need because we don't have a place where to keep the - * pointers to the clocks in each substream. We get the clocks only - * when we are actually using them so we don't block stuff like - * frequency change or oscillator power-off */ -static int clk_users; -static DEFINE_MUTEX(clk_lock); - -static unsigned int rates[33 * 2]; -#ifdef ENFORCE_RATES -static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; -#endif - -static struct platform_device *s3c24xx_uda134x_snd_device; - -static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) -{ - int ret = 0; -#ifdef ENFORCE_RATES - struct snd_pcm_runtime *runtime = substream->runtime;; -#endif - - mutex_lock(&clk_lock); - pr_debug("%s %d\n", __func__, clk_users); - if (clk_users == 0) { - xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal"); - if (!xtal) { - printk(KERN_ERR "%s cannot get xtal\n", __func__); - ret = -EBUSY; - } else { - pclk = clk_get(&s3c24xx_uda134x_snd_device->dev, - "pclk"); - if (!pclk) { - printk(KERN_ERR "%s cannot get pclk\n", - __func__); - clk_put(xtal); - ret = -EBUSY; - } - } - if (!ret) { - int i, j; - - for (i = 0; i < 2; i++) { - int fs = i ? 256 : 384; - - rates[i*33] = clk_get_rate(xtal) / fs; - for (j = 1; j < 33; j++) - rates[i*33 + j] = clk_get_rate(pclk) / - (j * fs); - } - } - } - clk_users += 1; - mutex_unlock(&clk_lock); - if (!ret) { -#ifdef ENFORCE_RATES - ret = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &hw_constraints_rates); - if (ret < 0) - printk(KERN_ERR "%s cannot set constraints\n", - __func__); -#endif - } - return ret; -} - -static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) -{ - mutex_lock(&clk_lock); - pr_debug("%s %d\n", __func__, clk_users); - clk_users -= 1; - if (clk_users == 0) { - clk_put(xtal); - xtal = NULL; - clk_put(pclk); - pclk = NULL; - } - mutex_unlock(&clk_lock); -} - -static int s3c24xx_uda134x_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->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - unsigned int clk = 0; - int ret = 0; - int clk_source, fs_mode; - unsigned long rate = params_rate(params); - long err, cerr; - unsigned int div; - int i, bi; - - err = 999999; - bi = 0; - for (i = 0; i < 2*33; i++) { - cerr = rates[i] - rate; - if (cerr < 0) - cerr = -cerr; - if (cerr < err) { - err = cerr; - bi = i; - } - } - if (bi / 33 == 1) - fs_mode = S3C2410_IISMOD_256FS; - else - fs_mode = S3C2410_IISMOD_384FS; - if (bi % 33 == 0) { - clk_source = S3C24XX_CLKSRC_MPLL; - div = 1; - } else { - clk_source = S3C24XX_CLKSRC_PCLK; - div = bi % 33; - } - pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi); - - clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate; - pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__, - fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS", - clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK", - div, clk, err); - - if ((err * 100 / rate) > 5) { - printk(KERN_ERR "S3C24XX_UDA134X: effective frequency " - "too different from desired (%ld%%)\n", - err * 100 / rate); - return -EINVAL; - } - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk, - SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, - S3C2410_IISMOD_32FS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, - S3C24XX_PRESCALE(div, div)); - if (ret < 0) - return ret; - - /* set the codec system clock for DAC and ADC */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, - SND_SOC_CLOCK_OUT); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops s3c24xx_uda134x_ops = { - .startup = s3c24xx_uda134x_startup, - .shutdown = s3c24xx_uda134x_shutdown, - .hw_params = s3c24xx_uda134x_hw_params, -}; - -static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { - .name = "UDA134X", - .stream_name = "UDA134X", - .codec_dai = &uda134x_dai, - .cpu_dai = &s3c24xx_i2s_dai, - .ops = &s3c24xx_uda134x_ops, -}; - -static struct snd_soc_card snd_soc_s3c24xx_uda134x = { - .name = "S3C24XX_UDA134X", - .platform = &s3c24xx_soc_platform, - .dai_link = &s3c24xx_uda134x_dai_link, - .num_links = 1, -}; - -static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins; - -static void setdat(int v) -{ - gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0); -} - -static void setclk(int v) -{ - gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0); -} - -static void setmode(int v) -{ - gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0); -} - -static struct uda134x_platform_data s3c24xx_uda134x = { - .l3 = { - .setdat = setdat, - .setclk = setclk, - .setmode = setmode, - .data_hold = 1, - .data_setup = 1, - .clock_high = 1, - .mode_hold = 1, - .mode = 1, - .mode_setup = 1, - }, -}; - -static struct snd_soc_device s3c24xx_uda134x_snd_devdata = { - .card = &snd_soc_s3c24xx_uda134x, - .codec_dev = &soc_codec_dev_uda134x, - .codec_data = &s3c24xx_uda134x, -}; - -static int s3c24xx_uda134x_setup_pin(int pin, char *fun) -{ - if (gpio_request(pin, "s3c24xx_uda134x") < 0) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " - "l3 %s pin already in use", fun); - return -EBUSY; - } - gpio_direction_output(pin, 0); - return 0; -} - -static int s3c24xx_uda134x_probe(struct platform_device *pdev) -{ - int ret; - - printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n"); - - s3c24xx_uda134x_l3_pins = pdev->dev.platform_data; - if (s3c24xx_uda134x_l3_pins == NULL) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " - "unable to find platform data\n"); - return -ENODEV; - } - s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power; - s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model; - - if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data, - "data") < 0) - return -EBUSY; - if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk, - "clk") < 0) { - gpio_free(s3c24xx_uda134x_l3_pins->l3_data); - return -EBUSY; - } - if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode, - "mode") < 0) { - gpio_free(s3c24xx_uda134x_l3_pins->l3_data); - gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); - return -EBUSY; - } - - s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1); - if (!s3c24xx_uda134x_snd_device) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " - "Unable to register\n"); - return -ENOMEM; - } - - platform_set_drvdata(s3c24xx_uda134x_snd_device, - &s3c24xx_uda134x_snd_devdata); - s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev; - ret = platform_device_add(s3c24xx_uda134x_snd_device); - if (ret) { - printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n"); - platform_device_put(s3c24xx_uda134x_snd_device); - } - - return ret; -} - -static int s3c24xx_uda134x_remove(struct platform_device *pdev) -{ - platform_device_unregister(s3c24xx_uda134x_snd_device); - gpio_free(s3c24xx_uda134x_l3_pins->l3_data); - gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); - gpio_free(s3c24xx_uda134x_l3_pins->l3_mode); - return 0; -} - -static struct platform_driver s3c24xx_uda134x_driver = { - .probe = s3c24xx_uda134x_probe, - .remove = s3c24xx_uda134x_remove, - .driver = { - .name = "s3c24xx_uda134x", - .owner = THIS_MODULE, - }, -}; - -static int __init s3c24xx_uda134x_init(void) -{ - return platform_driver_register(&s3c24xx_uda134x_driver); -} - -static void __exit s3c24xx_uda134x_exit(void) -{ - platform_driver_unregister(&s3c24xx_uda134x_driver); -} - - -module_init(s3c24xx_uda134x_init); -module_exit(s3c24xx_uda134x_exit); - -MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>"); -MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index a2a4f5323c17..8515d6ff03f2 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c @@ -23,7 +23,7 @@ #include "s3c24xx-pcm.h" #include "s3c24xx-ac97.h" -static struct snd_soc_card smdk2443; +static struct snd_soc_machine smdk2443; static struct snd_soc_dai_link smdk2443_dai[] = { { @@ -34,15 +34,15 @@ static struct snd_soc_dai_link smdk2443_dai[] = { }, }; -static struct snd_soc_card smdk2443 = { +static struct snd_soc_machine smdk2443 = { .name = "SMDK2443", - .platform = &s3c24xx_soc_platform, .dai_link = smdk2443_dai, .num_links = ARRAY_SIZE(smdk2443_dai), }; static struct snd_soc_device smdk2443_snd_ac97_devdata = { - .card = &smdk2443, + .machine = &smdk2443, + .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 39ffca0933a2..9faa12622d09 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -348,18 +348,6 @@ struct snd_soc_platform sh7760_soc_platform = { }; EXPORT_SYMBOL_GPL(sh7760_soc_platform); -static int __devinit sh7760_soc_platform_init(void) -{ - return snd_soc_register_platform(&sh7760_soc_platform); -} -module_init(sh7760_soc_platform_init); - -static void __exit sh7760_soc_platform_exit(void) -{ - snd_soc_unregister_platform(&sh7760_soc_platform); -} -module_exit(sh7760_soc_platform_exit); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver"); MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 9169bad1acfb..df7bc345c320 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -236,8 +236,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); static int hac_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id]; @@ -271,7 +270,7 @@ struct snd_soc_dai sh4_hac_dai[] = { { .name = "HAC0", .id = 0, - .ac97_control = 1, + .type = SND_SOC_DAI_AC97, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, @@ -291,8 +290,8 @@ struct snd_soc_dai sh4_hac_dai[] = { #ifdef CONFIG_CPU_SUBTYPE_SH7760 { .name = "HAC1", - .ac97_control = 1, .id = 1, + .type = SND_SOC_DAI_AC97, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, @@ -314,18 +313,6 @@ struct snd_soc_dai sh4_hac_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_hac_dai); -static int __devinit sh4_hac_init(void) -{ - return snd_soc_register_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); -} -module_init(sh4_hac_init); - -static void __exit sh4_hac_exit(void) -{ - snd_soc_unregister_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); -} -module_exit(sh4_hac_exit); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver"); MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c index ce7f95b59de3..92bfaf4774a7 100644 --- a/sound/soc/sh/sh7760-ac97.c +++ b/sound/soc/sh/sh7760-ac97.c @@ -38,15 +38,15 @@ static struct snd_soc_dai_link sh7760_ac97_dai = { .ops = NULL, }; -static struct snd_soc_card sh7760_ac97_soc_machine = { +static struct snd_soc_machine sh7760_ac97_soc_machine = { .name = "SH7760 AC97", - .platform = &sh7760_soc_platform, .dai_link = &sh7760_ac97_dai, .num_links = 1, }; static struct snd_soc_device sh7760_ac97_snd_devdata = { - .card = &sh7760_ac97_soc_machine, + .machine = &sh7760_ac97_soc_machine, + .platform = &sh7760_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 9093588d4d07..55c3464163ab 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -89,8 +89,7 @@ struct ssi_priv { * track usage of the SSI; it is simplex-only so prevent attempts of * concurrent playback + capture. FIXME: any locking required? */ -static int ssi_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int ssi_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -102,8 +101,7 @@ static int ssi_startup(struct snd_pcm_substream *substream, return 0; } -static void ssi_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static void ssi_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -111,8 +109,7 @@ static void ssi_shutdown(struct snd_pcm_substream *substream, ssi->inuse = 0; } -static int ssi_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +static int ssi_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -132,8 +129,7 @@ static int ssi_trigger(struct snd_pcm_substream *substream, int cmd, } static int ssi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -340,6 +336,7 @@ struct snd_soc_dai sh4_ssi_dai[] = { { .name = "SSI0", .id = 0, + .type = SND_SOC_DAI_I2S, .playback = { .rates = SSI_RATES, .formats = SSI_FMTS, @@ -357,6 +354,8 @@ struct snd_soc_dai sh4_ssi_dai[] = { .shutdown = ssi_shutdown, .trigger = ssi_trigger, .hw_params = ssi_hw_params, + }, + .dai_ops = { .set_sysclk = ssi_set_sysclk, .set_clkdiv = ssi_set_clkdiv, .set_fmt = ssi_set_fmt, @@ -366,6 +365,7 @@ struct snd_soc_dai sh4_ssi_dai[] = { { .name = "SSI1", .id = 1, + .type = SND_SOC_DAI_I2S, .playback = { .rates = SSI_RATES, .formats = SSI_FMTS, @@ -383,6 +383,8 @@ struct snd_soc_dai sh4_ssi_dai[] = { .shutdown = ssi_shutdown, .trigger = ssi_trigger, .hw_params = ssi_hw_params, + }, + .dai_ops = { .set_sysclk = ssi_set_sysclk, .set_clkdiv = ssi_set_clkdiv, .set_fmt = ssi_set_fmt, @@ -392,18 +394,6 @@ struct snd_soc_dai sh4_ssi_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_ssi_dai); -static int __devinit sh4_ssi_init(void) -{ - return snd_soc_register_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); -} -module_init(sh4_ssi_init); - -static void __exit sh4_ssi_exit(void) -{ - snd_soc_unregister_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); -} -module_exit(sh4_ssi_exit); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver"); MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 76a89eb65baf..16c7453f4946 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -26,7 +26,6 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/bitops.h> -#include <linux/debugfs.h> #include <linux/platform_device.h> #include <sound/core.h> #include <sound/pcm.h> @@ -35,22 +34,18 @@ #include <sound/soc-dapm.h> #include <sound/initval.h> +/* debug */ +#define SOC_DEBUG 0 +#if SOC_DEBUG +#define dbg(format, arg...) printk(format, ## arg) +#else +#define dbg(format, arg...) +#endif + static DEFINE_MUTEX(pcm_mutex); static DEFINE_MUTEX(io_mutex); static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); -#ifdef CONFIG_DEBUG_FS -static struct dentry *debugfs_root; -#endif - -static DEFINE_MUTEX(client_mutex); -static LIST_HEAD(card_list); -static LIST_HEAD(dai_list); -static LIST_HEAD(platform_list); - -static int snd_soc_register_card(struct snd_soc_card *card); -static int snd_soc_unregister_card(struct snd_soc_card *card); - /* * This is a timeout to do a DAPM powerdown after a stream is closed(). * It can be used to eliminate pops between different playback streams, e.g. @@ -112,6 +107,20 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) } #endif +static inline const char *get_dai_name(int type) +{ + switch (type) { + case SND_SOC_DAI_AC97_BUS: + case SND_SOC_DAI_AC97: + return "AC97"; + case SND_SOC_DAI_I2S: + return "I2S"; + case SND_SOC_DAI_PCM: + return "PCM"; + } + return NULL; +} + /* * Called by ALSA when a PCM substream is opened, the runtime->hw record is * then initialized and any private data can be allocated. This also calls @@ -121,10 +130,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_card *card = socdev->card; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret = 0; @@ -133,7 +141,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) /* startup the audio subsystem */ if (cpu_dai->ops.startup) { - ret = cpu_dai->ops.startup(substream, cpu_dai); + ret = cpu_dai->ops.startup(substream); if (ret < 0) { printk(KERN_ERR "asoc: can't open interface %s\n", cpu_dai->name); @@ -150,7 +158,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } if (codec_dai->ops.startup) { - ret = codec_dai->ops.startup(substream, codec_dai); + ret = codec_dai->ops.startup(substream); if (ret < 0) { printk(KERN_ERR "asoc: can't open codec %s\n", codec_dai->name); @@ -220,12 +228,12 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto machine_err; } - pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); - pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); - pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, - runtime->hw.channels_max); - pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, - runtime->hw.rate_max); + dbg("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); + dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); + dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, + runtime->hw.channels_max); + dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, + runtime->hw.rate_max); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) cpu_dai->playback.active = codec_dai->playback.active = 1; @@ -247,7 +255,7 @@ codec_dai_err: platform_err: if (cpu_dai->ops.shutdown) - cpu_dai->ops.shutdown(substream, cpu_dai); + cpu_dai->ops.shutdown(substream); out: mutex_unlock(&pcm_mutex); return ret; @@ -260,9 +268,8 @@ out: */ static void close_delayed_work(struct work_struct *work) { - struct snd_soc_card *card = container_of(work, struct snd_soc_card, - delayed_work.work); - struct snd_soc_device *socdev = card->socdev; + struct snd_soc_device *socdev = + container_of(work, struct snd_soc_device, delayed_work.work); struct snd_soc_codec *codec = socdev->codec; struct snd_soc_dai *codec_dai; int i; @@ -271,18 +278,18 @@ static void close_delayed_work(struct work_struct *work) for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; - pr_debug("pop wq checking: %s status: %s waiting: %s\n", - codec_dai->playback.stream_name, - codec_dai->playback.active ? "active" : "inactive", - codec_dai->pop_wait ? "yes" : "no"); + dbg("pop wq checking: %s status: %s waiting: %s\n", + codec_dai->playback.stream_name, + codec_dai->playback.active ? "active" : "inactive", + codec_dai->pop_wait ? "yes" : "no"); /* are we waiting on this codec DAI stream */ if (codec_dai->pop_wait == 1) { /* Reduce power if no longer active */ if (codec->active == 0) { - pr_debug("pop wq D1 %s %s\n", codec->name, - codec_dai->playback.stream_name); + dbg("pop wq D1 %s %s\n", codec->name, + codec_dai->playback.stream_name); snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE); } @@ -294,8 +301,8 @@ static void close_delayed_work(struct work_struct *work) /* Fall into standby if no longer active */ if (codec->active == 0) { - pr_debug("pop wq D3 %s %s\n", codec->name, - codec_dai->playback.stream_name); + dbg("pop wq D3 %s %s\n", codec->name, + codec_dai->playback.stream_name); snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY); } @@ -313,9 +320,8 @@ static int soc_codec_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -340,10 +346,10 @@ static int soc_codec_close(struct snd_pcm_substream *substream) snd_soc_dai_digital_mute(codec_dai, 1); if (cpu_dai->ops.shutdown) - cpu_dai->ops.shutdown(substream, cpu_dai); + cpu_dai->ops.shutdown(substream); if (codec_dai->ops.shutdown) - codec_dai->ops.shutdown(substream, codec_dai); + codec_dai->ops.shutdown(substream); if (machine->ops && machine->ops->shutdown) machine->ops->shutdown(substream); @@ -355,7 +361,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* start delayed pop wq here for playback streams */ codec_dai->pop_wait = 1; - schedule_delayed_work(&card->delayed_work, + schedule_delayed_work(&socdev->delayed_work, msecs_to_jiffies(pmdown_time)); } else { /* capture streams can be powered down now */ @@ -381,9 +387,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -408,7 +413,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } if (codec_dai->ops.prepare) { - ret = codec_dai->ops.prepare(substream, codec_dai); + ret = codec_dai->ops.prepare(substream); if (ret < 0) { printk(KERN_ERR "asoc: codec DAI prepare error\n"); goto out; @@ -416,49 +421,58 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } if (cpu_dai->ops.prepare) { - ret = cpu_dai->ops.prepare(substream, cpu_dai); + ret = cpu_dai->ops.prepare(substream); if (ret < 0) { printk(KERN_ERR "asoc: cpu DAI prepare error\n"); goto out; } } - /* cancel any delayed stream shutdown that is pending */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - codec_dai->pop_wait) { - codec_dai->pop_wait = 0; - cancel_delayed_work(&card->delayed_work); - } + /* we only want to start a DAPM playback stream if we are not waiting + * on an existing one stopping */ + if (codec_dai->pop_wait) { + /* we are waiting for the delayed work to start */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + snd_soc_dapm_stream_event(socdev->codec, + codec_dai->capture.stream_name, + SND_SOC_DAPM_STREAM_START); + else { + codec_dai->pop_wait = 0; + cancel_delayed_work(&socdev->delayed_work); + snd_soc_dai_digital_mute(codec_dai, 0); + } + } else { + /* no delayed work - do we need to power up codec */ + if (codec->bias_level != SND_SOC_BIAS_ON) { - /* do we need to power up codec */ - if (codec->bias_level != SND_SOC_BIAS_ON) { - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_PREPARE); + snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_PREPARE); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(codec, + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(codec, + else + snd_soc_dapm_stream_event(codec, codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); - snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); - snd_soc_dai_digital_mute(codec_dai, 0); + snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); + snd_soc_dai_digital_mute(codec_dai, 0); - } else { - /* codec already powered - power on widgets */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(codec, + } else { + /* codec already powered - power on widgets */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(codec, + else + snd_soc_dapm_stream_event(codec, codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); - snd_soc_dai_digital_mute(codec_dai, 0); + snd_soc_dai_digital_mute(codec_dai, 0); + } } out: @@ -477,8 +491,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret = 0; @@ -494,7 +507,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } if (codec_dai->ops.hw_params) { - ret = codec_dai->ops.hw_params(substream, params, codec_dai); + ret = codec_dai->ops.hw_params(substream, params); if (ret < 0) { printk(KERN_ERR "asoc: can't set codec %s hw params\n", codec_dai->name); @@ -503,7 +516,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } if (cpu_dai->ops.hw_params) { - ret = cpu_dai->ops.hw_params(substream, params, cpu_dai); + ret = cpu_dai->ops.hw_params(substream, params); if (ret < 0) { printk(KERN_ERR "asoc: interface %s hw params failed\n", cpu_dai->name); @@ -526,11 +539,11 @@ out: platform_err: if (cpu_dai->ops.hw_free) - cpu_dai->ops.hw_free(substream, cpu_dai); + cpu_dai->ops.hw_free(substream); interface_err: if (codec_dai->ops.hw_free) - codec_dai->ops.hw_free(substream, codec_dai); + codec_dai->ops.hw_free(substream); codec_err: if (machine->ops && machine->ops->hw_free) @@ -548,8 +561,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -570,10 +582,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) /* now free hw params for the DAI's */ if (codec_dai->ops.hw_free) - codec_dai->ops.hw_free(substream, codec_dai); + codec_dai->ops.hw_free(substream); if (cpu_dai->ops.hw_free) - cpu_dai->ops.hw_free(substream, cpu_dai); + cpu_dai->ops.hw_free(substream); mutex_unlock(&pcm_mutex); return 0; @@ -583,15 +595,14 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_card *card= socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret; if (codec_dai->ops.trigger) { - ret = codec_dai->ops.trigger(substream, cmd, codec_dai); + ret = codec_dai->ops.trigger(substream, cmd); if (ret < 0) return ret; } @@ -603,7 +614,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } if (cpu_dai->ops.trigger) { - ret = cpu_dai->ops.trigger(substream, cmd, cpu_dai); + ret = cpu_dai->ops.trigger(substream, cmd); if (ret < 0) return ret; } @@ -625,8 +636,8 @@ static struct snd_pcm_ops soc_pcm_ops = { static int soc_suspend(struct platform_device *pdev, pm_message_t state) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; int i; @@ -642,29 +653,29 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot); /* mute any active DAC's */ - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *dai = card->dai_link[i].codec_dai; - if (dai->ops.digital_mute && dai->playback.active) - dai->ops.digital_mute(dai, 1); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; + if (dai->dai_ops.digital_mute && dai->playback.active) + dai->dai_ops.digital_mute(dai, 1); } /* suspend all pcms */ - for (i = 0; i < card->num_links; i++) - snd_pcm_suspend_all(card->dai_link[i].pcm); + for (i = 0; i < machine->num_links; i++) + snd_pcm_suspend_all(machine->dai_link[i].pcm); - if (card->suspend_pre) - card->suspend_pre(pdev, state); + if (machine->suspend_pre) + machine->suspend_pre(pdev, state); - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->suspend && !cpu_dai->ac97_control) - cpu_dai->suspend(cpu_dai); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) + cpu_dai->suspend(pdev, cpu_dai); if (platform->suspend) - platform->suspend(cpu_dai); + platform->suspend(pdev, cpu_dai); } /* close any waiting streams and save state */ - run_delayed_work(&card->delayed_work); + run_delayed_work(&socdev->delayed_work); codec->suspend_bias_level = codec->bias_level; for (i = 0; i < codec->num_dai; i++) { @@ -681,14 +692,14 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) if (codec_dev->suspend) codec_dev->suspend(pdev, state); - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->suspend && cpu_dai->ac97_control) - cpu_dai->suspend(cpu_dai); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) + cpu_dai->suspend(pdev, cpu_dai); } - if (card->suspend_post) - card->suspend_post(pdev, state); + if (machine->suspend_post) + machine->suspend_post(pdev, state); return 0; } @@ -698,11 +709,11 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) */ static void soc_resume_deferred(struct work_struct *work) { - struct snd_soc_card *card = container_of(work, - struct snd_soc_card, - deferred_resume_work); - struct snd_soc_device *socdev = card->socdev; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_device *socdev = container_of(work, + struct snd_soc_device, + deferred_resume_work); + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; struct platform_device *pdev = to_platform_device(socdev->dev); @@ -712,15 +723,15 @@ static void soc_resume_deferred(struct work_struct *work) * so userspace apps are blocked from touching us */ - dev_dbg(socdev->dev, "starting resume work\n"); + dev_info(socdev->dev, "starting resume work\n"); - if (card->resume_pre) - card->resume_pre(pdev); + if (machine->resume_pre) + machine->resume_pre(pdev); - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->resume && cpu_dai->ac97_control) - cpu_dai->resume(cpu_dai); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) + cpu_dai->resume(pdev, cpu_dai); } if (codec_dev->resume) @@ -738,24 +749,24 @@ static void soc_resume_deferred(struct work_struct *work) } /* unmute any active DACs */ - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *dai = card->dai_link[i].codec_dai; - if (dai->ops.digital_mute && dai->playback.active) - dai->ops.digital_mute(dai, 0); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; + if (dai->dai_ops.digital_mute && dai->playback.active) + dai->dai_ops.digital_mute(dai, 0); } - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->resume && !cpu_dai->ac97_control) - cpu_dai->resume(cpu_dai); + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) + cpu_dai->resume(pdev, cpu_dai); if (platform->resume) - platform->resume(cpu_dai); + platform->resume(pdev, cpu_dai); } - if (card->resume_post) - card->resume_post(pdev); + if (machine->resume_post) + machine->resume_post(pdev); - dev_dbg(socdev->dev, "resume work completed\n"); + dev_info(socdev->dev, "resume work completed\n"); /* userspace can access us now we are back as we were before */ snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0); @@ -765,12 +776,11 @@ static void soc_resume_deferred(struct work_struct *work) static int soc_resume(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - dev_dbg(socdev->dev, "scheduling resume work\n"); + dev_info(socdev->dev, "scheduling resume work\n"); - if (!schedule_work(&card->deferred_resume_work)) - dev_err(socdev->dev, "resume work item may be lost\n"); + if (!schedule_work(&socdev->deferred_resume_work)) + dev_err(socdev->dev, "work item may be lost\n"); return 0; } @@ -780,83 +790,23 @@ static int soc_resume(struct platform_device *pdev) #define soc_resume NULL #endif -static void snd_soc_instantiate_card(struct snd_soc_card *card) +/* probes a new socdev */ +static int soc_probe(struct platform_device *pdev) { - struct platform_device *pdev = container_of(card->dev, - struct platform_device, - dev); - struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev; - struct snd_soc_platform *platform; - struct snd_soc_dai *dai; - int i, found, ret, ac97; - - if (card->instantiated) - return; - - found = 0; - list_for_each_entry(platform, &platform_list, list) - if (card->platform == platform) { - found = 1; - break; - } - if (!found) { - dev_dbg(card->dev, "Platform %s not registered\n", - card->platform->name); - return; - } - - ac97 = 0; - for (i = 0; i < card->num_links; i++) { - found = 0; - list_for_each_entry(dai, &dai_list, list) - if (card->dai_link[i].cpu_dai == dai) { - found = 1; - break; - } - if (!found) { - dev_dbg(card->dev, "DAI %s not registered\n", - card->dai_link[i].cpu_dai->name); - return; - } - - if (card->dai_link[i].cpu_dai->ac97_control) - ac97 = 1; - } - - /* If we have AC97 in the system then don't wait for the - * codec. This will need revisiting if we have to handle - * systems with mixed AC97 and non-AC97 parts. Only check for - * DAIs currently; we can't do this per link since some AC97 - * codecs have non-AC97 DAIs. - */ - if (!ac97) - for (i = 0; i < card->num_links; i++) { - found = 0; - list_for_each_entry(dai, &dai_list, list) - if (card->dai_link[i].codec_dai == dai) { - found = 1; - break; - } - if (!found) { - dev_dbg(card->dev, "DAI %s not registered\n", - card->dai_link[i].codec_dai->name); - return; - } - } - - /* Note that we do not current check for codec components */ - - dev_dbg(card->dev, "All components present, instantiating\n"); + int ret = 0, i; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - /* Found everything, bring it up */ - if (card->probe) { - ret = card->probe(pdev); + if (machine->probe) { + ret = machine->probe(pdev); if (ret < 0) - return; + return ret; } - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->probe) { ret = cpu_dai->probe(pdev, cpu_dai); if (ret < 0) @@ -877,15 +827,13 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) } /* DAPM stream work */ - INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work); + INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); #ifdef CONFIG_PM /* deferred resume work */ - INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); + INIT_WORK(&socdev->deferred_resume_work, soc_resume_deferred); #endif - card->instantiated = 1; - - return; + return 0; platform_err: if (codec_dev->remove) @@ -893,45 +841,15 @@ platform_err: cpu_dai_err: for (i--; i >= 0; i--) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->remove) cpu_dai->remove(pdev, cpu_dai); } - if (card->remove) - card->remove(pdev); -} - -/* - * Attempt to initialise any uninitalised cards. Must be called with - * client_mutex. - */ -static void snd_soc_instantiate_cards(void) -{ - struct snd_soc_card *card; - list_for_each_entry(card, &card_list, list) - snd_soc_instantiate_card(card); -} + if (machine->remove) + machine->remove(pdev); -/* probes a new socdev */ -static int soc_probe(struct platform_device *pdev) -{ - int ret = 0; - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - - /* Bodge while we push things out of socdev */ - card->socdev = socdev; - - /* Bodge while we unpick instantiation */ - card->dev = &pdev->dev; - ret = snd_soc_register_card(card); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to register card\n"); - return ret; - } - - return 0; + return ret; } /* removes a socdev */ @@ -939,11 +857,11 @@ static int soc_remove(struct platform_device *pdev) { int i; struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; + struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - run_delayed_work(&card->delayed_work); + run_delayed_work(&socdev->delayed_work); if (platform->remove) platform->remove(pdev); @@ -951,16 +869,14 @@ static int soc_remove(struct platform_device *pdev) if (codec_dev->remove) codec_dev->remove(pdev); - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; + for (i = 0; i < machine->num_links; i++) { + struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; if (cpu_dai->remove) cpu_dai->remove(pdev, cpu_dai); } - if (card->remove) - card->remove(pdev); - - snd_soc_unregister_card(card); + if (machine->remove) + machine->remove(pdev); return 0; } @@ -982,8 +898,6 @@ static int soc_new_pcm(struct snd_soc_device *socdev, struct snd_soc_dai_link *dai_link, int num) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *codec_dai = dai_link->codec_dai; struct snd_soc_dai *cpu_dai = dai_link->cpu_dai; struct snd_soc_pcm_runtime *rtd; @@ -1000,8 +914,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, codec_dai->codec = socdev->codec; /* check client and interface hw capabilities */ - sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name, - num); + sprintf(new_name, "%s %s-%s-%d", dai_link->stream_name, codec_dai->name, + get_dai_name(cpu_dai->type), num); if (codec_dai->playback.channels_min) playback = 1; @@ -1019,13 +933,13 @@ static int soc_new_pcm(struct snd_soc_device *socdev, dai_link->pcm = pcm; pcm->private_data = rtd; - soc_pcm_ops.mmap = platform->pcm_ops->mmap; - soc_pcm_ops.pointer = platform->pcm_ops->pointer; - soc_pcm_ops.ioctl = platform->pcm_ops->ioctl; - soc_pcm_ops.copy = platform->pcm_ops->copy; - soc_pcm_ops.silence = platform->pcm_ops->silence; - soc_pcm_ops.ack = platform->pcm_ops->ack; - soc_pcm_ops.page = platform->pcm_ops->page; + soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap; + soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer; + soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl; + soc_pcm_ops.copy = socdev->platform->pcm_ops->copy; + soc_pcm_ops.silence = socdev->platform->pcm_ops->silence; + soc_pcm_ops.ack = socdev->platform->pcm_ops->ack; + soc_pcm_ops.page = socdev->platform->pcm_ops->page; if (playback) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); @@ -1033,22 +947,24 @@ static int soc_new_pcm(struct snd_soc_device *socdev, if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); - ret = platform->pcm_new(codec->card, codec_dai, pcm); + ret = socdev->platform->pcm_new(codec->card, codec_dai, pcm); if (ret < 0) { printk(KERN_ERR "asoc: platform pcm constructor failed\n"); kfree(rtd); return ret; } - pcm->private_free = platform->pcm_free; + pcm->private_free = socdev->platform->pcm_free; printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, cpu_dai->name); return ret; } /* codec register dump */ -static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf) +static ssize_t codec_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) { + struct snd_soc_device *devdata = dev_get_drvdata(dev); struct snd_soc_codec *codec = devdata->codec; int i, step = 1, count = 0; @@ -1085,110 +1001,8 @@ static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf) return count; } -static ssize_t codec_reg_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct snd_soc_device *devdata = dev_get_drvdata(dev); - return soc_codec_reg_show(devdata, buf); -} - static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); -#ifdef CONFIG_DEBUG_FS -static int codec_reg_open_file(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - ssize_t ret; - struct snd_soc_codec *codec = file->private_data; - struct device *card_dev = codec->card->dev; - struct snd_soc_device *devdata = card_dev->driver_data; - char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - ret = soc_codec_reg_show(devdata, buf); - if (ret >= 0) - ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); - kfree(buf); - return ret; -} - -static ssize_t codec_reg_write_file(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - char buf[32]; - int buf_size; - char *start = buf; - unsigned long reg, value; - int step = 1; - struct snd_soc_codec *codec = file->private_data; - - buf_size = min(count, (sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; - - if (codec->reg_cache_step) - step = codec->reg_cache_step; - - while (*start == ' ') - start++; - reg = simple_strtoul(start, &start, 16); - if ((reg >= codec->reg_cache_size) || (reg % step)) - return -EINVAL; - while (*start == ' ') - start++; - if (strict_strtoul(start, 16, &value)) - return -EINVAL; - codec->write(codec, reg, value); - return buf_size; -} - -static const struct file_operations codec_reg_fops = { - .open = codec_reg_open_file, - .read = codec_reg_read_file, - .write = codec_reg_write_file, -}; - -static void soc_init_codec_debugfs(struct snd_soc_codec *codec) -{ - codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, - debugfs_root, codec, - &codec_reg_fops); - if (!codec->debugfs_reg) - printk(KERN_WARNING - "ASoC: Failed to create codec register debugfs file\n"); - - codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744, - debugfs_root, - &codec->pop_time); - if (!codec->debugfs_pop_time) - printk(KERN_WARNING - "Failed to create pop time debugfs file\n"); -} - -static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ - debugfs_remove(codec->debugfs_pop_time); - debugfs_remove(codec->debugfs_reg); -} - -#else - -static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) -{ -} - -static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) -{ -} -#endif - /** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec @@ -1307,7 +1121,7 @@ EXPORT_SYMBOL_GPL(snd_soc_test_bits); int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_card *card = socdev->card; + struct snd_soc_machine *machine = socdev->machine; int ret = 0, i; mutex_lock(&codec->mutex); @@ -1326,11 +1140,11 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); /* create the pcms */ - for (i = 0; i < card->num_links; i++) { - ret = soc_new_pcm(socdev, &card->dai_link[i], i); + for (i = 0; i < machine->num_links; i++) { + ret = soc_new_pcm(socdev, &machine->dai_link[i], i); if (ret < 0) { printk(KERN_ERR "asoc: can't create pcm %s\n", - card->dai_link[i].stream_name); + machine->dai_link[i].stream_name); mutex_unlock(&codec->mutex); return ret; } @@ -1342,7 +1156,7 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) EXPORT_SYMBOL_GPL(snd_soc_new_pcms); /** - * snd_soc_init_card - register sound card + * snd_soc_register_card - register sound card * @socdev: the SoC audio device * * Register a SoC sound card. Also registers an AC97 device if the @@ -1350,28 +1164,29 @@ EXPORT_SYMBOL_GPL(snd_soc_new_pcms); * * Returns 0 for success, else error. */ -int snd_soc_init_card(struct snd_soc_device *socdev) +int snd_soc_register_card(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_card *card = socdev->card; + struct snd_soc_machine *machine = socdev->machine; int ret = 0, i, ac97 = 0, err = 0; - for (i = 0; i < card->num_links; i++) { - if (card->dai_link[i].init) { - err = card->dai_link[i].init(codec); + for (i = 0; i < machine->num_links; i++) { + if (socdev->machine->dai_link[i].init) { + err = socdev->machine->dai_link[i].init(codec); if (err < 0) { printk(KERN_ERR "asoc: failed to init %s\n", - card->dai_link[i].stream_name); + socdev->machine->dai_link[i].stream_name); continue; } } - if (card->dai_link[i].codec_dai->ac97_control) + if (socdev->machine->dai_link[i].codec_dai->type == + SND_SOC_DAI_AC97_BUS) ac97 = 1; } snprintf(codec->card->shortname, sizeof(codec->card->shortname), - "%s", card->name); + "%s", machine->name); snprintf(codec->card->longname, sizeof(codec->card->longname), - "%s (%s)", card->name, codec->name); + "%s (%s)", machine->name, codec->name); ret = snd_card_register(codec->card); if (ret < 0) { @@ -1401,13 +1216,12 @@ int snd_soc_init_card(struct snd_soc_device *socdev) if (err < 0) printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); - soc_init_codec_debugfs(socdev->codec); mutex_unlock(&codec->mutex); out: return ret; } -EXPORT_SYMBOL_GPL(snd_soc_init_card); +EXPORT_SYMBOL_GPL(snd_soc_register_card); /** * snd_soc_free_pcms - free sound card and pcms @@ -1425,11 +1239,10 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev) #endif mutex_lock(&codec->mutex); - soc_cleanup_codec_debugfs(socdev->codec); #ifdef CONFIG_SND_SOC_AC97_BUS for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; - if (codec_dai->ac97_control && codec->ac97) { + if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) { soc_ac97_dev_unregister(codec); goto free_card; } @@ -1943,8 +1756,8 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { - if (dai->ops.set_sysclk) - return dai->ops.set_sysclk(dai, clk_id, freq, dir); + if (dai->dai_ops.set_sysclk) + return dai->dai_ops.set_sysclk(dai, clk_id, freq, dir); else return -EINVAL; } @@ -1963,8 +1776,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { - if (dai->ops.set_clkdiv) - return dai->ops.set_clkdiv(dai, div_id, div); + if (dai->dai_ops.set_clkdiv) + return dai->dai_ops.set_clkdiv(dai, div_id, div); else return -EINVAL; } @@ -1982,8 +1795,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { - if (dai->ops.set_pll) - return dai->ops.set_pll(dai, pll_id, freq_in, freq_out); + if (dai->dai_ops.set_pll) + return dai->dai_ops.set_pll(dai, pll_id, freq_in, freq_out); else return -EINVAL; } @@ -1992,14 +1805,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); /** * snd_soc_dai_set_fmt - configure DAI hardware audio format. * @dai: DAI + * @clk_id: DAI specific clock ID * @fmt: SND_SOC_DAIFMT_ format value. * * Configures the DAI hardware format and clocking. */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if (dai->ops.set_fmt) - return dai->ops.set_fmt(dai, fmt); + if (dai->dai_ops.set_fmt) + return dai->dai_ops.set_fmt(dai, fmt); else return -EINVAL; } @@ -2017,8 +1831,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int mask, int slots) { - if (dai->ops.set_sysclk) - return dai->ops.set_tdm_slot(dai, mask, slots); + if (dai->dai_ops.set_sysclk) + return dai->dai_ops.set_tdm_slot(dai, mask, slots); else return -EINVAL; } @@ -2033,8 +1847,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); */ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) { - if (dai->ops.set_sysclk) - return dai->ops.set_tristate(dai, tristate); + if (dai->dai_ops.set_sysclk) + return dai->dai_ops.set_tristate(dai, tristate); else return -EINVAL; } @@ -2049,200 +1863,21 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); */ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) { - if (dai->ops.digital_mute) - return dai->ops.digital_mute(dai, mute); + if (dai->dai_ops.digital_mute) + return dai->dai_ops.digital_mute(dai, mute); else return -EINVAL; } EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); -/** - * snd_soc_register_card - Register a card with the ASoC core - * - * @param card Card to register - * - * Note that currently this is an internal only function: it will be - * exposed to machine drivers after further backporting of ASoC v2 - * registration APIs. - */ -static int snd_soc_register_card(struct snd_soc_card *card) -{ - if (!card->name || !card->dev) - return -EINVAL; - - INIT_LIST_HEAD(&card->list); - card->instantiated = 0; - - mutex_lock(&client_mutex); - list_add(&card->list, &card_list); - snd_soc_instantiate_cards(); - mutex_unlock(&client_mutex); - - dev_dbg(card->dev, "Registered card '%s'\n", card->name); - - return 0; -} - -/** - * snd_soc_unregister_card - Unregister a card with the ASoC core - * - * @param card Card to unregister - * - * Note that currently this is an internal only function: it will be - * exposed to machine drivers after further backporting of ASoC v2 - * registration APIs. - */ -static int snd_soc_unregister_card(struct snd_soc_card *card) -{ - mutex_lock(&client_mutex); - list_del(&card->list); - mutex_unlock(&client_mutex); - - dev_dbg(card->dev, "Unregistered card '%s'\n", card->name); - - return 0; -} - -/** - * snd_soc_register_dai - Register a DAI with the ASoC core - * - * @param dai DAI to register - */ -int snd_soc_register_dai(struct snd_soc_dai *dai) -{ - if (!dai->name) - return -EINVAL; - - /* The device should become mandatory over time */ - if (!dai->dev) - printk(KERN_WARNING "No device for DAI %s\n", dai->name); - - INIT_LIST_HEAD(&dai->list); - - mutex_lock(&client_mutex); - list_add(&dai->list, &dai_list); - snd_soc_instantiate_cards(); - mutex_unlock(&client_mutex); - - pr_debug("Registered DAI '%s'\n", dai->name); - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_register_dai); - -/** - * snd_soc_unregister_dai - Unregister a DAI from the ASoC core - * - * @param dai DAI to unregister - */ -void snd_soc_unregister_dai(struct snd_soc_dai *dai) -{ - mutex_lock(&client_mutex); - list_del(&dai->list); - mutex_unlock(&client_mutex); - - pr_debug("Unregistered DAI '%s'\n", dai->name); -} -EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); - -/** - * snd_soc_register_dais - Register multiple DAIs with the ASoC core - * - * @param dai Array of DAIs to register - * @param count Number of DAIs - */ -int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - ret = snd_soc_register_dai(&dai[i]); - if (ret != 0) - goto err; - } - - return 0; - -err: - for (i--; i >= 0; i--) - snd_soc_unregister_dai(&dai[i]); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_register_dais); - -/** - * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core - * - * @param dai Array of DAIs to unregister - * @param count Number of DAIs - */ -void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count) -{ - int i; - - for (i = 0; i < count; i++) - snd_soc_unregister_dai(&dai[i]); -} -EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); - -/** - * snd_soc_register_platform - Register a platform with the ASoC core - * - * @param platform platform to register - */ -int snd_soc_register_platform(struct snd_soc_platform *platform) -{ - if (!platform->name) - return -EINVAL; - - INIT_LIST_HEAD(&platform->list); - - mutex_lock(&client_mutex); - list_add(&platform->list, &platform_list); - snd_soc_instantiate_cards(); - mutex_unlock(&client_mutex); - - pr_debug("Registered platform '%s'\n", platform->name); - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_register_platform); - -/** - * snd_soc_unregister_platform - Unregister a platform from the ASoC core - * - * @param platform platform to unregister - */ -void snd_soc_unregister_platform(struct snd_soc_platform *platform) -{ - mutex_lock(&client_mutex); - list_del(&platform->list); - mutex_unlock(&client_mutex); - - pr_debug("Unregistered platform '%s'\n", platform->name); -} -EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); - static int __devinit snd_soc_init(void) { -#ifdef CONFIG_DEBUG_FS - debugfs_root = debugfs_create_dir("asoc", NULL); - if (IS_ERR(debugfs_root) || !debugfs_root) { - printk(KERN_WARNING - "ASoC: Failed to create debugfs directory\n"); - debugfs_root = NULL; - } -#endif - + printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); return platform_driver_register(&soc_driver); } -static void __exit snd_soc_exit(void) +static void snd_soc_exit(void) { -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(debugfs_root); -#endif platform_driver_unregister(&soc_driver); } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 61d7d85aa578..7351db9606e4 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -37,6 +37,7 @@ #include <linux/bitops.h> #include <linux/platform_device.h> #include <linux/jiffies.h> +#include <linux/debugfs.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -66,13 +67,17 @@ static int dapm_status = 1; module_param(dapm_status, int, 0); MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); -static void pop_wait(u32 pop_time) +static struct dentry *asoc_debugfs; + +static u32 pop_time; + +static void pop_wait(void) { if (pop_time) schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); } -static void pop_dbg(u32 pop_time, const char *fmt, ...) +static void pop_dbg(const char *fmt, ...) { va_list args; @@ -80,7 +85,7 @@ static void pop_dbg(u32 pop_time, const char *fmt, ...) if (pop_time) { vprintk(fmt, args); - pop_wait(pop_time); + pop_wait(); } va_end(args); @@ -225,11 +230,10 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget) change = old != new; if (change) { - pop_dbg(codec->pop_time, "pop test %s : %s in %d ms\n", - widget->name, widget->power ? "on" : "off", - codec->pop_time); + pop_dbg("pop test %s : %s in %d ms\n", widget->name, + widget->power ? "on" : "off", pop_time); snd_soc_write(codec, widget->reg, new); - pop_wait(codec->pop_time); + pop_wait(); } pr_debug("reg %x old %x new %x change %d\n", widget->reg, old, new, change); @@ -289,7 +293,7 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, struct snd_soc_dapm_widget *w) { int i, ret = 0; - size_t name_len; + char name[32]; struct snd_soc_dapm_path *path; /* add kcontrol */ @@ -303,16 +307,11 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, continue; /* add dapm control with long name */ - name_len = 2 + strlen(w->name) - + strlen(w->kcontrols[i].name); - path->long_name = kmalloc(name_len, GFP_KERNEL); + snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name); + path->long_name = kstrdup (name, GFP_KERNEL); if (path->long_name == NULL) return -ENOMEM; - snprintf(path->long_name, name_len, "%s %s", - w->name, w->kcontrols[i].name); - path->long_name[name_len - 1] = '\0'; - path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, path->long_name); ret = snd_ctl_add(codec->card, path->kcontrol); @@ -822,9 +821,23 @@ static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); int snd_soc_dapm_sys_add(struct device *dev) { + int ret = 0; + if (!dapm_status) return 0; - return device_create_file(dev, &dev_attr_dapm_widget); + + ret = device_create_file(dev, &dev_attr_dapm_widget); + if (ret != 0) + return ret; + + asoc_debugfs = debugfs_create_dir("asoc", NULL); + if (!IS_ERR(asoc_debugfs) && asoc_debugfs) + debugfs_create_u32("dapm_pop_time", 0744, asoc_debugfs, + &pop_time); + else + asoc_debugfs = NULL; + + return 0; } static void snd_soc_dapm_sys_remove(struct device *dev) @@ -832,6 +845,9 @@ static void snd_soc_dapm_sys_remove(struct device *dev) if (dapm_status) { device_remove_file(dev, &dev_attr_dapm_widget); } + + if (asoc_debugfs) + debugfs_remove_recursive(asoc_debugfs); } /* free all dapm widgets and resources */ @@ -991,6 +1007,28 @@ err: } /** + * snd_soc_dapm_connect_input - connect dapm widgets + * @codec: audio codec + * @sink: name of target widget + * @control: mixer control name + * @source: name of source name + * + * Connects 2 dapm widgets together via a named audio path. The sink is + * the widget receiving the audio signal, whilst the source is the sender + * of the audio signal. + * + * This function has been deprecated in favour of snd_soc_dapm_add_routes(). + * + * Returns 0 for success else error. + */ +int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, + const char *control, const char *source) +{ + return snd_soc_dapm_add_route(codec, sink, control, source); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); + +/** * snd_soc_dapm_add_routes - Add routes between DAPM widgets * @codec: codec * @route: audio routes @@ -1402,11 +1440,11 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, enum snd_soc_bias_level level) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_card *card = socdev->card; + struct snd_soc_machine *machine = socdev->machine; int ret = 0; - if (card->set_bias_level) - ret = card->set_bias_level(card, level); + if (machine->set_bias_level) + ret = machine->set_bias_level(machine, level); if (ret == 0 && codec->set_bias_level) ret = codec->set_bias_level(codec, level); |