xref: /openbmc/linux/sound/soc/sh/ssi.c (revision 8fccf469)
1aef3b06aSManuel Lauss /*
2aef3b06aSManuel Lauss  * Serial Sound Interface (I2S) support for SH7760/SH7780
3aef3b06aSManuel Lauss  *
4aef3b06aSManuel Lauss  * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
5aef3b06aSManuel Lauss  *
6aef3b06aSManuel Lauss  *  licensed under the terms outlined in the file COPYING at the root
7aef3b06aSManuel Lauss  *  of the linux kernel sources.
8aef3b06aSManuel Lauss  *
9aef3b06aSManuel Lauss  * dont forget to set IPSEL/OMSEL register bits (in your board code) to
10aef3b06aSManuel Lauss  * enable SSI output pins!
11aef3b06aSManuel Lauss  */
12aef3b06aSManuel Lauss 
13aef3b06aSManuel Lauss /*
14aef3b06aSManuel Lauss  * LIMITATIONS:
15aef3b06aSManuel Lauss  *	The SSI unit has only one physical data line, so full duplex is
16aef3b06aSManuel Lauss  *	impossible.  This can be remedied  on the  SH7760 by  using the
17aef3b06aSManuel Lauss  *	other SSI unit for recording; however the SH7780 has only 1 SSI
18aef3b06aSManuel Lauss  *	unit, and its pins are shared with the AC97 unit,  among others.
19aef3b06aSManuel Lauss  *
20aef3b06aSManuel Lauss  * FEATURES:
21aef3b06aSManuel Lauss  *	The SSI features "compressed mode": in this mode it continuously
22aef3b06aSManuel Lauss  *	streams PCM data over the I2S lines and uses LRCK as a handshake
23aef3b06aSManuel Lauss  *	signal.  Can be used to send compressed data (AC3/DTS) to a DSP.
24aef3b06aSManuel Lauss  *	The number of bits sent over the wire in a frame can be adjusted
25aef3b06aSManuel Lauss  *	and can be independent from the actual sample bit depth. This is
26aef3b06aSManuel Lauss  *	useful to support TDM mode codecs like the AD1939 which have a
27aef3b06aSManuel Lauss  *	fixed TDM slot size, regardless of sample resolution.
28aef3b06aSManuel Lauss  */
29aef3b06aSManuel Lauss 
30aef3b06aSManuel Lauss #include <linux/init.h>
31aef3b06aSManuel Lauss #include <linux/module.h>
32aef3b06aSManuel Lauss #include <linux/platform_device.h>
33aef3b06aSManuel Lauss #include <sound/core.h>
34aef3b06aSManuel Lauss #include <sound/pcm.h>
35aef3b06aSManuel Lauss #include <sound/initval.h>
36aef3b06aSManuel Lauss #include <sound/soc.h>
37aef3b06aSManuel Lauss #include <asm/io.h>
38aef3b06aSManuel Lauss 
39aef3b06aSManuel Lauss #define SSICR	0x00
40aef3b06aSManuel Lauss #define SSISR	0x04
41aef3b06aSManuel Lauss 
42aef3b06aSManuel Lauss #define CR_DMAEN	(1 << 28)
43aef3b06aSManuel Lauss #define CR_CHNL_SHIFT	22
44aef3b06aSManuel Lauss #define CR_CHNL_MASK	(3 << CR_CHNL_SHIFT)
45aef3b06aSManuel Lauss #define CR_DWL_SHIFT	19
46aef3b06aSManuel Lauss #define CR_DWL_MASK	(7 << CR_DWL_SHIFT)
47aef3b06aSManuel Lauss #define CR_SWL_SHIFT	16
48aef3b06aSManuel Lauss #define CR_SWL_MASK	(7 << CR_SWL_SHIFT)
49aef3b06aSManuel Lauss #define CR_SCK_MASTER	(1 << 15)	/* bitclock master bit */
50aef3b06aSManuel Lauss #define CR_SWS_MASTER	(1 << 14)	/* wordselect master bit */
51aef3b06aSManuel Lauss #define CR_SCKP		(1 << 13)	/* I2Sclock polarity */
52aef3b06aSManuel Lauss #define CR_SWSP		(1 << 12)	/* LRCK polarity */
53aef3b06aSManuel Lauss #define CR_SPDP		(1 << 11)
54aef3b06aSManuel Lauss #define CR_SDTA		(1 << 10)	/* i2s alignment (msb/lsb) */
55aef3b06aSManuel Lauss #define CR_PDTA		(1 << 9)	/* fifo data alignment */
56aef3b06aSManuel Lauss #define CR_DEL		(1 << 8)	/* delay data by 1 i2sclk */
57aef3b06aSManuel Lauss #define CR_BREN		(1 << 7)	/* clock gating in burst mode */
58aef3b06aSManuel Lauss #define CR_CKDIV_SHIFT	4
59aef3b06aSManuel Lauss #define CR_CKDIV_MASK	(7 << CR_CKDIV_SHIFT)	/* bitclock divider */
60aef3b06aSManuel Lauss #define CR_MUTE		(1 << 3)	/* SSI mute */
61aef3b06aSManuel Lauss #define CR_CPEN		(1 << 2)	/* compressed mode */
62aef3b06aSManuel Lauss #define CR_TRMD		(1 << 1)	/* transmit/receive select */
63aef3b06aSManuel Lauss #define CR_EN		(1 << 0)	/* enable SSI */
64aef3b06aSManuel Lauss 
65aef3b06aSManuel Lauss #define SSIREG(reg)	(*(unsigned long *)(ssi->mmio + (reg)))
66aef3b06aSManuel Lauss 
67aef3b06aSManuel Lauss struct ssi_priv {
68aef3b06aSManuel Lauss 	unsigned long mmio;
69aef3b06aSManuel Lauss 	unsigned long sysclk;
70aef3b06aSManuel Lauss 	int inuse;
71aef3b06aSManuel Lauss } ssi_cpu_data[] = {
72aef3b06aSManuel Lauss #if defined(CONFIG_CPU_SUBTYPE_SH7760)
73aef3b06aSManuel Lauss 	{
74aef3b06aSManuel Lauss 		.mmio	= 0xFE680000,
75aef3b06aSManuel Lauss 	},
76aef3b06aSManuel Lauss 	{
77aef3b06aSManuel Lauss 		.mmio	= 0xFE690000,
78aef3b06aSManuel Lauss 	},
79aef3b06aSManuel Lauss #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
80aef3b06aSManuel Lauss 	{
81aef3b06aSManuel Lauss 		.mmio	= 0xFFE70000,
82aef3b06aSManuel Lauss 	},
83aef3b06aSManuel Lauss #else
84aef3b06aSManuel Lauss #error "Unsupported SuperH SoC"
85aef3b06aSManuel Lauss #endif
86aef3b06aSManuel Lauss };
87aef3b06aSManuel Lauss 
88aef3b06aSManuel Lauss /*
89aef3b06aSManuel Lauss  * track usage of the SSI; it is simplex-only so prevent attempts of
90aef3b06aSManuel Lauss  * concurrent playback + capture. FIXME: any locking required?
91aef3b06aSManuel Lauss  */
92dee89c4dSMark Brown static int ssi_startup(struct snd_pcm_substream *substream,
93dee89c4dSMark Brown 		       struct snd_soc_dai *dai)
94aef3b06aSManuel Lauss {
95f0fba2adSLiam Girdwood 	struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
96aef3b06aSManuel Lauss 	if (ssi->inuse) {
97aef3b06aSManuel Lauss 		pr_debug("ssi: already in use!\n");
98aef3b06aSManuel Lauss 		return -EBUSY;
99aef3b06aSManuel Lauss 	} else
100aef3b06aSManuel Lauss 		ssi->inuse = 1;
101aef3b06aSManuel Lauss 	return 0;
102aef3b06aSManuel Lauss }
103aef3b06aSManuel Lauss 
104dee89c4dSMark Brown static void ssi_shutdown(struct snd_pcm_substream *substream,
105dee89c4dSMark Brown 			 struct snd_soc_dai *dai)
106aef3b06aSManuel Lauss {
107f0fba2adSLiam Girdwood 	struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
108aef3b06aSManuel Lauss 
109aef3b06aSManuel Lauss 	ssi->inuse = 0;
110aef3b06aSManuel Lauss }
111aef3b06aSManuel Lauss 
112dee89c4dSMark Brown static int ssi_trigger(struct snd_pcm_substream *substream, int cmd,
113dee89c4dSMark Brown 		       struct snd_soc_dai *dai)
114aef3b06aSManuel Lauss {
115f0fba2adSLiam Girdwood 	struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
116aef3b06aSManuel Lauss 
117aef3b06aSManuel Lauss 	switch (cmd) {
118aef3b06aSManuel Lauss 	case SNDRV_PCM_TRIGGER_START:
119aef3b06aSManuel Lauss 		SSIREG(SSICR) |= CR_DMAEN | CR_EN;
120aef3b06aSManuel Lauss 		break;
121aef3b06aSManuel Lauss 	case SNDRV_PCM_TRIGGER_STOP:
122aef3b06aSManuel Lauss 		SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN);
123aef3b06aSManuel Lauss 		break;
124aef3b06aSManuel Lauss 	default:
125aef3b06aSManuel Lauss 		return -EINVAL;
126aef3b06aSManuel Lauss 	}
127aef3b06aSManuel Lauss 
128aef3b06aSManuel Lauss 	return 0;
129aef3b06aSManuel Lauss }
130aef3b06aSManuel Lauss 
131aef3b06aSManuel Lauss static int ssi_hw_params(struct snd_pcm_substream *substream,
132dee89c4dSMark Brown 			 struct snd_pcm_hw_params *params,
133dee89c4dSMark Brown 			 struct snd_soc_dai *dai)
134aef3b06aSManuel Lauss {
135f0fba2adSLiam Girdwood 	struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
136aef3b06aSManuel Lauss 	unsigned long ssicr = SSIREG(SSICR);
137aef3b06aSManuel Lauss 	unsigned int bits, channels, swl, recv, i;
138aef3b06aSManuel Lauss 
139aef3b06aSManuel Lauss 	channels = params_channels(params);
140aef3b06aSManuel Lauss 	bits = params->msbits;
141aef3b06aSManuel Lauss 	recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
142aef3b06aSManuel Lauss 
143aef3b06aSManuel Lauss 	pr_debug("ssi_hw_params() enter\nssicr was    %08lx\n", ssicr);
144449bd54dSRoel Kluin 	pr_debug("bits: %u channels: %u\n", bits, channels);
145aef3b06aSManuel Lauss 
146aef3b06aSManuel Lauss 	ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA |
147aef3b06aSManuel Lauss 		   CR_SWL_MASK);
148aef3b06aSManuel Lauss 
149aef3b06aSManuel Lauss 	/* direction (send/receive) */
150aef3b06aSManuel Lauss 	if (!recv)
151aef3b06aSManuel Lauss 		ssicr |= CR_TRMD;	/* transmit */
152aef3b06aSManuel Lauss 
153aef3b06aSManuel Lauss 	/* channels */
154aef3b06aSManuel Lauss 	if ((channels < 2) || (channels > 8) || (channels & 1)) {
155aef3b06aSManuel Lauss 		pr_debug("ssi: invalid number of channels\n");
156aef3b06aSManuel Lauss 		return -EINVAL;
157aef3b06aSManuel Lauss 	}
158aef3b06aSManuel Lauss 	ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT;
159aef3b06aSManuel Lauss 
160aef3b06aSManuel Lauss 	/* DATA WORD LENGTH (DWL): databits in audio sample */
161aef3b06aSManuel Lauss 	i = 0;
162aef3b06aSManuel Lauss 	switch (bits) {
163aef3b06aSManuel Lauss 	case 32: ++i;
164aef3b06aSManuel Lauss 	case 24: ++i;
165aef3b06aSManuel Lauss 	case 22: ++i;
166aef3b06aSManuel Lauss 	case 20: ++i;
167aef3b06aSManuel Lauss 	case 18: ++i;
168aef3b06aSManuel Lauss 	case 16: ++i;
169aef3b06aSManuel Lauss 		 ssicr |= i << CR_DWL_SHIFT;
170aef3b06aSManuel Lauss 	case 8:	 break;
171aef3b06aSManuel Lauss 	default:
172aef3b06aSManuel Lauss 		pr_debug("ssi: invalid sample width\n");
173aef3b06aSManuel Lauss 		return -EINVAL;
174aef3b06aSManuel Lauss 	}
175aef3b06aSManuel Lauss 
176aef3b06aSManuel Lauss 	/*
177aef3b06aSManuel Lauss 	 * SYSTEM WORD LENGTH: size in bits of half a frame over the I2S
178aef3b06aSManuel Lauss 	 * wires. This is usually bits_per_sample x channels/2;  i.e. in
179aef3b06aSManuel Lauss 	 * Stereo mode  the SWL equals DWL.  SWL can  be bigger than the
180aef3b06aSManuel Lauss 	 * product of (channels_per_slot x samplebits), e.g.  for codecs
181aef3b06aSManuel Lauss 	 * like the AD1939 which  only accept 32bit wide TDM slots.  For
182aef3b06aSManuel Lauss 	 * "standard" I2S operation we set SWL = chans / 2 * DWL here.
183aef3b06aSManuel Lauss 	 * Waiting for ASoC to get TDM support ;-)
184aef3b06aSManuel Lauss 	 */
185aef3b06aSManuel Lauss 	if ((bits > 16) && (bits <= 24)) {
186aef3b06aSManuel Lauss 		bits = 24;	/* these are padded by the SSI */
187aef3b06aSManuel Lauss 		/*ssicr |= CR_PDTA;*/ /* cpu/data endianness ? */
188aef3b06aSManuel Lauss 	}
189aef3b06aSManuel Lauss 	i = 0;
190aef3b06aSManuel Lauss 	swl = (bits * channels) / 2;
191aef3b06aSManuel Lauss 	switch (swl) {
192aef3b06aSManuel Lauss 	case 256: ++i;
193aef3b06aSManuel Lauss 	case 128: ++i;
194aef3b06aSManuel Lauss 	case 64:  ++i;
195aef3b06aSManuel Lauss 	case 48:  ++i;
196aef3b06aSManuel Lauss 	case 32:  ++i;
197aef3b06aSManuel Lauss 	case 16:  ++i;
198aef3b06aSManuel Lauss 		  ssicr |= i << CR_SWL_SHIFT;
199aef3b06aSManuel Lauss 	case 8:   break;
200aef3b06aSManuel Lauss 	default:
201aef3b06aSManuel Lauss 		pr_debug("ssi: invalid system word length computed\n");
202aef3b06aSManuel Lauss 		return -EINVAL;
203aef3b06aSManuel Lauss 	}
204aef3b06aSManuel Lauss 
205aef3b06aSManuel Lauss 	SSIREG(SSICR) = ssicr;
206aef3b06aSManuel Lauss 
207aef3b06aSManuel Lauss 	pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr);
208aef3b06aSManuel Lauss 	return 0;
209aef3b06aSManuel Lauss }
210aef3b06aSManuel Lauss 
21153640650SLiam Girdwood static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
212aef3b06aSManuel Lauss 			  unsigned int freq, int dir)
213aef3b06aSManuel Lauss {
214aef3b06aSManuel Lauss 	struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id];
215aef3b06aSManuel Lauss 
216aef3b06aSManuel Lauss 	ssi->sysclk = freq;
217aef3b06aSManuel Lauss 
218aef3b06aSManuel Lauss 	return 0;
219aef3b06aSManuel Lauss }
220aef3b06aSManuel Lauss 
221aef3b06aSManuel Lauss /*
222aef3b06aSManuel Lauss  * This divider is used to generate the SSI_SCK (I2S bitclock) from the
223aef3b06aSManuel Lauss  * clock at the HAC_BIT_CLK ("oversampling clock") pin.
224aef3b06aSManuel Lauss  */
22553640650SLiam Girdwood static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div)
226aef3b06aSManuel Lauss {
227aef3b06aSManuel Lauss 	struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
228aef3b06aSManuel Lauss 	unsigned long ssicr;
229aef3b06aSManuel Lauss 	int i;
230aef3b06aSManuel Lauss 
231aef3b06aSManuel Lauss 	i = 0;
232aef3b06aSManuel Lauss 	ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK;
233aef3b06aSManuel Lauss 	switch (div) {
234aef3b06aSManuel Lauss 	case 16: ++i;
235aef3b06aSManuel Lauss 	case 8:  ++i;
236aef3b06aSManuel Lauss 	case 4:  ++i;
237aef3b06aSManuel Lauss 	case 2:  ++i;
238aef3b06aSManuel Lauss 		 SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT);
239aef3b06aSManuel Lauss 	case 1:  break;
240aef3b06aSManuel Lauss 	default:
241aef3b06aSManuel Lauss 		pr_debug("ssi: invalid sck divider %d\n", div);
242aef3b06aSManuel Lauss 		return -EINVAL;
243aef3b06aSManuel Lauss 	}
244aef3b06aSManuel Lauss 
245aef3b06aSManuel Lauss 	return 0;
246aef3b06aSManuel Lauss }
247aef3b06aSManuel Lauss 
24853640650SLiam Girdwood static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
249aef3b06aSManuel Lauss {
250aef3b06aSManuel Lauss 	struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
251aef3b06aSManuel Lauss 	unsigned long ssicr = SSIREG(SSICR);
252aef3b06aSManuel Lauss 
253aef3b06aSManuel Lauss 	pr_debug("ssi_set_fmt()\nssicr was    0x%08lx\n", ssicr);
254aef3b06aSManuel Lauss 
255aef3b06aSManuel Lauss 	ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP |
256aef3b06aSManuel Lauss 		   CR_SWS_MASTER | CR_SCK_MASTER);
257aef3b06aSManuel Lauss 
258aef3b06aSManuel Lauss 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
259aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_I2S:
260aef3b06aSManuel Lauss 		break;
261aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_RIGHT_J:
262aef3b06aSManuel Lauss 		ssicr |= CR_DEL | CR_PDTA;
263aef3b06aSManuel Lauss 		break;
264aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_LEFT_J:
265aef3b06aSManuel Lauss 		ssicr |= CR_DEL;
266aef3b06aSManuel Lauss 		break;
267aef3b06aSManuel Lauss 	default:
268aef3b06aSManuel Lauss 		pr_debug("ssi: unsupported format\n");
269aef3b06aSManuel Lauss 		return -EINVAL;
270aef3b06aSManuel Lauss 	}
271aef3b06aSManuel Lauss 
272aef3b06aSManuel Lauss 	switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
273aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_CONT:
274aef3b06aSManuel Lauss 		break;
275aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_GATED:
276aef3b06aSManuel Lauss 		ssicr |= CR_BREN;
277aef3b06aSManuel Lauss 		break;
278aef3b06aSManuel Lauss 	}
279aef3b06aSManuel Lauss 
280aef3b06aSManuel Lauss 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
281aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_NB_NF:
282aef3b06aSManuel Lauss 		ssicr |= CR_SCKP;	/* sample data at low clkedge */
283aef3b06aSManuel Lauss 		break;
284aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_NB_IF:
285aef3b06aSManuel Lauss 		ssicr |= CR_SCKP | CR_SWSP;
286aef3b06aSManuel Lauss 		break;
287aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_IB_NF:
288aef3b06aSManuel Lauss 		break;
289aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_IB_IF:
290aef3b06aSManuel Lauss 		ssicr |= CR_SWSP;	/* word select starts low */
291aef3b06aSManuel Lauss 		break;
292aef3b06aSManuel Lauss 	default:
293aef3b06aSManuel Lauss 		pr_debug("ssi: invalid inversion\n");
294aef3b06aSManuel Lauss 		return -EINVAL;
295aef3b06aSManuel Lauss 	}
296aef3b06aSManuel Lauss 
297aef3b06aSManuel Lauss 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
298aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_CBM_CFM:
299aef3b06aSManuel Lauss 		break;
300aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_CBS_CFM:
301aef3b06aSManuel Lauss 		ssicr |= CR_SCK_MASTER;
302aef3b06aSManuel Lauss 		break;
303aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_CBM_CFS:
304aef3b06aSManuel Lauss 		ssicr |= CR_SWS_MASTER;
305aef3b06aSManuel Lauss 		break;
306aef3b06aSManuel Lauss 	case SND_SOC_DAIFMT_CBS_CFS:
307aef3b06aSManuel Lauss 		ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
308aef3b06aSManuel Lauss 		break;
309aef3b06aSManuel Lauss 	default:
310aef3b06aSManuel Lauss 		pr_debug("ssi: invalid master/slave configuration\n");
311aef3b06aSManuel Lauss 		return -EINVAL;
312aef3b06aSManuel Lauss 	}
313aef3b06aSManuel Lauss 
314aef3b06aSManuel Lauss 	SSIREG(SSICR) = ssicr;
315aef3b06aSManuel Lauss 	pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr);
316aef3b06aSManuel Lauss 
317aef3b06aSManuel Lauss 	return 0;
318aef3b06aSManuel Lauss }
319aef3b06aSManuel Lauss 
320aef3b06aSManuel Lauss /* the SSI depends on an external clocksource (at HAC_BIT_CLK) even in
321aef3b06aSManuel Lauss  * Master mode,  so really this is board specific;  the SSI can do any
322aef3b06aSManuel Lauss  * rate with the right bitclk and divider settings.
323aef3b06aSManuel Lauss  */
324aef3b06aSManuel Lauss #define SSI_RATES	\
325aef3b06aSManuel Lauss 	SNDRV_PCM_RATE_8000_192000
326aef3b06aSManuel Lauss 
327aef3b06aSManuel Lauss /* the SSI can do 8-32 bit samples, with 8 possible channels */
328aef3b06aSManuel Lauss #define SSI_FMTS	\
329aef3b06aSManuel Lauss 	(SNDRV_PCM_FMTBIT_S8      | SNDRV_PCM_FMTBIT_U8      |	\
330aef3b06aSManuel Lauss 	 SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_U16_LE  |	\
331aef3b06aSManuel Lauss 	 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE |	\
332aef3b06aSManuel Lauss 	 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |	\
333aef3b06aSManuel Lauss 	 SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
334aef3b06aSManuel Lauss 
3356335d055SEric Miao static struct snd_soc_dai_ops ssi_dai_ops = {
3366335d055SEric Miao 	.startup	= ssi_startup,
3376335d055SEric Miao 	.shutdown	= ssi_shutdown,
3386335d055SEric Miao 	.trigger	= ssi_trigger,
3396335d055SEric Miao 	.hw_params	= ssi_hw_params,
3406335d055SEric Miao 	.set_sysclk	= ssi_set_sysclk,
3416335d055SEric Miao 	.set_clkdiv	= ssi_set_clkdiv,
3426335d055SEric Miao 	.set_fmt	= ssi_set_fmt,
3436335d055SEric Miao };
3446335d055SEric Miao 
3458fccf469SAxel Lin static struct snd_soc_dai_driver sh4_ssi_dai[] = {
346aef3b06aSManuel Lauss {
347f0fba2adSLiam Girdwood 	.name			= "ssi-dai.0",
348aef3b06aSManuel Lauss 	.playback = {
349aef3b06aSManuel Lauss 		.rates		= SSI_RATES,
350aef3b06aSManuel Lauss 		.formats	= SSI_FMTS,
351aef3b06aSManuel Lauss 		.channels_min	= 2,
352aef3b06aSManuel Lauss 		.channels_max	= 8,
353aef3b06aSManuel Lauss 	},
354aef3b06aSManuel Lauss 	.capture = {
355aef3b06aSManuel Lauss 		.rates		= SSI_RATES,
356aef3b06aSManuel Lauss 		.formats	= SSI_FMTS,
357aef3b06aSManuel Lauss 		.channels_min	= 2,
358aef3b06aSManuel Lauss 		.channels_max	= 8,
359aef3b06aSManuel Lauss 	},
3606335d055SEric Miao 	.ops = &ssi_dai_ops,
361aef3b06aSManuel Lauss },
362aef3b06aSManuel Lauss #ifdef CONFIG_CPU_SUBTYPE_SH7760
363aef3b06aSManuel Lauss {
364f0fba2adSLiam Girdwood 	.name			= "ssi-dai.1",
365aef3b06aSManuel Lauss 	.playback = {
366aef3b06aSManuel Lauss 		.rates		= SSI_RATES,
367aef3b06aSManuel Lauss 		.formats	= SSI_FMTS,
368aef3b06aSManuel Lauss 		.channels_min	= 2,
369aef3b06aSManuel Lauss 		.channels_max	= 8,
370aef3b06aSManuel Lauss 	},
371aef3b06aSManuel Lauss 	.capture = {
372aef3b06aSManuel Lauss 		.rates		= SSI_RATES,
373aef3b06aSManuel Lauss 		.formats	= SSI_FMTS,
374aef3b06aSManuel Lauss 		.channels_min	= 2,
375aef3b06aSManuel Lauss 		.channels_max	= 8,
376aef3b06aSManuel Lauss 	},
3776335d055SEric Miao 	.ops = &ssi_dai_ops,
378aef3b06aSManuel Lauss },
379aef3b06aSManuel Lauss #endif
380aef3b06aSManuel Lauss };
381aef3b06aSManuel Lauss 
382f0fba2adSLiam Girdwood static int __devinit sh4_soc_dai_probe(struct platform_device *pdev)
3833f4b783cSMark Brown {
384f0fba2adSLiam Girdwood 	return snd_soc_register_dais(&pdev->dev, sh4_ssi_dai,
385f0fba2adSLiam Girdwood 			ARRAY_SIZE(sh4_ssi_dai));
3863f4b783cSMark Brown }
3873f4b783cSMark Brown 
388f0fba2adSLiam Girdwood static int __devexit sh4_soc_dai_remove(struct platform_device *pdev)
3893f4b783cSMark Brown {
3903b6bc354SAxel Lin 	snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai));
391f0fba2adSLiam Girdwood 	return 0;
3923f4b783cSMark Brown }
393f0fba2adSLiam Girdwood 
394f0fba2adSLiam Girdwood static struct platform_driver sh4_ssi_driver = {
395f0fba2adSLiam Girdwood 	.driver = {
396f0fba2adSLiam Girdwood 			.name = "sh4-ssi-dai",
397f0fba2adSLiam Girdwood 			.owner = THIS_MODULE,
398f0fba2adSLiam Girdwood 	},
399f0fba2adSLiam Girdwood 
400f0fba2adSLiam Girdwood 	.probe = sh4_soc_dai_probe,
401f0fba2adSLiam Girdwood 	.remove = __devexit_p(sh4_soc_dai_remove),
402f0fba2adSLiam Girdwood };
403f0fba2adSLiam Girdwood 
404f0fba2adSLiam Girdwood static int __init snd_sh4_ssi_init(void)
405f0fba2adSLiam Girdwood {
406f0fba2adSLiam Girdwood 	return platform_driver_register(&sh4_ssi_driver);
407f0fba2adSLiam Girdwood }
408f0fba2adSLiam Girdwood module_init(snd_sh4_ssi_init);
409f0fba2adSLiam Girdwood 
410f0fba2adSLiam Girdwood static void __exit snd_sh4_ssi_exit(void)
411f0fba2adSLiam Girdwood {
412f0fba2adSLiam Girdwood 	platform_driver_unregister(&sh4_ssi_driver);
413f0fba2adSLiam Girdwood }
414f0fba2adSLiam Girdwood module_exit(snd_sh4_ssi_exit);
4153f4b783cSMark Brown 
416aef3b06aSManuel Lauss MODULE_LICENSE("GPL");
417aef3b06aSManuel Lauss MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
418aef3b06aSManuel Lauss MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
419