tas5720.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * tas5720.c - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier
  4. *
  5. * Copyright (C)2015-2016 Texas Instruments Incorporated - https://www.ti.com
  6. *
  7. * Author: Andreas Dannenberg <dannenberg@ti.com>
  8. */
  9. #include <linux/module.h>
  10. #include <linux/errno.h>
  11. #include <linux/device.h>
  12. #include <linux/i2c.h>
  13. #include <linux/pm_runtime.h>
  14. #include <linux/regmap.h>
  15. #include <linux/slab.h>
  16. #include <linux/regulator/consumer.h>
  17. #include <linux/delay.h>
  18. #include <sound/pcm.h>
  19. #include <sound/pcm_params.h>
  20. #include <sound/soc.h>
  21. #include <sound/soc-dapm.h>
  22. #include <sound/tlv.h>
  23. #include "tas5720.h"
  24. /* Define how often to check (and clear) the fault status register (in ms) */
  25. #define TAS5720_FAULT_CHECK_INTERVAL 200
  26. enum tas572x_type {
  27. TAS5720,
  28. TAS5722,
  29. };
  30. static const char * const tas5720_supply_names[] = {
  31. "dvdd", /* Digital power supply. Connect to 3.3-V supply. */
  32. "pvdd", /* Class-D amp and analog power supply (connected). */
  33. };
  34. #define TAS5720_NUM_SUPPLIES ARRAY_SIZE(tas5720_supply_names)
  35. struct tas5720_data {
  36. struct snd_soc_component *component;
  37. struct regmap *regmap;
  38. struct i2c_client *tas5720_client;
  39. enum tas572x_type devtype;
  40. struct regulator_bulk_data supplies[TAS5720_NUM_SUPPLIES];
  41. struct delayed_work fault_check_work;
  42. unsigned int last_fault;
  43. };
  44. static int tas5720_hw_params(struct snd_pcm_substream *substream,
  45. struct snd_pcm_hw_params *params,
  46. struct snd_soc_dai *dai)
  47. {
  48. struct snd_soc_component *component = dai->component;
  49. unsigned int rate = params_rate(params);
  50. bool ssz_ds;
  51. int ret;
  52. switch (rate) {
  53. case 44100:
  54. case 48000:
  55. ssz_ds = false;
  56. break;
  57. case 88200:
  58. case 96000:
  59. ssz_ds = true;
  60. break;
  61. default:
  62. dev_err(component->dev, "unsupported sample rate: %u\n", rate);
  63. return -EINVAL;
  64. }
  65. ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
  66. TAS5720_SSZ_DS, ssz_ds);
  67. if (ret < 0) {
  68. dev_err(component->dev, "error setting sample rate: %d\n", ret);
  69. return ret;
  70. }
  71. return 0;
  72. }
  73. static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  74. {
  75. struct snd_soc_component *component = dai->component;
  76. u8 serial_format;
  77. int ret;
  78. if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
  79. dev_vdbg(component->dev, "DAI Format master is not found\n");
  80. return -EINVAL;
  81. }
  82. switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
  83. SND_SOC_DAIFMT_INV_MASK)) {
  84. case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
  85. /* 1st data bit occur one BCLK cycle after the frame sync */
  86. serial_format = TAS5720_SAIF_I2S;
  87. break;
  88. case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF):
  89. /*
  90. * Note that although the TAS5720 does not have a dedicated DSP
  91. * mode it doesn't care about the LRCLK duty cycle during TDM
  92. * operation. Therefore we can use the device's I2S mode with
  93. * its delaying of the 1st data bit to receive DSP_A formatted
  94. * data. See device datasheet for additional details.
  95. */
  96. serial_format = TAS5720_SAIF_I2S;
  97. break;
  98. case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF):
  99. /*
  100. * Similar to DSP_A, we can use the fact that the TAS5720 does
  101. * not care about the LRCLK duty cycle during TDM to receive
  102. * DSP_B formatted data in LEFTJ mode (no delaying of the 1st
  103. * data bit).
  104. */
  105. serial_format = TAS5720_SAIF_LEFTJ;
  106. break;
  107. case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
  108. /* No delay after the frame sync */
  109. serial_format = TAS5720_SAIF_LEFTJ;
  110. break;
  111. default:
  112. dev_vdbg(component->dev, "DAI Format is not found\n");
  113. return -EINVAL;
  114. }
  115. ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
  116. TAS5720_SAIF_FORMAT_MASK,
  117. serial_format);
  118. if (ret < 0) {
  119. dev_err(component->dev, "error setting SAIF format: %d\n", ret);
  120. return ret;
  121. }
  122. return 0;
  123. }
  124. static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
  125. unsigned int tx_mask, unsigned int rx_mask,
  126. int slots, int slot_width)
  127. {
  128. struct snd_soc_component *component = dai->component;
  129. struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
  130. unsigned int first_slot;
  131. int ret;
  132. if (!tx_mask) {
  133. dev_err(component->dev, "tx masks must not be 0\n");
  134. return -EINVAL;
  135. }
  136. /*
  137. * Determine the first slot that is being requested. We will only
  138. * use the first slot that is found since the TAS5720 is a mono
  139. * amplifier.
  140. */
  141. first_slot = __ffs(tx_mask);
  142. if (first_slot > 7) {
  143. dev_err(component->dev, "slot selection out of bounds (%u)\n",
  144. first_slot);
  145. return -EINVAL;
  146. }
  147. /* Enable manual TDM slot selection (instead of I2C ID based) */
  148. ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
  149. TAS5720_TDM_CFG_SRC, TAS5720_TDM_CFG_SRC);
  150. if (ret < 0)
  151. goto error_snd_soc_component_update_bits;
  152. /* Configure the TDM slot to process audio from */
  153. ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
  154. TAS5720_TDM_SLOT_SEL_MASK, first_slot);
  155. if (ret < 0)
  156. goto error_snd_soc_component_update_bits;
  157. /* Configure TDM slot width. This is only applicable to TAS5722. */
  158. switch (tas5720->devtype) {
  159. case TAS5722:
  160. ret = snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
  161. TAS5722_TDM_SLOT_16B,
  162. slot_width == 16 ?
  163. TAS5722_TDM_SLOT_16B : 0);
  164. if (ret < 0)
  165. goto error_snd_soc_component_update_bits;
  166. break;
  167. default:
  168. break;
  169. }
  170. return 0;
  171. error_snd_soc_component_update_bits:
  172. dev_err(component->dev, "error configuring TDM mode: %d\n", ret);
  173. return ret;
  174. }
  175. static int tas5720_mute(struct snd_soc_dai *dai, int mute, int direction)
  176. {
  177. struct snd_soc_component *component = dai->component;
  178. int ret;
  179. ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
  180. TAS5720_MUTE, mute ? TAS5720_MUTE : 0);
  181. if (ret < 0) {
  182. dev_err(component->dev, "error (un-)muting device: %d\n", ret);
  183. return ret;
  184. }
  185. return 0;
  186. }
  187. static void tas5720_fault_check_work(struct work_struct *work)
  188. {
  189. struct tas5720_data *tas5720 = container_of(work, struct tas5720_data,
  190. fault_check_work.work);
  191. struct device *dev = tas5720->component->dev;
  192. unsigned int curr_fault;
  193. int ret;
  194. ret = regmap_read(tas5720->regmap, TAS5720_FAULT_REG, &curr_fault);
  195. if (ret < 0) {
  196. dev_err(dev, "failed to read FAULT register: %d\n", ret);
  197. goto out;
  198. }
  199. /* Check/handle all errors except SAIF clock errors */
  200. curr_fault &= TAS5720_OCE | TAS5720_DCE | TAS5720_OTE;
  201. /*
  202. * Only flag errors once for a given occurrence. This is needed as
  203. * the TAS5720 will take time clearing the fault condition internally
  204. * during which we don't want to bombard the system with the same
  205. * error message over and over.
  206. */
  207. if ((curr_fault & TAS5720_OCE) && !(tas5720->last_fault & TAS5720_OCE))
  208. dev_crit(dev, "experienced an over current hardware fault\n");
  209. if ((curr_fault & TAS5720_DCE) && !(tas5720->last_fault & TAS5720_DCE))
  210. dev_crit(dev, "experienced a DC detection fault\n");
  211. if ((curr_fault & TAS5720_OTE) && !(tas5720->last_fault & TAS5720_OTE))
  212. dev_crit(dev, "experienced an over temperature fault\n");
  213. /* Store current fault value so we can detect any changes next time */
  214. tas5720->last_fault = curr_fault;
  215. if (!curr_fault)
  216. goto out;
  217. /*
  218. * Periodically toggle SDZ (shutdown bit) H->L->H to clear any latching
  219. * faults as long as a fault condition persists. Always going through
  220. * the full sequence no matter the first return value to minimizes
  221. * chances for the device to end up in shutdown mode.
  222. */
  223. ret = regmap_write_bits(tas5720->regmap, TAS5720_POWER_CTRL_REG,
  224. TAS5720_SDZ, 0);
  225. if (ret < 0)
  226. dev_err(dev, "failed to write POWER_CTRL register: %d\n", ret);
  227. ret = regmap_write_bits(tas5720->regmap, TAS5720_POWER_CTRL_REG,
  228. TAS5720_SDZ, TAS5720_SDZ);
  229. if (ret < 0)
  230. dev_err(dev, "failed to write POWER_CTRL register: %d\n", ret);
  231. out:
  232. /* Schedule the next fault check at the specified interval */
  233. schedule_delayed_work(&tas5720->fault_check_work,
  234. msecs_to_jiffies(TAS5720_FAULT_CHECK_INTERVAL));
  235. }
  236. static int tas5720_codec_probe(struct snd_soc_component *component)
  237. {
  238. struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
  239. unsigned int device_id, expected_device_id;
  240. int ret;
  241. tas5720->component = component;
  242. ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies),
  243. tas5720->supplies);
  244. if (ret != 0) {
  245. dev_err(component->dev, "failed to enable supplies: %d\n", ret);
  246. return ret;
  247. }
  248. /*
  249. * Take a liberal approach to checking the device ID to allow the
  250. * driver to be used even if the device ID does not match, however
  251. * issue a warning if there is a mismatch.
  252. */
  253. ret = regmap_read(tas5720->regmap, TAS5720_DEVICE_ID_REG, &device_id);
  254. if (ret < 0) {
  255. dev_err(component->dev, "failed to read device ID register: %d\n",
  256. ret);
  257. goto probe_fail;
  258. }
  259. switch (tas5720->devtype) {
  260. case TAS5720:
  261. expected_device_id = TAS5720_DEVICE_ID;
  262. break;
  263. case TAS5722:
  264. expected_device_id = TAS5722_DEVICE_ID;
  265. break;
  266. default:
  267. dev_err(component->dev, "unexpected private driver data\n");
  268. return -EINVAL;
  269. }
  270. if (device_id != expected_device_id)
  271. dev_warn(component->dev, "wrong device ID. expected: %u read: %u\n",
  272. expected_device_id, device_id);
  273. /* Set device to mute */
  274. ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
  275. TAS5720_MUTE, TAS5720_MUTE);
  276. if (ret < 0)
  277. goto error_snd_soc_component_update_bits;
  278. /*
  279. * Enter shutdown mode - our default when not playing audio - to
  280. * minimize current consumption. On the TAS5720 there is no real down
  281. * side doing so as all device registers are preserved and the wakeup
  282. * of the codec is rather quick which we do using a dapm widget.
  283. */
  284. ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
  285. TAS5720_SDZ, 0);
  286. if (ret < 0)
  287. goto error_snd_soc_component_update_bits;
  288. INIT_DELAYED_WORK(&tas5720->fault_check_work, tas5720_fault_check_work);
  289. return 0;
  290. error_snd_soc_component_update_bits:
  291. dev_err(component->dev, "error configuring device registers: %d\n", ret);
  292. probe_fail:
  293. regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
  294. tas5720->supplies);
  295. return ret;
  296. }
  297. static void tas5720_codec_remove(struct snd_soc_component *component)
  298. {
  299. struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
  300. int ret;
  301. cancel_delayed_work_sync(&tas5720->fault_check_work);
  302. ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
  303. tas5720->supplies);
  304. if (ret < 0)
  305. dev_err(component->dev, "failed to disable supplies: %d\n", ret);
  306. };
  307. static int tas5720_dac_event(struct snd_soc_dapm_widget *w,
  308. struct snd_kcontrol *kcontrol, int event)
  309. {
  310. struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
  311. struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
  312. int ret;
  313. if (event & SND_SOC_DAPM_POST_PMU) {
  314. /* Take TAS5720 out of shutdown mode */
  315. ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
  316. TAS5720_SDZ, TAS5720_SDZ);
  317. if (ret < 0) {
  318. dev_err(component->dev, "error waking component: %d\n", ret);
  319. return ret;
  320. }
  321. /*
  322. * Observe codec shutdown-to-active time. The datasheet only
  323. * lists a nominal value however just use-it as-is without
  324. * additional padding to minimize the delay introduced in
  325. * starting to play audio (actually there is other setup done
  326. * by the ASoC framework that will provide additional delays,
  327. * so we should always be safe).
  328. */
  329. msleep(25);
  330. /* Turn on TAS5720 periodic fault checking/handling */
  331. tas5720->last_fault = 0;
  332. schedule_delayed_work(&tas5720->fault_check_work,
  333. msecs_to_jiffies(TAS5720_FAULT_CHECK_INTERVAL));
  334. } else if (event & SND_SOC_DAPM_PRE_PMD) {
  335. /* Disable TAS5720 periodic fault checking/handling */
  336. cancel_delayed_work_sync(&tas5720->fault_check_work);
  337. /* Place TAS5720 in shutdown mode to minimize current draw */
  338. ret = snd_soc_component_update_bits(component, TAS5720_POWER_CTRL_REG,
  339. TAS5720_SDZ, 0);
  340. if (ret < 0) {
  341. dev_err(component->dev, "error shutting down component: %d\n",
  342. ret);
  343. return ret;
  344. }
  345. }
  346. return 0;
  347. }
  348. #ifdef CONFIG_PM
  349. static int tas5720_suspend(struct snd_soc_component *component)
  350. {
  351. struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
  352. int ret;
  353. regcache_cache_only(tas5720->regmap, true);
  354. regcache_mark_dirty(tas5720->regmap);
  355. ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies),
  356. tas5720->supplies);
  357. if (ret < 0)
  358. dev_err(component->dev, "failed to disable supplies: %d\n", ret);
  359. return ret;
  360. }
  361. static int tas5720_resume(struct snd_soc_component *component)
  362. {
  363. struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
  364. int ret;
  365. ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies),
  366. tas5720->supplies);
  367. if (ret < 0) {
  368. dev_err(component->dev, "failed to enable supplies: %d\n", ret);
  369. return ret;
  370. }
  371. regcache_cache_only(tas5720->regmap, false);
  372. ret = regcache_sync(tas5720->regmap);
  373. if (ret < 0) {
  374. dev_err(component->dev, "failed to sync regcache: %d\n", ret);
  375. return ret;
  376. }
  377. return 0;
  378. }
  379. #else
  380. #define tas5720_suspend NULL
  381. #define tas5720_resume NULL
  382. #endif
  383. static bool tas5720_is_volatile_reg(struct device *dev, unsigned int reg)
  384. {
  385. switch (reg) {
  386. case TAS5720_DEVICE_ID_REG:
  387. case TAS5720_FAULT_REG:
  388. return true;
  389. default:
  390. return false;
  391. }
  392. }
  393. static const struct regmap_config tas5720_regmap_config = {
  394. .reg_bits = 8,
  395. .val_bits = 8,
  396. .max_register = TAS5720_MAX_REG,
  397. .cache_type = REGCACHE_RBTREE,
  398. .volatile_reg = tas5720_is_volatile_reg,
  399. };
  400. static const struct regmap_config tas5722_regmap_config = {
  401. .reg_bits = 8,
  402. .val_bits = 8,
  403. .max_register = TAS5722_MAX_REG,
  404. .cache_type = REGCACHE_RBTREE,
  405. .volatile_reg = tas5720_is_volatile_reg,
  406. };
  407. /*
  408. * DAC analog gain. There are four discrete values to select from, ranging
  409. * from 19.2 dB to 26.3dB.
  410. */
  411. static const DECLARE_TLV_DB_RANGE(dac_analog_tlv,
  412. 0x0, 0x0, TLV_DB_SCALE_ITEM(1920, 0, 0),
  413. 0x1, 0x1, TLV_DB_SCALE_ITEM(2070, 0, 0),
  414. 0x2, 0x2, TLV_DB_SCALE_ITEM(2350, 0, 0),
  415. 0x3, 0x3, TLV_DB_SCALE_ITEM(2630, 0, 0),
  416. );
  417. /*
  418. * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB or 0.25 dB steps
  419. * depending on the device. Note that setting the gain below -100 dB
  420. * (register value <0x7) is effectively a MUTE as per device datasheet.
  421. *
  422. * Note that for the TAS5722 the digital volume controls are actually split
  423. * over two registers, so we need custom getters/setters for access.
  424. */
  425. static DECLARE_TLV_DB_SCALE(tas5720_dac_tlv, -10350, 50, 0);
  426. static DECLARE_TLV_DB_SCALE(tas5722_dac_tlv, -10350, 25, 0);
  427. static int tas5722_volume_get(struct snd_kcontrol *kcontrol,
  428. struct snd_ctl_elem_value *ucontrol)
  429. {
  430. struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
  431. unsigned int val;
  432. val = snd_soc_component_read(component, TAS5720_VOLUME_CTRL_REG);
  433. ucontrol->value.integer.value[0] = val << 1;
  434. val = snd_soc_component_read(component, TAS5722_DIGITAL_CTRL2_REG);
  435. ucontrol->value.integer.value[0] |= val & TAS5722_VOL_CONTROL_LSB;
  436. return 0;
  437. }
  438. static int tas5722_volume_set(struct snd_kcontrol *kcontrol,
  439. struct snd_ctl_elem_value *ucontrol)
  440. {
  441. struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
  442. unsigned int sel = ucontrol->value.integer.value[0];
  443. snd_soc_component_write(component, TAS5720_VOLUME_CTRL_REG, sel >> 1);
  444. snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG,
  445. TAS5722_VOL_CONTROL_LSB, sel);
  446. return 0;
  447. }
  448. static const struct snd_kcontrol_new tas5720_snd_controls[] = {
  449. SOC_SINGLE_TLV("Speaker Driver Playback Volume",
  450. TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, tas5720_dac_tlv),
  451. SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
  452. TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
  453. };
  454. static const struct snd_kcontrol_new tas5722_snd_controls[] = {
  455. SOC_SINGLE_EXT_TLV("Speaker Driver Playback Volume",
  456. 0, 0, 511, 0,
  457. tas5722_volume_get, tas5722_volume_set,
  458. tas5722_dac_tlv),
  459. SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
  460. TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
  461. };
  462. static const struct snd_soc_dapm_widget tas5720_dapm_widgets[] = {
  463. SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
  464. SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas5720_dac_event,
  465. SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
  466. SND_SOC_DAPM_OUTPUT("OUT")
  467. };
  468. static const struct snd_soc_dapm_route tas5720_audio_map[] = {
  469. { "DAC", NULL, "DAC IN" },
  470. { "OUT", NULL, "DAC" },
  471. };
  472. static const struct snd_soc_component_driver soc_component_dev_tas5720 = {
  473. .probe = tas5720_codec_probe,
  474. .remove = tas5720_codec_remove,
  475. .suspend = tas5720_suspend,
  476. .resume = tas5720_resume,
  477. .controls = tas5720_snd_controls,
  478. .num_controls = ARRAY_SIZE(tas5720_snd_controls),
  479. .dapm_widgets = tas5720_dapm_widgets,
  480. .num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets),
  481. .dapm_routes = tas5720_audio_map,
  482. .num_dapm_routes = ARRAY_SIZE(tas5720_audio_map),
  483. .idle_bias_on = 1,
  484. .use_pmdown_time = 1,
  485. .endianness = 1,
  486. .non_legacy_dai_naming = 1,
  487. };
  488. static const struct snd_soc_component_driver soc_component_dev_tas5722 = {
  489. .probe = tas5720_codec_probe,
  490. .remove = tas5720_codec_remove,
  491. .suspend = tas5720_suspend,
  492. .resume = tas5720_resume,
  493. .controls = tas5722_snd_controls,
  494. .num_controls = ARRAY_SIZE(tas5722_snd_controls),
  495. .dapm_widgets = tas5720_dapm_widgets,
  496. .num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets),
  497. .dapm_routes = tas5720_audio_map,
  498. .num_dapm_routes = ARRAY_SIZE(tas5720_audio_map),
  499. .idle_bias_on = 1,
  500. .use_pmdown_time = 1,
  501. .endianness = 1,
  502. .non_legacy_dai_naming = 1,
  503. };
  504. /* PCM rates supported by the TAS5720 driver */
  505. #define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
  506. SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
  507. /* Formats supported by TAS5720 driver */
  508. #define TAS5720_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\
  509. SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
  510. static const struct snd_soc_dai_ops tas5720_speaker_dai_ops = {
  511. .hw_params = tas5720_hw_params,
  512. .set_fmt = tas5720_set_dai_fmt,
  513. .set_tdm_slot = tas5720_set_dai_tdm_slot,
  514. .mute_stream = tas5720_mute,
  515. .no_capture_mute = 1,
  516. };
  517. /*
  518. * TAS5720 DAI structure
  519. *
  520. * Note that were are advertising .playback.channels_max = 2 despite this being
  521. * a mono amplifier. The reason for that is that some serial ports such as TI's
  522. * McASP module have a minimum number of channels (2) that they can output.
  523. * Advertising more channels than we have will allow us to interface with such
  524. * a serial port without really any negative side effects as the TAS5720 will
  525. * simply ignore any extra channel(s) asides from the one channel that is
  526. * configured to be played back.
  527. */
  528. static struct snd_soc_dai_driver tas5720_dai[] = {
  529. {
  530. .name = "tas5720-amplifier",
  531. .playback = {
  532. .stream_name = "Playback",
  533. .channels_min = 1,
  534. .channels_max = 2,
  535. .rates = TAS5720_RATES,
  536. .formats = TAS5720_FORMATS,
  537. },
  538. .ops = &tas5720_speaker_dai_ops,
  539. },
  540. };
  541. static int tas5720_probe(struct i2c_client *client,
  542. const struct i2c_device_id *id)
  543. {
  544. struct device *dev = &client->dev;
  545. struct tas5720_data *data;
  546. const struct regmap_config *regmap_config;
  547. int ret;
  548. int i;
  549. data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
  550. if (!data)
  551. return -ENOMEM;
  552. data->tas5720_client = client;
  553. data->devtype = id->driver_data;
  554. switch (id->driver_data) {
  555. case TAS5720:
  556. regmap_config = &tas5720_regmap_config;
  557. break;
  558. case TAS5722:
  559. regmap_config = &tas5722_regmap_config;
  560. break;
  561. default:
  562. dev_err(dev, "unexpected private driver data\n");
  563. return -EINVAL;
  564. }
  565. data->regmap = devm_regmap_init_i2c(client, regmap_config);
  566. if (IS_ERR(data->regmap)) {
  567. ret = PTR_ERR(data->regmap);
  568. dev_err(dev, "failed to allocate register map: %d\n", ret);
  569. return ret;
  570. }
  571. for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
  572. data->supplies[i].supply = tas5720_supply_names[i];
  573. ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
  574. data->supplies);
  575. if (ret != 0) {
  576. dev_err(dev, "failed to request supplies: %d\n", ret);
  577. return ret;
  578. }
  579. dev_set_drvdata(dev, data);
  580. switch (id->driver_data) {
  581. case TAS5720:
  582. ret = devm_snd_soc_register_component(&client->dev,
  583. &soc_component_dev_tas5720,
  584. tas5720_dai,
  585. ARRAY_SIZE(tas5720_dai));
  586. break;
  587. case TAS5722:
  588. ret = devm_snd_soc_register_component(&client->dev,
  589. &soc_component_dev_tas5722,
  590. tas5720_dai,
  591. ARRAY_SIZE(tas5720_dai));
  592. break;
  593. default:
  594. dev_err(dev, "unexpected private driver data\n");
  595. return -EINVAL;
  596. }
  597. if (ret < 0) {
  598. dev_err(dev, "failed to register component: %d\n", ret);
  599. return ret;
  600. }
  601. return 0;
  602. }
  603. static const struct i2c_device_id tas5720_id[] = {
  604. { "tas5720", TAS5720 },
  605. { "tas5722", TAS5722 },
  606. { }
  607. };
  608. MODULE_DEVICE_TABLE(i2c, tas5720_id);
  609. #if IS_ENABLED(CONFIG_OF)
  610. static const struct of_device_id tas5720_of_match[] = {
  611. { .compatible = "ti,tas5720", },
  612. { .compatible = "ti,tas5722", },
  613. { },
  614. };
  615. MODULE_DEVICE_TABLE(of, tas5720_of_match);
  616. #endif
  617. static struct i2c_driver tas5720_i2c_driver = {
  618. .driver = {
  619. .name = "tas5720",
  620. .of_match_table = of_match_ptr(tas5720_of_match),
  621. },
  622. .probe = tas5720_probe,
  623. .id_table = tas5720_id,
  624. };
  625. module_i2c_driver(tas5720_i2c_driver);
  626. MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
  627. MODULE_DESCRIPTION("TAS5720 Audio amplifier driver");
  628. MODULE_LICENSE("GPL");