brcm2708: switch to linux 4.4 and update patches
[openwrt.git] / target / linux / brcm2708 / patches-4.4 / 0072-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch
1 From eb7a554225c0ac786a6795f330b8ccf7454b5ff8 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 072/156] Added driver for HiFiBerry Amp amplifier add-on board
5
6 The driver contains a low-level hardware driver for the TAS5713 and the
7 drivers for the Raspberry Pi I2S subsystem.
8
9 TAS5713: return error if initialisation fails
10
11 Existing TAS5713 driver logs errors during initialisation, but does not return
12 an error code. Therefore even if initialisation fails, the driver will still be
13 loaded, but won't work. This patch fixes this. I2C communication error will now
14 reported correctly by a non-zero return code.
15
16 HiFiBerry Amp: fix device-tree problems
17
18 Some code to load the driver based on device-tree-overlays was missing. This is added by this patch.
19 ---
20  sound/soc/bcm/Kconfig         |   7 +
21  sound/soc/bcm/Makefile        |   2 +
22  sound/soc/bcm/hifiberry_amp.c | 127 +++++++++++++++
23  sound/soc/codecs/Kconfig      |   4 +
24  sound/soc/codecs/Makefile     |   2 +
25  sound/soc/codecs/tas5713.c    | 369 ++++++++++++++++++++++++++++++++++++++++++
26  sound/soc/codecs/tas5713.h    | 210 ++++++++++++++++++++++++
27  7 files changed, 721 insertions(+)
28  create mode 100644 sound/soc/bcm/hifiberry_amp.c
29  create mode 100644 sound/soc/codecs/tas5713.c
30  create mode 100644 sound/soc/codecs/tas5713.h
31
32 --- a/sound/soc/bcm/Kconfig
33 +++ b/sound/soc/bcm/Kconfig
34 @@ -29,6 +29,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DIGI
35          help
36           Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
37  
38 +config SND_BCM2708_SOC_HIFIBERRY_AMP
39 +        tristate "Support for the HifiBerry Amp"
40 +        depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
41 +        select SND_SOC_TAS5713
42 +        help
43 +         Say Y or M if you want to add support for the HifiBerry Amp amplifier board.
44 +
45  config SND_BCM2708_SOC_RPI_DAC
46          tristate "Support for RPi-DAC"
47          depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
48 --- a/sound/soc/bcm/Makefile
49 +++ b/sound/soc/bcm/Makefile
50 @@ -7,11 +7,13 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
51  snd-soc-hifiberry-dac-objs := hifiberry_dac.o
52  snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
53  snd-soc-hifiberry-digi-objs := hifiberry_digi.o
54 +snd-soc-hifiberry-amp-objs := hifiberry_amp.o
55  snd-soc-rpi-dac-objs := rpi-dac.o
56  snd-soc-iqaudio-dac-objs := iqaudio-dac.o
57  
58  obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
59  obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
60  obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
61 +obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
62  obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
63  obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
64 --- /dev/null
65 +++ b/sound/soc/bcm/hifiberry_amp.c
66 @@ -0,0 +1,127 @@
67 +/*
68 + * ASoC Driver for HifiBerry AMP
69 + *
70 + * Author:     Sebastian Eickhoff <basti.eickhoff@googlemail.com>
71 + *             Copyright 2014
72 + *
73 + * This program is free software; you can redistribute it and/or
74 + * modify it under the terms of the GNU General Public License
75 + * version 2 as published by the Free Software Foundation.
76 + *
77 + * This program is distributed in the hope that it will be useful, but
78 + * WITHOUT ANY WARRANTY; without even the implied warranty of
79 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
80 + * General Public License for more details.
81 + */
82 +
83 +#include <linux/module.h>
84 +#include <linux/platform_device.h>
85 +
86 +#include <sound/core.h>
87 +#include <sound/pcm.h>
88 +#include <sound/pcm_params.h>
89 +#include <sound/soc.h>
90 +#include <sound/jack.h>
91 +
92 +static int snd_rpi_hifiberry_amp_init(struct snd_soc_pcm_runtime *rtd)
93 +{
94 +       // ToDo: init of the dsp-registers.
95 +       return 0;
96 +}
97 +
98 +static int snd_rpi_hifiberry_amp_hw_params( struct snd_pcm_substream *substream,
99 +                                      struct snd_pcm_hw_params *params )
100 +{
101 +       struct snd_soc_pcm_runtime *rtd = substream->private_data;
102 +       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
103 +
104 +       return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
105 +}
106 +
107 +static struct snd_soc_ops snd_rpi_hifiberry_amp_ops = {
108 +       .hw_params = snd_rpi_hifiberry_amp_hw_params,
109 +};
110 +
111 +static struct snd_soc_dai_link snd_rpi_hifiberry_amp_dai[] = {
112 +    {
113 +               .name                   = "HifiBerry AMP",
114 +               .stream_name    = "HifiBerry AMP HiFi",
115 +               .cpu_dai_name   = "bcm2708-i2s.0",
116 +               .codec_dai_name = "tas5713-hifi",
117 +               .platform_name  = "bcm2708-i2s.0",
118 +               .codec_name             = "tas5713.1-001b",
119 +               .dai_fmt                = SND_SOC_DAIFMT_I2S |
120 +                                                 SND_SOC_DAIFMT_NB_NF |
121 +                                                 SND_SOC_DAIFMT_CBS_CFS,
122 +               .ops                    = &snd_rpi_hifiberry_amp_ops,
123 +               .init                   = snd_rpi_hifiberry_amp_init,
124 +       },
125 +};
126 +
127 +
128 +static struct snd_soc_card snd_rpi_hifiberry_amp = {
129 +       .name         = "snd_rpi_hifiberry_amp",
130 +       .dai_link     = snd_rpi_hifiberry_amp_dai,
131 +       .num_links    = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai),
132 +};
133 +
134 +static const struct of_device_id snd_rpi_hifiberry_amp_of_match[] = {
135 +        { .compatible = "hifiberry,hifiberry-amp", },
136 +        {},
137 +};
138 +MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_amp_of_match);
139 +
140 +
141 +static int snd_rpi_hifiberry_amp_probe(struct platform_device *pdev)
142 +{
143 +       int ret = 0;
144 +
145 +       snd_rpi_hifiberry_amp.dev = &pdev->dev;
146 +
147 +        if (pdev->dev.of_node) {
148 +            struct device_node *i2s_node;
149 +            struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_amp_dai[0];
150 +            i2s_node = of_parse_phandle(pdev->dev.of_node,
151 +                                        "i2s-controller", 0);
152 +
153 +            if (i2s_node) {
154 +                dai->cpu_dai_name = NULL;
155 +                dai->cpu_of_node = i2s_node;
156 +                dai->platform_name = NULL;
157 +                dai->platform_of_node = i2s_node;
158 +            }
159 +        }
160 +
161 +       ret = snd_soc_register_card(&snd_rpi_hifiberry_amp);
162 +
163 +       if (ret != 0) {
164 +               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
165 +       }
166 +
167 +       return ret;
168 +}
169 +
170 +
171 +static int snd_rpi_hifiberry_amp_remove(struct platform_device *pdev)
172 +{
173 +       return snd_soc_unregister_card(&snd_rpi_hifiberry_amp);
174 +}
175 +
176 +
177 +static struct platform_driver snd_rpi_hifiberry_amp_driver = {
178 +        .driver = {
179 +                .name   = "snd-hifiberry-amp",
180 +                .owner  = THIS_MODULE,
181 +               .of_match_table = snd_rpi_hifiberry_amp_of_match,
182 +        },
183 +        .probe          = snd_rpi_hifiberry_amp_probe,
184 +        .remove         = snd_rpi_hifiberry_amp_remove,
185 +};
186 +
187 +
188 +module_platform_driver(snd_rpi_hifiberry_amp_driver);
189 +
190 +
191 +MODULE_AUTHOR("Sebastian Eickhoff <basti.eickhoff@googlemail.com>");
192 +MODULE_DESCRIPTION("ASoC driver for HiFiBerry-AMP");
193 +MODULE_LICENSE("GPL v2");
194 --- a/sound/soc/codecs/Kconfig
195 +++ b/sound/soc/codecs/Kconfig
196 @@ -117,6 +117,7 @@ config SND_SOC_ALL_CODECS
197         select SND_SOC_TFA9879 if I2C
198         select SND_SOC_TLV320AIC23_I2C if I2C
199         select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
200 +       select SND_SOC_TAS5713 if I2C
201         select SND_SOC_TLV320AIC26 if SPI_MASTER
202         select SND_SOC_TLV320AIC31XX if I2C
203         select SND_SOC_TLV320AIC32X4 if I2C
204 @@ -674,6 +675,9 @@ config SND_SOC_TFA9879
205         tristate "NXP Semiconductors TFA9879 amplifier"
206         depends on I2C
207  
208 +config SND_SOC_TAS5713
209 +       tristate
210 +
211  config SND_SOC_TLV320AIC23
212         tristate
213  
214 --- a/sound/soc/codecs/Makefile
215 +++ b/sound/soc/codecs/Makefile
216 @@ -118,6 +118,7 @@ snd-soc-sti-sas-objs := sti-sas.o
217  snd-soc-tas5086-objs := tas5086.o
218  snd-soc-tas571x-objs := tas571x.o
219  snd-soc-tfa9879-objs := tfa9879.o
220 +snd-soc-tas5713-objs := tas5713.o
221  snd-soc-tlv320aic23-objs := tlv320aic23.o
222  snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
223  snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
224 @@ -312,6 +313,7 @@ obj-$(CONFIG_SND_SOC_TAS2552)       += snd-soc
225  obj-$(CONFIG_SND_SOC_TAS5086)  += snd-soc-tas5086.o
226  obj-$(CONFIG_SND_SOC_TAS571X)  += snd-soc-tas571x.o
227  obj-$(CONFIG_SND_SOC_TFA9879)  += snd-soc-tfa9879.o
228 +obj-$(CONFIG_SND_SOC_TAS5713)  += snd-soc-tas5713.o
229  obj-$(CONFIG_SND_SOC_TLV320AIC23)      += snd-soc-tlv320aic23.o
230  obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C)  += snd-soc-tlv320aic23-i2c.o
231  obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI)  += snd-soc-tlv320aic23-spi.o
232 --- /dev/null
233 +++ b/sound/soc/codecs/tas5713.c
234 @@ -0,0 +1,369 @@
235 +/*
236 + * ASoC Driver for TAS5713
237 + *
238 + * Author:     Sebastian Eickhoff <basti.eickhoff@googlemail.com>
239 + *             Copyright 2014
240 + *
241 + * This program is free software; you can redistribute it and/or
242 + * modify it under the terms of the GNU General Public License
243 + * version 2 as published by the Free Software Foundation.
244 + *
245 + * This program is distributed in the hope that it will be useful, but
246 + * WITHOUT ANY WARRANTY; without even the implied warranty of
247 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
248 + * General Public License for more details.
249 + */
250 +
251 +#include <linux/module.h>
252 +#include <linux/moduleparam.h>
253 +#include <linux/init.h>
254 +#include <linux/delay.h>
255 +#include <linux/pm.h>
256 +#include <linux/i2c.h>
257 +#include <linux/of_device.h>
258 +#include <linux/spi/spi.h>
259 +#include <linux/regmap.h>
260 +#include <linux/regulator/consumer.h>
261 +#include <linux/slab.h>
262 +#include <sound/core.h>
263 +#include <sound/pcm.h>
264 +#include <sound/pcm_params.h>
265 +#include <sound/soc.h>
266 +#include <sound/initval.h>
267 +#include <sound/tlv.h>
268 +
269 +#include <linux/kernel.h>
270 +#include <linux/string.h>
271 +#include <linux/fs.h>
272 +#include <asm/uaccess.h>
273 +
274 +#include "tas5713.h"
275 +
276 +
277 +static struct i2c_client *i2c;
278 +
279 +struct tas5713_priv {
280 +       struct regmap *regmap;
281 +       int mclk_div;
282 +       struct snd_soc_codec *codec;
283 +};
284 +
285 +static struct tas5713_priv *priv_data;
286 +
287 +
288 +
289 +
290 +/*
291 + *    _   _    ___   _      ___         _           _
292 + *   /_\ | |  / __| /_\    / __|___ _ _| |_ _ _ ___| |___
293 + *  / _ \| |__\__ \/ _ \  | (__/ _ \ ' \  _| '_/ _ \ (_-<
294 + * /_/ \_\____|___/_/ \_\  \___\___/_||_\__|_| \___/_/__/
295 + *
296 + */
297 +
298 +static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1);
299 +
300 +
301 +static const struct snd_kcontrol_new tas5713_snd_controls[] = {
302 +       SOC_SINGLE_TLV  ("Master"    , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv),
303 +       SOC_DOUBLE_R_TLV("Channels"  , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv)
304 +};
305 +
306 +
307 +
308 +
309 +/*
310 + *  __  __         _    _            ___      _
311 + * |  \/  |__ _ __| |_ (_)_ _  ___  |   \ _ _(_)_ _____ _ _
312 + * | |\/| / _` / _| ' \| | ' \/ -_) | |) | '_| \ V / -_) '_|
313 + * |_|  |_\__,_\__|_||_|_|_||_\___| |___/|_| |_|\_/\___|_|
314 + *
315 + */
316 +
317 +static int tas5713_hw_params(struct snd_pcm_substream *substream,
318 +                           struct snd_pcm_hw_params *params,
319 +                           struct snd_soc_dai *dai)
320 +{
321 +       u16 blen = 0x00;
322 +
323 +       struct snd_soc_codec *codec;
324 +       codec = dai->codec;
325 +       priv_data->codec = dai->codec;
326 +
327 +       switch (params_format(params)) {
328 +       case SNDRV_PCM_FORMAT_S16_LE:
329 +               blen = 0x03;
330 +               break;
331 +       case SNDRV_PCM_FORMAT_S20_3LE:
332 +               blen = 0x1;
333 +               break;
334 +       case SNDRV_PCM_FORMAT_S24_LE:
335 +               blen = 0x04;
336 +               break;
337 +       case SNDRV_PCM_FORMAT_S32_LE:
338 +               blen = 0x05;
339 +               break;
340 +       default:
341 +               dev_err(dai->dev, "Unsupported word length: %u\n",
342 +                       params_format(params));
343 +               return -EINVAL;
344 +       }
345 +
346 +       // set word length
347 +       snd_soc_update_bits(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x7, blen);
348 +
349 +       return 0;
350 +}
351 +
352 +
353 +static int tas5713_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
354 +{
355 +       unsigned int val = 0;
356 +
357 +       struct tas5713_priv *tas5713;
358 +       struct snd_soc_codec *codec = dai->codec;
359 +       tas5713 = snd_soc_codec_get_drvdata(codec);
360 +
361 +       if (mute) {
362 +               val = TAS5713_SOFT_MUTE_ALL;
363 +       }
364 +
365 +       return regmap_write(tas5713->regmap, TAS5713_SOFT_MUTE, val);
366 +}
367 +
368 +
369 +static const struct snd_soc_dai_ops tas5713_dai_ops = {
370 +       .hw_params              = tas5713_hw_params,
371 +       .mute_stream    = tas5713_mute_stream,
372 +};
373 +
374 +
375 +static struct snd_soc_dai_driver tas5713_dai = {
376 +       .name           = "tas5713-hifi",
377 +       .playback       = {
378 +               .stream_name    = "Playback",
379 +               .channels_min   = 2,
380 +               .channels_max   = 2,
381 +               .rates              = SNDRV_PCM_RATE_8000_48000,
382 +               .formats            = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE ),
383 +       },
384 +       .ops        = &tas5713_dai_ops,
385 +};
386 +
387 +
388 +
389 +
390 +/*
391 + *   ___         _          ___      _
392 + *  / __|___  __| |___ __  |   \ _ _(_)_ _____ _ _
393 + * | (__/ _ \/ _` / -_) _| | |) | '_| \ V / -_) '_|
394 + *  \___\___/\__,_\___\__| |___/|_| |_|\_/\___|_|
395 + *
396 + */
397 +
398 +static int tas5713_remove(struct snd_soc_codec *codec)
399 +{
400 +       struct tas5713_priv *tas5713;
401 +
402 +       tas5713 = snd_soc_codec_get_drvdata(codec);
403 +
404 +       return 0;
405 +}
406 +
407 +
408 +static int tas5713_probe(struct snd_soc_codec *codec)
409 +{
410 +       struct tas5713_priv *tas5713;
411 +       int i, ret;
412 +
413 +       i2c = container_of(codec->dev, struct i2c_client, dev);
414 +
415 +       tas5713 = snd_soc_codec_get_drvdata(codec);
416 +
417 +       // Reset error
418 +       ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00);
419 +       if (ret < 0) return ret;
420 +
421 +       // Trim oscillator
422 +       ret = snd_soc_write(codec, TAS5713_OSC_TRIM, 0x00);
423 +       if (ret < 0) return ret;
424 +       msleep(1000);
425 +
426 +       // Reset error
427 +       ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00);
428 +       if (ret < 0) return ret;
429 +
430 +       // Clock mode: 44/48kHz, MCLK=64xfs
431 +       ret = snd_soc_write(codec, TAS5713_CLOCK_CTRL, 0x60);
432 +       if (ret < 0) return ret;
433 +
434 +       // I2S 24bit
435 +       ret = snd_soc_write(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x05);
436 +       if (ret < 0) return ret;
437 +
438 +       // Unmute
439 +       ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00);
440 +       if (ret < 0) return ret;
441 +       ret = snd_soc_write(codec, TAS5713_SOFT_MUTE, 0x00);
442 +       if (ret < 0) return ret;
443 +
444 +       // Set volume to 0db
445 +       ret = snd_soc_write(codec, TAS5713_VOL_MASTER, 0x00);
446 +       if (ret < 0) return ret;
447 +
448 +       // Now start programming the default initialization sequence
449 +       for (i = 0; i < ARRAY_SIZE(tas5713_init_sequence); ++i) {
450 +               ret = i2c_master_send(i2c,
451 +                                    tas5713_init_sequence[i].data,
452 +                                    tas5713_init_sequence[i].size);
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 +       if (ret < 0) return ret;
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 */