xref: /OK3568_Linux_fs/kernel/sound/soc/codecs/zx_aud96p22.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2017 Sanechips Technology Co., Ltd.
4*4882a593Smuzhiyun  * Copyright 2017 Linaro Ltd.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Author: Baoyou Xie <baoyou.xie@linaro.org>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
10*4882a593Smuzhiyun #include <linux/i2c.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/regmap.h>
13*4882a593Smuzhiyun #include <sound/pcm.h>
14*4882a593Smuzhiyun #include <sound/pcm_params.h>
15*4882a593Smuzhiyun #include <sound/soc.h>
16*4882a593Smuzhiyun #include <sound/soc-dai.h>
17*4882a593Smuzhiyun #include <sound/tlv.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define AUD96P22_RESET			0x00
20*4882a593Smuzhiyun #define RST_DAC_DPZ			BIT(0)
21*4882a593Smuzhiyun #define RST_ADC_DPZ			BIT(1)
22*4882a593Smuzhiyun #define AUD96P22_I2S1_CONFIG_0		0x03
23*4882a593Smuzhiyun #define I2S1_MS_MODE			BIT(3)
24*4882a593Smuzhiyun #define I2S1_MODE_MASK			0x7
25*4882a593Smuzhiyun #define I2S1_MODE_RIGHT_J		0x0
26*4882a593Smuzhiyun #define I2S1_MODE_I2S			0x1
27*4882a593Smuzhiyun #define I2S1_MODE_LEFT_J		0x2
28*4882a593Smuzhiyun #define AUD96P22_PD_0			0x15
29*4882a593Smuzhiyun #define AUD96P22_PD_1			0x16
30*4882a593Smuzhiyun #define AUD96P22_PD_3			0x18
31*4882a593Smuzhiyun #define AUD96P22_PD_4			0x19
32*4882a593Smuzhiyun #define AUD96P22_MUTE_0			0x1d
33*4882a593Smuzhiyun #define AUD96P22_MUTE_2			0x1f
34*4882a593Smuzhiyun #define AUD96P22_MUTE_4			0x21
35*4882a593Smuzhiyun #define AUD96P22_RECVOL_0		0x24
36*4882a593Smuzhiyun #define AUD96P22_RECVOL_1		0x25
37*4882a593Smuzhiyun #define AUD96P22_PGA1VOL_0		0x26
38*4882a593Smuzhiyun #define AUD96P22_PGA1VOL_1		0x27
39*4882a593Smuzhiyun #define AUD96P22_LMVOL_0		0x34
40*4882a593Smuzhiyun #define AUD96P22_LMVOL_1		0x35
41*4882a593Smuzhiyun #define AUD96P22_HS1VOL_0		0x38
42*4882a593Smuzhiyun #define AUD96P22_HS1VOL_1		0x39
43*4882a593Smuzhiyun #define AUD96P22_PGA1SEL_0		0x47
44*4882a593Smuzhiyun #define AUD96P22_PGA1SEL_1		0x48
45*4882a593Smuzhiyun #define AUD96P22_LDR1SEL_0		0x59
46*4882a593Smuzhiyun #define AUD96P22_LDR1SEL_1		0x60
47*4882a593Smuzhiyun #define AUD96P22_LDR2SEL_0		0x5d
48*4882a593Smuzhiyun #define AUD96P22_REG_MAX		0xfb
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun struct aud96p22_priv {
51*4882a593Smuzhiyun 	struct regmap *regmap;
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun 
aud96p22_adc_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)54*4882a593Smuzhiyun static int aud96p22_adc_event(struct snd_soc_dapm_widget *w,
55*4882a593Smuzhiyun 			      struct snd_kcontrol *kcontrol, int event)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
58*4882a593Smuzhiyun 	struct aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
59*4882a593Smuzhiyun 	struct regmap *regmap = priv->regmap;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	if (event != SND_SOC_DAPM_POST_PMU)
62*4882a593Smuzhiyun 		return -EINVAL;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	/* Assert/de-assert the bit to reset ADC data path  */
65*4882a593Smuzhiyun 	regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, 0);
66*4882a593Smuzhiyun 	regmap_update_bits(regmap, AUD96P22_RESET, RST_ADC_DPZ, RST_ADC_DPZ);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	return 0;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
aud96p22_dac_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)71*4882a593Smuzhiyun static int aud96p22_dac_event(struct snd_soc_dapm_widget *w,
72*4882a593Smuzhiyun 			      struct snd_kcontrol *kcontrol, int event)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
75*4882a593Smuzhiyun 	struct aud96p22_priv *priv = snd_soc_component_get_drvdata(component);
76*4882a593Smuzhiyun 	struct regmap *regmap = priv->regmap;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	if (event != SND_SOC_DAPM_POST_PMU)
79*4882a593Smuzhiyun 		return -EINVAL;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	/* Assert/de-assert the bit to reset DAC data path  */
82*4882a593Smuzhiyun 	regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, 0);
83*4882a593Smuzhiyun 	regmap_update_bits(regmap, AUD96P22_RESET, RST_DAC_DPZ, RST_DAC_DPZ);
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	return 0;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(lm_tlv, -11550, 50, 0);
89*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(hs_tlv, -3900, 300, 0);
90*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(rec_tlv, -9550, 50, 0);
91*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(pga_tlv, -1800, 100, 0);
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun static const struct snd_kcontrol_new aud96p22_snd_controls[] = {
94*4882a593Smuzhiyun 	/* Volume control */
95*4882a593Smuzhiyun 	SOC_DOUBLE_R_TLV("Master Playback Volume", AUD96P22_LMVOL_0,
96*4882a593Smuzhiyun 			 AUD96P22_LMVOL_1, 0, 0xff, 0, lm_tlv),
97*4882a593Smuzhiyun 	SOC_DOUBLE_R_TLV("Headphone Volume", AUD96P22_HS1VOL_0,
98*4882a593Smuzhiyun 			 AUD96P22_HS1VOL_1, 0, 0xf, 0, hs_tlv),
99*4882a593Smuzhiyun 	SOC_DOUBLE_R_TLV("Master Capture Volume", AUD96P22_RECVOL_0,
100*4882a593Smuzhiyun 			 AUD96P22_RECVOL_1, 0, 0xff, 0, rec_tlv),
101*4882a593Smuzhiyun 	SOC_DOUBLE_R_TLV("Analogue Capture Volume", AUD96P22_PGA1VOL_0,
102*4882a593Smuzhiyun 			 AUD96P22_PGA1VOL_1, 0, 0x37, 0, pga_tlv),
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	/* Mute control */
105*4882a593Smuzhiyun 	SOC_DOUBLE("Master Playback Switch", AUD96P22_MUTE_2, 0, 1, 1, 1),
106*4882a593Smuzhiyun 	SOC_DOUBLE("Headphone Switch", AUD96P22_MUTE_2, 4, 5, 1, 1),
107*4882a593Smuzhiyun 	SOC_DOUBLE("Line Out Switch", AUD96P22_MUTE_4, 0, 1, 1, 1),
108*4882a593Smuzhiyun 	SOC_DOUBLE("Speaker Switch", AUD96P22_MUTE_4, 2, 3, 1, 1),
109*4882a593Smuzhiyun 	SOC_DOUBLE("Master Capture Switch", AUD96P22_MUTE_0, 0, 1, 1, 1),
110*4882a593Smuzhiyun 	SOC_DOUBLE("Analogue Capture Switch", AUD96P22_MUTE_0, 2, 3, 1, 1),
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun /* Input mux kcontrols */
114*4882a593Smuzhiyun static const unsigned int ain_mux_values[] = {
115*4882a593Smuzhiyun 	0, 1, 3, 4, 5,
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun static const char * const ainl_mux_texts[] = {
119*4882a593Smuzhiyun 	"AINL1 differential",
120*4882a593Smuzhiyun 	"AINL1 single-ended",
121*4882a593Smuzhiyun 	"AINL3 single-ended",
122*4882a593Smuzhiyun 	"AINL2 differential",
123*4882a593Smuzhiyun 	"AINL2 single-ended",
124*4882a593Smuzhiyun };
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun static const char * const ainr_mux_texts[] = {
127*4882a593Smuzhiyun 	"AINR1 differential",
128*4882a593Smuzhiyun 	"AINR1 single-ended",
129*4882a593Smuzhiyun 	"AINR3 single-ended",
130*4882a593Smuzhiyun 	"AINR2 differential",
131*4882a593Smuzhiyun 	"AINR2 single-ended",
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun static SOC_VALUE_ENUM_SINGLE_DECL(ainl_mux_enum, AUD96P22_PGA1SEL_0,
135*4882a593Smuzhiyun 				  0, 0x7, ainl_mux_texts, ain_mux_values);
136*4882a593Smuzhiyun static SOC_VALUE_ENUM_SINGLE_DECL(ainr_mux_enum, AUD96P22_PGA1SEL_1,
137*4882a593Smuzhiyun 				  0, 0x7, ainr_mux_texts, ain_mux_values);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun static const struct snd_kcontrol_new ainl_mux_kcontrol =
140*4882a593Smuzhiyun 			SOC_DAPM_ENUM("AINL Mux", ainl_mux_enum);
141*4882a593Smuzhiyun static const struct snd_kcontrol_new ainr_mux_kcontrol =
142*4882a593Smuzhiyun 			SOC_DAPM_ENUM("AINR Mux", ainr_mux_enum);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun /* Output mixer kcontrols */
145*4882a593Smuzhiyun static const struct snd_kcontrol_new ld1_left_kcontrols[] = {
146*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("DACL LD1L Switch", AUD96P22_LDR1SEL_0, 0, 1, 0),
147*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("AINL LD1L Switch", AUD96P22_LDR1SEL_0, 1, 1, 0),
148*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("AINR LD1L Switch", AUD96P22_LDR1SEL_0, 2, 1, 0),
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun static const struct snd_kcontrol_new ld1_right_kcontrols[] = {
152*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("DACR LD1R Switch", AUD96P22_LDR1SEL_1, 8, 1, 0),
153*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("AINR LD1R Switch", AUD96P22_LDR1SEL_1, 9, 1, 0),
154*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("AINL LD1R Switch", AUD96P22_LDR1SEL_1, 10, 1, 0),
155*4882a593Smuzhiyun };
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun static const struct snd_kcontrol_new ld2_kcontrols[] = {
158*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("DACL LD2 Switch", AUD96P22_LDR2SEL_0, 0, 1, 0),
159*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("AINL LD2 Switch", AUD96P22_LDR2SEL_0, 1, 1, 0),
160*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("DACR LD2 Switch", AUD96P22_LDR2SEL_0, 2, 1, 0),
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun static const struct snd_soc_dapm_widget aud96p22_dapm_widgets[] = {
164*4882a593Smuzhiyun 	/* Overall power bit */
165*4882a593Smuzhiyun 	SND_SOC_DAPM_SUPPLY("POWER", AUD96P22_PD_0, 0, 0, NULL, 0),
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	/* Input pins */
168*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AINL1P"),
169*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AINL2P"),
170*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AINL3"),
171*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AINL1N"),
172*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AINL2N"),
173*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AINR2N"),
174*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AINR1N"),
175*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AINR3"),
176*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AINR2P"),
177*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AINR1P"),
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	/* Input muxes */
180*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("AINLMUX", AUD96P22_PD_1, 2, 0, &ainl_mux_kcontrol),
181*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("AINRMUX", AUD96P22_PD_1, 3, 0, &ainr_mux_kcontrol),
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	/* ADCs */
184*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC_E("ADCL", "Capture Left", AUD96P22_PD_1, 0, 0,
185*4882a593Smuzhiyun 			   aud96p22_adc_event, SND_SOC_DAPM_POST_PMU),
186*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC_E("ADCR", "Capture Right", AUD96P22_PD_1, 1, 0,
187*4882a593Smuzhiyun 			   aud96p22_adc_event, SND_SOC_DAPM_POST_PMU),
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	/* DACs */
190*4882a593Smuzhiyun 	SND_SOC_DAPM_DAC_E("DACL", "Playback Left", AUD96P22_PD_3, 0, 0,
191*4882a593Smuzhiyun 			   aud96p22_dac_event, SND_SOC_DAPM_POST_PMU),
192*4882a593Smuzhiyun 	SND_SOC_DAPM_DAC_E("DACR", "Playback Right", AUD96P22_PD_3, 1, 0,
193*4882a593Smuzhiyun 			   aud96p22_dac_event, SND_SOC_DAPM_POST_PMU),
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	/* Output mixers */
196*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("LD1L", AUD96P22_PD_3, 6, 0, ld1_left_kcontrols,
197*4882a593Smuzhiyun 			   ARRAY_SIZE(ld1_left_kcontrols)),
198*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("LD1R", AUD96P22_PD_3, 7, 0, ld1_right_kcontrols,
199*4882a593Smuzhiyun 			   ARRAY_SIZE(ld1_right_kcontrols)),
200*4882a593Smuzhiyun 	SND_SOC_DAPM_MIXER("LD2", AUD96P22_PD_4, 2, 0, ld2_kcontrols,
201*4882a593Smuzhiyun 			   ARRAY_SIZE(ld2_kcontrols)),
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	/* Headset power switch */
204*4882a593Smuzhiyun 	SND_SOC_DAPM_SUPPLY("HS1L", AUD96P22_PD_3, 4, 0, NULL, 0),
205*4882a593Smuzhiyun 	SND_SOC_DAPM_SUPPLY("HS1R", AUD96P22_PD_3, 5, 0, NULL, 0),
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	/* Output pins */
208*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("HSOUTL"),
209*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("LINEOUTL"),
210*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("LINEOUTMP"),
211*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("LINEOUTMN"),
212*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("LINEOUTR"),
213*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("HSOUTR"),
214*4882a593Smuzhiyun };
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun static const struct snd_soc_dapm_route aud96p22_dapm_routes[] = {
217*4882a593Smuzhiyun 	{ "AINLMUX", "AINL1 differential", "AINL1N" },
218*4882a593Smuzhiyun 	{ "AINLMUX", "AINL1 single-ended", "AINL1P" },
219*4882a593Smuzhiyun 	{ "AINLMUX", "AINL3 single-ended", "AINL3" },
220*4882a593Smuzhiyun 	{ "AINLMUX", "AINL2 differential", "AINL2N" },
221*4882a593Smuzhiyun 	{ "AINLMUX", "AINL2 single-ended", "AINL2P" },
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	{ "AINRMUX", "AINR1 differential", "AINR1N" },
224*4882a593Smuzhiyun 	{ "AINRMUX", "AINR1 single-ended", "AINR1P" },
225*4882a593Smuzhiyun 	{ "AINRMUX", "AINR3 single-ended", "AINR3" },
226*4882a593Smuzhiyun 	{ "AINRMUX", "AINR2 differential", "AINR2N" },
227*4882a593Smuzhiyun 	{ "AINRMUX", "AINR2 single-ended", "AINR2P" },
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	{ "ADCL", NULL, "AINLMUX" },
230*4882a593Smuzhiyun 	{ "ADCR", NULL, "AINRMUX" },
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	{ "ADCL", NULL, "POWER" },
233*4882a593Smuzhiyun 	{ "ADCR", NULL, "POWER" },
234*4882a593Smuzhiyun 	{ "DACL", NULL, "POWER" },
235*4882a593Smuzhiyun 	{ "DACR", NULL, "POWER" },
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	{ "LD1L", "DACL LD1L Switch", "DACL" },
238*4882a593Smuzhiyun 	{ "LD1L", "AINL LD1L Switch", "AINLMUX" },
239*4882a593Smuzhiyun 	{ "LD1L", "AINR LD1L Switch", "AINRMUX" },
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	{ "LD1R", "DACR LD1R Switch", "DACR" },
242*4882a593Smuzhiyun 	{ "LD1R", "AINR LD1R Switch", "AINRMUX" },
243*4882a593Smuzhiyun 	{ "LD1R", "AINL LD1R Switch", "AINLMUX" },
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	{ "LD2", "DACL LD2 Switch", "DACL" },
246*4882a593Smuzhiyun 	{ "LD2", "AINL LD2 Switch", "AINLMUX" },
247*4882a593Smuzhiyun 	{ "LD2", "DACR LD2 Switch", "DACR" },
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	{ "HSOUTL", NULL, "LD1L" },
250*4882a593Smuzhiyun 	{ "HSOUTR", NULL, "LD1R" },
251*4882a593Smuzhiyun 	{ "HSOUTL", NULL, "HS1L" },
252*4882a593Smuzhiyun 	{ "HSOUTR", NULL, "HS1R" },
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	{ "LINEOUTL", NULL, "LD1L" },
255*4882a593Smuzhiyun 	{ "LINEOUTR", NULL, "LD1R" },
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	{ "LINEOUTMP", NULL, "LD2" },
258*4882a593Smuzhiyun 	{ "LINEOUTMN", NULL, "LD2" },
259*4882a593Smuzhiyun };
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun static const struct snd_soc_component_driver aud96p22_driver = {
262*4882a593Smuzhiyun 	.controls		= aud96p22_snd_controls,
263*4882a593Smuzhiyun 	.num_controls		= ARRAY_SIZE(aud96p22_snd_controls),
264*4882a593Smuzhiyun 	.dapm_widgets		= aud96p22_dapm_widgets,
265*4882a593Smuzhiyun 	.num_dapm_widgets	= ARRAY_SIZE(aud96p22_dapm_widgets),
266*4882a593Smuzhiyun 	.dapm_routes		= aud96p22_dapm_routes,
267*4882a593Smuzhiyun 	.num_dapm_routes	= ARRAY_SIZE(aud96p22_dapm_routes),
268*4882a593Smuzhiyun 	.idle_bias_on		= 1,
269*4882a593Smuzhiyun 	.use_pmdown_time	= 1,
270*4882a593Smuzhiyun 	.endianness		= 1,
271*4882a593Smuzhiyun 	.non_legacy_dai_naming	= 1,
272*4882a593Smuzhiyun };
273*4882a593Smuzhiyun 
aud96p22_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)274*4882a593Smuzhiyun static int aud96p22_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun 	struct aud96p22_priv *priv = snd_soc_component_get_drvdata(dai->component);
277*4882a593Smuzhiyun 	struct regmap *regmap = priv->regmap;
278*4882a593Smuzhiyun 	unsigned int val;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	/* Master/slave mode */
281*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
282*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBS_CFS:
283*4882a593Smuzhiyun 		val = 0;
284*4882a593Smuzhiyun 		break;
285*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
286*4882a593Smuzhiyun 		val = I2S1_MS_MODE;
287*4882a593Smuzhiyun 		break;
288*4882a593Smuzhiyun 	default:
289*4882a593Smuzhiyun 		return -EINVAL;
290*4882a593Smuzhiyun 	}
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MS_MODE, val);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	/* Audio format */
295*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
296*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_RIGHT_J:
297*4882a593Smuzhiyun 		val = I2S1_MODE_RIGHT_J;
298*4882a593Smuzhiyun 		break;
299*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
300*4882a593Smuzhiyun 		val = I2S1_MODE_I2S;
301*4882a593Smuzhiyun 		break;
302*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_LEFT_J:
303*4882a593Smuzhiyun 		val = I2S1_MODE_LEFT_J;
304*4882a593Smuzhiyun 		break;
305*4882a593Smuzhiyun 	default:
306*4882a593Smuzhiyun 		return -EINVAL;
307*4882a593Smuzhiyun 	}
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	regmap_update_bits(regmap, AUD96P22_I2S1_CONFIG_0, I2S1_MODE_MASK, val);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	return 0;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun static const struct snd_soc_dai_ops aud96p22_dai_ops = {
315*4882a593Smuzhiyun 	.set_fmt = aud96p22_set_fmt,
316*4882a593Smuzhiyun };
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun #define AUD96P22_RATES	SNDRV_PCM_RATE_8000_192000
319*4882a593Smuzhiyun #define AUD96P22_FORMATS (\
320*4882a593Smuzhiyun 		SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
321*4882a593Smuzhiyun 		SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun static struct snd_soc_dai_driver aud96p22_dai = {
324*4882a593Smuzhiyun 	.name = "aud96p22-dai",
325*4882a593Smuzhiyun 	.playback = {
326*4882a593Smuzhiyun 		.stream_name = "Playback",
327*4882a593Smuzhiyun 		.channels_min = 1,
328*4882a593Smuzhiyun 		.channels_max = 2,
329*4882a593Smuzhiyun 		.rates = AUD96P22_RATES,
330*4882a593Smuzhiyun 		.formats = AUD96P22_FORMATS,
331*4882a593Smuzhiyun 	},
332*4882a593Smuzhiyun 	.capture = {
333*4882a593Smuzhiyun 		.stream_name = "Capture",
334*4882a593Smuzhiyun 		.channels_min = 1,
335*4882a593Smuzhiyun 		.channels_max = 2,
336*4882a593Smuzhiyun 		.rates = AUD96P22_RATES,
337*4882a593Smuzhiyun 		.formats = AUD96P22_FORMATS,
338*4882a593Smuzhiyun 	},
339*4882a593Smuzhiyun 	.ops = &aud96p22_dai_ops,
340*4882a593Smuzhiyun };
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun static const struct regmap_config aud96p22_regmap = {
343*4882a593Smuzhiyun 	.reg_bits = 8,
344*4882a593Smuzhiyun 	.val_bits = 8,
345*4882a593Smuzhiyun 	.max_register = AUD96P22_REG_MAX,
346*4882a593Smuzhiyun 	.cache_type = REGCACHE_RBTREE,
347*4882a593Smuzhiyun };
348*4882a593Smuzhiyun 
aud96p22_i2c_probe(struct i2c_client * i2c,const struct i2c_device_id * id)349*4882a593Smuzhiyun static int aud96p22_i2c_probe(struct i2c_client *i2c,
350*4882a593Smuzhiyun 			      const struct i2c_device_id *id)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	struct device *dev = &i2c->dev;
353*4882a593Smuzhiyun 	struct aud96p22_priv *priv;
354*4882a593Smuzhiyun 	int ret;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
357*4882a593Smuzhiyun 	if (priv == NULL)
358*4882a593Smuzhiyun 		return -ENOMEM;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	priv->regmap = devm_regmap_init_i2c(i2c, &aud96p22_regmap);
361*4882a593Smuzhiyun 	if (IS_ERR(priv->regmap)) {
362*4882a593Smuzhiyun 		ret = PTR_ERR(priv->regmap);
363*4882a593Smuzhiyun 		dev_err(dev, "failed to init i2c regmap: %d\n", ret);
364*4882a593Smuzhiyun 		return ret;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	i2c_set_clientdata(i2c, priv);
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	ret = devm_snd_soc_register_component(dev, &aud96p22_driver, &aud96p22_dai, 1);
370*4882a593Smuzhiyun 	if (ret) {
371*4882a593Smuzhiyun 		dev_err(dev, "failed to register component: %d\n", ret);
372*4882a593Smuzhiyun 		return ret;
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	return 0;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun 
aud96p22_i2c_remove(struct i2c_client * i2c)378*4882a593Smuzhiyun static int aud96p22_i2c_remove(struct i2c_client *i2c)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun 	return 0;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun static const struct of_device_id aud96p22_dt_ids[] = {
384*4882a593Smuzhiyun 	{ .compatible = "zte,zx-aud96p22", },
385*4882a593Smuzhiyun 	{ }
386*4882a593Smuzhiyun };
387*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, aud96p22_dt_ids);
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun static struct i2c_driver aud96p22_i2c_driver = {
390*4882a593Smuzhiyun 	.driver = {
391*4882a593Smuzhiyun 		.name = "zx_aud96p22",
392*4882a593Smuzhiyun 		.of_match_table = aud96p22_dt_ids,
393*4882a593Smuzhiyun 	},
394*4882a593Smuzhiyun 	.probe = aud96p22_i2c_probe,
395*4882a593Smuzhiyun 	.remove = aud96p22_i2c_remove,
396*4882a593Smuzhiyun };
397*4882a593Smuzhiyun module_i2c_driver(aud96p22_i2c_driver);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun MODULE_DESCRIPTION("ZTE ASoC AUD96P22 CODEC driver");
400*4882a593Smuzhiyun MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
401*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
402