* [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
@ 2008-07-12 8:39 Grant Likely
2008-07-12 8:39 ` [PATCH v2 2/3] ALSA SoC: Add mpc5200-psc I2S driver Grant Likely
` (3 more replies)
0 siblings, 4 replies; 46+ messages in thread
From: Grant Likely @ 2008-07-12 8:39 UTC (permalink / raw)
To: linuxppc-dev, alsa-devel, liam.girdwood, jonsmirl
From: Grant Likely <grant.likely@secretlab.ca>
Simple utility layer for creating ASoC machine instances based on data
in the OpenFirmware device tree. OF aware platform drivers and codec
drivers register themselves with this framework and the framework
automatically instantiates a machine driver.
This is most likely temporary glue code to work around limitations in
the ASoC v1 framework. I expect ASoC v2 won't need this.
---
include/sound/soc-of.h | 21 ++++++
sound/soc/Kconfig | 3 +
sound/soc/Makefile | 1
sound/soc/soc-of.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 196 insertions(+), 0 deletions(-)
diff --git a/include/sound/soc-of.h b/include/sound/soc-of.h
new file mode 100644
index 0000000..a963032
--- /dev/null
+++ b/include/sound/soc-of.h
@@ -0,0 +1,21 @@
+/*
+ * OF helpers for ALSA SoC
+ *
+ * Copyright (C) 2008, Secret Lab Technologies Ltd.
+ */
+
+#ifndef _INCLUDE_SOC_OF_H_
+#define _INCLUDE_SOC_OF_H_
+
+#include <linux/of.h>
+#include <sound/soc.h>
+
+int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
+ void *codec_data, struct snd_soc_codec_dai *dai,
+ struct device_node *node);
+
+int of_snd_soc_register_platform(struct snd_soc_platform *platform,
+ struct device_node *node,
+ struct snd_soc_cpu_dai *cpu_dai);
+
+#endif /* _INCLUDE_SOC_OF_H_ */
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 18f28ac..99118ed 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -23,6 +23,9 @@ config SND_SOC
This ASoC audio support can also be built as a module. If so, the module
will be called snd-soc-core.
+config SND_SOC_OF
+ tristate
+
# All the supported Soc's
source "sound/soc/at91/Kconfig"
source "sound/soc/pxa/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 782db21..191c2e5 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -2,3 +2,4 @@ snd-soc-core-objs := soc-core.o soc-dapm.o
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ omap/
+obj-$(CONFIG_SND_SOC_OF) += soc-of.o
diff --git a/sound/soc/soc-of.c b/sound/soc/soc-of.c
new file mode 100644
index 0000000..0c855df
--- /dev/null
+++ b/sound/soc/soc-of.c
@@ -0,0 +1,171 @@
+/*
+ * OF helpers for ALSA SoC Layer
+ *
+ * Copyright (C) 2008, Secret Lab Technologies Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-of.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
+
+static DEFINE_MUTEX(of_snd_soc_mutex);
+static LIST_HEAD(of_snd_soc_device_list);
+static int of_snd_soc_next_index;
+
+struct of_snd_soc_device {
+ int id;
+ struct list_head list;
+ struct snd_soc_device device;
+ struct snd_soc_machine machine;
+ struct snd_soc_dai_link dai_link;
+ struct platform_device *pdev;
+ struct device_node *platform_node;
+ struct device_node *codec_node;
+};
+
+static struct snd_soc_ops of_snd_soc_ops = {
+};
+
+static struct of_snd_soc_device *
+of_snd_soc_get_device(struct device_node *codec_node)
+{
+ struct of_snd_soc_device *of_soc;
+
+ list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
+ if (of_soc->codec_node == codec_node)
+ return of_soc;
+ }
+
+ of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
+ if (!of_soc)
+ return NULL;
+
+ /* 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->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);
+
+ return of_soc;
+}
+
+static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
+{
+ struct platform_device *pdev;
+ int rc;
+
+ /* Only register the device if both the codec and platform have
+ * been registered */
+ if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
+ return;
+
+ pr_info("platform<-->codec match achieved; registering machine\n");
+
+ pdev = platform_device_alloc("soc-audio", of_soc->id);
+ if (!pdev) {
+ pr_err("of_soc: platform_device_alloc() failed\n");
+ return;
+ }
+
+ pdev->dev.platform_data = of_soc;
+ platform_set_drvdata(pdev, &of_soc->device);
+ of_soc->device.dev = &pdev->dev;
+
+ /* The ASoC device is complete; register it */
+ rc = platform_device_add(pdev);
+ if (rc) {
+ pr_err("of_soc: platform_device_add() failed\n");
+ return;
+ }
+
+}
+
+int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
+ void *codec_data, struct snd_soc_codec_dai *dai,
+ struct device_node *node)
+{
+ struct of_snd_soc_device *of_soc;
+ int rc = 0;
+
+ pr_info("registering ASoC codec driver: %s\n", node->full_name);
+
+ mutex_lock(&of_snd_soc_mutex);
+ of_soc = of_snd_soc_get_device(node);
+ if (!of_soc) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Store the codec data */
+ of_soc->device.codec_data = codec_data;
+ of_soc->device.codec_dev = codec_dev;
+ of_soc->dai_link.name = node->name;
+ of_soc->dai_link.stream_name = node->name;
+ of_soc->dai_link.codec_dai = dai;
+
+ /* Now try to register the SoC device */
+ of_snd_soc_register_device(of_soc);
+
+ out:
+ mutex_unlock(&of_snd_soc_mutex);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
+
+int of_snd_soc_register_platform(struct snd_soc_platform *platform,
+ struct device_node *node,
+ struct snd_soc_cpu_dai *cpu_dai)
+{
+ struct of_snd_soc_device *of_soc;
+ struct device_node *codec_node;
+ const phandle *handle;
+ int len, rc = 0;
+
+ pr_info("registering ASoC platform driver: %s\n", node->full_name);
+
+ handle = of_get_property(node, "codec-handle", &len);
+ if (!handle || len < sizeof(handle))
+ return -ENODEV;
+ codec_node = of_find_node_by_phandle(*handle);
+ if (!codec_node)
+ return -ENODEV;
+ pr_info("looking for codec: %s\n", codec_node->full_name);
+
+ mutex_lock(&of_snd_soc_mutex);
+ of_soc = of_snd_soc_get_device(codec_node);
+ if (!of_soc) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ of_soc->platform_node = node;
+ of_soc->dai_link.cpu_dai = cpu_dai;
+ 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);
+
+ out:
+ mutex_unlock(&of_snd_soc_mutex);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH v2 2/3] ALSA SoC: Add mpc5200-psc I2S driver
2008-07-12 8:39 [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers Grant Likely
@ 2008-07-12 8:39 ` Grant Likely
2008-07-14 12:10 ` [alsa-devel] " Mark Brown
2008-07-12 8:39 ` [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver Grant Likely
` (2 subsequent siblings)
3 siblings, 1 reply; 46+ messages in thread
From: Grant Likely @ 2008-07-12 8:39 UTC (permalink / raw)
To: linuxppc-dev, alsa-devel, liam.girdwood, jonsmirl
From: Grant Likely <grant.likely@secretlab.ca>
This is an I2S bus driver for the MPC5200 PSC device. It is probably
will not be merged as-is because it uses v1 of the ASoC API, but I want
to get it out there for comments.
---
include/asm-powerpc/mpc52xx_psc.h | 32 +
sound/soc/fsl/Kconfig | 7
sound/soc/fsl/Makefile | 2
sound/soc/fsl/mpc5200_psc_i2s.c | 896 +++++++++++++++++++++++++++++++++++++
4 files changed, 936 insertions(+), 1 deletions(-)
diff --git a/include/asm-powerpc/mpc52xx_psc.h b/include/asm-powerpc/mpc52xx_psc.h
index 710c5d3..0985dc8 100644
--- a/include/asm-powerpc/mpc52xx_psc.h
+++ b/include/asm-powerpc/mpc52xx_psc.h
@@ -60,10 +60,12 @@
#define MPC52xx_PSC_RXTX_FIFO_ALARM 0x0002
#define MPC52xx_PSC_RXTX_FIFO_EMPTY 0x0001
-/* PSC interrupt mask bits */
+/* PSC interrupt status/mask bits */
#define MPC52xx_PSC_IMR_TXRDY 0x0100
#define MPC52xx_PSC_IMR_RXRDY 0x0200
#define MPC52xx_PSC_IMR_DB 0x0400
+#define MPC52xx_PSC_IMR_TXEMP 0x0800
+#define MPC52xx_PSC_IMR_ORERR 0x1000
#define MPC52xx_PSC_IMR_IPC 0x8000
/* PSC input port change bit */
@@ -92,6 +94,34 @@
#define MPC52xx_PSC_RFNUM_MASK 0x01ff
+#define MPC52xx_PSC_SICR_DTS1 (1 << 29)
+#define MPC52xx_PSC_SICR_SHDR (1 << 28)
+#define MPC52xx_PSC_SICR_SIM_MASK (0xf << 24)
+#define MPC52xx_PSC_SICR_SIM_UART (0x0 << 24)
+#define MPC52xx_PSC_SICR_SIM_UART_DCD (0x8 << 24)
+#define MPC52xx_PSC_SICR_SIM_CODEC_8 (0x1 << 24)
+#define MPC52xx_PSC_SICR_SIM_CODEC_16 (0x2 << 24)
+#define MPC52xx_PSC_SICR_SIM_AC97 (0x3 << 24)
+#define MPC52xx_PSC_SICR_SIM_SIR (0x8 << 24)
+#define MPC52xx_PSC_SICR_SIM_SIR_DCD (0xc << 24)
+#define MPC52xx_PSC_SICR_SIM_MIR (0x5 << 24)
+#define MPC52xx_PSC_SICR_SIM_FIR (0x6 << 24)
+#define MPC52xx_PSC_SICR_SIM_CODEC_24 (0x7 << 24)
+#define MPC52xx_PSC_SICR_SIM_CODEC_32 (0xf << 24)
+#define MPC52xx_PSC_SICR_GENCLK (1 << 23)
+#define MPC52xx_PSC_SICR_I2S (1 << 22)
+#define MPC52xx_PSC_SICR_CLKPOL (1 << 21)
+#define MPC52xx_PSC_SICR_SYNCPOL (1 << 20)
+#define MPC52xx_PSC_SICR_CELLSLAVE (1 << 19)
+#define MPC52xx_PSC_SICR_CELL2XCLK (1 << 18)
+#define MPC52xx_PSC_SICR_ESAI (1 << 17)
+#define MPC52xx_PSC_SICR_ENAC97 (1 << 16)
+#define MPC52xx_PSC_SICR_SPI (1 << 15)
+#define MPC52xx_PSC_SICR_MSTR (1 << 14)
+#define MPC52xx_PSC_SICR_CPOL (1 << 13)
+#define MPC52xx_PSC_SICR_CPHA (1 << 12)
+#define MPC52xx_PSC_SICR_USEEOF (1 << 11)
+#define MPC52xx_PSC_SICR_DISABLEEOF (1 << 10)
/* Structure of the hardware registers */
struct mpc52xx_psc {
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 257101f..9ac970e 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -17,4 +17,11 @@ config SND_SOC_MPC8610_HPCD
help
Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
+config SND_SOC_MPC5200_I2S
+ tristate "Freescale MPC5200 PSC in I2S mode driver"
+ select SND_SOC_OF
+ depends on SND_SOC && PPC_MPC52xx
+ help
+ Say Y here to support the MPC5200 PSCs in I2S mode.
+
endmenu
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 62f680a..98729a1 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -4,3 +4,5 @@ obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o
# MPC8610 Platform Support
obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o
+obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
+
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
new file mode 100644
index 0000000..cdaae72
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -0,0 +1,896 @@
+/*
+ * Freescale MPC5200 PSC in I2S mode
+ * ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-of.h>
+
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/gen_bd.h>
+#include <asm/mpc52xx_psc.h>
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
+MODULE_LICENSE("GPL");
+
+/**
+ * PSC_I2S_RATES: sample rates supported by the I2S
+ *
+ * This driver currently only supports the PSC running in I2S slave mode,
+ * which means the codec determines the sample rate. Therefore, we tell
+ * ALSA that we support all rates and let the codec driver decide what rates
+ * are really supported.
+ */
+#define PSC_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
+ SNDRV_PCM_RATE_CONTINUOUS)
+
+/**
+ * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode
+ */
+#define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
+ SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \
+ SNDRV_PCM_FMTBIT_S32_BE)
+
+/**
+ * psc_i2s_stream - Data specific to a single stream (playback or capture)
+ * @active: flag indicating if the stream is active
+ * @psc_i2s: pointer back to parent psc_i2s data structure
+ * @bcom_task: bestcomm task structure
+ * @irq: irq number for bestcomm task
+ * @period_start: physical address of start of DMA region
+ * @period_end: physical address of end of DMA region
+ * @period_next_pt: physical address of next DMA buffer to enqueue
+ * @period_bytes: size of DMA period in bytes
+ */
+struct psc_i2s_stream {
+ int active;
+ struct psc_i2s *psc_i2s;
+ struct bcom_task *bcom_task;
+ int irq;
+ struct snd_pcm_substream *stream;
+ dma_addr_t period_start;
+ dma_addr_t period_end;
+ dma_addr_t period_next_pt;
+ dma_addr_t period_current_pt;
+ int period_bytes;
+};
+
+/**
+ * psc_i2s - Private driver data
+ * @name: short name for this device ("PSC0", "PSC1", etc)
+ * @psc_regs: pointer to the PSC's registers
+ * @fifo_regs: pointer to the PSC's FIFO registers
+ * @irq: IRQ of this PSC
+ * @dev: struct device pointer
+ * @playback: the number of playback streams opened
+ * @capture: the number of capture streams opened
+ * @dai: the CPU DAI for this device
+ * @playback_stream: Playback stream context data
+ * @capture_stream: Capture stream context data
+ */
+struct psc_i2s {
+ char name[32];
+ struct mpc52xx_psc __iomem *psc_regs;
+ struct mpc52xx_psc_fifo __iomem *fifo_regs;
+ unsigned int irq;
+ struct device *dev;
+ struct snd_soc_cpu_dai dai;
+ spinlock_t lock;
+
+ /* per-stream data */
+ struct psc_i2s_stream playback_stream;
+ struct psc_i2s_stream capture_stream;
+
+ /* Statistics */
+ struct {
+ int overrun_count;
+ int underrun_count;
+ } stats;
+};
+
+/*
+ * Interrupt handlers
+ */
+static irqreturn_t psc_i2s_status_irq(int irq, void *_psc_i2s)
+{
+ struct psc_i2s *psc_i2s = _psc_i2s;
+ struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs;
+ u16 imr;
+ u16 isr;
+
+ isr = in_be16(®s->mpc52xx_psc_isr);
+ imr = in_be16(®s->mpc52xx_psc_imr);
+
+ /* Playback underrun error */
+ if (isr & imr & MPC52xx_PSC_IMR_TXEMP)
+ psc_i2s->stats.underrun_count++;
+
+ /* Capture overrun error */
+ if (isr & imr & MPC52xx_PSC_IMR_ORERR)
+ psc_i2s->stats.overrun_count++;
+
+ out_8(®s->command, 4 << 4); /* reset the error status */
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * psc_i2s_bcom_enqueue_next_buffer - Enqueue another audio buffer
+ * @s: pointer to stream private data structure
+ *
+ * Enqueues another audio period buffer into the bestcomm queue.
+ *
+ * Note: The routine must only be called when there is space available in
+ * the queue. Otherwise the enqueue will fail and the audio ring buffer
+ * will get out of sync
+ */
+static void psc_i2s_bcom_enqueue_next_buffer(struct psc_i2s_stream *s)
+{
+ struct bcom_bd *bd;
+
+ /* Prepare and enqueue the next buffer descriptor */
+ bd = bcom_prepare_next_buffer(s->bcom_task);
+ bd->status = s->period_bytes;
+ bd->data[0] = s->period_next_pt;
+ bcom_submit_next_buffer(s->bcom_task, NULL);
+
+ /* Update for next period */
+ s->period_next_pt += s->period_bytes;
+ if (s->period_next_pt >= s->period_end)
+ s->period_next_pt = s->period_start;
+}
+
+/* Bestcomm DMA irq handler */
+static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream)
+{
+ struct psc_i2s_stream *s = _psc_i2s_stream;
+
+ //spin_lock(&s->psc_i2s->lock);
+
+ /* For each finished period, dequeue the completed period buffer
+ * and enqueue a new one in it's place. */
+ while (bcom_buffer_done(s->bcom_task)) {
+ bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+ s->period_current_pt += s->period_bytes;
+ if (s->period_current_pt >= s->period_end)
+ s->period_current_pt = s->period_start;
+ psc_i2s_bcom_enqueue_next_buffer(s);
+ bcom_enable(s->bcom_task);
+ }
+
+ //spin_unlock(&s->psc_i2s->lock);
+
+ /* If the stream is active, then also inform the PCM middle layer
+ * of the period finished event. */
+ if (s->active)
+ snd_pcm_period_elapsed(s->stream);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * psc_i2s_startup: create a new substream
+ *
+ * This is the first function called when a stream is opened.
+ *
+ * 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)
+{
+ int playback_irq, capture_irq, rc;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+ struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs;
+ struct mpc52xx_psc_fifo __iomem *fiforegs = psc_i2s->fifo_regs;
+
+ dev_dbg(psc_i2s->dev, "psc_i2s_startup(substream=%p)\n", substream);
+
+ /* Disable all interrupts and reset the PSC */
+ out_be16(®s->mpc52xx_psc_imr, 0);
+ out_8(®s->command, 3 << 4); /* reset transmitter */
+ out_8(®s->command, 2 << 4); /* reset receiver */
+ out_8(®s->command, 1 << 4); /* reset mode */
+ out_8(®s->command, 4 << 4); /* reset error */
+
+ /* Default to CODEC8 mode */
+ out_be32(®s->sicr,
+ MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
+ MPC52xx_PSC_SICR_CLKPOL | MPC52xx_PSC_SICR_SIM_CODEC_8);
+
+ /* First write: RxRdy (FIFO Alarm) generates receive FIFO interrupt */
+ /* Second write to mode: register Normal mode for non loopback */
+ out_8(®s->mode, 0);
+ out_8(®s->mode, 0);
+
+ /* Set the TX and RX fifo alarm thresholds */
+ out_be16(&fiforegs->rfalarm, 0x100); /* set RFALARM level */
+ out_8(&fiforegs->rfcntl, 0x4); /* set RFGRAN level (bytes) */
+ out_be16(&fiforegs->tfalarm, 0x100); /* set TFALARM level */
+ out_8(&fiforegs->tfcntl, 0x7); /* set TFGRAN level (bytes*4) */
+
+ /* Setup the IRQs */
+ playback_irq = bcom_get_task_irq(psc_i2s->playback_stream.bcom_task);
+ capture_irq = bcom_get_task_irq(psc_i2s->capture_stream.bcom_task);
+ rc = request_irq(psc_i2s->irq, &psc_i2s_status_irq, IRQF_SHARED,
+ "psc-i2s-status", psc_i2s);
+ rc |= request_irq(capture_irq, &psc_i2s_bcom_irq, IRQF_SHARED,
+ "psc-i2s-capture", &psc_i2s->capture_stream);
+ rc |= request_irq(playback_irq, &psc_i2s_bcom_irq, IRQF_SHARED,
+ "psc-i2s-playback", &psc_i2s->playback_stream);
+ if (rc) {
+ free_irq(psc_i2s->irq, psc_i2s);
+ free_irq(capture_irq, &psc_i2s->capture_stream);
+ free_irq(playback_irq, &psc_i2s->playback_stream);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
+ 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;
+ u32 sicr;
+
+ dev_dbg(psc_i2s->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
+ " periods=%i buffer_size=%i buffer_bytes=%i\n",
+ __FUNCTION__, substream, params_period_size(params),
+ params_period_bytes(params), params_periods(params),
+ params_buffer_size(params), params_buffer_bytes(params));
+
+ sicr = MPC52xx_PSC_SICR_DTS1 |
+ MPC52xx_PSC_SICR_I2S | MPC52xx_PSC_SICR_CLKPOL;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ sicr |= MPC52xx_PSC_SICR_SIM_CODEC_8;
+ break;
+ case SNDRV_PCM_FORMAT_S16_BE:
+ sicr |= MPC52xx_PSC_SICR_SIM_CODEC_16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_BE:
+ sicr |= MPC52xx_PSC_SICR_SIM_CODEC_24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_BE:
+ sicr |= MPC52xx_PSC_SICR_SIM_CODEC_32;
+ break;
+ default:
+ dev_dbg(psc_i2s->dev, "invalid format\n");
+ return -EINVAL;
+ }
+ out_be32(&psc_i2s->psc_regs->sicr, sicr);
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+ return 0;
+}
+
+static int psc_i2s_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ return 0;
+}
+
+/**
+ * psc_i2s_trigger: start and stop the DMA transfer.
+ *
+ * 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_pcm_runtime *rtd = substream->private_data;
+ struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct psc_i2s_stream *s;
+ struct mpc52xx_psc __iomem *regs = psc_i2s->psc_regs;
+ u16 imr;
+ u8 psc_cmd;
+ long flags;
+
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s = &psc_i2s->capture_stream;
+ else
+ s = &psc_i2s->playback_stream;
+
+ dev_dbg(psc_i2s->dev, "psc_i2s_trigger(substream=%p, cmd=%i)"
+ " stream_id=%i\n",
+ substream, cmd, substream->pstr->stream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ s->period_bytes = frames_to_bytes(runtime,
+ runtime->period_size);
+ s->period_start = virt_to_phys(runtime->dma_area);
+ s->period_end = s->period_start +
+ (s->period_bytes * runtime->periods);
+ s->period_next_pt = s->period_start;
+ s->period_current_pt = s->period_start;
+ s->active = 1;
+
+ /* First; reset everything */
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ out_8(®s->command, MPC52xx_PSC_RST_RX);
+ out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT);
+ } else {
+ out_8(®s->command, MPC52xx_PSC_RST_TX);
+ out_8(®s->command, MPC52xx_PSC_RST_ERR_STAT);
+ }
+
+ /* Next, fill up the bestcomm bd queue and enable DMA.
+ * This will begin filling the PSC's fifo. */
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ bcom_gen_bd_rx_reset(s->bcom_task);
+ else
+ bcom_gen_bd_tx_reset(s->bcom_task);
+ while (!bcom_queue_full(s->bcom_task))
+ psc_i2s_bcom_enqueue_next_buffer(s);
+ bcom_enable(s->bcom_task);
+
+ /* Update interrupt enable settings. This must be done
+ * before the PSC is enabled so that TX underrun events
+ * are not missed. */
+ imr = 0;
+ if (psc_i2s->playback_stream.active)
+ imr |= MPC52xx_PSC_IMR_TXEMP;
+ if (psc_i2s->capture_stream.active)
+ imr |= MPC52xx_PSC_IMR_ORERR;
+ out_be16(®s->isr_imr.imr, imr);
+
+ /* Due to errata in the i2s mode; need to line up enabling
+ * the transmitter with a transition on the frame sync
+ * line */
+
+ spin_lock_irqsave(&psc_i2s->lock, flags);
+ /* first make sure it is low */
+ while ((in_8(®s->ipcr_acr.ipcr) & 0x80) != 0);
+ /* then wait for the transition to high */
+ while ((in_8(®s->ipcr_acr.ipcr) & 0x80) == 0);
+ /* Finally, enable the PSC.
+ * Receiver must always be enabled; even when we only want
+ * transmit. (see 15.3.2.3 of MPC5200B User's Guide) */
+ psc_cmd = MPC52xx_PSC_RX_ENABLE;
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ psc_cmd |= MPC52xx_PSC_TX_ENABLE;
+ out_8(®s->command, psc_cmd);
+ spin_unlock_irqrestore(&psc_i2s->lock, flags);
+
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* Turn off the PSC */
+ s->active = 0;
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (!psc_i2s->playback_stream.active) {
+ out_8(®s->command, 2 << 4); /* reset rx */
+ out_8(®s->command, 3 << 4); /* reset tx */
+ out_8(®s->command, 4 << 4); /* reset err */
+ }
+ } else {
+ out_8(®s->command, 3 << 4); /* reset tx */
+ out_8(®s->command, 4 << 4); /* reset err */
+ if (!psc_i2s->capture_stream.active)
+ out_8(®s->command, 2 << 4); /* reset rx */
+ }
+
+ bcom_disable(s->bcom_task);
+ while (!bcom_queue_empty(s->bcom_task))
+ bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+
+ break;
+
+ default:
+ dev_dbg(psc_i2s->dev, "invalid command\n");
+ return -EINVAL;
+ }
+
+ /* Update interrupt enable settings */
+ imr = 0;
+ if (psc_i2s->playback_stream.active) imr |= MPC52xx_PSC_IMR_TXEMP;
+ if (psc_i2s->capture_stream.active) imr |= MPC52xx_PSC_IMR_ORERR;
+ out_be16(®s->isr_imr.imr, imr);
+
+ return 0;
+}
+
+/**
+ * psc_i2s_shutdown: shutdown the data transfer on a stream
+ *
+ * Shutdown the PSC if there are no other substreams open.
+ */
+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;
+
+ dev_dbg(psc_i2s->dev, "psc_i2s_shutdown(substream=%p)\n", substream);
+
+ /*
+ * If this is the last active substream, disable the PSC and release
+ * the IRQ.
+ */
+ if (!psc_i2s->playback_stream.active &&
+ !psc_i2s->capture_stream.active) {
+ /* TODO: shut off channels */
+ free_irq(psc_i2s->irq, psc_i2s);
+ free_irq(bcom_get_task_irq(psc_i2s->capture_stream.bcom_task),
+ &psc_i2s->capture_stream);
+ free_irq(bcom_get_task_irq(psc_i2s->playback_stream.bcom_task),
+ &psc_i2s->playback_stream);
+ }
+}
+
+/**
+ * psc_i2s_set_sysclk: set the clock frequency and direction
+ *
+ * This function is called by the machine driver to tell us what the clock
+ * frequency and direction are.
+ *
+ * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
+ * and we don't care about the frequency. Return an error if the direction
+ * is not SND_SOC_CLOCK_IN.
+ *
+ * @clk_id: reserved, should be zero
+ * @freq: the frequency of the given clock ID, currently ignored
+ * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
+ */
+static int psc_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct psc_i2s *psc_i2s = cpu_dai->private_data;
+ dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
+ cpu_dai, dir);
+ return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
+}
+
+/**
+ * psc_i2s_set_fmt: set the serial format.
+ *
+ * This function is called by the machine driver to tell us what serial
+ * format to use.
+ *
+ * This driver only supports I2S mode. Return an error if the format is
+ * not SND_SOC_DAIFMT_I2S.
+ *
+ * @format: one of SND_SOC_DAIFMT_xxx
+ */
+static int psc_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int format)
+{
+ struct psc_i2s *psc_i2s = cpu_dai->private_data;
+ dev_dbg(psc_i2s->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
+ cpu_dai, format);
+ return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
+}
+
+/* ---------------------------------------------------------------------
+ * ALSA SoC Bindings
+ *
+ * - Digital Audio Interface (DAI) template
+ * - create/destroy dai hooks
+ */
+
+/**
+ * psc_i2s_dai_template: template CPU Digital Audio Interface
+ */
+static struct snd_soc_cpu_dai psc_i2s_dai_template = {
+ .type = SND_SOC_DAI_I2S,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PSC_I2S_RATES,
+ .formats = PSC_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = PSC_I2S_RATES,
+ .formats = PSC_I2S_FORMATS,
+ },
+ .ops = {
+ .startup = psc_i2s_startup,
+ .hw_params = psc_i2s_hw_params,
+ .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,
+ },
+};
+
+/* ---------------------------------------------------------------------
+ * The PSC I2S 'ASoC platform' driver
+ *
+ * Can be referenced by an 'ASoC machine' driver
+ * This driver only deals with the audio bus; it doesn't have any
+ * interaction with the attached codec
+ */
+
+static const struct snd_pcm_hardware psc_i2s_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .formats = SNDRV_PCM_FMTBIT_S8 |SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .period_bytes_max = 1024 * 1024,
+ .period_bytes_min = 32,
+ .period_bytes_max = 1024 * 1024,
+ .periods_min = 2,
+ .periods_max = 256,
+ .buffer_bytes_max = 2 * 1024 * 1024,
+ .fifo_size = 0,
+};
+
+static unsigned int psc_i2s_fixed_rates[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
+};
+
+static struct snd_pcm_hw_constraint_list psc_i2s_constraints_rates = {
+ .count = ARRAY_SIZE(psc_i2s_fixed_rates),
+ .list = psc_i2s_fixed_rates,
+ .mask = 0,
+};
+
+static int psc_i2s_pcm_open(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;
+ struct psc_i2s_stream *s;
+ int rc;
+
+ dev_dbg(psc_i2s->dev, "psc_i2s_pcm_open(substream=%p)\n", substream);
+
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s = &psc_i2s->capture_stream;
+ else
+ s = &psc_i2s->playback_stream;
+
+ snd_soc_set_runtime_hwparams(substream, &psc_i2s_pcm_hardware);
+
+ rc = snd_pcm_hw_constraint_integer(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (rc < 0) {
+ dev_err(psc_i2s->dev, "invalid buffer size\n");
+ return rc;
+ }
+ rc = snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &psc_i2s_constraints_rates);
+ if (rc < 0) {
+ dev_err(psc_i2s->dev, "invalid rate\n");
+ return rc;
+ }
+
+ s->stream = substream;
+ return 0;
+}
+
+static int psc_i2s_pcm_close(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;
+ struct psc_i2s_stream *s;
+
+ dev_dbg(psc_i2s->dev, "psc_i2s_pcm_close(substream=%p)\n", substream);
+
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s = &psc_i2s->capture_stream;
+ else
+ s = &psc_i2s->playback_stream;
+
+ s->stream = NULL;
+ return 0;
+}
+
+static snd_pcm_uframes_t
+psc_i2s_pcm_pointer(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;
+ struct psc_i2s_stream *s;
+ dma_addr_t count;
+
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s = &psc_i2s->capture_stream;
+ else
+ s = &psc_i2s->playback_stream;
+
+ count = s->period_current_pt - s->period_start;
+
+ return bytes_to_frames(substream->runtime, count);
+}
+
+static struct snd_pcm_ops psc_i2s_pcm_ops = {
+ .open = psc_i2s_pcm_open,
+ .close = psc_i2s_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .pointer = psc_i2s_pcm_pointer,
+};
+
+static u64 psc_i2s_pcm_dmamask = 0xffffffff;
+static int psc_i2s_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+ struct snd_pcm *pcm)
+{
+ struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+ size_t size = psc_i2s_pcm_hardware.buffer_bytes_max;
+ int rc = 0;
+
+ dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_new(card=%p, dai=%p, pcm=%p)\n",
+ card, dai, pcm);
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &psc_i2s_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = 0xffffffff;
+
+ if (pcm->streams[0].substream) {
+ rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
+ &pcm->streams[0].substream->dma_buffer);
+ if (rc) {
+ dev_err(card->dev, "Cannot alloc playback buffer\n");
+ return -ENOMEM;
+ }
+ }
+
+ if (pcm->streams[1].substream) {
+ rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
+ &pcm->streams[1].substream->dma_buffer);
+ if (rc) {
+ if (pcm->streams[0].substream)
+ snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+ dev_err(card->dev, "Cannot allocate capture buffer\n");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+static void psc_i2s_pcm_free(struct snd_pcm *pcm)
+{
+ struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+ struct snd_pcm_substream *substream;
+ int stream;
+
+ dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_free(pcm=%p)\n", pcm);
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (substream) {
+ snd_dma_free_pages(&substream->dma_buffer);
+ substream->dma_buffer.area = NULL;
+ substream->dma_buffer.addr = 0;
+ }
+ }
+}
+
+struct snd_soc_platform psc_i2s_pcm_soc_platform = {
+ .name = "mpc5200-psc-audio",
+ .pcm_ops = &psc_i2s_pcm_ops,
+ .pcm_new = &psc_i2s_pcm_new,
+ .pcm_free = &psc_i2s_pcm_free,
+};
+
+/* ---------------------------------------------------------------------
+ * Sysfs attributes for debugging
+ */
+
+static ssize_t psc_i2s_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
+
+ return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x tfnum=%i tfstat=0x%.4x\n",
+ in_be16(&psc_i2s->psc_regs->sr_csr.status),
+ in_be32(&psc_i2s->psc_regs->sicr),
+ in_be16(&psc_i2s->fifo_regs->rfnum) & 0x1ff,
+ in_be16(&psc_i2s->fifo_regs->rfstat),
+ in_be16(&psc_i2s->fifo_regs->tfnum) & 0x1ff,
+ in_be16(&psc_i2s->fifo_regs->tfstat));
+}
+
+static int * psc_i2s_get_stat_attr(struct psc_i2s *psc_i2s,
+ const char *name)
+{
+ if (strcmp(name, "playback_underrun") == 0)
+ return &psc_i2s->stats.underrun_count;
+ if (strcmp(name, "capture_overrun") == 0)
+ return &psc_i2s->stats.overrun_count;
+
+ return NULL;
+}
+
+static ssize_t psc_i2s_stat_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
+ int *attrib;
+
+ attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name);
+ if (!attrib)
+ return 0;
+
+ return sprintf(buf, "%i\n", *attrib);
+}
+
+static ssize_t psc_i2s_stat_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct psc_i2s *psc_i2s = dev_get_drvdata(dev);
+ int *attrib;
+
+ attrib = psc_i2s_get_stat_attr(psc_i2s, attr->attr.name);
+ if (!attrib)
+ return 0;
+
+ *attrib = simple_strtoul(buf, NULL, 0);
+ return count;
+}
+
+DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL);
+DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show,psc_i2s_stat_store);
+DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show, psc_i2s_stat_store);
+
+/* ---------------------------------------------------------------------
+ * OF platform bus binding code:
+ * - Probe/remove operations
+ * - OF device match table
+ */
+static int __devinit psc_i2s_of_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ phys_addr_t fifo;
+ struct psc_i2s *psc_i2s;
+ struct resource res;
+ int size, psc_id, irq, rc;
+ const __be32 *prop;
+ void __iomem *regs;
+
+ dev_dbg(&op->dev, "probing psc i2s device\n");
+
+ /* Get the PSC ID */
+ prop = of_get_property(op->node, "cell-index", &size);
+ if (!prop || size < sizeof *prop)
+ return -ENODEV;
+ psc_id = be32_to_cpu(*prop);
+
+ /* Fetch the registers and IRQ of the PSC */
+ irq = irq_of_parse_and_map(op->node, 0);
+ if (of_address_to_resource(op->node, 0, &res)) {
+ dev_err(&op->dev, "Missing reg property\n");
+ return -ENODEV;
+ }
+ regs = ioremap(res.start, 1 + res.end - res.start);
+ if (!regs) {
+ dev_err(&op->dev, "Could not map registers\n");
+ return -ENODEV;
+ }
+
+ /* Allocate and initialize the driver private data */
+ psc_i2s = kzalloc(sizeof *psc_i2s, GFP_KERNEL);
+ if (!psc_i2s) {
+ iounmap(regs);
+ return -ENOMEM;
+ }
+ spin_lock_init(&psc_i2s->lock);
+ psc_i2s->irq = irq;
+ psc_i2s->psc_regs = regs;
+ psc_i2s->fifo_regs = regs + sizeof *psc_i2s->psc_regs;
+ psc_i2s->dev = &op->dev;
+ psc_i2s->playback_stream.psc_i2s = psc_i2s;
+ psc_i2s->capture_stream.psc_i2s = psc_i2s;
+ snprintf(psc_i2s->name, sizeof psc_i2s->name, "PSC%u", psc_id+1);
+
+ /* Fill out the CPU DAI structure */
+ memcpy(&psc_i2s->dai, &psc_i2s_dai_template, sizeof psc_i2s->dai);
+ psc_i2s->dai.private_data = psc_i2s;
+ psc_i2s->dai.name = psc_i2s->name;
+ psc_i2s->dai.id = psc_id;
+
+ /* Find the address of the fifo data registers and setup the
+ * DMA tasks */
+ fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
+ psc_i2s->capture_stream.bcom_task =
+ bcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512);
+ psc_i2s->playback_stream.bcom_task =
+ bcom_psc_gen_bd_tx_init(psc_id, 10, fifo);
+ if (!psc_i2s->capture_stream.bcom_task ||
+ !psc_i2s->playback_stream.bcom_task) {
+ dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
+ iounmap(regs);
+ kfree(psc_i2s);
+ return -ENODEV;
+ }
+
+ /* Save what we've done so it can be found again later */
+ dev_set_drvdata(&op->dev, psc_i2s);
+
+ /* Register the SYSFS files */
+ rc = device_create_file(psc_i2s->dev, &dev_attr_status);
+ rc = device_create_file(psc_i2s->dev, &dev_attr_capture_overrun);
+ rc = device_create_file(psc_i2s->dev, &dev_attr_playback_underrun);
+ if (rc)
+ dev_info(psc_i2s->dev, "error creating sysfs files\n");
+
+ /* Tell the ASoC OF helpers about it */
+ of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node,
+ &psc_i2s->dai);
+
+ return 0;
+}
+
+static int __devexit psc_i2s_of_remove(struct of_device *op)
+{
+ struct psc_i2s *psc_i2s = dev_get_drvdata(&op->dev);
+
+ dev_dbg(&op->dev, "psc_i2s_remove()\n");
+
+ bcom_gen_bd_rx_release(psc_i2s->capture_stream.bcom_task);
+ bcom_gen_bd_tx_release(psc_i2s->playback_stream.bcom_task);
+
+ iounmap(psc_i2s->psc_regs);
+ iounmap(psc_i2s->fifo_regs);
+ kfree(psc_i2s);
+ dev_set_drvdata(&op->dev, NULL);
+
+ return 0;
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id psc_i2s_match[] __devinitdata = {
+ { .compatible = "fsl,mpc5200-psc-i2s", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, psc_i2s_match);
+
+static struct of_platform_driver psc_i2s_driver = {
+ .match_table = psc_i2s_match,
+ .probe = psc_i2s_of_probe,
+ .remove = __devexit_p(psc_i2s_of_remove),
+ .driver = {
+ .name = "mpc5200-psc-i2s",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* ---------------------------------------------------------------------
+ * Module setup and teardown; simply register the of_platform driver
+ * for the PSC in I2S mode.
+ */
+static int __init psc_i2s_init(void)
+{
+ return of_register_platform_driver(&psc_i2s_driver);
+}
+module_init(psc_i2s_init);
+
+static void __exit psc_i2s_exit(void)
+{
+ of_unregister_platform_driver(&psc_i2s_driver);
+}
+module_exit(psc_i2s_exit);
+
+
^ permalink raw reply related [flat|nested] 46+ messages in thread
* [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver
2008-07-12 8:39 [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers Grant Likely
2008-07-12 8:39 ` [PATCH v2 2/3] ALSA SoC: Add mpc5200-psc I2S driver Grant Likely
@ 2008-07-12 8:39 ` Grant Likely
2008-07-12 18:10 ` [alsa-devel] " Mark Brown
` (4 more replies)
2008-07-14 13:49 ` [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers Mark Brown
2008-07-14 14:16 ` Anton Vorontsov
3 siblings, 5 replies; 46+ messages in thread
From: Grant Likely @ 2008-07-12 8:39 UTC (permalink / raw)
To: linuxppc-dev, alsa-devel, liam.girdwood, jonsmirl
From: Grant Likely <grant.likely@secretlab.ca>
ASoC Codec driver for the TLV320AIC26 device. This driver uses the ASoC
v1 API, so I don't expect it to get merged as-is, but I want to get it
out there for review.
---
sound/soc/codecs/Kconfig | 4
sound/soc/codecs/Makefile | 2
sound/soc/codecs/tlv320aic26.c | 546 ++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/tlv320aic26.h | 103 ++++++++
4 files changed, 655 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 3903ab7..96c7bfe 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -41,6 +41,10 @@ config SND_SOC_CS4270_VD33_ERRATA
bool
depends on SND_SOC_CS4270
+config SND_SOC_TLV320AIC26
+ tristate "TI TLB320AIC26 Codec support"
+ depends on SND_SOC && SPI
+
config SND_SOC_TLV320AIC3X
tristate
depends on SND_SOC && I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 4e1314c..ec0cd93 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -5,6 +5,7 @@ snd-soc-wm8753-objs := wm8753.o
snd-soc-wm9712-objs := wm9712.o
snd-soc-wm9713-objs := wm9713.o
snd-soc-cs4270-objs := cs4270.o
+snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
@@ -14,4 +15,5 @@ obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
new file mode 100644
index 0000000..3ebfa23
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -0,0 +1,546 @@
+/*
+ * Texas Instruments TLV320AIC26 low power audio CODEC
+ * ALSA SoC CODEC driver
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/sysfs.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/soc-of.h>
+#include <sound/initval.h>
+
+#include "tlv320aic26.h"
+
+MODULE_DESCRIPTION("ASoC TLV320AIC26 codec driver");
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_LICENSE("GPL");
+
+/* AIC26 driver private data */
+struct aic26 {
+ struct spi_device *spi;
+ struct snd_soc_codec codec;
+ u16 reg_cache[AIC26_REG_CACHE_SIZE]; /* shadow registers */
+ int master;
+ int datfm;
+ int mclk;
+
+ /* Keyclick parameters */
+ int keyclick_amplitude;
+ int keyclick_freq;
+ int keyclick_len;
+};
+
+/* ---------------------------------------------------------------------
+ * Register access routines
+ */
+static unsigned int aic26_reg_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ struct aic26 *aic26 = codec->private_data;
+ u16 *cache = codec->reg_cache;
+ u16 cmd, value;
+ u8 buffer[2];
+ int rc;
+
+ if (reg >= AIC26_NUM_REGS) {
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+
+ /* Do SPI transfer; first 16bits are command; remaining is
+ * register contents */
+ cmd = AIC26_READ_COMMAND_WORD(reg);
+ buffer[0] = (cmd >> 8) & 0xff;
+ buffer[1] = cmd & 0xff;
+ rc = spi_write_then_read(aic26->spi, buffer, 2, buffer, 2);
+ if (rc) {
+ dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
+ return -EIO;
+ }
+ value = (buffer[0] << 8) | buffer[1];
+
+ /* Update the cache before returning with the value */
+ if (AIC26_REG_IS_CACHED(reg))
+ cache[AIC26_REG_CACHE_ADDR(reg)] = value;
+ return value;
+}
+
+static unsigned int aic26_reg_read_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+
+ if ((reg < 0) || (reg >= AIC26_NUM_REGS)) {
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+
+ if (AIC26_REG_IS_CACHED(reg))
+ return cache[AIC26_REG_CACHE_ADDR(reg)];
+
+ return aic26_reg_read(codec, reg);
+}
+
+static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ struct aic26 *aic26 = codec->private_data;
+ u16 *cache = codec->reg_cache;
+ u16 cmd;
+ u8 buffer[4];
+ int rc;
+
+ if ((reg < 0) || (reg >= AIC26_NUM_REGS)) {
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
+
+ /* Do SPI transfer; first 16bits are command; remaining is data
+ * to write into register */
+ cmd = AIC26_WRITE_COMMAND_WORD(reg);
+ buffer[0] = (cmd >> 8) & 0xff;
+ buffer[1] = cmd & 0xff;
+ buffer[2] = value >> 8;
+ buffer[3] = value;
+ rc = spi_write(aic26->spi, buffer, 4);
+ if (rc) {
+ dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
+ return -EIO;
+ }
+
+ /* update cache before returning */
+ if (AIC26_REG_IS_CACHED(reg))
+ cache[AIC26_REG_CACHE_ADDR(reg)] = value;
+ return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Digital Audio Interface Operations
+ */
+static int aic26_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_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+ struct aic26 *aic26 = codec->private_data;
+ int fsref, divisor, wlen, pval, jval, dval, qval;
+ u16 reg;
+
+ dev_dbg(&aic26->spi->dev, "aic26_hw_params(substream=%p, params=%p)\n",
+ substream, params);
+ dev_dbg(&aic26->spi->dev, "rate=%i format=%i\n", params_rate(params),
+ params_format(params));
+
+ switch (params_rate(params)) {
+ case 8000: fsref = 48000; divisor = AIC26_DIV_6; break;
+ case 11025: fsref = 44100; divisor = AIC26_DIV_4; break;
+ case 12000: fsref = 48000; divisor = AIC26_DIV_4; break;
+ case 16000: fsref = 48000; divisor = AIC26_DIV_3; break;
+ case 22050: fsref = 44100; divisor = AIC26_DIV_2; break;
+ case 24000: fsref = 48000; divisor = AIC26_DIV_2; break;
+ case 32000: fsref = 48000; divisor = AIC26_DIV_1_5; break;
+ case 44100: fsref = 44100; divisor = AIC26_DIV_1; break;
+ case 48000: fsref = 48000; divisor = AIC26_DIV_1; break;
+ default: dev_dbg(&aic26->spi->dev, "bad rate\n"); return -EINVAL;
+ }
+
+ /* select data word length */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8: wlen = AIC26_WLEN_16; break;
+ case SNDRV_PCM_FORMAT_S16_BE: wlen = AIC26_WLEN_16; break;
+ case SNDRV_PCM_FORMAT_S24_BE: wlen = AIC26_WLEN_24; break;
+ case SNDRV_PCM_FORMAT_S32_BE: wlen = AIC26_WLEN_32; break;
+ default: dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
+ }
+
+ /* Configure PLL */
+ pval = 1;
+ jval = (fsref == 44100) ? 7 : 8;
+ dval = (fsref == 44100) ? 5264 : 1920;
+ qval = 0;
+ reg = 0x8000 | qval << 11 | pval << 8 | jval << 2;
+ aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg);
+ reg = dval << 2;
+ aic26_reg_write(codec, AIC26_REG_PLL_PROG2, reg);
+
+ /* Power up CODEC */
+ aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0);
+
+ /* Audio Control 3 (master mode, fsref rate) */
+ reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3);
+ reg &= ~0xf800;
+ if (aic26->master)
+ reg |= 0x0800;
+ if (fsref == 48000)
+ reg |= 0x2000;
+ aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
+
+ /* Audio Control 1 (FSref divisor) */
+ reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1);
+ reg &= ~0x0fff;
+ reg |= wlen | aic26->datfm | (divisor << 3) | divisor;
+ aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL1, reg);
+
+ return 0;
+}
+
+/**
+ * aic26_mute - Mute control to reduce noise when changing audio format
+ */
+static int aic26_mute(struct snd_soc_codec_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct aic26 *aic26 = codec->private_data;
+ u16 reg = aic26_reg_read_cache(codec, AIC26_REG_DAC_GAIN);
+
+ dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n",
+ dai, mute);
+
+ if (mute)
+ reg |= 0x8080;
+ else
+ reg &= ~0x8080;
+ aic26_reg_write(codec, AIC26_REG_DAC_GAIN, reg);
+
+ return 0;
+}
+
+static int aic26_set_sysclk(struct snd_soc_codec_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct aic26 *aic26 = codec->private_data;
+
+ dev_dbg(&aic26->spi->dev, "aic26_set_sysclk(dai=%p, clk_id==%i,"
+ " freq=%i, dir=%i)\n",
+ codec_dai, clk_id, freq, dir);
+
+ /* MCLK needs to fall between 2MHz and 50 MHz */
+ if ((freq < 2000000) || (freq > 50000000))
+ return -EINVAL;
+
+ aic26->mclk = freq;
+ return 0;
+}
+
+static int aic26_set_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct aic26 *aic26 = codec->private_data;
+
+ dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n",
+ codec_dai, fmt);
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break;
+ case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break;
+ default: dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S: aic26->datfm = AIC26_DATFM_I2S; break;
+ case SND_SOC_DAIFMT_DSP_A: aic26->datfm = AIC26_DATFM_DSP; break;
+ case SND_SOC_DAIFMT_RIGHT_J: aic26->datfm = AIC26_DATFM_RIGHTJ; break;
+ case SND_SOC_DAIFMT_LEFT_J: aic26->datfm = AIC26_DATFM_LEFTJ; break;
+ default: dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Digital Audio Interface Definition
+ */
+struct snd_soc_codec_dai aic26_dai = {
+ .name = "tlv320aic26",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AIC26_RATES,
+ .formats = AIC26_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AIC26_RATES,
+ .formats = AIC26_FORMATS,
+ },
+ .ops = {
+ .hw_params = aic26_hw_params,
+ },
+ .dai_ops = {
+ .digital_mute = aic26_mute,
+ .set_sysclk = aic26_set_sysclk,
+ .set_fmt = aic26_set_fmt,
+ },
+};
+EXPORT_SYMBOL_GPL(aic26_dai);
+
+/* ---------------------------------------------------------------------
+ * ALSA controls
+ */
+static const char *aic26_capture_src_text[] = {"Mic", "Aux"};
+static const struct soc_enum aic26_capture_src_enum =
+ SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12,2, aic26_capture_src_text);
+
+static const struct snd_kcontrol_new aic26_snd_controls[] = {
+ /* Output */
+ SOC_DOUBLE("PCM Playback Volume", AIC26_REG_DAC_GAIN, 8, 0, 0x7f, 1),
+ SOC_DOUBLE("PCM Playback Switch", AIC26_REG_DAC_GAIN, 15, 7, 1, 1),
+ SOC_SINGLE("PCM Capture Volume", AIC26_REG_ADC_GAIN, 8, 0x7f, 0),
+ SOC_SINGLE("PCM Capture Mute", AIC26_REG_ADC_GAIN, 15, 1, 1),
+ SOC_SINGLE("Keyclick activate", AIC26_REG_AUDIO_CTRL2, 15, 0x1, 0),
+ SOC_SINGLE("Keyclick amplitude", AIC26_REG_AUDIO_CTRL2, 12, 0x7, 0),
+ SOC_SINGLE("Keyclick frequency", AIC26_REG_AUDIO_CTRL2, 8, 0x7, 0),
+ SOC_SINGLE("Keyclick period", AIC26_REG_AUDIO_CTRL2, 4, 0xf, 0),
+ SOC_ENUM("Capture Source", aic26_capture_src_enum),
+};
+
+/* ---------------------------------------------------------------------
+ * SoC CODEC portion of driver: probe and release routines
+ */
+static int aic26_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ struct snd_kcontrol *kcontrol;
+ struct aic26 *aic26;
+ int i, ret, err;
+
+ dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n");
+ dev_dbg(&pdev->dev, "socdev=%p\n", socdev);
+ dev_dbg(&pdev->dev, "codec_data=%p\n", socdev->codec_data);
+
+ /* Fetch the relevant aic26 private data here (it's already been
+ * stored in the .codec pointer) */
+ aic26 = socdev->codec_data;
+ if (aic26 == NULL) {
+ dev_err(&pdev->dev, "aic26: missing codec pointer\n");
+ return -ENODEV;
+ }
+ codec = &aic26->codec;
+ socdev->codec = codec;
+
+ dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n",
+ &pdev->dev, socdev->dev);
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "aic26: failed to create pcms\n");
+ return -ENODEV;
+ }
+
+ /* register controls */
+ dev_dbg(&pdev->dev, "Registering controls\n");
+ for (i = 0; i < ARRAY_SIZE(aic26_snd_controls); i++) {
+ kcontrol = snd_soc_cnew(&aic26_snd_controls[i], codec, NULL);
+ err = snd_ctl_add(codec->card, kcontrol);
+ WARN_ON(err < 0);
+ }
+
+ /* CODEC is setup, we can register the card now */
+ dev_dbg(&pdev->dev, "Registering card\n");
+ ret = snd_soc_register_card(socdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "aic26: failed to register card\n");
+ goto card_err;
+ }
+ return 0;
+
+ card_err:
+ snd_soc_free_pcms(socdev);
+ return ret;
+}
+
+static int aic26_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ snd_soc_free_pcms(socdev);
+ return 0;
+}
+
+struct snd_soc_codec_device aic26_soc_codec_dev = {
+ .probe = aic26_probe,
+ .remove = aic26_remove,
+};
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: sysfs files for debugging
+ */
+
+static ssize_t aic26_regs_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct aic26 *aic26 = dev_get_drvdata(dev);
+ char *idx = buf;
+ int cache_flag, addr, page, i, reg;
+
+ cache_flag = (strcmp(attr->attr.name, "regs_cache") == 0);
+
+ for (page = 0; page < 3; page++) {
+ for (i = 0; i < 0x20; i++) {
+ addr = AIC26_PAGE_ADDR(page, i);
+ if (i % 8 == 0)
+ idx += sprintf(idx, "%i:%.2i:", page,i);
+ if (cache_flag)
+ reg = aic26_reg_read_cache(&aic26->codec, addr);
+ else
+ reg = aic26_reg_read(&aic26->codec, addr);
+ idx += sprintf(idx, " %.4x", reg);
+ if (i % 8 == 7)
+ idx += sprintf(idx, "\n");
+ }
+ }
+ return idx - buf;
+}
+
+static ssize_t aic26_keyclick_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct aic26 *aic26 = dev_get_drvdata(dev);
+ int val, amp, freq, len;
+
+ val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+ amp = (val >> 12) & 0x7;
+ freq = (125 << ((val >> 8) & 0x7)) >> 1;
+ len = 2 * (1 +((val >> 4) & 0xf));
+
+ return sprintf(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len);
+}
+
+/* Any write to the keyclick attribute will trigger the keyclick */
+static ssize_t aic26_keyclick_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct aic26 *aic26 = dev_get_drvdata(dev);
+ int val;
+
+ val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+ val |= 0x8000;
+ aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL2, val);
+
+ return count;
+}
+
+DEVICE_ATTR(regs, 0644, aic26_regs_show, NULL);
+DEVICE_ATTR(regs_cache, 0644, aic26_regs_show, NULL);
+DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: probe and release routines and SPI
+ * driver registration.
+ */
+static int aic26_spi_probe(struct spi_device *spi)
+{
+ struct aic26 *aic26;
+ int rc, i, reg;
+
+ dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
+
+ /* Allocate driver data */
+ aic26 = kzalloc(sizeof *aic26, GFP_KERNEL);
+ if (!aic26)
+ return -ENOMEM;
+
+ /* Initialize the driver data */
+ aic26->spi = spi;
+ dev_set_drvdata(&spi->dev, aic26);
+
+ /* Setup what we can in the codec structure so that the register
+ * access functions will work as expected. More will be filled
+ * out when it is probed by the SoC CODEC part of this driver */
+ aic26->codec.private_data = aic26;
+ aic26->codec.name = "aic26";
+ aic26->codec.owner = THIS_MODULE;
+ aic26->codec.dai = &aic26_dai;
+ aic26->codec.num_dai = 1;
+ aic26->codec.read = aic26_reg_read;
+ aic26->codec.write = aic26_reg_write;
+ aic26->master = 1;
+ mutex_init(&aic26->codec.mutex);
+ INIT_LIST_HEAD(&aic26->codec.dapm_widgets);
+ INIT_LIST_HEAD(&aic26->codec.dapm_paths);
+ aic26->codec.reg_cache_size = sizeof(aic26->reg_cache);
+ aic26->codec.reg_cache = aic26->reg_cache;
+
+ /* Reset the codec to power on defaults */
+ aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00);
+
+ /* Power up CODEC */
+ aic26_reg_write(&aic26->codec, AIC26_REG_POWER_CTRL, 0);
+
+ /* Audio Control 3 (master mode, fsref rate) */
+ reg = aic26_reg_read(&aic26->codec, AIC26_REG_AUDIO_CTRL3);
+ reg &= ~0xf800;
+ reg |= 0x0800; /* set master mode */
+ aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL3, reg);
+
+ /* Fill page 2 register cache */
+ for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
+ aic26_reg_read(&aic26->codec, AIC26_PAGE_ADDR(2, i));
+
+ /* Register the sysfs files for debugging */
+ /* Create SysFS files */
+ rc = device_create_file(&spi->dev, &dev_attr_regs);
+ rc |= device_create_file(&spi->dev, &dev_attr_regs_cache);
+ 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)
+ /* Tell the of_soc helper about this codec */
+ of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
+ spi->dev.archdata.of_node);
+#endif
+
+ dev_dbg(&spi->dev, "SPI device initialized\n");
+ return 0;
+}
+
+static int aic26_spi_remove(struct spi_device *spi)
+{
+ struct aic26 *aic26 = dev_get_drvdata(&spi->dev);
+
+ kfree(aic26);
+
+ return 0;
+}
+
+static struct spi_driver aic26_spi = {
+ .driver = {
+ .name = "tlv320aic26",
+ .owner = THIS_MODULE,
+ },
+ .probe = aic26_spi_probe,
+ .remove = aic26_spi_remove,
+};
+
+static int __init aic26_init(void)
+{
+ return spi_register_driver(&aic26_spi);
+}
+module_init(aic26_init);
+
+static void __exit aic26_exit(void)
+{
+ spi_unregister_driver(&aic26_spi);
+}
+module_exit(aic26_exit);
diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h
new file mode 100644
index 0000000..9edb8e9
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic26.h
@@ -0,0 +1,103 @@
+/*
+ * Texas Instruments TLV320AIC26 low power audio CODEC
+ * register definitions
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#ifndef _TLV320AIC16_H_
+#define _TLV320AIC16_H_
+
+/* AIC26 Registers */
+#define AIC26_READ_COMMAND_WORD(addr) ((1 << 15) | (addr << 5))
+#define AIC26_WRITE_COMMAND_WORD(addr) ((0 << 15) | (addr << 5))
+#define AIC26_PAGE_ADDR(page, offset) ((page << 6) | offset)
+#define AIC26_NUM_REGS AIC26_PAGE_ADDR(3, 0)
+#define AIC26_REG_CACHE_SIZE (0x20) /* only page 2 cached */
+#define AIC26_REG_IS_CACHED(addr) ((addr & ~0x1f) == (2 << 6))
+#define AIC26_REG_CACHE_ADDR(addr) (addr & 0x1f)
+
+/* Page 0: Auxillary data registers */
+#define AIC26_REG_BAT1 AIC26_PAGE_ADDR(0, 0x05)
+#define AIC26_REG_BAT2 AIC26_PAGE_ADDR(0, 0x06)
+#define AIC26_REG_AUX AIC26_PAGE_ADDR(0, 0x07)
+#define AIC26_REG_TEMP1 AIC26_PAGE_ADDR(0, 0x09)
+#define AIC26_REG_TEMP2 AIC26_PAGE_ADDR(0, 0x0A)
+
+/* Page 1: Auxillary control registers */
+#define AIC26_REG_AUX_ADC AIC26_PAGE_ADDR(1, 0x00)
+#define AIC26_REG_STATUS AIC26_PAGE_ADDR(1, 0x01)
+#define AIC26_REG_REFERENCE AIC26_PAGE_ADDR(1, 0x03)
+#define AIC26_REG_RESET AIC26_PAGE_ADDR(1, 0x04)
+
+/* Page 2: Audio control registers */
+#define AIC26_REG_AUDIO_CTRL1 AIC26_PAGE_ADDR(2, 0x00)
+#define AIC26_REG_ADC_GAIN AIC26_PAGE_ADDR(2, 0x01)
+#define AIC26_REG_DAC_GAIN AIC26_PAGE_ADDR(2, 0x02)
+#define AIC26_REG_SIDETONE AIC26_PAGE_ADDR(2, 0x03)
+#define AIC26_REG_AUDIO_CTRL2 AIC26_PAGE_ADDR(2, 0x04)
+#define AIC26_REG_POWER_CTRL AIC26_PAGE_ADDR(2, 0x05)
+#define AIC26_REG_AUDIO_CTRL3 AIC26_PAGE_ADDR(2, 0x06)
+
+#define AIC26_REG_FILTER_COEFF_L_N0 AIC26_PAGE_ADDR(2, 0x07)
+#define AIC26_REG_FILTER_COEFF_L_N1 AIC26_PAGE_ADDR(2, 0x08)
+#define AIC26_REG_FILTER_COEFF_L_N2 AIC26_PAGE_ADDR(2, 0x09)
+#define AIC26_REG_FILTER_COEFF_L_N3 AIC26_PAGE_ADDR(2, 0x0A)
+#define AIC26_REG_FILTER_COEFF_L_N4 AIC26_PAGE_ADDR(2, 0x0B)
+#define AIC26_REG_FILTER_COEFF_L_N5 AIC26_PAGE_ADDR(2, 0x0C)
+#define AIC26_REG_FILTER_COEFF_L_D1 AIC26_PAGE_ADDR(2, 0x0D)
+#define AIC26_REG_FILTER_COEFF_L_D2 AIC26_PAGE_ADDR(2, 0x0E)
+#define AIC26_REG_FILTER_COEFF_L_D4 AIC26_PAGE_ADDR(2, 0x0F)
+#define AIC26_REG_FILTER_COEFF_L_D5 AIC26_PAGE_ADDR(2, 0x10)
+#define AIC26_REG_FILTER_COEFF_R_N0 AIC26_PAGE_ADDR(2, 0x11)
+#define AIC26_REG_FILTER_COEFF_R_N1 AIC26_PAGE_ADDR(2, 0x12)
+#define AIC26_REG_FILTER_COEFF_R_N2 AIC26_PAGE_ADDR(2, 0x13)
+#define AIC26_REG_FILTER_COEFF_R_N3 AIC26_PAGE_ADDR(2, 0x14)
+#define AIC26_REG_FILTER_COEFF_R_N4 AIC26_PAGE_ADDR(2, 0x15)
+#define AIC26_REG_FILTER_COEFF_R_N5 AIC26_PAGE_ADDR(2, 0x16)
+#define AIC26_REG_FILTER_COEFF_R_D1 AIC26_PAGE_ADDR(2, 0x17)
+#define AIC26_REG_FILTER_COEFF_R_D2 AIC26_PAGE_ADDR(2, 0x18)
+#define AIC26_REG_FILTER_COEFF_R_D4 AIC26_PAGE_ADDR(2, 0x19)
+#define AIC26_REG_FILTER_COEFF_R_D5 AIC26_PAGE_ADDR(2, 0x1A)
+
+#define AIC26_REG_PLL_PROG1 AIC26_PAGE_ADDR(2, 0x1B)
+#define AIC26_REG_PLL_PROG2 AIC26_PAGE_ADDR(2, 0x1C)
+#define AIC26_REG_AUDIO_CTRL4 AIC26_PAGE_ADDR(2, 0x1D)
+#define AIC26_REG_AUDIO_CTRL5 AIC26_PAGE_ADDR(2, 0x1E)
+
+#define AIC26_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)
+#define AIC26_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |\
+ SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
+
+/* fsref dividers; used in register 'Audio Control 1' */
+enum aic26_divisors {
+ AIC26_DIV_1 = 0,
+ AIC26_DIV_1_5 = 1,
+ AIC26_DIV_2 = 2,
+ AIC26_DIV_3 = 3,
+ AIC26_DIV_4 = 4,
+ AIC26_DIV_5 = 5,
+ AIC26_DIV_5_5 = 6,
+ AIC26_DIV_6 = 7,
+};
+
+/* Digital data format */
+enum aic26_datfm {
+ AIC26_DATFM_I2S = 0 << 8,
+ AIC26_DATFM_DSP = 1 << 8,
+ AIC26_DATFM_RIGHTJ = 2 << 8, /* right justified */
+ AIC26_DATFM_LEFTJ = 3 << 8, /* left justified */
+};
+
+/* Sample word length in bits; used in register 'Audio Control 1' */
+enum aic26_wlen {
+ AIC26_WLEN_16 = 0 << 10,
+ AIC26_WLEN_20 = 1 << 10,
+ AIC26_WLEN_24 = 2 << 10,
+ AIC26_WLEN_32 = 3 << 10,
+};
+
+#endif /* _TLV320AIC16_H_ */
^ permalink raw reply related [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver
2008-07-12 8:39 ` [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver Grant Likely
@ 2008-07-12 18:10 ` Mark Brown
2008-07-12 18:14 ` Grant Likely
2008-07-14 11:45 ` Mark Brown
` (3 subsequent siblings)
4 siblings, 1 reply; 46+ messages in thread
From: Mark Brown @ 2008-07-12 18:10 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Sat, Jul 12, 2008 at 02:39:39AM -0600, Grant Likely wrote:
> ASoC Codec driver for the TLV320AIC26 device. This driver uses the ASoC
> v1 API, so I don't expect it to get merged as-is, but I want to get it
> out there for review.
I've not reviewed this revision of these drivers yet but I just wanted
to point out that there's absoluely no problem with merging v1 drivers -
so long as a driver uses the existing merged APIs there's no issue from
that point of view.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver
2008-07-12 18:10 ` [alsa-devel] " Mark Brown
@ 2008-07-12 18:14 ` Grant Likely
0 siblings, 0 replies; 46+ messages in thread
From: Grant Likely @ 2008-07-12 18:14 UTC (permalink / raw)
To: Grant Likely, linuxppc-dev, alsa-devel, liam.girdwood, jonsmirl
On Sat, Jul 12, 2008 at 12:10 PM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Sat, Jul 12, 2008 at 02:39:39AM -0600, Grant Likely wrote:
>
>> ASoC Codec driver for the TLV320AIC26 device. This driver uses the ASoC
>> v1 API, so I don't expect it to get merged as-is, but I want to get it
>> out there for review.
>
> I've not reviewed this revision of these drivers yet but I just wanted
> to point out that there's absoluely no problem with merging v1 drivers -
> so long as a driver uses the existing merged APIs there's no issue from
> that point of view.
Oops, I forgot to update my commit messages. I'll probably repost v3
of the series this evening and I'll fix this.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver
2008-07-12 8:39 ` [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver Grant Likely
2008-07-12 18:10 ` [alsa-devel] " Mark Brown
@ 2008-07-14 11:45 ` Mark Brown
2008-07-18 6:29 ` Grant Likely
2008-07-15 7:57 ` dinesh
` (2 subsequent siblings)
4 siblings, 1 reply; 46+ messages in thread
From: Mark Brown @ 2008-07-14 11:45 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Sat, Jul 12, 2008 at 02:39:39AM -0600, Grant Likely wrote:
> ASoC Codec driver for the TLV320AIC26 device. This driver uses the ASoC
> v1 API, so I don't expect it to get merged as-is, but I want to get it
> out there for review.
This looks basically good - most of the issues below are nitpicky.
> + /* Configure PLL */
> + pval = 1;
> + jval = (fsref == 44100) ? 7 : 8;
> + dval = (fsref == 44100) ? 5264 : 1920;
> + qval = 0;
> + reg = 0x8000 | qval << 11 | pval << 8 | jval << 2;
> + aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg);
> + reg = dval << 2;
> + aic26_reg_write(codec, AIC26_REG_PLL_PROG2, reg);
Does the PLL configuration not depend on the input clock frequency? You
have a set_sysclk() method to configure the MCLK supplied but the driver
never appears to reference the value anywhere.
> + /* Power up CODEC */
> + aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0);
As discussed this should probably just be removed from hw_params().
> +static int aic26_set_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt)
> +{
> + /* interface format */
> + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> + case SND_SOC_DAIFMT_I2S: aic26->datfm = AIC26_DATFM_I2S; break;
> + case SND_SOC_DAIFMT_DSP_A: aic26->datfm = AIC26_DATFM_DSP; break;
> + case SND_SOC_DAIFMT_RIGHT_J: aic26->datfm = AIC26_DATFM_RIGHTJ; break;
> + case SND_SOC_DAIFMT_LEFT_J: aic26->datfm = AIC26_DATFM_LEFTJ; break;
> + default: dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
> + }
I'm having a hard time liking this indentation style. It's not an
obstacle to merging but it doesn't really help legibility - there's not
enough white space and once you have a non-standard line like the
default: one.
> +static const char *aic26_capture_src_text[] = {"Mic", "Aux"};
> +static const struct soc_enum aic26_capture_src_enum =
> + SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12,2, aic26_capture_src_text);
checkpatch complains about the 12,2 here and a bunch of other stuff -
ALSA is generally very strict about that.
> + SOC_SINGLE("Keyclick activate", AIC26_REG_AUDIO_CTRL2, 15, 0x1, 0),
> + SOC_SINGLE("Keyclick amplitude", AIC26_REG_AUDIO_CTRL2, 12, 0x7, 0),
> + SOC_SINGLE("Keyclick frequency", AIC26_REG_AUDIO_CTRL2, 8, 0x7, 0),
> + SOC_SINGLE("Keyclick period", AIC26_REG_AUDIO_CTRL2, 4, 0xf, 0),
This configuration is also exposed via a sysfs file, including some of
the configurability. Exposing the information via sysfs isn't a
particular problem but allowing it to be written to without going
through ALSA seems wrong.
> +static ssize_t aic26_regs_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
As discussed this is replicating the existing codec register display
sysfs file.
> +#if defined(CONFIG_SND_SOC_OF)
> + /* Tell the of_soc helper about this codec */
> + of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
> + spi->dev.archdata.of_node);
> +#endif
CONFIG_SND_SOC_OF could be a module - this needs to also check for it
being a module.
> +#define AIC26_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)
> +#define AIC26_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |\
> + SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
These are usually kept in the driver code.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 2/3] ALSA SoC: Add mpc5200-psc I2S driver
2008-07-12 8:39 ` [PATCH v2 2/3] ALSA SoC: Add mpc5200-psc I2S driver Grant Likely
@ 2008-07-14 12:10 ` Mark Brown
0 siblings, 0 replies; 46+ messages in thread
From: Mark Brown @ 2008-07-14 12:10 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Sat, Jul 12, 2008 at 02:39:34AM -0600, Grant Likely wrote:
> This is an I2S bus driver for the MPC5200 PSC device. It is probably
> will not be merged as-is because it uses v1 of the ASoC API, but I want
> to get it out there for comments.
Looks basically good. A few things below, plus you probably want to run
checkpatch over it.
> +/* Bestcomm DMA irq handler */
> +static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream)
> +{
> + struct psc_i2s_stream *s = _psc_i2s_stream;
> +
> + //spin_lock(&s->psc_i2s->lock);
Either the lock is needed or it isn't :) .
> + * 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)
> +{
The comment here doesn't seem to reflect what the function does - it
looks to just unconditionally reinitialise the controller with things
like this:
> + /* Disable all interrupts and reset the PSC */
> + out_be16(®s->mpc52xx_psc_imr, 0);
> + out_8(®s->command, 3 << 4); /* reset transmitter */
> + out_8(®s->command, 2 << 4); /* reset receiver */
> + out_8(®s->command, 1 << 4); /* reset mode */
> + out_8(®s->command, 4 << 4); /* reset error */
which I'd imagine might upset running streams?
> +static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
> +{
> + case SNDRV_PCM_TRIGGER_STOP:
> + case SNDRV_PCM_TRIGGER_STOP:
> + default:
> + dev_dbg(psc_i2s->dev, "invalid command\n");
> + return -EINVAL;
> + }
This doesn't handle the pause, suspend, resume or pause_release
triggers. If there's really nothing to do for those it should ignore
them, especially given the default: behaviour.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-12 8:39 [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers Grant Likely
2008-07-12 8:39 ` [PATCH v2 2/3] ALSA SoC: Add mpc5200-psc I2S driver Grant Likely
2008-07-12 8:39 ` [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver Grant Likely
@ 2008-07-14 13:49 ` Mark Brown
2008-07-14 14:13 ` Jon Smirl
2008-07-14 17:06 ` Grant Likely
2008-07-14 14:16 ` Anton Vorontsov
3 siblings, 2 replies; 46+ messages in thread
From: Mark Brown @ 2008-07-14 13:49 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Sat, Jul 12, 2008 at 02:39:29AM -0600, Grant Likely wrote:
> Simple utility layer for creating ASoC machine instances based on data
> in the OpenFirmware device tree. OF aware platform drivers and codec
> drivers register themselves with this framework and the framework
> automatically instantiates a machine driver.
Ideally someone from the PowerPC community would sign off on this -
given the nature and volume of discussion people obviously have very
strong opinions about how machine drivers should be done so I'd really
like to see some community buy in for something like this. From an ASoC
point of view if this works it's fine.
> This is most likely temporary glue code to work around limitations in
> the ASoC v1 framework. I expect ASoC v2 won't need this.
It will need some way of providing a machine driver, generic (like this
one) or otherwise.
> +static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
> +{
> + struct platform_device *pdev;
> + int rc;
> +
> + /* Only register the device if both the codec and platform have
> + * been registered */
> + if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
> + return;
> +
> + pr_info("platform<-->codec match achieved; registering machine\n");
So what this does is add an extremely simple machine driver which
matches up the first DAI on a single codec and platform with no facility
for setting up any configurable clocking or anything? This is fine in
so far as it goes but it's going to work for very few systems as it is -
most codecs will need some additional configuration. This could be
added later, though.
Given this it might be worth renaming it to something less generic and
perhaps pushing it down into an of directory below the main ASoC
directory to parallel existing machine drivers. I'm happy with the code
from an ASoC point of view.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 13:49 ` [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers Mark Brown
@ 2008-07-14 14:13 ` Jon Smirl
2008-07-14 15:05 ` Mark Brown
2008-07-14 15:51 ` Timur Tabi
2008-07-14 17:06 ` Grant Likely
1 sibling, 2 replies; 46+ messages in thread
From: Jon Smirl @ 2008-07-14 14:13 UTC (permalink / raw)
To: Grant Likely, linuxppc-dev, alsa-devel, liam.girdwood, jonsmirl
On 7/14/08, Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:
> On Sat, Jul 12, 2008 at 02:39:29AM -0600, Grant Likely wrote:
>
> > Simple utility layer for creating ASoC machine instances based on data
> > in the OpenFirmware device tree. OF aware platform drivers and codec
> > drivers register themselves with this framework and the framework
> > automatically instantiates a machine driver.
>
>
> Ideally someone from the PowerPC community would sign off on this -
> given the nature and volume of discussion people obviously have very
> strong opinions about how machine drivers should be done so I'd really
> like to see some community buy in for something like this. From an ASoC
> point of view if this works it's fine.
Grant is one of the core PowerPC developers. There's no big
disagreement on the driver model, there just isn't a clean solution
for building a PowerPC ASoC driver under ASoC v1. The ASoC v1 driver
model is simply not compatible with the PowerPC device tree model.
That's why all of this glue code is needed.
Hopefully we can get the driver model sorted out in v2. If the ASoC
driver model is fixed all of this glue code disappears.
The PowerPC side isn't without fault too. PowerPC still doesn't have a
good way to load the fabric/machine driver.
Which are we going to call it, fabric or machine? I had been working
on the Apple code in sound/aoa. It is called fabric in that code. The
equivalent driver is called machine in ASoC v1.
>
>
> > This is most likely temporary glue code to work around limitations in
> > the ASoC v1 framework. I expect ASoC v2 won't need this.
>
>
> It will need some way of providing a machine driver, generic (like this
> one) or otherwise.
>
>
> > +static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
> > +{
> > + struct platform_device *pdev;
> > + int rc;
> > +
> > + /* Only register the device if both the codec and platform have
> > + * been registered */
> > + if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
> > + return;
> > +
> > + pr_info("platform<-->codec match achieved; registering machine\n");
>
>
> So what this does is add an extremely simple machine driver which
> matches up the first DAI on a single codec and platform with no facility
> for setting up any configurable clocking or anything? This is fine in
> so far as it goes but it's going to work for very few systems as it is -
> most codecs will need some additional configuration. This could be
> added later, though.
>
> Given this it might be worth renaming it to something less generic and
> perhaps pushing it down into an of directory below the main ASoC
> directory to parallel existing machine drivers. I'm happy with the code
> from an ASoC point of view.
>
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-12 8:39 [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers Grant Likely
` (2 preceding siblings ...)
2008-07-14 13:49 ` [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers Mark Brown
@ 2008-07-14 14:16 ` Anton Vorontsov
2008-07-14 17:11 ` Grant Likely
3 siblings, 1 reply; 46+ messages in thread
From: Anton Vorontsov @ 2008-07-14 14:16 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Sat, Jul 12, 2008 at 02:39:29AM -0600, Grant Likely wrote:
> From: Grant Likely <grant.likely@secretlab.ca>
>
> Simple utility layer for creating ASoC machine instances based on data
> in the OpenFirmware device tree. OF aware platform drivers and codec
> drivers register themselves with this framework and the framework
> automatically instantiates a machine driver.
>
> This is most likely temporary glue code to work around limitations in
> the ASoC v1 framework. I expect ASoC v2 won't need this.
> ---
[...]
> --- /dev/null
> +++ b/sound/soc/soc-of.c
It's quite inconvenient to spread the firmware-specific bits over the
whole kernel source tree. So, can we place this in driver/of/, just as
we did for i2c, spi and gpio?
> @@ -0,0 +1,171 @@
> +/*
> + * OF helpers for ALSA SoC Layer
> + *
> + * Copyright (C) 2008, Secret Lab Technologies Ltd.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/init.h>
> +#include <linux/delay.h>
> +#include <linux/pm.h>
> +#include <linux/bitops.h>
> +#include <linux/platform_device.h>
> +#include <linux/of.h>
> +#include <sound/core.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +#include <sound/soc-of.h>
> +#include <sound/initval.h>
> +
> +MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
> +
> +static DEFINE_MUTEX(of_snd_soc_mutex);
> +static LIST_HEAD(of_snd_soc_device_list);
> +static int of_snd_soc_next_index;
> +
> +struct of_snd_soc_device {
> + int id;
> + struct list_head list;
> + struct snd_soc_device device;
> + struct snd_soc_machine machine;
> + struct snd_soc_dai_link dai_link;
> + struct platform_device *pdev;
> + struct device_node *platform_node;
> + struct device_node *codec_node;
> +};
> +
> +static struct snd_soc_ops of_snd_soc_ops = {
> +};
> +
> +static struct of_snd_soc_device *
> +of_snd_soc_get_device(struct device_node *codec_node)
> +{
> + struct of_snd_soc_device *of_soc;
> +
> + list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
> + if (of_soc->codec_node == codec_node)
> + return of_soc;
> + }
> +
> + of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
> + if (!of_soc)
> + return NULL;
> +
> + /* 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->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);
> +
> + return of_soc;
> +}
> +
> +static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
> +{
> + struct platform_device *pdev;
> + int rc;
> +
> + /* Only register the device if both the codec and platform have
> + * been registered */
> + if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
> + return;
> +
> + pr_info("platform<-->codec match achieved; registering machine\n");
> +
> + pdev = platform_device_alloc("soc-audio", of_soc->id);
> + if (!pdev) {
> + pr_err("of_soc: platform_device_alloc() failed\n");
> + return;
> + }
> +
> + pdev->dev.platform_data = of_soc;
> + platform_set_drvdata(pdev, &of_soc->device);
> + of_soc->device.dev = &pdev->dev;
> +
> + /* The ASoC device is complete; register it */
> + rc = platform_device_add(pdev);
> + if (rc) {
> + pr_err("of_soc: platform_device_add() failed\n");
> + return;
> + }
> +
> +}
> +
> +int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
> + void *codec_data, struct snd_soc_codec_dai *dai,
> + struct device_node *node)
> +{
> + struct of_snd_soc_device *of_soc;
> + int rc = 0;
> +
> + pr_info("registering ASoC codec driver: %s\n", node->full_name);
> +
> + mutex_lock(&of_snd_soc_mutex);
> + of_soc = of_snd_soc_get_device(node);
> + if (!of_soc) {
> + rc = -ENOMEM;
> + goto out;
> + }
> +
> + /* Store the codec data */
> + of_soc->device.codec_data = codec_data;
> + of_soc->device.codec_dev = codec_dev;
> + of_soc->dai_link.name = node->name;
> + of_soc->dai_link.stream_name = node->name;
> + of_soc->dai_link.codec_dai = dai;
> +
> + /* Now try to register the SoC device */
> + of_snd_soc_register_device(of_soc);
> +
> + out:
> + mutex_unlock(&of_snd_soc_mutex);
> + return rc;
> +}
> +EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
> +
> +int of_snd_soc_register_platform(struct snd_soc_platform *platform,
> + struct device_node *node,
> + struct snd_soc_cpu_dai *cpu_dai)
> +{
> + struct of_snd_soc_device *of_soc;
> + struct device_node *codec_node;
> + const phandle *handle;
> + int len, rc = 0;
> +
> + pr_info("registering ASoC platform driver: %s\n", node->full_name);
> +
> + handle = of_get_property(node, "codec-handle", &len);
> + if (!handle || len < sizeof(handle))
> + return -ENODEV;
> + codec_node = of_find_node_by_phandle(*handle);
> + if (!codec_node)
> + return -ENODEV;
> + pr_info("looking for codec: %s\n", codec_node->full_name);
> +
> + mutex_lock(&of_snd_soc_mutex);
> + of_soc = of_snd_soc_get_device(codec_node);
> + if (!of_soc) {
> + rc = -ENOMEM;
> + goto out;
> + }
> +
> + of_soc->platform_node = node;
> + of_soc->dai_link.cpu_dai = cpu_dai;
> + 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);
> +
> + out:
> + mutex_unlock(&of_snd_soc_mutex);
> + return rc;
> +}
> +EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);
Thanks,
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 14:13 ` Jon Smirl
@ 2008-07-14 15:05 ` Mark Brown
2008-07-14 16:14 ` Timur Tabi
2008-07-14 15:51 ` Timur Tabi
1 sibling, 1 reply; 46+ messages in thread
From: Mark Brown @ 2008-07-14 15:05 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Mon, Jul 14, 2008 at 10:13:14AM -0400, Jon Smirl wrote:
> On 7/14/08, Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:
> > Ideally someone from the PowerPC community would sign off on this -
> > given the nature and volume of discussion people obviously have very
> Grant is one of the core PowerPC developers. There's no big
OK, fair enough...
> Hopefully we can get the driver model sorted out in v2. If the ASoC
> driver model is fixed all of this glue code disappears.
> The PowerPC side isn't without fault too. PowerPC still doesn't have a
> good way to load the fabric/machine driver.
I'm finding it difficult to square these two statements - from an ASoC
point of view the main thing this patch is doing is adding a machine
driver and that's not something that's going to go away. With version 2
you will get the wait for all components to come on-line logic that's
implemented here from the ASoC core but that doesn't remove the need for
a machine driver to tell the core what to wait for and arrange any
machine specific things like clocking. It's this debate about machine
drivers that makes me nervous here.
Like I say, from an ASoC point of view it's not an issue and the current
approach is fine.
> Which are we going to call it, fabric or machine? I had been working
> on the Apple code in sound/aoa. It is called fabric in that code. The
> equivalent driver is called machine in ASoC v1.
ASoC has always called it a machine driver.
> > > This is most likely temporary glue code to work around limitations in
> > > the ASoC v1 framework. I expect ASoC v2 won't need this.
> >
> >
> > It will need some way of providing a machine driver, generic (like this
> > one) or otherwise.
[BTW, it'd be helpful if you could delete unreferenced quotes when you
reply - it makes things much easier to read, especially when reviewing
lengthy patches. Unfortunately the GMail UI encourages doing this :(]
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 14:13 ` Jon Smirl
2008-07-14 15:05 ` Mark Brown
@ 2008-07-14 15:51 ` Timur Tabi
1 sibling, 0 replies; 46+ messages in thread
From: Timur Tabi @ 2008-07-14 15:51 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
Jon Smirl wrote:
> Which are we going to call it, fabric or machine?
Fabric.
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 15:05 ` Mark Brown
@ 2008-07-14 16:14 ` Timur Tabi
2008-07-14 16:27 ` Grant Likely
2008-07-14 16:53 ` Mark Brown
0 siblings, 2 replies; 46+ messages in thread
From: Timur Tabi @ 2008-07-14 16:14 UTC (permalink / raw)
To: Jon Smirl, Grant Likely, linuxppc-dev, alsa-devel, liam.girdwood
Mark Brown wrote:
>> The PowerPC side isn't without fault too. PowerPC still doesn't have a
>> good way to load the fabric/machine driver.
>
> I'm finding it difficult to square these two statements - from an ASoC
> point of view the main thing this patch is doing is adding a machine
> driver and that's not something that's going to go away.
Jon's concern is that there is no straightforward way to build a kernel with
multiple fabric drivers and have the right one chosen via the device tree. This
is just a limitation of the device tree model, and no one has come up with a
good solution yet.
The problem still exists in ASoC V2. However, it's not anything that ASoC
itself needs to be concerned with. It's purely a PowerPC problem.
>> Which are we going to call it, fabric or machine? I had been working
>> on the Apple code in sound/aoa. It is called fabric in that code. The
>> equivalent driver is called machine in ASoC v1.
>
> ASoC has always called it a machine driver.
Wait, I thought it's supposed to be called a fabric driver now? On PowerPC, it
should be called a fabric driver because we already have machine drivers.
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 16:14 ` Timur Tabi
@ 2008-07-14 16:27 ` Grant Likely
2008-07-14 16:53 ` Mark Brown
1 sibling, 0 replies; 46+ messages in thread
From: Grant Likely @ 2008-07-14 16:27 UTC (permalink / raw)
To: Timur Tabi; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Mon, Jul 14, 2008 at 10:14 AM, Timur Tabi <timur@freescale.com> wrote:
> Mark Brown wrote:
>
>>> The PowerPC side isn't without fault too. PowerPC still doesn't have a
>>> good way to load the fabric/machine driver.
>>
>> I'm finding it difficult to square these two statements - from an ASoC
>> point of view the main thing this patch is doing is adding a machine
>> driver and that's not something that's going to go away.
>
> Jon's concern is that there is no straightforward way to build a kernel with
> multiple fabric drivers and have the right one chosen via the device tree. This
> is just a limitation of the device tree model, and no one has come up with a
> good solution yet.
>
> The problem still exists in ASoC V2. However, it's not anything that ASoC
> itself needs to be concerned with. It's purely a PowerPC problem.
It's purely an *OF Device Tree* problem. PowerPC isn't the only
platform using the device tree. :-)
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 16:14 ` Timur Tabi
2008-07-14 16:27 ` Grant Likely
@ 2008-07-14 16:53 ` Mark Brown
2008-07-14 17:21 ` Grant Likely
1 sibling, 1 reply; 46+ messages in thread
From: Mark Brown @ 2008-07-14 16:53 UTC (permalink / raw)
To: Timur Tabi; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Mon, Jul 14, 2008 at 11:14:41AM -0500, Timur Tabi wrote:
> Mark Brown wrote:
> > I'm finding it difficult to square these two statements - from an ASoC
> > point of view the main thing this patch is doing is adding a machine
> > driver and that's not something that's going to go away.
> Jon's concern is that there is no straightforward way to build a kernel with
> multiple fabric drivers and have the right one chosen via the device tree. This
> is just a limitation of the device tree model, and no one has come up with a
> good solution yet.
Indeed - I understand what the problem you guys have is, I just want to
make sure that there is a reasonable consensus among the PowerPC people
that this approach is OK to go in and won't create ructions. The lack
of resolution on this issue makes me nervous about any proposed solution
where I haven't seen any explicit indication that the community is OK
with it.
Incidentally, nobody ever really commented on my suggestion to do
something DMI-like - you've already got the board type information
present in the device trees (in the model and compatible information in
the root nodes), all that's needed is an API to allow matching on it.
> The problem still exists in ASoC V2. However, it's not anything that ASoC
> itself needs to be concerned with. It's purely a PowerPC problem.
Right, I just want to be clear that you guys all understand what this
code does and that there won't be too many complaints after the fact.
> > ASoC has always called it a machine driver.
> Wait, I thought it's supposed to be called a fabric driver now? On PowerPC, it
> should be called a fabric driver because we already have machine drivers.
I don't mind - you can call it what you like inside PowerPC-specific
code.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 13:49 ` [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers Mark Brown
2008-07-14 14:13 ` Jon Smirl
@ 2008-07-14 17:06 ` Grant Likely
2008-07-14 17:16 ` Mark Brown
1 sibling, 1 reply; 46+ messages in thread
From: Grant Likely @ 2008-07-14 17:06 UTC (permalink / raw)
To: Grant Likely, linuxppc-dev, alsa-devel, liam.girdwood, jonsmirl
On Mon, Jul 14, 2008 at 7:49 AM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Sat, Jul 12, 2008 at 02:39:29AM -0600, Grant Likely wrote:
>> +static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
>> +{
>> + struct platform_device *pdev;
>> + int rc;
>> +
>> + /* Only register the device if both the codec and platform have
>> + * been registered */
>> + if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
>> + return;
>> +
>> + pr_info("platform<-->codec match achieved; registering machine\n");
>
> So what this does is add an extremely simple machine driver which
> matches up the first DAI on a single codec and platform with no facility
> for setting up any configurable clocking or anything? This is fine in
> so far as it goes but it's going to work for very few systems as it is -
> most codecs will need some additional configuration. This could be
> added later, though.
Yes, that is pretty much exactly what it is. When I wrote this my
goal was just to get something working that had some semblance of
cleanliness. Since it is now looking like something that could get
merged, I'll clean up the documentation describing exactly what it is
and what the limitations are. I fully expect that if others find it
useful then they will need to extend it to extract additional
configuration information out of the device tree.
That being said, I expect this code to be completely rewritten when
ASoC v2 hits mainline. Most of the code is devoted to matching
platforms with codecs. The mechanism will be completely different
when the ASoC layer handles making sure all devices are present before
setting up the machine driver. I expect that some machines can be
handled with some form of generic of-asoc driver, while more complex
ones will need custom code.
> Given this it might be worth renaming it to something less generic and
> perhaps pushing it down into an of directory below the main ASoC
> directory to parallel existing machine drivers. I'm happy with the code
> from an ASoC point of view.
I'm okay with that. How about fsl/mpc5200-of-machine.c for now?
(only the mpc5200 i2s driver uses it at the moment). It can always be
renamed if other folks want to use it for other chips.
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 14:16 ` Anton Vorontsov
@ 2008-07-14 17:11 ` Grant Likely
0 siblings, 0 replies; 46+ messages in thread
From: Grant Likely @ 2008-07-14 17:11 UTC (permalink / raw)
To: avorontsov; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Mon, Jul 14, 2008 at 8:16 AM, Anton Vorontsov
<avorontsov@ru.mvista.com> wrote:
> On Sat, Jul 12, 2008 at 02:39:29AM -0600, Grant Likely wrote:
>> --- /dev/null
>> +++ b/sound/soc/soc-of.c
>
> It's quite inconvenient to spread the firmware-specific bits over the
> whole kernel source tree. So, can we place this in driver/of/, just as
> we did for i2c, spi and gpio?
This isn't any more specific than say how device drivers are specific
for particular devices. This is an ASoC machine driver and should
live with all the other ASoC machine drivers.
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 17:06 ` Grant Likely
@ 2008-07-14 17:16 ` Mark Brown
2008-07-14 17:22 ` Grant Likely
2008-07-18 7:17 ` Grant Likely
0 siblings, 2 replies; 46+ messages in thread
From: Mark Brown @ 2008-07-14 17:16 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Mon, Jul 14, 2008 at 11:06:34AM -0600, Grant Likely wrote:
> I'm okay with that. How about fsl/mpc5200-of-machine.c for now?
> (only the mpc5200 i2s driver uses it at the moment). It can always be
> renamed if other folks want to use it for other chips.
That seems reasonable so long as you're happy with it, though it does
seem to be going to the other extreme in terms of broadness :)
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 16:53 ` Mark Brown
@ 2008-07-14 17:21 ` Grant Likely
2008-07-14 18:36 ` Mark Brown
0 siblings, 1 reply; 46+ messages in thread
From: Grant Likely @ 2008-07-14 17:21 UTC (permalink / raw)
To: Timur Tabi, Jon Smirl, Grant Likely, linuxppc-dev, alsa-devel,
liam.girdwood
On Mon, Jul 14, 2008 at 10:53 AM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Mon, Jul 14, 2008 at 11:14:41AM -0500, Timur Tabi wrote:
>> Mark Brown wrote:
>
>> > I'm finding it difficult to square these two statements - from an ASoC
>> > point of view the main thing this patch is doing is adding a machine
>> > driver and that's not something that's going to go away.
>
>> Jon's concern is that there is no straightforward way to build a kernel with
>> multiple fabric drivers and have the right one chosen via the device tree. This
>> is just a limitation of the device tree model, and no one has come up with a
>> good solution yet.
>
> Indeed - I understand what the problem you guys have is, I just want to
> make sure that there is a reasonable consensus among the PowerPC people
> that this approach is OK to go in and won't create ructions. The lack
> of resolution on this issue makes me nervous about any proposed solution
> where I haven't seen any explicit indication that the community is OK
> with it.
>
> Incidentally, nobody ever really commented on my suggestion to do
> something DMI-like
I'm feeling stupid; what does "DMI" stand for?
> - you've already got the board type information
> present in the device trees (in the model and compatible information in
> the root nodes), all that's needed is an API to allow matching on it.
Yes, we have APIs for matching against device trees. Personally, I'm
leaning towards having the powerpc platform code
(arch/powerpc/platforms/* stuff; not ASoC platform stuff) register a
platform device for the machine driver and let as many machine drivers
as needed be written. Hopefully we'll be able to do at least one
generic machine driver that will be usable by most PowerPC boards, but
I don't think it is a requirement or even realistic to shoehorn all
powerpc sound circuits into a single driver.
>> The problem still exists in ASoC V2. However, it's not anything that ASoC
>> itself needs to be concerned with. It's purely a PowerPC problem.
>
> Right, I just want to be clear that you guys all understand what this
> code does and that there won't be too many complaints after the fact.
Shouldn't be. I'm certainly not pushing this as the end-all be-all
powerpc sound machine driver.
>> > ASoC has always called it a machine driver.
>
>> Wait, I thought it's supposed to be called a fabric driver now? On PowerPC, it
>> should be called a fabric driver because we already have machine drivers.
>
> I don't mind - you can call it what you like inside PowerPC-specific
> code.
Oh help! Don't tell us that! Otherwise we'll always be talking
across purposes. When ambiguous, let's just be sure to always refer
to them as "ASoC machine drivers". :-)
Cheers,
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 17:16 ` Mark Brown
@ 2008-07-14 17:22 ` Grant Likely
2008-07-18 7:17 ` Grant Likely
1 sibling, 0 replies; 46+ messages in thread
From: Grant Likely @ 2008-07-14 17:22 UTC (permalink / raw)
To: Grant Likely, linuxppc-dev, alsa-devel, liam.girdwood, jonsmirl
On Mon, Jul 14, 2008 at 11:16 AM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Mon, Jul 14, 2008 at 11:06:34AM -0600, Grant Likely wrote:
>
>> I'm okay with that. How about fsl/mpc5200-of-machine.c for now?
>> (only the mpc5200 i2s driver uses it at the moment). It can always be
>> renamed if other folks want to use it for other chips.
>
> That seems reasonable so long as you're happy with it, though it does
> seem to be going to the other extreme in terms of broadness :)
heh; I don't care. This stuff is all going to be in flux anyway, so
change is inevitable whatever is chosen now. :-)
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 17:21 ` Grant Likely
@ 2008-07-14 18:36 ` Mark Brown
2008-07-14 18:40 ` Timur Tabi
0 siblings, 1 reply; 46+ messages in thread
From: Mark Brown @ 2008-07-14 18:36 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, Timur Tabi, liam.girdwood
On Mon, Jul 14, 2008 at 11:21:12AM -0600, Grant Likely wrote:
> On Mon, Jul 14, 2008 at 10:53 AM, Mark Brown
> > Incidentally, nobody ever really commented on my suggestion to do
> > something DMI-like
> I'm feeling stupid; what does "DMI" stand for?
Desktop Management Interface, a standard BIOS interface for getting
system data on x86 class hardware. Of particular interest here is the
fact that it contains various ID strings for things like motherboard and
chassis - on Linux drivers can be automatically loaded based on these
strings. See drivers/misc/thinkpad_acpi.c for an example of a driver
that does this.
Note that it's *not* binding a driver, it just provides the hooks to
enable the modules to be automatically loaded and to let drivers query
information in DMI.
> Yes, we have APIs for matching against device trees. Personally, I'm
> leaning towards having the powerpc platform code
> (arch/powerpc/platforms/* stuff; not ASoC platform stuff) register a
> platform device for the machine driver and let as many machine drivers
> as needed be written. Hopefully we'll be able to do at least one
That would be what I'd expected initially - it is, after all, what other
platforms are doing here.
> generic machine driver that will be usable by most PowerPC boards, but
> I don't think it is a requirement or even realistic to shoehorn all
> powerpc sound circuits into a single driver.
Yes, that'd be completely unrealistic.
> > I don't mind - you can call it what you like inside PowerPC-specific
> > code.
> Oh help! Don't tell us that! Otherwise we'll always be talking
> across purposes. When ambiguous, let's just be sure to always refer
> to them as "ASoC machine drivers". :-)
Feh, from now on I shall me naming all new concepts with pwgen :) .
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 18:36 ` Mark Brown
@ 2008-07-14 18:40 ` Timur Tabi
2008-07-14 18:49 ` Mark Brown
` (2 more replies)
0 siblings, 3 replies; 46+ messages in thread
From: Timur Tabi @ 2008-07-14 18:40 UTC (permalink / raw)
To: Grant Likely, Timur Tabi, Jon Smirl, linuxppc-dev, alsa-devel,
liam.girdwood
Mark Brown wrote:
> Desktop Management Interface, a standard BIOS interface for getting
> system data on x86 class hardware. Of particular interest here is the
> fact that it contains various ID strings for things like motherboard and
> chassis - on Linux drivers can be automatically loaded based on these
> strings. See drivers/misc/thinkpad_acpi.c for an example of a driver
> that does this.
The only problem with this is that the OF probing code in the kernel binds
drivers to device tree nodes. So when a driver claims a node, no other driver
will be probed with it.
So we can't have generic nodes that classify the motherboard and just let
everyone get probed on it.
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 18:40 ` Timur Tabi
@ 2008-07-14 18:49 ` Mark Brown
2008-07-14 18:53 ` Timur Tabi
2008-07-14 22:28 ` Grant Likely
2008-07-14 23:45 ` Jon Smirl
2 siblings, 1 reply; 46+ messages in thread
From: Mark Brown @ 2008-07-14 18:49 UTC (permalink / raw)
To: Timur Tabi; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Mon, Jul 14, 2008 at 01:40:24PM -0500, Timur Tabi wrote:
> Mark Brown wrote:
> > Desktop Management Interface, a standard BIOS interface for getting
> > system data on x86 class hardware. Of particular interest here is the
> > fact that it contains various ID strings for things like motherboard and
> > chassis - on Linux drivers can be automatically loaded based on these
> > strings. See drivers/misc/thinkpad_acpi.c for an example of a driver
> > that does this.
> The only problem with this is that the OF probing code in the kernel binds
> drivers to device tree nodes. So when a driver claims a node, no other driver
> will be probed with it.
> So we can't have generic nodes that classify the motherboard and just let
> everyone get probed on it.
My suggestion is that you change this for the root node. It's already
got the information required in there, it's just there's no way to use
it to load modules at the minute. You could presumably read the
information out of the device tree using existing APIs to check you're
running on the right board once code is loaded?
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 18:49 ` Mark Brown
@ 2008-07-14 18:53 ` Timur Tabi
0 siblings, 0 replies; 46+ messages in thread
From: Timur Tabi @ 2008-07-14 18:53 UTC (permalink / raw)
To: Timur Tabi, Grant Likely, Jon Smirl, linuxppc-dev, alsa-devel,
liam.girdwood
Mark Brown wrote:
>> The only problem with this is that the OF probing code in the kernel binds
>> drivers to device tree nodes. So when a driver claims a node, no other driver
>> will be probed with it.
>
>> So we can't have generic nodes that classify the motherboard and just let
>> everyone get probed on it.
>
> My suggestion is that you change this for the root node.
That's an interesting idea.
> It's already
> got the information required in there, it's just there's no way to use
> it to load modules at the minute.
Correct.
> You could presumably read the
> information out of the device tree using existing APIs to check you're
> running on the right board once code is loaded?
Yes. The driver <-> node binding is only for probing. Any driver can scan the
entire tree at any time.
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 18:40 ` Timur Tabi
2008-07-14 18:49 ` Mark Brown
@ 2008-07-14 22:28 ` Grant Likely
2008-07-14 23:45 ` Jon Smirl
2 siblings, 0 replies; 46+ messages in thread
From: Grant Likely @ 2008-07-14 22:28 UTC (permalink / raw)
To: Timur Tabi; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Mon, Jul 14, 2008 at 01:40:24PM -0500, Timur Tabi wrote:
> Mark Brown wrote:
>
> > Desktop Management Interface, a standard BIOS interface for getting
> > system data on x86 class hardware. Of particular interest here is the
> > fact that it contains various ID strings for things like motherboard and
> > chassis - on Linux drivers can be automatically loaded based on these
> > strings. See drivers/misc/thinkpad_acpi.c for an example of a driver
> > that does this.
>
> The only problem with this is that the OF probing code in the kernel binds
> drivers to device tree nodes. So when a driver claims a node, no other driver
> will be probed with it.
Yes, but that is only for the of_platform bus which is just one way to
setup device drivers from the device tree. Setting it up from the
platform code is just as valid an option. Or, each ASoC machine driver could
read the device tree itself in the module_init hook to decide whether or not
to instantiate itself.
Cheers,
g.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 18:40 ` Timur Tabi
2008-07-14 18:49 ` Mark Brown
2008-07-14 22:28 ` Grant Likely
@ 2008-07-14 23:45 ` Jon Smirl
2008-07-15 10:13 ` Mark Brown
2 siblings, 1 reply; 46+ messages in thread
From: Jon Smirl @ 2008-07-14 23:45 UTC (permalink / raw)
To: Timur Tabi; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On 7/14/08, Timur Tabi <timur@freescale.com> wrote:
> Mark Brown wrote:
>
> > Desktop Management Interface, a standard BIOS interface for getting
> > system data on x86 class hardware. Of particular interest here is the
> > fact that it contains various ID strings for things like motherboard and
> > chassis - on Linux drivers can be automatically loaded based on these
> > strings. See drivers/misc/thinkpad_acpi.c for an example of a driver
> > that does this.
>
>
> The only problem with this is that the OF probing code in the kernel binds
> drivers to device tree nodes. So when a driver claims a node, no other driver
> will be probed with it.
>
> So we can't have generic nodes that classify the motherboard and just let
> everyone get probed on it.
Allowing multiple binds at the root causes the problem of something
like compatible="lite5200b,mpc5200-simple". Both platforms would bind
and that's not what you want.
I'm not a fan of each platform creating a platform device in
arch/powerpc/platforms/*. That implies that each platform would cause
another source file to be added each containing pretty much identical
code. It also makes the mpc5200-simple platform pointless. Of course
this scheme works and I'm doing it right now, but it's clearly not an
optimal solution.
Another scheme would be to add kernel code to always create virtual OF
devices like "lite5200b-fabric" that are derived off from the machine
name that achieved a bind.
A third scheme would be to convert the powerpc machine drivers
themselves to device drivers and move them out of
arch/powerpc/platforms/* into drivers/whatever. Then add the ASoC
fabric code to them. I don't know if you can load device drivers early
enough to load a powerpc machine driver from initrd.
A fourth scheme is to do it at compile time. But that means no
universal firmware images that support multiple hardware revisions. We
have this one today too.
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver
2008-07-12 8:39 ` [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver Grant Likely
2008-07-12 18:10 ` [alsa-devel] " Mark Brown
2008-07-14 11:45 ` Mark Brown
@ 2008-07-15 7:57 ` dinesh
2008-07-15 10:33 ` Mark Brown
2008-07-16 9:05 ` WRITING AN SOC DRIVER WITHOUT DMA dinesh
2008-07-17 16:02 ` [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver Timur Tabi
4 siblings, 1 reply; 46+ messages in thread
From: dinesh @ 2008-07-15 7:57 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
[-- Attachment #1: Type: text/plain, Size: 23131 bytes --]
Hi
I have one query about this soc driver.
I want to know when u will merge it with kernel then
where and by which name this device will be available
in /dev directory of your file system.
As i am following the same structure for my driver so please help me. I
am ot able to recognise the device in the file system.
-----Original Message-----
From: Grant Likely <grant.likely@secretlab.ca>
To: linuxppc-dev@ozlabs.org, alsa-devel@alsa-project.org,
liam.girdwood@wolfsonmicro.com, jonsmirl@gmail.com
Subject: [alsa-devel] [PATCH v2 3/3] ALSA SoC: Add Texas Instruments
TLV320AIC26 codec driver
Date: Sat, 12 Jul 2008 02:39:39 -0600
From: Grant Likely <grant.likely@secretlab.ca>
ASoC Codec driver for the TLV320AIC26 device. This driver uses the ASoC
v1 API, so I don't expect it to get merged as-is, but I want to get it
out there for review.
---
sound/soc/codecs/Kconfig | 4
sound/soc/codecs/Makefile | 2
sound/soc/codecs/tlv320aic26.c | 546 ++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/tlv320aic26.h | 103 ++++++++
4 files changed, 655 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 3903ab7..96c7bfe 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -41,6 +41,10 @@ config SND_SOC_CS4270_VD33_ERRATA
bool
depends on SND_SOC_CS4270
+config SND_SOC_TLV320AIC26
+ tristate "TI TLB320AIC26 Codec support"
+ depends on SND_SOC && SPI
+
config SND_SOC_TLV320AIC3X
tristate
depends on SND_SOC && I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 4e1314c..ec0cd93 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -5,6 +5,7 @@ snd-soc-wm8753-objs := wm8753.o
snd-soc-wm9712-objs := wm9712.o
snd-soc-wm9713-objs := wm9713.o
snd-soc-cs4270-objs := cs4270.o
+snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
@@ -14,4 +15,5 @@ obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
new file mode 100644
index 0000000..3ebfa23
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -0,0 +1,546 @@
+/*
+ * Texas Instruments TLV320AIC26 low power audio CODEC
+ * ALSA SoC CODEC driver
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/sysfs.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/soc-of.h>
+#include <sound/initval.h>
+
+#include "tlv320aic26.h"
+
+MODULE_DESCRIPTION("ASoC TLV320AIC26 codec driver");
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_LICENSE("GPL");
+
+/* AIC26 driver private data */
+struct aic26 {
+ struct spi_device *spi;
+ struct snd_soc_codec codec;
+ u16 reg_cache[AIC26_REG_CACHE_SIZE]; /* shadow registers */
+ int master;
+ int datfm;
+ int mclk;
+
+ /* Keyclick parameters */
+ int keyclick_amplitude;
+ int keyclick_freq;
+ int keyclick_len;
+};
+
+/* ---------------------------------------------------------------------
+ * Register access routines
+ */
+static unsigned int aic26_reg_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ struct aic26 *aic26 = codec->private_data;
+ u16 *cache = codec->reg_cache;
+ u16 cmd, value;
+ u8 buffer[2];
+ int rc;
+
+ if (reg >= AIC26_NUM_REGS) {
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+
+ /* Do SPI transfer; first 16bits are command; remaining is
+ * register contents */
+ cmd = AIC26_READ_COMMAND_WORD(reg);
+ buffer[0] = (cmd >> 8) & 0xff;
+ buffer[1] = cmd & 0xff;
+ rc = spi_write_then_read(aic26->spi, buffer, 2, buffer, 2);
+ if (rc) {
+ dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
+ return -EIO;
+ }
+ value = (buffer[0] << 8) | buffer[1];
+
+ /* Update the cache before returning with the value */
+ if (AIC26_REG_IS_CACHED(reg))
+ cache[AIC26_REG_CACHE_ADDR(reg)] = value;
+ return value;
+}
+
+static unsigned int aic26_reg_read_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+
+ if ((reg < 0) || (reg >= AIC26_NUM_REGS)) {
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+
+ if (AIC26_REG_IS_CACHED(reg))
+ return cache[AIC26_REG_CACHE_ADDR(reg)];
+
+ return aic26_reg_read(codec, reg);
+}
+
+static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ struct aic26 *aic26 = codec->private_data;
+ u16 *cache = codec->reg_cache;
+ u16 cmd;
+ u8 buffer[4];
+ int rc;
+
+ if ((reg < 0) || (reg >= AIC26_NUM_REGS)) {
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
+
+ /* Do SPI transfer; first 16bits are command; remaining is data
+ * to write into register */
+ cmd = AIC26_WRITE_COMMAND_WORD(reg);
+ buffer[0] = (cmd >> 8) & 0xff;
+ buffer[1] = cmd & 0xff;
+ buffer[2] = value >> 8;
+ buffer[3] = value;
+ rc = spi_write(aic26->spi, buffer, 4);
+ if (rc) {
+ dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
+ return -EIO;
+ }
+
+ /* update cache before returning */
+ if (AIC26_REG_IS_CACHED(reg))
+ cache[AIC26_REG_CACHE_ADDR(reg)] = value;
+ return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Digital Audio Interface Operations
+ */
+static int aic26_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_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->codec;
+ struct aic26 *aic26 = codec->private_data;
+ int fsref, divisor, wlen, pval, jval, dval, qval;
+ u16 reg;
+
+ dev_dbg(&aic26->spi->dev, "aic26_hw_params(substream=%p, params=%p)\n",
+ substream, params);
+ dev_dbg(&aic26->spi->dev, "rate=%i format=%i\n", params_rate(params),
+ params_format(params));
+
+ switch (params_rate(params)) {
+ case 8000: fsref = 48000; divisor = AIC26_DIV_6; break;
+ case 11025: fsref = 44100; divisor = AIC26_DIV_4; break;
+ case 12000: fsref = 48000; divisor = AIC26_DIV_4; break;
+ case 16000: fsref = 48000; divisor = AIC26_DIV_3; break;
+ case 22050: fsref = 44100; divisor = AIC26_DIV_2; break;
+ case 24000: fsref = 48000; divisor = AIC26_DIV_2; break;
+ case 32000: fsref = 48000; divisor = AIC26_DIV_1_5; break;
+ case 44100: fsref = 44100; divisor = AIC26_DIV_1; break;
+ case 48000: fsref = 48000; divisor = AIC26_DIV_1; break;
+ default: dev_dbg(&aic26->spi->dev, "bad rate\n"); return -EINVAL;
+ }
+
+ /* select data word length */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8: wlen = AIC26_WLEN_16; break;
+ case SNDRV_PCM_FORMAT_S16_BE: wlen = AIC26_WLEN_16; break;
+ case SNDRV_PCM_FORMAT_S24_BE: wlen = AIC26_WLEN_24; break;
+ case SNDRV_PCM_FORMAT_S32_BE: wlen = AIC26_WLEN_32; break;
+ default: dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
+ }
+
+ /* Configure PLL */
+ pval = 1;
+ jval = (fsref == 44100) ? 7 : 8;
+ dval = (fsref == 44100) ? 5264 : 1920;
+ qval = 0;
+ reg = 0x8000 | qval << 11 | pval << 8 | jval << 2;
+ aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg);
+ reg = dval << 2;
+ aic26_reg_write(codec, AIC26_REG_PLL_PROG2, reg);
+
+ /* Power up CODEC */
+ aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0);
+
+ /* Audio Control 3 (master mode, fsref rate) */
+ reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3);
+ reg &= ~0xf800;
+ if (aic26->master)
+ reg |= 0x0800;
+ if (fsref == 48000)
+ reg |= 0x2000;
+ aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
+
+ /* Audio Control 1 (FSref divisor) */
+ reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1);
+ reg &= ~0x0fff;
+ reg |= wlen | aic26->datfm | (divisor << 3) | divisor;
+ aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL1, reg);
+
+ return 0;
+}
+
+/**
+ * aic26_mute - Mute control to reduce noise when changing audio format
+ */
+static int aic26_mute(struct snd_soc_codec_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct aic26 *aic26 = codec->private_data;
+ u16 reg = aic26_reg_read_cache(codec, AIC26_REG_DAC_GAIN);
+
+ dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n",
+ dai, mute);
+
+ if (mute)
+ reg |= 0x8080;
+ else
+ reg &= ~0x8080;
+ aic26_reg_write(codec, AIC26_REG_DAC_GAIN, reg);
+
+ return 0;
+}
+
+static int aic26_set_sysclk(struct snd_soc_codec_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct aic26 *aic26 = codec->private_data;
+
+ dev_dbg(&aic26->spi->dev, "aic26_set_sysclk(dai=%p, clk_id==%i,"
+ " freq=%i, dir=%i)\n",
+ codec_dai, clk_id, freq, dir);
+
+ /* MCLK needs to fall between 2MHz and 50 MHz */
+ if ((freq < 2000000) || (freq > 50000000))
+ return -EINVAL;
+
+ aic26->mclk = freq;
+ return 0;
+}
+
+static int aic26_set_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct aic26 *aic26 = codec->private_data;
+
+ dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n",
+ codec_dai, fmt);
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM: aic26->master = 1; break;
+ case SND_SOC_DAIFMT_CBS_CFS: aic26->master = 0; break;
+ default: dev_dbg(&aic26->spi->dev, "bad master\n"); return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S: aic26->datfm = AIC26_DATFM_I2S; break;
+ case SND_SOC_DAIFMT_DSP_A: aic26->datfm = AIC26_DATFM_DSP; break;
+ case SND_SOC_DAIFMT_RIGHT_J: aic26->datfm = AIC26_DATFM_RIGHTJ; break;
+ case SND_SOC_DAIFMT_LEFT_J: aic26->datfm = AIC26_DATFM_LEFTJ; break;
+ default: dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Digital Audio Interface Definition
+ */
+struct snd_soc_codec_dai aic26_dai = {
+ .name = "tlv320aic26",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AIC26_RATES,
+ .formats = AIC26_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = AIC26_RATES,
+ .formats = AIC26_FORMATS,
+ },
+ .ops = {
+ .hw_params = aic26_hw_params,
+ },
+ .dai_ops = {
+ .digital_mute = aic26_mute,
+ .set_sysclk = aic26_set_sysclk,
+ .set_fmt = aic26_set_fmt,
+ },
+};
+EXPORT_SYMBOL_GPL(aic26_dai);
+
+/* ---------------------------------------------------------------------
+ * ALSA controls
+ */
+static const char *aic26_capture_src_text[] = {"Mic", "Aux"};
+static const struct soc_enum aic26_capture_src_enum =
+ SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12,2, aic26_capture_src_text);
+
+static const struct snd_kcontrol_new aic26_snd_controls[] = {
+ /* Output */
+ SOC_DOUBLE("PCM Playback Volume", AIC26_REG_DAC_GAIN, 8, 0, 0x7f, 1),
+ SOC_DOUBLE("PCM Playback Switch", AIC26_REG_DAC_GAIN, 15, 7, 1, 1),
+ SOC_SINGLE("PCM Capture Volume", AIC26_REG_ADC_GAIN, 8, 0x7f, 0),
+ SOC_SINGLE("PCM Capture Mute", AIC26_REG_ADC_GAIN, 15, 1, 1),
+ SOC_SINGLE("Keyclick activate", AIC26_REG_AUDIO_CTRL2, 15, 0x1, 0),
+ SOC_SINGLE("Keyclick amplitude", AIC26_REG_AUDIO_CTRL2, 12, 0x7, 0),
+ SOC_SINGLE("Keyclick frequency", AIC26_REG_AUDIO_CTRL2, 8, 0x7, 0),
+ SOC_SINGLE("Keyclick period", AIC26_REG_AUDIO_CTRL2, 4, 0xf, 0),
+ SOC_ENUM("Capture Source", aic26_capture_src_enum),
+};
+
+/* ---------------------------------------------------------------------
+ * SoC CODEC portion of driver: probe and release routines
+ */
+static int aic26_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ struct snd_kcontrol *kcontrol;
+ struct aic26 *aic26;
+ int i, ret, err;
+
+ dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n");
+ dev_dbg(&pdev->dev, "socdev=%p\n", socdev);
+ dev_dbg(&pdev->dev, "codec_data=%p\n", socdev->codec_data);
+
+ /* Fetch the relevant aic26 private data here (it's already been
+ * stored in the .codec pointer) */
+ aic26 = socdev->codec_data;
+ if (aic26 == NULL) {
+ dev_err(&pdev->dev, "aic26: missing codec pointer\n");
+ return -ENODEV;
+ }
+ codec = &aic26->codec;
+ socdev->codec = codec;
+
+ dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n",
+ &pdev->dev, socdev->dev);
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "aic26: failed to create pcms\n");
+ return -ENODEV;
+ }
+
+ /* register controls */
+ dev_dbg(&pdev->dev, "Registering controls\n");
+ for (i = 0; i < ARRAY_SIZE(aic26_snd_controls); i++) {
+ kcontrol = snd_soc_cnew(&aic26_snd_controls[i], codec, NULL);
+ err = snd_ctl_add(codec->card, kcontrol);
+ WARN_ON(err < 0);
+ }
+
+ /* CODEC is setup, we can register the card now */
+ dev_dbg(&pdev->dev, "Registering card\n");
+ ret = snd_soc_register_card(socdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "aic26: failed to register card\n");
+ goto card_err;
+ }
+ return 0;
+
+ card_err:
+ snd_soc_free_pcms(socdev);
+ return ret;
+}
+
+static int aic26_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ snd_soc_free_pcms(socdev);
+ return 0;
+}
+
+struct snd_soc_codec_device aic26_soc_codec_dev = {
+ .probe = aic26_probe,
+ .remove = aic26_remove,
+};
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: sysfs files for debugging
+ */
+
+static ssize_t aic26_regs_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct aic26 *aic26 = dev_get_drvdata(dev);
+ char *idx = buf;
+ int cache_flag, addr, page, i, reg;
+
+ cache_flag = (strcmp(attr->attr.name, "regs_cache") == 0);
+
+ for (page = 0; page < 3; page++) {
+ for (i = 0; i < 0x20; i++) {
+ addr = AIC26_PAGE_ADDR(page, i);
+ if (i % 8 == 0)
+ idx += sprintf(idx, "%i:%.2i:", page,i);
+ if (cache_flag)
+ reg = aic26_reg_read_cache(&aic26->codec, addr);
+ else
+ reg = aic26_reg_read(&aic26->codec, addr);
+ idx += sprintf(idx, " %.4x", reg);
+ if (i % 8 == 7)
+ idx += sprintf(idx, "\n");
+ }
+ }
+ return idx - buf;
+}
+
+static ssize_t aic26_keyclick_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct aic26 *aic26 = dev_get_drvdata(dev);
+ int val, amp, freq, len;
+
+ val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+ amp = (val >> 12) & 0x7;
+ freq = (125 << ((val >> 8) & 0x7)) >> 1;
+ len = 2 * (1 +((val >> 4) & 0xf));
+
+ return sprintf(buf, "amp=%x freq=%iHz len=%iclks\n", amp, freq, len);
+}
+
+/* Any write to the keyclick attribute will trigger the keyclick */
+static ssize_t aic26_keyclick_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct aic26 *aic26 = dev_get_drvdata(dev);
+ int val;
+
+ val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+ val |= 0x8000;
+ aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL2, val);
+
+ return count;
+}
+
+DEVICE_ATTR(regs, 0644, aic26_regs_show, NULL);
+DEVICE_ATTR(regs_cache, 0644, aic26_regs_show, NULL);
+DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: probe and release routines and SPI
+ * driver registration.
+ */
+static int aic26_spi_probe(struct spi_device *spi)
+{
+ struct aic26 *aic26;
+ int rc, i, reg;
+
+ dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
+
+ /* Allocate driver data */
+ aic26 = kzalloc(sizeof *aic26, GFP_KERNEL);
+ if (!aic26)
+ return -ENOMEM;
+
+ /* Initialize the driver data */
+ aic26->spi = spi;
+ dev_set_drvdata(&spi->dev, aic26);
+
+ /* Setup what we can in the codec structure so that the register
+ * access functions will work as expected. More will be filled
+ * out when it is probed by the SoC CODEC part of this driver */
+ aic26->codec.private_data = aic26;
+ aic26->codec.name = "aic26";
+ aic26->codec.owner = THIS_MODULE;
+ aic26->codec.dai = &aic26_dai;
+ aic26->codec.num_dai = 1;
+ aic26->codec.read = aic26_reg_read;
+ aic26->codec.write = aic26_reg_write;
+ aic26->master = 1;
+ mutex_init(&aic26->codec.mutex);
+ INIT_LIST_HEAD(&aic26->codec.dapm_widgets);
+ INIT_LIST_HEAD(&aic26->codec.dapm_paths);
+ aic26->codec.reg_cache_size = sizeof(aic26->reg_cache);
+ aic26->codec.reg_cache = aic26->reg_cache;
+
+ /* Reset the codec to power on defaults */
+ aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00);
+
+ /* Power up CODEC */
+ aic26_reg_write(&aic26->codec, AIC26_REG_POWER_CTRL, 0);
+
+ /* Audio Control 3 (master mode, fsref rate) */
+ reg = aic26_reg_read(&aic26->codec, AIC26_REG_AUDIO_CTRL3);
+ reg &= ~0xf800;
+ reg |= 0x0800; /* set master mode */
+ aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL3, reg);
+
+ /* Fill page 2 register cache */
+ for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
+ aic26_reg_read(&aic26->codec, AIC26_PAGE_ADDR(2, i));
+
+ /* Register the sysfs files for debugging */
+ /* Create SysFS files */
+ rc = device_create_file(&spi->dev, &dev_attr_regs);
+ rc |= device_create_file(&spi->dev, &dev_attr_regs_cache);
+ 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)
+ /* Tell the of_soc helper about this codec */
+ of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
+ spi->dev.archdata.of_node);
+#endif
+
+ dev_dbg(&spi->dev, "SPI device initialized\n");
+ return 0;
+}
+
+static int aic26_spi_remove(struct spi_device *spi)
+{
+ struct aic26 *aic26 = dev_get_drvdata(&spi->dev);
+
+ kfree(aic26);
+
+ return 0;
+}
+
+static struct spi_driver aic26_spi = {
+ .driver = {
+ .name = "tlv320aic26",
+ .owner = THIS_MODULE,
+ },
+ .probe = aic26_spi_probe,
+ .remove = aic26_spi_remove,
+};
+
+static int __init aic26_init(void)
+{
+ return spi_register_driver(&aic26_spi);
+}
+module_init(aic26_init);
+
+static void __exit aic26_exit(void)
+{
+ spi_unregister_driver(&aic26_spi);
+}
+module_exit(aic26_exit);
diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h
new file mode 100644
index 0000000..9edb8e9
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic26.h
@@ -0,0 +1,103 @@
+/*
+ * Texas Instruments TLV320AIC26 low power audio CODEC
+ * register definitions
+ *
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ */
+
+#ifndef _TLV320AIC16_H_
+#define _TLV320AIC16_H_
+
+/* AIC26 Registers */
+#define AIC26_READ_COMMAND_WORD(addr) ((1 << 15) | (addr << 5))
+#define AIC26_WRITE_COMMAND_WORD(addr) ((0 << 15) | (addr << 5))
+#define AIC26_PAGE_ADDR(page, offset) ((page << 6) | offset)
+#define AIC26_NUM_REGS AIC26_PAGE_ADDR(3, 0)
+#define AIC26_REG_CACHE_SIZE (0x20) /* only page 2 cached */
+#define AIC26_REG_IS_CACHED(addr) ((addr & ~0x1f) == (2 << 6))
+#define AIC26_REG_CACHE_ADDR(addr) (addr & 0x1f)
+
+/* Page 0: Auxillary data registers */
+#define AIC26_REG_BAT1 AIC26_PAGE_ADDR(0, 0x05)
+#define AIC26_REG_BAT2 AIC26_PAGE_ADDR(0, 0x06)
+#define AIC26_REG_AUX AIC26_PAGE_ADDR(0, 0x07)
+#define AIC26_REG_TEMP1 AIC26_PAGE_ADDR(0, 0x09)
+#define AIC26_REG_TEMP2 AIC26_PAGE_ADDR(0, 0x0A)
+
+/* Page 1: Auxillary control registers */
+#define AIC26_REG_AUX_ADC AIC26_PAGE_ADDR(1, 0x00)
+#define AIC26_REG_STATUS AIC26_PAGE_ADDR(1, 0x01)
+#define AIC26_REG_REFERENCE AIC26_PAGE_ADDR(1, 0x03)
+#define AIC26_REG_RESET AIC26_PAGE_ADDR(1, 0x04)
+
+/* Page 2: Audio control registers */
+#define AIC26_REG_AUDIO_CTRL1 AIC26_PAGE_ADDR(2, 0x00)
+#define AIC26_REG_ADC_GAIN AIC26_PAGE_ADDR(2, 0x01)
+#define AIC26_REG_DAC_GAIN AIC26_PAGE_ADDR(2, 0x02)
+#define AIC26_REG_SIDETONE AIC26_PAGE_ADDR(2, 0x03)
+#define AIC26_REG_AUDIO_CTRL2 AIC26_PAGE_ADDR(2, 0x04)
+#define AIC26_REG_POWER_CTRL AIC26_PAGE_ADDR(2, 0x05)
+#define AIC26_REG_AUDIO_CTRL3 AIC26_PAGE_ADDR(2, 0x06)
+
+#define AIC26_REG_FILTER_COEFF_L_N0 AIC26_PAGE_ADDR(2, 0x07)
+#define AIC26_REG_FILTER_COEFF_L_N1 AIC26_PAGE_ADDR(2, 0x08)
+#define AIC26_REG_FILTER_COEFF_L_N2 AIC26_PAGE_ADDR(2, 0x09)
+#define AIC26_REG_FILTER_COEFF_L_N3 AIC26_PAGE_ADDR(2, 0x0A)
+#define AIC26_REG_FILTER_COEFF_L_N4 AIC26_PAGE_ADDR(2, 0x0B)
+#define AIC26_REG_FILTER_COEFF_L_N5 AIC26_PAGE_ADDR(2, 0x0C)
+#define AIC26_REG_FILTER_COEFF_L_D1 AIC26_PAGE_ADDR(2, 0x0D)
+#define AIC26_REG_FILTER_COEFF_L_D2 AIC26_PAGE_ADDR(2, 0x0E)
+#define AIC26_REG_FILTER_COEFF_L_D4 AIC26_PAGE_ADDR(2, 0x0F)
+#define AIC26_REG_FILTER_COEFF_L_D5 AIC26_PAGE_ADDR(2, 0x10)
+#define AIC26_REG_FILTER_COEFF_R_N0 AIC26_PAGE_ADDR(2, 0x11)
+#define AIC26_REG_FILTER_COEFF_R_N1 AIC26_PAGE_ADDR(2, 0x12)
+#define AIC26_REG_FILTER_COEFF_R_N2 AIC26_PAGE_ADDR(2, 0x13)
+#define AIC26_REG_FILTER_COEFF_R_N3 AIC26_PAGE_ADDR(2, 0x14)
+#define AIC26_REG_FILTER_COEFF_R_N4 AIC26_PAGE_ADDR(2, 0x15)
+#define AIC26_REG_FILTER_COEFF_R_N5 AIC26_PAGE_ADDR(2, 0x16)
+#define AIC26_REG_FILTER_COEFF_R_D1 AIC26_PAGE_ADDR(2, 0x17)
+#define AIC26_REG_FILTER_COEFF_R_D2 AIC26_PAGE_ADDR(2, 0x18)
+#define AIC26_REG_FILTER_COEFF_R_D4 AIC26_PAGE_ADDR(2, 0x19)
+#define AIC26_REG_FILTER_COEFF_R_D5 AIC26_PAGE_ADDR(2, 0x1A)
+
+#define AIC26_REG_PLL_PROG1 AIC26_PAGE_ADDR(2, 0x1B)
+#define AIC26_REG_PLL_PROG2 AIC26_PAGE_ADDR(2, 0x1C)
+#define AIC26_REG_AUDIO_CTRL4 AIC26_PAGE_ADDR(2, 0x1D)
+#define AIC26_REG_AUDIO_CTRL5 AIC26_PAGE_ADDR(2, 0x1E)
+
+#define AIC26_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)
+#define AIC26_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |\
+ SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
+
+/* fsref dividers; used in register 'Audio Control 1' */
+enum aic26_divisors {
+ AIC26_DIV_1 = 0,
+ AIC26_DIV_1_5 = 1,
+ AIC26_DIV_2 = 2,
+ AIC26_DIV_3 = 3,
+ AIC26_DIV_4 = 4,
+ AIC26_DIV_5 = 5,
+ AIC26_DIV_5_5 = 6,
+ AIC26_DIV_6 = 7,
+};
+
+/* Digital data format */
+enum aic26_datfm {
+ AIC26_DATFM_I2S = 0 << 8,
+ AIC26_DATFM_DSP = 1 << 8,
+ AIC26_DATFM_RIGHTJ = 2 << 8, /* right justified */
+ AIC26_DATFM_LEFTJ = 3 << 8, /* left justified */
+};
+
+/* Sample word length in bits; used in register 'Audio Control 1' */
+enum aic26_wlen {
+ AIC26_WLEN_16 = 0 << 10,
+ AIC26_WLEN_20 = 1 << 10,
+ AIC26_WLEN_24 = 2 << 10,
+ AIC26_WLEN_32 = 3 << 10,
+};
+
+#endif /* _TLV320AIC16_H_ */
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
[-- Attachment #2: Type: text/html, Size: 25433 bytes --]
^ permalink raw reply related [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 23:45 ` Jon Smirl
@ 2008-07-15 10:13 ` Mark Brown
2008-07-15 13:08 ` Jon Smirl
0 siblings, 1 reply; 46+ messages in thread
From: Mark Brown @ 2008-07-15 10:13 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, Timur Tabi, liam.girdwood
On Mon, Jul 14, 2008 at 07:45:46PM -0400, Jon Smirl wrote:
> On 7/14/08, Timur Tabi <timur@freescale.com> wrote:
> > Mark Brown wrote:
> > > chassis - on Linux drivers can be automatically loaded based on these
> > > strings. See drivers/misc/thinkpad_acpi.c for an example of a driver
> > > that does this.
> Allowing multiple binds at the root causes the problem of something
> like compatible="lite5200b,mpc5200-simple". Both platforms would bind
> and that's not what you want.
Binding isn't the issue here - it's loading the driver in the first
place. Once the drivers are loaded they can (hopefully) figure out if
they are running on appropriate hardware.
> Another scheme would be to add kernel code to always create virtual OF
> devices like "lite5200b-fabric" that are derived off from the machine
> name that achieved a bind.
This is what I'm suggesting, modulo the fact that I'm suggesting *not*
creating virtual devices but rather providing a mechanism for drivers to
load without binding to anything. It strikes me that you're going to
run into similar situations with other hardware at some point - either
for undocumented extras that you happen to know exist on the system
(like much of the DMI usage on x86) or for other things where you've got
on-board hardware structured like sound hardware tends to be.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver
2008-07-15 7:57 ` dinesh
@ 2008-07-15 10:33 ` Mark Brown
2008-07-15 12:38 ` dinesh
0 siblings, 1 reply; 46+ messages in thread
From: Mark Brown @ 2008-07-15 10:33 UTC (permalink / raw)
To: dinesh; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Tue, Jul 15, 2008 at 01:27:52PM +0530, dinesh wrote:
> I have one query about this soc driver.
> I want to know when u will merge it with kernel then
> where and by which name this device will be available
> in /dev directory of your file system.
> As i am following the same structure for my driver so please help me. I
> am ot able to recognise the device in the file system.
It will appear via the standard ALSA interfaces (and OSS interfaces if
you enable OSS compatibility). The standard location for ALSA device
files is under /dev/snd where you'll see several files per device.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver
2008-07-15 10:33 ` Mark Brown
@ 2008-07-15 12:38 ` dinesh
2008-07-15 12:46 ` Mark Brown
0 siblings, 1 reply; 46+ messages in thread
From: dinesh @ 2008-07-15 12:38 UTC (permalink / raw)
To: Mark Brown; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
[-- Attachment #1: Type: text/plain, Size: 1291 bytes --]
thanks for your response but there is no /dev/snd directory in my file
structure is there any special method to create it please tell in
detail.
-----Original Message-----
From: Mark Brown <broonie@opensource.wolfsonmicro.com>
To: dinesh <dinesh.dua@coraltele.com>
Cc: Grant Likely <grant.likely@secretlab.ca>, linuxppc-dev@ozlabs.org,
alsa-devel@alsa-project.org, liam.girdwood@wolfsonmicro.com
Subject: Re: [alsa-devel] [PATCH v2 3/3] ALSA SoC: Add Texas Instruments
TLV320AIC26 codec driver
Date: Tue, 15 Jul 2008 11:33:34 +0100
On Tue, Jul 15, 2008 at 01:27:52PM +0530, dinesh wrote:
> I have one query about this soc driver.
> I want to know when u will merge it with kernel then
> where and by which name this device will be available
> in /dev directory of your file system.
> As i am following the same structure for my driver so please help me. I
> am ot able to recognise the device in the file system.
It will appear via the standard ALSA interfaces (and OSS interfaces if
you enable OSS compatibility). The standard location for ALSA device
files is under /dev/snd where you'll see several files per device.
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
[-- Attachment #2: Type: text/html, Size: 2205 bytes --]
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver
2008-07-15 12:38 ` dinesh
@ 2008-07-15 12:46 ` Mark Brown
0 siblings, 0 replies; 46+ messages in thread
From: Mark Brown @ 2008-07-15 12:46 UTC (permalink / raw)
To: dinesh; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Tue, Jul 15, 2008 at 06:08:19PM +0530, dinesh wrote:
> thanks for your response but there is no /dev/snd directory in my file
> structure is there any special method to create it please tell in
> detail.
The devices appear via the standard kernel interfaces so if you are
using udev or mdev they should be created automatically. Otherwise
you'll need to create them statically using whatever method you usually
use (eg, a MAKEDEV script supplied by your distribution or manually by
reference to the device numbers exposed in /sys/class/sound/*/dev).
The ALSA devices use the standard Linux mechanisms to create their
devices so whatever you normally use to create devices should work for
ALSA too.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-15 10:13 ` Mark Brown
@ 2008-07-15 13:08 ` Jon Smirl
2008-07-15 14:04 ` Mark Brown
0 siblings, 1 reply; 46+ messages in thread
From: Jon Smirl @ 2008-07-15 13:08 UTC (permalink / raw)
To: Timur Tabi, Grant Likely, linuxppc-dev, alsa-devel, liam.girdwood
On 7/15/08, Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:
> On Mon, Jul 14, 2008 at 07:45:46PM -0400, Jon Smirl wrote:
> > On 7/14/08, Timur Tabi <timur@freescale.com> wrote:
> > > Mark Brown wrote:
>
>
> > > > chassis - on Linux drivers can be automatically loaded based on these
> > > > strings. See drivers/misc/thinkpad_acpi.c for an example of a driver
> > > > that does this.
>
>
> > Allowing multiple binds at the root causes the problem of something
> > like compatible="lite5200b,mpc5200-simple". Both platforms would bind
> > and that's not what you want.
>
> Binding isn't the issue here - it's loading the driver in the first
> place. Once the drivers are loaded they can (hopefully) figure out if
> they are running on appropriate hardware.
In this case we would end up with two core PowerPC machine drivers
bound, not ALSA ones. We have machine drivers in the PowerPC core,
that's one reason why it is confusing to call the ALSA drivers machine
drivers too.
If we allow multiple bindings both lite5200b and mpc5200-simple would
bind. The compatible list is a priority list from most specific to
most general. First you check for the specific driver lite5200b, if
it's not found then load the generic one mpc5200-simple.
> > Another scheme would be to add kernel code to always create virtual OF
> > devices like "lite5200b-fabric" that are derived off from the machine
> > name that achieved a bind.
>
>
> This is what I'm suggesting, modulo the fact that I'm suggesting *not*
> creating virtual devices but rather providing a mechanism for drivers to
> load without binding to anything. It strikes me that you're going to
If you have drivers for four different hardware releases compiled into
your kernel, the only kernel mechanism I know of to trigger only one
of these to initialize is to create a device and then let the probe
mechanism sort it out. This is even more true when the drivers are on
initrd and need to be dynamically loaded. The module load code will
search through the alias lists in the module .ko files.
It has been pointed out that a lite5200b-fabric device isn't really a
virtual devices. It's a device that represents the traces on the PCB
wiring the generic chip drivers together.
> run into similar situations with other hardware at some point - either
> for undocumented extras that you happen to know exist on the system
> (like much of the DMI usage on x86) or for other things where you've got
> on-board hardware structured like sound hardware tends to be.
This makes sense, it is possible that other areas we aren't familiar
with will need fabric drivers too. The problem is easily exposed in
audio hardware since we use external clock and amp chips.
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-15 13:08 ` Jon Smirl
@ 2008-07-15 14:04 ` Mark Brown
0 siblings, 0 replies; 46+ messages in thread
From: Mark Brown @ 2008-07-15 14:04 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, Timur Tabi, liam.girdwood
On Tue, Jul 15, 2008 at 09:08:28AM -0400, Jon Smirl wrote:
> On 7/15/08, Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:
> > Binding isn't the issue here - it's loading the driver in the first
> > place. Once the drivers are loaded they can (hopefully) figure out if
> > they are running on appropriate hardware.
> In this case we would end up with two core PowerPC machine drivers
> bound, not ALSA ones. We have machine drivers in the PowerPC core,
> that's one reason why it is confusing to call the ALSA drivers machine
> drivers too.
Again, I'm not talking about binding anything.
> > This is what I'm suggesting, modulo the fact that I'm suggesting *not*
> > creating virtual devices but rather providing a mechanism for drivers to
> > load without binding to anything. It strikes me that you're going to
> If you have drivers for four different hardware releases compiled into
> your kernel, the only kernel mechanism I know of to trigger only one
> of these to initialize is to create a device and then let the probe
> mechanism sort it out. This is even more true when the drivers are on
> initrd and need to be dynamically loaded. The module load code will
> search through the alias lists in the module .ko files.
This can be handled in the module initialisation (rather than driver
probe) - providing something can arrange for the driver to get loaded
then the drivers can check the system they're running on when that
happens and fail if it's inappropriate. The ARM ASoC drivers and x86
DMI based stuff do things this way, for example (ARM doesn't have the
automatic module load stuff implemented, though).
The infrastructure for automatically loading modules is usable
separately from device registration, though normally the two do go hand
in hand.
> It has been pointed out that a lite5200b-fabric device isn't really a
> virtual devices. It's a device that represents the traces on the PCB
> wiring the generic chip drivers together.
This was brought up very early on when you guys first started working on
it. :/
^ permalink raw reply [flat|nested] 46+ messages in thread
* WRITING AN SOC DRIVER WITHOUT DMA
2008-07-12 8:39 ` [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver Grant Likely
` (2 preceding siblings ...)
2008-07-15 7:57 ` dinesh
@ 2008-07-16 9:05 ` dinesh
2008-07-16 10:07 ` [alsa-devel] " Nobin Mathew
2008-07-17 16:02 ` [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver Timur Tabi
4 siblings, 1 reply; 46+ messages in thread
From: dinesh @ 2008-07-16 9:05 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
[-- Attachment #1: Type: text/plain, Size: 202 bytes --]
Hi,
I am writing a soc sound driver for MPC8323 board linux 2.6.24 in which i want to do data transfer to and from device myself using BUFFER DESCRIPTOR not with the usual DMA transfer.
Please help me.
[-- Attachment #2: Type: text/html, Size: 444 bytes --]
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
2008-07-16 9:05 ` WRITING AN SOC DRIVER WITHOUT DMA dinesh
@ 2008-07-16 10:07 ` Nobin Mathew
2008-07-16 10:13 ` dinesh
0 siblings, 1 reply; 46+ messages in thread
From: Nobin Mathew @ 2008-07-16 10:07 UTC (permalink / raw)
To: dinesh; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
[-- Attachment #1: Type: text/plain, Size: 543 bytes --]
Hi dinesh,
If you are working on ARM, see the ARM AACi code, in sound/arm/aaci.c
Thanks
Nobin Mathew.
On 7/16/08, dinesh <dinesh.dua@coraltele.com> wrote:
>
> Hi,
> I am writing a soc sound driver for MPC8323 board linux 2.6.24 in which i
> want to do data transfer to and from device myself using BUFFER DESCRIPTOR
> not with the usual DMA transfer.
> Please help me.
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
[-- Attachment #2: Type: text/html, Size: 1025 bytes --]
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
2008-07-16 10:07 ` [alsa-devel] " Nobin Mathew
@ 2008-07-16 10:13 ` dinesh
2008-07-17 6:03 ` dinesh
0 siblings, 1 reply; 46+ messages in thread
From: dinesh @ 2008-07-16 10:13 UTC (permalink / raw)
To: Nobin Mathew; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
[-- Attachment #1: Type: text/plain, Size: 1085 bytes --]
no i am working on powerpc. MPC8323
-----Original Message-----
From: Nobin Mathew <nobin.mathew@gmail.com>
To: dinesh <dinesh.dua@coraltele.com>
Cc: Grant Likely <grant.likely@secretlab.ca>, linuxppc-dev@ozlabs.org,
alsa-devel@alsa-project.org, liam.girdwood@wolfsonmicro.com
Subject: Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
Date: Wed, 16 Jul 2008 15:37:54 +0530
Hi dinesh,
If you are working on ARM, see the ARM AACi code, in sound/arm/aaci.c
Thanks
Nobin Mathew.
On 7/16/08, dinesh <dinesh.dua@coraltele.com> wrote:
>
> Hi,
> I am writing a soc sound driver for MPC8323 board linux 2.6.24 in which i
> want to do data transfer to and from device myself using BUFFER DESCRIPTOR
> not with the usual DMA transfer.
> Please help me.
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
[-- Attachment #2: Type: text/html, Size: 2198 bytes --]
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
2008-07-16 10:13 ` dinesh
@ 2008-07-17 6:03 ` dinesh
2008-07-17 10:56 ` Mark Brown
0 siblings, 1 reply; 46+ messages in thread
From: dinesh @ 2008-07-17 6:03 UTC (permalink / raw)
To: Nobin Mathew; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
[-- Attachment #1: Type: text/plain, Size: 1967 bytes --]
Hi,
I think no one is able to understand my problem, let me break it to low
level.
What i want is that i have a buffer in driver code which is also handled
by some other application i want that this buffer data is to be used for
capture and playback stream fills data to another buffer which i can
passover to my other application.
If someone can help me please.
Regards,
Dinesh
-----Original Message-----
From: dinesh <dinesh.dua@coraltele.com>
To: Nobin Mathew <nobin.mathew@gmail.com>
Cc: Grant Likely <grant.likely@secretlab.ca>, linuxppc-dev@ozlabs.org,
alsa-devel@alsa-project.org, liam.girdwood@wolfsonmicro.com
Subject: Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
Date: Wed, 16 Jul 2008 15:43:26 +0530
no i am working on powerpc. MPC8323
-----Original Message-----
From: Nobin Mathew <nobin.mathew@gmail.com>
To: dinesh <dinesh.dua@coraltele.com>
Cc: Grant Likely <grant.likely@secretlab.ca>, linuxppc-dev@ozlabs.org,
alsa-devel@alsa-project.org, liam.girdwood@wolfsonmicro.com
Subject: Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
Date: Wed, 16 Jul 2008 15:37:54 +0530
Hi dinesh,
If you are working on ARM, see the ARM AACi code, in sound/arm/aaci.c
Thanks
Nobin Mathew.
On 7/16/08, dinesh <dinesh.dua@coraltele.com> wrote:
>
> Hi,
> I am writing a soc sound driver for MPC8323 board linux 2.6.24 in which i
> want to do data transfer to and from device myself using BUFFER DESCRIPTOR
> not with the usual DMA transfer.
> Please help me.
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
[-- Attachment #2: Type: text/html, Size: 3509 bytes --]
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
2008-07-17 6:03 ` dinesh
@ 2008-07-17 10:56 ` Mark Brown
2008-07-17 11:26 ` Nobin Mathew
0 siblings, 1 reply; 46+ messages in thread
From: Mark Brown @ 2008-07-17 10:56 UTC (permalink / raw)
To: dinesh; +Cc: linuxppc-dev, alsa-devel, Nobin Mathew, liam.girdwood
On Thu, Jul 17, 2008 at 11:33:31AM +0530, dinesh wrote:
> What i want is that i have a buffer in driver code which is also handled
> by some other application i want that this buffer data is to be used for
> capture and playback stream fills data to another buffer which i can
> passover to my other application.
Depending on what exactly you're doing here you may find that this is
best implemented in user space with an ALSA plugin rather than doing it
as part of a driver. If you do want to do this in kernel space then the
parts of an ASoC driver which transfer audio data are just the same as
those for any other ALSA driver so things like sound/arm/aaci.c may
provide useful examples.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
2008-07-17 10:56 ` Mark Brown
@ 2008-07-17 11:26 ` Nobin Mathew
2008-07-17 12:05 ` Jon Smirl
0 siblings, 1 reply; 46+ messages in thread
From: Nobin Mathew @ 2008-07-17 11:26 UTC (permalink / raw)
To: dinesh, Nobin Mathew, Grant Likely, linuxppc-dev, alsa-devel,
liam.girdwood
[-- Attachment #1: Type: text/plain, Size: 949 bytes --]
Hi Dinesh,
If that is your requirement then go and see the actual code
sound/arm/aaci.c. They are not using DMA. It is programmed IO.
Thanks
Nobin Mathew
On 7/17/08, Mark Brown <broonie@opensource.wolfsonmicro.com> wrote:
>
> On Thu, Jul 17, 2008 at 11:33:31AM +0530, dinesh wrote:
>
> > What i want is that i have a buffer in driver code which is also handled
> > by some other application i want that this buffer data is to be used for
> > capture and playback stream fills data to another buffer which i can
> > passover to my other application.
>
> Depending on what exactly you're doing here you may find that this is
> best implemented in user space with an ALSA plugin rather than doing it
> as part of a driver. If you do want to do this in kernel space then the
> parts of an ASoC driver which transfer audio data are just the same as
> those for any other ALSA driver so things like sound/arm/aaci.c may
> provide useful examples.
>
[-- Attachment #2: Type: text/html, Size: 1374 bytes --]
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
2008-07-17 11:26 ` Nobin Mathew
@ 2008-07-17 12:05 ` Jon Smirl
0 siblings, 0 replies; 46+ messages in thread
From: Jon Smirl @ 2008-07-17 12:05 UTC (permalink / raw)
To: Nobin Mathew; +Cc: dinesh, alsa-devel, liam.girdwood, linuxppc-dev
On 7/17/08, Nobin Mathew <nobin.mathew@gmail.com> wrote:
> Hi Dinesh,
>
> If that is your requirement then go and see the actual code
> sound/arm/aaci.c. They are not using DMA. It is programmed IO.
Search around the list archives, the first version of the
Efika/mpc5200 ac97 driver was programmed IO. The next version updated
it to DMA.
>
>
> Thanks
> Nobin Mathew
>
>
> On 7/17/08, Mark Brown
> <broonie@opensource.wolfsonmicro.com> wrote:
> > On Thu, Jul 17, 2008 at 11:33:31AM +0530, dinesh wrote:
> >
> > > What i want is that i have a buffer in driver code which is also handled
> > > by some other application i want that this buffer data is to be used for
> > > capture and playback stream fills data to another buffer which i can
> > > passover to my other application.
> >
> > Depending on what exactly you're doing here you may find that this is
> > best implemented in user space with an ALSA plugin rather than doing it
> > as part of a driver. If you do want to do this in kernel space then the
> > parts of an ASoC driver which transfer audio data are just the same as
> > those for any other ALSA driver so things like sound/arm/aaci.c may
> > provide useful examples.
> >
>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver
2008-07-12 8:39 ` [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver Grant Likely
` (3 preceding siblings ...)
2008-07-16 9:05 ` WRITING AN SOC DRIVER WITHOUT DMA dinesh
@ 2008-07-17 16:02 ` Timur Tabi
4 siblings, 0 replies; 46+ messages in thread
From: Timur Tabi @ 2008-07-17 16:02 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
Grant Likely wrote:
> + aic26->codec.reg_cache_size = sizeof(aic26->reg_cache);
> + aic26->codec.reg_cache = aic26->reg_cache;
...
> + /* Register the sysfs files for debugging */
> + /* Create SysFS files */
> + rc = device_create_file(&spi->dev, &dev_attr_regs);
> + rc |= device_create_file(&spi->dev, &dev_attr_regs_cache);
> + rc |= device_create_file(&spi->dev, &dev_attr_keyclick);
> + if (rc)
> + dev_info(&spi->dev, "error creating sysfs files\n");
I believe ASoC creates sysfs entries if you use reg_cache and reg_cache_size, so
you should not be creating your own sysfs entries if you use these variables.
> +
> +#if defined(CONFIG_SND_SOC_OF)
> + /* Tell the of_soc helper about this codec */
> + of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
> + spi->dev.archdata.of_node);
> +#endif
I haven't paid any attention to the of_soc helper, because it's for ASoC V1
only. However, I don't understand why you need to reference it in the codec
driver. My CS4270 codec driver knows nothing about OF and works fine in
arch/powerpc.
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver
2008-07-14 11:45 ` Mark Brown
@ 2008-07-18 6:29 ` Grant Likely
2008-07-18 10:39 ` Mark Brown
0 siblings, 1 reply; 46+ messages in thread
From: Grant Likely @ 2008-07-18 6:29 UTC (permalink / raw)
To: linuxppc-dev, alsa-devel, liam.girdwood, jonsmirl
On Mon, Jul 14, 2008 at 12:45:55PM +0100, Mark Brown wrote:
> On Sat, Jul 12, 2008 at 02:39:39AM -0600, Grant Likely wrote:
>
> > ASoC Codec driver for the TLV320AIC26 device. This driver uses the ASoC
> > v1 API, so I don't expect it to get merged as-is, but I want to get it
> > out there for review.
>
> This looks basically good - most of the issues below are nitpicky.
>
> > + /* Configure PLL */
> > + pval = 1;
> > + jval = (fsref == 44100) ? 7 : 8;
> > + dval = (fsref == 44100) ? 5264 : 1920;
> > + qval = 0;
> > + reg = 0x8000 | qval << 11 | pval << 8 | jval << 2;
> > + aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg);
> > + reg = dval << 2;
> > + aic26_reg_write(codec, AIC26_REG_PLL_PROG2, reg);
>
> Does the PLL configuration not depend on the input clock frequency? You
> have a set_sysclk() method to configure the MCLK supplied but the driver
> never appears to reference the value anywhere.
Yes, this should be done better. I'm working on making this better, but
I'm hoping it is okay to have that as follow-on patches.
> > + /* Power up CODEC */
> > + aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0);
>
> As discussed this should probably just be removed from hw_params().
done
> > +static int aic26_set_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt)
> > +{
>
> > + /* interface format */
> > + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> > + case SND_SOC_DAIFMT_I2S: aic26->datfm = AIC26_DATFM_I2S; break;
> > + case SND_SOC_DAIFMT_DSP_A: aic26->datfm = AIC26_DATFM_DSP; break;
> > + case SND_SOC_DAIFMT_RIGHT_J: aic26->datfm = AIC26_DATFM_RIGHTJ; break;
> > + case SND_SOC_DAIFMT_LEFT_J: aic26->datfm = AIC26_DATFM_LEFTJ; break;
> > + default: dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
> > + }
>
> I'm having a hard time liking this indentation style. It's not an
> obstacle to merging but it doesn't really help legibility - there's not
> enough white space and once you have a non-standard line like the
> default: one.
Cleaned up.
> > +static const char *aic26_capture_src_text[] = {"Mic", "Aux"};
> > +static const struct soc_enum aic26_capture_src_enum =
> > + SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12,2, aic26_capture_src_text);
>
> checkpatch complains about the 12,2 here and a bunch of other stuff -
> ALSA is generally very strict about that.
Originally, that had been to keep the line under 80 chars, but some of
the names have changed since then to make it no longer necessary. I'll
clean up the checkpatch stuff.
>
> > + SOC_SINGLE("Keyclick activate", AIC26_REG_AUDIO_CTRL2, 15, 0x1, 0),
> > + SOC_SINGLE("Keyclick amplitude", AIC26_REG_AUDIO_CTRL2, 12, 0x7, 0),
> > + SOC_SINGLE("Keyclick frequency", AIC26_REG_AUDIO_CTRL2, 8, 0x7, 0),
> > + SOC_SINGLE("Keyclick period", AIC26_REG_AUDIO_CTRL2, 4, 0xf, 0),
>
> This configuration is also exposed via a sysfs file, including some of
> the configurability. Exposing the information via sysfs isn't a
> particular problem but allowing it to be written to without going
> through ALSA seems wrong.
All the written bit does is trigger the keyclick event. It doesn't
adjust the parameters in any way.
> > +static ssize_t aic26_regs_show(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
>
> As discussed this is replicating the existing codec register display
> sysfs file.
removed
> > +#if defined(CONFIG_SND_SOC_OF)
> > + /* Tell the of_soc helper about this codec */
> > + of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
> > + spi->dev.archdata.of_node);
> > +#endif
>
> CONFIG_SND_SOC_OF could be a module - this needs to also check for it
> being a module.
Doesn't #if defined() match on both static and module selection?
> > +#define AIC26_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)
> > +#define AIC26_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |\
> > + SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
>
> These are usually kept in the driver code.
fixed.
Thanks,
g.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-14 17:16 ` Mark Brown
2008-07-14 17:22 ` Grant Likely
@ 2008-07-18 7:17 ` Grant Likely
2008-07-18 10:00 ` Mark Brown
2008-07-18 14:59 ` Timur Tabi
1 sibling, 2 replies; 46+ messages in thread
From: Grant Likely @ 2008-07-18 7:17 UTC (permalink / raw)
To: linuxppc-dev, alsa-devel, liam.girdwood, jonsmirl
On Mon, Jul 14, 2008 at 06:16:33PM +0100, Mark Brown wrote:
> On Mon, Jul 14, 2008 at 11:06:34AM -0600, Grant Likely wrote:
>
> > I'm okay with that. How about fsl/mpc5200-of-machine.c for now?
> > (only the mpc5200 i2s driver uses it at the moment). It can always be
> > renamed if other folks want to use it for other chips.
>
> That seems reasonable so long as you're happy with it, though it does
> seem to be going to the other extreme in terms of broadness :)
Okay, I've changed my mind. :-) I'll back off a bit from this extreme and
call it:
sound/soc/fsl/soc-of-simple.c
Does that sound okay? If non-freescale chips decide to use it then it
can be moved out of the freescale director.
Cheers,
g.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-18 7:17 ` Grant Likely
@ 2008-07-18 10:00 ` Mark Brown
2008-07-18 14:59 ` Timur Tabi
1 sibling, 0 replies; 46+ messages in thread
From: Mark Brown @ 2008-07-18 10:00 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Fri, Jul 18, 2008 at 01:17:20AM -0600, Grant Likely wrote:
> Okay, I've changed my mind. :-) I'll back off a bit from this extreme and
> call it:
> sound/soc/fsl/soc-of-simple.c
> Does that sound okay? If non-freescale chips decide to use it then it
> can be moved out of the freescale director.
Fine by me - you could add an of directory but I don't mind either way
so long as the people actually using the code are happy.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver
2008-07-18 6:29 ` Grant Likely
@ 2008-07-18 10:39 ` Mark Brown
0 siblings, 0 replies; 46+ messages in thread
From: Mark Brown @ 2008-07-18 10:39 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
On Fri, Jul 18, 2008 at 12:29:37AM -0600, Grant Likely wrote:
> On Mon, Jul 14, 2008 at 12:45:55PM +0100, Mark Brown wrote:
> > On Sat, Jul 12, 2008 at 02:39:39AM -0600, Grant Likely wrote:
> > This configuration is also exposed via a sysfs file, including some of
> > the configurability. Exposing the information via sysfs isn't a
> > particular problem but allowing it to be written to without going
> > through ALSA seems wrong.
> All the written bit does is trigger the keyclick event. It doesn't
> adjust the parameters in any way.
That should be OK for now but we ought to work out a way of doing this
via an ALSA control so it can be standardised over the devices that
support it. I can't see anything suitable currently, though.
> > > +#if defined(CONFIG_SND_SOC_OF)
> > > + /* Tell the of_soc helper about this codec */
> > > + of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
> > > + spi->dev.archdata.of_node);
> > > +#endif
> > CONFIG_SND_SOC_OF could be a module - this needs to also check for it
> > being a module.
> Doesn't #if defined() match on both static and module selection?
Sadly not.
^ permalink raw reply [flat|nested] 46+ messages in thread
* Re: [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
2008-07-18 7:17 ` Grant Likely
2008-07-18 10:00 ` Mark Brown
@ 2008-07-18 14:59 ` Timur Tabi
1 sibling, 0 replies; 46+ messages in thread
From: Timur Tabi @ 2008-07-18 14:59 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
Grant Likely wrote:
> Okay, I've changed my mind. :-) I'll back off a bit from this extreme and
> call it:
>
> sound/soc/fsl/soc-of-simple.c
That works for me.
And please don't forget to CC: me on any discussion involving sound/soc/fsl.
--
Timur Tabi
Linux Kernel Developer @ Freescale
^ permalink raw reply [flat|nested] 46+ messages in thread
end of thread, other threads:[~2008-07-18 14:59 UTC | newest]
Thread overview: 46+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-12 8:39 [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers Grant Likely
2008-07-12 8:39 ` [PATCH v2 2/3] ALSA SoC: Add mpc5200-psc I2S driver Grant Likely
2008-07-14 12:10 ` [alsa-devel] " Mark Brown
2008-07-12 8:39 ` [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver Grant Likely
2008-07-12 18:10 ` [alsa-devel] " Mark Brown
2008-07-12 18:14 ` Grant Likely
2008-07-14 11:45 ` Mark Brown
2008-07-18 6:29 ` Grant Likely
2008-07-18 10:39 ` Mark Brown
2008-07-15 7:57 ` dinesh
2008-07-15 10:33 ` Mark Brown
2008-07-15 12:38 ` dinesh
2008-07-15 12:46 ` Mark Brown
2008-07-16 9:05 ` WRITING AN SOC DRIVER WITHOUT DMA dinesh
2008-07-16 10:07 ` [alsa-devel] " Nobin Mathew
2008-07-16 10:13 ` dinesh
2008-07-17 6:03 ` dinesh
2008-07-17 10:56 ` Mark Brown
2008-07-17 11:26 ` Nobin Mathew
2008-07-17 12:05 ` Jon Smirl
2008-07-17 16:02 ` [PATCH v2 3/3] ALSA SoC: Add Texas Instruments TLV320AIC26 codec driver Timur Tabi
2008-07-14 13:49 ` [alsa-devel] [PATCH v2 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers Mark Brown
2008-07-14 14:13 ` Jon Smirl
2008-07-14 15:05 ` Mark Brown
2008-07-14 16:14 ` Timur Tabi
2008-07-14 16:27 ` Grant Likely
2008-07-14 16:53 ` Mark Brown
2008-07-14 17:21 ` Grant Likely
2008-07-14 18:36 ` Mark Brown
2008-07-14 18:40 ` Timur Tabi
2008-07-14 18:49 ` Mark Brown
2008-07-14 18:53 ` Timur Tabi
2008-07-14 22:28 ` Grant Likely
2008-07-14 23:45 ` Jon Smirl
2008-07-15 10:13 ` Mark Brown
2008-07-15 13:08 ` Jon Smirl
2008-07-15 14:04 ` Mark Brown
2008-07-14 15:51 ` Timur Tabi
2008-07-14 17:06 ` Grant Likely
2008-07-14 17:16 ` Mark Brown
2008-07-14 17:22 ` Grant Likely
2008-07-18 7:17 ` Grant Likely
2008-07-18 10:00 ` Mark Brown
2008-07-18 14:59 ` Timur Tabi
2008-07-14 14:16 ` Anton Vorontsov
2008-07-14 17:11 ` Grant Likely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).