1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * AK4104 ALSA SoC (ASoC) driver |
4 | * |
5 | * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> |
6 | */ |
7 | |
8 | #include <linux/mod_devicetable.h> |
9 | #include <linux/module.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/spi/spi.h> |
12 | #include <linux/gpio/consumer.h> |
13 | #include <linux/regulator/consumer.h> |
14 | #include <sound/asoundef.h> |
15 | #include <sound/core.h> |
16 | #include <sound/soc.h> |
17 | #include <sound/initval.h> |
18 | |
19 | /* AK4104 registers addresses */ |
20 | #define AK4104_REG_CONTROL1 0x00 |
21 | #define AK4104_REG_RESERVED 0x01 |
22 | #define AK4104_REG_CONTROL2 0x02 |
23 | #define AK4104_REG_TX 0x03 |
24 | #define AK4104_REG_CHN_STATUS(x) ((x) + 0x04) |
25 | #define AK4104_NUM_REGS 10 |
26 | |
27 | #define AK4104_REG_MASK 0x1f |
28 | #define AK4104_READ 0xc0 |
29 | #define AK4104_WRITE 0xe0 |
30 | #define AK4104_RESERVED_VAL 0x5b |
31 | |
32 | /* Bit masks for AK4104 registers */ |
33 | #define AK4104_CONTROL1_RSTN (1 << 0) |
34 | #define AK4104_CONTROL1_PW (1 << 1) |
35 | #define AK4104_CONTROL1_DIF0 (1 << 2) |
36 | #define AK4104_CONTROL1_DIF1 (1 << 3) |
37 | |
38 | #define AK4104_CONTROL2_SEL0 (1 << 0) |
39 | #define AK4104_CONTROL2_SEL1 (1 << 1) |
40 | #define AK4104_CONTROL2_MODE (1 << 2) |
41 | |
42 | #define AK4104_TX_TXE (1 << 0) |
43 | #define AK4104_TX_V (1 << 1) |
44 | |
45 | struct ak4104_private { |
46 | struct regmap *regmap; |
47 | struct regulator *regulator; |
48 | }; |
49 | |
50 | static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = { |
51 | SND_SOC_DAPM_PGA("TXE" , AK4104_REG_TX, AK4104_TX_TXE, 0, NULL, 0), |
52 | |
53 | SND_SOC_DAPM_OUTPUT("TX" ), |
54 | }; |
55 | |
56 | static const struct snd_soc_dapm_route ak4104_dapm_routes[] = { |
57 | { "TXE" , NULL, "Playback" }, |
58 | { "TX" , NULL, "TXE" }, |
59 | }; |
60 | |
61 | static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai, |
62 | unsigned int format) |
63 | { |
64 | struct snd_soc_component *component = codec_dai->component; |
65 | struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(c: component); |
66 | int val = 0; |
67 | int ret; |
68 | |
69 | /* set DAI format */ |
70 | switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { |
71 | case SND_SOC_DAIFMT_RIGHT_J: |
72 | break; |
73 | case SND_SOC_DAIFMT_LEFT_J: |
74 | val |= AK4104_CONTROL1_DIF0; |
75 | break; |
76 | case SND_SOC_DAIFMT_I2S: |
77 | val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1; |
78 | break; |
79 | default: |
80 | dev_err(component->dev, "invalid dai format\n" ); |
81 | return -EINVAL; |
82 | } |
83 | |
84 | /* This device can only be consumer */ |
85 | if ((format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) |
86 | return -EINVAL; |
87 | |
88 | ret = regmap_update_bits(map: ak4104->regmap, AK4104_REG_CONTROL1, |
89 | AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1, |
90 | val); |
91 | if (ret < 0) |
92 | return ret; |
93 | |
94 | return 0; |
95 | } |
96 | |
97 | static int ak4104_hw_params(struct snd_pcm_substream *substream, |
98 | struct snd_pcm_hw_params *params, |
99 | struct snd_soc_dai *dai) |
100 | { |
101 | struct snd_soc_component *component = dai->component; |
102 | struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(c: component); |
103 | int ret, val = 0; |
104 | |
105 | /* set the IEC958 bits: consumer mode, no copyright bit */ |
106 | val |= IEC958_AES0_CON_NOT_COPYRIGHT; |
107 | regmap_write(map: ak4104->regmap, AK4104_REG_CHN_STATUS(0), val); |
108 | |
109 | val = 0; |
110 | |
111 | switch (params_rate(p: params)) { |
112 | case 22050: |
113 | val |= IEC958_AES3_CON_FS_22050; |
114 | break; |
115 | case 24000: |
116 | val |= IEC958_AES3_CON_FS_24000; |
117 | break; |
118 | case 32000: |
119 | val |= IEC958_AES3_CON_FS_32000; |
120 | break; |
121 | case 44100: |
122 | val |= IEC958_AES3_CON_FS_44100; |
123 | break; |
124 | case 48000: |
125 | val |= IEC958_AES3_CON_FS_48000; |
126 | break; |
127 | case 88200: |
128 | val |= IEC958_AES3_CON_FS_88200; |
129 | break; |
130 | case 96000: |
131 | val |= IEC958_AES3_CON_FS_96000; |
132 | break; |
133 | case 176400: |
134 | val |= IEC958_AES3_CON_FS_176400; |
135 | break; |
136 | case 192000: |
137 | val |= IEC958_AES3_CON_FS_192000; |
138 | break; |
139 | default: |
140 | dev_err(component->dev, "unsupported sampling rate\n" ); |
141 | return -EINVAL; |
142 | } |
143 | |
144 | ret = regmap_write(map: ak4104->regmap, AK4104_REG_CHN_STATUS(3), val); |
145 | if (ret < 0) |
146 | return ret; |
147 | |
148 | return 0; |
149 | } |
150 | |
151 | static const struct snd_soc_dai_ops ak4101_dai_ops = { |
152 | .hw_params = ak4104_hw_params, |
153 | .set_fmt = ak4104_set_dai_fmt, |
154 | }; |
155 | |
156 | static struct snd_soc_dai_driver ak4104_dai = { |
157 | .name = "ak4104-hifi" , |
158 | .playback = { |
159 | .stream_name = "Playback" , |
160 | .channels_min = 2, |
161 | .channels_max = 2, |
162 | .rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | |
163 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | |
164 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | |
165 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, |
166 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
167 | SNDRV_PCM_FMTBIT_S24_3LE | |
168 | SNDRV_PCM_FMTBIT_S24_LE |
169 | }, |
170 | .ops = &ak4101_dai_ops, |
171 | }; |
172 | |
173 | static int ak4104_probe(struct snd_soc_component *component) |
174 | { |
175 | struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(c: component); |
176 | int ret; |
177 | |
178 | ret = regulator_enable(regulator: ak4104->regulator); |
179 | if (ret < 0) { |
180 | dev_err(component->dev, "Unable to enable regulator: %d\n" , ret); |
181 | return ret; |
182 | } |
183 | |
184 | /* set power-up and non-reset bits */ |
185 | ret = regmap_update_bits(map: ak4104->regmap, AK4104_REG_CONTROL1, |
186 | AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, |
187 | AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); |
188 | if (ret < 0) |
189 | goto exit_disable_regulator; |
190 | |
191 | /* enable transmitter */ |
192 | ret = regmap_update_bits(map: ak4104->regmap, AK4104_REG_TX, |
193 | AK4104_TX_TXE, AK4104_TX_TXE); |
194 | if (ret < 0) |
195 | goto exit_disable_regulator; |
196 | |
197 | return 0; |
198 | |
199 | exit_disable_regulator: |
200 | regulator_disable(regulator: ak4104->regulator); |
201 | return ret; |
202 | } |
203 | |
204 | static void ak4104_remove(struct snd_soc_component *component) |
205 | { |
206 | struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(c: component); |
207 | |
208 | regmap_update_bits(map: ak4104->regmap, AK4104_REG_CONTROL1, |
209 | AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, val: 0); |
210 | regulator_disable(regulator: ak4104->regulator); |
211 | } |
212 | |
213 | #ifdef CONFIG_PM |
214 | static int ak4104_soc_suspend(struct snd_soc_component *component) |
215 | { |
216 | struct ak4104_private *priv = snd_soc_component_get_drvdata(c: component); |
217 | |
218 | regulator_disable(regulator: priv->regulator); |
219 | |
220 | return 0; |
221 | } |
222 | |
223 | static int ak4104_soc_resume(struct snd_soc_component *component) |
224 | { |
225 | struct ak4104_private *priv = snd_soc_component_get_drvdata(c: component); |
226 | int ret; |
227 | |
228 | ret = regulator_enable(regulator: priv->regulator); |
229 | if (ret < 0) |
230 | return ret; |
231 | |
232 | return 0; |
233 | } |
234 | #else |
235 | #define ak4104_soc_suspend NULL |
236 | #define ak4104_soc_resume NULL |
237 | #endif /* CONFIG_PM */ |
238 | |
239 | static const struct snd_soc_component_driver soc_component_device_ak4104 = { |
240 | .probe = ak4104_probe, |
241 | .remove = ak4104_remove, |
242 | .suspend = ak4104_soc_suspend, |
243 | .resume = ak4104_soc_resume, |
244 | .dapm_widgets = ak4104_dapm_widgets, |
245 | .num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets), |
246 | .dapm_routes = ak4104_dapm_routes, |
247 | .num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes), |
248 | .idle_bias_on = 1, |
249 | .use_pmdown_time = 1, |
250 | .endianness = 1, |
251 | }; |
252 | |
253 | static const struct regmap_config ak4104_regmap = { |
254 | .reg_bits = 8, |
255 | .val_bits = 8, |
256 | |
257 | .max_register = AK4104_NUM_REGS - 1, |
258 | .read_flag_mask = AK4104_READ, |
259 | .write_flag_mask = AK4104_WRITE, |
260 | |
261 | .cache_type = REGCACHE_RBTREE, |
262 | }; |
263 | |
264 | static int ak4104_spi_probe(struct spi_device *spi) |
265 | { |
266 | struct ak4104_private *ak4104; |
267 | struct gpio_desc *reset_gpiod; |
268 | unsigned int val; |
269 | int ret; |
270 | |
271 | spi->bits_per_word = 8; |
272 | spi->mode = SPI_MODE_0; |
273 | ret = spi_setup(spi); |
274 | if (ret < 0) |
275 | return ret; |
276 | |
277 | ak4104 = devm_kzalloc(dev: &spi->dev, size: sizeof(struct ak4104_private), |
278 | GFP_KERNEL); |
279 | if (ak4104 == NULL) |
280 | return -ENOMEM; |
281 | |
282 | ak4104->regulator = devm_regulator_get(dev: &spi->dev, id: "vdd" ); |
283 | if (IS_ERR(ptr: ak4104->regulator)) { |
284 | ret = PTR_ERR(ptr: ak4104->regulator); |
285 | dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n" , ret); |
286 | return ret; |
287 | } |
288 | |
289 | ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap); |
290 | if (IS_ERR(ptr: ak4104->regmap)) { |
291 | ret = PTR_ERR(ptr: ak4104->regmap); |
292 | return ret; |
293 | } |
294 | |
295 | reset_gpiod = devm_gpiod_get_optional(dev: &spi->dev, con_id: "reset" , |
296 | flags: GPIOD_OUT_HIGH); |
297 | if (PTR_ERR(ptr: reset_gpiod) == -EPROBE_DEFER) |
298 | return -EPROBE_DEFER; |
299 | |
300 | /* read the 'reserved' register - according to the datasheet, it |
301 | * should contain 0x5b. Not a good way to verify the presence of |
302 | * the device, but there is no hardware ID register. */ |
303 | ret = regmap_read(map: ak4104->regmap, AK4104_REG_RESERVED, val: &val); |
304 | if (ret != 0) |
305 | return ret; |
306 | if (val != AK4104_RESERVED_VAL) |
307 | return -ENODEV; |
308 | |
309 | spi_set_drvdata(spi, data: ak4104); |
310 | |
311 | ret = devm_snd_soc_register_component(dev: &spi->dev, |
312 | component_driver: &soc_component_device_ak4104, dai_drv: &ak4104_dai, num_dai: 1); |
313 | return ret; |
314 | } |
315 | |
316 | static const struct of_device_id ak4104_of_match[] = { |
317 | { .compatible = "asahi-kasei,ak4104" , }, |
318 | { } |
319 | }; |
320 | MODULE_DEVICE_TABLE(of, ak4104_of_match); |
321 | |
322 | static const struct spi_device_id ak4104_id_table[] = { |
323 | { "ak4104" , 0 }, |
324 | { } |
325 | }; |
326 | MODULE_DEVICE_TABLE(spi, ak4104_id_table); |
327 | |
328 | static struct spi_driver ak4104_spi_driver = { |
329 | .driver = { |
330 | .name = "ak4104" , |
331 | .of_match_table = ak4104_of_match, |
332 | }, |
333 | .id_table = ak4104_id_table, |
334 | .probe = ak4104_spi_probe, |
335 | }; |
336 | |
337 | module_spi_driver(ak4104_spi_driver); |
338 | |
339 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>" ); |
340 | MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver" ); |
341 | MODULE_LICENSE("GPL" ); |
342 | |
343 | |