aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/ak4613.c
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2015-09-15 04:26:36 -0400
committerMark Brown <broonie@kernel.org>2015-09-17 07:33:08 -0400
commitb07570628471777aabb5695284e1af4533e502da (patch)
tree8a0699b1be2d78e54da8687800edaeba2cf290ef /sound/soc/codecs/ak4613.c
parent6ff33f3902c3b1c5d0db6b1e2c70b6d76fba357f (diff)
ASoC: add ak4613 support
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/codecs/ak4613.c')
-rw-r--r--sound/soc/codecs/ak4613.c469
1 files changed, 469 insertions, 0 deletions
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
new file mode 100644
index 000000000000..fd96a8f9e2d3
--- /dev/null
+++ b/sound/soc/codecs/ak4613.c
@@ -0,0 +1,469 @@
1/*
2 * ak4613.c -- Asahi Kasei ALSA Soc Audio driver
3 *
4 * Copyright (C) 2015 Renesas Electronics Corporation
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6 *
7 * Based on ak4642.c by Kuninori Morimoto
8 * Based on wm8731.c by Richard Purdie
9 * Based on ak4535.c by Richard Purdie
10 * Based on wm8753.c by Liam Girdwood
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 */
16
17#include <linux/clk.h>
18#include <linux/i2c.h>
19#include <linux/slab.h>
20#include <linux/of_device.h>
21#include <linux/module.h>
22#include <linux/regmap.h>
23#include <sound/soc.h>
24#include <sound/pcm_params.h>
25
26#define PW_MGMT1 0x00 /* Power Management 1 */
27#define PW_MGMT2 0x01 /* Power Management 2 */
28#define PW_MGMT3 0x02 /* Power Management 3 */
29#define CTRL1 0x03 /* Control 1 */
30#define CTRL2 0x04 /* Control 2 */
31#define DEMP1 0x05 /* De-emphasis1 */
32#define DEMP2 0x06 /* De-emphasis2 */
33#define OFD 0x07 /* Overflow Detect */
34#define ZRD 0x08 /* Zero Detect */
35#define ICTRL 0x09 /* Input Control */
36#define OCTRL 0x0a /* Output Control */
37#define LOUT1 0x0b /* LOUT1 Volume Control */
38#define ROUT1 0x0c /* ROUT1 Volume Control */
39#define LOUT2 0x0d /* LOUT2 Volume Control */
40#define ROUT2 0x0e /* ROUT2 Volume Control */
41#define LOUT3 0x0f /* LOUT3 Volume Control */
42#define ROUT3 0x10 /* ROUT3 Volume Control */
43#define LOUT4 0x11 /* LOUT4 Volume Control */
44#define ROUT4 0x12 /* ROUT4 Volume Control */
45#define LOUT5 0x13 /* LOUT5 Volume Control */
46#define ROUT5 0x14 /* ROUT5 Volume Control */
47#define LOUT6 0x15 /* LOUT6 Volume Control */
48#define ROUT6 0x16 /* ROUT6 Volume Control */
49
50/* PW_MGMT1 */
51#define RSTN BIT(0)
52#define PMDAC BIT(1)
53#define PMADC BIT(2)
54#define PMVR BIT(3)
55
56/* PW_MGMT2 */
57#define PMAD_ALL 0x7
58
59/* PW_MGMT3 */
60#define PMDA_ALL 0x3f
61
62/* CTRL1 */
63#define DIF0 BIT(3)
64#define DIF1 BIT(4)
65#define DIF2 BIT(5)
66#define TDM0 BIT(6)
67#define TDM1 BIT(7)
68#define NO_FMT (0xff)
69#define FMT_MASK (0xf8)
70
71/* CTRL2 */
72#define DFS_NORMAL_SPEED (0 << 2)
73#define DFS_DOUBLE_SPEED (1 << 2)
74#define DFS_QUAD_SPEED (2 << 2)
75
76struct ak4613_priv {
77 struct mutex lock;
78
79 unsigned int fmt;
80 u8 fmt_ctrl;
81 int cnt;
82};
83
84struct ak4613_formats {
85 unsigned int width;
86 unsigned int fmt;
87};
88
89struct ak4613_interface {
90 struct ak4613_formats capture;
91 struct ak4613_formats playback;
92};
93
94static const struct reg_default ak4613_reg[] = {
95 { 0x0, 0x0f }, { 0x1, 0x07 }, { 0x2, 0x3f }, { 0x3, 0x20 },
96 { 0x4, 0x20 }, { 0x5, 0x55 }, { 0x6, 0x05 }, { 0x7, 0x07 },
97 { 0x8, 0x0f }, { 0x9, 0x07 }, { 0xa, 0x3f }, { 0xb, 0x00 },
98 { 0xc, 0x00 }, { 0xd, 0x00 }, { 0xe, 0x00 }, { 0xf, 0x00 },
99 { 0x10, 0x00 }, { 0x11, 0x00 }, { 0x12, 0x00 }, { 0x13, 0x00 },
100 { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 },
101};
102
103#define AUDIO_IFACE_IDX_TO_VAL(i) (i << 3)
104#define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt }
105static const struct ak4613_interface ak4613_iface[] = {
106 /* capture */ /* playback */
107 [0] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(16, RIGHT_J) },
108 [1] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(20, RIGHT_J) },
109 [2] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(24, RIGHT_J) },
110 [3] = { AUDIO_IFACE(24, LEFT_J), AUDIO_IFACE(24, LEFT_J) },
111 [4] = { AUDIO_IFACE(24, I2S), AUDIO_IFACE(24, I2S) },
112};
113
114static const struct regmap_config ak4613_regmap_cfg = {
115 .reg_bits = 8,
116 .val_bits = 8,
117 .max_register = 0x16,
118 .reg_defaults = ak4613_reg,
119 .num_reg_defaults = ARRAY_SIZE(ak4613_reg),
120};
121
122static const struct of_device_id ak4613_of_match[] = {
123 { .compatible = "asahi-kasei,ak4613", .data = &ak4613_regmap_cfg },
124 {},
125};
126MODULE_DEVICE_TABLE(of, ak4613_of_match);
127
128static const struct i2c_device_id ak4613_i2c_id[] = {
129 { "ak4613", (kernel_ulong_t)&ak4613_regmap_cfg },
130 { }
131};
132MODULE_DEVICE_TABLE(i2c, ak4613_i2c_id);
133
134static const struct snd_soc_dapm_widget ak4613_dapm_widgets[] = {
135
136 /* Outputs */
137 SND_SOC_DAPM_OUTPUT("LOUT1"),
138 SND_SOC_DAPM_OUTPUT("LOUT2"),
139 SND_SOC_DAPM_OUTPUT("LOUT3"),
140 SND_SOC_DAPM_OUTPUT("LOUT4"),
141 SND_SOC_DAPM_OUTPUT("LOUT5"),
142 SND_SOC_DAPM_OUTPUT("LOUT6"),
143
144 SND_SOC_DAPM_OUTPUT("ROUT1"),
145 SND_SOC_DAPM_OUTPUT("ROUT2"),
146 SND_SOC_DAPM_OUTPUT("ROUT3"),
147 SND_SOC_DAPM_OUTPUT("ROUT4"),
148 SND_SOC_DAPM_OUTPUT("ROUT5"),
149 SND_SOC_DAPM_OUTPUT("ROUT6"),
150
151 /* Inputs */
152 SND_SOC_DAPM_INPUT("LIN1"),
153 SND_SOC_DAPM_INPUT("LIN2"),
154
155 SND_SOC_DAPM_INPUT("RIN1"),
156 SND_SOC_DAPM_INPUT("RIN2"),
157
158 /* DAC */
159 SND_SOC_DAPM_DAC("DAC1", NULL, PW_MGMT3, 0, 0),
160 SND_SOC_DAPM_DAC("DAC2", NULL, PW_MGMT3, 1, 0),
161 SND_SOC_DAPM_DAC("DAC3", NULL, PW_MGMT3, 2, 0),
162 SND_SOC_DAPM_DAC("DAC4", NULL, PW_MGMT3, 3, 0),
163 SND_SOC_DAPM_DAC("DAC5", NULL, PW_MGMT3, 4, 0),
164 SND_SOC_DAPM_DAC("DAC6", NULL, PW_MGMT3, 5, 0),
165
166 /* ADC */
167 SND_SOC_DAPM_ADC("ADC1", NULL, PW_MGMT2, 0, 0),
168 SND_SOC_DAPM_ADC("ADC2", NULL, PW_MGMT2, 1, 0),
169};
170
171static const struct snd_soc_dapm_route ak4613_intercon[] = {
172 {"LOUT1", NULL, "DAC1"},
173 {"LOUT2", NULL, "DAC2"},
174 {"LOUT3", NULL, "DAC3"},
175 {"LOUT4", NULL, "DAC4"},
176 {"LOUT5", NULL, "DAC5"},
177 {"LOUT6", NULL, "DAC6"},
178
179 {"ROUT1", NULL, "DAC1"},
180 {"ROUT2", NULL, "DAC2"},
181 {"ROUT3", NULL, "DAC3"},
182 {"ROUT4", NULL, "DAC4"},
183 {"ROUT5", NULL, "DAC5"},
184 {"ROUT6", NULL, "DAC6"},
185
186 {"DAC1", NULL, "Playback"},
187 {"DAC2", NULL, "Playback"},
188 {"DAC3", NULL, "Playback"},
189 {"DAC4", NULL, "Playback"},
190 {"DAC5", NULL, "Playback"},
191 {"DAC6", NULL, "Playback"},
192
193 {"Capture", NULL, "ADC1"},
194 {"Capture", NULL, "ADC2"},
195
196 {"ADC1", NULL, "LIN1"},
197 {"ADC2", NULL, "LIN2"},
198
199 {"ADC1", NULL, "RIN1"},
200 {"ADC2", NULL, "RIN2"},
201};
202
203static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
204 struct snd_soc_dai *dai)
205{
206 struct snd_soc_codec *codec = dai->codec;
207 struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
208 struct device *dev = codec->dev;
209
210 mutex_lock(&priv->lock);
211 priv->cnt--;
212 if (priv->cnt < 0) {
213 dev_err(dev, "unexpected counter error\n");
214 priv->cnt = 0;
215 }
216 if (!priv->cnt)
217 priv->fmt_ctrl = NO_FMT;
218 mutex_unlock(&priv->lock);
219}
220
221static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
222{
223 struct snd_soc_codec *codec = dai->codec;
224 struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
225
226 fmt &= SND_SOC_DAIFMT_FORMAT_MASK;
227
228 switch (fmt) {
229 case SND_SOC_DAIFMT_RIGHT_J:
230 case SND_SOC_DAIFMT_LEFT_J:
231 case SND_SOC_DAIFMT_I2S:
232 priv->fmt = fmt;
233
234 break;
235 default:
236 return -EINVAL;
237 }
238
239 return 0;
240}
241
242static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
243 struct snd_pcm_hw_params *params,
244 struct snd_soc_dai *dai)
245{
246 struct snd_soc_codec *codec = dai->codec;
247 struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
248 const struct ak4613_formats *fmts;
249 struct device *dev = codec->dev;
250 unsigned int width = params_width(params);
251 unsigned int fmt = priv->fmt;
252 unsigned int rate;
253 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
254 int i, ret;
255 u8 fmt_ctrl, ctrl2;
256
257 rate = params_rate(params);
258 switch (rate) {
259 case 32000:
260 case 44100:
261 case 48000:
262 ctrl2 = DFS_NORMAL_SPEED;
263 break;
264 case 88200:
265 case 96000:
266 ctrl2 = DFS_DOUBLE_SPEED;
267 break;
268 case 176400:
269 case 192000:
270 ctrl2 = DFS_QUAD_SPEED;
271 break;
272 default:
273 return -EINVAL;
274 }
275
276 /*
277 * FIXME
278 *
279 * It doesn't support TDM at this point
280 */
281 fmt_ctrl = NO_FMT;
282 for (i = 0; i < ARRAY_SIZE(ak4613_iface); i++) {
283 fmts = (is_play) ? &ak4613_iface[i].playback :
284 &ak4613_iface[i].capture;
285
286 if (fmts->fmt != fmt)
287 continue;
288
289 if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
290 if (fmts->width != width)
291 continue;
292 } else {
293 if (fmts->width < width)
294 continue;
295 }
296
297 fmt_ctrl = AUDIO_IFACE_IDX_TO_VAL(i);
298 break;
299 }
300
301 ret = -EINVAL;
302 if (fmt_ctrl == NO_FMT)
303 goto hw_params_end;
304
305 mutex_lock(&priv->lock);
306 if ((priv->fmt_ctrl == NO_FMT) ||
307 (priv->fmt_ctrl == fmt_ctrl)) {
308 priv->fmt_ctrl = fmt_ctrl;
309 priv->cnt++;
310 ret = 0;
311 }
312 mutex_unlock(&priv->lock);
313
314 if (ret < 0)
315 goto hw_params_end;
316
317 snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl);
318 snd_soc_write(codec, CTRL2, ctrl2);
319
320hw_params_end:
321 if (ret < 0)
322 dev_warn(dev, "unsupported data width/format combination\n");
323
324 return ret;
325}
326
327static int ak4613_set_bias_level(struct snd_soc_codec *codec,
328 enum snd_soc_bias_level level)
329{
330 u8 mgmt1 = 0;
331
332 switch (level) {
333 case SND_SOC_BIAS_ON:
334 mgmt1 |= RSTN;
335 /* fall through */
336 case SND_SOC_BIAS_PREPARE:
337 mgmt1 |= PMADC | PMDAC;
338 /* fall through */
339 case SND_SOC_BIAS_STANDBY:
340 mgmt1 |= PMVR;
341 /* fall through */
342 case SND_SOC_BIAS_OFF:
343 default:
344 break;
345 }
346
347 snd_soc_write(codec, PW_MGMT1, mgmt1);
348
349 return 0;
350}
351
352static const struct snd_soc_dai_ops ak4613_dai_ops = {
353 .shutdown = ak4613_dai_shutdown,
354 .set_fmt = ak4613_dai_set_fmt,
355 .hw_params = ak4613_dai_hw_params,
356};
357
358#define AK4613_PCM_RATE (SNDRV_PCM_RATE_32000 |\
359 SNDRV_PCM_RATE_44100 |\
360 SNDRV_PCM_RATE_48000 |\
361 SNDRV_PCM_RATE_64000 |\
362 SNDRV_PCM_RATE_88200 |\
363 SNDRV_PCM_RATE_96000 |\
364 SNDRV_PCM_RATE_176400 |\
365 SNDRV_PCM_RATE_192000)
366#define AK4613_PCM_FMTBIT (SNDRV_PCM_FMTBIT_S16_LE |\
367 SNDRV_PCM_FMTBIT_S24_LE)
368
369static struct snd_soc_dai_driver ak4613_dai = {
370 .name = "ak4613-hifi",
371 .playback = {
372 .stream_name = "Playback",
373 .channels_min = 2,
374 .channels_max = 2,
375 .rates = AK4613_PCM_RATE,
376 .formats = AK4613_PCM_FMTBIT,
377 },
378 .capture = {
379 .stream_name = "Capture",
380 .channels_min = 2,
381 .channels_max = 2,
382 .rates = AK4613_PCM_RATE,
383 .formats = AK4613_PCM_FMTBIT,
384 },
385 .ops = &ak4613_dai_ops,
386 .symmetric_rates = 1,
387};
388
389static int ak4613_resume(struct snd_soc_codec *codec)
390{
391 struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
392
393 regcache_mark_dirty(regmap);
394 return regcache_sync(regmap);
395}
396
397static struct snd_soc_codec_driver soc_codec_dev_ak4613 = {
398 .resume = ak4613_resume,
399 .set_bias_level = ak4613_set_bias_level,
400 .dapm_widgets = ak4613_dapm_widgets,
401 .num_dapm_widgets = ARRAY_SIZE(ak4613_dapm_widgets),
402 .dapm_routes = ak4613_intercon,
403 .num_dapm_routes = ARRAY_SIZE(ak4613_intercon),
404};
405
406static int ak4613_i2c_probe(struct i2c_client *i2c,
407 const struct i2c_device_id *id)
408{
409 struct device *dev = &i2c->dev;
410 struct device_node *np = dev->of_node;
411 const struct regmap_config *regmap_cfg;
412 struct regmap *regmap;
413 struct ak4613_priv *priv;
414
415 regmap_cfg = NULL;
416 if (np) {
417 const struct of_device_id *of_id;
418
419 of_id = of_match_device(ak4613_of_match, dev);
420 if (of_id)
421 regmap_cfg = of_id->data;
422 } else {
423 regmap_cfg = (const struct regmap_config *)id->driver_data;
424 }
425
426 if (!regmap_cfg)
427 return -EINVAL;
428
429 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
430 if (!priv)
431 return -ENOMEM;
432
433 priv->fmt_ctrl = NO_FMT;
434 priv->cnt = 0;
435
436 mutex_init(&priv->lock);
437
438 i2c_set_clientdata(i2c, priv);
439
440 regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
441 if (IS_ERR(regmap))
442 return PTR_ERR(regmap);
443
444 return snd_soc_register_codec(dev, &soc_codec_dev_ak4613,
445 &ak4613_dai, 1);
446}
447
448static int ak4613_i2c_remove(struct i2c_client *client)
449{
450 snd_soc_unregister_codec(&client->dev);
451 return 0;
452}
453
454static struct i2c_driver ak4613_i2c_driver = {
455 .driver = {
456 .name = "ak4613-codec",
457 .owner = THIS_MODULE,
458 .of_match_table = ak4613_of_match,
459 },
460 .probe = ak4613_i2c_probe,
461 .remove = ak4613_i2c_remove,
462 .id_table = ak4613_i2c_id,
463};
464
465module_i2c_driver(ak4613_i2c_driver);
466
467MODULE_DESCRIPTION("Soc AK4613 driver");
468MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
469MODULE_LICENSE("GPL v2");