diff options
Diffstat (limited to 'target/linux/coldfire/patches/009-Add-ALSA-driver-for-MCF5445x.patch')
-rw-r--r-- | target/linux/coldfire/patches/009-Add-ALSA-driver-for-MCF5445x.patch | 1869 |
1 files changed, 0 insertions, 1869 deletions
diff --git a/target/linux/coldfire/patches/009-Add-ALSA-driver-for-MCF5445x.patch b/target/linux/coldfire/patches/009-Add-ALSA-driver-for-MCF5445x.patch deleted file mode 100644 index 52c1f56..0000000 --- a/target/linux/coldfire/patches/009-Add-ALSA-driver-for-MCF5445x.patch +++ /dev/null @@ -1,1869 +0,0 @@ -From d37d2d880efdc0ce515df4155ddafef3835d1b7f Mon Sep 17 00:00:00 2001 -From: Alison Wang <b18965@freescale.com> -Date: Thu, 4 Aug 2011 09:59:41 +0800 -Subject: [PATCH 09/52] Add ALSA driver for MCF5445x - -Add ALSA driver for MCF54451 and MCF54455. - -Signed-off-by: Alison Wang <b18965@freescale.com> ---- - sound/Kconfig | 6 +- - sound/Makefile | 1 + - sound/coldfire/Kconfig | 14 + - sound/coldfire/Makefile | 6 + - sound/coldfire/coldfire-codec-spi.c | 93 ++ - sound/coldfire/snd-coldfire.c | 1664 +++++++++++++++++++++++++++++++++++ - sound/coldfire/snd-coldfire.h | 15 + - 7 files changed, 1795 insertions(+), 4 deletions(-) - create mode 100644 sound/coldfire/Kconfig - create mode 100644 sound/coldfire/Makefile - create mode 100644 sound/coldfire/coldfire-codec-spi.c - create mode 100644 sound/coldfire/snd-coldfire.c - create mode 100644 sound/coldfire/snd-coldfire.h - ---- a/sound/Kconfig -+++ b/sound/Kconfig -@@ -59,8 +59,6 @@ config SOUND_OSS_CORE_PRECLAIM - - source "sound/oss/dmasound/Kconfig" - --if !M68K -- - menuconfig SND - tristate "Advanced Linux Sound Architecture" - help -@@ -85,6 +83,8 @@ source "sound/aoa/Kconfig" - - source "sound/arm/Kconfig" - -+source "sound/coldfire/Kconfig" -+ - source "sound/atmel/Kconfig" - - source "sound/spi/Kconfig" -@@ -121,8 +121,6 @@ source "sound/oss/Kconfig" - - endif # SOUND_PRIME - --endif # !M68K -- - endif # SOUND - - # AC97_BUS is used from both sound and ucb1400 ---- a/sound/Makefile -+++ b/sound/Makefile -@@ -8,6 +8,7 @@ obj-$(CONFIG_DMASOUND) += oss/ - obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ - sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ - obj-$(CONFIG_SND_AOA) += aoa/ -+obj-$(CONFIG_SND_COLDFIRE) += coldfire/ - - # This one must be compilable even if sound is configured out - obj-$(CONFIG_AC97_BUS) += ac97_bus.o ---- /dev/null -+++ b/sound/coldfire/Kconfig -@@ -0,0 +1,14 @@ -+ -+menu "ALSA for Coldfire" -+ -+config SND_COLDFIRE -+ bool "Coldfire sound devices" -+ depends on SND -+ select SND_PCM -+ select SSIAUDIO_USE_EDMA -+ default y -+ help -+ Support for sound devices specific to Coldfire architectures. -+ -+endmenu -+ ---- /dev/null -+++ b/sound/coldfire/Makefile -@@ -0,0 +1,6 @@ -+# -+# Makefile for Coldfire ALSA -+# -+ -+obj-y += snd-coldfire.o coldfire-codec-spi.o -+ ---- /dev/null -+++ b/sound/coldfire/coldfire-codec-spi.c -@@ -0,0 +1,93 @@ -+/* -+ * linux/sound/coldfire/coldfire-codec-spi.c -+ * -+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. -+ * Author: Kurt Mahan <kmahan@freescale.com> -+ * -+ * Simple SPI interface for the CODEC. -+ * -+ * This 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/device.h> -+#include <linux/init.h> -+#include <linux/spi/spi.h> -+#include <linux/kernel.h> -+#include <asm/mcfsim.h> -+#include <asm/coldfire.h> -+#include <linux/delay.h> -+ -+#define MCF_CODEC_SPI_DRIVER_NAME "mcf_codec_spi" -+ -+static struct spi_device *mcf_codec_spi; -+ -+/* -+ * Write CODEC register via SPI -+ */ -+int mcf_codec_spi_write(u8 addr, u16 data) -+{ -+ u16 spi_word; -+ -+ if (mcf_codec_spi == NULL) -+ return -ENODEV; -+ -+ spi_word = ((addr & 0x7F)<<9)|(data & 0x1FF); -+ return spi_write(mcf_codec_spi, (const u8 *)&spi_word, -+ sizeof(spi_word)); -+} -+EXPORT_SYMBOL(mcf_codec_spi_write); -+ -+static int __devinit mcf_codec_spi_probe(struct spi_device *spi) -+{ -+ spi->dev.power.power_state = PMSG_ON; -+ mcf_codec_spi = spi; -+ -+ return 0; -+} -+ -+static int __devexit mcf_codec_spi_remove(struct spi_device *spi) -+{ -+ return 0; -+} -+ -+static int mcf_codec_spi_suspend(struct spi_device *spi, pm_message_t message) -+{ -+ return 0; -+} -+ -+static int mcf_codec_spi_resume(struct spi_device *spi) -+{ -+ return 0; -+} -+ -+static struct spi_driver mcf_codec_spi_driver = { -+ .driver = { -+ .name = MCF_CODEC_SPI_DRIVER_NAME, -+ .bus = &spi_bus_type, -+ .owner = THIS_MODULE, -+ }, -+ .probe = mcf_codec_spi_probe, -+ .remove = __devexit_p(mcf_codec_spi_remove), -+ .suspend = mcf_codec_spi_suspend, -+ .resume = mcf_codec_spi_resume, -+}; -+ -+static int __init mcf_codec_spi_init(void) -+{ -+ return spi_register_driver(&mcf_codec_spi_driver); -+} -+module_init(mcf_codec_spi_init); -+ -+static void __exit mcf_codec_spi_exit(void) -+{ -+ spi_unregister_driver(&mcf_codec_spi_driver); -+} -+module_exit(mcf_codec_spi_exit); -+ -+ -+MODULE_DESCRIPTION("Coldfire Codec SPI driver"); -+MODULE_AUTHOR("Kurt Mahan, Freescale Semiconductor, Inc."); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/sound/coldfire/snd-coldfire.c -@@ -0,0 +1,1664 @@ -+/* -+ * linux/sound/coldfire/snd-coldfire.c -+ * -+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. -+ * Author: York Sun <r58495@freescale.com> -+ * Alison Wang <b18965@freescale.com> -+ * -+ * Coldfire ALSA driver based on SSI and TLV320A -+ * -+ * This 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. -+ * -+ *************************************************************************** -+ * -+ * NOTE: This driver was tested on MCF5445x, MCF5301x, MCF5227x, MCF532x and -+ * MCF537x platforms. -+ * */ -+ -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/platform_device.h> -+#include <linux/init.h> -+#include <linux/device.h> -+#include <linux/slab.h> -+#include <linux/dma-mapping.h> -+#include <linux/ioctl.h> -+#include <linux/soundcard.h> -+#include <linux/spi/spi.h> -+ -+#include <sound/core.h> -+#include <sound/pcm.h> -+#include <sound/pcm_params.h> -+#include <sound/control.h> -+#include <linux/fs.h> -+#include <linux/delay.h> -+ -+#include <asm/mcfsim.h> -+#include <asm/coldfire.h> -+#include <asm/mcf_edma.h> -+#include "snd-coldfire.h" -+ -+#if defined(CONFIG_M5445X) -+#include <asm/mcf5445x_ssi.h> -+#endif -+ -+#define CF_ALSA_DEBUG 0 -+#if CF_ALSA_DEBUG -+#define DBG(fmt, args...) printk(KERN_INFO "[%s] " fmt , \ -+ __func__, ## args) -+#else -+#define DBG(fmt, args...) do {} while (0) -+#endif -+ -+#define SOUND_CARD_NAME "Coldfire ALSA" -+#define MAX_BUFFER_SIZE (32*1024) -+ -+/* eDMA channel for SSI channel 0,1 TX,RX */ -+#define DMA_TX_TCD0 MCF_EDMA_CHAN_TIMER2 -+#define DMA_TX_TCD1 MCF_EDMA_CHAN_TIMER3 -+#define DMA_RX_TCD0 MCF_EDMA_CHAN_TIMER0 -+#define DMA_RX_TCD1 MCF_EDMA_CHAN_TIMER1 -+ -+#define CODEC_LEFT_IN_REG (0x00) -+#define CODEC_RIGHT_IN_REG (0x01) -+#define CODEC_LEFT_HP_VOL_REG (0x02) -+#define CODEC_RIGHT_HP_VOL_REG (0x03) -+#define CODEC_ANALOG_APATH_REG (0x04) -+#define CODEC_DIGITAL_APATH_REG (0x05) -+#define CODEC_POWER_DOWN_REG (0x06) -+#define CODEC_DIGITAL_IF_FMT_REG (0x07) -+#define CODEC_SAMPLE_RATE_REG (0x08) -+#define CODEC_DIGITAL_IF_ACT_REG (0x09) -+#define CODEC_RESET_REG (0x0f) -+ -+#define TLV320AIC23_CODEC_SAMPLE_RATE_REG (0x08) -+#define TLV320AIC23_CODEC_SAMPLERATE_REG_8KHZ (0x0C) -+#define TLV320AIC23_CODEC_SAMPLERATE_REG_11KHZ (0x0C) -+#define TLV320AIC23_CODEC_SAMPLERATE_REG_16KHZ (0x58) -+#define TLV320AIC23_CODEC_SAMPLERATE_REG_22KHZ (0x62) -+#define TLV320AIC23_CODEC_SAMPLERATE_REG_44KHZ (0x22) -+#define TLV320AIC23_CODEC_SAMPLERATE_REG_48KHZ (0x00) -+ -+#define MCF_SSI_AUDIO_IRQ_LEVEL (5) -+#define TLV320A_VOL_MAX 0x07F -+#define TLV320A_VOL_MIN 0x030 -+#define TLV320A_VOL_INIT 0x065 -+#define TLV320A_LINEIN_MAX 0x1F -+#define TLV320A_LINEIN_INIT 0x17 -+#define TLV320A_ANALOGPATH_INIT 0x11 -+ -+/* Codec settings */ -+#define MCF_SSI_AUDIO_MCLK_1 (12288000U) /*Hz*/ -+#define MCF_SSI_AUDIO_MCLK_2 (16934400U) /*Hz*/ -+#define MCF_SSI_AUDIO_MCLK_3 (14112000U) /*Hz*/ -+#define MCF_SSI_AUDIO_MCLK_4 (18432000U) /*Hz*/ -+ -+#define MCF_SSI_AUDIO_SSDIV_VALUE_1 \ -+ ((((u32)MCF_CLK*2)/MCF_SSI_AUDIO_MCLK_1)+ \ -+ (((((u32)MCF_CLK*2*10)/MCF_SSI_AUDIO_MCLK_1)%10) > 5)) -+ -+#define MCF_SSI_AUDIO_SSDIV_VALUE_2 \ -+ ((((u32)MCF_CLK*2)/MCF_SSI_AUDIO_MCLK_2)+ \ -+ (((((u32)MCF_CLK*2*10)/MCF_SSI_AUDIO_MCLK_2)%10) > 5)) -+ -+#define MCF_SSI_AUDIO_SSDIV_VALUE_3 \ -+ ((((u32)MCF_CLK*2)/MCF_SSI_AUDIO_MCLK_3)+ \ -+ (((((u32)MCF_CLK*2*10)/MCF_SSI_AUDIO_MCLK_3)%10) > 5)) -+ -+#define MCF_SSI_AUDIO_SSDIV_VALUE_4 \ -+ ((((u32)MCF_CLK*2)/MCF_SSI_AUDIO_MCLK_4)+ \ -+ (((((u32)MCF_CLK*2*10)/MCF_SSI_AUDIO_MCLK_4)%10) > 5)) -+ -+#define SNDRV_COLDFIRE_PCM_PLAYBACK_FORMATS SNDRV_PCM_FMTBIT_S16_BE -+#define SNDRV_COLDFIRE_PCM_CAPTURE_FORMATS SNDRV_PCM_FMTBIT_S16_BE -+ -+#define RXFWM 2 -+#define TXFWM 2 -+#define HW_PERIODS_BYTES_MIN 4096 -+#define HW_PERIODS_BYTES_STEP 4096 -+ -+#define INPUT_MICROPHONE 0 -+#define INPUT_LINEIN 1 -+#define NUM_TCDS 4 -+ -+static char *id; -+static struct platform_device *device; -+static int g_tx_dmaing; -+static int g_rx_dmaing; -+static unsigned char g_mastervol, g_lineinvol, g_analogpath; -+ -+/** Use 4 TCDs for scatter/gather address -+ * to setup dma chain, one TCD per period -+ * so that we don't need change them on the fly -+ */ -+ -+/** -+ * Link Descriptor -+ * -+ * must be aligned on a 32-byte boundary. -+ */ -+struct dma_tcd { -+ __be32 saddr; /* source address */ -+ __be16 attr; /* transfer attribute */ -+ __be16 soffset; /* source offset */ -+ __be32 nbytes; /* minor byte count */ -+ __be32 slast; /* last source address adjust */ -+ __be32 daddr; /* dest address */ -+ __be16 citer; /* current minor looplink, major count */ -+ __be16 doffset; /* dest offset */ -+ __be32 dlast_sga; /* last dest addr adjust, scatter/gather addr*/ -+ __be16 biter; /* begging minor looklink, major count */ -+ __be16 csr; /* control and status */ -+} __packed; -+ -+/** dma_private: p-substream DMA data -+ * -+ * The tcd[] array is first because it needs to be aligned on a 32-byte -+ * boundary, so putting it first will ensure alignment without padding the -+ * structure. -+ * -+ * @tcd[]: array of TCDs -+ */ -+struct dma_private { -+ struct dma_tcd tcd0[NUM_TCDS]; -+ struct dma_tcd tcd1[NUM_TCDS]; -+ dma_addr_t tcd_buf_phys; /* physical address of dma_private */ -+ dma_addr_t dma_buf_phys; -+ dma_addr_t dma_buf_next; -+ dma_addr_t dma_buf_end; -+ size_t period_size; -+ unsigned int num_periods; -+}; -+ -+struct tlv320a_audio_device { -+ struct spi_device *spi; -+ u32 speed; -+ u32 stereo; -+ u32 bits; -+ u32 format; -+ u8 isopen; -+ u8 dmaing; -+ u8 ssi_enabled; -+ u8 channel; -+ spinlock_t lock; -+ u8 *audio_buf; -+}; -+ -+/* chip specific define */ -+struct chip_spec { -+ struct snd_card *card; -+ struct snd_pcm *pcm; -+ struct tlv320a_audio_device *audio_device; -+ u32 offset; -+ void *mixer_data; -+}; -+ -+/* hardware definition */ -+static struct snd_pcm_hardware snd_coldfire_playback_hw = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED | -+#if defined(CONFIG_MMU) -+ SNDRV_PCM_INFO_MMAP | -+ SNDRV_PCM_INFO_MMAP_VALID| -+#endif -+ SNDRV_PCM_INFO_BLOCK_TRANSFER), -+ .formats = SNDRV_COLDFIRE_PCM_PLAYBACK_FORMATS, -+ .rates = SNDRV_PCM_RATE_8000_48000, -+ .rate_min = 8000, -+ .rate_max = 48000, -+ .channels_min = 1, -+ .channels_max = 2, -+ .buffer_bytes_max = MAX_BUFFER_SIZE, -+ .period_bytes_min = HW_PERIODS_BYTES_MIN, -+ .period_bytes_max = MAX_BUFFER_SIZE/NUM_TCDS, -+ .periods_min = NUM_TCDS, -+ .periods_max = NUM_TCDS, -+ .fifo_size = 0, -+}; -+ -+/* hardware definition */ -+static struct snd_pcm_hardware snd_coldfire_capture_hw = { -+ .info = (SNDRV_PCM_INFO_INTERLEAVED | -+#if defined(CONFIG_MMU) -+ SNDRV_PCM_INFO_MMAP | -+ SNDRV_PCM_INFO_MMAP_VALID| -+#endif -+ SNDRV_PCM_INFO_BLOCK_TRANSFER), -+ .formats = SNDRV_COLDFIRE_PCM_CAPTURE_FORMATS, -+ .rates = SNDRV_PCM_RATE_8000_48000, -+ .rate_min = 8000, -+ .rate_max = 48000, -+ .channels_min = 1, -+ .channels_max = 2, -+ .buffer_bytes_max = MAX_BUFFER_SIZE, -+ .period_bytes_min = HW_PERIODS_BYTES_MIN, -+ .period_bytes_max = MAX_BUFFER_SIZE/NUM_TCDS, -+ .periods_min = NUM_TCDS, -+ .periods_max = NUM_TCDS, -+ .fifo_size = 0, -+}; -+ -+static unsigned int rates[] = {8000, 11025, 16000, 22000, -+ 22050, 44000, 44100, 48000}; -+ -+/* hw constraints */ -+static struct snd_pcm_hw_constraint_list constraints_rates = { -+ .count = ARRAY_SIZE(rates), -+ .list = rates, -+ .mask = 0, -+}; -+ -+static inline void ssi_audio_dma_playback_start(void) -+{ -+ g_tx_dmaing = 1; -+ mcf_edma_start_transfer(DMA_TX_TCD0); -+ mcf_edma_start_transfer(DMA_TX_TCD1); -+} -+ -+static inline void ssi_audio_dma_capture_start(void) -+{ -+ g_rx_dmaing = 1; -+ mcf_edma_start_transfer(DMA_RX_TCD0); -+ mcf_edma_start_transfer(DMA_RX_TCD1); -+} -+ -+static inline void ssi_audio_dma_playback_stop(void) -+{ -+ g_tx_dmaing = 0; -+ mcf_edma_stop_transfer(DMA_TX_TCD0); -+ mcf_edma_stop_transfer(DMA_TX_TCD1); -+} -+ -+inline void ssi_audio_dma_capture_stop(void) -+{ -+ g_rx_dmaing = 0; -+ mcf_edma_stop_transfer(DMA_RX_TCD0); -+ mcf_edma_stop_transfer(DMA_RX_TCD1); -+} -+ -+/** -+ * fill_tcd_params - Fill transfer control descriptor (TCD) -+ * @base: base address of TCD -+ * @source: source address -+ * @dest: destination address -+ * @attr: attributes -+ * @soff: source offset -+ * @nbytes: number of bytes to be transfered in minor loop -+ * @slast: last source address adjustment -+ * @citer: major loop count -+ * @biter: beginning minor loop count -+ * @doff: destination offset -+ * @dlast_sga: last destination address adjustment -+ * @major_int: generate interrupt after each major loop -+ * @disable_req: disable DMA request after major loop -+ * @enable_sg: enable scatter/gather address -+ */ -+void fill_tcd_params(u32 base, u32 source, u32 dest, -+ u32 attr, u32 soff, u32 nbytes, u32 slast, -+ u32 citer, u32 biter, u32 doff, u32 dlast_sga, -+ int major_int, int disable_req, int enable_sg) -+{ -+ struct dma_tcd *tcd = (struct dma_tcd *) base; -+ -+ tcd->saddr = source; -+ tcd->attr = attr; -+ tcd->soffset = soff; -+ tcd->nbytes = nbytes; -+ tcd->slast = slast; -+ tcd->daddr = dest; -+ tcd->citer = citer & 0x7fff; -+ tcd->doffset = doff; -+ tcd->dlast_sga = dlast_sga; -+ tcd->biter = biter & 0x7fff; -+ tcd->csr = ((major_int) ? 0x2 : 0) | -+ ((disable_req) ? 0x8 : 0) | -+ ((enable_sg) ? 0x10 : 0); -+} -+ -+static int -+ssi_audio_dma_playback_config(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct dma_private *dma_private = runtime->private_data; -+ u32 size = frames_to_bytes(runtime, runtime->period_size); -+ u32 offset, soffset, daddr0, daddr1, attr, sga0, sga1; -+ u32 i, nbyte, major_loops; -+ -+ if ((runtime->channels < 1) || (runtime->channels > 2)) { -+ printk(KERN_ERR "Error on channels = %d\n", runtime->channels); -+ return -EINVAL; -+ } -+ -+ dma_private->dma_buf_phys = runtime->dma_addr; -+ dma_private->dma_buf_next = dma_private->dma_buf_phys; -+ dma_private->dma_buf_end = dma_private->dma_buf_phys + -+ runtime->periods * size; -+ -+ if (runtime->format == SNDRV_PCM_FORMAT_S16_BE) { -+ nbyte = 2 * TXFWM; -+ soffset = 2 * runtime->channels; -+ daddr0 = (u32)&MCF_SSI_TX0 + 2; -+ daddr1 = (u32)&MCF_SSI_TX1 + 2; -+ attr = MCF_EDMA_TCD_ATTR_SSIZE_16BIT | -+ MCF_EDMA_TCD_ATTR_DSIZE_16BIT; -+ } else { -+ printk(KERN_ERR "Not supported PCM format %x\n", -+ runtime->format); -+ return -EINVAL; -+ } -+ -+ major_loops = size/nbyte/runtime->channels; -+ sga0 = (u32)dma_private->tcd_buf_phys; -+ sga1 = (u32)dma_private->tcd_buf_phys + -+ 4 * sizeof(struct dma_tcd); -+ -+#if defined(CONFIG_M5301x) || defined(CONFIG_M5445X) -+ MCF_EDMA_TCD10_CSR = 0; -+ MCF_EDMA_TCD11_CSR = 0; -+#else -+ MCF_EDMA_TCD11_CSR = 0; -+ MCF_EDMA_TCD12_CSR = 0; -+#endif -+ offset = (runtime->channels - 1) * 2; -+ mcf_edma_set_tcd_params(DMA_TX_TCD0, -+ (u32)dma_private->dma_buf_next, -+ daddr0, -+ attr, -+ soffset, -+ nbyte, -+ 0, /* slast */ -+ major_loops, /* citer */ -+ major_loops, /* biter */ -+ 0, /* dest offset */ -+ sga0, -+ 1, /* major_int */ -+ 0); /* enable dma request after */ -+ -+ mcf_edma_set_tcd_params(DMA_TX_TCD1, -+ (u32)dma_private->dma_buf_next + offset, -+ daddr1, -+ attr, -+ soffset, -+ nbyte, -+ 0, /* slast */ -+ major_loops, /* citer */ -+ major_loops, /* biter */ -+ 0, /* dest offset */ -+ sga1, -+ 0, /* major_int */ -+ 0); /* enable dma request after */ -+ -+ while (!(MCF_EDMA_TCD_CSR(DMA_TX_TCD0) & MCF_EDMA_TCD_CSR_E_SG)) -+ MCF_EDMA_TCD_CSR(DMA_TX_TCD0) |= MCF_EDMA_TCD_CSR_E_SG; -+ while (!(MCF_EDMA_TCD_CSR(DMA_TX_TCD1) & MCF_EDMA_TCD_CSR_E_SG)) -+ MCF_EDMA_TCD_CSR(DMA_TX_TCD1) |= MCF_EDMA_TCD_CSR_E_SG; -+ -+ for (i = 0; i < NUM_TCDS; i++) { -+ dma_private->dma_buf_next += size; -+ if (dma_private->dma_buf_next >= dma_private->dma_buf_end) -+ dma_private->dma_buf_next = dma_private->dma_buf_phys; -+ sga0 = (u32)dma_private->tcd_buf_phys + -+ ((i+1)%NUM_TCDS) * sizeof(struct dma_tcd); -+ sga1 = (u32)dma_private->tcd_buf_phys + -+ ((i+1)%NUM_TCDS + 4) * sizeof(struct dma_tcd); -+ DBG("sga0 = 0x%x, sga1 = 0x%x.\n", sga0, sga1); -+ fill_tcd_params((u32)&dma_private->tcd0[i], -+ (u32)dma_private->dma_buf_next, -+ daddr0, -+ attr, -+ soffset, -+ nbyte, -+ 0, /* slast */ -+ major_loops, /* citer */ -+ major_loops, /* biter */ -+ 0, /* dest offset */ -+ sga0, -+ 1, /* major_int */ -+ 0, /* enable dma request after */ -+ 1); /* enable scatter/gather */ -+ -+ fill_tcd_params((u32)&dma_private->tcd1[i], -+ (u32)dma_private->dma_buf_next + offset, -+ daddr1, -+ attr, -+ soffset, -+ nbyte, -+ 0, /* slast */ -+ major_loops, /* citer */ -+ major_loops, /* biter */ -+ 0, /* dest offset */ -+ sga1, -+ 0, /* major_int */ -+ 0, /* enable dma request after */ -+ 1); /* enable scatter/gather */ -+ } -+ -+ return 0; -+} -+ -+static int -+ssi_audio_dma_capture_config(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct dma_private *dma_private = runtime->private_data; -+ u32 size = frames_to_bytes(runtime, runtime->period_size); -+ u32 offset, saddr0, saddr1, doffset, attr, sga0, sga1; -+ int i, nbyte, major_loops; -+ -+ if ((runtime->channels < 1) || (runtime->channels > 2)) { -+ printk(KERN_ERR "Error on channels = %d\n", runtime->channels); -+ return -EINVAL; -+ } -+ -+ dma_private->dma_buf_phys = runtime->dma_addr; -+ dma_private->dma_buf_next = dma_private->dma_buf_phys; -+ dma_private->dma_buf_end = dma_private->dma_buf_phys + -+ runtime->periods * size; -+ -+ switch (runtime->format) { -+ case SNDRV_PCM_FORMAT_S16_BE: -+ saddr0 = (u32)&MCF_SSI_RX0 + 2; -+ saddr1 = (u32)&MCF_SSI_RX1 + 2; -+ nbyte = 2 * RXFWM; -+ doffset = 2 * runtime->channels; -+ attr = MCF_EDMA_TCD_ATTR_SSIZE_16BIT | -+ MCF_EDMA_TCD_ATTR_DSIZE_16BIT; -+ break; -+ default: -+ printk(KERN_ERR "Not supported PCM format %x\n", -+ runtime->format); -+ return -EINVAL; -+ } -+ -+ major_loops = size/nbyte/runtime->channels; -+ sga0 = (u32)dma_private->tcd_buf_phys; -+ sga1 = (u32)dma_private->tcd_buf_phys + -+ 4 * sizeof(struct dma_tcd); -+ -+#if defined(CONFIG_M5301x) || defined(CONFIG_M5445X) -+ MCF_EDMA_TCD8_CSR = 0; -+ MCF_EDMA_TCD9_CSR = 0; -+#else -+ MCF_EDMA_TCD9_CSR = 0; -+ MCF_EDMA_TCD10_CSR = 0; -+#endif -+ offset = (runtime->channels - 1) * 2; -+ mcf_edma_set_tcd_params(DMA_RX_TCD0, -+ saddr0, -+ (u32)dma_private->dma_buf_next, -+ attr, -+ 0, /* source offset */ -+ nbyte, -+ 0, /* slast */ -+ major_loops, /* citer */ -+ major_loops, /* biter */ -+ doffset, -+ sga0, -+ 1, /* major_int */ -+ 0); /* enable dma request after */ -+ -+ mcf_edma_set_tcd_params(DMA_RX_TCD1, -+ saddr1, -+ (u32)dma_private->dma_buf_next + offset, -+ attr, -+ 0, /* source offset */ -+ nbyte, -+ 0, /* slast */ -+ major_loops, /* citer */ -+ major_loops, /* biter */ -+ doffset, -+ sga1, -+ 0, /* major_int */ -+ 0); /* enable dma request after */ -+ -+ while (!(MCF_EDMA_TCD_CSR(DMA_RX_TCD0) & MCF_EDMA_TCD_CSR_E_SG)) -+ MCF_EDMA_TCD_CSR(DMA_RX_TCD0) |= MCF_EDMA_TCD_CSR_E_SG; -+ while (!(MCF_EDMA_TCD_CSR(DMA_RX_TCD1) & MCF_EDMA_TCD_CSR_E_SG)) -+ MCF_EDMA_TCD_CSR(DMA_RX_TCD1) |= MCF_EDMA_TCD_CSR_E_SG; -+ -+ for (i = 0; i < NUM_TCDS; i++) { -+ dma_private->dma_buf_next += size; -+ if (dma_private->dma_buf_next >= dma_private->dma_buf_end) -+ dma_private->dma_buf_next = dma_private->dma_buf_phys; -+ sga0 = (u32)dma_private->tcd_buf_phys + -+ ((i+1)%NUM_TCDS) * sizeof(struct dma_tcd); -+ sga1 = (u32)dma_private->tcd_buf_phys + -+ ((i+1)%NUM_TCDS + 4) * sizeof(struct dma_tcd); -+ fill_tcd_params((u32)&dma_private->tcd0[i], -+ saddr0, -+ (u32)dma_private->dma_buf_next, -+ attr, -+ 0, /* source offset */ -+ nbyte, -+ 0, /* slast */ -+ major_loops, /* citer */ -+ major_loops, /* biter */ -+ doffset, -+ sga0, -+ 1, /* major_int */ -+ 0, /* enable dma request after */ -+ 1); /* enable scatter/gather */ -+ fill_tcd_params((u32)&dma_private->tcd1[i], -+ saddr1, -+ (u32)dma_private->dma_buf_next + offset, -+ attr, -+ 0, /* source offset */ -+ nbyte, -+ 0, /* slast */ -+ major_loops, /* citer */ -+ major_loops, /* biter */ -+ doffset, -+ sga1, -+ 0, /* major_int */ -+ 0, /* enable dma request after */ -+ 1); /* enable scatter/gather */ -+ } -+ return 0; -+} -+ -+static inline void ssi_audio_enable_ssi_playback(void) -+{ -+ MCF_SSI_CR |= MCF_SSI_CR_SSI_EN | MCF_SSI_CR_TE; -+} -+ -+static inline void ssi_audio_enable_ssi_capture(void) -+{ -+ MCF_SSI_CR |= MCF_SSI_CR_SSI_EN | MCF_SSI_CR_RE; -+} -+ -+static inline void ssi_audio_disable_ssi(void) -+{ -+ MCF_SSI_CR &= ~(MCF_SSI_CR_TE | MCF_SSI_CR_RE | MCF_SSI_CR_SSI_EN); -+} -+ -+static inline void ssi_audio_disable_ssi_playback(void) -+{ -+ MCF_SSI_CR &= ~MCF_SSI_CR_TE; -+} -+ -+static inline void ssi_audio_disable_ssi_capture(void) -+{ -+ MCF_SSI_CR &= ~MCF_SSI_CR_RE; -+} -+ -+static irqreturn_t ssi_audio_dma_playback_handler(int channel, void *dev_id) -+{ -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ -+ substream = (struct snd_pcm_substream *)dev_id; -+ runtime = substream->runtime; -+ -+ /* inform ALSA middle layer about transfer status */ -+ snd_pcm_period_elapsed(substream); -+ mcf_edma_confirm_interrupt_handled(DMA_TX_TCD0); -+ mcf_edma_confirm_interrupt_handled(DMA_TX_TCD1); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t ssi_audio_dma_capture_handler(int channel, void *dev_id) -+{ -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ -+ substream = (struct snd_pcm_substream *)dev_id; -+ runtime = substream->runtime; -+ -+ /* inform ALSA middle layer about transfer status */ -+ snd_pcm_period_elapsed(substream); -+ mcf_edma_confirm_interrupt_handled(DMA_RX_TCD0); -+ mcf_edma_confirm_interrupt_handled(DMA_RX_TCD1); -+ -+ return IRQ_HANDLED; -+} -+ -+int ssi_audio_dma_request_playback_channel(struct snd_pcm_substream *substream) -+{ -+ int err; -+ struct chip_spec *chip = snd_pcm_substream_chip(substream); -+ -+ /* request eDMA channel */ -+ err = mcf_edma_request_channel(DMA_TX_TCD0, -+ ssi_audio_dma_playback_handler, -+ NULL, -+ MCF_SSI_AUDIO_IRQ_LEVEL, -+ substream, -+ &(chip->audio_device->lock), -+ id); -+ if (err < 0) -+ return err; -+ err = mcf_edma_request_channel(DMA_TX_TCD1, -+ ssi_audio_dma_playback_handler, -+ NULL, -+ MCF_SSI_AUDIO_IRQ_LEVEL, -+ substream, -+ &(chip->audio_device->lock), -+ id); -+ return err; -+} -+ -+int ssi_audio_dma_request_capture_channel(struct snd_pcm_substream *substream) -+{ -+ int err; -+ struct chip_spec *chip = snd_pcm_substream_chip(substream); -+ -+ /* request 2 eDMA channels for two fifo */ -+ err = mcf_edma_request_channel(DMA_RX_TCD0, -+ ssi_audio_dma_capture_handler, -+ NULL, -+ MCF_SSI_AUDIO_IRQ_LEVEL, -+ substream, -+ &(chip->audio_device->lock), -+ id); -+ if (err < 0) -+ return err; -+ err = mcf_edma_request_channel(DMA_RX_TCD1, -+ ssi_audio_dma_capture_handler, -+ NULL, -+ MCF_SSI_AUDIO_IRQ_LEVEL, -+ substream, -+ &(chip->audio_device->lock), -+ id); -+ return err; -+} -+ -+static inline void ssi_audio_init_dma(void) -+{ -+ /* SSI DMA Signals mapped to DMA request */ -+ MCF_CCM_MISCCR &= ~MCF_CCM_MISCCR_TIM_DMA; -+} -+ -+static void ssi_audio_adjust_codec_speed(struct snd_pcm_substream *substream) -+{ -+ ssi_audio_disable_ssi(); -+ -+ if (substream->runtime->format == SNDRV_PCM_FORMAT_S16_BE) { -+ MCF_SSI_CCR = MCF_SSI_CCR_WL(7) | /* 16 bit word length */ -+ MCF_SSI_CCR_DC(1); /* Frame rate divider */ -+ } -+ -+ switch (substream->runtime->rate) { -+ case 8000: -+#if defined(CONFIG_M532x) || defined(CONFIG_M537x) -+ MCF_CCM_CDR = (MCF_CCM_CDR | MCF_CCM_CDR_SSIDIV(0x20)) -+ | MCF_CCM_CDR_SSIDIV(MCF_SSI_AUDIO_SSDIV_VALUE_1); -+#else -+ MCF_CCM_CDR = (MCF_CCM_CDR & ~MCF_CCM_CDR_SSIDIV(0xFF)) | -+ MCF_CCM_CDR_SSIDIV(MCF_SSI_AUDIO_SSDIV_VALUE_1); -+#endif -+ MCF_SSI_CCR |= MCF_SSI_CCR_PM(11); -+ mcf_codec_spi_write(TLV320AIC23_CODEC_SAMPLE_RATE_REG, -+ TLV320AIC23_CODEC_SAMPLERATE_REG_8KHZ); -+ break; -+ case 11000: -+ case 11025: -+#if defined(CONFIG_M532x) || defined(CONFIG_M537x) -+ MCF_CCM_CDR = (MCF_CCM_CDR & ~MCF_CCM_CDR_SSIDIV(0x3F)) | -+ MCF_CCM_CDR_SSIDIV(0x2B); -+ MCF_SSI_CCR |= MCF_SSI_CCR_PM(11); -+#else -+ MCF_CCM_CDR = (MCF_CCM_CDR & ~MCF_CCM_CDR_SSIDIV(0xFF)) | -+ MCF_CCM_CDR_SSIDIV(MCF_SSI_AUDIO_SSDIV_VALUE_3); -+ MCF_SSI_CCR |= MCF_SSI_CCR_PM(9); -+#endif -+ mcf_codec_spi_write(TLV320AIC23_CODEC_SAMPLE_RATE_REG, -+ TLV320AIC23_CODEC_SAMPLERATE_REG_11KHZ); -+ break; -+ case 16000: -+#if defined(CONFIG_M532x) || defined(CONFIG_M537x) -+ MCF_CCM_CDR = (MCF_CCM_CDR | MCF_CCM_CDR_SSIDIV(0x20)) -+ | MCF_CCM_CDR_SSIDIV(MCF_SSI_AUDIO_SSDIV_VALUE_1); -+#else -+ MCF_CCM_CDR = (MCF_CCM_CDR & ~MCF_CCM_CDR_SSIDIV(0xFF)) | -+ MCF_CCM_CDR_SSIDIV(MCF_SSI_AUDIO_SSDIV_VALUE_1); -+#endif -+ MCF_SSI_CCR |= MCF_SSI_CCR_PM(5); -+ mcf_codec_spi_write(TLV320AIC23_CODEC_SAMPLE_RATE_REG, -+ TLV320AIC23_CODEC_SAMPLERATE_REG_16KHZ); -+ break; -+ case 22000: -+ case 22050: -+#if defined(CONFIG_M532x) || defined(CONFIG_M537x) -+ MCF_CCM_CDR = (MCF_CCM_CDR & ~MCF_CCM_CDR_SSIDIV(0x3F)) | -+ MCF_CCM_CDR_SSIDIV(0x2B); -+ MCF_SSI_CCR |= MCF_SSI_CCR_PM(5); -+#else -+ MCF_CCM_CDR = (MCF_CCM_CDR & ~MCF_CCM_CDR_SSIDIV(0xFF)) | -+ MCF_CCM_CDR_SSIDIV(MCF_SSI_AUDIO_SSDIV_VALUE_3); -+ MCF_SSI_CCR |= MCF_SSI_CCR_PM(4); -+#endif -+ mcf_codec_spi_write(TLV320AIC23_CODEC_SAMPLE_RATE_REG, -+ TLV320AIC23_CODEC_SAMPLERATE_REG_22KHZ); -+ break; -+ case 48000: -+#if defined(CONFIG_M532x) || defined(CONFIG_M537x) -+ MCF_CCM_CDR = (MCF_CCM_CDR & ~MCF_CCM_CDR_SSIDIV(0x3F)) | -+ MCF_CCM_CDR_SSIDIV(MCF_SSI_AUDIO_SSDIV_VALUE_4); -+ MCF_SSI_CCR |= MCF_SSI_CCR_PM(3); -+#else -+ MCF_CCM_CDR = (MCF_CCM_CDR & ~MCF_CCM_CDR_SSIDIV(0xFF)) | -+ MCF_CCM_CDR_SSIDIV(MCF_SSI_AUDIO_SSDIV_VALUE_1); -+ MCF_SSI_CCR |= MCF_SSI_CCR_PM(1); -+#endif -+ mcf_codec_spi_write(TLV320AIC23_CODEC_SAMPLE_RATE_REG, -+ TLV320AIC23_CODEC_SAMPLERATE_REG_48KHZ); -+ break; -+ case 44000: -+ case 44100: -+ default: -+#if defined(CONFIG_M532x) || defined(CONFIG_M537x) -+ MCF_CCM_CDR = (MCF_CCM_CDR & ~MCF_CCM_CDR_SSIDIV(0x3F)) | -+ MCF_CCM_CDR_SSIDIV(0x2B); -+#else -+ MCF_CCM_CDR = (MCF_CCM_CDR & ~MCF_CCM_CDR_SSIDIV(0xFF)) | -+ MCF_CCM_CDR_SSIDIV(MCF_SSI_AUDIO_SSDIV_VALUE_2); -+#endif -+ MCF_SSI_CCR |= MCF_SSI_CCR_PM(2); -+ mcf_codec_spi_write(TLV320AIC23_CODEC_SAMPLE_RATE_REG, -+ TLV320AIC23_CODEC_SAMPLERATE_REG_44KHZ); -+ break; -+ } -+ DBG("MCF_CCM_CDR = 0x%x, MCF_SSI_CCR = 0x%x.\n", -+ MCF_CCM_CDR, MCF_SSI_CCR); -+} -+ -+static void ssi_audio_codec_reset(void) -+{ -+ mcf_codec_spi_write(CODEC_RESET_REG, 0); /* reset the audio chip */ -+ udelay(2500); /* wait for reset */ -+} -+ -+static void -+ssi_audio_init_codec_for_playback(struct snd_pcm_substream *substream) -+{ -+ mcf_codec_spi_write(CODEC_LEFT_IN_REG, g_lineinvol); -+ mcf_codec_spi_write(CODEC_RIGHT_IN_REG, g_lineinvol); -+ mcf_codec_spi_write(CODEC_POWER_DOWN_REG, 0x060); -+ mcf_codec_spi_write(CODEC_DIGITAL_IF_FMT_REG, 0x02); -+ mcf_codec_spi_write(CODEC_DIGITAL_APATH_REG, 0x006); -+ mcf_codec_spi_write(CODEC_DIGITAL_IF_ACT_REG, 0x001); -+ mcf_codec_spi_write(CODEC_ANALOG_APATH_REG, g_analogpath); -+ mcf_codec_spi_write(CODEC_LEFT_HP_VOL_REG, g_mastervol); -+ mcf_codec_spi_write(CODEC_RIGHT_HP_VOL_REG, g_mastervol); -+} -+ -+static void -+ssi_audio_init_codec_for_capture(struct snd_pcm_substream *substream) -+{ -+ mcf_codec_spi_write(CODEC_LEFT_IN_REG, g_lineinvol); -+ mcf_codec_spi_write(CODEC_RIGHT_IN_REG, g_lineinvol); -+ mcf_codec_spi_write(CODEC_POWER_DOWN_REG, 0x060); -+ mcf_codec_spi_write(CODEC_DIGITAL_IF_FMT_REG, 0x02); -+ mcf_codec_spi_write(CODEC_DIGITAL_APATH_REG, 0x006); -+ mcf_codec_spi_write(CODEC_DIGITAL_IF_ACT_REG, 0x001); -+ mcf_codec_spi_write(CODEC_ANALOG_APATH_REG, g_analogpath); -+ mcf_codec_spi_write(CODEC_LEFT_HP_VOL_REG, g_mastervol); -+ mcf_codec_spi_write(CODEC_RIGHT_HP_VOL_REG, g_mastervol); -+} -+ -+static void ssi_audio_chip_init(void) -+{ -+ int chip_initialized = 0; -+ if (chip_initialized == 1) -+ return; -+ -+ ssi_audio_init_dma(); -+ /* Enable the SSI pins */ -+#if defined(CONFIG_M5227x) -+ MCF_GPIO_PAR_UART = (MCF_GPIO_PAR_UART -+ &~MCF_GPIO_PAR_UART_PAR_U1TXD(0xF) -+ &~MCF_GPIO_PAR_UART_PAR_U1RXD(0xF) -+ &~MCF_GPIO_PAR_UART_PAR_U1RTS(0xF) -+ &~MCF_GPIO_PAR_UART_PAR_U1CTS(0xF)) -+ | MCF_GPIO_PAR_UART_PAR_U1CTS_SSI_BCLK -+ | MCF_GPIO_PAR_UART_PAR_U1RTS_SSI_FS -+ | MCF_GPIO_PAR_UART_PAR_U1RXD_SSI_RXD -+ | MCF_GPIO_PAR_UART_PAR_U1TXD_SSI_TXD; -+ -+ MCF_GPIO_PAR_TIMER = (MCF_GPIO_PAR_TIMER -+ &~MCF_GPIO_PAR_TIMER_PAR_T3IN(0xF)) -+ | MCF_GPIO_PAR_TIMER_PAR_T3IN_SSI_MCLK; -+#endif -+#if defined(CONFIG_M532x) -+ MCF_GPIO_PAR_SSI = (0 -+ | MCF_GPIO_PAR_SSI_PAR_MCLK -+ | MCF_GPIO_PAR_SSI_PAR_TXD(3) -+ | MCF_GPIO_PAR_SSI_PAR_RXD(3) -+ | MCF_GPIO_PAR_SSI_PAR_FS(3) -+ | MCF_GPIO_PAR_SSI_PAR_BCLK(3)); -+#endif -+#if defined(CONFIG_M537x) -+ MCF_GPIO_PAR_UART = (MCF_GPIO_PAR_UART -+ &~MCF_GPIO_PAR_UART_PAR_UTXD1(0xF) -+ &~MCF_GPIO_PAR_UART_PAR_URXD1(0xF) -+ &~MCF_GPIO_PAR_UART_PAR_URTS1(0xF) -+ &~MCF_GPIO_PAR_UART_PAR_UCTS1(0xF)) -+ | MCF_GPIO_PAR_UART_PAR_UCTS1_SSI_BCLK -+ | MCF_GPIO_PAR_UART_PAR_URTS1_SSI_FS -+ | MCF_GPIO_PAR_UART_PAR_URXD1_SSI_RXD -+ | MCF_GPIO_PAR_UART_PAR_UTXD1_SSI_TXD; -+ -+ MCF_GPIO_PAR_IRQ = MCF_GPIO_PAR_IRQ_PAR_IRQ4(1); -+#endif -+#if defined(CONFIG_M5301x) -+ MCF_GPIO_PAR_SSIH = (MCF_GPIO_PAR_SSIH_PAR_RXD_SSI_RXD | -+ MCF_GPIO_PAR_SSIH_PAR_TXD_SSI_TXD | -+ MCF_GPIO_PAR_SSIH_PAR_FS_SSI_FS | -+ MCF_GPIO_PAR_SSIH_PAR_MCLK_SSI_MCLK); -+ MCF_GPIO_PAR_SSIL = MCF_GPIO_PAR_SSIL_PAR_BCLK_SSI_BCLK; -+#endif -+#if defined(CONFIG_M5445X) -+ MCF_GPIO_PAR_SSI = (MCF_GPIO_PAR_SSI_MCLK | -+ MCF_GPIO_PAR_SSI_STXD_STXD | -+ MCF_GPIO_PAR_SSI_SRXD_SRXD | -+ MCF_GPIO_PAR_SSI_FS_FS | -+ MCF_GPIO_PAR_SSI_BCLK_BCLK); -+#endif -+ chip_initialized = 1; -+} -+ -+static void ssi_audio_init_ssi_playback(void) -+{ -+ /* Issue a SSI reset */ -+ MCF_SSI_CR &= ~MCF_SSI_CR_SSI_EN; -+ -+ /* SSI module uses internal CPU clock */ -+ MCF_CCM_MISCCR |= MCF_CCM_MISCCR_SSI_SRC; -+#if defined(CONFIG_M5445X) || defined(CONFIG_M532x) || defined(CONFIG_M537x) \ -+ || defined(CONFIG_M5227x) -+ MCF_CCM_MISCCR |= MCF_CCM_MISCCR_SSI_PUE | MCF_CCM_MISCCR_SSI_PUS; -+#endif -+#if defined(CONFIG_M5301x) -+ MCF_GPIO_PCRH |= MCF_GPIO_PCRH_SSI_PUS | MCF_GPIO_PCRH_SSI_PUE; -+#endif -+ MCF_SSI_CR = MCF_SSI_CR_CIS | -+ MCF_SSI_CR_TCH | /* Enable two channel mode */ -+ MCF_SSI_CR_MCE | /* clock out on SSI_MCLK pin */ -+ MCF_SSI_CR_I2S_MASTER | /* I2S master mode */ -+ MCF_SSI_CR_SYN | /* Enable synchronous mode */ -+ MCF_SSI_CR_NET; /* Auto set by I2S Master */ -+ -+ MCF_SSI_TCR = 0 | -+ /* internally generated bit clock */ -+ MCF_SSI_TCR_TXDIR | -+ /* internally generated frame sync */ -+ MCF_SSI_TCR_TFDIR | -+ /* Clock data on falling edge of bit clock */ -+ MCF_SSI_TCR_TSCKP | -+ /* Frame sync active low */ -+ MCF_SSI_TCR_TFSI | -+ /* TX frame sync 1 bit before data */ -+ MCF_SSI_TCR_TEFS | -+ /* TX FIFO 0 enabled */ -+ MCF_SSI_TCR_TFEN0 | -+ /* TX FIFO 1 enabled */ -+ MCF_SSI_TCR_TFEN1 | -+ MCF_SSI_TCR_TXBIT0; -+ -+ MCF_SSI_FCSR = MCF_SSI_FCSR_TFWM0(TXFWM) | MCF_SSI_FCSR_TFWM1(TXFWM); -+ -+ MCF_SSI_IER = MCF_SSI_IER_TDMAE | /* DMA request enabled */ -+ MCF_SSI_IER_TFE0 | -+ MCF_SSI_IER_TFE1; /* set by reset actually*/ -+} -+ -+static void ssi_audio_init_ssi_capture(void) -+{ -+ /* Issue a SSI reset */ -+ MCF_SSI_CR &= ~MCF_SSI_CR_SSI_EN; -+ -+ /* SSI module uses internal CPU clock */ -+ MCF_CCM_MISCCR |= MCF_CCM_MISCCR_SSI_SRC; -+#if defined(CONFIG_M5445X) || defined(CONFIG_M532x) || defined(CONFIG_M537x) \ -+ || defined(CONFIG_M5227x) -+ MCF_CCM_MISCCR |= MCF_CCM_MISCCR_SSI_PUE | MCF_CCM_MISCCR_SSI_PUS; -+#endif -+#if defined(CONFIG_M5301x) -+ MCF_GPIO_PCRH |= MCF_GPIO_PCRH_SSI_PUS | MCF_GPIO_PCRH_SSI_PUE; -+#endif -+ MCF_SSI_CR = MCF_SSI_CR_CIS | -+ MCF_SSI_CR_TCH | /* Enable two channel mode */ -+ MCF_SSI_CR_MCE | /* clock out on SSI_MCLK pin */ -+ MCF_SSI_CR_I2S_MASTER | /* I2S master mode */ -+ MCF_SSI_CR_SYN | /* Enable synchronous mode */ -+ MCF_SSI_CR_NET; /* Auto set by I2S Master */ -+ -+ MCF_SSI_TCR = 0 | -+ /* internally generated bit clock */ -+ MCF_SSI_TCR_TXDIR | -+ /* internally generated frame sync */ -+ MCF_SSI_TCR_TFDIR | -+ /* Clock data on falling edge of bit clock */ -+ MCF_SSI_TCR_TSCKP | -+ /* Frame sync active low */ -+ MCF_SSI_TCR_TFSI | -+ /* TX frame sync 1 bit before data */ -+ MCF_SSI_TCR_TEFS | -+ /* TX FIFO 0 enabled */ -+ MCF_SSI_TCR_TFEN0 | -+ /* TX FIFO 1 enabled */ -+ MCF_SSI_TCR_TFEN1 | -+ MCF_SSI_TCR_TXBIT0; -+ -+ MCF_SSI_RCR = 0 | -+ /* Clock data on rising edge of bit clock */ -+ MCF_SSI_RCR_RSCKP | -+ /* Frame sync active low */ -+ MCF_SSI_RCR_RFSI | -+ /* RX frame sync 1 bit before data */ -+ MCF_SSI_RCR_REFS | -+ /* RX FIFO 0 enabled */ -+ MCF_SSI_RCR_RFEN0 | -+ /* RX FIFO 1 enabled */ -+ MCF_SSI_RCR_RFEN1 | -+ MCF_SSI_RCR_RXBIT0; /* Auto set by I2S Master */ -+ -+ MCF_SSI_FCSR = MCF_SSI_FCSR_RFWM0(RXFWM) | MCF_SSI_FCSR_RFWM1(RXFWM); -+ -+ /* interrupts */ -+ MCF_SSI_IER = MCF_SSI_IER_RDMAE | /* DMA request enabled */ -+ MCF_SSI_IER_RFF0 | /* rx FIFO 0 full */ -+ MCF_SSI_IER_RFF1; /* rx FIFO 1 full */ -+} -+ -+static int snd_coldfire_playback_open(struct snd_pcm_substream *substream) -+{ -+ int err; -+ struct chip_spec *chip = snd_pcm_substream_chip(substream); -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct dma_private *dma_private; -+ dma_addr_t tcd_buf_phys; -+ -+ runtime->hw = snd_coldfire_playback_hw; -+ err = snd_pcm_hw_constraint_integer(runtime, -+ SNDRV_PCM_HW_PARAM_PERIODS); -+ if (err < 0) { -+ printk(KERN_ERR "invalid buffer size\n"); -+ return err; -+ } -+ /* to make sure period_bytes is the multiple of size of minor loops */ -+ err = snd_pcm_hw_constraint_step(runtime, 0, -+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -+ HW_PERIODS_BYTES_STEP); -+ if (err < 0) { -+ printk(KERN_ERR "Error setting period_bytes step, " -+ "err=%d\n", err); -+ return err; -+ } -+ err = snd_pcm_hw_constraint_list(substream->runtime, 0, -+ SNDRV_PCM_HW_PARAM_RATE, -+ &constraints_rates); -+ if (err < 0) { -+ printk(KERN_ERR "Error setting rate constraints, " -+ "err=%d\n", err); -+ return err; -+ } -+ ssi_audio_chip_init(); -+ ssi_audio_init_ssi_playback(); -+ ssi_audio_init_codec_for_playback(substream); -+ err = ssi_audio_dma_request_playback_channel(substream); -+ if (err < 0) { -+ printk(KERN_ERR "Error requesting dma channel, err=%d\n", err); -+ return err; -+ } -+ -+ dma_private = dma_alloc_coherent(substream->pcm->dev, -+ sizeof(struct dma_private), &tcd_buf_phys, GFP_KERNEL); -+ -+ if (!dma_private) { -+ dev_err(substream->pcm->card->dev, -+ "can't allocate DMA private data\n"); -+ return -ENOMEM; -+ } -+ -+ dma_private->tcd_buf_phys = tcd_buf_phys; -+ runtime->private_data = dma_private; -+ -+ chip->offset = 0; -+ g_tx_dmaing = 0; -+ return 0; -+} -+ -+static int snd_coldfire_capture_open(struct snd_pcm_substream *substream) -+{ -+ int err; -+ struct chip_spec *chip = snd_pcm_substream_chip(substream); -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct dma_private *dma_private; -+ dma_addr_t tcd_buf_phys; -+ -+ runtime->hw = snd_coldfire_capture_hw; -+ -+ err = snd_pcm_hw_constraint_integer(runtime, -+ SNDRV_PCM_HW_PARAM_PERIODS); -+ if (err < 0) { -+ printk(KERN_ERR "invalid buffer size\n"); -+ return err; -+ } -+ /* to make sure period_bytes is the multiple of size of minor loops */ -+ err = snd_pcm_hw_constraint_step(runtime, 0, -+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -+ HW_PERIODS_BYTES_STEP); -+ if (err < 0) { -+ printk(KERN_ERR "Error setting period_bytes step, " -+ "err=%d\n", err); -+ return err; -+ } -+ err = snd_pcm_hw_constraint_list(substream->runtime, 0, -+ SNDRV_PCM_HW_PARAM_RATE, -+ &constraints_rates); -+ if (err < 0) { -+ printk(KERN_ERR "Error setting pcm_hw_constraint_list, " -+ "err=%d\n", err); -+ return err; -+ } -+ -+ ssi_audio_chip_init(); -+ ssi_audio_init_ssi_capture(); -+ ssi_audio_init_codec_for_capture(substream); -+ err = ssi_audio_dma_request_capture_channel(substream); -+ if (err < 0) { -+ printk(KERN_ERR "Error requesting dma channel, err=%d\n", err); -+ return err; -+ } -+ -+ dma_private = dma_alloc_coherent(substream->pcm->dev, -+ sizeof(struct dma_private), &tcd_buf_phys, GFP_KERNEL); -+ -+ if (!dma_private) { -+ dev_err(substream->pcm->card->dev, -+ "can't allocate DMA private data\n"); -+ return -ENOMEM; -+ } -+ dma_private->tcd_buf_phys = tcd_buf_phys; -+ dma_private->dma_buf_phys = substream->dma_buffer.addr; -+ -+ runtime->private_data = dma_private; -+ -+ chip->offset = 0; -+ g_rx_dmaing = 0; -+ return 0; -+} -+ -+static int snd_coldfire_playback_close(struct snd_pcm_substream *substream) -+{ -+ struct dma_private *dma_private = substream->runtime->private_data; -+ -+ ssi_audio_dma_playback_stop(); -+ mcf_edma_free_channel(DMA_TX_TCD0, substream); -+ mcf_edma_free_channel(DMA_TX_TCD1, substream); -+ if (dma_private) { -+ dma_free_coherent(substream->pcm->dev, -+ sizeof(struct dma_private), -+ dma_private, dma_private->tcd_buf_phys); -+ substream->runtime->private_data = NULL; -+ } -+ ssi_audio_disable_ssi(); -+ return 0; -+} -+ -+static int snd_coldfire_capture_close(struct snd_pcm_substream *substream) -+{ -+ struct dma_private *dma_private = substream->runtime->private_data; -+ -+ ssi_audio_dma_capture_stop(); -+ mcf_edma_free_channel(DMA_RX_TCD0, substream); -+ mcf_edma_free_channel(DMA_RX_TCD1, substream); -+ /* Deallocate the fsl_dma_private structure */ -+ if (dma_private) { -+ dma_free_coherent(substream->pcm->dev, -+ sizeof(struct dma_private), -+ dma_private, dma_private->tcd_buf_phys); -+ substream->runtime->private_data = NULL; -+ } -+ ssi_audio_disable_ssi(); -+ return 0; -+} -+ -+static int snd_coldfire_pcm_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *hw_params) -+{ -+ int err; -+ -+ /* set runtime buffer */ -+ err = snd_pcm_lib_malloc_pages( -+ substream, params_buffer_bytes(hw_params)); -+ if (err < 0) -+ printk(KERN_ERR "Error allocating pages, err=%d\n", err); -+ return err; -+} -+ -+static int snd_coldfire_pcm_hw_free(struct snd_pcm_substream *substream) -+{ -+ /* free the memory if was newly allocated */ -+ return snd_pcm_lib_free_pages(substream); -+} -+ -+static int -+snd_coldfire_pcm_playback_prepare(struct snd_pcm_substream *substream) -+{ -+ int err; -+ -+ if (g_tx_dmaing == 1) -+ return 0; -+ -+ ssi_audio_adjust_codec_speed(substream); -+ err = ssi_audio_dma_playback_config(substream); -+ if (err < 0) { -+ printk(KERN_ERR "Error configuring playback, " -+ "err=%d\n", err); -+ return err; -+ } -+ -+ ssi_audio_dma_playback_start(); -+ return 0; -+} -+ -+static int snd_coldfire_pcm_capture_prepare(struct snd_pcm_substream *substream) -+{ -+ int err; -+ -+ if (g_rx_dmaing == 1) -+ return 0; -+ -+ ssi_audio_adjust_codec_speed(substream); -+ err = ssi_audio_dma_capture_config(substream); -+ if (err < 0) { -+ printk(KERN_ERR "Error configuring capture, " -+ "err=%d\n", err); -+ return err; -+ } -+ ssi_audio_dma_capture_start(); -+ -+ return 0; -+} -+ -+static int -+snd_coldfire_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ ssi_audio_enable_ssi_playback(); -+ break; -+ case SNDRV_PCM_TRIGGER_STOP: -+ ssi_audio_disable_ssi_playback(); -+ break; -+ default: -+ printk(KERN_ERR "Unsupported trigger command, cmd=%d\n", cmd); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int -+snd_coldfire_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ ssi_audio_enable_ssi_capture(); -+ break; -+ case SNDRV_PCM_TRIGGER_STOP: -+ ssi_audio_disable_ssi_capture(); -+ break; -+ default: -+ printk(KERN_ERR "Unsupported trigger command, cmd=%d\n", cmd); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static snd_pcm_uframes_t -+snd_coldfire_pcm_playback_pointer(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct dma_private *dma_private = runtime->private_data; -+ snd_pcm_uframes_t pointer; -+ u32 offset; -+ -+ offset = (u32)(MCF_EDMA_TCD_SADDR(DMA_TX_TCD0) - -+ dma_private->dma_buf_phys); -+ if (runtime->format == SNDRV_PCM_FORMAT_S16_BE) -+ pointer = offset / (runtime->channels == 1 ? 2 : 4); -+ else -+ pointer = 0; -+ -+ return pointer; -+} -+ -+static snd_pcm_uframes_t -+snd_coldfire_pcm_capture_pointer(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct dma_private *dma_private = runtime->private_data; -+ snd_pcm_uframes_t pointer; -+ u32 offset; -+ -+ offset = (u32)(MCF_EDMA_TCD_DADDR(DMA_RX_TCD0) - -+ dma_private->dma_buf_phys); -+ if (runtime->format == SNDRV_PCM_FORMAT_S16_BE) -+ pointer = offset / (runtime->channels == 1 ? 2 : 4); -+ else -+ pointer = 0; -+ -+ return pointer; -+} -+ -+static struct snd_pcm_ops snd_coldfire_playback_ops = { -+ .open = snd_coldfire_playback_open, -+ .close = snd_coldfire_playback_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = snd_coldfire_pcm_hw_params, -+ .hw_free = snd_coldfire_pcm_hw_free, -+ .prepare = snd_coldfire_pcm_playback_prepare, -+ .trigger = snd_coldfire_pcm_playback_trigger, -+ .pointer = snd_coldfire_pcm_playback_pointer, -+}; -+ -+static struct snd_pcm_ops snd_coldfire_capture_ops = { -+ .open = snd_coldfire_capture_open, -+ .close = snd_coldfire_capture_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = snd_coldfire_pcm_hw_params, -+ .hw_free = snd_coldfire_pcm_hw_free, -+ .prepare = snd_coldfire_pcm_capture_prepare, -+ .trigger = snd_coldfire_pcm_capture_trigger, -+ .pointer = snd_coldfire_pcm_capture_pointer, -+}; -+ -+static int snd_coldfire_new_pcm(struct chip_spec *chip) -+{ -+ struct snd_pcm *pcm; -+ int err; -+ -+ err = snd_pcm_new(chip->card, "coldfire", 0, 1, 1, -+ &pcm); -+ if (err < 0) { -+ printk(KERN_ERR "Error creating new pcm, err=%d\n", err); -+ return err; -+ } -+ pcm->private_data = chip; -+ strncpy(pcm->name, SOUND_CARD_NAME, sizeof(pcm->name)); -+ chip->pcm = pcm; -+ pcm->info_flags = 0; -+ -+ /* set operators */ -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, -+ &snd_coldfire_playback_ops); -+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, -+ &snd_coldfire_capture_ops); -+ /* pre-allocation of buffers */ -+ err = snd_pcm_lib_preallocate_pages_for_all( -+ pcm, -+ SNDRV_DMA_TYPE_CONTINUOUS, -+ snd_dma_continuous_data(GFP_KERNEL), -+ MAX_BUFFER_SIZE, -+ MAX_BUFFER_SIZE); -+ -+ if (!pcm->streams[0].substream->dma_buffer.addr) -+ pcm->streams[0].substream->dma_buffer.addr = -+ virt_to_phys(pcm->streams[0].substream->dma_buffer.area); -+ if (!pcm->streams[1].substream->dma_buffer.addr) -+ pcm->streams[1].substream->dma_buffer.addr = -+ virt_to_phys(pcm->streams[1].substream->dma_buffer.area); -+ -+ if (err) { -+ printk(KERN_ERR -+ "Can't pre-allocate DMA buffer (size=%u)\n", -+ MAX_BUFFER_SIZE); -+ return -ENOMEM; -+ } -+ -+ chip->audio_device = -+ kmalloc(sizeof(struct tlv320a_audio_device), GFP_DMA); -+ -+ if (!chip->audio_device) { -+ snd_pcm_lib_preallocate_free_for_all(pcm); -+ printk(KERN_ERR -+ "Can't allocate buffer for audio device\n"); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static int tlv320a_set_out_volume(unsigned char value) -+{ -+ unsigned char data; -+ -+ if (value > TLV320A_VOL_MAX) -+ data = TLV320A_VOL_MAX; -+ else -+ data = value; -+ -+ if (mcf_codec_spi_write(CODEC_LEFT_HP_VOL_REG, data) < 0) -+ return -EINVAL; -+ -+ if (mcf_codec_spi_write(CODEC_RIGHT_HP_VOL_REG, data) < 0) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int tlv320a_info_out_volume(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ uinfo->value.integer.min = TLV320A_VOL_MIN; -+ uinfo->value.integer.max = TLV320A_VOL_MAX; -+ return 0; -+} -+ -+static int tlv320a_get_out_volume(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ ucontrol->value.integer.value[0] = g_mastervol; -+ return 0; -+} -+ -+static int tlv320a_put_out_volume(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ unsigned char vol; -+ int change; -+ -+ vol = ucontrol->value.integer.value[0]; -+ -+ if (vol > TLV320A_VOL_MAX) -+ return -EINVAL; -+ -+ change = (g_mastervol != vol); -+ if (change) { -+ g_mastervol = vol; -+ tlv320a_set_out_volume(vol); -+ } -+ return change; -+} -+ -+static int tlv320a_set_linein_volume(unsigned char value) -+{ -+ unsigned char data; -+ -+ if (value > TLV320A_LINEIN_MAX) -+ data = TLV320A_LINEIN_MAX; -+ else -+ data = value; -+ -+ if (mcf_codec_spi_write(CODEC_LEFT_IN_REG, data) < 0) -+ return -EINVAL; -+ -+ if (mcf_codec_spi_write(CODEC_RIGHT_IN_REG, data) < 0) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int tlv320a_info_linein_volume(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; -+ uinfo->count = 1; -+ uinfo->value.integer.min = 0; -+ uinfo->value.integer.max = TLV320A_LINEIN_MAX; -+ return 0; -+} -+ -+static int tlv320a_get_linein_volume(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ ucontrol->value.integer.value[0] = g_lineinvol; -+ return 0; -+} -+ -+static int tlv320a_put_linein_volume(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ unsigned char vol; -+ int change; -+ -+ vol = ucontrol->value.integer.value[0]; -+ -+ if (vol > TLV320A_LINEIN_MAX) -+ return -EINVAL; -+ -+ change = (g_lineinvol != vol); -+ if (change) { -+ g_lineinvol = vol; -+ tlv320a_set_linein_volume(vol); -+ } -+ return change; -+} -+ -+#define tlv320a_info_mic_boost snd_ctl_boolean_mono_info -+static int tlv320a_get_mic_boost(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ ucontrol->value.integer.value[0] = ((g_analogpath & 0x1) == 1); -+ return 0; -+} -+ -+static int tlv320a_put_mic_boost(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ int oldboost, newboost; -+ u8 data; -+ if (ucontrol->value.integer.value[0] == 1) -+ newboost = 1; -+ else -+ newboost = 0; -+ oldboost = g_analogpath & 0x1; -+ -+ if (oldboost == newboost) -+ return 0; -+ data = (g_analogpath & 0xfe) | (newboost & 0x1); -+ if (mcf_codec_spi_write(CODEC_ANALOG_APATH_REG, data) < 0) -+ return -EINVAL; -+ g_analogpath = data; -+ return 1; -+} -+ -+static int tlv320a_info_capture_source(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ static char *texts[] = { "Line-In", "Microphone" }; -+ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; -+ uinfo->count = 1; -+ uinfo->value.enumerated.items = 2; -+ if (uinfo->value.enumerated.item > 1) -+ uinfo->value.enumerated.item = 1; -+ strcpy(uinfo->value.enumerated.name, -+ texts[uinfo->value.enumerated.item]); -+ return 0; -+} -+ -+static int tlv320a_get_capture_source(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ -+ ucontrol->value.enumerated.item[0] = ((g_analogpath & 0x4) == 0x4); -+ return 0; -+} -+ -+static int tlv320a_put_capture_source(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ int oldinput, newinput; -+ u8 data; -+ -+ if (ucontrol->value.enumerated.item[0] > 1) -+ return -EINVAL; -+ -+ oldinput = (g_analogpath & 0x4) ? INPUT_MICROPHONE : INPUT_LINEIN; -+ -+ if (ucontrol->value.enumerated.item[0]) -+ newinput = INPUT_MICROPHONE; -+ else -+ newinput = INPUT_LINEIN; -+ if (oldinput == newinput) -+ return 0; -+ data = (g_analogpath & 0xfb) | -+ (newinput == INPUT_MICROPHONE ? 0x4 : 0); -+ if (mcf_codec_spi_write(CODEC_ANALOG_APATH_REG, data) < 0) -+ return -EINVAL; -+ g_analogpath = data; -+ return 1; -+} -+ -+static struct snd_kcontrol_new tlv320_mixer_out __devinitdata = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .name = "play volume", -+ .index = 0, -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .info = tlv320a_info_out_volume, -+ .get = tlv320a_get_out_volume, -+ .put = tlv320a_put_out_volume, -+}; -+ -+static struct snd_kcontrol_new tlv320_mixer_linein __devinitdata = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .name = "record volume", -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .info = tlv320a_info_linein_volume, -+ .get = tlv320a_get_linein_volume, -+ .put = tlv320a_put_linein_volume, -+}; -+ -+static struct snd_kcontrol_new tlv320_mixer_capture_source __devinitdata = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .name = "record source", -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .info = tlv320a_info_capture_source, -+ .get = tlv320a_get_capture_source, -+ .put = tlv320a_put_capture_source, -+}; -+ -+static struct snd_kcontrol_new tlv320_mixer_mic_boost __devinitdata = { -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -+ .name = "mic Boost", -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, -+ .info = tlv320a_info_mic_boost, -+ .get = tlv320a_get_mic_boost, -+ .put = tlv320a_put_mic_boost, -+}; -+ -+static int __devinit coldfire_alsa_audio_probe(struct platform_device *dev) -+{ -+ struct snd_card *card; -+ struct chip_spec *chip; -+ int err; -+ -+ err = snd_card_create(-1, id, THIS_MODULE, -+ sizeof(struct chip_spec), &card); -+ if (err < 0) -+ return -ENOMEM; -+ -+ chip = card->private_data; -+ -+ chip->card = card; -+ card->dev = &dev->dev; -+ -+ err = snd_coldfire_new_pcm(chip); -+ if (err < 0) -+ return -ENOMEM; -+ -+ strcpy(card->driver, "coldfire"); -+ strcpy(card->shortname, "Coldfire-TLV320A"); -+ sprintf(card->longname, "Freescale Coldfire with TLV320A"); -+ -+ err = snd_card_register(card); -+ if (err == 0) { -+ pr_debug(KERN_INFO "Coldfire audio support initialized\n"); -+ platform_set_drvdata(dev, card); -+ } -+ -+ strcpy(chip->card->mixername, "TLV320A Volume"); -+ err = snd_ctl_add(chip->card, snd_ctl_new1(&tlv320_mixer_out, chip)); -+ if (err) -+ goto error; -+ err = snd_ctl_add(chip->card, snd_ctl_new1(&tlv320_mixer_linein, chip)); -+ if (err) -+ goto error; -+ err = snd_ctl_add(chip->card, -+ snd_ctl_new1(&tlv320_mixer_capture_source, -+ chip)); -+ if (err) -+ goto error; -+ err = snd_ctl_add(chip->card, -+ snd_ctl_new1(&tlv320_mixer_mic_boost, -+ chip)); -+ if (err) -+ goto error; -+ g_mastervol = TLV320A_VOL_INIT; -+ g_lineinvol = TLV320A_LINEIN_INIT; -+ g_analogpath = TLV320A_ANALOGPATH_INIT; -+ ssi_audio_codec_reset(); -+ return 0; -+error: -+ kfree(card->private_data); -+ snd_card_free(card); -+ platform_set_drvdata(dev, NULL); -+ return err; -+} -+ -+static int coldfire_alsa_audio_remove(struct platform_device *dev) -+{ -+ struct snd_card *card; -+ -+ card = platform_get_drvdata(dev); -+ kfree(card->private_data); -+ snd_card_free(card); -+ platform_set_drvdata(dev, NULL); -+ -+ return 0; -+} -+ -+static struct platform_driver coldfire_alsa_audio_driver = { -+ .probe = coldfire_alsa_audio_probe, -+ .remove = coldfire_alsa_audio_remove, -+ .driver = { -+ .name = SOUND_CARD_NAME, -+ }, -+}; -+ -+static int __init coldfire_alsa_audio_init(void) -+{ -+ int err; -+ err = platform_driver_register(&coldfire_alsa_audio_driver); -+ if (err < 0) -+ return err; -+ -+ device = platform_device_register_simple(SOUND_CARD_NAME, -1, NULL, 0); -+ if (!IS_ERR(device)) { -+ if (platform_get_drvdata(device)) -+ return 0; -+ platform_device_unregister(device); -+ platform_driver_unregister(&coldfire_alsa_audio_driver); -+ err = -ENODEV; -+ } else -+ err = PTR_ERR(device); -+ -+ platform_driver_unregister(&coldfire_alsa_audio_driver); -+ return err; -+} -+ -+static void __exit coldfire_alsa_audio_exit(void) -+{ -+ platform_device_unregister(device); -+ platform_driver_unregister(&coldfire_alsa_audio_driver); -+} -+ -+module_init(coldfire_alsa_audio_init); -+module_exit(coldfire_alsa_audio_exit); -+ -+MODULE_DESCRIPTION("Coldfire driver for ALSA"); -+MODULE_LICENSE("GPL"); -+MODULE_SUPPORTED_DEVICE("{{TLV320A}}"); -+ -+module_param(id, charp, 0444); -+MODULE_PARM_DESC(id, "ID string for Coldfire + TLV320A soundcard."); ---- /dev/null -+++ b/sound/coldfire/snd-coldfire.h -@@ -0,0 +1,15 @@ -+/* -+ * linux/sound/coldfire/snd-coldfire.h -+ * -+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. -+ * -+ * ALSA driver for Coldfire SSI -+ * -+ * This 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. -+ */ -+ -+extern int mcf_codec_spi_write(u8 addr, u16 data); -+ |