xref: /linux/sound/pci/ctxfi/ctamixer.c (revision 97ef3b7f4fdf8ad6818aa2c8201c3b72cc635e16)
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 int amixer_master(struct rsc *rsc)
27 {
28 	rsc->conj = 0;
29 	return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
30 }
31 
32 static int amixer_next_conj(struct rsc *rsc)
33 {
34 	rsc->conj++;
35 	return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
36 }
37 
38 static int amixer_index(const struct rsc *rsc)
39 {
40 	return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
41 }
42 
43 static int amixer_output_slot(const struct rsc *rsc)
44 {
45 	return (amixer_index(rsc) << 4) + 0x4;
46 }
47 
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,
53 };
54 
55 static int amixer_set_input(struct amixer *amixer, struct rsc *rsc)
56 {
57 	struct hw *hw;
58 
59 	hw = amixer->rsc.hw;
60 	hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE);
61 	amixer->input = rsc;
62 	if (!rsc)
63 		hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT);
64 	else
65 		hw->amixer_set_x(amixer->rsc.ctrl_blk,
66 					rsc->ops->output_slot(rsc));
67 
68 	return 0;
69 }
70 
71 /* y is a 14-bit immediate constant */
72 static int amixer_set_y(struct amixer *amixer, unsigned int y)
73 {
74 	struct hw *hw;
75 
76 	hw = amixer->rsc.hw;
77 	hw->amixer_set_y(amixer->rsc.ctrl_blk, y);
78 
79 	return 0;
80 }
81 
82 static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv)
83 {
84 	struct hw *hw;
85 
86 	hw = amixer->rsc.hw;
87 	hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv);
88 
89 	return 0;
90 }
91 
92 static int amixer_set_sum(struct amixer *amixer, struct sum *sum)
93 {
94 	struct hw *hw;
95 
96 	hw = amixer->rsc.hw;
97 	amixer->sum = sum;
98 	if (!sum) {
99 		hw->amixer_set_se(amixer->rsc.ctrl_blk, 0);
100 	} else {
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));
104 	}
105 
106 	return 0;
107 }
108 
109 static int amixer_commit_write(struct amixer *amixer)
110 {
111 	struct hw *hw;
112 	unsigned int index;
113 	int i;
114 	struct rsc *input;
115 	struct sum *sum;
116 
117 	hw = amixer->rsc.hw;
118 	input = amixer->input;
119 	sum = amixer->sum;
120 
121 	/* Program master and conjugate resources */
122 	amixer->rsc.ops->master(&amixer->rsc);
123 	if (input)
124 		input->ops->master(input);
125 
126 	if (sum)
127 		sum->rsc.ops->master(&sum->rsc);
128 
129 	for (i = 0; i < amixer->rsc.msr; i++) {
130 		hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk);
131 		if (input) {
132 			hw->amixer_set_x(amixer->rsc.ctrl_blk,
133 						input->ops->output_slot(input));
134 			input->ops->next_conj(input);
135 		}
136 		if (sum) {
137 			hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
138 						sum->rsc.ops->index(&sum->rsc));
139 			sum->rsc.ops->next_conj(&sum->rsc);
140 		}
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);
144 	}
145 	amixer->rsc.ops->master(&amixer->rsc);
146 	if (input)
147 		input->ops->master(input);
148 
149 	if (sum)
150 		sum->rsc.ops->master(&sum->rsc);
151 
152 	return 0;
153 }
154 
155 static int amixer_commit_raw_write(struct amixer *amixer)
156 {
157 	struct hw *hw;
158 	unsigned int index;
159 
160 	hw = amixer->rsc.hw;
161 	index = amixer->rsc.ops->output_slot(&amixer->rsc);
162 	hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
163 
164 	return 0;
165 }
166 
167 static int amixer_get_y(struct amixer *amixer)
168 {
169 	struct hw *hw;
170 
171 	hw = amixer->rsc.hw;
172 	return hw->amixer_get_y(amixer->rsc.ctrl_blk);
173 }
174 
175 static int amixer_setup(struct amixer *amixer, struct rsc *input,
176 			unsigned int scale, struct sum *sum)
177 {
178 	amixer_set_input(amixer, input);
179 	amixer_set_y(amixer, scale);
180 	amixer_set_sum(amixer, sum);
181 	amixer_commit_write(amixer);
182 	return 0;
183 }
184 
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,
194 };
195 
196 static int amixer_rsc_init(struct amixer *amixer,
197 			   const struct amixer_desc *desc,
198 			   struct amixer_mgr *mgr)
199 {
200 	int err;
201 
202 	err = rsc_init(&amixer->rsc, amixer->idx[0],
203 			AMIXER, desc->msr, mgr->mgr.hw);
204 	if (err)
205 		return err;
206 
207 	/* Set amixer specific operations */
208 	amixer->rsc.ops = &amixer_basic_rsc_ops;
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 
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 
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 	unsigned long flags;
236 
237 	*ramixer = NULL;
238 
239 	/* Allocate mem for amixer resource */
240 	amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
241 	if (!amixer)
242 		return -ENOMEM;
243 
244 	/* Check whether there are sufficient
245 	 * amixer resources to meet request. */
246 	err = 0;
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);
250 		if (err)
251 			break;
252 
253 		amixer->idx[i] = idx;
254 	}
255 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
256 	if (err) {
257 		dev_err(mgr->card->dev,
258 			"Can't meet AMIXER resource request!\n");
259 		goto error;
260 	}
261 
262 	err = amixer_rsc_init(amixer, desc, mgr);
263 	if (err)
264 		goto error;
265 
266 	*ramixer = amixer;
267 
268 	return 0;
269 
270 error:
271 	spin_lock_irqsave(&mgr->mgr_lock, flags);
272 	for (i--; i >= 0; i--)
273 		mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
274 
275 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
276 	kfree(amixer);
277 	return err;
278 }
279 
280 static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
281 {
282 	unsigned long flags;
283 	int i;
284 
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]);
288 
289 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
290 	amixer_rsc_uninit(amixer);
291 	kfree(amixer);
292 
293 	return 0;
294 }
295 
296 int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr)
297 {
298 	int err;
299 	struct amixer_mgr *amixer_mgr;
300 
301 	*ramixer_mgr = NULL;
302 	amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
303 	if (!amixer_mgr)
304 		return -ENOMEM;
305 
306 	err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
307 	if (err)
308 		goto error;
309 
310 	spin_lock_init(&amixer_mgr->mgr_lock);
311 
312 	amixer_mgr->get_amixer = get_amixer_rsc;
313 	amixer_mgr->put_amixer = put_amixer_rsc;
314 	amixer_mgr->card = hw->card;
315 
316 	*ramixer_mgr = amixer_mgr;
317 
318 	return 0;
319 
320 error:
321 	kfree(amixer_mgr);
322 	return err;
323 }
324 
325 int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
326 {
327 	rsc_mgr_uninit(&amixer_mgr->mgr);
328 	kfree(amixer_mgr);
329 	return 0;
330 }
331 
332 /* SUM resource management */
333 
334 static int sum_master(struct rsc *rsc)
335 {
336 	rsc->conj = 0;
337 	return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
338 }
339 
340 static int sum_next_conj(struct rsc *rsc)
341 {
342 	rsc->conj++;
343 	return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
344 }
345 
346 static int sum_index(const struct rsc *rsc)
347 {
348 	return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
349 }
350 
351 static int sum_output_slot(const struct rsc *rsc)
352 {
353 	return (sum_index(rsc) << 4) + 0xc;
354 }
355 
356 static const struct rsc_ops sum_basic_rsc_ops = {
357 	.master		= sum_master,
358 	.next_conj	= sum_next_conj,
359 	.index		= sum_index,
360 	.output_slot	= sum_output_slot,
361 };
362 
363 static int sum_rsc_init(struct sum *sum,
364 			const struct sum_desc *desc,
365 			struct sum_mgr *mgr)
366 {
367 	int err;
368 
369 	err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw);
370 	if (err)
371 		return err;
372 
373 	sum->rsc.ops = &sum_basic_rsc_ops;
374 
375 	return 0;
376 }
377 
378 static int sum_rsc_uninit(struct sum *sum)
379 {
380 	rsc_uninit(&sum->rsc);
381 	return 0;
382 }
383 
384 static int get_sum_rsc(struct sum_mgr *mgr,
385 		       const struct sum_desc *desc,
386 		       struct sum **rsum)
387 {
388 	int err, i;
389 	unsigned int idx;
390 	struct sum *sum;
391 	unsigned long flags;
392 
393 	*rsum = NULL;
394 
395 	/* Allocate mem for sum resource */
396 	sum = kzalloc(sizeof(*sum), GFP_KERNEL);
397 	if (!sum)
398 		return -ENOMEM;
399 
400 	/* Check whether there are sufficient sum resources to meet request. */
401 	err = 0;
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);
405 		if (err)
406 			break;
407 
408 		sum->idx[i] = idx;
409 	}
410 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
411 	if (err) {
412 		dev_err(mgr->card->dev,
413 			"Can't meet SUM resource request!\n");
414 		goto error;
415 	}
416 
417 	err = sum_rsc_init(sum, desc, mgr);
418 	if (err)
419 		goto error;
420 
421 	*rsum = sum;
422 
423 	return 0;
424 
425 error:
426 	spin_lock_irqsave(&mgr->mgr_lock, flags);
427 	for (i--; i >= 0; i--)
428 		mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
429 
430 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
431 	kfree(sum);
432 	return err;
433 }
434 
435 static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
436 {
437 	unsigned long flags;
438 	int i;
439 
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]);
443 
444 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
445 	sum_rsc_uninit(sum);
446 	kfree(sum);
447 
448 	return 0;
449 }
450 
451 int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr)
452 {
453 	int err;
454 	struct sum_mgr *sum_mgr;
455 
456 	*rsum_mgr = NULL;
457 	sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
458 	if (!sum_mgr)
459 		return -ENOMEM;
460 
461 	err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
462 	if (err)
463 		goto error;
464 
465 	spin_lock_init(&sum_mgr->mgr_lock);
466 
467 	sum_mgr->get_sum = get_sum_rsc;
468 	sum_mgr->put_sum = put_sum_rsc;
469 	sum_mgr->card = hw->card;
470 
471 	*rsum_mgr = sum_mgr;
472 
473 	return 0;
474 
475 error:
476 	kfree(sum_mgr);
477 	return err;
478 }
479 
480 int sum_mgr_destroy(struct sum_mgr *sum_mgr)
481 {
482 	rsc_mgr_uninit(&sum_mgr->mgr);
483 	kfree(sum_mgr);
484 	return 0;
485 }
486 
487