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