0071-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  1. From 8508fddff6dbb8b83296a4aa9edad6288b3b50bb Mon Sep 17 00:00:00 2001
  2. From: Daniel Matuschek <info@crazy-audio.com>
  3. Date: Mon, 4 Aug 2014 11:09:58 +0200
  4. Subject: [PATCH] Added driver for HiFiBerry Amp amplifier add-on board
  5. The driver contains a low-level hardware driver for the TAS5713 and the
  6. drivers for the Raspberry Pi I2S subsystem.
  7. TAS5713: return error if initialisation fails
  8. Existing TAS5713 driver logs errors during initialisation, but does not return
  9. an error code. Therefore even if initialisation fails, the driver will still be
  10. loaded, but won't work. This patch fixes this. I2C communication error will now
  11. reported correctly by a non-zero return code.
  12. HiFiBerry Amp: fix device-tree problems
  13. Some code to load the driver based on device-tree-overlays was missing. This is added by this patch.
  14. ---
  15. sound/soc/bcm/Kconfig | 7 +
  16. sound/soc/bcm/Makefile | 2 +
  17. sound/soc/bcm/hifiberry_amp.c | 127 +++++++++++++++
  18. sound/soc/codecs/Kconfig | 4 +
  19. sound/soc/codecs/Makefile | 2 +
  20. sound/soc/codecs/tas5713.c | 369 ++++++++++++++++++++++++++++++++++++++++++
  21. sound/soc/codecs/tas5713.h | 210 ++++++++++++++++++++++++
  22. 7 files changed, 721 insertions(+)
  23. create mode 100644 sound/soc/bcm/hifiberry_amp.c
  24. create mode 100644 sound/soc/codecs/tas5713.c
  25. create mode 100644 sound/soc/codecs/tas5713.h
  26. --- a/sound/soc/bcm/Kconfig
  27. +++ b/sound/soc/bcm/Kconfig
  28. @@ -29,6 +29,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DIGI
  29. help
  30. Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
  31. +config SND_BCM2708_SOC_HIFIBERRY_AMP
  32. + tristate "Support for the HifiBerry Amp"
  33. + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
  34. + select SND_SOC_TAS5713
  35. + help
  36. + Say Y or M if you want to add support for the HifiBerry Amp amplifier board.
  37. +
  38. config SND_BCM2708_SOC_RPI_DAC
  39. tristate "Support for RPi-DAC"
  40. depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
  41. --- a/sound/soc/bcm/Makefile
  42. +++ b/sound/soc/bcm/Makefile
  43. @@ -7,11 +7,13 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
  44. snd-soc-hifiberry-dac-objs := hifiberry_dac.o
  45. snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
  46. snd-soc-hifiberry-digi-objs := hifiberry_digi.o
  47. +snd-soc-hifiberry-amp-objs := hifiberry_amp.o
  48. snd-soc-rpi-dac-objs := rpi-dac.o
  49. snd-soc-iqaudio-dac-objs := iqaudio-dac.o
  50. obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
  51. obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
  52. obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
  53. +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
  54. obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
  55. obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
  56. --- /dev/null
  57. +++ b/sound/soc/bcm/hifiberry_amp.c
  58. @@ -0,0 +1,127 @@
  59. +/*
  60. + * ASoC Driver for HifiBerry AMP
  61. + *
  62. + * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
  63. + * Copyright 2014
  64. + *
  65. + * This program is free software; you can redistribute it and/or
  66. + * modify it under the terms of the GNU General Public License
  67. + * version 2 as published by the Free Software Foundation.
  68. + *
  69. + * This program is distributed in the hope that it will be useful, but
  70. + * WITHOUT ANY WARRANTY; without even the implied warranty of
  71. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  72. + * General Public License for more details.
  73. + */
  74. +
  75. +#include <linux/module.h>
  76. +#include <linux/platform_device.h>
  77. +
  78. +#include <sound/core.h>
  79. +#include <sound/pcm.h>
  80. +#include <sound/pcm_params.h>
  81. +#include <sound/soc.h>
  82. +#include <sound/jack.h>
  83. +
  84. +static int snd_rpi_hifiberry_amp_init(struct snd_soc_pcm_runtime *rtd)
  85. +{
  86. + // ToDo: init of the dsp-registers.
  87. + return 0;
  88. +}
  89. +
  90. +static int snd_rpi_hifiberry_amp_hw_params( struct snd_pcm_substream *substream,
  91. + struct snd_pcm_hw_params *params )
  92. +{
  93. + struct snd_soc_pcm_runtime *rtd = substream->private_data;
  94. + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  95. +
  96. + return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
  97. +}
  98. +
  99. +static struct snd_soc_ops snd_rpi_hifiberry_amp_ops = {
  100. + .hw_params = snd_rpi_hifiberry_amp_hw_params,
  101. +};
  102. +
  103. +static struct snd_soc_dai_link snd_rpi_hifiberry_amp_dai[] = {
  104. + {
  105. + .name = "HifiBerry AMP",
  106. + .stream_name = "HifiBerry AMP HiFi",
  107. + .cpu_dai_name = "bcm2708-i2s.0",
  108. + .codec_dai_name = "tas5713-hifi",
  109. + .platform_name = "bcm2708-i2s.0",
  110. + .codec_name = "tas5713.1-001b",
  111. + .dai_fmt = SND_SOC_DAIFMT_I2S |
  112. + SND_SOC_DAIFMT_NB_NF |
  113. + SND_SOC_DAIFMT_CBS_CFS,
  114. + .ops = &snd_rpi_hifiberry_amp_ops,
  115. + .init = snd_rpi_hifiberry_amp_init,
  116. + },
  117. +};
  118. +
  119. +
  120. +static struct snd_soc_card snd_rpi_hifiberry_amp = {
  121. + .name = "snd_rpi_hifiberry_amp",
  122. + .dai_link = snd_rpi_hifiberry_amp_dai,
  123. + .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai),
  124. +};
  125. +
  126. +static const struct of_device_id snd_rpi_hifiberry_amp_of_match[] = {
  127. + { .compatible = "hifiberry,hifiberry-amp", },
  128. + {},
  129. +};
  130. +MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_amp_of_match);
  131. +
  132. +
  133. +static int snd_rpi_hifiberry_amp_probe(struct platform_device *pdev)
  134. +{
  135. + int ret = 0;
  136. +
  137. + snd_rpi_hifiberry_amp.dev = &pdev->dev;
  138. +
  139. + if (pdev->dev.of_node) {
  140. + struct device_node *i2s_node;
  141. + struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_amp_dai[0];
  142. + i2s_node = of_parse_phandle(pdev->dev.of_node,
  143. + "i2s-controller", 0);
  144. +
  145. + if (i2s_node) {
  146. + dai->cpu_dai_name = NULL;
  147. + dai->cpu_of_node = i2s_node;
  148. + dai->platform_name = NULL;
  149. + dai->platform_of_node = i2s_node;
  150. + }
  151. + }
  152. +
  153. + ret = snd_soc_register_card(&snd_rpi_hifiberry_amp);
  154. +
  155. + if (ret != 0) {
  156. + dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
  157. + }
  158. +
  159. + return ret;
  160. +}
  161. +
  162. +
  163. +static int snd_rpi_hifiberry_amp_remove(struct platform_device *pdev)
  164. +{
  165. + return snd_soc_unregister_card(&snd_rpi_hifiberry_amp);
  166. +}
  167. +
  168. +
  169. +static struct platform_driver snd_rpi_hifiberry_amp_driver = {
  170. + .driver = {
  171. + .name = "snd-hifiberry-amp",
  172. + .owner = THIS_MODULE,
  173. + .of_match_table = snd_rpi_hifiberry_amp_of_match,
  174. + },
  175. + .probe = snd_rpi_hifiberry_amp_probe,
  176. + .remove = snd_rpi_hifiberry_amp_remove,
  177. +};
  178. +
  179. +
  180. +module_platform_driver(snd_rpi_hifiberry_amp_driver);
  181. +
  182. +
  183. +MODULE_AUTHOR("Sebastian Eickhoff <basti.eickhoff@googlemail.com>");
  184. +MODULE_DESCRIPTION("ASoC driver for HiFiBerry-AMP");
  185. +MODULE_LICENSE("GPL v2");
  186. --- a/sound/soc/codecs/Kconfig
  187. +++ b/sound/soc/codecs/Kconfig
  188. @@ -117,6 +117,7 @@ config SND_SOC_ALL_CODECS
  189. select SND_SOC_TFA9879 if I2C
  190. select SND_SOC_TLV320AIC23_I2C if I2C
  191. select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
  192. + select SND_SOC_TAS5713 if I2C
  193. select SND_SOC_TLV320AIC26 if SPI_MASTER
  194. select SND_SOC_TLV320AIC31XX if I2C
  195. select SND_SOC_TLV320AIC32X4 if I2C
  196. @@ -674,6 +675,9 @@ config SND_SOC_TFA9879
  197. tristate "NXP Semiconductors TFA9879 amplifier"
  198. depends on I2C
  199. +config SND_SOC_TAS5713
  200. + tristate
  201. +
  202. config SND_SOC_TLV320AIC23
  203. tristate
  204. --- a/sound/soc/codecs/Makefile
  205. +++ b/sound/soc/codecs/Makefile
  206. @@ -118,6 +118,7 @@ snd-soc-sti-sas-objs := sti-sas.o
  207. snd-soc-tas5086-objs := tas5086.o
  208. snd-soc-tas571x-objs := tas571x.o
  209. snd-soc-tfa9879-objs := tfa9879.o
  210. +snd-soc-tas5713-objs := tas5713.o
  211. snd-soc-tlv320aic23-objs := tlv320aic23.o
  212. snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
  213. snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
  214. @@ -312,6 +313,7 @@ obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc
  215. obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
  216. obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
  217. obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
  218. +obj-$(CONFIG_SND_SOC_TAS5713) += snd-soc-tas5713.o
  219. obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
  220. obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
  221. obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o
  222. --- /dev/null
  223. +++ b/sound/soc/codecs/tas5713.c
  224. @@ -0,0 +1,369 @@
  225. +/*
  226. + * ASoC Driver for TAS5713
  227. + *
  228. + * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
  229. + * Copyright 2014
  230. + *
  231. + * This program is free software; you can redistribute it and/or
  232. + * modify it under the terms of the GNU General Public License
  233. + * version 2 as published by the Free Software Foundation.
  234. + *
  235. + * This program is distributed in the hope that it will be useful, but
  236. + * WITHOUT ANY WARRANTY; without even the implied warranty of
  237. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  238. + * General Public License for more details.
  239. + */
  240. +
  241. +#include <linux/module.h>
  242. +#include <linux/moduleparam.h>
  243. +#include <linux/init.h>
  244. +#include <linux/delay.h>
  245. +#include <linux/pm.h>
  246. +#include <linux/i2c.h>
  247. +#include <linux/of_device.h>
  248. +#include <linux/spi/spi.h>
  249. +#include <linux/regmap.h>
  250. +#include <linux/regulator/consumer.h>
  251. +#include <linux/slab.h>
  252. +#include <sound/core.h>
  253. +#include <sound/pcm.h>
  254. +#include <sound/pcm_params.h>
  255. +#include <sound/soc.h>
  256. +#include <sound/initval.h>
  257. +#include <sound/tlv.h>
  258. +
  259. +#include <linux/kernel.h>
  260. +#include <linux/string.h>
  261. +#include <linux/fs.h>
  262. +#include <asm/uaccess.h>
  263. +
  264. +#include "tas5713.h"
  265. +
  266. +
  267. +static struct i2c_client *i2c;
  268. +
  269. +struct tas5713_priv {
  270. + struct regmap *regmap;
  271. + int mclk_div;
  272. + struct snd_soc_codec *codec;
  273. +};
  274. +
  275. +static struct tas5713_priv *priv_data;
  276. +
  277. +
  278. +
  279. +
  280. +/*
  281. + * _ _ ___ _ ___ _ _
  282. + * /_\ | | / __| /_\ / __|___ _ _| |_ _ _ ___| |___
  283. + * / _ \| |__\__ \/ _ \ | (__/ _ \ ' \ _| '_/ _ \ (_-<
  284. + * /_/ \_\____|___/_/ \_\ \___\___/_||_\__|_| \___/_/__/
  285. + *
  286. + */
  287. +
  288. +static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1);
  289. +
  290. +
  291. +static const struct snd_kcontrol_new tas5713_snd_controls[] = {
  292. + SOC_SINGLE_TLV ("Master" , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv),
  293. + SOC_DOUBLE_R_TLV("Channels" , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv)
  294. +};
  295. +
  296. +
  297. +
  298. +
  299. +/*
  300. + * __ __ _ _ ___ _
  301. + * | \/ |__ _ __| |_ (_)_ _ ___ | \ _ _(_)_ _____ _ _
  302. + * | |\/| / _` / _| ' \| | ' \/ -_) | |) | '_| \ V / -_) '_|
  303. + * |_| |_\__,_\__|_||_|_|_||_\___| |___/|_| |_|\_/\___|_|
  304. + *
  305. + */
  306. +
  307. +static int tas5713_hw_params(struct snd_pcm_substream *substream,
  308. + struct snd_pcm_hw_params *params,
  309. + struct snd_soc_dai *dai)
  310. +{
  311. + u16 blen = 0x00;
  312. +
  313. + struct snd_soc_codec *codec;
  314. + codec = dai->codec;
  315. + priv_data->codec = dai->codec;
  316. +
  317. + switch (params_format(params)) {
  318. + case SNDRV_PCM_FORMAT_S16_LE:
  319. + blen = 0x03;
  320. + break;
  321. + case SNDRV_PCM_FORMAT_S20_3LE:
  322. + blen = 0x1;
  323. + break;
  324. + case SNDRV_PCM_FORMAT_S24_LE:
  325. + blen = 0x04;
  326. + break;
  327. + case SNDRV_PCM_FORMAT_S32_LE:
  328. + blen = 0x05;
  329. + break;
  330. + default:
  331. + dev_err(dai->dev, "Unsupported word length: %u\n",
  332. + params_format(params));
  333. + return -EINVAL;
  334. + }
  335. +
  336. + // set word length
  337. + snd_soc_update_bits(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x7, blen);
  338. +
  339. + return 0;
  340. +}
  341. +
  342. +
  343. +static int tas5713_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
  344. +{
  345. + unsigned int val = 0;
  346. +
  347. + struct tas5713_priv *tas5713;
  348. + struct snd_soc_codec *codec = dai->codec;
  349. + tas5713 = snd_soc_codec_get_drvdata(codec);
  350. +
  351. + if (mute) {
  352. + val = TAS5713_SOFT_MUTE_ALL;
  353. + }
  354. +
  355. + return regmap_write(tas5713->regmap, TAS5713_SOFT_MUTE, val);
  356. +}
  357. +
  358. +
  359. +static const struct snd_soc_dai_ops tas5713_dai_ops = {
  360. + .hw_params = tas5713_hw_params,
  361. + .mute_stream = tas5713_mute_stream,
  362. +};
  363. +
  364. +
  365. +static struct snd_soc_dai_driver tas5713_dai = {
  366. + .name = "tas5713-hifi",
  367. + .playback = {
  368. + .stream_name = "Playback",
  369. + .channels_min = 2,
  370. + .channels_max = 2,
  371. + .rates = SNDRV_PCM_RATE_8000_48000,
  372. + .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE ),
  373. + },
  374. + .ops = &tas5713_dai_ops,
  375. +};
  376. +
  377. +
  378. +
  379. +
  380. +/*
  381. + * ___ _ ___ _
  382. + * / __|___ __| |___ __ | \ _ _(_)_ _____ _ _
  383. + * | (__/ _ \/ _` / -_) _| | |) | '_| \ V / -_) '_|
  384. + * \___\___/\__,_\___\__| |___/|_| |_|\_/\___|_|
  385. + *
  386. + */
  387. +
  388. +static int tas5713_remove(struct snd_soc_codec *codec)
  389. +{
  390. + struct tas5713_priv *tas5713;
  391. +
  392. + tas5713 = snd_soc_codec_get_drvdata(codec);
  393. +
  394. + return 0;
  395. +}
  396. +
  397. +
  398. +static int tas5713_probe(struct snd_soc_codec *codec)
  399. +{
  400. + struct tas5713_priv *tas5713;
  401. + int i, ret;
  402. +
  403. + i2c = container_of(codec->dev, struct i2c_client, dev);
  404. +
  405. + tas5713 = snd_soc_codec_get_drvdata(codec);
  406. +
  407. + // Reset error
  408. + ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00);
  409. + if (ret < 0) return ret;
  410. +
  411. + // Trim oscillator
  412. + ret = snd_soc_write(codec, TAS5713_OSC_TRIM, 0x00);
  413. + if (ret < 0) return ret;
  414. + msleep(1000);
  415. +
  416. + // Reset error
  417. + ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00);
  418. + if (ret < 0) return ret;
  419. +
  420. + // Clock mode: 44/48kHz, MCLK=64xfs
  421. + ret = snd_soc_write(codec, TAS5713_CLOCK_CTRL, 0x60);
  422. + if (ret < 0) return ret;
  423. +
  424. + // I2S 24bit
  425. + ret = snd_soc_write(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x05);
  426. + if (ret < 0) return ret;
  427. +
  428. + // Unmute
  429. + ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00);
  430. + if (ret < 0) return ret;
  431. + ret = snd_soc_write(codec, TAS5713_SOFT_MUTE, 0x00);
  432. + if (ret < 0) return ret;
  433. +
  434. + // Set volume to 0db
  435. + ret = snd_soc_write(codec, TAS5713_VOL_MASTER, 0x00);
  436. + if (ret < 0) return ret;
  437. +
  438. + // Now start programming the default initialization sequence
  439. + for (i = 0; i < ARRAY_SIZE(tas5713_init_sequence); ++i) {
  440. + ret = i2c_master_send(i2c,
  441. + tas5713_init_sequence[i].data,
  442. + tas5713_init_sequence[i].size);
  443. + if (ret < 0) {
  444. + printk(KERN_INFO "TAS5713 CODEC PROBE: InitSeq returns: %d\n", ret);
  445. + }
  446. + }
  447. +
  448. + // Unmute
  449. + ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00);
  450. + if (ret < 0) return ret;
  451. +
  452. + return 0;
  453. +}
  454. +
  455. +
  456. +static struct snd_soc_codec_driver soc_codec_dev_tas5713 = {
  457. + .probe = tas5713_probe,
  458. + .remove = tas5713_remove,
  459. + .controls = tas5713_snd_controls,
  460. + .num_controls = ARRAY_SIZE(tas5713_snd_controls),
  461. +};
  462. +
  463. +
  464. +
  465. +
  466. +/*
  467. + * ___ ___ ___ ___ _
  468. + * |_ _|_ ) __| | \ _ _(_)_ _____ _ _
  469. + * | | / / (__ | |) | '_| \ V / -_) '_|
  470. + * |___/___\___| |___/|_| |_|\_/\___|_|
  471. + *
  472. + */
  473. +
  474. +static const struct reg_default tas5713_reg_defaults[] = {
  475. + { 0x07 ,0x80 }, // R7 - VOL_MASTER - -40dB
  476. + { 0x08 , 30 }, // R8 - VOL_CH1 - 0dB
  477. + { 0x09 , 30 }, // R9 - VOL_CH2 - 0dB
  478. + { 0x0A ,0x80 }, // R10 - VOL_HEADPHONE - -40dB
  479. +};
  480. +
  481. +
  482. +static bool tas5713_reg_volatile(struct device *dev, unsigned int reg)
  483. +{
  484. + switch (reg) {
  485. + case TAS5713_DEVICE_ID:
  486. + case TAS5713_ERROR_STATUS:
  487. + return true;
  488. + default:
  489. + return false;
  490. + }
  491. +}
  492. +
  493. +
  494. +static const struct of_device_id tas5713_of_match[] = {
  495. + { .compatible = "ti,tas5713", },
  496. + { }
  497. +};
  498. +MODULE_DEVICE_TABLE(of, tas5713_of_match);
  499. +
  500. +
  501. +static struct regmap_config tas5713_regmap_config = {
  502. + .reg_bits = 8,
  503. + .val_bits = 8,
  504. +
  505. + .max_register = TAS5713_MAX_REGISTER,
  506. + .volatile_reg = tas5713_reg_volatile,
  507. +
  508. + .cache_type = REGCACHE_RBTREE,
  509. + .reg_defaults = tas5713_reg_defaults,
  510. + .num_reg_defaults = ARRAY_SIZE(tas5713_reg_defaults),
  511. +};
  512. +
  513. +
  514. +static int tas5713_i2c_probe(struct i2c_client *i2c,
  515. + const struct i2c_device_id *id)
  516. +{
  517. + int ret;
  518. +
  519. + priv_data = devm_kzalloc(&i2c->dev, sizeof *priv_data, GFP_KERNEL);
  520. + if (!priv_data)
  521. + return -ENOMEM;
  522. +
  523. + priv_data->regmap = devm_regmap_init_i2c(i2c, &tas5713_regmap_config);
  524. + if (IS_ERR(priv_data->regmap)) {
  525. + ret = PTR_ERR(priv_data->regmap);
  526. + return ret;
  527. + }
  528. +
  529. + i2c_set_clientdata(i2c, priv_data);
  530. +
  531. + ret = snd_soc_register_codec(&i2c->dev,
  532. + &soc_codec_dev_tas5713, &tas5713_dai, 1);
  533. +
  534. + return ret;
  535. +}
  536. +
  537. +
  538. +static int tas5713_i2c_remove(struct i2c_client *i2c)
  539. +{
  540. + snd_soc_unregister_codec(&i2c->dev);
  541. + i2c_set_clientdata(i2c, NULL);
  542. +
  543. + kfree(priv_data);
  544. +
  545. + return 0;
  546. +}
  547. +
  548. +
  549. +static const struct i2c_device_id tas5713_i2c_id[] = {
  550. + { "tas5713", 0 },
  551. + { }
  552. +};
  553. +
  554. +MODULE_DEVICE_TABLE(i2c, tas5713_i2c_id);
  555. +
  556. +
  557. +static struct i2c_driver tas5713_i2c_driver = {
  558. + .driver = {
  559. + .name = "tas5713",
  560. + .owner = THIS_MODULE,
  561. + .of_match_table = tas5713_of_match,
  562. + },
  563. + .probe = tas5713_i2c_probe,
  564. + .remove = tas5713_i2c_remove,
  565. + .id_table = tas5713_i2c_id
  566. +};
  567. +
  568. +
  569. +static int __init tas5713_modinit(void)
  570. +{
  571. + int ret = 0;
  572. +
  573. + ret = i2c_add_driver(&tas5713_i2c_driver);
  574. + if (ret) {
  575. + printk(KERN_ERR "Failed to register tas5713 I2C driver: %d\n",
  576. + ret);
  577. + }
  578. +
  579. + return ret;
  580. +}
  581. +module_init(tas5713_modinit);
  582. +
  583. +
  584. +static void __exit tas5713_exit(void)
  585. +{
  586. + i2c_del_driver(&tas5713_i2c_driver);
  587. +}
  588. +module_exit(tas5713_exit);
  589. +
  590. +
  591. +MODULE_AUTHOR("Sebastian Eickhoff <basti.eickhoff@googlemail.com>");
  592. +MODULE_DESCRIPTION("ASoC driver for TAS5713");
  593. +MODULE_LICENSE("GPL v2");
  594. --- /dev/null
  595. +++ b/sound/soc/codecs/tas5713.h
  596. @@ -0,0 +1,210 @@
  597. +/*
  598. + * ASoC Driver for TAS5713
  599. + *
  600. + * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
  601. + * Copyright 2014
  602. + *
  603. + * This program is free software; you can redistribute it and/or
  604. + * modify it under the terms of the GNU General Public License
  605. + * version 2 as published by the Free Software Foundation.
  606. + *
  607. + * This program is distributed in the hope that it will be useful, but
  608. + * WITHOUT ANY WARRANTY; without even the implied warranty of
  609. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  610. + * General Public License for more details.
  611. + */
  612. +
  613. +#ifndef _TAS5713_H
  614. +#define _TAS5713_H
  615. +
  616. +
  617. +// TAS5713 I2C-bus register addresses
  618. +
  619. +#define TAS5713_CLOCK_CTRL 0x00
  620. +#define TAS5713_DEVICE_ID 0x01
  621. +#define TAS5713_ERROR_STATUS 0x02
  622. +#define TAS5713_SYSTEM_CTRL1 0x03
  623. +#define TAS5713_SERIAL_DATA_INTERFACE 0x04
  624. +#define TAS5713_SYSTEM_CTRL2 0x05
  625. +#define TAS5713_SOFT_MUTE 0x06
  626. +#define TAS5713_VOL_MASTER 0x07
  627. +#define TAS5713_VOL_CH1 0x08
  628. +#define TAS5713_VOL_CH2 0x09
  629. +#define TAS5713_VOL_HEADPHONE 0x0A
  630. +#define TAS5713_VOL_CONFIG 0x0E
  631. +#define TAS5713_MODULATION_LIMIT 0x10
  632. +#define TAS5713_IC_DLY_CH1 0x11
  633. +#define TAS5713_IC_DLY_CH2 0x12
  634. +#define TAS5713_IC_DLY_CH3 0x13
  635. +#define TAS5713_IC_DLY_CH4 0x14
  636. +
  637. +#define TAS5713_START_STOP_PERIOD 0x1A
  638. +#define TAS5713_OSC_TRIM 0x1B
  639. +#define TAS5713_BKND_ERR 0x1C
  640. +
  641. +#define TAS5713_INPUT_MUX 0x20
  642. +#define TAS5713_SRC_SELECT_CH4 0x21
  643. +#define TAS5713_PWM_MUX 0x25
  644. +
  645. +#define TAS5713_CH1_BQ0 0x29
  646. +#define TAS5713_CH1_BQ1 0x2A
  647. +#define TAS5713_CH1_BQ2 0x2B
  648. +#define TAS5713_CH1_BQ3 0x2C
  649. +#define TAS5713_CH1_BQ4 0x2D
  650. +#define TAS5713_CH1_BQ5 0x2E
  651. +#define TAS5713_CH1_BQ6 0x2F
  652. +#define TAS5713_CH1_BQ7 0x58
  653. +#define TAS5713_CH1_BQ8 0x59
  654. +
  655. +#define TAS5713_CH2_BQ0 0x30
  656. +#define TAS5713_CH2_BQ1 0x31
  657. +#define TAS5713_CH2_BQ2 0x32
  658. +#define TAS5713_CH2_BQ3 0x33
  659. +#define TAS5713_CH2_BQ4 0x34
  660. +#define TAS5713_CH2_BQ5 0x35
  661. +#define TAS5713_CH2_BQ6 0x36
  662. +#define TAS5713_CH2_BQ7 0x5C
  663. +#define TAS5713_CH2_BQ8 0x5D
  664. +
  665. +#define TAS5713_CH4_BQ0 0x5A
  666. +#define TAS5713_CH4_BQ1 0x5B
  667. +#define TAS5713_CH3_BQ0 0x5E
  668. +#define TAS5713_CH3_BQ1 0x5F
  669. +
  670. +#define TAS5713_DRC1_SOFTENING_FILTER_ALPHA_OMEGA 0x3B
  671. +#define TAS5713_DRC1_ATTACK_RELEASE_RATE 0x3C
  672. +#define TAS5713_DRC2_SOFTENING_FILTER_ALPHA_OMEGA 0x3E
  673. +#define TAS5713_DRC2_ATTACK_RELEASE_RATE 0x3F
  674. +#define TAS5713_DRC1_ATTACK_RELEASE_THRES 0x40
  675. +#define TAS5713_DRC2_ATTACK_RELEASE_THRES 0x43
  676. +#define TAS5713_DRC_CTRL 0x46
  677. +
  678. +#define TAS5713_BANK_SW_CTRL 0x50
  679. +#define TAS5713_CH1_OUTPUT_MIXER 0x51
  680. +#define TAS5713_CH2_OUTPUT_MIXER 0x52
  681. +#define TAS5713_CH1_INPUT_MIXER 0x53
  682. +#define TAS5713_CH2_INPUT_MIXER 0x54
  683. +#define TAS5713_OUTPUT_POST_SCALE 0x56
  684. +#define TAS5713_OUTPUT_PRESCALE 0x57
  685. +
  686. +#define TAS5713_IDF_POST_SCALE 0x62
  687. +
  688. +#define TAS5713_CH1_INLINE_MIXER 0x70
  689. +#define TAS5713_CH1_INLINE_DRC_EN_MIXER 0x71
  690. +#define TAS5713_CH1_R_CHANNEL_MIXER 0x72
  691. +#define TAS5713_CH1_L_CHANNEL_MIXER 0x73
  692. +#define TAS5713_CH2_INLINE_MIXER 0x74
  693. +#define TAS5713_CH2_INLINE_DRC_EN_MIXER 0x75
  694. +#define TAS5713_CH2_L_CHANNEL_MIXER 0x76
  695. +#define TAS5713_CH2_R_CHANNEL_MIXER 0x77
  696. +
  697. +#define TAS5713_UPDATE_DEV_ADDR_KEY 0xF8
  698. +#define TAS5713_UPDATE_DEV_ADDR_REG 0xF9
  699. +
  700. +#define TAS5713_REGISTER_COUNT 0x46
  701. +#define TAS5713_MAX_REGISTER 0xF9
  702. +
  703. +
  704. +// Bitmasks for registers
  705. +#define TAS5713_SOFT_MUTE_ALL 0x07
  706. +
  707. +
  708. +
  709. +struct tas5713_init_command {
  710. + const int size;
  711. + const char *const data;
  712. +};
  713. +
  714. +static const struct tas5713_init_command tas5713_init_sequence[] = {
  715. +
  716. + // Trim oscillator
  717. + { .size = 2, .data = "\x1B\x00" },
  718. + // System control register 1 (0x03): block DC
  719. + { .size = 2, .data = "\x03\x80" },
  720. + // Mute everything
  721. + { .size = 2, .data = "\x05\x40" },
  722. + // Modulation limit register (0x10): 97.7%
  723. + { .size = 2, .data = "\x10\x02" },
  724. + // Interchannel delay registers
  725. + // (0x11, 0x12, 0x13, and 0x14): BD mode
  726. + { .size = 2, .data = "\x11\xB8" },
  727. + { .size = 2, .data = "\x12\x60" },
  728. + { .size = 2, .data = "\x13\xA0" },
  729. + { .size = 2, .data = "\x14\x48" },
  730. + // PWM shutdown group register (0x19): no shutdown
  731. + { .size = 2, .data = "\x19\x00" },
  732. + // Input multiplexer register (0x20): BD mode
  733. + { .size = 2, .data = "\x20\x00\x89\x77\x72" },
  734. + // PWM output mux register (0x25)
  735. + // Channel 1 --> OUTA, channel 1 neg --> OUTB
  736. + // Channel 2 --> OUTC, channel 2 neg --> OUTD
  737. + { .size = 5, .data = "\x25\x01\x02\x13\x45" },
  738. + // DRC control (0x46): DRC off
  739. + { .size = 5, .data = "\x46\x00\x00\x00\x00" },
  740. + // BKND_ERR register (0x1C): 299ms reset period
  741. + { .size = 2, .data = "\x1C\x07" },
  742. + // Mute channel 3
  743. + { .size = 2, .data = "\x0A\xFF" },
  744. + // Volume configuration register (0x0E): volume slew 512 steps
  745. + { .size = 2, .data = "\x0E\x90" },
  746. + // Clock control register (0x00): 44/48kHz, MCLK=64xfs
  747. + { .size = 2, .data = "\x00\x60" },
  748. + // Bank switch and eq control (0x50): no bank switching
  749. + { .size = 5, .data = "\x50\x00\x00\x00\x00" },
  750. + // Volume registers (0x07, 0x08, 0x09, 0x0A)
  751. + { .size = 2, .data = "\x07\x20" },
  752. + { .size = 2, .data = "\x08\x30" },
  753. + { .size = 2, .data = "\x09\x30" },
  754. + { .size = 2, .data = "\x0A\xFF" },
  755. + // 0x72, 0x73, 0x76, 0x77 input mixer:
  756. + // no intermix between channels
  757. + { .size = 5, .data = "\x72\x00\x00\x00\x00" },
  758. + { .size = 5, .data = "\x73\x00\x80\x00\x00" },
  759. + { .size = 5, .data = "\x76\x00\x00\x00\x00" },
  760. + { .size = 5, .data = "\x77\x00\x80\x00\x00" },
  761. + // 0x70, 0x71, 0x74, 0x75 inline DRC mixer:
  762. + // no inline DRC inmix
  763. + { .size = 5, .data = "\x70\x00\x80\x00\x00" },
  764. + { .size = 5, .data = "\x71\x00\x00\x00\x00" },
  765. + { .size = 5, .data = "\x74\x00\x80\x00\x00" },
  766. + { .size = 5, .data = "\x75\x00\x00\x00\x00" },
  767. + // 0x56, 0x57 Output scale
  768. + { .size = 5, .data = "\x56\x00\x80\x00\x00" },
  769. + { .size = 5, .data = "\x57\x00\x02\x00\x00" },
  770. + // 0x3B, 0x3c
  771. + { .size = 9, .data = "\x3B\x00\x08\x00\x00\x00\x78\x00\x00" },
  772. + { .size = 9, .data = "\x3C\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
  773. + { .size = 9, .data = "\x3E\x00\x08\x00\x00\x00\x78\x00\x00" },
  774. + { .size = 9, .data = "\x3F\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
  775. + { .size = 9, .data = "\x40\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
  776. + { .size = 9, .data = "\x43\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
  777. + // 0x51, 0x52: output mixer
  778. + { .size = 9, .data = "\x51\x00\x80\x00\x00\x00\x00\x00\x00" },
  779. + { .size = 9, .data = "\x52\x00\x80\x00\x00\x00\x00\x00\x00" },
  780. + // PEQ defaults
  781. + { .size = 21, .data = "\x29\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  782. + { .size = 21, .data = "\x2A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  783. + { .size = 21, .data = "\x2B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  784. + { .size = 21, .data = "\x2C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  785. + { .size = 21, .data = "\x2D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  786. + { .size = 21, .data = "\x2E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  787. + { .size = 21, .data = "\x2F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  788. + { .size = 21, .data = "\x30\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  789. + { .size = 21, .data = "\x31\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  790. + { .size = 21, .data = "\x32\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  791. + { .size = 21, .data = "\x33\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  792. + { .size = 21, .data = "\x34\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  793. + { .size = 21, .data = "\x35\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  794. + { .size = 21, .data = "\x36\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  795. + { .size = 21, .data = "\x58\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  796. + { .size = 21, .data = "\x59\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  797. + { .size = 21, .data = "\x5C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  798. + { .size = 21, .data = "\x5D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  799. + { .size = 21, .data = "\x5E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  800. + { .size = 21, .data = "\x5F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  801. + { .size = 21, .data = "\x5A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  802. + { .size = 21, .data = "\x5B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
  803. +};
  804. +
  805. +
  806. +#endif /* _TAS5713_H */