xref: /linux/sound/pci/ctxfi/ctamixer.c (revision 6e49f9e05c528055c005bb42018a6b5a615b45b9)
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 
amixer_master(struct rsc * rsc)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 
amixer_next_conj(struct rsc * rsc)32 static void amixer_next_conj(struct rsc *rsc)
33 {
34 	rsc->conj++;
35 }
36 
amixer_index(const struct rsc * rsc)37 static int amixer_index(const struct rsc *rsc)
38 {
39 	return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
40 }
41 
amixer_output_slot(const struct rsc * rsc)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 
amixer_set_input(struct amixer * amixer,struct rsc * rsc)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 */
amixer_set_y(struct amixer * amixer,unsigned int y)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 
amixer_set_invalid_squash(struct amixer * amixer,unsigned int iv)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 
amixer_set_sum(struct amixer * amixer,struct sum * sum)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 
amixer_commit_write(struct amixer * amixer)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 
amixer_commit_raw_write(struct amixer * amixer)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 
amixer_get_y(struct amixer * amixer)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 
amixer_setup(struct amixer * amixer,struct rsc * input,unsigned int scale,struct sum * sum)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 
amixer_rsc_init(struct amixer * amixer,const struct amixer_desc * desc,struct amixer_mgr * mgr)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->rsc.conj = 0;
209 	amixer->ops = &amixer_ops;
210 	amixer->input = NULL;
211 	amixer->sum = NULL;
212 
213 	amixer_setup(amixer, NULL, 0, NULL);
214 
215 	return 0;
216 }
217 
amixer_rsc_uninit(struct amixer * amixer)218 static int amixer_rsc_uninit(struct amixer *amixer)
219 {
220 	amixer_setup(amixer, NULL, 0, NULL);
221 	rsc_uninit(&amixer->rsc);
222 	amixer->ops = NULL;
223 	amixer->input = NULL;
224 	amixer->sum = NULL;
225 	return 0;
226 }
227 
get_amixer_rsc(struct amixer_mgr * mgr,const struct amixer_desc * desc,struct amixer ** ramixer)228 static int get_amixer_rsc(struct amixer_mgr *mgr,
229 			  const struct amixer_desc *desc,
230 			  struct amixer **ramixer)
231 {
232 	int err, i;
233 	unsigned int idx;
234 	struct amixer *amixer;
235 
236 	*ramixer = NULL;
237 
238 	/* Allocate mem for amixer resource */
239 	amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
240 	if (!amixer)
241 		return -ENOMEM;
242 
243 	/* Check whether there are sufficient
244 	 * amixer resources to meet request. */
245 	err = 0;
246 	scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
247 		for (i = 0; i < desc->msr; i++) {
248 			err = mgr_get_resource(&mgr->mgr, 1, &idx);
249 			if (err)
250 				break;
251 
252 			amixer->idx[i] = idx;
253 		}
254 	}
255 	if (err) {
256 		dev_err(mgr->card->dev,
257 			"Can't meet AMIXER resource request!\n");
258 		goto error;
259 	}
260 
261 	err = amixer_rsc_init(amixer, desc, mgr);
262 	if (err)
263 		goto error;
264 
265 	*ramixer = amixer;
266 
267 	return 0;
268 
269 error:
270 	scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
271 		for (i--; i >= 0; i--)
272 			mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
273 	}
274 
275 	kfree(amixer);
276 	return err;
277 }
278 
put_amixer_rsc(struct amixer_mgr * mgr,struct amixer * amixer)279 static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
280 {
281 	int i;
282 
283 	scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
284 		for (i = 0; i < amixer->rsc.msr; i++)
285 			mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
286 	}
287 	amixer_rsc_uninit(amixer);
288 	kfree(amixer);
289 
290 	return 0;
291 }
292 
amixer_mgr_create(struct hw * hw,void ** ramixer_mgr)293 int amixer_mgr_create(struct hw *hw, void **ramixer_mgr)
294 {
295 	int err;
296 	struct amixer_mgr *amixer_mgr;
297 
298 	*ramixer_mgr = NULL;
299 	amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
300 	if (!amixer_mgr)
301 		return -ENOMEM;
302 
303 	err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
304 	if (err)
305 		goto error;
306 
307 	spin_lock_init(&amixer_mgr->mgr_lock);
308 
309 	amixer_mgr->get_amixer = get_amixer_rsc;
310 	amixer_mgr->put_amixer = put_amixer_rsc;
311 	amixer_mgr->card = hw->card;
312 
313 	*ramixer_mgr = amixer_mgr;
314 
315 	return 0;
316 
317 error:
318 	kfree(amixer_mgr);
319 	return err;
320 }
321 
amixer_mgr_destroy(void * ptr)322 int amixer_mgr_destroy(void *ptr)
323 {
324 	struct amixer_mgr *amixer_mgr = ptr;
325 	rsc_mgr_uninit(&amixer_mgr->mgr);
326 	kfree(amixer_mgr);
327 	return 0;
328 }
329 
330 /* SUM resource management */
331 
sum_master(struct rsc * rsc)332 static void sum_master(struct rsc *rsc)
333 {
334 	rsc->conj = 0;
335 	rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
336 }
337 
sum_next_conj(struct rsc * rsc)338 static void sum_next_conj(struct rsc *rsc)
339 {
340 	rsc->conj++;
341 }
342 
sum_index(const struct rsc * rsc)343 static int sum_index(const struct rsc *rsc)
344 {
345 	return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
346 }
347 
sum_output_slot(const struct rsc * rsc)348 static int sum_output_slot(const struct rsc *rsc)
349 {
350 	return (sum_index(rsc) << 4) + 0xc;
351 }
352 
353 static const struct rsc_ops sum_basic_rsc_ops = {
354 	.master		= sum_master,
355 	.next_conj	= sum_next_conj,
356 	.index		= sum_index,
357 	.output_slot	= sum_output_slot,
358 };
359 
sum_rsc_init(struct sum * sum,const struct sum_desc * desc,struct sum_mgr * mgr)360 static int sum_rsc_init(struct sum *sum,
361 			const struct sum_desc *desc,
362 			struct sum_mgr *mgr)
363 {
364 	int err;
365 
366 	err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw);
367 	if (err)
368 		return err;
369 
370 	sum->rsc.ops = &sum_basic_rsc_ops;
371 	sum->rsc.conj = 0;
372 
373 	return 0;
374 }
375 
sum_rsc_uninit(struct sum * sum)376 static int sum_rsc_uninit(struct sum *sum)
377 {
378 	rsc_uninit(&sum->rsc);
379 	return 0;
380 }
381 
get_sum_rsc(struct sum_mgr * mgr,const struct sum_desc * desc,struct sum ** rsum)382 static int get_sum_rsc(struct sum_mgr *mgr,
383 		       const struct sum_desc *desc,
384 		       struct sum **rsum)
385 {
386 	int err, i;
387 	unsigned int idx;
388 	struct sum *sum;
389 
390 	*rsum = NULL;
391 
392 	/* Allocate mem for sum resource */
393 	sum = kzalloc(sizeof(*sum), GFP_KERNEL);
394 	if (!sum)
395 		return -ENOMEM;
396 
397 	/* Check whether there are sufficient sum resources to meet request. */
398 	err = 0;
399 	scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
400 		for (i = 0; i < desc->msr; i++) {
401 			err = mgr_get_resource(&mgr->mgr, 1, &idx);
402 			if (err)
403 				break;
404 
405 			sum->idx[i] = idx;
406 		}
407 	}
408 	if (err) {
409 		dev_err(mgr->card->dev,
410 			"Can't meet SUM resource request!\n");
411 		goto error;
412 	}
413 
414 	err = sum_rsc_init(sum, desc, mgr);
415 	if (err)
416 		goto error;
417 
418 	*rsum = sum;
419 
420 	return 0;
421 
422 error:
423 	scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
424 		for (i--; i >= 0; i--)
425 			mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
426 	}
427 	kfree(sum);
428 	return err;
429 }
430 
put_sum_rsc(struct sum_mgr * mgr,struct sum * sum)431 static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
432 {
433 	int i;
434 
435 	scoped_guard(spinlock_irqsave, &mgr->mgr_lock) {
436 		for (i = 0; i < sum->rsc.msr; i++)
437 			mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
438 	}
439 	sum_rsc_uninit(sum);
440 	kfree(sum);
441 
442 	return 0;
443 }
444 
sum_mgr_create(struct hw * hw,void ** rsum_mgr)445 int sum_mgr_create(struct hw *hw, void **rsum_mgr)
446 {
447 	int err;
448 	struct sum_mgr *sum_mgr;
449 
450 	*rsum_mgr = NULL;
451 	sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
452 	if (!sum_mgr)
453 		return -ENOMEM;
454 
455 	err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
456 	if (err)
457 		goto error;
458 
459 	spin_lock_init(&sum_mgr->mgr_lock);
460 
461 	sum_mgr->get_sum = get_sum_rsc;
462 	sum_mgr->put_sum = put_sum_rsc;
463 	sum_mgr->card = hw->card;
464 
465 	*rsum_mgr = sum_mgr;
466 
467 	return 0;
468 
469 error:
470 	kfree(sum_mgr);
471 	return err;
472 }
473 
sum_mgr_destroy(void * ptr)474 int sum_mgr_destroy(void *ptr)
475 {
476 	struct sum_mgr *sum_mgr = ptr;
477 	rsc_mgr_uninit(&sum_mgr->mgr);
478 	kfree(sum_mgr);
479 	return 0;
480 }
481 
482