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