Commit | Line | Data |
---|---|---|
8cc72361 WYC |
1 | /** |
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | |
3 | * | |
4 | * This source file is released under GPL v2 license (no other versions). | |
5 | * See the COPYING file included in the main directory of this source | |
6 | * distribution for the license terms and conditions. | |
7 | * | |
8 | * @File ctamixer.c | |
9 | * | |
10 | * @Brief | |
11 | * This file contains the implementation of the Audio Mixer | |
12 | * resource management object. | |
13 | * | |
14 | * @Author Liu Chun | |
15 | * @Date May 21 2008 | |
16 | * | |
17 | */ | |
18 | ||
19 | #include "ctamixer.h" | |
20 | #include "cthardware.h" | |
21 | #include <linux/slab.h> | |
22 | ||
23 | #define AMIXER_RESOURCE_NUM 256 | |
24 | #define SUM_RESOURCE_NUM 256 | |
25 | ||
26 | #define AMIXER_Y_IMMEDIATE 1 | |
27 | ||
28 | #define BLANK_SLOT 4094 | |
29 | ||
30 | static int amixer_master(struct rsc *rsc) | |
31 | { | |
32 | rsc->conj = 0; | |
33 | return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0]; | |
34 | } | |
35 | ||
36 | static int amixer_next_conj(struct rsc *rsc) | |
37 | { | |
38 | rsc->conj++; | |
39 | return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; | |
40 | } | |
41 | ||
42 | static int amixer_index(const struct rsc *rsc) | |
43 | { | |
44 | return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; | |
45 | } | |
46 | ||
47 | static int amixer_output_slot(const struct rsc *rsc) | |
48 | { | |
49 | return (amixer_index(rsc) << 4) + 0x4; | |
50 | } | |
51 | ||
52 | static struct rsc_ops amixer_basic_rsc_ops = { | |
53 | .master = amixer_master, | |
54 | .next_conj = amixer_next_conj, | |
55 | .index = amixer_index, | |
56 | .output_slot = amixer_output_slot, | |
57 | }; | |
58 | ||
59 | static int amixer_set_input(struct amixer *amixer, struct rsc *rsc) | |
60 | { | |
61 | struct hw *hw = NULL; | |
62 | ||
63 | hw = (struct hw *)amixer->rsc.hw; | |
64 | hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE); | |
65 | amixer->input = rsc; | |
66 | if (NULL == rsc) | |
67 | hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT); | |
68 | else | |
69 | hw->amixer_set_x(amixer->rsc.ctrl_blk, | |
70 | rsc->ops->output_slot(rsc)); | |
71 | ||
72 | return 0; | |
73 | } | |
74 | ||
75 | /* y is a 14-bit immediate constant */ | |
76 | static int amixer_set_y(struct amixer *amixer, unsigned int y) | |
77 | { | |
78 | struct hw *hw = NULL; | |
79 | ||
80 | hw = (struct hw *)amixer->rsc.hw; | |
81 | hw->amixer_set_y(amixer->rsc.ctrl_blk, y); | |
82 | ||
83 | return 0; | |
84 | } | |
85 | ||
86 | static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv) | |
87 | { | |
88 | struct hw *hw = NULL; | |
89 | ||
90 | hw = (struct hw *)amixer->rsc.hw; | |
91 | hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv); | |
92 | ||
93 | return 0; | |
94 | } | |
95 | ||
96 | static int amixer_set_sum(struct amixer *amixer, struct sum *sum) | |
97 | { | |
98 | struct hw *hw = NULL; | |
99 | ||
100 | hw = (struct hw *)amixer->rsc.hw; | |
101 | amixer->sum = sum; | |
102 | if (NULL == sum) { | |
103 | hw->amixer_set_se(amixer->rsc.ctrl_blk, 0); | |
104 | } else { | |
105 | hw->amixer_set_se(amixer->rsc.ctrl_blk, 1); | |
106 | hw->amixer_set_sadr(amixer->rsc.ctrl_blk, | |
107 | sum->rsc.ops->index(&sum->rsc)); | |
108 | } | |
109 | ||
110 | return 0; | |
111 | } | |
112 | ||
113 | static int amixer_commit_write(struct amixer *amixer) | |
114 | { | |
115 | struct hw *hw = NULL; | |
116 | unsigned int index = 0; | |
117 | int i = 0; | |
118 | struct rsc *input = NULL; | |
119 | struct sum *sum = NULL; | |
120 | ||
121 | hw = (struct hw *)amixer->rsc.hw; | |
122 | input = amixer->input; | |
123 | sum = amixer->sum; | |
124 | ||
125 | /* Program master and conjugate resources */ | |
126 | amixer->rsc.ops->master(&amixer->rsc); | |
127 | if (NULL != input) | |
128 | input->ops->master(input); | |
129 | ||
130 | if (NULL != sum) | |
131 | sum->rsc.ops->master(&sum->rsc); | |
132 | ||
133 | for (i = 0; i < amixer->rsc.msr; i++) { | |
134 | hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk); | |
135 | if (NULL != input) { | |
136 | hw->amixer_set_x(amixer->rsc.ctrl_blk, | |
137 | input->ops->output_slot(input)); | |
138 | input->ops->next_conj(input); | |
139 | } | |
140 | if (NULL != sum) { | |
141 | hw->amixer_set_sadr(amixer->rsc.ctrl_blk, | |
142 | sum->rsc.ops->index(&sum->rsc)); | |
143 | sum->rsc.ops->next_conj(&sum->rsc); | |
144 | } | |
145 | index = amixer->rsc.ops->output_slot(&amixer->rsc); | |
146 | hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); | |
147 | amixer->rsc.ops->next_conj(&amixer->rsc); | |
148 | } | |
149 | amixer->rsc.ops->master(&amixer->rsc); | |
150 | if (NULL != input) | |
151 | input->ops->master(input); | |
152 | ||
153 | if (NULL != sum) | |
154 | sum->rsc.ops->master(&sum->rsc); | |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
159 | static int amixer_commit_raw_write(struct amixer *amixer) | |
160 | { | |
161 | struct hw *hw = NULL; | |
162 | unsigned int index = 0; | |
163 | ||
164 | hw = (struct hw *)amixer->rsc.hw; | |
165 | index = amixer->rsc.ops->output_slot(&amixer->rsc); | |
166 | hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); | |
167 | ||
168 | return 0; | |
169 | } | |
170 | ||
171 | static int amixer_get_y(struct amixer *amixer) | |
172 | { | |
173 | struct hw *hw = NULL; | |
174 | ||
175 | hw = (struct hw *)amixer->rsc.hw; | |
176 | return hw->amixer_get_y(amixer->rsc.ctrl_blk); | |
177 | } | |
178 | ||
179 | static int amixer_setup(struct amixer *amixer, struct rsc *input, | |
180 | unsigned int scale, struct sum *sum) | |
181 | { | |
182 | amixer_set_input(amixer, input); | |
183 | amixer_set_y(amixer, scale); | |
184 | amixer_set_sum(amixer, sum); | |
185 | amixer_commit_write(amixer); | |
186 | return 0; | |
187 | } | |
188 | ||
189 | static struct amixer_rsc_ops amixer_ops = { | |
190 | .set_input = amixer_set_input, | |
191 | .set_invalid_squash = amixer_set_invalid_squash, | |
192 | .set_scale = amixer_set_y, | |
193 | .set_sum = amixer_set_sum, | |
194 | .commit_write = amixer_commit_write, | |
195 | .commit_raw_write = amixer_commit_raw_write, | |
196 | .setup = amixer_setup, | |
197 | .get_scale = amixer_get_y, | |
198 | }; | |
199 | ||
200 | static int amixer_rsc_init(struct amixer *amixer, | |
201 | const struct amixer_desc *desc, | |
202 | struct amixer_mgr *mgr) | |
203 | { | |
204 | int err = 0; | |
205 | ||
206 | err = rsc_init(&amixer->rsc, amixer->idx[0], | |
207 | AMIXER, desc->msr, mgr->mgr.hw); | |
208 | if (err) | |
209 | return err; | |
210 | ||
211 | /* Set amixer specific operations */ | |
212 | amixer->rsc.ops = &amixer_basic_rsc_ops; | |
213 | amixer->ops = &amixer_ops; | |
214 | amixer->input = NULL; | |
215 | amixer->sum = NULL; | |
216 | ||
217 | amixer_setup(amixer, NULL, 0, NULL); | |
218 | ||
219 | return 0; | |
220 | } | |
221 | ||
222 | static int amixer_rsc_uninit(struct amixer *amixer) | |
223 | { | |
224 | amixer_setup(amixer, NULL, 0, NULL); | |
225 | rsc_uninit(&amixer->rsc); | |
226 | amixer->ops = NULL; | |
227 | amixer->input = NULL; | |
228 | amixer->sum = NULL; | |
229 | return 0; | |
230 | } | |
231 | ||
232 | static int get_amixer_rsc(struct amixer_mgr *mgr, | |
233 | const struct amixer_desc *desc, | |
234 | struct amixer **ramixer) | |
235 | { | |
236 | int err = 0, i = 0; | |
237 | unsigned int idx = 0; | |
238 | struct amixer *amixer = NULL; | |
239 | unsigned long flags; | |
240 | ||
241 | *ramixer = NULL; | |
242 | ||
243 | /* Allocate mem for amixer resource */ | |
244 | amixer = kzalloc(sizeof(*amixer), GFP_KERNEL); | |
245 | if (NULL == amixer) { | |
246 | err = -ENOMEM; | |
247 | return err; | |
248 | } | |
249 | ||
250 | /* Check whether there are sufficient | |
251 | * amixer resources to meet request. */ | |
252 | spin_lock_irqsave(&mgr->mgr_lock, flags); | |
253 | for (i = 0; i < desc->msr; i++) { | |
254 | err = mgr_get_resource(&mgr->mgr, 1, &idx); | |
255 | if (err) | |
256 | break; | |
257 | ||
258 | amixer->idx[i] = idx; | |
259 | } | |
260 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | |
261 | if (err) { | |
262 | printk(KERN_ERR "Can't meet AMIXER resource request!\n"); | |
263 | goto error; | |
264 | } | |
265 | ||
266 | err = amixer_rsc_init(amixer, desc, mgr); | |
267 | if (err) | |
268 | goto error; | |
269 | ||
270 | *ramixer = amixer; | |
271 | ||
272 | return 0; | |
273 | ||
274 | error: | |
275 | spin_lock_irqsave(&mgr->mgr_lock, flags); | |
276 | for (i--; i >= 0; i--) | |
277 | mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); | |
278 | ||
279 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | |
280 | kfree(amixer); | |
281 | return err; | |
282 | } | |
283 | ||
284 | static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) | |
285 | { | |
286 | unsigned long flags; | |
287 | int i = 0; | |
288 | ||
289 | spin_lock_irqsave(&mgr->mgr_lock, flags); | |
290 | for (i = 0; i < amixer->rsc.msr; i++) | |
291 | mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); | |
292 | ||
293 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | |
294 | amixer_rsc_uninit(amixer); | |
295 | kfree(amixer); | |
296 | ||
297 | return 0; | |
298 | } | |
299 | ||
300 | int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr) | |
301 | { | |
302 | int err = 0; | |
303 | struct amixer_mgr *amixer_mgr; | |
304 | ||
305 | *ramixer_mgr = NULL; | |
306 | amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL); | |
307 | if (NULL == amixer_mgr) | |
308 | return -ENOMEM; | |
309 | ||
310 | err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw); | |
311 | if (err) | |
312 | goto error; | |
313 | ||
314 | spin_lock_init(&amixer_mgr->mgr_lock); | |
315 | ||
316 | amixer_mgr->get_amixer = get_amixer_rsc; | |
317 | amixer_mgr->put_amixer = put_amixer_rsc; | |
318 | ||
319 | *ramixer_mgr = amixer_mgr; | |
320 | ||
321 | return 0; | |
322 | ||
323 | error: | |
324 | kfree(amixer_mgr); | |
325 | return err; | |
326 | } | |
327 | ||
328 | int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr) | |
329 | { | |
330 | rsc_mgr_uninit(&amixer_mgr->mgr); | |
331 | kfree(amixer_mgr); | |
332 | return 0; | |
333 | } | |
334 | ||
335 | /* SUM resource management */ | |
336 | ||
337 | static int sum_master(struct rsc *rsc) | |
338 | { | |
339 | rsc->conj = 0; | |
340 | return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0]; | |
341 | } | |
342 | ||
343 | static int sum_next_conj(struct rsc *rsc) | |
344 | { | |
345 | rsc->conj++; | |
346 | return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; | |
347 | } | |
348 | ||
349 | static int sum_index(const struct rsc *rsc) | |
350 | { | |
351 | return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; | |
352 | } | |
353 | ||
354 | static int sum_output_slot(const struct rsc *rsc) | |
355 | { | |
356 | return (sum_index(rsc) << 4) + 0xc; | |
357 | } | |
358 | ||
359 | static struct rsc_ops sum_basic_rsc_ops = { | |
360 | .master = sum_master, | |
361 | .next_conj = sum_next_conj, | |
362 | .index = sum_index, | |
363 | .output_slot = sum_output_slot, | |
364 | }; | |
365 | ||
366 | static int sum_rsc_init(struct sum *sum, | |
367 | const struct sum_desc *desc, | |
368 | struct sum_mgr *mgr) | |
369 | { | |
370 | int err = 0; | |
371 | ||
372 | err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw); | |
373 | if (err) | |
374 | return err; | |
375 | ||
376 | sum->rsc.ops = &sum_basic_rsc_ops; | |
377 | ||
378 | return 0; | |
379 | } | |
380 | ||
381 | static int sum_rsc_uninit(struct sum *sum) | |
382 | { | |
383 | rsc_uninit(&sum->rsc); | |
384 | return 0; | |
385 | } | |
386 | ||
387 | static int get_sum_rsc(struct sum_mgr *mgr, | |
388 | const struct sum_desc *desc, | |
389 | struct sum **rsum) | |
390 | { | |
391 | int err = 0, i = 0; | |
392 | unsigned int idx = 0; | |
393 | struct sum *sum = NULL; | |
394 | unsigned long flags; | |
395 | ||
396 | *rsum = NULL; | |
397 | ||
398 | /* Allocate mem for sum resource */ | |
399 | sum = kzalloc(sizeof(*sum), GFP_KERNEL); | |
400 | if (NULL == sum) { | |
401 | err = -ENOMEM; | |
402 | return err; | |
403 | } | |
404 | ||
405 | /* Check whether there are sufficient sum resources to meet request. */ | |
406 | spin_lock_irqsave(&mgr->mgr_lock, flags); | |
407 | for (i = 0; i < desc->msr; i++) { | |
408 | err = mgr_get_resource(&mgr->mgr, 1, &idx); | |
409 | if (err) | |
410 | break; | |
411 | ||
412 | sum->idx[i] = idx; | |
413 | } | |
414 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | |
415 | if (err) { | |
416 | printk(KERN_ERR "Can't meet SUM resource request!\n"); | |
417 | goto error; | |
418 | } | |
419 | ||
420 | err = sum_rsc_init(sum, desc, mgr); | |
421 | if (err) | |
422 | goto error; | |
423 | ||
424 | *rsum = sum; | |
425 | ||
426 | return 0; | |
427 | ||
428 | error: | |
429 | spin_lock_irqsave(&mgr->mgr_lock, flags); | |
430 | for (i--; i >= 0; i--) | |
431 | mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); | |
432 | ||
433 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | |
434 | kfree(sum); | |
435 | return err; | |
436 | } | |
437 | ||
438 | static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) | |
439 | { | |
440 | unsigned long flags; | |
441 | int i = 0; | |
442 | ||
443 | spin_lock_irqsave(&mgr->mgr_lock, flags); | |
444 | for (i = 0; i < sum->rsc.msr; i++) | |
445 | mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); | |
446 | ||
447 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | |
448 | sum_rsc_uninit(sum); | |
449 | kfree(sum); | |
450 | ||
451 | return 0; | |
452 | } | |
453 | ||
454 | int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr) | |
455 | { | |
456 | int err = 0; | |
457 | struct sum_mgr *sum_mgr; | |
458 | ||
459 | *rsum_mgr = NULL; | |
460 | sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL); | |
461 | if (NULL == sum_mgr) | |
462 | return -ENOMEM; | |
463 | ||
464 | err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw); | |
465 | if (err) | |
466 | goto error; | |
467 | ||
468 | spin_lock_init(&sum_mgr->mgr_lock); | |
469 | ||
470 | sum_mgr->get_sum = get_sum_rsc; | |
471 | sum_mgr->put_sum = put_sum_rsc; | |
472 | ||
473 | *rsum_mgr = sum_mgr; | |
474 | ||
475 | return 0; | |
476 | ||
477 | error: | |
478 | kfree(sum_mgr); | |
479 | return err; | |
480 | } | |
481 | ||
482 | int sum_mgr_destroy(struct sum_mgr *sum_mgr) | |
483 | { | |
484 | rsc_mgr_uninit(&sum_mgr->mgr); | |
485 | kfree(sum_mgr); | |
486 | return 0; | |
487 | } | |
488 |