aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2014-09-01 11:36:34 -0400
committerMark Brown <broonie@kernel.org>2014-09-01 11:36:34 -0400
commit025b78b809134ae710efca7ccf0a84b927ffb7c4 (patch)
treeb091bbcb46e23bbd932bdc8e7c541503f5b9fa20
parent855675f6e6a65688a7f4cf45b9b5a98cf6c6f5c3 (diff)
parent014fd22ef9c6a7e9536b7e16635714a1a34810a8 (diff)
Merge branch 'topic/fsl' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-fsl-sai
-rw-r--r--Documentation/devicetree/bindings/regmap/regmap.txt47
-rw-r--r--Documentation/devicetree/bindings/sound/es8328.txt38
-rw-r--r--Documentation/devicetree/bindings/sound/fsl-asoc-card.txt82
-rw-r--r--Documentation/devicetree/bindings/sound/fsl-sai.txt7
-rw-r--r--Documentation/devicetree/bindings/sound/imx-audio-es8328.txt60
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt1
-rw-r--r--drivers/base/regmap/regmap-i2c.c2
-rw-r--r--drivers/base/regmap/regmap-spi.c2
-rw-r--r--drivers/base/regmap/regmap.c74
-rw-r--r--sound/soc/codecs/Kconfig13
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/es8328-i2c.c60
-rw-r--r--sound/soc/codecs/es8328-spi.c49
-rw-r--r--sound/soc/codecs/es8328.c756
-rw-r--r--sound/soc/codecs/es8328.h314
-rw-r--r--sound/soc/fsl/Kconfig29
-rw-r--r--sound/soc/fsl/Makefile4
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c574
-rw-r--r--sound/soc/fsl/fsl_asrc.c6
-rw-r--r--sound/soc/fsl/fsl_esai.c5
-rw-r--r--sound/soc/fsl/fsl_sai.c6
-rw-r--r--sound/soc/fsl/fsl_sai.h1
-rw-r--r--sound/soc/fsl/fsl_spdif.c5
-rw-r--r--sound/soc/fsl/imx-es8328.c232
24 files changed, 2339 insertions, 34 deletions
diff --git a/Documentation/devicetree/bindings/regmap/regmap.txt b/Documentation/devicetree/bindings/regmap/regmap.txt
new file mode 100644
index 000000000000..b494f8b8ef72
--- /dev/null
+++ b/Documentation/devicetree/bindings/regmap/regmap.txt
@@ -0,0 +1,47 @@
1Device-Tree binding for regmap
2
3The endianness mode of CPU & Device scenarios:
4Index Device Endianness properties
5---------------------------------------------------
61 BE 'big-endian'
72 LE 'little-endian'
8
9For one device driver, which will run in different scenarios above
10on different SoCs using the devicetree, we need one way to simplify
11this.
12
13Required properties:
14- {big,little}-endian: these are boolean properties, if absent
15 meaning that the CPU and the Device are in the same endianness mode,
16 these properties are for register values and all the buffers only.
17
18Examples:
19Scenario 1 : CPU in LE mode & device in LE mode.
20dev: dev@40031000 {
21 compatible = "name";
22 reg = <0x40031000 0x1000>;
23 ...
24};
25
26Scenario 2 : CPU in LE mode & device in BE mode.
27dev: dev@40031000 {
28 compatible = "name";
29 reg = <0x40031000 0x1000>;
30 ...
31 big-endian;
32};
33
34Scenario 3 : CPU in BE mode & device in BE mode.
35dev: dev@40031000 {
36 compatible = "name";
37 reg = <0x40031000 0x1000>;
38 ...
39};
40
41Scenario 4 : CPU in BE mode & device in LE mode.
42dev: dev@40031000 {
43 compatible = "name";
44 reg = <0x40031000 0x1000>;
45 ...
46 little-endian;
47};
diff --git a/Documentation/devicetree/bindings/sound/es8328.txt b/Documentation/devicetree/bindings/sound/es8328.txt
new file mode 100644
index 000000000000..30ea8a318ae9
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/es8328.txt
@@ -0,0 +1,38 @@
1Everest ES8328 audio CODEC
2
3This device supports both I2C and SPI.
4
5Required properties:
6
7 - compatible : "everest,es8328"
8 - DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V
9 - AVDD-supply : Regulator providing analog supply voltage 3.3V
10 - PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V
11 - IPVDD-supply : Regulator providing analog output voltage 3.3V
12 - clocks : A 22.5792 or 11.2896 MHz clock
13 - reg : the I2C address of the device for I2C, the chip select number for SPI
14
15Pins on the device (for linking into audio routes):
16
17 * LOUT1
18 * LOUT2
19 * ROUT1
20 * ROUT2
21 * LINPUT1
22 * RINPUT1
23 * LINPUT2
24 * RINPUT2
25 * Mic Bias
26
27
28Example:
29
30codec: es8328@11 {
31 compatible = "everest,es8328";
32 DVDD-supply = <&reg_3p3v>;
33 AVDD-supply = <&reg_3p3v>;
34 PVDD-supply = <&reg_3p3v>;
35 HPVDD-supply = <&reg_3p3v>;
36 clocks = <&clks 169>;
37 reg = <0x11>;
38};
diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
new file mode 100644
index 000000000000..a96774c194c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
@@ -0,0 +1,82 @@
1Freescale Generic ASoC Sound Card with ASRC support
2
3The Freescale Generic ASoC Sound Card can be used, ideally, for all Freescale
4SoCs connecting with external CODECs.
5
6The idea of this generic sound card is a bit like ASoC Simple Card. However,
7for Freescale SoCs (especially those released in recent years), most of them
8have ASRC (Documentation/devicetree/bindings/sound/fsl,asrc.txt) inside. And
9this is a specific feature that might be painstakingly controlled and merged
10into the Simple Card.
11
12So having this generic sound card allows all Freescale SoC users to benefit
13from the simplification of a new card support and the capability of the wide
14sample rates support through ASRC.
15
16Note: The card is initially designed for those sound cards who use I2S and
17 PCM DAI formats. However, it'll be also possible to support those non
18 I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as long
19 as the driver has been properly upgraded.
20
21
22The compatible list for this generic sound card currently:
23 "fsl,imx-audio-cs42888"
24
25 "fsl,imx-audio-wm8962"
26 (compatible with Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt)
27
28 "fsl,imx-audio-sgtl5000"
29 (compatible with Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt)
30
31Required properties:
32
33 - compatible : Contains one of entries in the compatible list.
34
35 - model : The user-visible name of this sound complex
36
37 - audio-cpu : The phandle of an CPU DAI controller
38
39 - audio-codec : The phandle of an audio codec
40
41 - audio-routing : A list of the connections between audio components.
42 Each entry is a pair of strings, the first being the
43 connection's sink, the second being the connection's
44 source. There're a few pre-designed board connectors:
45 * Line Out Jack
46 * Line In Jack
47 * Headphone Jack
48 * Mic Jack
49 * Ext Spk
50 * AMIC (stands for Analog Microphone Jack)
51 * DMIC (stands for Digital Microphone Jack)
52
53 Note: The "Mic Jack" and "AMIC" are redundant while
54 coexsiting in order to support the old bindings
55 of wm8962 and sgtl5000.
56
57Optional properties:
58
59 - audio-asrc : The phandle of ASRC. It can be absent if there's no
60 need to add ASRC support via DPCM.
61
62Example:
63sound-cs42888 {
64 compatible = "fsl,imx-audio-cs42888";
65 model = "cs42888-audio";
66 audio-cpu = <&esai>;
67 audio-asrc = <&asrc>;
68 audio-codec = <&cs42888>;
69 audio-routing =
70 "Line Out Jack", "AOUT1L",
71 "Line Out Jack", "AOUT1R",
72 "Line Out Jack", "AOUT2L",
73 "Line Out Jack", "AOUT2R",
74 "Line Out Jack", "AOUT3L",
75 "Line Out Jack", "AOUT3R",
76 "Line Out Jack", "AOUT4L",
77 "Line Out Jack", "AOUT4R",
78 "AIN1L", "Line In Jack",
79 "AIN1R", "Line In Jack",
80 "AIN2L", "Line In Jack",
81 "AIN2R", "Line In Jack";
82};
diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt
index dc9f9c356268..06a405e7f3e7 100644
--- a/Documentation/devicetree/bindings/sound/fsl-sai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt
@@ -18,9 +18,8 @@ Required properties:
18- pinctrl-names: Must contain a "default" entry. 18- pinctrl-names: Must contain a "default" entry.
19- pinctrl-NNN: One property must exist for each entry in pinctrl-names. 19- pinctrl-NNN: One property must exist for each entry in pinctrl-names.
20 See ../pinctrl/pinctrl-bindings.txt for details of the property values. 20 See ../pinctrl/pinctrl-bindings.txt for details of the property values.
21- big-endian-regs: If this property is absent, the little endian mode will 21- big-endian: Boolean property, required if all the FTM_PWM registers
22 be in use as default, or the big endian mode will be in use for all the 22 are big-endian rather than little-endian.
23 device registers.
24- big-endian-data: If this property is absent, the little endian mode will 23- big-endian-data: If this property is absent, the little endian mode will
25 be in use as default, or the big endian mode will be in use for all the 24 be in use as default, or the big endian mode will be in use for all the
26 fifo data. 25 fifo data.
@@ -53,6 +52,6 @@ sai2: sai@40031000 {
53 dma-names = "tx", "rx"; 52 dma-names = "tx", "rx";
54 dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>, 53 dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>,
55 <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>; 54 <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>;
56 big-endian-regs; 55 big-endian;
57 big-endian-data; 56 big-endian-data;
58}; 57};
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt b/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt
new file mode 100644
index 000000000000..07b68ab206fb
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/imx-audio-es8328.txt
@@ -0,0 +1,60 @@
1Freescale i.MX audio complex with ES8328 codec
2
3Required properties:
4- compatible : "fsl,imx-audio-es8328"
5- model : The user-visible name of this sound complex
6- ssi-controller : The phandle of the i.MX SSI controller
7- jack-gpio : Optional GPIO for headphone jack
8- audio-amp-supply : Power regulator for speaker amps
9- audio-codec : The phandle of the ES8328 audio codec
10- audio-routing : A list of the connections between audio components.
11 Each entry is a pair of strings, the first being the
12 connection's sink, the second being the connection's
13 source. Valid names could be power supplies, ES8328
14 pins, and the jacks on the board:
15
16 Power supplies:
17 * audio-amp
18
19 ES8328 pins:
20 * LOUT1
21 * LOUT2
22 * ROUT1
23 * ROUT2
24 * LINPUT1
25 * LINPUT2
26 * RINPUT1
27 * RINPUT2
28 * Mic PGA
29
30 Board connectors:
31 * Headphone
32 * Speaker
33 * Mic Jack
34- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
35- mux-ext-port : The external port of the i.MX audio muxer (AUDMIX)
36
37Note: The AUDMUX port numbering should start at 1, which is consistent with
38hardware manual.
39
40Example:
41
42sound {
43 compatible = "fsl,imx-audio-es8328";
44 model = "imx-audio-es8328";
45 ssi-controller = <&ssi1>;
46 audio-codec = <&codec>;
47 jack-gpio = <&gpio5 15 0>;
48 audio-amp-supply = <&reg_audio_amp>;
49 audio-routing =
50 "Speaker", "LOUT2",
51 "Speaker", "ROUT2",
52 "Speaker", "audio-amp",
53 "Headphone", "ROUT1",
54 "Headphone", "LOUT1",
55 "LINPUT1", "Mic Jack",
56 "RINPUT1", "Mic Jack",
57 "Mic Jack", "Mic Bias";
58 mux-int-port = <1>;
59 mux-ext-port = <3>;
60};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index ac7269f90764..34cc1bfcebfd 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -48,6 +48,7 @@ epfl Ecole Polytechnique Fédérale de Lausanne
48epson Seiko Epson Corp. 48epson Seiko Epson Corp.
49est ESTeem Wireless Modems 49est ESTeem Wireless Modems
50eukrea Eukréa Electromatique 50eukrea Eukréa Electromatique
51everest Everest Semiconductor Co. Ltd.
51excito Excito 52excito Excito
52fsl Freescale Semiconductor 53fsl Freescale Semiconductor
53GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. 54GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index ca193d1ef47c..053150a7f9f2 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -168,6 +168,8 @@ static struct regmap_bus regmap_i2c = {
168 .write = regmap_i2c_write, 168 .write = regmap_i2c_write,
169 .gather_write = regmap_i2c_gather_write, 169 .gather_write = regmap_i2c_gather_write,
170 .read = regmap_i2c_read, 170 .read = regmap_i2c_read,
171 .reg_format_endian_default = REGMAP_ENDIAN_BIG,
172 .val_format_endian_default = REGMAP_ENDIAN_BIG,
171}; 173};
172 174
173static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, 175static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c
index 0eb3097c0d76..53d1148e80a0 100644
--- a/drivers/base/regmap/regmap-spi.c
+++ b/drivers/base/regmap/regmap-spi.c
@@ -109,6 +109,8 @@ static struct regmap_bus regmap_spi = {
109 .async_alloc = regmap_spi_async_alloc, 109 .async_alloc = regmap_spi_async_alloc,
110 .read = regmap_spi_read, 110 .read = regmap_spi_read,
111 .read_flag_mask = 0x80, 111 .read_flag_mask = 0x80,
112 .reg_format_endian_default = REGMAP_ENDIAN_BIG,
113 .val_format_endian_default = REGMAP_ENDIAN_BIG,
112}; 114};
113 115
114/** 116/**
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 78f43fb2fe84..01ae4b829360 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -15,6 +15,7 @@
15#include <linux/export.h> 15#include <linux/export.h>
16#include <linux/mutex.h> 16#include <linux/mutex.h>
17#include <linux/err.h> 17#include <linux/err.h>
18#include <linux/of.h>
18#include <linux/rbtree.h> 19#include <linux/rbtree.h>
19#include <linux/sched.h> 20#include <linux/sched.h>
20 21
@@ -448,6 +449,66 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
448} 449}
449EXPORT_SYMBOL_GPL(regmap_attach_dev); 450EXPORT_SYMBOL_GPL(regmap_attach_dev);
450 451
452static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus,
453 const struct regmap_config *config)
454{
455 enum regmap_endian endian;
456
457 /* Retrieve the endianness specification from the regmap config */
458 endian = config->reg_format_endian;
459
460 /* If the regmap config specified a non-default value, use that */
461 if (endian != REGMAP_ENDIAN_DEFAULT)
462 return endian;
463
464 /* Retrieve the endianness specification from the bus config */
465 if (bus && bus->reg_format_endian_default)
466 endian = bus->reg_format_endian_default;
467
468 /* If the bus specified a non-default value, use that */
469 if (endian != REGMAP_ENDIAN_DEFAULT)
470 return endian;
471
472 /* Use this if no other value was found */
473 return REGMAP_ENDIAN_BIG;
474}
475
476static enum regmap_endian regmap_get_val_endian(struct device *dev,
477 const struct regmap_bus *bus,
478 const struct regmap_config *config)
479{
480 struct device_node *np = dev->of_node;
481 enum regmap_endian endian;
482
483 /* Retrieve the endianness specification from the regmap config */
484 endian = config->val_format_endian;
485
486 /* If the regmap config specified a non-default value, use that */
487 if (endian != REGMAP_ENDIAN_DEFAULT)
488 return endian;
489
490 /* Parse the device's DT node for an endianness specification */
491 if (of_property_read_bool(np, "big-endian"))
492 endian = REGMAP_ENDIAN_BIG;
493 else if (of_property_read_bool(np, "little-endian"))
494 endian = REGMAP_ENDIAN_LITTLE;
495
496 /* If the endianness was specified in DT, use that */
497 if (endian != REGMAP_ENDIAN_DEFAULT)
498 return endian;
499
500 /* Retrieve the endianness specification from the bus config */
501 if (bus && bus->val_format_endian_default)
502 endian = bus->val_format_endian_default;
503
504 /* If the bus specified a non-default value, use that */
505 if (endian != REGMAP_ENDIAN_DEFAULT)
506 return endian;
507
508 /* Use this if no other value was found */
509 return REGMAP_ENDIAN_BIG;
510}
511
451/** 512/**
452 * regmap_init(): Initialise register map 513 * regmap_init(): Initialise register map
453 * 514 *
@@ -551,17 +612,8 @@ struct regmap *regmap_init(struct device *dev,
551 map->reg_read = _regmap_bus_read; 612 map->reg_read = _regmap_bus_read;
552 } 613 }
553 614
554 reg_endian = config->reg_format_endian; 615 reg_endian = regmap_get_reg_endian(bus, config);
555 if (reg_endian == REGMAP_ENDIAN_DEFAULT) 616 val_endian = regmap_get_val_endian(dev, bus, config);
556 reg_endian = bus->reg_format_endian_default;
557 if (reg_endian == REGMAP_ENDIAN_DEFAULT)
558 reg_endian = REGMAP_ENDIAN_BIG;
559
560 val_endian = config->val_format_endian;
561 if (val_endian == REGMAP_ENDIAN_DEFAULT)
562 val_endian = bus->val_format_endian_default;
563 if (val_endian == REGMAP_ENDIAN_DEFAULT)
564 val_endian = REGMAP_ENDIAN_BIG;
565 617
566 switch (config->reg_bits + map->reg_shift) { 618 switch (config->reg_bits + map->reg_shift) {
567 case 2: 619 case 2:
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 8838838e25ed..8bca6343d8a3 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -57,6 +57,8 @@ config SND_SOC_ALL_CODECS
57 select SND_SOC_DA732X if I2C 57 select SND_SOC_DA732X if I2C
58 select SND_SOC_DA9055 if I2C 58 select SND_SOC_DA9055 if I2C
59 select SND_SOC_BT_SCO 59 select SND_SOC_BT_SCO
60 select SND_SOC_ES8328_SPI if SPI_MASTER
61 select SND_SOC_ES8328_I2C if I2C
60 select SND_SOC_ISABELLE if I2C 62 select SND_SOC_ISABELLE if I2C
61 select SND_SOC_JZ4740_CODEC 63 select SND_SOC_JZ4740_CODEC
62 select SND_SOC_LM4857 if I2C 64 select SND_SOC_LM4857 if I2C
@@ -405,6 +407,17 @@ config SND_SOC_DMIC
405config SND_SOC_HDMI_CODEC 407config SND_SOC_HDMI_CODEC
406 tristate "HDMI stub CODEC" 408 tristate "HDMI stub CODEC"
407 409
410config SND_SOC_ES8328
411 tristate "Everest Semi ES8328 CODEC"
412
413config SND_SOC_ES8328_I2C
414 tristate
415 select SND_SOC_ES8328
416
417config SND_SOC_ES8328_SPI
418 tristate
419 select SND_SOC_ES8328
420
408config SND_SOC_ISABELLE 421config SND_SOC_ISABELLE
409 tristate 422 tristate
410 423
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 20afe0f0c5be..31a8283006d1 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -49,6 +49,9 @@ snd-soc-da732x-objs := da732x.o
49snd-soc-da9055-objs := da9055.o 49snd-soc-da9055-objs := da9055.o
50snd-soc-bt-sco-objs := bt-sco.o 50snd-soc-bt-sco-objs := bt-sco.o
51snd-soc-dmic-objs := dmic.o 51snd-soc-dmic-objs := dmic.o
52snd-soc-es8328-objs := es8328.o
53snd-soc-es8328-i2c-objs := es8328-i2c.o
54snd-soc-es8328-spi-objs := es8328-spi.o
52snd-soc-isabelle-objs := isabelle.o 55snd-soc-isabelle-objs := isabelle.o
53snd-soc-jz4740-codec-objs := jz4740.o 56snd-soc-jz4740-codec-objs := jz4740.o
54snd-soc-l3-objs := l3.o 57snd-soc-l3-objs := l3.o
@@ -220,6 +223,9 @@ obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
220obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o 223obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
221obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o 224obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
222obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o 225obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
226obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
227obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
228obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
223obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o 229obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
224obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o 230obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
225obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o 231obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c
new file mode 100644
index 000000000000..aae410d122ee
--- /dev/null
+++ b/sound/soc/codecs/es8328-i2c.c
@@ -0,0 +1,60 @@
1/*
2 * es8328-i2c.c -- ES8328 ALSA SoC I2C Audio driver
3 *
4 * Copyright 2014 Sutajio Ko-Usagi PTE LTD
5 *
6 * Author: Sean Cross <xobs@kosagi.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/i2c.h>
15#include <linux/regmap.h>
16
17#include <sound/soc.h>
18
19#include "es8328.h"
20
21static const struct i2c_device_id es8328_id[] = {
22 { "everest,es8328", 0 },
23 { }
24};
25MODULE_DEVICE_TABLE(i2c, es8328_id);
26
27static const struct of_device_id es8328_of_match[] = {
28 { .compatible = "everest,es8328", },
29 { }
30};
31MODULE_DEVICE_TABLE(of, es8328_of_match);
32
33static int es8328_i2c_probe(struct i2c_client *i2c,
34 const struct i2c_device_id *id)
35{
36 return es8328_probe(&i2c->dev,
37 devm_regmap_init_i2c(i2c, &es8328_regmap_config));
38}
39
40static int es8328_i2c_remove(struct i2c_client *i2c)
41{
42 snd_soc_unregister_codec(&i2c->dev);
43 return 0;
44}
45
46static struct i2c_driver es8328_i2c_driver = {
47 .driver = {
48 .name = "es8328",
49 .of_match_table = es8328_of_match,
50 },
51 .probe = es8328_i2c_probe,
52 .remove = es8328_i2c_remove,
53 .id_table = es8328_id,
54};
55
56module_i2c_driver(es8328_i2c_driver);
57
58MODULE_DESCRIPTION("ASoC ES8328 audio CODEC I2C driver");
59MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
60MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328-spi.c b/sound/soc/codecs/es8328-spi.c
new file mode 100644
index 000000000000..8fbd935e1c76
--- /dev/null
+++ b/sound/soc/codecs/es8328-spi.c
@@ -0,0 +1,49 @@
1/*
2 * es8328.c -- ES8328 ALSA SoC SPI Audio driver
3 *
4 * Copyright 2014 Sutajio Ko-Usagi PTE LTD
5 *
6 * Author: Sean Cross <xobs@kosagi.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/regmap.h>
15#include <linux/spi/spi.h>
16#include <sound/soc.h>
17#include "es8328.h"
18
19static const struct of_device_id es8328_of_match[] = {
20 { .compatible = "everest,es8328", },
21 { }
22};
23MODULE_DEVICE_TABLE(of, es8328_of_match);
24
25static int es8328_spi_probe(struct spi_device *spi)
26{
27 return es8328_probe(&spi->dev,
28 devm_regmap_init_spi(spi, &es8328_regmap_config));
29}
30
31static int es8328_spi_remove(struct spi_device *spi)
32{
33 snd_soc_unregister_codec(&spi->dev);
34 return 0;
35}
36
37static struct spi_driver es8328_spi_driver = {
38 .driver = {
39 .name = "es8328",
40 .of_match_table = es8328_of_match,
41 },
42 .probe = es8328_spi_probe,
43 .remove = es8328_spi_remove,
44};
45
46module_spi_driver(es8328_spi_driver);
47MODULE_DESCRIPTION("ASoC ES8328 audio CODEC SPI driver");
48MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
49MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
new file mode 100644
index 000000000000..7a9f65ad183d
--- /dev/null
+++ b/sound/soc/codecs/es8328.c
@@ -0,0 +1,756 @@
1/*
2 * es8328.c -- ES8328 ALSA SoC Audio driver
3 *
4 * Copyright 2014 Sutajio Ko-Usagi PTE LTD
5 *
6 * Author: Sean Cross <xobs@kosagi.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/clk.h>
14#include <linux/delay.h>
15#include <linux/of_device.h>
16#include <linux/module.h>
17#include <linux/pm.h>
18#include <linux/regmap.h>
19#include <linux/slab.h>
20#include <linux/regulator/consumer.h>
21#include <sound/core.h>
22#include <sound/initval.h>
23#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/soc.h>
26#include <sound/tlv.h>
27#include "es8328.h"
28
29#define ES8328_SYSCLK_RATE_1X 11289600
30#define ES8328_SYSCLK_RATE_2X 22579200
31
32/* Run the codec at 22.5792 or 11.2896 MHz to support these rates */
33static struct {
34 int rate;
35 u8 ratio;
36} mclk_ratios[] = {
37 { 8000, 9 },
38 {11025, 7 },
39 {22050, 4 },
40 {44100, 2 },
41};
42
43/* regulator supplies for sgtl5000, VDDD is an optional external supply */
44enum sgtl5000_regulator_supplies {
45 DVDD,
46 AVDD,
47 PVDD,
48 HPVDD,
49 ES8328_SUPPLY_NUM
50};
51
52/* vddd is optional supply */
53static const char * const supply_names[ES8328_SUPPLY_NUM] = {
54 "DVDD",
55 "AVDD",
56 "PVDD",
57 "HPVDD",
58};
59
60#define ES8328_RATES (SNDRV_PCM_RATE_44100 | \
61 SNDRV_PCM_RATE_22050 | \
62 SNDRV_PCM_RATE_11025)
63#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
64
65struct es8328_priv {
66 struct regmap *regmap;
67 struct clk *clk;
68 int playback_fs;
69 bool deemph;
70 struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM];
71};
72
73/*
74 * ES8328 Controls
75 */
76
77static const char * const adcpol_txt[] = {"Normal", "L Invert", "R Invert",
78 "L + R Invert"};
79static SOC_ENUM_SINGLE_DECL(adcpol,
80 ES8328_ADCCONTROL6, 6, adcpol_txt);
81
82static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0);
83static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0);
84static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0);
85static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
86static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0);
87
88static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
89
90static int es8328_set_deemph(struct snd_soc_codec *codec)
91{
92 struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
93 int val, i, best;
94
95 /*
96 * If we're using deemphasis select the nearest available sample
97 * rate.
98 */
99 if (es8328->deemph) {
100 best = 1;
101 for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
102 if (abs(deemph_settings[i] - es8328->playback_fs) <
103 abs(deemph_settings[best] - es8328->playback_fs))
104 best = i;
105 }
106
107 val = best << 1;
108 } else {
109 val = 0;
110 }
111
112 dev_dbg(codec->dev, "Set deemphasis %d\n", val);
113
114 return snd_soc_update_bits(codec, ES8328_DACCONTROL6, 0x6, val);
115}
116
117static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
118 struct snd_ctl_elem_value *ucontrol)
119{
120 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
121 struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
122
123 ucontrol->value.enumerated.item[0] = es8328->deemph;
124 return 0;
125}
126
127static int es8328_put_deemph(struct snd_kcontrol *kcontrol,
128 struct snd_ctl_elem_value *ucontrol)
129{
130 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
131 struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
132 int deemph = ucontrol->value.enumerated.item[0];
133 int ret;
134
135 if (deemph > 1)
136 return -EINVAL;
137
138 ret = es8328_set_deemph(codec);
139 if (ret < 0)
140 return ret;
141
142 es8328->deemph = deemph;
143
144 return 0;
145}
146
147
148
149static const struct snd_kcontrol_new es8328_snd_controls[] = {
150 SOC_DOUBLE_R_TLV("Capture Digital Volume",
151 ES8328_ADCCONTROL8, ES8328_ADCCONTROL9,
152 0, 0xc0, 1, dac_adc_tlv),
153 SOC_SINGLE("Capture ZC Switch", ES8328_ADCCONTROL7, 6, 1, 0),
154
155 SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
156 es8328_get_deemph, es8328_put_deemph),
157
158 SOC_ENUM("Capture Polarity", adcpol),
159
160 SOC_SINGLE_TLV("Left Mixer Left Bypass Volume",
161 ES8328_DACCONTROL17, 3, 7, 1, bypass_tlv),
162 SOC_SINGLE_TLV("Left Mixer Right Bypass Volume",
163 ES8328_DACCONTROL19, 3, 7, 1, bypass_tlv),
164 SOC_SINGLE_TLV("Right Mixer Left Bypass Volume",
165 ES8328_DACCONTROL18, 3, 7, 1, bypass_tlv),
166 SOC_SINGLE_TLV("Right Mixer Right Bypass Volume",
167 ES8328_DACCONTROL20, 3, 7, 1, bypass_tlv),
168
169 SOC_DOUBLE_R_TLV("PCM Volume",
170 ES8328_LDACVOL, ES8328_RDACVOL,
171 0, ES8328_DACVOL_MAX, 1, dac_adc_tlv),
172
173 SOC_DOUBLE_R_TLV("Output 1 Playback Volume",
174 ES8328_LOUT1VOL, ES8328_ROUT1VOL,
175 0, ES8328_OUT1VOL_MAX, 0, play_tlv),
176
177 SOC_DOUBLE_R_TLV("Output 2 Playback Volume",
178 ES8328_LOUT2VOL, ES8328_ROUT2VOL,
179 0, ES8328_OUT2VOL_MAX, 0, play_tlv),
180
181 SOC_DOUBLE_TLV("Mic PGA Volume", ES8328_ADCCONTROL1,
182 4, 0, 8, 0, mic_tlv),
183};
184
185/*
186 * DAPM Controls
187 */
188
189static const char * const es8328_line_texts[] = {
190 "Line 1", "Line 2", "PGA", "Differential"};
191
192static const struct soc_enum es8328_lline_enum =
193 SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 3,
194 ARRAY_SIZE(es8328_line_texts),
195 es8328_line_texts);
196static const struct snd_kcontrol_new es8328_left_line_controls =
197 SOC_DAPM_ENUM("Route", es8328_lline_enum);
198
199static const struct soc_enum es8328_rline_enum =
200 SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 0,
201 ARRAY_SIZE(es8328_line_texts),
202 es8328_line_texts);
203static const struct snd_kcontrol_new es8328_right_line_controls =
204 SOC_DAPM_ENUM("Route", es8328_lline_enum);
205
206/* Left Mixer */
207static const struct snd_kcontrol_new es8328_left_mixer_controls[] = {
208 SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0),
209 SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0),
210 SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0),
211 SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0),
212};
213
214/* Right Mixer */
215static const struct snd_kcontrol_new es8328_right_mixer_controls[] = {
216 SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0),
217 SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0),
218 SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0),
219 SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0),
220};
221
222static const char * const es8328_pga_sel[] = {
223 "Line 1", "Line 2", "Line 3", "Differential"};
224
225/* Left PGA Mux */
226static const struct soc_enum es8328_lpga_enum =
227 SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 6,
228 ARRAY_SIZE(es8328_pga_sel),
229 es8328_pga_sel);
230static const struct snd_kcontrol_new es8328_left_pga_controls =
231 SOC_DAPM_ENUM("Route", es8328_lpga_enum);
232
233/* Right PGA Mux */
234static const struct soc_enum es8328_rpga_enum =
235 SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 4,
236 ARRAY_SIZE(es8328_pga_sel),
237 es8328_pga_sel);
238static const struct snd_kcontrol_new es8328_right_pga_controls =
239 SOC_DAPM_ENUM("Route", es8328_rpga_enum);
240
241/* Differential Mux */
242static const char * const es8328_diff_sel[] = {"Line 1", "Line 2"};
243static SOC_ENUM_SINGLE_DECL(diffmux,
244 ES8328_ADCCONTROL3, 7, es8328_diff_sel);
245static const struct snd_kcontrol_new es8328_diffmux_controls =
246 SOC_DAPM_ENUM("Route", diffmux);
247
248/* Mono ADC Mux */
249static const char * const es8328_mono_mux[] = {"Stereo", "Mono (Left)",
250 "Mono (Right)", "Digital Mono"};
251static SOC_ENUM_SINGLE_DECL(monomux,
252 ES8328_ADCCONTROL3, 3, es8328_mono_mux);
253static const struct snd_kcontrol_new es8328_monomux_controls =
254 SOC_DAPM_ENUM("Route", monomux);
255
256static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = {
257 SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
258 &es8328_diffmux_controls),
259 SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
260 &es8328_monomux_controls),
261 SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,
262 &es8328_monomux_controls),
263
264 SND_SOC_DAPM_MUX("Left PGA Mux", ES8328_ADCPOWER,
265 ES8328_ADCPOWER_AINL_OFF, 1,
266 &es8328_left_pga_controls),
267 SND_SOC_DAPM_MUX("Right PGA Mux", ES8328_ADCPOWER,
268 ES8328_ADCPOWER_AINR_OFF, 1,
269 &es8328_right_pga_controls),
270
271 SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,
272 &es8328_left_line_controls),
273 SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,
274 &es8328_right_line_controls),
275
276 SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ES8328_ADCPOWER,
277 ES8328_ADCPOWER_ADCR_OFF, 1),
278 SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ES8328_ADCPOWER,
279 ES8328_ADCPOWER_ADCL_OFF, 1),
280
281 SND_SOC_DAPM_SUPPLY("Mic Bias", ES8328_ADCPOWER,
282 ES8328_ADCPOWER_MIC_BIAS_OFF, 1, NULL, 0),
283 SND_SOC_DAPM_SUPPLY("Mic Bias Gen", ES8328_ADCPOWER,
284 ES8328_ADCPOWER_ADC_BIAS_GEN_OFF, 1, NULL, 0),
285
286 SND_SOC_DAPM_SUPPLY("DAC STM", ES8328_CHIPPOWER,
287 ES8328_CHIPPOWER_DACSTM_RESET, 1, NULL, 0),
288 SND_SOC_DAPM_SUPPLY("ADC STM", ES8328_CHIPPOWER,
289 ES8328_CHIPPOWER_ADCSTM_RESET, 1, NULL, 0),
290
291 SND_SOC_DAPM_SUPPLY("DAC DIG", ES8328_CHIPPOWER,
292 ES8328_CHIPPOWER_DACDIG_OFF, 1, NULL, 0),
293 SND_SOC_DAPM_SUPPLY("ADC DIG", ES8328_CHIPPOWER,
294 ES8328_CHIPPOWER_ADCDIG_OFF, 1, NULL, 0),
295
296 SND_SOC_DAPM_SUPPLY("DAC DLL", ES8328_CHIPPOWER,
297 ES8328_CHIPPOWER_DACDLL_OFF, 1, NULL, 0),
298 SND_SOC_DAPM_SUPPLY("ADC DLL", ES8328_CHIPPOWER,
299 ES8328_CHIPPOWER_ADCDLL_OFF, 1, NULL, 0),
300
301 SND_SOC_DAPM_SUPPLY("ADC Vref", ES8328_CHIPPOWER,
302 ES8328_CHIPPOWER_ADCVREF_OFF, 1, NULL, 0),
303 SND_SOC_DAPM_SUPPLY("DAC Vref", ES8328_CHIPPOWER,
304 ES8328_CHIPPOWER_DACVREF_OFF, 1, NULL, 0),
305
306 SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8328_DACPOWER,
307 ES8328_DACPOWER_RDAC_OFF, 1),
308 SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER,
309 ES8328_DACPOWER_LDAC_OFF, 1),
310
311 SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
312 &es8328_left_mixer_controls[0],
313 ARRAY_SIZE(es8328_left_mixer_controls)),
314 SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
315 &es8328_right_mixer_controls[0],
316 ARRAY_SIZE(es8328_right_mixer_controls)),
317
318 SND_SOC_DAPM_PGA("Right Out 2", ES8328_DACPOWER,
319 ES8328_DACPOWER_ROUT2_ON, 0, NULL, 0),
320 SND_SOC_DAPM_PGA("Left Out 2", ES8328_DACPOWER,
321 ES8328_DACPOWER_LOUT2_ON, 0, NULL, 0),
322 SND_SOC_DAPM_PGA("Right Out 1", ES8328_DACPOWER,
323 ES8328_DACPOWER_ROUT1_ON, 0, NULL, 0),
324 SND_SOC_DAPM_PGA("Left Out 1", ES8328_DACPOWER,
325 ES8328_DACPOWER_LOUT1_ON, 0, NULL, 0),
326
327 SND_SOC_DAPM_OUTPUT("LOUT1"),
328 SND_SOC_DAPM_OUTPUT("ROUT1"),
329 SND_SOC_DAPM_OUTPUT("LOUT2"),
330 SND_SOC_DAPM_OUTPUT("ROUT2"),
331
332 SND_SOC_DAPM_INPUT("LINPUT1"),
333 SND_SOC_DAPM_INPUT("LINPUT2"),
334 SND_SOC_DAPM_INPUT("RINPUT1"),
335 SND_SOC_DAPM_INPUT("RINPUT2"),
336};
337
338static const struct snd_soc_dapm_route es8328_dapm_routes[] = {
339
340 { "Left Line Mux", "Line 1", "LINPUT1" },
341 { "Left Line Mux", "Line 2", "LINPUT2" },
342 { "Left Line Mux", "PGA", "Left PGA Mux" },
343 { "Left Line Mux", "Differential", "Differential Mux" },
344
345 { "Right Line Mux", "Line 1", "RINPUT1" },
346 { "Right Line Mux", "Line 2", "RINPUT2" },
347 { "Right Line Mux", "PGA", "Right PGA Mux" },
348 { "Right Line Mux", "Differential", "Differential Mux" },
349
350 { "Left PGA Mux", "Line 1", "LINPUT1" },
351 { "Left PGA Mux", "Line 2", "LINPUT2" },
352 { "Left PGA Mux", "Differential", "Differential Mux" },
353
354 { "Right PGA Mux", "Line 1", "RINPUT1" },
355 { "Right PGA Mux", "Line 2", "RINPUT2" },
356 { "Right PGA Mux", "Differential", "Differential Mux" },
357
358 { "Differential Mux", "Line 1", "LINPUT1" },
359 { "Differential Mux", "Line 1", "RINPUT1" },
360 { "Differential Mux", "Line 2", "LINPUT2" },
361 { "Differential Mux", "Line 2", "RINPUT2" },
362
363 { "Left ADC Mux", "Stereo", "Left PGA Mux" },
364 { "Left ADC Mux", "Mono (Left)", "Left PGA Mux" },
365 { "Left ADC Mux", "Digital Mono", "Left PGA Mux" },
366
367 { "Right ADC Mux", "Stereo", "Right PGA Mux" },
368 { "Right ADC Mux", "Mono (Right)", "Right PGA Mux" },
369 { "Right ADC Mux", "Digital Mono", "Right PGA Mux" },
370
371 { "Left ADC", NULL, "Left ADC Mux" },
372 { "Right ADC", NULL, "Right ADC Mux" },
373
374 { "ADC DIG", NULL, "ADC STM" },
375 { "ADC DIG", NULL, "ADC Vref" },
376 { "ADC DIG", NULL, "ADC DLL" },
377
378 { "Left ADC", NULL, "ADC DIG" },
379 { "Right ADC", NULL, "ADC DIG" },
380
381 { "Mic Bias", NULL, "Mic Bias Gen" },
382
383 { "Left Line Mux", "Line 1", "LINPUT1" },
384 { "Left Line Mux", "Line 2", "LINPUT2" },
385 { "Left Line Mux", "PGA", "Left PGA Mux" },
386 { "Left Line Mux", "Differential", "Differential Mux" },
387
388 { "Right Line Mux", "Line 1", "RINPUT1" },
389 { "Right Line Mux", "Line 2", "RINPUT2" },
390 { "Right Line Mux", "PGA", "Right PGA Mux" },
391 { "Right Line Mux", "Differential", "Differential Mux" },
392
393 { "Left Out 1", NULL, "Left DAC" },
394 { "Right Out 1", NULL, "Right DAC" },
395 { "Left Out 2", NULL, "Left DAC" },
396 { "Right Out 2", NULL, "Right DAC" },
397
398 { "Left Mixer", "Playback Switch", "Left DAC" },
399 { "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
400 { "Left Mixer", "Right Playback Switch", "Right DAC" },
401 { "Left Mixer", "Right Bypass Switch", "Right Line Mux" },
402
403 { "Right Mixer", "Left Playback Switch", "Left DAC" },
404 { "Right Mixer", "Left Bypass Switch", "Left Line Mux" },
405 { "Right Mixer", "Playback Switch", "Right DAC" },
406 { "Right Mixer", "Right Bypass Switch", "Right Line Mux" },
407
408 { "DAC DIG", NULL, "DAC STM" },
409 { "DAC DIG", NULL, "DAC Vref" },
410 { "DAC DIG", NULL, "DAC DLL" },
411
412 { "Left DAC", NULL, "DAC DIG" },
413 { "Right DAC", NULL, "DAC DIG" },
414
415 { "Left Out 1", NULL, "Left Mixer" },
416 { "LOUT1", NULL, "Left Out 1" },
417 { "Right Out 1", NULL, "Right Mixer" },
418 { "ROUT1", NULL, "Right Out 1" },
419
420 { "Left Out 2", NULL, "Left Mixer" },
421 { "LOUT2", NULL, "Left Out 2" },
422 { "Right Out 2", NULL, "Right Mixer" },
423 { "ROUT2", NULL, "Right Out 2" },
424};
425
426static int es8328_mute(struct snd_soc_dai *dai, int mute)
427{
428 return snd_soc_update_bits(dai->codec, ES8328_DACCONTROL3,
429 ES8328_DACCONTROL3_DACMUTE,
430 mute ? ES8328_DACCONTROL3_DACMUTE : 0);
431}
432
433static int es8328_hw_params(struct snd_pcm_substream *substream,
434 struct snd_pcm_hw_params *params,
435 struct snd_soc_dai *dai)
436{
437 struct snd_soc_codec *codec = dai->codec;
438 struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
439 int clk_rate;
440 int i;
441 int reg;
442 u8 ratio;
443
444 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
445 reg = ES8328_DACCONTROL2;
446 else
447 reg = ES8328_ADCCONTROL5;
448
449 clk_rate = clk_get_rate(es8328->clk);
450
451 if ((clk_rate != ES8328_SYSCLK_RATE_1X) &&
452 (clk_rate != ES8328_SYSCLK_RATE_2X)) {
453 dev_err(codec->dev,
454 "%s: clock is running at %d Hz, not %d or %d Hz\n",
455 __func__, clk_rate,
456 ES8328_SYSCLK_RATE_1X, ES8328_SYSCLK_RATE_2X);
457 return -EINVAL;
458 }
459
460 /* find master mode MCLK to sampling frequency ratio */
461 ratio = mclk_ratios[0].rate;
462 for (i = 1; i < ARRAY_SIZE(mclk_ratios); i++)
463 if (params_rate(params) <= mclk_ratios[i].rate)
464 ratio = mclk_ratios[i].ratio;
465
466 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
467 es8328->playback_fs = params_rate(params);
468 es8328_set_deemph(codec);
469 }
470
471 return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio);
472}
473
474static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
475 unsigned int fmt)
476{
477 struct snd_soc_codec *codec = codec_dai->codec;
478 struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
479 int clk_rate;
480 u8 mode = ES8328_DACCONTROL1_DACWL_16;
481
482 /* set master/slave audio interface */
483 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM)
484 return -EINVAL;
485
486 /* interface format */
487 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
488 case SND_SOC_DAIFMT_I2S:
489 mode |= ES8328_DACCONTROL1_DACFORMAT_I2S;
490 break;
491 case SND_SOC_DAIFMT_RIGHT_J:
492 mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST;
493 break;
494 case SND_SOC_DAIFMT_LEFT_J:
495 mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST;
496 break;
497 default:
498 return -EINVAL;
499 }
500
501 /* clock inversion */
502 if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
503 return -EINVAL;
504
505 snd_soc_write(codec, ES8328_DACCONTROL1, mode);
506 snd_soc_write(codec, ES8328_ADCCONTROL4, mode);
507
508 /* Master serial port mode, with BCLK generated automatically */
509 clk_rate = clk_get_rate(es8328->clk);
510 if (clk_rate == ES8328_SYSCLK_RATE_1X)
511 snd_soc_write(codec, ES8328_MASTERMODE,
512 ES8328_MASTERMODE_MSC);
513 else
514 snd_soc_write(codec, ES8328_MASTERMODE,
515 ES8328_MASTERMODE_MCLKDIV2 |
516 ES8328_MASTERMODE_MSC);
517
518 return 0;
519}
520
521static int es8328_set_bias_level(struct snd_soc_codec *codec,
522 enum snd_soc_bias_level level)
523{
524 switch (level) {
525 case SND_SOC_BIAS_ON:
526 break;
527
528 case SND_SOC_BIAS_PREPARE:
529 /* VREF, VMID=2x50k, digital enabled */
530 snd_soc_write(codec, ES8328_CHIPPOWER, 0);
531 snd_soc_update_bits(codec, ES8328_CONTROL1,
532 ES8328_CONTROL1_VMIDSEL_MASK |
533 ES8328_CONTROL1_ENREF,
534 ES8328_CONTROL1_VMIDSEL_50k |
535 ES8328_CONTROL1_ENREF);
536 break;
537
538 case SND_SOC_BIAS_STANDBY:
539 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
540 snd_soc_update_bits(codec, ES8328_CONTROL1,
541 ES8328_CONTROL1_VMIDSEL_MASK |
542 ES8328_CONTROL1_ENREF,
543 ES8328_CONTROL1_VMIDSEL_5k |
544 ES8328_CONTROL1_ENREF);
545
546 /* Charge caps */
547 msleep(100);
548 }
549
550 snd_soc_write(codec, ES8328_CONTROL2,
551 ES8328_CONTROL2_OVERCURRENT_ON |
552 ES8328_CONTROL2_THERMAL_SHUTDOWN_ON);
553
554 /* VREF, VMID=2*500k, digital stopped */
555 snd_soc_update_bits(codec, ES8328_CONTROL1,
556 ES8328_CONTROL1_VMIDSEL_MASK |
557 ES8328_CONTROL1_ENREF,
558 ES8328_CONTROL1_VMIDSEL_500k |
559 ES8328_CONTROL1_ENREF);
560 break;
561
562 case SND_SOC_BIAS_OFF:
563 snd_soc_update_bits(codec, ES8328_CONTROL1,
564 ES8328_CONTROL1_VMIDSEL_MASK |
565 ES8328_CONTROL1_ENREF,
566 0);
567 break;
568 }
569 codec->dapm.bias_level = level;
570 return 0;
571}
572
573static const struct snd_soc_dai_ops es8328_dai_ops = {
574 .hw_params = es8328_hw_params,
575 .digital_mute = es8328_mute,
576 .set_fmt = es8328_set_dai_fmt,
577};
578
579static struct snd_soc_dai_driver es8328_dai = {
580 .name = "es8328-hifi-analog",
581 .playback = {
582 .stream_name = "Playback",
583 .channels_min = 2,
584 .channels_max = 2,
585 .rates = ES8328_RATES,
586 .formats = ES8328_FORMATS,
587 },
588 .capture = {
589 .stream_name = "Capture",
590 .channels_min = 2,
591 .channels_max = 2,
592 .rates = ES8328_RATES,
593 .formats = ES8328_FORMATS,
594 },
595 .ops = &es8328_dai_ops,
596};
597
598static int es8328_suspend(struct snd_soc_codec *codec)
599{
600 struct es8328_priv *es8328;
601 int ret;
602
603 es8328 = snd_soc_codec_get_drvdata(codec);
604
605 es8328_set_bias_level(codec, SND_SOC_BIAS_OFF);
606
607 clk_disable_unprepare(es8328->clk);
608
609 ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
610 es8328->supplies);
611 if (ret) {
612 dev_err(codec->dev, "unable to disable regulators\n");
613 return ret;
614 }
615 return 0;
616}
617
618static int es8328_resume(struct snd_soc_codec *codec)
619{
620 struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
621 struct es8328_priv *es8328;
622 int ret;
623
624 es8328 = snd_soc_codec_get_drvdata(codec);
625
626 ret = clk_prepare_enable(es8328->clk);
627 if (ret) {
628 dev_err(codec->dev, "unable to enable clock\n");
629 return ret;
630 }
631
632 ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
633 es8328->supplies);
634 if (ret) {
635 dev_err(codec->dev, "unable to enable regulators\n");
636 return ret;
637 }
638
639 regcache_mark_dirty(regmap);
640 ret = regcache_sync(regmap);
641 if (ret) {
642 dev_err(codec->dev, "unable to sync regcache\n");
643 return ret;
644 }
645
646 es8328_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
647 return 0;
648}
649
650static int es8328_codec_probe(struct snd_soc_codec *codec)
651{
652 struct es8328_priv *es8328;
653 int ret;
654
655 es8328 = snd_soc_codec_get_drvdata(codec);
656
657 ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies),
658 es8328->supplies);
659 if (ret) {
660 dev_err(codec->dev, "unable to enable regulators\n");
661 return ret;
662 }
663
664 /* Setup clocks */
665 es8328->clk = devm_clk_get(codec->dev, NULL);
666 if (IS_ERR(es8328->clk)) {
667 dev_err(codec->dev, "codec clock missing or invalid\n");
668 goto clk_fail;
669 }
670
671 ret = clk_prepare_enable(es8328->clk);
672 if (ret) {
673 dev_err(codec->dev, "unable to prepare codec clk\n");
674 goto clk_fail;
675 }
676
677 return 0;
678
679clk_fail:
680 regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
681 es8328->supplies);
682 return ret;
683}
684
685static int es8328_remove(struct snd_soc_codec *codec)
686{
687 struct es8328_priv *es8328;
688
689 es8328 = snd_soc_codec_get_drvdata(codec);
690
691 if (es8328->clk)
692 clk_disable_unprepare(es8328->clk);
693
694 regulator_bulk_disable(ARRAY_SIZE(es8328->supplies),
695 es8328->supplies);
696
697 return 0;
698}
699
700const struct regmap_config es8328_regmap_config = {
701 .reg_bits = 8,
702 .val_bits = 8,
703 .max_register = ES8328_REG_MAX,
704 .cache_type = REGCACHE_RBTREE,
705};
706EXPORT_SYMBOL_GPL(es8328_regmap_config);
707
708static struct snd_soc_codec_driver es8328_codec_driver = {
709 .probe = es8328_codec_probe,
710 .suspend = es8328_suspend,
711 .resume = es8328_resume,
712 .remove = es8328_remove,
713 .set_bias_level = es8328_set_bias_level,
714 .controls = es8328_snd_controls,
715 .num_controls = ARRAY_SIZE(es8328_snd_controls),
716 .dapm_widgets = es8328_dapm_widgets,
717 .num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets),
718 .dapm_routes = es8328_dapm_routes,
719 .num_dapm_routes = ARRAY_SIZE(es8328_dapm_routes),
720};
721
722int es8328_probe(struct device *dev, struct regmap *regmap)
723{
724 struct es8328_priv *es8328;
725 int ret;
726 int i;
727
728 if (IS_ERR(regmap))
729 return PTR_ERR(regmap);
730
731 es8328 = devm_kzalloc(dev, sizeof(*es8328), GFP_KERNEL);
732 if (es8328 == NULL)
733 return -ENOMEM;
734
735 es8328->regmap = regmap;
736
737 for (i = 0; i < ARRAY_SIZE(es8328->supplies); i++)
738 es8328->supplies[i].supply = supply_names[i];
739
740 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8328->supplies),
741 es8328->supplies);
742 if (ret) {
743 dev_err(dev, "unable to get regulators\n");
744 return ret;
745 }
746
747 dev_set_drvdata(dev, es8328);
748
749 return snd_soc_register_codec(dev,
750 &es8328_codec_driver, &es8328_dai, 1);
751}
752EXPORT_SYMBOL_GPL(es8328_probe);
753
754MODULE_DESCRIPTION("ASoC ES8328 driver");
755MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
756MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h
new file mode 100644
index 000000000000..cb36afe10c0e
--- /dev/null
+++ b/sound/soc/codecs/es8328.h
@@ -0,0 +1,314 @@
1/*
2 * es8328.h -- ES8328 ALSA SoC Audio driver
3 */
4
5#ifndef _ES8328_H
6#define _ES8328_H
7
8#include <linux/regmap.h>
9
10struct device;
11
12extern const struct regmap_config es8328_regmap_config;
13int es8328_probe(struct device *dev, struct regmap *regmap);
14
15#define ES8328_DACLVOL 46
16#define ES8328_DACRVOL 47
17#define ES8328_DACCTL 28
18#define ES8328_RATEMASK (0x1f << 0)
19
20#define ES8328_CONTROL1 0x00
21#define ES8328_CONTROL1_VMIDSEL_OFF (0 << 0)
22#define ES8328_CONTROL1_VMIDSEL_50k (1 << 0)
23#define ES8328_CONTROL1_VMIDSEL_500k (2 << 0)
24#define ES8328_CONTROL1_VMIDSEL_5k (3 << 0)
25#define ES8328_CONTROL1_VMIDSEL_MASK (7 << 0)
26#define ES8328_CONTROL1_ENREF (1 << 2)
27#define ES8328_CONTROL1_SEQEN (1 << 3)
28#define ES8328_CONTROL1_SAMEFS (1 << 4)
29#define ES8328_CONTROL1_DACMCLK_ADC (0 << 5)
30#define ES8328_CONTROL1_DACMCLK_DAC (1 << 5)
31#define ES8328_CONTROL1_LRCM (1 << 6)
32#define ES8328_CONTROL1_SCP_RESET (1 << 7)
33
34#define ES8328_CONTROL2 0x01
35#define ES8328_CONTROL2_VREF_BUF_OFF (1 << 0)
36#define ES8328_CONTROL2_VREF_LOWPOWER (1 << 1)
37#define ES8328_CONTROL2_IBIASGEN_OFF (1 << 2)
38#define ES8328_CONTROL2_ANALOG_OFF (1 << 3)
39#define ES8328_CONTROL2_VREF_BUF_LOWPOWER (1 << 4)
40#define ES8328_CONTROL2_VCM_MOD_LOWPOWER (1 << 5)
41#define ES8328_CONTROL2_OVERCURRENT_ON (1 << 6)
42#define ES8328_CONTROL2_THERMAL_SHUTDOWN_ON (1 << 7)
43
44#define ES8328_CHIPPOWER 0x02
45#define ES8328_CHIPPOWER_DACVREF_OFF 0
46#define ES8328_CHIPPOWER_ADCVREF_OFF 1
47#define ES8328_CHIPPOWER_DACDLL_OFF 2
48#define ES8328_CHIPPOWER_ADCDLL_OFF 3
49#define ES8328_CHIPPOWER_DACSTM_RESET 4
50#define ES8328_CHIPPOWER_ADCSTM_RESET 5
51#define ES8328_CHIPPOWER_DACDIG_OFF 6
52#define ES8328_CHIPPOWER_ADCDIG_OFF 7
53
54#define ES8328_ADCPOWER 0x03
55#define ES8328_ADCPOWER_INT1_LOWPOWER 0
56#define ES8328_ADCPOWER_FLASH_ADC_LOWPOWER 1
57#define ES8328_ADCPOWER_ADC_BIAS_GEN_OFF 2
58#define ES8328_ADCPOWER_MIC_BIAS_OFF 3
59#define ES8328_ADCPOWER_ADCR_OFF 4
60#define ES8328_ADCPOWER_ADCL_OFF 5
61#define ES8328_ADCPOWER_AINR_OFF 6
62#define ES8328_ADCPOWER_AINL_OFF 7
63
64#define ES8328_DACPOWER 0x04
65#define ES8328_DACPOWER_OUT3_ON 0
66#define ES8328_DACPOWER_MONO_ON 1
67#define ES8328_DACPOWER_ROUT2_ON 2
68#define ES8328_DACPOWER_LOUT2_ON 3
69#define ES8328_DACPOWER_ROUT1_ON 4
70#define ES8328_DACPOWER_LOUT1_ON 5
71#define ES8328_DACPOWER_RDAC_OFF 6
72#define ES8328_DACPOWER_LDAC_OFF 7
73
74#define ES8328_CHIPLOPOW1 0x05
75#define ES8328_CHIPLOPOW2 0x06
76#define ES8328_ANAVOLMANAG 0x07
77
78#define ES8328_MASTERMODE 0x08
79#define ES8328_MASTERMODE_BCLKDIV (0 << 0)
80#define ES8328_MASTERMODE_BCLK_INV (1 << 5)
81#define ES8328_MASTERMODE_MCLKDIV2 (1 << 6)
82#define ES8328_MASTERMODE_MSC (1 << 7)
83
84#define ES8328_ADCCONTROL1 0x09
85#define ES8328_ADCCONTROL2 0x0a
86#define ES8328_ADCCONTROL3 0x0b
87#define ES8328_ADCCONTROL4 0x0c
88#define ES8328_ADCCONTROL5 0x0d
89#define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0)
90
91#define ES8328_ADCCONTROL6 0x0e
92
93#define ES8328_ADCCONTROL7 0x0f
94#define ES8328_ADCCONTROL7_ADC_MUTE (1 << 2)
95#define ES8328_ADCCONTROL7_ADC_LER (1 << 3)
96#define ES8328_ADCCONTROL7_ADC_ZERO_CROSS (1 << 4)
97#define ES8328_ADCCONTROL7_ADC_SOFT_RAMP (1 << 5)
98#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_4 (0 << 6)
99#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_8 (1 << 6)
100#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_16 (2 << 6)
101#define ES8328_ADCCONTROL7_ADC_RAMP_RATE_32 (3 << 6)
102
103#define ES8328_ADCCONTROL8 0x10
104#define ES8328_ADCCONTROL9 0x11
105#define ES8328_ADCCONTROL10 0x12
106#define ES8328_ADCCONTROL11 0x13
107#define ES8328_ADCCONTROL12 0x14
108#define ES8328_ADCCONTROL13 0x15
109#define ES8328_ADCCONTROL14 0x16
110
111#define ES8328_DACCONTROL1 0x17
112#define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1)
113#define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1)
114#define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1)
115#define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1)
116#define ES8328_DACCONTROL1_DACWL_24 (0 << 3)
117#define ES8328_DACCONTROL1_DACWL_20 (1 << 3)
118#define ES8328_DACCONTROL1_DACWL_18 (2 << 3)
119#define ES8328_DACCONTROL1_DACWL_16 (3 << 3)
120#define ES8328_DACCONTROL1_DACWL_32 (4 << 3)
121#define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6)
122#define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6)
123#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6)
124#define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK1 (1 << 6)
125#define ES8328_DACCONTROL1_LRSWAP (1 << 7)
126
127#define ES8328_DACCONTROL2 0x18
128#define ES8328_DACCONTROL2_RATEMASK (0x1f << 0)
129#define ES8328_DACCONTROL2_DOUBLESPEED (1 << 5)
130
131#define ES8328_DACCONTROL3 0x19
132#define ES8328_DACCONTROL3_AUTOMUTE (1 << 2)
133#define ES8328_DACCONTROL3_DACMUTE (1 << 2)
134#define ES8328_DACCONTROL3_LEFTGAINVOL (1 << 3)
135#define ES8328_DACCONTROL3_DACZEROCROSS (1 << 4)
136#define ES8328_DACCONTROL3_DACSOFTRAMP (1 << 5)
137#define ES8328_DACCONTROL3_DACRAMPRATE (3 << 6)
138
139#define ES8328_LDACVOL 0x1a
140#define ES8328_LDACVOL_MASK (0 << 0)
141#define ES8328_LDACVOL_MAX (0xc0)
142
143#define ES8328_RDACVOL 0x1b
144#define ES8328_RDACVOL_MASK (0 << 0)
145#define ES8328_RDACVOL_MAX (0xc0)
146
147#define ES8328_DACVOL_MAX (0xc0)
148
149#define ES8328_DACCONTROL4 0x1a
150#define ES8328_DACCONTROL5 0x1b
151
152#define ES8328_DACCONTROL6 0x1c
153#define ES8328_DACCONTROL6_CLICKFREE (1 << 3)
154#define ES8328_DACCONTROL6_DAC_INVR (1 << 4)
155#define ES8328_DACCONTROL6_DAC_INVL (1 << 5)
156#define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6)
157#define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6)
158#define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6)
159#define ES8328_DACCONTROL6_DEEMPH_48k (3 << 6)
160
161#define ES8328_DACCONTROL7 0x1d
162#define ES8328_DACCONTROL7_VPP_SCALE_3p5 (0 << 0)
163#define ES8328_DACCONTROL7_VPP_SCALE_4p0 (1 << 0)
164#define ES8328_DACCONTROL7_VPP_SCALE_3p0 (2 << 0)
165#define ES8328_DACCONTROL7_VPP_SCALE_2p5 (3 << 0)
166#define ES8328_DACCONTROL7_SHELVING_STRENGTH (1 << 2) /* In eights */
167#define ES8328_DACCONTROL7_MONO (1 << 5)
168#define ES8328_DACCONTROL7_ZEROR (1 << 6)
169#define ES8328_DACCONTROL7_ZEROL (1 << 7)
170
171/* Shelving filter */
172#define ES8328_DACCONTROL8 0x1e
173#define ES8328_DACCONTROL9 0x1f
174#define ES8328_DACCONTROL10 0x20
175#define ES8328_DACCONTROL11 0x21
176#define ES8328_DACCONTROL12 0x22
177#define ES8328_DACCONTROL13 0x23
178#define ES8328_DACCONTROL14 0x24
179#define ES8328_DACCONTROL15 0x25
180
181#define ES8328_DACCONTROL16 0x26
182#define ES8328_DACCONTROL16_RMIXSEL_RIN1 (0 << 0)
183#define ES8328_DACCONTROL16_RMIXSEL_RIN2 (1 << 0)
184#define ES8328_DACCONTROL16_RMIXSEL_RIN3 (2 << 0)
185#define ES8328_DACCONTROL16_RMIXSEL_RADC (3 << 0)
186#define ES8328_DACCONTROL16_LMIXSEL_LIN1 (0 << 3)
187#define ES8328_DACCONTROL16_LMIXSEL_LIN2 (1 << 3)
188#define ES8328_DACCONTROL16_LMIXSEL_LIN3 (2 << 3)
189#define ES8328_DACCONTROL16_LMIXSEL_LADC (3 << 3)
190
191#define ES8328_DACCONTROL17 0x27
192#define ES8328_DACCONTROL17_LI2LOVOL (7 << 3)
193#define ES8328_DACCONTROL17_LI2LO (1 << 6)
194#define ES8328_DACCONTROL17_LD2LO (1 << 7)
195
196#define ES8328_DACCONTROL18 0x28
197#define ES8328_DACCONTROL18_RI2LOVOL (7 << 3)
198#define ES8328_DACCONTROL18_RI2LO (1 << 6)
199#define ES8328_DACCONTROL18_RD2LO (1 << 7)
200
201#define ES8328_DACCONTROL19 0x29
202#define ES8328_DACCONTROL19_LI2ROVOL (7 << 3)
203#define ES8328_DACCONTROL19_LI2RO (1 << 6)
204#define ES8328_DACCONTROL19_LD2RO (1 << 7)
205
206#define ES8328_DACCONTROL20 0x2a
207#define ES8328_DACCONTROL20_RI2ROVOL (7 << 3)
208#define ES8328_DACCONTROL20_RI2RO (1 << 6)
209#define ES8328_DACCONTROL20_RD2RO (1 << 7)
210
211#define ES8328_DACCONTROL21 0x2b
212#define ES8328_DACCONTROL21_LI2MOVOL (7 << 3)
213#define ES8328_DACCONTROL21_LI2MO (1 << 6)
214#define ES8328_DACCONTROL21_LD2MO (1 << 7)
215
216#define ES8328_DACCONTROL22 0x2c
217#define ES8328_DACCONTROL22_RI2MOVOL (7 << 3)
218#define ES8328_DACCONTROL22_RI2MO (1 << 6)
219#define ES8328_DACCONTROL22_RD2MO (1 << 7)
220
221#define ES8328_DACCONTROL23 0x2d
222#define ES8328_DACCONTROL23_MOUTINV (1 << 1)
223#define ES8328_DACCONTROL23_HPSWPOL (1 << 2)
224#define ES8328_DACCONTROL23_HPSWEN (1 << 3)
225#define ES8328_DACCONTROL23_VROI_1p5k (0 << 4)
226#define ES8328_DACCONTROL23_VROI_40k (1 << 4)
227#define ES8328_DACCONTROL23_OUT3_VREF (0 << 5)
228#define ES8328_DACCONTROL23_OUT3_ROUT1 (1 << 5)
229#define ES8328_DACCONTROL23_OUT3_MONOOUT (2 << 5)
230#define ES8328_DACCONTROL23_OUT3_RIGHT_MIXER (3 << 5)
231#define ES8328_DACCONTROL23_ROUT2INV (1 << 7)
232
233/* LOUT1 Amplifier */
234#define ES8328_LOUT1VOL 0x2e
235#define ES8328_LOUT1VOL_MASK (0 << 5)
236#define ES8328_LOUT1VOL_MAX (0x24)
237
238/* ROUT1 Amplifier */
239#define ES8328_ROUT1VOL 0x2f
240#define ES8328_ROUT1VOL_MASK (0 << 5)
241#define ES8328_ROUT1VOL_MAX (0x24)
242
243#define ES8328_OUT1VOL_MAX (0x24)
244
245/* LOUT2 Amplifier */
246#define ES8328_LOUT2VOL 0x30
247#define ES8328_LOUT2VOL_MASK (0 << 5)
248#define ES8328_LOUT2VOL_MAX (0x24)
249
250/* ROUT2 Amplifier */
251#define ES8328_ROUT2VOL 0x31
252#define ES8328_ROUT2VOL_MASK (0 << 5)
253#define ES8328_ROUT2VOL_MAX (0x24)
254
255#define ES8328_OUT2VOL_MAX (0x24)
256
257/* Mono Out Amplifier */
258#define ES8328_MONOOUTVOL 0x32
259#define ES8328_MONOOUTVOL_MASK (0 << 5)
260#define ES8328_MONOOUTVOL_MAX (0x24)
261
262#define ES8328_DACCONTROL29 0x33
263#define ES8328_DACCONTROL30 0x34
264
265#define ES8328_SYSCLK 0
266
267#define ES8328_REG_MAX 0x35
268
269#define ES8328_PLL1 0
270#define ES8328_PLL2 1
271
272/* clock inputs */
273#define ES8328_MCLK 0
274#define ES8328_PCMCLK 1
275
276/* clock divider id's */
277#define ES8328_PCMDIV 0
278#define ES8328_BCLKDIV 1
279#define ES8328_VXCLKDIV 2
280
281/* PCM clock dividers */
282#define ES8328_PCM_DIV_1 (0 << 6)
283#define ES8328_PCM_DIV_3 (2 << 6)
284#define ES8328_PCM_DIV_5_5 (3 << 6)
285#define ES8328_PCM_DIV_2 (4 << 6)
286#define ES8328_PCM_DIV_4 (5 << 6)
287#define ES8328_PCM_DIV_6 (6 << 6)
288#define ES8328_PCM_DIV_8 (7 << 6)
289
290/* BCLK clock dividers */
291#define ES8328_BCLK_DIV_1 (0 << 7)
292#define ES8328_BCLK_DIV_2 (1 << 7)
293#define ES8328_BCLK_DIV_4 (2 << 7)
294#define ES8328_BCLK_DIV_8 (3 << 7)
295
296/* VXCLK clock dividers */
297#define ES8328_VXCLK_DIV_1 (0 << 6)
298#define ES8328_VXCLK_DIV_2 (1 << 6)
299#define ES8328_VXCLK_DIV_4 (2 << 6)
300#define ES8328_VXCLK_DIV_8 (3 << 6)
301#define ES8328_VXCLK_DIV_16 (4 << 6)
302
303#define ES8328_DAI_HIFI 0
304#define ES8328_DAI_VOICE 1
305
306#define ES8328_1536FS 1536
307#define ES8328_1024FS 1024
308#define ES8328_768FS 768
309#define ES8328_512FS 512
310#define ES8328_384FS 384
311#define ES8328_256FS 256
312#define ES8328_128FS 128
313
314#endif
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index f54a8fc99291..7c1da8ede975 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -241,6 +241,18 @@ config SND_SOC_IMX_WM8962
241 Say Y if you want to add support for SoC audio on an i.MX board with 241 Say Y if you want to add support for SoC audio on an i.MX board with
242 a wm8962 codec. 242 a wm8962 codec.
243 243
244config SND_SOC_IMX_ES8328
245 tristate "SoC Audio support for i.MX boards with the ES8328 codec"
246 depends on OF && (I2C || SPI)
247 select SND_SOC_ES8328_I2C if I2C
248 select SND_SOC_ES8328_SPI if SPI_MASTER
249 select SND_SOC_IMX_PCM_DMA
250 select SND_SOC_IMX_AUDMUX
251 select SND_SOC_FSL_SSI
252 help
253 Say Y if you want to add support for the ES8328 audio codec connected
254 via SSI/I2S over either SPI or I2C.
255
244config SND_SOC_IMX_SGTL5000 256config SND_SOC_IMX_SGTL5000
245 tristate "SoC Audio support for i.MX boards with sgtl5000" 257 tristate "SoC Audio support for i.MX boards with sgtl5000"
246 depends on OF && I2C 258 depends on OF && I2C
@@ -269,6 +281,23 @@ config SND_SOC_IMX_MC13783
269 select SND_SOC_MC13783 281 select SND_SOC_MC13783
270 select SND_SOC_IMX_PCM_DMA 282 select SND_SOC_IMX_PCM_DMA
271 283
284config SND_SOC_FSL_ASOC_CARD
285 tristate "Generic ASoC Sound Card with ASRC support"
286 depends on OF && I2C
287 select SND_SOC_IMX_AUDMUX
288 select SND_SOC_IMX_PCM_DMA
289 select SND_SOC_FSL_ESAI
290 select SND_SOC_FSL_SAI
291 select SND_SOC_FSL_SSI
292 select SND_SOC_CS42XX8_I2C
293 select SND_SOC_SGTL5000
294 select SND_SOC_WM8962
295 help
296 ALSA SoC Audio support with ASRC feature for Freescale SoCs that have
297 ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888
298 and SGTL5000.
299 Say Y if you want to add support for Freescale Generic ASoC Sound Card.
300
272endif # SND_IMX_SOC 301endif # SND_IMX_SOC
273 302
274endmenu 303endmenu
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 9ff59267eac9..d28dc25c9375 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -11,6 +11,7 @@ snd-soc-p1022-rdk-objs := p1022_rdk.o
11obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o 11obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
12 12
13# Freescale SSI/DMA/SAI/SPDIF Support 13# Freescale SSI/DMA/SAI/SPDIF Support
14snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o
14snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o 15snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o
15snd-soc-fsl-sai-objs := fsl_sai.o 16snd-soc-fsl-sai-objs := fsl_sai.o
16snd-soc-fsl-ssi-y := fsl_ssi.o 17snd-soc-fsl-ssi-y := fsl_ssi.o
@@ -19,6 +20,7 @@ snd-soc-fsl-spdif-objs := fsl_spdif.o
19snd-soc-fsl-esai-objs := fsl_esai.o 20snd-soc-fsl-esai-objs := fsl_esai.o
20snd-soc-fsl-utils-objs := fsl_utils.o 21snd-soc-fsl-utils-objs := fsl_utils.o
21snd-soc-fsl-dma-objs := fsl_dma.o 22snd-soc-fsl-dma-objs := fsl_dma.o
23obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
22obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o 24obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o
23obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o 25obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
24obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o 26obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
@@ -50,6 +52,7 @@ snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
50snd-soc-phycore-ac97-objs := phycore-ac97.o 52snd-soc-phycore-ac97-objs := phycore-ac97.o
51snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o 53snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
52snd-soc-wm1133-ev1-objs := wm1133-ev1.o 54snd-soc-wm1133-ev1-objs := wm1133-ev1.o
55snd-soc-imx-es8328-objs := imx-es8328.o
53snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o 56snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
54snd-soc-imx-wm8962-objs := imx-wm8962.o 57snd-soc-imx-wm8962-objs := imx-wm8962.o
55snd-soc-imx-spdif-objs := imx-spdif.o 58snd-soc-imx-spdif-objs := imx-spdif.o
@@ -59,6 +62,7 @@ obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
59obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o 62obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
60obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o 63obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
61obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o 64obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
65obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o
62obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o 66obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
63obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o 67obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
64obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o 68obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
new file mode 100644
index 000000000000..007c772f3cef
--- /dev/null
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -0,0 +1,574 @@
1/*
2 * Freescale Generic ASoC Sound Card driver with ASRC
3 *
4 * Copyright (C) 2014 Freescale Semiconductor, Inc.
5 *
6 * Author: Nicolin Chen <nicoleotsuka@gmail.com>
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 */
12
13#include <linux/clk.h>
14#include <linux/i2c.h>
15#include <linux/module.h>
16#include <linux/of_platform.h>
17#include <sound/pcm_params.h>
18#include <sound/soc.h>
19
20#include "fsl_esai.h"
21#include "fsl_sai.h"
22#include "imx-audmux.h"
23
24#include "../codecs/sgtl5000.h"
25#include "../codecs/wm8962.h"
26
27#define RX 0
28#define TX 1
29
30/* Default DAI format without Master and Slave flag */
31#define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF)
32
33/**
34 * CODEC private data
35 *
36 * @mclk_freq: Clock rate of MCLK
37 * @mclk_id: MCLK (or main clock) id for set_sysclk()
38 * @fll_id: FLL (or secordary clock) id for set_sysclk()
39 * @pll_id: PLL id for set_pll()
40 */
41struct codec_priv {
42 unsigned long mclk_freq;
43 u32 mclk_id;
44 u32 fll_id;
45 u32 pll_id;
46};
47
48/**
49 * CPU private data
50 *
51 * @sysclk_freq[2]: SYSCLK rates for set_sysclk()
52 * @sysclk_dir[2]: SYSCLK directions for set_sysclk()
53 * @sysclk_id[2]: SYSCLK ids for set_sysclk()
54 *
55 * Note: [1] for tx and [0] for rx
56 */
57struct cpu_priv {
58 unsigned long sysclk_freq[2];
59 u32 sysclk_dir[2];
60 u32 sysclk_id[2];
61};
62
63/**
64 * Freescale Generic ASOC card private data
65 *
66 * @dai_link[3]: DAI link structure including normal one and DPCM link
67 * @pdev: platform device pointer
68 * @codec_priv: CODEC private data
69 * @cpu_priv: CPU private data
70 * @card: ASoC card structure
71 * @sample_rate: Current sample rate
72 * @sample_format: Current sample format
73 * @asrc_rate: ASRC sample rate used by Back-Ends
74 * @asrc_format: ASRC sample format used by Back-Ends
75 * @dai_fmt: DAI format between CPU and CODEC
76 * @name: Card name
77 */
78
79struct fsl_asoc_card_priv {
80 struct snd_soc_dai_link dai_link[3];
81 struct platform_device *pdev;
82 struct codec_priv codec_priv;
83 struct cpu_priv cpu_priv;
84 struct snd_soc_card card;
85 u32 sample_rate;
86 u32 sample_format;
87 u32 asrc_rate;
88 u32 asrc_format;
89 u32 dai_fmt;
90 char name[32];
91};
92
93/**
94 * This dapm route map exsits for DPCM link only.
95 * The other routes shall go through Device Tree.
96 */
97static const struct snd_soc_dapm_route audio_map[] = {
98 {"CPU-Playback", NULL, "ASRC-Playback"},
99 {"Playback", NULL, "CPU-Playback"},
100 {"ASRC-Capture", NULL, "CPU-Capture"},
101 {"CPU-Capture", NULL, "Capture"},
102};
103
104/* Add all possible widgets into here without being redundant */
105static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
106 SND_SOC_DAPM_LINE("Line Out Jack", NULL),
107 SND_SOC_DAPM_LINE("Line In Jack", NULL),
108 SND_SOC_DAPM_HP("Headphone Jack", NULL),
109 SND_SOC_DAPM_SPK("Ext Spk", NULL),
110 SND_SOC_DAPM_MIC("Mic Jack", NULL),
111 SND_SOC_DAPM_MIC("AMIC", NULL),
112 SND_SOC_DAPM_MIC("DMIC", NULL),
113};
114
115static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
116 struct snd_pcm_hw_params *params)
117{
118 struct snd_soc_pcm_runtime *rtd = substream->private_data;
119 struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
120 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
121 struct cpu_priv *cpu_priv = &priv->cpu_priv;
122 struct device *dev = rtd->card->dev;
123 int ret;
124
125 priv->sample_rate = params_rate(params);
126 priv->sample_format = params_format(params);
127
128 if (priv->card.set_bias_level)
129 return 0;
130
131 /* Specific configurations of DAIs starts from here */
132 ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, cpu_priv->sysclk_id[tx],
133 cpu_priv->sysclk_freq[tx],
134 cpu_priv->sysclk_dir[tx]);
135 if (ret) {
136 dev_err(dev, "failed to set sysclk for cpu dai\n");
137 return ret;
138 }
139
140 return 0;
141}
142
143static struct snd_soc_ops fsl_asoc_card_ops = {
144 .hw_params = fsl_asoc_card_hw_params,
145};
146
147static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
148 struct snd_pcm_hw_params *params)
149{
150 struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
151 struct snd_interval *rate;
152 struct snd_mask *mask;
153
154 rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
155 rate->max = rate->min = priv->asrc_rate;
156
157 mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
158 snd_mask_none(mask);
159 snd_mask_set(mask, priv->asrc_format);
160
161 return 0;
162}
163
164static struct snd_soc_dai_link fsl_asoc_card_dai[] = {
165 /* Default ASoC DAI Link*/
166 {
167 .name = "HiFi",
168 .stream_name = "HiFi",
169 .ops = &fsl_asoc_card_ops,
170 },
171 /* DPCM Link between Front-End and Back-End (Optional) */
172 {
173 .name = "HiFi-ASRC-FE",
174 .stream_name = "HiFi-ASRC-FE",
175 .codec_name = "snd-soc-dummy",
176 .codec_dai_name = "snd-soc-dummy-dai",
177 .dpcm_playback = 1,
178 .dpcm_capture = 1,
179 .dynamic = 1,
180 },
181 {
182 .name = "HiFi-ASRC-BE",
183 .stream_name = "HiFi-ASRC-BE",
184 .platform_name = "snd-soc-dummy",
185 .be_hw_params_fixup = be_hw_params_fixup,
186 .ops = &fsl_asoc_card_ops,
187 .dpcm_playback = 1,
188 .dpcm_capture = 1,
189 .no_pcm = 1,
190 },
191};
192
193static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card,
194 struct snd_soc_dapm_context *dapm,
195 enum snd_soc_bias_level level)
196{
197 struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
198 struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
199 struct codec_priv *codec_priv = &priv->codec_priv;
200 struct device *dev = card->dev;
201 unsigned int pll_out;
202 int ret;
203
204 if (dapm->dev != codec_dai->dev)
205 return 0;
206
207 switch (level) {
208 case SND_SOC_BIAS_PREPARE:
209 if (dapm->bias_level != SND_SOC_BIAS_STANDBY)
210 break;
211
212 if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE)
213 pll_out = priv->sample_rate * 384;
214 else
215 pll_out = priv->sample_rate * 256;
216
217 ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id,
218 codec_priv->mclk_id,
219 codec_priv->mclk_freq, pll_out);
220 if (ret) {
221 dev_err(dev, "failed to start FLL: %d\n", ret);
222 return ret;
223 }
224
225 ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->fll_id,
226 pll_out, SND_SOC_CLOCK_IN);
227 if (ret) {
228 dev_err(dev, "failed to set SYSCLK: %d\n", ret);
229 return ret;
230 }
231 break;
232
233 case SND_SOC_BIAS_STANDBY:
234 if (dapm->bias_level != SND_SOC_BIAS_PREPARE)
235 break;
236
237 ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
238 codec_priv->mclk_freq,
239 SND_SOC_CLOCK_IN);
240 if (ret) {
241 dev_err(dev, "failed to switch away from FLL: %d\n", ret);
242 return ret;
243 }
244
245 ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, 0, 0, 0);
246 if (ret) {
247 dev_err(dev, "failed to stop FLL: %d\n", ret);
248 return ret;
249 }
250 break;
251
252 default:
253 break;
254 }
255
256 return 0;
257}
258
259static int fsl_asoc_card_audmux_init(struct device_node *np,
260 struct fsl_asoc_card_priv *priv)
261{
262 struct device *dev = &priv->pdev->dev;
263 u32 int_ptcr = 0, ext_ptcr = 0;
264 int int_port, ext_port;
265 int ret;
266
267 ret = of_property_read_u32(np, "mux-int-port", &int_port);
268 if (ret) {
269 dev_err(dev, "mux-int-port missing or invalid\n");
270 return ret;
271 }
272 ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
273 if (ret) {
274 dev_err(dev, "mux-ext-port missing or invalid\n");
275 return ret;
276 }
277
278 /*
279 * The port numbering in the hardware manual starts at 1, while
280 * the AUDMUX API expects it starts at 0.
281 */
282 int_port--;
283 ext_port--;
284
285 /*
286 * Use asynchronous mode (6 wires) for all cases.
287 * If only 4 wires are needed, just set SSI into
288 * synchronous mode and enable 4 PADs in IOMUX.
289 */
290 switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
291 case SND_SOC_DAIFMT_CBM_CFM:
292 int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) |
293 IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) |
294 IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
295 IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
296 IMX_AUDMUX_V2_PTCR_RFSDIR |
297 IMX_AUDMUX_V2_PTCR_RCLKDIR |
298 IMX_AUDMUX_V2_PTCR_TFSDIR |
299 IMX_AUDMUX_V2_PTCR_TCLKDIR;
300 break;
301 case SND_SOC_DAIFMT_CBM_CFS:
302 int_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) |
303 IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
304 IMX_AUDMUX_V2_PTCR_RCLKDIR |
305 IMX_AUDMUX_V2_PTCR_TCLKDIR;
306 ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) |
307 IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
308 IMX_AUDMUX_V2_PTCR_RFSDIR |
309 IMX_AUDMUX_V2_PTCR_TFSDIR;
310 break;
311 case SND_SOC_DAIFMT_CBS_CFM:
312 int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) |
313 IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
314 IMX_AUDMUX_V2_PTCR_RFSDIR |
315 IMX_AUDMUX_V2_PTCR_TFSDIR;
316 ext_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) |
317 IMX_AUDMUX_V2_PTCR_TCSEL(int_port) |
318 IMX_AUDMUX_V2_PTCR_RCLKDIR |
319 IMX_AUDMUX_V2_PTCR_TCLKDIR;
320 break;
321 case SND_SOC_DAIFMT_CBS_CFS:
322 ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) |
323 IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) |
324 IMX_AUDMUX_V2_PTCR_TFSEL(int_port) |
325 IMX_AUDMUX_V2_PTCR_TCSEL(int_port) |
326 IMX_AUDMUX_V2_PTCR_RFSDIR |
327 IMX_AUDMUX_V2_PTCR_RCLKDIR |
328 IMX_AUDMUX_V2_PTCR_TFSDIR |
329 IMX_AUDMUX_V2_PTCR_TCLKDIR;
330 break;
331 default:
332 return -EINVAL;
333 }
334
335 /* Asynchronous mode can not be set along with RCLKDIR */
336 ret = imx_audmux_v2_configure_port(int_port, 0,
337 IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
338 if (ret) {
339 dev_err(dev, "audmux internal port setup failed\n");
340 return ret;
341 }
342
343 ret = imx_audmux_v2_configure_port(int_port, int_ptcr,
344 IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
345 if (ret) {
346 dev_err(dev, "audmux internal port setup failed\n");
347 return ret;
348 }
349
350 ret = imx_audmux_v2_configure_port(ext_port, 0,
351 IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
352 if (ret) {
353 dev_err(dev, "audmux external port setup failed\n");
354 return ret;
355 }
356
357 ret = imx_audmux_v2_configure_port(ext_port, ext_ptcr,
358 IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
359 if (ret) {
360 dev_err(dev, "audmux external port setup failed\n");
361 return ret;
362 }
363
364 return 0;
365}
366
367static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
368{
369 struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
370 struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
371 struct codec_priv *codec_priv = &priv->codec_priv;
372 struct device *dev = card->dev;
373 int ret;
374
375 ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
376 codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
377 if (ret) {
378 dev_err(dev, "failed to set sysclk in %s\n", __func__);
379 return ret;
380 }
381
382 return 0;
383}
384
385static int fsl_asoc_card_probe(struct platform_device *pdev)
386{
387 struct device_node *cpu_np, *codec_np, *asrc_np;
388 struct device_node *np = pdev->dev.of_node;
389 struct platform_device *asrc_pdev = NULL;
390 struct platform_device *cpu_pdev;
391 struct fsl_asoc_card_priv *priv;
392 struct i2c_client *codec_dev;
393 struct clk *codec_clk;
394 u32 width;
395 int ret;
396
397 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
398 if (!priv)
399 return -ENOMEM;
400
401 cpu_np = of_parse_phandle(np, "audio-cpu", 0);
402 /* Give a chance to old DT binding */
403 if (!cpu_np)
404 cpu_np = of_parse_phandle(np, "ssi-controller", 0);
405 codec_np = of_parse_phandle(np, "audio-codec", 0);
406 if (!cpu_np || !codec_np) {
407 dev_err(&pdev->dev, "phandle missing or invalid\n");
408 ret = -EINVAL;
409 goto fail;
410 }
411
412 cpu_pdev = of_find_device_by_node(cpu_np);
413 if (!cpu_pdev) {
414 dev_err(&pdev->dev, "failed to find CPU DAI device\n");
415 ret = -EINVAL;
416 goto fail;
417 }
418
419 codec_dev = of_find_i2c_device_by_node(codec_np);
420 if (!codec_dev) {
421 dev_err(&pdev->dev, "failed to find codec platform device\n");
422 ret = -EINVAL;
423 goto fail;
424 }
425
426 asrc_np = of_parse_phandle(np, "audio-asrc", 0);
427 if (asrc_np)
428 asrc_pdev = of_find_device_by_node(asrc_np);
429
430 /* Get the MCLK rate only, and leave it controlled by CODEC drivers */
431 codec_clk = clk_get(&codec_dev->dev, NULL);
432 if (!IS_ERR(codec_clk)) {
433 priv->codec_priv.mclk_freq = clk_get_rate(codec_clk);
434 clk_put(codec_clk);
435 }
436
437 /* Default sample rate and format, will be updated in hw_params() */
438 priv->sample_rate = 44100;
439 priv->sample_format = SNDRV_PCM_FORMAT_S16_LE;
440
441 /* Assign a default DAI format, and allow each card to overwrite it */
442 priv->dai_fmt = DAI_FMT_BASE;
443
444 /* Diversify the card configurations */
445 if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
446 priv->card.set_bias_level = NULL;
447 priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq;
448 priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
449 priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
450 priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
451 priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
452 } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
453 priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
454 priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
455 } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) {
456 priv->card.set_bias_level = fsl_asoc_card_set_bias_level;
457 priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK;
458 priv->codec_priv.fll_id = WM8962_SYSCLK_FLL;
459 priv->codec_priv.pll_id = WM8962_FLL;
460 priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
461 } else {
462 dev_err(&pdev->dev, "unknown Device Tree compatible\n");
463 return -EINVAL;
464 }
465
466 /* Common settings for corresponding Freescale CPU DAI driver */
467 if (strstr(cpu_np->name, "ssi")) {
468 /* Only SSI needs to configure AUDMUX */
469 ret = fsl_asoc_card_audmux_init(np, priv);
470 if (ret) {
471 dev_err(&pdev->dev, "failed to init audmux\n");
472 goto asrc_fail;
473 }
474 } else if (strstr(cpu_np->name, "esai")) {
475 priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
476 priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
477 } else if (strstr(cpu_np->name, "sai")) {
478 priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
479 priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
480 }
481
482 sprintf(priv->name, "%s-audio", codec_dev->name);
483
484 /* Initialize sound card */
485 priv->pdev = pdev;
486 priv->card.dev = &pdev->dev;
487 priv->card.name = priv->name;
488 priv->card.dai_link = priv->dai_link;
489 priv->card.dapm_routes = audio_map;
490 priv->card.late_probe = fsl_asoc_card_late_probe;
491 priv->card.num_dapm_routes = ARRAY_SIZE(audio_map);
492 priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets;
493 priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets);
494
495 memcpy(priv->dai_link, fsl_asoc_card_dai,
496 sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
497
498 /* Normal DAI Link */
499 priv->dai_link[0].cpu_of_node = cpu_np;
500 priv->dai_link[0].codec_of_node = codec_np;
501 priv->dai_link[0].codec_dai_name = codec_dev->name;
502 priv->dai_link[0].platform_of_node = cpu_np;
503 priv->dai_link[0].dai_fmt = priv->dai_fmt;
504 priv->card.num_links = 1;
505
506 if (asrc_pdev) {
507 /* DPCM DAI Links only if ASRC exsits */
508 priv->dai_link[1].cpu_of_node = asrc_np;
509 priv->dai_link[1].platform_of_node = asrc_np;
510 priv->dai_link[2].codec_dai_name = codec_dev->name;
511 priv->dai_link[2].codec_of_node = codec_np;
512 priv->dai_link[2].cpu_of_node = cpu_np;
513 priv->dai_link[2].dai_fmt = priv->dai_fmt;
514 priv->card.num_links = 3;
515
516 ret = of_property_read_u32(asrc_np, "fsl,asrc-rate",
517 &priv->asrc_rate);
518 if (ret) {
519 dev_err(&pdev->dev, "failed to get output rate\n");
520 ret = -EINVAL;
521 goto asrc_fail;
522 }
523
524 ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width);
525 if (ret) {
526 dev_err(&pdev->dev, "failed to get output rate\n");
527 ret = -EINVAL;
528 goto asrc_fail;
529 }
530
531 if (width == 24)
532 priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE;
533 else
534 priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE;
535 }
536
537 /* Finish card registering */
538 platform_set_drvdata(pdev, priv);
539 snd_soc_card_set_drvdata(&priv->card, priv);
540
541 ret = devm_snd_soc_register_card(&pdev->dev, &priv->card);
542 if (ret)
543 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
544
545asrc_fail:
546 of_node_put(asrc_np);
547fail:
548 of_node_put(codec_np);
549 of_node_put(cpu_np);
550
551 return ret;
552}
553
554static const struct of_device_id fsl_asoc_card_dt_ids[] = {
555 { .compatible = "fsl,imx-audio-cs42888", },
556 { .compatible = "fsl,imx-audio-sgtl5000", },
557 { .compatible = "fsl,imx-audio-wm8962", },
558 {}
559};
560
561static struct platform_driver fsl_asoc_card_driver = {
562 .probe = fsl_asoc_card_probe,
563 .driver = {
564 .name = "fsl-asoc-card",
565 .pm = &snd_soc_pm_ops,
566 .of_match_table = fsl_asoc_card_dt_ids,
567 },
568};
569module_platform_driver(fsl_asoc_card_driver);
570
571MODULE_DESCRIPTION("Freescale Generic ASoC Sound Card driver with ASRC");
572MODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>");
573MODULE_ALIAS("platform:fsl-asoc-card");
574MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 822110420b71..3b145313f93e 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -684,7 +684,7 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg)
684 } 684 }
685} 685}
686 686
687static struct regmap_config fsl_asrc_regmap_config = { 687static const struct regmap_config fsl_asrc_regmap_config = {
688 .reg_bits = 32, 688 .reg_bits = 32,
689 .reg_stride = 4, 689 .reg_stride = 4,
690 .val_bits = 32, 690 .val_bits = 32,
@@ -802,10 +802,6 @@ static int fsl_asrc_probe(struct platform_device *pdev)
802 802
803 asrc_priv->paddr = res->start; 803 asrc_priv->paddr = res->start;
804 804
805 /* Register regmap and let it prepare core clock */
806 if (of_property_read_bool(np, "big-endian"))
807 fsl_asrc_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
808
809 asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, 805 asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs,
810 &fsl_asrc_regmap_config); 806 &fsl_asrc_regmap_config);
811 if (IS_ERR(asrc_priv->regmap)) { 807 if (IS_ERR(asrc_priv->regmap)) {
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 72d154e7dd03..2882fc66a10d 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -707,7 +707,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
707 } 707 }
708} 708}
709 709
710static struct regmap_config fsl_esai_regmap_config = { 710static const struct regmap_config fsl_esai_regmap_config = {
711 .reg_bits = 32, 711 .reg_bits = 32,
712 .reg_stride = 4, 712 .reg_stride = 4,
713 .val_bits = 32, 713 .val_bits = 32,
@@ -733,9 +733,6 @@ static int fsl_esai_probe(struct platform_device *pdev)
733 esai_priv->pdev = pdev; 733 esai_priv->pdev = pdev;
734 strcpy(esai_priv->name, np->name); 734 strcpy(esai_priv->name, np->name);
735 735
736 if (of_property_read_bool(np, "big-endian"))
737 fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
738
739 /* Get the addresses and IRQ */ 736 /* Get the addresses and IRQ */
740 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 737 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
741 regs = devm_ioremap_resource(&pdev->dev, res); 738 regs = devm_ioremap_resource(&pdev->dev, res);
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 60fe7c77ba22..a6eb7849959c 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -544,7 +544,7 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
544 } 544 }
545} 545}
546 546
547static struct regmap_config fsl_sai_regmap_config = { 547static const struct regmap_config fsl_sai_regmap_config = {
548 .reg_bits = 32, 548 .reg_bits = 32,
549 .reg_stride = 4, 549 .reg_stride = 4,
550 .val_bits = 32, 550 .val_bits = 32,
@@ -573,10 +573,6 @@ static int fsl_sai_probe(struct platform_device *pdev)
573 if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai")) 573 if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai"))
574 sai->sai_on_imx = true; 574 sai->sai_on_imx = true;
575 575
576 sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
577 if (sai->big_endian_regs)
578 fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
579
580 sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); 576 sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
581 577
582 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 578 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index b3d8864cd5f2..2cded440d567 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -132,7 +132,6 @@ struct fsl_sai {
132 struct clk *bus_clk; 132 struct clk *bus_clk;
133 struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; 133 struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
134 134
135 bool big_endian_regs;
136 bool big_endian_data; 135 bool big_endian_data;
137 bool is_dsp_mode; 136 bool is_dsp_mode;
138 bool sai_on_imx; 137 bool sai_on_imx;
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 70acfe4a9bd5..ae4e408810ec 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -1040,7 +1040,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
1040 } 1040 }
1041} 1041}
1042 1042
1043static struct regmap_config fsl_spdif_regmap_config = { 1043static const struct regmap_config fsl_spdif_regmap_config = {
1044 .reg_bits = 32, 1044 .reg_bits = 32,
1045 .reg_stride = 4, 1045 .reg_stride = 4,
1046 .val_bits = 32, 1046 .val_bits = 32,
@@ -1184,9 +1184,6 @@ static int fsl_spdif_probe(struct platform_device *pdev)
1184 memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); 1184 memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
1185 spdif_priv->cpu_dai_drv.name = spdif_priv->name; 1185 spdif_priv->cpu_dai_drv.name = spdif_priv->name;
1186 1186
1187 if (of_property_read_bool(np, "big-endian"))
1188 fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
1189
1190 /* Get the addresses and IRQ */ 1187 /* Get the addresses and IRQ */
1191 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1188 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1192 regs = devm_ioremap_resource(&pdev->dev, res); 1189 regs = devm_ioremap_resource(&pdev->dev, res);
diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c
new file mode 100644
index 000000000000..653e66d150c8
--- /dev/null
+++ b/sound/soc/fsl/imx-es8328.c
@@ -0,0 +1,232 @@
1/*
2 * Copyright 2012 Freescale Semiconductor, Inc.
3 * Copyright 2012 Linaro Ltd.
4 *
5 * The code contained herein is licensed under the GNU General Public
6 * License. You may obtain a copy of the GNU General Public License
7 * Version 2 or later at the following locations:
8 *
9 * http://www.opensource.org/licenses/gpl-license.html
10 * http://www.gnu.org/copyleft/gpl.html
11 */
12
13#include <linux/gpio.h>
14#include <linux/module.h>
15#include <linux/of.h>
16#include <linux/of_platform.h>
17#include <linux/i2c.h>
18#include <linux/of_gpio.h>
19#include <sound/soc.h>
20#include <sound/jack.h>
21
22#include "imx-audmux.h"
23
24#define DAI_NAME_SIZE 32
25#define MUX_PORT_MAX 7
26
27struct imx_es8328_data {
28 struct device *dev;
29 struct snd_soc_dai_link dai;
30 struct snd_soc_card card;
31 char codec_dai_name[DAI_NAME_SIZE];
32 char platform_name[DAI_NAME_SIZE];
33 int jack_gpio;
34};
35
36static struct snd_soc_jack_gpio headset_jack_gpios[] = {
37 {
38 .gpio = -1,
39 .name = "headset-gpio",
40 .report = SND_JACK_HEADSET,
41 .invert = 0,
42 .debounce_time = 200,
43 },
44};
45
46static struct snd_soc_jack headset_jack;
47
48static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd)
49{
50 struct imx_es8328_data *data = container_of(rtd->card,
51 struct imx_es8328_data, card);
52 int ret = 0;
53
54 /* Headphone jack detection */
55 if (gpio_is_valid(data->jack_gpio)) {
56 ret = snd_soc_jack_new(rtd->codec, "Headphone",
57 SND_JACK_HEADPHONE | SND_JACK_BTN_0,
58 &headset_jack);
59 if (ret)
60 return ret;
61
62 headset_jack_gpios[0].gpio = data->jack_gpio;
63 ret = snd_soc_jack_add_gpios(&headset_jack,
64 ARRAY_SIZE(headset_jack_gpios),
65 headset_jack_gpios);
66 }
67
68 return ret;
69}
70
71static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = {
72 SND_SOC_DAPM_MIC("Mic Jack", NULL),
73 SND_SOC_DAPM_HP("Headphone", NULL),
74 SND_SOC_DAPM_SPK("Speaker", NULL),
75 SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0),
76};
77
78static int imx_es8328_probe(struct platform_device *pdev)
79{
80 struct device_node *np = pdev->dev.of_node;
81 struct device_node *ssi_np, *codec_np;
82 struct platform_device *ssi_pdev;
83 struct imx_es8328_data *data;
84 u32 int_port, ext_port;
85 int ret;
86 struct device *dev = &pdev->dev;
87
88 ret = of_property_read_u32(np, "mux-int-port", &int_port);
89 if (ret) {
90 dev_err(dev, "mux-int-port missing or invalid\n");
91 goto fail;
92 }
93 if (int_port > MUX_PORT_MAX || int_port == 0) {
94 dev_err(dev, "mux-int-port: hardware only has %d mux ports\n",
95 MUX_PORT_MAX);
96 goto fail;
97 }
98
99 ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
100 if (ret) {
101 dev_err(dev, "mux-ext-port missing or invalid\n");
102 goto fail;
103 }
104 if (ext_port > MUX_PORT_MAX || ext_port == 0) {
105 dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n",
106 MUX_PORT_MAX);
107 goto fail;
108 }
109
110 /*
111 * The port numbering in the hardware manual starts at 1, while
112 * the audmux API expects it starts at 0.
113 */
114 int_port--;
115 ext_port--;
116 ret = imx_audmux_v2_configure_port(int_port,
117 IMX_AUDMUX_V2_PTCR_SYN |
118 IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
119 IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
120 IMX_AUDMUX_V2_PTCR_TFSDIR |
121 IMX_AUDMUX_V2_PTCR_TCLKDIR,
122 IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
123 if (ret) {
124 dev_err(dev, "audmux internal port setup failed\n");
125 return ret;
126 }
127 ret = imx_audmux_v2_configure_port(ext_port,
128 IMX_AUDMUX_V2_PTCR_SYN,
129 IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
130 if (ret) {
131 dev_err(dev, "audmux external port setup failed\n");
132 return ret;
133 }
134
135 ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
136 codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
137 if (!ssi_np || !codec_np) {
138 dev_err(dev, "phandle missing or invalid\n");
139 ret = -EINVAL;
140 goto fail;
141 }
142
143 ssi_pdev = of_find_device_by_node(ssi_np);
144 if (!ssi_pdev) {
145 dev_err(dev, "failed to find SSI platform device\n");
146 ret = -EINVAL;
147 goto fail;
148 }
149
150 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
151 if (!data) {
152 ret = -ENOMEM;
153 goto fail;
154 }
155
156 data->dev = dev;
157
158 data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0);
159
160 data->dai.name = "hifi";
161 data->dai.stream_name = "hifi";
162 data->dai.codec_dai_name = "es8328-hifi-analog";
163 data->dai.codec_of_node = codec_np;
164 data->dai.cpu_of_node = ssi_np;
165 data->dai.platform_of_node = ssi_np;
166 data->dai.init = &imx_es8328_dai_init;
167 data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
168 SND_SOC_DAIFMT_CBM_CFM;
169
170 data->card.dev = dev;
171 data->card.dapm_widgets = imx_es8328_dapm_widgets;
172 data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets);
173 ret = snd_soc_of_parse_card_name(&data->card, "model");
174 if (ret) {
175 dev_err(dev, "Unable to parse card name\n");
176 goto fail;
177 }
178 ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
179 if (ret) {
180 dev_err(dev, "Unable to parse routing: %d\n", ret);
181 goto fail;
182 }
183 data->card.num_links = 1;
184 data->card.owner = THIS_MODULE;
185 data->card.dai_link = &data->dai;
186
187 ret = snd_soc_register_card(&data->card);
188 if (ret) {
189 dev_err(dev, "Unable to register: %d\n", ret);
190 goto fail;
191 }
192
193 platform_set_drvdata(pdev, data);
194fail:
195 of_node_put(ssi_np);
196 of_node_put(codec_np);
197
198 return ret;
199}
200
201static int imx_es8328_remove(struct platform_device *pdev)
202{
203 struct imx_es8328_data *data = platform_get_drvdata(pdev);
204
205 snd_soc_jack_free_gpios(&headset_jack, ARRAY_SIZE(headset_jack_gpios),
206 headset_jack_gpios);
207
208 snd_soc_unregister_card(&data->card);
209
210 return 0;
211}
212
213static const struct of_device_id imx_es8328_dt_ids[] = {
214 { .compatible = "fsl,imx-audio-es8328", },
215 { /* sentinel */ }
216};
217MODULE_DEVICE_TABLE(of, imx_es8328_dt_ids);
218
219static struct platform_driver imx_es8328_driver = {
220 .driver = {
221 .name = "imx-es8328",
222 .of_match_table = imx_es8328_dt_ids,
223 },
224 .probe = imx_es8328_probe,
225 .remove = imx_es8328_remove,
226};
227module_platform_driver(imx_es8328_driver);
228
229MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
230MODULE_DESCRIPTION("Kosagi i.MX6 ES8328 ASoC machine driver");
231MODULE_LICENSE("GPL v2");
232MODULE_ALIAS("platform:imx-audio-es8328");