xref: /openbmc/linux/sound/soc/codecs/ak4104.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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