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