18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/**
38c2ecf20Sopenharmony_ci * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * @File	ctamixer.c
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * @Brief
88c2ecf20Sopenharmony_ci * This file contains the implementation of the Audio Mixer
98c2ecf20Sopenharmony_ci * resource management object.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * @Author	Liu Chun
128c2ecf20Sopenharmony_ci * @Date 	May 21 2008
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "ctamixer.h"
168c2ecf20Sopenharmony_ci#include "cthardware.h"
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define AMIXER_RESOURCE_NUM	256
208c2ecf20Sopenharmony_ci#define SUM_RESOURCE_NUM	256
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define AMIXER_Y_IMMEDIATE	1
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define BLANK_SLOT		4094
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic void amixer_master(struct rsc *rsc)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	rsc->conj = 0;
298c2ecf20Sopenharmony_ci	rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic void amixer_next_conj(struct rsc *rsc)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	rsc->conj++;
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic int amixer_index(const struct rsc *rsc)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic int amixer_output_slot(const struct rsc *rsc)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	return (amixer_index(rsc) << 4) + 0x4;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic const struct rsc_ops amixer_basic_rsc_ops = {
488c2ecf20Sopenharmony_ci	.master		= amixer_master,
498c2ecf20Sopenharmony_ci	.next_conj	= amixer_next_conj,
508c2ecf20Sopenharmony_ci	.index		= amixer_index,
518c2ecf20Sopenharmony_ci	.output_slot	= amixer_output_slot,
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic int amixer_set_input(struct amixer *amixer, struct rsc *rsc)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct hw *hw;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	hw = amixer->rsc.hw;
598c2ecf20Sopenharmony_ci	hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE);
608c2ecf20Sopenharmony_ci	amixer->input = rsc;
618c2ecf20Sopenharmony_ci	if (!rsc)
628c2ecf20Sopenharmony_ci		hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT);
638c2ecf20Sopenharmony_ci	else
648c2ecf20Sopenharmony_ci		hw->amixer_set_x(amixer->rsc.ctrl_blk,
658c2ecf20Sopenharmony_ci					rsc->ops->output_slot(rsc));
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	return 0;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/* y is a 14-bit immediate constant */
718c2ecf20Sopenharmony_cistatic int amixer_set_y(struct amixer *amixer, unsigned int y)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct hw *hw;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	hw = amixer->rsc.hw;
768c2ecf20Sopenharmony_ci	hw->amixer_set_y(amixer->rsc.ctrl_blk, y);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return 0;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct hw *hw;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	hw = amixer->rsc.hw;
868c2ecf20Sopenharmony_ci	hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return 0;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic int amixer_set_sum(struct amixer *amixer, struct sum *sum)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct hw *hw;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	hw = amixer->rsc.hw;
968c2ecf20Sopenharmony_ci	amixer->sum = sum;
978c2ecf20Sopenharmony_ci	if (!sum) {
988c2ecf20Sopenharmony_ci		hw->amixer_set_se(amixer->rsc.ctrl_blk, 0);
998c2ecf20Sopenharmony_ci	} else {
1008c2ecf20Sopenharmony_ci		hw->amixer_set_se(amixer->rsc.ctrl_blk, 1);
1018c2ecf20Sopenharmony_ci		hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
1028c2ecf20Sopenharmony_ci					sum->rsc.ops->index(&sum->rsc));
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic int amixer_commit_write(struct amixer *amixer)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct hw *hw;
1118c2ecf20Sopenharmony_ci	unsigned int index;
1128c2ecf20Sopenharmony_ci	int i;
1138c2ecf20Sopenharmony_ci	struct rsc *input;
1148c2ecf20Sopenharmony_ci	struct sum *sum;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	hw = amixer->rsc.hw;
1178c2ecf20Sopenharmony_ci	input = amixer->input;
1188c2ecf20Sopenharmony_ci	sum = amixer->sum;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	/* Program master and conjugate resources */
1218c2ecf20Sopenharmony_ci	amixer->rsc.ops->master(&amixer->rsc);
1228c2ecf20Sopenharmony_ci	if (input)
1238c2ecf20Sopenharmony_ci		input->ops->master(input);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (sum)
1268c2ecf20Sopenharmony_ci		sum->rsc.ops->master(&sum->rsc);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	for (i = 0; i < amixer->rsc.msr; i++) {
1298c2ecf20Sopenharmony_ci		hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk);
1308c2ecf20Sopenharmony_ci		if (input) {
1318c2ecf20Sopenharmony_ci			hw->amixer_set_x(amixer->rsc.ctrl_blk,
1328c2ecf20Sopenharmony_ci						input->ops->output_slot(input));
1338c2ecf20Sopenharmony_ci			input->ops->next_conj(input);
1348c2ecf20Sopenharmony_ci		}
1358c2ecf20Sopenharmony_ci		if (sum) {
1368c2ecf20Sopenharmony_ci			hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
1378c2ecf20Sopenharmony_ci						sum->rsc.ops->index(&sum->rsc));
1388c2ecf20Sopenharmony_ci			sum->rsc.ops->next_conj(&sum->rsc);
1398c2ecf20Sopenharmony_ci		}
1408c2ecf20Sopenharmony_ci		index = amixer->rsc.ops->output_slot(&amixer->rsc);
1418c2ecf20Sopenharmony_ci		hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
1428c2ecf20Sopenharmony_ci		amixer->rsc.ops->next_conj(&amixer->rsc);
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci	amixer->rsc.ops->master(&amixer->rsc);
1458c2ecf20Sopenharmony_ci	if (input)
1468c2ecf20Sopenharmony_ci		input->ops->master(input);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (sum)
1498c2ecf20Sopenharmony_ci		sum->rsc.ops->master(&sum->rsc);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return 0;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic int amixer_commit_raw_write(struct amixer *amixer)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	struct hw *hw;
1578c2ecf20Sopenharmony_ci	unsigned int index;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	hw = amixer->rsc.hw;
1608c2ecf20Sopenharmony_ci	index = amixer->rsc.ops->output_slot(&amixer->rsc);
1618c2ecf20Sopenharmony_ci	hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	return 0;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int amixer_get_y(struct amixer *amixer)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct hw *hw;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	hw = amixer->rsc.hw;
1718c2ecf20Sopenharmony_ci	return hw->amixer_get_y(amixer->rsc.ctrl_blk);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int amixer_setup(struct amixer *amixer, struct rsc *input,
1758c2ecf20Sopenharmony_ci			unsigned int scale, struct sum *sum)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	amixer_set_input(amixer, input);
1788c2ecf20Sopenharmony_ci	amixer_set_y(amixer, scale);
1798c2ecf20Sopenharmony_ci	amixer_set_sum(amixer, sum);
1808c2ecf20Sopenharmony_ci	amixer_commit_write(amixer);
1818c2ecf20Sopenharmony_ci	return 0;
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic const struct amixer_rsc_ops amixer_ops = {
1858c2ecf20Sopenharmony_ci	.set_input		= amixer_set_input,
1868c2ecf20Sopenharmony_ci	.set_invalid_squash	= amixer_set_invalid_squash,
1878c2ecf20Sopenharmony_ci	.set_scale		= amixer_set_y,
1888c2ecf20Sopenharmony_ci	.set_sum		= amixer_set_sum,
1898c2ecf20Sopenharmony_ci	.commit_write		= amixer_commit_write,
1908c2ecf20Sopenharmony_ci	.commit_raw_write	= amixer_commit_raw_write,
1918c2ecf20Sopenharmony_ci	.setup			= amixer_setup,
1928c2ecf20Sopenharmony_ci	.get_scale		= amixer_get_y,
1938c2ecf20Sopenharmony_ci};
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int amixer_rsc_init(struct amixer *amixer,
1968c2ecf20Sopenharmony_ci			   const struct amixer_desc *desc,
1978c2ecf20Sopenharmony_ci			   struct amixer_mgr *mgr)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	int err;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	err = rsc_init(&amixer->rsc, amixer->idx[0],
2028c2ecf20Sopenharmony_ci			AMIXER, desc->msr, mgr->mgr.hw);
2038c2ecf20Sopenharmony_ci	if (err)
2048c2ecf20Sopenharmony_ci		return err;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	/* Set amixer specific operations */
2078c2ecf20Sopenharmony_ci	amixer->rsc.ops = &amixer_basic_rsc_ops;
2088c2ecf20Sopenharmony_ci	amixer->ops = &amixer_ops;
2098c2ecf20Sopenharmony_ci	amixer->input = NULL;
2108c2ecf20Sopenharmony_ci	amixer->sum = NULL;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	amixer_setup(amixer, NULL, 0, NULL);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	return 0;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic int amixer_rsc_uninit(struct amixer *amixer)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	amixer_setup(amixer, NULL, 0, NULL);
2208c2ecf20Sopenharmony_ci	rsc_uninit(&amixer->rsc);
2218c2ecf20Sopenharmony_ci	amixer->ops = NULL;
2228c2ecf20Sopenharmony_ci	amixer->input = NULL;
2238c2ecf20Sopenharmony_ci	amixer->sum = NULL;
2248c2ecf20Sopenharmony_ci	return 0;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic int get_amixer_rsc(struct amixer_mgr *mgr,
2288c2ecf20Sopenharmony_ci			  const struct amixer_desc *desc,
2298c2ecf20Sopenharmony_ci			  struct amixer **ramixer)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	int err, i;
2328c2ecf20Sopenharmony_ci	unsigned int idx;
2338c2ecf20Sopenharmony_ci	struct amixer *amixer;
2348c2ecf20Sopenharmony_ci	unsigned long flags;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	*ramixer = NULL;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* Allocate mem for amixer resource */
2398c2ecf20Sopenharmony_ci	amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
2408c2ecf20Sopenharmony_ci	if (!amixer)
2418c2ecf20Sopenharmony_ci		return -ENOMEM;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	/* Check whether there are sufficient
2448c2ecf20Sopenharmony_ci	 * amixer resources to meet request. */
2458c2ecf20Sopenharmony_ci	err = 0;
2468c2ecf20Sopenharmony_ci	spin_lock_irqsave(&mgr->mgr_lock, flags);
2478c2ecf20Sopenharmony_ci	for (i = 0; i < desc->msr; i++) {
2488c2ecf20Sopenharmony_ci		err = mgr_get_resource(&mgr->mgr, 1, &idx);
2498c2ecf20Sopenharmony_ci		if (err)
2508c2ecf20Sopenharmony_ci			break;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci		amixer->idx[i] = idx;
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
2558c2ecf20Sopenharmony_ci	if (err) {
2568c2ecf20Sopenharmony_ci		dev_err(mgr->card->dev,
2578c2ecf20Sopenharmony_ci			"Can't meet AMIXER resource request!\n");
2588c2ecf20Sopenharmony_ci		goto error;
2598c2ecf20Sopenharmony_ci	}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	err = amixer_rsc_init(amixer, desc, mgr);
2628c2ecf20Sopenharmony_ci	if (err)
2638c2ecf20Sopenharmony_ci		goto error;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	*ramixer = amixer;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	return 0;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cierror:
2708c2ecf20Sopenharmony_ci	spin_lock_irqsave(&mgr->mgr_lock, flags);
2718c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
2728c2ecf20Sopenharmony_ci		mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
2758c2ecf20Sopenharmony_ci	kfree(amixer);
2768c2ecf20Sopenharmony_ci	return err;
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	unsigned long flags;
2828c2ecf20Sopenharmony_ci	int i;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	spin_lock_irqsave(&mgr->mgr_lock, flags);
2858c2ecf20Sopenharmony_ci	for (i = 0; i < amixer->rsc.msr; i++)
2868c2ecf20Sopenharmony_ci		mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
2898c2ecf20Sopenharmony_ci	amixer_rsc_uninit(amixer);
2908c2ecf20Sopenharmony_ci	kfree(amixer);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	return 0;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ciint amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	int err;
2988c2ecf20Sopenharmony_ci	struct amixer_mgr *amixer_mgr;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	*ramixer_mgr = NULL;
3018c2ecf20Sopenharmony_ci	amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
3028c2ecf20Sopenharmony_ci	if (!amixer_mgr)
3038c2ecf20Sopenharmony_ci		return -ENOMEM;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
3068c2ecf20Sopenharmony_ci	if (err)
3078c2ecf20Sopenharmony_ci		goto error;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	spin_lock_init(&amixer_mgr->mgr_lock);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	amixer_mgr->get_amixer = get_amixer_rsc;
3128c2ecf20Sopenharmony_ci	amixer_mgr->put_amixer = put_amixer_rsc;
3138c2ecf20Sopenharmony_ci	amixer_mgr->card = hw->card;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	*ramixer_mgr = amixer_mgr;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	return 0;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cierror:
3208c2ecf20Sopenharmony_ci	kfree(amixer_mgr);
3218c2ecf20Sopenharmony_ci	return err;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ciint amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	rsc_mgr_uninit(&amixer_mgr->mgr);
3278c2ecf20Sopenharmony_ci	kfree(amixer_mgr);
3288c2ecf20Sopenharmony_ci	return 0;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci/* SUM resource management */
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic void sum_master(struct rsc *rsc)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	rsc->conj = 0;
3368c2ecf20Sopenharmony_ci	rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic void sum_next_conj(struct rsc *rsc)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	rsc->conj++;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic int sum_index(const struct rsc *rsc)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int sum_output_slot(const struct rsc *rsc)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	return (sum_index(rsc) << 4) + 0xc;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic const struct rsc_ops sum_basic_rsc_ops = {
3558c2ecf20Sopenharmony_ci	.master		= sum_master,
3568c2ecf20Sopenharmony_ci	.next_conj	= sum_next_conj,
3578c2ecf20Sopenharmony_ci	.index		= sum_index,
3588c2ecf20Sopenharmony_ci	.output_slot	= sum_output_slot,
3598c2ecf20Sopenharmony_ci};
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic int sum_rsc_init(struct sum *sum,
3628c2ecf20Sopenharmony_ci			const struct sum_desc *desc,
3638c2ecf20Sopenharmony_ci			struct sum_mgr *mgr)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	int err;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw);
3688c2ecf20Sopenharmony_ci	if (err)
3698c2ecf20Sopenharmony_ci		return err;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	sum->rsc.ops = &sum_basic_rsc_ops;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	return 0;
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic int sum_rsc_uninit(struct sum *sum)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	rsc_uninit(&sum->rsc);
3798c2ecf20Sopenharmony_ci	return 0;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic int get_sum_rsc(struct sum_mgr *mgr,
3838c2ecf20Sopenharmony_ci		       const struct sum_desc *desc,
3848c2ecf20Sopenharmony_ci		       struct sum **rsum)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	int err, i;
3878c2ecf20Sopenharmony_ci	unsigned int idx;
3888c2ecf20Sopenharmony_ci	struct sum *sum;
3898c2ecf20Sopenharmony_ci	unsigned long flags;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	*rsum = NULL;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	/* Allocate mem for sum resource */
3948c2ecf20Sopenharmony_ci	sum = kzalloc(sizeof(*sum), GFP_KERNEL);
3958c2ecf20Sopenharmony_ci	if (!sum)
3968c2ecf20Sopenharmony_ci		return -ENOMEM;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	/* Check whether there are sufficient sum resources to meet request. */
3998c2ecf20Sopenharmony_ci	err = 0;
4008c2ecf20Sopenharmony_ci	spin_lock_irqsave(&mgr->mgr_lock, flags);
4018c2ecf20Sopenharmony_ci	for (i = 0; i < desc->msr; i++) {
4028c2ecf20Sopenharmony_ci		err = mgr_get_resource(&mgr->mgr, 1, &idx);
4038c2ecf20Sopenharmony_ci		if (err)
4048c2ecf20Sopenharmony_ci			break;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci		sum->idx[i] = idx;
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
4098c2ecf20Sopenharmony_ci	if (err) {
4108c2ecf20Sopenharmony_ci		dev_err(mgr->card->dev,
4118c2ecf20Sopenharmony_ci			"Can't meet SUM resource request!\n");
4128c2ecf20Sopenharmony_ci		goto error;
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	err = sum_rsc_init(sum, desc, mgr);
4168c2ecf20Sopenharmony_ci	if (err)
4178c2ecf20Sopenharmony_ci		goto error;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	*rsum = sum;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	return 0;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cierror:
4248c2ecf20Sopenharmony_ci	spin_lock_irqsave(&mgr->mgr_lock, flags);
4258c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
4268c2ecf20Sopenharmony_ci		mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
4298c2ecf20Sopenharmony_ci	kfree(sum);
4308c2ecf20Sopenharmony_ci	return err;
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	unsigned long flags;
4368c2ecf20Sopenharmony_ci	int i;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	spin_lock_irqsave(&mgr->mgr_lock, flags);
4398c2ecf20Sopenharmony_ci	for (i = 0; i < sum->rsc.msr; i++)
4408c2ecf20Sopenharmony_ci		mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&mgr->mgr_lock, flags);
4438c2ecf20Sopenharmony_ci	sum_rsc_uninit(sum);
4448c2ecf20Sopenharmony_ci	kfree(sum);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	return 0;
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ciint sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	int err;
4528c2ecf20Sopenharmony_ci	struct sum_mgr *sum_mgr;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	*rsum_mgr = NULL;
4558c2ecf20Sopenharmony_ci	sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
4568c2ecf20Sopenharmony_ci	if (!sum_mgr)
4578c2ecf20Sopenharmony_ci		return -ENOMEM;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
4608c2ecf20Sopenharmony_ci	if (err)
4618c2ecf20Sopenharmony_ci		goto error;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	spin_lock_init(&sum_mgr->mgr_lock);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	sum_mgr->get_sum = get_sum_rsc;
4668c2ecf20Sopenharmony_ci	sum_mgr->put_sum = put_sum_rsc;
4678c2ecf20Sopenharmony_ci	sum_mgr->card = hw->card;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	*rsum_mgr = sum_mgr;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	return 0;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cierror:
4748c2ecf20Sopenharmony_ci	kfree(sum_mgr);
4758c2ecf20Sopenharmony_ci	return err;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ciint sum_mgr_destroy(struct sum_mgr *sum_mgr)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	rsc_mgr_uninit(&sum_mgr->mgr);
4818c2ecf20Sopenharmony_ci	kfree(sum_mgr);
4828c2ecf20Sopenharmony_ci	return 0;
4838c2ecf20Sopenharmony_ci}
4848c2ecf20Sopenharmony_ci
485