wm8741.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /*
  2. * wm8741.c -- WM8741 ALSA SoC Audio driver
  3. *
  4. * Copyright 2010-1 Wolfson Microelectronics plc
  5. *
  6. * Author: Ian Lartey <ian@opensource.wolfsonmicro.com>
  7. *
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. */
  13. #include <linux/module.h>
  14. #include <linux/moduleparam.h>
  15. #include <linux/init.h>
  16. #include <linux/delay.h>
  17. #include <linux/pm.h>
  18. #include <linux/i2c.h>
  19. #include <linux/spi/spi.h>
  20. #include <linux/regmap.h>
  21. #include <linux/regulator/consumer.h>
  22. #include <linux/slab.h>
  23. #include <linux/of_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/initval.h>
  29. #include <sound/tlv.h>
  30. #include "wm8741.h"
  31. #define WM8741_NUM_SUPPLIES 2
  32. static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
  33. "AVDD",
  34. "DVDD",
  35. };
  36. #define WM8741_NUM_RATES 6
  37. /* codec private data */
  38. struct wm8741_priv {
  39. struct wm8741_platform_data pdata;
  40. struct regmap *regmap;
  41. struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
  42. unsigned int sysclk;
  43. const struct snd_pcm_hw_constraint_list *sysclk_constraints;
  44. };
  45. static const struct reg_default wm8741_reg_defaults[] = {
  46. { 0, 0x0000 }, /* R0 - DACLLSB Attenuation */
  47. { 1, 0x0000 }, /* R1 - DACLMSB Attenuation */
  48. { 2, 0x0000 }, /* R2 - DACRLSB Attenuation */
  49. { 3, 0x0000 }, /* R3 - DACRMSB Attenuation */
  50. { 4, 0x0000 }, /* R4 - Volume Control */
  51. { 5, 0x000A }, /* R5 - Format Control */
  52. { 6, 0x0000 }, /* R6 - Filter Control */
  53. { 7, 0x0000 }, /* R7 - Mode Control 1 */
  54. { 8, 0x0002 }, /* R8 - Mode Control 2 */
  55. { 32, 0x0002 }, /* R32 - ADDITONAL_CONTROL_1 */
  56. };
  57. static int wm8741_reset(struct snd_soc_codec *codec)
  58. {
  59. return snd_soc_write(codec, WM8741_RESET, 0);
  60. }
  61. static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0);
  62. static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0);
  63. static const struct snd_kcontrol_new wm8741_snd_controls_stereo[] = {
  64. SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
  65. WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine),
  66. SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
  67. WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv),
  68. };
  69. static const struct snd_kcontrol_new wm8741_snd_controls_mono_left[] = {
  70. SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
  71. 1, 255, 1, dac_tlv_fine),
  72. SOC_SINGLE_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
  73. 0, 511, 1, dac_tlv),
  74. };
  75. static const struct snd_kcontrol_new wm8741_snd_controls_mono_right[] = {
  76. SOC_SINGLE_TLV("Fine Playback Volume", WM8741_DACRLSB_ATTENUATION,
  77. 1, 255, 1, dac_tlv_fine),
  78. SOC_SINGLE_TLV("Playback Volume", WM8741_DACRMSB_ATTENUATION,
  79. 0, 511, 1, dac_tlv),
  80. };
  81. static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = {
  82. SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0),
  83. SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0),
  84. SND_SOC_DAPM_OUTPUT("VOUTLP"),
  85. SND_SOC_DAPM_OUTPUT("VOUTLN"),
  86. SND_SOC_DAPM_OUTPUT("VOUTRP"),
  87. SND_SOC_DAPM_OUTPUT("VOUTRN"),
  88. };
  89. static const struct snd_soc_dapm_route wm8741_dapm_routes[] = {
  90. { "VOUTLP", NULL, "DACL" },
  91. { "VOUTLN", NULL, "DACL" },
  92. { "VOUTRP", NULL, "DACR" },
  93. { "VOUTRN", NULL, "DACR" },
  94. };
  95. static const unsigned int rates_11289[] = {
  96. 44100, 88200,
  97. };
  98. static const struct snd_pcm_hw_constraint_list constraints_11289 = {
  99. .count = ARRAY_SIZE(rates_11289),
  100. .list = rates_11289,
  101. };
  102. static const unsigned int rates_12288[] = {
  103. 32000, 48000, 96000,
  104. };
  105. static const struct snd_pcm_hw_constraint_list constraints_12288 = {
  106. .count = ARRAY_SIZE(rates_12288),
  107. .list = rates_12288,
  108. };
  109. static const unsigned int rates_16384[] = {
  110. 32000,
  111. };
  112. static const struct snd_pcm_hw_constraint_list constraints_16384 = {
  113. .count = ARRAY_SIZE(rates_16384),
  114. .list = rates_16384,
  115. };
  116. static const unsigned int rates_16934[] = {
  117. 44100, 88200,
  118. };
  119. static const struct snd_pcm_hw_constraint_list constraints_16934 = {
  120. .count = ARRAY_SIZE(rates_16934),
  121. .list = rates_16934,
  122. };
  123. static const unsigned int rates_18432[] = {
  124. 48000, 96000,
  125. };
  126. static const struct snd_pcm_hw_constraint_list constraints_18432 = {
  127. .count = ARRAY_SIZE(rates_18432),
  128. .list = rates_18432,
  129. };
  130. static const unsigned int rates_22579[] = {
  131. 44100, 88200, 176400
  132. };
  133. static const struct snd_pcm_hw_constraint_list constraints_22579 = {
  134. .count = ARRAY_SIZE(rates_22579),
  135. .list = rates_22579,
  136. };
  137. static const unsigned int rates_24576[] = {
  138. 32000, 48000, 96000, 192000
  139. };
  140. static const struct snd_pcm_hw_constraint_list constraints_24576 = {
  141. .count = ARRAY_SIZE(rates_24576),
  142. .list = rates_24576,
  143. };
  144. static const unsigned int rates_36864[] = {
  145. 48000, 96000, 192000
  146. };
  147. static const struct snd_pcm_hw_constraint_list constraints_36864 = {
  148. .count = ARRAY_SIZE(rates_36864),
  149. .list = rates_36864,
  150. };
  151. static int wm8741_startup(struct snd_pcm_substream *substream,
  152. struct snd_soc_dai *dai)
  153. {
  154. struct snd_soc_codec *codec = dai->codec;
  155. struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
  156. if (wm8741->sysclk)
  157. snd_pcm_hw_constraint_list(substream->runtime, 0,
  158. SNDRV_PCM_HW_PARAM_RATE,
  159. wm8741->sysclk_constraints);
  160. return 0;
  161. }
  162. static int wm8741_hw_params(struct snd_pcm_substream *substream,
  163. struct snd_pcm_hw_params *params,
  164. struct snd_soc_dai *dai)
  165. {
  166. struct snd_soc_codec *codec = dai->codec;
  167. struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
  168. u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
  169. int i;
  170. /* The set of sample rates that can be supported depends on the
  171. * MCLK supplied to the CODEC - enforce this.
  172. */
  173. if (!wm8741->sysclk) {
  174. dev_err(codec->dev,
  175. "No MCLK configured, call set_sysclk() on init or in hw_params\n");
  176. return -EINVAL;
  177. }
  178. /* Find a supported LRCLK rate */
  179. for (i = 0; i < wm8741->sysclk_constraints->count; i++) {
  180. if (wm8741->sysclk_constraints->list[i] == params_rate(params))
  181. break;
  182. }
  183. if (i == wm8741->sysclk_constraints->count) {
  184. dev_err(codec->dev, "LRCLK %d unsupported with MCLK %d\n",
  185. params_rate(params), wm8741->sysclk);
  186. return -EINVAL;
  187. }
  188. /* bit size */
  189. switch (params_width(params)) {
  190. case 16:
  191. break;
  192. case 20:
  193. iface |= 0x0001;
  194. break;
  195. case 24:
  196. iface |= 0x0002;
  197. break;
  198. case 32:
  199. iface |= 0x0003;
  200. break;
  201. default:
  202. dev_dbg(codec->dev, "wm8741_hw_params: Unsupported bit size param = %d",
  203. params_width(params));
  204. return -EINVAL;
  205. }
  206. dev_dbg(codec->dev, "wm8741_hw_params: bit size param = %d, rate param = %d",
  207. params_width(params), params_rate(params));
  208. snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface);
  209. return 0;
  210. }
  211. static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
  212. int clk_id, unsigned int freq, int dir)
  213. {
  214. struct snd_soc_codec *codec = codec_dai->codec;
  215. struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
  216. dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq);
  217. switch (freq) {
  218. case 0:
  219. wm8741->sysclk_constraints = NULL;
  220. break;
  221. case 11289600:
  222. wm8741->sysclk_constraints = &constraints_11289;
  223. break;
  224. case 12288000:
  225. wm8741->sysclk_constraints = &constraints_12288;
  226. break;
  227. case 16384000:
  228. wm8741->sysclk_constraints = &constraints_16384;
  229. break;
  230. case 16934400:
  231. wm8741->sysclk_constraints = &constraints_16934;
  232. break;
  233. case 18432000:
  234. wm8741->sysclk_constraints = &constraints_18432;
  235. break;
  236. case 22579200:
  237. case 33868800:
  238. wm8741->sysclk_constraints = &constraints_22579;
  239. break;
  240. case 24576000:
  241. wm8741->sysclk_constraints = &constraints_24576;
  242. break;
  243. case 36864000:
  244. wm8741->sysclk_constraints = &constraints_36864;
  245. break;
  246. default:
  247. return -EINVAL;
  248. }
  249. wm8741->sysclk = freq;
  250. return 0;
  251. }
  252. static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
  253. unsigned int fmt)
  254. {
  255. struct snd_soc_codec *codec = codec_dai->codec;
  256. u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1C3;
  257. /* check master/slave audio interface */
  258. switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
  259. case SND_SOC_DAIFMT_CBS_CFS:
  260. break;
  261. default:
  262. return -EINVAL;
  263. }
  264. /* interface format */
  265. switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  266. case SND_SOC_DAIFMT_I2S:
  267. iface |= 0x0008;
  268. break;
  269. case SND_SOC_DAIFMT_RIGHT_J:
  270. break;
  271. case SND_SOC_DAIFMT_LEFT_J:
  272. iface |= 0x0004;
  273. break;
  274. case SND_SOC_DAIFMT_DSP_A:
  275. iface |= 0x000C;
  276. break;
  277. case SND_SOC_DAIFMT_DSP_B:
  278. iface |= 0x001C;
  279. break;
  280. default:
  281. return -EINVAL;
  282. }
  283. /* clock inversion */
  284. switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
  285. case SND_SOC_DAIFMT_NB_NF:
  286. break;
  287. case SND_SOC_DAIFMT_IB_IF:
  288. iface |= 0x0010;
  289. break;
  290. case SND_SOC_DAIFMT_IB_NF:
  291. iface |= 0x0020;
  292. break;
  293. case SND_SOC_DAIFMT_NB_IF:
  294. iface |= 0x0030;
  295. break;
  296. default:
  297. return -EINVAL;
  298. }
  299. dev_dbg(codec->dev, "wm8741_set_dai_fmt: Format=%x, Clock Inv=%x\n",
  300. fmt & SND_SOC_DAIFMT_FORMAT_MASK,
  301. ((fmt & SND_SOC_DAIFMT_INV_MASK)));
  302. snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface);
  303. return 0;
  304. }
  305. #define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
  306. SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
  307. SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
  308. SNDRV_PCM_RATE_192000)
  309. #define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
  310. SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
  311. static const struct snd_soc_dai_ops wm8741_dai_ops = {
  312. .startup = wm8741_startup,
  313. .hw_params = wm8741_hw_params,
  314. .set_sysclk = wm8741_set_dai_sysclk,
  315. .set_fmt = wm8741_set_dai_fmt,
  316. };
  317. static struct snd_soc_dai_driver wm8741_dai = {
  318. .name = "wm8741",
  319. .playback = {
  320. .stream_name = "Playback",
  321. .channels_min = 2,
  322. .channels_max = 2,
  323. .rates = WM8741_RATES,
  324. .formats = WM8741_FORMATS,
  325. },
  326. .ops = &wm8741_dai_ops,
  327. };
  328. #ifdef CONFIG_PM
  329. static int wm8741_resume(struct snd_soc_codec *codec)
  330. {
  331. snd_soc_cache_sync(codec);
  332. return 0;
  333. }
  334. #else
  335. #define wm8741_resume NULL
  336. #endif
  337. static int wm8741_configure(struct snd_soc_codec *codec)
  338. {
  339. struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
  340. /* Configure differential mode */
  341. switch (wm8741->pdata.diff_mode) {
  342. case WM8741_DIFF_MODE_STEREO:
  343. case WM8741_DIFF_MODE_STEREO_REVERSED:
  344. case WM8741_DIFF_MODE_MONO_LEFT:
  345. case WM8741_DIFF_MODE_MONO_RIGHT:
  346. snd_soc_update_bits(codec, WM8741_MODE_CONTROL_2,
  347. WM8741_DIFF_MASK,
  348. wm8741->pdata.diff_mode << WM8741_DIFF_SHIFT);
  349. break;
  350. default:
  351. return -EINVAL;
  352. }
  353. /* Change some default settings - latch VU */
  354. snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION,
  355. WM8741_UPDATELL, WM8741_UPDATELL);
  356. snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION,
  357. WM8741_UPDATELM, WM8741_UPDATELM);
  358. snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
  359. WM8741_UPDATERL, WM8741_UPDATERL);
  360. snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION,
  361. WM8741_UPDATERM, WM8741_UPDATERM);
  362. return 0;
  363. }
  364. static int wm8741_add_controls(struct snd_soc_codec *codec)
  365. {
  366. struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
  367. switch (wm8741->pdata.diff_mode) {
  368. case WM8741_DIFF_MODE_STEREO:
  369. case WM8741_DIFF_MODE_STEREO_REVERSED:
  370. snd_soc_add_codec_controls(codec,
  371. wm8741_snd_controls_stereo,
  372. ARRAY_SIZE(wm8741_snd_controls_stereo));
  373. break;
  374. case WM8741_DIFF_MODE_MONO_LEFT:
  375. snd_soc_add_codec_controls(codec,
  376. wm8741_snd_controls_mono_left,
  377. ARRAY_SIZE(wm8741_snd_controls_mono_left));
  378. break;
  379. case WM8741_DIFF_MODE_MONO_RIGHT:
  380. snd_soc_add_codec_controls(codec,
  381. wm8741_snd_controls_mono_right,
  382. ARRAY_SIZE(wm8741_snd_controls_mono_right));
  383. break;
  384. default:
  385. return -EINVAL;
  386. }
  387. return 0;
  388. }
  389. static int wm8741_probe(struct snd_soc_codec *codec)
  390. {
  391. struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
  392. int ret = 0;
  393. ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
  394. wm8741->supplies);
  395. if (ret != 0) {
  396. dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
  397. goto err_get;
  398. }
  399. ret = wm8741_reset(codec);
  400. if (ret < 0) {
  401. dev_err(codec->dev, "Failed to issue reset\n");
  402. goto err_enable;
  403. }
  404. ret = wm8741_configure(codec);
  405. if (ret < 0) {
  406. dev_err(codec->dev, "Failed to change default settings\n");
  407. goto err_enable;
  408. }
  409. ret = wm8741_add_controls(codec);
  410. if (ret < 0) {
  411. dev_err(codec->dev, "Failed to add controls\n");
  412. goto err_enable;
  413. }
  414. dev_dbg(codec->dev, "Successful registration\n");
  415. return ret;
  416. err_enable:
  417. regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
  418. err_get:
  419. return ret;
  420. }
  421. static int wm8741_remove(struct snd_soc_codec *codec)
  422. {
  423. struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
  424. regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
  425. return 0;
  426. }
  427. static const struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
  428. .probe = wm8741_probe,
  429. .remove = wm8741_remove,
  430. .resume = wm8741_resume,
  431. .component_driver = {
  432. .dapm_widgets = wm8741_dapm_widgets,
  433. .num_dapm_widgets = ARRAY_SIZE(wm8741_dapm_widgets),
  434. .dapm_routes = wm8741_dapm_routes,
  435. .num_dapm_routes = ARRAY_SIZE(wm8741_dapm_routes),
  436. },
  437. };
  438. static const struct of_device_id wm8741_of_match[] = {
  439. { .compatible = "wlf,wm8741", },
  440. { }
  441. };
  442. MODULE_DEVICE_TABLE(of, wm8741_of_match);
  443. static const struct regmap_config wm8741_regmap = {
  444. .reg_bits = 7,
  445. .val_bits = 9,
  446. .max_register = WM8741_MAX_REGISTER,
  447. .reg_defaults = wm8741_reg_defaults,
  448. .num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults),
  449. .cache_type = REGCACHE_RBTREE,
  450. };
  451. static int wm8741_set_pdata(struct device *dev, struct wm8741_priv *wm8741)
  452. {
  453. const struct wm8741_platform_data *pdata = dev_get_platdata(dev);
  454. u32 diff_mode;
  455. if (dev->of_node) {
  456. if (of_property_read_u32(dev->of_node, "diff-mode", &diff_mode)
  457. >= 0)
  458. wm8741->pdata.diff_mode = diff_mode;
  459. } else {
  460. if (pdata != NULL)
  461. memcpy(&wm8741->pdata, pdata, sizeof(wm8741->pdata));
  462. }
  463. return 0;
  464. }
  465. #if IS_ENABLED(CONFIG_I2C)
  466. static int wm8741_i2c_probe(struct i2c_client *i2c,
  467. const struct i2c_device_id *id)
  468. {
  469. struct wm8741_priv *wm8741;
  470. int ret, i;
  471. wm8741 = devm_kzalloc(&i2c->dev, sizeof(struct wm8741_priv),
  472. GFP_KERNEL);
  473. if (wm8741 == NULL)
  474. return -ENOMEM;
  475. for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
  476. wm8741->supplies[i].supply = wm8741_supply_names[i];
  477. ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies),
  478. wm8741->supplies);
  479. if (ret != 0) {
  480. dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
  481. return ret;
  482. }
  483. wm8741->regmap = devm_regmap_init_i2c(i2c, &wm8741_regmap);
  484. if (IS_ERR(wm8741->regmap)) {
  485. ret = PTR_ERR(wm8741->regmap);
  486. dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
  487. return ret;
  488. }
  489. ret = wm8741_set_pdata(&i2c->dev, wm8741);
  490. if (ret != 0) {
  491. dev_err(&i2c->dev, "Failed to set pdata: %d\n", ret);
  492. return ret;
  493. }
  494. i2c_set_clientdata(i2c, wm8741);
  495. ret = snd_soc_register_codec(&i2c->dev,
  496. &soc_codec_dev_wm8741, &wm8741_dai, 1);
  497. return ret;
  498. }
  499. static int wm8741_i2c_remove(struct i2c_client *client)
  500. {
  501. snd_soc_unregister_codec(&client->dev);
  502. return 0;
  503. }
  504. static const struct i2c_device_id wm8741_i2c_id[] = {
  505. { "wm8741", 0 },
  506. { }
  507. };
  508. MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
  509. static struct i2c_driver wm8741_i2c_driver = {
  510. .driver = {
  511. .name = "wm8741",
  512. .of_match_table = wm8741_of_match,
  513. },
  514. .probe = wm8741_i2c_probe,
  515. .remove = wm8741_i2c_remove,
  516. .id_table = wm8741_i2c_id,
  517. };
  518. #endif
  519. #if defined(CONFIG_SPI_MASTER)
  520. static int wm8741_spi_probe(struct spi_device *spi)
  521. {
  522. struct wm8741_priv *wm8741;
  523. int ret, i;
  524. wm8741 = devm_kzalloc(&spi->dev, sizeof(struct wm8741_priv),
  525. GFP_KERNEL);
  526. if (wm8741 == NULL)
  527. return -ENOMEM;
  528. for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
  529. wm8741->supplies[i].supply = wm8741_supply_names[i];
  530. ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8741->supplies),
  531. wm8741->supplies);
  532. if (ret != 0) {
  533. dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
  534. return ret;
  535. }
  536. wm8741->regmap = devm_regmap_init_spi(spi, &wm8741_regmap);
  537. if (IS_ERR(wm8741->regmap)) {
  538. ret = PTR_ERR(wm8741->regmap);
  539. dev_err(&spi->dev, "Failed to init regmap: %d\n", ret);
  540. return ret;
  541. }
  542. ret = wm8741_set_pdata(&spi->dev, wm8741);
  543. if (ret != 0) {
  544. dev_err(&spi->dev, "Failed to set pdata: %d\n", ret);
  545. return ret;
  546. }
  547. spi_set_drvdata(spi, wm8741);
  548. ret = snd_soc_register_codec(&spi->dev,
  549. &soc_codec_dev_wm8741, &wm8741_dai, 1);
  550. return ret;
  551. }
  552. static int wm8741_spi_remove(struct spi_device *spi)
  553. {
  554. snd_soc_unregister_codec(&spi->dev);
  555. return 0;
  556. }
  557. static struct spi_driver wm8741_spi_driver = {
  558. .driver = {
  559. .name = "wm8741",
  560. .of_match_table = wm8741_of_match,
  561. },
  562. .probe = wm8741_spi_probe,
  563. .remove = wm8741_spi_remove,
  564. };
  565. #endif /* CONFIG_SPI_MASTER */
  566. static int __init wm8741_modinit(void)
  567. {
  568. int ret = 0;
  569. #if IS_ENABLED(CONFIG_I2C)
  570. ret = i2c_add_driver(&wm8741_i2c_driver);
  571. if (ret != 0)
  572. pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
  573. #endif
  574. #if defined(CONFIG_SPI_MASTER)
  575. ret = spi_register_driver(&wm8741_spi_driver);
  576. if (ret != 0) {
  577. printk(KERN_ERR "Failed to register wm8741 SPI driver: %d\n",
  578. ret);
  579. }
  580. #endif
  581. return ret;
  582. }
  583. module_init(wm8741_modinit);
  584. static void __exit wm8741_exit(void)
  585. {
  586. #if defined(CONFIG_SPI_MASTER)
  587. spi_unregister_driver(&wm8741_spi_driver);
  588. #endif
  589. #if IS_ENABLED(CONFIG_I2C)
  590. i2c_del_driver(&wm8741_i2c_driver);
  591. #endif
  592. }
  593. module_exit(wm8741_exit);
  594. MODULE_DESCRIPTION("ASoC WM8741 driver");
  595. MODULE_AUTHOR("Ian Lartey <ian@opensource.wolfsonmicro.com>");
  596. MODULE_LICENSE("GPL");