cs4265.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /*
  2. * cs4265.c -- CS4265 ALSA SoC audio driver
  3. *
  4. * Copyright 2014 Cirrus Logic, Inc.
  5. *
  6. * Author: Paul Handrigan <paul.handrigan@cirrus.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. *
  12. */
  13. #include <linux/module.h>
  14. #include <linux/moduleparam.h>
  15. #include <linux/kernel.h>
  16. #include <linux/gpio/consumer.h>
  17. #include <linux/init.h>
  18. #include <linux/delay.h>
  19. #include <linux/i2c.h>
  20. #include <linux/input.h>
  21. #include <linux/regmap.h>
  22. #include <linux/slab.h>
  23. #include <linux/platform_device.h>
  24. #include <sound/core.h>
  25. #include <sound/pcm.h>
  26. #include <sound/pcm_params.h>
  27. #include <sound/soc.h>
  28. #include <sound/soc-dapm.h>
  29. #include <sound/initval.h>
  30. #include <sound/tlv.h>
  31. #include "cs4265.h"
  32. struct cs4265_private {
  33. struct regmap *regmap;
  34. struct gpio_desc *reset_gpio;
  35. u8 format;
  36. u32 sysclk;
  37. };
  38. static const struct reg_default cs4265_reg_defaults[] = {
  39. { CS4265_PWRCTL, 0x0F },
  40. { CS4265_DAC_CTL, 0x08 },
  41. { CS4265_ADC_CTL, 0x00 },
  42. { CS4265_MCLK_FREQ, 0x00 },
  43. { CS4265_SIG_SEL, 0x40 },
  44. { CS4265_CHB_PGA_CTL, 0x00 },
  45. { CS4265_CHA_PGA_CTL, 0x00 },
  46. { CS4265_ADC_CTL2, 0x19 },
  47. { CS4265_DAC_CHA_VOL, 0x00 },
  48. { CS4265_DAC_CHB_VOL, 0x00 },
  49. { CS4265_DAC_CTL2, 0xC0 },
  50. { CS4265_SPDIF_CTL1, 0x00 },
  51. { CS4265_SPDIF_CTL2, 0x00 },
  52. { CS4265_INT_MASK, 0x00 },
  53. { CS4265_STATUS_MODE_MSB, 0x00 },
  54. { CS4265_STATUS_MODE_LSB, 0x00 },
  55. };
  56. static bool cs4265_readable_register(struct device *dev, unsigned int reg)
  57. {
  58. switch (reg) {
  59. case CS4265_CHIP_ID ... CS4265_SPDIF_CTL2:
  60. return true;
  61. default:
  62. return false;
  63. }
  64. }
  65. static bool cs4265_volatile_register(struct device *dev, unsigned int reg)
  66. {
  67. switch (reg) {
  68. case CS4265_INT_STATUS:
  69. return true;
  70. default:
  71. return false;
  72. }
  73. }
  74. static DECLARE_TLV_DB_SCALE(pga_tlv, -1200, 50, 0);
  75. static DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 0);
  76. static const char * const digital_input_mux_text[] = {
  77. "SDIN1", "SDIN2"
  78. };
  79. static SOC_ENUM_SINGLE_DECL(digital_input_mux_enum, CS4265_SIG_SEL, 7,
  80. digital_input_mux_text);
  81. static const struct snd_kcontrol_new digital_input_mux =
  82. SOC_DAPM_ENUM("Digital Input Mux", digital_input_mux_enum);
  83. static const char * const mic_linein_text[] = {
  84. "MIC", "LINEIN"
  85. };
  86. static SOC_ENUM_SINGLE_DECL(mic_linein_enum, CS4265_ADC_CTL2, 0,
  87. mic_linein_text);
  88. static const char * const cam_mode_text[] = {
  89. "One Byte", "Two Byte"
  90. };
  91. static SOC_ENUM_SINGLE_DECL(cam_mode_enum, CS4265_SPDIF_CTL1, 5,
  92. cam_mode_text);
  93. static const char * const cam_mono_stereo_text[] = {
  94. "Stereo", "Mono"
  95. };
  96. static SOC_ENUM_SINGLE_DECL(spdif_mono_stereo_enum, CS4265_SPDIF_CTL2, 2,
  97. cam_mono_stereo_text);
  98. static const char * const mono_select_text[] = {
  99. "Channel A", "Channel B"
  100. };
  101. static SOC_ENUM_SINGLE_DECL(spdif_mono_select_enum, CS4265_SPDIF_CTL2, 0,
  102. mono_select_text);
  103. static const struct snd_kcontrol_new mic_linein_mux =
  104. SOC_DAPM_ENUM("ADC Input Capture Mux", mic_linein_enum);
  105. static const struct snd_kcontrol_new loopback_ctl =
  106. SOC_DAPM_SINGLE("Switch", CS4265_SIG_SEL, 1, 1, 0);
  107. static const struct snd_kcontrol_new spdif_switch =
  108. SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 0, 0);
  109. static const struct snd_kcontrol_new dac_switch =
  110. SOC_DAPM_SINGLE("Switch", CS4265_PWRCTL, 1, 1, 0);
  111. static const struct snd_kcontrol_new cs4265_snd_controls[] = {
  112. SOC_DOUBLE_R_SX_TLV("PGA Volume", CS4265_CHA_PGA_CTL,
  113. CS4265_CHB_PGA_CTL, 0, 0x28, 0x30, pga_tlv),
  114. SOC_DOUBLE_R_TLV("DAC Volume", CS4265_DAC_CHA_VOL,
  115. CS4265_DAC_CHB_VOL, 0, 0xFF, 1, dac_tlv),
  116. SOC_SINGLE("De-emp 44.1kHz Switch", CS4265_DAC_CTL, 1,
  117. 1, 0),
  118. SOC_SINGLE("DAC INV Switch", CS4265_DAC_CTL2, 5,
  119. 1, 0),
  120. SOC_SINGLE("DAC Zero Cross Switch", CS4265_DAC_CTL2, 6,
  121. 1, 0),
  122. SOC_SINGLE("DAC Soft Ramp Switch", CS4265_DAC_CTL2, 7,
  123. 1, 0),
  124. SOC_SINGLE("ADC HPF Switch", CS4265_ADC_CTL, 1,
  125. 1, 0),
  126. SOC_SINGLE("ADC Zero Cross Switch", CS4265_ADC_CTL2, 3,
  127. 1, 1),
  128. SOC_SINGLE("ADC Soft Ramp Switch", CS4265_ADC_CTL2, 7,
  129. 1, 0),
  130. SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1,
  131. 6, 1, 0),
  132. SOC_ENUM("C Data Access", cam_mode_enum),
  133. SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2,
  134. 3, 1, 0),
  135. SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum),
  136. SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2,
  137. 0, 1, 0),
  138. SOC_ENUM("Mono Channel Select", spdif_mono_select_enum),
  139. SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24),
  140. };
  141. static const struct snd_soc_dapm_widget cs4265_dapm_widgets[] = {
  142. SND_SOC_DAPM_INPUT("LINEINL"),
  143. SND_SOC_DAPM_INPUT("LINEINR"),
  144. SND_SOC_DAPM_INPUT("MICL"),
  145. SND_SOC_DAPM_INPUT("MICR"),
  146. SND_SOC_DAPM_AIF_OUT("DOUT", NULL, 0,
  147. SND_SOC_NOPM, 0, 0),
  148. SND_SOC_DAPM_AIF_OUT("SPDIFOUT", NULL, 0,
  149. SND_SOC_NOPM, 0, 0),
  150. SND_SOC_DAPM_MUX("ADC Mux", SND_SOC_NOPM, 0, 0, &mic_linein_mux),
  151. SND_SOC_DAPM_ADC("ADC", NULL, CS4265_PWRCTL, 2, 1),
  152. SND_SOC_DAPM_PGA("Pre-amp MIC", CS4265_PWRCTL, 3,
  153. 1, NULL, 0),
  154. SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM,
  155. 0, 0, &digital_input_mux),
  156. SND_SOC_DAPM_MIXER("SDIN1 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
  157. SND_SOC_DAPM_MIXER("SDIN2 Input Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
  158. SND_SOC_DAPM_MIXER("SPDIF Transmitter", SND_SOC_NOPM, 0, 0, NULL, 0),
  159. SND_SOC_DAPM_SWITCH("Loopback", SND_SOC_NOPM, 0, 0,
  160. &loopback_ctl),
  161. SND_SOC_DAPM_SWITCH("SPDIF", SND_SOC_NOPM, 0, 0,
  162. &spdif_switch),
  163. SND_SOC_DAPM_SWITCH("DAC", CS4265_PWRCTL, 1, 1,
  164. &dac_switch),
  165. SND_SOC_DAPM_AIF_IN("DIN1", NULL, 0,
  166. SND_SOC_NOPM, 0, 0),
  167. SND_SOC_DAPM_AIF_IN("DIN2", NULL, 0,
  168. SND_SOC_NOPM, 0, 0),
  169. SND_SOC_DAPM_AIF_IN("TXIN", NULL, 0,
  170. CS4265_SPDIF_CTL2, 5, 1),
  171. SND_SOC_DAPM_OUTPUT("LINEOUTL"),
  172. SND_SOC_DAPM_OUTPUT("LINEOUTR"),
  173. };
  174. static const struct snd_soc_dapm_route cs4265_audio_map[] = {
  175. {"DIN1", NULL, "DAI1 Playback"},
  176. {"DIN2", NULL, "DAI2 Playback"},
  177. {"SDIN1 Input Mixer", NULL, "DIN1"},
  178. {"SDIN2 Input Mixer", NULL, "DIN2"},
  179. {"Input Mux", "SDIN1", "SDIN1 Input Mixer"},
  180. {"Input Mux", "SDIN2", "SDIN2 Input Mixer"},
  181. {"DAC", "Switch", "Input Mux"},
  182. {"SPDIF", "Switch", "Input Mux"},
  183. {"LINEOUTL", NULL, "DAC"},
  184. {"LINEOUTR", NULL, "DAC"},
  185. {"SPDIFOUT", NULL, "SPDIF"},
  186. {"ADC Mux", "LINEIN", "LINEINL"},
  187. {"ADC Mux", "LINEIN", "LINEINR"},
  188. {"ADC Mux", "MIC", "MICL"},
  189. {"ADC Mux", "MIC", "MICR"},
  190. {"ADC", NULL, "ADC Mux"},
  191. {"DOUT", NULL, "ADC"},
  192. {"DAI1 Capture", NULL, "DOUT"},
  193. {"DAI2 Capture", NULL, "DOUT"},
  194. /* Loopback */
  195. {"Loopback", "Switch", "ADC"},
  196. {"DAC", NULL, "Loopback"},
  197. };
  198. struct cs4265_clk_para {
  199. u32 mclk;
  200. u32 rate;
  201. u8 fm_mode; /* values 1, 2, or 4 */
  202. u8 mclkdiv;
  203. };
  204. static const struct cs4265_clk_para clk_map_table[] = {
  205. /*32k*/
  206. {8192000, 32000, 0, 0},
  207. {12288000, 32000, 0, 1},
  208. {16384000, 32000, 0, 2},
  209. {24576000, 32000, 0, 3},
  210. {32768000, 32000, 0, 4},
  211. /*44.1k*/
  212. {11289600, 44100, 0, 0},
  213. {16934400, 44100, 0, 1},
  214. {22579200, 44100, 0, 2},
  215. {33868000, 44100, 0, 3},
  216. {45158400, 44100, 0, 4},
  217. /*48k*/
  218. {12288000, 48000, 0, 0},
  219. {18432000, 48000, 0, 1},
  220. {24576000, 48000, 0, 2},
  221. {36864000, 48000, 0, 3},
  222. {49152000, 48000, 0, 4},
  223. /*64k*/
  224. {8192000, 64000, 1, 0},
  225. {12288000, 64000, 1, 1},
  226. {16934400, 64000, 1, 2},
  227. {24576000, 64000, 1, 3},
  228. {32768000, 64000, 1, 4},
  229. /* 88.2k */
  230. {11289600, 88200, 1, 0},
  231. {16934400, 88200, 1, 1},
  232. {22579200, 88200, 1, 2},
  233. {33868000, 88200, 1, 3},
  234. {45158400, 88200, 1, 4},
  235. /* 96k */
  236. {12288000, 96000, 1, 0},
  237. {18432000, 96000, 1, 1},
  238. {24576000, 96000, 1, 2},
  239. {36864000, 96000, 1, 3},
  240. {49152000, 96000, 1, 4},
  241. /* 128k */
  242. {8192000, 128000, 2, 0},
  243. {12288000, 128000, 2, 1},
  244. {16934400, 128000, 2, 2},
  245. {24576000, 128000, 2, 3},
  246. {32768000, 128000, 2, 4},
  247. /* 176.4k */
  248. {11289600, 176400, 2, 0},
  249. {16934400, 176400, 2, 1},
  250. {22579200, 176400, 2, 2},
  251. {33868000, 176400, 2, 3},
  252. {49152000, 176400, 2, 4},
  253. /* 192k */
  254. {12288000, 192000, 2, 0},
  255. {18432000, 192000, 2, 1},
  256. {24576000, 192000, 2, 2},
  257. {36864000, 192000, 2, 3},
  258. {49152000, 192000, 2, 4},
  259. };
  260. static int cs4265_get_clk_index(int mclk, int rate)
  261. {
  262. int i;
  263. for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
  264. if (clk_map_table[i].rate == rate &&
  265. clk_map_table[i].mclk == mclk)
  266. return i;
  267. }
  268. return -EINVAL;
  269. }
  270. static int cs4265_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
  271. unsigned int freq, int dir)
  272. {
  273. struct snd_soc_codec *codec = codec_dai->codec;
  274. struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
  275. int i;
  276. if (clk_id != 0) {
  277. dev_err(codec->dev, "Invalid clk_id %d\n", clk_id);
  278. return -EINVAL;
  279. }
  280. for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
  281. if (clk_map_table[i].mclk == freq) {
  282. cs4265->sysclk = freq;
  283. return 0;
  284. }
  285. }
  286. cs4265->sysclk = 0;
  287. dev_err(codec->dev, "Invalid freq parameter %d\n", freq);
  288. return -EINVAL;
  289. }
  290. static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
  291. {
  292. struct snd_soc_codec *codec = codec_dai->codec;
  293. struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
  294. u8 iface = 0;
  295. switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
  296. case SND_SOC_DAIFMT_CBM_CFM:
  297. snd_soc_update_bits(codec, CS4265_ADC_CTL,
  298. CS4265_ADC_MASTER,
  299. CS4265_ADC_MASTER);
  300. break;
  301. case SND_SOC_DAIFMT_CBS_CFS:
  302. snd_soc_update_bits(codec, CS4265_ADC_CTL,
  303. CS4265_ADC_MASTER,
  304. 0);
  305. break;
  306. default:
  307. return -EINVAL;
  308. }
  309. /* interface format */
  310. switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  311. case SND_SOC_DAIFMT_I2S:
  312. iface |= SND_SOC_DAIFMT_I2S;
  313. break;
  314. case SND_SOC_DAIFMT_RIGHT_J:
  315. iface |= SND_SOC_DAIFMT_RIGHT_J;
  316. break;
  317. case SND_SOC_DAIFMT_LEFT_J:
  318. iface |= SND_SOC_DAIFMT_LEFT_J;
  319. break;
  320. default:
  321. return -EINVAL;
  322. }
  323. cs4265->format = iface;
  324. return 0;
  325. }
  326. static int cs4265_digital_mute(struct snd_soc_dai *dai, int mute)
  327. {
  328. struct snd_soc_codec *codec = dai->codec;
  329. if (mute) {
  330. snd_soc_update_bits(codec, CS4265_DAC_CTL,
  331. CS4265_DAC_CTL_MUTE,
  332. CS4265_DAC_CTL_MUTE);
  333. snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
  334. CS4265_SPDIF_CTL2_MUTE,
  335. CS4265_SPDIF_CTL2_MUTE);
  336. } else {
  337. snd_soc_update_bits(codec, CS4265_DAC_CTL,
  338. CS4265_DAC_CTL_MUTE,
  339. 0);
  340. snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
  341. CS4265_SPDIF_CTL2_MUTE,
  342. 0);
  343. }
  344. return 0;
  345. }
  346. static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
  347. struct snd_pcm_hw_params *params,
  348. struct snd_soc_dai *dai)
  349. {
  350. struct snd_soc_codec *codec = dai->codec;
  351. struct cs4265_private *cs4265 = snd_soc_codec_get_drvdata(codec);
  352. int index;
  353. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
  354. ((cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK)
  355. == SND_SOC_DAIFMT_RIGHT_J))
  356. return -EINVAL;
  357. index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params));
  358. if (index >= 0) {
  359. snd_soc_update_bits(codec, CS4265_ADC_CTL,
  360. CS4265_ADC_FM, clk_map_table[index].fm_mode << 6);
  361. snd_soc_update_bits(codec, CS4265_MCLK_FREQ,
  362. CS4265_MCLK_FREQ_MASK,
  363. clk_map_table[index].mclkdiv << 4);
  364. } else {
  365. dev_err(codec->dev, "can't get correct mclk\n");
  366. return -EINVAL;
  367. }
  368. switch (cs4265->format & SND_SOC_DAIFMT_FORMAT_MASK) {
  369. case SND_SOC_DAIFMT_I2S:
  370. snd_soc_update_bits(codec, CS4265_DAC_CTL,
  371. CS4265_DAC_CTL_DIF, (1 << 4));
  372. snd_soc_update_bits(codec, CS4265_ADC_CTL,
  373. CS4265_ADC_DIF, (1 << 4));
  374. snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
  375. CS4265_SPDIF_CTL2_DIF, (1 << 6));
  376. break;
  377. case SND_SOC_DAIFMT_RIGHT_J:
  378. if (params_width(params) == 16) {
  379. snd_soc_update_bits(codec, CS4265_DAC_CTL,
  380. CS4265_DAC_CTL_DIF, (2 << 4));
  381. snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
  382. CS4265_SPDIF_CTL2_DIF, (2 << 6));
  383. } else {
  384. snd_soc_update_bits(codec, CS4265_DAC_CTL,
  385. CS4265_DAC_CTL_DIF, (3 << 4));
  386. snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
  387. CS4265_SPDIF_CTL2_DIF, (3 << 6));
  388. }
  389. break;
  390. case SND_SOC_DAIFMT_LEFT_J:
  391. snd_soc_update_bits(codec, CS4265_DAC_CTL,
  392. CS4265_DAC_CTL_DIF, 0);
  393. snd_soc_update_bits(codec, CS4265_ADC_CTL,
  394. CS4265_ADC_DIF, 0);
  395. snd_soc_update_bits(codec, CS4265_SPDIF_CTL2,
  396. CS4265_SPDIF_CTL2_DIF, 0);
  397. break;
  398. default:
  399. return -EINVAL;
  400. }
  401. return 0;
  402. }
  403. static int cs4265_set_bias_level(struct snd_soc_codec *codec,
  404. enum snd_soc_bias_level level)
  405. {
  406. switch (level) {
  407. case SND_SOC_BIAS_ON:
  408. break;
  409. case SND_SOC_BIAS_PREPARE:
  410. snd_soc_update_bits(codec, CS4265_PWRCTL,
  411. CS4265_PWRCTL_PDN, 0);
  412. break;
  413. case SND_SOC_BIAS_STANDBY:
  414. snd_soc_update_bits(codec, CS4265_PWRCTL,
  415. CS4265_PWRCTL_PDN,
  416. CS4265_PWRCTL_PDN);
  417. break;
  418. case SND_SOC_BIAS_OFF:
  419. snd_soc_update_bits(codec, CS4265_PWRCTL,
  420. CS4265_PWRCTL_PDN,
  421. CS4265_PWRCTL_PDN);
  422. break;
  423. }
  424. return 0;
  425. }
  426. #define CS4265_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
  427. SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
  428. SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
  429. SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
  430. #define CS4265_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
  431. SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
  432. static const struct snd_soc_dai_ops cs4265_ops = {
  433. .hw_params = cs4265_pcm_hw_params,
  434. .digital_mute = cs4265_digital_mute,
  435. .set_fmt = cs4265_set_fmt,
  436. .set_sysclk = cs4265_set_sysclk,
  437. };
  438. static struct snd_soc_dai_driver cs4265_dai[] = {
  439. {
  440. .name = "cs4265-dai1",
  441. .playback = {
  442. .stream_name = "DAI1 Playback",
  443. .channels_min = 1,
  444. .channels_max = 2,
  445. .rates = CS4265_RATES,
  446. .formats = CS4265_FORMATS,
  447. },
  448. .capture = {
  449. .stream_name = "DAI1 Capture",
  450. .channels_min = 1,
  451. .channels_max = 2,
  452. .rates = CS4265_RATES,
  453. .formats = CS4265_FORMATS,
  454. },
  455. .ops = &cs4265_ops,
  456. },
  457. {
  458. .name = "cs4265-dai2",
  459. .playback = {
  460. .stream_name = "DAI2 Playback",
  461. .channels_min = 1,
  462. .channels_max = 2,
  463. .rates = CS4265_RATES,
  464. .formats = CS4265_FORMATS,
  465. },
  466. .capture = {
  467. .stream_name = "DAI2 Capture",
  468. .channels_min = 1,
  469. .channels_max = 2,
  470. .rates = CS4265_RATES,
  471. .formats = CS4265_FORMATS,
  472. },
  473. .ops = &cs4265_ops,
  474. },
  475. };
  476. static const struct snd_soc_codec_driver soc_codec_cs4265 = {
  477. .set_bias_level = cs4265_set_bias_level,
  478. .dapm_widgets = cs4265_dapm_widgets,
  479. .num_dapm_widgets = ARRAY_SIZE(cs4265_dapm_widgets),
  480. .dapm_routes = cs4265_audio_map,
  481. .num_dapm_routes = ARRAY_SIZE(cs4265_audio_map),
  482. .controls = cs4265_snd_controls,
  483. .num_controls = ARRAY_SIZE(cs4265_snd_controls),
  484. };
  485. static const struct regmap_config cs4265_regmap = {
  486. .reg_bits = 8,
  487. .val_bits = 8,
  488. .max_register = CS4265_MAX_REGISTER,
  489. .reg_defaults = cs4265_reg_defaults,
  490. .num_reg_defaults = ARRAY_SIZE(cs4265_reg_defaults),
  491. .readable_reg = cs4265_readable_register,
  492. .volatile_reg = cs4265_volatile_register,
  493. .cache_type = REGCACHE_RBTREE,
  494. };
  495. static int cs4265_i2c_probe(struct i2c_client *i2c_client,
  496. const struct i2c_device_id *id)
  497. {
  498. struct cs4265_private *cs4265;
  499. int ret = 0;
  500. unsigned int devid = 0;
  501. unsigned int reg;
  502. cs4265 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4265_private),
  503. GFP_KERNEL);
  504. if (cs4265 == NULL)
  505. return -ENOMEM;
  506. cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap);
  507. if (IS_ERR(cs4265->regmap)) {
  508. ret = PTR_ERR(cs4265->regmap);
  509. dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
  510. return ret;
  511. }
  512. cs4265->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
  513. "reset", GPIOD_OUT_LOW);
  514. if (IS_ERR(cs4265->reset_gpio))
  515. return PTR_ERR(cs4265->reset_gpio);
  516. if (cs4265->reset_gpio) {
  517. mdelay(1);
  518. gpiod_set_value_cansleep(cs4265->reset_gpio, 1);
  519. }
  520. i2c_set_clientdata(i2c_client, cs4265);
  521. ret = regmap_read(cs4265->regmap, CS4265_CHIP_ID, &reg);
  522. devid = reg & CS4265_CHIP_ID_MASK;
  523. if (devid != CS4265_CHIP_ID_VAL) {
  524. ret = -ENODEV;
  525. dev_err(&i2c_client->dev,
  526. "CS4265 Device ID (%X). Expected %X\n",
  527. devid, CS4265_CHIP_ID);
  528. return ret;
  529. }
  530. dev_info(&i2c_client->dev,
  531. "CS4265 Version %x\n",
  532. reg & CS4265_REV_ID_MASK);
  533. regmap_write(cs4265->regmap, CS4265_PWRCTL, 0x0F);
  534. ret = snd_soc_register_codec(&i2c_client->dev,
  535. &soc_codec_cs4265, cs4265_dai,
  536. ARRAY_SIZE(cs4265_dai));
  537. return ret;
  538. }
  539. static int cs4265_i2c_remove(struct i2c_client *client)
  540. {
  541. snd_soc_unregister_codec(&client->dev);
  542. return 0;
  543. }
  544. static const struct of_device_id cs4265_of_match[] = {
  545. { .compatible = "cirrus,cs4265", },
  546. { }
  547. };
  548. MODULE_DEVICE_TABLE(of, cs4265_of_match);
  549. static const struct i2c_device_id cs4265_id[] = {
  550. { "cs4265", 0 },
  551. { }
  552. };
  553. MODULE_DEVICE_TABLE(i2c, cs4265_id);
  554. static struct i2c_driver cs4265_i2c_driver = {
  555. .driver = {
  556. .name = "cs4265",
  557. .of_match_table = cs4265_of_match,
  558. },
  559. .id_table = cs4265_id,
  560. .probe = cs4265_i2c_probe,
  561. .remove = cs4265_i2c_remove,
  562. };
  563. module_i2c_driver(cs4265_i2c_driver);
  564. MODULE_DESCRIPTION("ASoC CS4265 driver");
  565. MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paul.handrigan@cirrus.com>");
  566. MODULE_LICENSE("GPL");