2 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
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.
11 * This file contains the implementation of the Audio Mixer
12 * resource management object.
20 #include "cthardware.h"
21 #include <linux/slab.h>
23 #define AMIXER_RESOURCE_NUM 256
24 #define SUM_RESOURCE_NUM 256
26 #define AMIXER_Y_IMMEDIATE 1
28 #define BLANK_SLOT 4094
30 static int amixer_master(struct rsc
*rsc
)
33 return rsc
->idx
= container_of(rsc
, struct amixer
, rsc
)->idx
[0];
36 static int amixer_next_conj(struct rsc
*rsc
)
39 return container_of(rsc
, struct amixer
, rsc
)->idx
[rsc
->conj
];
42 static int amixer_index(const struct rsc
*rsc
)
44 return container_of(rsc
, struct amixer
, rsc
)->idx
[rsc
->conj
];
47 static int amixer_output_slot(const struct rsc
*rsc
)
49 return (amixer_index(rsc
) << 4) + 0x4;
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
,
59 static int amixer_set_input(struct amixer
*amixer
, struct rsc
*rsc
)
64 hw
->amixer_set_mode(amixer
->rsc
.ctrl_blk
, AMIXER_Y_IMMEDIATE
);
67 hw
->amixer_set_x(amixer
->rsc
.ctrl_blk
, BLANK_SLOT
);
69 hw
->amixer_set_x(amixer
->rsc
.ctrl_blk
,
70 rsc
->ops
->output_slot(rsc
));
75 /* y is a 14-bit immediate constant */
76 static int amixer_set_y(struct amixer
*amixer
, unsigned int y
)
81 hw
->amixer_set_y(amixer
->rsc
.ctrl_blk
, y
);
86 static int amixer_set_invalid_squash(struct amixer
*amixer
, unsigned int iv
)
91 hw
->amixer_set_iv(amixer
->rsc
.ctrl_blk
, iv
);
96 static int amixer_set_sum(struct amixer
*amixer
, struct sum
*sum
)
103 hw
->amixer_set_se(amixer
->rsc
.ctrl_blk
, 0);
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
));
113 static int amixer_commit_write(struct amixer
*amixer
)
122 input
= amixer
->input
;
125 /* Program master and conjugate resources */
126 amixer
->rsc
.ops
->master(&amixer
->rsc
);
128 input
->ops
->master(input
);
131 sum
->rsc
.ops
->master(&sum
->rsc
);
133 for (i
= 0; i
< amixer
->rsc
.msr
; i
++) {
134 hw
->amixer_set_dirty_all(amixer
->rsc
.ctrl_blk
);
136 hw
->amixer_set_x(amixer
->rsc
.ctrl_blk
,
137 input
->ops
->output_slot(input
));
138 input
->ops
->next_conj(input
);
141 hw
->amixer_set_sadr(amixer
->rsc
.ctrl_blk
,
142 sum
->rsc
.ops
->index(&sum
->rsc
));
143 sum
->rsc
.ops
->next_conj(&sum
->rsc
);
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
);
149 amixer
->rsc
.ops
->master(&amixer
->rsc
);
151 input
->ops
->master(input
);
154 sum
->rsc
.ops
->master(&sum
->rsc
);
159 static int amixer_commit_raw_write(struct amixer
*amixer
)
165 index
= amixer
->rsc
.ops
->output_slot(&amixer
->rsc
);
166 hw
->amixer_commit_write(hw
, index
, amixer
->rsc
.ctrl_blk
);
171 static int amixer_get_y(struct amixer
*amixer
)
176 return hw
->amixer_get_y(amixer
->rsc
.ctrl_blk
);
179 static int amixer_setup(struct amixer
*amixer
, struct rsc
*input
,
180 unsigned int scale
, struct sum
*sum
)
182 amixer_set_input(amixer
, input
);
183 amixer_set_y(amixer
, scale
);
184 amixer_set_sum(amixer
, sum
);
185 amixer_commit_write(amixer
);
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
,
200 static int amixer_rsc_init(struct amixer
*amixer
,
201 const struct amixer_desc
*desc
,
202 struct amixer_mgr
*mgr
)
206 err
= rsc_init(&amixer
->rsc
, amixer
->idx
[0],
207 AMIXER
, desc
->msr
, mgr
->mgr
.hw
);
211 /* Set amixer specific operations */
212 amixer
->rsc
.ops
= &amixer_basic_rsc_ops
;
213 amixer
->ops
= &amixer_ops
;
214 amixer
->input
= NULL
;
217 amixer_setup(amixer
, NULL
, 0, NULL
);
222 static int amixer_rsc_uninit(struct amixer
*amixer
)
224 amixer_setup(amixer
, NULL
, 0, NULL
);
225 rsc_uninit(&amixer
->rsc
);
227 amixer
->input
= NULL
;
232 static int get_amixer_rsc(struct amixer_mgr
*mgr
,
233 const struct amixer_desc
*desc
,
234 struct amixer
**ramixer
)
238 struct amixer
*amixer
;
243 /* Allocate mem for amixer resource */
244 amixer
= kzalloc(sizeof(*amixer
), GFP_KERNEL
);
248 /* Check whether there are sufficient
249 * amixer resources to meet request. */
251 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
252 for (i
= 0; i
< desc
->msr
; i
++) {
253 err
= mgr_get_resource(&mgr
->mgr
, 1, &idx
);
257 amixer
->idx
[i
] = idx
;
259 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
261 printk(KERN_ERR
"ctxfi: Can't meet AMIXER resource request!\n");
265 err
= amixer_rsc_init(amixer
, desc
, mgr
);
274 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
275 for (i
--; i
>= 0; i
--)
276 mgr_put_resource(&mgr
->mgr
, 1, amixer
->idx
[i
]);
278 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
283 static int put_amixer_rsc(struct amixer_mgr
*mgr
, struct amixer
*amixer
)
288 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
289 for (i
= 0; i
< amixer
->rsc
.msr
; i
++)
290 mgr_put_resource(&mgr
->mgr
, 1, amixer
->idx
[i
]);
292 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
293 amixer_rsc_uninit(amixer
);
299 int amixer_mgr_create(void *hw
, struct amixer_mgr
**ramixer_mgr
)
302 struct amixer_mgr
*amixer_mgr
;
305 amixer_mgr
= kzalloc(sizeof(*amixer_mgr
), GFP_KERNEL
);
306 if (NULL
== amixer_mgr
)
309 err
= rsc_mgr_init(&amixer_mgr
->mgr
, AMIXER
, AMIXER_RESOURCE_NUM
, hw
);
313 spin_lock_init(&amixer_mgr
->mgr_lock
);
315 amixer_mgr
->get_amixer
= get_amixer_rsc
;
316 amixer_mgr
->put_amixer
= put_amixer_rsc
;
318 *ramixer_mgr
= amixer_mgr
;
327 int amixer_mgr_destroy(struct amixer_mgr
*amixer_mgr
)
329 rsc_mgr_uninit(&amixer_mgr
->mgr
);
334 /* SUM resource management */
336 static int sum_master(struct rsc
*rsc
)
339 return rsc
->idx
= container_of(rsc
, struct sum
, rsc
)->idx
[0];
342 static int sum_next_conj(struct rsc
*rsc
)
345 return container_of(rsc
, struct sum
, rsc
)->idx
[rsc
->conj
];
348 static int sum_index(const struct rsc
*rsc
)
350 return container_of(rsc
, struct sum
, rsc
)->idx
[rsc
->conj
];
353 static int sum_output_slot(const struct rsc
*rsc
)
355 return (sum_index(rsc
) << 4) + 0xc;
358 static struct rsc_ops sum_basic_rsc_ops
= {
359 .master
= sum_master
,
360 .next_conj
= sum_next_conj
,
362 .output_slot
= sum_output_slot
,
365 static int sum_rsc_init(struct sum
*sum
,
366 const struct sum_desc
*desc
,
371 err
= rsc_init(&sum
->rsc
, sum
->idx
[0], SUM
, desc
->msr
, mgr
->mgr
.hw
);
375 sum
->rsc
.ops
= &sum_basic_rsc_ops
;
380 static int sum_rsc_uninit(struct sum
*sum
)
382 rsc_uninit(&sum
->rsc
);
386 static int get_sum_rsc(struct sum_mgr
*mgr
,
387 const struct sum_desc
*desc
,
397 /* Allocate mem for sum resource */
398 sum
= kzalloc(sizeof(*sum
), GFP_KERNEL
);
402 /* Check whether there are sufficient sum resources to meet request. */
404 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
405 for (i
= 0; i
< desc
->msr
; i
++) {
406 err
= mgr_get_resource(&mgr
->mgr
, 1, &idx
);
412 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
414 printk(KERN_ERR
"ctxfi: Can't meet SUM resource request!\n");
418 err
= sum_rsc_init(sum
, desc
, mgr
);
427 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
428 for (i
--; i
>= 0; i
--)
429 mgr_put_resource(&mgr
->mgr
, 1, sum
->idx
[i
]);
431 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
436 static int put_sum_rsc(struct sum_mgr
*mgr
, struct sum
*sum
)
441 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
442 for (i
= 0; i
< sum
->rsc
.msr
; i
++)
443 mgr_put_resource(&mgr
->mgr
, 1, sum
->idx
[i
]);
445 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
452 int sum_mgr_create(void *hw
, struct sum_mgr
**rsum_mgr
)
455 struct sum_mgr
*sum_mgr
;
458 sum_mgr
= kzalloc(sizeof(*sum_mgr
), GFP_KERNEL
);
462 err
= rsc_mgr_init(&sum_mgr
->mgr
, SUM
, SUM_RESOURCE_NUM
, hw
);
466 spin_lock_init(&sum_mgr
->mgr_lock
);
468 sum_mgr
->get_sum
= get_sum_rsc
;
469 sum_mgr
->put_sum
= put_sum_rsc
;
480 int sum_mgr_destroy(struct sum_mgr
*sum_mgr
)
482 rsc_mgr_uninit(&sum_mgr
->mgr
);