cs42xx8.c 17 KB

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