162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// ak4613.c  --  Asahi Kasei ALSA Soc Audio driver
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (C) 2015 Renesas Electronics Corporation
662306a36Sopenharmony_ci// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// Based on ak4642.c by Kuninori Morimoto
962306a36Sopenharmony_ci// Based on wm8731.c by Richard Purdie
1062306a36Sopenharmony_ci// Based on ak4535.c by Richard Purdie
1162306a36Sopenharmony_ci// Based on wm8753.c by Liam Girdwood
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci *		+-------+
1562306a36Sopenharmony_ci *		|AK4613	|
1662306a36Sopenharmony_ci *	SDTO1 <-|	|
1762306a36Sopenharmony_ci *		|	|
1862306a36Sopenharmony_ci *	SDTI1 ->|	|
1962306a36Sopenharmony_ci *	SDTI2 ->|	|
2062306a36Sopenharmony_ci *	SDTI3 ->|	|
2162306a36Sopenharmony_ci *		+-------+
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci *	  +---+
2462306a36Sopenharmony_ci * clk	  |   |___________________________________________...
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * [TDM512]
2762306a36Sopenharmony_ci * SDTO1  [L1][R1][L2][R2]
2862306a36Sopenharmony_ci * SDTI1  [L1][R1][L2][R2][L3][R3][L4][R4][L5][R5][L6][R6]
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * [TDM256]
3162306a36Sopenharmony_ci * SDTO1  [L1][R1][L2][R2]
3262306a36Sopenharmony_ci * SDTI1  [L1][R1][L2][R2][L3][R3][L4][R4]
3362306a36Sopenharmony_ci * SDTI2  [L5][R5][L6][R6]
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * [TDM128]
3662306a36Sopenharmony_ci * SDTO1  [L1][R1][L2][R2]
3762306a36Sopenharmony_ci * SDTI1  [L1][R1][L2][R2]
3862306a36Sopenharmony_ci * SDTI2  [L3][R3][L4][R4]
3962306a36Sopenharmony_ci * SDTI3  [L5][R5][L6][R6]
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * [STEREO]
4262306a36Sopenharmony_ci *	Playback  2ch : SDTI1
4362306a36Sopenharmony_ci *	Capture   2ch : SDTO1
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * [TDM512]
4662306a36Sopenharmony_ci *	Playback 12ch : SDTI1
4762306a36Sopenharmony_ci *	Capture   4ch : SDTO1
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci * [TDM256]
5062306a36Sopenharmony_ci *	Playback 12ch : SDTI1 + SDTI2
5162306a36Sopenharmony_ci *	Playback  8ch : SDTI1
5262306a36Sopenharmony_ci *	Capture   4ch : SDTO1
5362306a36Sopenharmony_ci *
5462306a36Sopenharmony_ci * [TDM128]
5562306a36Sopenharmony_ci *	Playback 12ch : SDTI1 + SDTI2 + SDTI3
5662306a36Sopenharmony_ci *	Playback  8ch : SDTI1 + SDTI2
5762306a36Sopenharmony_ci *	Playback  4ch : SDTI1
5862306a36Sopenharmony_ci *	Capture   4ch : SDTO1
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci *
6162306a36Sopenharmony_ci * !!! NOTE !!!
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci * Renesas is the only user of ak4613 on upstream so far,
6462306a36Sopenharmony_ci * but the chip connection is like below.
6562306a36Sopenharmony_ci * Thus, Renesas can't test all connection case.
6662306a36Sopenharmony_ci * Tested TDM is very limited.
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * +-----+	+-----------+
6962306a36Sopenharmony_ci * | SoC |	|  AK4613   |
7062306a36Sopenharmony_ci * |     |<-----|SDTO1	 IN1|<-- Mic
7162306a36Sopenharmony_ci * |     |	|	 IN2|
7262306a36Sopenharmony_ci * |     |	|	    |
7362306a36Sopenharmony_ci * |     |----->|SDTI1	OUT1|--> Headphone
7462306a36Sopenharmony_ci * +-----+	|SDTI2	OUT2|
7562306a36Sopenharmony_ci *		|SDTI3	OUT3|
7662306a36Sopenharmony_ci *		|	OUT4|
7762306a36Sopenharmony_ci *		|	OUT5|
7862306a36Sopenharmony_ci *		|	OUT6|
7962306a36Sopenharmony_ci *		+-----------+
8062306a36Sopenharmony_ci *
8162306a36Sopenharmony_ci * Renesas SoC can handle [2,  6,8]    channels.
8262306a36Sopenharmony_ci * Ak4613      can handle [2,4,  8,12] channels.
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * Because of above HW connection and available channels number,
8562306a36Sopenharmony_ci * Renesas could test are ...
8662306a36Sopenharmony_ci *
8762306a36Sopenharmony_ci *	[STEREO] Playback  2ch : SDTI1
8862306a36Sopenharmony_ci *		 Capture   2ch : SDTO1
8962306a36Sopenharmony_ci *	[TDM256] Playback  8ch : SDTI1 (*)
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci * (*) it used 8ch data between SoC <-> AK4613 on TDM256 mode,
9262306a36Sopenharmony_ci *     but could confirm is only first 2ch because only 1
9362306a36Sopenharmony_ci *     Headphone is connected.
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * see
9662306a36Sopenharmony_ci *	AK4613_ENABLE_TDM_TEST
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_ci#include <linux/clk.h>
9962306a36Sopenharmony_ci#include <linux/delay.h>
10062306a36Sopenharmony_ci#include <linux/i2c.h>
10162306a36Sopenharmony_ci#include <linux/slab.h>
10262306a36Sopenharmony_ci#include <linux/of_device.h>
10362306a36Sopenharmony_ci#include <linux/of_graph.h>
10462306a36Sopenharmony_ci#include <linux/module.h>
10562306a36Sopenharmony_ci#include <linux/regmap.h>
10662306a36Sopenharmony_ci#include <sound/soc.h>
10762306a36Sopenharmony_ci#include <sound/pcm_params.h>
10862306a36Sopenharmony_ci#include <sound/tlv.h>
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define PW_MGMT1	0x00 /* Power Management 1 */
11162306a36Sopenharmony_ci#define PW_MGMT2	0x01 /* Power Management 2 */
11262306a36Sopenharmony_ci#define PW_MGMT3	0x02 /* Power Management 3 */
11362306a36Sopenharmony_ci#define CTRL1		0x03 /* Control 1 */
11462306a36Sopenharmony_ci#define CTRL2		0x04 /* Control 2 */
11562306a36Sopenharmony_ci#define DEMP1		0x05 /* De-emphasis1 */
11662306a36Sopenharmony_ci#define DEMP2		0x06 /* De-emphasis2 */
11762306a36Sopenharmony_ci#define OFD		0x07 /* Overflow Detect */
11862306a36Sopenharmony_ci#define ZRD		0x08 /* Zero Detect */
11962306a36Sopenharmony_ci#define ICTRL		0x09 /* Input Control */
12062306a36Sopenharmony_ci#define OCTRL		0x0a /* Output Control */
12162306a36Sopenharmony_ci#define LOUT1		0x0b /* LOUT1 Volume Control */
12262306a36Sopenharmony_ci#define ROUT1		0x0c /* ROUT1 Volume Control */
12362306a36Sopenharmony_ci#define LOUT2		0x0d /* LOUT2 Volume Control */
12462306a36Sopenharmony_ci#define ROUT2		0x0e /* ROUT2 Volume Control */
12562306a36Sopenharmony_ci#define LOUT3		0x0f /* LOUT3 Volume Control */
12662306a36Sopenharmony_ci#define ROUT3		0x10 /* ROUT3 Volume Control */
12762306a36Sopenharmony_ci#define LOUT4		0x11 /* LOUT4 Volume Control */
12862306a36Sopenharmony_ci#define ROUT4		0x12 /* ROUT4 Volume Control */
12962306a36Sopenharmony_ci#define LOUT5		0x13 /* LOUT5 Volume Control */
13062306a36Sopenharmony_ci#define ROUT5		0x14 /* ROUT5 Volume Control */
13162306a36Sopenharmony_ci#define LOUT6		0x15 /* LOUT6 Volume Control */
13262306a36Sopenharmony_ci#define ROUT6		0x16 /* ROUT6 Volume Control */
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/* PW_MGMT1 */
13562306a36Sopenharmony_ci#define RSTN		BIT(0)
13662306a36Sopenharmony_ci#define PMDAC		BIT(1)
13762306a36Sopenharmony_ci#define PMADC		BIT(2)
13862306a36Sopenharmony_ci#define PMVR		BIT(3)
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/* PW_MGMT2 */
14162306a36Sopenharmony_ci#define PMAD_ALL	0x7
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci/* PW_MGMT3 */
14462306a36Sopenharmony_ci#define PMDA_ALL	0x3f
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* CTRL1 */
14762306a36Sopenharmony_ci#define DIF0		BIT(3)
14862306a36Sopenharmony_ci#define DIF1		BIT(4)
14962306a36Sopenharmony_ci#define DIF2		BIT(5)
15062306a36Sopenharmony_ci#define TDM0		BIT(6)
15162306a36Sopenharmony_ci#define TDM1		BIT(7)
15262306a36Sopenharmony_ci#define NO_FMT		(0xff)
15362306a36Sopenharmony_ci#define FMT_MASK	(0xf8)
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/* CTRL2 */
15662306a36Sopenharmony_ci#define DFS_MASK		(3 << 2)
15762306a36Sopenharmony_ci#define DFS_NORMAL_SPEED	(0 << 2)
15862306a36Sopenharmony_ci#define DFS_DOUBLE_SPEED	(1 << 2)
15962306a36Sopenharmony_ci#define DFS_QUAD_SPEED		(2 << 2)
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci/* ICTRL */
16262306a36Sopenharmony_ci#define ICTRL_MASK	(0x3)
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/* OCTRL */
16562306a36Sopenharmony_ci#define OCTRL_MASK	(0x3F)
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/*
16862306a36Sopenharmony_ci * configs
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * 0x000000BA
17162306a36Sopenharmony_ci *
17262306a36Sopenharmony_ci * B : AK4613_CONFIG_SDTI_x
17362306a36Sopenharmony_ci * A : AK4613_CONFIG_MODE_x
17462306a36Sopenharmony_ci */
17562306a36Sopenharmony_ci#define AK4613_CONFIG_SET(priv, x)	 priv->configs |= AK4613_CONFIG_##x
17662306a36Sopenharmony_ci#define AK4613_CONFIG_GET(priv, x)	(priv->configs &  AK4613_CONFIG_##x##_MASK)
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/*
17962306a36Sopenharmony_ci * AK4613_CONFIG_SDTI_x
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci * It indicates how many SDTIx is connected.
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_ci#define AK4613_CONFIG_SDTI_MASK		(0xF << 4)
18462306a36Sopenharmony_ci#define AK4613_CONFIG_SDTI(x)		(((x) & 0xF) << 4)
18562306a36Sopenharmony_ci#define AK4613_CONFIG_SDTI_set(priv, x)	  AK4613_CONFIG_SET(priv, SDTI(x))
18662306a36Sopenharmony_ci#define AK4613_CONFIG_SDTI_get(priv)	((AK4613_CONFIG_GET(priv, SDTI) >> 4) & 0xF)
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/*
18962306a36Sopenharmony_ci * AK4613_CONFIG_MODE_x
19062306a36Sopenharmony_ci *
19162306a36Sopenharmony_ci * Same as Ctrl1 :: TDM1/TDM0
19262306a36Sopenharmony_ci * No shift is requested
19362306a36Sopenharmony_ci * see
19462306a36Sopenharmony_ci *	AK4613_CTRL1_TO_MODE()
19562306a36Sopenharmony_ci *	Table 11/12/13/14
19662306a36Sopenharmony_ci */
19762306a36Sopenharmony_ci#define AK4613_CONFIG_MODE_MASK		(0xF)
19862306a36Sopenharmony_ci#define AK4613_CONFIG_MODE_STEREO	(0x0)
19962306a36Sopenharmony_ci#define AK4613_CONFIG_MODE_TDM512	(0x1)
20062306a36Sopenharmony_ci#define AK4613_CONFIG_MODE_TDM256	(0x2)
20162306a36Sopenharmony_ci#define AK4613_CONFIG_MODE_TDM128	(0x3)
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/*
20462306a36Sopenharmony_ci * !!!! FIXME !!!!
20562306a36Sopenharmony_ci *
20662306a36Sopenharmony_ci * Because of testable HW limitation, TDM256 8ch TDM was only tested.
20762306a36Sopenharmony_ci * This driver uses AK4613_ENABLE_TDM_TEST instead of new DT property so far.
20862306a36Sopenharmony_ci * Don't hesitate to update driver, you don't need to care compatible
20962306a36Sopenharmony_ci * with Renesas.
21062306a36Sopenharmony_ci *
21162306a36Sopenharmony_ci * #define AK4613_ENABLE_TDM_TEST
21262306a36Sopenharmony_ci */
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistruct ak4613_interface {
21562306a36Sopenharmony_ci	unsigned int width;
21662306a36Sopenharmony_ci	unsigned int fmt;
21762306a36Sopenharmony_ci	u8 dif;
21862306a36Sopenharmony_ci};
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistruct ak4613_priv {
22162306a36Sopenharmony_ci	struct mutex lock;
22262306a36Sopenharmony_ci	struct snd_pcm_hw_constraint_list constraint_rates;
22362306a36Sopenharmony_ci	struct snd_pcm_hw_constraint_list constraint_channels;
22462306a36Sopenharmony_ci	struct work_struct dummy_write_work;
22562306a36Sopenharmony_ci	struct snd_soc_component *component;
22662306a36Sopenharmony_ci	unsigned int rate;
22762306a36Sopenharmony_ci	unsigned int sysclk;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	unsigned int fmt;
23062306a36Sopenharmony_ci	unsigned int configs;
23162306a36Sopenharmony_ci	int cnt;
23262306a36Sopenharmony_ci	u8 ctrl1;
23362306a36Sopenharmony_ci	u8 oc;
23462306a36Sopenharmony_ci	u8 ic;
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci/*
23862306a36Sopenharmony_ci * Playback Volume
23962306a36Sopenharmony_ci *
24062306a36Sopenharmony_ci * max : 0x00 : 0 dB
24162306a36Sopenharmony_ci *       ( 0.5 dB step )
24262306a36Sopenharmony_ci * min : 0xFE : -127.0 dB
24362306a36Sopenharmony_ci * mute: 0xFF
24462306a36Sopenharmony_ci */
24562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(out_tlv, -12750, 50, 1);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic const struct snd_kcontrol_new ak4613_snd_controls[] = {
24862306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Digital Playback Volume1", LOUT1, ROUT1,
24962306a36Sopenharmony_ci			 0, 0xFF, 1, out_tlv),
25062306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Digital Playback Volume2", LOUT2, ROUT2,
25162306a36Sopenharmony_ci			 0, 0xFF, 1, out_tlv),
25262306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Digital Playback Volume3", LOUT3, ROUT3,
25362306a36Sopenharmony_ci			 0, 0xFF, 1, out_tlv),
25462306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Digital Playback Volume4", LOUT4, ROUT4,
25562306a36Sopenharmony_ci			 0, 0xFF, 1, out_tlv),
25662306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Digital Playback Volume5", LOUT5, ROUT5,
25762306a36Sopenharmony_ci			 0, 0xFF, 1, out_tlv),
25862306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Digital Playback Volume6", LOUT6, ROUT6,
25962306a36Sopenharmony_ci			 0, 0xFF, 1, out_tlv),
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic const struct reg_default ak4613_reg[] = {
26362306a36Sopenharmony_ci	{ 0x0,  0x0f }, { 0x1,  0x07 }, { 0x2,  0x3f }, { 0x3,  0x20 },
26462306a36Sopenharmony_ci	{ 0x4,  0x20 }, { 0x5,  0x55 }, { 0x6,  0x05 }, { 0x7,  0x07 },
26562306a36Sopenharmony_ci	{ 0x8,  0x0f }, { 0x9,  0x07 }, { 0xa,  0x3f }, { 0xb,  0x00 },
26662306a36Sopenharmony_ci	{ 0xc,  0x00 }, { 0xd,  0x00 }, { 0xe,  0x00 }, { 0xf,  0x00 },
26762306a36Sopenharmony_ci	{ 0x10, 0x00 }, { 0x11, 0x00 }, { 0x12, 0x00 }, { 0x13, 0x00 },
26862306a36Sopenharmony_ci	{ 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 },
26962306a36Sopenharmony_ci};
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/*
27262306a36Sopenharmony_ci * CTRL1 register
27362306a36Sopenharmony_ci * see
27462306a36Sopenharmony_ci *	Table 11/12/13/14
27562306a36Sopenharmony_ci */
27662306a36Sopenharmony_ci#define AUDIO_IFACE(_dif, _width, _fmt)		\
27762306a36Sopenharmony_ci	{					\
27862306a36Sopenharmony_ci		.dif	= _dif,			\
27962306a36Sopenharmony_ci		.width	= _width,		\
28062306a36Sopenharmony_ci		.fmt	= SND_SOC_DAIFMT_##_fmt,\
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_cistatic const struct ak4613_interface ak4613_iface[] = {
28362306a36Sopenharmony_ci	/* It doesn't support asymmetric format */
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	AUDIO_IFACE(0x03, 24, LEFT_J),
28662306a36Sopenharmony_ci	AUDIO_IFACE(0x04, 24, I2S),
28762306a36Sopenharmony_ci};
28862306a36Sopenharmony_ci#define AK4613_CTRL1_TO_MODE(priv)	((priv)->ctrl1 >> 6) /* AK4613_CONFIG_MODE_x */
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic const struct regmap_config ak4613_regmap_cfg = {
29162306a36Sopenharmony_ci	.reg_bits		= 8,
29262306a36Sopenharmony_ci	.val_bits		= 8,
29362306a36Sopenharmony_ci	.max_register		= 0x16,
29462306a36Sopenharmony_ci	.reg_defaults		= ak4613_reg,
29562306a36Sopenharmony_ci	.num_reg_defaults	= ARRAY_SIZE(ak4613_reg),
29662306a36Sopenharmony_ci	.cache_type		= REGCACHE_RBTREE,
29762306a36Sopenharmony_ci};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic const struct of_device_id ak4613_of_match[] = {
30062306a36Sopenharmony_ci	{ .compatible = "asahi-kasei,ak4613",	.data = &ak4613_regmap_cfg },
30162306a36Sopenharmony_ci	{},
30262306a36Sopenharmony_ci};
30362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ak4613_of_match);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic const struct i2c_device_id ak4613_i2c_id[] = {
30662306a36Sopenharmony_ci	{ "ak4613", (kernel_ulong_t)&ak4613_regmap_cfg },
30762306a36Sopenharmony_ci	{ }
30862306a36Sopenharmony_ci};
30962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ak4613_i2c_id);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget ak4613_dapm_widgets[] = {
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* Outputs */
31462306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LOUT1"),
31562306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LOUT2"),
31662306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LOUT3"),
31762306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LOUT4"),
31862306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LOUT5"),
31962306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LOUT6"),
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("ROUT1"),
32262306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("ROUT2"),
32362306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("ROUT3"),
32462306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("ROUT4"),
32562306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("ROUT5"),
32662306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("ROUT6"),
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/* Inputs */
32962306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("LIN1"),
33062306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("LIN2"),
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("RIN1"),
33362306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("RIN2"),
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* DAC */
33662306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC1", NULL, PW_MGMT3, 0, 0),
33762306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC2", NULL, PW_MGMT3, 1, 0),
33862306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC3", NULL, PW_MGMT3, 2, 0),
33962306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC4", NULL, PW_MGMT3, 3, 0),
34062306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC5", NULL, PW_MGMT3, 4, 0),
34162306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC6", NULL, PW_MGMT3, 5, 0),
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/* ADC */
34462306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC1", NULL, PW_MGMT2, 0, 0),
34562306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC2", NULL, PW_MGMT2, 1, 0),
34662306a36Sopenharmony_ci};
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic const struct snd_soc_dapm_route ak4613_intercon[] = {
34962306a36Sopenharmony_ci	{"LOUT1", NULL, "DAC1"},
35062306a36Sopenharmony_ci	{"LOUT2", NULL, "DAC2"},
35162306a36Sopenharmony_ci	{"LOUT3", NULL, "DAC3"},
35262306a36Sopenharmony_ci	{"LOUT4", NULL, "DAC4"},
35362306a36Sopenharmony_ci	{"LOUT5", NULL, "DAC5"},
35462306a36Sopenharmony_ci	{"LOUT6", NULL, "DAC6"},
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	{"ROUT1", NULL, "DAC1"},
35762306a36Sopenharmony_ci	{"ROUT2", NULL, "DAC2"},
35862306a36Sopenharmony_ci	{"ROUT3", NULL, "DAC3"},
35962306a36Sopenharmony_ci	{"ROUT4", NULL, "DAC4"},
36062306a36Sopenharmony_ci	{"ROUT5", NULL, "DAC5"},
36162306a36Sopenharmony_ci	{"ROUT6", NULL, "DAC6"},
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	{"DAC1", NULL, "Playback"},
36462306a36Sopenharmony_ci	{"DAC2", NULL, "Playback"},
36562306a36Sopenharmony_ci	{"DAC3", NULL, "Playback"},
36662306a36Sopenharmony_ci	{"DAC4", NULL, "Playback"},
36762306a36Sopenharmony_ci	{"DAC5", NULL, "Playback"},
36862306a36Sopenharmony_ci	{"DAC6", NULL, "Playback"},
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	{"Capture", NULL, "ADC1"},
37162306a36Sopenharmony_ci	{"Capture", NULL, "ADC2"},
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	{"ADC1", NULL, "LIN1"},
37462306a36Sopenharmony_ci	{"ADC2", NULL, "LIN2"},
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	{"ADC1", NULL, "RIN1"},
37762306a36Sopenharmony_ci	{"ADC2", NULL, "RIN2"},
37862306a36Sopenharmony_ci};
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
38162306a36Sopenharmony_ci			       struct snd_soc_dai *dai)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
38462306a36Sopenharmony_ci	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
38562306a36Sopenharmony_ci	struct device *dev = component->dev;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	mutex_lock(&priv->lock);
38862306a36Sopenharmony_ci	priv->cnt--;
38962306a36Sopenharmony_ci	if (priv->cnt < 0) {
39062306a36Sopenharmony_ci		dev_err(dev, "unexpected counter error\n");
39162306a36Sopenharmony_ci		priv->cnt = 0;
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci	if (!priv->cnt)
39462306a36Sopenharmony_ci		priv->ctrl1 = 0;
39562306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic void ak4613_hw_constraints(struct ak4613_priv *priv,
39962306a36Sopenharmony_ci				  struct snd_pcm_substream *substream)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
40262306a36Sopenharmony_ci	static const unsigned int ak4613_rates[] = {
40362306a36Sopenharmony_ci		 32000,
40462306a36Sopenharmony_ci		 44100,
40562306a36Sopenharmony_ci		 48000,
40662306a36Sopenharmony_ci		 64000,
40762306a36Sopenharmony_ci		 88200,
40862306a36Sopenharmony_ci		 96000,
40962306a36Sopenharmony_ci		176400,
41062306a36Sopenharmony_ci		192000,
41162306a36Sopenharmony_ci	};
41262306a36Sopenharmony_ci#define AK4613_CHANNEL_2	 0
41362306a36Sopenharmony_ci#define AK4613_CHANNEL_4	 1
41462306a36Sopenharmony_ci#define AK4613_CHANNEL_8	 2
41562306a36Sopenharmony_ci#define AK4613_CHANNEL_12	 3
41662306a36Sopenharmony_ci#define AK4613_CHANNEL_NONE	-1
41762306a36Sopenharmony_ci	static const unsigned int ak4613_channels[] = {
41862306a36Sopenharmony_ci		[AK4613_CHANNEL_2]  =  2,
41962306a36Sopenharmony_ci		[AK4613_CHANNEL_4]  =  4,
42062306a36Sopenharmony_ci		[AK4613_CHANNEL_8]  =  8,
42162306a36Sopenharmony_ci		[AK4613_CHANNEL_12] = 12,
42262306a36Sopenharmony_ci	};
42362306a36Sopenharmony_ci#define MODE_MAX 4
42462306a36Sopenharmony_ci#define SDTx_MAX 4
42562306a36Sopenharmony_ci#define MASK(x) (1 << AK4613_CHANNEL_##x)
42662306a36Sopenharmony_ci	static const int mask_list[MODE_MAX][SDTx_MAX] = {
42762306a36Sopenharmony_ci		/* 				SDTO	 SDTIx1    SDTIx2		SDTIx3 */
42862306a36Sopenharmony_ci		[AK4613_CONFIG_MODE_STEREO] = { MASK(2), MASK(2),  MASK(2),		MASK(2)},
42962306a36Sopenharmony_ci		[AK4613_CONFIG_MODE_TDM512] = { MASK(4), MASK(12), MASK(12),		MASK(12)},
43062306a36Sopenharmony_ci		[AK4613_CONFIG_MODE_TDM256] = { MASK(4), MASK(8),  MASK(8)|MASK(12),	MASK(8)|MASK(12)},
43162306a36Sopenharmony_ci		[AK4613_CONFIG_MODE_TDM128] = { MASK(4), MASK(4),  MASK(4)|MASK(8),	MASK(4)|MASK(8)|MASK(12)},
43262306a36Sopenharmony_ci	};
43362306a36Sopenharmony_ci	struct snd_pcm_hw_constraint_list *constraint;
43462306a36Sopenharmony_ci	unsigned int mask;
43562306a36Sopenharmony_ci	unsigned int mode;
43662306a36Sopenharmony_ci	unsigned int fs;
43762306a36Sopenharmony_ci	int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
43862306a36Sopenharmony_ci	int sdti_num;
43962306a36Sopenharmony_ci	int i;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	constraint		= &priv->constraint_rates;
44262306a36Sopenharmony_ci	constraint->list	= ak4613_rates;
44362306a36Sopenharmony_ci	constraint->mask	= 0;
44462306a36Sopenharmony_ci	constraint->count	= 0;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/*
44762306a36Sopenharmony_ci	 * Slave Mode
44862306a36Sopenharmony_ci	 *	Normal: [32kHz, 48kHz] : 256fs,384fs or 512fs
44962306a36Sopenharmony_ci	 *	Double: [64kHz, 96kHz] : 256fs
45062306a36Sopenharmony_ci	 *	Quad  : [128kHz,192kHz]: 128fs
45162306a36Sopenharmony_ci	 *
45262306a36Sopenharmony_ci	 * Master mode
45362306a36Sopenharmony_ci	 *	Normal: [32kHz, 48kHz] : 256fs or 512fs
45462306a36Sopenharmony_ci	 *	Double: [64kHz, 96kHz] : 256fs
45562306a36Sopenharmony_ci	 *	Quad  : [128kHz,192kHz]: 128fs
45662306a36Sopenharmony_ci	*/
45762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ak4613_rates); i++) {
45862306a36Sopenharmony_ci		/* minimum fs on each range */
45962306a36Sopenharmony_ci		fs = (ak4613_rates[i] <= 96000) ? 256 : 128;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		if (priv->sysclk >= ak4613_rates[i] * fs)
46262306a36Sopenharmony_ci			constraint->count = i + 1;
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	snd_pcm_hw_constraint_list(runtime, 0,
46662306a36Sopenharmony_ci				SNDRV_PCM_HW_PARAM_RATE, constraint);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	sdti_num = AK4613_CONFIG_SDTI_get(priv);
47062306a36Sopenharmony_ci	if (WARN_ON(sdti_num >= SDTx_MAX))
47162306a36Sopenharmony_ci		return;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (priv->cnt) {
47462306a36Sopenharmony_ci		/*
47562306a36Sopenharmony_ci		 * If it was already working,
47662306a36Sopenharmony_ci		 * the constraint is same as working mode.
47762306a36Sopenharmony_ci		 */
47862306a36Sopenharmony_ci		mode = AK4613_CTRL1_TO_MODE(priv);
47962306a36Sopenharmony_ci		mask = 0; /* no default */
48062306a36Sopenharmony_ci	} else {
48162306a36Sopenharmony_ci		/*
48262306a36Sopenharmony_ci		 * It is not yet working,
48362306a36Sopenharmony_ci		 * the constraint is based on board configs.
48462306a36Sopenharmony_ci		 * STEREO mask is default
48562306a36Sopenharmony_ci		 */
48662306a36Sopenharmony_ci		mode = AK4613_CONFIG_GET(priv, MODE);
48762306a36Sopenharmony_ci		mask = mask_list[AK4613_CONFIG_MODE_STEREO][is_play * sdti_num];
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (WARN_ON(mode >= MODE_MAX))
49162306a36Sopenharmony_ci		return;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	/* add each mode mask */
49462306a36Sopenharmony_ci	mask |= mask_list[mode][is_play * sdti_num];
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	constraint		= &priv->constraint_channels;
49762306a36Sopenharmony_ci	constraint->list	= ak4613_channels;
49862306a36Sopenharmony_ci	constraint->mask	= mask;
49962306a36Sopenharmony_ci	constraint->count	= sizeof(ak4613_channels);
50062306a36Sopenharmony_ci	snd_pcm_hw_constraint_list(runtime, 0,
50162306a36Sopenharmony_ci				   SNDRV_PCM_HW_PARAM_CHANNELS, constraint);
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic int ak4613_dai_startup(struct snd_pcm_substream *substream,
50562306a36Sopenharmony_ci			      struct snd_soc_dai *dai)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
50862306a36Sopenharmony_ci	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	mutex_lock(&priv->lock);
51162306a36Sopenharmony_ci	ak4613_hw_constraints(priv, substream);
51262306a36Sopenharmony_ci	priv->cnt++;
51362306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	return 0;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic int ak4613_dai_set_sysclk(struct snd_soc_dai *codec_dai,
51962306a36Sopenharmony_ci				 int clk_id, unsigned int freq, int dir)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	struct snd_soc_component *component = codec_dai->component;
52262306a36Sopenharmony_ci	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	priv->sysclk = freq;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	return 0;
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int format)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
53262306a36Sopenharmony_ci	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
53362306a36Sopenharmony_ci	unsigned int fmt;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	fmt = format & SND_SOC_DAIFMT_FORMAT_MASK;
53662306a36Sopenharmony_ci	switch (fmt) {
53762306a36Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
53862306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
53962306a36Sopenharmony_ci		priv->fmt = fmt;
54062306a36Sopenharmony_ci		break;
54162306a36Sopenharmony_ci	default:
54262306a36Sopenharmony_ci		return -EINVAL;
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	fmt = format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
54662306a36Sopenharmony_ci	switch (fmt) {
54762306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBC_CFC:
54862306a36Sopenharmony_ci		break;
54962306a36Sopenharmony_ci	default:
55062306a36Sopenharmony_ci		/*
55162306a36Sopenharmony_ci		 * SUPPORTME
55262306a36Sopenharmony_ci		 *
55362306a36Sopenharmony_ci		 * "clock provider" is not yet supperted
55462306a36Sopenharmony_ci		 */
55562306a36Sopenharmony_ci		return -EINVAL;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	return 0;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
56262306a36Sopenharmony_ci				struct snd_pcm_hw_params *params,
56362306a36Sopenharmony_ci				struct snd_soc_dai *dai)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
56662306a36Sopenharmony_ci	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
56762306a36Sopenharmony_ci	struct device *dev = component->dev;
56862306a36Sopenharmony_ci	unsigned int width = params_width(params);
56962306a36Sopenharmony_ci	unsigned int fmt = priv->fmt;
57062306a36Sopenharmony_ci	unsigned int rate;
57162306a36Sopenharmony_ci	int i, ret;
57262306a36Sopenharmony_ci	u8 ctrl2;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	rate = params_rate(params);
57562306a36Sopenharmony_ci	switch (rate) {
57662306a36Sopenharmony_ci	case 32000:
57762306a36Sopenharmony_ci	case 44100:
57862306a36Sopenharmony_ci	case 48000:
57962306a36Sopenharmony_ci		ctrl2 = DFS_NORMAL_SPEED;
58062306a36Sopenharmony_ci		break;
58162306a36Sopenharmony_ci	case 64000:
58262306a36Sopenharmony_ci	case 88200:
58362306a36Sopenharmony_ci	case 96000:
58462306a36Sopenharmony_ci		ctrl2 = DFS_DOUBLE_SPEED;
58562306a36Sopenharmony_ci		break;
58662306a36Sopenharmony_ci	case 176400:
58762306a36Sopenharmony_ci	case 192000:
58862306a36Sopenharmony_ci		ctrl2 = DFS_QUAD_SPEED;
58962306a36Sopenharmony_ci		break;
59062306a36Sopenharmony_ci	default:
59162306a36Sopenharmony_ci		return -EINVAL;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci	priv->rate = rate;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/*
59662306a36Sopenharmony_ci	 * FIXME
59762306a36Sopenharmony_ci	 *
59862306a36Sopenharmony_ci	 * It doesn't have full TDM suppert yet
59962306a36Sopenharmony_ci	 */
60062306a36Sopenharmony_ci	ret = -EINVAL;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	mutex_lock(&priv->lock);
60362306a36Sopenharmony_ci	if (priv->cnt > 1) {
60462306a36Sopenharmony_ci		/*
60562306a36Sopenharmony_ci		 * If it was already working, use current priv->ctrl1
60662306a36Sopenharmony_ci		 */
60762306a36Sopenharmony_ci		ret = 0;
60862306a36Sopenharmony_ci	} else {
60962306a36Sopenharmony_ci		/*
61062306a36Sopenharmony_ci		 * It is not yet working,
61162306a36Sopenharmony_ci		 */
61262306a36Sopenharmony_ci		unsigned int channel = params_channels(params);
61362306a36Sopenharmony_ci		u8 tdm;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		/* STEREO or TDM */
61662306a36Sopenharmony_ci		if (channel == 2)
61762306a36Sopenharmony_ci			tdm = AK4613_CONFIG_MODE_STEREO;
61862306a36Sopenharmony_ci		else
61962306a36Sopenharmony_ci			tdm = AK4613_CONFIG_GET(priv, MODE);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) {
62262306a36Sopenharmony_ci			const struct ak4613_interface *iface = ak4613_iface + i;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci			if ((iface->fmt == fmt) && (iface->width == width)) {
62562306a36Sopenharmony_ci				/*
62662306a36Sopenharmony_ci				 * Ctrl1
62762306a36Sopenharmony_ci				 * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0  |
62862306a36Sopenharmony_ci				 * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE|
62962306a36Sopenharmony_ci				 *  <  tdm  > < iface->dif >
63062306a36Sopenharmony_ci				 */
63162306a36Sopenharmony_ci				priv->ctrl1 = (tdm << 6) | (iface->dif << 3);
63262306a36Sopenharmony_ci				ret = 0;
63362306a36Sopenharmony_ci				break;
63462306a36Sopenharmony_ci			}
63562306a36Sopenharmony_ci		}
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	if (ret < 0)
64062306a36Sopenharmony_ci		goto hw_params_end;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	snd_soc_component_update_bits(component, CTRL1, FMT_MASK, priv->ctrl1);
64362306a36Sopenharmony_ci	snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic);
64662306a36Sopenharmony_ci	snd_soc_component_update_bits(component, OCTRL, OCTRL_MASK, priv->oc);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cihw_params_end:
64962306a36Sopenharmony_ci	if (ret < 0)
65062306a36Sopenharmony_ci		dev_warn(dev, "unsupported data width/format combination\n");
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	return ret;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic int ak4613_set_bias_level(struct snd_soc_component *component,
65662306a36Sopenharmony_ci				 enum snd_soc_bias_level level)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	u8 mgmt1 = 0;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	switch (level) {
66162306a36Sopenharmony_ci	case SND_SOC_BIAS_ON:
66262306a36Sopenharmony_ci		mgmt1 |= RSTN;
66362306a36Sopenharmony_ci		fallthrough;
66462306a36Sopenharmony_ci	case SND_SOC_BIAS_PREPARE:
66562306a36Sopenharmony_ci		mgmt1 |= PMADC | PMDAC;
66662306a36Sopenharmony_ci		fallthrough;
66762306a36Sopenharmony_ci	case SND_SOC_BIAS_STANDBY:
66862306a36Sopenharmony_ci		mgmt1 |= PMVR;
66962306a36Sopenharmony_ci		fallthrough;
67062306a36Sopenharmony_ci	case SND_SOC_BIAS_OFF:
67162306a36Sopenharmony_ci	default:
67262306a36Sopenharmony_ci		break;
67362306a36Sopenharmony_ci	}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	snd_soc_component_write(component, PW_MGMT1, mgmt1);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	return 0;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic void ak4613_dummy_write(struct work_struct *work)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	struct ak4613_priv *priv = container_of(work,
68362306a36Sopenharmony_ci						struct ak4613_priv,
68462306a36Sopenharmony_ci						dummy_write_work);
68562306a36Sopenharmony_ci	struct snd_soc_component *component = priv->component;
68662306a36Sopenharmony_ci	unsigned int mgmt1;
68762306a36Sopenharmony_ci	unsigned int mgmt3;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	/*
69062306a36Sopenharmony_ci	 * PW_MGMT1 / PW_MGMT3 needs dummy write at least after 5 LR clocks
69162306a36Sopenharmony_ci	 *
69262306a36Sopenharmony_ci	 * Note
69362306a36Sopenharmony_ci	 *
69462306a36Sopenharmony_ci	 * To avoid extra delay, we want to avoid preemption here,
69562306a36Sopenharmony_ci	 * but we can't. Because it uses I2C access which is using IRQ
69662306a36Sopenharmony_ci	 * and sleep. Thus, delay might be more than 5 LR clocks
69762306a36Sopenharmony_ci	 * see also
69862306a36Sopenharmony_ci	 *	ak4613_dai_trigger()
69962306a36Sopenharmony_ci	 */
70062306a36Sopenharmony_ci	udelay(5000000 / priv->rate);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	mgmt1 = snd_soc_component_read(component, PW_MGMT1);
70362306a36Sopenharmony_ci	mgmt3 = snd_soc_component_read(component, PW_MGMT3);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	snd_soc_component_write(component, PW_MGMT1, mgmt1);
70662306a36Sopenharmony_ci	snd_soc_component_write(component, PW_MGMT3, mgmt3);
70762306a36Sopenharmony_ci}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_cistatic int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd,
71062306a36Sopenharmony_ci			      struct snd_soc_dai *dai)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
71362306a36Sopenharmony_ci	struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/*
71662306a36Sopenharmony_ci	 * FIXME
71762306a36Sopenharmony_ci	 *
71862306a36Sopenharmony_ci	 * PW_MGMT1 / PW_MGMT3 needs dummy write at least after 5 LR clocks
71962306a36Sopenharmony_ci	 * from Power Down Release. Otherwise, Playback volume will be 0dB.
72062306a36Sopenharmony_ci	 * To avoid complex multiple delay/dummy_write method from
72162306a36Sopenharmony_ci	 * ak4613_set_bias_level() / SND_SOC_DAPM_DAC_E("DACx", ...),
72262306a36Sopenharmony_ci	 * call it once here.
72362306a36Sopenharmony_ci	 *
72462306a36Sopenharmony_ci	 * But, unfortunately, we can't "write" here because here is atomic
72562306a36Sopenharmony_ci	 * context (It uses I2C access for writing).
72662306a36Sopenharmony_ci	 * Thus, use schedule_work() to switching to normal context
72762306a36Sopenharmony_ci	 * immediately.
72862306a36Sopenharmony_ci	 *
72962306a36Sopenharmony_ci	 * Note
73062306a36Sopenharmony_ci	 *
73162306a36Sopenharmony_ci	 * Calling ak4613_dummy_write() function might be delayed.
73262306a36Sopenharmony_ci	 * In such case, ak4613 volume might be temporarily 0dB when
73362306a36Sopenharmony_ci	 * beggining of playback.
73462306a36Sopenharmony_ci	 * see also
73562306a36Sopenharmony_ci	 *	ak4613_dummy_write()
73662306a36Sopenharmony_ci	 */
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if ((cmd != SNDRV_PCM_TRIGGER_START) &&
73962306a36Sopenharmony_ci	    (cmd != SNDRV_PCM_TRIGGER_RESUME))
74062306a36Sopenharmony_ci		return 0;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
74362306a36Sopenharmony_ci		return  0;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	priv->component = component;
74662306a36Sopenharmony_ci	schedule_work(&priv->dummy_write_work);
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	return 0;
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci/*
75262306a36Sopenharmony_ci * Select below from Sound Card, not Auto
75362306a36Sopenharmony_ci *	SND_SOC_DAIFMT_CBC_CFC
75462306a36Sopenharmony_ci *	SND_SOC_DAIFMT_CBP_CFP
75562306a36Sopenharmony_ci */
75662306a36Sopenharmony_cistatic u64 ak4613_dai_formats =
75762306a36Sopenharmony_ci	SND_SOC_POSSIBLE_DAIFMT_I2S	|
75862306a36Sopenharmony_ci	SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic const struct snd_soc_dai_ops ak4613_dai_ops = {
76162306a36Sopenharmony_ci	.startup	= ak4613_dai_startup,
76262306a36Sopenharmony_ci	.shutdown	= ak4613_dai_shutdown,
76362306a36Sopenharmony_ci	.set_sysclk	= ak4613_dai_set_sysclk,
76462306a36Sopenharmony_ci	.set_fmt	= ak4613_dai_set_fmt,
76562306a36Sopenharmony_ci	.trigger	= ak4613_dai_trigger,
76662306a36Sopenharmony_ci	.hw_params	= ak4613_dai_hw_params,
76762306a36Sopenharmony_ci	.auto_selectable_formats	= &ak4613_dai_formats,
76862306a36Sopenharmony_ci	.num_auto_selectable_formats	= 1,
76962306a36Sopenharmony_ci};
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci#define AK4613_PCM_RATE		(SNDRV_PCM_RATE_32000  |\
77262306a36Sopenharmony_ci				 SNDRV_PCM_RATE_44100  |\
77362306a36Sopenharmony_ci				 SNDRV_PCM_RATE_48000  |\
77462306a36Sopenharmony_ci				 SNDRV_PCM_RATE_64000  |\
77562306a36Sopenharmony_ci				 SNDRV_PCM_RATE_88200  |\
77662306a36Sopenharmony_ci				 SNDRV_PCM_RATE_96000  |\
77762306a36Sopenharmony_ci				 SNDRV_PCM_RATE_176400 |\
77862306a36Sopenharmony_ci				 SNDRV_PCM_RATE_192000)
77962306a36Sopenharmony_ci#define AK4613_PCM_FMTBIT	(SNDRV_PCM_FMTBIT_S24_LE)
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic struct snd_soc_dai_driver ak4613_dai = {
78262306a36Sopenharmony_ci	.name = "ak4613-hifi",
78362306a36Sopenharmony_ci	.playback = {
78462306a36Sopenharmony_ci		.stream_name	= "Playback",
78562306a36Sopenharmony_ci		.channels_min	= 2,
78662306a36Sopenharmony_ci		.channels_max	= 12,
78762306a36Sopenharmony_ci		.rates		= AK4613_PCM_RATE,
78862306a36Sopenharmony_ci		.formats	= AK4613_PCM_FMTBIT,
78962306a36Sopenharmony_ci	},
79062306a36Sopenharmony_ci	.capture = {
79162306a36Sopenharmony_ci		.stream_name	= "Capture",
79262306a36Sopenharmony_ci		.channels_min	= 2,
79362306a36Sopenharmony_ci		.channels_max	= 4,
79462306a36Sopenharmony_ci		.rates		= AK4613_PCM_RATE,
79562306a36Sopenharmony_ci		.formats	= AK4613_PCM_FMTBIT,
79662306a36Sopenharmony_ci	},
79762306a36Sopenharmony_ci	.ops = &ak4613_dai_ops,
79862306a36Sopenharmony_ci	.symmetric_rate = 1,
79962306a36Sopenharmony_ci};
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistatic int ak4613_suspend(struct snd_soc_component *component)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	regcache_cache_only(regmap, true);
80662306a36Sopenharmony_ci	regcache_mark_dirty(regmap);
80762306a36Sopenharmony_ci	return 0;
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_cistatic int ak4613_resume(struct snd_soc_component *component)
81162306a36Sopenharmony_ci{
81262306a36Sopenharmony_ci	struct regmap *regmap = dev_get_regmap(component->dev, NULL);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	regcache_cache_only(regmap, false);
81562306a36Sopenharmony_ci	return regcache_sync(regmap);
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_ak4613 = {
81962306a36Sopenharmony_ci	.suspend		= ak4613_suspend,
82062306a36Sopenharmony_ci	.resume			= ak4613_resume,
82162306a36Sopenharmony_ci	.set_bias_level		= ak4613_set_bias_level,
82262306a36Sopenharmony_ci	.controls		= ak4613_snd_controls,
82362306a36Sopenharmony_ci	.num_controls		= ARRAY_SIZE(ak4613_snd_controls),
82462306a36Sopenharmony_ci	.dapm_widgets		= ak4613_dapm_widgets,
82562306a36Sopenharmony_ci	.num_dapm_widgets	= ARRAY_SIZE(ak4613_dapm_widgets),
82662306a36Sopenharmony_ci	.dapm_routes		= ak4613_intercon,
82762306a36Sopenharmony_ci	.num_dapm_routes	= ARRAY_SIZE(ak4613_intercon),
82862306a36Sopenharmony_ci	.idle_bias_on		= 1,
82962306a36Sopenharmony_ci	.endianness		= 1,
83062306a36Sopenharmony_ci};
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cistatic void ak4613_parse_of(struct ak4613_priv *priv,
83362306a36Sopenharmony_ci			    struct device *dev)
83462306a36Sopenharmony_ci{
83562306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
83662306a36Sopenharmony_ci	char prop[32];
83762306a36Sopenharmony_ci	int sdti_num;
83862306a36Sopenharmony_ci	int i;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	/* Input 1 - 2 */
84162306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
84262306a36Sopenharmony_ci		snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1);
84362306a36Sopenharmony_ci		if (!of_get_property(np, prop, NULL))
84462306a36Sopenharmony_ci			priv->ic |= 1 << i;
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	/* Output 1 - 6 */
84862306a36Sopenharmony_ci	for (i = 0; i < 6; i++) {
84962306a36Sopenharmony_ci		snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1);
85062306a36Sopenharmony_ci		if (!of_get_property(np, prop, NULL))
85162306a36Sopenharmony_ci			priv->oc |= 1 << i;
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	/*
85562306a36Sopenharmony_ci	 * enable TDM256 test
85662306a36Sopenharmony_ci	 *
85762306a36Sopenharmony_ci	 * !!! FIXME !!!
85862306a36Sopenharmony_ci	 *
85962306a36Sopenharmony_ci	 * It should be configured by DT or other way
86062306a36Sopenharmony_ci	 * if it was full supported.
86162306a36Sopenharmony_ci	 * But it is using ifdef style for now for test
86262306a36Sopenharmony_ci	 * purpose.
86362306a36Sopenharmony_ci	 */
86462306a36Sopenharmony_ci#if defined(AK4613_ENABLE_TDM_TEST)
86562306a36Sopenharmony_ci	AK4613_CONFIG_SET(priv, MODE_TDM256);
86662306a36Sopenharmony_ci#endif
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	/*
86962306a36Sopenharmony_ci	 * connected STDI
87062306a36Sopenharmony_ci	 * TDM support is assuming it is probed via Audio-Graph-Card style here.
87162306a36Sopenharmony_ci	 * Default is SDTIx1 if it was probed via Simple-Audio-Card for now.
87262306a36Sopenharmony_ci	 */
87362306a36Sopenharmony_ci	sdti_num = of_graph_get_endpoint_count(np);
87462306a36Sopenharmony_ci	if ((sdti_num >= SDTx_MAX) || (sdti_num < 1))
87562306a36Sopenharmony_ci		sdti_num = 1;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	AK4613_CONFIG_SDTI_set(priv, sdti_num);
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic int ak4613_i2c_probe(struct i2c_client *i2c)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	struct device *dev = &i2c->dev;
88362306a36Sopenharmony_ci	const struct regmap_config *regmap_cfg;
88462306a36Sopenharmony_ci	struct regmap *regmap;
88562306a36Sopenharmony_ci	struct ak4613_priv *priv;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	regmap_cfg = i2c_get_match_data(i2c);
88862306a36Sopenharmony_ci	if (!regmap_cfg)
88962306a36Sopenharmony_ci		return -EINVAL;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
89262306a36Sopenharmony_ci	if (!priv)
89362306a36Sopenharmony_ci		return -ENOMEM;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	ak4613_parse_of(priv, dev);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	priv->ctrl1		= 0;
89862306a36Sopenharmony_ci	priv->cnt		= 0;
89962306a36Sopenharmony_ci	priv->sysclk		= 0;
90062306a36Sopenharmony_ci	INIT_WORK(&priv->dummy_write_work, ak4613_dummy_write);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	mutex_init(&priv->lock);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	i2c_set_clientdata(i2c, priv);
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	regmap = devm_regmap_init_i2c(i2c, regmap_cfg);
90762306a36Sopenharmony_ci	if (IS_ERR(regmap))
90862306a36Sopenharmony_ci		return PTR_ERR(regmap);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	return devm_snd_soc_register_component(dev, &soc_component_dev_ak4613,
91162306a36Sopenharmony_ci				      &ak4613_dai, 1);
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic struct i2c_driver ak4613_i2c_driver = {
91562306a36Sopenharmony_ci	.driver = {
91662306a36Sopenharmony_ci		.name = "ak4613-codec",
91762306a36Sopenharmony_ci		.of_match_table = ak4613_of_match,
91862306a36Sopenharmony_ci	},
91962306a36Sopenharmony_ci	.probe		= ak4613_i2c_probe,
92062306a36Sopenharmony_ci	.id_table	= ak4613_i2c_id,
92162306a36Sopenharmony_ci};
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_cimodule_i2c_driver(ak4613_i2c_driver);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ciMODULE_DESCRIPTION("Soc AK4613 driver");
92662306a36Sopenharmony_ciMODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
92762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
928