aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Dannenberg <dannenberg@ti.com>2017-12-05 15:52:56 -0500
committerMark Brown <broonie@kernel.org>2017-12-06 08:06:04 -0500
commit993a3450712b2a723689b6b6b1a7fe6fe053708e (patch)
tree4ee3c3a1481503b1d2f2b2396f8c9c15933056c2
parent4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff)
ASoC: pcm186x: Add initial PCM1862/63/64/65 universal ADC driver
This is an initial version of the PCM186x codec driver supporting both 2-channel and 4-channel device variants. Not all device features are supported yet such as master/slave mode PLL configuration for which the codec driver currently relies on the PCM186x built-in clock auto-detection feature or the connection of digital microphones. However here is what's here and what should work: - Support for SPI and I2C low-level interfaces - Regmap support and basic register definitions - Input Mixer and Mux selection - I2C, LJ, and TDM DAI format support Signed-off-by: Andreas Dannenberg <dannenberg@ti.com> Signed-off-by: Michael Stecklein <m-stecklein@ti.com> Signed-off-by: Andrew F. Davis <afd@ti.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/Kconfig17
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/pcm186x-i2c.c69
-rw-r--r--sound/soc/codecs/pcm186x-spi.c69
-rw-r--r--sound/soc/codecs/pcm186x.c719
-rw-r--r--sound/soc/codecs/pcm186x.h220
6 files changed, 1100 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index a42ddbc93f3d..dda8c01170b3 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -109,6 +109,8 @@ config SND_SOC_ALL_CODECS
109 select SND_SOC_PCM1681 if I2C 109 select SND_SOC_PCM1681 if I2C
110 select SND_SOC_PCM179X_I2C if I2C 110 select SND_SOC_PCM179X_I2C if I2C
111 select SND_SOC_PCM179X_SPI if SPI_MASTER 111 select SND_SOC_PCM179X_SPI if SPI_MASTER
112 select SND_SOC_PCM186X_I2C if I2C
113 select SND_SOC_PCM186X_SPI if SPI_MASTER
112 select SND_SOC_PCM3008 114 select SND_SOC_PCM3008
113 select SND_SOC_PCM3168A_I2C if I2C 115 select SND_SOC_PCM3168A_I2C if I2C
114 select SND_SOC_PCM3168A_SPI if SPI_MASTER 116 select SND_SOC_PCM3168A_SPI if SPI_MASTER
@@ -661,6 +663,21 @@ config SND_SOC_PCM179X_SPI
661 Enable support for Texas Instruments PCM179x CODEC. 663 Enable support for Texas Instruments PCM179x CODEC.
662 Select this if your PCM179x is connected via an SPI bus. 664 Select this if your PCM179x is connected via an SPI bus.
663 665
666config SND_SOC_PCM186X
667 tristate
668
669config SND_SOC_PCM186X_I2C
670 tristate "Texas Instruments PCM186x CODECs - I2C"
671 depends on I2C
672 select SND_SOC_PCM186X
673 select REGMAP_I2C
674
675config SND_SOC_PCM186X_SPI
676 tristate "Texas Instruments PCM186x CODECs - SPI"
677 depends on SPI_MASTER
678 select SND_SOC_PCM186X
679 select REGMAP_SPI
680
664config SND_SOC_PCM3008 681config SND_SOC_PCM3008
665 tristate 682 tristate
666 683
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 0001069ce2a7..146e48a60098 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -105,6 +105,9 @@ snd-soc-pcm1681-objs := pcm1681.o
105snd-soc-pcm179x-codec-objs := pcm179x.o 105snd-soc-pcm179x-codec-objs := pcm179x.o
106snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o 106snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o
107snd-soc-pcm179x-spi-objs := pcm179x-spi.o 107snd-soc-pcm179x-spi-objs := pcm179x-spi.o
108snd-soc-pcm186x-objs := pcm186x.o
109snd-soc-pcm186x-i2c-objs := pcm186x-i2c.o
110snd-soc-pcm186x-spi-objs := pcm186x-spi.o
108snd-soc-pcm3008-objs := pcm3008.o 111snd-soc-pcm3008-objs := pcm3008.o
109snd-soc-pcm3168a-objs := pcm3168a.o 112snd-soc-pcm3168a-objs := pcm3168a.o
110snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o 113snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o
@@ -345,6 +348,9 @@ obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
345obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o 348obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o
346obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o 349obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o
347obj-$(CONFIG_SND_SOC_PCM179X_SPI) += snd-soc-pcm179x-spi.o 350obj-$(CONFIG_SND_SOC_PCM179X_SPI) += snd-soc-pcm179x-spi.o
351obj-$(CONFIG_SND_SOC_PCM186X) += snd-soc-pcm186x.o
352obj-$(CONFIG_SND_SOC_PCM186X_I2C) += snd-soc-pcm186x-i2c.o
353obj-$(CONFIG_SND_SOC_PCM186X_SPI) += snd-soc-pcm186x-spi.o
348obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o 354obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
349obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o 355obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o
350obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o 356obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o
diff --git a/sound/soc/codecs/pcm186x-i2c.c b/sound/soc/codecs/pcm186x-i2c.c
new file mode 100644
index 000000000000..543621232d60
--- /dev/null
+++ b/sound/soc/codecs/pcm186x-i2c.c
@@ -0,0 +1,69 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Texas Instruments PCM186x Universal Audio ADC - I2C
4 *
5 * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
6 * Andreas Dannenberg <dannenberg@ti.com>
7 * Andrew F. Davis <afd@ti.com>
8 */
9
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/i2c.h>
13
14#include "pcm186x.h"
15
16static const struct of_device_id pcm186x_of_match[] = {
17 { .compatible = "ti,pcm1862", .data = (void *)PCM1862 },
18 { .compatible = "ti,pcm1863", .data = (void *)PCM1863 },
19 { .compatible = "ti,pcm1864", .data = (void *)PCM1864 },
20 { .compatible = "ti,pcm1865", .data = (void *)PCM1865 },
21 { }
22};
23MODULE_DEVICE_TABLE(of, pcm186x_of_match);
24
25static int pcm186x_i2c_probe(struct i2c_client *i2c,
26 const struct i2c_device_id *id)
27{
28 const enum pcm186x_type type = (enum pcm186x_type)id->driver_data;
29 int irq = i2c->irq;
30 struct regmap *regmap;
31
32 regmap = devm_regmap_init_i2c(i2c, &pcm186x_regmap);
33 if (IS_ERR(regmap))
34 return PTR_ERR(regmap);
35
36 return pcm186x_probe(&i2c->dev, type, irq, regmap);
37}
38
39static int pcm186x_i2c_remove(struct i2c_client *i2c)
40{
41 pcm186x_remove(&i2c->dev);
42
43 return 0;
44}
45
46static const struct i2c_device_id pcm186x_i2c_id[] = {
47 { "pcm1862", PCM1862 },
48 { "pcm1863", PCM1863 },
49 { "pcm1864", PCM1864 },
50 { "pcm1865", PCM1865 },
51 { }
52};
53MODULE_DEVICE_TABLE(i2c, pcm186x_i2c_id);
54
55static struct i2c_driver pcm186x_i2c_driver = {
56 .probe = pcm186x_i2c_probe,
57 .remove = pcm186x_i2c_remove,
58 .id_table = pcm186x_i2c_id,
59 .driver = {
60 .name = "pcm186x",
61 .of_match_table = pcm186x_of_match,
62 },
63};
64module_i2c_driver(pcm186x_i2c_driver);
65
66MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
67MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
68MODULE_DESCRIPTION("PCM186x Universal Audio ADC I2C Interface Driver");
69MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm186x-spi.c b/sound/soc/codecs/pcm186x-spi.c
new file mode 100644
index 000000000000..2366f8e4d4d4
--- /dev/null
+++ b/sound/soc/codecs/pcm186x-spi.c
@@ -0,0 +1,69 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Texas Instruments PCM186x Universal Audio ADC - SPI
4 *
5 * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
6 * Andreas Dannenberg <dannenberg@ti.com>
7 * Andrew F. Davis <afd@ti.com>
8 */
9
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/spi/spi.h>
13
14#include "pcm186x.h"
15
16static const struct of_device_id pcm186x_of_match[] = {
17 { .compatible = "ti,pcm1862", .data = (void *)PCM1862 },
18 { .compatible = "ti,pcm1863", .data = (void *)PCM1863 },
19 { .compatible = "ti,pcm1864", .data = (void *)PCM1864 },
20 { .compatible = "ti,pcm1865", .data = (void *)PCM1865 },
21 { }
22};
23MODULE_DEVICE_TABLE(of, pcm186x_of_match);
24
25static int pcm186x_spi_probe(struct spi_device *spi)
26{
27 const enum pcm186x_type type =
28 (enum pcm186x_type)spi_get_device_id(spi)->driver_data;
29 int irq = spi->irq;
30 struct regmap *regmap;
31
32 regmap = devm_regmap_init_spi(spi, &pcm186x_regmap);
33 if (IS_ERR(regmap))
34 return PTR_ERR(regmap);
35
36 return pcm186x_probe(&spi->dev, type, irq, regmap);
37}
38
39static int pcm186x_spi_remove(struct spi_device *spi)
40{
41 pcm186x_remove(&spi->dev);
42
43 return 0;
44}
45
46static const struct spi_device_id pcm186x_spi_id[] = {
47 { "pcm1862", PCM1862 },
48 { "pcm1863", PCM1863 },
49 { "pcm1864", PCM1864 },
50 { "pcm1865", PCM1865 },
51 { }
52};
53MODULE_DEVICE_TABLE(spi, pcm186x_spi_id);
54
55static struct spi_driver pcm186x_spi_driver = {
56 .probe = pcm186x_spi_probe,
57 .remove = pcm186x_spi_remove,
58 .id_table = pcm186x_spi_id,
59 .driver = {
60 .name = "pcm186x",
61 .of_match_table = pcm186x_of_match,
62 },
63};
64module_spi_driver(pcm186x_spi_driver);
65
66MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
67MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
68MODULE_DESCRIPTION("PCM186x Universal Audio ADC SPI Interface Driver");
69MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c
new file mode 100644
index 000000000000..f7aa56e20169
--- /dev/null
+++ b/sound/soc/codecs/pcm186x.c
@@ -0,0 +1,719 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Texas Instruments PCM186x Universal Audio ADC
4 *
5 * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
6 * Andreas Dannenberg <dannenberg@ti.com>
7 * Andrew F. Davis <afd@ti.com>
8 */
9
10#include <linux/module.h>
11#include <linux/moduleparam.h>
12#include <linux/init.h>
13#include <linux/delay.h>
14#include <linux/pm.h>
15#include <linux/pm_runtime.h>
16#include <linux/regulator/consumer.h>
17#include <linux/regmap.h>
18#include <linux/slab.h>
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/pcm_params.h>
22#include <sound/soc.h>
23#include <sound/jack.h>
24#include <sound/initval.h>
25#include <sound/tlv.h>
26
27#include "pcm186x.h"
28
29static const char * const pcm186x_supply_names[] = {
30 "avdd", /* Analog power supply. Connect to 3.3-V supply. */
31 "dvdd", /* Digital power supply. Connect to 3.3-V supply. */
32 "iovdd", /* I/O power supply. Connect to 3.3-V or 1.8-V. */
33};
34#define PCM186x_NUM_SUPPLIES ARRAY_SIZE(pcm186x_supply_names)
35
36struct pcm186x_priv {
37 struct regmap *regmap;
38 struct regulator_bulk_data supplies[PCM186x_NUM_SUPPLIES];
39 unsigned int sysclk;
40 unsigned int tdm_offset;
41 bool is_tdm_mode;
42 bool is_master_mode;
43};
44
45static const DECLARE_TLV_DB_SCALE(pcm186x_pga_tlv, -1200, 4000, 50);
46
47static const struct snd_kcontrol_new pcm1863_snd_controls[] = {
48 SOC_DOUBLE_R_S_TLV("ADC Capture Volume", PCM186X_PGA_VAL_CH1_L,
49 PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
50 pcm186x_pga_tlv),
51};
52
53static const struct snd_kcontrol_new pcm1865_snd_controls[] = {
54 SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", PCM186X_PGA_VAL_CH1_L,
55 PCM186X_PGA_VAL_CH1_R, 0, -24, 80, 7, 0,
56 pcm186x_pga_tlv),
57 SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", PCM186X_PGA_VAL_CH2_L,
58 PCM186X_PGA_VAL_CH2_R, 0, -24, 80, 7, 0,
59 pcm186x_pga_tlv),
60};
61
62const unsigned int pcm186x_adc_input_channel_sel_value[] = {
63 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
64 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
65 0x10, 0x20, 0x30
66};
67
68static const char * const pcm186x_adcl_input_channel_sel_text[] = {
69 "No Select",
70 "VINL1[SE]", /* Default for ADC1L */
71 "VINL2[SE]", /* Default for ADC2L */
72 "VINL2[SE] + VINL1[SE]",
73 "VINL3[SE]",
74 "VINL3[SE] + VINL1[SE]",
75 "VINL3[SE] + VINL2[SE]",
76 "VINL3[SE] + VINL2[SE] + VINL1[SE]",
77 "VINL4[SE]",
78 "VINL4[SE] + VINL1[SE]",
79 "VINL4[SE] + VINL2[SE]",
80 "VINL4[SE] + VINL2[SE] + VINL1[SE]",
81 "VINL4[SE] + VINL3[SE]",
82 "VINL4[SE] + VINL3[SE] + VINL1[SE]",
83 "VINL4[SE] + VINL3[SE] + VINL2[SE]",
84 "VINL4[SE] + VINL3[SE] + VINL2[SE] + VINL1[SE]",
85 "{VIN1P, VIN1M}[DIFF]",
86 "{VIN4P, VIN4M}[DIFF]",
87 "{VIN1P, VIN1M}[DIFF] + {VIN4P, VIN4M}[DIFF]"
88};
89
90static const char * const pcm186x_adcr_input_channel_sel_text[] = {
91 "No Select",
92 "VINR1[SE]", /* Default for ADC1R */
93 "VINR2[SE]", /* Default for ADC2R */
94 "VINR2[SE] + VINR1[SE]",
95 "VINR3[SE]",
96 "VINR3[SE] + VINR1[SE]",
97 "VINR3[SE] + VINR2[SE]",
98 "VINR3[SE] + VINR2[SE] + VINR1[SE]",
99 "VINR4[SE]",
100 "VINR4[SE] + VINR1[SE]",
101 "VINR4[SE] + VINR2[SE]",
102 "VINR4[SE] + VINR2[SE] + VINR1[SE]",
103 "VINR4[SE] + VINR3[SE]",
104 "VINR4[SE] + VINR3[SE] + VINR1[SE]",
105 "VINR4[SE] + VINR3[SE] + VINR2[SE]",
106 "VINR4[SE] + VINR3[SE] + VINR2[SE] + VINR1[SE]",
107 "{VIN2P, VIN2M}[DIFF]",
108 "{VIN3P, VIN3M}[DIFF]",
109 "{VIN2P, VIN2M}[DIFF] + {VIN3P, VIN3M}[DIFF]"
110};
111
112static const struct soc_enum pcm186x_adc_input_channel_sel[] = {
113 SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_L, 0,
114 PCM186X_ADC_INPUT_SEL_MASK,
115 ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
116 pcm186x_adcl_input_channel_sel_text,
117 pcm186x_adc_input_channel_sel_value),
118 SOC_VALUE_ENUM_SINGLE(PCM186X_ADC1_INPUT_SEL_R, 0,
119 PCM186X_ADC_INPUT_SEL_MASK,
120 ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
121 pcm186x_adcr_input_channel_sel_text,
122 pcm186x_adc_input_channel_sel_value),
123 SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_L, 0,
124 PCM186X_ADC_INPUT_SEL_MASK,
125 ARRAY_SIZE(pcm186x_adcl_input_channel_sel_text),
126 pcm186x_adcl_input_channel_sel_text,
127 pcm186x_adc_input_channel_sel_value),
128 SOC_VALUE_ENUM_SINGLE(PCM186X_ADC2_INPUT_SEL_R, 0,
129 PCM186X_ADC_INPUT_SEL_MASK,
130 ARRAY_SIZE(pcm186x_adcr_input_channel_sel_text),
131 pcm186x_adcr_input_channel_sel_text,
132 pcm186x_adc_input_channel_sel_value),
133};
134
135static const struct snd_kcontrol_new pcm186x_adc_mux_controls[] = {
136 SOC_DAPM_ENUM("ADC1 Left Input", pcm186x_adc_input_channel_sel[0]),
137 SOC_DAPM_ENUM("ADC1 Right Input", pcm186x_adc_input_channel_sel[1]),
138 SOC_DAPM_ENUM("ADC2 Left Input", pcm186x_adc_input_channel_sel[2]),
139 SOC_DAPM_ENUM("ADC2 Right Input", pcm186x_adc_input_channel_sel[3]),
140};
141
142static const struct snd_soc_dapm_widget pcm1863_dapm_widgets[] = {
143 SND_SOC_DAPM_INPUT("VINL1"),
144 SND_SOC_DAPM_INPUT("VINR1"),
145 SND_SOC_DAPM_INPUT("VINL2"),
146 SND_SOC_DAPM_INPUT("VINR2"),
147 SND_SOC_DAPM_INPUT("VINL3"),
148 SND_SOC_DAPM_INPUT("VINR3"),
149 SND_SOC_DAPM_INPUT("VINL4"),
150 SND_SOC_DAPM_INPUT("VINR4"),
151
152 SND_SOC_DAPM_MUX("ADC Left Capture Source", SND_SOC_NOPM, 0, 0,
153 &pcm186x_adc_mux_controls[0]),
154 SND_SOC_DAPM_MUX("ADC Right Capture Source", SND_SOC_NOPM, 0, 0,
155 &pcm186x_adc_mux_controls[1]),
156
157 /*
158 * Put the codec into SLEEP mode when not in use, allowing the
159 * Energysense mechanism to operate.
160 */
161 SND_SOC_DAPM_ADC("ADC", "HiFi Capture", PCM186X_POWER_CTRL, 1, 0),
162};
163
164static const struct snd_soc_dapm_widget pcm1865_dapm_widgets[] = {
165 SND_SOC_DAPM_INPUT("VINL1"),
166 SND_SOC_DAPM_INPUT("VINR1"),
167 SND_SOC_DAPM_INPUT("VINL2"),
168 SND_SOC_DAPM_INPUT("VINR2"),
169 SND_SOC_DAPM_INPUT("VINL3"),
170 SND_SOC_DAPM_INPUT("VINR3"),
171 SND_SOC_DAPM_INPUT("VINL4"),
172 SND_SOC_DAPM_INPUT("VINR4"),
173
174 SND_SOC_DAPM_MUX("ADC1 Left Capture Source", SND_SOC_NOPM, 0, 0,
175 &pcm186x_adc_mux_controls[0]),
176 SND_SOC_DAPM_MUX("ADC1 Right Capture Source", SND_SOC_NOPM, 0, 0,
177 &pcm186x_adc_mux_controls[1]),
178 SND_SOC_DAPM_MUX("ADC2 Left Capture Source", SND_SOC_NOPM, 0, 0,
179 &pcm186x_adc_mux_controls[2]),
180 SND_SOC_DAPM_MUX("ADC2 Right Capture Source", SND_SOC_NOPM, 0, 0,
181 &pcm186x_adc_mux_controls[3]),
182
183 /*
184 * Put the codec into SLEEP mode when not in use, allowing the
185 * Energysense mechanism to operate.
186 */
187 SND_SOC_DAPM_ADC("ADC1", "HiFi Capture 1", PCM186X_POWER_CTRL, 1, 0),
188 SND_SOC_DAPM_ADC("ADC2", "HiFi Capture 2", PCM186X_POWER_CTRL, 1, 0),
189};
190
191static const struct snd_soc_dapm_route pcm1863_dapm_routes[] = {
192 { "ADC Left Capture Source", NULL, "VINL1" },
193 { "ADC Left Capture Source", NULL, "VINR1" },
194 { "ADC Left Capture Source", NULL, "VINL2" },
195 { "ADC Left Capture Source", NULL, "VINR2" },
196 { "ADC Left Capture Source", NULL, "VINL3" },
197 { "ADC Left Capture Source", NULL, "VINR3" },
198 { "ADC Left Capture Source", NULL, "VINL4" },
199 { "ADC Left Capture Source", NULL, "VINR4" },
200
201 { "ADC", NULL, "ADC Left Capture Source" },
202
203 { "ADC Right Capture Source", NULL, "VINL1" },
204 { "ADC Right Capture Source", NULL, "VINR1" },
205 { "ADC Right Capture Source", NULL, "VINL2" },
206 { "ADC Right Capture Source", NULL, "VINR2" },
207 { "ADC Right Capture Source", NULL, "VINL3" },
208 { "ADC Right Capture Source", NULL, "VINR3" },
209 { "ADC Right Capture Source", NULL, "VINL4" },
210 { "ADC Right Capture Source", NULL, "VINR4" },
211
212 { "ADC", NULL, "ADC Right Capture Source" },
213};
214
215static const struct snd_soc_dapm_route pcm1865_dapm_routes[] = {
216 { "ADC1 Left Capture Source", NULL, "VINL1" },
217 { "ADC1 Left Capture Source", NULL, "VINR1" },
218 { "ADC1 Left Capture Source", NULL, "VINL2" },
219 { "ADC1 Left Capture Source", NULL, "VINR2" },
220 { "ADC1 Left Capture Source", NULL, "VINL3" },
221 { "ADC1 Left Capture Source", NULL, "VINR3" },
222 { "ADC1 Left Capture Source", NULL, "VINL4" },
223 { "ADC1 Left Capture Source", NULL, "VINR4" },
224
225 { "ADC1", NULL, "ADC1 Left Capture Source" },
226
227 { "ADC1 Right Capture Source", NULL, "VINL1" },
228 { "ADC1 Right Capture Source", NULL, "VINR1" },
229 { "ADC1 Right Capture Source", NULL, "VINL2" },
230 { "ADC1 Right Capture Source", NULL, "VINR2" },
231 { "ADC1 Right Capture Source", NULL, "VINL3" },
232 { "ADC1 Right Capture Source", NULL, "VINR3" },
233 { "ADC1 Right Capture Source", NULL, "VINL4" },
234 { "ADC1 Right Capture Source", NULL, "VINR4" },
235
236 { "ADC1", NULL, "ADC1 Right Capture Source" },
237
238 { "ADC2 Left Capture Source", NULL, "VINL1" },
239 { "ADC2 Left Capture Source", NULL, "VINR1" },
240 { "ADC2 Left Capture Source", NULL, "VINL2" },
241 { "ADC2 Left Capture Source", NULL, "VINR2" },
242 { "ADC2 Left Capture Source", NULL, "VINL3" },
243 { "ADC2 Left Capture Source", NULL, "VINR3" },
244 { "ADC2 Left Capture Source", NULL, "VINL4" },
245 { "ADC2 Left Capture Source", NULL, "VINR4" },
246
247 { "ADC2", NULL, "ADC2 Left Capture Source" },
248
249 { "ADC2 Right Capture Source", NULL, "VINL1" },
250 { "ADC2 Right Capture Source", NULL, "VINR1" },
251 { "ADC2 Right Capture Source", NULL, "VINL2" },
252 { "ADC2 Right Capture Source", NULL, "VINR2" },
253 { "ADC2 Right Capture Source", NULL, "VINL3" },
254 { "ADC2 Right Capture Source", NULL, "VINR3" },
255 { "ADC2 Right Capture Source", NULL, "VINL4" },
256 { "ADC2 Right Capture Source", NULL, "VINR4" },
257
258 { "ADC2", NULL, "ADC2 Right Capture Source" },
259};
260
261static int pcm186x_hw_params(struct snd_pcm_substream *substream,
262 struct snd_pcm_hw_params *params,
263 struct snd_soc_dai *dai)
264{
265 struct snd_soc_codec *codec = dai->codec;
266
267 struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
268 unsigned int rate = params_rate(params);
269 unsigned int format = params_format(params);
270 unsigned int width = params_width(params);
271 unsigned int channels = params_channels(params);
272 unsigned int div_lrck;
273 unsigned int div_bck;
274 u8 tdm_tx_sel = 0;
275 u8 pcm_cfg = 0;
276
277 dev_dbg(codec->dev, "%s() rate=%u format=0x%x width=%u channels=%u\n",
278 __func__, rate, format, width, channels);
279
280 switch (width) {
281 case 16:
282 pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_16 <<
283 PCM186X_PCM_CFG_RX_WLEN_SHIFT |
284 PCM186X_PCM_CFG_TX_WLEN_16 <<
285 PCM186X_PCM_CFG_TX_WLEN_SHIFT;
286 break;
287 case 20:
288 pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_20 <<
289 PCM186X_PCM_CFG_RX_WLEN_SHIFT |
290 PCM186X_PCM_CFG_TX_WLEN_20 <<
291 PCM186X_PCM_CFG_TX_WLEN_SHIFT;
292 break;
293 case 24:
294 pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_24 <<
295 PCM186X_PCM_CFG_RX_WLEN_SHIFT |
296 PCM186X_PCM_CFG_TX_WLEN_24 <<
297 PCM186X_PCM_CFG_TX_WLEN_SHIFT;
298 break;
299 case 32:
300 pcm_cfg = PCM186X_PCM_CFG_RX_WLEN_32 <<
301 PCM186X_PCM_CFG_RX_WLEN_SHIFT |
302 PCM186X_PCM_CFG_TX_WLEN_32 <<
303 PCM186X_PCM_CFG_TX_WLEN_SHIFT;
304 break;
305 default:
306 return -EINVAL;
307 }
308
309 snd_soc_update_bits(codec, PCM186X_PCM_CFG,
310 PCM186X_PCM_CFG_RX_WLEN_MASK |
311 PCM186X_PCM_CFG_TX_WLEN_MASK,
312 pcm_cfg);
313
314 div_lrck = width * channels;
315
316 if (priv->is_tdm_mode) {
317 /* Select TDM transmission data */
318 switch (channels) {
319 case 2:
320 tdm_tx_sel = PCM186X_TDM_TX_SEL_2CH;
321 break;
322 case 4:
323 tdm_tx_sel = PCM186X_TDM_TX_SEL_4CH;
324 break;
325 case 6:
326 tdm_tx_sel = PCM186X_TDM_TX_SEL_6CH;
327 break;
328 default:
329 return -EINVAL;
330 }
331
332 snd_soc_update_bits(codec, PCM186X_TDM_TX_SEL,
333 PCM186X_TDM_TX_SEL_MASK, tdm_tx_sel);
334
335 /* In DSP/TDM mode, the LRCLK divider must be 256 */
336 div_lrck = 256;
337
338 /* Configure 1/256 duty cycle for LRCK */
339 snd_soc_update_bits(codec, PCM186X_PCM_CFG,
340 PCM186X_PCM_CFG_TDM_LRCK_MODE,
341 PCM186X_PCM_CFG_TDM_LRCK_MODE);
342 }
343
344 /* Only configure clock dividers in master mode. */
345 if (priv->is_master_mode) {
346 div_bck = priv->sysclk / (div_lrck * rate);
347
348 dev_dbg(codec->dev,
349 "%s() master_clk=%u div_bck=%u div_lrck=%u\n",
350 __func__, priv->sysclk, div_bck, div_lrck);
351
352 snd_soc_write(codec, PCM186X_BCK_DIV, div_bck - 1);
353 snd_soc_write(codec, PCM186X_LRK_DIV, div_lrck - 1);
354 }
355
356 return 0;
357}
358
359static int pcm186x_set_fmt(struct snd_soc_dai *dai, unsigned int format)
360{
361 struct snd_soc_codec *codec = dai->codec;
362 struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
363 u8 clk_ctrl = 0;
364 u8 pcm_cfg = 0;
365
366 dev_dbg(codec->dev, "%s() format=0x%x\n", __func__, format);
367
368 /* set master/slave audio interface */
369 switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
370 case SND_SOC_DAIFMT_CBM_CFM:
371 if (!priv->sysclk) {
372 dev_err(codec->dev, "operating in master mode requires sysclock to be configured\n");
373 return -EINVAL;
374 }
375 clk_ctrl |= PCM186X_CLK_CTRL_MST_MODE;
376 priv->is_master_mode = true;
377 break;
378 case SND_SOC_DAIFMT_CBS_CFS:
379 priv->is_master_mode = false;
380 break;
381 default:
382 dev_err(codec->dev, "Invalid DAI master/slave interface\n");
383 return -EINVAL;
384 }
385
386 /* set interface polarity */
387 switch (format & SND_SOC_DAIFMT_INV_MASK) {
388 case SND_SOC_DAIFMT_NB_NF:
389 break;
390 default:
391 dev_err(codec->dev, "Inverted DAI clocks not supported\n");
392 return -EINVAL;
393 }
394
395 /* set interface format */
396 switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
397 case SND_SOC_DAIFMT_I2S:
398 pcm_cfg = PCM186X_PCM_CFG_FMT_I2S;
399 break;
400 case SND_SOC_DAIFMT_LEFT_J:
401 pcm_cfg = PCM186X_PCM_CFG_FMT_LEFTJ;
402 break;
403 case SND_SOC_DAIFMT_DSP_A:
404 priv->tdm_offset += 1;
405 /* Fall through... DSP_A uses the same basic config as DSP_B
406 * except we need to shift the TDM output by one BCK cycle
407 */
408 case SND_SOC_DAIFMT_DSP_B:
409 priv->is_tdm_mode = true;
410 pcm_cfg = PCM186X_PCM_CFG_FMT_TDM;
411 break;
412 default:
413 dev_err(codec->dev, "Invalid DAI format\n");
414 return -EINVAL;
415 }
416
417 snd_soc_update_bits(codec, PCM186X_CLK_CTRL,
418 PCM186X_CLK_CTRL_MST_MODE, clk_ctrl);
419
420 snd_soc_write(codec, PCM186X_TDM_TX_OFFSET, priv->tdm_offset);
421
422 snd_soc_update_bits(codec, PCM186X_PCM_CFG,
423 PCM186X_PCM_CFG_FMT_MASK, pcm_cfg);
424
425 return 0;
426}
427
428static int pcm186x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
429 unsigned int rx_mask, int slots, int slot_width)
430{
431 struct snd_soc_codec *codec = dai->codec;
432 struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
433 unsigned int first_slot, last_slot, tdm_offset;
434
435 dev_dbg(codec->dev,
436 "%s() tx_mask=0x%x rx_mask=0x%x slots=%d slot_width=%d\n",
437 __func__, tx_mask, rx_mask, slots, slot_width);
438
439 if (!tx_mask) {
440 dev_err(codec->dev, "tdm tx mask must not be 0\n");
441 return -EINVAL;
442 }
443
444 first_slot = __ffs(tx_mask);
445 last_slot = __fls(tx_mask);
446
447 if (last_slot - first_slot != hweight32(tx_mask) - 1) {
448 dev_err(codec->dev, "tdm tx mask must be contiguous\n");
449 return -EINVAL;
450 }
451
452 tdm_offset = first_slot * slot_width;
453
454 if (tdm_offset > 255) {
455 dev_err(codec->dev, "tdm tx slot selection out of bounds\n");
456 return -EINVAL;
457 }
458
459 priv->tdm_offset = tdm_offset;
460
461 return 0;
462}
463
464static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
465 unsigned int freq, int dir)
466{
467 struct snd_soc_codec *codec = dai->codec;
468 struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
469
470 dev_dbg(codec->dev, "%s() clk_id=%d freq=%u dir=%d\n",
471 __func__, clk_id, freq, dir);
472
473 priv->sysclk = freq;
474
475 return 0;
476}
477
478const struct snd_soc_dai_ops pcm186x_dai_ops = {
479 .set_sysclk = pcm186x_set_dai_sysclk,
480 .set_tdm_slot = pcm186x_set_tdm_slot,
481 .set_fmt = pcm186x_set_fmt,
482 .hw_params = pcm186x_hw_params,
483};
484
485static struct snd_soc_dai_driver pcm1863_dai = {
486 .name = "pcm1863-aif",
487 .capture = {
488 .stream_name = "Capture",
489 .channels_min = 1,
490 .channels_max = 2,
491 .rates = PCM186X_RATES,
492 .formats = PCM186X_FORMATS,
493 },
494 .ops = &pcm186x_dai_ops,
495};
496
497static struct snd_soc_dai_driver pcm1865_dai = {
498 .name = "pcm1865-aif",
499 .capture = {
500 .stream_name = "Capture",
501 .channels_min = 1,
502 .channels_max = 4,
503 .rates = PCM186X_RATES,
504 .formats = PCM186X_FORMATS,
505 },
506 .ops = &pcm186x_dai_ops,
507};
508
509static int pcm186x_power_on(struct snd_soc_codec *codec)
510{
511 struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
512 int ret = 0;
513
514 ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
515 priv->supplies);
516 if (ret)
517 return ret;
518
519 regcache_cache_only(priv->regmap, false);
520 ret = regcache_sync(priv->regmap);
521 if (ret) {
522 dev_err(codec->dev, "Failed to restore cache\n");
523 regcache_cache_only(priv->regmap, true);
524 regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
525 priv->supplies);
526 return ret;
527 }
528
529 snd_soc_update_bits(codec, PCM186X_POWER_CTRL,
530 PCM186X_PWR_CTRL_PWRDN, 0);
531
532 return 0;
533}
534
535static int pcm186x_power_off(struct snd_soc_codec *codec)
536{
537 struct pcm186x_priv *priv = snd_soc_codec_get_drvdata(codec);
538 int ret;
539
540 snd_soc_update_bits(codec, PCM186X_POWER_CTRL,
541 PCM186X_PWR_CTRL_PWRDN, PCM186X_PWR_CTRL_PWRDN);
542
543 regcache_cache_only(priv->regmap, true);
544
545 ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
546 priv->supplies);
547 if (ret)
548 return ret;
549
550 return 0;
551}
552
553static int pcm186x_set_bias_level(struct snd_soc_codec *codec,
554 enum snd_soc_bias_level level)
555{
556 dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__,
557 snd_soc_codec_get_bias_level(codec), level);
558
559 switch (level) {
560 case SND_SOC_BIAS_ON:
561 break;
562 case SND_SOC_BIAS_PREPARE:
563 break;
564 case SND_SOC_BIAS_STANDBY:
565 if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
566 pcm186x_power_on(codec);
567 break;
568 case SND_SOC_BIAS_OFF:
569 pcm186x_power_off(codec);
570 break;
571 }
572
573 return 0;
574}
575
576static struct snd_soc_codec_driver soc_codec_dev_pcm1863 = {
577 .set_bias_level = pcm186x_set_bias_level,
578
579 .component_driver = {
580 .controls = pcm1863_snd_controls,
581 .num_controls = ARRAY_SIZE(pcm1863_snd_controls),
582 .dapm_widgets = pcm1863_dapm_widgets,
583 .num_dapm_widgets = ARRAY_SIZE(pcm1863_dapm_widgets),
584 .dapm_routes = pcm1863_dapm_routes,
585 .num_dapm_routes = ARRAY_SIZE(pcm1863_dapm_routes),
586 },
587};
588
589static struct snd_soc_codec_driver soc_codec_dev_pcm1865 = {
590 .set_bias_level = pcm186x_set_bias_level,
591 .suspend_bias_off = true,
592
593 .component_driver = {
594 .controls = pcm1865_snd_controls,
595 .num_controls = ARRAY_SIZE(pcm1865_snd_controls),
596 .dapm_widgets = pcm1865_dapm_widgets,
597 .num_dapm_widgets = ARRAY_SIZE(pcm1865_dapm_widgets),
598 .dapm_routes = pcm1865_dapm_routes,
599 .num_dapm_routes = ARRAY_SIZE(pcm1865_dapm_routes),
600 },
601};
602
603static bool pcm186x_volatile(struct device *dev, unsigned int reg)
604{
605 switch (reg) {
606 case PCM186X_PAGE:
607 case PCM186X_DEVICE_STATUS:
608 case PCM186X_FSAMPLE_STATUS:
609 case PCM186X_DIV_STATUS:
610 case PCM186X_CLK_STATUS:
611 case PCM186X_SUPPLY_STATUS:
612 case PCM186X_MMAP_STAT_CTRL:
613 case PCM186X_MMAP_ADDRESS:
614 return true;
615 }
616
617 return false;
618}
619
620static const struct regmap_range_cfg pcm186x_range = {
621 .name = "Pages",
622 .range_max = PCM186X_MAX_REGISTER,
623 .selector_reg = PCM186X_PAGE,
624 .selector_mask = 0xff,
625 .window_len = PCM186X_PAGE_LEN,
626};
627
628const struct regmap_config pcm186x_regmap = {
629 .reg_bits = 8,
630 .val_bits = 8,
631
632 .volatile_reg = pcm186x_volatile,
633
634 .ranges = &pcm186x_range,
635 .num_ranges = 1,
636
637 .max_register = PCM186X_MAX_REGISTER,
638
639 .cache_type = REGCACHE_RBTREE,
640};
641EXPORT_SYMBOL_GPL(pcm186x_regmap);
642
643int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
644 struct regmap *regmap)
645{
646 struct pcm186x_priv *priv;
647 int i, ret;
648
649 priv = devm_kzalloc(dev, sizeof(struct pcm186x_priv), GFP_KERNEL);
650 if (!priv)
651 return -ENOMEM;
652
653 dev_set_drvdata(dev, priv);
654 priv->regmap = regmap;
655
656 for (i = 0; i < ARRAY_SIZE(priv->supplies); i++)
657 priv->supplies[i].supply = pcm186x_supply_names[i];
658
659 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies),
660 priv->supplies);
661 if (ret) {
662 dev_err(dev, "failed to request supplies: %d\n", ret);
663 return ret;
664 }
665
666 ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
667 priv->supplies);
668 if (ret) {
669 dev_err(dev, "failed enable supplies: %d\n", ret);
670 return ret;
671 }
672
673 /* Reset device registers for a consistent power-on like state */
674 ret = regmap_write(regmap, PCM186X_PAGE, PCM186X_RESET);
675 if (ret) {
676 dev_err(dev, "failed to write device: %d\n", ret);
677 return ret;
678 }
679
680 ret = regulator_bulk_disable(ARRAY_SIZE(priv->supplies),
681 priv->supplies);
682 if (ret) {
683 dev_err(dev, "failed disable supplies: %d\n", ret);
684 return ret;
685 }
686
687 switch (type) {
688 case PCM1865:
689 case PCM1864:
690 ret = snd_soc_register_codec(dev, &soc_codec_dev_pcm1865,
691 &pcm1865_dai, 1);
692 break;
693 case PCM1863:
694 case PCM1862:
695 default:
696 ret = snd_soc_register_codec(dev, &soc_codec_dev_pcm1863,
697 &pcm1863_dai, 1);
698 }
699 if (ret) {
700 dev_err(dev, "failed to register CODEC: %d\n", ret);
701 return ret;
702 }
703
704 return 0;
705}
706EXPORT_SYMBOL_GPL(pcm186x_probe);
707
708int pcm186x_remove(struct device *dev)
709{
710 snd_soc_unregister_codec(dev);
711
712 return 0;
713}
714EXPORT_SYMBOL_GPL(pcm186x_remove);
715
716MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
717MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
718MODULE_DESCRIPTION("PCM186x Universal Audio ADC driver");
719MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/pcm186x.h b/sound/soc/codecs/pcm186x.h
new file mode 100644
index 000000000000..b630111bb3c4
--- /dev/null
+++ b/sound/soc/codecs/pcm186x.h
@@ -0,0 +1,220 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Texas Instruments PCM186x Universal Audio ADC
4 *
5 * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com
6 * Andreas Dannenberg <dannenberg@ti.com>
7 * Andrew F. Davis <afd@ti.com>
8 */
9
10#ifndef _PCM186X_H_
11#define _PCM186X_H_
12
13#include <linux/pm.h>
14#include <linux/regmap.h>
15
16enum pcm186x_type {
17 PCM1862,
18 PCM1863,
19 PCM1864,
20 PCM1865,
21};
22
23#define PCM186X_RATES SNDRV_PCM_RATE_8000_192000
24#define PCM186X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
25 SNDRV_PCM_FMTBIT_S20_3LE |\
26 SNDRV_PCM_FMTBIT_S24_LE | \
27 SNDRV_PCM_FMTBIT_S32_LE)
28
29#define PCM186X_PAGE_LEN 0x0100
30#define PCM186X_PAGE_BASE(n) (PCM186X_PAGE_LEN * n)
31
32/* The page selection register address is the same on all pages */
33#define PCM186X_PAGE 0
34
35/* Register Definitions - Page 0 */
36#define PCM186X_PGA_VAL_CH1_L (PCM186X_PAGE_BASE(0) + 1)
37#define PCM186X_PGA_VAL_CH1_R (PCM186X_PAGE_BASE(0) + 2)
38#define PCM186X_PGA_VAL_CH2_L (PCM186X_PAGE_BASE(0) + 3)
39#define PCM186X_PGA_VAL_CH2_R (PCM186X_PAGE_BASE(0) + 4)
40#define PCM186X_PGA_CTRL (PCM186X_PAGE_BASE(0) + 5)
41#define PCM186X_ADC1_INPUT_SEL_L (PCM186X_PAGE_BASE(0) + 6)
42#define PCM186X_ADC1_INPUT_SEL_R (PCM186X_PAGE_BASE(0) + 7)
43#define PCM186X_ADC2_INPUT_SEL_L (PCM186X_PAGE_BASE(0) + 8)
44#define PCM186X_ADC2_INPUT_SEL_R (PCM186X_PAGE_BASE(0) + 9)
45#define PCM186X_AUXADC_INPUT_SEL (PCM186X_PAGE_BASE(0) + 10)
46#define PCM186X_PCM_CFG (PCM186X_PAGE_BASE(0) + 11)
47#define PCM186X_TDM_TX_SEL (PCM186X_PAGE_BASE(0) + 12)
48#define PCM186X_TDM_TX_OFFSET (PCM186X_PAGE_BASE(0) + 13)
49#define PCM186X_TDM_RX_OFFSET (PCM186X_PAGE_BASE(0) + 14)
50#define PCM186X_DPGA_VAL_CH1_L (PCM186X_PAGE_BASE(0) + 15)
51#define PCM186X_GPIO1_0_CTRL (PCM186X_PAGE_BASE(0) + 16)
52#define PCM186X_GPIO3_2_CTRL (PCM186X_PAGE_BASE(0) + 17)
53#define PCM186X_GPIO1_0_DIR_CTRL (PCM186X_PAGE_BASE(0) + 18)
54#define PCM186X_GPIO3_2_DIR_CTRL (PCM186X_PAGE_BASE(0) + 19)
55#define PCM186X_GPIO_IN_OUT (PCM186X_PAGE_BASE(0) + 20)
56#define PCM186X_GPIO_PULL_CTRL (PCM186X_PAGE_BASE(0) + 21)
57#define PCM186X_DPGA_VAL_CH1_R (PCM186X_PAGE_BASE(0) + 22)
58#define PCM186X_DPGA_VAL_CH2_L (PCM186X_PAGE_BASE(0) + 23)
59#define PCM186X_DPGA_VAL_CH2_R (PCM186X_PAGE_BASE(0) + 24)
60#define PCM186X_DPGA_GAIN_CTRL (PCM186X_PAGE_BASE(0) + 25)
61#define PCM186X_DPGA_MIC_CTRL (PCM186X_PAGE_BASE(0) + 26)
62#define PCM186X_DIN_RESAMP_CTRL (PCM186X_PAGE_BASE(0) + 27)
63#define PCM186X_CLK_CTRL (PCM186X_PAGE_BASE(0) + 32)
64#define PCM186X_DSP1_CLK_DIV (PCM186X_PAGE_BASE(0) + 33)
65#define PCM186X_DSP2_CLK_DIV (PCM186X_PAGE_BASE(0) + 34)
66#define PCM186X_ADC_CLK_DIV (PCM186X_PAGE_BASE(0) + 35)
67#define PCM186X_PLL_SCK_DIV (PCM186X_PAGE_BASE(0) + 37)
68#define PCM186X_BCK_DIV (PCM186X_PAGE_BASE(0) + 38)
69#define PCM186X_LRK_DIV (PCM186X_PAGE_BASE(0) + 39)
70#define PCM186X_PLL_CTRL (PCM186X_PAGE_BASE(0) + 40)
71#define PCM186X_PLL_P_DIV (PCM186X_PAGE_BASE(0) + 41)
72#define PCM186X_PLL_R_DIV (PCM186X_PAGE_BASE(0) + 42)
73#define PCM186X_PLL_J_DIV (PCM186X_PAGE_BASE(0) + 43)
74#define PCM186X_PLL_D_DIV_LSB (PCM186X_PAGE_BASE(0) + 44)
75#define PCM186X_PLL_D_DIV_MSB (PCM186X_PAGE_BASE(0) + 45)
76#define PCM186X_SIGDET_MODE (PCM186X_PAGE_BASE(0) + 48)
77#define PCM186X_SIGDET_MASK (PCM186X_PAGE_BASE(0) + 49)
78#define PCM186X_SIGDET_STAT (PCM186X_PAGE_BASE(0) + 50)
79#define PCM186X_SIGDET_LOSS_TIME (PCM186X_PAGE_BASE(0) + 52)
80#define PCM186X_SIGDET_SCAN_TIME (PCM186X_PAGE_BASE(0) + 53)
81#define PCM186X_SIGDET_INT_INTVL (PCM186X_PAGE_BASE(0) + 54)
82#define PCM186X_SIGDET_DC_REF_CH1_L (PCM186X_PAGE_BASE(0) + 64)
83#define PCM186X_SIGDET_DC_DIFF_CH1_L (PCM186X_PAGE_BASE(0) + 65)
84#define PCM186X_SIGDET_DC_LEV_CH1_L (PCM186X_PAGE_BASE(0) + 66)
85#define PCM186X_SIGDET_DC_REF_CH1_R (PCM186X_PAGE_BASE(0) + 67)
86#define PCM186X_SIGDET_DC_DIFF_CH1_R (PCM186X_PAGE_BASE(0) + 68)
87#define PCM186X_SIGDET_DC_LEV_CH1_R (PCM186X_PAGE_BASE(0) + 69)
88#define PCM186X_SIGDET_DC_REF_CH2_L (PCM186X_PAGE_BASE(0) + 70)
89#define PCM186X_SIGDET_DC_DIFF_CH2_L (PCM186X_PAGE_BASE(0) + 71)
90#define PCM186X_SIGDET_DC_LEV_CH2_L (PCM186X_PAGE_BASE(0) + 72)
91#define PCM186X_SIGDET_DC_REF_CH2_R (PCM186X_PAGE_BASE(0) + 73)
92#define PCM186X_SIGDET_DC_DIFF_CH2_R (PCM186X_PAGE_BASE(0) + 74)
93#define PCM186X_SIGDET_DC_LEV_CH2_R (PCM186X_PAGE_BASE(0) + 75)
94#define PCM186X_SIGDET_DC_REF_CH3_L (PCM186X_PAGE_BASE(0) + 76)
95#define PCM186X_SIGDET_DC_DIFF_CH3_L (PCM186X_PAGE_BASE(0) + 77)
96#define PCM186X_SIGDET_DC_LEV_CH3_L (PCM186X_PAGE_BASE(0) + 78)
97#define PCM186X_SIGDET_DC_REF_CH3_R (PCM186X_PAGE_BASE(0) + 79)
98#define PCM186X_SIGDET_DC_DIFF_CH3_R (PCM186X_PAGE_BASE(0) + 80)
99#define PCM186X_SIGDET_DC_LEV_CH3_R (PCM186X_PAGE_BASE(0) + 81)
100#define PCM186X_SIGDET_DC_REF_CH4_L (PCM186X_PAGE_BASE(0) + 82)
101#define PCM186X_SIGDET_DC_DIFF_CH4_L (PCM186X_PAGE_BASE(0) + 83)
102#define PCM186X_SIGDET_DC_LEV_CH4_L (PCM186X_PAGE_BASE(0) + 84)
103#define PCM186X_SIGDET_DC_REF_CH4_R (PCM186X_PAGE_BASE(0) + 85)
104#define PCM186X_SIGDET_DC_DIFF_CH4_R (PCM186X_PAGE_BASE(0) + 86)
105#define PCM186X_SIGDET_DC_LEV_CH4_R (PCM186X_PAGE_BASE(0) + 87)
106#define PCM186X_AUXADC_DATA_CTRL (PCM186X_PAGE_BASE(0) + 88)
107#define PCM186X_AUXADC_DATA_LSB (PCM186X_PAGE_BASE(0) + 89)
108#define PCM186X_AUXADC_DATA_MSB (PCM186X_PAGE_BASE(0) + 90)
109#define PCM186X_INT_ENABLE (PCM186X_PAGE_BASE(0) + 96)
110#define PCM186X_INT_FLAG (PCM186X_PAGE_BASE(0) + 97)
111#define PCM186X_INT_POL_WIDTH (PCM186X_PAGE_BASE(0) + 98)
112#define PCM186X_POWER_CTRL (PCM186X_PAGE_BASE(0) + 112)
113#define PCM186X_FILTER_MUTE_CTRL (PCM186X_PAGE_BASE(0) + 113)
114#define PCM186X_DEVICE_STATUS (PCM186X_PAGE_BASE(0) + 114)
115#define PCM186X_FSAMPLE_STATUS (PCM186X_PAGE_BASE(0) + 115)
116#define PCM186X_DIV_STATUS (PCM186X_PAGE_BASE(0) + 116)
117#define PCM186X_CLK_STATUS (PCM186X_PAGE_BASE(0) + 117)
118#define PCM186X_SUPPLY_STATUS (PCM186X_PAGE_BASE(0) + 120)
119
120/* Register Definitions - Page 1 */
121#define PCM186X_MMAP_STAT_CTRL (PCM186X_PAGE_BASE(1) + 1)
122#define PCM186X_MMAP_ADDRESS (PCM186X_PAGE_BASE(1) + 2)
123#define PCM186X_MEM_WDATA0 (PCM186X_PAGE_BASE(1) + 4)
124#define PCM186X_MEM_WDATA1 (PCM186X_PAGE_BASE(1) + 5)
125#define PCM186X_MEM_WDATA2 (PCM186X_PAGE_BASE(1) + 6)
126#define PCM186X_MEM_WDATA3 (PCM186X_PAGE_BASE(1) + 7)
127#define PCM186X_MEM_RDATA0 (PCM186X_PAGE_BASE(1) + 8)
128#define PCM186X_MEM_RDATA1 (PCM186X_PAGE_BASE(1) + 9)
129#define PCM186X_MEM_RDATA2 (PCM186X_PAGE_BASE(1) + 10)
130#define PCM186X_MEM_RDATA3 (PCM186X_PAGE_BASE(1) + 11)
131
132/* Register Definitions - Page 3 */
133#define PCM186X_OSC_PWR_DOWN_CTRL (PCM186X_PAGE_BASE(3) + 18)
134#define PCM186X_MIC_BIAS_CTRL (PCM186X_PAGE_BASE(3) + 21)
135
136/* Register Definitions - Page 253 */
137#define PCM186X_CURR_TRIM_CTRL (PCM186X_PAGE_BASE(253) + 20)
138
139#define PCM186X_MAX_REGISTER PCM186X_CURR_TRIM_CTRL
140
141/* PCM186X_PAGE */
142#define PCM186X_RESET 0xff
143
144/* PCM186X_ADCX_INPUT_SEL_X */
145#define PCM186X_ADC_INPUT_SEL_POL BIT(7)
146#define PCM186X_ADC_INPUT_SEL_MASK GENMASK(5, 0)
147
148/* PCM186X_PCM_CFG */
149#define PCM186X_PCM_CFG_RX_WLEN_MASK GENMASK(7, 6)
150#define PCM186X_PCM_CFG_RX_WLEN_SHIFT 6
151#define PCM186X_PCM_CFG_RX_WLEN_32 0x00
152#define PCM186X_PCM_CFG_RX_WLEN_24 0x01
153#define PCM186X_PCM_CFG_RX_WLEN_20 0x02
154#define PCM186X_PCM_CFG_RX_WLEN_16 0x03
155#define PCM186X_PCM_CFG_TDM_LRCK_MODE BIT(4)
156#define PCM186X_PCM_CFG_TX_WLEN_MASK GENMASK(3, 2)
157#define PCM186X_PCM_CFG_TX_WLEN_SHIFT 2
158#define PCM186X_PCM_CFG_TX_WLEN_32 0x00
159#define PCM186X_PCM_CFG_TX_WLEN_24 0x01
160#define PCM186X_PCM_CFG_TX_WLEN_20 0x02
161#define PCM186X_PCM_CFG_TX_WLEN_16 0x03
162#define PCM186X_PCM_CFG_FMT_MASK GENMASK(1, 0)
163#define PCM186X_PCM_CFG_FMT_SHIFT 0
164#define PCM186X_PCM_CFG_FMT_I2S 0x00
165#define PCM186X_PCM_CFG_FMT_LEFTJ 0x01
166#define PCM186X_PCM_CFG_FMT_RIGHTJ 0x02
167#define PCM186X_PCM_CFG_FMT_TDM 0x03
168
169/* PCM186X_TDM_TX_SEL */
170#define PCM186X_TDM_TX_SEL_2CH 0x00
171#define PCM186X_TDM_TX_SEL_4CH 0x01
172#define PCM186X_TDM_TX_SEL_6CH 0x02
173#define PCM186X_TDM_TX_SEL_MASK 0x03
174
175/* PCM186X_CLK_CTRL */
176#define PCM186X_CLK_CTRL_SCK_XI_SEL1 BIT(7)
177#define PCM186X_CLK_CTRL_SCK_XI_SEL0 BIT(6)
178#define PCM186X_CLK_CTRL_SCK_SRC_PLL BIT(5)
179#define PCM186X_CLK_CTRL_MST_MODE BIT(4)
180#define PCM186X_CLK_CTRL_ADC_SRC_PLL BIT(3)
181#define PCM186X_CLK_CTRL_DSP2_SRC_PLL BIT(2)
182#define PCM186X_CLK_CTRL_DSP1_SRC_PLL BIT(1)
183#define PCM186X_CLK_CTRL_CLKDET_EN BIT(0)
184
185/* PCM186X_PLL_CTRL */
186#define PCM186X_PLL_CTRL_LOCK BIT(4)
187#define PCM186X_PLL_CTRL_REF_SEL BIT(1)
188#define PCM186X_PLL_CTRL_EN BIT(0)
189
190/* PCM186X_POWER_CTRL */
191#define PCM186X_PWR_CTRL_PWRDN BIT(2)
192#define PCM186X_PWR_CTRL_SLEEP BIT(1)
193#define PCM186X_PWR_CTRL_STBY BIT(0)
194
195/* PCM186X_CLK_STATUS */
196#define PCM186X_CLK_STATUS_LRCKHLT BIT(6)
197#define PCM186X_CLK_STATUS_BCKHLT BIT(5)
198#define PCM186X_CLK_STATUS_SCKHLT BIT(4)
199#define PCM186X_CLK_STATUS_LRCKERR BIT(2)
200#define PCM186X_CLK_STATUS_BCKERR BIT(1)
201#define PCM186X_CLK_STATUS_SCKERR BIT(0)
202
203/* PCM186X_SUPPLY_STATUS */
204#define PCM186X_SUPPLY_STATUS_DVDD BIT(2)
205#define PCM186X_SUPPLY_STATUS_AVDD BIT(1)
206#define PCM186X_SUPPLY_STATUS_LDO BIT(0)
207
208/* PCM186X_MMAP_STAT_CTRL */
209#define PCM186X_MMAP_STAT_DONE BIT(4)
210#define PCM186X_MMAP_STAT_BUSY BIT(2)
211#define PCM186X_MMAP_STAT_R_REQ BIT(1)
212#define PCM186X_MMAP_STAT_W_REQ BIT(0)
213
214extern const struct regmap_config pcm186x_regmap;
215
216int pcm186x_probe(struct device *dev, enum pcm186x_type type, int irq,
217 struct regmap *regmap);
218int pcm186x_remove(struct device *dev);
219
220#endif /* _PCM186X_H_ */