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