0061-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch 27 KB

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