1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
8 * This file contains the implementation of the Audio Mixer
9 * resource management object.
16 #include "cthardware.h"
17 #include <linux/slab.h>
19 #define AMIXER_RESOURCE_NUM 256
20 #define SUM_RESOURCE_NUM 256
22 #define AMIXER_Y_IMMEDIATE 1
24 #define BLANK_SLOT 4094
26 static int amixer_master(struct rsc
*rsc
)
29 return rsc
->idx
= container_of(rsc
, struct amixer
, rsc
)->idx
[0];
32 static int amixer_next_conj(struct rsc
*rsc
)
35 return container_of(rsc
, struct amixer
, rsc
)->idx
[rsc
->conj
];
38 static int amixer_index(const struct rsc
*rsc
)
40 return container_of(rsc
, struct amixer
, rsc
)->idx
[rsc
->conj
];
43 static int amixer_output_slot(const struct rsc
*rsc
)
45 return (amixer_index(rsc
) << 4) + 0x4;
48 static const struct rsc_ops amixer_basic_rsc_ops
= {
49 .master
= amixer_master
,
50 .next_conj
= amixer_next_conj
,
51 .index
= amixer_index
,
52 .output_slot
= amixer_output_slot
,
55 static int amixer_set_input(struct amixer
*amixer
, struct rsc
*rsc
)
60 hw
->amixer_set_mode(amixer
->rsc
.ctrl_blk
, AMIXER_Y_IMMEDIATE
);
63 hw
->amixer_set_x(amixer
->rsc
.ctrl_blk
, BLANK_SLOT
);
65 hw
->amixer_set_x(amixer
->rsc
.ctrl_blk
,
66 rsc
->ops
->output_slot(rsc
));
71 /* y is a 14-bit immediate constant */
72 static int amixer_set_y(struct amixer
*amixer
, unsigned int y
)
77 hw
->amixer_set_y(amixer
->rsc
.ctrl_blk
, y
);
82 static int amixer_set_invalid_squash(struct amixer
*amixer
, unsigned int iv
)
87 hw
->amixer_set_iv(amixer
->rsc
.ctrl_blk
, iv
);
92 static int amixer_set_sum(struct amixer
*amixer
, struct sum
*sum
)
99 hw
->amixer_set_se(amixer
->rsc
.ctrl_blk
, 0);
101 hw
->amixer_set_se(amixer
->rsc
.ctrl_blk
, 1);
102 hw
->amixer_set_sadr(amixer
->rsc
.ctrl_blk
,
103 sum
->rsc
.ops
->index(&sum
->rsc
));
109 static int amixer_commit_write(struct amixer
*amixer
)
118 input
= amixer
->input
;
121 /* Program master and conjugate resources */
122 amixer
->rsc
.ops
->master(&amixer
->rsc
);
124 input
->ops
->master(input
);
127 sum
->rsc
.ops
->master(&sum
->rsc
);
129 for (i
= 0; i
< amixer
->rsc
.msr
; i
++) {
130 hw
->amixer_set_dirty_all(amixer
->rsc
.ctrl_blk
);
132 hw
->amixer_set_x(amixer
->rsc
.ctrl_blk
,
133 input
->ops
->output_slot(input
));
134 input
->ops
->next_conj(input
);
137 hw
->amixer_set_sadr(amixer
->rsc
.ctrl_blk
,
138 sum
->rsc
.ops
->index(&sum
->rsc
));
139 sum
->rsc
.ops
->next_conj(&sum
->rsc
);
141 index
= amixer
->rsc
.ops
->output_slot(&amixer
->rsc
);
142 hw
->amixer_commit_write(hw
, index
, amixer
->rsc
.ctrl_blk
);
143 amixer
->rsc
.ops
->next_conj(&amixer
->rsc
);
145 amixer
->rsc
.ops
->master(&amixer
->rsc
);
147 input
->ops
->master(input
);
150 sum
->rsc
.ops
->master(&sum
->rsc
);
155 static int amixer_commit_raw_write(struct amixer
*amixer
)
161 index
= amixer
->rsc
.ops
->output_slot(&amixer
->rsc
);
162 hw
->amixer_commit_write(hw
, index
, amixer
->rsc
.ctrl_blk
);
167 static int amixer_get_y(struct amixer
*amixer
)
172 return hw
->amixer_get_y(amixer
->rsc
.ctrl_blk
);
175 static int amixer_setup(struct amixer
*amixer
, struct rsc
*input
,
176 unsigned int scale
, struct sum
*sum
)
178 amixer_set_input(amixer
, input
);
179 amixer_set_y(amixer
, scale
);
180 amixer_set_sum(amixer
, sum
);
181 amixer_commit_write(amixer
);
185 static const struct amixer_rsc_ops amixer_ops
= {
186 .set_input
= amixer_set_input
,
187 .set_invalid_squash
= amixer_set_invalid_squash
,
188 .set_scale
= amixer_set_y
,
189 .set_sum
= amixer_set_sum
,
190 .commit_write
= amixer_commit_write
,
191 .commit_raw_write
= amixer_commit_raw_write
,
192 .setup
= amixer_setup
,
193 .get_scale
= amixer_get_y
,
196 static int amixer_rsc_init(struct amixer
*amixer
,
197 const struct amixer_desc
*desc
,
198 struct amixer_mgr
*mgr
)
202 err
= rsc_init(&amixer
->rsc
, amixer
->idx
[0],
203 AMIXER
, desc
->msr
, mgr
->mgr
.hw
);
207 /* Set amixer specific operations */
208 amixer
->rsc
.ops
= &amixer_basic_rsc_ops
;
209 amixer
->ops
= &amixer_ops
;
210 amixer
->input
= NULL
;
213 amixer_setup(amixer
, NULL
, 0, NULL
);
218 static int amixer_rsc_uninit(struct amixer
*amixer
)
220 amixer_setup(amixer
, NULL
, 0, NULL
);
221 rsc_uninit(&amixer
->rsc
);
223 amixer
->input
= NULL
;
228 static int get_amixer_rsc(struct amixer_mgr
*mgr
,
229 const struct amixer_desc
*desc
,
230 struct amixer
**ramixer
)
234 struct amixer
*amixer
;
239 /* Allocate mem for amixer resource */
240 amixer
= kzalloc(sizeof(*amixer
), GFP_KERNEL
);
244 /* Check whether there are sufficient
245 * amixer resources to meet request. */
247 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
248 for (i
= 0; i
< desc
->msr
; i
++) {
249 err
= mgr_get_resource(&mgr
->mgr
, 1, &idx
);
253 amixer
->idx
[i
] = idx
;
255 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
257 dev_err(mgr
->card
->dev
,
258 "Can't meet AMIXER resource request!\n");
262 err
= amixer_rsc_init(amixer
, desc
, mgr
);
271 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
272 for (i
--; i
>= 0; i
--)
273 mgr_put_resource(&mgr
->mgr
, 1, amixer
->idx
[i
]);
275 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
280 static int put_amixer_rsc(struct amixer_mgr
*mgr
, struct amixer
*amixer
)
285 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
286 for (i
= 0; i
< amixer
->rsc
.msr
; i
++)
287 mgr_put_resource(&mgr
->mgr
, 1, amixer
->idx
[i
]);
289 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
290 amixer_rsc_uninit(amixer
);
296 int amixer_mgr_create(struct hw
*hw
, struct amixer_mgr
**ramixer_mgr
)
299 struct amixer_mgr
*amixer_mgr
;
302 amixer_mgr
= kzalloc(sizeof(*amixer_mgr
), GFP_KERNEL
);
306 err
= rsc_mgr_init(&amixer_mgr
->mgr
, AMIXER
, AMIXER_RESOURCE_NUM
, hw
);
310 spin_lock_init(&amixer_mgr
->mgr_lock
);
312 amixer_mgr
->get_amixer
= get_amixer_rsc
;
313 amixer_mgr
->put_amixer
= put_amixer_rsc
;
314 amixer_mgr
->card
= hw
->card
;
316 *ramixer_mgr
= amixer_mgr
;
325 int amixer_mgr_destroy(struct amixer_mgr
*amixer_mgr
)
327 rsc_mgr_uninit(&amixer_mgr
->mgr
);
332 /* SUM resource management */
334 static int sum_master(struct rsc
*rsc
)
337 return rsc
->idx
= container_of(rsc
, struct sum
, rsc
)->idx
[0];
340 static int sum_next_conj(struct rsc
*rsc
)
343 return container_of(rsc
, struct sum
, rsc
)->idx
[rsc
->conj
];
346 static int sum_index(const struct rsc
*rsc
)
348 return container_of(rsc
, struct sum
, rsc
)->idx
[rsc
->conj
];
351 static int sum_output_slot(const struct rsc
*rsc
)
353 return (sum_index(rsc
) << 4) + 0xc;
356 static const struct rsc_ops sum_basic_rsc_ops
= {
357 .master
= sum_master
,
358 .next_conj
= sum_next_conj
,
360 .output_slot
= sum_output_slot
,
363 static int sum_rsc_init(struct sum
*sum
,
364 const struct sum_desc
*desc
,
369 err
= rsc_init(&sum
->rsc
, sum
->idx
[0], SUM
, desc
->msr
, mgr
->mgr
.hw
);
373 sum
->rsc
.ops
= &sum_basic_rsc_ops
;
378 static int sum_rsc_uninit(struct sum
*sum
)
380 rsc_uninit(&sum
->rsc
);
384 static int get_sum_rsc(struct sum_mgr
*mgr
,
385 const struct sum_desc
*desc
,
395 /* Allocate mem for sum resource */
396 sum
= kzalloc(sizeof(*sum
), GFP_KERNEL
);
400 /* Check whether there are sufficient sum resources to meet request. */
402 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
403 for (i
= 0; i
< desc
->msr
; i
++) {
404 err
= mgr_get_resource(&mgr
->mgr
, 1, &idx
);
410 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
412 dev_err(mgr
->card
->dev
,
413 "Can't meet SUM resource request!\n");
417 err
= sum_rsc_init(sum
, desc
, mgr
);
426 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
427 for (i
--; i
>= 0; i
--)
428 mgr_put_resource(&mgr
->mgr
, 1, sum
->idx
[i
]);
430 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
435 static int put_sum_rsc(struct sum_mgr
*mgr
, struct sum
*sum
)
440 spin_lock_irqsave(&mgr
->mgr_lock
, flags
);
441 for (i
= 0; i
< sum
->rsc
.msr
; i
++)
442 mgr_put_resource(&mgr
->mgr
, 1, sum
->idx
[i
]);
444 spin_unlock_irqrestore(&mgr
->mgr_lock
, flags
);
451 int sum_mgr_create(struct hw
*hw
, struct sum_mgr
**rsum_mgr
)
454 struct sum_mgr
*sum_mgr
;
457 sum_mgr
= kzalloc(sizeof(*sum_mgr
), GFP_KERNEL
);
461 err
= rsc_mgr_init(&sum_mgr
->mgr
, SUM
, SUM_RESOURCE_NUM
, hw
);
465 spin_lock_init(&sum_mgr
->mgr_lock
);
467 sum_mgr
->get_sum
= get_sum_rsc
;
468 sum_mgr
->put_sum
= put_sum_rsc
;
469 sum_mgr
->card
= hw
->card
;
480 int sum_mgr_destroy(struct sum_mgr
*sum_mgr
)
482 rsc_mgr_uninit(&sum_mgr
->mgr
);