Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/renesas/hac.c
26428 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// Hitachi Audio Controller (AC97) support for SH7760/SH7780
4
//
5
// Copyright (c) 2007 Manuel Lauss <[email protected]>
6
//
7
// dont forget to set IPSEL/OMSEL register bits (in your board code) to
8
// enable HAC output pins!
9
10
/* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only
11
* the FIRST can be used since ASoC does not pass any information to the
12
* ac97_read/write() functions regarding WHICH unit to use. You'll have
13
* to edit the code a bit to use the other AC97 unit. --mlau
14
*/
15
16
#include <linux/init.h>
17
#include <linux/module.h>
18
#include <linux/platform_device.h>
19
#include <linux/interrupt.h>
20
#include <linux/wait.h>
21
#include <linux/delay.h>
22
#include <sound/core.h>
23
#include <sound/pcm.h>
24
#include <sound/ac97_codec.h>
25
#include <sound/initval.h>
26
#include <sound/soc.h>
27
28
/* regs and bits */
29
#define HACCR 0x08
30
#define HACCSAR 0x20
31
#define HACCSDR 0x24
32
#define HACPCML 0x28
33
#define HACPCMR 0x2C
34
#define HACTIER 0x50
35
#define HACTSR 0x54
36
#define HACRIER 0x58
37
#define HACRSR 0x5C
38
#define HACACR 0x60
39
40
#define CR_CR (1 << 15) /* "codec-ready" indicator */
41
#define CR_CDRT (1 << 11) /* cold reset */
42
#define CR_WMRT (1 << 10) /* warm reset */
43
#define CR_B9 (1 << 9) /* the mysterious "bit 9" */
44
#define CR_ST (1 << 5) /* AC97 link start bit */
45
46
#define CSAR_RD (1 << 19) /* AC97 data read bit */
47
#define CSAR_WR (0)
48
49
#define TSR_CMDAMT (1 << 31)
50
#define TSR_CMDDMT (1 << 30)
51
52
#define RSR_STARY (1 << 22)
53
#define RSR_STDRY (1 << 21)
54
55
#define ACR_DMARX16 (1 << 30)
56
#define ACR_DMATX16 (1 << 29)
57
#define ACR_TX12ATOM (1 << 26)
58
#define ACR_DMARX20 ((1 << 24) | (1 << 22))
59
#define ACR_DMATX20 ((1 << 23) | (1 << 21))
60
61
#define CSDR_SHIFT 4
62
#define CSDR_MASK (0xffff << CSDR_SHIFT)
63
#define CSAR_SHIFT 12
64
#define CSAR_MASK (0x7f << CSAR_SHIFT)
65
66
#define AC97_WRITE_RETRY 1
67
#define AC97_READ_RETRY 5
68
69
/* manual-suggested AC97 codec access timeouts (us) */
70
#define TMO_E1 500 /* 21 < E1 < 1000 */
71
#define TMO_E2 13 /* 13 < E2 */
72
#define TMO_E3 21 /* 21 < E3 */
73
#define TMO_E4 500 /* 21 < E4 < 1000 */
74
75
struct hac_priv {
76
unsigned long mmio; /* HAC base address */
77
} hac_cpu_data[] = {
78
#if defined(CONFIG_CPU_SUBTYPE_SH7760)
79
{
80
.mmio = 0xFE240000,
81
},
82
{
83
.mmio = 0xFE250000,
84
},
85
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
86
{
87
.mmio = 0xFFE40000,
88
},
89
#else
90
#error "Unsupported SuperH SoC"
91
#endif
92
};
93
94
#define HACREG(reg) (*(unsigned long *)(hac->mmio + (reg)))
95
96
/*
97
* AC97 read/write flow as outlined in the SH7760 manual (pages 903-906)
98
*/
99
static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
100
unsigned short *v)
101
{
102
unsigned int to1, to2, i;
103
unsigned short adr;
104
105
for (i = AC97_READ_RETRY; i; i--) {
106
*v = 0;
107
/* wait for HAC to receive something from the codec */
108
for (to1 = TMO_E4;
109
to1 && !(HACREG(HACRSR) & RSR_STARY);
110
--to1)
111
udelay(1);
112
for (to2 = TMO_E4;
113
to2 && !(HACREG(HACRSR) & RSR_STDRY);
114
--to2)
115
udelay(1);
116
117
if (!to1 && !to2)
118
return 0; /* codec comm is down */
119
120
adr = ((HACREG(HACCSAR) & CSAR_MASK) >> CSAR_SHIFT);
121
*v = ((HACREG(HACCSDR) & CSDR_MASK) >> CSDR_SHIFT);
122
123
HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
124
125
if (r == adr)
126
break;
127
128
/* manual says: wait at least 21 usec before retrying */
129
udelay(21);
130
}
131
HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
132
return i;
133
}
134
135
static unsigned short hac_read_codec_aux(struct hac_priv *hac,
136
unsigned short reg)
137
{
138
unsigned short val;
139
unsigned int i, to;
140
141
for (i = AC97_READ_RETRY; i; i--) {
142
/* send_read_request */
143
local_irq_disable();
144
HACREG(HACTSR) &= ~(TSR_CMDAMT);
145
HACREG(HACCSAR) = (reg << CSAR_SHIFT) | CSAR_RD;
146
local_irq_enable();
147
148
for (to = TMO_E3;
149
to && !(HACREG(HACTSR) & TSR_CMDAMT);
150
--to)
151
udelay(1);
152
153
HACREG(HACTSR) &= ~TSR_CMDAMT;
154
val = 0;
155
if (hac_get_codec_data(hac, reg, &val) != 0)
156
break;
157
}
158
159
return i ? val : ~0;
160
}
161
162
static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
163
unsigned short val)
164
{
165
int unit_id = 0 /* ac97->private_data */;
166
struct hac_priv *hac = &hac_cpu_data[unit_id];
167
unsigned int i, to;
168
/* write_codec_aux */
169
for (i = AC97_WRITE_RETRY; i; i--) {
170
/* send_write_request */
171
local_irq_disable();
172
HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT);
173
HACREG(HACCSDR) = (val << CSDR_SHIFT);
174
HACREG(HACCSAR) = (reg << CSAR_SHIFT) & (~CSAR_RD);
175
local_irq_enable();
176
177
/* poll-wait for CMDAMT and CMDDMT */
178
for (to = TMO_E1;
179
to && !(HACREG(HACTSR) & (TSR_CMDAMT|TSR_CMDDMT));
180
--to)
181
udelay(1);
182
183
HACREG(HACTSR) &= ~(TSR_CMDAMT | TSR_CMDDMT);
184
if (to)
185
break;
186
/* timeout, try again */
187
}
188
}
189
190
static unsigned short hac_ac97_read(struct snd_ac97 *ac97,
191
unsigned short reg)
192
{
193
int unit_id = 0 /* ac97->private_data */;
194
struct hac_priv *hac = &hac_cpu_data[unit_id];
195
return hac_read_codec_aux(hac, reg);
196
}
197
198
static void hac_ac97_warmrst(struct snd_ac97 *ac97)
199
{
200
int unit_id = 0 /* ac97->private_data */;
201
struct hac_priv *hac = &hac_cpu_data[unit_id];
202
unsigned int tmo;
203
204
HACREG(HACCR) = CR_WMRT | CR_ST | CR_B9;
205
msleep(10);
206
HACREG(HACCR) = CR_ST | CR_B9;
207
for (tmo = 1000; (tmo > 0) && !(HACREG(HACCR) & CR_CR); tmo--)
208
udelay(1);
209
210
if (!tmo)
211
printk(KERN_INFO "hac: reset: AC97 link down!\n");
212
/* settings this bit lets us have a conversation with codec */
213
HACREG(HACACR) |= ACR_TX12ATOM;
214
}
215
216
static void hac_ac97_coldrst(struct snd_ac97 *ac97)
217
{
218
int unit_id = 0 /* ac97->private_data */;
219
struct hac_priv *hac;
220
hac = &hac_cpu_data[unit_id];
221
222
HACREG(HACCR) = 0;
223
HACREG(HACCR) = CR_CDRT | CR_ST | CR_B9;
224
msleep(10);
225
hac_ac97_warmrst(ac97);
226
}
227
228
static struct snd_ac97_bus_ops hac_ac97_ops = {
229
.read = hac_ac97_read,
230
.write = hac_ac97_write,
231
.reset = hac_ac97_coldrst,
232
.warm_reset = hac_ac97_warmrst,
233
};
234
235
static int hac_hw_params(struct snd_pcm_substream *substream,
236
struct snd_pcm_hw_params *params,
237
struct snd_soc_dai *dai)
238
{
239
struct hac_priv *hac = &hac_cpu_data[dai->id];
240
int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
241
242
switch (params->msbits) {
243
case 16:
244
HACREG(HACACR) |= d ? ACR_DMARX16 : ACR_DMATX16;
245
HACREG(HACACR) &= d ? ~ACR_DMARX20 : ~ACR_DMATX20;
246
break;
247
case 20:
248
HACREG(HACACR) &= d ? ~ACR_DMARX16 : ~ACR_DMATX16;
249
HACREG(HACACR) |= d ? ACR_DMARX20 : ACR_DMATX20;
250
break;
251
default:
252
pr_debug("hac: invalid depth %d bit\n", params->msbits);
253
return -EINVAL;
254
break;
255
}
256
257
return 0;
258
}
259
260
#define AC97_RATES \
261
SNDRV_PCM_RATE_8000_192000
262
263
#define AC97_FMTS \
264
SNDRV_PCM_FMTBIT_S16_LE
265
266
static const struct snd_soc_dai_ops hac_dai_ops = {
267
.hw_params = hac_hw_params,
268
};
269
270
static struct snd_soc_dai_driver sh4_hac_dai[] = {
271
{
272
.name = "hac-dai.0",
273
.playback = {
274
.rates = AC97_RATES,
275
.formats = AC97_FMTS,
276
.channels_min = 2,
277
.channels_max = 2,
278
},
279
.capture = {
280
.rates = AC97_RATES,
281
.formats = AC97_FMTS,
282
.channels_min = 2,
283
.channels_max = 2,
284
},
285
.ops = &hac_dai_ops,
286
},
287
#ifdef CONFIG_CPU_SUBTYPE_SH7760
288
{
289
.name = "hac-dai.1",
290
.id = 1,
291
.playback = {
292
.rates = AC97_RATES,
293
.formats = AC97_FMTS,
294
.channels_min = 2,
295
.channels_max = 2,
296
},
297
.capture = {
298
.rates = AC97_RATES,
299
.formats = AC97_FMTS,
300
.channels_min = 2,
301
.channels_max = 2,
302
},
303
.ops = &hac_dai_ops,
304
305
},
306
#endif
307
};
308
309
static const struct snd_soc_component_driver sh4_hac_component = {
310
.name = "sh4-hac",
311
.legacy_dai_naming = 1,
312
};
313
314
static int hac_soc_platform_probe(struct platform_device *pdev)
315
{
316
int ret;
317
318
ret = snd_soc_set_ac97_ops(&hac_ac97_ops);
319
if (ret != 0)
320
return ret;
321
322
return devm_snd_soc_register_component(&pdev->dev, &sh4_hac_component,
323
sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
324
}
325
326
static void hac_soc_platform_remove(struct platform_device *pdev)
327
{
328
snd_soc_set_ac97_ops(NULL);
329
}
330
331
static struct platform_driver hac_pcm_driver = {
332
.driver = {
333
.name = "hac-pcm-audio",
334
},
335
336
.probe = hac_soc_platform_probe,
337
.remove = hac_soc_platform_remove,
338
};
339
340
module_platform_driver(hac_pcm_driver);
341
342
MODULE_LICENSE("GPL v2");
343
MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
344
MODULE_AUTHOR("Manuel Lauss <[email protected]>");
345
346