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