blob: 418c64629ee7e6c7844c9503d17d9ced461b8dff [file] [log] [blame]
Timur Tabi17467f22008-01-11 18:15:26 +01001/*
2 * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
3 *
4 * Author: Timur Tabi <timur@freescale.com>
5 *
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00006 * Copyright 2007-2010 Freescale Semiconductor, Inc.
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
Markus Pargmannde623ec2013-07-27 13:31:53 +020011 *
12 *
13 * Some notes why imx-pcm-fiq is used instead of DMA on some boards:
14 *
15 * The i.MX SSI core has some nasty limitations in AC97 mode. While most
16 * sane processor vendors have a FIFO per AC97 slot, the i.MX has only
17 * one FIFO which combines all valid receive slots. We cannot even select
18 * which slots we want to receive. The WM9712 with which this driver
19 * was developed with always sends GPIO status data in slot 12 which
20 * we receive in our (PCM-) data stream. The only chance we have is to
21 * manually skip this data in the FIQ handler. With sampling rates different
22 * from 48000Hz not every frame has valid receive data, so the ratio
23 * between pcm data and GPIO status data changes. Our FIQ handler is not
24 * able to handle this, hence this driver only works with 48000Hz sampling
25 * rate.
26 * Reading and writing AC97 registers is another challenge. The core
27 * provides us status bits when the read register is updated with *another*
28 * value. When we read the same register two times (and the register still
29 * contains the same value) these status bits are not set. We work
30 * around this by not polling these bits but only wait a fixed delay.
Timur Tabi17467f22008-01-11 18:15:26 +010031 */
32
33#include <linux/init.h>
Shawn Guodfa1a102012-03-16 16:56:42 +080034#include <linux/io.h>
Timur Tabi17467f22008-01-11 18:15:26 +010035#include <linux/module.h>
36#include <linux/interrupt.h>
Shawn Guo95cd98f2012-03-29 10:53:41 +080037#include <linux/clk.h>
Timur Tabi17467f22008-01-11 18:15:26 +010038#include <linux/device.h>
39#include <linux/delay.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090040#include <linux/slab.h>
Nicolin Chenaafa85e2013-12-12 18:44:45 +080041#include <linux/spinlock.h>
Shawn Guodfa1a102012-03-16 16:56:42 +080042#include <linux/of_address.h>
43#include <linux/of_irq.h>
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +000044#include <linux/of_platform.h>
Timur Tabi17467f22008-01-11 18:15:26 +010045
Timur Tabi17467f22008-01-11 18:15:26 +010046#include <sound/core.h>
47#include <sound/pcm.h>
48#include <sound/pcm_params.h>
49#include <sound/initval.h>
50#include <sound/soc.h>
Lars-Peter Clausena8909c92013-04-03 11:06:04 +020051#include <sound/dmaengine_pcm.h>
Timur Tabi17467f22008-01-11 18:15:26 +010052
Timur Tabi17467f22008-01-11 18:15:26 +010053#include "fsl_ssi.h"
Shawn Guo09ce1112012-03-16 16:56:43 +080054#include "imx-pcm.h"
Timur Tabi17467f22008-01-11 18:15:26 +010055
Shawn Guodfa1a102012-03-16 16:56:42 +080056#ifdef PPC
57#define read_ssi(addr) in_be32(addr)
58#define write_ssi(val, addr) out_be32(addr, val)
59#define write_ssi_mask(addr, clear, set) clrsetbits_be32(addr, clear, set)
Mark Brown0a9eaa32013-07-19 11:40:13 +010060#else
Shawn Guodfa1a102012-03-16 16:56:42 +080061#define read_ssi(addr) readl(addr)
62#define write_ssi(val, addr) writel(val, addr)
63/*
64 * FIXME: Proper locking should be added at write_ssi_mask caller level
65 * to ensure this register read/modify/write sequence is race free.
66 */
67static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
68{
69 u32 val = readl(addr);
70 val = (val & ~clear) | set;
71 writel(val, addr);
72}
73#endif
74
Timur Tabi17467f22008-01-11 18:15:26 +010075/**
76 * FSLSSI_I2S_RATES: sample rates supported by the I2S
77 *
78 * This driver currently only supports the SSI running in I2S slave mode,
79 * which means the codec determines the sample rate. Therefore, we tell
80 * ALSA that we support all rates and let the codec driver decide what rates
81 * are really supported.
82 */
Lars-Peter Clausen24710c92014-01-11 10:24:41 +010083#define FSLSSI_I2S_RATES SNDRV_PCM_RATE_CONTINUOUS
Timur Tabi17467f22008-01-11 18:15:26 +010084
85/**
86 * FSLSSI_I2S_FORMATS: audio formats supported by the SSI
87 *
88 * This driver currently only supports the SSI running in I2S slave mode.
89 *
90 * The SSI has a limitation in that the samples must be in the same byte
91 * order as the host CPU. This is because when multiple bytes are written
92 * to the STX register, the bytes and bits must be written in the same
93 * order. The STX is a shift register, so all the bits need to be aligned
94 * (bit-endianness must match byte-endianness). Processors typically write
95 * the bits within a byte in the same order that the bytes of a word are
96 * written in. So if the host CPU is big-endian, then only big-endian
97 * samples will be written to STX properly.
98 */
99#ifdef __BIG_ENDIAN
100#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
101 SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_S20_3BE | \
102 SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_S24_BE)
103#else
104#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
105 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \
106 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
107#endif
108
Markus Pargmann9368acc2013-12-20 14:11:29 +0100109#define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \
110 CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \
111 CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_RFRC_EN)
112#define FSLSSI_SIER_DBG_TX_FLAGS (CCSR_SSI_SIER_TFE0_EN | \
113 CCSR_SSI_SIER_TLS_EN | CCSR_SSI_SIER_TFS_EN | \
114 CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN)
Markus Pargmannc1953bf2013-12-20 14:11:30 +0100115
116enum fsl_ssi_type {
117 FSL_SSI_MCP8610,
118 FSL_SSI_MX21,
Markus Pargmann0888efd2013-12-20 14:11:31 +0100119 FSL_SSI_MX35,
Markus Pargmannc1953bf2013-12-20 14:11:30 +0100120 FSL_SSI_MX51,
121};
122
Markus Pargmann4e6ec0d2013-12-20 14:11:33 +0100123struct fsl_ssi_reg_val {
124 u32 sier;
125 u32 srcr;
126 u32 stcr;
127 u32 scr;
128};
129
130struct fsl_ssi_rxtx_reg_val {
131 struct fsl_ssi_reg_val rx;
132 struct fsl_ssi_reg_val tx;
133};
Timur Tabid5a908b2009-03-26 11:42:38 -0500134
Timur Tabi17467f22008-01-11 18:15:26 +0100135/**
136 * fsl_ssi_private: per-SSI private data
137 *
Timur Tabi17467f22008-01-11 18:15:26 +0100138 * @ssi: pointer to the SSI's registers
139 * @ssi_phys: physical address of the SSI registers
140 * @irq: IRQ of this SSI
Timur Tabi17467f22008-01-11 18:15:26 +0100141 * @playback: the number of playback streams opened
142 * @capture: the number of capture streams opened
143 * @cpu_dai: the CPU DAI for this device
144 * @dev_attr: the sysfs device attribute structure
145 * @stats: SSI statistics
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000146 * @name: name for this device
Timur Tabi17467f22008-01-11 18:15:26 +0100147 */
148struct fsl_ssi_private {
Timur Tabi17467f22008-01-11 18:15:26 +0100149 struct ccsr_ssi __iomem *ssi;
150 dma_addr_t ssi_phys;
151 unsigned int irq;
Timur Tabi8e9d8692010-08-06 12:16:12 -0500152 unsigned int fifo_depth;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000153 struct snd_soc_dai_driver cpu_dai_drv;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000154 struct platform_device *pdev;
Timur Tabi17467f22008-01-11 18:15:26 +0100155
Markus Pargmann0888efd2013-12-20 14:11:31 +0100156 enum fsl_ssi_type hw_type;
Shawn Guo09ce1112012-03-16 16:56:43 +0800157 bool new_binding;
158 bool ssi_on_imx;
Markus Pargmanncd7f0292013-08-19 17:05:58 +0200159 bool imx_ac97;
Markus Pargmannde623ec2013-07-27 13:31:53 +0200160 bool use_dma;
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800161 bool baudclk_locked;
Markus Pargmann2841be92013-12-20 14:11:28 +0100162 bool irq_stats;
Markus Pargmannbd3ca7d2013-12-20 14:11:32 +0100163 bool offline_config;
Nicolin Chen0da9e552013-11-13 22:55:26 +0800164 bool use_dual_fifo;
Nicolin Chen2924a992013-12-02 23:29:03 +0800165 u8 i2s_mode;
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800166 spinlock_t baudclk_lock;
167 struct clk *baudclk;
Shawn Guo95cd98f2012-03-29 10:53:41 +0800168 struct clk *clk;
Lars-Peter Clausena8909c92013-04-03 11:06:04 +0200169 struct snd_dmaengine_dai_dma_data dma_params_tx;
170 struct snd_dmaengine_dai_dma_data dma_params_rx;
171 struct imx_dma_data filter_data_tx;
172 struct imx_dma_data filter_data_rx;
Markus Pargmannde623ec2013-07-27 13:31:53 +0200173 struct imx_pcm_fiq_params fiq_params;
Markus Pargmann4e6ec0d2013-12-20 14:11:33 +0100174 /* Register values for rx/tx configuration */
175 struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
Shawn Guo09ce1112012-03-16 16:56:43 +0800176
Markus Pargmannf138e622014-04-28 12:54:43 +0200177 struct fsl_ssi_dbg dbg_stats;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000178
179 char name[1];
Timur Tabi17467f22008-01-11 18:15:26 +0100180};
181
Markus Pargmannc1953bf2013-12-20 14:11:30 +0100182static const struct of_device_id fsl_ssi_ids[] = {
183 { .compatible = "fsl,mpc8610-ssi", .data = (void *) FSL_SSI_MCP8610},
184 { .compatible = "fsl,imx51-ssi", .data = (void *) FSL_SSI_MX51},
Markus Pargmann0888efd2013-12-20 14:11:31 +0100185 { .compatible = "fsl,imx35-ssi", .data = (void *) FSL_SSI_MX35},
Markus Pargmannc1953bf2013-12-20 14:11:30 +0100186 { .compatible = "fsl,imx21-ssi", .data = (void *) FSL_SSI_MX21},
187 {}
188};
189MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
190
Timur Tabi17467f22008-01-11 18:15:26 +0100191/**
192 * fsl_ssi_isr: SSI interrupt handler
193 *
194 * Although it's possible to use the interrupt handler to send and receive
195 * data to/from the SSI, we use the DMA instead. Programming is more
196 * complicated, but the performance is much better.
197 *
198 * This interrupt handler is used only to gather statistics.
199 *
200 * @irq: IRQ of the SSI device
201 * @dev_id: pointer to the ssi_private structure for this SSI device
202 */
203static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
204{
205 struct fsl_ssi_private *ssi_private = dev_id;
206 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
Timur Tabi17467f22008-01-11 18:15:26 +0100207 __be32 sisr;
Markus Pargmann0888efd2013-12-20 14:11:31 +0100208 __be32 sisr2;
209 __be32 sisr_write_mask = 0;
210
211 switch (ssi_private->hw_type) {
212 case FSL_SSI_MX21:
213 sisr_write_mask = 0;
214 break;
215
216 case FSL_SSI_MCP8610:
217 case FSL_SSI_MX35:
218 sisr_write_mask = CCSR_SSI_SISR_RFRC | CCSR_SSI_SISR_TFRC |
219 CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 |
220 CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1;
221 break;
222
223 case FSL_SSI_MX51:
224 sisr_write_mask = CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 |
225 CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1;
226 break;
227 }
Timur Tabi17467f22008-01-11 18:15:26 +0100228
229 /* We got an interrupt, so read the status register to see what we
230 were interrupted for. We mask it with the Interrupt Enable register
231 so that we only check for events that we're interested in.
232 */
Markus Pargmannf138e622014-04-28 12:54:43 +0200233 sisr = read_ssi(&ssi->sisr);
Timur Tabi17467f22008-01-11 18:15:26 +0100234
Markus Pargmann0888efd2013-12-20 14:11:31 +0100235 sisr2 = sisr & sisr_write_mask;
Timur Tabi17467f22008-01-11 18:15:26 +0100236 /* Clear the bits that we set */
237 if (sisr2)
Shawn Guodfa1a102012-03-16 16:56:42 +0800238 write_ssi(sisr2, &ssi->sisr);
Timur Tabi17467f22008-01-11 18:15:26 +0100239
Markus Pargmannf138e622014-04-28 12:54:43 +0200240 fsl_ssi_dbg_isr(&ssi_private->dbg_stats, sisr);
241
242 return IRQ_HANDLED;
Timur Tabi17467f22008-01-11 18:15:26 +0100243}
244
Markus Pargmann4e6ec0d2013-12-20 14:11:33 +0100245/*
246 * Enable/Disable all rx/tx config flags at once.
247 */
248static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private,
249 bool enable)
250{
251 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
252 struct fsl_ssi_rxtx_reg_val *vals = &ssi_private->rxtx_reg_val;
253
254 if (enable) {
255 write_ssi_mask(&ssi->sier, 0, vals->rx.sier | vals->tx.sier);
256 write_ssi_mask(&ssi->srcr, 0, vals->rx.srcr | vals->tx.srcr);
257 write_ssi_mask(&ssi->stcr, 0, vals->rx.stcr | vals->tx.stcr);
258 } else {
259 write_ssi_mask(&ssi->srcr, vals->rx.srcr | vals->tx.srcr, 0);
260 write_ssi_mask(&ssi->stcr, vals->rx.stcr | vals->tx.stcr, 0);
261 write_ssi_mask(&ssi->sier, vals->rx.sier | vals->tx.sier, 0);
262 }
263}
264
265/*
Markus Pargmann65c961c2014-04-28 12:54:42 +0200266 * Calculate the bits that have to be disabled for the current stream that is
267 * getting disabled. This keeps the bits enabled that are necessary for the
268 * second stream to work if 'stream_active' is true.
269 *
270 * Detailed calculation:
271 * These are the values that need to be active after disabling. For non-active
272 * second stream, this is 0:
273 * vals_stream * !!stream_active
274 *
275 * The following computes the overall differences between the setup for the
276 * to-disable stream and the active stream, a simple XOR:
277 * vals_disable ^ (vals_stream * !!(stream_active))
278 *
279 * The full expression adds a mask on all values we care about
280 */
281#define fsl_ssi_disable_val(vals_disable, vals_stream, stream_active) \
282 ((vals_disable) & \
283 ((vals_disable) ^ ((vals_stream) * (u32)!!(stream_active))))
284
285/*
Markus Pargmann4e6ec0d2013-12-20 14:11:33 +0100286 * Enable/Disable a ssi configuration. You have to pass either
287 * ssi_private->rxtx_reg_val.rx or tx as vals parameter.
288 */
289static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
290 struct fsl_ssi_reg_val *vals)
291{
292 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
293 struct fsl_ssi_reg_val *avals;
294 u32 scr_val = read_ssi(&ssi->scr);
295 int nr_active_streams = !!(scr_val & CCSR_SSI_SCR_TE) +
296 !!(scr_val & CCSR_SSI_SCR_RE);
Markus Pargmann65c961c2014-04-28 12:54:42 +0200297 int keep_active;
298
299 if (nr_active_streams - 1 > 0)
300 keep_active = 1;
301 else
302 keep_active = 0;
Markus Pargmann4e6ec0d2013-12-20 14:11:33 +0100303
304 /* Find the other direction values rx or tx which we do not want to
305 * modify */
306 if (&ssi_private->rxtx_reg_val.rx == vals)
307 avals = &ssi_private->rxtx_reg_val.tx;
308 else
309 avals = &ssi_private->rxtx_reg_val.rx;
310
311 /* If vals should be disabled, start with disabling the unit */
312 if (!enable) {
Markus Pargmann65c961c2014-04-28 12:54:42 +0200313 u32 scr = fsl_ssi_disable_val(vals->scr, avals->scr,
314 keep_active);
Markus Pargmann4e6ec0d2013-12-20 14:11:33 +0100315 write_ssi_mask(&ssi->scr, scr, 0);
316 }
317
318 /*
319 * We are running on a SoC which does not support online SSI
320 * reconfiguration, so we have to enable all necessary flags at once
321 * even if we do not use them later (capture and playback configuration)
322 */
323 if (ssi_private->offline_config) {
324 if ((enable && !nr_active_streams) ||
Markus Pargmann65c961c2014-04-28 12:54:42 +0200325 (!enable && !keep_active))
Markus Pargmann4e6ec0d2013-12-20 14:11:33 +0100326 fsl_ssi_rxtx_config(ssi_private, enable);
327
328 goto config_done;
329 }
330
331 /*
332 * Configure single direction units while the SSI unit is running
333 * (online configuration)
334 */
335 if (enable) {
336 write_ssi_mask(&ssi->sier, 0, vals->sier);
337 write_ssi_mask(&ssi->srcr, 0, vals->srcr);
338 write_ssi_mask(&ssi->stcr, 0, vals->stcr);
339 } else {
340 u32 sier;
341 u32 srcr;
342 u32 stcr;
343
344 /*
345 * Disabling the necessary flags for one of rx/tx while the
346 * other stream is active is a little bit more difficult. We
347 * have to disable only those flags that differ between both
348 * streams (rx XOR tx) and that are set in the stream that is
349 * disabled now. Otherwise we could alter flags of the other
350 * stream
351 */
352
353 /* These assignments are simply vals without bits set in avals*/
Markus Pargmann65c961c2014-04-28 12:54:42 +0200354 sier = fsl_ssi_disable_val(vals->sier, avals->sier,
355 keep_active);
356 srcr = fsl_ssi_disable_val(vals->srcr, avals->srcr,
357 keep_active);
358 stcr = fsl_ssi_disable_val(vals->stcr, avals->stcr,
359 keep_active);
Markus Pargmann4e6ec0d2013-12-20 14:11:33 +0100360
361 write_ssi_mask(&ssi->srcr, srcr, 0);
362 write_ssi_mask(&ssi->stcr, stcr, 0);
363 write_ssi_mask(&ssi->sier, sier, 0);
364 }
365
366config_done:
367 /* Enabling of subunits is done after configuration */
368 if (enable)
369 write_ssi_mask(&ssi->scr, 0, vals->scr);
370}
371
372
373static void fsl_ssi_rx_config(struct fsl_ssi_private *ssi_private, bool enable)
374{
375 fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.rx);
376}
377
378static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable)
379{
380 fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.tx);
381}
382
Markus Pargmann6de83872013-12-20 14:11:34 +0100383/*
384 * Setup rx/tx register values used to enable/disable the streams. These will
385 * be used later in fsl_ssi_config to setup the streams without the need to
386 * check for all different SSI modes.
387 */
388static void fsl_ssi_setup_reg_vals(struct fsl_ssi_private *ssi_private)
389{
390 struct fsl_ssi_rxtx_reg_val *reg = &ssi_private->rxtx_reg_val;
391
392 reg->rx.sier = CCSR_SSI_SIER_RFF0_EN;
393 reg->rx.srcr = CCSR_SSI_SRCR_RFEN0;
394 reg->rx.scr = 0;
395 reg->tx.sier = CCSR_SSI_SIER_TFE0_EN;
396 reg->tx.stcr = CCSR_SSI_STCR_TFEN0;
397 reg->tx.scr = 0;
398
399 if (!ssi_private->imx_ac97) {
400 reg->rx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE;
401 reg->rx.sier |= CCSR_SSI_SIER_RFF0_EN;
402 reg->tx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE;
403 reg->tx.sier |= CCSR_SSI_SIER_TFE0_EN;
404 }
405
406 if (ssi_private->use_dma) {
407 reg->rx.sier |= CCSR_SSI_SIER_RDMAE;
408 reg->tx.sier |= CCSR_SSI_SIER_TDMAE;
409 } else {
410 reg->rx.sier |= CCSR_SSI_SIER_RIE;
411 reg->tx.sier |= CCSR_SSI_SIER_TIE;
412 }
413
414 reg->rx.sier |= FSLSSI_SIER_DBG_RX_FLAGS;
415 reg->tx.sier |= FSLSSI_SIER_DBG_TX_FLAGS;
416}
417
Markus Pargmannd8764642013-11-20 10:04:15 +0100418static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
419{
420 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
421
422 /*
423 * Setup the clock control register
424 */
425 write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
426 &ssi->stccr);
427 write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
428 &ssi->srccr);
429
430 /*
431 * Enable AC97 mode and startup the SSI
432 */
433 write_ssi(CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV,
434 &ssi->sacnt);
435 write_ssi(0xff, &ssi->saccdis);
436 write_ssi(0x300, &ssi->saccen);
437
438 /*
439 * Enable SSI, Transmit and Receive. AC97 has to communicate with the
440 * codec before a stream is started.
441 */
442 write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN |
443 CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE);
444
445 write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
446}
447
Timur Tabi17467f22008-01-11 18:15:26 +0100448/**
449 * fsl_ssi_startup: create a new substream
450 *
451 * This is the first function called when a stream is opened.
452 *
453 * If this is the first stream open, then grab the IRQ and program most of
454 * the SSI registers.
455 */
Mark Browndee89c42008-11-18 22:11:38 +0000456static int fsl_ssi_startup(struct snd_pcm_substream *substream,
457 struct snd_soc_dai *dai)
Timur Tabi17467f22008-01-11 18:15:26 +0100458{
459 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Timur Tabi5e538ec2011-09-13 12:59:37 -0500460 struct fsl_ssi_private *ssi_private =
461 snd_soc_dai_get_drvdata(rtd->cpu_dai);
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800462 unsigned long flags;
Timur Tabi17467f22008-01-11 18:15:26 +0100463
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800464 if (!dai->active && !ssi_private->imx_ac97) {
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800465 spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
466 ssi_private->baudclk_locked = false;
467 spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
468 }
Timur Tabibe41e942008-07-28 17:04:39 -0500469
Nicolin Chen0da9e552013-11-13 22:55:26 +0800470 /* When using dual fifo mode, it is safer to ensure an even period
471 * size. If appearing to an odd number while DMA always starts its
472 * task from fifo0, fifo1 would be neglected at the end of each
473 * period. But SSI would still access fifo1 with an invalid data.
474 */
475 if (ssi_private->use_dual_fifo)
476 snd_pcm_hw_constraint_step(substream->runtime, 0,
477 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
478
Timur Tabi17467f22008-01-11 18:15:26 +0100479 return 0;
480}
481
482/**
Timur Tabi85ef2372009-02-05 17:56:02 -0600483 * fsl_ssi_hw_params - program the sample size
Timur Tabi17467f22008-01-11 18:15:26 +0100484 *
485 * Most of the SSI registers have been programmed in the startup function,
486 * but the word length must be programmed here. Unfortunately, programming
487 * the SxCCR.WL bits requires the SSI to be temporarily disabled. This can
488 * cause a problem with supporting simultaneous playback and capture. If
489 * the SSI is already playing a stream, then that stream may be temporarily
490 * stopped when you start capture.
491 *
492 * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the
493 * clock master.
494 */
Timur Tabi85ef2372009-02-05 17:56:02 -0600495static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
496 struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
Timur Tabi17467f22008-01-11 18:15:26 +0100497{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000498 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
Timur Tabi5e538ec2011-09-13 12:59:37 -0500499 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
Nicolin Chen2924a992013-12-02 23:29:03 +0800500 unsigned int channels = params_channels(hw_params);
Timur Tabi5e538ec2011-09-13 12:59:37 -0500501 unsigned int sample_size =
502 snd_pcm_format_width(params_format(hw_params));
503 u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
Shawn Guodfa1a102012-03-16 16:56:42 +0800504 int enabled = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
Timur Tabi17467f22008-01-11 18:15:26 +0100505
Timur Tabi5e538ec2011-09-13 12:59:37 -0500506 /*
507 * If we're in synchronous mode, and the SSI is already enabled,
508 * then STCCR is already set properly.
509 */
510 if (enabled && ssi_private->cpu_dai_drv.symmetric_rates)
511 return 0;
Timur Tabi17467f22008-01-11 18:15:26 +0100512
Timur Tabi5e538ec2011-09-13 12:59:37 -0500513 /*
514 * FIXME: The documentation says that SxCCR[WL] should not be
515 * modified while the SSI is enabled. The only time this can
516 * happen is if we're trying to do simultaneous playback and
517 * capture in asynchronous mode. Unfortunately, I have been enable
518 * to get that to work at all on the P1022DS. Therefore, we don't
519 * bother to disable/enable the SSI when setting SxCCR[WL], because
520 * the SSI will stop anyway. Maybe one day, this will get fixed.
521 */
Timur Tabi17467f22008-01-11 18:15:26 +0100522
Timur Tabi5e538ec2011-09-13 12:59:37 -0500523 /* In synchronous mode, the SSI uses STCCR for capture */
524 if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
525 ssi_private->cpu_dai_drv.symmetric_rates)
Shawn Guodfa1a102012-03-16 16:56:42 +0800526 write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
Timur Tabi5e538ec2011-09-13 12:59:37 -0500527 else
Shawn Guodfa1a102012-03-16 16:56:42 +0800528 write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
Timur Tabi17467f22008-01-11 18:15:26 +0100529
Nicolin Chen2924a992013-12-02 23:29:03 +0800530 if (!ssi_private->imx_ac97)
531 write_ssi_mask(&ssi->scr,
532 CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
533 channels == 1 ? 0 : ssi_private->i2s_mode);
534
Timur Tabi17467f22008-01-11 18:15:26 +0100535 return 0;
536}
537
538/**
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800539 * fsl_ssi_set_dai_fmt - configure Digital Audio Interface Format.
540 */
541static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
542{
543 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
544 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
545 u32 strcr = 0, stcr, srcr, scr, mask;
Markus Pargmann2b0db992014-03-15 13:44:09 +0100546 u8 wm;
547
548 fsl_ssi_setup_reg_vals(ssi_private);
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800549
550 scr = read_ssi(&ssi->scr) & ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK);
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800551
552 mask = CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR |
553 CCSR_SSI_STCR_TSCKP | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TFSL |
554 CCSR_SSI_STCR_TEFS;
555 stcr = read_ssi(&ssi->stcr) & ~mask;
556 srcr = read_ssi(&ssi->srcr) & ~mask;
557
Markus Pargmann07a28db2014-03-15 13:44:10 +0100558 ssi_private->i2s_mode = CCSR_SSI_SCR_NET;
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800559 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
560 case SND_SOC_DAIFMT_I2S:
561 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
562 case SND_SOC_DAIFMT_CBS_CFS:
Markus Pargmann07a28db2014-03-15 13:44:10 +0100563 ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER;
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800564 break;
565 case SND_SOC_DAIFMT_CBM_CFM:
Markus Pargmann07a28db2014-03-15 13:44:10 +0100566 ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_SLAVE;
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800567 break;
568 default:
569 return -EINVAL;
570 }
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800571
572 /* Data on rising edge of bclk, frame low, 1clk before data */
573 strcr |= CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TSCKP |
574 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS;
575 break;
576 case SND_SOC_DAIFMT_LEFT_J:
577 /* Data on rising edge of bclk, frame high */
578 strcr |= CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TSCKP;
579 break;
580 case SND_SOC_DAIFMT_DSP_A:
581 /* Data on rising edge of bclk, frame high, 1clk before data */
582 strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
583 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS;
584 break;
585 case SND_SOC_DAIFMT_DSP_B:
586 /* Data on rising edge of bclk, frame high */
587 strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
588 CCSR_SSI_STCR_TXBIT0;
589 break;
Markus Pargmann2b0db992014-03-15 13:44:09 +0100590 case SND_SOC_DAIFMT_AC97:
Markus Pargmann07a28db2014-03-15 13:44:10 +0100591 ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_NORMAL;
Markus Pargmann2b0db992014-03-15 13:44:09 +0100592 break;
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800593 default:
594 return -EINVAL;
595 }
Markus Pargmann2b0db992014-03-15 13:44:09 +0100596 scr |= ssi_private->i2s_mode;
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800597
598 /* DAI clock inversion */
599 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
600 case SND_SOC_DAIFMT_NB_NF:
601 /* Nothing to do for both normal cases */
602 break;
603 case SND_SOC_DAIFMT_IB_NF:
604 /* Invert bit clock */
605 strcr ^= CCSR_SSI_STCR_TSCKP;
606 break;
607 case SND_SOC_DAIFMT_NB_IF:
608 /* Invert frame clock */
609 strcr ^= CCSR_SSI_STCR_TFSI;
610 break;
611 case SND_SOC_DAIFMT_IB_IF:
612 /* Invert both clocks */
613 strcr ^= CCSR_SSI_STCR_TSCKP;
614 strcr ^= CCSR_SSI_STCR_TFSI;
615 break;
616 default:
617 return -EINVAL;
618 }
619
620 /* DAI clock master masks */
621 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
622 case SND_SOC_DAIFMT_CBS_CFS:
623 strcr |= CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR;
624 scr |= CCSR_SSI_SCR_SYS_CLK_EN;
625 break;
626 case SND_SOC_DAIFMT_CBM_CFM:
627 scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
628 break;
629 default:
630 return -EINVAL;
631 }
632
633 stcr |= strcr;
634 srcr |= strcr;
635
636 if (ssi_private->cpu_dai_drv.symmetric_rates) {
637 /* Need to clear RXDIR when using SYNC mode */
638 srcr &= ~CCSR_SSI_SRCR_RXDIR;
639 scr |= CCSR_SSI_SCR_SYN;
640 }
641
642 write_ssi(stcr, &ssi->stcr);
643 write_ssi(srcr, &ssi->srcr);
644 write_ssi(scr, &ssi->scr);
645
Markus Pargmann2b0db992014-03-15 13:44:09 +0100646 /*
647 * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't
648 * use FIFO 1. We program the transmit water to signal a DMA transfer
649 * if there are only two (or fewer) elements left in the FIFO. Two
650 * elements equals one frame (left channel, right channel). This value,
651 * however, depends on the depth of the transmit buffer.
652 *
653 * We set the watermark on the same level as the DMA burstsize. For
654 * fiq it is probably better to use the biggest possible watermark
655 * size.
656 */
657 if (ssi_private->use_dma)
658 wm = ssi_private->fifo_depth - 2;
659 else
660 wm = ssi_private->fifo_depth;
661
662 write_ssi(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) |
663 CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm),
664 &ssi->sfcsr);
665
666 if (ssi_private->use_dual_fifo) {
667 write_ssi_mask(&ssi->srcr, CCSR_SSI_SRCR_RFEN1,
668 CCSR_SSI_SRCR_RFEN1);
669 write_ssi_mask(&ssi->stcr, CCSR_SSI_STCR_TFEN1,
670 CCSR_SSI_STCR_TFEN1);
671 write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TCH_EN,
672 CCSR_SSI_SCR_TCH_EN);
673 }
674
675 if (fmt & SND_SOC_DAIFMT_AC97)
676 fsl_ssi_setup_ac97(ssi_private);
677
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800678 return 0;
679}
680
681/**
682 * fsl_ssi_set_dai_sysclk - configure Digital Audio Interface bit clock
683 *
684 * Note: This function can be only called when using SSI as DAI master
685 *
686 * Quick instruction for parameters:
687 * freq: Output BCLK frequency = samplerate * 32 (fixed) * channels
688 * dir: SND_SOC_CLOCK_OUT -> TxBCLK, SND_SOC_CLOCK_IN -> RxBCLK.
689 */
690static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
691 int clk_id, unsigned int freq, int dir)
692{
693 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
694 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
695 int synchronous = ssi_private->cpu_dai_drv.symmetric_rates, ret;
696 u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i;
697 unsigned long flags, clkrate, baudrate, tmprate;
698 u64 sub, savesub = 100000;
699
700 /* Don't apply it to any non-baudclk circumstance */
701 if (IS_ERR(ssi_private->baudclk))
702 return -EINVAL;
703
704 /* It should be already enough to divide clock by setting pm alone */
705 psr = 0;
706 div2 = 0;
707
708 factor = (div2 + 1) * (7 * psr + 1) * 2;
709
710 for (i = 0; i < 255; i++) {
711 /* The bclk rate must be smaller than 1/5 sysclk rate */
712 if (factor * (i + 1) < 5)
713 continue;
714
715 tmprate = freq * factor * (i + 2);
716 clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
717
718 do_div(clkrate, factor);
719 afreq = (u32)clkrate / (i + 1);
720
721 if (freq == afreq)
722 sub = 0;
723 else if (freq / afreq == 1)
724 sub = freq - afreq;
725 else if (afreq / freq == 1)
726 sub = afreq - freq;
727 else
728 continue;
729
730 /* Calculate the fraction */
731 sub *= 100000;
732 do_div(sub, freq);
733
734 if (sub < savesub) {
735 baudrate = tmprate;
736 savesub = sub;
737 pm = i;
738 }
739
740 /* We are lucky */
741 if (savesub == 0)
742 break;
743 }
744
745 /* No proper pm found if it is still remaining the initial value */
746 if (pm == 999) {
747 dev_err(cpu_dai->dev, "failed to handle the required sysclk\n");
748 return -EINVAL;
749 }
750
751 stccr = CCSR_SSI_SxCCR_PM(pm + 1) | (div2 ? CCSR_SSI_SxCCR_DIV2 : 0) |
752 (psr ? CCSR_SSI_SxCCR_PSR : 0);
753 mask = CCSR_SSI_SxCCR_PM_MASK | CCSR_SSI_SxCCR_DIV2 | CCSR_SSI_SxCCR_PSR;
754
755 if (dir == SND_SOC_CLOCK_OUT || synchronous)
756 write_ssi_mask(&ssi->stccr, mask, stccr);
757 else
758 write_ssi_mask(&ssi->srccr, mask, stccr);
759
760 spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
761 if (!ssi_private->baudclk_locked) {
762 ret = clk_set_rate(ssi_private->baudclk, baudrate);
763 if (ret) {
764 spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
765 dev_err(cpu_dai->dev, "failed to set baudclk rate\n");
766 return -EINVAL;
767 }
768 ssi_private->baudclk_locked = true;
769 }
770 spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
771
772 return 0;
773}
774
775/**
776 * fsl_ssi_set_dai_tdm_slot - set TDM slot number
777 *
778 * Note: This function can be only called when using SSI as DAI master
779 */
780static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
781 u32 rx_mask, int slots, int slot_width)
782{
783 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
784 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
785 u32 val;
786
787 /* The slot number should be >= 2 if using Network mode or I2S mode */
788 val = read_ssi(&ssi->scr) & (CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_NET);
789 if (val && slots < 2) {
790 dev_err(cpu_dai->dev, "slot number should be >= 2 in I2S or NET\n");
791 return -EINVAL;
792 }
793
794 write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK,
795 CCSR_SSI_SxCCR_DC(slots));
796 write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK,
797 CCSR_SSI_SxCCR_DC(slots));
798
799 /* The register SxMSKs needs SSI to provide essential clock due to
800 * hardware design. So we here temporarily enable SSI to set them.
801 */
802 val = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
803 write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN);
804
805 write_ssi(tx_mask, &ssi->stmsk);
806 write_ssi(rx_mask, &ssi->srmsk);
807
808 write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, val);
809
810 return 0;
811}
812
813/**
Timur Tabi17467f22008-01-11 18:15:26 +0100814 * fsl_ssi_trigger: start and stop the DMA transfer.
815 *
816 * This function is called by ALSA to start, stop, pause, and resume the DMA
817 * transfer of data.
818 *
819 * The DMA channel is in external master start and pause mode, which
820 * means the SSI completely controls the flow of data.
821 */
Mark Browndee89c42008-11-18 22:11:38 +0000822static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
823 struct snd_soc_dai *dai)
Timur Tabi17467f22008-01-11 18:15:26 +0100824{
825 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000826 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
Timur Tabi17467f22008-01-11 18:15:26 +0100827 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800828 unsigned long flags;
Michael Grzeschik9b443e32013-08-19 17:06:00 +0200829
Timur Tabi17467f22008-01-11 18:15:26 +0100830 switch (cmd) {
831 case SNDRV_PCM_TRIGGER_START:
Timur Tabi17467f22008-01-11 18:15:26 +0100832 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
Timur Tabia4d11fe2009-03-25 18:20:37 -0500833 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Markus Pargmann6de83872013-12-20 14:11:34 +0100834 fsl_ssi_tx_config(ssi_private, true);
Timur Tabia4d11fe2009-03-25 18:20:37 -0500835 else
Markus Pargmann6de83872013-12-20 14:11:34 +0100836 fsl_ssi_rx_config(ssi_private, true);
Timur Tabi17467f22008-01-11 18:15:26 +0100837 break;
838
839 case SNDRV_PCM_TRIGGER_STOP:
Timur Tabi17467f22008-01-11 18:15:26 +0100840 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
841 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
Markus Pargmann6de83872013-12-20 14:11:34 +0100842 fsl_ssi_tx_config(ssi_private, false);
Timur Tabi17467f22008-01-11 18:15:26 +0100843 else
Markus Pargmann6de83872013-12-20 14:11:34 +0100844 fsl_ssi_rx_config(ssi_private, false);
Nicolin Chenb2c119b2013-07-10 18:43:54 +0800845
Markus Pargmanncd7f0292013-08-19 17:05:58 +0200846 if (!ssi_private->imx_ac97 && (read_ssi(&ssi->scr) &
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800847 (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) {
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800848 spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
849 ssi_private->baudclk_locked = false;
850 spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
851 }
Timur Tabi17467f22008-01-11 18:15:26 +0100852 break;
853
854 default:
855 return -EINVAL;
856 }
857
Markus Pargmanna5a7ee72013-12-20 14:11:35 +0100858 if (ssi_private->imx_ac97) {
859 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
860 write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor);
861 else
862 write_ssi(CCSR_SSI_SOR_RX_CLR, &ssi->sor);
863 }
Michael Grzeschik9b443e32013-08-19 17:06:00 +0200864
Timur Tabi17467f22008-01-11 18:15:26 +0100865 return 0;
866}
867
Lars-Peter Clausenfc8ba7f2013-04-15 19:19:58 +0200868static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
869{
870 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai);
871
Markus Pargmannde623ec2013-07-27 13:31:53 +0200872 if (ssi_private->ssi_on_imx && ssi_private->use_dma) {
Lars-Peter Clausenfc8ba7f2013-04-15 19:19:58 +0200873 dai->playback_dma_data = &ssi_private->dma_params_tx;
874 dai->capture_dma_data = &ssi_private->dma_params_rx;
875 }
876
877 return 0;
878}
879
Lars-Peter Clausen85e76522011-11-23 11:40:40 +0100880static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
Eric Miao6335d052009-03-03 09:41:00 +0800881 .startup = fsl_ssi_startup,
882 .hw_params = fsl_ssi_hw_params,
Nicolin Chenaafa85e2013-12-12 18:44:45 +0800883 .set_fmt = fsl_ssi_set_dai_fmt,
884 .set_sysclk = fsl_ssi_set_dai_sysclk,
885 .set_tdm_slot = fsl_ssi_set_dai_tdm_slot,
Eric Miao6335d052009-03-03 09:41:00 +0800886 .trigger = fsl_ssi_trigger,
Eric Miao6335d052009-03-03 09:41:00 +0800887};
888
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000889/* Template for the CPU dai driver structure */
890static struct snd_soc_dai_driver fsl_ssi_dai_template = {
Lars-Peter Clausenfc8ba7f2013-04-15 19:19:58 +0200891 .probe = fsl_ssi_dai_probe,
Timur Tabi17467f22008-01-11 18:15:26 +0100892 .playback = {
Nicolin Chen2924a992013-12-02 23:29:03 +0800893 .channels_min = 1,
Timur Tabi17467f22008-01-11 18:15:26 +0100894 .channels_max = 2,
895 .rates = FSLSSI_I2S_RATES,
896 .formats = FSLSSI_I2S_FORMATS,
897 },
898 .capture = {
Nicolin Chen2924a992013-12-02 23:29:03 +0800899 .channels_min = 1,
Timur Tabi17467f22008-01-11 18:15:26 +0100900 .channels_max = 2,
901 .rates = FSLSSI_I2S_RATES,
902 .formats = FSLSSI_I2S_FORMATS,
903 },
Eric Miao6335d052009-03-03 09:41:00 +0800904 .ops = &fsl_ssi_dai_ops,
Timur Tabi17467f22008-01-11 18:15:26 +0100905};
906
Kuninori Morimoto3580aa12013-03-21 03:32:04 -0700907static const struct snd_soc_component_driver fsl_ssi_component = {
908 .name = "fsl-ssi",
909};
910
Markus Pargmanncd7f0292013-08-19 17:05:58 +0200911static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
912 .ac97_control = 1,
913 .playback = {
914 .stream_name = "AC97 Playback",
915 .channels_min = 2,
916 .channels_max = 2,
917 .rates = SNDRV_PCM_RATE_8000_48000,
918 .formats = SNDRV_PCM_FMTBIT_S16_LE,
919 },
920 .capture = {
921 .stream_name = "AC97 Capture",
922 .channels_min = 2,
923 .channels_max = 2,
924 .rates = SNDRV_PCM_RATE_48000,
925 .formats = SNDRV_PCM_FMTBIT_S16_LE,
926 },
Markus Pargmanna5a7ee72013-12-20 14:11:35 +0100927 .ops = &fsl_ssi_dai_ops,
Markus Pargmanncd7f0292013-08-19 17:05:58 +0200928};
929
930
931static struct fsl_ssi_private *fsl_ac97_data;
932
Sachin Kamata851a2b2013-09-13 15:22:17 +0530933static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
Markus Pargmanncd7f0292013-08-19 17:05:58 +0200934 unsigned short val)
935{
936 struct ccsr_ssi *ssi = fsl_ac97_data->ssi;
937 unsigned int lreg;
938 unsigned int lval;
939
940 if (reg > 0x7f)
941 return;
942
943
944 lreg = reg << 12;
945 write_ssi(lreg, &ssi->sacadd);
946
947 lval = val << 4;
948 write_ssi(lval , &ssi->sacdat);
949
950 write_ssi_mask(&ssi->sacnt, CCSR_SSI_SACNT_RDWR_MASK,
951 CCSR_SSI_SACNT_WR);
952 udelay(100);
953}
954
Sachin Kamata851a2b2013-09-13 15:22:17 +0530955static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
Markus Pargmanncd7f0292013-08-19 17:05:58 +0200956 unsigned short reg)
957{
958 struct ccsr_ssi *ssi = fsl_ac97_data->ssi;
959
960 unsigned short val = -1;
961 unsigned int lreg;
962
963 lreg = (reg & 0x7f) << 12;
964 write_ssi(lreg, &ssi->sacadd);
965 write_ssi_mask(&ssi->sacnt, CCSR_SSI_SACNT_RDWR_MASK,
966 CCSR_SSI_SACNT_RD);
967
968 udelay(100);
969
970 val = (read_ssi(&ssi->sacdat) >> 4) & 0xffff;
971
972 return val;
973}
974
975static struct snd_ac97_bus_ops fsl_ssi_ac97_ops = {
976 .read = fsl_ssi_ac97_read,
977 .write = fsl_ssi_ac97_write,
978};
979
Timur Tabi17467f22008-01-11 18:15:26 +0100980/**
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000981 * Make every character in a string lower-case
Timur Tabi17467f22008-01-11 18:15:26 +0100982 */
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000983static void make_lowercase(char *s)
Timur Tabi17467f22008-01-11 18:15:26 +0100984{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000985 char *p = s;
986 char c;
987
988 while ((c = *p)) {
989 if ((c >= 'A') && (c <= 'Z'))
990 *p = c + ('a' - 'A');
991 p++;
992 }
993}
994
Markus Pargmann49da09e2014-04-28 12:54:45 +0200995static int fsl_ssi_imx_probe(struct platform_device *pdev,
996 struct fsl_ssi_private *ssi_private)
997{
998 struct device_node *np = pdev->dev.of_node;
999 u32 dma_events[2], dmas[4];
1000 bool shared;
1001 int ret;
1002
1003 ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
1004 if (IS_ERR(ssi_private->clk)) {
1005 ret = PTR_ERR(ssi_private->clk);
1006 dev_err(&pdev->dev, "could not get clock: %d\n", ret);
1007 return ret;
1008 }
1009
1010 ret = clk_prepare_enable(ssi_private->clk);
1011 if (ret) {
1012 dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
1013 return ret;
1014 }
1015
1016 /* For those SLAVE implementations, we ingore non-baudclk cases
1017 * and, instead, abandon MASTER mode that needs baud clock.
1018 */
1019 ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
1020 if (IS_ERR(ssi_private->baudclk))
1021 dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
1022 PTR_ERR(ssi_private->baudclk));
1023 else
1024 clk_prepare_enable(ssi_private->baudclk);
1025
1026 /*
1027 * We have burstsize be "fifo_depth - 2" to match the SSI
1028 * watermark setting in fsl_ssi_startup().
1029 */
1030 ssi_private->dma_params_tx.maxburst = ssi_private->fifo_depth - 2;
1031 ssi_private->dma_params_rx.maxburst = ssi_private->fifo_depth - 2;
1032 ssi_private->dma_params_tx.addr = ssi_private->ssi_phys +
1033 offsetof(struct ccsr_ssi, stx0);
1034 ssi_private->dma_params_rx.addr = ssi_private->ssi_phys +
1035 offsetof(struct ccsr_ssi, srx0);
1036 ssi_private->dma_params_tx.filter_data = &ssi_private->filter_data_tx;
1037 ssi_private->dma_params_rx.filter_data = &ssi_private->filter_data_rx;
1038
1039 if (!of_property_read_bool(pdev->dev.of_node, "dmas") &&
1040 ssi_private->use_dma) {
1041 /*
1042 * FIXME: This is a temporary solution until all
1043 * necessary dma drivers support the generic dma
1044 * bindings.
1045 */
1046 ret = of_property_read_u32_array(pdev->dev.of_node,
1047 "fsl,ssi-dma-events", dma_events, 2);
1048 if (ret && ssi_private->use_dma) {
1049 dev_err(&pdev->dev, "could not get dma events but fsl-ssi is configured to use DMA\n");
1050 goto error_dma_events;
1051 }
1052 }
1053 /* Should this be merge with the above? */
1054 if (!of_property_read_u32_array(pdev->dev.of_node, "dmas", dmas, 4)
1055 && dmas[2] == IMX_DMATYPE_SSI_DUAL) {
1056 ssi_private->use_dual_fifo = true;
1057 /* When using dual fifo mode, we need to keep watermark
1058 * as even numbers due to dma script limitation.
1059 */
1060 ssi_private->dma_params_tx.maxburst &= ~0x1;
1061 ssi_private->dma_params_rx.maxburst &= ~0x1;
1062 }
1063
1064 shared = of_device_is_compatible(of_get_parent(np), "fsl,spba-bus");
1065
1066 imx_pcm_dma_params_init_data(&ssi_private->filter_data_tx,
1067 dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
1068 imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
1069 dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
1070
1071 return 0;
1072
1073error_dma_events:
1074 if (!IS_ERR(ssi_private->baudclk))
1075 clk_disable_unprepare(ssi_private->baudclk);
1076 clk_disable_unprepare(ssi_private->clk);
1077
1078 return ret;
1079}
1080
1081static void fsl_ssi_imx_clean(struct platform_device *pdev,
1082 struct fsl_ssi_private *ssi_private)
1083{
1084 if (!IS_ERR(ssi_private->baudclk))
1085 clk_disable_unprepare(ssi_private->baudclk);
1086 clk_disable_unprepare(ssi_private->clk);
1087}
1088
Bill Pembertona0a3d512012-12-07 09:26:16 -05001089static int fsl_ssi_probe(struct platform_device *pdev)
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001090{
Timur Tabi17467f22008-01-11 18:15:26 +01001091 struct fsl_ssi_private *ssi_private;
1092 int ret = 0;
Timur Tabi87a06322010-08-03 17:55:28 -05001093 struct device_attribute *dev_attr = NULL;
Timur Tabi38fec722010-08-19 15:26:58 -05001094 struct device_node *np = pdev->dev.of_node;
Markus Pargmannc1953bf2013-12-20 14:11:30 +01001095 const struct of_device_id *of_id;
1096 enum fsl_ssi_type hw_type;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001097 const char *p, *sprop;
Timur Tabi8e9d8692010-08-06 12:16:12 -05001098 const uint32_t *iprop;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001099 struct resource res;
1100 char name[64];
Markus Pargmanncd7f0292013-08-19 17:05:58 +02001101 bool ac97 = false;
Timur Tabi17467f22008-01-11 18:15:26 +01001102
Timur Tabiff713342010-08-04 17:51:08 -05001103 /* SSIs that are not connected on the board should have a
1104 * status = "disabled"
1105 * property in their device tree nodes.
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001106 */
Timur Tabiff713342010-08-04 17:51:08 -05001107 if (!of_device_is_available(np))
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001108 return -ENODEV;
1109
Markus Pargmannc1953bf2013-12-20 14:11:30 +01001110 of_id = of_match_device(fsl_ssi_ids, &pdev->dev);
1111 if (!of_id)
1112 return -EINVAL;
1113 hw_type = (enum fsl_ssi_type) of_id->data;
1114
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001115 sprop = of_get_property(np, "fsl,mode", NULL);
Markus Pargmanncd7f0292013-08-19 17:05:58 +02001116 if (!sprop) {
1117 dev_err(&pdev->dev, "fsl,mode property is necessary\n");
1118 return -EINVAL;
1119 }
Fabio Estevamae1f8ce2014-01-20 17:35:40 -02001120 if (!strcmp(sprop, "ac97-slave"))
Markus Pargmanncd7f0292013-08-19 17:05:58 +02001121 ac97 = true;
Timur Tabi17467f22008-01-11 18:15:26 +01001122
Markus Pargmann2a1d1022014-04-28 12:54:44 +02001123 ssi_private = devm_kzalloc(&pdev->dev, sizeof(*ssi_private),
1124 GFP_KERNEL);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001125 if (!ssi_private) {
Timur Tabi38fec722010-08-19 15:26:58 -05001126 dev_err(&pdev->dev, "could not allocate DAI object\n");
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001127 return -ENOMEM;
1128 }
Timur Tabi17467f22008-01-11 18:15:26 +01001129
Markus Pargmannde623ec2013-07-27 13:31:53 +02001130 ssi_private->use_dma = !of_property_read_bool(np,
1131 "fsl,fiq-stream-filter");
Markus Pargmann0888efd2013-12-20 14:11:31 +01001132 ssi_private->hw_type = hw_type;
Markus Pargmannde623ec2013-07-27 13:31:53 +02001133
Markus Pargmanncd7f0292013-08-19 17:05:58 +02001134 if (ac97) {
1135 memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_ac97_dai,
1136 sizeof(fsl_ssi_ac97_dai));
1137
1138 fsl_ac97_data = ssi_private;
1139 ssi_private->imx_ac97 = true;
1140
1141 snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
1142 } else {
1143 /* Initialize this copy of the CPU DAI driver structure */
1144 memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
1145 sizeof(fsl_ssi_dai_template));
1146 }
Markus Pargmann2a1d1022014-04-28 12:54:44 +02001147 ssi_private->cpu_dai_drv.name = dev_name(&pdev->dev);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001148
1149 /* Get the addresses and IRQ */
1150 ret = of_address_to_resource(np, 0, &res);
1151 if (ret) {
Timur Tabi38fec722010-08-19 15:26:58 -05001152 dev_err(&pdev->dev, "could not determine device resources\n");
Fabio Estevamb0a47472013-07-17 02:00:38 -03001153 return ret;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001154 }
Timur Tabi147dfe92011-06-08 15:02:55 -05001155 ssi_private->ssi = of_iomap(np, 0);
1156 if (!ssi_private->ssi) {
1157 dev_err(&pdev->dev, "could not map device resources\n");
Fabio Estevamb0a47472013-07-17 02:00:38 -03001158 return -ENOMEM;
Timur Tabi147dfe92011-06-08 15:02:55 -05001159 }
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001160 ssi_private->ssi_phys = res.start;
Timur Tabi1fab6ca2011-08-16 18:47:45 -04001161
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001162 ssi_private->irq = irq_of_parse_and_map(np, 0);
Chen Gangd60336e2013-09-23 11:36:21 +08001163 if (!ssi_private->irq) {
Timur Tabi1fab6ca2011-08-16 18:47:45 -04001164 dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
Fabio Estevamb0a47472013-07-17 02:00:38 -03001165 return -ENXIO;
Timur Tabi1fab6ca2011-08-16 18:47:45 -04001166 }
1167
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001168 /* Are the RX and the TX clocks locked? */
Nicolin Chen07a94832013-12-03 18:38:07 +08001169 if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) {
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001170 ssi_private->cpu_dai_drv.symmetric_rates = 1;
Nicolin Chen07a94832013-12-03 18:38:07 +08001171 ssi_private->cpu_dai_drv.symmetric_channels = 1;
1172 ssi_private->cpu_dai_drv.symmetric_samplebits = 1;
1173 }
Timur Tabi17467f22008-01-11 18:15:26 +01001174
Timur Tabi8e9d8692010-08-06 12:16:12 -05001175 /* Determine the FIFO depth. */
1176 iprop = of_get_property(np, "fsl,fifo-depth", NULL);
1177 if (iprop)
Timur Tabi147dfe92011-06-08 15:02:55 -05001178 ssi_private->fifo_depth = be32_to_cpup(iprop);
Timur Tabi8e9d8692010-08-06 12:16:12 -05001179 else
1180 /* Older 8610 DTs didn't have the fifo-depth property */
1181 ssi_private->fifo_depth = 8;
1182
Nicolin Chenaafa85e2013-12-12 18:44:45 +08001183 ssi_private->baudclk_locked = false;
1184 spin_lock_init(&ssi_private->baudclk_lock);
1185
Markus Pargmannbd3ca7d2013-12-20 14:11:32 +01001186 /*
1187 * imx51 and later SoCs have a slightly different IP that allows the
1188 * SSI configuration while the SSI unit is running.
1189 *
1190 * More important, it is necessary on those SoCs to configure the
1191 * sperate TX/RX DMA bits just before starting the stream
1192 * (fsl_ssi_trigger). The SDMA unit has to be configured before fsl_ssi
1193 * sends any DMA requests to the SDMA unit, otherwise it is not defined
1194 * how the SDMA unit handles the DMA request.
1195 *
1196 * SDMA units are present on devices starting at imx35 but the imx35
1197 * reference manual states that the DMA bits should not be changed
1198 * while the SSI unit is running (SSIEN). So we support the necessary
1199 * online configuration of fsl-ssi starting at imx51.
1200 */
1201 switch (hw_type) {
1202 case FSL_SSI_MCP8610:
1203 case FSL_SSI_MX21:
1204 case FSL_SSI_MX35:
1205 ssi_private->offline_config = true;
1206 break;
1207 case FSL_SSI_MX51:
1208 ssi_private->offline_config = false;
1209 break;
1210 }
1211
Markus Pargmannc1953bf2013-12-20 14:11:30 +01001212 if (hw_type == FSL_SSI_MX21 || hw_type == FSL_SSI_MX51 ||
1213 hw_type == FSL_SSI_MX35) {
Shawn Guo09ce1112012-03-16 16:56:43 +08001214 ssi_private->ssi_on_imx = true;
Shawn Guo95cd98f2012-03-29 10:53:41 +08001215
Markus Pargmann49da09e2014-04-28 12:54:45 +02001216 ret = fsl_ssi_imx_probe(pdev, ssi_private);
1217 if (ret)
Fabio Estevamb0a47472013-07-17 02:00:38 -03001218 goto error_irqmap;
Markus Pargmann0888efd2013-12-20 14:11:31 +01001219 }
1220
1221 /*
1222 * Enable interrupts only for MCP8610 and MX51. The other MXs have
1223 * different writeable interrupt status registers.
1224 */
1225 if (ssi_private->use_dma) {
Michael Grzeschikf0377082013-08-19 17:06:01 +02001226 ret = devm_request_irq(&pdev->dev, ssi_private->irq,
1227 fsl_ssi_isr, 0, ssi_private->name,
1228 ssi_private);
Markus Pargmann2841be92013-12-20 14:11:28 +01001229 ssi_private->irq_stats = true;
Michael Grzeschikf0377082013-08-19 17:06:01 +02001230 if (ret < 0) {
1231 dev_err(&pdev->dev, "could not claim irq %u\n",
1232 ssi_private->irq);
Markus Pargmann49da09e2014-04-28 12:54:45 +02001233 goto error_irq;
Michael Grzeschikf0377082013-08-19 17:06:01 +02001234 }
Shawn Guo09ce1112012-03-16 16:56:43 +08001235 }
1236
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001237 /* Register with ASoC */
Timur Tabi38fec722010-08-19 15:26:58 -05001238 dev_set_drvdata(&pdev->dev, ssi_private);
Mark Brown3f4b7832008-12-03 19:26:35 +00001239
Kuninori Morimoto3580aa12013-03-21 03:32:04 -07001240 ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component,
1241 &ssi_private->cpu_dai_drv, 1);
Timur Tabi87a06322010-08-03 17:55:28 -05001242 if (ret) {
Timur Tabi38fec722010-08-19 15:26:58 -05001243 dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
Timur Tabi1fab6ca2011-08-16 18:47:45 -04001244 goto error_dev;
Mark Brown3f4b7832008-12-03 19:26:35 +00001245 }
Timur Tabi17467f22008-01-11 18:15:26 +01001246
Markus Pargmannf138e622014-04-28 12:54:43 +02001247 ret = fsl_ssi_debugfs_create(&ssi_private->dbg_stats, &pdev->dev);
Markus Pargmann9368acc2013-12-20 14:11:29 +01001248 if (ret)
1249 goto error_dbgfs;
1250
Shawn Guo09ce1112012-03-16 16:56:43 +08001251 if (ssi_private->ssi_on_imx) {
Markus Pargmannde623ec2013-07-27 13:31:53 +02001252 if (!ssi_private->use_dma) {
1253
1254 /*
1255 * Some boards use an incompatible codec. To get it
1256 * working, we are using imx-fiq-pcm-audio, that
1257 * can handle those codecs. DMA is not possible in this
1258 * situation.
1259 */
1260
1261 ssi_private->fiq_params.irq = ssi_private->irq;
1262 ssi_private->fiq_params.base = ssi_private->ssi;
1263 ssi_private->fiq_params.dma_params_rx =
1264 &ssi_private->dma_params_rx;
1265 ssi_private->fiq_params.dma_params_tx =
1266 &ssi_private->dma_params_tx;
1267
1268 ret = imx_pcm_fiq_init(pdev, &ssi_private->fiq_params);
1269 if (ret)
Markus Pargmann2841be92013-12-20 14:11:28 +01001270 goto error_pcm;
Markus Pargmannde623ec2013-07-27 13:31:53 +02001271 } else {
1272 ret = imx_pcm_dma_init(pdev);
1273 if (ret)
Markus Pargmann2841be92013-12-20 14:11:28 +01001274 goto error_pcm;
Markus Pargmannde623ec2013-07-27 13:31:53 +02001275 }
Shawn Guo09ce1112012-03-16 16:56:43 +08001276 }
1277
1278 /*
1279 * If codec-handle property is missing from SSI node, we assume
1280 * that the machine driver uses new binding which does not require
1281 * SSI driver to trigger machine driver's probe.
1282 */
1283 if (!of_get_property(np, "codec-handle", NULL)) {
1284 ssi_private->new_binding = true;
1285 goto done;
1286 }
1287
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001288 /* Trigger the machine driver's probe function. The platform driver
Shawn Guo2b81ec62012-03-09 00:59:46 +08001289 * name of the machine driver is taken from /compatible property of the
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001290 * device tree. We also pass the address of the CPU DAI driver
1291 * structure.
1292 */
Shawn Guo2b81ec62012-03-09 00:59:46 +08001293 sprop = of_get_property(of_find_node_by_path("/"), "compatible", NULL);
1294 /* Sometimes the compatible name has a "fsl," prefix, so we strip it. */
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001295 p = strrchr(sprop, ',');
1296 if (p)
1297 sprop = p + 1;
1298 snprintf(name, sizeof(name), "snd-soc-%s", sprop);
1299 make_lowercase(name);
1300
1301 ssi_private->pdev =
Timur Tabi38fec722010-08-19 15:26:58 -05001302 platform_device_register_data(&pdev->dev, name, 0, NULL, 0);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001303 if (IS_ERR(ssi_private->pdev)) {
1304 ret = PTR_ERR(ssi_private->pdev);
Timur Tabi38fec722010-08-19 15:26:58 -05001305 dev_err(&pdev->dev, "failed to register platform: %d\n", ret);
Timur Tabi1fab6ca2011-08-16 18:47:45 -04001306 goto error_dai;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001307 }
1308
Shawn Guo09ce1112012-03-16 16:56:43 +08001309done:
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001310 return 0;
Timur Tabi87a06322010-08-03 17:55:28 -05001311
Timur Tabi1fab6ca2011-08-16 18:47:45 -04001312error_dai:
Markus Pargmann2841be92013-12-20 14:11:28 +01001313 if (ssi_private->ssi_on_imx && !ssi_private->use_dma)
1314 imx_pcm_fiq_exit(pdev);
1315
1316error_pcm:
Markus Pargmannf138e622014-04-28 12:54:43 +02001317 fsl_ssi_debugfs_remove(&ssi_private->dbg_stats);
Markus Pargmann9368acc2013-12-20 14:11:29 +01001318
1319error_dbgfs:
Kuninori Morimoto3580aa12013-03-21 03:32:04 -07001320 snd_soc_unregister_component(&pdev->dev);
Timur Tabi1fab6ca2011-08-16 18:47:45 -04001321
1322error_dev:
Timur Tabi1fab6ca2011-08-16 18:47:45 -04001323 device_remove_file(&pdev->dev, dev_attr);
1324
Markus Pargmann49da09e2014-04-28 12:54:45 +02001325error_irq:
Nicolin Chenaafa85e2013-12-12 18:44:45 +08001326 if (ssi_private->ssi_on_imx) {
Markus Pargmann49da09e2014-04-28 12:54:45 +02001327 fsl_ssi_imx_clean(pdev, ssi_private);
Nicolin Chenaafa85e2013-12-12 18:44:45 +08001328 }
Timur Tabi1fab6ca2011-08-16 18:47:45 -04001329
1330error_irqmap:
Markus Pargmann2841be92013-12-20 14:11:28 +01001331 if (ssi_private->irq_stats)
1332 irq_dispose_mapping(ssi_private->irq);
Timur Tabi1fab6ca2011-08-16 18:47:45 -04001333
Timur Tabi87a06322010-08-03 17:55:28 -05001334 return ret;
Timur Tabi17467f22008-01-11 18:15:26 +01001335}
Timur Tabi17467f22008-01-11 18:15:26 +01001336
Timur Tabi38fec722010-08-19 15:26:58 -05001337static int fsl_ssi_remove(struct platform_device *pdev)
Timur Tabi17467f22008-01-11 18:15:26 +01001338{
Timur Tabi38fec722010-08-19 15:26:58 -05001339 struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
Timur Tabi17467f22008-01-11 18:15:26 +01001340
Markus Pargmannf138e622014-04-28 12:54:43 +02001341 fsl_ssi_debugfs_remove(&ssi_private->dbg_stats);
Markus Pargmann9368acc2013-12-20 14:11:29 +01001342
Shawn Guo09ce1112012-03-16 16:56:43 +08001343 if (!ssi_private->new_binding)
1344 platform_device_unregister(ssi_private->pdev);
Kuninori Morimoto3580aa12013-03-21 03:32:04 -07001345 snd_soc_unregister_component(&pdev->dev);
Markus Pargmann49da09e2014-04-28 12:54:45 +02001346
1347 if (ssi_private->ssi_on_imx)
1348 fsl_ssi_imx_clean(pdev, ssi_private);
1349
Markus Pargmann2841be92013-12-20 14:11:28 +01001350 if (ssi_private->irq_stats)
1351 irq_dispose_mapping(ssi_private->irq);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001352
1353 return 0;
Timur Tabi17467f22008-01-11 18:15:26 +01001354}
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001355
Grant Likelyf07eb222011-02-22 21:05:04 -07001356static struct platform_driver fsl_ssi_driver = {
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001357 .driver = {
1358 .name = "fsl-ssi-dai",
1359 .owner = THIS_MODULE,
1360 .of_match_table = fsl_ssi_ids,
1361 },
1362 .probe = fsl_ssi_probe,
1363 .remove = fsl_ssi_remove,
1364};
Timur Tabi17467f22008-01-11 18:15:26 +01001365
Axel Linba0a7e02011-11-25 10:10:55 +08001366module_platform_driver(fsl_ssi_driver);
Timur Tabia454dad2009-03-05 17:23:37 -06001367
Fabio Estevamf3142802013-07-20 16:16:01 -03001368MODULE_ALIAS("platform:fsl-ssi-dai");
Timur Tabi17467f22008-01-11 18:15:26 +01001369MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
1370MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001371MODULE_LICENSE("GPL v2");