2 * rt3261_ioctl.h -- RT3261 ALSA SoC audio driver IO control
4 * Copyright 2012 Realtek Microelectronics
5 * Author: Bard <bardliao@realtek.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/spi/spi.h>
13 #include <sound/soc.h>
14 #include "rt_codec_ioctl.h"
15 #include "rt3261_ioctl.h"
17 #if defined (CONFIG_SND_SOC_RT3261)
18 #include "rt3261-dsp.h"
21 static hweq_t hweq_param[] = {
28 {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2},
29 {0x1c10,0x01f4, 0xc5e9, 0x1a98, 0x1d2c, 0xc882, 0x1c10, 0x01f4, 0xe904, 0x1c10, 0x01f4, 0xe904, 0x1c10, 0x01f4, 0x1c10, 0x01f4, 0x2000, 0x0000, 0x2000},
33 {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2},
34 {0x1c10,0x01f4, 0xc5e9, 0x1a98, 0x1d2c, 0xc882, 0x1c10, 0x01f4, 0xe904, 0x1c10, 0x01f4, 0xe904, 0x1c10, 0x01f4, 0x1c10, 0x01f4, 0x2000, 0x0000, 0x2000},
38 #define RT3261_HWEQ_LEN ARRAY_SIZE(hweq_param)
40 int rt3261_update_eqmode(
41 struct snd_soc_codec *codec, int mode)
43 struct rt_codec_ops *ioctl_ops = rt_codec_get_ioctl_ops();
47 if(codec == NULL || mode >= RT3261_HWEQ_LEN)
50 dev_dbg(codec->dev, "%s(): mode=%d\n", __func__, mode);
54 for(i = 0; i <= EQ_REG_NUM; i++) {
55 if(hweq_param[mode].reg[i])
56 ioctl_ops->index_write(codec, hweq_param[mode].reg[i],
57 hweq_param[mode].value[i]);
61 snd_soc_update_bits(codec, RT3261_EQ_CTRL2, RT3261_EQ_CTRL_MASK,
62 hweq_param[mode].ctrl);
63 snd_soc_update_bits(codec, RT3261_EQ_CTRL1,
64 RT3261_EQ_UPD, RT3261_EQ_UPD);
65 snd_soc_update_bits(codec, RT3261_EQ_CTRL1, RT3261_EQ_UPD, 0);
71 static void set_drc_agc_enable(struct snd_soc_codec *codec, int enable, int path)
73 snd_soc_update_bits(codec, RT3261_DRC_AGC_1, RT3261_DRC_AGC_P_MASK |
74 RT3261_DRC_AGC_MASK | RT3261_DRC_AGC_UPD,
75 enable << RT3261_DRC_AGC_SFT | path << RT3261_DRC_AGC_P_SFT |
76 1 << RT3261_DRC_AGC_UPD_BIT);
79 static void set_drc_agc_parameters(struct snd_soc_codec *codec, int attack_rate,
80 int sample_rate, int recovery_rate, int limit_level)
82 snd_soc_update_bits(codec, RT3261_DRC_AGC_3, RT3261_DRC_AGC_TAR_MASK,
83 limit_level << RT3261_DRC_AGC_TAR_SFT);
84 snd_soc_update_bits(codec, RT3261_DRC_AGC_1, RT3261_DRC_AGC_AR_MASK |
85 RT3261_DRC_AGC_R_MASK | RT3261_DRC_AGC_UPD |
86 RT3261_DRC_AGC_RC_MASK, attack_rate << RT3261_DRC_AGC_AR_SFT |
87 sample_rate << RT3261_DRC_AGC_R_SFT |
88 recovery_rate << RT3261_DRC_AGC_RC_SFT |
89 0x1 << RT3261_DRC_AGC_UPD_BIT);
92 static void set_digital_boost_gain(struct snd_soc_codec *codec,
93 int post_gain, int pre_gain)
95 snd_soc_update_bits(codec, RT3261_DRC_AGC_2,
96 RT3261_DRC_AGC_POB_MASK | RT3261_DRC_AGC_PRB_MASK,
97 post_gain << RT3261_DRC_AGC_POB_SFT |
98 pre_gain << RT3261_DRC_AGC_PRB_SFT);
99 snd_soc_update_bits(codec, RT3261_DRC_AGC_1,
100 RT3261_DRC_AGC_UPD, 1 << RT3261_DRC_AGC_UPD_BIT);
103 static void set_noise_gate(struct snd_soc_codec *codec, int noise_gate_en,
104 int noise_gate_hold_en, int compression_gain, int noise_gate_th)
106 snd_soc_update_bits(codec, RT3261_DRC_AGC_3,
107 RT3261_DRC_AGC_NGB_MASK | RT3261_DRC_AGC_NG_MASK |
108 RT3261_DRC_AGC_NGH_MASK | RT3261_DRC_AGC_NGT_MASK,
109 noise_gate_en << RT3261_DRC_AGC_NG_SFT |
110 noise_gate_hold_en << RT3261_DRC_AGC_NGH_SFT |
111 compression_gain << RT3261_DRC_AGC_NGB_SFT |
112 noise_gate_th << RT3261_DRC_AGC_NGT_SFT);
113 snd_soc_update_bits(codec, RT3261_DRC_AGC_1,
114 RT3261_DRC_AGC_UPD, 1 << RT3261_DRC_AGC_UPD_BIT);
117 static void set_drc_agc_compression(struct snd_soc_codec *codec,
118 int compression_en, int compression_ratio)
120 snd_soc_update_bits(codec, RT3261_DRC_AGC_2,
121 RT3261_DRC_AGC_CP_MASK | RT3261_DRC_AGC_CPR_MASK,
122 compression_en << RT3261_DRC_AGC_CP_SFT |
123 compression_ratio << RT3261_DRC_AGC_CPR_SFT);
124 snd_soc_update_bits(codec, RT3261_DRC_AGC_1,
125 RT3261_DRC_AGC_UPD, 1 << RT3261_DRC_AGC_UPD_BIT);
128 static void get_drc_agc_enable(struct snd_soc_codec *codec, int *enable, int *path)
130 unsigned int reg = snd_soc_read(codec, RT3261_DRC_AGC_1);
132 *enable = (reg & RT3261_DRC_AGC_MASK) >> RT3261_DRC_AGC_SFT;
133 *path = (reg & RT3261_DRC_AGC_P_MASK) >> RT3261_DRC_AGC_P_SFT;
136 void get_drc_agc_parameters(struct snd_soc_codec *codec, int *attack_rate,
137 int *sample_rate, int *recovery_rate, int *limit_level)
139 unsigned int reg = snd_soc_read(codec, RT3261_DRC_AGC_3);
141 *limit_level = (reg & RT3261_DRC_AGC_TAR_MASK) >>
142 RT3261_DRC_AGC_TAR_SFT;
143 reg = snd_soc_read(codec, RT3261_DRC_AGC_1);
144 *attack_rate = (reg & RT3261_DRC_AGC_AR_MASK) >> RT3261_DRC_AGC_AR_SFT;
145 *sample_rate = (reg & RT3261_DRC_AGC_R_MASK) >> RT3261_DRC_AGC_R_SFT;
146 *recovery_rate = (reg & RT3261_DRC_AGC_RC_MASK) >>
147 RT3261_DRC_AGC_RC_SFT;
150 static void get_digital_boost_gain(struct snd_soc_codec *codec,
151 int *post_gain, int *pre_gain)
153 unsigned int reg = snd_soc_read(codec, RT3261_DRC_AGC_2);
155 *post_gain = (reg & RT3261_DRC_AGC_POB_MASK) >> RT3261_DRC_AGC_POB_SFT;
156 *pre_gain = (reg & RT3261_DRC_AGC_PRB_MASK) >> RT3261_DRC_AGC_PRB_SFT;
159 static void get_noise_gate(struct snd_soc_codec *codec, int *noise_gate_en,
160 int *noise_gate_hold_en, int *compression_gain, int *noise_gate_th)
162 unsigned int reg = snd_soc_read(codec, RT3261_DRC_AGC_3);
164 printk("get_noise_gate reg=0x%04x\n",reg);
165 *noise_gate_en = (reg & RT3261_DRC_AGC_NG_MASK) >>
166 RT3261_DRC_AGC_NG_SFT;
167 *noise_gate_hold_en = (reg & RT3261_DRC_AGC_NGH_MASK) >>
168 RT3261_DRC_AGC_NGH_SFT;
169 *compression_gain = (reg & RT3261_DRC_AGC_NGB_MASK) >>
170 RT3261_DRC_AGC_NGB_SFT;
171 *noise_gate_th = (reg & RT3261_DRC_AGC_NGT_MASK) >>
172 RT3261_DRC_AGC_NGT_SFT;
175 static void get_drc_agc_compression(struct snd_soc_codec *codec,
176 int *compression_en, int *compression_ratio)
178 unsigned int reg = snd_soc_read(codec, RT3261_DRC_AGC_2);
180 *compression_en = (reg & RT3261_DRC_AGC_CP_MASK) >>
181 RT3261_DRC_AGC_CP_SFT;
182 *compression_ratio = (reg & RT3261_DRC_AGC_CPR_MASK) >>
183 RT3261_DRC_AGC_CPR_SFT;
186 int rt3261_ioctl_common(struct snd_hwdep *hw, struct file *file,
187 unsigned int cmd, unsigned long arg)
189 struct snd_soc_codec *codec = hw->private_data;
190 struct rt_codec_cmd __user *_rt_codec = (struct rt_codec_cmd *)arg;
191 struct rt_codec_cmd rt_codec;
192 struct rt_codec_ops *ioctl_ops = rt_codec_get_ioctl_ops();
193 int *buf, mask1 = 0, mask2 = 0;
196 if (copy_from_user(&rt_codec, _rt_codec, sizeof(rt_codec))) {
197 dev_err(codec->dev,"copy_from_user faild\n");
200 dev_dbg(codec->dev, "%s(): rt_codec.number=%zu, cmd=%d\n",
201 __func__, rt_codec.number, cmd);
202 buf = kmalloc(sizeof(*buf) * rt_codec.number, GFP_KERNEL);
205 if (copy_from_user(buf, rt_codec.buf, sizeof(*buf) * rt_codec.number)) {
210 case RT_SET_CODEC_HWEQ_IOCTL:
214 rt3261_update_eqmode(codec, eq_mode);
217 case RT_GET_CODEC_ID:
218 *buf = snd_soc_read(codec, RT3261_VENDOR_ID2);
219 if (copy_to_user(rt_codec.buf, buf, sizeof(*buf) * rt_codec.number))
223 case RT_SET_CODEC_SPK_VOL_IOCTL:
225 snd_soc_update_bits(codec, RT3261_SPK_VOL,
226 RT3261_L_VOL_MASK | RT3261_R_VOL_MASK,
227 *(buf) << RT3261_L_VOL_SFT |
228 *(buf) << RT3261_R_VOL_SFT);
232 case RT_SET_CODEC_MIC_GAIN_IOCTL:
234 snd_soc_update_bits(codec, RT3261_IN1_IN2,
235 RT3261_BST_MASK1, *(buf) << RT3261_BST_SFT1);
236 snd_soc_update_bits(codec, RT3261_IN3_IN4,
237 RT3261_BST_MASK2, *(buf) << RT3261_BST_SFT2);
241 case RT_SET_CODEC_3D_SPK_IOCTL:
242 if(rt_codec.number < 4)
244 if (NULL == ioctl_ops->index_update_bits)
249 mask1 |= RT3261_3D_SPK_MASK;
251 mask1 |= RT3261_3D_SPK_M_MASK;
253 mask1 |= RT3261_3D_SPK_CG_MASK;
255 mask1 |= RT3261_3D_SPK_SG_MASK;
256 ioctl_ops->index_update_bits(codec, RT3261_3D_SPK, mask1,
257 *(buf) << RT3261_3D_SPK_SFT |
258 *(buf + 1) << RT3261_3D_SPK_M_SFT |
259 *(buf + 2) << RT3261_3D_SPK_CG_SFT |
260 *(buf + 3) << RT3261_3D_SPK_SG_SFT);
263 case RT_SET_CODEC_MP3PLUS_IOCTL:
264 if(rt_codec.number < 5)
268 mask1 |= RT3261_M_MP3_MASK;
270 mask1 |= RT3261_EG_MP3_MASK;
272 mask2 |= RT3261_OG_MP3_MASK;
274 mask2 |= RT3261_HG_MP3_MASK;
276 mask2 |= RT3261_MP3_WT_MASK;
278 snd_soc_update_bits(codec, RT3261_MP3_PLUS1, mask1,
279 *(buf) << RT3261_M_MP3_SFT |
280 *(buf + 1) << RT3261_EG_MP3_SFT);
281 snd_soc_update_bits(codec, RT3261_MP3_PLUS2, mask2,
282 *(buf + 2) << RT3261_OG_MP3_SFT |
283 *(buf + 3) << RT3261_HG_MP3_SFT |
284 *(buf + 4) << RT3261_MP3_WT_SFT);
286 case RT_SET_CODEC_3D_HEADPHONE_IOCTL:
287 if(rt_codec.number < 4)
289 if (NULL == ioctl_ops->index_update_bits)
294 mask1 |= RT3261_3D_HP_MASK;
296 mask1 |= RT3261_3D_BT_MASK;
298 mask1 |= RT3261_3D_1F_MIX_MASK;
300 mask1 |= RT3261_3D_HP_M_MASK;
302 snd_soc_update_bits(codec, RT3261_3D_HP, mask1,
303 *(buf)<<RT3261_3D_HP_SFT |
304 *(buf + 1) << RT3261_3D_BT_SFT |
305 *(buf + 2) << RT3261_3D_1F_MIX_SFT |
306 *(buf + 3) << RT3261_3D_HP_M_SFT);
308 ioctl_ops->index_update_bits(codec,
309 0x59, 0x1f, *(buf+4));
312 case RT_SET_CODEC_BASS_BACK_IOCTL:
313 if(rt_codec.number < 3)
317 mask1 |= RT3261_BB_MASK;
319 mask1 |= RT3261_BB_CT_MASK;
321 mask1 |= RT3261_G_BB_BST_MASK;
323 snd_soc_update_bits(codec, RT3261_BASE_BACK, mask1,
324 *(buf) << RT3261_BB_SFT |
325 *(buf + 1) << RT3261_BB_CT_SFT |
326 *(buf + 2) << RT3261_G_BB_BST_SFT);
329 case RT_SET_CODEC_DIPOLE_SPK_IOCTL:
330 if(rt_codec.number < 2)
332 if (NULL == ioctl_ops->index_update_bits)
337 mask1 |= RT3261_DP_SPK_MASK;
339 mask1 |= RT3261_DP_ATT_MASK;
341 ioctl_ops->index_update_bits(codec, RT3261_DIP_SPK_INF,
342 mask1, *(buf) << RT3261_DP_SPK_SFT |
343 *(buf + 1) << RT3261_DP_ATT_SFT );
346 case RT_SET_CODEC_DRC_AGC_ENABLE_IOCTL:
347 if(rt_codec.number < 2)
349 set_drc_agc_enable(codec, *(buf), *(buf + 1));
352 case RT_SET_CODEC_DRC_AGC_PAR_IOCTL:
353 if(rt_codec.number < 4)
355 set_drc_agc_parameters(codec, *(buf), *(buf + 1),
356 *(buf + 2), *(buf + 3));
359 case RT_SET_CODEC_DIGI_BOOST_GAIN_IOCTL:
360 if(rt_codec.number < 2)
362 set_digital_boost_gain(codec, *(buf), *(buf + 1));
365 case RT_SET_CODEC_NOISE_GATE_IOCTL:
366 if(rt_codec.number < 4)
368 set_noise_gate(codec, *(buf), *(buf + 1),
369 *(buf + 2), *(buf + 3));
372 case RT_SET_CODEC_DRC_AGC_COMP_IOCTL:
373 if(rt_codec.number < 2)
375 set_drc_agc_compression(codec, *(buf), *(buf + 1));
378 case RT_SET_CODEC_WNR_ENABLE_IOCTL:
379 if (NULL == ioctl_ops->index_update_bits)
382 ioctl_ops->index_update_bits(codec, RT3261_WND_1,
383 RT3261_WND_MASK, *(buf) << RT3261_WND_SFT );
386 case RT_GET_CODEC_DRC_AGC_ENABLE_IOCTL:
387 if(rt_codec.number < 2)
389 get_drc_agc_enable(codec, (buf), (buf + 1));
390 if (copy_to_user(rt_codec.buf, buf, sizeof(*buf) * rt_codec.number))
394 case RT_GET_CODEC_DRC_AGC_PAR_IOCTL:
395 if(rt_codec.number < 4)
397 get_drc_agc_parameters(codec, (buf), (buf + 1),
398 (buf + 2), (buf + 3));
399 if (copy_to_user(rt_codec.buf, buf,
400 sizeof(*buf) * rt_codec.number))
404 case RT_GET_CODEC_DIGI_BOOST_GAIN_IOCTL:
405 if(rt_codec.number < 2)
407 get_digital_boost_gain(codec, (buf), (buf + 1));
408 if (copy_to_user(rt_codec.buf, buf,
409 sizeof(*buf) * rt_codec.number))
413 case RT_GET_CODEC_NOISE_GATE_IOCTL:
414 if(rt_codec.number < 4)
416 get_noise_gate(codec, (buf), (buf + 1), (buf + 2), (buf + 3));
417 if (copy_to_user(rt_codec.buf, buf,
418 sizeof(*buf) * rt_codec.number))
422 case RT_GET_CODEC_DRC_AGC_COMP_IOCTL:
423 if(rt_codec.number < 2)
425 get_drc_agc_compression(codec, (buf), (buf + 1));
426 if (copy_to_user(rt_codec.buf, buf,
427 sizeof(*buf) * rt_codec.number))
431 case RT_GET_CODEC_SPK_VOL_IOCTL:
432 *buf = (snd_soc_read(codec, RT3261_SPK_VOL) & RT3261_L_VOL_MASK)
434 if (copy_to_user(rt_codec.buf, buf, sizeof(*buf) * rt_codec.number))
438 case RT_GET_CODEC_MIC_GAIN_IOCTL:
439 *buf = (snd_soc_read(codec, RT3261_IN1_IN2) & RT3261_BST_MASK1)
441 if (copy_to_user(rt_codec.buf, buf, sizeof(*buf) * rt_codec.number))
444 #if defined (CONFIG_SND_SOC_RT3261)
445 case RT_READ_CODEC_DSP_IOCTL:
446 case RT_WRITE_CODEC_DSP_IOCTL:
447 case RT_GET_CODEC_DSP_MODE_IOCTL:
448 return rt_codec_dsp_ioctl_common(hw, file, cmd, arg);
450 case RT_GET_CODEC_HWEQ_IOCTL:
451 case RT_GET_CODEC_3D_SPK_IOCTL:
452 case RT_GET_CODEC_MP3PLUS_IOCTL:
453 case RT_GET_CODEC_3D_HEADPHONE_IOCTL:
454 case RT_GET_CODEC_BASS_BACK_IOCTL:
455 case RT_GET_CODEC_DIPOLE_SPK_IOCTL:
467 EXPORT_SYMBOL_GPL(rt3261_ioctl_common);