2 * rt3261.c -- RT3261 ALSA SoC DSP driver
4 * Copyright 2011 Realtek Semiconductor Corp.
5 * Author: Johnny Hsu <johnnyhsu@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/delay.h>
13 #include <linux/i2c.h>
14 #include <linux/platform_device.h>
15 #include <sound/soc.h>
16 #include <sound/soc-dapm.h>
20 #include <linux/spi/spi.h>
21 #include "rt_codec_ioctl.h"
25 #include "rt3261-dsp.h"
27 #define INIT_DSP_IN_PROBE
29 static const u16 rt3261_dsp_init[][2] = {
30 {0x3fd2, 0x0038}, {0x229C, 0x0fa0}, {0x22d2, 0x8400}, {0x22ee, 0x0000},
31 {0x22f2, 0x0040}, {0x22f5, 0x8000}, {0x22f6, 0x0000}, {0x22f9, 0x007f},
34 #define RT3261_DSP_INIT_NUM \
35 (sizeof(rt3261_dsp_init) / sizeof(rt3261_dsp_init[0]))
37 static const u16 rt3261_dsp_48[][2] = {
38 {0x22c8, 0x0026}, {0x22fe, 0x0fa0}, {0x22ff, 0x3893}, {0x22fa, 0x2487},
41 #define RT3261_DSP_48_NUM (sizeof(rt3261_dsp_48) / sizeof(rt3261_dsp_48[0]))
43 static const u16 rt3261_dsp_441[][2] = {
44 {0x22c6, 0x0031}, {0x22c7, 0x0050}, {0x22c8, 0x0009}, {0x22fe, 0x0e5b},
45 {0x22ff, 0x3883}, {0x22fa, 0x2484}, {0x2301, 0x0001},
47 #define RT3261_DSP_441_NUM (sizeof(rt3261_dsp_441) / sizeof(rt3261_dsp_441[0]))
49 static const u16 rt3261_dsp_16[][2] = {
50 {0x22c8, 0x0026}, {0x22fa, 0x2484}, {0x2301, 0x0002},
52 #define RT3261_DSP_16_NUM (sizeof(rt3261_dsp_16) / sizeof(rt3261_dsp_16[0]))
54 static const u16 rt3261_dsp_rate_tab[] = {
55 0x22c6, 0x22c7, 0x22c8, 0x22fe, 0x22ff, 0x22fa, 0x2301,
57 #define RT3261_DSP_RATE_NUM (sizeof(rt3261_dsp_rate_tab) / sizeof(rt3261_dsp_rate_tab[0]))
59 static const u16 rt3261_dsp_aec_ns_fens[][2] = {
117 #define RT3261_DSP_AEC_NUM \
118 (sizeof(rt3261_dsp_aec_ns_fens) / sizeof(rt3261_dsp_aec_ns_fens[0]))
119 static const u16 rt3261_dsp_hfbf[][2] = {
120 {0x22f8, 0x8004}, {0x22a0, 0x1205}, {0x22a1, 0x0f00}, {0x22a2, 0x1000},
121 {0x22a3, 0x1000}, {0x22a4, 0x1000}, {0x22aa, 0x0006}, {0x22ad, 0x0060},
122 {0x22ae, 0x0080}, {0x22af, 0x0000}, {0x22b0, 0x000e}, {0x22b1, 0x0010},
123 {0x22b2, 0x0006}, {0x22b3, 0x0001}, {0x22b4, 0x0010}, {0x22b5, 0x0001},
124 {0x22b7, 0x0005}, {0x22d8, 0x0017}, {0x22f9, 0x007f}, {0x2303, 0x0971},
125 {0x2304, 0x0302}, {0x2303, 0x0971}, {0x2304, 0x4302}, {0x2305, 0x102d},
126 {0x2309, 0x0400}, {0x230c, 0x0400}, {0x230d, 0x0200}, {0x232f, 0x0020},
127 {0x2332, 0x0100}, {0x2333, 0x0020}, {0x2337, 0xffff}, {0x2339, 0x0010},
128 {0x2348, 0x1000}, {0x2349, 0x1000}, {0x236e, 0x1800}, {0x236f, 0x1006},
129 {0x2370, 0x1000}, {0x2372, 0x0200}, {0x237b, 0x001e}, {0x2380, 0x7fff},
130 {0x2381, 0x4000}, {0x2382, 0x0080}, {0x2383, 0x0200}, {0x2386, 0x7f80},
131 {0x2387, 0x0040}, {0x238a, 0x0280}, {0x238c, 0x6000}, {0x238e, 0x5000},
132 {0x2396, 0x6a00}, {0x2397, 0x6000}, {0x2398, 0x00e0}, {0x23a5, 0x0005},
133 {0x23b3, 0x000f}, {0x23b4, 0x0003}, {0x23bb, 0x2000}, {0x23bc, 0x00d0},
134 {0x23bd, 0x0140}, {0x23be, 0x1000}, {0x23cf, 0x0800}, {0x23d0, 0x0400},
135 {0x23d1, 0x0100}, {0x23d2, 0x0100}, {0x23d5, 0x7c00}, {0x23ed, 0x0300},
136 {0x23ee, 0x3000}, {0x23ef, 0x2800}, {0x22fb, 0x0000},
138 #define RT3261_DSP_HFBF_NUM \
139 (sizeof(rt3261_dsp_hfbf) / sizeof(rt3261_dsp_hfbf[0]))
141 static const u16 rt3261_dsp_ffp[][2] = {
142 {0x22f8, 0x8005}, {0x2303, 0x1971}, {0x2304, 0x8312}, {0x2305, 0x0005},
143 {0x2309, 0x0200}, {0x230a, 0x1b00}, {0x230c, 0x0800}, {0x230d, 0x0400},
144 {0x2325, 0x5000}, {0x2326, 0x0040}, {0x232f, 0x0080}, {0x2332, 0x0100},
145 {0x2333, 0x0020}, {0x2337, 0x0001}, {0x2339, 0x0010}, {0x233c, 0x0040},
146 {0x2348, 0x1000}, {0x2349, 0x1000}, {0x2360, 0x0180}, {0x2361, 0x1800},
147 {0x2362, 0x0200}, {0x2363, 0x0200}, {0x2364, 0x0200}, {0x2365, 0x2000},
148 {0x236e, 0x1000}, {0x236f, 0x0a05}, {0x2370, 0x0f00}, {0x2372, 0x1a00},
149 {0x2373, 0x3000}, {0x2374, 0x2400}, {0x2375, 0x1800}, {0x2380, 0x7fff},
150 {0x2381, 0x4000}, {0x2382, 0x0400}, {0x2383, 0x0400}, {0x2384, 0x0005},
151 {0x2385, 0x0005}, {0x238e, 0x7000}, {0x2393, 0x4444}, {0x2394, 0x4444},
152 {0x2395, 0x4444}, {0x2396, 0x2000}, {0x2397, 0x3000}, {0x2398, 0x0020},
153 {0x23a5, 0x0006}, {0x23a6, 0x7fff}, {0x23b3, 0x000a}, {0x23b4, 0x0006},
154 {0x23b7, 0x0008}, {0x23bb, 0x1000}, {0x23bc, 0x0130}, {0x23bd, 0x0160},
155 {0x23be, 0x2400}, {0x23cf, 0x0800}, {0x23d0, 0x0400}, {0x23d1, 0xff80},
156 {0x23d2, 0xff80}, {0x23d3, 0x2000}, {0x23d4, 0x5000}, {0x23d5, 0x5000},
157 {0x23e7, 0x0c00}, {0x23e8, 0x1400}, {0x23e9, 0x6000}, {0x23ea, 0x7f00},
158 {0x23ed, 0x0300}, {0x23ee, 0x2800}, {0x22fb, 0x0000},
160 #define RT3261_DSP_FFP_NUM (sizeof(rt3261_dsp_ffp) / sizeof(rt3261_dsp_ffp[0]))
162 static const u16 rt3261_dsp_p3_tab[][3] = {
163 {0x4af0, 0x1000, 0x822b}, {0x90f0, 0x1001, 0x8393},
164 {0x64f0, 0x1002, 0x822b}, {0x0ff0, 0x1003, 0x26e0},
165 {0x55f0, 0x1004, 0x2200}, {0xcff0, 0x1005, 0x1a7b},
166 {0x5af0, 0x1006, 0x823a}, {0x90f0, 0x1007, 0x8393},
167 {0x64f0, 0x1008, 0x822b}, {0x0ff0, 0x1009, 0x26e0},
168 {0x03f0, 0x100a, 0x2218}, {0x0ef0, 0x100b, 0x3400},
169 {0x4ff0, 0x100c, 0x195e}, {0x00f0, 0x100d, 0x0000},
170 {0xf0f0, 0x100e, 0x8143}, {0x1ff0, 0x100f, 0x2788},
171 {0x0ef0, 0x1010, 0x3400}, {0xe0f0, 0x1011, 0x1a26},
172 {0x2cf0, 0x1012, 0x8001}, {0x0ff0, 0x1013, 0x267c},
173 {0x82f0, 0x1014, 0x1a27}, {0x3cf0, 0x1015, 0x8001},
174 {0x0ff0, 0x1016, 0x267c}, {0x82f0, 0x1017, 0x1a27},
175 {0xeff0, 0x1018, 0x1a26}, {0x01f0, 0x1019, 0x4ff0},
176 {0x5cf0, 0x101a, 0x2b81}, {0xfaf0, 0x101b, 0x2a6a},
177 {0x05f0, 0x101c, 0x4011}, {0x0ff0, 0x101d, 0x278e},
178 {0x0ef0, 0x101e, 0x3400}, {0xe1f0, 0x101f, 0x1997},
179 {0x1ff0, 0x1020, 0x1997}, {0x03f0, 0x1021, 0x2279},
180 {0xb8f0, 0x1022, 0x8206}, {0xf8f0, 0x1023, 0x0f00},
181 {0xfff0, 0x1024, 0x279e}, {0x0ff0, 0x1025, 0x2272},
182 {0x0ef0, 0x1026, 0x3400}, {0x3ff0, 0x1027, 0x199a},
183 {0x0ff0, 0x1028, 0x2262}, {0x0ff0, 0x1029, 0x2272},
184 {0x0ef0, 0x102a, 0x3400}, {0xfff0, 0x102b, 0x199a},
185 {0x7ff0, 0x102c, 0x22e2}, {0x0ef0, 0x102d, 0x3400},
186 {0xfff0, 0x102e, 0x19cb}, {0xfff0, 0x102f, 0x47ff},
187 {0xb1f0, 0x1030, 0x80b1}, {0x5ff0, 0x1031, 0x2261},
188 {0x62f0, 0x1032, 0x1903}, {0x9af0, 0x1033, 0x0d00},
189 {0xcff0, 0x1034, 0x80b1}, {0x0ff0, 0x1035, 0x0e27},
190 {0x8ff0, 0x1036, 0x9229}, {0x0ef0, 0x1037, 0x3400},
191 {0xaff0, 0x1038, 0x19f5}, {0x81f0, 0x1039, 0x8229},
192 {0x0ef0, 0x103a, 0x3400}, {0xfff0, 0x103b, 0x19f6},
193 {0x5af0, 0x103c, 0x8234}, {0xeaf0, 0x103d, 0x9113},
194 {0x0ef0, 0x103e, 0x3400}, {0x7ff0, 0x103f, 0x19ea},
195 {0x8af0, 0x1040, 0x924d}, {0x08f0, 0x1041, 0x3400},
196 {0x3ff0, 0x1042, 0x1a74}, {0x00f0, 0x1043, 0x0000},
197 {0x00f0, 0x1044, 0x0000}, {0x00f0, 0x1045, 0x0c38},
198 {0x0ff0, 0x1046, 0x2618}, {0xb0f0, 0x1047, 0x8148},
199 {0x01f0, 0x1048, 0x3700}, {0x02f0, 0x1049, 0x3a70},
200 {0x03f0, 0x104a, 0x3a78}, {0x9af0, 0x104b, 0x8229},
201 {0xd6f0, 0x104c, 0x47c4}, {0x95f0, 0x104d, 0x4361},
202 {0x0ff0, 0x104e, 0x2082}, {0x76f0, 0x104f, 0x626b},
203 {0x0ff0, 0x1050, 0x208a}, {0x0ff0, 0x1051, 0x204a},
204 {0xc9f0, 0x1052, 0x7882}, {0x75f0, 0x1053, 0x626b},
205 {0x0ff0, 0x1054, 0x208a}, {0x0ff0, 0x1055, 0x204a},
206 {0xcdf0, 0x1056, 0x7882}, {0x0ff0, 0x1057, 0x2630},
207 {0x8af0, 0x1058, 0x2b30}, {0xf4f0, 0x1059, 0x1904},
208 {0x98f0, 0x105a, 0x9229}, {0x0ef0, 0x105b, 0x3400},
209 {0xeff0, 0x105c, 0x19fd}, {0xd7f0, 0x105d, 0x40cc},
210 {0x0ef0, 0x105e, 0x3400}, {0xdff0, 0x105f, 0x1a44},
211 {0x00f0, 0x1060, 0x0000}, {0xcef0, 0x1061, 0x1507},
212 {0x90f0, 0x1062, 0x1020}, {0x5ff0, 0x1063, 0x1006},
213 {0x89f0, 0x1064, 0x608f}, {0x0ff0, 0x1065, 0x0e64},
214 {0x49f0, 0x1066, 0x1044}, {0xcff0, 0x1067, 0x2b28},
215 {0x93f0, 0x1068, 0x2a62}, {0x5ff0, 0x1069, 0x266a},
216 {0x54f0, 0x106a, 0x22a8}, {0x0af0, 0x106b, 0x0f22},
217 {0xfbf0, 0x106c, 0x0f0c}, {0x5ff0, 0x106d, 0x0d00},
218 {0x90f0, 0x106e, 0x1020}, {0x4ff0, 0x106f, 0x1006},
219 {0x8df0, 0x1070, 0x6087}, {0x0ff0, 0x1071, 0x0e64},
220 {0xb9f0, 0x1072, 0x1044}, {0xcff0, 0x1073, 0x2a63},
221 {0x5ff0, 0x1074, 0x266a}, {0x54f0, 0x1075, 0x22a8},
222 {0x0af0, 0x1076, 0x0f22}, {0xfbf0, 0x1077, 0x0f0c},
223 {0x93f0, 0x1078, 0x2aef}, {0x0ff0, 0x1079, 0x227a},
224 {0xc2f0, 0x107a, 0x1907}, {0xf5f0, 0x107b, 0x0d00},
225 {0xfdf0, 0x107c, 0x7800}, {0x0ef0, 0x107d, 0x3400},
226 {0xaff0, 0x107e, 0x1899},
228 #define RT3261_DSP_PATCH3_NUM \
229 (sizeof(rt3261_dsp_p3_tab) / sizeof(rt3261_dsp_p3_tab[0]))
231 static const u16 rt3261_dsp_p2_tab[][2] = {
232 {0x3fa1, 0xe7bb}, {0x3fb1, 0x5000}, {0x3fa2, 0xa26b}, {0x3fb2, 0x500e},
233 {0x3fa3, 0xa27c}, {0x3fb3, 0x2282}, {0x3fa4, 0x996e}, {0x3fb4, 0x5019},
234 {0x3fa5, 0x99a2}, {0x3fb5, 0x5021}, {0x3fa6, 0x99ae}, {0x3fb6, 0x5028},
235 {0x3fa7, 0x9cbb}, {0x3fb7, 0x502c}, {0x3fa8, 0x9900}, {0x3fb8, 0x1903},
236 {0x3fa9, 0x9f59}, {0x3fb9, 0x502f}, {0x3faa, 0x9f6e}, {0x3fba, 0x5039},
237 {0x3fab, 0x9ea2}, {0x3fbb, 0x503c}, {0x3fac, 0x9fc8}, {0x3fbc, 0x5045},
238 {0x3fad, 0xa44c}, {0x3fbd, 0x505d}, {0x3fae, 0x8983}, {0x3fbe, 0x5061},
239 {0x3faf, 0x95e3}, {0x3fbf, 0x5006}, {0x3fa0, 0xe742}, {0x3fb0, 0x5040},
241 #define RT3261_DSP_PATCH2_NUM \
242 (sizeof(rt3261_dsp_p2_tab) / sizeof(rt3261_dsp_p2_tab[0]))
245 * rt3261_dsp_done - Wait until DSP is ready.
246 * @codec: SoC Audio Codec device.
248 * To check voice DSP status and confirm it's ready for next work.
250 * Returns 0 for success or negative error code.
252 static int rt3261_dsp_done(struct snd_soc_codec *codec)
254 unsigned int count = 0, dsp_val;
256 dsp_val = snd_soc_read(codec, RT3261_DSP_CTRL3);
257 while(dsp_val & RT3261_DSP_BUSY_MASK) {
260 dsp_val = snd_soc_read(codec, RT3261_DSP_CTRL3);
269 * rt3261_dsp_write - Write DSP register.
270 * @codec: SoC audio codec device.
271 * @param: DSP parameters.
273 * Modify voice DSP register for sound effect. The DSP can be controlled
274 * through DSP command format (0xfc), addr (0xc4), data (0xc5) and cmd (0xc6)
275 * register. It has to wait until the DSP is ready.
277 * Returns 0 for success or negative error code.
279 int rt3261_dsp_write(struct snd_soc_codec *codec,
280 struct rt3261_dsp_param *param)
282 unsigned int dsp_val = snd_soc_read(codec, RT3261_DSP_CTRL3);
285 ret = rt3261_dsp_done(codec);
287 dev_err(codec->dev, "DSP is busy: %d\n", ret);
290 ret = snd_soc_write(codec, RT3261_GEN_CTRL3, param->cmd_fmt);
292 dev_err(codec->dev, "Failed to write cmd format: %d\n", ret);
295 ret = snd_soc_write(codec, RT3261_DSP_CTRL1, param->addr);
297 dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret);
300 ret = snd_soc_write(codec, RT3261_DSP_CTRL2, param->data);
302 dev_err(codec->dev, "Failed to write DSP data reg: %d\n", ret);
305 dsp_val &= ~(RT3261_DSP_R_EN | RT3261_DSP_CMD_MASK);
306 dsp_val |= RT3261_DSP_W_EN | param->cmd;
307 ret = snd_soc_write(codec, RT3261_DSP_CTRL3, dsp_val);
309 dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret);
319 EXPORT_SYMBOL_GPL(rt3261_dsp_write);
322 * rt3261_dsp_read - Read DSP register.
323 * @codec: SoC audio codec device.
324 * @reg: DSP register index.
326 * Read DSP setting value from voice DSP. The DSP can be controlled
327 * through DSP addr (0xc4), data (0xc5) and cmd (0xc6) register. Each
328 * command has to wait until the DSP is ready.
330 * Returns DSP register value or negative error code.
332 unsigned int rt3261_dsp_read(
333 struct snd_soc_codec *codec, unsigned int reg)
335 unsigned int val_h, val_l, value;
336 unsigned int dsp_val = snd_soc_read(codec, RT3261_DSP_CTRL3);
339 ret = rt3261_dsp_done(codec);
341 dev_err(codec->dev, "DSP is busy: %d\n", ret);
344 ret = snd_soc_write(codec, RT3261_GEN_CTRL3, 0);
346 dev_err(codec->dev, "Failed to write fc = 0: %d\n", ret);
349 ret = snd_soc_write(codec, RT3261_DSP_CTRL1, reg);
351 dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret);
354 dsp_val &= ~(RT3261_DSP_W_EN | RT3261_DSP_CMD_MASK);
355 dsp_val |= RT3261_DSP_R_EN | RT3261_DSP_CMD_MR;
356 ret = snd_soc_write(codec, RT3261_DSP_CTRL3, dsp_val);
358 dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret);
362 /* Read DSP high byte data */
363 ret = rt3261_dsp_done(codec);
365 dev_err(codec->dev, "DSP is busy: %d\n", ret);
368 ret = snd_soc_write(codec, RT3261_DSP_CTRL1, RT3261_DSP_REG_DATHI);
370 dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret);
373 dsp_val &= ~(RT3261_DSP_W_EN | RT3261_DSP_CMD_MASK);
374 dsp_val |= RT3261_DSP_R_EN | RT3261_DSP_CMD_RR;
375 ret = snd_soc_write(codec, RT3261_DSP_CTRL3, dsp_val);
377 dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret);
380 ret = rt3261_dsp_done(codec);
382 dev_err(codec->dev, "DSP is busy: %d\n", ret);
385 ret = snd_soc_read(codec, RT3261_DSP_CTRL2);
387 dev_err(codec->dev, "Failed to read DSP data reg: %d\n", ret);
392 /* Read DSP low byte data */
393 ret = snd_soc_write(codec, RT3261_DSP_CTRL1, RT3261_DSP_REG_DATLO);
395 dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret);
398 ret = snd_soc_write(codec, RT3261_DSP_CTRL3, dsp_val);
400 dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret);
403 ret = rt3261_dsp_done(codec);
405 dev_err(codec->dev, "DSP is busy: %d\n", ret);
408 ret = snd_soc_read(codec, RT3261_DSP_CTRL2);
410 dev_err(codec->dev, "Failed to read DSP data reg: %d\n", ret);
415 value = ((val_h & 0xff) << 8) |(val_l & 0xff);
421 EXPORT_SYMBOL_GPL(rt3261_dsp_read);
423 static int rt3261_dsp_get(struct snd_kcontrol *kcontrol,
424 struct snd_ctl_elem_value *ucontrol)
426 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
427 struct rt3261_priv *rt3261 = snd_soc_codec_get_drvdata(codec);
429 ucontrol->value.integer.value[0] = rt3261->dsp_sw;
434 static int rt3261_dsp_put(struct snd_kcontrol *kcontrol,
435 struct snd_ctl_elem_value *ucontrol)
437 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
438 struct rt3261_priv *rt3261 = snd_soc_codec_get_drvdata(codec);
440 if (rt3261->dsp_sw != ucontrol->value.integer.value[0])
441 rt3261->dsp_sw = ucontrol->value.integer.value[0];
446 /* DSP Path Control 1 */
447 static const char *rt3261_src_rxdp_mode[] = {
448 "Normal", "Divided by 3"};
450 static const SOC_ENUM_SINGLE_DECL(
451 rt3261_src_rxdp_enum, RT3261_DSP_PATH1,
452 RT3261_RXDP_SRC_SFT, rt3261_src_rxdp_mode);
454 static const char *rt3261_src_txdp_mode[] = {
455 "Normal", "Multiplied by 3"};
457 static const SOC_ENUM_SINGLE_DECL(
458 rt3261_src_txdp_enum, RT3261_DSP_PATH1,
459 RT3261_TXDP_SRC_SFT, rt3261_src_txdp_mode);
461 /* DSP data select */
462 static const char *rt3261_dsp_data_select[] = {
463 "Normal", "left copy to right", "right copy to left", "Swap"};
465 static const SOC_ENUM_SINGLE_DECL(rt3261_rxdc_data_enum, RT3261_DSP_PATH2,
466 RT3261_RXDC_SEL_SFT, rt3261_dsp_data_select);
468 static const SOC_ENUM_SINGLE_DECL(rt3261_rxdp_data_enum, RT3261_DSP_PATH2,
469 RT3261_RXDP_SEL_SFT, rt3261_dsp_data_select);
471 static const SOC_ENUM_SINGLE_DECL(rt3261_txdc_data_enum, RT3261_DSP_PATH2,
472 RT3261_TXDC_SEL_SFT, rt3261_dsp_data_select);
474 static const SOC_ENUM_SINGLE_DECL(rt3261_txdp_data_enum, RT3261_DSP_PATH2,
475 RT3261_TXDP_SEL_SFT, rt3261_dsp_data_select);
478 static const char *rt3261_dsp_mode[] = {
479 "Disable", "AEC+NS+FENS", "HFBF", "Far Field Pick-up"};
481 static const SOC_ENUM_SINGLE_DECL(rt3261_dsp_enum, 0, 0, rt3261_dsp_mode);
483 static const char *rt3261_rxdp2_src[] =
484 {"IF2_DAC", "Stereo_ADC"};
486 static const SOC_ENUM_SINGLE_DECL(
487 rt3261_rxdp2_enum, RT3261_GEN_CTRL2,
488 RT3261_RXDP2_SEL_SFT, rt3261_rxdp2_src);
490 static const struct snd_kcontrol_new rt3261_rxdp2_mux =
491 SOC_DAPM_ENUM("RxDP2 sel", rt3261_rxdp2_enum);
493 static const char *rt3261_rxdp_src[] =
496 static const SOC_ENUM_SINGLE_DECL(
497 rt3261_rxdp_enum, RT3261_DUMMY_PR3F,
498 10, rt3261_rxdp_src);
500 static const struct snd_kcontrol_new rt3261_rxdp_mux =
501 SOC_DAPM_ENUM("RxDP sel", rt3261_rxdp_enum);
503 static const char *rt3261_rxdc_src[] =
504 {"Mono_ADC", "Stereo_ADC"};
506 static const SOC_ENUM_SINGLE_DECL(
507 rt3261_rxdc_enum, RT3261_GEN_CTRL2,
508 RT3261_RXDC_SRC_SFT, rt3261_rxdc_src);
510 static const struct snd_kcontrol_new rt3261_rxdc_mux =
511 SOC_DAPM_ENUM("RxDC sel", rt3261_rxdc_enum);
513 static const char *rt3261_rxdp1_src[] =
516 static const SOC_ENUM_SINGLE_DECL(
517 rt3261_rxdp1_enum, RT3261_DUMMY_PR3F,
518 9, rt3261_rxdp1_src);
520 static const struct snd_kcontrol_new rt3261_rxdp1_mux =
521 SOC_DAPM_ENUM("RxDP1 sel", rt3261_rxdp1_enum);
523 static const struct snd_kcontrol_new rt3261_dsp_snd_controls[] = {
524 SOC_ENUM("RxDC input data", rt3261_rxdc_data_enum),
525 SOC_ENUM("RxDP input data", rt3261_rxdp_data_enum),
526 SOC_ENUM("TxDC input data", rt3261_txdc_data_enum),
527 SOC_ENUM("TxDP input data", rt3261_txdp_data_enum),
528 SOC_ENUM("SRC for RxDP", rt3261_src_rxdp_enum),
529 SOC_ENUM("SRC for TxDP", rt3261_src_txdp_enum),
531 SOC_ENUM_EXT("DSP Function Switch", rt3261_dsp_enum,
532 rt3261_dsp_get, rt3261_dsp_put),
535 /*static int rt3261_dsp_patch_3(struct snd_soc_codec *codec)
537 struct rt3261_dsp_param param;
540 param.cmd_fmt = 0x0090;
543 param.cmd = RT3261_DSP_CMD_RW;
544 ret = rt3261_dsp_write(codec, ¶m);
547 "Fail to set DSP 3 bytes patch entrance: %d\n", ret);
551 param.cmd = RT3261_DSP_CMD_PE;
552 for(i = 0; i < RT3261_DSP_PATCH3_NUM; i++) {
553 param.cmd_fmt = rt3261_dsp_p3_tab[i][0];
554 param.addr = rt3261_dsp_p3_tab[i][1];
555 param.data = rt3261_dsp_p3_tab[i][2];
556 ret = rt3261_dsp_write(codec, ¶m);
558 dev_err(codec->dev, "Fail to patch Dsp: %d\n", ret);
570 static int rt3261_dsp_patch_2(struct snd_soc_codec *codec)
572 struct rt3261_dsp_param param;
575 param.cmd_fmt = 0x0090;
578 param.cmd = RT3261_DSP_CMD_RW;
579 ret = rt3261_dsp_write(codec, ¶m);
582 "Fail to set DSP 2 bytes patch entrance: %d\n", ret);
586 param.cmd_fmt = 0x00e0;
587 param.cmd = RT3261_DSP_CMD_MW;
588 for(i = 0; i < RT3261_DSP_PATCH2_NUM; i++) {
589 param.addr = rt3261_dsp_p2_tab[i][0];
590 param.data = rt3261_dsp_p2_tab[i][1];
591 ret = rt3261_dsp_write(codec, ¶m);
593 dev_err(codec->dev, "Fail to patch Dsp: %d\n", ret);
606 * rt3261_dsp_patch - Write DSP patch code.
608 * @codec: SoC audio codec device.
610 * Write patch codes to DSP including 3 and 2 bytes data.
612 * Returns 0 for success or negative error code.
614 /*static int rt3261_dsp_patch(struct snd_soc_codec *codec)
618 dev_dbg(codec->dev, "\n DSP Patch Start ......\n");
620 ret = snd_soc_update_bits(codec, RT3261_MICBIAS,
621 RT3261_PWR_CLK25M_MASK, RT3261_PWR_CLK25M_PU);
625 ret = snd_soc_update_bits(codec, RT3261_GLB_CLK,
626 RT3261_SCLK_SRC_MASK, RT3261_SCLK_SRC_RCCLK);
630 ret = snd_soc_update_bits(codec, RT3261_PWR_DIG2,
631 RT3261_PWR_I2S_DSP, RT3261_PWR_I2S_DSP);
635 ret = snd_soc_update_bits(codec, RT3261_DSP_CTRL3,
636 RT3261_DSP_PD_PIN_MASK, RT3261_DSP_PD_PIN_HI);
638 dev_err(codec->dev, "Failed to power up DSP: %d\n", ret);
642 ret = snd_soc_update_bits(codec, RT3261_DSP_CTRL3,
643 RT3261_DSP_RST_PIN_MASK, RT3261_DSP_RST_PIN_LO);
645 dev_err(codec->dev, "Failed to reset DSP: %d\n", ret);
651 ret = snd_soc_update_bits(codec, RT3261_DSP_CTRL3,
652 RT3261_DSP_RST_PIN_MASK, RT3261_DSP_RST_PIN_HI);
654 dev_err(codec->dev, "Failed to recover DSP: %d\n", ret);
658 ret = rt3261_dsp_patch_3(codec);
662 ret = rt3261_dsp_patch_2(codec);
673 static void rt3261_do_dsp_patch(struct work_struct *work)
675 struct rt3261_priv *rt3261 =
676 container_of(work, struct rt3261_priv, patch_work.work);
677 struct snd_soc_codec *codec = rt3261->codec;
679 if (rt3261_dsp_patch(codec) < 0)
680 dev_err(codec->dev, "Patch DSP rom code Fail !!!\n");
685 * rt3261_dsp_conf - Set DSP basic setting.
687 * @codec: SoC audio codec device.
689 * Set parameters of basic setting to DSP.
691 * Returns 0 for success or negative error code.
693 static int rt3261_dsp_conf(struct snd_soc_codec *codec)
695 struct rt3261_dsp_param param;
698 ret = snd_soc_update_bits(codec, RT3261_DSP_CTRL3,
699 RT3261_DSP_PD_PIN_MASK, RT3261_DSP_PD_PIN_HI);
701 dev_err(codec->dev, "Failed to power up DSP: %d\n", ret);
705 ret = snd_soc_update_bits(codec, RT3261_DSP_CTRL3,
706 RT3261_DSP_RST_PIN_MASK, RT3261_DSP_RST_PIN_LO);
708 dev_err(codec->dev, "Failed to reset DSP: %d\n", ret);
714 ret = snd_soc_update_bits(codec, RT3261_DSP_CTRL3,
715 RT3261_DSP_RST_PIN_MASK | RT3261_DSP_CLK_MASK,
716 RT3261_DSP_RST_PIN_HI | RT3261_DSP_CLK_384K);
718 dev_err(codec->dev, "Failed to recover DSP: %d\n", ret);
722 param.cmd_fmt = 0x00e0;
723 param.cmd = RT3261_DSP_CMD_MW;
724 for(i = 0; i < RT3261_DSP_INIT_NUM; i++) {
725 param.addr = rt3261_dsp_init[i][0];
726 param.data = rt3261_dsp_init[i][1];
727 ret = rt3261_dsp_write(codec, ¶m);
729 dev_err(codec->dev, "Fail to config Dsp: %d\n", ret);
742 * rt3261_dsp_rate - Set DSP rate setting.
744 * @codec: SoC audio codec device.
745 * @rate: Sampling rate.
747 * Set parameters of sampling rate to DSP.
749 * Returns 0 for success or negative error code.
751 static int rt3261_dsp_rate(struct snd_soc_codec *codec, int rate)
753 struct rt3261_dsp_param param;
755 static const unsigned short (*rate_tab)[2];
757 if (rate != 48000 && rate != 44100 && rate != 16000)
761 rate_tab = rt3261_dsp_48;
762 tab_num = RT3261_DSP_48_NUM;
765 rate_tab = rt3261_dsp_441;
766 tab_num = RT3261_DSP_441_NUM;
768 rate_tab = rt3261_dsp_16;
769 tab_num = RT3261_DSP_16_NUM;
773 param.cmd_fmt = 0x00e0;
774 param.cmd = RT3261_DSP_CMD_MW;
775 for (i = 0; i < tab_num; i++) {
776 param.addr = rate_tab[i][0];
777 param.data = rate_tab[i][1];
778 ret = rt3261_dsp_write(codec, ¶m);
787 dev_err(codec->dev, "Fail to set rate %d parameters: %d\n", rate, ret);
792 * rt3261_dsp_set_mode - Set DSP mode parameters.
794 * @codec: SoC audio codec device.
797 * Set parameters of mode to DSP.
798 * There are three modes which includes " mic AEC + NS + FENS",
799 * "HFBF" and "Far-field pickup".
801 * Returns 0 for success or negative error code.
803 static int rt3261_dsp_set_mode(struct snd_soc_codec *codec, int mode)
805 struct rt3261_dsp_param param;
808 unsigned short (*mode_tab)[2];
811 case RT3261_DSP_AEC_NS_FENS:
812 dev_info(codec->dev, "AEC\n");
813 mode_tab = rt3261_dsp_aec_ns_fens;
814 tab_num = RT3261_DSP_AEC_NUM;
817 case RT3261_DSP_HFBF:
818 dev_info(codec->dev, "Beamforming\n");
819 mode_tab = rt3261_dsp_hfbf;
820 tab_num = RT3261_DSP_HFBF_NUM;
824 dev_info(codec->dev, "Far Field Pick-up\n");
825 mode_tab = rt3261_dsp_ffp;
826 tab_num = RT3261_DSP_FFP_NUM;
831 dev_info(codec->dev, "Disable\n");
835 param.cmd_fmt = 0x00e0;
836 param.cmd = RT3261_DSP_CMD_MW;
837 for (i = 0; i < RT3261_DSP_AEC_NUM; i++) {
838 param.addr = rt3261_dsp_aec_ns_fens[i][0];
839 param.data = rt3261_dsp_aec_ns_fens[i][1];
840 ret = rt3261_dsp_write(codec, ¶m);
849 dev_err(codec->dev, "Fail to set mode %d parameters: %d\n", mode, ret);
854 * rt3261_dsp_snd_effect - Set DSP sound effect.
856 * Set parameters of sound effect to DSP.
858 * Returns 0 for success or negative error code.
860 static int rt3261_dsp_snd_effect(struct snd_soc_codec *codec)
862 struct rt3261_priv *rt3261 = snd_soc_codec_get_drvdata(codec);
865 ret = rt3261_dsp_conf(codec);
869 ret = rt3261_dsp_rate(codec, rt3261->lrck[rt3261->aif_pu] ?
870 rt3261->lrck[rt3261->aif_pu] : 44100);
874 ret = rt3261_dsp_set_mode(codec, rt3261->dsp_sw);
887 static int rt3261_dsp_event(struct snd_soc_dapm_widget *w,
888 struct snd_kcontrol *k, int event)
890 struct snd_soc_codec *codec = w->codec;
891 struct rt3261_priv *rt3261 = snd_soc_codec_get_drvdata(codec);
892 static unsigned int power_on;
895 case SND_SOC_DAPM_POST_PMD:
896 pr_info("%s(): PMD\n", __func__);
902 snd_soc_update_bits(codec, RT3261_PWR_DIG2,
903 RT3261_PWR_I2S_DSP, 0);
904 snd_soc_update_bits(codec, RT3261_DSP_CTRL3,
905 RT3261_DSP_PD_PIN_MASK, RT3261_DSP_PD_PIN_LO);
909 case SND_SOC_DAPM_POST_PMU:
910 pr_info("%s(): PMU\n", __func__);
911 if (rt3261->dsp_sw == RT3261_DSP_DIS || 2 <= power_on)
915 snd_soc_update_bits(codec, RT3261_PWR_DIG2,
916 RT3261_PWR_I2S_DSP, RT3261_PWR_I2S_DSP);
917 #ifdef INIT_DSP_IN_PROBE
918 snd_soc_update_bits(codec, RT3261_DSP_CTRL3,
919 RT3261_DSP_PD_PIN_MASK, RT3261_DSP_PD_PIN_HI);
921 rt3261_dsp_snd_effect(codec);
934 static const struct snd_soc_dapm_widget rt3261_dsp_dapm_widgets[] = {
935 SND_SOC_DAPM_PGA_E("DSP Downstream", SND_SOC_NOPM,
936 0, 0, NULL, 0, rt3261_dsp_event,
937 SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
938 SND_SOC_DAPM_PGA_E("DSP Upstream", SND_SOC_NOPM,
939 0, 0, NULL, 0, rt3261_dsp_event,
940 SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
941 SND_SOC_DAPM_MUX("RxDP Mux", SND_SOC_NOPM, 0, 0,
943 SND_SOC_DAPM_MUX("RxDP2 Mux", SND_SOC_NOPM, 0, 0,
945 SND_SOC_DAPM_MUX("RxDP1 Mux", SND_SOC_NOPM, 0, 0,
947 SND_SOC_DAPM_MUX("RxDC Mux", SND_SOC_NOPM, 0, 0,
949 SND_SOC_DAPM_PGA("RxDP", SND_SOC_NOPM, 0, 0, NULL, 0),
950 SND_SOC_DAPM_PGA("RxDC", SND_SOC_NOPM, 0, 0, NULL, 0),
951 SND_SOC_DAPM_PGA("TxDC", SND_SOC_NOPM, 0, 0, NULL, 0),
952 SND_SOC_DAPM_PGA("TxDP", SND_SOC_NOPM, 0, 0, NULL, 0),
955 static const struct snd_soc_dapm_route rt3261_dsp_dapm_routes[] = {
956 {"RxDC", NULL, "RxDC Mux"},
957 {"RxDC Mux", "Mono_ADC", "Mono ADC MIXL"},
958 {"RxDC Mux", "Mono_ADC", "Mono ADC MIXR"},
959 {"RxDC Mux", "Stereo_ADC", "Stereo ADC MIXL"},
960 {"RxDC Mux", "Stereo_ADC", "Stereo ADC MIXR"},
961 {"RxDP", NULL, "RxDP Mux"},
962 {"RxDP Mux", "RxDP2", "RxDP2 Mux"},
963 {"RxDP Mux", "RxDP1", "RxDP1 Mux"},
964 {"RxDP2 Mux", "IF2_DAC", "IF2 DAC L"},
965 {"RxDP2 Mux", "IF2_DAC", "IF2 DAC R"},
966 {"RxDP2 Mux", "Stereo_ADC", "Stereo ADC MIXL"},
967 {"RxDP2 Mux", "Stereo_ADC", "Stereo ADC MIXR"},
968 {"RxDP1 Mux", "DAC1", "Stereo DAC MIXL"},
969 {"RxDP1 Mux", "DAC1", "Stereo DAC MIXR"},
970 {"RxDP1 Mux", "IF1_DAC", "IF1 DAC L"},
971 {"RxDP1 Mux", "IF1_DAC", "IF1 DAC R"},
973 {"DSP Downstream", NULL, "RxDP"},
974 {"TxDC", NULL, "DSP Downstream"},
975 {"DSP Upstream", NULL, "RxDP"},
976 {"DSP Upstream", NULL, "RxDC"},
977 {"TxDP", NULL, "DSP Upstream"},
979 {"IF2 ADC L Mux", "TxDP", "TxDP"},
980 {"IF2 ADC R Mux", "TxDP", "TxDP"},
981 {"DAC L2 Mux", "TxDC", "TxDC"},
982 {"DAC R2 Mux", "TxDC", "TxDC"},
986 * rt3261_dsp_show - Dump DSP registers.
987 * @dev: codec device.
988 * @attr: device attribute.
989 * @buf: buffer for display.
991 * To show non-zero values of all DSP registers.
993 * Returns buffer length.
995 static ssize_t rt3261_dsp_show(struct device *dev,
996 struct device_attribute *attr, char *buf)
998 struct i2c_client *client = to_i2c_client(dev);
999 struct rt3261_priv *rt3261 = i2c_get_clientdata(client);
1000 struct snd_soc_codec *codec = rt3261->codec;
1001 static const unsigned short (*rt3261_dsp_tab)[2];
1003 int cnt = 0, i, tab_num;
1005 switch (rt3261->dsp_sw) {
1006 case RT3261_DSP_AEC_NS_FENS:
1007 cnt += sprintf(buf, "[ RT3261 DSP 'AEC' ]\n");
1008 rt3261_dsp_tab = rt3261_dsp_aec_ns_fens;
1009 tab_num = RT3261_DSP_AEC_NUM;
1012 case RT3261_DSP_HFBF:
1013 cnt += sprintf(buf, "[ RT3261 DSP 'Beamforming' ]\n");
1014 rt3261_dsp_tab = rt3261_dsp_hfbf;
1015 tab_num = RT3261_DSP_HFBF_NUM;
1018 case RT3261_DSP_FFP:
1019 cnt += sprintf(buf, "[ RT3261 DSP 'Far Field Pick-up' ]\n");
1020 rt3261_dsp_tab = rt3261_dsp_ffp;
1021 tab_num = RT3261_DSP_FFP_NUM;
1024 case RT3261_DSP_DIS:
1026 cnt += sprintf(buf, "RT3261 DSP Disabled\n");
1030 for (i = 0; i < tab_num; i++) {
1031 if (cnt + RT3261_DSP_REG_DISP_LEN >= PAGE_SIZE)
1033 val = rt3261_dsp_read(codec, rt3261_dsp_tab[i][0]);
1036 cnt += snprintf(buf + cnt, RT3261_DSP_REG_DISP_LEN,
1037 "#rnv%04x #rv%04x #rd0\n\n", rt3261_dsp_tab[i][0], val);
1040 tab_num = RT3261_DSP_INIT_NUM;
1041 for (i = 0; i < tab_num; i++) {
1042 if (cnt + RT3261_DSP_REG_DISP_LEN >= PAGE_SIZE)
1044 val = rt3261_dsp_read(codec, rt3261_dsp_init[i][0]);
1047 cnt += snprintf(buf + cnt, RT3261_DSP_REG_DISP_LEN,
1048 "#rnv%04x #rv%04x #rd0\n", rt3261_dsp_init[i][0], val);
1050 for (i = 0; i < RT3261_DSP_RATE_NUM; i++) {
1051 if (cnt + RT3261_DSP_REG_DISP_LEN >= PAGE_SIZE)
1053 val = rt3261_dsp_read(codec, rt3261_dsp_rate_tab[i]);
1056 cnt += snprintf(buf + cnt, RT3261_DSP_REG_DISP_LEN,
1057 "#rnv%04x #rv%04x #rd0\n", rt3261_dsp_rate_tab[i], val);
1062 if (cnt >= PAGE_SIZE)
1063 cnt = PAGE_SIZE - 1;
1068 static ssize_t dsp_reg_store(struct device *dev,
1069 struct device_attribute *attr, const char *buf, size_t count)
1071 struct i2c_client *client = to_i2c_client(dev);
1072 struct rt3261_priv *rt3261 = i2c_get_clientdata(client);
1073 struct snd_soc_codec *codec = rt3261->codec;
1074 struct rt3261_dsp_param param;
1075 unsigned int val=0,addr=0;
1078 printk("register \"%s\" count=%d\n",buf,count);
1080 for(i=0;i<count;i++) //address
1082 if(*(buf+i) <= '9' && *(buf+i)>='0')
1084 addr = (addr << 4) | (*(buf+i)-'0');
1086 else if(*(buf+i) <= 'f' && *(buf+i)>='a')
1088 addr = (addr << 4) | ((*(buf+i)-'a')+0xa);
1090 else if(*(buf+i) <= 'A' && *(buf+i)>='A')
1092 addr = (addr << 4) | ((*(buf+i)-'A')+0xa);
1100 for(i=i+1 ;i<count;i++) //val
1102 if(*(buf+i) <= '9' && *(buf+i)>='0')
1104 val = (val << 4) | (*(buf+i)-'0');
1106 else if(*(buf+i) <= 'f' && *(buf+i)>='a')
1108 val = (val << 4) | ((*(buf+i)-'a')+0xa);
1110 else if(*(buf+i) <= 'F' && *(buf+i)>='A')
1112 val = (val << 4) | ((*(buf+i)-'A')+0xa);
1120 printk("addr=0x%x val=0x%x\n",addr,val);
1123 printk("0x%04x = 0x%04x\n",addr,rt3261_dsp_read(codec, addr));
1127 param.cmd_fmt = 0x00e0;
1128 param.cmd = RT3261_DSP_CMD_MW;
1131 rt3261_dsp_write(codec, ¶m);
1137 static DEVICE_ATTR(dsp_reg, 0666, rt3261_dsp_show, dsp_reg_store);
1140 * rt3261_dsp_probe - register DSP for rt3261
1141 * @codec: audio codec
1143 * To register DSP function for rt3261.
1145 * Returns 0 for success or negative error code.
1147 int rt3261_dsp_probe(struct snd_soc_codec *codec)
1149 //struct rt3261_priv *rt3261;
1155 snd_soc_add_codec_controls(codec, rt3261_dsp_snd_controls,
1156 ARRAY_SIZE(rt3261_dsp_snd_controls));
1157 snd_soc_dapm_new_controls(&codec->dapm, rt3261_dsp_dapm_widgets,
1158 ARRAY_SIZE(rt3261_dsp_dapm_widgets));
1159 snd_soc_dapm_add_routes(&codec->dapm, rt3261_dsp_dapm_routes,
1160 ARRAY_SIZE(rt3261_dsp_dapm_routes));
1162 /* Patch DSP rom code if IC version is larger than C version */
1164 ret = snd_soc_update_bits(codec, RT3261_PWR_DIG2,
1165 RT3261_PWR_I2S_DSP, RT3261_PWR_I2S_DSP);
1168 "Failed to power up DSP IIS interface: %d\n", ret);
1171 #ifdef INIT_DSP_IN_PROBE
1172 rt3261_dsp_snd_effect(codec);
1173 ret = rt3261_dsp_read(codec, 0x22fb);
1175 pr_info("DSP init success\n");
1177 pr_info("DSP init failed\n");
1179 rt3261_dsp_conf(codec);
1181 ret = rt3261_dsp_read(codec, 0x3800);
1182 pr_info("DSP version code = 0x%04x\n",ret);
1183 /*if(ret != 0x501a) {
1184 rt3261 = snd_soc_codec_get_drvdata(codec);
1185 INIT_DELAYED_WORK(&rt3261->patch_work, rt3261_do_dsp_patch);
1186 schedule_delayed_work(&rt3261->patch_work,
1187 msecs_to_jiffies(100));
1189 #ifdef INIT_DSP_IN_PROBE
1190 snd_soc_update_bits(codec, RT3261_DSP_CTRL3,
1191 RT3261_DSP_PD_PIN_MASK, RT3261_DSP_PD_PIN_LO);
1193 snd_soc_update_bits(codec, RT3261_PWR_DIG2,
1194 RT3261_PWR_I2S_DSP, 0);
1196 ret = device_create_file(codec->dev, &dev_attr_dsp_reg);
1199 "Failed to create index_reg sysfs files: %d\n", ret);
1205 EXPORT_SYMBOL_GPL(rt3261_dsp_probe);
1208 int rt_codec_dsp_ioctl_common(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
1210 struct rt_codec_cmd rt_codec;
1214 struct rt3261_dsp_param param;
1216 //int mask1 = 0, mask2 = 0;
1218 struct rt_codec_cmd __user *_rt_codec = (struct rt_codec_cmd *)arg;
1219 struct snd_soc_codec *codec = hw->private_data;
1220 struct rt3261_priv *rt3261 = snd_soc_codec_get_drvdata(codec);
1222 if (copy_from_user(&rt_codec, _rt_codec, sizeof(rt_codec))) {
1223 dev_err(codec->dev, "copy_from_user faild\n");
1226 dev_dbg(codec->dev, "rt_codec.number=%d\n",rt_codec.number);
1227 buf = kmalloc(sizeof(*buf) * rt_codec.number, GFP_KERNEL);
1230 if (copy_from_user(buf, rt_codec.buf, sizeof(*buf) * rt_codec.number)) {
1234 ret = snd_soc_update_bits(codec, RT3261_PWR_DIG2,
1235 RT3261_PWR_I2S_DSP, RT3261_PWR_I2S_DSP);
1238 "Failed to power up DSP IIS interface: %d\n", ret);
1243 case RT_READ_CODEC_DSP_IOCTL:
1244 for (p = buf; p < buf + rt_codec.number/2; p++)
1245 *(p+rt_codec.number/2) = rt3261_dsp_read(codec, *p);
1246 if (copy_to_user(rt_codec.buf, buf, sizeof(*buf) * rt_codec.number))
1250 case RT_WRITE_CODEC_DSP_IOCTL:
1251 param.cmd_fmt = 0x00e0;
1252 param.cmd = RT3261_DSP_CMD_MW;
1255 param.data = *(p+rt_codec.number/2);
1257 dev_dbg(codec->dev, "codec is null\n");
1260 for (p = buf; p < buf + rt_codec.number/2; p++)
1261 rt3261_dsp_write(codec, ¶m);
1264 case RT_GET_CODEC_DSP_MODE_IOCTL:
1265 *buf = rt3261->dsp_sw;
1266 if (copy_to_user(rt_codec.buf, buf, sizeof(*buf) * rt_codec.number))
1271 dev_info(codec->dev, "unsported dsp command\n");
1282 EXPORT_SYMBOL_GPL(rt_codec_dsp_ioctl_common);
1286 int rt3261_dsp_suspend(struct snd_soc_codec *codec)
1290 EXPORT_SYMBOL_GPL(rt3261_dsp_suspend);
1292 int rt3261_dsp_resume(struct snd_soc_codec *codec)
1296 EXPORT_SYMBOL_GPL(rt3261_dsp_resume);