diff options
author | Mark Brown <broonie@linaro.org> | 2014-03-12 19:04:08 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-03-12 19:04:08 -0400 |
commit | 52db65f0a8da885d591d75186f68bc15de0323c7 (patch) | |
tree | 8155fe9d473da90d135acf4f54a0e1d156fed173 | |
parent | 3b93f0598c30a4d14b72223023fa56315eab15a4 (diff) | |
parent | e97db9abf99280e6ff7d9b339dd2ca4846ce2eea (diff) |
Merge remote-tracking branch 'asoc/topic/pcm512x' into asoc-next
-rw-r--r-- | Documentation/devicetree/bindings/sound/pcm512x.txt | 30 | ||||
-rw-r--r-- | sound/soc/codecs/Kconfig | 17 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 6 | ||||
-rw-r--r-- | sound/soc/codecs/pcm512x-i2c.c | 71 | ||||
-rw-r--r-- | sound/soc/codecs/pcm512x-spi.c | 69 | ||||
-rw-r--r-- | sound/soc/codecs/pcm512x.c | 589 | ||||
-rw-r--r-- | sound/soc/codecs/pcm512x.h | 171 |
7 files changed, 953 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt new file mode 100644 index 000000000000..faff75e64573 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/pcm512x.txt | |||
@@ -0,0 +1,30 @@ | |||
1 | PCM512x audio CODECs | ||
2 | |||
3 | These devices support both I2C and SPI (configured with pin strapping | ||
4 | on the board). | ||
5 | |||
6 | Required properties: | ||
7 | |||
8 | - compatible : One of "ti,pcm5121" or "ti,pcm5122" | ||
9 | |||
10 | - reg : the I2C address of the device for I2C, the chip select | ||
11 | number for SPI. | ||
12 | |||
13 | - AVDD-supply, DVDD-supply, and CPVDD-supply : power supplies for the | ||
14 | device, as covered in bindings/regulator/regulator.txt | ||
15 | |||
16 | Optional properties: | ||
17 | |||
18 | - clocks : A clock specifier for the clock connected as SCLK. If this | ||
19 | is absent the device will be configured to clock from BCLK. | ||
20 | |||
21 | Example: | ||
22 | |||
23 | pcm5122: pcm5122@4c { | ||
24 | compatible = "ti,pcm5122"; | ||
25 | reg = <0x4c>; | ||
26 | |||
27 | AVDD-supply = <®_3v3_analog>; | ||
28 | DVDD-supply = <®_1v8>; | ||
29 | CPVDD-supply = <®_3v3>; | ||
30 | }; | ||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 983d087aa92a..cebe3ceef4bd 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -59,6 +59,8 @@ config SND_SOC_ALL_CODECS | |||
59 | select SND_SOC_PCM1681 if I2C | 59 | select SND_SOC_PCM1681 if I2C |
60 | select SND_SOC_PCM1792A if SPI_MASTER | 60 | select SND_SOC_PCM1792A if SPI_MASTER |
61 | select SND_SOC_PCM3008 | 61 | select SND_SOC_PCM3008 |
62 | select SND_SOC_PCM512x_I2C if I2C | ||
63 | select SND_SOC_PCM512x_SPI if SPI_MASTER | ||
62 | select SND_SOC_RT5631 if I2C | 64 | select SND_SOC_RT5631 if I2C |
63 | select SND_SOC_RT5640 if I2C | 65 | select SND_SOC_RT5640 if I2C |
64 | select SND_SOC_SGTL5000 if I2C | 66 | select SND_SOC_SGTL5000 if I2C |
@@ -313,6 +315,21 @@ config SND_SOC_PCM1792A | |||
313 | config SND_SOC_PCM3008 | 315 | config SND_SOC_PCM3008 |
314 | tristate | 316 | tristate |
315 | 317 | ||
318 | config SND_SOC_PCM512x | ||
319 | tristate | ||
320 | |||
321 | config SND_SOC_PCM512x_I2C | ||
322 | tristate "Texas Instruments PCM512x CODECs - I2C" | ||
323 | depends on I2C | ||
324 | select SND_SOC_PCM512x | ||
325 | select REGMAP_I2C | ||
326 | |||
327 | config SND_SOC_PCM512x_SPI | ||
328 | tristate "Texas Instruments PCM512x CODECs - SPI" | ||
329 | depends on SPI_MASTER | ||
330 | select SND_SOC_PCM512x | ||
331 | select REGMAP_SPI | ||
332 | |||
316 | config SND_SOC_RT5631 | 333 | config SND_SOC_RT5631 |
317 | tristate | 334 | tristate |
318 | 335 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index bc126764a44d..c1191c05c88e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -46,6 +46,9 @@ snd-soc-hdmi-codec-objs := hdmi.o | |||
46 | snd-soc-pcm1681-objs := pcm1681.o | 46 | snd-soc-pcm1681-objs := pcm1681.o |
47 | snd-soc-pcm1792a-codec-objs := pcm1792a.o | 47 | snd-soc-pcm1792a-codec-objs := pcm1792a.o |
48 | snd-soc-pcm3008-objs := pcm3008.o | 48 | snd-soc-pcm3008-objs := pcm3008.o |
49 | snd-soc-pcm512x-objs := pcm512x.o | ||
50 | snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o | ||
51 | snd-soc-pcm512x-spi-objs := pcm512x-spi.o | ||
49 | snd-soc-rt5631-objs := rt5631.o | 52 | snd-soc-rt5631-objs := rt5631.o |
50 | snd-soc-rt5640-objs := rt5640.o | 53 | snd-soc-rt5640-objs := rt5640.o |
51 | snd-soc-sgtl5000-objs := sgtl5000.o | 54 | snd-soc-sgtl5000-objs := sgtl5000.o |
@@ -179,6 +182,9 @@ obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o | |||
179 | obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o | 182 | obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o |
180 | obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o | 183 | obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o |
181 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o | 184 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o |
185 | obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o | ||
186 | obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o | ||
187 | obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o | ||
182 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o | 188 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o |
183 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o | 189 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o |
184 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o | 190 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o |
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c new file mode 100644 index 000000000000..4d62230bd378 --- /dev/null +++ b/sound/soc/codecs/pcm512x-i2c.c | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * Driver for the PCM512x CODECs | ||
3 | * | ||
4 | * Author: Mark Brown <broonie@linaro.org> | ||
5 | * Copyright 2014 Linaro Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/i2c.h> | ||
20 | |||
21 | #include "pcm512x.h" | ||
22 | |||
23 | static int pcm512x_i2c_probe(struct i2c_client *i2c, | ||
24 | const struct i2c_device_id *id) | ||
25 | { | ||
26 | struct regmap *regmap; | ||
27 | |||
28 | regmap = devm_regmap_init_i2c(i2c, &pcm512x_regmap); | ||
29 | if (IS_ERR(regmap)) | ||
30 | return PTR_ERR(regmap); | ||
31 | |||
32 | return pcm512x_probe(&i2c->dev, regmap); | ||
33 | } | ||
34 | |||
35 | static int pcm512x_i2c_remove(struct i2c_client *i2c) | ||
36 | { | ||
37 | pcm512x_remove(&i2c->dev); | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static const struct i2c_device_id pcm512x_i2c_id[] = { | ||
42 | { "pcm5121", }, | ||
43 | { "pcm5122", }, | ||
44 | { } | ||
45 | }; | ||
46 | MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); | ||
47 | |||
48 | static const struct of_device_id pcm512x_of_match[] = { | ||
49 | { .compatible = "ti,pcm5121", }, | ||
50 | { .compatible = "ti,pcm5122", }, | ||
51 | { } | ||
52 | }; | ||
53 | MODULE_DEVICE_TABLE(of, pcm512x_of_match); | ||
54 | |||
55 | static struct i2c_driver pcm512x_i2c_driver = { | ||
56 | .probe = pcm512x_i2c_probe, | ||
57 | .remove = pcm512x_i2c_remove, | ||
58 | .id_table = pcm512x_i2c_id, | ||
59 | .driver = { | ||
60 | .name = "pcm512x", | ||
61 | .owner = THIS_MODULE, | ||
62 | .of_match_table = pcm512x_of_match, | ||
63 | .pm = &pcm512x_pm_ops, | ||
64 | }, | ||
65 | }; | ||
66 | |||
67 | module_i2c_driver(pcm512x_i2c_driver); | ||
68 | |||
69 | MODULE_DESCRIPTION("ASoC PCM512x codec driver - I2C"); | ||
70 | MODULE_AUTHOR("Mark Brown <broonie@linaro.org>"); | ||
71 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c new file mode 100644 index 000000000000..f297058c0038 --- /dev/null +++ b/sound/soc/codecs/pcm512x-spi.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Driver for the PCM512x CODECs | ||
3 | * | ||
4 | * Author: Mark Brown <broonie@linaro.org> | ||
5 | * Copyright 2014 Linaro Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/spi/spi.h> | ||
20 | |||
21 | #include "pcm512x.h" | ||
22 | |||
23 | static int pcm512x_spi_probe(struct spi_device *spi) | ||
24 | { | ||
25 | struct regmap *regmap; | ||
26 | int ret; | ||
27 | |||
28 | regmap = devm_regmap_init_spi(spi, &pcm512x_regmap); | ||
29 | if (IS_ERR(regmap)) { | ||
30 | ret = PTR_ERR(regmap); | ||
31 | return ret; | ||
32 | } | ||
33 | |||
34 | return pcm512x_probe(&spi->dev, regmap); | ||
35 | } | ||
36 | |||
37 | static int pcm512x_spi_remove(struct spi_device *spi) | ||
38 | { | ||
39 | pcm512x_remove(&spi->dev); | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static const struct spi_device_id pcm512x_spi_id[] = { | ||
44 | { "pcm5121", }, | ||
45 | { "pcm5122", }, | ||
46 | { }, | ||
47 | }; | ||
48 | MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); | ||
49 | |||
50 | static const struct of_device_id pcm512x_of_match[] = { | ||
51 | { .compatible = "ti,pcm5121", }, | ||
52 | { .compatible = "ti,pcm5122", }, | ||
53 | { } | ||
54 | }; | ||
55 | MODULE_DEVICE_TABLE(of, pcm512x_of_match); | ||
56 | |||
57 | static struct spi_driver pcm512x_spi_driver = { | ||
58 | .probe = pcm512x_spi_probe, | ||
59 | .remove = pcm512x_spi_remove, | ||
60 | .id_table = pcm512x_spi_id, | ||
61 | .driver = { | ||
62 | .name = "pcm512x", | ||
63 | .owner = THIS_MODULE, | ||
64 | .of_match_table = pcm512x_of_match, | ||
65 | .pm = &pcm512x_pm_ops, | ||
66 | }, | ||
67 | }; | ||
68 | |||
69 | module_spi_driver(pcm512x_spi_driver); | ||
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c new file mode 100644 index 000000000000..4b4c0c7bb918 --- /dev/null +++ b/sound/soc/codecs/pcm512x.c | |||
@@ -0,0 +1,589 @@ | |||
1 | /* | ||
2 | * Driver for the PCM512x CODECs | ||
3 | * | ||
4 | * Author: Mark Brown <broonie@linaro.org> | ||
5 | * Copyright 2014 Linaro Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | |||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/pm_runtime.h> | ||
22 | #include <linux/regmap.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/soc-dapm.h> | ||
26 | #include <sound/tlv.h> | ||
27 | |||
28 | #include "pcm512x.h" | ||
29 | |||
30 | #define PCM512x_NUM_SUPPLIES 3 | ||
31 | static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { | ||
32 | "AVDD", | ||
33 | "DVDD", | ||
34 | "CPVDD", | ||
35 | }; | ||
36 | |||
37 | struct pcm512x_priv { | ||
38 | struct regmap *regmap; | ||
39 | struct clk *sclk; | ||
40 | struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; | ||
41 | struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * We can't use the same notifier block for more than one supply and | ||
46 | * there's no way I can see to get from a callback to the caller | ||
47 | * except container_of(). | ||
48 | */ | ||
49 | #define PCM512x_REGULATOR_EVENT(n) \ | ||
50 | static int pcm512x_regulator_event_##n(struct notifier_block *nb, \ | ||
51 | unsigned long event, void *data) \ | ||
52 | { \ | ||
53 | struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \ | ||
54 | supply_nb[n]); \ | ||
55 | if (event & REGULATOR_EVENT_DISABLE) { \ | ||
56 | regcache_mark_dirty(pcm512x->regmap); \ | ||
57 | regcache_cache_only(pcm512x->regmap, true); \ | ||
58 | } \ | ||
59 | return 0; \ | ||
60 | } | ||
61 | |||
62 | PCM512x_REGULATOR_EVENT(0) | ||
63 | PCM512x_REGULATOR_EVENT(1) | ||
64 | PCM512x_REGULATOR_EVENT(2) | ||
65 | |||
66 | static const struct reg_default pcm512x_reg_defaults[] = { | ||
67 | { PCM512x_RESET, 0x00 }, | ||
68 | { PCM512x_POWER, 0x00 }, | ||
69 | { PCM512x_MUTE, 0x00 }, | ||
70 | { PCM512x_DSP, 0x00 }, | ||
71 | { PCM512x_PLL_REF, 0x00 }, | ||
72 | { PCM512x_DAC_ROUTING, 0x11 }, | ||
73 | { PCM512x_DSP_PROGRAM, 0x01 }, | ||
74 | { PCM512x_CLKDET, 0x00 }, | ||
75 | { PCM512x_AUTO_MUTE, 0x00 }, | ||
76 | { PCM512x_ERROR_DETECT, 0x00 }, | ||
77 | { PCM512x_DIGITAL_VOLUME_1, 0x00 }, | ||
78 | { PCM512x_DIGITAL_VOLUME_2, 0x30 }, | ||
79 | { PCM512x_DIGITAL_VOLUME_3, 0x30 }, | ||
80 | { PCM512x_DIGITAL_MUTE_1, 0x22 }, | ||
81 | { PCM512x_DIGITAL_MUTE_2, 0x00 }, | ||
82 | { PCM512x_DIGITAL_MUTE_3, 0x07 }, | ||
83 | { PCM512x_OUTPUT_AMPLITUDE, 0x00 }, | ||
84 | { PCM512x_ANALOG_GAIN_CTRL, 0x00 }, | ||
85 | { PCM512x_UNDERVOLTAGE_PROT, 0x00 }, | ||
86 | { PCM512x_ANALOG_MUTE_CTRL, 0x00 }, | ||
87 | { PCM512x_ANALOG_GAIN_BOOST, 0x00 }, | ||
88 | { PCM512x_VCOM_CTRL_1, 0x00 }, | ||
89 | { PCM512x_VCOM_CTRL_2, 0x01 }, | ||
90 | }; | ||
91 | |||
92 | static bool pcm512x_readable(struct device *dev, unsigned int reg) | ||
93 | { | ||
94 | switch (reg) { | ||
95 | case PCM512x_RESET: | ||
96 | case PCM512x_POWER: | ||
97 | case PCM512x_MUTE: | ||
98 | case PCM512x_PLL_EN: | ||
99 | case PCM512x_SPI_MISO_FUNCTION: | ||
100 | case PCM512x_DSP: | ||
101 | case PCM512x_GPIO_EN: | ||
102 | case PCM512x_BCLK_LRCLK_CFG: | ||
103 | case PCM512x_DSP_GPIO_INPUT: | ||
104 | case PCM512x_MASTER_MODE: | ||
105 | case PCM512x_PLL_REF: | ||
106 | case PCM512x_PLL_COEFF_0: | ||
107 | case PCM512x_PLL_COEFF_1: | ||
108 | case PCM512x_PLL_COEFF_2: | ||
109 | case PCM512x_PLL_COEFF_3: | ||
110 | case PCM512x_PLL_COEFF_4: | ||
111 | case PCM512x_DSP_CLKDIV: | ||
112 | case PCM512x_DAC_CLKDIV: | ||
113 | case PCM512x_NCP_CLKDIV: | ||
114 | case PCM512x_OSR_CLKDIV: | ||
115 | case PCM512x_MASTER_CLKDIV_1: | ||
116 | case PCM512x_MASTER_CLKDIV_2: | ||
117 | case PCM512x_FS_SPEED_MODE: | ||
118 | case PCM512x_IDAC_1: | ||
119 | case PCM512x_IDAC_2: | ||
120 | case PCM512x_ERROR_DETECT: | ||
121 | case PCM512x_I2S_1: | ||
122 | case PCM512x_I2S_2: | ||
123 | case PCM512x_DAC_ROUTING: | ||
124 | case PCM512x_DSP_PROGRAM: | ||
125 | case PCM512x_CLKDET: | ||
126 | case PCM512x_AUTO_MUTE: | ||
127 | case PCM512x_DIGITAL_VOLUME_1: | ||
128 | case PCM512x_DIGITAL_VOLUME_2: | ||
129 | case PCM512x_DIGITAL_VOLUME_3: | ||
130 | case PCM512x_DIGITAL_MUTE_1: | ||
131 | case PCM512x_DIGITAL_MUTE_2: | ||
132 | case PCM512x_DIGITAL_MUTE_3: | ||
133 | case PCM512x_GPIO_OUTPUT_1: | ||
134 | case PCM512x_GPIO_OUTPUT_2: | ||
135 | case PCM512x_GPIO_OUTPUT_3: | ||
136 | case PCM512x_GPIO_OUTPUT_4: | ||
137 | case PCM512x_GPIO_OUTPUT_5: | ||
138 | case PCM512x_GPIO_OUTPUT_6: | ||
139 | case PCM512x_GPIO_CONTROL_1: | ||
140 | case PCM512x_GPIO_CONTROL_2: | ||
141 | case PCM512x_OVERFLOW: | ||
142 | case PCM512x_RATE_DET_1: | ||
143 | case PCM512x_RATE_DET_2: | ||
144 | case PCM512x_RATE_DET_3: | ||
145 | case PCM512x_RATE_DET_4: | ||
146 | case PCM512x_ANALOG_MUTE_DET: | ||
147 | case PCM512x_GPIN: | ||
148 | case PCM512x_DIGITAL_MUTE_DET: | ||
149 | case PCM512x_OUTPUT_AMPLITUDE: | ||
150 | case PCM512x_ANALOG_GAIN_CTRL: | ||
151 | case PCM512x_UNDERVOLTAGE_PROT: | ||
152 | case PCM512x_ANALOG_MUTE_CTRL: | ||
153 | case PCM512x_ANALOG_GAIN_BOOST: | ||
154 | case PCM512x_VCOM_CTRL_1: | ||
155 | case PCM512x_VCOM_CTRL_2: | ||
156 | case PCM512x_CRAM_CTRL: | ||
157 | return true; | ||
158 | default: | ||
159 | /* There are 256 raw register addresses */ | ||
160 | return reg < 0xff; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static bool pcm512x_volatile(struct device *dev, unsigned int reg) | ||
165 | { | ||
166 | switch (reg) { | ||
167 | case PCM512x_PLL_EN: | ||
168 | case PCM512x_OVERFLOW: | ||
169 | case PCM512x_RATE_DET_1: | ||
170 | case PCM512x_RATE_DET_2: | ||
171 | case PCM512x_RATE_DET_3: | ||
172 | case PCM512x_RATE_DET_4: | ||
173 | case PCM512x_ANALOG_MUTE_DET: | ||
174 | case PCM512x_GPIN: | ||
175 | case PCM512x_DIGITAL_MUTE_DET: | ||
176 | case PCM512x_CRAM_CTRL: | ||
177 | return true; | ||
178 | default: | ||
179 | /* There are 256 raw register addresses */ | ||
180 | return reg < 0xff; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); | ||
185 | static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); | ||
186 | static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); | ||
187 | |||
188 | static const char * const pcm512x_dsp_program_texts[] = { | ||
189 | "FIR interpolation with de-emphasis", | ||
190 | "Low latency IIR with de-emphasis", | ||
191 | "Fixed process flow", | ||
192 | "High attenuation with de-emphasis", | ||
193 | "Ringing-less low latency FIR", | ||
194 | }; | ||
195 | |||
196 | static const unsigned int pcm512x_dsp_program_values[] = { | ||
197 | 1, | ||
198 | 2, | ||
199 | 3, | ||
200 | 5, | ||
201 | 7, | ||
202 | }; | ||
203 | |||
204 | static SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, | ||
205 | PCM512x_DSP_PROGRAM, 0, 0x1f, | ||
206 | pcm512x_dsp_program_texts, | ||
207 | pcm512x_dsp_program_values); | ||
208 | |||
209 | static const char * const pcm512x_clk_missing_text[] = { | ||
210 | "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s" | ||
211 | }; | ||
212 | |||
213 | static const struct soc_enum pcm512x_clk_missing = | ||
214 | SOC_ENUM_SINGLE(PCM512x_CLKDET, 0, 8, pcm512x_clk_missing_text); | ||
215 | |||
216 | static const char * const pcm512x_autom_text[] = { | ||
217 | "21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s" | ||
218 | }; | ||
219 | |||
220 | static const struct soc_enum pcm512x_autom_l = | ||
221 | SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 8, | ||
222 | pcm512x_autom_text); | ||
223 | |||
224 | static const struct soc_enum pcm512x_autom_r = | ||
225 | SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8, | ||
226 | pcm512x_autom_text); | ||
227 | |||
228 | static const char * const pcm512x_ramp_rate_text[] = { | ||
229 | "1 sample/update", "2 samples/update", "4 samples/update", | ||
230 | "Immediate" | ||
231 | }; | ||
232 | |||
233 | static const struct soc_enum pcm512x_vndf = | ||
234 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDF_SHIFT, 4, | ||
235 | pcm512x_ramp_rate_text); | ||
236 | |||
237 | static const struct soc_enum pcm512x_vnuf = | ||
238 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUF_SHIFT, 4, | ||
239 | pcm512x_ramp_rate_text); | ||
240 | |||
241 | static const struct soc_enum pcm512x_vedf = | ||
242 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4, | ||
243 | pcm512x_ramp_rate_text); | ||
244 | |||
245 | static const char * const pcm512x_ramp_step_text[] = { | ||
246 | "4dB/step", "2dB/step", "1dB/step", "0.5dB/step" | ||
247 | }; | ||
248 | |||
249 | static const struct soc_enum pcm512x_vnds = | ||
250 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDS_SHIFT, 4, | ||
251 | pcm512x_ramp_step_text); | ||
252 | |||
253 | static const struct soc_enum pcm512x_vnus = | ||
254 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUS_SHIFT, 4, | ||
255 | pcm512x_ramp_step_text); | ||
256 | |||
257 | static const struct soc_enum pcm512x_veds = | ||
258 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, | ||
259 | pcm512x_ramp_step_text); | ||
260 | |||
261 | static const struct snd_kcontrol_new pcm512x_controls[] = { | ||
262 | SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, | ||
263 | PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), | ||
264 | SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, | ||
265 | PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), | ||
266 | SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, | ||
267 | PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), | ||
268 | SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, | ||
269 | PCM512x_RQMR_SHIFT, 1, 1), | ||
270 | |||
271 | SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), | ||
272 | SOC_VALUE_ENUM("DSP Program", pcm512x_dsp_program), | ||
273 | |||
274 | SOC_ENUM("Clock Missing Period", pcm512x_clk_missing), | ||
275 | SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l), | ||
276 | SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r), | ||
277 | SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3, | ||
278 | PCM512x_ACTL_SHIFT, 1, 0), | ||
279 | SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT, | ||
280 | PCM512x_AMLR_SHIFT, 1, 0), | ||
281 | |||
282 | SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf), | ||
283 | SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds), | ||
284 | SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), | ||
285 | SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), | ||
286 | SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), | ||
287 | SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), | ||
288 | }; | ||
289 | |||
290 | static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { | ||
291 | SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), | ||
292 | SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), | ||
293 | |||
294 | SND_SOC_DAPM_OUTPUT("OUTL"), | ||
295 | SND_SOC_DAPM_OUTPUT("OUTR"), | ||
296 | }; | ||
297 | |||
298 | static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { | ||
299 | { "DACL", NULL, "Playback" }, | ||
300 | { "DACR", NULL, "Playback" }, | ||
301 | |||
302 | { "OUTL", NULL, "DACL" }, | ||
303 | { "OUTR", NULL, "DACR" }, | ||
304 | }; | ||
305 | |||
306 | static int pcm512x_set_bias_level(struct snd_soc_codec *codec, | ||
307 | enum snd_soc_bias_level level) | ||
308 | { | ||
309 | struct pcm512x_priv *pcm512x = dev_get_drvdata(codec->dev); | ||
310 | int ret; | ||
311 | |||
312 | switch (level) { | ||
313 | case SND_SOC_BIAS_ON: | ||
314 | case SND_SOC_BIAS_PREPARE: | ||
315 | break; | ||
316 | |||
317 | case SND_SOC_BIAS_STANDBY: | ||
318 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
319 | PCM512x_RQST, 0); | ||
320 | if (ret != 0) { | ||
321 | dev_err(codec->dev, "Failed to remove standby: %d\n", | ||
322 | ret); | ||
323 | return ret; | ||
324 | } | ||
325 | break; | ||
326 | |||
327 | case SND_SOC_BIAS_OFF: | ||
328 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
329 | PCM512x_RQST, PCM512x_RQST); | ||
330 | if (ret != 0) { | ||
331 | dev_err(codec->dev, "Failed to request standby: %d\n", | ||
332 | ret); | ||
333 | return ret; | ||
334 | } | ||
335 | break; | ||
336 | } | ||
337 | |||
338 | codec->dapm.bias_level = level; | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static struct snd_soc_dai_driver pcm512x_dai = { | ||
344 | .name = "pcm512x-hifi", | ||
345 | .playback = { | ||
346 | .stream_name = "Playback", | ||
347 | .channels_min = 2, | ||
348 | .channels_max = 2, | ||
349 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
350 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
351 | SNDRV_PCM_FMTBIT_S24_LE | | ||
352 | SNDRV_PCM_FMTBIT_S32_LE | ||
353 | }, | ||
354 | }; | ||
355 | |||
356 | static struct snd_soc_codec_driver pcm512x_codec_driver = { | ||
357 | .set_bias_level = pcm512x_set_bias_level, | ||
358 | .idle_bias_off = true, | ||
359 | |||
360 | .controls = pcm512x_controls, | ||
361 | .num_controls = ARRAY_SIZE(pcm512x_controls), | ||
362 | .dapm_widgets = pcm512x_dapm_widgets, | ||
363 | .num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets), | ||
364 | .dapm_routes = pcm512x_dapm_routes, | ||
365 | .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), | ||
366 | }; | ||
367 | |||
368 | static const struct regmap_range_cfg pcm512x_range = { | ||
369 | .name = "Pages", .range_min = PCM512x_VIRT_BASE, | ||
370 | .range_max = PCM512x_MAX_REGISTER, | ||
371 | .selector_reg = PCM512x_PAGE, | ||
372 | .selector_mask = 0xff, | ||
373 | .window_start = 0, .window_len = 0x100, | ||
374 | }; | ||
375 | |||
376 | const struct regmap_config pcm512x_regmap = { | ||
377 | .reg_bits = 8, | ||
378 | .val_bits = 8, | ||
379 | |||
380 | .readable_reg = pcm512x_readable, | ||
381 | .volatile_reg = pcm512x_volatile, | ||
382 | |||
383 | .ranges = &pcm512x_range, | ||
384 | .num_ranges = 1, | ||
385 | |||
386 | .max_register = PCM512x_MAX_REGISTER, | ||
387 | .reg_defaults = pcm512x_reg_defaults, | ||
388 | .num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults), | ||
389 | .cache_type = REGCACHE_RBTREE, | ||
390 | }; | ||
391 | EXPORT_SYMBOL_GPL(pcm512x_regmap); | ||
392 | |||
393 | int pcm512x_probe(struct device *dev, struct regmap *regmap) | ||
394 | { | ||
395 | struct pcm512x_priv *pcm512x; | ||
396 | int i, ret; | ||
397 | |||
398 | pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL); | ||
399 | if (!pcm512x) | ||
400 | return -ENOMEM; | ||
401 | |||
402 | dev_set_drvdata(dev, pcm512x); | ||
403 | pcm512x->regmap = regmap; | ||
404 | |||
405 | for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) | ||
406 | pcm512x->supplies[i].supply = pcm512x_supply_names[i]; | ||
407 | |||
408 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies), | ||
409 | pcm512x->supplies); | ||
410 | if (ret != 0) { | ||
411 | dev_err(dev, "Failed to get supplies: %d\n", ret); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | pcm512x->supply_nb[0].notifier_call = pcm512x_regulator_event_0; | ||
416 | pcm512x->supply_nb[1].notifier_call = pcm512x_regulator_event_1; | ||
417 | pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; | ||
418 | |||
419 | for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { | ||
420 | ret = regulator_register_notifier(pcm512x->supplies[i].consumer, | ||
421 | &pcm512x->supply_nb[i]); | ||
422 | if (ret != 0) { | ||
423 | dev_err(dev, | ||
424 | "Failed to register regulator notifier: %d\n", | ||
425 | ret); | ||
426 | } | ||
427 | } | ||
428 | |||
429 | ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), | ||
430 | pcm512x->supplies); | ||
431 | if (ret != 0) { | ||
432 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | ||
433 | return ret; | ||
434 | } | ||
435 | |||
436 | /* Reset the device, verifying I/O in the process for I2C */ | ||
437 | ret = regmap_write(regmap, PCM512x_RESET, | ||
438 | PCM512x_RSTM | PCM512x_RSTR); | ||
439 | if (ret != 0) { | ||
440 | dev_err(dev, "Failed to reset device: %d\n", ret); | ||
441 | goto err; | ||
442 | } | ||
443 | |||
444 | ret = regmap_write(regmap, PCM512x_RESET, 0); | ||
445 | if (ret != 0) { | ||
446 | dev_err(dev, "Failed to reset device: %d\n", ret); | ||
447 | goto err; | ||
448 | } | ||
449 | |||
450 | pcm512x->sclk = devm_clk_get(dev, NULL); | ||
451 | if (IS_ERR(pcm512x->sclk)) { | ||
452 | if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) | ||
453 | return -EPROBE_DEFER; | ||
454 | |||
455 | dev_info(dev, "No SCLK, using BCLK: %ld\n", | ||
456 | PTR_ERR(pcm512x->sclk)); | ||
457 | |||
458 | /* Disable reporting of missing SCLK as an error */ | ||
459 | regmap_update_bits(regmap, PCM512x_ERROR_DETECT, | ||
460 | PCM512x_IDCH, PCM512x_IDCH); | ||
461 | |||
462 | /* Switch PLL input to BCLK */ | ||
463 | regmap_update_bits(regmap, PCM512x_PLL_REF, | ||
464 | PCM512x_SREF, PCM512x_SREF); | ||
465 | } else { | ||
466 | ret = clk_prepare_enable(pcm512x->sclk); | ||
467 | if (ret != 0) { | ||
468 | dev_err(dev, "Failed to enable SCLK: %d\n", ret); | ||
469 | return ret; | ||
470 | } | ||
471 | } | ||
472 | |||
473 | /* Default to standby mode */ | ||
474 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
475 | PCM512x_RQST, PCM512x_RQST); | ||
476 | if (ret != 0) { | ||
477 | dev_err(dev, "Failed to request standby: %d\n", | ||
478 | ret); | ||
479 | goto err_clk; | ||
480 | } | ||
481 | |||
482 | pm_runtime_set_active(dev); | ||
483 | pm_runtime_enable(dev); | ||
484 | pm_runtime_idle(dev); | ||
485 | |||
486 | ret = snd_soc_register_codec(dev, &pcm512x_codec_driver, | ||
487 | &pcm512x_dai, 1); | ||
488 | if (ret != 0) { | ||
489 | dev_err(dev, "Failed to register CODEC: %d\n", ret); | ||
490 | goto err_pm; | ||
491 | } | ||
492 | |||
493 | return 0; | ||
494 | |||
495 | err_pm: | ||
496 | pm_runtime_disable(dev); | ||
497 | err_clk: | ||
498 | if (!IS_ERR(pcm512x->sclk)) | ||
499 | clk_disable_unprepare(pcm512x->sclk); | ||
500 | err: | ||
501 | regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), | ||
502 | pcm512x->supplies); | ||
503 | return ret; | ||
504 | } | ||
505 | EXPORT_SYMBOL_GPL(pcm512x_probe); | ||
506 | |||
507 | void pcm512x_remove(struct device *dev) | ||
508 | { | ||
509 | struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); | ||
510 | |||
511 | snd_soc_unregister_codec(dev); | ||
512 | pm_runtime_disable(dev); | ||
513 | if (!IS_ERR(pcm512x->sclk)) | ||
514 | clk_disable_unprepare(pcm512x->sclk); | ||
515 | regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), | ||
516 | pcm512x->supplies); | ||
517 | } | ||
518 | EXPORT_SYMBOL_GPL(pcm512x_remove); | ||
519 | |||
520 | static int pcm512x_suspend(struct device *dev) | ||
521 | { | ||
522 | struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); | ||
523 | int ret; | ||
524 | |||
525 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
526 | PCM512x_RQPD, PCM512x_RQPD); | ||
527 | if (ret != 0) { | ||
528 | dev_err(dev, "Failed to request power down: %d\n", ret); | ||
529 | return ret; | ||
530 | } | ||
531 | |||
532 | ret = regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), | ||
533 | pcm512x->supplies); | ||
534 | if (ret != 0) { | ||
535 | dev_err(dev, "Failed to disable supplies: %d\n", ret); | ||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | if (!IS_ERR(pcm512x->sclk)) | ||
540 | clk_disable_unprepare(pcm512x->sclk); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static int pcm512x_resume(struct device *dev) | ||
546 | { | ||
547 | struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); | ||
548 | int ret; | ||
549 | |||
550 | if (!IS_ERR(pcm512x->sclk)) { | ||
551 | ret = clk_prepare_enable(pcm512x->sclk); | ||
552 | if (ret != 0) { | ||
553 | dev_err(dev, "Failed to enable SCLK: %d\n", ret); | ||
554 | return ret; | ||
555 | } | ||
556 | } | ||
557 | |||
558 | ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), | ||
559 | pcm512x->supplies); | ||
560 | if (ret != 0) { | ||
561 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | ||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | regcache_cache_only(pcm512x->regmap, false); | ||
566 | ret = regcache_sync(pcm512x->regmap); | ||
567 | if (ret != 0) { | ||
568 | dev_err(dev, "Failed to sync cache: %d\n", ret); | ||
569 | return ret; | ||
570 | } | ||
571 | |||
572 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
573 | PCM512x_RQPD, 0); | ||
574 | if (ret != 0) { | ||
575 | dev_err(dev, "Failed to remove power down: %d\n", ret); | ||
576 | return ret; | ||
577 | } | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | const struct dev_pm_ops pcm512x_pm_ops = { | ||
583 | SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) | ||
584 | }; | ||
585 | EXPORT_SYMBOL_GPL(pcm512x_pm_ops); | ||
586 | |||
587 | MODULE_DESCRIPTION("ASoC PCM512x codec driver"); | ||
588 | MODULE_AUTHOR("Mark Brown <broonie@linaro.org>"); | ||
589 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h new file mode 100644 index 000000000000..6ee76aaca09a --- /dev/null +++ b/sound/soc/codecs/pcm512x.h | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * Driver for the PCM512x CODECs | ||
3 | * | ||
4 | * Author: Mark Brown <broonie@linaro.org> | ||
5 | * Copyright 2014 Linaro Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef _SND_SOC_PCM512X | ||
18 | #define _SND_SOC_PCM512X | ||
19 | |||
20 | #include <linux/pm.h> | ||
21 | #include <linux/regmap.h> | ||
22 | |||
23 | #define PCM512x_VIRT_BASE 0x100 | ||
24 | #define PCM512x_PAGE_LEN 0x100 | ||
25 | #define PCM512x_PAGE_BASE(n) (PCM512x_VIRT_BASE + (PCM512x_PAGE_LEN * n)) | ||
26 | |||
27 | #define PCM512x_PAGE 0 | ||
28 | |||
29 | #define PCM512x_RESET (PCM512x_PAGE_BASE(0) + 1) | ||
30 | #define PCM512x_POWER (PCM512x_PAGE_BASE(0) + 2) | ||
31 | #define PCM512x_MUTE (PCM512x_PAGE_BASE(0) + 3) | ||
32 | #define PCM512x_PLL_EN (PCM512x_PAGE_BASE(0) + 4) | ||
33 | #define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_BASE(0) + 6) | ||
34 | #define PCM512x_DSP (PCM512x_PAGE_BASE(0) + 7) | ||
35 | #define PCM512x_GPIO_EN (PCM512x_PAGE_BASE(0) + 8) | ||
36 | #define PCM512x_BCLK_LRCLK_CFG (PCM512x_PAGE_BASE(0) + 9) | ||
37 | #define PCM512x_DSP_GPIO_INPUT (PCM512x_PAGE_BASE(0) + 10) | ||
38 | #define PCM512x_MASTER_MODE (PCM512x_PAGE_BASE(0) + 12) | ||
39 | #define PCM512x_PLL_REF (PCM512x_PAGE_BASE(0) + 13) | ||
40 | #define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_BASE(0) + 20) | ||
41 | #define PCM512x_PLL_COEFF_1 (PCM512x_PAGE_BASE(0) + 21) | ||
42 | #define PCM512x_PLL_COEFF_2 (PCM512x_PAGE_BASE(0) + 22) | ||
43 | #define PCM512x_PLL_COEFF_3 (PCM512x_PAGE_BASE(0) + 23) | ||
44 | #define PCM512x_PLL_COEFF_4 (PCM512x_PAGE_BASE(0) + 24) | ||
45 | #define PCM512x_DSP_CLKDIV (PCM512x_PAGE_BASE(0) + 27) | ||
46 | #define PCM512x_DAC_CLKDIV (PCM512x_PAGE_BASE(0) + 28) | ||
47 | #define PCM512x_NCP_CLKDIV (PCM512x_PAGE_BASE(0) + 29) | ||
48 | #define PCM512x_OSR_CLKDIV (PCM512x_PAGE_BASE(0) + 30) | ||
49 | #define PCM512x_MASTER_CLKDIV_1 (PCM512x_PAGE_BASE(0) + 32) | ||
50 | #define PCM512x_MASTER_CLKDIV_2 (PCM512x_PAGE_BASE(0) + 33) | ||
51 | #define PCM512x_FS_SPEED_MODE (PCM512x_PAGE_BASE(0) + 34) | ||
52 | #define PCM512x_IDAC_1 (PCM512x_PAGE_BASE(0) + 35) | ||
53 | #define PCM512x_IDAC_2 (PCM512x_PAGE_BASE(0) + 36) | ||
54 | #define PCM512x_ERROR_DETECT (PCM512x_PAGE_BASE(0) + 37) | ||
55 | #define PCM512x_I2S_1 (PCM512x_PAGE_BASE(0) + 40) | ||
56 | #define PCM512x_I2S_2 (PCM512x_PAGE_BASE(0) + 41) | ||
57 | #define PCM512x_DAC_ROUTING (PCM512x_PAGE_BASE(0) + 42) | ||
58 | #define PCM512x_DSP_PROGRAM (PCM512x_PAGE_BASE(0) + 43) | ||
59 | #define PCM512x_CLKDET (PCM512x_PAGE_BASE(0) + 44) | ||
60 | #define PCM512x_AUTO_MUTE (PCM512x_PAGE_BASE(0) + 59) | ||
61 | #define PCM512x_DIGITAL_VOLUME_1 (PCM512x_PAGE_BASE(0) + 60) | ||
62 | #define PCM512x_DIGITAL_VOLUME_2 (PCM512x_PAGE_BASE(0) + 61) | ||
63 | #define PCM512x_DIGITAL_VOLUME_3 (PCM512x_PAGE_BASE(0) + 62) | ||
64 | #define PCM512x_DIGITAL_MUTE_1 (PCM512x_PAGE_BASE(0) + 63) | ||
65 | #define PCM512x_DIGITAL_MUTE_2 (PCM512x_PAGE_BASE(0) + 64) | ||
66 | #define PCM512x_DIGITAL_MUTE_3 (PCM512x_PAGE_BASE(0) + 65) | ||
67 | #define PCM512x_GPIO_OUTPUT_1 (PCM512x_PAGE_BASE(0) + 80) | ||
68 | #define PCM512x_GPIO_OUTPUT_2 (PCM512x_PAGE_BASE(0) + 81) | ||
69 | #define PCM512x_GPIO_OUTPUT_3 (PCM512x_PAGE_BASE(0) + 82) | ||
70 | #define PCM512x_GPIO_OUTPUT_4 (PCM512x_PAGE_BASE(0) + 83) | ||
71 | #define PCM512x_GPIO_OUTPUT_5 (PCM512x_PAGE_BASE(0) + 84) | ||
72 | #define PCM512x_GPIO_OUTPUT_6 (PCM512x_PAGE_BASE(0) + 85) | ||
73 | #define PCM512x_GPIO_CONTROL_1 (PCM512x_PAGE_BASE(0) + 86) | ||
74 | #define PCM512x_GPIO_CONTROL_2 (PCM512x_PAGE_BASE(0) + 87) | ||
75 | #define PCM512x_OVERFLOW (PCM512x_PAGE_BASE(0) + 90) | ||
76 | #define PCM512x_RATE_DET_1 (PCM512x_PAGE_BASE(0) + 91) | ||
77 | #define PCM512x_RATE_DET_2 (PCM512x_PAGE_BASE(0) + 92) | ||
78 | #define PCM512x_RATE_DET_3 (PCM512x_PAGE_BASE(0) + 93) | ||
79 | #define PCM512x_RATE_DET_4 (PCM512x_PAGE_BASE(0) + 94) | ||
80 | #define PCM512x_ANALOG_MUTE_DET (PCM512x_PAGE_BASE(0) + 108) | ||
81 | #define PCM512x_GPIN (PCM512x_PAGE_BASE(0) + 119) | ||
82 | #define PCM512x_DIGITAL_MUTE_DET (PCM512x_PAGE_BASE(0) + 120) | ||
83 | |||
84 | #define PCM512x_OUTPUT_AMPLITUDE (PCM512x_PAGE_BASE(1) + 1) | ||
85 | #define PCM512x_ANALOG_GAIN_CTRL (PCM512x_PAGE_BASE(1) + 2) | ||
86 | #define PCM512x_UNDERVOLTAGE_PROT (PCM512x_PAGE_BASE(1) + 5) | ||
87 | #define PCM512x_ANALOG_MUTE_CTRL (PCM512x_PAGE_BASE(1) + 6) | ||
88 | #define PCM512x_ANALOG_GAIN_BOOST (PCM512x_PAGE_BASE(1) + 7) | ||
89 | #define PCM512x_VCOM_CTRL_1 (PCM512x_PAGE_BASE(1) + 8) | ||
90 | #define PCM512x_VCOM_CTRL_2 (PCM512x_PAGE_BASE(1) + 9) | ||
91 | |||
92 | #define PCM512x_CRAM_CTRL (PCM512x_PAGE_BASE(44) + 1) | ||
93 | |||
94 | #define PCM512x_MAX_REGISTER (PCM512x_PAGE_BASE(44) + 1) | ||
95 | |||
96 | /* Page 0, Register 1 - reset */ | ||
97 | #define PCM512x_RSTR (1 << 0) | ||
98 | #define PCM512x_RSTM (1 << 4) | ||
99 | |||
100 | /* Page 0, Register 2 - power */ | ||
101 | #define PCM512x_RQPD (1 << 0) | ||
102 | #define PCM512x_RQPD_SHIFT 0 | ||
103 | #define PCM512x_RQST (1 << 4) | ||
104 | #define PCM512x_RQST_SHIFT 4 | ||
105 | |||
106 | /* Page 0, Register 3 - mute */ | ||
107 | #define PCM512x_RQMR_SHIFT 0 | ||
108 | #define PCM512x_RQML_SHIFT 4 | ||
109 | |||
110 | /* Page 0, Register 4 - PLL */ | ||
111 | #define PCM512x_PLCE (1 << 0) | ||
112 | #define PCM512x_RLCE_SHIFT 0 | ||
113 | #define PCM512x_PLCK (1 << 4) | ||
114 | #define PCM512x_PLCK_SHIFT 4 | ||
115 | |||
116 | /* Page 0, Register 7 - DSP */ | ||
117 | #define PCM512x_SDSL (1 << 0) | ||
118 | #define PCM512x_SDSL_SHIFT 0 | ||
119 | #define PCM512x_DEMP (1 << 4) | ||
120 | #define PCM512x_DEMP_SHIFT 4 | ||
121 | |||
122 | /* Page 0, Register 13 - PLL reference */ | ||
123 | #define PCM512x_SREF (1 << 4) | ||
124 | |||
125 | /* Page 0, Register 37 - Error detection */ | ||
126 | #define PCM512x_IPLK (1 << 0) | ||
127 | #define PCM512x_DCAS (1 << 1) | ||
128 | #define PCM512x_IDCM (1 << 2) | ||
129 | #define PCM512x_IDCH (1 << 3) | ||
130 | #define PCM512x_IDSK (1 << 4) | ||
131 | #define PCM512x_IDBK (1 << 5) | ||
132 | #define PCM512x_IDFS (1 << 6) | ||
133 | |||
134 | /* Page 0, Register 42 - DAC routing */ | ||
135 | #define PCM512x_AUPR_SHIFT 0 | ||
136 | #define PCM512x_AUPL_SHIFT 4 | ||
137 | |||
138 | /* Page 0, Register 59 - auto mute */ | ||
139 | #define PCM512x_ATMR_SHIFT 0 | ||
140 | #define PCM512x_ATML_SHIFT 4 | ||
141 | |||
142 | /* Page 0, Register 63 - ramp rates */ | ||
143 | #define PCM512x_VNDF_SHIFT 6 | ||
144 | #define PCM512x_VNDS_SHIFT 4 | ||
145 | #define PCM512x_VNUF_SHIFT 2 | ||
146 | #define PCM512x_VNUS_SHIFT 0 | ||
147 | |||
148 | /* Page 0, Register 64 - emergency ramp rates */ | ||
149 | #define PCM512x_VEDF_SHIFT 6 | ||
150 | #define PCM512x_VEDS_SHIFT 4 | ||
151 | |||
152 | /* Page 0, Register 65 - Digital mute enables */ | ||
153 | #define PCM512x_ACTL_SHIFT 2 | ||
154 | #define PCM512x_AMLE_SHIFT 1 | ||
155 | #define PCM512x_AMLR_SHIFT 0 | ||
156 | |||
157 | /* Page 1, Register 2 - analog volume control */ | ||
158 | #define PCM512x_RAGN_SHIFT 0 | ||
159 | #define PCM512x_LAGN_SHIFT 4 | ||
160 | |||
161 | /* Page 1, Register 7 - analog boost control */ | ||
162 | #define PCM512x_AGBR_SHIFT 0 | ||
163 | #define PCM512x_AGBL_SHIFT 4 | ||
164 | |||
165 | extern const struct dev_pm_ops pcm512x_pm_ops; | ||
166 | extern const struct regmap_config pcm512x_regmap; | ||
167 | |||
168 | int pcm512x_probe(struct device *dev, struct regmap *regmap); | ||
169 | void pcm512x_remove(struct device *dev); | ||
170 | |||
171 | #endif | ||