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
26static void amixer_master(struct rsc *rsc)
27{
28	rsc->conj = 0;
29	rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
30}
31
32static void amixer_next_conj(struct rsc *rsc)
33{
34	rsc->conj++;
35}
36
37static int amixer_index(const struct rsc *rsc)
38{
39	return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
40}
41
42static int amixer_output_slot(const struct rsc *rsc)
43{
44	return (amixer_index(rsc) << 4) + 0x4;
45}
46
47static 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
54static 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 */
71static 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
81static 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
91static 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
108static 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
154static 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
166static 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
174static 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
184static 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
195static 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
217static 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
227static 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	unsigned long flags;
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	spin_lock_irqsave(&mgr->mgr_lock, flags);
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	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
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
269error:
270	spin_lock_irqsave(&mgr->mgr_lock, flags);
271	for (i--; i >= 0; i--)
272		mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
273
274	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
275	kfree(amixer);
276	return err;
277}
278
279static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
280{
281	unsigned long flags;
282	int i;
283
284	spin_lock_irqsave(&mgr->mgr_lock, flags);
285	for (i = 0; i < amixer->rsc.msr; i++)
286		mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
287
288	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
289	amixer_rsc_uninit(amixer);
290	kfree(amixer);
291
292	return 0;
293}
294
295int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr)
296{
297	int err;
298	struct amixer_mgr *amixer_mgr;
299
300	*ramixer_mgr = NULL;
301	amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
302	if (!amixer_mgr)
303		return -ENOMEM;
304
305	err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
306	if (err)
307		goto error;
308
309	spin_lock_init(&amixer_mgr->mgr_lock);
310
311	amixer_mgr->get_amixer = get_amixer_rsc;
312	amixer_mgr->put_amixer = put_amixer_rsc;
313	amixer_mgr->card = hw->card;
314
315	*ramixer_mgr = amixer_mgr;
316
317	return 0;
318
319error:
320	kfree(amixer_mgr);
321	return err;
322}
323
324int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
325{
326	rsc_mgr_uninit(&amixer_mgr->mgr);
327	kfree(amixer_mgr);
328	return 0;
329}
330
331/* SUM resource management */
332
333static void sum_master(struct rsc *rsc)
334{
335	rsc->conj = 0;
336	rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
337}
338
339static void sum_next_conj(struct rsc *rsc)
340{
341	rsc->conj++;
342}
343
344static int sum_index(const struct rsc *rsc)
345{
346	return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
347}
348
349static int sum_output_slot(const struct rsc *rsc)
350{
351	return (sum_index(rsc) << 4) + 0xc;
352}
353
354static const struct rsc_ops sum_basic_rsc_ops = {
355	.master		= sum_master,
356	.next_conj	= sum_next_conj,
357	.index		= sum_index,
358	.output_slot	= sum_output_slot,
359};
360
361static int sum_rsc_init(struct sum *sum,
362			const struct sum_desc *desc,
363			struct sum_mgr *mgr)
364{
365	int err;
366
367	err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw);
368	if (err)
369		return err;
370
371	sum->rsc.ops = &sum_basic_rsc_ops;
372
373	return 0;
374}
375
376static int sum_rsc_uninit(struct sum *sum)
377{
378	rsc_uninit(&sum->rsc);
379	return 0;
380}
381
382static 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	unsigned long flags;
390
391	*rsum = NULL;
392
393	/* Allocate mem for sum resource */
394	sum = kzalloc(sizeof(*sum), GFP_KERNEL);
395	if (!sum)
396		return -ENOMEM;
397
398	/* Check whether there are sufficient sum resources to meet request. */
399	err = 0;
400	spin_lock_irqsave(&mgr->mgr_lock, flags);
401	for (i = 0; i < desc->msr; i++) {
402		err = mgr_get_resource(&mgr->mgr, 1, &idx);
403		if (err)
404			break;
405
406		sum->idx[i] = idx;
407	}
408	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
409	if (err) {
410		dev_err(mgr->card->dev,
411			"Can't meet SUM resource request!\n");
412		goto error;
413	}
414
415	err = sum_rsc_init(sum, desc, mgr);
416	if (err)
417		goto error;
418
419	*rsum = sum;
420
421	return 0;
422
423error:
424	spin_lock_irqsave(&mgr->mgr_lock, flags);
425	for (i--; i >= 0; i--)
426		mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
427
428	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
429	kfree(sum);
430	return err;
431}
432
433static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
434{
435	unsigned long flags;
436	int i;
437
438	spin_lock_irqsave(&mgr->mgr_lock, flags);
439	for (i = 0; i < sum->rsc.msr; i++)
440		mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
441
442	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
443	sum_rsc_uninit(sum);
444	kfree(sum);
445
446	return 0;
447}
448
449int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr)
450{
451	int err;
452	struct sum_mgr *sum_mgr;
453
454	*rsum_mgr = NULL;
455	sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
456	if (!sum_mgr)
457		return -ENOMEM;
458
459	err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
460	if (err)
461		goto error;
462
463	spin_lock_init(&sum_mgr->mgr_lock);
464
465	sum_mgr->get_sum = get_sum_rsc;
466	sum_mgr->put_sum = put_sum_rsc;
467	sum_mgr->card = hw->card;
468
469	*rsum_mgr = sum_mgr;
470
471	return 0;
472
473error:
474	kfree(sum_mgr);
475	return err;
476}
477
478int sum_mgr_destroy(struct sum_mgr *sum_mgr)
479{
480	rsc_mgr_uninit(&sum_mgr->mgr);
481	kfree(sum_mgr);
482	return 0;
483}
484
485