1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * SiRF audio codec driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/platform_device.h>
10*4882a593Smuzhiyun #include <linux/pm_runtime.h>
11*4882a593Smuzhiyun #include <linux/of.h>
12*4882a593Smuzhiyun #include <linux/of_device.h>
13*4882a593Smuzhiyun #include <linux/clk.h>
14*4882a593Smuzhiyun #include <linux/delay.h>
15*4882a593Smuzhiyun #include <linux/io.h>
16*4882a593Smuzhiyun #include <linux/regmap.h>
17*4882a593Smuzhiyun #include <sound/core.h>
18*4882a593Smuzhiyun #include <sound/pcm.h>
19*4882a593Smuzhiyun #include <sound/pcm_params.h>
20*4882a593Smuzhiyun #include <sound/initval.h>
21*4882a593Smuzhiyun #include <sound/tlv.h>
22*4882a593Smuzhiyun #include <sound/soc.h>
23*4882a593Smuzhiyun #include <sound/dmaengine_pcm.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include "sirf-audio-codec.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun struct sirf_audio_codec {
28*4882a593Smuzhiyun struct clk *clk;
29*4882a593Smuzhiyun struct regmap *regmap;
30*4882a593Smuzhiyun u32 reg_ctrl0, reg_ctrl1;
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun static const char * const input_mode_mux[] = {"Single-ended",
34*4882a593Smuzhiyun "Differential"};
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun static const struct soc_enum input_mode_mux_enum =
37*4882a593Smuzhiyun SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux);
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control =
40*4882a593Smuzhiyun SOC_DAPM_ENUM("Route", input_mode_mux_enum);
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0);
43*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0);
44*4882a593Smuzhiyun static const DECLARE_TLV_DB_RANGE(capture_vol_tlv_atlas6,
45*4882a593Smuzhiyun 0, 7, TLV_DB_SCALE_ITEM(-100, 100, 0),
46*4882a593Smuzhiyun 0x22, 0x3F, TLV_DB_SCALE_ITEM(700, 100, 0),
47*4882a593Smuzhiyun );
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun static struct snd_kcontrol_new volume_controls_atlas6[] = {
50*4882a593Smuzhiyun SOC_DOUBLE_TLV("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
51*4882a593Smuzhiyun 0x7F, 0, playback_vol_tlv),
52*4882a593Smuzhiyun SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10,
53*4882a593Smuzhiyun 0x3F, 0, capture_vol_tlv_atlas6),
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun static struct snd_kcontrol_new volume_controls_prima2[] = {
57*4882a593Smuzhiyun SOC_DOUBLE_TLV("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
58*4882a593Smuzhiyun 0x7F, 0, playback_vol_tlv),
59*4882a593Smuzhiyun SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10,
60*4882a593Smuzhiyun 0x1F, 0, capture_vol_tlv_prima2),
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun static struct snd_kcontrol_new left_input_path_controls[] = {
64*4882a593Smuzhiyun SOC_DAPM_SINGLE("Line Left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0),
65*4882a593Smuzhiyun SOC_DAPM_SINGLE("Mic Left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0),
66*4882a593Smuzhiyun };
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun static struct snd_kcontrol_new right_input_path_controls[] = {
69*4882a593Smuzhiyun SOC_DAPM_SINGLE("Line Right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0),
70*4882a593Smuzhiyun SOC_DAPM_SINGLE("Mic Right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0),
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control =
74*4882a593Smuzhiyun SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control =
77*4882a593Smuzhiyun SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control =
80*4882a593Smuzhiyun SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control =
83*4882a593Smuzhiyun SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0);
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control =
86*4882a593Smuzhiyun SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control =
89*4882a593Smuzhiyun SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun /* After enable adc, Delay 200ms to avoid pop noise */
adc_enable_delay_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)92*4882a593Smuzhiyun static int adc_enable_delay_event(struct snd_soc_dapm_widget *w,
93*4882a593Smuzhiyun struct snd_kcontrol *kcontrol, int event)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun switch (event) {
96*4882a593Smuzhiyun case SND_SOC_DAPM_POST_PMU:
97*4882a593Smuzhiyun msleep(200);
98*4882a593Smuzhiyun break;
99*4882a593Smuzhiyun default:
100*4882a593Smuzhiyun break;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun return 0;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
enable_and_reset_codec(struct regmap * regmap,u32 codec_enable_bits,u32 codec_reset_bits)106*4882a593Smuzhiyun static void enable_and_reset_codec(struct regmap *regmap,
107*4882a593Smuzhiyun u32 codec_enable_bits, u32 codec_reset_bits)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
110*4882a593Smuzhiyun codec_enable_bits | codec_reset_bits,
111*4882a593Smuzhiyun codec_enable_bits);
112*4882a593Smuzhiyun msleep(20);
113*4882a593Smuzhiyun regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
114*4882a593Smuzhiyun codec_reset_bits, codec_reset_bits);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)117*4882a593Smuzhiyun static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
118*4882a593Smuzhiyun struct snd_kcontrol *kcontrol, int event)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun #define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
121*4882a593Smuzhiyun #define ATLAS6_CODEC_RESET_BITS (1 << 28)
122*4882a593Smuzhiyun struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
123*4882a593Smuzhiyun struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
124*4882a593Smuzhiyun switch (event) {
125*4882a593Smuzhiyun case SND_SOC_DAPM_PRE_PMU:
126*4882a593Smuzhiyun enable_and_reset_codec(sirf_audio_codec->regmap,
127*4882a593Smuzhiyun ATLAS6_CODEC_ENABLE_BITS, ATLAS6_CODEC_RESET_BITS);
128*4882a593Smuzhiyun break;
129*4882a593Smuzhiyun case SND_SOC_DAPM_POST_PMD:
130*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap,
131*4882a593Smuzhiyun AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS, 0);
132*4882a593Smuzhiyun break;
133*4882a593Smuzhiyun default:
134*4882a593Smuzhiyun break;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun return 0;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)140*4882a593Smuzhiyun static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
141*4882a593Smuzhiyun struct snd_kcontrol *kcontrol, int event)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun #define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
144*4882a593Smuzhiyun #define PRIMA2_CODEC_RESET_BITS (1 << 26)
145*4882a593Smuzhiyun struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
146*4882a593Smuzhiyun struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
147*4882a593Smuzhiyun switch (event) {
148*4882a593Smuzhiyun case SND_SOC_DAPM_POST_PMU:
149*4882a593Smuzhiyun enable_and_reset_codec(sirf_audio_codec->regmap,
150*4882a593Smuzhiyun PRIMA2_CODEC_ENABLE_BITS, PRIMA2_CODEC_RESET_BITS);
151*4882a593Smuzhiyun break;
152*4882a593Smuzhiyun case SND_SOC_DAPM_POST_PMD:
153*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap,
154*4882a593Smuzhiyun AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS, 0);
155*4882a593Smuzhiyun break;
156*4882a593Smuzhiyun default:
157*4882a593Smuzhiyun break;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun return 0;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun static const struct snd_soc_dapm_widget atlas6_output_driver_dapm_widgets[] = {
164*4882a593Smuzhiyun SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
165*4882a593Smuzhiyun 25, 0, NULL, 0),
166*4882a593Smuzhiyun SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
167*4882a593Smuzhiyun 26, 0, NULL, 0),
168*4882a593Smuzhiyun SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
169*4882a593Smuzhiyun 27, 0, NULL, 0),
170*4882a593Smuzhiyun };
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun static const struct snd_soc_dapm_widget prima2_output_driver_dapm_widgets[] = {
173*4882a593Smuzhiyun SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
174*4882a593Smuzhiyun 23, 0, NULL, 0),
175*4882a593Smuzhiyun SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
176*4882a593Smuzhiyun 24, 0, NULL, 0),
177*4882a593Smuzhiyun SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
178*4882a593Smuzhiyun 25, 0, NULL, 0),
179*4882a593Smuzhiyun };
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun static const struct snd_soc_dapm_widget atlas6_codec_clock_dapm_widget =
182*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
183*4882a593Smuzhiyun atlas6_codec_enable_and_reset_event,
184*4882a593Smuzhiyun SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun static const struct snd_soc_dapm_widget prima2_codec_clock_dapm_widget =
187*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
188*4882a593Smuzhiyun prima2_codec_enable_and_reset_event,
189*4882a593Smuzhiyun SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun static const struct snd_soc_dapm_widget sirf_audio_codec_dapm_widgets[] = {
192*4882a593Smuzhiyun SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0),
193*4882a593Smuzhiyun SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0),
194*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0,
195*4882a593Smuzhiyun &left_dac_to_hp_left_amp_switch_control),
196*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0,
197*4882a593Smuzhiyun &left_dac_to_hp_right_amp_switch_control),
198*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0,
199*4882a593Smuzhiyun &right_dac_to_hp_left_amp_switch_control),
200*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0,
201*4882a593Smuzhiyun &right_dac_to_hp_right_amp_switch_control),
202*4882a593Smuzhiyun SND_SOC_DAPM_OUT_DRV("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
203*4882a593Smuzhiyun NULL, 0),
204*4882a593Smuzhiyun SND_SOC_DAPM_OUT_DRV("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
205*4882a593Smuzhiyun NULL, 0),
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0,
208*4882a593Smuzhiyun &left_dac_to_speaker_lineout_switch_control),
209*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0,
210*4882a593Smuzhiyun &right_dac_to_speaker_lineout_switch_control),
211*4882a593Smuzhiyun SND_SOC_DAPM_OUT_DRV("Speaker amp driver", AUDIO_IC_CODEC_CTRL0, 4, 0,
212*4882a593Smuzhiyun NULL, 0),
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("HPOUTL"),
215*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("HPOUTR"),
216*4882a593Smuzhiyun SND_SOC_DAPM_OUTPUT("SPKOUT"),
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0,
219*4882a593Smuzhiyun adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
220*4882a593Smuzhiyun SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0,
221*4882a593Smuzhiyun adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
222*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0,
223*4882a593Smuzhiyun &left_input_path_controls[0],
224*4882a593Smuzhiyun ARRAY_SIZE(left_input_path_controls)),
225*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0,
226*4882a593Smuzhiyun &right_input_path_controls[0],
227*4882a593Smuzhiyun ARRAY_SIZE(right_input_path_controls)),
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0,
230*4882a593Smuzhiyun &sirf_audio_codec_input_mode_control),
231*4882a593Smuzhiyun SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0),
232*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("MICIN1"),
233*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("MICIN2"),
234*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("LINEIN1"),
235*4882a593Smuzhiyun SND_SOC_DAPM_INPUT("LINEIN2"),
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0,
238*4882a593Smuzhiyun 30, 0, NULL, 0),
239*4882a593Smuzhiyun };
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun static const struct snd_soc_dapm_route sirf_audio_codec_map[] = {
242*4882a593Smuzhiyun {"SPKOUT", NULL, "Speaker Driver"},
243*4882a593Smuzhiyun {"Speaker Driver", NULL, "Speaker amp driver"},
244*4882a593Smuzhiyun {"Speaker amp driver", NULL, "Left dac to speaker lineout"},
245*4882a593Smuzhiyun {"Speaker amp driver", NULL, "Right dac to speaker lineout"},
246*4882a593Smuzhiyun {"Left dac to speaker lineout", "Switch", "DAC left"},
247*4882a593Smuzhiyun {"Right dac to speaker lineout", "Switch", "DAC right"},
248*4882a593Smuzhiyun {"HPOUTL", NULL, "HP Left Driver"},
249*4882a593Smuzhiyun {"HPOUTR", NULL, "HP Right Driver"},
250*4882a593Smuzhiyun {"HP Left Driver", NULL, "HP amp left driver"},
251*4882a593Smuzhiyun {"HP Right Driver", NULL, "HP amp right driver"},
252*4882a593Smuzhiyun {"HP amp left driver", NULL, "Right dac to hp left amp"},
253*4882a593Smuzhiyun {"HP amp right driver", NULL , "Right dac to hp right amp"},
254*4882a593Smuzhiyun {"HP amp left driver", NULL, "Left dac to hp left amp"},
255*4882a593Smuzhiyun {"HP amp right driver", NULL , "Right dac to hp right amp"},
256*4882a593Smuzhiyun {"Right dac to hp left amp", "Switch", "DAC left"},
257*4882a593Smuzhiyun {"Right dac to hp right amp", "Switch", "DAC right"},
258*4882a593Smuzhiyun {"Left dac to hp left amp", "Switch", "DAC left"},
259*4882a593Smuzhiyun {"Left dac to hp right amp", "Switch", "DAC right"},
260*4882a593Smuzhiyun {"DAC left", NULL, "codecclk"},
261*4882a593Smuzhiyun {"DAC right", NULL, "codecclk"},
262*4882a593Smuzhiyun {"DAC left", NULL, "Playback"},
263*4882a593Smuzhiyun {"DAC right", NULL, "Playback"},
264*4882a593Smuzhiyun {"DAC left", NULL, "HSL Phase Opposite"},
265*4882a593Smuzhiyun {"DAC right", NULL, "HSL Phase Opposite"},
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun {"Capture", NULL, "ADC left"},
268*4882a593Smuzhiyun {"Capture", NULL, "ADC right"},
269*4882a593Smuzhiyun {"ADC left", NULL, "codecclk"},
270*4882a593Smuzhiyun {"ADC right", NULL, "codecclk"},
271*4882a593Smuzhiyun {"ADC left", NULL, "Left PGA mixer"},
272*4882a593Smuzhiyun {"ADC right", NULL, "Right PGA mixer"},
273*4882a593Smuzhiyun {"Left PGA mixer", "Line Left Switch", "LINEIN2"},
274*4882a593Smuzhiyun {"Right PGA mixer", "Line Right Switch", "LINEIN1"},
275*4882a593Smuzhiyun {"Left PGA mixer", "Mic Left Switch", "MICIN2"},
276*4882a593Smuzhiyun {"Right PGA mixer", "Mic Right Switch", "Mic input mode mux"},
277*4882a593Smuzhiyun {"Mic input mode mux", "Single-ended", "MICIN1"},
278*4882a593Smuzhiyun {"Mic input mode mux", "Differential", "MICIN1"},
279*4882a593Smuzhiyun };
280*4882a593Smuzhiyun
sirf_audio_codec_tx_enable(struct sirf_audio_codec * sirf_audio_codec)281*4882a593Smuzhiyun static void sirf_audio_codec_tx_enable(struct sirf_audio_codec *sirf_audio_codec)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
284*4882a593Smuzhiyun AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
285*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
286*4882a593Smuzhiyun AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
287*4882a593Smuzhiyun regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0);
288*4882a593Smuzhiyun regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
289*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
290*4882a593Smuzhiyun AUDIO_FIFO_START, AUDIO_FIFO_START);
291*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap,
292*4882a593Smuzhiyun AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, IC_TX_ENABLE);
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
sirf_audio_codec_tx_disable(struct sirf_audio_codec * sirf_audio_codec)295*4882a593Smuzhiyun static void sirf_audio_codec_tx_disable(struct sirf_audio_codec *sirf_audio_codec)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
298*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap,
299*4882a593Smuzhiyun AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, ~IC_TX_ENABLE);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
sirf_audio_codec_rx_enable(struct sirf_audio_codec * sirf_audio_codec,int channels)302*4882a593Smuzhiyun static void sirf_audio_codec_rx_enable(struct sirf_audio_codec *sirf_audio_codec,
303*4882a593Smuzhiyun int channels)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
306*4882a593Smuzhiyun AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
307*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
308*4882a593Smuzhiyun AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
309*4882a593Smuzhiyun regmap_write(sirf_audio_codec->regmap,
310*4882a593Smuzhiyun AUDIO_PORT_IC_RXFIFO_INT_MSK, 0);
311*4882a593Smuzhiyun regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0);
312*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
313*4882a593Smuzhiyun AUDIO_FIFO_START, AUDIO_FIFO_START);
314*4882a593Smuzhiyun if (channels == 1)
315*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap,
316*4882a593Smuzhiyun AUDIO_PORT_IC_CODEC_RX_CTRL,
317*4882a593Smuzhiyun IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO);
318*4882a593Smuzhiyun else
319*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap,
320*4882a593Smuzhiyun AUDIO_PORT_IC_CODEC_RX_CTRL,
321*4882a593Smuzhiyun IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
sirf_audio_codec_rx_disable(struct sirf_audio_codec * sirf_audio_codec)324*4882a593Smuzhiyun static void sirf_audio_codec_rx_disable(struct sirf_audio_codec *sirf_audio_codec)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap,
327*4882a593Smuzhiyun AUDIO_PORT_IC_CODEC_RX_CTRL,
328*4882a593Smuzhiyun IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
sirf_audio_codec_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)331*4882a593Smuzhiyun static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
332*4882a593Smuzhiyun int cmd,
333*4882a593Smuzhiyun struct snd_soc_dai *dai)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun struct snd_soc_component *component = dai->component;
336*4882a593Smuzhiyun struct sirf_audio_codec *sirf_audio_codec = snd_soc_component_get_drvdata(component);
337*4882a593Smuzhiyun int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun /*
340*4882a593Smuzhiyun * This is a workaround, When stop playback,
341*4882a593Smuzhiyun * need disable HP amp, avoid the current noise.
342*4882a593Smuzhiyun */
343*4882a593Smuzhiyun switch (cmd) {
344*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_STOP:
345*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_SUSPEND:
346*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
347*4882a593Smuzhiyun if (playback) {
348*4882a593Smuzhiyun snd_soc_component_update_bits(component, AUDIO_IC_CODEC_CTRL0,
349*4882a593Smuzhiyun IC_HSLEN | IC_HSREN, 0);
350*4882a593Smuzhiyun sirf_audio_codec_tx_disable(sirf_audio_codec);
351*4882a593Smuzhiyun } else
352*4882a593Smuzhiyun sirf_audio_codec_rx_disable(sirf_audio_codec);
353*4882a593Smuzhiyun break;
354*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_START:
355*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_RESUME:
356*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
357*4882a593Smuzhiyun if (playback) {
358*4882a593Smuzhiyun sirf_audio_codec_tx_enable(sirf_audio_codec);
359*4882a593Smuzhiyun snd_soc_component_update_bits(component, AUDIO_IC_CODEC_CTRL0,
360*4882a593Smuzhiyun IC_HSLEN | IC_HSREN, IC_HSLEN | IC_HSREN);
361*4882a593Smuzhiyun } else
362*4882a593Smuzhiyun sirf_audio_codec_rx_enable(sirf_audio_codec,
363*4882a593Smuzhiyun substream->runtime->channels);
364*4882a593Smuzhiyun break;
365*4882a593Smuzhiyun default:
366*4882a593Smuzhiyun return -EINVAL;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun return 0;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = {
373*4882a593Smuzhiyun .trigger = sirf_audio_codec_trigger,
374*4882a593Smuzhiyun };
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun static struct snd_soc_dai_driver sirf_audio_codec_dai = {
377*4882a593Smuzhiyun .name = "sirf-audio-codec",
378*4882a593Smuzhiyun .playback = {
379*4882a593Smuzhiyun .stream_name = "Playback",
380*4882a593Smuzhiyun .channels_min = 2,
381*4882a593Smuzhiyun .channels_max = 2,
382*4882a593Smuzhiyun .rates = SNDRV_PCM_RATE_48000,
383*4882a593Smuzhiyun .formats = SNDRV_PCM_FMTBIT_S16_LE,
384*4882a593Smuzhiyun },
385*4882a593Smuzhiyun .capture = {
386*4882a593Smuzhiyun .stream_name = "Capture",
387*4882a593Smuzhiyun .channels_min = 1,
388*4882a593Smuzhiyun .channels_max = 2,
389*4882a593Smuzhiyun .rates = SNDRV_PCM_RATE_48000,
390*4882a593Smuzhiyun .formats = SNDRV_PCM_FMTBIT_S16_LE,
391*4882a593Smuzhiyun },
392*4882a593Smuzhiyun .ops = &sirf_audio_codec_dai_ops,
393*4882a593Smuzhiyun };
394*4882a593Smuzhiyun
sirf_audio_codec_probe(struct snd_soc_component * component)395*4882a593Smuzhiyun static int sirf_audio_codec_probe(struct snd_soc_component *component)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun pm_runtime_enable(component->dev);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun if (of_device_is_compatible(component->dev->of_node, "sirf,prima2-audio-codec")) {
402*4882a593Smuzhiyun snd_soc_dapm_new_controls(dapm,
403*4882a593Smuzhiyun prima2_output_driver_dapm_widgets,
404*4882a593Smuzhiyun ARRAY_SIZE(prima2_output_driver_dapm_widgets));
405*4882a593Smuzhiyun snd_soc_dapm_new_controls(dapm,
406*4882a593Smuzhiyun &prima2_codec_clock_dapm_widget, 1);
407*4882a593Smuzhiyun return snd_soc_add_component_controls(component,
408*4882a593Smuzhiyun volume_controls_prima2,
409*4882a593Smuzhiyun ARRAY_SIZE(volume_controls_prima2));
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun if (of_device_is_compatible(component->dev->of_node, "sirf,atlas6-audio-codec")) {
412*4882a593Smuzhiyun snd_soc_dapm_new_controls(dapm,
413*4882a593Smuzhiyun atlas6_output_driver_dapm_widgets,
414*4882a593Smuzhiyun ARRAY_SIZE(atlas6_output_driver_dapm_widgets));
415*4882a593Smuzhiyun snd_soc_dapm_new_controls(dapm,
416*4882a593Smuzhiyun &atlas6_codec_clock_dapm_widget, 1);
417*4882a593Smuzhiyun return snd_soc_add_component_controls(component,
418*4882a593Smuzhiyun volume_controls_atlas6,
419*4882a593Smuzhiyun ARRAY_SIZE(volume_controls_atlas6));
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun return -EINVAL;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
sirf_audio_codec_remove(struct snd_soc_component * component)425*4882a593Smuzhiyun static void sirf_audio_codec_remove(struct snd_soc_component *component)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun pm_runtime_disable(component->dev);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun static const struct snd_soc_component_driver soc_codec_device_sirf_audio_codec = {
431*4882a593Smuzhiyun .probe = sirf_audio_codec_probe,
432*4882a593Smuzhiyun .remove = sirf_audio_codec_remove,
433*4882a593Smuzhiyun .dapm_widgets = sirf_audio_codec_dapm_widgets,
434*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
435*4882a593Smuzhiyun .dapm_routes = sirf_audio_codec_map,
436*4882a593Smuzhiyun .num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map),
437*4882a593Smuzhiyun .use_pmdown_time = 1,
438*4882a593Smuzhiyun .endianness = 1,
439*4882a593Smuzhiyun .non_legacy_dai_naming = 1,
440*4882a593Smuzhiyun };
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun static const struct of_device_id sirf_audio_codec_of_match[] = {
443*4882a593Smuzhiyun { .compatible = "sirf,prima2-audio-codec" },
444*4882a593Smuzhiyun { .compatible = "sirf,atlas6-audio-codec" },
445*4882a593Smuzhiyun {}
446*4882a593Smuzhiyun };
447*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match);
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun static const struct regmap_config sirf_audio_codec_regmap_config = {
450*4882a593Smuzhiyun .reg_bits = 32,
451*4882a593Smuzhiyun .reg_stride = 4,
452*4882a593Smuzhiyun .val_bits = 32,
453*4882a593Smuzhiyun .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK,
454*4882a593Smuzhiyun .cache_type = REGCACHE_NONE,
455*4882a593Smuzhiyun };
456*4882a593Smuzhiyun
sirf_audio_codec_driver_probe(struct platform_device * pdev)457*4882a593Smuzhiyun static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun int ret;
460*4882a593Smuzhiyun struct sirf_audio_codec *sirf_audio_codec;
461*4882a593Smuzhiyun void __iomem *base;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun sirf_audio_codec = devm_kzalloc(&pdev->dev,
464*4882a593Smuzhiyun sizeof(struct sirf_audio_codec), GFP_KERNEL);
465*4882a593Smuzhiyun if (!sirf_audio_codec)
466*4882a593Smuzhiyun return -ENOMEM;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun platform_set_drvdata(pdev, sirf_audio_codec);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun base = devm_platform_ioremap_resource(pdev, 0);
471*4882a593Smuzhiyun if (IS_ERR(base))
472*4882a593Smuzhiyun return PTR_ERR(base);
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
475*4882a593Smuzhiyun &sirf_audio_codec_regmap_config);
476*4882a593Smuzhiyun if (IS_ERR(sirf_audio_codec->regmap))
477*4882a593Smuzhiyun return PTR_ERR(sirf_audio_codec->regmap);
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun sirf_audio_codec->clk = devm_clk_get(&pdev->dev, NULL);
480*4882a593Smuzhiyun if (IS_ERR(sirf_audio_codec->clk)) {
481*4882a593Smuzhiyun dev_err(&pdev->dev, "Get clock failed.\n");
482*4882a593Smuzhiyun return PTR_ERR(sirf_audio_codec->clk);
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun ret = clk_prepare_enable(sirf_audio_codec->clk);
486*4882a593Smuzhiyun if (ret) {
487*4882a593Smuzhiyun dev_err(&pdev->dev, "Enable clock failed.\n");
488*4882a593Smuzhiyun return ret;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun ret = devm_snd_soc_register_component(&(pdev->dev),
492*4882a593Smuzhiyun &soc_codec_device_sirf_audio_codec,
493*4882a593Smuzhiyun &sirf_audio_codec_dai, 1);
494*4882a593Smuzhiyun if (ret) {
495*4882a593Smuzhiyun dev_err(&pdev->dev, "Register Audio Codec dai failed.\n");
496*4882a593Smuzhiyun goto err_clk_put;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun /*
500*4882a593Smuzhiyun * Always open charge pump, if not, when the charge pump closed the
501*4882a593Smuzhiyun * adc will not stable
502*4882a593Smuzhiyun */
503*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
504*4882a593Smuzhiyun IC_CPFREQ, IC_CPFREQ);
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio-codec"))
507*4882a593Smuzhiyun regmap_update_bits(sirf_audio_codec->regmap,
508*4882a593Smuzhiyun AUDIO_IC_CODEC_CTRL0, IC_CPEN, IC_CPEN);
509*4882a593Smuzhiyun return 0;
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun err_clk_put:
512*4882a593Smuzhiyun clk_disable_unprepare(sirf_audio_codec->clk);
513*4882a593Smuzhiyun return ret;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
sirf_audio_codec_driver_remove(struct platform_device * pdev)516*4882a593Smuzhiyun static int sirf_audio_codec_driver_remove(struct platform_device *pdev)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev);
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun clk_disable_unprepare(sirf_audio_codec->clk);
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun return 0;
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
sirf_audio_codec_suspend(struct device * dev)526*4882a593Smuzhiyun static int sirf_audio_codec_suspend(struct device *dev)
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
531*4882a593Smuzhiyun &sirf_audio_codec->reg_ctrl0);
532*4882a593Smuzhiyun regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
533*4882a593Smuzhiyun &sirf_audio_codec->reg_ctrl1);
534*4882a593Smuzhiyun clk_disable_unprepare(sirf_audio_codec->clk);
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun return 0;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
sirf_audio_codec_resume(struct device * dev)539*4882a593Smuzhiyun static int sirf_audio_codec_resume(struct device *dev)
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
542*4882a593Smuzhiyun int ret;
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun ret = clk_prepare_enable(sirf_audio_codec->clk);
545*4882a593Smuzhiyun if (ret)
546*4882a593Smuzhiyun return ret;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
549*4882a593Smuzhiyun sirf_audio_codec->reg_ctrl0);
550*4882a593Smuzhiyun regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
551*4882a593Smuzhiyun sirf_audio_codec->reg_ctrl1);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun return 0;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun #endif
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun static const struct dev_pm_ops sirf_audio_codec_pm_ops = {
558*4882a593Smuzhiyun SET_SYSTEM_SLEEP_PM_OPS(sirf_audio_codec_suspend, sirf_audio_codec_resume)
559*4882a593Smuzhiyun };
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun static struct platform_driver sirf_audio_codec_driver = {
562*4882a593Smuzhiyun .driver = {
563*4882a593Smuzhiyun .name = "sirf-audio-codec",
564*4882a593Smuzhiyun .of_match_table = sirf_audio_codec_of_match,
565*4882a593Smuzhiyun .pm = &sirf_audio_codec_pm_ops,
566*4882a593Smuzhiyun },
567*4882a593Smuzhiyun .probe = sirf_audio_codec_driver_probe,
568*4882a593Smuzhiyun .remove = sirf_audio_codec_driver_remove,
569*4882a593Smuzhiyun };
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun module_platform_driver(sirf_audio_codec_driver);
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun MODULE_DESCRIPTION("SiRF audio codec driver");
574*4882a593Smuzhiyun MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
575*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
576