162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AK4104 ALSA SoC (ASoC) driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <linux/spi/spi.h>
1162306a36Sopenharmony_ci#include <linux/of_device.h>
1262306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1362306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1462306a36Sopenharmony_ci#include <sound/asoundef.h>
1562306a36Sopenharmony_ci#include <sound/core.h>
1662306a36Sopenharmony_ci#include <sound/soc.h>
1762306a36Sopenharmony_ci#include <sound/initval.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* AK4104 registers addresses */
2062306a36Sopenharmony_ci#define AK4104_REG_CONTROL1		0x00
2162306a36Sopenharmony_ci#define AK4104_REG_RESERVED		0x01
2262306a36Sopenharmony_ci#define AK4104_REG_CONTROL2		0x02
2362306a36Sopenharmony_ci#define AK4104_REG_TX			0x03
2462306a36Sopenharmony_ci#define AK4104_REG_CHN_STATUS(x)	((x) + 0x04)
2562306a36Sopenharmony_ci#define AK4104_NUM_REGS			10
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define AK4104_REG_MASK			0x1f
2862306a36Sopenharmony_ci#define AK4104_READ			0xc0
2962306a36Sopenharmony_ci#define AK4104_WRITE			0xe0
3062306a36Sopenharmony_ci#define AK4104_RESERVED_VAL		0x5b
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Bit masks for AK4104 registers */
3362306a36Sopenharmony_ci#define AK4104_CONTROL1_RSTN		(1 << 0)
3462306a36Sopenharmony_ci#define AK4104_CONTROL1_PW		(1 << 1)
3562306a36Sopenharmony_ci#define AK4104_CONTROL1_DIF0		(1 << 2)
3662306a36Sopenharmony_ci#define AK4104_CONTROL1_DIF1		(1 << 3)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define AK4104_CONTROL2_SEL0		(1 << 0)
3962306a36Sopenharmony_ci#define AK4104_CONTROL2_SEL1		(1 << 1)
4062306a36Sopenharmony_ci#define AK4104_CONTROL2_MODE		(1 << 2)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define AK4104_TX_TXE			(1 << 0)
4362306a36Sopenharmony_ci#define AK4104_TX_V			(1 << 1)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistruct ak4104_private {
4662306a36Sopenharmony_ci	struct regmap *regmap;
4762306a36Sopenharmony_ci	struct regulator *regulator;
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = {
5162306a36Sopenharmony_ciSND_SOC_DAPM_PGA("TXE", AK4104_REG_TX, AK4104_TX_TXE, 0, NULL, 0),
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ciSND_SOC_DAPM_OUTPUT("TX"),
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic const struct snd_soc_dapm_route ak4104_dapm_routes[] = {
5762306a36Sopenharmony_ci	{ "TXE", NULL, "Playback" },
5862306a36Sopenharmony_ci	{ "TX", NULL, "TXE" },
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
6262306a36Sopenharmony_ci			      unsigned int format)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct snd_soc_component *component = codec_dai->component;
6562306a36Sopenharmony_ci	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
6662306a36Sopenharmony_ci	int val = 0;
6762306a36Sopenharmony_ci	int ret;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* set DAI format */
7062306a36Sopenharmony_ci	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
7162306a36Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
7262306a36Sopenharmony_ci		break;
7362306a36Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
7462306a36Sopenharmony_ci		val |= AK4104_CONTROL1_DIF0;
7562306a36Sopenharmony_ci		break;
7662306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
7762306a36Sopenharmony_ci		val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1;
7862306a36Sopenharmony_ci		break;
7962306a36Sopenharmony_ci	default:
8062306a36Sopenharmony_ci		dev_err(component->dev, "invalid dai format\n");
8162306a36Sopenharmony_ci		return -EINVAL;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/* This device can only be consumer */
8562306a36Sopenharmony_ci	if ((format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC)
8662306a36Sopenharmony_ci		return -EINVAL;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
8962306a36Sopenharmony_ci				 AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
9062306a36Sopenharmony_ci				 val);
9162306a36Sopenharmony_ci	if (ret < 0)
9262306a36Sopenharmony_ci		return ret;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return 0;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int ak4104_hw_params(struct snd_pcm_substream *substream,
9862306a36Sopenharmony_ci			    struct snd_pcm_hw_params *params,
9962306a36Sopenharmony_ci			    struct snd_soc_dai *dai)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
10262306a36Sopenharmony_ci	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
10362306a36Sopenharmony_ci	int ret, val = 0;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* set the IEC958 bits: consumer mode, no copyright bit */
10662306a36Sopenharmony_ci	val |= IEC958_AES0_CON_NOT_COPYRIGHT;
10762306a36Sopenharmony_ci	regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(0), val);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	val = 0;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	switch (params_rate(params)) {
11262306a36Sopenharmony_ci	case 22050:
11362306a36Sopenharmony_ci		val |= IEC958_AES3_CON_FS_22050;
11462306a36Sopenharmony_ci		break;
11562306a36Sopenharmony_ci	case 24000:
11662306a36Sopenharmony_ci		val |= IEC958_AES3_CON_FS_24000;
11762306a36Sopenharmony_ci		break;
11862306a36Sopenharmony_ci	case 32000:
11962306a36Sopenharmony_ci		val |= IEC958_AES3_CON_FS_32000;
12062306a36Sopenharmony_ci		break;
12162306a36Sopenharmony_ci	case 44100:
12262306a36Sopenharmony_ci		val |= IEC958_AES3_CON_FS_44100;
12362306a36Sopenharmony_ci		break;
12462306a36Sopenharmony_ci	case 48000:
12562306a36Sopenharmony_ci		val |= IEC958_AES3_CON_FS_48000;
12662306a36Sopenharmony_ci		break;
12762306a36Sopenharmony_ci	case 88200:
12862306a36Sopenharmony_ci		val |= IEC958_AES3_CON_FS_88200;
12962306a36Sopenharmony_ci		break;
13062306a36Sopenharmony_ci	case 96000:
13162306a36Sopenharmony_ci		val |= IEC958_AES3_CON_FS_96000;
13262306a36Sopenharmony_ci		break;
13362306a36Sopenharmony_ci	case 176400:
13462306a36Sopenharmony_ci		val |= IEC958_AES3_CON_FS_176400;
13562306a36Sopenharmony_ci		break;
13662306a36Sopenharmony_ci	case 192000:
13762306a36Sopenharmony_ci		val |= IEC958_AES3_CON_FS_192000;
13862306a36Sopenharmony_ci		break;
13962306a36Sopenharmony_ci	default:
14062306a36Sopenharmony_ci		dev_err(component->dev, "unsupported sampling rate\n");
14162306a36Sopenharmony_ci		return -EINVAL;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	ret = regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val);
14562306a36Sopenharmony_ci	if (ret < 0)
14662306a36Sopenharmony_ci		return ret;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return 0;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic const struct snd_soc_dai_ops ak4101_dai_ops = {
15262306a36Sopenharmony_ci	.hw_params = ak4104_hw_params,
15362306a36Sopenharmony_ci	.set_fmt = ak4104_set_dai_fmt,
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic struct snd_soc_dai_driver ak4104_dai = {
15762306a36Sopenharmony_ci	.name = "ak4104-hifi",
15862306a36Sopenharmony_ci	.playback = {
15962306a36Sopenharmony_ci		.stream_name = "Playback",
16062306a36Sopenharmony_ci		.channels_min = 2,
16162306a36Sopenharmony_ci		.channels_max = 2,
16262306a36Sopenharmony_ci		.rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
16362306a36Sopenharmony_ci			 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
16462306a36Sopenharmony_ci			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
16562306a36Sopenharmony_ci			 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
16662306a36Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE  |
16762306a36Sopenharmony_ci			   SNDRV_PCM_FMTBIT_S24_3LE |
16862306a36Sopenharmony_ci			   SNDRV_PCM_FMTBIT_S24_LE
16962306a36Sopenharmony_ci	},
17062306a36Sopenharmony_ci	.ops = &ak4101_dai_ops,
17162306a36Sopenharmony_ci};
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int ak4104_probe(struct snd_soc_component *component)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
17662306a36Sopenharmony_ci	int ret;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	ret = regulator_enable(ak4104->regulator);
17962306a36Sopenharmony_ci	if (ret < 0) {
18062306a36Sopenharmony_ci		dev_err(component->dev, "Unable to enable regulator: %d\n", ret);
18162306a36Sopenharmony_ci		return ret;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* set power-up and non-reset bits */
18562306a36Sopenharmony_ci	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
18662306a36Sopenharmony_ci				 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
18762306a36Sopenharmony_ci				 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
18862306a36Sopenharmony_ci	if (ret < 0)
18962306a36Sopenharmony_ci		goto exit_disable_regulator;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/* enable transmitter */
19262306a36Sopenharmony_ci	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
19362306a36Sopenharmony_ci				 AK4104_TX_TXE, AK4104_TX_TXE);
19462306a36Sopenharmony_ci	if (ret < 0)
19562306a36Sopenharmony_ci		goto exit_disable_regulator;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return 0;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ciexit_disable_regulator:
20062306a36Sopenharmony_ci	regulator_disable(ak4104->regulator);
20162306a36Sopenharmony_ci	return ret;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic void ak4104_remove(struct snd_soc_component *component)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct ak4104_private *ak4104 = snd_soc_component_get_drvdata(component);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
20962306a36Sopenharmony_ci			   AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
21062306a36Sopenharmony_ci	regulator_disable(ak4104->regulator);
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci#ifdef CONFIG_PM
21462306a36Sopenharmony_cistatic int ak4104_soc_suspend(struct snd_soc_component *component)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	struct ak4104_private *priv = snd_soc_component_get_drvdata(component);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	regulator_disable(priv->regulator);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	return 0;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic int ak4104_soc_resume(struct snd_soc_component *component)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct ak4104_private *priv = snd_soc_component_get_drvdata(component);
22662306a36Sopenharmony_ci	int ret;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	ret = regulator_enable(priv->regulator);
22962306a36Sopenharmony_ci	if (ret < 0)
23062306a36Sopenharmony_ci		return ret;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return 0;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci#else
23562306a36Sopenharmony_ci#define ak4104_soc_suspend	NULL
23662306a36Sopenharmony_ci#define ak4104_soc_resume	NULL
23762306a36Sopenharmony_ci#endif /* CONFIG_PM */
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_device_ak4104 = {
24062306a36Sopenharmony_ci	.probe			= ak4104_probe,
24162306a36Sopenharmony_ci	.remove			= ak4104_remove,
24262306a36Sopenharmony_ci	.suspend		= ak4104_soc_suspend,
24362306a36Sopenharmony_ci	.resume			= ak4104_soc_resume,
24462306a36Sopenharmony_ci	.dapm_widgets		= ak4104_dapm_widgets,
24562306a36Sopenharmony_ci	.num_dapm_widgets	= ARRAY_SIZE(ak4104_dapm_widgets),
24662306a36Sopenharmony_ci	.dapm_routes		= ak4104_dapm_routes,
24762306a36Sopenharmony_ci	.num_dapm_routes	= ARRAY_SIZE(ak4104_dapm_routes),
24862306a36Sopenharmony_ci	.idle_bias_on		= 1,
24962306a36Sopenharmony_ci	.use_pmdown_time	= 1,
25062306a36Sopenharmony_ci	.endianness		= 1,
25162306a36Sopenharmony_ci};
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic const struct regmap_config ak4104_regmap = {
25462306a36Sopenharmony_ci	.reg_bits = 8,
25562306a36Sopenharmony_ci	.val_bits = 8,
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	.max_register = AK4104_NUM_REGS - 1,
25862306a36Sopenharmony_ci	.read_flag_mask = AK4104_READ,
25962306a36Sopenharmony_ci	.write_flag_mask = AK4104_WRITE,
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
26262306a36Sopenharmony_ci};
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic int ak4104_spi_probe(struct spi_device *spi)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct ak4104_private *ak4104;
26762306a36Sopenharmony_ci	struct gpio_desc *reset_gpiod;
26862306a36Sopenharmony_ci	unsigned int val;
26962306a36Sopenharmony_ci	int ret;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	spi->bits_per_word = 8;
27262306a36Sopenharmony_ci	spi->mode = SPI_MODE_0;
27362306a36Sopenharmony_ci	ret = spi_setup(spi);
27462306a36Sopenharmony_ci	if (ret < 0)
27562306a36Sopenharmony_ci		return ret;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ak4104 = devm_kzalloc(&spi->dev, sizeof(struct ak4104_private),
27862306a36Sopenharmony_ci			      GFP_KERNEL);
27962306a36Sopenharmony_ci	if (ak4104 == NULL)
28062306a36Sopenharmony_ci		return -ENOMEM;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	ak4104->regulator = devm_regulator_get(&spi->dev, "vdd");
28362306a36Sopenharmony_ci	if (IS_ERR(ak4104->regulator)) {
28462306a36Sopenharmony_ci		ret = PTR_ERR(ak4104->regulator);
28562306a36Sopenharmony_ci		dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret);
28662306a36Sopenharmony_ci		return ret;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap);
29062306a36Sopenharmony_ci	if (IS_ERR(ak4104->regmap)) {
29162306a36Sopenharmony_ci		ret = PTR_ERR(ak4104->regmap);
29262306a36Sopenharmony_ci		return ret;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	reset_gpiod = devm_gpiod_get_optional(&spi->dev, "reset",
29662306a36Sopenharmony_ci					      GPIOD_OUT_HIGH);
29762306a36Sopenharmony_ci	if (PTR_ERR(reset_gpiod) == -EPROBE_DEFER)
29862306a36Sopenharmony_ci		return -EPROBE_DEFER;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* read the 'reserved' register - according to the datasheet, it
30162306a36Sopenharmony_ci	 * should contain 0x5b. Not a good way to verify the presence of
30262306a36Sopenharmony_ci	 * the device, but there is no hardware ID register. */
30362306a36Sopenharmony_ci	ret = regmap_read(ak4104->regmap, AK4104_REG_RESERVED, &val);
30462306a36Sopenharmony_ci	if (ret != 0)
30562306a36Sopenharmony_ci		return ret;
30662306a36Sopenharmony_ci	if (val != AK4104_RESERVED_VAL)
30762306a36Sopenharmony_ci		return -ENODEV;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	spi_set_drvdata(spi, ak4104);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	ret = devm_snd_soc_register_component(&spi->dev,
31262306a36Sopenharmony_ci			&soc_component_device_ak4104, &ak4104_dai, 1);
31362306a36Sopenharmony_ci	return ret;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic const struct of_device_id ak4104_of_match[] = {
31762306a36Sopenharmony_ci	{ .compatible = "asahi-kasei,ak4104", },
31862306a36Sopenharmony_ci	{ }
31962306a36Sopenharmony_ci};
32062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ak4104_of_match);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic const struct spi_device_id ak4104_id_table[] = {
32362306a36Sopenharmony_ci	{ "ak4104", 0 },
32462306a36Sopenharmony_ci	{ }
32562306a36Sopenharmony_ci};
32662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ak4104_id_table);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic struct spi_driver ak4104_spi_driver = {
32962306a36Sopenharmony_ci	.driver  = {
33062306a36Sopenharmony_ci		.name   = "ak4104",
33162306a36Sopenharmony_ci		.of_match_table = ak4104_of_match,
33262306a36Sopenharmony_ci	},
33362306a36Sopenharmony_ci	.id_table = ak4104_id_table,
33462306a36Sopenharmony_ci	.probe  = ak4104_spi_probe,
33562306a36Sopenharmony_ci};
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cimodule_spi_driver(ak4104_spi_driver);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ciMODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
34062306a36Sopenharmony_ciMODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver");
34162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
34262306a36Sopenharmony_ci
343