cs42l51.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  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. #include <linux/module.h>
  24. #include <linux/slab.h>
  25. #include <sound/core.h>
  26. #include <sound/soc.h>
  27. #include <sound/tlv.h>
  28. #include <sound/initval.h>
  29. #include <sound/pcm_params.h>
  30. #include <sound/pcm.h>
  31. #include <linux/regmap.h>
  32. #include "cs42l51.h"
  33. enum master_slave_mode {
  34. MODE_SLAVE,
  35. MODE_SLAVE_AUTO,
  36. MODE_MASTER,
  37. };
  38. struct cs42l51_private {
  39. unsigned int mclk;
  40. unsigned int audio_mode; /* The mode (I2S or left-justified) */
  41. enum master_slave_mode func;
  42. };
  43. #define CS42L51_FORMATS ( \
  44. SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
  45. SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
  46. SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
  47. SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
  48. static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
  49. struct snd_ctl_elem_value *ucontrol)
  50. {
  51. struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
  52. unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
  53. switch (value) {
  54. default:
  55. case 0:
  56. ucontrol->value.integer.value[0] = 0;
  57. break;
  58. /* same value : (L+R)/2 and (R+L)/2 */
  59. case 1:
  60. case 2:
  61. ucontrol->value.integer.value[0] = 1;
  62. break;
  63. case 3:
  64. ucontrol->value.integer.value[0] = 2;
  65. break;
  66. }
  67. return 0;
  68. }
  69. #define CHAN_MIX_NORMAL 0x00
  70. #define CHAN_MIX_BOTH 0x55
  71. #define CHAN_MIX_SWAP 0xFF
  72. static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
  73. struct snd_ctl_elem_value *ucontrol)
  74. {
  75. struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
  76. unsigned char val;
  77. switch (ucontrol->value.integer.value[0]) {
  78. default:
  79. case 0:
  80. val = CHAN_MIX_NORMAL;
  81. break;
  82. case 1:
  83. val = CHAN_MIX_BOTH;
  84. break;
  85. case 2:
  86. val = CHAN_MIX_SWAP;
  87. break;
  88. }
  89. snd_soc_write(codec, CS42L51_PCM_MIXER, val);
  90. return 1;
  91. }
  92. static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
  93. static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
  94. static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0);
  95. static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
  96. static const char *chan_mix[] = {
  97. "L R",
  98. "L+R",
  99. "R L",
  100. };
  101. static SOC_ENUM_SINGLE_EXT_DECL(cs42l51_chan_mix, chan_mix);
  102. static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
  103. SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
  104. CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
  105. 0, 0x19, 0x7F, adc_pcm_tlv),
  106. SOC_DOUBLE_R("PCM Playback Switch",
  107. CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
  108. SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
  109. CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
  110. 0, 0x34, 0xE4, aout_tlv),
  111. SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
  112. CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
  113. 0, 0x19, 0x7F, adc_pcm_tlv),
  114. SOC_DOUBLE_R("ADC Mixer Switch",
  115. CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
  116. SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
  117. SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
  118. SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
  119. SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
  120. SOC_DOUBLE_TLV("Mic Boost Volume",
  121. CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
  122. SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
  123. SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
  124. SOC_ENUM_EXT("PCM channel mixer",
  125. cs42l51_chan_mix,
  126. cs42l51_get_chan_mix, cs42l51_set_chan_mix),
  127. };
  128. /*
  129. * to power down, one must:
  130. * 1.) Enable the PDN bit
  131. * 2.) enable power-down for the select channels
  132. * 3.) disable the PDN bit.
  133. */
  134. static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
  135. struct snd_kcontrol *kcontrol, int event)
  136. {
  137. switch (event) {
  138. case SND_SOC_DAPM_PRE_PMD:
  139. snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
  140. CS42L51_POWER_CTL1_PDN,
  141. CS42L51_POWER_CTL1_PDN);
  142. break;
  143. default:
  144. case SND_SOC_DAPM_POST_PMD:
  145. snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
  146. CS42L51_POWER_CTL1_PDN, 0);
  147. break;
  148. }
  149. return 0;
  150. }
  151. static const char *cs42l51_dac_names[] = {"Direct PCM",
  152. "DSP PCM", "ADC"};
  153. static SOC_ENUM_SINGLE_DECL(cs42l51_dac_mux_enum,
  154. CS42L51_DAC_CTL, 6, cs42l51_dac_names);
  155. static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
  156. SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
  157. static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
  158. "MIC Left", "MIC+preamp Left"};
  159. static SOC_ENUM_SINGLE_DECL(cs42l51_adcl_mux_enum,
  160. CS42L51_ADC_INPUT, 4, cs42l51_adcl_names);
  161. static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
  162. SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
  163. static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
  164. "MIC Right", "MIC+preamp Right"};
  165. static SOC_ENUM_SINGLE_DECL(cs42l51_adcr_mux_enum,
  166. CS42L51_ADC_INPUT, 6, cs42l51_adcr_names);
  167. static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
  168. SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
  169. static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
  170. SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
  171. SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
  172. cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
  173. SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
  174. cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
  175. SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture",
  176. CS42L51_POWER_CTL1, 1, 1,
  177. cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
  178. SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
  179. CS42L51_POWER_CTL1, 2, 1,
  180. cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
  181. SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
  182. CS42L51_POWER_CTL1, 5, 1,
  183. cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
  184. SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
  185. CS42L51_POWER_CTL1, 6, 1,
  186. cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
  187. /* analog/mic */
  188. SND_SOC_DAPM_INPUT("AIN1L"),
  189. SND_SOC_DAPM_INPUT("AIN1R"),
  190. SND_SOC_DAPM_INPUT("AIN2L"),
  191. SND_SOC_DAPM_INPUT("AIN2R"),
  192. SND_SOC_DAPM_INPUT("MICL"),
  193. SND_SOC_DAPM_INPUT("MICR"),
  194. SND_SOC_DAPM_MIXER("Mic Preamp Left",
  195. CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0),
  196. SND_SOC_DAPM_MIXER("Mic Preamp Right",
  197. CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0),
  198. /* HP */
  199. SND_SOC_DAPM_OUTPUT("HPL"),
  200. SND_SOC_DAPM_OUTPUT("HPR"),
  201. /* mux */
  202. SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
  203. &cs42l51_dac_mux_controls),
  204. SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0,
  205. &cs42l51_adcl_mux_controls),
  206. SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0,
  207. &cs42l51_adcr_mux_controls),
  208. };
  209. static const struct snd_soc_dapm_route cs42l51_routes[] = {
  210. {"HPL", NULL, "Left DAC"},
  211. {"HPR", NULL, "Right DAC"},
  212. {"Left ADC", NULL, "Left PGA"},
  213. {"Right ADC", NULL, "Right PGA"},
  214. {"Mic Preamp Left", NULL, "MICL"},
  215. {"Mic Preamp Right", NULL, "MICR"},
  216. {"PGA-ADC Mux Left", "AIN1 Left", "AIN1L" },
  217. {"PGA-ADC Mux Left", "AIN2 Left", "AIN2L" },
  218. {"PGA-ADC Mux Left", "MIC Left", "MICL" },
  219. {"PGA-ADC Mux Left", "MIC+preamp Left", "Mic Preamp Left" },
  220. {"PGA-ADC Mux Right", "AIN1 Right", "AIN1R" },
  221. {"PGA-ADC Mux Right", "AIN2 Right", "AIN2R" },
  222. {"PGA-ADC Mux Right", "MIC Right", "MICR" },
  223. {"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" },
  224. {"Left PGA", NULL, "PGA-ADC Mux Left"},
  225. {"Right PGA", NULL, "PGA-ADC Mux Right"},
  226. };
  227. static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
  228. unsigned int format)
  229. {
  230. struct snd_soc_codec *codec = codec_dai->codec;
  231. struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
  232. switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
  233. case SND_SOC_DAIFMT_I2S:
  234. case SND_SOC_DAIFMT_LEFT_J:
  235. case SND_SOC_DAIFMT_RIGHT_J:
  236. cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
  237. break;
  238. default:
  239. dev_err(codec->dev, "invalid DAI format\n");
  240. return -EINVAL;
  241. }
  242. switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
  243. case SND_SOC_DAIFMT_CBM_CFM:
  244. cs42l51->func = MODE_MASTER;
  245. break;
  246. case SND_SOC_DAIFMT_CBS_CFS:
  247. cs42l51->func = MODE_SLAVE_AUTO;
  248. break;
  249. default:
  250. dev_err(codec->dev, "Unknown master/slave configuration\n");
  251. return -EINVAL;
  252. }
  253. return 0;
  254. }
  255. struct cs42l51_ratios {
  256. unsigned int ratio;
  257. unsigned char speed_mode;
  258. unsigned char mclk;
  259. };
  260. static struct cs42l51_ratios slave_ratios[] = {
  261. { 512, CS42L51_QSM_MODE, 0 }, { 768, CS42L51_QSM_MODE, 0 },
  262. { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
  263. { 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 },
  264. { 256, CS42L51_HSM_MODE, 0 }, { 384, CS42L51_HSM_MODE, 0 },
  265. { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
  266. { 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 },
  267. { 128, CS42L51_SSM_MODE, 0 }, { 192, CS42L51_SSM_MODE, 0 },
  268. { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
  269. { 512, CS42L51_SSM_MODE, 0 }, { 768, CS42L51_SSM_MODE, 0 },
  270. { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
  271. { 256, CS42L51_DSM_MODE, 0 }, { 384, CS42L51_DSM_MODE, 0 },
  272. };
  273. static struct cs42l51_ratios slave_auto_ratios[] = {
  274. { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
  275. { 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 },
  276. { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
  277. { 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 },
  278. { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
  279. { 512, CS42L51_SSM_MODE, 1 }, { 768, CS42L51_SSM_MODE, 1 },
  280. { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
  281. { 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 },
  282. };
  283. static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
  284. int clk_id, unsigned int freq, int dir)
  285. {
  286. struct snd_soc_codec *codec = codec_dai->codec;
  287. struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
  288. cs42l51->mclk = freq;
  289. return 0;
  290. }
  291. static int cs42l51_hw_params(struct snd_pcm_substream *substream,
  292. struct snd_pcm_hw_params *params,
  293. struct snd_soc_dai *dai)
  294. {
  295. struct snd_soc_codec *codec = dai->codec;
  296. struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
  297. int ret;
  298. unsigned int i;
  299. unsigned int rate;
  300. unsigned int ratio;
  301. struct cs42l51_ratios *ratios = NULL;
  302. int nr_ratios = 0;
  303. int intf_ctl, power_ctl, fmt;
  304. switch (cs42l51->func) {
  305. case MODE_MASTER:
  306. return -EINVAL;
  307. case MODE_SLAVE:
  308. ratios = slave_ratios;
  309. nr_ratios = ARRAY_SIZE(slave_ratios);
  310. break;
  311. case MODE_SLAVE_AUTO:
  312. ratios = slave_auto_ratios;
  313. nr_ratios = ARRAY_SIZE(slave_auto_ratios);
  314. break;
  315. }
  316. /* Figure out which MCLK/LRCK ratio to use */
  317. rate = params_rate(params); /* Sampling rate, in Hz */
  318. ratio = cs42l51->mclk / rate; /* MCLK/LRCK ratio */
  319. for (i = 0; i < nr_ratios; i++) {
  320. if (ratios[i].ratio == ratio)
  321. break;
  322. }
  323. if (i == nr_ratios) {
  324. /* We did not find a matching ratio */
  325. dev_err(codec->dev, "could not find matching ratio\n");
  326. return -EINVAL;
  327. }
  328. intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL);
  329. power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL);
  330. intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
  331. | CS42L51_INTF_CTL_DAC_FORMAT(7));
  332. power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
  333. | CS42L51_MIC_POWER_CTL_MCLK_DIV2);
  334. switch (cs42l51->func) {
  335. case MODE_MASTER:
  336. intf_ctl |= CS42L51_INTF_CTL_MASTER;
  337. power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
  338. break;
  339. case MODE_SLAVE:
  340. power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
  341. break;
  342. case MODE_SLAVE_AUTO:
  343. power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
  344. break;
  345. }
  346. switch (cs42l51->audio_mode) {
  347. case SND_SOC_DAIFMT_I2S:
  348. intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
  349. intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
  350. break;
  351. case SND_SOC_DAIFMT_LEFT_J:
  352. intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
  353. break;
  354. case SND_SOC_DAIFMT_RIGHT_J:
  355. switch (params_width(params)) {
  356. case 16:
  357. fmt = CS42L51_DAC_DIF_RJ16;
  358. break;
  359. case 18:
  360. fmt = CS42L51_DAC_DIF_RJ18;
  361. break;
  362. case 20:
  363. fmt = CS42L51_DAC_DIF_RJ20;
  364. break;
  365. case 24:
  366. fmt = CS42L51_DAC_DIF_RJ24;
  367. break;
  368. default:
  369. dev_err(codec->dev, "unknown format\n");
  370. return -EINVAL;
  371. }
  372. intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
  373. break;
  374. default:
  375. dev_err(codec->dev, "unknown format\n");
  376. return -EINVAL;
  377. }
  378. if (ratios[i].mclk)
  379. power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
  380. ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl);
  381. if (ret < 0)
  382. return ret;
  383. ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl);
  384. if (ret < 0)
  385. return ret;
  386. return 0;
  387. }
  388. static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
  389. {
  390. struct snd_soc_codec *codec = dai->codec;
  391. int reg;
  392. int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
  393. reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL);
  394. if (mute)
  395. reg |= mask;
  396. else
  397. reg &= ~mask;
  398. return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg);
  399. }
  400. static const struct snd_soc_dai_ops cs42l51_dai_ops = {
  401. .hw_params = cs42l51_hw_params,
  402. .set_sysclk = cs42l51_set_dai_sysclk,
  403. .set_fmt = cs42l51_set_dai_fmt,
  404. .digital_mute = cs42l51_dai_mute,
  405. };
  406. static struct snd_soc_dai_driver cs42l51_dai = {
  407. .name = "cs42l51-hifi",
  408. .playback = {
  409. .stream_name = "Playback",
  410. .channels_min = 1,
  411. .channels_max = 2,
  412. .rates = SNDRV_PCM_RATE_8000_96000,
  413. .formats = CS42L51_FORMATS,
  414. },
  415. .capture = {
  416. .stream_name = "Capture",
  417. .channels_min = 1,
  418. .channels_max = 2,
  419. .rates = SNDRV_PCM_RATE_8000_96000,
  420. .formats = CS42L51_FORMATS,
  421. },
  422. .ops = &cs42l51_dai_ops,
  423. };
  424. static int cs42l51_codec_probe(struct snd_soc_codec *codec)
  425. {
  426. int ret, reg;
  427. /*
  428. * DAC configuration
  429. * - Use signal processor
  430. * - auto mute
  431. * - vol changes immediate
  432. * - no de-emphasize
  433. */
  434. reg = CS42L51_DAC_CTL_DATA_SEL(1)
  435. | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
  436. ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
  437. if (ret < 0)
  438. return ret;
  439. return 0;
  440. }
  441. static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
  442. .probe = cs42l51_codec_probe,
  443. .controls = cs42l51_snd_controls,
  444. .num_controls = ARRAY_SIZE(cs42l51_snd_controls),
  445. .dapm_widgets = cs42l51_dapm_widgets,
  446. .num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets),
  447. .dapm_routes = cs42l51_routes,
  448. .num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
  449. };
  450. const struct regmap_config cs42l51_regmap = {
  451. .max_register = CS42L51_CHARGE_FREQ,
  452. .cache_type = REGCACHE_RBTREE,
  453. };
  454. EXPORT_SYMBOL_GPL(cs42l51_regmap);
  455. int cs42l51_probe(struct device *dev, struct regmap *regmap)
  456. {
  457. struct cs42l51_private *cs42l51;
  458. unsigned int val;
  459. int ret;
  460. if (IS_ERR(regmap))
  461. return PTR_ERR(regmap);
  462. cs42l51 = devm_kzalloc(dev, sizeof(struct cs42l51_private),
  463. GFP_KERNEL);
  464. if (!cs42l51)
  465. return -ENOMEM;
  466. dev_set_drvdata(dev, cs42l51);
  467. /* Verify that we have a CS42L51 */
  468. ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
  469. if (ret < 0) {
  470. dev_err(dev, "failed to read I2C\n");
  471. goto error;
  472. }
  473. if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
  474. (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
  475. dev_err(dev, "Invalid chip id: %x\n", val);
  476. ret = -ENODEV;
  477. goto error;
  478. }
  479. dev_info(dev, "Cirrus Logic CS42L51, Revision: %02X\n",
  480. val & CS42L51_CHIP_REV_MASK);
  481. ret = snd_soc_register_codec(dev,
  482. &soc_codec_device_cs42l51, &cs42l51_dai, 1);
  483. error:
  484. return ret;
  485. }
  486. EXPORT_SYMBOL_GPL(cs42l51_probe);
  487. const struct of_device_id cs42l51_of_match[] = {
  488. { .compatible = "cirrus,cs42l51", },
  489. { }
  490. };
  491. MODULE_DEVICE_TABLE(of, cs42l51_of_match);
  492. EXPORT_SYMBOL_GPL(cs42l51_of_match);
  493. MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
  494. MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
  495. MODULE_LICENSE("GPL");