aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/fsl
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@slimlogic.co.uk>2010-03-17 16:15:21 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-12 09:00:00 -0400
commitf0fba2ad1b6b53d5360125c41953b7afcd6deff0 (patch)
treef6ad50905f8daa616593c978d7ae992e73241180 /sound/soc/fsl
parentbda7d2a862e6b788bca2d02d38a07966a9c92e48 (diff)
ASoC: multi-component - ASoC Multi-Component Support
This patch extends the ASoC API to allow sound cards to have more than one CODEC and more than one platform DMA controller. This is achieved by dividing some current ASoC structures that contain both driver data and device data into structures that only either contain device data or driver data. i.e. struct snd_soc_codec ---> struct snd_soc_codec (device data) +-> struct snd_soc_codec_driver (driver data) struct snd_soc_platform ---> struct snd_soc_platform (device data) +-> struct snd_soc_platform_driver (driver data) struct snd_soc_dai ---> struct snd_soc_dai (device data) +-> struct snd_soc_dai_driver (driver data) struct snd_soc_device ---> deleted This now allows ASoC to be more tightly aligned with the Linux driver model and also means that every ASoC codec, platform and (platform) DAI is a kernel device. ASoC component private data is now stored as device private data. The ASoC sound card struct snd_soc_card has also been updated to store lists of it's components rather than a pointer to a codec and platform. The PCM runtime struct soc_pcm_runtime now has pointers to all its components. This patch adds DAPM support for ASoC multi-component and removes struct snd_soc_socdev from DAPM core. All DAPM calls are now made on a card, codec or runtime PCM level basis rather than using snd_soc_socdev. Other notable multi-component changes:- * Stream operations now de-reference less structures. * close_delayed work() now runs on a DAI basis rather than looping all DAIs in a card. * PM suspend()/resume() operations can now handle N CODECs and Platforms per sound card. * Added soc_bind_dai_link() to bind the component devices to the sound card. * Added soc_dai_link_probe() and soc_dai_link_remove() to probe and remove DAI link components. * sysfs entries can now be registered per component per card. * snd_soc_new_pcms() functionailty rolled into dai_link_probe(). * snd_soc_register_codec() now does all the codec list and mutex init. This patch changes the probe() and remove() of the CODEC drivers as follows:- o Make CODEC driver a platform driver o Moved all struct snd_soc_codec list, mutex, etc initialiasation to core. o Removed all static codec pointers (drivers now support > 1 codec dev) o snd_soc_register_pcms() now done by core. o snd_soc_register_dai() folded into snd_soc_register_codec(). CS4270 portions: Acked-by: Timur Tabi <timur@freescale.com> Some TLV320aic23 and Cirrus platform fixes. Signed-off-by: Ryan Mallon <ryan@bluewatersys.com> TI CODEC and OMAP fixes Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> Samsung platform and misc fixes :- Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Jassi Brar <jassi.brar@samsung.com> Signed-off-by: Seungwhan Youn <sw.youn@samsung.com> MPC8610 and PPC fixes. Signed-off-by: Timur Tabi <timur@freescale.com> i.MX fixes and some core fixes. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> J4740 platform fixes:- Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> CC: Tony Lindgren <tony@atomide.com> CC: Nicolas Ferre <nicolas.ferre@atmel.com> CC: Kevin Hilman <khilman@deeprootsystems.com> CC: Sascha Hauer <s.hauer@pengutronix.de> CC: Atsushi Nemoto <anemo@mba.ocn.ne.jp> CC: Kuninori Morimoto <morimoto.kuninori@renesas.com> CC: Daniel Gloeckner <dg@emlix.com> CC: Manuel Lauss <mano@roarinelk.homelinux.net> CC: Mike Frysinger <vapier.adi@gmail.com> CC: Arnaud Patard <apatard@mandriva.com> CC: Wan ZongShun <mcuos.com@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r--sound/soc/fsl/Kconfig3
-rw-r--r--sound/soc/fsl/Makefile3
-rw-r--r--sound/soc/fsl/efika-audio-fabric.c20
-rw-r--r--sound/soc/fsl/fsl_dma.c312
-rw-r--r--sound/soc/fsl/fsl_dma.h20
-rw-r--r--sound/soc/fsl/fsl_ssi.c249
-rw-r--r--sound/soc/fsl/fsl_ssi.h26
-rw-r--r--sound/soc/fsl/mpc5200_dma.c66
-rw-r--r--sound/soc/fsl/mpc5200_dma.h5
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c34
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.h2
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c19
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c658
-rw-r--r--sound/soc/fsl/pcm030-audio-fabric.c21
-rw-r--r--sound/soc/fsl/soc-of-simple.c172
15 files changed, 728 insertions, 882 deletions
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 8cb65ccad35f..981868700388 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,6 +1,3 @@
1config SND_SOC_OF_SIMPLE
2 tristate
3
4config SND_MPC52xx_DMA 1config SND_MPC52xx_DMA
5 tristate 2 tristate
6 3
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index a83a73967ec6..7e472a53fcd3 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -1,6 +1,3 @@
1# Simple machine driver that extracts configuration from the OF device tree
2obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o
3
4# MPC8610 HPCD Machine Support 1# MPC8610 HPCD Machine Support
5snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o 2snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o
6obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o 3obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c
index 1a5b8e0d6a34..53251e6b5bd5 100644
--- a/sound/soc/fsl/efika-audio-fabric.c
+++ b/sound/soc/fsl/efika-audio-fabric.c
@@ -24,7 +24,6 @@
24#include <sound/pcm_params.h> 24#include <sound/pcm_params.h>
25#include <sound/initval.h> 25#include <sound/initval.h>
26#include <sound/soc.h> 26#include <sound/soc.h>
27#include <sound/soc-of-simple.h>
28 27
29#include "mpc5200_dma.h" 28#include "mpc5200_dma.h"
30#include "mpc5200_psc_ac97.h" 29#include "mpc5200_psc_ac97.h"
@@ -32,21 +31,24 @@
32 31
33#define DRV_NAME "efika-audio-fabric" 32#define DRV_NAME "efika-audio-fabric"
34 33
35static struct snd_soc_device device;
36static struct snd_soc_card card; 34static struct snd_soc_card card;
37 35
38static struct snd_soc_dai_link efika_fabric_dai[] = { 36static struct snd_soc_dai_link efika_fabric_dai[] = {
39{ 37{
40 .name = "AC97", 38 .name = "AC97",
41 .stream_name = "AC97 Analog", 39 .stream_name = "AC97 Analog",
42 .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_ANALOG], 40 .codec_dai_name = "stac9766-hifi-analog",
43 .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL], 41 .cpu_dai_name = "mpc5200-psc-ac97.0",
42 .platform_name = "mpc5200-pcm-audio",
43 .codec_name = "stac9766-codec",
44}, 44},
45{ 45{
46 .name = "AC97", 46 .name = "AC97",
47 .stream_name = "AC97 IEC958", 47 .stream_name = "AC97 IEC958",
48 .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_DIGITAL], 48 .codec_dai_name = "stac9766-hifi-IEC958",
49 .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF], 49 .cpu_dai_name = "mpc5200-psc-ac97.1",
50 .platform_name = "mpc5200-pcm-audio",
51 .codec_name = "stac9766-codec",
50}, 52},
51}; 53};
52 54
@@ -58,13 +60,10 @@ static __init int efika_fabric_init(void)
58 if (!of_machine_is_compatible("bplan,efika")) 60 if (!of_machine_is_compatible("bplan,efika"))
59 return -ENODEV; 61 return -ENODEV;
60 62
61 card.platform = &mpc5200_audio_dma_platform;
62 card.name = "Efika"; 63 card.name = "Efika";
63 card.dai_link = efika_fabric_dai; 64 card.dai_link = efika_fabric_dai;
64 card.num_links = ARRAY_SIZE(efika_fabric_dai); 65 card.num_links = ARRAY_SIZE(efika_fabric_dai);
65 66
66 device.card = &card;
67 device.codec_dev = &soc_codec_dev_stac9766;
68 67
69 pdev = platform_device_alloc("soc-audio", 1); 68 pdev = platform_device_alloc("soc-audio", 1);
70 if (!pdev) { 69 if (!pdev) {
@@ -72,8 +71,7 @@ static __init int efika_fabric_init(void)
72 return -ENODEV; 71 return -ENODEV;
73 } 72 }
74 73
75 platform_set_drvdata(pdev, &device); 74 platform_set_drvdata(pdev, &card);
76 device.dev = &pdev->dev;
77 75
78 rc = platform_device_add(pdev); 76 rc = platform_device_add(pdev);
79 if (rc) { 77 if (rc) {
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 410c7496a18d..d09e1941b1fa 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -3,10 +3,11 @@
3 * 3 *
4 * Author: Timur Tabi <timur@freescale.com> 4 * Author: Timur Tabi <timur@freescale.com>
5 * 5 *
6 * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed 6 * Copyright 2007-2010 Freescale Semiconductor, Inc.
7 * under the terms of the GNU General Public License version 2. This 7 *
8 * program is licensed "as is" without any warranty of any kind, whether 8 * This file is licensed under the terms of the GNU General Public License
9 * express or implied. 9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
10 * 11 *
11 * This driver implements ASoC support for the Elo DMA controller, which is 12 * This driver implements ASoC support for the Elo DMA controller, which is
12 * the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms, 13 * the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms,
@@ -20,6 +21,8 @@
20#include <linux/interrupt.h> 21#include <linux/interrupt.h>
21#include <linux/delay.h> 22#include <linux/delay.h>
22#include <linux/gfp.h> 23#include <linux/gfp.h>
24#include <linux/of_platform.h>
25#include <linux/list.h>
23 26
24#include <sound/core.h> 27#include <sound/core.h>
25#include <sound/pcm.h> 28#include <sound/pcm.h>
@@ -29,6 +32,7 @@
29#include <asm/io.h> 32#include <asm/io.h>
30 33
31#include "fsl_dma.h" 34#include "fsl_dma.h"
35#include "fsl_ssi.h" /* For the offset of stx0 and srx0 */
32 36
33/* 37/*
34 * The formats that the DMA controller supports, which is anything 38 * The formats that the DMA controller supports, which is anything
@@ -52,26 +56,16 @@
52#define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \ 56#define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
53 SNDRV_PCM_RATE_CONTINUOUS) 57 SNDRV_PCM_RATE_CONTINUOUS)
54 58
55/* DMA global data. This structure is used by fsl_dma_open() to determine 59struct dma_object {
56 * which DMA channels to assign to a substream. Unfortunately, ASoC V1 does 60 struct list_head list;
57 * not allow the machine driver to provide this information to the PCM 61 struct snd_soc_platform_driver dai;
58 * driver in advance, and there's no way to differentiate between the two
59 * DMA controllers. So for now, this driver only supports one SSI device
60 * using two DMA channels. We cannot support multiple DMA devices.
61 *
62 * ssi_stx_phys: bus address of SSI STX register
63 * ssi_srx_phys: bus address of SSI SRX register
64 * dma_channel: pointer to the DMA channel's registers
65 * irq: IRQ for this DMA channel
66 * assigned: set to 1 if that DMA channel is assigned to a substream
67 */
68static struct {
69 dma_addr_t ssi_stx_phys; 62 dma_addr_t ssi_stx_phys;
70 dma_addr_t ssi_srx_phys; 63 dma_addr_t ssi_srx_phys;
71 struct ccsr_dma_channel __iomem *dma_channel[2]; 64 struct ccsr_dma_channel __iomem *channel;
72 unsigned int irq[2]; 65 unsigned int irq;
73 unsigned int assigned[2]; 66 bool assigned;
74} dma_global_data; 67 char path[1];
68};
75 69
76/* 70/*
77 * The number of DMA links to use. Two is the bare minimum, but if you 71 * The number of DMA links to use. Two is the bare minimum, but if you
@@ -88,8 +82,6 @@ static struct {
88 * structure. 82 * structure.
89 * 83 *
90 * @link[]: array of link descriptors 84 * @link[]: array of link descriptors
91 * @controller_id: which DMA controller (0, 1, ...)
92 * @channel_id: which DMA channel on the controller (0, 1, 2, ...)
93 * @dma_channel: pointer to the DMA channel's registers 85 * @dma_channel: pointer to the DMA channel's registers
94 * @irq: IRQ for this DMA channel 86 * @irq: IRQ for this DMA channel
95 * @substream: pointer to the substream object, needed by the ISR 87 * @substream: pointer to the substream object, needed by the ISR
@@ -104,8 +96,6 @@ static struct {
104 */ 96 */
105struct fsl_dma_private { 97struct fsl_dma_private {
106 struct fsl_dma_link_descriptor link[NUM_DMA_LINKS]; 98 struct fsl_dma_link_descriptor link[NUM_DMA_LINKS];
107 unsigned int controller_id;
108 unsigned int channel_id;
109 struct ccsr_dma_channel __iomem *dma_channel; 99 struct ccsr_dma_channel __iomem *dma_channel;
110 unsigned int irq; 100 unsigned int irq;
111 struct snd_pcm_substream *substream; 101 struct snd_pcm_substream *substream;
@@ -212,6 +202,9 @@ static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private)
212static irqreturn_t fsl_dma_isr(int irq, void *dev_id) 202static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
213{ 203{
214 struct fsl_dma_private *dma_private = dev_id; 204 struct fsl_dma_private *dma_private = dev_id;
205 struct snd_pcm_substream *substream = dma_private->substream;
206 struct snd_soc_pcm_runtime *rtd = substream->private_data;
207 struct device *dev = rtd->platform->dev;
215 struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; 208 struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
216 irqreturn_t ret = IRQ_NONE; 209 irqreturn_t ret = IRQ_NONE;
217 u32 sr, sr2 = 0; 210 u32 sr, sr2 = 0;
@@ -222,11 +215,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
222 sr = in_be32(&dma_channel->sr); 215 sr = in_be32(&dma_channel->sr);
223 216
224 if (sr & CCSR_DMA_SR_TE) { 217 if (sr & CCSR_DMA_SR_TE) {
225 dev_err(dma_private->substream->pcm->card->dev, 218 dev_err(dev, "dma transmit error\n");
226 "DMA transmit error (controller=%u channel=%u irq=%u\n", 219 fsl_dma_abort_stream(substream);
227 dma_private->controller_id,
228 dma_private->channel_id, irq);
229 fsl_dma_abort_stream(dma_private->substream);
230 sr2 |= CCSR_DMA_SR_TE; 220 sr2 |= CCSR_DMA_SR_TE;
231 ret = IRQ_HANDLED; 221 ret = IRQ_HANDLED;
232 } 222 }
@@ -235,11 +225,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
235 ret = IRQ_HANDLED; 225 ret = IRQ_HANDLED;
236 226
237 if (sr & CCSR_DMA_SR_PE) { 227 if (sr & CCSR_DMA_SR_PE) {
238 dev_err(dma_private->substream->pcm->card->dev, 228 dev_err(dev, "dma programming error\n");
239 "DMA%u programming error (channel=%u irq=%u)\n", 229 fsl_dma_abort_stream(substream);
240 dma_private->controller_id,
241 dma_private->channel_id, irq);
242 fsl_dma_abort_stream(dma_private->substream);
243 sr2 |= CCSR_DMA_SR_PE; 230 sr2 |= CCSR_DMA_SR_PE;
244 ret = IRQ_HANDLED; 231 ret = IRQ_HANDLED;
245 } 232 }
@@ -253,8 +240,6 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
253 ret = IRQ_HANDLED; 240 ret = IRQ_HANDLED;
254 241
255 if (sr & CCSR_DMA_SR_EOSI) { 242 if (sr & CCSR_DMA_SR_EOSI) {
256 struct snd_pcm_substream *substream = dma_private->substream;
257
258 /* Tell ALSA we completed a period. */ 243 /* Tell ALSA we completed a period. */
259 snd_pcm_period_elapsed(substream); 244 snd_pcm_period_elapsed(substream);
260 245
@@ -305,10 +290,8 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
305 fsl_dma_hardware.buffer_bytes_max, 290 fsl_dma_hardware.buffer_bytes_max,
306 &pcm->streams[0].substream->dma_buffer); 291 &pcm->streams[0].substream->dma_buffer);
307 if (ret) { 292 if (ret) {
308 dev_err(card->dev, 293 dev_err(card->dev, "can't allocate playback dma buffer\n");
309 "Can't allocate playback DMA buffer (size=%u)\n", 294 return ret;
310 fsl_dma_hardware.buffer_bytes_max);
311 return -ENOMEM;
312 } 295 }
313 296
314 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev, 297 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
@@ -316,10 +299,8 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
316 &pcm->streams[1].substream->dma_buffer); 299 &pcm->streams[1].substream->dma_buffer);
317 if (ret) { 300 if (ret) {
318 snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer); 301 snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
319 dev_err(card->dev, 302 dev_err(card->dev, "can't allocate capture dma buffer\n");
320 "Can't allocate capture DMA buffer (size=%u)\n", 303 return ret;
321 fsl_dma_hardware.buffer_bytes_max);
322 return -ENOMEM;
323 } 304 }
324 305
325 return 0; 306 return 0;
@@ -390,6 +371,10 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
390static int fsl_dma_open(struct snd_pcm_substream *substream) 371static int fsl_dma_open(struct snd_pcm_substream *substream)
391{ 372{
392 struct snd_pcm_runtime *runtime = substream->runtime; 373 struct snd_pcm_runtime *runtime = substream->runtime;
374 struct snd_soc_pcm_runtime *rtd = substream->private_data;
375 struct device *dev = rtd->platform->dev;
376 struct dma_object *dma =
377 container_of(rtd->platform->driver, struct dma_object, dai);
393 struct fsl_dma_private *dma_private; 378 struct fsl_dma_private *dma_private;
394 struct ccsr_dma_channel __iomem *dma_channel; 379 struct ccsr_dma_channel __iomem *dma_channel;
395 dma_addr_t ld_buf_phys; 380 dma_addr_t ld_buf_phys;
@@ -407,52 +392,44 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
407 ret = snd_pcm_hw_constraint_integer(runtime, 392 ret = snd_pcm_hw_constraint_integer(runtime,
408 SNDRV_PCM_HW_PARAM_PERIODS); 393 SNDRV_PCM_HW_PARAM_PERIODS);
409 if (ret < 0) { 394 if (ret < 0) {
410 dev_err(substream->pcm->card->dev, "invalid buffer size\n"); 395 dev_err(dev, "invalid buffer size\n");
411 return ret; 396 return ret;
412 } 397 }
413 398
414 channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; 399 channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
415 400
416 if (dma_global_data.assigned[channel]) { 401 if (dma->assigned) {
417 dev_err(substream->pcm->card->dev, 402 dev_err(dev, "dma channel already assigned\n");
418 "DMA channel already assigned\n");
419 return -EBUSY; 403 return -EBUSY;
420 } 404 }
421 405
422 dma_private = dma_alloc_coherent(substream->pcm->card->dev, 406 dma_private = dma_alloc_coherent(dev, sizeof(struct fsl_dma_private),
423 sizeof(struct fsl_dma_private), &ld_buf_phys, GFP_KERNEL); 407 &ld_buf_phys, GFP_KERNEL);
424 if (!dma_private) { 408 if (!dma_private) {
425 dev_err(substream->pcm->card->dev, 409 dev_err(dev, "can't allocate dma private data\n");
426 "can't allocate DMA private data\n");
427 return -ENOMEM; 410 return -ENOMEM;
428 } 411 }
429 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 412 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
430 dma_private->ssi_sxx_phys = dma_global_data.ssi_stx_phys; 413 dma_private->ssi_sxx_phys = dma->ssi_stx_phys;
431 else 414 else
432 dma_private->ssi_sxx_phys = dma_global_data.ssi_srx_phys; 415 dma_private->ssi_sxx_phys = dma->ssi_srx_phys;
433 416
434 dma_private->dma_channel = dma_global_data.dma_channel[channel]; 417 dma_private->dma_channel = dma->channel;
435 dma_private->irq = dma_global_data.irq[channel]; 418 dma_private->irq = dma->irq;
436 dma_private->substream = substream; 419 dma_private->substream = substream;
437 dma_private->ld_buf_phys = ld_buf_phys; 420 dma_private->ld_buf_phys = ld_buf_phys;
438 dma_private->dma_buf_phys = substream->dma_buffer.addr; 421 dma_private->dma_buf_phys = substream->dma_buffer.addr;
439 422
440 /* We only support one DMA controller for now */
441 dma_private->controller_id = 0;
442 dma_private->channel_id = channel;
443
444 ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "DMA", dma_private); 423 ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "DMA", dma_private);
445 if (ret) { 424 if (ret) {
446 dev_err(substream->pcm->card->dev, 425 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
447 "can't register ISR for IRQ %u (ret=%i)\n",
448 dma_private->irq, ret); 426 dma_private->irq, ret);
449 dma_free_coherent(substream->pcm->card->dev, 427 dma_free_coherent(dev, sizeof(struct fsl_dma_private),
450 sizeof(struct fsl_dma_private),
451 dma_private, dma_private->ld_buf_phys); 428 dma_private, dma_private->ld_buf_phys);
452 return ret; 429 return ret;
453 } 430 }
454 431
455 dma_global_data.assigned[channel] = 1; 432 dma->assigned = 1;
456 433
457 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 434 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
458 snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware); 435 snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware);
@@ -546,6 +523,8 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
546{ 523{
547 struct snd_pcm_runtime *runtime = substream->runtime; 524 struct snd_pcm_runtime *runtime = substream->runtime;
548 struct fsl_dma_private *dma_private = runtime->private_data; 525 struct fsl_dma_private *dma_private = runtime->private_data;
526 struct snd_soc_pcm_runtime *rtd = substream->private_data;
527 struct device *dev = rtd->platform->dev;
549 528
550 /* Number of bits per sample */ 529 /* Number of bits per sample */
551 unsigned int sample_size = 530 unsigned int sample_size =
@@ -606,8 +585,7 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
606 break; 585 break;
607 default: 586 default:
608 /* We should never get here */ 587 /* We should never get here */
609 dev_err(substream->pcm->card->dev, 588 dev_err(dev, "unsupported sample size %u\n", sample_size);
610 "unsupported sample size %u\n", sample_size);
611 return -EINVAL; 589 return -EINVAL;
612 } 590 }
613 591
@@ -689,6 +667,8 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
689{ 667{
690 struct snd_pcm_runtime *runtime = substream->runtime; 668 struct snd_pcm_runtime *runtime = substream->runtime;
691 struct fsl_dma_private *dma_private = runtime->private_data; 669 struct fsl_dma_private *dma_private = runtime->private_data;
670 struct snd_soc_pcm_runtime *rtd = substream->private_data;
671 struct device *dev = rtd->platform->dev;
692 struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; 672 struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
693 dma_addr_t position; 673 dma_addr_t position;
694 snd_pcm_uframes_t frames; 674 snd_pcm_uframes_t frames;
@@ -710,8 +690,7 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
710 690
711 if ((position < dma_private->dma_buf_phys) || 691 if ((position < dma_private->dma_buf_phys) ||
712 (position > dma_private->dma_buf_end)) { 692 (position > dma_private->dma_buf_end)) {
713 dev_err(substream->pcm->card->dev, 693 dev_err(dev, "dma pointer is out of range, halting stream\n");
714 "dma pointer is out of range, halting stream\n");
715 return SNDRV_PCM_POS_XRUN; 694 return SNDRV_PCM_POS_XRUN;
716 } 695 }
717 696
@@ -772,26 +751,28 @@ static int fsl_dma_close(struct snd_pcm_substream *substream)
772{ 751{
773 struct snd_pcm_runtime *runtime = substream->runtime; 752 struct snd_pcm_runtime *runtime = substream->runtime;
774 struct fsl_dma_private *dma_private = runtime->private_data; 753 struct fsl_dma_private *dma_private = runtime->private_data;
775 int dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; 754 struct snd_soc_pcm_runtime *rtd = substream->private_data;
755 struct device *dev = rtd->platform->dev;
756 struct dma_object *dma =
757 container_of(rtd->platform->driver, struct dma_object, dai);
776 758
777 if (dma_private) { 759 if (dma_private) {
778 if (dma_private->irq) 760 if (dma_private->irq)
779 free_irq(dma_private->irq, dma_private); 761 free_irq(dma_private->irq, dma_private);
780 762
781 if (dma_private->ld_buf_phys) { 763 if (dma_private->ld_buf_phys) {
782 dma_unmap_single(substream->pcm->card->dev, 764 dma_unmap_single(dev, dma_private->ld_buf_phys,
783 dma_private->ld_buf_phys, 765 sizeof(dma_private->link),
784 sizeof(dma_private->link), DMA_TO_DEVICE); 766 DMA_TO_DEVICE);
785 } 767 }
786 768
787 /* Deallocate the fsl_dma_private structure */ 769 /* Deallocate the fsl_dma_private structure */
788 dma_free_coherent(substream->pcm->card->dev, 770 dma_free_coherent(dev, sizeof(struct fsl_dma_private),
789 sizeof(struct fsl_dma_private), 771 dma_private, dma_private->ld_buf_phys);
790 dma_private, dma_private->ld_buf_phys);
791 substream->runtime->private_data = NULL; 772 substream->runtime->private_data = NULL;
792 } 773 }
793 774
794 dma_global_data.assigned[dir] = 0; 775 dma->assigned = 0;
795 776
796 return 0; 777 return 0;
797} 778}
@@ -814,6 +795,40 @@ static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm)
814 } 795 }
815} 796}
816 797
798/* List of DMA nodes that we've probed */
799static LIST_HEAD(dma_list);
800
801/**
802 * find_ssi_node -- returns the SSI node that points to his DMA channel node
803 *
804 * Although this DMA driver attempts to operate independently of the other
805 * devices, it still needs to determine some information about the SSI device
806 * that it's working with. Unfortunately, the device tree does not contain
807 * a pointer from the DMA channel node to the SSI node -- the pointer goes the
808 * other way. So we need to scan the device tree for SSI nodes until we find
809 * the one that points to the given DMA channel node. It's ugly, but at least
810 * it's contained in this one function.
811 */
812static struct device_node *find_ssi_node(struct device_node *dma_channel_np)
813{
814 struct device_node *ssi_np, *np;
815
816 for_each_compatible_node(ssi_np, NULL, "fsl,mpc8610-ssi") {
817 /* Check each DMA phandle to see if it points to us. We
818 * assume that device_node pointers are a valid comparison.
819 */
820 np = of_parse_phandle(ssi_np, "fsl,playback-dma", 0);
821 if (np == dma_channel_np)
822 return ssi_np;
823
824 np = of_parse_phandle(ssi_np, "fsl,capture-dma", 0);
825 if (np == dma_channel_np)
826 return ssi_np;
827 }
828
829 return NULL;
830}
831
817static struct snd_pcm_ops fsl_dma_ops = { 832static struct snd_pcm_ops fsl_dma_ops = {
818 .open = fsl_dma_open, 833 .open = fsl_dma_open,
819 .close = fsl_dma_close, 834 .close = fsl_dma_close,
@@ -823,59 +838,112 @@ static struct snd_pcm_ops fsl_dma_ops = {
823 .pointer = fsl_dma_pointer, 838 .pointer = fsl_dma_pointer,
824}; 839};
825 840
826struct snd_soc_platform fsl_soc_platform = { 841static int __devinit fsl_soc_dma_probe(struct of_device *of_dev,
827 .name = "fsl-dma", 842 const struct of_device_id *match)
828 .pcm_ops = &fsl_dma_ops, 843 {
829 .pcm_new = fsl_dma_new, 844 struct dma_object *dma;
830 .pcm_free = fsl_dma_free_dma_buffers, 845 struct device_node *np = of_dev->dev.of_node;
831}; 846 struct device_node *ssi_np;
832EXPORT_SYMBOL_GPL(fsl_soc_platform); 847 struct resource res;
848 int ret;
833 849
834/** 850 /* Find the SSI node that points to us. */
835 * fsl_dma_configure: store the DMA parameters from the fabric driver. 851 ssi_np = find_ssi_node(np);
836 * 852 if (!ssi_np) {
837 * This function is called by the ASoC fabric driver to give us the DMA and 853 dev_err(&of_dev->dev, "cannot find parent SSI node\n");
838 * SSI channel information. 854 return -ENODEV;
839 * 855 }
840 * Unfortunately, ASoC V1 does make it possible to determine the DMA/SSI 856
841 * data when a substream is created, so for now we need to store this data 857 ret = of_address_to_resource(ssi_np, 0, &res);
842 * into a global variable. This means that we can only support one DMA 858 of_node_put(ssi_np);
843 * controller, and hence only one SSI. 859 if (ret) {
844 */ 860 dev_err(&of_dev->dev, "could not determine device resources\n");
845int fsl_dma_configure(struct fsl_dma_info *dma_info) 861 return ret;
862 }
863
864 dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL);
865 if (!dma) {
866 dev_err(&of_dev->dev, "could not allocate dma object\n");
867 return -ENOMEM;
868 }
869
870 strcpy(dma->path, np->full_name);
871 dma->dai.ops = &fsl_dma_ops;
872 dma->dai.pcm_new = fsl_dma_new;
873 dma->dai.pcm_free = fsl_dma_free_dma_buffers;
874
875 /* Store the SSI-specific information that we need */
876 dma->ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0);
877 dma->ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0);
878
879 ret = snd_soc_register_platform(&of_dev->dev, &dma->dai);
880 if (ret) {
881 dev_err(&of_dev->dev, "could not register platform\n");
882 kfree(dma);
883 return ret;
884 }
885
886 dma->channel = of_iomap(np, 0);
887 dma->irq = irq_of_parse_and_map(np, 0);
888 list_add(&dma->list, &dma_list);
889
890 return 0;
891}
892
893static int __devexit fsl_soc_dma_remove(struct of_device *of_dev)
846{ 894{
847 static int initialized; 895 struct list_head *n, *ptr;
896 struct dma_object *dma;
848 897
849 /* We only support one DMA controller for now */ 898 list_for_each_safe(ptr, n, &dma_list) {
850 if (initialized) 899 dma = list_entry(ptr, struct dma_object, list);
851 return 0; 900 list_del_init(ptr);
901
902 snd_soc_unregister_platform(&of_dev->dev);
903 iounmap(dma->channel);
904 irq_dispose_mapping(dma->irq);
905 kfree(dma);
906 }
852 907
853 dma_global_data.ssi_stx_phys = dma_info->ssi_stx_phys; 908 return 0;
854 dma_global_data.ssi_srx_phys = dma_info->ssi_srx_phys;
855 dma_global_data.dma_channel[0] = dma_info->dma_channel[0];
856 dma_global_data.dma_channel[1] = dma_info->dma_channel[1];
857 dma_global_data.irq[0] = dma_info->dma_irq[0];
858 dma_global_data.irq[1] = dma_info->dma_irq[1];
859 dma_global_data.assigned[0] = 0;
860 dma_global_data.assigned[1] = 0;
861
862 initialized = 1;
863 return 1;
864} 909}
865EXPORT_SYMBOL_GPL(fsl_dma_configure);
866 910
867static int __init fsl_soc_platform_init(void) 911static const struct of_device_id fsl_soc_dma_ids[] = {
912 { .compatible = "fsl,ssi-dma-channel", },
913 {}
914};
915MODULE_DEVICE_TABLE(of, fsl_soc_dma_ids);
916
917static struct of_platform_driver fsl_soc_dma_driver = {
918 .driver = {
919 .name = "fsl-pcm-audio",
920 .owner = THIS_MODULE,
921 .of_match_table = fsl_soc_dma_ids,
922 },
923 .probe = fsl_soc_dma_probe,
924 .remove = __devexit_p(fsl_soc_dma_remove),
925};
926
927static int __init fsl_soc_dma_init(void)
868{ 928{
869 return snd_soc_register_platform(&fsl_soc_platform); 929 pr_info("Freescale Elo DMA ASoC PCM Driver\n");
930
931 return of_register_platform_driver(&fsl_soc_dma_driver);
870} 932}
871module_init(fsl_soc_platform_init);
872 933
873static void __exit fsl_soc_platform_exit(void) 934static void __exit fsl_soc_dma_exit(void)
874{ 935{
875 snd_soc_unregister_platform(&fsl_soc_platform); 936 of_unregister_platform_driver(&fsl_soc_dma_driver);
876} 937}
877module_exit(fsl_soc_platform_exit); 938
939/* We want the DMA driver to be initialized before the SSI driver, so that
940 * when the SSI driver calls fsl_soc_dma_dai_from_node(), the DMA driver
941 * will already have been probed. The easiest way to do that is to make the
942 * __init function called via arch_initcall().
943 */
944module_init(fsl_soc_dma_init);
945module_exit(fsl_soc_dma_exit);
878 946
879MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); 947MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
880MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module"); 948MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM Driver");
881MODULE_LICENSE("GPL"); 949MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h
index 385d4a42603c..78fee97e8036 100644
--- a/sound/soc/fsl/fsl_dma.h
+++ b/sound/soc/fsl/fsl_dma.h
@@ -126,24 +126,4 @@ struct fsl_dma_link_descriptor {
126 u8 res[4]; /* Reserved */ 126 u8 res[4]; /* Reserved */
127} __attribute__ ((aligned(32), packed)); 127} __attribute__ ((aligned(32), packed));
128 128
129/* DMA information needed to create a snd_soc_dai object
130 *
131 * ssi_stx_phys: bus address of SSI STX register to use
132 * ssi_srx_phys: bus address of SSI SRX register to use
133 * dma[0]: points to the DMA channel to use for playback
134 * dma[1]: points to the DMA channel to use for capture
135 * dma_irq[0]: IRQ of the DMA channel to use for playback
136 * dma_irq[1]: IRQ of the DMA channel to use for capture
137 */
138struct fsl_dma_info {
139 dma_addr_t ssi_stx_phys;
140 dma_addr_t ssi_srx_phys;
141 struct ccsr_dma_channel __iomem *dma_channel[2];
142 unsigned int dma_irq[2];
143};
144
145extern struct snd_soc_platform fsl_soc_platform;
146
147int fsl_dma_configure(struct fsl_dma_info *dma_info);
148
149#endif 129#endif
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 762c1b8e8e4e..64f65910a7d7 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -3,10 +3,11 @@
3 * 3 *
4 * Author: Timur Tabi <timur@freescale.com> 4 * Author: Timur Tabi <timur@freescale.com>
5 * 5 *
6 * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed 6 * Copyright 2007-2010 Freescale Semiconductor, Inc.
7 * under the terms of the GNU General Public License version 2. This 7 *
8 * program is licensed "as is" without any warranty of any kind, whether 8 * This file is licensed under the terms of the GNU General Public License
9 * express or implied. 9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
10 */ 11 */
11 12
12#include <linux/init.h> 13#include <linux/init.h>
@@ -15,6 +16,7 @@
15#include <linux/device.h> 16#include <linux/device.h>
16#include <linux/delay.h> 17#include <linux/delay.h>
17#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/of_platform.h>
18 20
19#include <sound/core.h> 21#include <sound/core.h>
20#include <sound/pcm.h> 22#include <sound/pcm.h>
@@ -71,33 +73,31 @@
71/** 73/**
72 * fsl_ssi_private: per-SSI private data 74 * fsl_ssi_private: per-SSI private data
73 * 75 *
74 * @name: short name for this device ("SSI0", "SSI1", etc)
75 * @ssi: pointer to the SSI's registers 76 * @ssi: pointer to the SSI's registers
76 * @ssi_phys: physical address of the SSI registers 77 * @ssi_phys: physical address of the SSI registers
77 * @irq: IRQ of this SSI 78 * @irq: IRQ of this SSI
78 * @first_stream: pointer to the stream that was opened first 79 * @first_stream: pointer to the stream that was opened first
79 * @second_stream: pointer to second stream 80 * @second_stream: pointer to second stream
80 * @dev: struct device pointer
81 * @playback: the number of playback streams opened 81 * @playback: the number of playback streams opened
82 * @capture: the number of capture streams opened 82 * @capture: the number of capture streams opened
83 * @asynchronous: 0=synchronous mode, 1=asynchronous mode 83 * @asynchronous: 0=synchronous mode, 1=asynchronous mode
84 * @cpu_dai: the CPU DAI for this device 84 * @cpu_dai: the CPU DAI for this device
85 * @dev_attr: the sysfs device attribute structure 85 * @dev_attr: the sysfs device attribute structure
86 * @stats: SSI statistics 86 * @stats: SSI statistics
87 * @name: name for this device
87 */ 88 */
88struct fsl_ssi_private { 89struct fsl_ssi_private {
89 char name[8];
90 struct ccsr_ssi __iomem *ssi; 90 struct ccsr_ssi __iomem *ssi;
91 dma_addr_t ssi_phys; 91 dma_addr_t ssi_phys;
92 unsigned int irq; 92 unsigned int irq;
93 struct snd_pcm_substream *first_stream; 93 struct snd_pcm_substream *first_stream;
94 struct snd_pcm_substream *second_stream; 94 struct snd_pcm_substream *second_stream;
95 struct device *dev;
96 unsigned int playback; 95 unsigned int playback;
97 unsigned int capture; 96 unsigned int capture;
98 int asynchronous; 97 int asynchronous;
99 struct snd_soc_dai cpu_dai; 98 struct snd_soc_dai_driver cpu_dai_drv;
100 struct device_attribute dev_attr; 99 struct device_attribute dev_attr;
100 struct platform_device *pdev;
101 101
102 struct { 102 struct {
103 unsigned int rfrc; 103 unsigned int rfrc;
@@ -122,6 +122,8 @@ struct fsl_ssi_private {
122 unsigned int tfe1; 122 unsigned int tfe1;
123 unsigned int tfe0; 123 unsigned int tfe0;
124 } stats; 124 } stats;
125
126 char name[1];
125}; 127};
126 128
127/** 129/**
@@ -280,7 +282,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
280 struct snd_soc_dai *dai) 282 struct snd_soc_dai *dai)
281{ 283{
282 struct snd_soc_pcm_runtime *rtd = substream->private_data; 284 struct snd_soc_pcm_runtime *rtd = substream->private_data;
283 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; 285 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
284 286
285 /* 287 /*
286 * If this is the first stream opened, then request the IRQ 288 * If this is the first stream opened, then request the IRQ
@@ -290,6 +292,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
290 struct ccsr_ssi __iomem *ssi = ssi_private->ssi; 292 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
291 int ret; 293 int ret;
292 294
295 /* The 'name' should not have any slashes in it. */
293 ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0, 296 ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0,
294 ssi_private->name, ssi_private); 297 ssi_private->name, ssi_private);
295 if (ret < 0) { 298 if (ret < 0) {
@@ -422,7 +425,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
422static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, 425static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
423 struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai) 426 struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
424{ 427{
425 struct fsl_ssi_private *ssi_private = cpu_dai->private_data; 428 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
426 429
427 if (substream == ssi_private->first_stream) { 430 if (substream == ssi_private->first_stream) {
428 struct ccsr_ssi __iomem *ssi = ssi_private->ssi; 431 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
@@ -458,7 +461,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
458 struct snd_soc_dai *dai) 461 struct snd_soc_dai *dai)
459{ 462{
460 struct snd_soc_pcm_runtime *rtd = substream->private_data; 463 struct snd_soc_pcm_runtime *rtd = substream->private_data;
461 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; 464 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
462 struct ccsr_ssi __iomem *ssi = ssi_private->ssi; 465 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
463 466
464 switch (cmd) { 467 switch (cmd) {
@@ -497,7 +500,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
497 struct snd_soc_dai *dai) 500 struct snd_soc_dai *dai)
498{ 501{
499 struct snd_soc_pcm_runtime *rtd = substream->private_data; 502 struct snd_soc_pcm_runtime *rtd = substream->private_data;
500 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; 503 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
501 504
502 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 505 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
503 ssi_private->playback--; 506 ssi_private->playback--;
@@ -523,56 +526,15 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
523 } 526 }
524} 527}
525 528
526/**
527 * fsl_ssi_set_sysclk: set the clock frequency and direction
528 *
529 * This function is called by the machine driver to tell us what the clock
530 * frequency and direction are.
531 *
532 * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
533 * and we don't care about the frequency. Return an error if the direction
534 * is not SND_SOC_CLOCK_IN.
535 *
536 * @clk_id: reserved, should be zero
537 * @freq: the frequency of the given clock ID, currently ignored
538 * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
539 */
540static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai,
541 int clk_id, unsigned int freq, int dir)
542{
543
544 return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
545}
546
547/**
548 * fsl_ssi_set_fmt: set the serial format.
549 *
550 * This function is called by the machine driver to tell us what serial
551 * format to use.
552 *
553 * Currently, we only support I2S mode. Return an error if the format is
554 * not SND_SOC_DAIFMT_I2S.
555 *
556 * @format: one of SND_SOC_DAIFMT_xxx
557 */
558static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
559{
560 return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
561}
562
563/**
564 * fsl_ssi_dai_template: template CPU DAI for the SSI
565 */
566static struct snd_soc_dai_ops fsl_ssi_dai_ops = { 529static struct snd_soc_dai_ops fsl_ssi_dai_ops = {
567 .startup = fsl_ssi_startup, 530 .startup = fsl_ssi_startup,
568 .hw_params = fsl_ssi_hw_params, 531 .hw_params = fsl_ssi_hw_params,
569 .shutdown = fsl_ssi_shutdown, 532 .shutdown = fsl_ssi_shutdown,
570 .trigger = fsl_ssi_trigger, 533 .trigger = fsl_ssi_trigger,
571 .set_sysclk = fsl_ssi_set_sysclk,
572 .set_fmt = fsl_ssi_set_fmt,
573}; 534};
574 535
575static struct snd_soc_dai fsl_ssi_dai_template = { 536/* Template for the CPU dai driver structure */
537static struct snd_soc_dai_driver fsl_ssi_dai_template = {
576 .playback = { 538 .playback = {
577 /* The SSI does not support monaural audio. */ 539 /* The SSI does not support monaural audio. */
578 .channels_min = 2, 540 .channels_min = 2,
@@ -640,95 +602,176 @@ static ssize_t fsl_sysfs_ssi_show(struct device *dev,
640} 602}
641 603
642/** 604/**
643 * fsl_ssi_create_dai: create a snd_soc_dai structure 605 * Make every character in a string lower-case
644 *
645 * This function is called by the machine driver to create a snd_soc_dai
646 * structure. The function creates an ssi_private object, which contains
647 * the snd_soc_dai. It also creates the sysfs statistics device.
648 */ 606 */
649struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) 607static void make_lowercase(char *s)
608{
609 char *p = s;
610 char c;
611
612 while ((c = *p)) {
613 if ((c >= 'A') && (c <= 'Z'))
614 *p = c + ('a' - 'A');
615 p++;
616 }
617}
618
619static int __devinit fsl_ssi_probe(struct of_device *of_dev,
620 const struct of_device_id *match)
650{ 621{
651 struct snd_soc_dai *fsl_ssi_dai;
652 struct fsl_ssi_private *ssi_private; 622 struct fsl_ssi_private *ssi_private;
653 int ret = 0; 623 int ret = 0;
654 struct device_attribute *dev_attr; 624 struct device_attribute *dev_attr;
625 struct device_node *np = of_dev->dev.of_node;
626 const char *p, *sprop;
627 struct resource res;
628 char name[64];
655 629
656 ssi_private = kzalloc(sizeof(struct fsl_ssi_private), GFP_KERNEL); 630 /* We are only interested in SSIs with a codec phandle in them, so let's
631 * make sure this SSI has one.
632 */
633 if (!of_get_property(np, "codec-handle", NULL))
634 return -ENODEV;
635
636 /* We only support the SSI in "I2S Slave" mode */
637 sprop = of_get_property(np, "fsl,mode", NULL);
638 if (!sprop || strcmp(sprop, "i2s-slave")) {
639 dev_notice(&of_dev->dev, "mode %s is unsupported\n", sprop);
640 return -ENODEV;
641 }
642
643 /* The DAI name is the last part of the full name of the node. */
644 p = strrchr(np->full_name, '/') + 1;
645 ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p),
646 GFP_KERNEL);
657 if (!ssi_private) { 647 if (!ssi_private) {
658 dev_err(ssi_info->dev, "could not allocate DAI object\n"); 648 dev_err(&of_dev->dev, "could not allocate DAI object\n");
659 return NULL; 649 return -ENOMEM;
660 } 650 }
661 memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template,
662 sizeof(struct snd_soc_dai));
663 651
664 fsl_ssi_dai = &ssi_private->cpu_dai; 652 strcpy(ssi_private->name, p);
665 dev_attr = &ssi_private->dev_attr;
666 653
667 sprintf(ssi_private->name, "ssi%u", (u8) ssi_info->id); 654 /* Initialize this copy of the CPU DAI driver structure */
668 ssi_private->ssi = ssi_info->ssi; 655 memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
669 ssi_private->ssi_phys = ssi_info->ssi_phys; 656 sizeof(fsl_ssi_dai_template));
670 ssi_private->irq = ssi_info->irq; 657 ssi_private->cpu_dai_drv.name = ssi_private->name;
671 ssi_private->dev = ssi_info->dev; 658
672 ssi_private->asynchronous = ssi_info->asynchronous; 659 /* Get the addresses and IRQ */
660 ret = of_address_to_resource(np, 0, &res);
661 if (ret) {
662 dev_err(&of_dev->dev, "could not determine device resources\n");
663 kfree(ssi_private);
664 return ret;
665 }
666 ssi_private->ssi = ioremap(res.start, 1 + res.end - res.start);
667 ssi_private->ssi_phys = res.start;
668 ssi_private->irq = irq_of_parse_and_map(np, 0);
673 669
674 dev_set_drvdata(ssi_private->dev, fsl_ssi_dai); 670 /* Are the RX and the TX clocks locked? */
671 if (of_find_property(np, "fsl,ssi-asynchronous", NULL))
672 ssi_private->asynchronous = 1;
673 else
674 ssi_private->cpu_dai_drv.symmetric_rates = 1;
675 675
676 /* Initialize the the device_attribute structure */ 676 /* Initialize the the device_attribute structure */
677 dev_attr->attr.name = "ssi-stats"; 677 dev_attr = &ssi_private->dev_attr;
678 dev_attr->attr.name = "statistics";
678 dev_attr->attr.mode = S_IRUGO; 679 dev_attr->attr.mode = S_IRUGO;
679 dev_attr->show = fsl_sysfs_ssi_show; 680 dev_attr->show = fsl_sysfs_ssi_show;
680 681
681 ret = device_create_file(ssi_private->dev, dev_attr); 682 ret = device_create_file(&of_dev->dev, dev_attr);
682 if (ret) { 683 if (ret) {
683 dev_err(ssi_info->dev, "could not create sysfs %s file\n", 684 dev_err(&of_dev->dev, "could not create sysfs %s file\n",
684 ssi_private->dev_attr.attr.name); 685 ssi_private->dev_attr.attr.name);
685 kfree(fsl_ssi_dai); 686 kfree(ssi_private);
686 return NULL; 687 return ret;
687 } 688 }
688 689
689 fsl_ssi_dai->private_data = ssi_private; 690 /* Register with ASoC */
690 fsl_ssi_dai->name = ssi_private->name; 691 dev_set_drvdata(&of_dev->dev, ssi_private);
691 fsl_ssi_dai->id = ssi_info->id;
692 fsl_ssi_dai->dev = ssi_info->dev;
693 fsl_ssi_dai->symmetric_rates = 1;
694 692
695 ret = snd_soc_register_dai(fsl_ssi_dai); 693 ret = snd_soc_register_dai(&of_dev->dev, &ssi_private->cpu_dai_drv);
696 if (ret != 0) { 694 if (ret != 0) {
697 dev_err(ssi_info->dev, "failed to register DAI: %d\n", ret); 695 dev_err(&of_dev->dev, "failed to register DAI: %d\n", ret);
698 kfree(fsl_ssi_dai); 696 kfree(ssi_private);
699 return NULL; 697 return ret;
698 }
699
700 /* Trigger the machine driver's probe function. The platform driver
701 * name of the machine driver is taken from the /model property of the
702 * device tree. We also pass the address of the CPU DAI driver
703 * structure.
704 */
705 sprop = of_get_property(of_find_node_by_path("/"), "model", NULL);
706 /* Sometimes the model name has a "fsl," prefix, so we strip that. */
707 p = strrchr(sprop, ',');
708 if (p)
709 sprop = p + 1;
710 snprintf(name, sizeof(name), "snd-soc-%s", sprop);
711 make_lowercase(name);
712
713 ssi_private->pdev =
714 platform_device_register_data(&of_dev->dev, name, 0, NULL, 0);
715 if (IS_ERR(ssi_private->pdev)) {
716 ret = PTR_ERR(ssi_private->pdev);
717 dev_err(&of_dev->dev, "failed to register platform: %d\n", ret);
718 kfree(ssi_private);
719 return ret;
700 } 720 }
701 721
702 return fsl_ssi_dai; 722 return 0;
703} 723}
704EXPORT_SYMBOL_GPL(fsl_ssi_create_dai);
705 724
706/** 725/**
707 * fsl_ssi_destroy_dai: destroy the snd_soc_dai object 726 * fsl_ssi_destroy_dai: destroy the snd_soc_dai object
708 * 727 *
709 * This function undoes the operations of fsl_ssi_create_dai() 728 * This function undoes the operations of fsl_ssi_probe()
710 */ 729 */
711void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai) 730static int fsl_ssi_remove(struct of_device *of_dev)
712{ 731{
713 struct fsl_ssi_private *ssi_private = 732 struct fsl_ssi_private *ssi_private = dev_get_drvdata(&of_dev->dev);
714 container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai);
715 733
716 device_remove_file(ssi_private->dev, &ssi_private->dev_attr); 734 platform_device_unregister(ssi_private->pdev);
717 735 snd_soc_unregister_dai(&of_dev->dev);
718 snd_soc_unregister_dai(&ssi_private->cpu_dai); 736 device_remove_file(&of_dev->dev, &ssi_private->dev_attr);
719 737
720 kfree(ssi_private); 738 kfree(ssi_private);
739 dev_set_drvdata(&of_dev->dev, NULL);
740
741 return 0;
721} 742}
722EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); 743
744static const struct of_device_id fsl_ssi_ids[] = {
745 { .compatible = "fsl,mpc8610-ssi", },
746 {}
747};
748MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
749
750static struct of_platform_driver fsl_ssi_driver = {
751 .driver = {
752 .name = "fsl-ssi-dai",
753 .owner = THIS_MODULE,
754 .of_match_table = fsl_ssi_ids,
755 },
756 .probe = fsl_ssi_probe,
757 .remove = fsl_ssi_remove,
758};
723 759
724static int __init fsl_ssi_init(void) 760static int __init fsl_ssi_init(void)
725{ 761{
726 printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n"); 762 printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
727 763
728 return 0; 764 return of_register_platform_driver(&fsl_ssi_driver);
765}
766
767static void __exit fsl_ssi_exit(void)
768{
769 of_unregister_platform_driver(&fsl_ssi_driver);
729} 770}
771
730module_init(fsl_ssi_init); 772module_init(fsl_ssi_init);
773module_exit(fsl_ssi_exit);
731 774
732MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); 775MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
733MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); 776MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
734MODULE_LICENSE("GPL"); 777MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index eade01feaab6..217300029b5b 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -196,31 +196,5 @@ struct ccsr_ssi {
196#define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT) 196#define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT)
197#define CCSR_SSI_SOR_SYNRST 0x00000001 197#define CCSR_SSI_SOR_SYNRST 0x00000001
198 198
199/* Instantiation data for an SSI interface
200 *
201 * This structure contains all the information that the the SSI driver needs
202 * to instantiate an SSI interface with ALSA. The machine driver should
203 * create this structure, fill it in, call fsl_ssi_create_dai(), and then
204 * delete the structure.
205 *
206 * id: which SSI this is (0, 1, etc. )
207 * ssi: pointer to the SSI's registers
208 * ssi_phys: physical address of the SSI registers
209 * irq: IRQ of this SSI
210 * dev: struct device, used to create the sysfs statistics file
211 * asynchronous: 0=synchronous mode, 1=asynchronous mode
212*/
213struct fsl_ssi_info {
214 unsigned int id;
215 struct ccsr_ssi __iomem *ssi;
216 dma_addr_t ssi_phys;
217 unsigned int irq;
218 struct device *dev;
219 int asynchronous;
220};
221
222struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
223void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai);
224
225#endif 199#endif
226 200
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 1d4e7164e80a..dce6b551cd78 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -9,6 +9,8 @@
9#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/of_device.h> 10#include <linux/of_device.h>
11#include <linux/slab.h> 11#include <linux/slab.h>
12#include <linux/of_device.h>
13#include <linux/of_platform.h>
12 14
13#include <sound/soc.h> 15#include <sound/soc.h>
14 16
@@ -107,7 +109,7 @@ static int psc_dma_hw_free(struct snd_pcm_substream *substream)
107static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd) 109static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
108{ 110{
109 struct snd_soc_pcm_runtime *rtd = substream->private_data; 111 struct snd_soc_pcm_runtime *rtd = substream->private_data;
110 struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; 112 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
111 struct snd_pcm_runtime *runtime = substream->runtime; 113 struct snd_pcm_runtime *runtime = substream->runtime;
112 struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma); 114 struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
113 struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; 115 struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
@@ -212,7 +214,7 @@ static int psc_dma_open(struct snd_pcm_substream *substream)
212{ 214{
213 struct snd_pcm_runtime *runtime = substream->runtime; 215 struct snd_pcm_runtime *runtime = substream->runtime;
214 struct snd_soc_pcm_runtime *rtd = substream->private_data; 216 struct snd_soc_pcm_runtime *rtd = substream->private_data;
215 struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; 217 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
216 struct psc_dma_stream *s; 218 struct psc_dma_stream *s;
217 int rc; 219 int rc;
218 220
@@ -239,7 +241,7 @@ static int psc_dma_open(struct snd_pcm_substream *substream)
239static int psc_dma_close(struct snd_pcm_substream *substream) 241static int psc_dma_close(struct snd_pcm_substream *substream)
240{ 242{
241 struct snd_soc_pcm_runtime *rtd = substream->private_data; 243 struct snd_soc_pcm_runtime *rtd = substream->private_data;
242 struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; 244 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
243 struct psc_dma_stream *s; 245 struct psc_dma_stream *s;
244 246
245 dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream); 247 dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);
@@ -264,7 +266,7 @@ static snd_pcm_uframes_t
264psc_dma_pointer(struct snd_pcm_substream *substream) 266psc_dma_pointer(struct snd_pcm_substream *substream)
265{ 267{
266 struct snd_soc_pcm_runtime *rtd = substream->private_data; 268 struct snd_soc_pcm_runtime *rtd = substream->private_data;
267 struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; 269 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
268 struct psc_dma_stream *s; 270 struct psc_dma_stream *s;
269 dma_addr_t count; 271 dma_addr_t count;
270 272
@@ -302,11 +304,11 @@ static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
302 struct snd_pcm *pcm) 304 struct snd_pcm *pcm)
303{ 305{
304 struct snd_soc_pcm_runtime *rtd = pcm->private_data; 306 struct snd_soc_pcm_runtime *rtd = pcm->private_data;
305 struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; 307 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
306 size_t size = psc_dma_hardware.buffer_bytes_max; 308 size_t size = psc_dma_hardware.buffer_bytes_max;
307 int rc = 0; 309 int rc = 0;
308 310
309 dev_dbg(rtd->socdev->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n", 311 dev_dbg(rtd->platform->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
310 card, dai, pcm); 312 card, dai, pcm);
311 313
312 if (!card->dev->dma_mask) 314 if (!card->dev->dma_mask)
@@ -328,8 +330,8 @@ static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
328 goto capture_alloc_err; 330 goto capture_alloc_err;
329 } 331 }
330 332
331 if (rtd->socdev->card->codec->ac97) 333 if (rtd->codec->ac97)
332 rtd->socdev->card->codec->ac97->private_data = psc_dma; 334 rtd->codec->ac97->private_data = psc_dma;
333 335
334 return 0; 336 return 0;
335 337
@@ -349,7 +351,7 @@ static void psc_dma_free(struct snd_pcm *pcm)
349 struct snd_pcm_substream *substream; 351 struct snd_pcm_substream *substream;
350 int stream; 352 int stream;
351 353
352 dev_dbg(rtd->socdev->dev, "psc_dma_free(pcm=%p)\n", pcm); 354 dev_dbg(rtd->platform->dev, "psc_dma_free(pcm=%p)\n", pcm);
353 355
354 for (stream = 0; stream < 2; stream++) { 356 for (stream = 0; stream < 2; stream++) {
355 substream = pcm->streams[stream].substream; 357 substream = pcm->streams[stream].substream;
@@ -361,15 +363,14 @@ static void psc_dma_free(struct snd_pcm *pcm)
361 } 363 }
362} 364}
363 365
364struct snd_soc_platform mpc5200_audio_dma_platform = { 366static struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
365 .name = "mpc5200-psc-audio", 367 .ops = &psc_dma_ops,
366 .pcm_ops = &psc_dma_ops,
367 .pcm_new = &psc_dma_new, 368 .pcm_new = &psc_dma_new,
368 .pcm_free = &psc_dma_free, 369 .pcm_free = &psc_dma_free,
369}; 370};
370EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform);
371 371
372int mpc5200_audio_dma_create(struct of_device *op) 372static int mpc5200_hpcd_probe(struct of_device *op,
373 const struct of_device_id *match)
373{ 374{
374 phys_addr_t fifo; 375 phys_addr_t fifo;
375 struct psc_dma *psc_dma; 376 struct psc_dma *psc_dma;
@@ -475,7 +476,7 @@ int mpc5200_audio_dma_create(struct of_device *op)
475 dev_set_drvdata(&op->dev, psc_dma); 476 dev_set_drvdata(&op->dev, psc_dma);
476 477
477 /* Tell the ASoC OF helpers about it */ 478 /* Tell the ASoC OF helpers about it */
478 return snd_soc_register_platform(&mpc5200_audio_dma_platform); 479 return snd_soc_register_platform(&op->dev, &mpc5200_audio_dma_platform);
479out_irq: 480out_irq:
480 free_irq(psc_dma->irq, psc_dma); 481 free_irq(psc_dma->irq, psc_dma);
481 free_irq(psc_dma->capture.irq, &psc_dma->capture); 482 free_irq(psc_dma->capture.irq, &psc_dma->capture);
@@ -486,15 +487,14 @@ out_unmap:
486 iounmap(regs); 487 iounmap(regs);
487 return ret; 488 return ret;
488} 489}
489EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
490 490
491int mpc5200_audio_dma_destroy(struct of_device *op) 491static int mpc5200_hpcd_remove(struct of_device *op)
492{ 492{
493 struct psc_dma *psc_dma = dev_get_drvdata(&op->dev); 493 struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
494 494
495 dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n"); 495 dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");
496 496
497 snd_soc_unregister_platform(&mpc5200_audio_dma_platform); 497 snd_soc_unregister_platform(&op->dev);
498 498
499 bcom_gen_bd_rx_release(psc_dma->capture.bcom_task); 499 bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
500 bcom_gen_bd_tx_release(psc_dma->playback.bcom_task); 500 bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
@@ -510,7 +510,35 @@ int mpc5200_audio_dma_destroy(struct of_device *op)
510 510
511 return 0; 511 return 0;
512} 512}
513EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy); 513
514static struct of_device_id mpc5200_hpcd_match[] = {
515 {
516 .compatible = "fsl,mpc5200-pcm",
517 },
518 {}
519};
520MODULE_DEVICE_TABLE(of, mpc5200_hpcd_match);
521
522static struct of_platform_driver mpc5200_hpcd_of_driver = {
523 .owner = THIS_MODULE,
524 .name = "mpc5200-pcm-audio",
525 .match_table = mpc5200_hpcd_match,
526 .probe = mpc5200_hpcd_probe,
527 .remove = mpc5200_hpcd_remove,
528};
529
530static int __init mpc5200_hpcd_init(void)
531{
532 return of_register_platform_driver(&mpc5200_hpcd_of_driver);
533}
534
535static void __exit mpc5200_hpcd_exit(void)
536{
537 of_unregister_platform_driver(&mpc5200_hpcd_of_driver);
538}
539
540module_init(mpc5200_hpcd_init);
541module_exit(mpc5200_hpcd_exit);
514 542
515MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); 543MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
516MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver"); 544MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
index 22208b373fb9..7472531bc2a4 100644
--- a/sound/soc/fsl/mpc5200_dma.h
+++ b/sound/soc/fsl/mpc5200_dma.h
@@ -81,9 +81,4 @@ to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma)
81 return &psc_dma->playback; 81 return &psc_dma->playback;
82} 82}
83 83
84int mpc5200_audio_dma_create(struct of_device *op);
85int mpc5200_audio_dma_destroy(struct of_device *op);
86
87extern struct snd_soc_platform mpc5200_audio_dma_platform;
88
89#endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */ 84#endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index e2ee220bfb7e..11706c128c08 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -129,7 +129,7 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
129 struct snd_pcm_hw_params *params, 129 struct snd_pcm_hw_params *params,
130 struct snd_soc_dai *cpu_dai) 130 struct snd_soc_dai *cpu_dai)
131{ 131{
132 struct psc_dma *psc_dma = cpu_dai->private_data; 132 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
133 struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma); 133 struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
134 134
135 dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i" 135 dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@ -152,7 +152,7 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
152 struct snd_pcm_hw_params *params, 152 struct snd_pcm_hw_params *params,
153 struct snd_soc_dai *cpu_dai) 153 struct snd_soc_dai *cpu_dai)
154{ 154{
155 struct psc_dma *psc_dma = cpu_dai->private_data; 155 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
156 156
157 dev_dbg(psc_dma->dev, "%s(substream=%p)\n", __func__, substream); 157 dev_dbg(psc_dma->dev, "%s(substream=%p)\n", __func__, substream);
158 158
@@ -167,8 +167,7 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
167static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd, 167static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
168 struct snd_soc_dai *dai) 168 struct snd_soc_dai *dai)
169{ 169{
170 struct snd_soc_pcm_runtime *rtd = substream->private_data; 170 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(dai);
171 struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
172 struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma); 171 struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
173 172
174 switch (cmd) { 173 switch (cmd) {
@@ -193,10 +192,9 @@ static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
193 return 0; 192 return 0;
194} 193}
195 194
196static int psc_ac97_probe(struct platform_device *pdev, 195static int psc_ac97_probe(struct snd_soc_dai *cpu_dai)
197 struct snd_soc_dai *cpu_dai)
198{ 196{
199 struct psc_dma *psc_dma = cpu_dai->private_data; 197 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
200 struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs; 198 struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
201 199
202 /* Go */ 200 /* Go */
@@ -223,9 +221,8 @@ static struct snd_soc_dai_ops psc_ac97_digital_ops = {
223 .hw_params = psc_ac97_hw_digital_params, 221 .hw_params = psc_ac97_hw_digital_params,
224}; 222};
225 223
226struct snd_soc_dai psc_ac97_dai[] = { 224static struct snd_soc_dai_driver psc_ac97_dai[] = {
227{ 225{
228 .name = "AC97",
229 .ac97_control = 1, 226 .ac97_control = 1,
230 .probe = psc_ac97_probe, 227 .probe = psc_ac97_probe,
231 .playback = { 228 .playback = {
@@ -243,7 +240,6 @@ struct snd_soc_dai psc_ac97_dai[] = {
243 .ops = &psc_ac97_analog_ops, 240 .ops = &psc_ac97_analog_ops,
244}, 241},
245{ 242{
246 .name = "SPDIF",
247 .ac97_control = 1, 243 .ac97_control = 1,
248 .playback = { 244 .playback = {
249 .channels_min = 1, 245 .channels_min = 1,
@@ -254,7 +250,6 @@ struct snd_soc_dai psc_ac97_dai[] = {
254 }, 250 },
255 .ops = &psc_ac97_digital_ops, 251 .ops = &psc_ac97_digital_ops,
256} }; 252} };
257EXPORT_SYMBOL_GPL(psc_ac97_dai);
258 253
259 254
260 255
@@ -266,18 +261,11 @@ EXPORT_SYMBOL_GPL(psc_ac97_dai);
266static int __devinit psc_ac97_of_probe(struct of_device *op, 261static int __devinit psc_ac97_of_probe(struct of_device *op,
267 const struct of_device_id *match) 262 const struct of_device_id *match)
268{ 263{
269 int rc, i; 264 int rc;
270 struct snd_ac97 ac97; 265 struct snd_ac97 ac97;
271 struct mpc52xx_psc __iomem *regs; 266 struct mpc52xx_psc __iomem *regs;
272 267
273 rc = mpc5200_audio_dma_create(op); 268 rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
274 if (rc != 0)
275 return rc;
276
277 for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
278 psc_ac97_dai[i].dev = &op->dev;
279
280 rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
281 if (rc != 0) { 269 if (rc != 0) {
282 dev_err(&op->dev, "Failed to register DAI\n"); 270 dev_err(&op->dev, "Failed to register DAI\n");
283 return rc; 271 return rc;
@@ -287,9 +275,6 @@ static int __devinit psc_ac97_of_probe(struct of_device *op,
287 regs = psc_dma->psc_regs; 275 regs = psc_dma->psc_regs;
288 ac97.private_data = psc_dma; 276 ac97.private_data = psc_dma;
289 277
290 for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
291 psc_ac97_dai[i].private_data = psc_dma;
292
293 psc_dma->imr = 0; 278 psc_dma->imr = 0;
294 out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); 279 out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
295 280
@@ -305,7 +290,8 @@ static int __devinit psc_ac97_of_probe(struct of_device *op,
305 290
306static int __devexit psc_ac97_of_remove(struct of_device *op) 291static int __devexit psc_ac97_of_remove(struct of_device *op)
307{ 292{
308 return mpc5200_audio_dma_destroy(op); 293 snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
294 return 0;
309} 295}
310 296
311/* Match table for of_platform binding */ 297/* Match table for of_platform binding */
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.h b/sound/soc/fsl/mpc5200_psc_ac97.h
index 4bc18c35c369..e881e784b270 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.h
+++ b/sound/soc/fsl/mpc5200_psc_ac97.h
@@ -7,8 +7,6 @@
7#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ 7#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
8#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ 8#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
9 9
10extern struct snd_soc_dai psc_ac97_dai[];
11
12#define MPC5200_AC97_NORMAL 0 10#define MPC5200_AC97_NORMAL 0
13#define MPC5200_AC97_SPDIF 1 11#define MPC5200_AC97_SPDIF 1
14 12
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 676841cbae98..5b9f2c73f031 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -40,7 +40,7 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
40 struct snd_soc_dai *dai) 40 struct snd_soc_dai *dai)
41{ 41{
42 struct snd_soc_pcm_runtime *rtd = substream->private_data; 42 struct snd_soc_pcm_runtime *rtd = substream->private_data;
43 struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data; 43 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
44 u32 mode; 44 u32 mode;
45 45
46 dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i" 46 dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@ -88,7 +88,7 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
88static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, 88static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
89 int clk_id, unsigned int freq, int dir) 89 int clk_id, unsigned int freq, int dir)
90{ 90{
91 struct psc_dma *psc_dma = cpu_dai->private_data; 91 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
92 dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n", 92 dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
93 cpu_dai, dir); 93 cpu_dai, dir);
94 return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL; 94 return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
@@ -107,7 +107,7 @@ static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
107 */ 107 */
108static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) 108static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
109{ 109{
110 struct psc_dma *psc_dma = cpu_dai->private_data; 110 struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
111 dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n", 111 dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
112 cpu_dai, format); 112 cpu_dai, format);
113 return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; 113 return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
@@ -129,8 +129,7 @@ static struct snd_soc_dai_ops psc_i2s_dai_ops = {
129 .set_fmt = psc_i2s_set_fmt, 129 .set_fmt = psc_i2s_set_fmt,
130}; 130};
131 131
132struct snd_soc_dai psc_i2s_dai[] = {{ 132static struct snd_soc_dai_driver psc_i2s_dai[] = {{
133 .name = "I2S",
134 .playback = { 133 .playback = {
135 .channels_min = 2, 134 .channels_min = 2,
136 .channels_max = 2, 135 .channels_max = 2,
@@ -145,7 +144,6 @@ struct snd_soc_dai psc_i2s_dai[] = {{
145 }, 144 },
146 .ops = &psc_i2s_dai_ops, 145 .ops = &psc_i2s_dai_ops,
147} }; 146} };
148EXPORT_SYMBOL_GPL(psc_i2s_dai);
149 147
150/* --------------------------------------------------------------------- 148/* ---------------------------------------------------------------------
151 * OF platform bus binding code: 149 * OF platform bus binding code:
@@ -159,11 +157,7 @@ static int __devinit psc_i2s_of_probe(struct of_device *op,
159 struct psc_dma *psc_dma; 157 struct psc_dma *psc_dma;
160 struct mpc52xx_psc __iomem *regs; 158 struct mpc52xx_psc __iomem *regs;
161 159
162 rc = mpc5200_audio_dma_create(op); 160 rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
163 if (rc != 0)
164 return rc;
165
166 rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
167 if (rc != 0) { 161 if (rc != 0) {
168 pr_err("Failed to register DAI\n"); 162 pr_err("Failed to register DAI\n");
169 return 0; 163 return 0;
@@ -207,7 +201,8 @@ static int __devinit psc_i2s_of_probe(struct of_device *op,
207 201
208static int __devexit psc_i2s_of_remove(struct of_device *op) 202static int __devexit psc_i2s_of_remove(struct of_device *op)
209{ 203{
210 return mpc5200_audio_dma_destroy(op); 204 snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
205 return 0;
211} 206}
212 207
213/* Match table for of_platform binding */ 208/* Match table for of_platform binding */
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 6a2764ee8203..5ba823213abe 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -1,85 +1,96 @@
1/** 1/**
2 * Freescale MPC8610HPCD ALSA SoC Fabric driver 2 * Freescale MPC8610HPCD ALSA SoC Machine driver
3 * 3 *
4 * Author: Timur Tabi <timur@freescale.com> 4 * Author: Timur Tabi <timur@freescale.com>
5 * 5 *
6 * Copyright 2007-2008 Freescale Semiconductor, Inc. This file is licensed 6 * Copyright 2007-2010 Freescale Semiconductor, Inc.
7 * under the terms of the GNU General Public License version 2. This 7 *
8 * program is licensed "as is" without any warranty of any kind, whether 8 * This file is licensed under the terms of the GNU General Public License
9 * express or implied. 9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
10 */ 11 */
11 12
12#include <linux/slab.h>
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/interrupt.h> 14#include <linux/interrupt.h>
15#include <linux/of_device.h> 15#include <linux/of_device.h>
16#include <linux/of_platform.h>
17#include <sound/soc.h> 16#include <sound/soc.h>
18#include <asm/immap_86xx.h> 17#include <asm/immap_86xx.h>
19 18
20#include "../codecs/cs4270.h"
21#include "fsl_dma.h" 19#include "fsl_dma.h"
22#include "fsl_ssi.h" 20#include "fsl_ssi.h"
23 21
22/* There's only one global utilities register */
23static phys_addr_t guts_phys;
24
25#define DAI_NAME_SIZE 32
26
24/** 27/**
25 * mpc8610_hpcd_data: fabric-specific ASoC device data 28 * mpc8610_hpcd_data: machine-specific ASoC device data
26 * 29 *
27 * This structure contains data for a single sound platform device on an 30 * This structure contains data for a single sound platform device on an
28 * MPC8610 HPCD. Some of the data is taken from the device tree. 31 * MPC8610 HPCD. Some of the data is taken from the device tree.
29 */ 32 */
30struct mpc8610_hpcd_data { 33struct mpc8610_hpcd_data {
31 struct snd_soc_device sound_devdata; 34 struct snd_soc_dai_link dai[2];
32 struct snd_soc_dai_link dai; 35 struct snd_soc_card card;
33 struct snd_soc_card machine;
34 unsigned int dai_format; 36 unsigned int dai_format;
35 unsigned int codec_clk_direction; 37 unsigned int codec_clk_direction;
36 unsigned int cpu_clk_direction; 38 unsigned int cpu_clk_direction;
37 unsigned int clk_frequency; 39 unsigned int clk_frequency;
38 struct ccsr_guts __iomem *guts; 40 unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
39 struct ccsr_ssi __iomem *ssi; 41 unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */
40 unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
41 unsigned int ssi_irq;
42 unsigned int dma_id; /* 0 = DMA1, 1 = DMA2, etc */
43 unsigned int dma_irq[2];
44 struct ccsr_dma_channel __iomem *dma[2];
45 unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/ 42 unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
43 char codec_dai_name[DAI_NAME_SIZE];
44 char codec_name[DAI_NAME_SIZE];
45 char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
46}; 46};
47 47
48/** 48/**
49 * mpc8610_hpcd_machine_probe: initalize the board 49 * mpc8610_hpcd_machine_probe: initialize the board
50 * 50 *
51 * This function is called when platform_device_add() is called. It is used 51 * This function is used to initialize the board-specific hardware.
52 * to initialize the board-specific hardware.
53 * 52 *
54 * Here we program the DMACR and PMUXCR registers. 53 * Here we program the DMACR and PMUXCR registers.
55 */ 54 */
56static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device) 55static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
57{ 56{
57 struct snd_soc_card *card = platform_get_drvdata(sound_device);
58 struct mpc8610_hpcd_data *machine_data = 58 struct mpc8610_hpcd_data *machine_data =
59 sound_device->dev.platform_data; 59 container_of(card, struct mpc8610_hpcd_data, card);
60 struct ccsr_guts __iomem *guts;
60 61
61 /* Program the signal routing between the SSI and the DMA */ 62 guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
62 guts_set_dmacr(machine_data->guts, machine_data->dma_id, 63 if (!guts) {
63 machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI); 64 dev_err(card->dev, "could not map global utilities\n");
64 guts_set_dmacr(machine_data->guts, machine_data->dma_id, 65 return -ENOMEM;
65 machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI); 66 }
66 67
67 guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id, 68 /* Program the signal routing between the SSI and the DMA */
68 machine_data->dma_channel_id[0], 0); 69 guts_set_dmacr(guts, machine_data->dma_id[0],
69 guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id, 70 machine_data->dma_channel_id[0],
70 machine_data->dma_channel_id[1], 0); 71 CCSR_GUTS_DMACR_DEV_SSI);
72 guts_set_dmacr(guts, machine_data->dma_id[1],
73 machine_data->dma_channel_id[1],
74 CCSR_GUTS_DMACR_DEV_SSI);
75
76 guts_set_pmuxcr_dma(guts, machine_data->dma_id[0],
77 machine_data->dma_channel_id[0], 0);
78 guts_set_pmuxcr_dma(guts, machine_data->dma_id[1],
79 machine_data->dma_channel_id[1], 0);
71 80
72 switch (machine_data->ssi_id) { 81 switch (machine_data->ssi_id) {
73 case 0: 82 case 0:
74 clrsetbits_be32(&machine_data->guts->pmuxcr, 83 clrsetbits_be32(&guts->pmuxcr,
75 CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI); 84 CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI);
76 break; 85 break;
77 case 1: 86 case 1:
78 clrsetbits_be32(&machine_data->guts->pmuxcr, 87 clrsetbits_be32(&guts->pmuxcr,
79 CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI); 88 CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI);
80 break; 89 break;
81 } 90 }
82 91
92 iounmap(guts);
93
83 return 0; 94 return 0;
84} 95}
85 96
@@ -93,38 +104,15 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
93static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream) 104static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
94{ 105{
95 struct snd_soc_pcm_runtime *rtd = substream->private_data; 106 struct snd_soc_pcm_runtime *rtd = substream->private_data;
96 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
97 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
98 struct mpc8610_hpcd_data *machine_data = 107 struct mpc8610_hpcd_data *machine_data =
99 rtd->socdev->dev->platform_data; 108 container_of(rtd->card, struct mpc8610_hpcd_data, card);
109 struct device *dev = rtd->card->dev;
100 int ret = 0; 110 int ret = 0;
101 111
102 /* Tell the CPU driver what the serial protocol is. */
103 ret = snd_soc_dai_set_fmt(cpu_dai, machine_data->dai_format);
104 if (ret < 0) {
105 dev_err(substream->pcm->card->dev,
106 "could not set CPU driver audio format\n");
107 return ret;
108 }
109
110 /* Tell the codec driver what the serial protocol is. */ 112 /* Tell the codec driver what the serial protocol is. */
111 ret = snd_soc_dai_set_fmt(codec_dai, machine_data->dai_format); 113 ret = snd_soc_dai_set_fmt(rtd->codec_dai, machine_data->dai_format);
112 if (ret < 0) { 114 if (ret < 0) {
113 dev_err(substream->pcm->card->dev, 115 dev_err(dev, "could not set codec driver audio format\n");
114 "could not set codec driver audio format\n");
115 return ret;
116 }
117
118 /*
119 * Tell the CPU driver what the clock frequency is, and whether it's a
120 * slave or master.
121 */
122 ret = snd_soc_dai_set_sysclk(cpu_dai, 0,
123 machine_data->clk_frequency,
124 machine_data->cpu_clk_direction);
125 if (ret < 0) {
126 dev_err(substream->pcm->card->dev,
127 "could not set CPU driver clock parameters\n");
128 return ret; 116 return ret;
129 } 117 }
130 118
@@ -132,12 +120,11 @@ static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
132 * Tell the codec driver what the MCLK frequency is, and whether it's 120 * Tell the codec driver what the MCLK frequency is, and whether it's
133 * a slave or master. 121 * a slave or master.
134 */ 122 */
135 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 123 ret = snd_soc_dai_set_sysclk(rtd->codec_dai, 0,
136 machine_data->clk_frequency, 124 machine_data->clk_frequency,
137 machine_data->codec_clk_direction); 125 machine_data->codec_clk_direction);
138 if (ret < 0) { 126 if (ret < 0) {
139 dev_err(substream->pcm->card->dev, 127 dev_err(dev, "could not set codec driver clock params\n");
140 "could not set codec driver clock params\n");
141 return ret; 128 return ret;
142 } 129 }
143 130
@@ -150,116 +137,254 @@ static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
150 * This function is called to remove the sound device for one SSI. We 137 * This function is called to remove the sound device for one SSI. We
151 * de-program the DMACR and PMUXCR register. 138 * de-program the DMACR and PMUXCR register.
152 */ 139 */
153int mpc8610_hpcd_machine_remove(struct platform_device *sound_device) 140static int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
154{ 141{
142 struct snd_soc_card *card = platform_get_drvdata(sound_device);
155 struct mpc8610_hpcd_data *machine_data = 143 struct mpc8610_hpcd_data *machine_data =
156 sound_device->dev.platform_data; 144 container_of(card, struct mpc8610_hpcd_data, card);
145 struct ccsr_guts __iomem *guts;
146
147 guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
148 if (!guts) {
149 dev_err(card->dev, "could not map global utilities\n");
150 return -ENOMEM;
151 }
157 152
158 /* Restore the signal routing */ 153 /* Restore the signal routing */
159 154
160 guts_set_dmacr(machine_data->guts, machine_data->dma_id, 155 guts_set_dmacr(guts, machine_data->dma_id[0],
161 machine_data->dma_channel_id[0], 0); 156 machine_data->dma_channel_id[0], 0);
162 guts_set_dmacr(machine_data->guts, machine_data->dma_id, 157 guts_set_dmacr(guts, machine_data->dma_id[1],
163 machine_data->dma_channel_id[1], 0); 158 machine_data->dma_channel_id[1], 0);
164 159
165 switch (machine_data->ssi_id) { 160 switch (machine_data->ssi_id) {
166 case 0: 161 case 0:
167 clrsetbits_be32(&machine_data->guts->pmuxcr, 162 clrsetbits_be32(&guts->pmuxcr,
168 CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA); 163 CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA);
169 break; 164 break;
170 case 1: 165 case 1:
171 clrsetbits_be32(&machine_data->guts->pmuxcr, 166 clrsetbits_be32(&guts->pmuxcr,
172 CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA); 167 CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA);
173 break; 168 break;
174 } 169 }
175 170
171 iounmap(guts);
172
176 return 0; 173 return 0;
177} 174}
178 175
179/** 176/**
180 * mpc8610_hpcd_ops: ASoC fabric driver operations 177 * mpc8610_hpcd_ops: ASoC machine driver operations
181 */ 178 */
182static struct snd_soc_ops mpc8610_hpcd_ops = { 179static struct snd_soc_ops mpc8610_hpcd_ops = {
183 .startup = mpc8610_hpcd_startup, 180 .startup = mpc8610_hpcd_startup,
184}; 181};
185 182
186/** 183/**
187 * mpc8610_hpcd_probe: OF probe function for the fabric driver 184 * get_node_by_phandle_name - get a node by its phandle name
188 * 185 *
189 * This function gets called when an SSI node is found in the device tree. 186 * This function takes a node, the name of a property in that node, and a
187 * compatible string. Assuming the property is a phandle to another node,
188 * it returns that node, (optionally) if that node is compatible.
190 * 189 *
191 * Although this is a fabric driver, the SSI node is the "master" node with 190 * If the property is not a phandle, or the node it points to is not compatible
192 * respect to audio hardware connections. Therefore, we create a new ASoC 191 * with the specific string, then NULL is returned.
193 * device for each new SSI node that has a codec attached. 192 */
193static struct device_node *get_node_by_phandle_name(struct device_node *np,
194 const char *name,
195 const char *compatible)
196{
197 const phandle *ph;
198 int len;
199
200 ph = of_get_property(np, name, &len);
201 if (!ph || (len != sizeof(phandle)))
202 return NULL;
203
204 np = of_find_node_by_phandle(*ph);
205 if (!np)
206 return NULL;
207
208 if (compatible && !of_device_is_compatible(np, compatible)) {
209 of_node_put(np);
210 return NULL;
211 }
212
213 return np;
214}
215
216/**
217 * get_parent_cell_index -- return the cell-index of the parent of a node
194 * 218 *
195 * FIXME: Currently, we only support one DMA controller, so if there are 219 * Return the value of the cell-index property of the parent of the given
196 * multiple SSI nodes with codecs, only the first will be supported. 220 * node. This is used for DMA channel nodes that need to know the DMA ID
221 * of the controller they are on.
222 */
223static int get_parent_cell_index(struct device_node *np)
224{
225 struct device_node *parent = of_get_parent(np);
226 const u32 *iprop;
227
228 if (!parent)
229 return -1;
230
231 iprop = of_get_property(parent, "cell-index", NULL);
232 of_node_put(parent);
233
234 if (!iprop)
235 return -1;
236
237 return *iprop;
238}
239
240/**
241 * codec_node_dev_name - determine the dev_name for a codec node
197 * 242 *
198 * FIXME: Even if we did support multiple DMA controllers, we have no 243 * This function determines the dev_name for an I2C node. This is the name
199 * mechanism for assigning DMA controllers and channels to the individual 244 * that would be returned by dev_name() if this device_node were part of a
200 * SSI devices. We also probably aren't compatible with the generic Elo DMA 245 * 'struct device' It's ugly and hackish, but it works.
201 * device driver. 246 *
247 * The dev_name for such devices include the bus number and I2C address. For
248 * example, "cs4270-codec.0-004f".
202 */ 249 */
203static int mpc8610_hpcd_probe(struct of_device *ofdev, 250static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
204 const struct of_device_id *match)
205{ 251{
206 struct device_node *np = ofdev->dev.of_node;
207 struct device_node *codec_np = NULL;
208 struct device_node *guts_np = NULL;
209 struct device_node *dma_np = NULL;
210 struct device_node *dma_channel_np = NULL;
211 const phandle *codec_ph;
212 const char *sprop;
213 const u32 *iprop; 252 const u32 *iprop;
253 int bus, addr;
254 char temp[DAI_NAME_SIZE];
255
256 of_modalias_node(np, temp, DAI_NAME_SIZE);
257
258 iprop = of_get_property(np, "reg", NULL);
259 if (!iprop)
260 return -EINVAL;
261
262 addr = *iprop;
263
264 bus = get_parent_cell_index(np);
265 if (bus < 0)
266 return bus;
267
268 snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
269
270 return 0;
271}
272
273static int get_dma_channel(struct device_node *ssi_np,
274 const char *compatible,
275 struct snd_soc_dai_link *dai,
276 unsigned int *dma_channel_id,
277 unsigned int *dma_id)
278{
214 struct resource res; 279 struct resource res;
280 struct device_node *dma_channel_np;
281 const u32 *iprop;
282 int ret;
283
284 dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
285 "fsl,ssi-dma-channel");
286 if (!dma_channel_np)
287 return -EINVAL;
288
289 /* Determine the dev_name for the device_node. This code mimics the
290 * behavior of of_device_make_bus_id(). We need this because ASoC uses
291 * the dev_name() of the device to match the platform (DMA) device with
292 * the CPU (SSI) device. It's all ugly and hackish, but it works (for
293 * now).
294 *
295 * dai->platform name should already point to an allocated buffer.
296 */
297 ret = of_address_to_resource(dma_channel_np, 0, &res);
298 if (ret)
299 return ret;
300 snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
301 (unsigned long long) res.start, dma_channel_np->name);
302
303 iprop = of_get_property(dma_channel_np, "cell-index", NULL);
304 if (!iprop) {
305 of_node_put(dma_channel_np);
306 return -EINVAL;
307 }
308
309 *dma_channel_id = *iprop;
310 *dma_id = get_parent_cell_index(dma_channel_np);
311 of_node_put(dma_channel_np);
312
313 return 0;
314}
315
316/**
317 * mpc8610_hpcd_probe: platform probe function for the machine driver
318 *
319 * Although this is a machine driver, the SSI node is the "master" node with
320 * respect to audio hardware connections. Therefore, we create a new ASoC
321 * device for each new SSI node that has a codec attached.
322 */
323static int mpc8610_hpcd_probe(struct platform_device *pdev)
324{
325 struct device *dev = pdev->dev.parent;
326 /* of_dev is the OF device for the SSI node that probed us */
327 struct of_device *of_dev = container_of(dev, struct of_device, dev);
328 struct device_node *np = of_dev->dev.of_node;
329 struct device_node *codec_np = NULL;
215 struct platform_device *sound_device = NULL; 330 struct platform_device *sound_device = NULL;
216 struct mpc8610_hpcd_data *machine_data; 331 struct mpc8610_hpcd_data *machine_data;
217 struct fsl_ssi_info ssi_info;
218 struct fsl_dma_info dma_info;
219 int ret = -ENODEV; 332 int ret = -ENODEV;
220 unsigned int playback_dma_channel; 333 const char *sprop;
221 unsigned int capture_dma_channel; 334 const u32 *iprop;
335
336 /* We are only interested in SSIs with a codec phandle in them,
337 * so let's make sure this SSI has one. The MPC8610 HPCD only
338 * knows about the CS4270 codec, so reject anything else.
339 */
340 codec_np = get_node_by_phandle_name(np, "codec-handle",
341 "cirrus,cs4270");
342 if (!codec_np) {
343 dev_err(dev, "invalid codec node\n");
344 return -EINVAL;
345 }
222 346
223 machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL); 347 machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
224 if (!machine_data) 348 if (!machine_data)
225 return -ENOMEM; 349 return -ENOMEM;
226 350
227 memset(&ssi_info, 0, sizeof(ssi_info)); 351 machine_data->dai[0].cpu_dai_name = dev_name(&of_dev->dev);
228 memset(&dma_info, 0, sizeof(dma_info)); 352 machine_data->dai[0].ops = &mpc8610_hpcd_ops;
229 353
230 ssi_info.dev = &ofdev->dev; 354 /* Determine the codec name, it will be used as the codec DAI name */
231 355 ret = codec_node_dev_name(codec_np, machine_data->codec_name,
232 /* 356 DAI_NAME_SIZE);
233 * We are only interested in SSIs with a codec phandle in them, so let's 357 if (ret) {
234 * make sure this SSI has one. 358 dev_err(&pdev->dev, "invalid codec node %s\n",
235 */ 359 codec_np->full_name);
236 codec_ph = of_get_property(np, "codec-handle", NULL); 360 ret = -EINVAL;
237 if (!codec_ph)
238 goto error; 361 goto error;
362 }
363 machine_data->dai[0].codec_name = machine_data->codec_name;
239 364
240 codec_np = of_find_node_by_phandle(*codec_ph); 365 /* The DAI name from the codec (snd_soc_dai_driver.name) */
241 if (!codec_np) 366 machine_data->dai[0].codec_dai_name = "cs4270-hifi";
242 goto error;
243 367
244 /* The MPC8610 HPCD only knows about the CS4270 codec, so reject 368 /* We register two DAIs per SSI, one for playback and the other for
245 anything else. */ 369 * capture. Currently, we only support codecs that have one DAI for
246 if (!of_device_is_compatible(codec_np, "cirrus,cs4270")) 370 * both playback and capture.
247 goto error; 371 */
372 memcpy(&machine_data->dai[1], &machine_data->dai[0],
373 sizeof(struct snd_soc_dai_link));
248 374
249 /* Get the device ID */ 375 /* Get the device ID */
250 iprop = of_get_property(np, "cell-index", NULL); 376 iprop = of_get_property(np, "cell-index", NULL);
251 if (!iprop) { 377 if (!iprop) {
252 dev_err(&ofdev->dev, "cell-index property not found\n"); 378 dev_err(&pdev->dev, "cell-index property not found\n");
253 ret = -EINVAL; 379 ret = -EINVAL;
254 goto error; 380 goto error;
255 } 381 }
256 machine_data->ssi_id = *iprop; 382 machine_data->ssi_id = *iprop;
257 ssi_info.id = *iprop;
258 383
259 /* Get the serial format and clock direction. */ 384 /* Get the serial format and clock direction. */
260 sprop = of_get_property(np, "fsl,mode", NULL); 385 sprop = of_get_property(np, "fsl,mode", NULL);
261 if (!sprop) { 386 if (!sprop) {
262 dev_err(&ofdev->dev, "fsl,mode property not found\n"); 387 dev_err(&pdev->dev, "fsl,mode property not found\n");
263 ret = -EINVAL; 388 ret = -EINVAL;
264 goto error; 389 goto error;
265 } 390 }
@@ -269,15 +394,14 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev,
269 machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT; 394 machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
270 machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN; 395 machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
271 396
272 /* 397 /* In i2s-slave mode, the codec has its own clock source, so we
273 * In i2s-slave mode, the codec has its own clock source, so we
274 * need to get the frequency from the device tree and pass it to 398 * need to get the frequency from the device tree and pass it to
275 * the codec driver. 399 * the codec driver.
276 */ 400 */
277 iprop = of_get_property(codec_np, "clock-frequency", NULL); 401 iprop = of_get_property(codec_np, "clock-frequency", NULL);
278 if (!iprop || !*iprop) { 402 if (!iprop || !*iprop) {
279 dev_err(&ofdev->dev, "codec bus-frequency property " 403 dev_err(&pdev->dev, "codec bus-frequency "
280 "is missing or invalid\n"); 404 "property is missing or invalid\n");
281 ret = -EINVAL; 405 ret = -EINVAL;
282 goto error; 406 goto error;
283 } 407 }
@@ -311,317 +435,153 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev,
311 machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; 435 machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
312 machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT; 436 machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
313 } else { 437 } else {
314 dev_err(&ofdev->dev, 438 dev_err(&pdev->dev,
315 "unrecognized fsl,mode property \"%s\"\n", sprop); 439 "unrecognized fsl,mode property '%s'\n", sprop);
316 ret = -EINVAL; 440 ret = -EINVAL;
317 goto error; 441 goto error;
318 } 442 }
319 443
320 if (!machine_data->clk_frequency) { 444 if (!machine_data->clk_frequency) {
321 dev_err(&ofdev->dev, "unknown clock frequency\n"); 445 dev_err(&pdev->dev, "unknown clock frequency\n");
322 ret = -EINVAL; 446 ret = -EINVAL;
323 goto error; 447 goto error;
324 } 448 }
325 449
326 /* Read the SSI information from the device tree */ 450 /* Find the playback DMA channel to use. */
327 ret = of_address_to_resource(np, 0, &res); 451 machine_data->dai[0].platform_name = machine_data->platform_name[0];
452 ret = get_dma_channel(np, "fsl,playback-dma", &machine_data->dai[0],
453 &machine_data->dma_channel_id[0],
454 &machine_data->dma_id[0]);
328 if (ret) { 455 if (ret) {
329 dev_err(&ofdev->dev, "could not obtain SSI address\n"); 456 dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
330 goto error;
331 }
332 if (!res.start) {
333 dev_err(&ofdev->dev, "invalid SSI address\n");
334 goto error;
335 }
336 ssi_info.ssi_phys = res.start;
337
338 machine_data->ssi = ioremap(ssi_info.ssi_phys, sizeof(struct ccsr_ssi));
339 if (!machine_data->ssi) {
340 dev_err(&ofdev->dev, "could not map SSI address %x\n",
341 ssi_info.ssi_phys);
342 ret = -EINVAL;
343 goto error;
344 }
345 ssi_info.ssi = machine_data->ssi;
346
347
348 /* Get the IRQ of the SSI */
349 machine_data->ssi_irq = irq_of_parse_and_map(np, 0);
350 if (!machine_data->ssi_irq) {
351 dev_err(&ofdev->dev, "could not get SSI IRQ\n");
352 ret = -EINVAL;
353 goto error;
354 }
355 ssi_info.irq = machine_data->ssi_irq;
356
357 /* Do we want to use asynchronous mode? */
358 ssi_info.asynchronous =
359 of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0;
360 if (ssi_info.asynchronous)
361 dev_info(&ofdev->dev, "using asynchronous mode\n");
362
363 /* Map the global utilities registers. */
364 guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
365 if (!guts_np) {
366 dev_err(&ofdev->dev, "could not obtain address of GUTS\n");
367 ret = -EINVAL;
368 goto error;
369 }
370 machine_data->guts = of_iomap(guts_np, 0);
371 of_node_put(guts_np);
372 if (!machine_data->guts) {
373 dev_err(&ofdev->dev, "could not map GUTS\n");
374 ret = -EINVAL;
375 goto error;
376 }
377
378 /* Find the DMA channels to use. Both SSIs need to use the same DMA
379 * controller, so let's use DMA#1.
380 */
381 for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") {
382 iprop = of_get_property(dma_np, "cell-index", NULL);
383 if (iprop && (*iprop == 0)) {
384 of_node_put(dma_np);
385 break;
386 }
387 }
388 if (!dma_np) {
389 dev_err(&ofdev->dev, "could not find DMA node\n");
390 ret = -EINVAL;
391 goto error;
392 }
393 machine_data->dma_id = *iprop;
394
395 /* SSI1 needs to use DMA Channels 0 and 1, and SSI2 needs to use DMA
396 * channels 2 and 3. This is just how the MPC8610 is wired
397 * internally.
398 */
399 playback_dma_channel = (machine_data->ssi_id == 0) ? 0 : 2;
400 capture_dma_channel = (machine_data->ssi_id == 0) ? 1 : 3;
401
402 /*
403 * Find the DMA channels to use.
404 */
405 while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) {
406 iprop = of_get_property(dma_channel_np, "cell-index", NULL);
407 if (iprop && (*iprop == playback_dma_channel)) {
408 /* dma_channel[0] and dma_irq[0] are for playback */
409 dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0);
410 dma_info.dma_irq[0] =
411 irq_of_parse_and_map(dma_channel_np, 0);
412 machine_data->dma_channel_id[0] = *iprop;
413 continue;
414 }
415 if (iprop && (*iprop == capture_dma_channel)) {
416 /* dma_channel[1] and dma_irq[1] are for capture */
417 dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0);
418 dma_info.dma_irq[1] =
419 irq_of_parse_and_map(dma_channel_np, 0);
420 machine_data->dma_channel_id[1] = *iprop;
421 continue;
422 }
423 }
424 if (!dma_info.dma_channel[0] || !dma_info.dma_channel[1] ||
425 !dma_info.dma_irq[0] || !dma_info.dma_irq[1]) {
426 dev_err(&ofdev->dev, "could not find DMA channels\n");
427 ret = -EINVAL;
428 goto error; 457 goto error;
429 } 458 }
430 459
431 dma_info.ssi_stx_phys = ssi_info.ssi_phys + 460 /* Find the capture DMA channel to use. */
432 offsetof(struct ccsr_ssi, stx0); 461 machine_data->dai[1].platform_name = machine_data->platform_name[1];
433 dma_info.ssi_srx_phys = ssi_info.ssi_phys + 462 ret = get_dma_channel(np, "fsl,capture-dma", &machine_data->dai[1],
434 offsetof(struct ccsr_ssi, srx0); 463 &machine_data->dma_channel_id[1],
435 464 &machine_data->dma_id[1]);
436 /* We have the DMA information, so tell the DMA driver what it is */ 465 if (ret) {
437 if (!fsl_dma_configure(&dma_info)) { 466 dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
438 dev_err(&ofdev->dev, "could not instantiate DMA device\n");
439 ret = -EBUSY;
440 goto error; 467 goto error;
441 } 468 }
442 469
443 /* 470 /* Initialize our DAI data structure. */
444 * Initialize our DAI data structure. We should probably get this 471 machine_data->dai[0].stream_name = "playback";
445 * information from the device tree. 472 machine_data->dai[1].stream_name = "capture";
446 */ 473 machine_data->dai[0].name = machine_data->dai[0].stream_name;
447 machine_data->dai.name = "CS4270"; 474 machine_data->dai[1].name = machine_data->dai[1].stream_name;
448 machine_data->dai.stream_name = "CS4270";
449
450 machine_data->dai.cpu_dai = fsl_ssi_create_dai(&ssi_info);
451 machine_data->dai.codec_dai = &cs4270_dai; /* The codec_dai we want */
452 machine_data->dai.ops = &mpc8610_hpcd_ops;
453 475
454 machine_data->machine.probe = mpc8610_hpcd_machine_probe; 476 machine_data->card.probe = mpc8610_hpcd_machine_probe;
455 machine_data->machine.remove = mpc8610_hpcd_machine_remove; 477 machine_data->card.remove = mpc8610_hpcd_machine_remove;
456 machine_data->machine.name = "MPC8610 HPCD"; 478 machine_data->card.name = pdev->name; /* The platform driver name */
457 machine_data->machine.num_links = 1; 479 machine_data->card.num_links = 2;
458 machine_data->machine.dai_link = &machine_data->dai; 480 machine_data->card.dai_link = machine_data->dai;
459 481
460 /* Allocate a new audio platform device structure */ 482 /* Allocate a new audio platform device structure */
461 sound_device = platform_device_alloc("soc-audio", -1); 483 sound_device = platform_device_alloc("soc-audio", -1);
462 if (!sound_device) { 484 if (!sound_device) {
463 dev_err(&ofdev->dev, "platform device allocation failed\n"); 485 dev_err(&pdev->dev, "platform device alloc failed\n");
464 ret = -ENOMEM; 486 ret = -ENOMEM;
465 goto error; 487 goto error;
466 } 488 }
467 489
468 machine_data->sound_devdata.card = &machine_data->machine; 490 /* Associate the card data with the sound device */
469 machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270; 491 platform_set_drvdata(sound_device, &machine_data->card);
470 machine_data->machine.platform = &fsl_soc_platform;
471
472 sound_device->dev.platform_data = machine_data;
473
474 492
475 /* Set the platform device and ASoC device to point to each other */ 493 /* Register with ASoC */
476 platform_set_drvdata(sound_device, &machine_data->sound_devdata);
477
478 machine_data->sound_devdata.dev = &sound_device->dev;
479
480
481 /* Tell ASoC to probe us. This will call mpc8610_hpcd_machine.probe(),
482 if it exists. */
483 ret = platform_device_add(sound_device); 494 ret = platform_device_add(sound_device);
484
485 if (ret) { 495 if (ret) {
486 dev_err(&ofdev->dev, "platform device add failed\n"); 496 dev_err(&pdev->dev, "platform device add failed\n");
487 goto error; 497 goto error;
488 } 498 }
489 499
490 dev_set_drvdata(&ofdev->dev, sound_device); 500 of_node_put(codec_np);
491 501
492 return 0; 502 return 0;
493 503
494error: 504error:
495 of_node_put(codec_np); 505 of_node_put(codec_np);
496 of_node_put(guts_np);
497 of_node_put(dma_np);
498 of_node_put(dma_channel_np);
499 506
500 if (sound_device) 507 if (sound_device)
501 platform_device_unregister(sound_device); 508 platform_device_unregister(sound_device);
502 509
503 if (machine_data->dai.cpu_dai)
504 fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
505
506 if (ssi_info.ssi)
507 iounmap(ssi_info.ssi);
508
509 if (ssi_info.irq)
510 irq_dispose_mapping(ssi_info.irq);
511
512 if (dma_info.dma_channel[0])
513 iounmap(dma_info.dma_channel[0]);
514
515 if (dma_info.dma_channel[1])
516 iounmap(dma_info.dma_channel[1]);
517
518 if (dma_info.dma_irq[0])
519 irq_dispose_mapping(dma_info.dma_irq[0]);
520
521 if (dma_info.dma_irq[1])
522 irq_dispose_mapping(dma_info.dma_irq[1]);
523
524 if (machine_data->guts)
525 iounmap(machine_data->guts);
526
527 kfree(machine_data); 510 kfree(machine_data);
528 511
529 return ret; 512 return ret;
530} 513}
531 514
532/** 515/**
533 * mpc8610_hpcd_remove: remove the OF device 516 * mpc8610_hpcd_remove: remove the platform device
534 * 517 *
535 * This function is called when the OF device is removed. 518 * This function is called when the platform device is removed.
536 */ 519 */
537static int mpc8610_hpcd_remove(struct of_device *ofdev) 520static int __devexit mpc8610_hpcd_remove(struct platform_device *pdev)
538{ 521{
539 struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev); 522 struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
523 struct snd_soc_card *card = platform_get_drvdata(sound_device);
540 struct mpc8610_hpcd_data *machine_data = 524 struct mpc8610_hpcd_data *machine_data =
541 sound_device->dev.platform_data; 525 container_of(card, struct mpc8610_hpcd_data, card);
542 526
543 platform_device_unregister(sound_device); 527 platform_device_unregister(sound_device);
544 528
545 if (machine_data->dai.cpu_dai)
546 fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
547
548 if (machine_data->ssi)
549 iounmap(machine_data->ssi);
550
551 if (machine_data->dma[0])
552 iounmap(machine_data->dma[0]);
553
554 if (machine_data->dma[1])
555 iounmap(machine_data->dma[1]);
556
557 if (machine_data->dma_irq[0])
558 irq_dispose_mapping(machine_data->dma_irq[0]);
559
560 if (machine_data->dma_irq[1])
561 irq_dispose_mapping(machine_data->dma_irq[1]);
562
563 if (machine_data->guts)
564 iounmap(machine_data->guts);
565
566 kfree(machine_data); 529 kfree(machine_data);
567 sound_device->dev.platform_data = NULL; 530 sound_device->dev.platform_data = NULL;
568 531
569 dev_set_drvdata(&ofdev->dev, NULL); 532 dev_set_drvdata(&pdev->dev, NULL);
570 533
571 return 0; 534 return 0;
572} 535}
573 536
574static struct of_device_id mpc8610_hpcd_match[] = { 537static struct platform_driver mpc8610_hpcd_driver = {
575 { 538 .probe = mpc8610_hpcd_probe,
576 .compatible = "fsl,mpc8610-ssi", 539 .remove = __devexit_p(mpc8610_hpcd_remove),
577 },
578 {}
579};
580MODULE_DEVICE_TABLE(of, mpc8610_hpcd_match);
581
582static struct of_platform_driver mpc8610_hpcd_of_driver = {
583 .driver = { 540 .driver = {
584 .name = "mpc8610_hpcd", 541 /* The name must match the 'model' property in the device tree,
542 * in lowercase letters.
543 */
544 .name = "snd-soc-mpc8610hpcd",
585 .owner = THIS_MODULE, 545 .owner = THIS_MODULE,
586 .of_match_table = mpc8610_hpcd_match,
587 }, 546 },
588 .probe = mpc8610_hpcd_probe,
589 .remove = mpc8610_hpcd_remove,
590}; 547};
591 548
592/** 549/**
593 * mpc8610_hpcd_init: fabric driver initialization. 550 * mpc8610_hpcd_init: machine driver initialization.
594 * 551 *
595 * This function is called when this module is loaded. 552 * This function is called when this module is loaded.
596 */ 553 */
597static int __init mpc8610_hpcd_init(void) 554static int __init mpc8610_hpcd_init(void)
598{ 555{
599 int ret; 556 struct device_node *guts_np;
600 557 struct resource res;
601 printk(KERN_INFO "Freescale MPC8610 HPCD ALSA SoC fabric driver\n");
602 558
603 ret = of_register_platform_driver(&mpc8610_hpcd_of_driver); 559 pr_info("Freescale MPC8610 HPCD ALSA SoC machine driver\n");
604 560
605 if (ret) 561 /* Get the physical address of the global utilities registers */
606 printk(KERN_ERR 562 guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
607 "mpc8610-hpcd: failed to register platform driver\n"); 563 if (of_address_to_resource(guts_np, 0, &res)) {
564 pr_err("mpc8610-hpcd: missing/invalid global utilities node\n");
565 return -EINVAL;
566 }
567 guts_phys = res.start;
608 568
609 return ret; 569 return platform_driver_register(&mpc8610_hpcd_driver);
610} 570}
611 571
612/** 572/**
613 * mpc8610_hpcd_exit: fabric driver exit 573 * mpc8610_hpcd_exit: machine driver exit
614 * 574 *
615 * This function is called when this driver is unloaded. 575 * This function is called when this driver is unloaded.
616 */ 576 */
617static void __exit mpc8610_hpcd_exit(void) 577static void __exit mpc8610_hpcd_exit(void)
618{ 578{
619 of_unregister_platform_driver(&mpc8610_hpcd_of_driver); 579 platform_driver_unregister(&mpc8610_hpcd_driver);
620} 580}
621 581
622module_init(mpc8610_hpcd_init); 582module_init(mpc8610_hpcd_init);
623module_exit(mpc8610_hpcd_exit); 583module_exit(mpc8610_hpcd_exit);
624 584
625MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); 585MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
626MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC fabric driver"); 586MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC machine driver");
627MODULE_LICENSE("GPL"); 587MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
index 6644cba7cbf2..fe15bb26e484 100644
--- a/sound/soc/fsl/pcm030-audio-fabric.c
+++ b/sound/soc/fsl/pcm030-audio-fabric.c
@@ -32,21 +32,24 @@
32 32
33#define DRV_NAME "pcm030-audio-fabric" 33#define DRV_NAME "pcm030-audio-fabric"
34 34
35static struct snd_soc_device device;
36static struct snd_soc_card card; 35static struct snd_soc_card card;
37 36
38static struct snd_soc_dai_link pcm030_fabric_dai[] = { 37static struct snd_soc_dai_link pcm030_fabric_dai[] = {
39{ 38{
40 .name = "AC97", 39 .name = "AC97",
41 .stream_name = "AC97 Analog", 40 .stream_name = "AC97 Analog",
42 .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], 41 .codec_dai_name = "wm9712-hifi",
43 .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL], 42 .cpu_dai_name = "mpc5200-psc-ac97.0",
43 .platform_name = "mpc5200-pcm-audio",
44 .codec_name = "wm9712-codec",
44}, 45},
45{ 46{
46 .name = "AC97", 47 .name = "AC97",
47 .stream_name = "AC97 IEC958", 48 .stream_name = "AC97 IEC958",
48 .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], 49 .codec_dai_name = "wm9712-aux",
49 .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF], 50 .cpu_dai_name = "mpc5200-psc-ac97.1",
51 .platform_name = "mpc5200-pcm-audio",
52 ..codec_name = "wm9712-codec",
50}, 53},
51}; 54};
52 55
@@ -58,22 +61,18 @@ static __init int pcm030_fabric_init(void)
58 if (!of_machine_is_compatible("phytec,pcm030")) 61 if (!of_machine_is_compatible("phytec,pcm030"))
59 return -ENODEV; 62 return -ENODEV;
60 63
61 card.platform = &mpc5200_audio_dma_platform; 64
62 card.name = "pcm030"; 65 card.name = "pcm030";
63 card.dai_link = pcm030_fabric_dai; 66 card.dai_link = pcm030_fabric_dai;
64 card.num_links = ARRAY_SIZE(pcm030_fabric_dai); 67 card.num_links = ARRAY_SIZE(pcm030_fabric_dai);
65 68
66 device.card = &card;
67 device.codec_dev = &soc_codec_dev_wm9712;
68
69 pdev = platform_device_alloc("soc-audio", 1); 69 pdev = platform_device_alloc("soc-audio", 1);
70 if (!pdev) { 70 if (!pdev) {
71 pr_err("pcm030_fabric_init: platform_device_alloc() failed\n"); 71 pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
72 return -ENODEV; 72 return -ENODEV;
73 } 73 }
74 74
75 platform_set_drvdata(pdev, &device); 75 platform_set_drvdata(pdev, &card);
76 device.dev = &pdev->dev;
77 76
78 rc = platform_device_add(pdev); 77 rc = platform_device_add(pdev);
79 if (rc) { 78 if (rc) {
diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c
deleted file mode 100644
index 3bc13fd89096..000000000000
--- a/sound/soc/fsl/soc-of-simple.c
+++ /dev/null
@@ -1,172 +0,0 @@
1/*
2 * OF helpers for ALSA SoC Layer
3 *
4 * Copyright (C) 2008, Secret Lab Technologies Ltd.
5 */
6
7#include <linux/module.h>
8#include <linux/moduleparam.h>
9#include <linux/init.h>
10#include <linux/delay.h>
11#include <linux/pm.h>
12#include <linux/bitops.h>
13#include <linux/platform_device.h>
14#include <linux/of.h>
15#include <linux/slab.h>
16#include <sound/core.h>
17#include <sound/pcm.h>
18#include <sound/pcm_params.h>
19#include <sound/soc.h>
20#include <sound/soc-of-simple.h>
21#include <sound/initval.h>
22
23MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
24MODULE_LICENSE("GPL");
25MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
26
27static DEFINE_MUTEX(of_snd_soc_mutex);
28static LIST_HEAD(of_snd_soc_device_list);
29static int of_snd_soc_next_index;
30
31struct of_snd_soc_device {
32 int id;
33 struct list_head list;
34 struct snd_soc_device device;
35 struct snd_soc_card card;
36 struct snd_soc_dai_link dai_link;
37 struct platform_device *pdev;
38 struct device_node *platform_node;
39 struct device_node *codec_node;
40};
41
42static struct snd_soc_ops of_snd_soc_ops = {
43};
44
45static struct of_snd_soc_device *
46of_snd_soc_get_device(struct device_node *codec_node)
47{
48 struct of_snd_soc_device *of_soc;
49
50 list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
51 if (of_soc->codec_node == codec_node)
52 return of_soc;
53 }
54
55 of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
56 if (!of_soc)
57 return NULL;
58
59 /* Initialize the structure and add it to the global list */
60 of_soc->codec_node = codec_node;
61 of_soc->id = of_snd_soc_next_index++;
62 of_soc->card.dai_link = &of_soc->dai_link;
63 of_soc->card.num_links = 1;
64 of_soc->device.card = &of_soc->card;
65 of_soc->dai_link.ops = &of_snd_soc_ops;
66 list_add(&of_soc->list, &of_snd_soc_device_list);
67
68 return of_soc;
69}
70
71static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
72{
73 struct platform_device *pdev;
74 int rc;
75
76 /* Only register the device if both the codec and platform have
77 * been registered */
78 if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
79 return;
80
81 pr_info("platform<-->codec match achieved; registering machine\n");
82
83 pdev = platform_device_alloc("soc-audio", of_soc->id);
84 if (!pdev) {
85 pr_err("of_soc: platform_device_alloc() failed\n");
86 return;
87 }
88
89 pdev->dev.platform_data = of_soc;
90 platform_set_drvdata(pdev, &of_soc->device);
91 of_soc->device.dev = &pdev->dev;
92
93 /* The ASoC device is complete; register it */
94 rc = platform_device_add(pdev);
95 if (rc) {
96 pr_err("of_soc: platform_device_add() failed\n");
97 return;
98 }
99
100}
101
102int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
103 void *codec_data, struct snd_soc_dai *dai,
104 struct device_node *node)
105{
106 struct of_snd_soc_device *of_soc;
107 int rc = 0;
108
109 pr_info("registering ASoC codec driver: %s\n", node->full_name);
110
111 mutex_lock(&of_snd_soc_mutex);
112 of_soc = of_snd_soc_get_device(node);
113 if (!of_soc) {
114 rc = -ENOMEM;
115 goto out;
116 }
117
118 /* Store the codec data */
119 of_soc->device.codec_data = codec_data;
120 of_soc->device.codec_dev = codec_dev;
121 of_soc->dai_link.name = (char *)node->name;
122 of_soc->dai_link.stream_name = (char *)node->name;
123 of_soc->dai_link.codec_dai = dai;
124
125 /* Now try to register the SoC device */
126 of_snd_soc_register_device(of_soc);
127
128 out:
129 mutex_unlock(&of_snd_soc_mutex);
130 return rc;
131}
132EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
133
134int of_snd_soc_register_platform(struct snd_soc_platform *platform,
135 struct device_node *node,
136 struct snd_soc_dai *cpu_dai)
137{
138 struct of_snd_soc_device *of_soc;
139 struct device_node *codec_node;
140 const phandle *handle;
141 int len, rc = 0;
142
143 pr_info("registering ASoC platform driver: %s\n", node->full_name);
144
145 handle = of_get_property(node, "codec-handle", &len);
146 if (!handle || len < sizeof(handle))
147 return -ENODEV;
148 codec_node = of_find_node_by_phandle(*handle);
149 if (!codec_node)
150 return -ENODEV;
151 pr_info("looking for codec: %s\n", codec_node->full_name);
152
153 mutex_lock(&of_snd_soc_mutex);
154 of_soc = of_snd_soc_get_device(codec_node);
155 if (!of_soc) {
156 rc = -ENOMEM;
157 goto out;
158 }
159
160 of_soc->platform_node = node;
161 of_soc->dai_link.cpu_dai = cpu_dai;
162 of_soc->card.platform = platform;
163 of_soc->card.name = of_soc->dai_link.cpu_dai->name;
164
165 /* Now try to register the SoC device */
166 of_snd_soc_register_device(of_soc);
167
168 out:
169 mutex_unlock(&of_snd_soc_mutex);
170 return rc;
171}
172EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);