xref: /openbmc/linux/sound/pci/ctxfi/ctamixer.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
15765e78eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a08b9f2fSAditya Srivastava /*
38cc72361SWai Yew CHAY  * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
48cc72361SWai Yew CHAY  *
58cc72361SWai Yew CHAY  * @File	ctamixer.c
68cc72361SWai Yew CHAY  *
78cc72361SWai Yew CHAY  * @Brief
88cc72361SWai Yew CHAY  * This file contains the implementation of the Audio Mixer
98cc72361SWai Yew CHAY  * resource management object.
108cc72361SWai Yew CHAY  *
118cc72361SWai Yew CHAY  * @Author	Liu Chun
128cc72361SWai Yew CHAY  * @Date 	May 21 2008
138cc72361SWai Yew CHAY  */
148cc72361SWai Yew CHAY 
158cc72361SWai Yew CHAY #include "ctamixer.h"
168cc72361SWai Yew CHAY #include "cthardware.h"
178cc72361SWai Yew CHAY #include <linux/slab.h>
188cc72361SWai Yew CHAY 
198cc72361SWai Yew CHAY #define AMIXER_RESOURCE_NUM	256
208cc72361SWai Yew CHAY #define SUM_RESOURCE_NUM	256
218cc72361SWai Yew CHAY 
228cc72361SWai Yew CHAY #define AMIXER_Y_IMMEDIATE	1
238cc72361SWai Yew CHAY 
248cc72361SWai Yew CHAY #define BLANK_SLOT		4094
258cc72361SWai Yew CHAY 
amixer_master(struct rsc * rsc)26*76c47183STakashi Iwai static void amixer_master(struct rsc *rsc)
278cc72361SWai Yew CHAY {
288cc72361SWai Yew CHAY 	rsc->conj = 0;
29*76c47183STakashi Iwai 	rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
308cc72361SWai Yew CHAY }
318cc72361SWai Yew CHAY 
amixer_next_conj(struct rsc * rsc)32*76c47183STakashi Iwai static void amixer_next_conj(struct rsc *rsc)
338cc72361SWai Yew CHAY {
348cc72361SWai Yew CHAY 	rsc->conj++;
358cc72361SWai Yew CHAY }
368cc72361SWai Yew CHAY 
amixer_index(const struct rsc * rsc)378cc72361SWai Yew CHAY static int amixer_index(const struct rsc *rsc)
388cc72361SWai Yew CHAY {
398cc72361SWai Yew CHAY 	return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
408cc72361SWai Yew CHAY }
418cc72361SWai Yew CHAY 
amixer_output_slot(const struct rsc * rsc)428cc72361SWai Yew CHAY static int amixer_output_slot(const struct rsc *rsc)
438cc72361SWai Yew CHAY {
448cc72361SWai Yew CHAY 	return (amixer_index(rsc) << 4) + 0x4;
458cc72361SWai Yew CHAY }
468cc72361SWai Yew CHAY 
4743f2cdebSJulia Lawall static const struct rsc_ops amixer_basic_rsc_ops = {
488cc72361SWai Yew CHAY 	.master		= amixer_master,
498cc72361SWai Yew CHAY 	.next_conj	= amixer_next_conj,
508cc72361SWai Yew CHAY 	.index		= amixer_index,
518cc72361SWai Yew CHAY 	.output_slot	= amixer_output_slot,
528cc72361SWai Yew CHAY };
538cc72361SWai Yew CHAY 
amixer_set_input(struct amixer * amixer,struct rsc * rsc)548cc72361SWai Yew CHAY static int amixer_set_input(struct amixer *amixer, struct rsc *rsc)
558cc72361SWai Yew CHAY {
56514eef9cSTakashi Iwai 	struct hw *hw;
578cc72361SWai Yew CHAY 
58514eef9cSTakashi Iwai 	hw = amixer->rsc.hw;
598cc72361SWai Yew CHAY 	hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE);
608cc72361SWai Yew CHAY 	amixer->input = rsc;
6135ebf6e7STakashi Iwai 	if (!rsc)
628cc72361SWai Yew CHAY 		hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT);
638cc72361SWai Yew CHAY 	else
648cc72361SWai Yew CHAY 		hw->amixer_set_x(amixer->rsc.ctrl_blk,
658cc72361SWai Yew CHAY 					rsc->ops->output_slot(rsc));
668cc72361SWai Yew CHAY 
678cc72361SWai Yew CHAY 	return 0;
688cc72361SWai Yew CHAY }
698cc72361SWai Yew CHAY 
708cc72361SWai Yew CHAY /* y is a 14-bit immediate constant */
amixer_set_y(struct amixer * amixer,unsigned int y)718cc72361SWai Yew CHAY static int amixer_set_y(struct amixer *amixer, unsigned int y)
728cc72361SWai Yew CHAY {
73514eef9cSTakashi Iwai 	struct hw *hw;
748cc72361SWai Yew CHAY 
75514eef9cSTakashi Iwai 	hw = amixer->rsc.hw;
768cc72361SWai Yew CHAY 	hw->amixer_set_y(amixer->rsc.ctrl_blk, y);
778cc72361SWai Yew CHAY 
788cc72361SWai Yew CHAY 	return 0;
798cc72361SWai Yew CHAY }
808cc72361SWai Yew CHAY 
amixer_set_invalid_squash(struct amixer * amixer,unsigned int iv)818cc72361SWai Yew CHAY static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv)
828cc72361SWai Yew CHAY {
83514eef9cSTakashi Iwai 	struct hw *hw;
848cc72361SWai Yew CHAY 
85514eef9cSTakashi Iwai 	hw = amixer->rsc.hw;
868cc72361SWai Yew CHAY 	hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv);
878cc72361SWai Yew CHAY 
888cc72361SWai Yew CHAY 	return 0;
898cc72361SWai Yew CHAY }
908cc72361SWai Yew CHAY 
amixer_set_sum(struct amixer * amixer,struct sum * sum)918cc72361SWai Yew CHAY static int amixer_set_sum(struct amixer *amixer, struct sum *sum)
928cc72361SWai Yew CHAY {
93514eef9cSTakashi Iwai 	struct hw *hw;
948cc72361SWai Yew CHAY 
95514eef9cSTakashi Iwai 	hw = amixer->rsc.hw;
968cc72361SWai Yew CHAY 	amixer->sum = sum;
9735ebf6e7STakashi Iwai 	if (!sum) {
988cc72361SWai Yew CHAY 		hw->amixer_set_se(amixer->rsc.ctrl_blk, 0);
998cc72361SWai Yew CHAY 	} else {
1008cc72361SWai Yew CHAY 		hw->amixer_set_se(amixer->rsc.ctrl_blk, 1);
1018cc72361SWai Yew CHAY 		hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
1028cc72361SWai Yew CHAY 					sum->rsc.ops->index(&sum->rsc));
1038cc72361SWai Yew CHAY 	}
1048cc72361SWai Yew CHAY 
1058cc72361SWai Yew CHAY 	return 0;
1068cc72361SWai Yew CHAY }
1078cc72361SWai Yew CHAY 
amixer_commit_write(struct amixer * amixer)1088cc72361SWai Yew CHAY static int amixer_commit_write(struct amixer *amixer)
1098cc72361SWai Yew CHAY {
110514eef9cSTakashi Iwai 	struct hw *hw;
111514eef9cSTakashi Iwai 	unsigned int index;
112514eef9cSTakashi Iwai 	int i;
113514eef9cSTakashi Iwai 	struct rsc *input;
114514eef9cSTakashi Iwai 	struct sum *sum;
1158cc72361SWai Yew CHAY 
116514eef9cSTakashi Iwai 	hw = amixer->rsc.hw;
1178cc72361SWai Yew CHAY 	input = amixer->input;
1188cc72361SWai Yew CHAY 	sum = amixer->sum;
1198cc72361SWai Yew CHAY 
1208cc72361SWai Yew CHAY 	/* Program master and conjugate resources */
1218cc72361SWai Yew CHAY 	amixer->rsc.ops->master(&amixer->rsc);
12235ebf6e7STakashi Iwai 	if (input)
1238cc72361SWai Yew CHAY 		input->ops->master(input);
1248cc72361SWai Yew CHAY 
12535ebf6e7STakashi Iwai 	if (sum)
1268cc72361SWai Yew CHAY 		sum->rsc.ops->master(&sum->rsc);
1278cc72361SWai Yew CHAY 
1288cc72361SWai Yew CHAY 	for (i = 0; i < amixer->rsc.msr; i++) {
1298cc72361SWai Yew CHAY 		hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk);
13035ebf6e7STakashi Iwai 		if (input) {
1318cc72361SWai Yew CHAY 			hw->amixer_set_x(amixer->rsc.ctrl_blk,
1328cc72361SWai Yew CHAY 						input->ops->output_slot(input));
1338cc72361SWai Yew CHAY 			input->ops->next_conj(input);
1348cc72361SWai Yew CHAY 		}
13535ebf6e7STakashi Iwai 		if (sum) {
1368cc72361SWai Yew CHAY 			hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
1378cc72361SWai Yew CHAY 						sum->rsc.ops->index(&sum->rsc));
1388cc72361SWai Yew CHAY 			sum->rsc.ops->next_conj(&sum->rsc);
1398cc72361SWai Yew CHAY 		}
1408cc72361SWai Yew CHAY 		index = amixer->rsc.ops->output_slot(&amixer->rsc);
1418cc72361SWai Yew CHAY 		hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
1428cc72361SWai Yew CHAY 		amixer->rsc.ops->next_conj(&amixer->rsc);
1438cc72361SWai Yew CHAY 	}
1448cc72361SWai Yew CHAY 	amixer->rsc.ops->master(&amixer->rsc);
14535ebf6e7STakashi Iwai 	if (input)
1468cc72361SWai Yew CHAY 		input->ops->master(input);
1478cc72361SWai Yew CHAY 
14835ebf6e7STakashi Iwai 	if (sum)
1498cc72361SWai Yew CHAY 		sum->rsc.ops->master(&sum->rsc);
1508cc72361SWai Yew CHAY 
1518cc72361SWai Yew CHAY 	return 0;
1528cc72361SWai Yew CHAY }
1538cc72361SWai Yew CHAY 
amixer_commit_raw_write(struct amixer * amixer)1548cc72361SWai Yew CHAY static int amixer_commit_raw_write(struct amixer *amixer)
1558cc72361SWai Yew CHAY {
156514eef9cSTakashi Iwai 	struct hw *hw;
157514eef9cSTakashi Iwai 	unsigned int index;
1588cc72361SWai Yew CHAY 
159514eef9cSTakashi Iwai 	hw = amixer->rsc.hw;
1608cc72361SWai Yew CHAY 	index = amixer->rsc.ops->output_slot(&amixer->rsc);
1618cc72361SWai Yew CHAY 	hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
1628cc72361SWai Yew CHAY 
1638cc72361SWai Yew CHAY 	return 0;
1648cc72361SWai Yew CHAY }
1658cc72361SWai Yew CHAY 
amixer_get_y(struct amixer * amixer)1668cc72361SWai Yew CHAY static int amixer_get_y(struct amixer *amixer)
1678cc72361SWai Yew CHAY {
168514eef9cSTakashi Iwai 	struct hw *hw;
1698cc72361SWai Yew CHAY 
170514eef9cSTakashi Iwai 	hw = amixer->rsc.hw;
1718cc72361SWai Yew CHAY 	return hw->amixer_get_y(amixer->rsc.ctrl_blk);
1728cc72361SWai Yew CHAY }
1738cc72361SWai Yew CHAY 
amixer_setup(struct amixer * amixer,struct rsc * input,unsigned int scale,struct sum * sum)1748cc72361SWai Yew CHAY static int amixer_setup(struct amixer *amixer, struct rsc *input,
1758cc72361SWai Yew CHAY 			unsigned int scale, struct sum *sum)
1768cc72361SWai Yew CHAY {
1778cc72361SWai Yew CHAY 	amixer_set_input(amixer, input);
1788cc72361SWai Yew CHAY 	amixer_set_y(amixer, scale);
1798cc72361SWai Yew CHAY 	amixer_set_sum(amixer, sum);
1808cc72361SWai Yew CHAY 	amixer_commit_write(amixer);
1818cc72361SWai Yew CHAY 	return 0;
1828cc72361SWai Yew CHAY }
1838cc72361SWai Yew CHAY 
18443f2cdebSJulia Lawall static const struct amixer_rsc_ops amixer_ops = {
1858cc72361SWai Yew CHAY 	.set_input		= amixer_set_input,
1868cc72361SWai Yew CHAY 	.set_invalid_squash	= amixer_set_invalid_squash,
1878cc72361SWai Yew CHAY 	.set_scale		= amixer_set_y,
1888cc72361SWai Yew CHAY 	.set_sum		= amixer_set_sum,
1898cc72361SWai Yew CHAY 	.commit_write		= amixer_commit_write,
1908cc72361SWai Yew CHAY 	.commit_raw_write	= amixer_commit_raw_write,
1918cc72361SWai Yew CHAY 	.setup			= amixer_setup,
1928cc72361SWai Yew CHAY 	.get_scale		= amixer_get_y,
1938cc72361SWai Yew CHAY };
1948cc72361SWai Yew CHAY 
amixer_rsc_init(struct amixer * amixer,const struct amixer_desc * desc,struct amixer_mgr * mgr)1958cc72361SWai Yew CHAY static int amixer_rsc_init(struct amixer *amixer,
1968cc72361SWai Yew CHAY 			   const struct amixer_desc *desc,
1978cc72361SWai Yew CHAY 			   struct amixer_mgr *mgr)
1988cc72361SWai Yew CHAY {
199514eef9cSTakashi Iwai 	int err;
2008cc72361SWai Yew CHAY 
2018cc72361SWai Yew CHAY 	err = rsc_init(&amixer->rsc, amixer->idx[0],
2028cc72361SWai Yew CHAY 			AMIXER, desc->msr, mgr->mgr.hw);
2038cc72361SWai Yew CHAY 	if (err)
2048cc72361SWai Yew CHAY 		return err;
2058cc72361SWai Yew CHAY 
2068cc72361SWai Yew CHAY 	/* Set amixer specific operations */
2078cc72361SWai Yew CHAY 	amixer->rsc.ops = &amixer_basic_rsc_ops;
2088cc72361SWai Yew CHAY 	amixer->ops = &amixer_ops;
2098cc72361SWai Yew CHAY 	amixer->input = NULL;
2108cc72361SWai Yew CHAY 	amixer->sum = NULL;
2118cc72361SWai Yew CHAY 
2128cc72361SWai Yew CHAY 	amixer_setup(amixer, NULL, 0, NULL);
2138cc72361SWai Yew CHAY 
2148cc72361SWai Yew CHAY 	return 0;
2158cc72361SWai Yew CHAY }
2168cc72361SWai Yew CHAY 
amixer_rsc_uninit(struct amixer * amixer)2178cc72361SWai Yew CHAY static int amixer_rsc_uninit(struct amixer *amixer)
2188cc72361SWai Yew CHAY {
2198cc72361SWai Yew CHAY 	amixer_setup(amixer, NULL, 0, NULL);
2208cc72361SWai Yew CHAY 	rsc_uninit(&amixer->rsc);
2218cc72361SWai Yew CHAY 	amixer->ops = NULL;
2228cc72361SWai Yew CHAY 	amixer->input = NULL;
2238cc72361SWai Yew CHAY 	amixer->sum = NULL;
2248cc72361SWai Yew CHAY 	return 0;
2258cc72361SWai Yew CHAY }
2268cc72361SWai Yew CHAY 
get_amixer_rsc(struct amixer_mgr * mgr,const struct amixer_desc * desc,struct amixer ** ramixer)2278cc72361SWai Yew CHAY static int get_amixer_rsc(struct amixer_mgr *mgr,
2288cc72361SWai Yew CHAY 			  const struct amixer_desc *desc,
2298cc72361SWai Yew CHAY 			  struct amixer **ramixer)
2308cc72361SWai Yew CHAY {
231514eef9cSTakashi Iwai 	int err, i;
232514eef9cSTakashi Iwai 	unsigned int idx;
233514eef9cSTakashi Iwai 	struct amixer *amixer;
2348cc72361SWai Yew CHAY 	unsigned long flags;
2358cc72361SWai Yew CHAY 
2368cc72361SWai Yew CHAY 	*ramixer = NULL;
2378cc72361SWai Yew CHAY 
2388cc72361SWai Yew CHAY 	/* Allocate mem for amixer resource */
2398cc72361SWai Yew CHAY 	amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
24068110661STakashi Iwai 	if (!amixer)
24168110661STakashi Iwai 		return -ENOMEM;
2428cc72361SWai Yew CHAY 
2438cc72361SWai Yew CHAY 	/* Check whether there are sufficient
2448cc72361SWai Yew CHAY 	 * amixer resources to meet request. */
24568110661STakashi Iwai 	err = 0;
2468cc72361SWai Yew CHAY 	spin_lock_irqsave(&mgr->mgr_lock, flags);
2478cc72361SWai Yew CHAY 	for (i = 0; i < desc->msr; i++) {
2488cc72361SWai Yew CHAY 		err = mgr_get_resource(&mgr->mgr, 1, &idx);
2498cc72361SWai Yew CHAY 		if (err)
2508cc72361SWai Yew CHAY 			break;
2518cc72361SWai Yew CHAY 
2528cc72361SWai Yew CHAY 		amixer->idx[i] = idx;
2538cc72361SWai Yew CHAY 	}
2548cc72361SWai Yew CHAY 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
2558cc72361SWai Yew CHAY 	if (err) {
2560cae90a9SSudip Mukherjee 		dev_err(mgr->card->dev,
2570cae90a9SSudip Mukherjee 			"Can't meet AMIXER resource request!\n");
2588cc72361SWai Yew CHAY 		goto error;
2598cc72361SWai Yew CHAY 	}
2608cc72361SWai Yew CHAY 
2618cc72361SWai Yew CHAY 	err = amixer_rsc_init(amixer, desc, mgr);
2628cc72361SWai Yew CHAY 	if (err)
2638cc72361SWai Yew CHAY 		goto error;
2648cc72361SWai Yew CHAY 
2658cc72361SWai Yew CHAY 	*ramixer = amixer;
2668cc72361SWai Yew CHAY 
2678cc72361SWai Yew CHAY 	return 0;
2688cc72361SWai Yew CHAY 
2698cc72361SWai Yew CHAY error:
2708cc72361SWai Yew CHAY 	spin_lock_irqsave(&mgr->mgr_lock, flags);
2718cc72361SWai Yew CHAY 	for (i--; i >= 0; i--)
2728cc72361SWai Yew CHAY 		mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
2738cc72361SWai Yew CHAY 
2748cc72361SWai Yew CHAY 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
2758cc72361SWai Yew CHAY 	kfree(amixer);
2768cc72361SWai Yew CHAY 	return err;
2778cc72361SWai Yew CHAY }
2788cc72361SWai Yew CHAY 
put_amixer_rsc(struct amixer_mgr * mgr,struct amixer * amixer)2798cc72361SWai Yew CHAY static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
2808cc72361SWai Yew CHAY {
2818cc72361SWai Yew CHAY 	unsigned long flags;
282514eef9cSTakashi Iwai 	int i;
2838cc72361SWai Yew CHAY 
2848cc72361SWai Yew CHAY 	spin_lock_irqsave(&mgr->mgr_lock, flags);
2858cc72361SWai Yew CHAY 	for (i = 0; i < amixer->rsc.msr; i++)
2868cc72361SWai Yew CHAY 		mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
2878cc72361SWai Yew CHAY 
2888cc72361SWai Yew CHAY 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
2898cc72361SWai Yew CHAY 	amixer_rsc_uninit(amixer);
2908cc72361SWai Yew CHAY 	kfree(amixer);
2918cc72361SWai Yew CHAY 
2928cc72361SWai Yew CHAY 	return 0;
2938cc72361SWai Yew CHAY }
2948cc72361SWai Yew CHAY 
amixer_mgr_create(struct hw * hw,struct amixer_mgr ** ramixer_mgr)29566640898SSudip Mukherjee int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr)
2968cc72361SWai Yew CHAY {
297514eef9cSTakashi Iwai 	int err;
2988cc72361SWai Yew CHAY 	struct amixer_mgr *amixer_mgr;
2998cc72361SWai Yew CHAY 
3008cc72361SWai Yew CHAY 	*ramixer_mgr = NULL;
3018cc72361SWai Yew CHAY 	amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
30235ebf6e7STakashi Iwai 	if (!amixer_mgr)
3038cc72361SWai Yew CHAY 		return -ENOMEM;
3048cc72361SWai Yew CHAY 
3058cc72361SWai Yew CHAY 	err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
3068cc72361SWai Yew CHAY 	if (err)
3078cc72361SWai Yew CHAY 		goto error;
3088cc72361SWai Yew CHAY 
3098cc72361SWai Yew CHAY 	spin_lock_init(&amixer_mgr->mgr_lock);
3108cc72361SWai Yew CHAY 
3118cc72361SWai Yew CHAY 	amixer_mgr->get_amixer = get_amixer_rsc;
3128cc72361SWai Yew CHAY 	amixer_mgr->put_amixer = put_amixer_rsc;
313e5347f9aSSudip Mukherjee 	amixer_mgr->card = hw->card;
3148cc72361SWai Yew CHAY 
3158cc72361SWai Yew CHAY 	*ramixer_mgr = amixer_mgr;
3168cc72361SWai Yew CHAY 
3178cc72361SWai Yew CHAY 	return 0;
3188cc72361SWai Yew CHAY 
3198cc72361SWai Yew CHAY error:
3208cc72361SWai Yew CHAY 	kfree(amixer_mgr);
3218cc72361SWai Yew CHAY 	return err;
3228cc72361SWai Yew CHAY }
3238cc72361SWai Yew CHAY 
amixer_mgr_destroy(struct amixer_mgr * amixer_mgr)3248cc72361SWai Yew CHAY int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
3258cc72361SWai Yew CHAY {
3268cc72361SWai Yew CHAY 	rsc_mgr_uninit(&amixer_mgr->mgr);
3278cc72361SWai Yew CHAY 	kfree(amixer_mgr);
3288cc72361SWai Yew CHAY 	return 0;
3298cc72361SWai Yew CHAY }
3308cc72361SWai Yew CHAY 
3318cc72361SWai Yew CHAY /* SUM resource management */
3328cc72361SWai Yew CHAY 
sum_master(struct rsc * rsc)333*76c47183STakashi Iwai static void sum_master(struct rsc *rsc)
3348cc72361SWai Yew CHAY {
3358cc72361SWai Yew CHAY 	rsc->conj = 0;
336*76c47183STakashi Iwai 	rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
3378cc72361SWai Yew CHAY }
3388cc72361SWai Yew CHAY 
sum_next_conj(struct rsc * rsc)339*76c47183STakashi Iwai static void sum_next_conj(struct rsc *rsc)
3408cc72361SWai Yew CHAY {
3418cc72361SWai Yew CHAY 	rsc->conj++;
3428cc72361SWai Yew CHAY }
3438cc72361SWai Yew CHAY 
sum_index(const struct rsc * rsc)3448cc72361SWai Yew CHAY static int sum_index(const struct rsc *rsc)
3458cc72361SWai Yew CHAY {
3468cc72361SWai Yew CHAY 	return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
3478cc72361SWai Yew CHAY }
3488cc72361SWai Yew CHAY 
sum_output_slot(const struct rsc * rsc)3498cc72361SWai Yew CHAY static int sum_output_slot(const struct rsc *rsc)
3508cc72361SWai Yew CHAY {
3518cc72361SWai Yew CHAY 	return (sum_index(rsc) << 4) + 0xc;
3528cc72361SWai Yew CHAY }
3538cc72361SWai Yew CHAY 
35443f2cdebSJulia Lawall static const struct rsc_ops sum_basic_rsc_ops = {
3558cc72361SWai Yew CHAY 	.master		= sum_master,
3568cc72361SWai Yew CHAY 	.next_conj	= sum_next_conj,
3578cc72361SWai Yew CHAY 	.index		= sum_index,
3588cc72361SWai Yew CHAY 	.output_slot	= sum_output_slot,
3598cc72361SWai Yew CHAY };
3608cc72361SWai Yew CHAY 
sum_rsc_init(struct sum * sum,const struct sum_desc * desc,struct sum_mgr * mgr)3618cc72361SWai Yew CHAY static int sum_rsc_init(struct sum *sum,
3628cc72361SWai Yew CHAY 			const struct sum_desc *desc,
3638cc72361SWai Yew CHAY 			struct sum_mgr *mgr)
3648cc72361SWai Yew CHAY {
365514eef9cSTakashi Iwai 	int err;
3668cc72361SWai Yew CHAY 
3678cc72361SWai Yew CHAY 	err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw);
3688cc72361SWai Yew CHAY 	if (err)
3698cc72361SWai Yew CHAY 		return err;
3708cc72361SWai Yew CHAY 
3718cc72361SWai Yew CHAY 	sum->rsc.ops = &sum_basic_rsc_ops;
3728cc72361SWai Yew CHAY 
3738cc72361SWai Yew CHAY 	return 0;
3748cc72361SWai Yew CHAY }
3758cc72361SWai Yew CHAY 
sum_rsc_uninit(struct sum * sum)3768cc72361SWai Yew CHAY static int sum_rsc_uninit(struct sum *sum)
3778cc72361SWai Yew CHAY {
3788cc72361SWai Yew CHAY 	rsc_uninit(&sum->rsc);
3798cc72361SWai Yew CHAY 	return 0;
3808cc72361SWai Yew CHAY }
3818cc72361SWai Yew CHAY 
get_sum_rsc(struct sum_mgr * mgr,const struct sum_desc * desc,struct sum ** rsum)3828cc72361SWai Yew CHAY static int get_sum_rsc(struct sum_mgr *mgr,
3838cc72361SWai Yew CHAY 		       const struct sum_desc *desc,
3848cc72361SWai Yew CHAY 		       struct sum **rsum)
3858cc72361SWai Yew CHAY {
386514eef9cSTakashi Iwai 	int err, i;
387514eef9cSTakashi Iwai 	unsigned int idx;
388514eef9cSTakashi Iwai 	struct sum *sum;
3898cc72361SWai Yew CHAY 	unsigned long flags;
3908cc72361SWai Yew CHAY 
3918cc72361SWai Yew CHAY 	*rsum = NULL;
3928cc72361SWai Yew CHAY 
3938cc72361SWai Yew CHAY 	/* Allocate mem for sum resource */
3948cc72361SWai Yew CHAY 	sum = kzalloc(sizeof(*sum), GFP_KERNEL);
39568110661STakashi Iwai 	if (!sum)
39668110661STakashi Iwai 		return -ENOMEM;
3978cc72361SWai Yew CHAY 
3988cc72361SWai Yew CHAY 	/* Check whether there are sufficient sum resources to meet request. */
39968110661STakashi Iwai 	err = 0;
4008cc72361SWai Yew CHAY 	spin_lock_irqsave(&mgr->mgr_lock, flags);
4018cc72361SWai Yew CHAY 	for (i = 0; i < desc->msr; i++) {
4028cc72361SWai Yew CHAY 		err = mgr_get_resource(&mgr->mgr, 1, &idx);
4038cc72361SWai Yew CHAY 		if (err)
4048cc72361SWai Yew CHAY 			break;
4058cc72361SWai Yew CHAY 
4068cc72361SWai Yew CHAY 		sum->idx[i] = idx;
4078cc72361SWai Yew CHAY 	}
4088cc72361SWai Yew CHAY 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
4098cc72361SWai Yew CHAY 	if (err) {
4100cae90a9SSudip Mukherjee 		dev_err(mgr->card->dev,
4110cae90a9SSudip Mukherjee 			"Can't meet SUM resource request!\n");
4128cc72361SWai Yew CHAY 		goto error;
4138cc72361SWai Yew CHAY 	}
4148cc72361SWai Yew CHAY 
4158cc72361SWai Yew CHAY 	err = sum_rsc_init(sum, desc, mgr);
4168cc72361SWai Yew CHAY 	if (err)
4178cc72361SWai Yew CHAY 		goto error;
4188cc72361SWai Yew CHAY 
4198cc72361SWai Yew CHAY 	*rsum = sum;
4208cc72361SWai Yew CHAY 
4218cc72361SWai Yew CHAY 	return 0;
4228cc72361SWai Yew CHAY 
4238cc72361SWai Yew CHAY error:
4248cc72361SWai Yew CHAY 	spin_lock_irqsave(&mgr->mgr_lock, flags);
4258cc72361SWai Yew CHAY 	for (i--; i >= 0; i--)
4268cc72361SWai Yew CHAY 		mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
4278cc72361SWai Yew CHAY 
4288cc72361SWai Yew CHAY 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
4298cc72361SWai Yew CHAY 	kfree(sum);
4308cc72361SWai Yew CHAY 	return err;
4318cc72361SWai Yew CHAY }
4328cc72361SWai Yew CHAY 
put_sum_rsc(struct sum_mgr * mgr,struct sum * sum)4338cc72361SWai Yew CHAY static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
4348cc72361SWai Yew CHAY {
4358cc72361SWai Yew CHAY 	unsigned long flags;
436514eef9cSTakashi Iwai 	int i;
4378cc72361SWai Yew CHAY 
4388cc72361SWai Yew CHAY 	spin_lock_irqsave(&mgr->mgr_lock, flags);
4398cc72361SWai Yew CHAY 	for (i = 0; i < sum->rsc.msr; i++)
4408cc72361SWai Yew CHAY 		mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
4418cc72361SWai Yew CHAY 
4428cc72361SWai Yew CHAY 	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
4438cc72361SWai Yew CHAY 	sum_rsc_uninit(sum);
4448cc72361SWai Yew CHAY 	kfree(sum);
4458cc72361SWai Yew CHAY 
4468cc72361SWai Yew CHAY 	return 0;
4478cc72361SWai Yew CHAY }
4488cc72361SWai Yew CHAY 
sum_mgr_create(struct hw * hw,struct sum_mgr ** rsum_mgr)44966640898SSudip Mukherjee int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr)
4508cc72361SWai Yew CHAY {
451514eef9cSTakashi Iwai 	int err;
4528cc72361SWai Yew CHAY 	struct sum_mgr *sum_mgr;
4538cc72361SWai Yew CHAY 
4548cc72361SWai Yew CHAY 	*rsum_mgr = NULL;
4558cc72361SWai Yew CHAY 	sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
45635ebf6e7STakashi Iwai 	if (!sum_mgr)
4578cc72361SWai Yew CHAY 		return -ENOMEM;
4588cc72361SWai Yew CHAY 
4598cc72361SWai Yew CHAY 	err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
4608cc72361SWai Yew CHAY 	if (err)
4618cc72361SWai Yew CHAY 		goto error;
4628cc72361SWai Yew CHAY 
4638cc72361SWai Yew CHAY 	spin_lock_init(&sum_mgr->mgr_lock);
4648cc72361SWai Yew CHAY 
4658cc72361SWai Yew CHAY 	sum_mgr->get_sum = get_sum_rsc;
4668cc72361SWai Yew CHAY 	sum_mgr->put_sum = put_sum_rsc;
467e5347f9aSSudip Mukherjee 	sum_mgr->card = hw->card;
4688cc72361SWai Yew CHAY 
4698cc72361SWai Yew CHAY 	*rsum_mgr = sum_mgr;
4708cc72361SWai Yew CHAY 
4718cc72361SWai Yew CHAY 	return 0;
4728cc72361SWai Yew CHAY 
4738cc72361SWai Yew CHAY error:
4748cc72361SWai Yew CHAY 	kfree(sum_mgr);
4758cc72361SWai Yew CHAY 	return err;
4768cc72361SWai Yew CHAY }
4778cc72361SWai Yew CHAY 
sum_mgr_destroy(struct sum_mgr * sum_mgr)4788cc72361SWai Yew CHAY int sum_mgr_destroy(struct sum_mgr *sum_mgr)
4798cc72361SWai Yew CHAY {
4808cc72361SWai Yew CHAY 	rsc_mgr_uninit(&sum_mgr->mgr);
4818cc72361SWai Yew CHAY 	kfree(sum_mgr);
4828cc72361SWai Yew CHAY 	return 0;
4838cc72361SWai Yew CHAY }
4848cc72361SWai Yew CHAY 
485