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