162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PCM3168A codec driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2015 Imagination Technologies Ltd.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Damien Horsley <Damien.Horsley@imgtec.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/of_gpio.h>
1562306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1662306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <sound/pcm_params.h>
1962306a36Sopenharmony_ci#include <sound/soc.h>
2062306a36Sopenharmony_ci#include <sound/tlv.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "pcm3168a.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define PCM3168A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
2562306a36Sopenharmony_ci			 SNDRV_PCM_FMTBIT_S24_3LE | \
2662306a36Sopenharmony_ci			 SNDRV_PCM_FMTBIT_S24_LE)
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define PCM3168A_FMT_I2S		0x0
2962306a36Sopenharmony_ci#define PCM3168A_FMT_LEFT_J		0x1
3062306a36Sopenharmony_ci#define PCM3168A_FMT_RIGHT_J		0x2
3162306a36Sopenharmony_ci#define PCM3168A_FMT_RIGHT_J_16		0x3
3262306a36Sopenharmony_ci#define PCM3168A_FMT_DSP_A		0x4
3362306a36Sopenharmony_ci#define PCM3168A_FMT_DSP_B		0x5
3462306a36Sopenharmony_ci#define PCM3168A_FMT_I2S_TDM		0x6
3562306a36Sopenharmony_ci#define PCM3168A_FMT_LEFT_J_TDM		0x7
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic const char *const pcm3168a_supply_names[] = {
3862306a36Sopenharmony_ci	"VDD1",
3962306a36Sopenharmony_ci	"VDD2",
4062306a36Sopenharmony_ci	"VCCAD1",
4162306a36Sopenharmony_ci	"VCCAD2",
4262306a36Sopenharmony_ci	"VCCDA1",
4362306a36Sopenharmony_ci	"VCCDA2"
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define PCM3168A_DAI_DAC		0
4762306a36Sopenharmony_ci#define PCM3168A_DAI_ADC		1
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* ADC/DAC side parameters */
5062306a36Sopenharmony_cistruct pcm3168a_io_params {
5162306a36Sopenharmony_ci	bool provider_mode;
5262306a36Sopenharmony_ci	unsigned int format;
5362306a36Sopenharmony_ci	int tdm_slots;
5462306a36Sopenharmony_ci	u32 tdm_mask;
5562306a36Sopenharmony_ci	int slot_width;
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistruct pcm3168a_priv {
5962306a36Sopenharmony_ci	struct regulator_bulk_data supplies[ARRAY_SIZE(pcm3168a_supply_names)];
6062306a36Sopenharmony_ci	struct regmap *regmap;
6162306a36Sopenharmony_ci	struct clk *scki;
6262306a36Sopenharmony_ci	struct gpio_desc *gpio_rst;
6362306a36Sopenharmony_ci	unsigned long sysclk;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	struct pcm3168a_io_params io_params[2];
6662306a36Sopenharmony_ci	struct snd_soc_dai_driver dai_drv[2];
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_d1_roll_off, PCM3168A_DAC_OP_FLT,
7262306a36Sopenharmony_ci		PCM3168A_DAC_FLT_SHIFT, pcm3168a_roll_off);
7362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_d2_roll_off, PCM3168A_DAC_OP_FLT,
7462306a36Sopenharmony_ci		PCM3168A_DAC_FLT_SHIFT + 1, pcm3168a_roll_off);
7562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_d3_roll_off, PCM3168A_DAC_OP_FLT,
7662306a36Sopenharmony_ci		PCM3168A_DAC_FLT_SHIFT + 2, pcm3168a_roll_off);
7762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_d4_roll_off, PCM3168A_DAC_OP_FLT,
7862306a36Sopenharmony_ci		PCM3168A_DAC_FLT_SHIFT + 3, pcm3168a_roll_off);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic const char *const pcm3168a_volume_type[] = {
8162306a36Sopenharmony_ci		"Individual", "Master + Individual" };
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_dac_volume_type, PCM3168A_DAC_ATT_DEMP_ZF,
8462306a36Sopenharmony_ci		PCM3168A_DAC_ATMDDA_SHIFT, pcm3168a_volume_type);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic const char *const pcm3168a_att_speed_mult[] = { "2048", "4096" };
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_dac_att_mult, PCM3168A_DAC_ATT_DEMP_ZF,
8962306a36Sopenharmony_ci		PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_att_speed_mult);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic const char *const pcm3168a_demp[] = {
9262306a36Sopenharmony_ci		"Disabled", "48khz", "44.1khz", "32khz" };
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_dac_demp, PCM3168A_DAC_ATT_DEMP_ZF,
9562306a36Sopenharmony_ci		PCM3168A_DAC_DEMP_SHIFT, pcm3168a_demp);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic const char *const pcm3168a_zf_func[] = {
9862306a36Sopenharmony_ci		"DAC 1/2/3/4 AND", "DAC 1/2/3/4 OR", "DAC 1/2/3 AND",
9962306a36Sopenharmony_ci		"DAC 1/2/3 OR", "DAC 4 AND", "DAC 4 OR" };
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_func, PCM3168A_DAC_ATT_DEMP_ZF,
10262306a36Sopenharmony_ci		PCM3168A_DAC_AZRO_SHIFT, pcm3168a_zf_func);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic const char *const pcm3168a_pol[] = { "Active High", "Active Low" };
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_pol, PCM3168A_DAC_ATT_DEMP_ZF,
10762306a36Sopenharmony_ci		PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_pol);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic const char *const pcm3168a_con[] = { "Differential", "Single-Ended" };
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(pcm3168a_adc1_con, PCM3168A_ADC_SEAD,
11262306a36Sopenharmony_ci				0, 1, pcm3168a_con);
11362306a36Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(pcm3168a_adc2_con, PCM3168A_ADC_SEAD,
11462306a36Sopenharmony_ci				2, 3, pcm3168a_con);
11562306a36Sopenharmony_cistatic SOC_ENUM_DOUBLE_DECL(pcm3168a_adc3_con, PCM3168A_ADC_SEAD,
11662306a36Sopenharmony_ci				4, 5, pcm3168a_con);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_adc_volume_type, PCM3168A_ADC_ATT_OVF,
11962306a36Sopenharmony_ci		PCM3168A_ADC_ATMDAD_SHIFT, pcm3168a_volume_type);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_adc_att_mult, PCM3168A_ADC_ATT_OVF,
12262306a36Sopenharmony_ci		PCM3168A_ADC_ATSPAD_SHIFT, pcm3168a_att_speed_mult);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pcm3168a_adc_ov_pol, PCM3168A_ADC_ATT_OVF,
12562306a36Sopenharmony_ci		PCM3168A_ADC_OVFP_SHIFT, pcm3168a_pol);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/* -100db to 0db, register values 0-54 cause mute */
12862306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(pcm3168a_dac_tlv, -10050, 50, 1);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/* -100db to 20db, register values 0-14 cause mute */
13162306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(pcm3168a_adc_tlv, -10050, 50, 1);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic const struct snd_kcontrol_new pcm3168a_snd_controls[] = {
13462306a36Sopenharmony_ci	SOC_SINGLE("DAC Power-Save Switch", PCM3168A_DAC_PWR_MST_FMT,
13562306a36Sopenharmony_ci			PCM3168A_DAC_PSMDA_SHIFT, 1, 1),
13662306a36Sopenharmony_ci	SOC_ENUM("DAC1 Digital Filter roll-off", pcm3168a_d1_roll_off),
13762306a36Sopenharmony_ci	SOC_ENUM("DAC2 Digital Filter roll-off", pcm3168a_d2_roll_off),
13862306a36Sopenharmony_ci	SOC_ENUM("DAC3 Digital Filter roll-off", pcm3168a_d3_roll_off),
13962306a36Sopenharmony_ci	SOC_ENUM("DAC4 Digital Filter roll-off", pcm3168a_d4_roll_off),
14062306a36Sopenharmony_ci	SOC_DOUBLE("DAC1 Invert Switch", PCM3168A_DAC_INV, 0, 1, 1, 0),
14162306a36Sopenharmony_ci	SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0),
14262306a36Sopenharmony_ci	SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0),
14362306a36Sopenharmony_ci	SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0),
14462306a36Sopenharmony_ci	SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type),
14562306a36Sopenharmony_ci	SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult),
14662306a36Sopenharmony_ci	SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp),
14762306a36Sopenharmony_ci	SOC_ENUM("DAC Zero Flag Function", pcm3168a_dac_zf_func),
14862306a36Sopenharmony_ci	SOC_ENUM("DAC Zero Flag Polarity", pcm3168a_dac_zf_pol),
14962306a36Sopenharmony_ci	SOC_SINGLE_RANGE_TLV("Master Playback Volume",
15062306a36Sopenharmony_ci			PCM3168A_DAC_VOL_MASTER, 0, 54, 255, 0,
15162306a36Sopenharmony_ci			pcm3168a_dac_tlv),
15262306a36Sopenharmony_ci	SOC_DOUBLE_R_RANGE_TLV("DAC1 Playback Volume",
15362306a36Sopenharmony_ci			PCM3168A_DAC_VOL_CHAN_START,
15462306a36Sopenharmony_ci			PCM3168A_DAC_VOL_CHAN_START + 1,
15562306a36Sopenharmony_ci			0, 54, 255, 0, pcm3168a_dac_tlv),
15662306a36Sopenharmony_ci	SOC_DOUBLE_R_RANGE_TLV("DAC2 Playback Volume",
15762306a36Sopenharmony_ci			PCM3168A_DAC_VOL_CHAN_START + 2,
15862306a36Sopenharmony_ci			PCM3168A_DAC_VOL_CHAN_START + 3,
15962306a36Sopenharmony_ci			0, 54, 255, 0, pcm3168a_dac_tlv),
16062306a36Sopenharmony_ci	SOC_DOUBLE_R_RANGE_TLV("DAC3 Playback Volume",
16162306a36Sopenharmony_ci			PCM3168A_DAC_VOL_CHAN_START + 4,
16262306a36Sopenharmony_ci			PCM3168A_DAC_VOL_CHAN_START + 5,
16362306a36Sopenharmony_ci			0, 54, 255, 0, pcm3168a_dac_tlv),
16462306a36Sopenharmony_ci	SOC_DOUBLE_R_RANGE_TLV("DAC4 Playback Volume",
16562306a36Sopenharmony_ci			PCM3168A_DAC_VOL_CHAN_START + 6,
16662306a36Sopenharmony_ci			PCM3168A_DAC_VOL_CHAN_START + 7,
16762306a36Sopenharmony_ci			0, 54, 255, 0, pcm3168a_dac_tlv),
16862306a36Sopenharmony_ci	SOC_SINGLE("ADC1 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
16962306a36Sopenharmony_ci			PCM3168A_ADC_BYP_SHIFT, 1, 1),
17062306a36Sopenharmony_ci	SOC_SINGLE("ADC2 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
17162306a36Sopenharmony_ci			PCM3168A_ADC_BYP_SHIFT + 1, 1, 1),
17262306a36Sopenharmony_ci	SOC_SINGLE("ADC3 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB,
17362306a36Sopenharmony_ci			PCM3168A_ADC_BYP_SHIFT + 2, 1, 1),
17462306a36Sopenharmony_ci	SOC_ENUM("ADC1 Connection Type", pcm3168a_adc1_con),
17562306a36Sopenharmony_ci	SOC_ENUM("ADC2 Connection Type", pcm3168a_adc2_con),
17662306a36Sopenharmony_ci	SOC_ENUM("ADC3 Connection Type", pcm3168a_adc3_con),
17762306a36Sopenharmony_ci	SOC_DOUBLE("ADC1 Invert Switch", PCM3168A_ADC_INV, 0, 1, 1, 0),
17862306a36Sopenharmony_ci	SOC_DOUBLE("ADC2 Invert Switch", PCM3168A_ADC_INV, 2, 3, 1, 0),
17962306a36Sopenharmony_ci	SOC_DOUBLE("ADC3 Invert Switch", PCM3168A_ADC_INV, 4, 5, 1, 0),
18062306a36Sopenharmony_ci	SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0),
18162306a36Sopenharmony_ci	SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0),
18262306a36Sopenharmony_ci	SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0),
18362306a36Sopenharmony_ci	SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type),
18462306a36Sopenharmony_ci	SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult),
18562306a36Sopenharmony_ci	SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol),
18662306a36Sopenharmony_ci	SOC_SINGLE_RANGE_TLV("Master Capture Volume",
18762306a36Sopenharmony_ci			PCM3168A_ADC_VOL_MASTER, 0, 14, 255, 0,
18862306a36Sopenharmony_ci			pcm3168a_adc_tlv),
18962306a36Sopenharmony_ci	SOC_DOUBLE_R_RANGE_TLV("ADC1 Capture Volume",
19062306a36Sopenharmony_ci			PCM3168A_ADC_VOL_CHAN_START,
19162306a36Sopenharmony_ci			PCM3168A_ADC_VOL_CHAN_START + 1,
19262306a36Sopenharmony_ci			0, 14, 255, 0, pcm3168a_adc_tlv),
19362306a36Sopenharmony_ci	SOC_DOUBLE_R_RANGE_TLV("ADC2 Capture Volume",
19462306a36Sopenharmony_ci			PCM3168A_ADC_VOL_CHAN_START + 2,
19562306a36Sopenharmony_ci			PCM3168A_ADC_VOL_CHAN_START + 3,
19662306a36Sopenharmony_ci			0, 14, 255, 0, pcm3168a_adc_tlv),
19762306a36Sopenharmony_ci	SOC_DOUBLE_R_RANGE_TLV("ADC3 Capture Volume",
19862306a36Sopenharmony_ci			PCM3168A_ADC_VOL_CHAN_START + 4,
19962306a36Sopenharmony_ci			PCM3168A_ADC_VOL_CHAN_START + 5,
20062306a36Sopenharmony_ci			0, 14, 255, 0, pcm3168a_adc_tlv)
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget pcm3168a_dapm_widgets[] = {
20462306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC1", "Playback", PCM3168A_DAC_OP_FLT,
20562306a36Sopenharmony_ci			PCM3168A_DAC_OPEDA_SHIFT, 1),
20662306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC2", "Playback", PCM3168A_DAC_OP_FLT,
20762306a36Sopenharmony_ci			PCM3168A_DAC_OPEDA_SHIFT + 1, 1),
20862306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC3", "Playback", PCM3168A_DAC_OP_FLT,
20962306a36Sopenharmony_ci			PCM3168A_DAC_OPEDA_SHIFT + 2, 1),
21062306a36Sopenharmony_ci	SND_SOC_DAPM_DAC("DAC4", "Playback", PCM3168A_DAC_OP_FLT,
21162306a36Sopenharmony_ci			PCM3168A_DAC_OPEDA_SHIFT + 3, 1),
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("AOUT1L"),
21462306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("AOUT1R"),
21562306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("AOUT2L"),
21662306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("AOUT2R"),
21762306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("AOUT3L"),
21862306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("AOUT3R"),
21962306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("AOUT4L"),
22062306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("AOUT4R"),
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC1", "Capture", PCM3168A_ADC_PWR_HPFB,
22362306a36Sopenharmony_ci			PCM3168A_ADC_PSVAD_SHIFT, 1),
22462306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC2", "Capture", PCM3168A_ADC_PWR_HPFB,
22562306a36Sopenharmony_ci			PCM3168A_ADC_PSVAD_SHIFT + 1, 1),
22662306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("ADC3", "Capture", PCM3168A_ADC_PWR_HPFB,
22762306a36Sopenharmony_ci			PCM3168A_ADC_PSVAD_SHIFT + 2, 1),
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("AIN1L"),
23062306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("AIN1R"),
23162306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("AIN2L"),
23262306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("AIN2R"),
23362306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("AIN3L"),
23462306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("AIN3R")
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic const struct snd_soc_dapm_route pcm3168a_dapm_routes[] = {
23862306a36Sopenharmony_ci	/* Playback */
23962306a36Sopenharmony_ci	{ "AOUT1L", NULL, "DAC1" },
24062306a36Sopenharmony_ci	{ "AOUT1R", NULL, "DAC1" },
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	{ "AOUT2L", NULL, "DAC2" },
24362306a36Sopenharmony_ci	{ "AOUT2R", NULL, "DAC2" },
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	{ "AOUT3L", NULL, "DAC3" },
24662306a36Sopenharmony_ci	{ "AOUT3R", NULL, "DAC3" },
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	{ "AOUT4L", NULL, "DAC4" },
24962306a36Sopenharmony_ci	{ "AOUT4R", NULL, "DAC4" },
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* Capture */
25262306a36Sopenharmony_ci	{ "ADC1", NULL, "AIN1L" },
25362306a36Sopenharmony_ci	{ "ADC1", NULL, "AIN1R" },
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	{ "ADC2", NULL, "AIN2L" },
25662306a36Sopenharmony_ci	{ "ADC2", NULL, "AIN2R" },
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	{ "ADC3", NULL, "AIN3L" },
25962306a36Sopenharmony_ci	{ "ADC3", NULL, "AIN3R" }
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic unsigned int pcm3168a_scki_ratios[] = {
26362306a36Sopenharmony_ci	768,
26462306a36Sopenharmony_ci	512,
26562306a36Sopenharmony_ci	384,
26662306a36Sopenharmony_ci	256,
26762306a36Sopenharmony_ci	192,
26862306a36Sopenharmony_ci	128
26962306a36Sopenharmony_ci};
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci#define PCM3168A_NUM_SCKI_RATIOS_DAC	ARRAY_SIZE(pcm3168a_scki_ratios)
27262306a36Sopenharmony_ci#define PCM3168A_NUM_SCKI_RATIOS_ADC	(ARRAY_SIZE(pcm3168a_scki_ratios) - 2)
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci#define PCM3168A_MAX_SYSCLK		36864000
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int pcm3168a_reset(struct pcm3168a_priv *pcm3168a)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	int ret;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	ret = regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, 0);
28162306a36Sopenharmony_ci	if (ret)
28262306a36Sopenharmony_ci		return ret;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/* Internal reset is de-asserted after 3846 SCKI cycles */
28562306a36Sopenharmony_ci	msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk));
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE,
28862306a36Sopenharmony_ci			PCM3168A_MRST_MASK | PCM3168A_SRST_MASK);
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic int pcm3168a_mute(struct snd_soc_dai *dai, int mute, int direction)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
29462306a36Sopenharmony_ci	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	regmap_write(pcm3168a->regmap, PCM3168A_DAC_MUTE, mute ? 0xff : 0);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	return 0;
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
30262306a36Sopenharmony_ci				  int clk_id, unsigned int freq, int dir)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(dai->component);
30562306a36Sopenharmony_ci	int ret;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/*
30862306a36Sopenharmony_ci	 * Some sound card sets 0 Hz as reset,
30962306a36Sopenharmony_ci	 * but it is impossible to set. Ignore it here
31062306a36Sopenharmony_ci	 */
31162306a36Sopenharmony_ci	if (freq == 0)
31262306a36Sopenharmony_ci		return 0;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (freq > PCM3168A_MAX_SYSCLK)
31562306a36Sopenharmony_ci		return -EINVAL;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	ret = clk_set_rate(pcm3168a->scki, freq);
31862306a36Sopenharmony_ci	if (ret)
31962306a36Sopenharmony_ci		return ret;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	pcm3168a->sysclk = freq;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return 0;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
32962306a36Sopenharmony_ci	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
33062306a36Sopenharmony_ci	struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id];
33162306a36Sopenharmony_ci	u64 formats = SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE;
33262306a36Sopenharmony_ci	unsigned int channel_max = dai->id == PCM3168A_DAI_DAC ? 8 : 6;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (io_params->format == SND_SOC_DAIFMT_RIGHT_J) {
33562306a36Sopenharmony_ci		/* S16_LE is only supported in RIGHT_J mode */
33662306a36Sopenharmony_ci		formats |= SNDRV_PCM_FMTBIT_S16_LE;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci		/*
33962306a36Sopenharmony_ci		 * If multi DIN/DOUT is not selected, RIGHT_J can only support
34062306a36Sopenharmony_ci		 * two channels (no TDM support)
34162306a36Sopenharmony_ci		 */
34262306a36Sopenharmony_ci		if (io_params->tdm_slots != 2)
34362306a36Sopenharmony_ci			channel_max = 2;
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (dai->id == PCM3168A_DAI_DAC) {
34762306a36Sopenharmony_ci		dai->driver->playback.channels_max = channel_max;
34862306a36Sopenharmony_ci		dai->driver->playback.formats = formats;
34962306a36Sopenharmony_ci	} else {
35062306a36Sopenharmony_ci		dai->driver->capture.channels_max = channel_max;
35162306a36Sopenharmony_ci		dai->driver->capture.formats = formats;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
35862306a36Sopenharmony_ci	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
35962306a36Sopenharmony_ci	struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id];
36062306a36Sopenharmony_ci	bool provider_mode;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
36362306a36Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
36462306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
36562306a36Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
36662306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_A:
36762306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_B:
36862306a36Sopenharmony_ci		break;
36962306a36Sopenharmony_ci	default:
37062306a36Sopenharmony_ci		dev_err(component->dev, "unsupported dai format\n");
37162306a36Sopenharmony_ci		return -EINVAL;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	switch (format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
37562306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBC_CFC:
37662306a36Sopenharmony_ci		provider_mode = false;
37762306a36Sopenharmony_ci		break;
37862306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBP_CFP:
37962306a36Sopenharmony_ci		provider_mode = true;
38062306a36Sopenharmony_ci		break;
38162306a36Sopenharmony_ci	default:
38262306a36Sopenharmony_ci		dev_err(component->dev, "unsupported provider mode\n");
38362306a36Sopenharmony_ci		return -EINVAL;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	switch (format & SND_SOC_DAIFMT_INV_MASK) {
38762306a36Sopenharmony_ci	case SND_SOC_DAIFMT_NB_NF:
38862306a36Sopenharmony_ci		break;
38962306a36Sopenharmony_ci	default:
39062306a36Sopenharmony_ci		return -EINVAL;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	io_params->provider_mode = provider_mode;
39462306a36Sopenharmony_ci	io_params->format = format & SND_SOC_DAIFMT_FORMAT_MASK;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	pcm3168a_update_fixup_pcm_stream(dai);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	return 0;
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
40262306a36Sopenharmony_ci				 unsigned int rx_mask, int slots,
40362306a36Sopenharmony_ci				 int slot_width)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
40662306a36Sopenharmony_ci	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
40762306a36Sopenharmony_ci	struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id];
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (tx_mask >= (1<<slots) || rx_mask >= (1<<slots)) {
41062306a36Sopenharmony_ci		dev_err(component->dev,
41162306a36Sopenharmony_ci			"Bad tdm mask tx: 0x%08x rx: 0x%08x slots %d\n",
41262306a36Sopenharmony_ci			tx_mask, rx_mask, slots);
41362306a36Sopenharmony_ci		return -EINVAL;
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (slot_width &&
41762306a36Sopenharmony_ci	    (slot_width != 16 && slot_width != 24 && slot_width != 32 )) {
41862306a36Sopenharmony_ci		dev_err(component->dev, "Unsupported slot_width %d\n",
41962306a36Sopenharmony_ci			slot_width);
42062306a36Sopenharmony_ci		return -EINVAL;
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	io_params->tdm_slots = slots;
42462306a36Sopenharmony_ci	io_params->slot_width = slot_width;
42562306a36Sopenharmony_ci	/* Ignore the not relevant mask for the DAI/direction */
42662306a36Sopenharmony_ci	if (dai->id == PCM3168A_DAI_DAC)
42762306a36Sopenharmony_ci		io_params->tdm_mask = tx_mask;
42862306a36Sopenharmony_ci	else
42962306a36Sopenharmony_ci		io_params->tdm_mask = rx_mask;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	pcm3168a_update_fixup_pcm_stream(dai);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int pcm3168a_hw_params(struct snd_pcm_substream *substream,
43762306a36Sopenharmony_ci			     struct snd_pcm_hw_params *params,
43862306a36Sopenharmony_ci			     struct snd_soc_dai *dai)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
44162306a36Sopenharmony_ci	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
44262306a36Sopenharmony_ci	struct pcm3168a_io_params *io_params = &pcm3168a->io_params[dai->id];
44362306a36Sopenharmony_ci	bool provider_mode, tdm_mode;
44462306a36Sopenharmony_ci	unsigned int format;
44562306a36Sopenharmony_ci	unsigned int reg, mask, ms, ms_shift, fmt, fmt_shift, ratio, tdm_slots;
44662306a36Sopenharmony_ci	int i, num_scki_ratios, slot_width;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (dai->id == PCM3168A_DAI_DAC) {
44962306a36Sopenharmony_ci		num_scki_ratios = PCM3168A_NUM_SCKI_RATIOS_DAC;
45062306a36Sopenharmony_ci		reg = PCM3168A_DAC_PWR_MST_FMT;
45162306a36Sopenharmony_ci		mask = PCM3168A_DAC_MSDA_MASK | PCM3168A_DAC_FMT_MASK;
45262306a36Sopenharmony_ci		ms_shift = PCM3168A_DAC_MSDA_SHIFT;
45362306a36Sopenharmony_ci		fmt_shift = PCM3168A_DAC_FMT_SHIFT;
45462306a36Sopenharmony_ci	} else {
45562306a36Sopenharmony_ci		num_scki_ratios = PCM3168A_NUM_SCKI_RATIOS_ADC;
45662306a36Sopenharmony_ci		reg = PCM3168A_ADC_MST_FMT;
45762306a36Sopenharmony_ci		mask = PCM3168A_ADC_MSAD_MASK | PCM3168A_ADC_FMTAD_MASK;
45862306a36Sopenharmony_ci		ms_shift = PCM3168A_ADC_MSAD_SHIFT;
45962306a36Sopenharmony_ci		fmt_shift = PCM3168A_ADC_FMTAD_SHIFT;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	provider_mode = io_params->provider_mode;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (provider_mode) {
46562306a36Sopenharmony_ci		ratio = pcm3168a->sysclk / params_rate(params);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci		for (i = 0; i < num_scki_ratios; i++) {
46862306a36Sopenharmony_ci			if (pcm3168a_scki_ratios[i] == ratio)
46962306a36Sopenharmony_ci				break;
47062306a36Sopenharmony_ci		}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci		if (i == num_scki_ratios) {
47362306a36Sopenharmony_ci			dev_err(component->dev, "unsupported sysclk ratio\n");
47462306a36Sopenharmony_ci			return -EINVAL;
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		ms = (i + 1);
47862306a36Sopenharmony_ci	} else {
47962306a36Sopenharmony_ci		ms = 0;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	format = io_params->format;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (io_params->slot_width)
48562306a36Sopenharmony_ci		slot_width = io_params->slot_width;
48662306a36Sopenharmony_ci	else
48762306a36Sopenharmony_ci		slot_width = params_width(params);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	switch (slot_width) {
49062306a36Sopenharmony_ci	case 16:
49162306a36Sopenharmony_ci		if (provider_mode || (format != SND_SOC_DAIFMT_RIGHT_J)) {
49262306a36Sopenharmony_ci			dev_err(component->dev, "16-bit slots are supported only for consumer mode using right justified\n");
49362306a36Sopenharmony_ci			return -EINVAL;
49462306a36Sopenharmony_ci		}
49562306a36Sopenharmony_ci		break;
49662306a36Sopenharmony_ci	case 24:
49762306a36Sopenharmony_ci		if (provider_mode || (format == SND_SOC_DAIFMT_DSP_A) ||
49862306a36Sopenharmony_ci		    		     (format == SND_SOC_DAIFMT_DSP_B)) {
49962306a36Sopenharmony_ci			dev_err(component->dev, "24-bit slots not supported in provider mode, or consumer mode using DSP\n");
50062306a36Sopenharmony_ci			return -EINVAL;
50162306a36Sopenharmony_ci		}
50262306a36Sopenharmony_ci		break;
50362306a36Sopenharmony_ci	case 32:
50462306a36Sopenharmony_ci		break;
50562306a36Sopenharmony_ci	default:
50662306a36Sopenharmony_ci		dev_err(component->dev, "unsupported frame size: %d\n", slot_width);
50762306a36Sopenharmony_ci		return -EINVAL;
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (io_params->tdm_slots)
51162306a36Sopenharmony_ci		tdm_slots = io_params->tdm_slots;
51262306a36Sopenharmony_ci	else
51362306a36Sopenharmony_ci		tdm_slots = params_channels(params);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/*
51662306a36Sopenharmony_ci	 * Switch the codec to TDM mode when more than 2 TDM slots are needed
51762306a36Sopenharmony_ci	 * for the stream.
51862306a36Sopenharmony_ci	 * If pcm3168a->tdm_slots is not set or set to more than 2 (8/6 usually)
51962306a36Sopenharmony_ci	 * then DIN1/DOUT1 is used in TDM mode.
52062306a36Sopenharmony_ci	 * If pcm3168a->tdm_slots is set to 2 then DIN1/2/3/4 and DOUT1/2/3 is
52162306a36Sopenharmony_ci	 * used in normal mode, no need to switch to TDM modes.
52262306a36Sopenharmony_ci	 */
52362306a36Sopenharmony_ci	tdm_mode = (tdm_slots > 2);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (tdm_mode) {
52662306a36Sopenharmony_ci		switch (format) {
52762306a36Sopenharmony_ci		case SND_SOC_DAIFMT_I2S:
52862306a36Sopenharmony_ci		case SND_SOC_DAIFMT_DSP_A:
52962306a36Sopenharmony_ci		case SND_SOC_DAIFMT_LEFT_J:
53062306a36Sopenharmony_ci		case SND_SOC_DAIFMT_DSP_B:
53162306a36Sopenharmony_ci			break;
53262306a36Sopenharmony_ci		default:
53362306a36Sopenharmony_ci			dev_err(component->dev,
53462306a36Sopenharmony_ci				"TDM is supported under DSP/I2S/Left_J only\n");
53562306a36Sopenharmony_ci			return -EINVAL;
53662306a36Sopenharmony_ci		}
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	switch (format) {
54062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
54162306a36Sopenharmony_ci		fmt = tdm_mode ? PCM3168A_FMT_I2S_TDM : PCM3168A_FMT_I2S;
54262306a36Sopenharmony_ci		break;
54362306a36Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
54462306a36Sopenharmony_ci		fmt = tdm_mode ? PCM3168A_FMT_LEFT_J_TDM : PCM3168A_FMT_LEFT_J;
54562306a36Sopenharmony_ci		break;
54662306a36Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
54762306a36Sopenharmony_ci		fmt = (slot_width == 16) ? PCM3168A_FMT_RIGHT_J_16 :
54862306a36Sopenharmony_ci					   PCM3168A_FMT_RIGHT_J;
54962306a36Sopenharmony_ci		break;
55062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_A:
55162306a36Sopenharmony_ci		fmt = tdm_mode ? PCM3168A_FMT_I2S_TDM : PCM3168A_FMT_DSP_A;
55262306a36Sopenharmony_ci		break;
55362306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_B:
55462306a36Sopenharmony_ci		fmt = tdm_mode ? PCM3168A_FMT_LEFT_J_TDM : PCM3168A_FMT_DSP_B;
55562306a36Sopenharmony_ci		break;
55662306a36Sopenharmony_ci	default:
55762306a36Sopenharmony_ci		return -EINVAL;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	regmap_update_bits(pcm3168a->regmap, reg, mask,
56162306a36Sopenharmony_ci			(ms << ms_shift) | (fmt << fmt_shift));
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return 0;
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic u64 pcm3168a_dai_formats[] = {
56762306a36Sopenharmony_ci	/*
56862306a36Sopenharmony_ci	 * Select below from Sound Card, not here
56962306a36Sopenharmony_ci	 *	SND_SOC_DAIFMT_CBC_CFC
57062306a36Sopenharmony_ci	 *	SND_SOC_DAIFMT_CBP_CFP
57162306a36Sopenharmony_ci	 */
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/*
57462306a36Sopenharmony_ci	 * First Priority
57562306a36Sopenharmony_ci	 */
57662306a36Sopenharmony_ci	SND_SOC_POSSIBLE_DAIFMT_I2S	|
57762306a36Sopenharmony_ci	SND_SOC_POSSIBLE_DAIFMT_LEFT_J,
57862306a36Sopenharmony_ci	/*
57962306a36Sopenharmony_ci	 * Second Priority
58062306a36Sopenharmony_ci	 *
58162306a36Sopenharmony_ci	 * These have picky limitation.
58262306a36Sopenharmony_ci	 * see
58362306a36Sopenharmony_ci	 *	pcm3168a_hw_params()
58462306a36Sopenharmony_ci	 */
58562306a36Sopenharmony_ci	SND_SOC_POSSIBLE_DAIFMT_RIGHT_J	|
58662306a36Sopenharmony_ci	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
58762306a36Sopenharmony_ci	SND_SOC_POSSIBLE_DAIFMT_DSP_B,
58862306a36Sopenharmony_ci};
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic const struct snd_soc_dai_ops pcm3168a_dai_ops = {
59162306a36Sopenharmony_ci	.set_fmt	= pcm3168a_set_dai_fmt,
59262306a36Sopenharmony_ci	.set_sysclk	= pcm3168a_set_dai_sysclk,
59362306a36Sopenharmony_ci	.hw_params	= pcm3168a_hw_params,
59462306a36Sopenharmony_ci	.mute_stream	= pcm3168a_mute,
59562306a36Sopenharmony_ci	.set_tdm_slot	= pcm3168a_set_tdm_slot,
59662306a36Sopenharmony_ci	.no_capture_mute = 1,
59762306a36Sopenharmony_ci	.auto_selectable_formats	= pcm3168a_dai_formats,
59862306a36Sopenharmony_ci	.num_auto_selectable_formats	= ARRAY_SIZE(pcm3168a_dai_formats),
59962306a36Sopenharmony_ci};
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic struct snd_soc_dai_driver pcm3168a_dais[] = {
60262306a36Sopenharmony_ci	{
60362306a36Sopenharmony_ci		.name = "pcm3168a-dac",
60462306a36Sopenharmony_ci		.id = PCM3168A_DAI_DAC,
60562306a36Sopenharmony_ci		.playback = {
60662306a36Sopenharmony_ci			.stream_name = "Playback",
60762306a36Sopenharmony_ci			.channels_min = 1,
60862306a36Sopenharmony_ci			.channels_max = 8,
60962306a36Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_192000,
61062306a36Sopenharmony_ci			.formats = PCM3168A_FORMATS
61162306a36Sopenharmony_ci		},
61262306a36Sopenharmony_ci		.ops = &pcm3168a_dai_ops
61362306a36Sopenharmony_ci	},
61462306a36Sopenharmony_ci	{
61562306a36Sopenharmony_ci		.name = "pcm3168a-adc",
61662306a36Sopenharmony_ci		.id = PCM3168A_DAI_ADC,
61762306a36Sopenharmony_ci		.capture = {
61862306a36Sopenharmony_ci			.stream_name = "Capture",
61962306a36Sopenharmony_ci			.channels_min = 1,
62062306a36Sopenharmony_ci			.channels_max = 6,
62162306a36Sopenharmony_ci			.rates = SNDRV_PCM_RATE_8000_96000,
62262306a36Sopenharmony_ci			.formats = PCM3168A_FORMATS
62362306a36Sopenharmony_ci		},
62462306a36Sopenharmony_ci		.ops = &pcm3168a_dai_ops
62562306a36Sopenharmony_ci	},
62662306a36Sopenharmony_ci};
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cistatic const struct reg_default pcm3168a_reg_default[] = {
62962306a36Sopenharmony_ci	{ PCM3168A_RST_SMODE, PCM3168A_MRST_MASK | PCM3168A_SRST_MASK },
63062306a36Sopenharmony_ci	{ PCM3168A_DAC_PWR_MST_FMT, 0x00 },
63162306a36Sopenharmony_ci	{ PCM3168A_DAC_OP_FLT, 0x00 },
63262306a36Sopenharmony_ci	{ PCM3168A_DAC_INV, 0x00 },
63362306a36Sopenharmony_ci	{ PCM3168A_DAC_MUTE, 0x00 },
63462306a36Sopenharmony_ci	{ PCM3168A_DAC_ZERO, 0x00 },
63562306a36Sopenharmony_ci	{ PCM3168A_DAC_ATT_DEMP_ZF, 0x00 },
63662306a36Sopenharmony_ci	{ PCM3168A_DAC_VOL_MASTER, 0xff },
63762306a36Sopenharmony_ci	{ PCM3168A_DAC_VOL_CHAN_START, 0xff },
63862306a36Sopenharmony_ci	{ PCM3168A_DAC_VOL_CHAN_START + 1, 0xff },
63962306a36Sopenharmony_ci	{ PCM3168A_DAC_VOL_CHAN_START + 2, 0xff },
64062306a36Sopenharmony_ci	{ PCM3168A_DAC_VOL_CHAN_START + 3, 0xff },
64162306a36Sopenharmony_ci	{ PCM3168A_DAC_VOL_CHAN_START + 4, 0xff },
64262306a36Sopenharmony_ci	{ PCM3168A_DAC_VOL_CHAN_START + 5, 0xff },
64362306a36Sopenharmony_ci	{ PCM3168A_DAC_VOL_CHAN_START + 6, 0xff },
64462306a36Sopenharmony_ci	{ PCM3168A_DAC_VOL_CHAN_START + 7, 0xff },
64562306a36Sopenharmony_ci	{ PCM3168A_ADC_SMODE, 0x00 },
64662306a36Sopenharmony_ci	{ PCM3168A_ADC_MST_FMT, 0x00 },
64762306a36Sopenharmony_ci	{ PCM3168A_ADC_PWR_HPFB, 0x00 },
64862306a36Sopenharmony_ci	{ PCM3168A_ADC_SEAD, 0x00 },
64962306a36Sopenharmony_ci	{ PCM3168A_ADC_INV, 0x00 },
65062306a36Sopenharmony_ci	{ PCM3168A_ADC_MUTE, 0x00 },
65162306a36Sopenharmony_ci	{ PCM3168A_ADC_OV, 0x00 },
65262306a36Sopenharmony_ci	{ PCM3168A_ADC_ATT_OVF, 0x00 },
65362306a36Sopenharmony_ci	{ PCM3168A_ADC_VOL_MASTER, 0xd3 },
65462306a36Sopenharmony_ci	{ PCM3168A_ADC_VOL_CHAN_START, 0xd3 },
65562306a36Sopenharmony_ci	{ PCM3168A_ADC_VOL_CHAN_START + 1, 0xd3 },
65662306a36Sopenharmony_ci	{ PCM3168A_ADC_VOL_CHAN_START + 2, 0xd3 },
65762306a36Sopenharmony_ci	{ PCM3168A_ADC_VOL_CHAN_START + 3, 0xd3 },
65862306a36Sopenharmony_ci	{ PCM3168A_ADC_VOL_CHAN_START + 4, 0xd3 },
65962306a36Sopenharmony_ci	{ PCM3168A_ADC_VOL_CHAN_START + 5, 0xd3 }
66062306a36Sopenharmony_ci};
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic bool pcm3168a_readable_register(struct device *dev, unsigned int reg)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	if (reg >= PCM3168A_RST_SMODE)
66562306a36Sopenharmony_ci		return true;
66662306a36Sopenharmony_ci	else
66762306a36Sopenharmony_ci		return false;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic bool pcm3168a_volatile_register(struct device *dev, unsigned int reg)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	switch (reg) {
67362306a36Sopenharmony_ci	case PCM3168A_RST_SMODE:
67462306a36Sopenharmony_ci	case PCM3168A_DAC_ZERO:
67562306a36Sopenharmony_ci	case PCM3168A_ADC_OV:
67662306a36Sopenharmony_ci		return true;
67762306a36Sopenharmony_ci	default:
67862306a36Sopenharmony_ci		return false;
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic bool pcm3168a_writeable_register(struct device *dev, unsigned int reg)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	if (reg < PCM3168A_RST_SMODE)
68562306a36Sopenharmony_ci		return false;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	switch (reg) {
68862306a36Sopenharmony_ci	case PCM3168A_DAC_ZERO:
68962306a36Sopenharmony_ci	case PCM3168A_ADC_OV:
69062306a36Sopenharmony_ci		return false;
69162306a36Sopenharmony_ci	default:
69262306a36Sopenharmony_ci		return true;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ciconst struct regmap_config pcm3168a_regmap = {
69762306a36Sopenharmony_ci	.reg_bits = 8,
69862306a36Sopenharmony_ci	.val_bits = 8,
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	.max_register = PCM3168A_ADC_VOL_CHAN_START + 5,
70162306a36Sopenharmony_ci	.reg_defaults = pcm3168a_reg_default,
70262306a36Sopenharmony_ci	.num_reg_defaults = ARRAY_SIZE(pcm3168a_reg_default),
70362306a36Sopenharmony_ci	.readable_reg = pcm3168a_readable_register,
70462306a36Sopenharmony_ci	.volatile_reg = pcm3168a_volatile_register,
70562306a36Sopenharmony_ci	.writeable_reg = pcm3168a_writeable_register,
70662306a36Sopenharmony_ci	.cache_type = REGCACHE_FLAT
70762306a36Sopenharmony_ci};
70862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm3168a_regmap);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic const struct snd_soc_component_driver pcm3168a_driver = {
71162306a36Sopenharmony_ci	.controls		= pcm3168a_snd_controls,
71262306a36Sopenharmony_ci	.num_controls		= ARRAY_SIZE(pcm3168a_snd_controls),
71362306a36Sopenharmony_ci	.dapm_widgets		= pcm3168a_dapm_widgets,
71462306a36Sopenharmony_ci	.num_dapm_widgets	= ARRAY_SIZE(pcm3168a_dapm_widgets),
71562306a36Sopenharmony_ci	.dapm_routes		= pcm3168a_dapm_routes,
71662306a36Sopenharmony_ci	.num_dapm_routes	= ARRAY_SIZE(pcm3168a_dapm_routes),
71762306a36Sopenharmony_ci	.use_pmdown_time	= 1,
71862306a36Sopenharmony_ci	.endianness		= 1,
71962306a36Sopenharmony_ci};
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ciint pcm3168a_probe(struct device *dev, struct regmap *regmap)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	struct pcm3168a_priv *pcm3168a;
72462306a36Sopenharmony_ci	int ret, i;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	pcm3168a = devm_kzalloc(dev, sizeof(*pcm3168a), GFP_KERNEL);
72762306a36Sopenharmony_ci	if (pcm3168a == NULL)
72862306a36Sopenharmony_ci		return -ENOMEM;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	dev_set_drvdata(dev, pcm3168a);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	/*
73362306a36Sopenharmony_ci	 * Request the reset (connected to RST pin) gpio line as non exclusive
73462306a36Sopenharmony_ci	 * as the same reset line might be connected to multiple pcm3168a codec
73562306a36Sopenharmony_ci	 *
73662306a36Sopenharmony_ci	 * The RST is low active, we want the GPIO line to be high initially, so
73762306a36Sopenharmony_ci	 * request the initial level to LOW which in practice means DEASSERTED:
73862306a36Sopenharmony_ci	 * The deasserted level of GPIO_ACTIVE_LOW is HIGH.
73962306a36Sopenharmony_ci	 */
74062306a36Sopenharmony_ci	pcm3168a->gpio_rst = devm_gpiod_get_optional(dev, "reset",
74162306a36Sopenharmony_ci						GPIOD_OUT_LOW |
74262306a36Sopenharmony_ci						GPIOD_FLAGS_BIT_NONEXCLUSIVE);
74362306a36Sopenharmony_ci	if (IS_ERR(pcm3168a->gpio_rst))
74462306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(pcm3168a->gpio_rst),
74562306a36Sopenharmony_ci				     "failed to acquire RST gpio\n");
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	pcm3168a->scki = devm_clk_get(dev, "scki");
74862306a36Sopenharmony_ci	if (IS_ERR(pcm3168a->scki))
74962306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(pcm3168a->scki),
75062306a36Sopenharmony_ci				     "failed to acquire clock 'scki'\n");
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	ret = clk_prepare_enable(pcm3168a->scki);
75362306a36Sopenharmony_ci	if (ret) {
75462306a36Sopenharmony_ci		dev_err(dev, "Failed to enable mclk: %d\n", ret);
75562306a36Sopenharmony_ci		return ret;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	pcm3168a->sysclk = clk_get_rate(pcm3168a->scki);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++)
76162306a36Sopenharmony_ci		pcm3168a->supplies[i].supply = pcm3168a_supply_names[i];
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	ret = devm_regulator_bulk_get(dev,
76462306a36Sopenharmony_ci			ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies);
76562306a36Sopenharmony_ci	if (ret) {
76662306a36Sopenharmony_ci		dev_err_probe(dev, ret, "failed to request supplies\n");
76762306a36Sopenharmony_ci		goto err_clk;
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
77162306a36Sopenharmony_ci				    pcm3168a->supplies);
77262306a36Sopenharmony_ci	if (ret) {
77362306a36Sopenharmony_ci		dev_err(dev, "failed to enable supplies: %d\n", ret);
77462306a36Sopenharmony_ci		goto err_clk;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	pcm3168a->regmap = regmap;
77862306a36Sopenharmony_ci	if (IS_ERR(pcm3168a->regmap)) {
77962306a36Sopenharmony_ci		ret = PTR_ERR(pcm3168a->regmap);
78062306a36Sopenharmony_ci		dev_err(dev, "failed to allocate regmap: %d\n", ret);
78162306a36Sopenharmony_ci		goto err_regulator;
78262306a36Sopenharmony_ci	}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	if (pcm3168a->gpio_rst) {
78562306a36Sopenharmony_ci		/*
78662306a36Sopenharmony_ci		 * The device is taken out from reset via GPIO line, wait for
78762306a36Sopenharmony_ci		 * 3846 SCKI clock cycles for the internal reset de-assertion
78862306a36Sopenharmony_ci		 */
78962306a36Sopenharmony_ci		msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk));
79062306a36Sopenharmony_ci	} else {
79162306a36Sopenharmony_ci		ret = pcm3168a_reset(pcm3168a);
79262306a36Sopenharmony_ci		if (ret) {
79362306a36Sopenharmony_ci			dev_err(dev, "Failed to reset device: %d\n", ret);
79462306a36Sopenharmony_ci			goto err_regulator;
79562306a36Sopenharmony_ci		}
79662306a36Sopenharmony_ci	}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	pm_runtime_set_active(dev);
79962306a36Sopenharmony_ci	pm_runtime_enable(dev);
80062306a36Sopenharmony_ci	pm_runtime_idle(dev);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	memcpy(pcm3168a->dai_drv, pcm3168a_dais, sizeof(pcm3168a->dai_drv));
80362306a36Sopenharmony_ci	ret = devm_snd_soc_register_component(dev, &pcm3168a_driver,
80462306a36Sopenharmony_ci					      pcm3168a->dai_drv,
80562306a36Sopenharmony_ci					      ARRAY_SIZE(pcm3168a->dai_drv));
80662306a36Sopenharmony_ci	if (ret) {
80762306a36Sopenharmony_ci		dev_err(dev, "failed to register component: %d\n", ret);
80862306a36Sopenharmony_ci		goto err_regulator;
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	return 0;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_cierr_regulator:
81462306a36Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
81562306a36Sopenharmony_ci			pcm3168a->supplies);
81662306a36Sopenharmony_cierr_clk:
81762306a36Sopenharmony_ci	clk_disable_unprepare(pcm3168a->scki);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return ret;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm3168a_probe);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic void pcm3168a_disable(struct device *dev)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
82862306a36Sopenharmony_ci			       pcm3168a->supplies);
82962306a36Sopenharmony_ci	clk_disable_unprepare(pcm3168a->scki);
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_civoid pcm3168a_remove(struct device *dev)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/*
83762306a36Sopenharmony_ci	 * The RST is low active, we want the GPIO line to be low when the
83862306a36Sopenharmony_ci	 * driver is removed, so set level to 1 which in practice means
83962306a36Sopenharmony_ci	 * ASSERTED:
84062306a36Sopenharmony_ci	 * The asserted level of GPIO_ACTIVE_LOW is LOW.
84162306a36Sopenharmony_ci	 */
84262306a36Sopenharmony_ci	gpiod_set_value_cansleep(pcm3168a->gpio_rst, 1);
84362306a36Sopenharmony_ci	pm_runtime_disable(dev);
84462306a36Sopenharmony_ci#ifndef CONFIG_PM
84562306a36Sopenharmony_ci	pcm3168a_disable(dev);
84662306a36Sopenharmony_ci#endif
84762306a36Sopenharmony_ci}
84862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm3168a_remove);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci#ifdef CONFIG_PM
85162306a36Sopenharmony_cistatic int pcm3168a_rt_resume(struct device *dev)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
85462306a36Sopenharmony_ci	int ret;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	ret = clk_prepare_enable(pcm3168a->scki);
85762306a36Sopenharmony_ci	if (ret) {
85862306a36Sopenharmony_ci		dev_err(dev, "Failed to enable mclk: %d\n", ret);
85962306a36Sopenharmony_ci		return ret;
86062306a36Sopenharmony_ci	}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies),
86362306a36Sopenharmony_ci				    pcm3168a->supplies);
86462306a36Sopenharmony_ci	if (ret) {
86562306a36Sopenharmony_ci		dev_err(dev, "Failed to enable supplies: %d\n", ret);
86662306a36Sopenharmony_ci		goto err_clk;
86762306a36Sopenharmony_ci	}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	ret = pcm3168a_reset(pcm3168a);
87062306a36Sopenharmony_ci	if (ret) {
87162306a36Sopenharmony_ci		dev_err(dev, "Failed to reset device: %d\n", ret);
87262306a36Sopenharmony_ci		goto err_regulator;
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	regcache_cache_only(pcm3168a->regmap, false);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	regcache_mark_dirty(pcm3168a->regmap);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	ret = regcache_sync(pcm3168a->regmap);
88062306a36Sopenharmony_ci	if (ret) {
88162306a36Sopenharmony_ci		dev_err(dev, "Failed to sync regmap: %d\n", ret);
88262306a36Sopenharmony_ci		goto err_regulator;
88362306a36Sopenharmony_ci	}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	return 0;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_cierr_regulator:
88862306a36Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies),
88962306a36Sopenharmony_ci			       pcm3168a->supplies);
89062306a36Sopenharmony_cierr_clk:
89162306a36Sopenharmony_ci	clk_disable_unprepare(pcm3168a->scki);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	return ret;
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_cistatic int pcm3168a_rt_suspend(struct device *dev)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	regcache_cache_only(pcm3168a->regmap, true);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	pcm3168a_disable(dev);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	return 0;
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci#endif
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ciconst struct dev_pm_ops pcm3168a_pm_ops = {
90962306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL)
91062306a36Sopenharmony_ci};
91162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pcm3168a_pm_ops);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ciMODULE_DESCRIPTION("PCM3168A codec driver");
91462306a36Sopenharmony_ciMODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
91562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
916