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