summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/amlogic/cs42528.c (plain)
blob: b44e32f7b689057877bc04c027646facf56376c0
1#include <linux/module.h>
2#include <linux/moduleparam.h>
3#include <linux/init.h>
4#include <linux/delay.h>
5#include <linux/i2c.h>
6#include <linux/slab.h>
7#include <sound/core.h>
8#include <sound/pcm.h>
9#include <sound/pcm_params.h>
10#include <sound/soc.h>
11#include <sound/tlv.h>
12#include <linux/amlogic/aml_gpio_consumer.h>
13
14#include "cs42528.h"
15
16#define DEV_NAME "cs42528"
17
18
19#ifdef CONFIG_HAS_EARLYSUSPEND
20#include <linux/earlysuspend.h>
21static void cs42528_early_suspend(struct early_suspend *h);
22static void cs42528_late_resume(struct early_suspend *h);
23#endif
24
25/* Power-up register defaults */
26struct reg_default cs42528_reg_defaults[] = {
27 { 0x00, 0x00 },
28 { 0x03, 0x08 }, /* Functional Mode */
29 { 0x04, 0x40 }, /* Interface Formats */
30 { 0x05, 0x80 }, /* Misc Control */
31 { 0x06, 0x02 }, /* Clock Control */
32 { 0x0D, 0x28 }, /* Volume Control */
33 { 0x0E, 0xff }, /* Channel Mute */
34 { 0x0F, 0x14 }, /* Volume Control A1 */
35 { 0x10, 0x14 }, /* Volume Control B1 */
36 { 0x11, 0x14 }, /* Volume Control A2 */
37 { 0x12, 0x14 }, /* Volume Control B2 */
38 { 0x13, 0x14 }, /* Volume Control A3 */
39 { 0x14, 0x14 }, /* Volume Control B3 */
40 { 0x15, 0x14 }, /* Volume Control A4 */
41 { 0x16, 0x14 }, /* Volume Control B4 */
42 { 0x17, 0x00 }, /* Channel invert */
43 { 0x18, 0x09 }, /* Mixing Ctrl Pair 1 */
44 { 0x19, 0x09 }, /* Mixing Ctrl Pair 2 */
45 { 0x1A, 0x09 }, /* Mixing Ctrl Pair 3 */
46 { 0x1B, 0x09 }, /* Mixing Ctrl Pair 4 */
47 { 0x1C, 0x00 }, /* ADC Left Ch. Gain */
48 { 0x1D, 0x00 }, /* ADC Right Ch. Gain */
49 { 0x1E, 0x80 }, /* RVCR Mode Ctrl 1 */
50 { 0x1F, 0x00 }, /* RVCR Mode Ctrl 2 */
51 { 0x24, 0x00 }, /* Channel Status Data Buffer Control */
52 { 0x28, 0x1f }, /* MuteC Pin Control */
53};
54
55#define CS42528_REG_COUNT 26
56static int cs42528_reg_table[CS42528_REG_COUNT][2] = {
57 { 0x00, 0x00 },
58 { 0x03, 0x08 }, /* Functional Mode */
59 { 0x04, 0x40 }, /* Interface Formats */
60 { 0x05, 0x80 }, /* Misc Control */
61 { 0x06, 0x02 }, /* Clock Control */
62 { 0x0D, 0x28 }, /* Volume Control */
63 { 0x0E, 0xff }, /* Channel Mute */
64 { 0x0F, 0x14 }, /* Volume Control A1 */
65 { 0x10, 0x14 }, /* Volume Control B1 */
66 { 0x11, 0x14 }, /* Volume Control A2 */
67 { 0x12, 0x14 }, /* Volume Control B2 */
68 { 0x13, 0x14 }, /* Volume Control A3 */
69 { 0x14, 0x14 }, /* Volume Control B3 */
70 { 0x15, 0x14 }, /* Volume Control A4 */
71 { 0x16, 0x14 }, /* Volume Control B4 */
72 { 0x17, 0x00 }, /* Channel invert */
73 { 0x18, 0x09 }, /* Mixing Ctrl Pair 1 */
74 { 0x19, 0x09 }, /* Mixing Ctrl Pair 2 */
75 { 0x1A, 0x09 }, /* Mixing Ctrl Pair 3 */
76 { 0x1B, 0x09 }, /* Mixing Ctrl Pair 4 */
77 { 0x1C, 0x00 }, /* ADC Left Ch. Gain */
78 { 0x1D, 0x00 }, /* ADC Right Ch. Gain */
79 { 0x1E, 0x80 }, /* RVCR Mode Ctrl 1 */
80 { 0x1F, 0x00 }, /* RVCR Mode Ctrl 2 */
81 { 0x24, 0x00 }, /* Channel Status Data Buffer Control */
82 { 0x28, 0x1f }, /* MuteC Pin Control */
83};
84
85#define CS42528_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
86 SNDRV_PCM_FMTBIT_S24_LE | \
87 SNDRV_PCM_FMTBIT_S32_LE)
88
89/* codec private data */
90struct cs42528_priv {
91 struct regmap *regmap;
92 struct snd_soc_codec *codec;
93 struct cs42528_platform_data *pdata;
94 int sysclk;
95#ifdef CONFIG_HAS_EARLYSUSPEND
96 struct early_suspend early_suspend;
97#endif
98};
99
100/* -127dB to 0dB with step of 0.5dB */
101static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 0);
102
103/* -15dB to 15dB with step of 1dB */
104static const DECLARE_TLV_DB_SCALE(adc_tlv, -1500, 100, 0);
105
106static const char *const cs42528_szc[] = {
107 "Immediate Change",
108 "Zero Cross",
109 "Soft Ramp",
110 "Soft Ramp on Zero Cross"
111};
112
113static const struct soc_enum dac_szc_enum =
114 SOC_ENUM_SINGLE(CS42528_TXCTL, 4, 4, cs42528_szc);
115
116static const struct snd_kcontrol_new cs42528_snd_controls[] = {
117 SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42528_VOLCTLA1,
118 CS42528_VOLCTLB1, 0, 0xff, 1, dac_tlv),
119 SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42528_VOLCTLA2,
120 CS42528_VOLCTLB2, 0, 0xff, 1, dac_tlv),
121 SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42528_VOLCTLA3,
122 CS42528_VOLCTLB3, 0, 0xff, 1, dac_tlv),
123 SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42528_VOLCTLA4,
124 CS42528_VOLCTLB4, 0, 0xff, 1, dac_tlv),
125 SOC_DOUBLE_R_S_TLV("ADC Channel Gain", CS42528_ADCLGAIN,
126 CS42528_ADCRGAIN, 0, -0x0f, 0x0f, 5, 0, adc_tlv),
127 SOC_DOUBLE("DAC1 Invert Switch", CS42528_CHINV, 0, 1, 1, 0),
128 SOC_DOUBLE("DAC2 Invert Switch", CS42528_CHINV, 2, 3, 1, 0),
129 SOC_DOUBLE("DAC3 Invert Switch", CS42528_CHINV, 4, 5, 1, 0),
130 SOC_DOUBLE("DAC4 Invert Switch", CS42528_CHINV, 6, 7, 1, 0),
131 SOC_SINGLE("DAC Single Volume Control Switch", CS42528_TXCTL, 6, 1, 0),
132 SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
133 SOC_SINGLE("DAC Auto Mute Switch", CS42528_TXCTL, 3, 1, 0),
134 SOC_SINGLE("DAC Serial Port Mute Switch", CS42528_TXCTL, 2, 1, 0),
135};
136
137#if 0
138static const struct snd_soc_dapm_widget cs42528_dapm_widgets[] = {
139 SND_SOC_DAPM_DAC("DAC1", "Playback", CS42528_PWRCTL, 1, 1),
140 SND_SOC_DAPM_DAC("DAC2", "Playback", CS42528_PWRCTL, 2, 1),
141 SND_SOC_DAPM_DAC("DAC3", "Playback", CS42528_PWRCTL, 3, 1),
142 SND_SOC_DAPM_DAC("DAC4", "Playback", CS42528_PWRCTL, 4, 1),
143
144 SND_SOC_DAPM_OUTPUT("AOUT1L"),
145 SND_SOC_DAPM_OUTPUT("AOUT1R"),
146 SND_SOC_DAPM_OUTPUT("AOUT2L"),
147 SND_SOC_DAPM_OUTPUT("AOUT2R"),
148 SND_SOC_DAPM_OUTPUT("AOUT3L"),
149 SND_SOC_DAPM_OUTPUT("AOUT3R"),
150 SND_SOC_DAPM_OUTPUT("AOUT4L"),
151 SND_SOC_DAPM_OUTPUT("AOUT4R"),
152
153 SND_SOC_DAPM_ADC("ADC", "Capture", CS42528_PWRCTL, 5, 1),
154
155 SND_SOC_DAPM_INPUT("AIN1L"),
156 SND_SOC_DAPM_INPUT("AIN1R"),
157 SND_SOC_DAPM_INPUT("AIN2L"),
158 SND_SOC_DAPM_INPUT("AIN2R"),
159
160 SND_SOC_DAPM_SUPPLY("PWR", CS42528_PWRCTL, 0, 1, NULL, 0),
161};
162
163static const struct snd_soc_dapm_route cs42528_dapm_routes[] = {
164 /* Playback */
165 { "AOUT1L", NULL, "DAC1" },
166 { "AOUT1R", NULL, "DAC1" },
167 { "DAC1", NULL, "PWR" },
168
169 { "AOUT2L", NULL, "DAC2" },
170 { "AOUT2R", NULL, "DAC2" },
171 { "DAC2", NULL, "PWR" },
172
173 { "AOUT3L", NULL, "DAC3" },
174 { "AOUT3R", NULL, "DAC3" },
175 { "DAC3", NULL, "PWR" },
176
177 { "AOUT4L", NULL, "DAC4" },
178 { "AOUT4R", NULL, "DAC4" },
179 { "DAC4", NULL, "PWR" },
180
181 /* Capture */
182 { "ADC1", NULL, "AIN1L" },
183 { "ADC1", NULL, "AIN1R" },
184 { "ADC1", NULL, "PWR" },
185
186 { "ADC2", NULL, "AIN2L" },
187 { "ADC2", NULL, "AIN2R" },
188 { "ADC2", NULL, "PWR" },
189};
190#endif
191
192static int cs42528_set_dai_sysclk(struct snd_soc_dai *codec_dai,
193 int clk_id, unsigned int freq, int dir)
194{
195 struct snd_soc_codec *codec = codec_dai->codec;
196 struct cs42528_priv *cs42528 = snd_soc_codec_get_drvdata(codec);
197
198 cs42528->sysclk = freq;
199
200 pr_info("%s, %d clk:%d\n", __func__, __LINE__, freq);
201
202 return 0;
203}
204
205static int cs42528_set_dai_fmt(struct snd_soc_dai *codec_dai,
206 unsigned int format)
207{
208 struct snd_soc_codec *codec = codec_dai->codec;
209 struct cs42528_priv *cs42528 = snd_soc_codec_get_drvdata(codec);
210 u32 val;
211
212 pr_info("%s, %d format:%d\n", __func__, __LINE__, format);
213
214 /* Set DAI format */
215 switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
216 case SND_SOC_DAIFMT_LEFT_J:
217 val = CS42528_INTF_DAC_DIF_LEFTJ;
218 break;
219 case SND_SOC_DAIFMT_I2S:
220 val = CS42528_INTF_DAC_DIF_I2S;
221 break;
222 case SND_SOC_DAIFMT_RIGHT_J:
223 val = CS42528_INTF_DAC_DIF_RIGHTJ;
224 break;
225 default:
226 dev_err(codec->dev, "unsupported dai format\n");
227 return -EINVAL;
228 }
229
230 regmap_update_bits(cs42528->regmap, CS42528_INTF,
231 CS42528_INTF_DAC_DIF_MASK, val);
232
233 /* Set master/slave audio interface */
234 switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
235 case SND_SOC_DAIFMT_CBS_CFS:
236 break;
237 case SND_SOC_DAIFMT_CBM_CFM:
238 break;
239 default:
240 dev_err(codec->dev, "unsupported master/slave mode\n");
241 return -EINVAL;
242 }
243
244 return 0;
245}
246
247static int cs42528_hw_params(struct snd_pcm_substream *substream,
248 struct snd_pcm_hw_params *params,
249 struct snd_soc_dai *dai)
250{
251 unsigned int rate;
252
253 rate = params_rate(params);
254
255 pr_info("%s %d rate: %u\n", __func__, __LINE__, rate);
256
257 switch (params_format(params)) {
258 case SNDRV_PCM_FORMAT_S24_LE:
259 case SNDRV_PCM_FORMAT_S24_BE:
260 pr_debug("24bit\n");
261 break;
262
263 case SNDRV_PCM_FORMAT_S32_LE:
264 case SNDRV_PCM_FORMAT_S20_3LE:
265 case SNDRV_PCM_FORMAT_S20_3BE:
266 pr_debug("20bit\n");
267 break;
268
269 case SNDRV_PCM_FORMAT_S16_LE:
270 case SNDRV_PCM_FORMAT_S16_BE:
271 pr_debug("16bit\n");
272 break;
273
274 default:
275 return -EINVAL;
276 }
277
278 return 0;
279}
280
281static int cs42528_digital_mute(struct snd_soc_dai *dai, int mute)
282{
283 struct snd_soc_codec *codec = dai->codec;
284
285 pr_info("%s %d mute: %d\n", __func__, __LINE__, mute);
286
287 if (mute)
288 snd_soc_write(codec, CS42528_DACMUTE, 0xff);
289 else
290 snd_soc_write(codec, CS42528_DACMUTE, 0);
291
292 return 0;
293}
294
295static const struct snd_soc_dai_ops cs42528_dai_ops = {
296 .hw_params = cs42528_hw_params,
297 .set_sysclk = cs42528_set_dai_sysclk,
298 .set_fmt = cs42528_set_dai_fmt,
299 .digital_mute = cs42528_digital_mute,
300};
301
302static struct snd_soc_dai_driver cs42528_dai = {
303 .name = DEV_NAME,
304 .playback = {
305 .stream_name = "HIFI Playback",
306 .channels_min = 2,
307 .channels_max = 8,
308 .rates = SNDRV_PCM_RATE_8000_192000,
309 .formats = CS42528_FORMATS,
310 },
311 .capture = {
312 .stream_name = "Capture",
313 .channels_min = 2,
314 .channels_max = 8,
315 .rates = SNDRV_PCM_RATE_8000_192000,
316 .formats = CS42528_FORMATS,
317 },
318 .ops = &cs42528_dai_ops,
319};
320
321static int reset_cs42528(struct snd_soc_codec *codec)
322{
323 struct cs42528_priv *cs42528 = snd_soc_codec_get_drvdata(codec);
324 struct cs42528_platform_data *pdata = cs42528->pdata;
325 int ret = 0;
326
327 if (pdata->reset_pin < 0)
328 return 0;
329
330 ret = devm_gpio_request_one(codec->dev, pdata->reset_pin,
331 GPIOF_OUT_INIT_LOW,
332 "cs42528-reset-pin");
333 if (ret < 0)
334 return -1;
335
336 gpio_direction_output(pdata->reset_pin, GPIOF_OUT_INIT_LOW);
337 mdelay(1);
338 gpio_direction_output(pdata->reset_pin, GPIOF_OUT_INIT_HIGH);
339 mdelay(85);
340
341 return 0;
342}
343
344static int cs42528_init(struct snd_soc_codec *codec)
345{
346 int i;
347
348 dev_info(codec->dev, "cs42528_init!\n");
349
350 reset_cs42528(codec);
351
352 for (i = 0; i < CS42528_REG_COUNT; i++) {
353 snd_soc_write(codec, cs42528_reg_table[i][0],
354 cs42528_reg_table[i][1]);
355 }
356
357 // Short delay to finish register writes
358 mdelay(10);
359
360 // Write CS42528 Powerup Register
361 snd_soc_write(codec, CS42528_PWRCTL, 0x40);
362
363 return 0;
364}
365
366static int cs42528_probe(struct snd_soc_codec *codec)
367{
368
369#ifdef CONFIG_HAS_EARLYSUSPEND
370 cs42528->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
371 cs42528->early_suspend.suspend = cs42528_early_suspend;
372 cs42528->early_suspend.resume = cs42528_late_resume;
373 cs42528->early_suspend.param = codec;
374 register_early_suspend(&(cs42528->early_suspend));
375#endif
376
377 cs42528_init(codec);
378
379 return 0;
380}
381
382static int cs42528_remove(struct snd_soc_codec *codec)
383{
384#ifdef CONFIG_HAS_EARLYSUSPEND
385 struct cs42528_priv *cs42528 = snd_soc_codec_get_drvdata(codec);
386
387 unregister_early_suspend(&(cs42528->early_suspend));
388#endif
389
390 return 0;
391}
392
393#ifdef CONFIG_PM
394static int cs42528_suspend(struct snd_soc_codec *codec)
395{
396 dev_info(codec->dev, "cs42528_suspend!\n");
397 return 0;
398}
399
400static int cs42528_resume(struct snd_soc_codec *codec)
401{
402 dev_info(codec->dev, "cs42528_resume!\n");
403 return 0;
404}
405#else
406#define cs42528_suspend NULL
407#define cs42528_resume NULL
408#endif
409
410#ifdef CONFIG_HAS_EARLYSUSPEND
411static void cs42528_early_suspend(struct early_suspend *h)
412{
413}
414
415static void cs42528_late_resume(struct early_suspend *h)
416{
417}
418#endif
419
420static const struct snd_soc_codec_driver soc_codec_dev_cs42528 = {
421 .probe = cs42528_probe,
422 .remove = cs42528_remove,
423 .suspend = cs42528_suspend,
424 .resume = cs42528_resume,
425 .component_driver = {
426 .controls = cs42528_snd_controls,
427 .num_controls = ARRAY_SIZE(cs42528_snd_controls),
428 //.dapm_widgets = cs42528_dapm_widgets,
429 //.num_dapm_widgets = ARRAY_SIZE(cs42528_dapm_widgets),
430 //.dapm_routes = cs42528_dapm_routes,
431 //.num_dapm_routes = ARRAY_SIZE(cs42528_dapm_routes),
432 }
433};
434
435static const struct regmap_config cs42528_regmap = {
436 .reg_bits = 8,
437 .val_bits = 8,
438
439 .max_register = CS42528_NUMREGS,
440 .reg_defaults = cs42528_reg_defaults,
441 .num_reg_defaults = ARRAY_SIZE(cs42528_reg_defaults),
442 .cache_type = REGCACHE_RBTREE,
443};
444
445static int cs42528_parse_dt(
446 struct cs42528_priv *cs42528,
447 struct device_node *np)
448{
449 int ret = 0;
450 int reset_pin = -1;
451
452 reset_pin = of_get_named_gpio(np, "reset_pin", 0);
453 if (reset_pin < 0) {
454 pr_err("%s fail to get reset pin from dts!\n", __func__);
455 ret = -1;
456 } else {
457 pr_info("%s reset_pin = %d!\n", __func__, reset_pin);
458 }
459 cs42528->pdata->reset_pin = reset_pin;
460
461 return ret;
462}
463
464static int cs42528_i2c_probe(struct i2c_client *i2c,
465 const struct i2c_device_id *id)
466{
467 struct cs42528_priv *cs42528;
468 struct cs42528_platform_data *pdata;
469 int ret;
470 const char *codec_name;
471
472 cs42528 = devm_kzalloc(&i2c->dev, sizeof(struct cs42528_priv),
473 GFP_KERNEL);
474 if (!cs42528)
475 return -ENOMEM;
476
477 cs42528->regmap = devm_regmap_init_i2c(i2c, &cs42528_regmap);
478 if (IS_ERR(cs42528->regmap)) {
479 ret = PTR_ERR(cs42528->regmap);
480 dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
481 ret);
482 return ret;
483 }
484
485 pdata = devm_kzalloc(&i2c->dev,
486 sizeof(struct cs42528_platform_data),
487 GFP_KERNEL);
488 if (!pdata) {
489 pr_err("%s failed to kzalloc for cs42528 pdata\n", __func__);
490 return -ENOMEM;
491 }
492
493 cs42528->pdata = pdata;
494
495 cs42528_parse_dt(cs42528, i2c->dev.of_node);
496
497 if (of_property_read_string(i2c->dev.of_node,
498 "codec_name",
499 &codec_name)) {
500 pr_info("no codec name\n");
501 ret = -1;
502 }
503 pr_info("codec name = %s\n", codec_name);
504 if (codec_name)
505 dev_set_name(&i2c->dev, "%s", codec_name);
506
507 i2c_set_clientdata(i2c, cs42528);
508
509 ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_cs42528,
510 &cs42528_dai, 1);
511 if (ret != 0)
512 dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
513
514 return ret;
515}
516
517static int cs42528_i2c_remove(struct i2c_client *client)
518{
519 snd_soc_unregister_codec(&client->dev);
520
521 return 0;
522}
523
524static const struct i2c_device_id cs42528_i2c_id[] = {
525 { "cs42528", 0 },
526 {}
527};
528
529static const struct of_device_id cs42528_of_id[] = {
530 {.compatible = "cirrus,cs42528",},
531 { /* senitel */ }
532};
533MODULE_DEVICE_TABLE(of, cs42528_of_id);
534
535static struct i2c_driver cs42528_i2c_driver = {
536 .driver = {
537 .name = DEV_NAME,
538 .of_match_table = cs42528_of_id,
539 .owner = THIS_MODULE,
540 },
541 .probe = cs42528_i2c_probe,
542 .remove = cs42528_i2c_remove,
543 .id_table = cs42528_i2c_id,
544};
545module_i2c_driver(cs42528_i2c_driver);
546
547MODULE_DESCRIPTION("ASoC CS42528 driver");
548MODULE_AUTHOR("AML MM team");
549MODULE_LICENSE("GPL");
550