]>
Commit | Line | Data |
---|---|---|
fffa1cca VK |
1 | /* intel_sst_v1_control.c - Intel SST Driver for audio engine |
2 | * | |
3 | * Copyright (C) 2008-10 Intel Corp | |
4 | * Authors: Vinod Koul <vinod.koul@intel.com> | |
5 | * Harsha Priya <priya.harsha@intel.com> | |
6 | * Dharageswari R <dharageswari.r@intel.com> | |
7 | * KP Jeeja <jeeja.kp@intel.com> | |
8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; version 2 of the License. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License along | |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | |
21 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
22 | * | |
23 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
24 | * | |
25 | * This file contains the control operations of vendor 2 | |
26 | */ | |
27 | ||
d0f40c50 JP |
28 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
29 | ||
fffa1cca VK |
30 | #include <linux/pci.h> |
31 | #include <linux/file.h> | |
32 | #include <asm/mrst.h> | |
33 | #include <sound/pcm.h> | |
34 | #include "jack.h" | |
35 | #include <sound/pcm_params.h> | |
36 | #include <sound/control.h> | |
37 | #include <sound/initval.h> | |
38 | #include "intel_sst.h" | |
39 | #include "intel_sst_ioctl.h" | |
40 | #include "intelmid.h" | |
41 | #include "intelmid_snd_control.h" | |
42 | ||
43 | #include <linux/gpio.h> | |
44 | #define KOSKI_VOICE_CODEC_ENABLE 46 | |
45 | ||
46 | enum _reg_v2 { | |
47 | ||
48 | MASTER_CLOCK_PRESCALAR = 0x205, | |
49 | SET_MASTER_AND_LR_CLK1 = 0x20b, | |
50 | SET_MASTER_AND_LR_CLK2 = 0x20c, | |
51 | MASTER_MODE_AND_DATA_DELAY = 0x20d, | |
52 | DIGITAL_INTERFACE_TO_DAI2 = 0x20e, | |
53 | CLK_AND_FS1 = 0x208, | |
54 | CLK_AND_FS2 = 0x209, | |
55 | DAI2_TO_DAC_HP = 0x210, | |
56 | HP_OP_SINGLE_ENDED = 0x224, | |
57 | ENABLE_OPDEV_CTRL = 0x226, | |
58 | ENABLE_DEV_AND_USE_XTAL = 0x227, | |
59 | ||
60 | /* Max audio subsystem (PQ49) MAX 8921 */ | |
61 | AS_IP_MODE_CTL = 0xF9, | |
62 | AS_LEFT_SPKR_VOL_CTL = 0xFA, /* Mono Earpiece volume control */ | |
63 | AS_RIGHT_SPKR_VOL_CTL = 0xFB, | |
64 | AS_LEFT_HP_VOL_CTL = 0xFC, | |
65 | AS_RIGHT_HP_VOL_CTL = 0xFD, | |
66 | AS_OP_MIX_CTL = 0xFE, | |
67 | AS_CONFIG = 0xFF, | |
68 | ||
69 | /* Headphone volume control & mute registers */ | |
70 | VOL_CTRL_LT = 0x21c, | |
71 | VOL_CTRL_RT = 0x21d, | |
72 | ||
73 | }; | |
74 | /** | |
d9fed669 | 75 | * mx_init_card - initialize the sound card |
fffa1cca | 76 | * |
d9fed669 | 77 | * This initializes the audio paths to know values in case of this sound card |
fffa1cca VK |
78 | */ |
79 | static int mx_init_card(void) | |
80 | { | |
83cb1926 AC |
81 | struct sc_reg_access sc_access[] = { |
82 | {0x200, 0x80, 0x00}, | |
83 | {0x201, 0xC0, 0x00}, | |
84 | {0x202, 0x00, 0x00}, | |
85 | {0x203, 0x00, 0x00}, | |
86 | {0x204, 0x02, 0x00}, | |
87 | {0x205, 0x10, 0x00}, | |
88 | {0x206, 0x60, 0x00}, | |
89 | {0x207, 0x00, 0x00}, | |
90 | {0x208, 0x90, 0x00}, | |
91 | {0x209, 0x51, 0x00}, | |
92 | {0x20a, 0x00, 0x00}, | |
93 | {0x20b, 0x10, 0x00}, | |
94 | {0x20c, 0x00, 0x00}, | |
95 | {0x20d, 0x00, 0x00}, | |
96 | {0x20e, 0x21, 0x00}, | |
97 | {0x20f, 0x00, 0x00}, | |
98 | {0x210, 0x84, 0x00}, | |
99 | {0x211, 0xB3, 0x00}, | |
100 | {0x212, 0x00, 0x00}, | |
101 | {0x213, 0x00, 0x00}, | |
102 | {0x214, 0x41, 0x00}, | |
103 | {0x215, 0x00, 0x00}, | |
104 | {0x216, 0x00, 0x00}, | |
105 | {0x217, 0x00, 0x00}, | |
106 | {0x218, 0x03, 0x00}, | |
107 | {0x219, 0x03, 0x00}, | |
108 | {0x21a, 0x00, 0x00}, | |
109 | {0x21b, 0x00, 0x00}, | |
110 | {0x21c, 0x00, 0x00}, | |
111 | {0x21d, 0x00, 0x00}, | |
112 | {0x21e, 0x00, 0x00}, | |
113 | {0x21f, 0x00, 0x00}, | |
114 | {0x220, 0x20, 0x00}, | |
115 | {0x221, 0x20, 0x00}, | |
116 | {0x222, 0x51, 0x00}, | |
117 | {0x223, 0x20, 0x00}, | |
118 | {0x224, 0x04, 0x00}, | |
119 | {0x225, 0x80, 0x00}, | |
120 | {0x226, 0x0F, 0x00}, | |
121 | {0x227, 0x08, 0x00}, | |
122 | {0xf9, 0x40, 0x00}, | |
123 | {0xfa, 0x1f, 0x00}, | |
124 | {0xfb, 0x1f, 0x00}, | |
125 | {0xfc, 0x1f, 0x00}, | |
126 | {0xfd, 0x1f, 0x00}, | |
127 | {0xfe, 0x00, 0x00}, | |
128 | {0xff, 0x0c, 0x00}, | |
129 | }; | |
130 | snd_pmic_ops_mx.card_status = SND_CARD_INIT_DONE; | |
131 | snd_pmic_ops_mx.num_channel = 2; | |
132 | snd_pmic_ops_mx.master_mute = UNMUTE; | |
133 | snd_pmic_ops_mx.mute_status = UNMUTE; | |
134 | return sst_sc_reg_access(sc_access, PMIC_WRITE, 47); | |
fffa1cca VK |
135 | } |
136 | ||
fffa1cca VK |
137 | static int mx_enable_audiodac(int value) |
138 | { | |
139 | struct sc_reg_access sc_access[3]; | |
140 | int mute_val = 0; | |
141 | int mute_val1 = 0; | |
142 | int retval = 0; | |
143 | ||
144 | sc_access[0].reg_addr = AS_LEFT_HP_VOL_CTL; | |
145 | sc_access[1].reg_addr = AS_RIGHT_HP_VOL_CTL; | |
146 | ||
147 | if (value == UNMUTE) { | |
148 | mute_val = 0x1F; | |
149 | mute_val1 = 0x00; | |
150 | } else { | |
151 | mute_val = 0x00; | |
152 | mute_val1 = 0x40; | |
153 | } | |
154 | sc_access[0].mask = sc_access[1].mask = MASK0|MASK1|MASK2|MASK3|MASK4; | |
155 | sc_access[0].value = sc_access[1].value = (u8)mute_val; | |
156 | retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); | |
157 | if (retval) | |
158 | return retval; | |
d0f40c50 | 159 | pr_debug("mute status = %d\n", snd_pmic_ops_mx.mute_status); |
fffa1cca VK |
160 | if (snd_pmic_ops_mx.mute_status == MUTE || |
161 | snd_pmic_ops_mx.master_mute == MUTE) | |
162 | return retval; | |
163 | ||
164 | sc_access[0].reg_addr = VOL_CTRL_LT; | |
165 | sc_access[1].reg_addr = VOL_CTRL_RT; | |
166 | sc_access[0].mask = sc_access[1].mask = MASK6; | |
167 | sc_access[0].value = sc_access[1].value = mute_val1; | |
168 | if (snd_pmic_ops_mx.num_channel == 1) | |
169 | sc_access[1].value = 0x40; | |
170 | return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); | |
171 | } | |
172 | ||
173 | static int mx_power_up_pb(unsigned int port) | |
174 | { | |
175 | ||
176 | int retval = 0; | |
177 | struct sc_reg_access sc_access[3]; | |
178 | ||
179 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
180 | retval = mx_init_card(); | |
181 | if (retval) | |
182 | return retval; | |
183 | } | |
fffa1cca VK |
184 | retval = mx_enable_audiodac(MUTE); |
185 | if (retval) | |
186 | return retval; | |
187 | ||
188 | msleep(10); | |
189 | ||
190 | sc_access[0].reg_addr = AS_CONFIG; | |
191 | sc_access[0].mask = MASK7; | |
192 | sc_access[0].value = 0x80; | |
193 | retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); | |
194 | if (retval) | |
195 | return retval; | |
196 | ||
197 | sc_access[0].reg_addr = ENABLE_OPDEV_CTRL; | |
198 | sc_access[0].mask = 0xff; | |
199 | sc_access[0].value = 0x3C; | |
200 | retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); | |
201 | if (retval) | |
202 | return retval; | |
203 | ||
204 | sc_access[0].reg_addr = ENABLE_DEV_AND_USE_XTAL; | |
205 | sc_access[0].mask = 0x80; | |
206 | sc_access[0].value = 0x80; | |
207 | retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); | |
208 | if (retval) | |
209 | return retval; | |
210 | ||
211 | return mx_enable_audiodac(UNMUTE); | |
212 | } | |
213 | ||
214 | static int mx_power_down_pb(void) | |
215 | { | |
216 | struct sc_reg_access sc_access[3]; | |
217 | int retval = 0; | |
218 | ||
219 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
220 | retval = mx_init_card(); | |
221 | if (retval) | |
222 | return retval; | |
223 | } | |
224 | ||
225 | retval = mx_enable_audiodac(MUTE); | |
226 | if (retval) | |
227 | return retval; | |
228 | ||
229 | sc_access[0].reg_addr = ENABLE_OPDEV_CTRL; | |
230 | sc_access[0].mask = MASK3|MASK2; | |
231 | sc_access[0].value = 0x00; | |
232 | ||
233 | retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); | |
234 | if (retval) | |
235 | return retval; | |
236 | ||
237 | return mx_enable_audiodac(UNMUTE); | |
238 | } | |
239 | ||
240 | static int mx_power_up_cp(unsigned int port) | |
241 | { | |
242 | int retval = 0; | |
243 | struct sc_reg_access sc_access[] = { | |
244 | {ENABLE_DEV_AND_USE_XTAL, 0x80, MASK7}, | |
245 | {ENABLE_OPDEV_CTRL, 0x3, 0x3}, | |
246 | }; | |
247 | ||
248 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
249 | retval = mx_init_card(); | |
250 | if (retval) | |
251 | return retval; | |
252 | } | |
253 | ||
83cb1926 | 254 | return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); |
fffa1cca VK |
255 | } |
256 | ||
257 | static int mx_power_down_cp(void) | |
258 | { | |
259 | struct sc_reg_access sc_access[] = { | |
260 | {ENABLE_OPDEV_CTRL, 0x00, MASK1|MASK0}, | |
261 | }; | |
262 | int retval = 0; | |
263 | ||
264 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
265 | retval = mx_init_card(); | |
266 | if (retval) | |
267 | return retval; | |
268 | } | |
269 | ||
270 | return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); | |
271 | } | |
272 | ||
273 | static int mx_power_down(void) | |
274 | { | |
275 | int retval = 0; | |
276 | struct sc_reg_access sc_access[3]; | |
277 | ||
278 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
279 | retval = mx_init_card(); | |
280 | if (retval) | |
281 | return retval; | |
282 | } | |
283 | ||
284 | retval = mx_enable_audiodac(MUTE); | |
285 | if (retval) | |
286 | return retval; | |
287 | ||
288 | sc_access[0].reg_addr = AS_CONFIG; | |
289 | sc_access[0].mask = MASK7; | |
290 | sc_access[0].value = 0x00; | |
291 | retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); | |
292 | if (retval) | |
293 | return retval; | |
294 | ||
295 | sc_access[0].reg_addr = ENABLE_DEV_AND_USE_XTAL; | |
296 | sc_access[0].mask = MASK7; | |
297 | sc_access[0].value = 0x00; | |
298 | retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); | |
299 | if (retval) | |
300 | return retval; | |
301 | ||
302 | sc_access[0].reg_addr = ENABLE_OPDEV_CTRL; | |
303 | sc_access[0].mask = MASK3|MASK2; | |
304 | sc_access[0].value = 0x00; | |
305 | retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1); | |
306 | if (retval) | |
307 | return retval; | |
308 | ||
309 | return mx_enable_audiodac(UNMUTE); | |
310 | } | |
311 | ||
312 | static int mx_set_pcm_voice_params(void) | |
313 | { | |
314 | int retval = 0; | |
315 | struct sc_reg_access sc_access[] = { | |
316 | {0x200, 0x80, 0x00}, | |
317 | {0x201, 0xC0, 0x00}, | |
318 | {0x202, 0x00, 0x00}, | |
319 | {0x203, 0x00, 0x00}, | |
320 | {0x204, 0x0e, 0x00}, | |
321 | {0x205, 0x20, 0x00}, | |
322 | {0x206, 0x8f, 0x00}, | |
323 | {0x207, 0x21, 0x00}, | |
324 | {0x208, 0x18, 0x00}, | |
325 | {0x209, 0x32, 0x00}, | |
326 | {0x20a, 0x00, 0x00}, | |
327 | {0x20b, 0x5A, 0x00}, | |
328 | {0x20c, 0xBE, 0x00},/* 0x00 -> 0xBE Koski */ | |
329 | {0x20d, 0x00, 0x00}, /* DAI2 'off' */ | |
330 | {0x20e, 0x40, 0x00}, | |
331 | {0x20f, 0x00, 0x00}, | |
332 | {0x210, 0x84, 0x00}, | |
333 | {0x211, 0x33, 0x00}, /* Voice filter */ | |
334 | {0x212, 0x00, 0x00}, | |
335 | {0x213, 0x00, 0x00}, | |
336 | {0x214, 0x41, 0x00}, | |
337 | {0x215, 0x00, 0x00}, | |
338 | {0x216, 0x00, 0x00}, | |
339 | {0x217, 0x20, 0x00}, | |
340 | {0x218, 0x00, 0x00}, | |
341 | {0x219, 0x00, 0x00}, | |
342 | {0x21a, 0x40, 0x00}, | |
343 | {0x21b, 0x40, 0x00}, | |
344 | {0x21c, 0x09, 0x00}, | |
345 | {0x21d, 0x09, 0x00}, | |
346 | {0x21e, 0x00, 0x00}, | |
347 | {0x21f, 0x00, 0x00}, | |
348 | {0x220, 0x00, 0x00}, /* Microphone configurations */ | |
349 | {0x221, 0x00, 0x00}, /* Microphone configurations */ | |
350 | {0x222, 0x50, 0x00}, /* Microphone configurations */ | |
351 | {0x223, 0x21, 0x00}, /* Microphone configurations */ | |
352 | {0x224, 0x00, 0x00}, | |
353 | {0x225, 0x80, 0x00}, | |
354 | {0xf9, 0x40, 0x00}, | |
355 | {0xfa, 0x19, 0x00}, | |
356 | {0xfb, 0x19, 0x00}, | |
357 | {0xfc, 0x12, 0x00}, | |
358 | {0xfd, 0x12, 0x00}, | |
359 | {0xfe, 0x00, 0x00}, | |
360 | }; | |
361 | ||
362 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
363 | retval = mx_init_card(); | |
364 | if (retval) | |
365 | return retval; | |
366 | } | |
d0f40c50 | 367 | pr_debug("SST DBG:mx_set_pcm_voice_params called\n"); |
fffa1cca VK |
368 | return sst_sc_reg_access(sc_access, PMIC_WRITE, 44); |
369 | } | |
370 | ||
371 | static int mx_set_pcm_audio_params(int sfreq, int word_size, int num_channel) | |
372 | { | |
373 | int retval = 0; | |
374 | ||
83cb1926 AC |
375 | int config1 = 0, config2 = 0, filter = 0xB3; |
376 | struct sc_reg_access sc_access[5]; | |
377 | ||
378 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
379 | retval = mx_init_card(); | |
380 | if (retval) | |
381 | return retval; | |
382 | } | |
383 | ||
384 | switch (sfreq) { | |
385 | case 8000: | |
386 | config1 = 0x10; | |
387 | config2 = 0x00; | |
388 | filter = 0x33; | |
389 | break; | |
390 | case 11025: | |
391 | config1 = 0x16; | |
392 | config2 = 0x0d; | |
393 | break; | |
394 | case 12000: | |
395 | config1 = 0x18; | |
396 | config2 = 0x00; | |
397 | break; | |
398 | case 16000: | |
399 | config1 = 0x20; | |
400 | config2 = 0x00; | |
401 | break; | |
402 | case 22050: | |
403 | config1 = 0x2c; | |
404 | config2 = 0x1a; | |
405 | break; | |
406 | case 24000: | |
407 | config1 = 0x30; | |
408 | config2 = 0x00; | |
409 | break; | |
410 | case 32000: | |
411 | config1 = 0x40; | |
412 | config2 = 0x00; | |
413 | break; | |
414 | case 44100: | |
415 | config1 = 0x58; | |
416 | config2 = 0x33; | |
417 | break; | |
418 | case 48000: | |
419 | config1 = 0x60; | |
420 | config2 = 0x00; | |
421 | break; | |
422 | } | |
423 | snd_pmic_ops_mx.num_channel = num_channel; | |
424 | /*mute the right channel if MONO*/ | |
425 | if (snd_pmic_ops_mx.num_channel == 1) { | |
426 | sc_access[0].reg_addr = VOL_CTRL_RT; | |
427 | sc_access[0].value = 0x40; | |
428 | sc_access[0].mask = MASK6; | |
429 | ||
430 | sc_access[1].reg_addr = 0x224; | |
431 | sc_access[1].value = 0x05; | |
432 | sc_access[1].mask = MASK0|MASK1|MASK2; | |
433 | ||
434 | retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); | |
435 | if (retval) | |
436 | return retval; | |
fffa1cca | 437 | } else { |
83cb1926 AC |
438 | sc_access[0].reg_addr = VOL_CTRL_RT; |
439 | sc_access[0].value = 0x00; | |
440 | sc_access[0].mask = MASK6; | |
441 | ||
442 | sc_access[1].reg_addr = 0x224; | |
443 | sc_access[1].value = 0x04; | |
444 | sc_access[1].mask = MASK0|MASK1|MASK2; | |
445 | ||
446 | retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2); | |
447 | if (retval) | |
448 | return retval; | |
fffa1cca | 449 | } |
83cb1926 AC |
450 | sc_access[0].reg_addr = 0x206; |
451 | sc_access[0].value = config1; | |
452 | sc_access[1].reg_addr = 0x207; | |
453 | sc_access[1].value = config2; | |
454 | ||
455 | if (word_size == 16) { | |
456 | sc_access[2].value = 0x51; | |
457 | sc_access[3].value = 0x31; | |
458 | } else if (word_size == 24) { | |
459 | sc_access[2].value = 0x52; | |
460 | sc_access[3].value = 0x92; | |
461 | } | |
462 | ||
463 | sc_access[2].reg_addr = 0x209; | |
464 | sc_access[3].reg_addr = 0x20e; | |
465 | ||
466 | sc_access[4].reg_addr = 0x211; | |
467 | sc_access[4].value = filter; | |
468 | ||
469 | return sst_sc_reg_access(sc_access, PMIC_WRITE, 5); | |
fffa1cca VK |
470 | } |
471 | ||
472 | static int mx_set_selected_output_dev(u8 dev_id) | |
473 | { | |
474 | struct sc_reg_access sc_access[2]; | |
475 | int num_reg = 0; | |
476 | int retval = 0; | |
477 | ||
478 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
479 | retval = mx_init_card(); | |
480 | if (retval) | |
481 | return retval; | |
482 | } | |
483 | ||
d0f40c50 | 484 | pr_debug("mx_set_selected_output_dev dev_id:0x%x\n", dev_id); |
fffa1cca VK |
485 | snd_pmic_ops_mx.output_dev_id = dev_id; |
486 | switch (dev_id) { | |
487 | case STEREO_HEADPHONE: | |
488 | sc_access[0].reg_addr = 0xFF; | |
489 | sc_access[0].value = 0x8C; | |
490 | sc_access[0].mask = | |
491 | MASK2|MASK3|MASK5|MASK6|MASK4; | |
492 | ||
493 | num_reg = 1; | |
494 | break; | |
495 | case MONO_EARPIECE: | |
496 | case INTERNAL_SPKR: | |
497 | sc_access[0].reg_addr = 0xFF; | |
498 | sc_access[0].value = 0xb0; | |
499 | sc_access[0].mask = MASK2|MASK3|MASK5|MASK6|MASK4; | |
500 | ||
501 | num_reg = 1; | |
502 | break; | |
503 | case RECEIVER: | |
d0f40c50 | 504 | pr_debug("RECEIVER Koski selected\n"); |
fffa1cca VK |
505 | |
506 | /* configuration - AS enable, receiver enable */ | |
507 | sc_access[0].reg_addr = 0xFF; | |
508 | sc_access[0].value = 0x81; | |
509 | sc_access[0].mask = 0xff; | |
510 | ||
511 | num_reg = 1; | |
512 | break; | |
513 | default: | |
d0f40c50 | 514 | pr_err("Not a valid output dev\n"); |
fffa1cca VK |
515 | return 0; |
516 | } | |
517 | return sst_sc_reg_access(sc_access, PMIC_WRITE, num_reg); | |
518 | } | |
519 | ||
520 | ||
521 | static int mx_set_voice_port(int status) | |
522 | { | |
523 | int retval = 0; | |
524 | ||
525 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
526 | retval = mx_init_card(); | |
527 | if (retval) | |
528 | return retval; | |
529 | } | |
530 | if (status == ACTIVATE) | |
531 | retval = mx_set_pcm_voice_params(); | |
532 | ||
533 | return retval; | |
534 | } | |
535 | ||
536 | static int mx_set_audio_port(int status) | |
537 | { | |
83cb1926 | 538 | return 0; |
fffa1cca VK |
539 | } |
540 | ||
541 | static int mx_set_selected_input_dev(u8 dev_id) | |
542 | { | |
543 | struct sc_reg_access sc_access[2]; | |
544 | int num_reg = 0; | |
545 | int retval = 0; | |
546 | ||
547 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
548 | retval = mx_init_card(); | |
549 | if (retval) | |
550 | return retval; | |
551 | } | |
552 | snd_pmic_ops_mx.input_dev_id = dev_id; | |
d0f40c50 | 553 | pr_debug("mx_set_selected_input_dev dev_id:0x%x\n", dev_id); |
fffa1cca VK |
554 | |
555 | switch (dev_id) { | |
556 | case AMIC: | |
557 | sc_access[0].reg_addr = 0x223; | |
558 | sc_access[0].value = 0x00; | |
559 | sc_access[0].mask = MASK7|MASK6|MASK5|MASK4|MASK0; | |
560 | sc_access[1].reg_addr = 0x222; | |
561 | sc_access[1].value = 0x50; | |
562 | sc_access[1].mask = MASK7|MASK6|MASK5|MASK4; | |
563 | num_reg = 2; | |
564 | break; | |
565 | ||
566 | case HS_MIC: | |
567 | sc_access[0].reg_addr = 0x223; | |
568 | sc_access[0].value = 0x20; | |
569 | sc_access[0].mask = MASK7|MASK6|MASK5|MASK4|MASK0; | |
570 | sc_access[1].reg_addr = 0x222; | |
571 | sc_access[1].value = 0x51; | |
572 | sc_access[1].mask = MASK7|MASK6|MASK5|MASK4; | |
573 | num_reg = 2; | |
574 | break; | |
575 | case DMIC: | |
576 | sc_access[1].reg_addr = 0x222; | |
577 | sc_access[1].value = 0x00; | |
578 | sc_access[1].mask = MASK7|MASK6|MASK5|MASK4|MASK0; | |
579 | sc_access[0].reg_addr = 0x223; | |
580 | sc_access[0].value = 0x20; | |
581 | sc_access[0].mask = MASK7|MASK6|MASK5|MASK4|MASK0; | |
582 | num_reg = 2; | |
583 | break; | |
584 | } | |
585 | return sst_sc_reg_access(sc_access, PMIC_WRITE, num_reg); | |
586 | } | |
587 | ||
588 | static int mx_set_mute(int dev_id, u8 value) | |
589 | { | |
590 | struct sc_reg_access sc_access[5]; | |
591 | int num_reg = 0; | |
592 | int retval = 0; | |
593 | ||
594 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
595 | retval = mx_init_card(); | |
596 | if (retval) | |
597 | return retval; | |
598 | } | |
599 | ||
600 | ||
d0f40c50 | 601 | pr_debug("set_mute dev_id:0x%x , value:%d\n", dev_id, value); |
fffa1cca VK |
602 | |
603 | switch (dev_id) { | |
604 | case PMIC_SND_DMIC_MUTE: | |
605 | case PMIC_SND_AMIC_MUTE: | |
606 | case PMIC_SND_HP_MIC_MUTE: | |
607 | sc_access[0].reg_addr = 0x220; | |
608 | sc_access[1].reg_addr = 0x221; | |
609 | sc_access[2].reg_addr = 0x223; | |
610 | if (value == MUTE) { | |
611 | sc_access[0].value = 0x00; | |
612 | sc_access[1].value = 0x00; | |
613 | if (snd_pmic_ops_mx.input_dev_id == DMIC) | |
614 | sc_access[2].value = 0x00; | |
615 | else | |
616 | sc_access[2].value = 0x20; | |
617 | } else { | |
618 | sc_access[0].value = 0x20; | |
619 | sc_access[1].value = 0x20; | |
620 | if (snd_pmic_ops_mx.input_dev_id == DMIC) | |
621 | sc_access[2].value = 0x20; | |
622 | else | |
623 | sc_access[2].value = 0x00; | |
624 | } | |
625 | sc_access[0].mask = MASK5|MASK6; | |
626 | sc_access[1].mask = MASK5|MASK6; | |
627 | sc_access[2].mask = MASK5|MASK6; | |
628 | num_reg = 3; | |
629 | break; | |
630 | case PMIC_SND_LEFT_SPEAKER_MUTE: | |
631 | case PMIC_SND_LEFT_HP_MUTE: | |
632 | sc_access[0].reg_addr = VOL_CTRL_LT; | |
633 | if (value == MUTE) | |
634 | sc_access[0].value = 0x40; | |
635 | else | |
636 | sc_access[0].value = 0x00; | |
637 | sc_access[0].mask = MASK6; | |
638 | num_reg = 1; | |
639 | snd_pmic_ops_mx.mute_status = value; | |
640 | break; | |
641 | case PMIC_SND_RIGHT_SPEAKER_MUTE: | |
642 | case PMIC_SND_RIGHT_HP_MUTE: | |
643 | sc_access[0].reg_addr = VOL_CTRL_RT; | |
644 | if (snd_pmic_ops_mx.num_channel == 1) | |
645 | value = MUTE; | |
646 | if (value == MUTE) | |
647 | sc_access[0].value = 0x40; | |
648 | else | |
649 | sc_access[0].value = 0x00; | |
650 | sc_access[0].mask = MASK6; | |
651 | num_reg = 1; | |
652 | snd_pmic_ops_mx.mute_status = value; | |
653 | break; | |
654 | case PMIC_SND_MUTE_ALL: | |
655 | sc_access[0].reg_addr = VOL_CTRL_RT; | |
656 | sc_access[1].reg_addr = VOL_CTRL_LT; | |
657 | sc_access[2].reg_addr = 0x220; | |
658 | sc_access[3].reg_addr = 0x221; | |
659 | sc_access[4].reg_addr = 0x223; | |
660 | snd_pmic_ops_mx.master_mute = value; | |
661 | if (value == MUTE) { | |
662 | sc_access[0].value = sc_access[1].value = 0x40; | |
663 | sc_access[2].value = 0x00; | |
664 | sc_access[3].value = 0x00; | |
665 | if (snd_pmic_ops_mx.input_dev_id == DMIC) | |
666 | sc_access[4].value = 0x00; | |
667 | else | |
668 | sc_access[4].value = 0x20; | |
669 | ||
670 | } else { | |
671 | sc_access[0].value = sc_access[1].value = 0x00; | |
672 | sc_access[2].value = sc_access[3].value = 0x20; | |
673 | sc_access[4].value = 0x20; | |
674 | if (snd_pmic_ops_mx.input_dev_id == DMIC) | |
675 | sc_access[4].value = 0x20; | |
676 | else | |
677 | sc_access[4].value = 0x00; | |
678 | ||
679 | ||
680 | } | |
681 | if (snd_pmic_ops_mx.num_channel == 1) | |
682 | sc_access[0].value = 0x40; | |
683 | sc_access[0].mask = sc_access[1].mask = MASK6; | |
684 | sc_access[2].mask = MASK5|MASK6; | |
685 | sc_access[3].mask = MASK5|MASK6|MASK2|MASK4; | |
686 | sc_access[4].mask = MASK5|MASK6|MASK4; | |
687 | ||
688 | num_reg = 5; | |
689 | break; | |
690 | case PMIC_SND_RECEIVER_MUTE: | |
691 | sc_access[0].reg_addr = VOL_CTRL_RT; | |
692 | if (value == MUTE) | |
693 | sc_access[0].value = 0x40; | |
694 | else | |
695 | sc_access[0].value = 0x00; | |
696 | sc_access[0].mask = MASK6; | |
697 | num_reg = 1; | |
698 | break; | |
699 | } | |
700 | ||
701 | return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_reg); | |
702 | } | |
703 | ||
704 | static int mx_set_vol(int dev_id, int value) | |
705 | { | |
706 | struct sc_reg_access sc_access[2] = {{0},}; | |
707 | int num_reg = 0; | |
708 | int retval = 0; | |
709 | ||
710 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
711 | retval = mx_init_card(); | |
712 | if (retval) | |
713 | return retval; | |
714 | } | |
d0f40c50 | 715 | pr_debug("set_vol dev_id:0x%x ,value:%d\n", dev_id, value); |
fffa1cca VK |
716 | switch (dev_id) { |
717 | case PMIC_SND_RECEIVER_VOL: | |
718 | return 0; | |
719 | break; | |
720 | case PMIC_SND_CAPTURE_VOL: | |
721 | sc_access[0].reg_addr = 0x220; | |
722 | sc_access[1].reg_addr = 0x221; | |
723 | sc_access[0].value = sc_access[1].value = -value; | |
724 | sc_access[0].mask = sc_access[1].mask = | |
725 | (MASK0|MASK1|MASK2|MASK3|MASK4); | |
726 | num_reg = 2; | |
727 | break; | |
728 | case PMIC_SND_LEFT_PB_VOL: | |
729 | sc_access[0].value = -value; | |
730 | sc_access[0].reg_addr = VOL_CTRL_LT; | |
731 | sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); | |
732 | num_reg = 1; | |
733 | break; | |
734 | case PMIC_SND_RIGHT_PB_VOL: | |
735 | sc_access[0].value = -value; | |
736 | sc_access[0].reg_addr = VOL_CTRL_RT; | |
737 | sc_access[0].mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5); | |
738 | if (snd_pmic_ops_mx.num_channel == 1) { | |
739 | sc_access[0].value = 0x40; | |
740 | sc_access[0].mask = MASK6; | |
741 | sc_access[0].reg_addr = VOL_CTRL_RT; | |
742 | } | |
743 | num_reg = 1; | |
744 | break; | |
745 | } | |
746 | return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, num_reg); | |
747 | } | |
748 | ||
749 | static int mx_get_mute(int dev_id, u8 *value) | |
750 | { | |
751 | struct sc_reg_access sc_access[4] = {{0},}; | |
752 | int retval = 0, num_reg = 0, mask = 0; | |
753 | ||
754 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
755 | retval = mx_init_card(); | |
756 | if (retval) | |
757 | return retval; | |
758 | } | |
759 | switch (dev_id) { | |
760 | case PMIC_SND_DMIC_MUTE: | |
761 | case PMIC_SND_AMIC_MUTE: | |
762 | case PMIC_SND_HP_MIC_MUTE: | |
763 | sc_access[0].reg_addr = 0x220; | |
764 | mask = MASK5|MASK6; | |
765 | num_reg = 1; | |
766 | retval = sst_sc_reg_access(sc_access, PMIC_READ, num_reg); | |
767 | if (retval) | |
768 | return retval; | |
769 | *value = sc_access[0].value & mask; | |
770 | if (*value) | |
771 | *value = UNMUTE; | |
772 | else | |
773 | *value = MUTE; | |
774 | return retval; | |
775 | case PMIC_SND_LEFT_HP_MUTE: | |
776 | case PMIC_SND_LEFT_SPEAKER_MUTE: | |
777 | sc_access[0].reg_addr = VOL_CTRL_LT; | |
778 | num_reg = 1; | |
779 | mask = MASK6; | |
780 | break; | |
781 | case PMIC_SND_RIGHT_HP_MUTE: | |
782 | case PMIC_SND_RIGHT_SPEAKER_MUTE: | |
783 | sc_access[0].reg_addr = VOL_CTRL_RT; | |
784 | num_reg = 1; | |
785 | mask = MASK6; | |
786 | break; | |
787 | } | |
788 | retval = sst_sc_reg_access(sc_access, PMIC_READ, num_reg); | |
789 | if (retval) | |
790 | return retval; | |
791 | *value = sc_access[0].value & mask; | |
792 | if (*value) | |
793 | *value = MUTE; | |
794 | else | |
795 | *value = UNMUTE; | |
796 | return retval; | |
797 | } | |
798 | ||
799 | static int mx_get_vol(int dev_id, int *value) | |
800 | { | |
801 | struct sc_reg_access sc_access = {0,}; | |
802 | int retval = 0, mask = 0, num_reg = 0; | |
803 | ||
804 | if (snd_pmic_ops_mx.card_status == SND_CARD_UN_INIT) { | |
805 | retval = mx_init_card(); | |
806 | if (retval) | |
807 | return retval; | |
808 | } | |
809 | switch (dev_id) { | |
810 | case PMIC_SND_CAPTURE_VOL: | |
811 | sc_access.reg_addr = 0x220; | |
812 | mask = MASK0|MASK1|MASK2|MASK3|MASK4; | |
813 | num_reg = 1; | |
814 | break; | |
815 | case PMIC_SND_LEFT_PB_VOL: | |
816 | sc_access.reg_addr = VOL_CTRL_LT; | |
817 | mask = MASK0|MASK1|MASK2|MASK3|MASK4|MASK5; | |
818 | num_reg = 1; | |
819 | break; | |
820 | case PMIC_SND_RIGHT_PB_VOL: | |
821 | sc_access.reg_addr = VOL_CTRL_RT; | |
822 | mask = MASK0|MASK1|MASK2|MASK3|MASK4|MASK5; | |
823 | num_reg = 1; | |
824 | break; | |
825 | } | |
826 | retval = sst_sc_reg_access(&sc_access, PMIC_READ, num_reg); | |
827 | if (retval) | |
828 | return retval; | |
829 | *value = -(sc_access.value & mask); | |
d0f40c50 | 830 | pr_debug("get volume value extracted %d\n", *value); |
fffa1cca VK |
831 | return retval; |
832 | } | |
833 | ||
834 | struct snd_pmic_ops snd_pmic_ops_mx = { | |
835 | .set_input_dev = mx_set_selected_input_dev, | |
836 | .set_output_dev = mx_set_selected_output_dev, | |
837 | .set_mute = mx_set_mute, | |
838 | .get_mute = mx_get_mute, | |
839 | .set_vol = mx_set_vol, | |
840 | .get_vol = mx_get_vol, | |
841 | .init_card = mx_init_card, | |
842 | .set_pcm_audio_params = mx_set_pcm_audio_params, | |
843 | .set_pcm_voice_params = mx_set_pcm_voice_params, | |
844 | .set_voice_port = mx_set_voice_port, | |
845 | .set_audio_port = mx_set_audio_port, | |
846 | .power_up_pmic_pb = mx_power_up_pb, | |
847 | .power_up_pmic_cp = mx_power_up_cp, | |
848 | .power_down_pmic_pb = mx_power_down_pb, | |
849 | .power_down_pmic_cp = mx_power_down_cp, | |
850 | .power_down_pmic = mx_power_down, | |
851 | }; | |
852 |