Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/soc/codecs/cs42l51.c
10817 views
1
/*
2
* cs42l51.c
3
*
4
* ASoC Driver for Cirrus Logic CS42L51 codecs
5
*
6
* Copyright (c) 2010 Arnaud Patard <[email protected]>
7
*
8
* Based on cs4270.c - Copyright (c) Freescale Semiconductor
9
*
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License version 2 as
12
* published by the Free Software Foundation.
13
*
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
18
*
19
* For now:
20
* - Only I2C is support. Not SPI
21
* - master mode *NOT* supported
22
*/
23
24
#include <linux/module.h>
25
#include <linux/platform_device.h>
26
#include <linux/slab.h>
27
#include <sound/core.h>
28
#include <sound/soc.h>
29
#include <sound/tlv.h>
30
#include <sound/initval.h>
31
#include <sound/pcm_params.h>
32
#include <sound/pcm.h>
33
#include <linux/i2c.h>
34
35
#include "cs42l51.h"
36
37
enum master_slave_mode {
38
MODE_SLAVE,
39
MODE_SLAVE_AUTO,
40
MODE_MASTER,
41
};
42
43
struct cs42l51_private {
44
enum snd_soc_control_type control_type;
45
void *control_data;
46
unsigned int mclk;
47
unsigned int audio_mode; /* The mode (I2S or left-justified) */
48
enum master_slave_mode func;
49
};
50
51
#define CS42L51_FORMATS ( \
52
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
53
SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
54
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
55
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
56
57
static int cs42l51_fill_cache(struct snd_soc_codec *codec)
58
{
59
u8 *cache = codec->reg_cache + 1;
60
struct i2c_client *i2c_client = codec->control_data;
61
s32 length;
62
63
length = i2c_smbus_read_i2c_block_data(i2c_client,
64
CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache);
65
if (length != CS42L51_NUMREGS) {
66
dev_err(&i2c_client->dev,
67
"I2C read failure, addr=0x%x (ret=%d vs %d)\n",
68
i2c_client->addr, length, CS42L51_NUMREGS);
69
return -EIO;
70
}
71
72
return 0;
73
}
74
75
static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
76
struct snd_ctl_elem_value *ucontrol)
77
{
78
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
79
unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
80
81
switch (value) {
82
default:
83
case 0:
84
ucontrol->value.integer.value[0] = 0;
85
break;
86
/* same value : (L+R)/2 and (R+L)/2 */
87
case 1:
88
case 2:
89
ucontrol->value.integer.value[0] = 1;
90
break;
91
case 3:
92
ucontrol->value.integer.value[0] = 2;
93
break;
94
}
95
96
return 0;
97
}
98
99
#define CHAN_MIX_NORMAL 0x00
100
#define CHAN_MIX_BOTH 0x55
101
#define CHAN_MIX_SWAP 0xFF
102
103
static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
104
struct snd_ctl_elem_value *ucontrol)
105
{
106
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
107
unsigned char val;
108
109
switch (ucontrol->value.integer.value[0]) {
110
default:
111
case 0:
112
val = CHAN_MIX_NORMAL;
113
break;
114
case 1:
115
val = CHAN_MIX_BOTH;
116
break;
117
case 2:
118
val = CHAN_MIX_SWAP;
119
break;
120
}
121
122
snd_soc_write(codec, CS42L51_PCM_MIXER, val);
123
124
return 1;
125
}
126
127
static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
128
static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
129
/* This is a lie. after -102 db, it stays at -102 */
130
/* maybe a range would be better */
131
static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0);
132
133
static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
134
static const char *chan_mix[] = {
135
"L R",
136
"L+R",
137
"R L",
138
};
139
140
static const struct soc_enum cs42l51_chan_mix =
141
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix);
142
143
static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
144
SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
145
CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
146
7, 0xffffff99, 0x18, adc_pcm_tlv),
147
SOC_DOUBLE_R("PCM Playback Switch",
148
CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
149
SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
150
CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
151
8, 0xffffff19, 0x18, aout_tlv),
152
SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
153
CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
154
7, 0xffffff99, 0x18, adc_pcm_tlv),
155
SOC_DOUBLE_R("ADC Mixer Switch",
156
CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
157
SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
158
SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
159
SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
160
SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
161
SOC_DOUBLE_TLV("Mic Boost Volume",
162
CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
163
SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
164
SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
165
SOC_ENUM_EXT("PCM channel mixer",
166
cs42l51_chan_mix,
167
cs42l51_get_chan_mix, cs42l51_set_chan_mix),
168
};
169
170
/*
171
* to power down, one must:
172
* 1.) Enable the PDN bit
173
* 2.) enable power-down for the select channels
174
* 3.) disable the PDN bit.
175
*/
176
static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
177
struct snd_kcontrol *kcontrol, int event)
178
{
179
unsigned long value;
180
181
value = snd_soc_read(w->codec, CS42L51_POWER_CTL1);
182
value &= ~CS42L51_POWER_CTL1_PDN;
183
184
switch (event) {
185
case SND_SOC_DAPM_PRE_PMD:
186
value |= CS42L51_POWER_CTL1_PDN;
187
break;
188
default:
189
case SND_SOC_DAPM_POST_PMD:
190
break;
191
}
192
snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
193
CS42L51_POWER_CTL1_PDN, value);
194
195
return 0;
196
}
197
198
static const char *cs42l51_dac_names[] = {"Direct PCM",
199
"DSP PCM", "ADC"};
200
static const struct soc_enum cs42l51_dac_mux_enum =
201
SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names);
202
static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
203
SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
204
205
static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
206
"MIC Left", "MIC+preamp Left"};
207
static const struct soc_enum cs42l51_adcl_mux_enum =
208
SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names);
209
static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
210
SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
211
212
static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
213
"MIC Right", "MIC+preamp Right"};
214
static const struct soc_enum cs42l51_adcr_mux_enum =
215
SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names);
216
static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
217
SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
218
219
static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
220
SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
221
SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
222
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
223
SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
224
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
225
SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture",
226
CS42L51_POWER_CTL1, 1, 1,
227
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
228
SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
229
CS42L51_POWER_CTL1, 2, 1,
230
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
231
SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
232
CS42L51_POWER_CTL1, 5, 1,
233
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
234
SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
235
CS42L51_POWER_CTL1, 6, 1,
236
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
237
238
/* analog/mic */
239
SND_SOC_DAPM_INPUT("AIN1L"),
240
SND_SOC_DAPM_INPUT("AIN1R"),
241
SND_SOC_DAPM_INPUT("AIN2L"),
242
SND_SOC_DAPM_INPUT("AIN2R"),
243
SND_SOC_DAPM_INPUT("MICL"),
244
SND_SOC_DAPM_INPUT("MICR"),
245
246
SND_SOC_DAPM_MIXER("Mic Preamp Left",
247
CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0),
248
SND_SOC_DAPM_MIXER("Mic Preamp Right",
249
CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0),
250
251
/* HP */
252
SND_SOC_DAPM_OUTPUT("HPL"),
253
SND_SOC_DAPM_OUTPUT("HPR"),
254
255
/* mux */
256
SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
257
&cs42l51_dac_mux_controls),
258
SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0,
259
&cs42l51_adcl_mux_controls),
260
SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0,
261
&cs42l51_adcr_mux_controls),
262
};
263
264
static const struct snd_soc_dapm_route cs42l51_routes[] = {
265
{"HPL", NULL, "Left DAC"},
266
{"HPR", NULL, "Right DAC"},
267
268
{"Left ADC", NULL, "Left PGA"},
269
{"Right ADC", NULL, "Right PGA"},
270
271
{"Mic Preamp Left", NULL, "MICL"},
272
{"Mic Preamp Right", NULL, "MICR"},
273
274
{"PGA-ADC Mux Left", "AIN1 Left", "AIN1L" },
275
{"PGA-ADC Mux Left", "AIN2 Left", "AIN2L" },
276
{"PGA-ADC Mux Left", "MIC Left", "MICL" },
277
{"PGA-ADC Mux Left", "MIC+preamp Left", "Mic Preamp Left" },
278
{"PGA-ADC Mux Right", "AIN1 Right", "AIN1R" },
279
{"PGA-ADC Mux Right", "AIN2 Right", "AIN2R" },
280
{"PGA-ADC Mux Right", "MIC Right", "MICR" },
281
{"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" },
282
283
{"Left PGA", NULL, "PGA-ADC Mux Left"},
284
{"Right PGA", NULL, "PGA-ADC Mux Right"},
285
};
286
287
static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
288
unsigned int format)
289
{
290
struct snd_soc_codec *codec = codec_dai->codec;
291
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
292
int ret = 0;
293
294
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
295
case SND_SOC_DAIFMT_I2S:
296
case SND_SOC_DAIFMT_LEFT_J:
297
case SND_SOC_DAIFMT_RIGHT_J:
298
cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
299
break;
300
default:
301
dev_err(codec->dev, "invalid DAI format\n");
302
ret = -EINVAL;
303
}
304
305
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
306
case SND_SOC_DAIFMT_CBM_CFM:
307
cs42l51->func = MODE_MASTER;
308
break;
309
case SND_SOC_DAIFMT_CBS_CFS:
310
cs42l51->func = MODE_SLAVE_AUTO;
311
break;
312
default:
313
ret = -EINVAL;
314
break;
315
}
316
317
return ret;
318
}
319
320
struct cs42l51_ratios {
321
unsigned int ratio;
322
unsigned char speed_mode;
323
unsigned char mclk;
324
};
325
326
static struct cs42l51_ratios slave_ratios[] = {
327
{ 512, CS42L51_QSM_MODE, 0 }, { 768, CS42L51_QSM_MODE, 0 },
328
{ 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
329
{ 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 },
330
{ 256, CS42L51_HSM_MODE, 0 }, { 384, CS42L51_HSM_MODE, 0 },
331
{ 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
332
{ 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 },
333
{ 128, CS42L51_SSM_MODE, 0 }, { 192, CS42L51_SSM_MODE, 0 },
334
{ 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
335
{ 512, CS42L51_SSM_MODE, 0 }, { 768, CS42L51_SSM_MODE, 0 },
336
{ 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
337
{ 256, CS42L51_DSM_MODE, 0 }, { 384, CS42L51_DSM_MODE, 0 },
338
};
339
340
static struct cs42l51_ratios slave_auto_ratios[] = {
341
{ 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
342
{ 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 },
343
{ 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
344
{ 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 },
345
{ 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
346
{ 512, CS42L51_SSM_MODE, 1 }, { 768, CS42L51_SSM_MODE, 1 },
347
{ 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
348
{ 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 },
349
};
350
351
static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
352
int clk_id, unsigned int freq, int dir)
353
{
354
struct snd_soc_codec *codec = codec_dai->codec;
355
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
356
357
cs42l51->mclk = freq;
358
return 0;
359
}
360
361
static int cs42l51_hw_params(struct snd_pcm_substream *substream,
362
struct snd_pcm_hw_params *params,
363
struct snd_soc_dai *dai)
364
{
365
struct snd_soc_pcm_runtime *rtd = substream->private_data;
366
struct snd_soc_codec *codec = rtd->codec;
367
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
368
int ret;
369
unsigned int i;
370
unsigned int rate;
371
unsigned int ratio;
372
struct cs42l51_ratios *ratios = NULL;
373
int nr_ratios = 0;
374
int intf_ctl, power_ctl, fmt;
375
376
switch (cs42l51->func) {
377
case MODE_MASTER:
378
return -EINVAL;
379
case MODE_SLAVE:
380
ratios = slave_ratios;
381
nr_ratios = ARRAY_SIZE(slave_ratios);
382
break;
383
case MODE_SLAVE_AUTO:
384
ratios = slave_auto_ratios;
385
nr_ratios = ARRAY_SIZE(slave_auto_ratios);
386
break;
387
}
388
389
/* Figure out which MCLK/LRCK ratio to use */
390
rate = params_rate(params); /* Sampling rate, in Hz */
391
ratio = cs42l51->mclk / rate; /* MCLK/LRCK ratio */
392
for (i = 0; i < nr_ratios; i++) {
393
if (ratios[i].ratio == ratio)
394
break;
395
}
396
397
if (i == nr_ratios) {
398
/* We did not find a matching ratio */
399
dev_err(codec->dev, "could not find matching ratio\n");
400
return -EINVAL;
401
}
402
403
intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL);
404
power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL);
405
406
intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
407
| CS42L51_INTF_CTL_DAC_FORMAT(7));
408
power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
409
| CS42L51_MIC_POWER_CTL_MCLK_DIV2);
410
411
switch (cs42l51->func) {
412
case MODE_MASTER:
413
intf_ctl |= CS42L51_INTF_CTL_MASTER;
414
power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
415
break;
416
case MODE_SLAVE:
417
power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
418
break;
419
case MODE_SLAVE_AUTO:
420
power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
421
break;
422
}
423
424
switch (cs42l51->audio_mode) {
425
case SND_SOC_DAIFMT_I2S:
426
intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
427
intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
428
break;
429
case SND_SOC_DAIFMT_LEFT_J:
430
intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
431
break;
432
case SND_SOC_DAIFMT_RIGHT_J:
433
switch (params_format(params)) {
434
case SNDRV_PCM_FORMAT_S16_LE:
435
case SNDRV_PCM_FORMAT_S16_BE:
436
fmt = CS42L51_DAC_DIF_RJ16;
437
break;
438
case SNDRV_PCM_FORMAT_S18_3LE:
439
case SNDRV_PCM_FORMAT_S18_3BE:
440
fmt = CS42L51_DAC_DIF_RJ18;
441
break;
442
case SNDRV_PCM_FORMAT_S20_3LE:
443
case SNDRV_PCM_FORMAT_S20_3BE:
444
fmt = CS42L51_DAC_DIF_RJ20;
445
break;
446
case SNDRV_PCM_FORMAT_S24_LE:
447
case SNDRV_PCM_FORMAT_S24_BE:
448
fmt = CS42L51_DAC_DIF_RJ24;
449
break;
450
default:
451
dev_err(codec->dev, "unknown format\n");
452
return -EINVAL;
453
}
454
intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
455
break;
456
default:
457
dev_err(codec->dev, "unknown format\n");
458
return -EINVAL;
459
}
460
461
if (ratios[i].mclk)
462
power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
463
464
ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl);
465
if (ret < 0)
466
return ret;
467
468
ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl);
469
if (ret < 0)
470
return ret;
471
472
return 0;
473
}
474
475
static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
476
{
477
struct snd_soc_codec *codec = dai->codec;
478
int reg;
479
int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
480
481
reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL);
482
483
if (mute)
484
reg |= mask;
485
else
486
reg &= ~mask;
487
488
return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg);
489
}
490
491
static struct snd_soc_dai_ops cs42l51_dai_ops = {
492
.hw_params = cs42l51_hw_params,
493
.set_sysclk = cs42l51_set_dai_sysclk,
494
.set_fmt = cs42l51_set_dai_fmt,
495
.digital_mute = cs42l51_dai_mute,
496
};
497
498
static struct snd_soc_dai_driver cs42l51_dai = {
499
.name = "cs42l51-hifi",
500
.playback = {
501
.stream_name = "Playback",
502
.channels_min = 1,
503
.channels_max = 2,
504
.rates = SNDRV_PCM_RATE_8000_96000,
505
.formats = CS42L51_FORMATS,
506
},
507
.capture = {
508
.stream_name = "Capture",
509
.channels_min = 1,
510
.channels_max = 2,
511
.rates = SNDRV_PCM_RATE_8000_96000,
512
.formats = CS42L51_FORMATS,
513
},
514
.ops = &cs42l51_dai_ops,
515
};
516
517
static int cs42l51_probe(struct snd_soc_codec *codec)
518
{
519
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
520
struct snd_soc_dapm_context *dapm = &codec->dapm;
521
int ret, reg;
522
523
codec->control_data = cs42l51->control_data;
524
525
ret = cs42l51_fill_cache(codec);
526
if (ret < 0) {
527
dev_err(codec->dev, "failed to fill register cache\n");
528
return ret;
529
}
530
531
ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type);
532
if (ret < 0) {
533
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
534
return ret;
535
}
536
537
/*
538
* DAC configuration
539
* - Use signal processor
540
* - auto mute
541
* - vol changes immediate
542
* - no de-emphasize
543
*/
544
reg = CS42L51_DAC_CTL_DATA_SEL(1)
545
| CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
546
ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
547
if (ret < 0)
548
return ret;
549
550
snd_soc_add_controls(codec, cs42l51_snd_controls,
551
ARRAY_SIZE(cs42l51_snd_controls));
552
snd_soc_dapm_new_controls(dapm, cs42l51_dapm_widgets,
553
ARRAY_SIZE(cs42l51_dapm_widgets));
554
snd_soc_dapm_add_routes(dapm, cs42l51_routes,
555
ARRAY_SIZE(cs42l51_routes));
556
557
return 0;
558
}
559
560
static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
561
.probe = cs42l51_probe,
562
.reg_cache_size = CS42L51_NUMREGS,
563
.reg_word_size = sizeof(u8),
564
};
565
566
static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
567
const struct i2c_device_id *id)
568
{
569
struct cs42l51_private *cs42l51;
570
int ret;
571
572
/* Verify that we have a CS42L51 */
573
ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
574
if (ret < 0) {
575
dev_err(&i2c_client->dev, "failed to read I2C\n");
576
goto error;
577
}
578
579
if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
580
(ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
581
dev_err(&i2c_client->dev, "Invalid chip id\n");
582
ret = -ENODEV;
583
goto error;
584
}
585
586
dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
587
ret & 7);
588
589
cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
590
if (!cs42l51) {
591
dev_err(&i2c_client->dev, "could not allocate codec\n");
592
return -ENOMEM;
593
}
594
595
i2c_set_clientdata(i2c_client, cs42l51);
596
cs42l51->control_data = i2c_client;
597
cs42l51->control_type = SND_SOC_I2C;
598
599
ret = snd_soc_register_codec(&i2c_client->dev,
600
&soc_codec_device_cs42l51, &cs42l51_dai, 1);
601
if (ret < 0)
602
kfree(cs42l51);
603
error:
604
return ret;
605
}
606
607
static int cs42l51_i2c_remove(struct i2c_client *client)
608
{
609
struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
610
611
snd_soc_unregister_codec(&client->dev);
612
kfree(cs42l51);
613
return 0;
614
}
615
616
static const struct i2c_device_id cs42l51_id[] = {
617
{"cs42l51", 0},
618
{}
619
};
620
MODULE_DEVICE_TABLE(i2c, cs42l51_id);
621
622
static struct i2c_driver cs42l51_i2c_driver = {
623
.driver = {
624
.name = "cs42l51-codec",
625
.owner = THIS_MODULE,
626
},
627
.id_table = cs42l51_id,
628
.probe = cs42l51_i2c_probe,
629
.remove = cs42l51_i2c_remove,
630
};
631
632
static int __init cs42l51_init(void)
633
{
634
int ret;
635
636
ret = i2c_add_driver(&cs42l51_i2c_driver);
637
if (ret != 0) {
638
printk(KERN_ERR "%s: can't add i2c driver\n", __func__);
639
return ret;
640
}
641
return 0;
642
}
643
module_init(cs42l51_init);
644
645
static void __exit cs42l51_exit(void)
646
{
647
i2c_del_driver(&cs42l51_i2c_driver);
648
}
649
module_exit(cs42l51_exit);
650
651
MODULE_AUTHOR("Arnaud Patard <[email protected]>");
652
MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
653
MODULE_LICENSE("GPL");
654
655