1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // rk3228_codec.c -- rk3228 ALSA Soc Audio driver
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/device.h>
9*4882a593Smuzhiyun #include <linux/delay.h>
10*4882a593Smuzhiyun #include <linux/of.h>
11*4882a593Smuzhiyun #include <linux/of_gpio.h>
12*4882a593Smuzhiyun #include <linux/clk.h>
13*4882a593Smuzhiyun #include <linux/platform_device.h>
14*4882a593Smuzhiyun #include <linux/pm_runtime.h>
15*4882a593Smuzhiyun #include <linux/regmap.h>
16*4882a593Smuzhiyun #include <sound/pcm_params.h>
17*4882a593Smuzhiyun #include <sound/dmaengine_pcm.h>
18*4882a593Smuzhiyun #include "rk3228_codec.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /*
21*4882a593Smuzhiyun * volume setting
22*4882a593Smuzhiyun * 0: -39dB
23*4882a593Smuzhiyun * 26: 0dB
24*4882a593Smuzhiyun * 31: 6dB
25*4882a593Smuzhiyun * Step: 1.5dB
26*4882a593Smuzhiyun */
27*4882a593Smuzhiyun #define OUT_VOLUME (0x18)
28*4882a593Smuzhiyun #define INITIAL_FREQ (11289600)
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun struct rk3228_codec_priv {
31*4882a593Smuzhiyun struct regmap *regmap;
32*4882a593Smuzhiyun struct clk *mclk;
33*4882a593Smuzhiyun struct clk *pclk;
34*4882a593Smuzhiyun struct clk *sclk;
35*4882a593Smuzhiyun struct gpio_desc *spk_en_gpio;
36*4882a593Smuzhiyun int spk_depop_time; /* msec */
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun static const struct reg_default rk3228_codec_reg_defaults[] = {
40*4882a593Smuzhiyun { CODEC_RESET, 0x03 },
41*4882a593Smuzhiyun { DAC_INIT_CTRL1, 0x00 },
42*4882a593Smuzhiyun { DAC_INIT_CTRL2, 0x50 },
43*4882a593Smuzhiyun { DAC_INIT_CTRL3, 0x0e },
44*4882a593Smuzhiyun { DAC_PRECHARGE_CTRL, 0x01 },
45*4882a593Smuzhiyun { DAC_PWR_CTRL, 0x00 },
46*4882a593Smuzhiyun { DAC_CLK_CTRL, 0x00 },
47*4882a593Smuzhiyun { HPMIX_CTRL, 0x00 },
48*4882a593Smuzhiyun { HPOUT_CTRL, 0x00 },
49*4882a593Smuzhiyun { HPOUTL_GAIN_CTRL, 0x00 },
50*4882a593Smuzhiyun { HPOUTR_GAIN_CTRL, 0x00 },
51*4882a593Smuzhiyun { HPOUT_POP_CTRL, 0x11 },
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun
rk3228_codec_reset(struct snd_soc_component * component)54*4882a593Smuzhiyun static int rk3228_codec_reset(struct snd_soc_component *component)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun regmap_write(rk3228->regmap, CODEC_RESET, 0);
59*4882a593Smuzhiyun mdelay(10);
60*4882a593Smuzhiyun regmap_write(rk3228->regmap, CODEC_RESET, 0x03);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun return 0;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
rk3228_set_dai_fmt(struct snd_soc_dai * dai,unsigned int fmt)65*4882a593Smuzhiyun static int rk3228_set_dai_fmt(struct snd_soc_dai *dai,
66*4882a593Smuzhiyun unsigned int fmt)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun struct snd_soc_component *component = dai->component;
69*4882a593Smuzhiyun struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
70*4882a593Smuzhiyun unsigned int val = 0;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
73*4882a593Smuzhiyun case SND_SOC_DAIFMT_CBS_CFS:
74*4882a593Smuzhiyun val |= PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE;
75*4882a593Smuzhiyun break;
76*4882a593Smuzhiyun case SND_SOC_DAIFMT_CBM_CFM:
77*4882a593Smuzhiyun val |= PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER;
78*4882a593Smuzhiyun break;
79*4882a593Smuzhiyun default:
80*4882a593Smuzhiyun return -EINVAL;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, DAC_INIT_CTRL1,
84*4882a593Smuzhiyun PIN_DIRECTION_MASK | DAC_I2S_MODE_MASK, val);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun val = 0;
87*4882a593Smuzhiyun switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
88*4882a593Smuzhiyun case SND_SOC_DAIFMT_DSP_A:
89*4882a593Smuzhiyun case SND_SOC_DAIFMT_DSP_B:
90*4882a593Smuzhiyun val |= DAC_MODE_PCM;
91*4882a593Smuzhiyun break;
92*4882a593Smuzhiyun case SND_SOC_DAIFMT_I2S:
93*4882a593Smuzhiyun val |= DAC_MODE_I2S;
94*4882a593Smuzhiyun break;
95*4882a593Smuzhiyun case SND_SOC_DAIFMT_RIGHT_J:
96*4882a593Smuzhiyun val |= DAC_MODE_RJM;
97*4882a593Smuzhiyun break;
98*4882a593Smuzhiyun case SND_SOC_DAIFMT_LEFT_J:
99*4882a593Smuzhiyun val |= DAC_MODE_LJM;
100*4882a593Smuzhiyun break;
101*4882a593Smuzhiyun default:
102*4882a593Smuzhiyun return -EINVAL;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, DAC_INIT_CTRL2,
106*4882a593Smuzhiyun DAC_MODE_MASK, val);
107*4882a593Smuzhiyun return 0;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
rk3228_analog_output(struct rk3228_codec_priv * rk3228,int mute)110*4882a593Smuzhiyun static void rk3228_analog_output(struct rk3228_codec_priv *rk3228, int mute)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun if (rk3228->spk_en_gpio)
113*4882a593Smuzhiyun gpiod_set_value(rk3228->spk_en_gpio, mute);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
rk3228_digital_mute(struct snd_soc_dai * dai,int mute,int stream)116*4882a593Smuzhiyun static int rk3228_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun struct snd_soc_component *component = dai->component;
119*4882a593Smuzhiyun struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
120*4882a593Smuzhiyun unsigned int val = 0;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if (mute)
123*4882a593Smuzhiyun val = HPOUTL_MUTE | HPOUTR_MUTE;
124*4882a593Smuzhiyun else
125*4882a593Smuzhiyun val = HPOUTL_UNMUTE | HPOUTR_UNMUTE;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, HPOUT_CTRL,
128*4882a593Smuzhiyun HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, val);
129*4882a593Smuzhiyun return 0;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
rk3228_codec_power_on(struct snd_soc_component * component,int wait_ms)132*4882a593Smuzhiyun static int rk3228_codec_power_on(struct snd_soc_component *component, int wait_ms)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
137*4882a593Smuzhiyun DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_PRECHARGE);
138*4882a593Smuzhiyun mdelay(10);
139*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
140*4882a593Smuzhiyun DAC_CHARGE_CURRENT_ALL_MASK,
141*4882a593Smuzhiyun DAC_CHARGE_CURRENT_ALL_ON);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun mdelay(wait_ms);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
rk3228_codec_power_off(struct snd_soc_component * component,int wait_ms)148*4882a593Smuzhiyun static int rk3228_codec_power_off(struct snd_soc_component *component, int wait_ms)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
153*4882a593Smuzhiyun DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_DISCHARGE);
154*4882a593Smuzhiyun mdelay(10);
155*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
156*4882a593Smuzhiyun DAC_CHARGE_CURRENT_ALL_MASK,
157*4882a593Smuzhiyun DAC_CHARGE_CURRENT_ALL_ON);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun mdelay(wait_ms);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun return 0;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun static struct rk3228_reg_msk_val playback_open_list[] = {
165*4882a593Smuzhiyun { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_ON },
166*4882a593Smuzhiyun { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,
167*4882a593Smuzhiyun DACL_PATH_REFV_ON | DACR_PATH_REFV_ON },
168*4882a593Smuzhiyun { DAC_PWR_CTRL, HPOUTL_ZERO_CROSSING_ON | HPOUTR_ZERO_CROSSING_ON,
169*4882a593Smuzhiyun HPOUTL_ZERO_CROSSING_ON | HPOUTR_ZERO_CROSSING_ON },
170*4882a593Smuzhiyun { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,
171*4882a593Smuzhiyun HPOUTR_POP_WORK | HPOUTL_POP_WORK },
172*4882a593Smuzhiyun { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_EN | HPMIXR_EN },
173*4882a593Smuzhiyun { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,
174*4882a593Smuzhiyun HPMIXL_INIT_EN | HPMIXR_INIT_EN },
175*4882a593Smuzhiyun { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_EN | HPOUTR_EN },
176*4882a593Smuzhiyun { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,
177*4882a593Smuzhiyun HPOUTL_INIT_EN | HPOUTR_INIT_EN },
178*4882a593Smuzhiyun { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,
179*4882a593Smuzhiyun DACL_REFV_ON | DACR_REFV_ON },
180*4882a593Smuzhiyun { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,
181*4882a593Smuzhiyun DACL_CLK_ON | DACR_CLK_ON },
182*4882a593Smuzhiyun { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_ON | DACR_ON },
183*4882a593Smuzhiyun { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,
184*4882a593Smuzhiyun DACL_INIT_ON | DACR_INIT_ON },
185*4882a593Smuzhiyun { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,
186*4882a593Smuzhiyun DACL_SELECT | DACR_SELECT },
187*4882a593Smuzhiyun { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,
188*4882a593Smuzhiyun HPMIXL_INIT2_EN | HPMIXR_INIT2_EN },
189*4882a593Smuzhiyun { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,
190*4882a593Smuzhiyun HPOUTL_UNMUTE | HPOUTR_UNMUTE },
191*4882a593Smuzhiyun };
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun #define PLAYBACK_OPEN_LIST_LEN ARRAY_SIZE(playback_open_list)
194*4882a593Smuzhiyun
rk3228_codec_open_playback(struct snd_soc_component * component)195*4882a593Smuzhiyun static int rk3228_codec_open_playback(struct snd_soc_component *component)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
198*4882a593Smuzhiyun int i = 0;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
201*4882a593Smuzhiyun DAC_CHARGE_CURRENT_ALL_MASK,
202*4882a593Smuzhiyun DAC_CHARGE_CURRENT_I);
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun for (i = 0; i < PLAYBACK_OPEN_LIST_LEN; i++) {
205*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap,
206*4882a593Smuzhiyun playback_open_list[i].reg,
207*4882a593Smuzhiyun playback_open_list[i].msk,
208*4882a593Smuzhiyun playback_open_list[i].val);
209*4882a593Smuzhiyun mdelay(1);
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun msleep(rk3228->spk_depop_time);
213*4882a593Smuzhiyun rk3228_analog_output(rk3228, 1);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, HPOUTL_GAIN_CTRL,
216*4882a593Smuzhiyun HPOUTL_GAIN_MASK, OUT_VOLUME);
217*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, HPOUTR_GAIN_CTRL,
218*4882a593Smuzhiyun HPOUTR_GAIN_MASK, OUT_VOLUME);
219*4882a593Smuzhiyun return 0;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun static struct rk3228_reg_msk_val playback_close_list[] = {
223*4882a593Smuzhiyun { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,
224*4882a593Smuzhiyun HPMIXL_INIT2_DIS | HPMIXR_INIT2_DIS },
225*4882a593Smuzhiyun { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,
226*4882a593Smuzhiyun DACL_DESELECT | DACR_DESELECT },
227*4882a593Smuzhiyun { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,
228*4882a593Smuzhiyun HPOUTL_MUTE | HPOUTR_MUTE },
229*4882a593Smuzhiyun { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,
230*4882a593Smuzhiyun HPOUTL_INIT_DIS | HPOUTR_INIT_DIS },
231*4882a593Smuzhiyun { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_DIS | HPOUTR_DIS },
232*4882a593Smuzhiyun { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_DIS | HPMIXR_DIS },
233*4882a593Smuzhiyun { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_OFF | DACR_OFF },
234*4882a593Smuzhiyun { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,
235*4882a593Smuzhiyun DACL_CLK_OFF | DACR_CLK_OFF },
236*4882a593Smuzhiyun { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,
237*4882a593Smuzhiyun DACL_REFV_OFF | DACR_REFV_OFF },
238*4882a593Smuzhiyun { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,
239*4882a593Smuzhiyun HPOUTR_POP_XCHARGE | HPOUTL_POP_XCHARGE },
240*4882a593Smuzhiyun { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,
241*4882a593Smuzhiyun DACL_PATH_REFV_OFF | DACR_PATH_REFV_OFF },
242*4882a593Smuzhiyun { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_OFF },
243*4882a593Smuzhiyun { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,
244*4882a593Smuzhiyun HPMIXL_INIT_DIS | HPMIXR_INIT_DIS },
245*4882a593Smuzhiyun { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,
246*4882a593Smuzhiyun DACL_INIT_OFF | DACR_INIT_OFF },
247*4882a593Smuzhiyun };
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun #define PLAYBACK_CLOSE_LIST_LEN ARRAY_SIZE(playback_close_list)
250*4882a593Smuzhiyun
rk3228_codec_close_playback(struct snd_soc_component * component)251*4882a593Smuzhiyun static int rk3228_codec_close_playback(struct snd_soc_component *component)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
254*4882a593Smuzhiyun int i = 0;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun rk3228_analog_output(rk3228, 0);
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, HPOUTL_GAIN_CTRL,
259*4882a593Smuzhiyun HPOUTL_GAIN_MASK, 0);
260*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, HPOUTR_GAIN_CTRL,
261*4882a593Smuzhiyun HPOUTR_GAIN_MASK, 0);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun for (i = 0; i < PLAYBACK_CLOSE_LIST_LEN; i++) {
264*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap,
265*4882a593Smuzhiyun playback_close_list[i].reg,
266*4882a593Smuzhiyun playback_close_list[i].msk,
267*4882a593Smuzhiyun playback_close_list[i].val);
268*4882a593Smuzhiyun mdelay(1);
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
272*4882a593Smuzhiyun DAC_CHARGE_CURRENT_ALL_MASK,
273*4882a593Smuzhiyun DAC_CHARGE_CURRENT_I);
274*4882a593Smuzhiyun return 0;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
rk3228_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)277*4882a593Smuzhiyun static int rk3228_hw_params(struct snd_pcm_substream *substream,
278*4882a593Smuzhiyun struct snd_pcm_hw_params *params,
279*4882a593Smuzhiyun struct snd_soc_dai *dai)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun struct snd_soc_component *component = dai->component;
282*4882a593Smuzhiyun struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
283*4882a593Smuzhiyun unsigned int val = 0;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun switch (params_format(params)) {
286*4882a593Smuzhiyun case SNDRV_PCM_FORMAT_S16_LE:
287*4882a593Smuzhiyun val |= DAC_VDL_16BITS;
288*4882a593Smuzhiyun break;
289*4882a593Smuzhiyun case SNDRV_PCM_FORMAT_S20_3LE:
290*4882a593Smuzhiyun val |= DAC_VDL_20BITS;
291*4882a593Smuzhiyun break;
292*4882a593Smuzhiyun case SNDRV_PCM_FORMAT_S24_LE:
293*4882a593Smuzhiyun val |= DAC_VDL_24BITS;
294*4882a593Smuzhiyun break;
295*4882a593Smuzhiyun case SNDRV_PCM_FORMAT_S32_LE:
296*4882a593Smuzhiyun val |= DAC_VDL_32BITS;
297*4882a593Smuzhiyun break;
298*4882a593Smuzhiyun default:
299*4882a593Smuzhiyun return -EINVAL;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, DAC_INIT_CTRL2, DAC_VDL_MASK, val);
303*4882a593Smuzhiyun val = DAC_WL_32BITS | DAC_RST_DIS;
304*4882a593Smuzhiyun regmap_update_bits(rk3228->regmap, DAC_INIT_CTRL3,
305*4882a593Smuzhiyun DAC_WL_MASK | DAC_RST_MASK, val);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun return 0;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
rk3228_pcm_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)310*4882a593Smuzhiyun static int rk3228_pcm_startup(struct snd_pcm_substream *substream,
311*4882a593Smuzhiyun struct snd_soc_dai *dai)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun struct snd_soc_component *component = dai->component;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun return rk3228_codec_open_playback(component);
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
rk3228_pcm_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)318*4882a593Smuzhiyun static void rk3228_pcm_shutdown(struct snd_pcm_substream *substream,
319*4882a593Smuzhiyun struct snd_soc_dai *dai)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun struct snd_soc_component *component = dai->component;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun rk3228_codec_close_playback(component);
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun static struct snd_soc_dai_ops rk3228_dai_ops = {
327*4882a593Smuzhiyun .hw_params = rk3228_hw_params,
328*4882a593Smuzhiyun .set_fmt = rk3228_set_dai_fmt,
329*4882a593Smuzhiyun .mute_stream = rk3228_digital_mute,
330*4882a593Smuzhiyun .startup = rk3228_pcm_startup,
331*4882a593Smuzhiyun .shutdown = rk3228_pcm_shutdown,
332*4882a593Smuzhiyun .no_capture_mute = 1,
333*4882a593Smuzhiyun };
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun static struct snd_soc_dai_driver rk3228_dai[] = {
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun .name = "rk3228-hifi",
338*4882a593Smuzhiyun .id = RK3228_HIFI,
339*4882a593Smuzhiyun .playback = {
340*4882a593Smuzhiyun .stream_name = "HIFI Playback",
341*4882a593Smuzhiyun .channels_min = 1,
342*4882a593Smuzhiyun .channels_max = 2,
343*4882a593Smuzhiyun .rates = SNDRV_PCM_RATE_8000_96000,
344*4882a593Smuzhiyun .formats = (SNDRV_PCM_FMTBIT_S16_LE |
345*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S20_3LE |
346*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S24_LE |
347*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S32_LE),
348*4882a593Smuzhiyun },
349*4882a593Smuzhiyun .capture = {
350*4882a593Smuzhiyun .stream_name = "HIFI Capture",
351*4882a593Smuzhiyun .channels_min = 2,
352*4882a593Smuzhiyun .channels_max = 8,
353*4882a593Smuzhiyun .rates = SNDRV_PCM_RATE_8000_96000,
354*4882a593Smuzhiyun .formats = (SNDRV_PCM_FMTBIT_S16_LE |
355*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S20_3LE |
356*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S24_LE |
357*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S32_LE),
358*4882a593Smuzhiyun },
359*4882a593Smuzhiyun .ops = &rk3228_dai_ops,
360*4882a593Smuzhiyun },
361*4882a593Smuzhiyun };
362*4882a593Smuzhiyun
rk3228_codec_probe(struct snd_soc_component * component)363*4882a593Smuzhiyun static int rk3228_codec_probe(struct snd_soc_component *component)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun rk3228_codec_reset(component);
366*4882a593Smuzhiyun rk3228_codec_power_on(component, 0);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun return 0;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
rk3228_codec_remove(struct snd_soc_component * component)371*4882a593Smuzhiyun static void rk3228_codec_remove(struct snd_soc_component *component)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun rk3228_codec_close_playback(component);
374*4882a593Smuzhiyun rk3228_codec_power_off(component, 0);
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun static struct snd_soc_component_driver soc_codec_dev_rk3228 = {
378*4882a593Smuzhiyun .probe = rk3228_codec_probe,
379*4882a593Smuzhiyun .remove = rk3228_codec_remove,
380*4882a593Smuzhiyun };
381*4882a593Smuzhiyun
rk3228_codec_write_read_reg(struct device * dev,unsigned int reg)382*4882a593Smuzhiyun static bool rk3228_codec_write_read_reg(struct device *dev, unsigned int reg)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun switch (reg) {
385*4882a593Smuzhiyun case CODEC_RESET:
386*4882a593Smuzhiyun case DAC_INIT_CTRL1:
387*4882a593Smuzhiyun case DAC_INIT_CTRL2:
388*4882a593Smuzhiyun case DAC_INIT_CTRL3:
389*4882a593Smuzhiyun case DAC_PRECHARGE_CTRL:
390*4882a593Smuzhiyun case DAC_PWR_CTRL:
391*4882a593Smuzhiyun case DAC_CLK_CTRL:
392*4882a593Smuzhiyun case HPMIX_CTRL:
393*4882a593Smuzhiyun case DAC_SELECT:
394*4882a593Smuzhiyun case HPOUT_CTRL:
395*4882a593Smuzhiyun case HPOUTL_GAIN_CTRL:
396*4882a593Smuzhiyun case HPOUTR_GAIN_CTRL:
397*4882a593Smuzhiyun case HPOUT_POP_CTRL:
398*4882a593Smuzhiyun return true;
399*4882a593Smuzhiyun default:
400*4882a593Smuzhiyun return false;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
rk3228_codec_volatile_reg(struct device * dev,unsigned int reg)404*4882a593Smuzhiyun static bool rk3228_codec_volatile_reg(struct device *dev, unsigned int reg)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun switch (reg) {
407*4882a593Smuzhiyun case CODEC_RESET:
408*4882a593Smuzhiyun return true;
409*4882a593Smuzhiyun default:
410*4882a593Smuzhiyun return false;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun static const struct regmap_config rk3228_codec_regmap_config = {
415*4882a593Smuzhiyun .reg_bits = 32,
416*4882a593Smuzhiyun .reg_stride = 4,
417*4882a593Smuzhiyun .val_bits = 32,
418*4882a593Smuzhiyun .max_register = HPOUT_POP_CTRL,
419*4882a593Smuzhiyun .writeable_reg = rk3228_codec_write_read_reg,
420*4882a593Smuzhiyun .readable_reg = rk3228_codec_write_read_reg,
421*4882a593Smuzhiyun .volatile_reg = rk3228_codec_volatile_reg,
422*4882a593Smuzhiyun .reg_defaults = rk3228_codec_reg_defaults,
423*4882a593Smuzhiyun .num_reg_defaults = ARRAY_SIZE(rk3228_codec_reg_defaults),
424*4882a593Smuzhiyun .cache_type = REGCACHE_FLAT,
425*4882a593Smuzhiyun };
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun #ifdef CONFIG_OF
428*4882a593Smuzhiyun static const struct of_device_id rk3228codec_of_match[] = {
429*4882a593Smuzhiyun { .compatible = "rockchip,rk3228-codec", },
430*4882a593Smuzhiyun {},
431*4882a593Smuzhiyun };
432*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, rk3228codec_of_match);
433*4882a593Smuzhiyun #endif
434*4882a593Smuzhiyun
rk3228_platform_probe(struct platform_device * pdev)435*4882a593Smuzhiyun static int rk3228_platform_probe(struct platform_device *pdev)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun struct device_node *rk3228_np = pdev->dev.of_node;
438*4882a593Smuzhiyun struct rk3228_codec_priv *rk3228;
439*4882a593Smuzhiyun struct resource *res;
440*4882a593Smuzhiyun void __iomem *base;
441*4882a593Smuzhiyun int ret = 0;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun rk3228 = devm_kzalloc(&pdev->dev, sizeof(*rk3228), GFP_KERNEL);
444*4882a593Smuzhiyun if (!rk3228)
445*4882a593Smuzhiyun return -ENOMEM;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun rk3228->mclk = devm_clk_get(&pdev->dev, "mclk");
448*4882a593Smuzhiyun if (PTR_ERR(rk3228->mclk) == -EPROBE_DEFER)
449*4882a593Smuzhiyun return -EPROBE_DEFER;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun rk3228->pclk = devm_clk_get(&pdev->dev, "pclk");
452*4882a593Smuzhiyun if (IS_ERR(rk3228->pclk))
453*4882a593Smuzhiyun return PTR_ERR(rk3228->pclk);
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun rk3228->sclk = devm_clk_get(&pdev->dev, "sclk");
456*4882a593Smuzhiyun if (IS_ERR(rk3228->sclk))
457*4882a593Smuzhiyun return PTR_ERR(rk3228->sclk);
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun rk3228->spk_en_gpio = devm_gpiod_get_optional(&pdev->dev,
460*4882a593Smuzhiyun "spk-en",
461*4882a593Smuzhiyun GPIOD_OUT_LOW);
462*4882a593Smuzhiyun if (IS_ERR(rk3228->spk_en_gpio))
463*4882a593Smuzhiyun return PTR_ERR(rk3228->spk_en_gpio);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun ret = of_property_read_u32(rk3228_np, "spk-depop-time-ms",
466*4882a593Smuzhiyun &rk3228->spk_depop_time);
467*4882a593Smuzhiyun if (ret < 0) {
468*4882a593Smuzhiyun dev_info(&pdev->dev, "spk_depop_time use default value.\n");
469*4882a593Smuzhiyun rk3228->spk_depop_time = 100;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
473*4882a593Smuzhiyun base = devm_ioremap_resource(&pdev->dev, res);
474*4882a593Smuzhiyun if (IS_ERR(base))
475*4882a593Smuzhiyun return PTR_ERR(base);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun ret = clk_prepare_enable(rk3228->mclk);
478*4882a593Smuzhiyun if (ret)
479*4882a593Smuzhiyun return ret;
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun ret = clk_prepare_enable(rk3228->pclk);
482*4882a593Smuzhiyun if (ret < 0)
483*4882a593Smuzhiyun goto err_pclk;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun ret = clk_prepare_enable(rk3228->sclk);
486*4882a593Smuzhiyun if (ret)
487*4882a593Smuzhiyun goto err_sclk;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun clk_set_rate(rk3228->sclk, INITIAL_FREQ);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun rk3228->regmap = devm_regmap_init_mmio(&pdev->dev, base,
492*4882a593Smuzhiyun &rk3228_codec_regmap_config);
493*4882a593Smuzhiyun if (IS_ERR(rk3228->regmap)) {
494*4882a593Smuzhiyun ret = PTR_ERR(rk3228->regmap);
495*4882a593Smuzhiyun goto err_clk;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun platform_set_drvdata(pdev, rk3228);
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rk3228,
501*4882a593Smuzhiyun rk3228_dai, ARRAY_SIZE(rk3228_dai));
502*4882a593Smuzhiyun if (!ret)
503*4882a593Smuzhiyun return 0;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun err_clk:
506*4882a593Smuzhiyun clk_disable_unprepare(rk3228->sclk);
507*4882a593Smuzhiyun err_sclk:
508*4882a593Smuzhiyun clk_disable_unprepare(rk3228->pclk);
509*4882a593Smuzhiyun err_pclk:
510*4882a593Smuzhiyun clk_disable_unprepare(rk3228->mclk);
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun return ret;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun
rk3228_platform_remove(struct platform_device * pdev)515*4882a593Smuzhiyun static int rk3228_platform_remove(struct platform_device *pdev)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun struct rk3228_codec_priv *rk3228 = platform_get_drvdata(pdev);
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun if (!IS_ERR(rk3228->mclk))
520*4882a593Smuzhiyun clk_disable_unprepare(rk3228->mclk);
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun if (!IS_ERR(rk3228->pclk))
523*4882a593Smuzhiyun clk_disable_unprepare(rk3228->pclk);
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun if (!IS_ERR(rk3228->sclk))
526*4882a593Smuzhiyun clk_disable_unprepare(rk3228->sclk);
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun return 0;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun static struct platform_driver rk3228_codec_driver = {
532*4882a593Smuzhiyun .driver = {
533*4882a593Smuzhiyun .name = "rk3228-codec",
534*4882a593Smuzhiyun .of_match_table = of_match_ptr(rk3228codec_of_match),
535*4882a593Smuzhiyun },
536*4882a593Smuzhiyun .probe = rk3228_platform_probe,
537*4882a593Smuzhiyun .remove = rk3228_platform_remove,
538*4882a593Smuzhiyun };
539*4882a593Smuzhiyun module_platform_driver(rk3228_codec_driver);
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>");
542*4882a593Smuzhiyun MODULE_DESCRIPTION("ASoC rk3228 codec driver");
543*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
544