cs42xx8.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. /*
  2. * Cirrus Logic CS42448/CS42888 Audio CODEC Digital Audio Interface (DAI) driver
  3. *
  4. * Copyright (C) 2014 Freescale Semiconductor, Inc.
  5. *
  6. * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
  7. *
  8. * This file is licensed under the terms of the GNU General Public License
  9. * version 2. This program is licensed "as is" without any warranty of any
  10. * kind, whether express or implied.
  11. */
  12. #include <linux/clk.h>
  13. #include <linux/delay.h>
  14. #include <linux/module.h>
  15. #include <linux/of_device.h>
  16. #include <linux/pm_runtime.h>
  17. #include <linux/regulator/consumer.h>
  18. #include <sound/pcm_params.h>
  19. #include <sound/soc.h>
  20. #include <sound/tlv.h>
  21. #include "cs42xx8.h"
  22. #define CS42XX8_NUM_SUPPLIES 4
  23. static const char *const cs42xx8_supply_names[CS42XX8_NUM_SUPPLIES] = {
  24. "VA",
  25. "VD",
  26. "VLS",
  27. "VLC",
  28. };
  29. #define CS42XX8_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
  30. SNDRV_PCM_FMTBIT_S20_3LE | \
  31. SNDRV_PCM_FMTBIT_S24_LE | \
  32. SNDRV_PCM_FMTBIT_S32_LE)
  33. /* codec private data */
  34. struct cs42xx8_priv {
  35. struct regulator_bulk_data supplies[CS42XX8_NUM_SUPPLIES];
  36. const struct cs42xx8_driver_data *drvdata;
  37. struct regmap *regmap;
  38. struct clk *clk;
  39. bool slave_mode;
  40. unsigned long sysclk;
  41. };
  42. /* -127.5dB to 0dB with step of 0.5dB */
  43. static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
  44. /* -64dB to 24dB with step of 0.5dB */
  45. static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
  46. static const char *const cs42xx8_adc_single[] = { "Differential", "Single-Ended" };
  47. static const char *const cs42xx8_szc[] = { "Immediate Change", "Zero Cross",
  48. "Soft Ramp", "Soft Ramp on Zero Cross" };
  49. static const struct soc_enum adc1_single_enum =
  50. SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 4, 2, cs42xx8_adc_single);
  51. static const struct soc_enum adc2_single_enum =
  52. SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 3, 2, cs42xx8_adc_single);
  53. static const struct soc_enum adc3_single_enum =
  54. SOC_ENUM_SINGLE(CS42XX8_ADCCTL, 2, 2, cs42xx8_adc_single);
  55. static const struct soc_enum dac_szc_enum =
  56. SOC_ENUM_SINGLE(CS42XX8_TXCTL, 5, 4, cs42xx8_szc);
  57. static const struct soc_enum adc_szc_enum =
  58. SOC_ENUM_SINGLE(CS42XX8_TXCTL, 0, 4, cs42xx8_szc);
  59. static const struct snd_kcontrol_new cs42xx8_snd_controls[] = {
  60. SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42XX8_VOLAOUT1,
  61. CS42XX8_VOLAOUT2, 0, 0xff, 1, dac_tlv),
  62. SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42XX8_VOLAOUT3,
  63. CS42XX8_VOLAOUT4, 0, 0xff, 1, dac_tlv),
  64. SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42XX8_VOLAOUT5,
  65. CS42XX8_VOLAOUT6, 0, 0xff, 1, dac_tlv),
  66. SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42XX8_VOLAOUT7,
  67. CS42XX8_VOLAOUT8, 0, 0xff, 1, dac_tlv),
  68. SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42XX8_VOLAIN1,
  69. CS42XX8_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
  70. SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42XX8_VOLAIN3,
  71. CS42XX8_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
  72. SOC_DOUBLE("DAC1 Invert Switch", CS42XX8_DACINV, 0, 1, 1, 0),
  73. SOC_DOUBLE("DAC2 Invert Switch", CS42XX8_DACINV, 2, 3, 1, 0),
  74. SOC_DOUBLE("DAC3 Invert Switch", CS42XX8_DACINV, 4, 5, 1, 0),
  75. SOC_DOUBLE("DAC4 Invert Switch", CS42XX8_DACINV, 6, 7, 1, 0),
  76. SOC_DOUBLE("ADC1 Invert Switch", CS42XX8_ADCINV, 0, 1, 1, 0),
  77. SOC_DOUBLE("ADC2 Invert Switch", CS42XX8_ADCINV, 2, 3, 1, 0),
  78. SOC_SINGLE("ADC High-Pass Filter Switch", CS42XX8_ADCCTL, 7, 1, 1),
  79. SOC_SINGLE("DAC De-emphasis Switch", CS42XX8_ADCCTL, 5, 1, 0),
  80. SOC_ENUM("ADC1 Single Ended Mode Switch", adc1_single_enum),
  81. SOC_ENUM("ADC2 Single Ended Mode Switch", adc2_single_enum),
  82. SOC_SINGLE("DAC Single Volume Control Switch", CS42XX8_TXCTL, 7, 1, 0),
  83. SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", dac_szc_enum),
  84. SOC_SINGLE("DAC Auto Mute Switch", CS42XX8_TXCTL, 4, 1, 0),
  85. SOC_SINGLE("Mute ADC Serial Port Switch", CS42XX8_TXCTL, 3, 1, 0),
  86. SOC_SINGLE("ADC Single Volume Control Switch", CS42XX8_TXCTL, 2, 1, 0),
  87. SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", adc_szc_enum),
  88. };
  89. static const struct snd_kcontrol_new cs42xx8_adc3_snd_controls[] = {
  90. SOC_DOUBLE_R_S_TLV("ADC3 Capture Volume", CS42XX8_VOLAIN5,
  91. CS42XX8_VOLAIN6, 0, -0x80, 0x30, 7, 0, adc_tlv),
  92. SOC_DOUBLE("ADC3 Invert Switch", CS42XX8_ADCINV, 4, 5, 1, 0),
  93. SOC_ENUM("ADC3 Single Ended Mode Switch", adc3_single_enum),
  94. };
  95. static const struct snd_soc_dapm_widget cs42xx8_dapm_widgets[] = {
  96. SND_SOC_DAPM_DAC("DAC1", "Playback", CS42XX8_PWRCTL, 1, 1),
  97. SND_SOC_DAPM_DAC("DAC2", "Playback", CS42XX8_PWRCTL, 2, 1),
  98. SND_SOC_DAPM_DAC("DAC3", "Playback", CS42XX8_PWRCTL, 3, 1),
  99. SND_SOC_DAPM_DAC("DAC4", "Playback", CS42XX8_PWRCTL, 4, 1),
  100. SND_SOC_DAPM_OUTPUT("AOUT1L"),
  101. SND_SOC_DAPM_OUTPUT("AOUT1R"),
  102. SND_SOC_DAPM_OUTPUT("AOUT2L"),
  103. SND_SOC_DAPM_OUTPUT("AOUT2R"),
  104. SND_SOC_DAPM_OUTPUT("AOUT3L"),
  105. SND_SOC_DAPM_OUTPUT("AOUT3R"),
  106. SND_SOC_DAPM_OUTPUT("AOUT4L"),
  107. SND_SOC_DAPM_OUTPUT("AOUT4R"),
  108. SND_SOC_DAPM_ADC("ADC1", "Capture", CS42XX8_PWRCTL, 5, 1),
  109. SND_SOC_DAPM_ADC("ADC2", "Capture", CS42XX8_PWRCTL, 6, 1),
  110. SND_SOC_DAPM_INPUT("AIN1L"),
  111. SND_SOC_DAPM_INPUT("AIN1R"),
  112. SND_SOC_DAPM_INPUT("AIN2L"),
  113. SND_SOC_DAPM_INPUT("AIN2R"),
  114. SND_SOC_DAPM_SUPPLY("PWR", CS42XX8_PWRCTL, 0, 1, NULL, 0),
  115. };
  116. static const struct snd_soc_dapm_widget cs42xx8_adc3_dapm_widgets[] = {
  117. SND_SOC_DAPM_ADC("ADC3", "Capture", CS42XX8_PWRCTL, 7, 1),
  118. SND_SOC_DAPM_INPUT("AIN3L"),
  119. SND_SOC_DAPM_INPUT("AIN3R"),
  120. };
  121. static const struct snd_soc_dapm_route cs42xx8_dapm_routes[] = {
  122. /* Playback */
  123. { "AOUT1L", NULL, "DAC1" },
  124. { "AOUT1R", NULL, "DAC1" },
  125. { "DAC1", NULL, "PWR" },
  126. { "AOUT2L", NULL, "DAC2" },
  127. { "AOUT2R", NULL, "DAC2" },
  128. { "DAC2", NULL, "PWR" },
  129. { "AOUT3L", NULL, "DAC3" },
  130. { "AOUT3R", NULL, "DAC3" },
  131. { "DAC3", NULL, "PWR" },
  132. { "AOUT4L", NULL, "DAC4" },
  133. { "AOUT4R", NULL, "DAC4" },
  134. { "DAC4", NULL, "PWR" },
  135. /* Capture */
  136. { "ADC1", NULL, "AIN1L" },
  137. { "ADC1", NULL, "AIN1R" },
  138. { "ADC1", NULL, "PWR" },
  139. { "ADC2", NULL, "AIN2L" },
  140. { "ADC2", NULL, "AIN2R" },
  141. { "ADC2", NULL, "PWR" },
  142. };
  143. static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = {
  144. /* Capture */
  145. { "ADC3", NULL, "AIN3L" },
  146. { "ADC3", NULL, "AIN3R" },
  147. { "ADC3", NULL, "PWR" },
  148. };
  149. struct cs42xx8_ratios {
  150. unsigned int ratio;
  151. unsigned char speed;
  152. unsigned char mclk;
  153. };
  154. static const struct cs42xx8_ratios cs42xx8_ratios[] = {
  155. { 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) },
  156. { 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) },
  157. { 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) },
  158. { 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) },
  159. { 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) },
  160. { 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) },
  161. { 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) },
  162. { 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) },
  163. { 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) }
  164. };
  165. static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai,
  166. int clk_id, unsigned int freq, int dir)
  167. {
  168. struct snd_soc_codec *codec = codec_dai->codec;
  169. struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
  170. cs42xx8->sysclk = freq;
  171. return 0;
  172. }
  173. static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
  174. unsigned int format)
  175. {
  176. struct snd_soc_codec *codec = codec_dai->codec;
  177. struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
  178. u32 val;
  179. /* Set DAI format */
  180. switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
  181. case SND_SOC_DAIFMT_LEFT_J:
  182. val = CS42XX8_INTF_DAC_DIF_LEFTJ | CS42XX8_INTF_ADC_DIF_LEFTJ;
  183. break;
  184. case SND_SOC_DAIFMT_I2S:
  185. val = CS42XX8_INTF_DAC_DIF_I2S | CS42XX8_INTF_ADC_DIF_I2S;
  186. break;
  187. case SND_SOC_DAIFMT_RIGHT_J:
  188. val = CS42XX8_INTF_DAC_DIF_RIGHTJ | CS42XX8_INTF_ADC_DIF_RIGHTJ;
  189. break;
  190. case SND_SOC_DAIFMT_DSP_A:
  191. val = CS42XX8_INTF_DAC_DIF_TDM | CS42XX8_INTF_ADC_DIF_TDM;
  192. break;
  193. default:
  194. dev_err(codec->dev, "unsupported dai format\n");
  195. return -EINVAL;
  196. }
  197. regmap_update_bits(cs42xx8->regmap, CS42XX8_INTF,
  198. CS42XX8_INTF_DAC_DIF_MASK |
  199. CS42XX8_INTF_ADC_DIF_MASK, val);
  200. /* Set master/slave audio interface */
  201. switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
  202. case SND_SOC_DAIFMT_CBS_CFS:
  203. cs42xx8->slave_mode = true;
  204. break;
  205. case SND_SOC_DAIFMT_CBM_CFM:
  206. cs42xx8->slave_mode = false;
  207. break;
  208. default:
  209. dev_err(codec->dev, "unsupported master/slave mode\n");
  210. return -EINVAL;
  211. }
  212. return 0;
  213. }
  214. static int cs42xx8_hw_params(struct snd_pcm_substream *substream,
  215. struct snd_pcm_hw_params *params,
  216. struct snd_soc_dai *dai)
  217. {
  218. struct snd_soc_codec *codec = dai->codec;
  219. struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
  220. bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
  221. u32 ratio = cs42xx8->sysclk / params_rate(params);
  222. u32 i, fm, val, mask;
  223. for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) {
  224. if (cs42xx8_ratios[i].ratio == ratio)
  225. break;
  226. }
  227. if (i == ARRAY_SIZE(cs42xx8_ratios)) {
  228. dev_err(codec->dev, "unsupported sysclk ratio\n");
  229. return -EINVAL;
  230. }
  231. mask = CS42XX8_FUNCMOD_MFREQ_MASK;
  232. val = cs42xx8_ratios[i].mclk;
  233. fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed;
  234. regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD,
  235. CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask,
  236. CS42XX8_FUNCMOD_xC_FM(tx, fm) | val);
  237. return 0;
  238. }
  239. static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute)
  240. {
  241. struct snd_soc_codec *codec = dai->codec;
  242. struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
  243. regmap_update_bits(cs42xx8->regmap, CS42XX8_DACMUTE,
  244. CS42XX8_DACMUTE_ALL, mute ? CS42XX8_DACMUTE_ALL : 0);
  245. return 0;
  246. }
  247. static const struct snd_soc_dai_ops cs42xx8_dai_ops = {
  248. .set_fmt = cs42xx8_set_dai_fmt,
  249. .set_sysclk = cs42xx8_set_dai_sysclk,
  250. .hw_params = cs42xx8_hw_params,
  251. .digital_mute = cs42xx8_digital_mute,
  252. };
  253. static struct snd_soc_dai_driver cs42xx8_dai = {
  254. .playback = {
  255. .stream_name = "Playback",
  256. .channels_min = 1,
  257. .channels_max = 8,
  258. .rates = SNDRV_PCM_RATE_8000_192000,
  259. .formats = CS42XX8_FORMATS,
  260. },
  261. .capture = {
  262. .stream_name = "Capture",
  263. .channels_min = 1,
  264. .rates = SNDRV_PCM_RATE_8000_192000,
  265. .formats = CS42XX8_FORMATS,
  266. },
  267. .ops = &cs42xx8_dai_ops,
  268. };
  269. static const struct reg_default cs42xx8_reg[] = {
  270. { 0x01, 0x01 }, /* Chip I.D. and Revision Register */
  271. { 0x02, 0x00 }, /* Power Control */
  272. { 0x03, 0xF0 }, /* Functional Mode */
  273. { 0x04, 0x46 }, /* Interface Formats */
  274. { 0x05, 0x00 }, /* ADC Control & DAC De-Emphasis */
  275. { 0x06, 0x10 }, /* Transition Control */
  276. { 0x07, 0x00 }, /* DAC Channel Mute */
  277. { 0x08, 0x00 }, /* Volume Control AOUT1 */
  278. { 0x09, 0x00 }, /* Volume Control AOUT2 */
  279. { 0x0a, 0x00 }, /* Volume Control AOUT3 */
  280. { 0x0b, 0x00 }, /* Volume Control AOUT4 */
  281. { 0x0c, 0x00 }, /* Volume Control AOUT5 */
  282. { 0x0d, 0x00 }, /* Volume Control AOUT6 */
  283. { 0x0e, 0x00 }, /* Volume Control AOUT7 */
  284. { 0x0f, 0x00 }, /* Volume Control AOUT8 */
  285. { 0x10, 0x00 }, /* DAC Channel Invert */
  286. { 0x11, 0x00 }, /* Volume Control AIN1 */
  287. { 0x12, 0x00 }, /* Volume Control AIN2 */
  288. { 0x13, 0x00 }, /* Volume Control AIN3 */
  289. { 0x14, 0x00 }, /* Volume Control AIN4 */
  290. { 0x15, 0x00 }, /* Volume Control AIN5 */
  291. { 0x16, 0x00 }, /* Volume Control AIN6 */
  292. { 0x17, 0x00 }, /* ADC Channel Invert */
  293. { 0x18, 0x00 }, /* Status Control */
  294. { 0x1a, 0x00 }, /* Status Mask */
  295. { 0x1b, 0x00 }, /* MUTEC Pin Control */
  296. };
  297. static bool cs42xx8_volatile_register(struct device *dev, unsigned int reg)
  298. {
  299. switch (reg) {
  300. case CS42XX8_STATUS:
  301. return true;
  302. default:
  303. return false;
  304. }
  305. }
  306. static bool cs42xx8_writeable_register(struct device *dev, unsigned int reg)
  307. {
  308. switch (reg) {
  309. case CS42XX8_CHIPID:
  310. case CS42XX8_STATUS:
  311. return false;
  312. default:
  313. return true;
  314. }
  315. }
  316. const struct regmap_config cs42xx8_regmap_config = {
  317. .reg_bits = 8,
  318. .val_bits = 8,
  319. .max_register = CS42XX8_LASTREG,
  320. .reg_defaults = cs42xx8_reg,
  321. .num_reg_defaults = ARRAY_SIZE(cs42xx8_reg),
  322. .volatile_reg = cs42xx8_volatile_register,
  323. .writeable_reg = cs42xx8_writeable_register,
  324. .cache_type = REGCACHE_RBTREE,
  325. };
  326. EXPORT_SYMBOL_GPL(cs42xx8_regmap_config);
  327. static int cs42xx8_codec_probe(struct snd_soc_codec *codec)
  328. {
  329. struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec);
  330. struct snd_soc_dapm_context *dapm = &codec->dapm;
  331. switch (cs42xx8->drvdata->num_adcs) {
  332. case 3:
  333. snd_soc_add_codec_controls(codec, cs42xx8_adc3_snd_controls,
  334. ARRAY_SIZE(cs42xx8_adc3_snd_controls));
  335. snd_soc_dapm_new_controls(dapm, cs42xx8_adc3_dapm_widgets,
  336. ARRAY_SIZE(cs42xx8_adc3_dapm_widgets));
  337. snd_soc_dapm_add_routes(dapm, cs42xx8_adc3_dapm_routes,
  338. ARRAY_SIZE(cs42xx8_adc3_dapm_routes));
  339. break;
  340. default:
  341. break;
  342. }
  343. /* Mute all DAC channels */
  344. regmap_write(cs42xx8->regmap, CS42XX8_DACMUTE, CS42XX8_DACMUTE_ALL);
  345. return 0;
  346. }
  347. static const struct snd_soc_codec_driver cs42xx8_driver = {
  348. .probe = cs42xx8_codec_probe,
  349. .idle_bias_off = true,
  350. .controls = cs42xx8_snd_controls,
  351. .num_controls = ARRAY_SIZE(cs42xx8_snd_controls),
  352. .dapm_widgets = cs42xx8_dapm_widgets,
  353. .num_dapm_widgets = ARRAY_SIZE(cs42xx8_dapm_widgets),
  354. .dapm_routes = cs42xx8_dapm_routes,
  355. .num_dapm_routes = ARRAY_SIZE(cs42xx8_dapm_routes),
  356. };
  357. const struct cs42xx8_driver_data cs42448_data = {
  358. .name = "cs42448",
  359. .num_adcs = 3,
  360. };
  361. EXPORT_SYMBOL_GPL(cs42448_data);
  362. const struct cs42xx8_driver_data cs42888_data = {
  363. .name = "cs42888",
  364. .num_adcs = 2,
  365. };
  366. EXPORT_SYMBOL_GPL(cs42888_data);
  367. static const struct of_device_id cs42xx8_of_match[] = {
  368. { .compatible = "cirrus,cs42448", .data = &cs42448_data, },
  369. { .compatible = "cirrus,cs42888", .data = &cs42888_data, },
  370. { /* sentinel */ }
  371. };
  372. MODULE_DEVICE_TABLE(of, cs42xx8_of_match);
  373. EXPORT_SYMBOL_GPL(cs42xx8_of_match);
  374. int cs42xx8_probe(struct device *dev, struct regmap *regmap)
  375. {
  376. const struct of_device_id *of_id = of_match_device(cs42xx8_of_match, dev);
  377. struct cs42xx8_priv *cs42xx8;
  378. int ret, val, i;
  379. cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL);
  380. if (cs42xx8 == NULL)
  381. return -ENOMEM;
  382. dev_set_drvdata(dev, cs42xx8);
  383. if (of_id)
  384. cs42xx8->drvdata = of_id->data;
  385. if (!cs42xx8->drvdata) {
  386. dev_err(dev, "failed to find driver data\n");
  387. return -EINVAL;
  388. }
  389. cs42xx8->clk = devm_clk_get(dev, "mclk");
  390. if (IS_ERR(cs42xx8->clk)) {
  391. dev_err(dev, "failed to get the clock: %ld\n",
  392. PTR_ERR(cs42xx8->clk));
  393. return -EINVAL;
  394. }
  395. cs42xx8->sysclk = clk_get_rate(cs42xx8->clk);
  396. for (i = 0; i < ARRAY_SIZE(cs42xx8->supplies); i++)
  397. cs42xx8->supplies[i].supply = cs42xx8_supply_names[i];
  398. ret = devm_regulator_bulk_get(dev,
  399. ARRAY_SIZE(cs42xx8->supplies), cs42xx8->supplies);
  400. if (ret) {
  401. dev_err(dev, "failed to request supplies: %d\n", ret);
  402. return ret;
  403. }
  404. ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
  405. cs42xx8->supplies);
  406. if (ret) {
  407. dev_err(dev, "failed to enable supplies: %d\n", ret);
  408. return ret;
  409. }
  410. /* Make sure hardware reset done */
  411. msleep(5);
  412. cs42xx8->regmap = regmap;
  413. if (IS_ERR(cs42xx8->regmap)) {
  414. ret = PTR_ERR(cs42xx8->regmap);
  415. dev_err(dev, "failed to allocate regmap: %d\n", ret);
  416. goto err_enable;
  417. }
  418. /*
  419. * We haven't marked the chip revision as volatile due to
  420. * sharing a register with the right input volume; explicitly
  421. * bypass the cache to read it.
  422. */
  423. regcache_cache_bypass(cs42xx8->regmap, true);
  424. /* Validate the chip ID */
  425. ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
  426. if (ret < 0) {
  427. dev_err(dev, "failed to get device ID, ret = %d", ret);
  428. goto err_enable;
  429. }
  430. /* The top four bits of the chip ID should be 0000 */
  431. if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) {
  432. dev_err(dev, "unmatched chip ID: %d\n",
  433. (val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4);
  434. ret = -EINVAL;
  435. goto err_enable;
  436. }
  437. dev_info(dev, "found device, revision %X\n",
  438. val & CS42XX8_CHIPID_REV_ID_MASK);
  439. regcache_cache_bypass(cs42xx8->regmap, false);
  440. cs42xx8_dai.name = cs42xx8->drvdata->name;
  441. /* Each adc supports stereo input */
  442. cs42xx8_dai.capture.channels_max = cs42xx8->drvdata->num_adcs * 2;
  443. ret = snd_soc_register_codec(dev, &cs42xx8_driver, &cs42xx8_dai, 1);
  444. if (ret) {
  445. dev_err(dev, "failed to register codec:%d\n", ret);
  446. goto err_enable;
  447. }
  448. regcache_cache_only(cs42xx8->regmap, true);
  449. err_enable:
  450. regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
  451. cs42xx8->supplies);
  452. return ret;
  453. }
  454. EXPORT_SYMBOL_GPL(cs42xx8_probe);
  455. #ifdef CONFIG_PM_RUNTIME
  456. static int cs42xx8_runtime_resume(struct device *dev)
  457. {
  458. struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
  459. int ret;
  460. ret = clk_prepare_enable(cs42xx8->clk);
  461. if (ret) {
  462. dev_err(dev, "failed to enable mclk: %d\n", ret);
  463. return ret;
  464. }
  465. ret = regulator_bulk_enable(ARRAY_SIZE(cs42xx8->supplies),
  466. cs42xx8->supplies);
  467. if (ret) {
  468. dev_err(dev, "failed to enable supplies: %d\n", ret);
  469. goto err_clk;
  470. }
  471. /* Make sure hardware reset done */
  472. msleep(5);
  473. regcache_cache_only(cs42xx8->regmap, false);
  474. ret = regcache_sync(cs42xx8->regmap);
  475. if (ret) {
  476. dev_err(dev, "failed to sync regmap: %d\n", ret);
  477. goto err_bulk;
  478. }
  479. return 0;
  480. err_bulk:
  481. regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
  482. cs42xx8->supplies);
  483. err_clk:
  484. clk_disable_unprepare(cs42xx8->clk);
  485. return ret;
  486. }
  487. static int cs42xx8_runtime_suspend(struct device *dev)
  488. {
  489. struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
  490. regcache_cache_only(cs42xx8->regmap, true);
  491. regulator_bulk_disable(ARRAY_SIZE(cs42xx8->supplies),
  492. cs42xx8->supplies);
  493. clk_disable_unprepare(cs42xx8->clk);
  494. return 0;
  495. }
  496. #endif
  497. const struct dev_pm_ops cs42xx8_pm = {
  498. SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
  499. };
  500. EXPORT_SYMBOL_GPL(cs42xx8_pm);
  501. MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
  502. MODULE_AUTHOR("Freescale Semiconductor, Inc.");
  503. MODULE_LICENSE("GPL");