162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * 88pm860x-codec.c -- 88PM860x ALSA SoC Audio Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2010 Marvell International Ltd.
662306a36Sopenharmony_ci * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/i2c.h>
1262306a36Sopenharmony_ci#include <linux/platform_device.h>
1362306a36Sopenharmony_ci#include <linux/mfd/88pm860x.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/regmap.h>
1762306a36Sopenharmony_ci#include <sound/core.h>
1862306a36Sopenharmony_ci#include <sound/pcm.h>
1962306a36Sopenharmony_ci#include <sound/pcm_params.h>
2062306a36Sopenharmony_ci#include <sound/soc.h>
2162306a36Sopenharmony_ci#include <sound/tlv.h>
2262306a36Sopenharmony_ci#include <sound/initval.h>
2362306a36Sopenharmony_ci#include <sound/jack.h>
2462306a36Sopenharmony_ci#include <trace/events/asoc.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "88pm860x-codec.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define MAX_NAME_LEN		20
2962306a36Sopenharmony_ci#define REG_CACHE_SIZE		0x40
3062306a36Sopenharmony_ci#define REG_CACHE_BASE		0xb0
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Status Register 1 (0x01) */
3362306a36Sopenharmony_ci#define REG_STATUS_1		0x01
3462306a36Sopenharmony_ci#define MIC_STATUS		(1 << 7)
3562306a36Sopenharmony_ci#define HOOK_STATUS		(1 << 6)
3662306a36Sopenharmony_ci#define HEADSET_STATUS		(1 << 5)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* Mic Detection Register (0x37) */
3962306a36Sopenharmony_ci#define REG_MIC_DET		0x37
4062306a36Sopenharmony_ci#define CONTINUOUS_POLLING	(3 << 1)
4162306a36Sopenharmony_ci#define EN_MIC_DET		(1 << 0)
4262306a36Sopenharmony_ci#define MICDET_MASK		0x07
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* Headset Detection Register (0x38) */
4562306a36Sopenharmony_ci#define REG_HS_DET		0x38
4662306a36Sopenharmony_ci#define EN_HS_DET		(1 << 0)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* Misc2 Register (0x42) */
4962306a36Sopenharmony_ci#define REG_MISC2		0x42
5062306a36Sopenharmony_ci#define AUDIO_PLL		(1 << 5)
5162306a36Sopenharmony_ci#define AUDIO_SECTION_RESET	(1 << 4)
5262306a36Sopenharmony_ci#define AUDIO_SECTION_ON	(1 << 3)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* PCM Interface Register 2 (0xb1) */
5562306a36Sopenharmony_ci#define PCM_INF2_BCLK		(1 << 6)	/* Bit clock polarity */
5662306a36Sopenharmony_ci#define PCM_INF2_FS		(1 << 5)	/* Frame Sync polarity */
5762306a36Sopenharmony_ci#define PCM_INF2_MASTER		(1 << 4)	/* Master / Slave */
5862306a36Sopenharmony_ci#define PCM_INF2_18WL		(1 << 3)	/* 18 / 16 bits */
5962306a36Sopenharmony_ci#define PCM_GENERAL_I2S		0
6062306a36Sopenharmony_ci#define PCM_EXACT_I2S		1
6162306a36Sopenharmony_ci#define PCM_LEFT_I2S		2
6262306a36Sopenharmony_ci#define PCM_RIGHT_I2S		3
6362306a36Sopenharmony_ci#define PCM_SHORT_FS		4
6462306a36Sopenharmony_ci#define PCM_LONG_FS		5
6562306a36Sopenharmony_ci#define PCM_MODE_MASK		7
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* I2S Interface Register 4 (0xbe) */
6862306a36Sopenharmony_ci#define I2S_EQU_BYP		(1 << 6)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* DAC Offset Register (0xcb) */
7162306a36Sopenharmony_ci#define DAC_MUTE		(1 << 7)
7262306a36Sopenharmony_ci#define MUTE_LEFT		(1 << 6)
7362306a36Sopenharmony_ci#define MUTE_RIGHT		(1 << 2)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* ADC Analog Register 1 (0xd0) */
7662306a36Sopenharmony_ci#define REG_ADC_ANA_1		0xd0
7762306a36Sopenharmony_ci#define MIC1BIAS_MASK		0x60
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* Earpiece/Speaker Control Register 2 (0xda) */
8062306a36Sopenharmony_ci#define REG_EAR2		0xda
8162306a36Sopenharmony_ci#define RSYNC_CHANGE		(1 << 2)
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/* Audio Supplies Register 2 (0xdc) */
8462306a36Sopenharmony_ci#define REG_SUPPLIES2		0xdc
8562306a36Sopenharmony_ci#define LDO15_READY		(1 << 4)
8662306a36Sopenharmony_ci#define LDO15_EN		(1 << 3)
8762306a36Sopenharmony_ci#define CPUMP_READY		(1 << 2)
8862306a36Sopenharmony_ci#define CPUMP_EN		(1 << 1)
8962306a36Sopenharmony_ci#define AUDIO_EN		(1 << 0)
9062306a36Sopenharmony_ci#define SUPPLY_MASK		(LDO15_EN | CPUMP_EN | AUDIO_EN)
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* Audio Enable Register 1 (0xdd) */
9362306a36Sopenharmony_ci#define ADC_MOD_RIGHT		(1 << 1)
9462306a36Sopenharmony_ci#define ADC_MOD_LEFT		(1 << 0)
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* Audio Enable Register 2 (0xde) */
9762306a36Sopenharmony_ci#define ADC_LEFT		(1 << 5)
9862306a36Sopenharmony_ci#define ADC_RIGHT		(1 << 4)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* DAC Enable Register 2 (0xe1) */
10162306a36Sopenharmony_ci#define DAC_LEFT		(1 << 5)
10262306a36Sopenharmony_ci#define DAC_RIGHT		(1 << 4)
10362306a36Sopenharmony_ci#define MODULATOR		(1 << 3)
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/* Shorts Register (0xeb) */
10662306a36Sopenharmony_ci#define REG_SHORTS		0xeb
10762306a36Sopenharmony_ci#define CLR_SHORT_LO2		(1 << 7)
10862306a36Sopenharmony_ci#define SHORT_LO2		(1 << 6)
10962306a36Sopenharmony_ci#define CLR_SHORT_LO1		(1 << 5)
11062306a36Sopenharmony_ci#define SHORT_LO1		(1 << 4)
11162306a36Sopenharmony_ci#define CLR_SHORT_HS2		(1 << 3)
11262306a36Sopenharmony_ci#define SHORT_HS2		(1 << 2)
11362306a36Sopenharmony_ci#define CLR_SHORT_HS1		(1 << 1)
11462306a36Sopenharmony_ci#define SHORT_HS1		(1 << 0)
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci/*
11762306a36Sopenharmony_ci * This widget should be just after DAC & PGA in DAPM power-on sequence and
11862306a36Sopenharmony_ci * before DAC & PGA in DAPM power-off sequence.
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_ci#define PM860X_DAPM_OUTPUT(wname, wevent)	\
12162306a36Sopenharmony_ci	SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, 0, 0, NULL, 0, wevent, \
12262306a36Sopenharmony_ci			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD)
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistruct pm860x_det {
12562306a36Sopenharmony_ci	struct snd_soc_jack	*hp_jack;
12662306a36Sopenharmony_ci	struct snd_soc_jack	*mic_jack;
12762306a36Sopenharmony_ci	int			hp_det;
12862306a36Sopenharmony_ci	int			mic_det;
12962306a36Sopenharmony_ci	int			hook_det;
13062306a36Sopenharmony_ci	int			hs_shrt;
13162306a36Sopenharmony_ci	int			lo_shrt;
13262306a36Sopenharmony_ci};
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistruct pm860x_priv {
13562306a36Sopenharmony_ci	unsigned int		sysclk;
13662306a36Sopenharmony_ci	unsigned int		pcmclk;
13762306a36Sopenharmony_ci	unsigned int		dir;
13862306a36Sopenharmony_ci	unsigned int		filter;
13962306a36Sopenharmony_ci	struct snd_soc_component *component;
14062306a36Sopenharmony_ci	struct i2c_client	*i2c;
14162306a36Sopenharmony_ci	struct regmap		*regmap;
14262306a36Sopenharmony_ci	struct pm860x_chip	*chip;
14362306a36Sopenharmony_ci	struct pm860x_det	det;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	int			irq[4];
14662306a36Sopenharmony_ci	unsigned char		name[4][MAX_NAME_LEN];
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
15062306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/* -9dB to 0db in 3dB steps */
15362306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */
15662306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(mic_tlv,
15762306a36Sopenharmony_ci	0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0),
15862306a36Sopenharmony_ci	1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0),
15962306a36Sopenharmony_ci	2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0),
16062306a36Sopenharmony_ci	3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0),
16162306a36Sopenharmony_ci	4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0)
16262306a36Sopenharmony_ci);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/* {0, 0, 0, -6, 0, 6, 12, 18}dB */
16562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(aux_tlv,
16662306a36Sopenharmony_ci	0, 2, TLV_DB_SCALE_ITEM(0, 0, 0),
16762306a36Sopenharmony_ci	3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0)
16862306a36Sopenharmony_ci);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */
17162306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(out_tlv,
17262306a36Sopenharmony_ci	0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1),
17362306a36Sopenharmony_ci	4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0),
17462306a36Sopenharmony_ci	5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0),
17562306a36Sopenharmony_ci	6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0)
17662306a36Sopenharmony_ci);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(st_tlv,
17962306a36Sopenharmony_ci	0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0),
18062306a36Sopenharmony_ci	2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0),
18162306a36Sopenharmony_ci	4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0),
18262306a36Sopenharmony_ci	6, 7, TLV_DB_SCALE_ITEM(-10351, 116, 0),
18362306a36Sopenharmony_ci	8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0),
18462306a36Sopenharmony_ci	10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0),
18562306a36Sopenharmony_ci	14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0),
18662306a36Sopenharmony_ci	18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0)
18762306a36Sopenharmony_ci);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/* Sidetone Gain = M * 2^(-5-N) */
19062306a36Sopenharmony_cistruct st_gain {
19162306a36Sopenharmony_ci	unsigned int	db;
19262306a36Sopenharmony_ci	unsigned int	m;
19362306a36Sopenharmony_ci	unsigned int	n;
19462306a36Sopenharmony_ci};
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic struct st_gain st_table[] = {
19762306a36Sopenharmony_ci	{-12041,  1, 15}, {-11439,  1, 14}, {-11087,  3, 15}, {-10837,  1, 13},
19862306a36Sopenharmony_ci	{-10643,  5, 15}, {-10485,  3, 14}, {-10351,  7, 15}, {-10235,  1, 12},
19962306a36Sopenharmony_ci	{-10133,  9, 15}, {-10041,  5, 14}, { -9958, 11, 15}, { -9883,  3, 13},
20062306a36Sopenharmony_ci	{ -9813, 13, 15}, { -9749,  7, 14}, { -9689, 15, 15}, { -9633,  1, 11},
20162306a36Sopenharmony_ci	{ -9580, 17, 15}, { -9531,  9, 14}, { -9484, 19, 15}, { -9439,  5, 13},
20262306a36Sopenharmony_ci	{ -9397, 21, 15}, { -9356, 11, 14}, { -9318, 23, 15}, { -9281,  3, 12},
20362306a36Sopenharmony_ci	{ -9245, 25, 15}, { -9211, 13, 14}, { -9178, 27, 15}, { -9147,  7, 13},
20462306a36Sopenharmony_ci	{ -9116, 29, 15}, { -9087, 15, 14}, { -9058, 31, 15}, { -9031,  1, 10},
20562306a36Sopenharmony_ci	{ -8978, 17, 14}, { -8929,  9, 13}, { -8882, 19, 14}, { -8837,  5, 12},
20662306a36Sopenharmony_ci	{ -8795, 21, 14}, { -8754, 11, 13}, { -8716, 23, 14}, { -8679,  3, 11},
20762306a36Sopenharmony_ci	{ -8643, 25, 14}, { -8609, 13, 13}, { -8576, 27, 14}, { -8545,  7, 12},
20862306a36Sopenharmony_ci	{ -8514, 29, 14}, { -8485, 15, 13}, { -8456, 31, 14}, { -8429,  1,  9},
20962306a36Sopenharmony_ci	{ -8376, 17, 13}, { -8327,  9, 12}, { -8280, 19, 13}, { -8235,  5, 11},
21062306a36Sopenharmony_ci	{ -8193, 21, 13}, { -8152, 11, 12}, { -8114, 23, 13}, { -8077,  3, 10},
21162306a36Sopenharmony_ci	{ -8041, 25, 13}, { -8007, 13, 12}, { -7974, 27, 13}, { -7943,  7, 11},
21262306a36Sopenharmony_ci	{ -7912, 29, 13}, { -7883, 15, 12}, { -7854, 31, 13}, { -7827,  1,  8},
21362306a36Sopenharmony_ci	{ -7774, 17, 12}, { -7724,  9, 11}, { -7678, 19, 12}, { -7633,  5, 10},
21462306a36Sopenharmony_ci	{ -7591, 21, 12}, { -7550, 11, 11}, { -7512, 23, 12}, { -7475,  3,  9},
21562306a36Sopenharmony_ci	{ -7439, 25, 12}, { -7405, 13, 11}, { -7372, 27, 12}, { -7341,  7, 10},
21662306a36Sopenharmony_ci	{ -7310, 29, 12}, { -7281, 15, 11}, { -7252, 31, 12}, { -7225,  1,  7},
21762306a36Sopenharmony_ci	{ -7172, 17, 11}, { -7122,  9, 10}, { -7075, 19, 11}, { -7031,  5,  9},
21862306a36Sopenharmony_ci	{ -6989, 21, 11}, { -6948, 11, 10}, { -6910, 23, 11}, { -6873,  3,  8},
21962306a36Sopenharmony_ci	{ -6837, 25, 11}, { -6803, 13, 10}, { -6770, 27, 11}, { -6739,  7,  9},
22062306a36Sopenharmony_ci	{ -6708, 29, 11}, { -6679, 15, 10}, { -6650, 31, 11}, { -6623,  1,  6},
22162306a36Sopenharmony_ci	{ -6570, 17, 10}, { -6520,  9,  9}, { -6473, 19, 10}, { -6429,  5,  8},
22262306a36Sopenharmony_ci	{ -6386, 21, 10}, { -6346, 11,  9}, { -6307, 23, 10}, { -6270,  3,  7},
22362306a36Sopenharmony_ci	{ -6235, 25, 10}, { -6201, 13,  9}, { -6168, 27, 10}, { -6137,  7,  8},
22462306a36Sopenharmony_ci	{ -6106, 29, 10}, { -6077, 15,  9}, { -6048, 31, 10}, { -6021,  1,  5},
22562306a36Sopenharmony_ci	{ -5968, 17,  9}, { -5918,  9,  8}, { -5871, 19,  9}, { -5827,  5,  7},
22662306a36Sopenharmony_ci	{ -5784, 21,  9}, { -5744, 11,  8}, { -5705, 23,  9}, { -5668,  3,  6},
22762306a36Sopenharmony_ci	{ -5633, 25,  9}, { -5599, 13,  8}, { -5566, 27,  9}, { -5535,  7,  7},
22862306a36Sopenharmony_ci	{ -5504, 29,  9}, { -5475, 15,  8}, { -5446, 31,  9}, { -5419,  1,  4},
22962306a36Sopenharmony_ci	{ -5366, 17,  8}, { -5316,  9,  7}, { -5269, 19,  8}, { -5225,  5,  6},
23062306a36Sopenharmony_ci	{ -5182, 21,  8}, { -5142, 11,  7}, { -5103, 23,  8}, { -5066,  3,  5},
23162306a36Sopenharmony_ci	{ -5031, 25,  8}, { -4997, 13,  7}, { -4964, 27,  8}, { -4932,  7,  6},
23262306a36Sopenharmony_ci	{ -4902, 29,  8}, { -4873, 15,  7}, { -4844, 31,  8}, { -4816,  1,  3},
23362306a36Sopenharmony_ci	{ -4764, 17,  7}, { -4714,  9,  6}, { -4667, 19,  7}, { -4623,  5,  5},
23462306a36Sopenharmony_ci	{ -4580, 21,  7}, { -4540, 11,  6}, { -4501, 23,  7}, { -4464,  3,  4},
23562306a36Sopenharmony_ci	{ -4429, 25,  7}, { -4395, 13,  6}, { -4362, 27,  7}, { -4330,  7,  5},
23662306a36Sopenharmony_ci	{ -4300, 29,  7}, { -4270, 15,  6}, { -4242, 31,  7}, { -4214,  1,  2},
23762306a36Sopenharmony_ci	{ -4162, 17,  6}, { -4112,  9,  5}, { -4065, 19,  6}, { -4021,  5,  4},
23862306a36Sopenharmony_ci	{ -3978, 21,  6}, { -3938, 11,  5}, { -3899, 23,  6}, { -3862,  3,  3},
23962306a36Sopenharmony_ci	{ -3827, 25,  6}, { -3793, 13,  5}, { -3760, 27,  6}, { -3728,  7,  4},
24062306a36Sopenharmony_ci	{ -3698, 29,  6}, { -3668, 15,  5}, { -3640, 31,  6}, { -3612,  1,  1},
24162306a36Sopenharmony_ci	{ -3560, 17,  5}, { -3510,  9,  4}, { -3463, 19,  5}, { -3419,  5,  3},
24262306a36Sopenharmony_ci	{ -3376, 21,  5}, { -3336, 11,  4}, { -3297, 23,  5}, { -3260,  3,  2},
24362306a36Sopenharmony_ci	{ -3225, 25,  5}, { -3191, 13,  4}, { -3158, 27,  5}, { -3126,  7,  3},
24462306a36Sopenharmony_ci	{ -3096, 29,  5}, { -3066, 15,  4}, { -3038, 31,  5}, { -3010,  1,  0},
24562306a36Sopenharmony_ci	{ -2958, 17,  4}, { -2908,  9,  3}, { -2861, 19,  4}, { -2816,  5,  2},
24662306a36Sopenharmony_ci	{ -2774, 21,  4}, { -2734, 11,  3}, { -2695, 23,  4}, { -2658,  3,  1},
24762306a36Sopenharmony_ci	{ -2623, 25,  4}, { -2589, 13,  3}, { -2556, 27,  4}, { -2524,  7,  2},
24862306a36Sopenharmony_ci	{ -2494, 29,  4}, { -2464, 15,  3}, { -2436, 31,  4}, { -2408,  2,  0},
24962306a36Sopenharmony_ci	{ -2356, 17,  3}, { -2306,  9,  2}, { -2259, 19,  3}, { -2214,  5,  1},
25062306a36Sopenharmony_ci	{ -2172, 21,  3}, { -2132, 11,  2}, { -2093, 23,  3}, { -2056,  3,  0},
25162306a36Sopenharmony_ci	{ -2021, 25,  3}, { -1987, 13,  2}, { -1954, 27,  3}, { -1922,  7,  1},
25262306a36Sopenharmony_ci	{ -1892, 29,  3}, { -1862, 15,  2}, { -1834, 31,  3}, { -1806,  4,  0},
25362306a36Sopenharmony_ci	{ -1754, 17,  2}, { -1704,  9,  1}, { -1657, 19,  2}, { -1612,  5,  0},
25462306a36Sopenharmony_ci	{ -1570, 21,  2}, { -1530, 11,  1}, { -1491, 23,  2}, { -1454,  6,  0},
25562306a36Sopenharmony_ci	{ -1419, 25,  2}, { -1384, 13,  1}, { -1352, 27,  2}, { -1320,  7,  0},
25662306a36Sopenharmony_ci	{ -1290, 29,  2}, { -1260, 15,  1}, { -1232, 31,  2}, { -1204,  8,  0},
25762306a36Sopenharmony_ci	{ -1151, 17,  1}, { -1102,  9,  0}, { -1055, 19,  1}, { -1010, 10,  0},
25862306a36Sopenharmony_ci	{  -968, 21,  1}, {  -928, 11,  0}, {  -889, 23,  1}, {  -852, 12,  0},
25962306a36Sopenharmony_ci	{  -816, 25,  1}, {  -782, 13,  0}, {  -750, 27,  1}, {  -718, 14,  0},
26062306a36Sopenharmony_ci	{  -688, 29,  1}, {  -658, 15,  0}, {  -630, 31,  1}, {  -602, 16,  0},
26162306a36Sopenharmony_ci	{  -549, 17,  0}, {  -500, 18,  0}, {  -453, 19,  0}, {  -408, 20,  0},
26262306a36Sopenharmony_ci	{  -366, 21,  0}, {  -325, 22,  0}, {  -287, 23,  0}, {  -250, 24,  0},
26362306a36Sopenharmony_ci	{  -214, 25,  0}, {  -180, 26,  0}, {  -148, 27,  0}, {  -116, 28,  0},
26462306a36Sopenharmony_ci	{   -86, 29,  0}, {   -56, 30,  0}, {   -28, 31,  0}, {     0,  0,  0},
26562306a36Sopenharmony_ci};
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
26862306a36Sopenharmony_ci				   struct snd_ctl_elem_value *ucontrol)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct soc_mixer_control *mc =
27162306a36Sopenharmony_ci		(struct soc_mixer_control *)kcontrol->private_value;
27262306a36Sopenharmony_ci	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
27362306a36Sopenharmony_ci	unsigned int reg = mc->reg;
27462306a36Sopenharmony_ci	unsigned int reg2 = mc->rreg;
27562306a36Sopenharmony_ci	int val[2], val2[2], i;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	val[0] = snd_soc_component_read(component, reg) & 0x3f;
27862306a36Sopenharmony_ci	val[1] = (snd_soc_component_read(component, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
27962306a36Sopenharmony_ci	val2[0] = snd_soc_component_read(component, reg2) & 0x3f;
28062306a36Sopenharmony_ci	val2[1] = (snd_soc_component_read(component, PM860X_SIDETONE_SHIFT)) & 0xf;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(st_table); i++) {
28362306a36Sopenharmony_ci		if ((st_table[i].m == val[0]) && (st_table[i].n == val[1]))
28462306a36Sopenharmony_ci			ucontrol->value.integer.value[0] = i;
28562306a36Sopenharmony_ci		if ((st_table[i].m == val2[0]) && (st_table[i].n == val2[1]))
28662306a36Sopenharmony_ci			ucontrol->value.integer.value[1] = i;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci	return 0;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
29262306a36Sopenharmony_ci				   struct snd_ctl_elem_value *ucontrol)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct soc_mixer_control *mc =
29562306a36Sopenharmony_ci		(struct soc_mixer_control *)kcontrol->private_value;
29662306a36Sopenharmony_ci	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
29762306a36Sopenharmony_ci	unsigned int reg = mc->reg;
29862306a36Sopenharmony_ci	unsigned int reg2 = mc->rreg;
29962306a36Sopenharmony_ci	int err;
30062306a36Sopenharmony_ci	unsigned int val, val2;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	val = ucontrol->value.integer.value[0];
30362306a36Sopenharmony_ci	val2 = ucontrol->value.integer.value[1];
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (val >= ARRAY_SIZE(st_table) || val2 >= ARRAY_SIZE(st_table))
30662306a36Sopenharmony_ci		return -EINVAL;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	err = snd_soc_component_update_bits(component, reg, 0x3f, st_table[val].m);
30962306a36Sopenharmony_ci	if (err < 0)
31062306a36Sopenharmony_ci		return err;
31162306a36Sopenharmony_ci	err = snd_soc_component_update_bits(component, PM860X_SIDETONE_SHIFT, 0xf0,
31262306a36Sopenharmony_ci				  st_table[val].n << 4);
31362306a36Sopenharmony_ci	if (err < 0)
31462306a36Sopenharmony_ci		return err;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	err = snd_soc_component_update_bits(component, reg2, 0x3f, st_table[val2].m);
31762306a36Sopenharmony_ci	if (err < 0)
31862306a36Sopenharmony_ci		return err;
31962306a36Sopenharmony_ci	err = snd_soc_component_update_bits(component, PM860X_SIDETONE_SHIFT, 0x0f,
32062306a36Sopenharmony_ci				  st_table[val2].n);
32162306a36Sopenharmony_ci	return err;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
32562306a36Sopenharmony_ci				    struct snd_ctl_elem_value *ucontrol)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct soc_mixer_control *mc =
32862306a36Sopenharmony_ci		(struct soc_mixer_control *)kcontrol->private_value;
32962306a36Sopenharmony_ci	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
33062306a36Sopenharmony_ci	unsigned int reg = mc->reg;
33162306a36Sopenharmony_ci	unsigned int reg2 = mc->rreg;
33262306a36Sopenharmony_ci	unsigned int shift = mc->shift;
33362306a36Sopenharmony_ci	int max = mc->max, val, val2;
33462306a36Sopenharmony_ci	unsigned int mask = (1 << fls(max)) - 1;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	val = snd_soc_component_read(component, reg) >> shift;
33762306a36Sopenharmony_ci	val2 = snd_soc_component_read(component, reg2) >> shift;
33862306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = (max - val) & mask;
33962306a36Sopenharmony_ci	ucontrol->value.integer.value[1] = (max - val2) & mask;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	return 0;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
34562306a36Sopenharmony_ci				    struct snd_ctl_elem_value *ucontrol)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	struct soc_mixer_control *mc =
34862306a36Sopenharmony_ci		(struct soc_mixer_control *)kcontrol->private_value;
34962306a36Sopenharmony_ci	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
35062306a36Sopenharmony_ci	unsigned int reg = mc->reg;
35162306a36Sopenharmony_ci	unsigned int reg2 = mc->rreg;
35262306a36Sopenharmony_ci	unsigned int shift = mc->shift;
35362306a36Sopenharmony_ci	int max = mc->max;
35462306a36Sopenharmony_ci	unsigned int mask = (1 << fls(max)) - 1;
35562306a36Sopenharmony_ci	int err;
35662306a36Sopenharmony_ci	unsigned int val, val2, val_mask;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	val_mask = mask << shift;
35962306a36Sopenharmony_ci	val = ((max - ucontrol->value.integer.value[0]) & mask);
36062306a36Sopenharmony_ci	val2 = ((max - ucontrol->value.integer.value[1]) & mask);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	val = val << shift;
36362306a36Sopenharmony_ci	val2 = val2 << shift;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	err = snd_soc_component_update_bits(component, reg, val_mask, val);
36662306a36Sopenharmony_ci	if (err < 0)
36762306a36Sopenharmony_ci		return err;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	err = snd_soc_component_update_bits(component, reg2, val_mask, val2);
37062306a36Sopenharmony_ci	return err;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci/* DAPM Widget Events */
37462306a36Sopenharmony_ci/*
37562306a36Sopenharmony_ci * A lot registers are belong to RSYNC domain. It requires enabling RSYNC bit
37662306a36Sopenharmony_ci * after updating these registers. Otherwise, these updated registers won't
37762306a36Sopenharmony_ci * be effective.
37862306a36Sopenharmony_ci */
37962306a36Sopenharmony_cistatic int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
38062306a36Sopenharmony_ci			      struct snd_kcontrol *kcontrol, int event)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	/*
38562306a36Sopenharmony_ci	 * In order to avoid current on the load, mute power-on and power-off
38662306a36Sopenharmony_ci	 * should be transients.
38762306a36Sopenharmony_ci	 * Unmute by DAC_MUTE. It should be unmuted when DAPM sequence is
38862306a36Sopenharmony_ci	 * finished.
38962306a36Sopenharmony_ci	 */
39062306a36Sopenharmony_ci	snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, DAC_MUTE, 0);
39162306a36Sopenharmony_ci	snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
39262306a36Sopenharmony_ci			    RSYNC_CHANGE, RSYNC_CHANGE);
39362306a36Sopenharmony_ci	return 0;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic int pm860x_dac_event(struct snd_soc_dapm_widget *w,
39762306a36Sopenharmony_ci			    struct snd_kcontrol *kcontrol, int event)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
40062306a36Sopenharmony_ci	unsigned int dac = 0;
40162306a36Sopenharmony_ci	int data;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (!strcmp(w->name, "Left DAC"))
40462306a36Sopenharmony_ci		dac = DAC_LEFT;
40562306a36Sopenharmony_ci	if (!strcmp(w->name, "Right DAC"))
40662306a36Sopenharmony_ci		dac = DAC_RIGHT;
40762306a36Sopenharmony_ci	switch (event) {
40862306a36Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMU:
40962306a36Sopenharmony_ci		if (dac) {
41062306a36Sopenharmony_ci			/* Auto mute in power-on sequence. */
41162306a36Sopenharmony_ci			dac |= MODULATOR;
41262306a36Sopenharmony_ci			snd_soc_component_update_bits(component, PM860X_DAC_OFFSET,
41362306a36Sopenharmony_ci					    DAC_MUTE, DAC_MUTE);
41462306a36Sopenharmony_ci			snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
41562306a36Sopenharmony_ci					    RSYNC_CHANGE, RSYNC_CHANGE);
41662306a36Sopenharmony_ci			/* update dac */
41762306a36Sopenharmony_ci			snd_soc_component_update_bits(component, PM860X_DAC_EN_2,
41862306a36Sopenharmony_ci					    dac, dac);
41962306a36Sopenharmony_ci		}
42062306a36Sopenharmony_ci		break;
42162306a36Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMD:
42262306a36Sopenharmony_ci		if (dac) {
42362306a36Sopenharmony_ci			/* Auto mute in power-off sequence. */
42462306a36Sopenharmony_ci			snd_soc_component_update_bits(component, PM860X_DAC_OFFSET,
42562306a36Sopenharmony_ci					    DAC_MUTE, DAC_MUTE);
42662306a36Sopenharmony_ci			snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
42762306a36Sopenharmony_ci					    RSYNC_CHANGE, RSYNC_CHANGE);
42862306a36Sopenharmony_ci			/* update dac */
42962306a36Sopenharmony_ci			data = snd_soc_component_read(component, PM860X_DAC_EN_2);
43062306a36Sopenharmony_ci			data &= ~dac;
43162306a36Sopenharmony_ci			if (!(data & (DAC_LEFT | DAC_RIGHT)))
43262306a36Sopenharmony_ci				data &= ~MODULATOR;
43362306a36Sopenharmony_ci			snd_soc_component_write(component, PM860X_DAC_EN_2, data);
43462306a36Sopenharmony_ci		}
43562306a36Sopenharmony_ci		break;
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci	return 0;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"};
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"};
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_hs1_opamp_enum,
44562306a36Sopenharmony_ci			    PM860X_HS1_CTRL, 5, pm860x_opamp_texts);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_hs2_opamp_enum,
44862306a36Sopenharmony_ci			    PM860X_HS2_CTRL, 5, pm860x_opamp_texts);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_hs1_pa_enum,
45162306a36Sopenharmony_ci			    PM860X_HS1_CTRL, 3, pm860x_pa_texts);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_hs2_pa_enum,
45462306a36Sopenharmony_ci			    PM860X_HS2_CTRL, 3, pm860x_pa_texts);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_lo1_opamp_enum,
45762306a36Sopenharmony_ci			    PM860X_LO1_CTRL, 5, pm860x_opamp_texts);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_lo2_opamp_enum,
46062306a36Sopenharmony_ci			    PM860X_LO2_CTRL, 5, pm860x_opamp_texts);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_lo1_pa_enum,
46362306a36Sopenharmony_ci			    PM860X_LO1_CTRL, 3, pm860x_pa_texts);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_lo2_pa_enum,
46662306a36Sopenharmony_ci			    PM860X_LO2_CTRL, 3, pm860x_pa_texts);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_spk_pa_enum,
46962306a36Sopenharmony_ci			    PM860X_EAR_CTRL_1, 5, pm860x_pa_texts);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_ear_pa_enum,
47262306a36Sopenharmony_ci			    PM860X_EAR_CTRL_2, 0, pm860x_pa_texts);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(pm860x_spk_ear_opamp_enum,
47562306a36Sopenharmony_ci			    PM860X_EAR_CTRL_1, 3, pm860x_opamp_texts);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic const struct snd_kcontrol_new pm860x_snd_controls[] = {
47862306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2,
47962306a36Sopenharmony_ci			PM860X_ADC_ANA_3, 6, 3, 0, adc_tlv),
48062306a36Sopenharmony_ci	SOC_DOUBLE_TLV("AUX Capture Volume", PM860X_ADC_ANA_3, 0, 3, 7, 0,
48162306a36Sopenharmony_ci			aux_tlv),
48262306a36Sopenharmony_ci	SOC_SINGLE_TLV("MIC1 Capture Volume", PM860X_ADC_ANA_2, 0, 7, 0,
48362306a36Sopenharmony_ci			mic_tlv),
48462306a36Sopenharmony_ci	SOC_SINGLE_TLV("MIC3 Capture Volume", PM860X_ADC_ANA_2, 3, 7, 0,
48562306a36Sopenharmony_ci			mic_tlv),
48662306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("Sidetone Volume", PM860X_SIDETONE_L_GAIN,
48762306a36Sopenharmony_ci			     PM860X_SIDETONE_R_GAIN, 0, ARRAY_SIZE(st_table)-1,
48862306a36Sopenharmony_ci			     0, snd_soc_get_volsw_2r_st,
48962306a36Sopenharmony_ci			     snd_soc_put_volsw_2r_st, st_tlv),
49062306a36Sopenharmony_ci	SOC_SINGLE_TLV("Speaker Playback Volume", PM860X_EAR_CTRL_1,
49162306a36Sopenharmony_ci			0, 7, 0, out_tlv),
49262306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Line Playback Volume", PM860X_LO1_CTRL,
49362306a36Sopenharmony_ci			 PM860X_LO2_CTRL, 0, 7, 0, out_tlv),
49462306a36Sopenharmony_ci	SOC_DOUBLE_R_TLV("Headset Playback Volume", PM860X_HS1_CTRL,
49562306a36Sopenharmony_ci			 PM860X_HS2_CTRL, 0, 7, 0, out_tlv),
49662306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("Hifi Left Playback Volume",
49762306a36Sopenharmony_ci			     PM860X_HIFIL_GAIN_LEFT,
49862306a36Sopenharmony_ci			     PM860X_HIFIL_GAIN_RIGHT, 0, 63, 0,
49962306a36Sopenharmony_ci			     snd_soc_get_volsw_2r_out,
50062306a36Sopenharmony_ci			     snd_soc_put_volsw_2r_out, dpga_tlv),
50162306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("Hifi Right Playback Volume",
50262306a36Sopenharmony_ci			     PM860X_HIFIR_GAIN_LEFT,
50362306a36Sopenharmony_ci			     PM860X_HIFIR_GAIN_RIGHT, 0, 63, 0,
50462306a36Sopenharmony_ci			     snd_soc_get_volsw_2r_out,
50562306a36Sopenharmony_ci			     snd_soc_put_volsw_2r_out, dpga_tlv),
50662306a36Sopenharmony_ci	SOC_DOUBLE_R_EXT_TLV("Lofi Playback Volume", PM860X_LOFI_GAIN_LEFT,
50762306a36Sopenharmony_ci			     PM860X_LOFI_GAIN_RIGHT, 0, 63, 0,
50862306a36Sopenharmony_ci			     snd_soc_get_volsw_2r_out,
50962306a36Sopenharmony_ci			     snd_soc_put_volsw_2r_out, dpga_tlv),
51062306a36Sopenharmony_ci	SOC_ENUM("Headset1 Operational Amplifier Current",
51162306a36Sopenharmony_ci		 pm860x_hs1_opamp_enum),
51262306a36Sopenharmony_ci	SOC_ENUM("Headset2 Operational Amplifier Current",
51362306a36Sopenharmony_ci		 pm860x_hs2_opamp_enum),
51462306a36Sopenharmony_ci	SOC_ENUM("Headset1 Amplifier Current", pm860x_hs1_pa_enum),
51562306a36Sopenharmony_ci	SOC_ENUM("Headset2 Amplifier Current", pm860x_hs2_pa_enum),
51662306a36Sopenharmony_ci	SOC_ENUM("Lineout1 Operational Amplifier Current",
51762306a36Sopenharmony_ci		 pm860x_lo1_opamp_enum),
51862306a36Sopenharmony_ci	SOC_ENUM("Lineout2 Operational Amplifier Current",
51962306a36Sopenharmony_ci		 pm860x_lo2_opamp_enum),
52062306a36Sopenharmony_ci	SOC_ENUM("Lineout1 Amplifier Current", pm860x_lo1_pa_enum),
52162306a36Sopenharmony_ci	SOC_ENUM("Lineout2 Amplifier Current", pm860x_lo2_pa_enum),
52262306a36Sopenharmony_ci	SOC_ENUM("Speaker Operational Amplifier Current",
52362306a36Sopenharmony_ci		 pm860x_spk_ear_opamp_enum),
52462306a36Sopenharmony_ci	SOC_ENUM("Speaker Amplifier Current", pm860x_spk_pa_enum),
52562306a36Sopenharmony_ci	SOC_ENUM("Earpiece Amplifier Current", pm860x_ear_pa_enum),
52662306a36Sopenharmony_ci};
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci/*
52962306a36Sopenharmony_ci * DAPM Controls
53062306a36Sopenharmony_ci */
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci/* AUX1 Switch */
53362306a36Sopenharmony_cistatic const struct snd_kcontrol_new aux1_switch_controls =
53462306a36Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci/* AUX2 Switch */
53762306a36Sopenharmony_cistatic const struct snd_kcontrol_new aux2_switch_controls =
53862306a36Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 5, 1, 0);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci/* Left Ex. PA Switch */
54162306a36Sopenharmony_cistatic const struct snd_kcontrol_new lepa_switch_controls =
54262306a36Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 2, 1, 0);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci/* Right Ex. PA Switch */
54562306a36Sopenharmony_cistatic const struct snd_kcontrol_new repa_switch_controls =
54662306a36Sopenharmony_ci	SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci/* I2S Mux / Mux9 */
54962306a36Sopenharmony_cistatic const char *i2s_din_text[] = {
55062306a36Sopenharmony_ci	"DIN", "DIN1",
55162306a36Sopenharmony_ci};
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(i2s_din_enum,
55462306a36Sopenharmony_ci			    PM860X_I2S_IFACE_3, 1, i2s_din_text);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic const struct snd_kcontrol_new i2s_din_mux =
55762306a36Sopenharmony_ci	SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci/* I2S Mic Mux / Mux8 */
56062306a36Sopenharmony_cistatic const char *i2s_mic_text[] = {
56162306a36Sopenharmony_ci	"Ex PA", "ADC",
56262306a36Sopenharmony_ci};
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(i2s_mic_enum,
56562306a36Sopenharmony_ci			    PM860X_I2S_IFACE_3, 4, i2s_mic_text);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic const struct snd_kcontrol_new i2s_mic_mux =
56862306a36Sopenharmony_ci	SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci/* ADCL Mux / Mux2 */
57162306a36Sopenharmony_cistatic const char *adcl_text[] = {
57262306a36Sopenharmony_ci	"ADCR", "ADCL",
57362306a36Sopenharmony_ci};
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(adcl_enum,
57662306a36Sopenharmony_ci			    PM860X_PCM_IFACE_3, 4, adcl_text);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic const struct snd_kcontrol_new adcl_mux =
57962306a36Sopenharmony_ci	SOC_DAPM_ENUM("ADC Left Mux", adcl_enum);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci/* ADCR Mux / Mux3 */
58262306a36Sopenharmony_cistatic const char *adcr_text[] = {
58362306a36Sopenharmony_ci	"ADCL", "ADCR",
58462306a36Sopenharmony_ci};
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(adcr_enum,
58762306a36Sopenharmony_ci			    PM860X_PCM_IFACE_3, 2, adcr_text);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_cistatic const struct snd_kcontrol_new adcr_mux =
59062306a36Sopenharmony_ci	SOC_DAPM_ENUM("ADC Right Mux", adcr_enum);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci/* ADCR EC Mux / Mux6 */
59362306a36Sopenharmony_cistatic const char *adcr_ec_text[] = {
59462306a36Sopenharmony_ci	"ADCR", "EC",
59562306a36Sopenharmony_ci};
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(adcr_ec_enum,
59862306a36Sopenharmony_ci			    PM860X_ADC_EN_2, 3, adcr_ec_text);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic const struct snd_kcontrol_new adcr_ec_mux =
60162306a36Sopenharmony_ci	SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci/* EC Mux / Mux4 */
60462306a36Sopenharmony_cistatic const char *ec_text[] = {
60562306a36Sopenharmony_ci	"Left", "Right", "Left + Right",
60662306a36Sopenharmony_ci};
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(ec_enum,
60962306a36Sopenharmony_ci			    PM860X_EC_PATH, 1, ec_text);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic const struct snd_kcontrol_new ec_mux =
61262306a36Sopenharmony_ci	SOC_DAPM_ENUM("EC Mux", ec_enum);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic const char *dac_text[] = {
61562306a36Sopenharmony_ci	"No input", "Right", "Left", "No input",
61662306a36Sopenharmony_ci};
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci/* DAC Headset 1 Mux / Mux10 */
61962306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dac_hs1_enum,
62062306a36Sopenharmony_ci			    PM860X_ANA_INPUT_SEL_1, 0, dac_text);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic const struct snd_kcontrol_new dac_hs1_mux =
62362306a36Sopenharmony_ci	SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci/* DAC Headset 2 Mux / Mux11 */
62662306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dac_hs2_enum,
62762306a36Sopenharmony_ci			    PM860X_ANA_INPUT_SEL_1, 2, dac_text);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cistatic const struct snd_kcontrol_new dac_hs2_mux =
63062306a36Sopenharmony_ci	SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci/* DAC Lineout 1 Mux / Mux12 */
63362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dac_lo1_enum,
63462306a36Sopenharmony_ci			    PM860X_ANA_INPUT_SEL_1, 4, dac_text);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic const struct snd_kcontrol_new dac_lo1_mux =
63762306a36Sopenharmony_ci	SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci/* DAC Lineout 2 Mux / Mux13 */
64062306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dac_lo2_enum,
64162306a36Sopenharmony_ci			    PM860X_ANA_INPUT_SEL_1, 6, dac_text);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cistatic const struct snd_kcontrol_new dac_lo2_mux =
64462306a36Sopenharmony_ci	SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci/* DAC Spearker Earphone Mux / Mux14 */
64762306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(dac_spk_ear_enum,
64862306a36Sopenharmony_ci			    PM860X_ANA_INPUT_SEL_2, 0, dac_text);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cistatic const struct snd_kcontrol_new dac_spk_ear_mux =
65162306a36Sopenharmony_ci	SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci/* Headset 1 Mux / Mux15 */
65462306a36Sopenharmony_cistatic const char *in_text[] = {
65562306a36Sopenharmony_ci	"Digital", "Analog",
65662306a36Sopenharmony_ci};
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(hs1_enum,
65962306a36Sopenharmony_ci			    PM860X_ANA_TO_ANA, 0, in_text);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic const struct snd_kcontrol_new hs1_mux =
66262306a36Sopenharmony_ci	SOC_DAPM_ENUM("Headset1 Mux", hs1_enum);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/* Headset 2 Mux / Mux16 */
66562306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(hs2_enum,
66662306a36Sopenharmony_ci			    PM860X_ANA_TO_ANA, 1, in_text);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic const struct snd_kcontrol_new hs2_mux =
66962306a36Sopenharmony_ci	SOC_DAPM_ENUM("Headset2 Mux", hs2_enum);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci/* Lineout 1 Mux / Mux17 */
67262306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(lo1_enum,
67362306a36Sopenharmony_ci			    PM860X_ANA_TO_ANA, 2, in_text);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic const struct snd_kcontrol_new lo1_mux =
67662306a36Sopenharmony_ci	SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci/* Lineout 2 Mux / Mux18 */
67962306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(lo2_enum,
68062306a36Sopenharmony_ci			    PM860X_ANA_TO_ANA, 3, in_text);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic const struct snd_kcontrol_new lo2_mux =
68362306a36Sopenharmony_ci	SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci/* Speaker Earpiece Demux */
68662306a36Sopenharmony_cistatic const char *spk_text[] = {
68762306a36Sopenharmony_ci	"Earpiece", "Speaker",
68862306a36Sopenharmony_ci};
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(spk_enum,
69162306a36Sopenharmony_ci			    PM860X_ANA_TO_ANA, 6, spk_text);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cistatic const struct snd_kcontrol_new spk_demux =
69462306a36Sopenharmony_ci	SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci/* MIC Mux / Mux1 */
69762306a36Sopenharmony_cistatic const char *mic_text[] = {
69862306a36Sopenharmony_ci	"Mic 1", "Mic 2",
69962306a36Sopenharmony_ci};
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(mic_enum,
70262306a36Sopenharmony_ci			    PM860X_ADC_ANA_4, 4, mic_text);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_cistatic const struct snd_kcontrol_new mic_mux =
70562306a36Sopenharmony_ci	SOC_DAPM_ENUM("MIC Mux", mic_enum);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = {
70862306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("PCM SDI", "PCM Playback", 0,
70962306a36Sopenharmony_ci			    PM860X_ADC_EN_2, 0, 0),
71062306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("PCM SDO", "PCM Capture", 0,
71162306a36Sopenharmony_ci			     PM860X_PCM_IFACE_3, 1, 1),
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0,
71562306a36Sopenharmony_ci			    SND_SOC_NOPM, 0, 0),
71662306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0,
71762306a36Sopenharmony_ci			    SND_SOC_NOPM, 0, 0),
71862306a36Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0,
71962306a36Sopenharmony_ci			     PM860X_I2S_IFACE_3, 5, 1),
72062306a36Sopenharmony_ci	SND_SOC_DAPM_SUPPLY("I2S CLK", PM860X_DAC_EN_2, 0, 0, NULL, 0),
72162306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux),
72262306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux),
72362306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
72462306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("EC Mux", SND_SOC_NOPM, 0, 0, &ec_mux),
72562306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("ADCR EC Mux", SND_SOC_NOPM, 0, 0, &adcr_ec_mux),
72662306a36Sopenharmony_ci	SND_SOC_DAPM_SWITCH("Left EPA", SND_SOC_NOPM, 0, 0,
72762306a36Sopenharmony_ci			    &lepa_switch_controls),
72862306a36Sopenharmony_ci	SND_SOC_DAPM_SWITCH("Right EPA", SND_SOC_NOPM, 0, 0,
72962306a36Sopenharmony_ci			    &repa_switch_controls),
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Left ADC MOD", PM860X_ADC_EN_1,
73262306a36Sopenharmony_ci			 0, 1, 1, 0),
73362306a36Sopenharmony_ci	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Right ADC MOD", PM860X_ADC_EN_1,
73462306a36Sopenharmony_ci			 1, 1, 1, 0),
73562306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("Left ADC", NULL, PM860X_ADC_EN_2, 5, 0),
73662306a36Sopenharmony_ci	SND_SOC_DAPM_ADC("Right ADC", NULL, PM860X_ADC_EN_2, 4, 0),
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	SND_SOC_DAPM_SWITCH("AUX1 Switch", SND_SOC_NOPM, 0, 0,
73962306a36Sopenharmony_ci			    &aux1_switch_controls),
74062306a36Sopenharmony_ci	SND_SOC_DAPM_SWITCH("AUX2 Switch", SND_SOC_NOPM, 0, 0,
74162306a36Sopenharmony_ci			    &aux2_switch_controls),
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("MIC Mux", SND_SOC_NOPM, 0, 0, &mic_mux),
74462306a36Sopenharmony_ci	SND_SOC_DAPM_MICBIAS("Mic1 Bias", PM860X_ADC_ANA_1, 2, 0),
74562306a36Sopenharmony_ci	SND_SOC_DAPM_MICBIAS("Mic3 Bias", PM860X_ADC_ANA_1, 7, 0),
74662306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("MIC1 Volume", PM860X_ADC_EN_1, 2, 0, NULL, 0),
74762306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("MIC3 Volume", PM860X_ADC_EN_1, 3, 0, NULL, 0),
74862306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("AUX1 Volume", PM860X_ADC_EN_1, 4, 0, NULL, 0),
74962306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("AUX2 Volume", PM860X_ADC_EN_1, 5, 0, NULL, 0),
75062306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("Sidetone PGA", PM860X_ADC_EN_2, 1, 0, NULL, 0),
75162306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("Lofi PGA", PM860X_ADC_EN_2, 2, 0, NULL, 0),
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("AUX1"),
75462306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("AUX2"),
75562306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("MIC1P"),
75662306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("MIC1N"),
75762306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("MIC2P"),
75862306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("MIC2N"),
75962306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("MIC3P"),
76062306a36Sopenharmony_ci	SND_SOC_DAPM_INPUT("MIC3N"),
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	SND_SOC_DAPM_DAC_E("Left DAC", NULL, SND_SOC_NOPM, 0, 0,
76362306a36Sopenharmony_ci			   pm860x_dac_event,
76462306a36Sopenharmony_ci			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
76562306a36Sopenharmony_ci	SND_SOC_DAPM_DAC_E("Right DAC", NULL, SND_SOC_NOPM, 0, 0,
76662306a36Sopenharmony_ci			   pm860x_dac_event,
76762306a36Sopenharmony_ci			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("I2S DIN Mux", SND_SOC_NOPM, 0, 0, &i2s_din_mux),
77062306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("DAC HS1 Mux", SND_SOC_NOPM, 0, 0, &dac_hs1_mux),
77162306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("DAC HS2 Mux", SND_SOC_NOPM, 0, 0, &dac_hs2_mux),
77262306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("DAC LO1 Mux", SND_SOC_NOPM, 0, 0, &dac_lo1_mux),
77362306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("DAC LO2 Mux", SND_SOC_NOPM, 0, 0, &dac_lo2_mux),
77462306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("DAC SP Mux", SND_SOC_NOPM, 0, 0, &dac_spk_ear_mux),
77562306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("Headset1 Mux", SND_SOC_NOPM, 0, 0, &hs1_mux),
77662306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("Headset2 Mux", SND_SOC_NOPM, 0, 0, &hs2_mux),
77762306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("Lineout1 Mux", SND_SOC_NOPM, 0, 0, &lo1_mux),
77862306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("Lineout2 Mux", SND_SOC_NOPM, 0, 0, &lo2_mux),
77962306a36Sopenharmony_ci	SND_SOC_DAPM_MUX("Speaker Earpiece Demux", SND_SOC_NOPM, 0, 0,
78062306a36Sopenharmony_ci			 &spk_demux),
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("Headset1 PGA", PM860X_DAC_EN_1, 0, 0, NULL, 0),
78462306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("Headset2 PGA", PM860X_DAC_EN_1, 1, 0, NULL, 0),
78562306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("HS1"),
78662306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("HS2"),
78762306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("Lineout1 PGA", PM860X_DAC_EN_1, 2, 0, NULL, 0),
78862306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("Lineout2 PGA", PM860X_DAC_EN_1, 3, 0, NULL, 0),
78962306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
79062306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
79162306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("Earpiece PGA", PM860X_DAC_EN_1, 4, 0, NULL, 0),
79262306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("EARP"),
79362306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("EARN"),
79462306a36Sopenharmony_ci	SND_SOC_DAPM_PGA("Speaker PGA", PM860X_DAC_EN_1, 5, 0, NULL, 0),
79562306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LSP"),
79662306a36Sopenharmony_ci	SND_SOC_DAPM_OUTPUT("LSN"),
79762306a36Sopenharmony_ci	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "VCODEC", PM860X_AUDIO_SUPPLIES_2,
79862306a36Sopenharmony_ci			 0, SUPPLY_MASK, SUPPLY_MASK, 0),
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	PM860X_DAPM_OUTPUT("RSYNC", pm860x_rsync_event),
80162306a36Sopenharmony_ci};
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic const struct snd_soc_dapm_route pm860x_dapm_routes[] = {
80462306a36Sopenharmony_ci	/* supply */
80562306a36Sopenharmony_ci	{"Left DAC", NULL, "VCODEC"},
80662306a36Sopenharmony_ci	{"Right DAC", NULL, "VCODEC"},
80762306a36Sopenharmony_ci	{"Left ADC", NULL, "VCODEC"},
80862306a36Sopenharmony_ci	{"Right ADC", NULL, "VCODEC"},
80962306a36Sopenharmony_ci	{"Left ADC", NULL, "Left ADC MOD"},
81062306a36Sopenharmony_ci	{"Right ADC", NULL, "Right ADC MOD"},
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/* I2S Clock */
81362306a36Sopenharmony_ci	{"I2S DIN", NULL, "I2S CLK"},
81462306a36Sopenharmony_ci	{"I2S DIN1", NULL, "I2S CLK"},
81562306a36Sopenharmony_ci	{"I2S DOUT", NULL, "I2S CLK"},
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/* PCM/AIF1 Inputs */
81862306a36Sopenharmony_ci	{"PCM SDO", NULL, "ADC Left Mux"},
81962306a36Sopenharmony_ci	{"PCM SDO", NULL, "ADCR EC Mux"},
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	/* PCM/AFI2 Outputs */
82262306a36Sopenharmony_ci	{"Lofi PGA", NULL, "PCM SDI"},
82362306a36Sopenharmony_ci	{"Lofi PGA", NULL, "Sidetone PGA"},
82462306a36Sopenharmony_ci	{"Left DAC", NULL, "Lofi PGA"},
82562306a36Sopenharmony_ci	{"Right DAC", NULL, "Lofi PGA"},
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	/* I2S/AIF2 Inputs */
82862306a36Sopenharmony_ci	{"MIC Mux", "Mic 1", "MIC1P"},
82962306a36Sopenharmony_ci	{"MIC Mux", "Mic 1", "MIC1N"},
83062306a36Sopenharmony_ci	{"MIC Mux", "Mic 2", "MIC2P"},
83162306a36Sopenharmony_ci	{"MIC Mux", "Mic 2", "MIC2N"},
83262306a36Sopenharmony_ci	{"MIC1 Volume", NULL, "MIC Mux"},
83362306a36Sopenharmony_ci	{"MIC3 Volume", NULL, "MIC3P"},
83462306a36Sopenharmony_ci	{"MIC3 Volume", NULL, "MIC3N"},
83562306a36Sopenharmony_ci	{"Left ADC", NULL, "MIC1 Volume"},
83662306a36Sopenharmony_ci	{"Right ADC", NULL, "MIC3 Volume"},
83762306a36Sopenharmony_ci	{"ADC Left Mux", "ADCR", "Right ADC"},
83862306a36Sopenharmony_ci	{"ADC Left Mux", "ADCL", "Left ADC"},
83962306a36Sopenharmony_ci	{"ADC Right Mux", "ADCL", "Left ADC"},
84062306a36Sopenharmony_ci	{"ADC Right Mux", "ADCR", "Right ADC"},
84162306a36Sopenharmony_ci	{"Left EPA", "Switch", "Left DAC"},
84262306a36Sopenharmony_ci	{"Right EPA", "Switch", "Right DAC"},
84362306a36Sopenharmony_ci	{"EC Mux", "Left", "Left DAC"},
84462306a36Sopenharmony_ci	{"EC Mux", "Right", "Right DAC"},
84562306a36Sopenharmony_ci	{"EC Mux", "Left + Right", "Left DAC"},
84662306a36Sopenharmony_ci	{"EC Mux", "Left + Right", "Right DAC"},
84762306a36Sopenharmony_ci	{"ADCR EC Mux", "ADCR", "ADC Right Mux"},
84862306a36Sopenharmony_ci	{"ADCR EC Mux", "EC", "EC Mux"},
84962306a36Sopenharmony_ci	{"I2S Mic Mux", "Ex PA", "Left EPA"},
85062306a36Sopenharmony_ci	{"I2S Mic Mux", "Ex PA", "Right EPA"},
85162306a36Sopenharmony_ci	{"I2S Mic Mux", "ADC", "ADC Left Mux"},
85262306a36Sopenharmony_ci	{"I2S Mic Mux", "ADC", "ADCR EC Mux"},
85362306a36Sopenharmony_ci	{"I2S DOUT", NULL, "I2S Mic Mux"},
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	/* I2S/AIF2 Outputs */
85662306a36Sopenharmony_ci	{"I2S DIN Mux", "DIN", "I2S DIN"},
85762306a36Sopenharmony_ci	{"I2S DIN Mux", "DIN1", "I2S DIN1"},
85862306a36Sopenharmony_ci	{"Left DAC", NULL, "I2S DIN Mux"},
85962306a36Sopenharmony_ci	{"Right DAC", NULL, "I2S DIN Mux"},
86062306a36Sopenharmony_ci	{"DAC HS1 Mux", "Left", "Left DAC"},
86162306a36Sopenharmony_ci	{"DAC HS1 Mux", "Right", "Right DAC"},
86262306a36Sopenharmony_ci	{"DAC HS2 Mux", "Left", "Left DAC"},
86362306a36Sopenharmony_ci	{"DAC HS2 Mux", "Right", "Right DAC"},
86462306a36Sopenharmony_ci	{"DAC LO1 Mux", "Left", "Left DAC"},
86562306a36Sopenharmony_ci	{"DAC LO1 Mux", "Right", "Right DAC"},
86662306a36Sopenharmony_ci	{"DAC LO2 Mux", "Left", "Left DAC"},
86762306a36Sopenharmony_ci	{"DAC LO2 Mux", "Right", "Right DAC"},
86862306a36Sopenharmony_ci	{"Headset1 Mux", "Digital", "DAC HS1 Mux"},
86962306a36Sopenharmony_ci	{"Headset2 Mux", "Digital", "DAC HS2 Mux"},
87062306a36Sopenharmony_ci	{"Lineout1 Mux", "Digital", "DAC LO1 Mux"},
87162306a36Sopenharmony_ci	{"Lineout2 Mux", "Digital", "DAC LO2 Mux"},
87262306a36Sopenharmony_ci	{"Headset1 PGA", NULL, "Headset1 Mux"},
87362306a36Sopenharmony_ci	{"Headset2 PGA", NULL, "Headset2 Mux"},
87462306a36Sopenharmony_ci	{"Lineout1 PGA", NULL, "Lineout1 Mux"},
87562306a36Sopenharmony_ci	{"Lineout2 PGA", NULL, "Lineout2 Mux"},
87662306a36Sopenharmony_ci	{"DAC SP Mux", "Left", "Left DAC"},
87762306a36Sopenharmony_ci	{"DAC SP Mux", "Right", "Right DAC"},
87862306a36Sopenharmony_ci	{"Speaker Earpiece Demux", "Speaker", "DAC SP Mux"},
87962306a36Sopenharmony_ci	{"Speaker PGA", NULL, "Speaker Earpiece Demux"},
88062306a36Sopenharmony_ci	{"Earpiece PGA", NULL, "Speaker Earpiece Demux"},
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	{"RSYNC", NULL, "Headset1 PGA"},
88362306a36Sopenharmony_ci	{"RSYNC", NULL, "Headset2 PGA"},
88462306a36Sopenharmony_ci	{"RSYNC", NULL, "Lineout1 PGA"},
88562306a36Sopenharmony_ci	{"RSYNC", NULL, "Lineout2 PGA"},
88662306a36Sopenharmony_ci	{"RSYNC", NULL, "Speaker PGA"},
88762306a36Sopenharmony_ci	{"RSYNC", NULL, "Speaker PGA"},
88862306a36Sopenharmony_ci	{"RSYNC", NULL, "Earpiece PGA"},
88962306a36Sopenharmony_ci	{"RSYNC", NULL, "Earpiece PGA"},
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	{"HS1", NULL, "RSYNC"},
89262306a36Sopenharmony_ci	{"HS2", NULL, "RSYNC"},
89362306a36Sopenharmony_ci	{"LINEOUT1", NULL, "RSYNC"},
89462306a36Sopenharmony_ci	{"LINEOUT2", NULL, "RSYNC"},
89562306a36Sopenharmony_ci	{"LSP", NULL, "RSYNC"},
89662306a36Sopenharmony_ci	{"LSN", NULL, "RSYNC"},
89762306a36Sopenharmony_ci	{"EARP", NULL, "RSYNC"},
89862306a36Sopenharmony_ci	{"EARN", NULL, "RSYNC"},
89962306a36Sopenharmony_ci};
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci/*
90262306a36Sopenharmony_ci * Use MUTE_LEFT & MUTE_RIGHT to implement digital mute.
90362306a36Sopenharmony_ci * These bits can also be used to mute.
90462306a36Sopenharmony_ci */
90562306a36Sopenharmony_cistatic int pm860x_mute_stream(struct snd_soc_dai *codec_dai, int mute, int direction)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	struct snd_soc_component *component = codec_dai->component;
90862306a36Sopenharmony_ci	int data = 0, mask = MUTE_LEFT | MUTE_RIGHT;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	if (mute)
91162306a36Sopenharmony_ci		data = mask;
91262306a36Sopenharmony_ci	snd_soc_component_update_bits(component, PM860X_DAC_OFFSET, mask, data);
91362306a36Sopenharmony_ci	snd_soc_component_update_bits(component, PM860X_EAR_CTRL_2,
91462306a36Sopenharmony_ci			    RSYNC_CHANGE, RSYNC_CHANGE);
91562306a36Sopenharmony_ci	return 0;
91662306a36Sopenharmony_ci}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_cistatic int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
91962306a36Sopenharmony_ci				struct snd_pcm_hw_params *params,
92062306a36Sopenharmony_ci				struct snd_soc_dai *dai)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
92362306a36Sopenharmony_ci	unsigned char inf = 0, mask = 0;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	/* bit size */
92662306a36Sopenharmony_ci	switch (params_width(params)) {
92762306a36Sopenharmony_ci	case 16:
92862306a36Sopenharmony_ci		inf &= ~PCM_INF2_18WL;
92962306a36Sopenharmony_ci		break;
93062306a36Sopenharmony_ci	case 18:
93162306a36Sopenharmony_ci		inf |= PCM_INF2_18WL;
93262306a36Sopenharmony_ci		break;
93362306a36Sopenharmony_ci	default:
93462306a36Sopenharmony_ci		return -EINVAL;
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci	mask |= PCM_INF2_18WL;
93762306a36Sopenharmony_ci	snd_soc_component_update_bits(component, PM860X_PCM_IFACE_2, mask, inf);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	/* sample rate */
94062306a36Sopenharmony_ci	switch (params_rate(params)) {
94162306a36Sopenharmony_ci	case 8000:
94262306a36Sopenharmony_ci		inf = 0;
94362306a36Sopenharmony_ci		break;
94462306a36Sopenharmony_ci	case 16000:
94562306a36Sopenharmony_ci		inf = 3;
94662306a36Sopenharmony_ci		break;
94762306a36Sopenharmony_ci	case 32000:
94862306a36Sopenharmony_ci		inf = 6;
94962306a36Sopenharmony_ci		break;
95062306a36Sopenharmony_ci	case 48000:
95162306a36Sopenharmony_ci		inf = 8;
95262306a36Sopenharmony_ci		break;
95362306a36Sopenharmony_ci	default:
95462306a36Sopenharmony_ci		return -EINVAL;
95562306a36Sopenharmony_ci	}
95662306a36Sopenharmony_ci	snd_soc_component_update_bits(component, PM860X_PCM_RATE, 0x0f, inf);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	return 0;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
96262306a36Sopenharmony_ci				  unsigned int fmt)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	struct snd_soc_component *component = codec_dai->component;
96562306a36Sopenharmony_ci	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
96662306a36Sopenharmony_ci	unsigned char inf = 0, mask = 0;
96762306a36Sopenharmony_ci	int ret = -EINVAL;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	/* set audio interface clocking */
97262306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
97362306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBP_CFP:
97462306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBP_CFC:
97562306a36Sopenharmony_ci		if (pm860x->dir == PM860X_CLK_DIR_OUT) {
97662306a36Sopenharmony_ci			inf |= PCM_INF2_MASTER;
97762306a36Sopenharmony_ci			ret = 0;
97862306a36Sopenharmony_ci		}
97962306a36Sopenharmony_ci		break;
98062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBC_CFC:
98162306a36Sopenharmony_ci		if (pm860x->dir == PM860X_CLK_DIR_IN) {
98262306a36Sopenharmony_ci			inf &= ~PCM_INF2_MASTER;
98362306a36Sopenharmony_ci			ret = 0;
98462306a36Sopenharmony_ci		}
98562306a36Sopenharmony_ci		break;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
98962306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
99062306a36Sopenharmony_ci		inf |= PCM_EXACT_I2S;
99162306a36Sopenharmony_ci		ret = 0;
99262306a36Sopenharmony_ci		break;
99362306a36Sopenharmony_ci	}
99462306a36Sopenharmony_ci	mask |= PCM_MODE_MASK;
99562306a36Sopenharmony_ci	if (ret)
99662306a36Sopenharmony_ci		return ret;
99762306a36Sopenharmony_ci	snd_soc_component_update_bits(component, PM860X_PCM_IFACE_2, mask, inf);
99862306a36Sopenharmony_ci	return 0;
99962306a36Sopenharmony_ci}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cistatic int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
100262306a36Sopenharmony_ci				 int clk_id, unsigned int freq, int dir)
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	struct snd_soc_component *component = codec_dai->component;
100562306a36Sopenharmony_ci	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	if (dir == PM860X_CLK_DIR_OUT)
100862306a36Sopenharmony_ci		pm860x->dir = PM860X_CLK_DIR_OUT;
100962306a36Sopenharmony_ci	else	/* Slave mode is not supported */
101062306a36Sopenharmony_ci		return -EINVAL;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	return 0;
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
101662306a36Sopenharmony_ci				struct snd_pcm_hw_params *params,
101762306a36Sopenharmony_ci				struct snd_soc_dai *dai)
101862306a36Sopenharmony_ci{
101962306a36Sopenharmony_ci	struct snd_soc_component *component = dai->component;
102062306a36Sopenharmony_ci	unsigned char inf;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	/* bit size */
102362306a36Sopenharmony_ci	switch (params_width(params)) {
102462306a36Sopenharmony_ci	case 16:
102562306a36Sopenharmony_ci		inf = 0;
102662306a36Sopenharmony_ci		break;
102762306a36Sopenharmony_ci	case 18:
102862306a36Sopenharmony_ci		inf = PCM_INF2_18WL;
102962306a36Sopenharmony_ci		break;
103062306a36Sopenharmony_ci	default:
103162306a36Sopenharmony_ci		return -EINVAL;
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci	snd_soc_component_update_bits(component, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	/* sample rate */
103662306a36Sopenharmony_ci	switch (params_rate(params)) {
103762306a36Sopenharmony_ci	case 8000:
103862306a36Sopenharmony_ci		inf = 0;
103962306a36Sopenharmony_ci		break;
104062306a36Sopenharmony_ci	case 11025:
104162306a36Sopenharmony_ci		inf = 1;
104262306a36Sopenharmony_ci		break;
104362306a36Sopenharmony_ci	case 16000:
104462306a36Sopenharmony_ci		inf = 3;
104562306a36Sopenharmony_ci		break;
104662306a36Sopenharmony_ci	case 22050:
104762306a36Sopenharmony_ci		inf = 4;
104862306a36Sopenharmony_ci		break;
104962306a36Sopenharmony_ci	case 32000:
105062306a36Sopenharmony_ci		inf = 6;
105162306a36Sopenharmony_ci		break;
105262306a36Sopenharmony_ci	case 44100:
105362306a36Sopenharmony_ci		inf = 7;
105462306a36Sopenharmony_ci		break;
105562306a36Sopenharmony_ci	case 48000:
105662306a36Sopenharmony_ci		inf = 8;
105762306a36Sopenharmony_ci		break;
105862306a36Sopenharmony_ci	default:
105962306a36Sopenharmony_ci		return -EINVAL;
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci	snd_soc_component_update_bits(component, PM860X_I2S_IFACE_4, 0xf, inf);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	return 0;
106462306a36Sopenharmony_ci}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_cistatic int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
106762306a36Sopenharmony_ci				  unsigned int fmt)
106862306a36Sopenharmony_ci{
106962306a36Sopenharmony_ci	struct snd_soc_component *component = codec_dai->component;
107062306a36Sopenharmony_ci	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
107162306a36Sopenharmony_ci	unsigned char inf = 0, mask = 0;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	/* set audio interface clocking */
107662306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
107762306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBP_CFP:
107862306a36Sopenharmony_ci		if (pm860x->dir == PM860X_CLK_DIR_OUT)
107962306a36Sopenharmony_ci			inf |= PCM_INF2_MASTER;
108062306a36Sopenharmony_ci		else
108162306a36Sopenharmony_ci			return -EINVAL;
108262306a36Sopenharmony_ci		break;
108362306a36Sopenharmony_ci	case SND_SOC_DAIFMT_CBC_CFC:
108462306a36Sopenharmony_ci		if (pm860x->dir == PM860X_CLK_DIR_IN)
108562306a36Sopenharmony_ci			inf &= ~PCM_INF2_MASTER;
108662306a36Sopenharmony_ci		else
108762306a36Sopenharmony_ci			return -EINVAL;
108862306a36Sopenharmony_ci		break;
108962306a36Sopenharmony_ci	default:
109062306a36Sopenharmony_ci		return -EINVAL;
109162306a36Sopenharmony_ci	}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
109462306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
109562306a36Sopenharmony_ci		inf |= PCM_EXACT_I2S;
109662306a36Sopenharmony_ci		break;
109762306a36Sopenharmony_ci	default:
109862306a36Sopenharmony_ci		return -EINVAL;
109962306a36Sopenharmony_ci	}
110062306a36Sopenharmony_ci	mask |= PCM_MODE_MASK;
110162306a36Sopenharmony_ci	snd_soc_component_update_bits(component, PM860X_I2S_IFACE_2, mask, inf);
110262306a36Sopenharmony_ci	return 0;
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cistatic int pm860x_set_bias_level(struct snd_soc_component *component,
110662306a36Sopenharmony_ci				 enum snd_soc_bias_level level)
110762306a36Sopenharmony_ci{
110862306a36Sopenharmony_ci	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
110962306a36Sopenharmony_ci	int data;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	switch (level) {
111262306a36Sopenharmony_ci	case SND_SOC_BIAS_ON:
111362306a36Sopenharmony_ci		break;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	case SND_SOC_BIAS_PREPARE:
111662306a36Sopenharmony_ci		break;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	case SND_SOC_BIAS_STANDBY:
111962306a36Sopenharmony_ci		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
112062306a36Sopenharmony_ci			/* Enable Audio PLL & Audio section */
112162306a36Sopenharmony_ci			data = AUDIO_PLL | AUDIO_SECTION_ON;
112262306a36Sopenharmony_ci			pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
112362306a36Sopenharmony_ci			udelay(300);
112462306a36Sopenharmony_ci			data = AUDIO_PLL | AUDIO_SECTION_RESET
112562306a36Sopenharmony_ci				| AUDIO_SECTION_ON;
112662306a36Sopenharmony_ci			pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
112762306a36Sopenharmony_ci		}
112862306a36Sopenharmony_ci		break;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	case SND_SOC_BIAS_OFF:
113162306a36Sopenharmony_ci		data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON;
113262306a36Sopenharmony_ci		pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0);
113362306a36Sopenharmony_ci		break;
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci	return 0;
113662306a36Sopenharmony_ci}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_cistatic const struct snd_soc_dai_ops pm860x_pcm_dai_ops = {
113962306a36Sopenharmony_ci	.mute_stream	= pm860x_mute_stream,
114062306a36Sopenharmony_ci	.hw_params	= pm860x_pcm_hw_params,
114162306a36Sopenharmony_ci	.set_fmt	= pm860x_pcm_set_dai_fmt,
114262306a36Sopenharmony_ci	.set_sysclk	= pm860x_set_dai_sysclk,
114362306a36Sopenharmony_ci	.no_capture_mute = 1,
114462306a36Sopenharmony_ci};
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_cistatic const struct snd_soc_dai_ops pm860x_i2s_dai_ops = {
114762306a36Sopenharmony_ci	.mute_stream	= pm860x_mute_stream,
114862306a36Sopenharmony_ci	.hw_params	= pm860x_i2s_hw_params,
114962306a36Sopenharmony_ci	.set_fmt	= pm860x_i2s_set_dai_fmt,
115062306a36Sopenharmony_ci	.set_sysclk	= pm860x_set_dai_sysclk,
115162306a36Sopenharmony_ci	.no_capture_mute = 1,
115262306a36Sopenharmony_ci};
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci#define PM860X_RATES	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |	\
115562306a36Sopenharmony_ci			 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic struct snd_soc_dai_driver pm860x_dai[] = {
115862306a36Sopenharmony_ci	{
115962306a36Sopenharmony_ci		/* DAI PCM */
116062306a36Sopenharmony_ci		.name	= "88pm860x-pcm",
116162306a36Sopenharmony_ci		.id	= 1,
116262306a36Sopenharmony_ci		.playback = {
116362306a36Sopenharmony_ci			.stream_name	= "PCM Playback",
116462306a36Sopenharmony_ci			.channels_min	= 2,
116562306a36Sopenharmony_ci			.channels_max	= 2,
116662306a36Sopenharmony_ci			.rates		= PM860X_RATES,
116762306a36Sopenharmony_ci			.formats	= SNDRV_PCM_FMTBIT_S16_LE | \
116862306a36Sopenharmony_ci					  SNDRV_PCM_FMTBIT_S18_3LE,
116962306a36Sopenharmony_ci		},
117062306a36Sopenharmony_ci		.capture = {
117162306a36Sopenharmony_ci			.stream_name	= "PCM Capture",
117262306a36Sopenharmony_ci			.channels_min	= 2,
117362306a36Sopenharmony_ci			.channels_max	= 2,
117462306a36Sopenharmony_ci			.rates		= PM860X_RATES,
117562306a36Sopenharmony_ci			.formats	= SNDRV_PCM_FMTBIT_S16_LE | \
117662306a36Sopenharmony_ci					  SNDRV_PCM_FMTBIT_S18_3LE,
117762306a36Sopenharmony_ci		},
117862306a36Sopenharmony_ci		.ops	= &pm860x_pcm_dai_ops,
117962306a36Sopenharmony_ci	}, {
118062306a36Sopenharmony_ci		/* DAI I2S */
118162306a36Sopenharmony_ci		.name	= "88pm860x-i2s",
118262306a36Sopenharmony_ci		.id	= 2,
118362306a36Sopenharmony_ci		.playback = {
118462306a36Sopenharmony_ci			.stream_name	= "I2S Playback",
118562306a36Sopenharmony_ci			.channels_min	= 2,
118662306a36Sopenharmony_ci			.channels_max	= 2,
118762306a36Sopenharmony_ci			.rates		= SNDRV_PCM_RATE_8000_48000,
118862306a36Sopenharmony_ci			.formats	= SNDRV_PCM_FMTBIT_S16_LE | \
118962306a36Sopenharmony_ci					  SNDRV_PCM_FMTBIT_S18_3LE,
119062306a36Sopenharmony_ci		},
119162306a36Sopenharmony_ci		.capture = {
119262306a36Sopenharmony_ci			.stream_name	= "I2S Capture",
119362306a36Sopenharmony_ci			.channels_min	= 2,
119462306a36Sopenharmony_ci			.channels_max	= 2,
119562306a36Sopenharmony_ci			.rates		= SNDRV_PCM_RATE_8000_48000,
119662306a36Sopenharmony_ci			.formats	= SNDRV_PCM_FMTBIT_S16_LE | \
119762306a36Sopenharmony_ci					  SNDRV_PCM_FMTBIT_S18_3LE,
119862306a36Sopenharmony_ci		},
119962306a36Sopenharmony_ci		.ops	= &pm860x_i2s_dai_ops,
120062306a36Sopenharmony_ci	},
120162306a36Sopenharmony_ci};
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_cistatic irqreturn_t pm860x_component_handler(int irq, void *data)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	struct pm860x_priv *pm860x = data;
120662306a36Sopenharmony_ci	int status, shrt, report = 0, mic_report = 0;
120762306a36Sopenharmony_ci	int mask;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	status = pm860x_reg_read(pm860x->i2c, REG_STATUS_1);
121062306a36Sopenharmony_ci	shrt = pm860x_reg_read(pm860x->i2c, REG_SHORTS);
121162306a36Sopenharmony_ci	mask = pm860x->det.hs_shrt | pm860x->det.hook_det | pm860x->det.lo_shrt
121262306a36Sopenharmony_ci		| pm860x->det.hp_det;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci#ifndef CONFIG_SND_SOC_88PM860X_MODULE
121562306a36Sopenharmony_ci	if (status & (HEADSET_STATUS | MIC_STATUS | SHORT_HS1 | SHORT_HS2 |
121662306a36Sopenharmony_ci		      SHORT_LO1 | SHORT_LO2))
121762306a36Sopenharmony_ci		trace_snd_soc_jack_irq(dev_name(pm860x->component->dev));
121862306a36Sopenharmony_ci#endif
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
122162306a36Sopenharmony_ci		&& (status & HEADSET_STATUS))
122262306a36Sopenharmony_ci		report |= SND_JACK_HEADPHONE;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	if ((pm860x->det.mic_det & SND_JACK_MICROPHONE)
122562306a36Sopenharmony_ci		&& (status & MIC_STATUS))
122662306a36Sopenharmony_ci		mic_report |= SND_JACK_MICROPHONE;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	if (pm860x->det.hs_shrt && (shrt & (SHORT_HS1 | SHORT_HS2)))
122962306a36Sopenharmony_ci		report |= pm860x->det.hs_shrt;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	if (pm860x->det.hook_det && (status & HOOK_STATUS))
123262306a36Sopenharmony_ci		report |= pm860x->det.hook_det;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	if (pm860x->det.lo_shrt && (shrt & (SHORT_LO1 | SHORT_LO2)))
123562306a36Sopenharmony_ci		report |= pm860x->det.lo_shrt;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	if (report)
123862306a36Sopenharmony_ci		snd_soc_jack_report(pm860x->det.hp_jack, report, mask);
123962306a36Sopenharmony_ci	if (mic_report)
124062306a36Sopenharmony_ci		snd_soc_jack_report(pm860x->det.mic_jack, SND_JACK_MICROPHONE,
124162306a36Sopenharmony_ci				    SND_JACK_MICROPHONE);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	dev_dbg(pm860x->component->dev, "headphone report:0x%x, mask:%x\n",
124462306a36Sopenharmony_ci		report, mask);
124562306a36Sopenharmony_ci	dev_dbg(pm860x->component->dev, "microphone report:0x%x\n", mic_report);
124662306a36Sopenharmony_ci	return IRQ_HANDLED;
124762306a36Sopenharmony_ci}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ciint pm860x_hs_jack_detect(struct snd_soc_component *component,
125062306a36Sopenharmony_ci			  struct snd_soc_jack *jack,
125162306a36Sopenharmony_ci			  int det, int hook, int hs_shrt, int lo_shrt)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
125462306a36Sopenharmony_ci	int data;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	pm860x->det.hp_jack = jack;
125762306a36Sopenharmony_ci	pm860x->det.hp_det = det;
125862306a36Sopenharmony_ci	pm860x->det.hook_det = hook;
125962306a36Sopenharmony_ci	pm860x->det.hs_shrt = hs_shrt;
126062306a36Sopenharmony_ci	pm860x->det.lo_shrt = lo_shrt;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	if (det & SND_JACK_HEADPHONE)
126362306a36Sopenharmony_ci		pm860x_set_bits(pm860x->i2c, REG_HS_DET,
126462306a36Sopenharmony_ci				EN_HS_DET, EN_HS_DET);
126562306a36Sopenharmony_ci	/* headset short detect */
126662306a36Sopenharmony_ci	if (hs_shrt) {
126762306a36Sopenharmony_ci		data = CLR_SHORT_HS2 | CLR_SHORT_HS1;
126862306a36Sopenharmony_ci		pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data);
126962306a36Sopenharmony_ci	}
127062306a36Sopenharmony_ci	/* Lineout short detect */
127162306a36Sopenharmony_ci	if (lo_shrt) {
127262306a36Sopenharmony_ci		data = CLR_SHORT_LO2 | CLR_SHORT_LO1;
127362306a36Sopenharmony_ci		pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data);
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	/* sync status */
127762306a36Sopenharmony_ci	pm860x_component_handler(0, pm860x);
127862306a36Sopenharmony_ci	return 0;
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pm860x_hs_jack_detect);
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ciint pm860x_mic_jack_detect(struct snd_soc_component *component,
128362306a36Sopenharmony_ci			   struct snd_soc_jack *jack, int det)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	pm860x->det.mic_jack = jack;
128862306a36Sopenharmony_ci	pm860x->det.mic_det = det;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	if (det & SND_JACK_MICROPHONE)
129162306a36Sopenharmony_ci		pm860x_set_bits(pm860x->i2c, REG_MIC_DET,
129262306a36Sopenharmony_ci				MICDET_MASK, MICDET_MASK);
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	/* sync status */
129562306a36Sopenharmony_ci	pm860x_component_handler(0, pm860x);
129662306a36Sopenharmony_ci	return 0;
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_cistatic int pm860x_probe(struct snd_soc_component *component)
130162306a36Sopenharmony_ci{
130262306a36Sopenharmony_ci	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
130362306a36Sopenharmony_ci	int i, ret;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	pm860x->component = component;
130662306a36Sopenharmony_ci	snd_soc_component_init_regmap(component,  pm860x->regmap);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
130962306a36Sopenharmony_ci		ret = request_threaded_irq(pm860x->irq[i], NULL,
131062306a36Sopenharmony_ci					   pm860x_component_handler, IRQF_ONESHOT,
131162306a36Sopenharmony_ci					   pm860x->name[i], pm860x);
131262306a36Sopenharmony_ci		if (ret < 0) {
131362306a36Sopenharmony_ci			dev_err(component->dev, "Failed to request IRQ!\n");
131462306a36Sopenharmony_ci			goto out;
131562306a36Sopenharmony_ci		}
131662306a36Sopenharmony_ci	}
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	return 0;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ciout:
132162306a36Sopenharmony_ci	while (--i >= 0)
132262306a36Sopenharmony_ci		free_irq(pm860x->irq[i], pm860x);
132362306a36Sopenharmony_ci	return ret;
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cistatic void pm860x_remove(struct snd_soc_component *component)
132762306a36Sopenharmony_ci{
132862306a36Sopenharmony_ci	struct pm860x_priv *pm860x = snd_soc_component_get_drvdata(component);
132962306a36Sopenharmony_ci	int i;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	for (i = 3; i >= 0; i--)
133262306a36Sopenharmony_ci		free_irq(pm860x->irq[i], pm860x);
133362306a36Sopenharmony_ci}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_pm860x = {
133662306a36Sopenharmony_ci	.probe			= pm860x_probe,
133762306a36Sopenharmony_ci	.remove			= pm860x_remove,
133862306a36Sopenharmony_ci	.set_bias_level		= pm860x_set_bias_level,
133962306a36Sopenharmony_ci	.controls		= pm860x_snd_controls,
134062306a36Sopenharmony_ci	.num_controls		= ARRAY_SIZE(pm860x_snd_controls),
134162306a36Sopenharmony_ci	.dapm_widgets		= pm860x_dapm_widgets,
134262306a36Sopenharmony_ci	.num_dapm_widgets	= ARRAY_SIZE(pm860x_dapm_widgets),
134362306a36Sopenharmony_ci	.dapm_routes		= pm860x_dapm_routes,
134462306a36Sopenharmony_ci	.num_dapm_routes	= ARRAY_SIZE(pm860x_dapm_routes),
134562306a36Sopenharmony_ci	.idle_bias_on		= 1,
134662306a36Sopenharmony_ci	.use_pmdown_time	= 1,
134762306a36Sopenharmony_ci	.endianness		= 1,
134862306a36Sopenharmony_ci};
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistatic int pm860x_codec_probe(struct platform_device *pdev)
135162306a36Sopenharmony_ci{
135262306a36Sopenharmony_ci	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
135362306a36Sopenharmony_ci	struct pm860x_priv *pm860x;
135462306a36Sopenharmony_ci	struct resource *res;
135562306a36Sopenharmony_ci	int i, ret;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	pm860x = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_priv),
135862306a36Sopenharmony_ci			      GFP_KERNEL);
135962306a36Sopenharmony_ci	if (pm860x == NULL)
136062306a36Sopenharmony_ci		return -ENOMEM;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	pm860x->chip = chip;
136362306a36Sopenharmony_ci	pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client
136462306a36Sopenharmony_ci			: chip->companion;
136562306a36Sopenharmony_ci	pm860x->regmap = (chip->id == CHIP_PM8607) ? chip->regmap
136662306a36Sopenharmony_ci			: chip->regmap_companion;
136762306a36Sopenharmony_ci	platform_set_drvdata(pdev, pm860x);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
137062306a36Sopenharmony_ci		res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
137162306a36Sopenharmony_ci		if (!res) {
137262306a36Sopenharmony_ci			dev_err(&pdev->dev, "Failed to get IRQ resources\n");
137362306a36Sopenharmony_ci			return -EINVAL;
137462306a36Sopenharmony_ci		}
137562306a36Sopenharmony_ci		pm860x->irq[i] = res->start + chip->irq_base;
137662306a36Sopenharmony_ci		strscpy(pm860x->name[i], res->name, MAX_NAME_LEN);
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	ret = devm_snd_soc_register_component(&pdev->dev,
138062306a36Sopenharmony_ci				     &soc_component_dev_pm860x,
138162306a36Sopenharmony_ci				     pm860x_dai, ARRAY_SIZE(pm860x_dai));
138262306a36Sopenharmony_ci	if (ret) {
138362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to register component\n");
138462306a36Sopenharmony_ci		return -EINVAL;
138562306a36Sopenharmony_ci	}
138662306a36Sopenharmony_ci	return ret;
138762306a36Sopenharmony_ci}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_cistatic struct platform_driver pm860x_codec_driver = {
139062306a36Sopenharmony_ci	.driver	= {
139162306a36Sopenharmony_ci		.name	= "88pm860x-codec",
139262306a36Sopenharmony_ci	},
139362306a36Sopenharmony_ci	.probe	= pm860x_codec_probe,
139462306a36Sopenharmony_ci};
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_cimodule_platform_driver(pm860x_codec_driver);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC 88PM860x driver");
139962306a36Sopenharmony_ciMODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
140062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
140162306a36Sopenharmony_ciMODULE_ALIAS("platform:88pm860x-codec");
140262306a36Sopenharmony_ci
1403