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