12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2a381934eSDaniel Mack /*
3a381934eSDaniel Mack * AK4104 ALSA SoC (ASoC) driver
4a381934eSDaniel Mack *
5a381934eSDaniel Mack * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
6a381934eSDaniel Mack */
7a381934eSDaniel Mack
8a381934eSDaniel Mack #include <linux/module.h>
95a0e3ad6STejun Heo #include <linux/slab.h>
10a381934eSDaniel Mack #include <linux/spi/spi.h>
11385a4c2eSDaniel Mack #include <linux/of_device.h>
12d8f2c859SDaniel Mack #include <linux/gpio/consumer.h>
13b38d10edSDaniel Mack #include <linux/regulator/consumer.h>
14a381934eSDaniel Mack #include <sound/asoundef.h>
15b38d10edSDaniel Mack #include <sound/core.h>
16b38d10edSDaniel Mack #include <sound/soc.h>
17b38d10edSDaniel Mack #include <sound/initval.h>
18a381934eSDaniel Mack
19a381934eSDaniel Mack /* AK4104 registers addresses */
20a381934eSDaniel Mack #define AK4104_REG_CONTROL1 0x00
21a381934eSDaniel Mack #define AK4104_REG_RESERVED 0x01
22a381934eSDaniel Mack #define AK4104_REG_CONTROL2 0x02
23a381934eSDaniel Mack #define AK4104_REG_TX 0x03
24a381934eSDaniel Mack #define AK4104_REG_CHN_STATUS(x) ((x) + 0x04)
25a381934eSDaniel Mack #define AK4104_NUM_REGS 10
26a381934eSDaniel Mack
27a381934eSDaniel Mack #define AK4104_REG_MASK 0x1f
28a381934eSDaniel Mack #define AK4104_READ 0xc0
29a381934eSDaniel Mack #define AK4104_WRITE 0xe0
30a381934eSDaniel Mack #define AK4104_RESERVED_VAL 0x5b
31a381934eSDaniel Mack
32a381934eSDaniel Mack /* Bit masks for AK4104 registers */
33a381934eSDaniel Mack #define AK4104_CONTROL1_RSTN (1 << 0)
34a381934eSDaniel Mack #define AK4104_CONTROL1_PW (1 << 1)
35a381934eSDaniel Mack #define AK4104_CONTROL1_DIF0 (1 << 2)
36a381934eSDaniel Mack #define AK4104_CONTROL1_DIF1 (1 << 3)
37a381934eSDaniel Mack
38a381934eSDaniel Mack #define AK4104_CONTROL2_SEL0 (1 << 0)
39a381934eSDaniel Mack #define AK4104_CONTROL2_SEL1 (1 << 1)
40a381934eSDaniel Mack #define AK4104_CONTROL2_MODE (1 << 2)
41a381934eSDaniel Mack
42a381934eSDaniel Mack #define AK4104_TX_TXE (1 << 0)
43a381934eSDaniel Mack #define AK4104_TX_V (1 << 1)
44a381934eSDaniel Mack
45a381934eSDaniel Mack struct ak4104_private {
462901d6ebSMark Brown struct regmap *regmap;
47b38d10edSDaniel Mack struct regulator *regulator;
48a381934eSDaniel Mack };
49a381934eSDaniel Mack
502e61926cSMark Brown static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = {
51a5db4d50SMark Brown SND_SOC_DAPM_PGA("TXE", AK4104_REG_TX, AK4104_TX_TXE, 0, NULL, 0),
52a5db4d50SMark Brown
532e61926cSMark Brown SND_SOC_DAPM_OUTPUT("TX"),
542e61926cSMark Brown };
552e61926cSMark Brown
562e61926cSMark Brown static const struct snd_soc_dapm_route ak4104_dapm_routes[] = {
57a5db4d50SMark Brown { "TXE", NULL, "Playback" },
58a5db4d50SMark Brown { "TX", NULL, "TXE" },
592e61926cSMark Brown };
602e61926cSMark Brown
ak4104_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int format)61a381934eSDaniel Mack static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
62a381934eSDaniel Mack unsigned int format)
63a381934eSDaniel Mack {
6461feead8SKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
6561feead8SKuninori Morimoto struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
66a381934eSDaniel Mack int val = 0;
672901d6ebSMark Brown int ret;
68a381934eSDaniel Mack
69a381934eSDaniel Mack /* set DAI format */
70a381934eSDaniel Mack switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
71a381934eSDaniel Mack case SND_SOC_DAIFMT_RIGHT_J:
72a381934eSDaniel Mack break;
73a381934eSDaniel Mack case SND_SOC_DAIFMT_LEFT_J:
74a381934eSDaniel Mack val |= AK4104_CONTROL1_DIF0;
75a381934eSDaniel Mack break;
76a381934eSDaniel Mack case SND_SOC_DAIFMT_I2S:
77a381934eSDaniel Mack val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1;
78a381934eSDaniel Mack break;
79a381934eSDaniel Mack default:
8061feead8SKuninori Morimoto dev_err(component->dev, "invalid dai format\n");
81a381934eSDaniel Mack return -EINVAL;
82a381934eSDaniel Mack }
83a381934eSDaniel Mack
84*8515f828SMark Brown /* This device can only be consumer */
85*8515f828SMark Brown if ((format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC)
86a381934eSDaniel Mack return -EINVAL;
87a381934eSDaniel Mack
88b0ec761bSDaniel Mack ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
89afad95f8SMark Brown AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
90afad95f8SMark Brown val);
91afad95f8SMark Brown if (ret < 0)
92afad95f8SMark Brown return ret;
93afad95f8SMark Brown
94afad95f8SMark Brown return 0;
95a381934eSDaniel Mack }
96a381934eSDaniel Mack
ak4104_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)97a381934eSDaniel Mack static int ak4104_hw_params(struct snd_pcm_substream *substream,
98a381934eSDaniel Mack struct snd_pcm_hw_params *params,
99a381934eSDaniel Mack struct snd_soc_dai *dai)
100a381934eSDaniel Mack {
10161feead8SKuninori Morimoto struct snd_soc_component *component = dai->component;
10261feead8SKuninori Morimoto struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
103b692a436SDaniel Mack int ret, val = 0;
104a381934eSDaniel Mack
105a381934eSDaniel Mack /* set the IEC958 bits: consumer mode, no copyright bit */
106a381934eSDaniel Mack val |= IEC958_AES0_CON_NOT_COPYRIGHT;
107b0ec761bSDaniel Mack regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(0), val);
108a381934eSDaniel Mack
109a381934eSDaniel Mack val = 0;
110a381934eSDaniel Mack
111a381934eSDaniel Mack switch (params_rate(params)) {
11208201debSDaniel Mack case 22050:
11308201debSDaniel Mack val |= IEC958_AES3_CON_FS_22050;
11408201debSDaniel Mack break;
11508201debSDaniel Mack case 24000:
11608201debSDaniel Mack val |= IEC958_AES3_CON_FS_24000;
11708201debSDaniel Mack break;
11808201debSDaniel Mack case 32000:
11908201debSDaniel Mack val |= IEC958_AES3_CON_FS_32000;
12008201debSDaniel Mack break;
121a381934eSDaniel Mack case 44100:
122a381934eSDaniel Mack val |= IEC958_AES3_CON_FS_44100;
123a381934eSDaniel Mack break;
124a381934eSDaniel Mack case 48000:
125a381934eSDaniel Mack val |= IEC958_AES3_CON_FS_48000;
126a381934eSDaniel Mack break;
12708201debSDaniel Mack case 88200:
12808201debSDaniel Mack val |= IEC958_AES3_CON_FS_88200;
12908201debSDaniel Mack break;
13008201debSDaniel Mack case 96000:
13108201debSDaniel Mack val |= IEC958_AES3_CON_FS_96000;
13208201debSDaniel Mack break;
13308201debSDaniel Mack case 176400:
13408201debSDaniel Mack val |= IEC958_AES3_CON_FS_176400;
13508201debSDaniel Mack break;
13608201debSDaniel Mack case 192000:
13708201debSDaniel Mack val |= IEC958_AES3_CON_FS_192000;
138a381934eSDaniel Mack break;
139a381934eSDaniel Mack default:
14061feead8SKuninori Morimoto dev_err(component->dev, "unsupported sampling rate\n");
141a381934eSDaniel Mack return -EINVAL;
142a381934eSDaniel Mack }
143a381934eSDaniel Mack
144b692a436SDaniel Mack ret = regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val);
145b692a436SDaniel Mack if (ret < 0)
146b692a436SDaniel Mack return ret;
147b692a436SDaniel Mack
148b692a436SDaniel Mack return 0;
149b692a436SDaniel Mack }
150b692a436SDaniel Mack
15185e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops ak4101_dai_ops = {
15265ec1cd1SMark Brown .hw_params = ak4104_hw_params,
15365ec1cd1SMark Brown .set_fmt = ak4104_set_dai_fmt,
15465ec1cd1SMark Brown };
15565ec1cd1SMark Brown
156f0fba2adSLiam Girdwood static struct snd_soc_dai_driver ak4104_dai = {
157f0fba2adSLiam Girdwood .name = "ak4104-hifi",
158a381934eSDaniel Mack .playback = {
159a381934eSDaniel Mack .stream_name = "Playback",
160a381934eSDaniel Mack .channels_min = 2,
161a381934eSDaniel Mack .channels_max = 2,
162c14c59f2SVishal Thanki .rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
163c14c59f2SVishal Thanki SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
164c14c59f2SVishal Thanki SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
165c14c59f2SVishal Thanki SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
166a381934eSDaniel Mack .formats = SNDRV_PCM_FMTBIT_S16_LE |
167a381934eSDaniel Mack SNDRV_PCM_FMTBIT_S24_3LE |
168a381934eSDaniel Mack SNDRV_PCM_FMTBIT_S24_LE
169a381934eSDaniel Mack },
17065ec1cd1SMark Brown .ops = &ak4101_dai_ops,
171a381934eSDaniel Mack };
172a381934eSDaniel Mack
ak4104_probe(struct snd_soc_component * component)17361feead8SKuninori Morimoto static int ak4104_probe(struct snd_soc_component *component)
174f0fba2adSLiam Girdwood {
17561feead8SKuninori Morimoto struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
1762901d6ebSMark Brown int ret;
177f0fba2adSLiam Girdwood
178b38d10edSDaniel Mack ret = regulator_enable(ak4104->regulator);
179b38d10edSDaniel Mack if (ret < 0) {
18061feead8SKuninori Morimoto dev_err(component->dev, "Unable to enable regulator: %d\n", ret);
181b38d10edSDaniel Mack return ret;
182b38d10edSDaniel Mack }
183b38d10edSDaniel Mack
184f0fba2adSLiam Girdwood /* set power-up and non-reset bits */
185b0ec761bSDaniel Mack ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
186afad95f8SMark Brown AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
187afad95f8SMark Brown AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
188f0fba2adSLiam Girdwood if (ret < 0)
189b38d10edSDaniel Mack goto exit_disable_regulator;
190f0fba2adSLiam Girdwood
191f0fba2adSLiam Girdwood /* enable transmitter */
192b0ec761bSDaniel Mack ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
193afad95f8SMark Brown AK4104_TX_TXE, AK4104_TX_TXE);
194f0fba2adSLiam Girdwood if (ret < 0)
195b38d10edSDaniel Mack goto exit_disable_regulator;
196f0fba2adSLiam Girdwood
197f0fba2adSLiam Girdwood return 0;
198b38d10edSDaniel Mack
199b38d10edSDaniel Mack exit_disable_regulator:
200b38d10edSDaniel Mack regulator_disable(ak4104->regulator);
201b38d10edSDaniel Mack return ret;
202f0fba2adSLiam Girdwood }
203f0fba2adSLiam Girdwood
ak4104_remove(struct snd_soc_component * component)20461feead8SKuninori Morimoto static void ak4104_remove(struct snd_soc_component *component)
205f0fba2adSLiam Girdwood {
20661feead8SKuninori Morimoto struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
207b0ec761bSDaniel Mack
208b0ec761bSDaniel Mack regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
209afad95f8SMark Brown AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
210b38d10edSDaniel Mack regulator_disable(ak4104->regulator);
211f0fba2adSLiam Girdwood }
212f0fba2adSLiam Girdwood
213b38d10edSDaniel Mack #ifdef CONFIG_PM
ak4104_soc_suspend(struct snd_soc_component * component)21461feead8SKuninori Morimoto static int ak4104_soc_suspend(struct snd_soc_component *component)
215b38d10edSDaniel Mack {
21661feead8SKuninori Morimoto struct ak4104_private *priv = snd_soc_component_get_drvdata(component);
217b38d10edSDaniel Mack
218b38d10edSDaniel Mack regulator_disable(priv->regulator);
219b38d10edSDaniel Mack
220b38d10edSDaniel Mack return 0;
221b38d10edSDaniel Mack }
222b38d10edSDaniel Mack
ak4104_soc_resume(struct snd_soc_component * component)22361feead8SKuninori Morimoto static int ak4104_soc_resume(struct snd_soc_component *component)
224b38d10edSDaniel Mack {
22561feead8SKuninori Morimoto struct ak4104_private *priv = snd_soc_component_get_drvdata(component);
226b38d10edSDaniel Mack int ret;
227b38d10edSDaniel Mack
228b38d10edSDaniel Mack ret = regulator_enable(priv->regulator);
229b38d10edSDaniel Mack if (ret < 0)
230b38d10edSDaniel Mack return ret;
231b38d10edSDaniel Mack
232b38d10edSDaniel Mack return 0;
233b38d10edSDaniel Mack }
234b38d10edSDaniel Mack #else
235b38d10edSDaniel Mack #define ak4104_soc_suspend NULL
236b38d10edSDaniel Mack #define ak4104_soc_resume NULL
237b38d10edSDaniel Mack #endif /* CONFIG_PM */
238b38d10edSDaniel Mack
23961feead8SKuninori Morimoto static const struct snd_soc_component_driver soc_component_device_ak4104 = {
240f0fba2adSLiam Girdwood .probe = ak4104_probe,
241f0fba2adSLiam Girdwood .remove = ak4104_remove,
242b38d10edSDaniel Mack .suspend = ak4104_soc_suspend,
243b38d10edSDaniel Mack .resume = ak4104_soc_resume,
2442e61926cSMark Brown .dapm_widgets = ak4104_dapm_widgets,
2452e61926cSMark Brown .num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets),
2462e61926cSMark Brown .dapm_routes = ak4104_dapm_routes,
2472e61926cSMark Brown .num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes),
24861feead8SKuninori Morimoto .idle_bias_on = 1,
24961feead8SKuninori Morimoto .use_pmdown_time = 1,
25061feead8SKuninori Morimoto .endianness = 1,
2512901d6ebSMark Brown };
2522901d6ebSMark Brown
2532901d6ebSMark Brown static const struct regmap_config ak4104_regmap = {
2542901d6ebSMark Brown .reg_bits = 8,
2552901d6ebSMark Brown .val_bits = 8,
2562901d6ebSMark Brown
2572901d6ebSMark Brown .max_register = AK4104_NUM_REGS - 1,
2582901d6ebSMark Brown .read_flag_mask = AK4104_READ,
2592901d6ebSMark Brown .write_flag_mask = AK4104_WRITE,
2602901d6ebSMark Brown
2612901d6ebSMark Brown .cache_type = REGCACHE_RBTREE,
262f0fba2adSLiam Girdwood };
263a381934eSDaniel Mack
ak4104_spi_probe(struct spi_device * spi)264a381934eSDaniel Mack static int ak4104_spi_probe(struct spi_device *spi)
265a381934eSDaniel Mack {
266a381934eSDaniel Mack struct ak4104_private *ak4104;
267d8f2c859SDaniel Mack struct gpio_desc *reset_gpiod;
2682901d6ebSMark Brown unsigned int val;
269f0fba2adSLiam Girdwood int ret;
270a381934eSDaniel Mack
271a381934eSDaniel Mack spi->bits_per_word = 8;
272a381934eSDaniel Mack spi->mode = SPI_MODE_0;
273a381934eSDaniel Mack ret = spi_setup(spi);
274a381934eSDaniel Mack if (ret < 0)
275a381934eSDaniel Mack return ret;
276a381934eSDaniel Mack
2773922d518SAxel Lin ak4104 = devm_kzalloc(&spi->dev, sizeof(struct ak4104_private),
2783922d518SAxel Lin GFP_KERNEL);
279f0fba2adSLiam Girdwood if (ak4104 == NULL)
280a381934eSDaniel Mack return -ENOMEM;
281a381934eSDaniel Mack
282b38d10edSDaniel Mack ak4104->regulator = devm_regulator_get(&spi->dev, "vdd");
283b38d10edSDaniel Mack if (IS_ERR(ak4104->regulator)) {
284b38d10edSDaniel Mack ret = PTR_ERR(ak4104->regulator);
285b38d10edSDaniel Mack dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret);
286b38d10edSDaniel Mack return ret;
287b38d10edSDaniel Mack }
288b38d10edSDaniel Mack
289a273cd13STushar Behera ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap);
2902901d6ebSMark Brown if (IS_ERR(ak4104->regmap)) {
2912901d6ebSMark Brown ret = PTR_ERR(ak4104->regmap);
2922901d6ebSMark Brown return ret;
2932901d6ebSMark Brown }
2942901d6ebSMark Brown
295d8f2c859SDaniel Mack reset_gpiod = devm_gpiod_get_optional(&spi->dev, "reset",
296d8f2c859SDaniel Mack GPIOD_OUT_HIGH);
29745586c70SMasahiro Yamada if (PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
298d8f2c859SDaniel Mack return -EPROBE_DEFER;
299385a4c2eSDaniel Mack
3002901d6ebSMark Brown /* read the 'reserved' register - according to the datasheet, it
3012901d6ebSMark Brown * should contain 0x5b. Not a good way to verify the presence of
3022901d6ebSMark Brown * the device, but there is no hardware ID register. */
3032901d6ebSMark Brown ret = regmap_read(ak4104->regmap, AK4104_REG_RESERVED, &val);
3042901d6ebSMark Brown if (ret != 0)
305a273cd13STushar Behera return ret;
306a273cd13STushar Behera if (val != AK4104_RESERVED_VAL)
307a273cd13STushar Behera return -ENODEV;
3082901d6ebSMark Brown
309a381934eSDaniel Mack spi_set_drvdata(spi, ak4104);
310a381934eSDaniel Mack
31161feead8SKuninori Morimoto ret = devm_snd_soc_register_component(&spi->dev,
31261feead8SKuninori Morimoto &soc_component_device_ak4104, &ak4104_dai, 1);
313a381934eSDaniel Mack return ret;
314a381934eSDaniel Mack }
315a381934eSDaniel Mack
316ac5dbea0SDaniel Mack static const struct of_device_id ak4104_of_match[] = {
317ac5dbea0SDaniel Mack { .compatible = "asahi-kasei,ak4104", },
318ac5dbea0SDaniel Mack { }
319ac5dbea0SDaniel Mack };
320ac5dbea0SDaniel Mack MODULE_DEVICE_TABLE(of, ak4104_of_match);
321ac5dbea0SDaniel Mack
322193b2f65SDaniel Mack static const struct spi_device_id ak4104_id_table[] = {
323193b2f65SDaniel Mack { "ak4104", 0 },
324193b2f65SDaniel Mack { }
325193b2f65SDaniel Mack };
326193b2f65SDaniel Mack MODULE_DEVICE_TABLE(spi, ak4104_id_table);
327193b2f65SDaniel Mack
328a381934eSDaniel Mack static struct spi_driver ak4104_spi_driver = {
329a381934eSDaniel Mack .driver = {
330193b2f65SDaniel Mack .name = "ak4104",
331ac5dbea0SDaniel Mack .of_match_table = ak4104_of_match,
332a381934eSDaniel Mack },
333193b2f65SDaniel Mack .id_table = ak4104_id_table,
334a381934eSDaniel Mack .probe = ak4104_spi_probe,
335a381934eSDaniel Mack };
336a381934eSDaniel Mack
33738d78bafSMark Brown module_spi_driver(ak4104_spi_driver);
338a381934eSDaniel Mack
339a381934eSDaniel Mack MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
340a381934eSDaniel Mack MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver");
341a381934eSDaniel Mack MODULE_LICENSE("GPL");
342a381934eSDaniel Mack
343