Merge 5.16-rc3 into char-misc-next
[linux-2.6-microblaze.git] / sound / pci / ctxfi / ctamixer.c
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         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
269 error:
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
279 static 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
295 int 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
319 error:
320         kfree(amixer_mgr);
321         return err;
322 }
323
324 int 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
333 static void sum_master(struct rsc *rsc)
334 {
335         rsc->conj = 0;
336         rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
337 }
338
339 static void sum_next_conj(struct rsc *rsc)
340 {
341         rsc->conj++;
342 }
343
344 static int sum_index(const struct rsc *rsc)
345 {
346         return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
347 }
348
349 static int sum_output_slot(const struct rsc *rsc)
350 {
351         return (sum_index(rsc) << 4) + 0xc;
352 }
353
354 static 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
361 static 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
376 static int sum_rsc_uninit(struct sum *sum)
377 {
378         rsc_uninit(&sum->rsc);
379         return 0;
380 }
381
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         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
423 error:
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
433 static 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
449 int 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
473 error:
474         kfree(sum_mgr);
475         return err;
476 }
477
478 int 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