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