162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * @File ctamixer.c 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * @Brief 862306a36Sopenharmony_ci * This file contains the implementation of the Audio Mixer 962306a36Sopenharmony_ci * resource management object. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * @Author Liu Chun 1262306a36Sopenharmony_ci * @Date May 21 2008 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "ctamixer.h" 1662306a36Sopenharmony_ci#include "cthardware.h" 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define AMIXER_RESOURCE_NUM 256 2062306a36Sopenharmony_ci#define SUM_RESOURCE_NUM 256 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define AMIXER_Y_IMMEDIATE 1 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define BLANK_SLOT 4094 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic void amixer_master(struct rsc *rsc) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci rsc->conj = 0; 2962306a36Sopenharmony_ci rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0]; 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic void amixer_next_conj(struct rsc *rsc) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci rsc->conj++; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic int amixer_index(const struct rsc *rsc) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic int amixer_output_slot(const struct rsc *rsc) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci return (amixer_index(rsc) << 4) + 0x4; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic const struct rsc_ops amixer_basic_rsc_ops = { 4862306a36Sopenharmony_ci .master = amixer_master, 4962306a36Sopenharmony_ci .next_conj = amixer_next_conj, 5062306a36Sopenharmony_ci .index = amixer_index, 5162306a36Sopenharmony_ci .output_slot = amixer_output_slot, 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic int amixer_set_input(struct amixer *amixer, struct rsc *rsc) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct hw *hw; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci hw = amixer->rsc.hw; 5962306a36Sopenharmony_ci hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE); 6062306a36Sopenharmony_ci amixer->input = rsc; 6162306a36Sopenharmony_ci if (!rsc) 6262306a36Sopenharmony_ci hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT); 6362306a36Sopenharmony_ci else 6462306a36Sopenharmony_ci hw->amixer_set_x(amixer->rsc.ctrl_blk, 6562306a36Sopenharmony_ci rsc->ops->output_slot(rsc)); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return 0; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* y is a 14-bit immediate constant */ 7162306a36Sopenharmony_cistatic int amixer_set_y(struct amixer *amixer, unsigned int y) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct hw *hw; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci hw = amixer->rsc.hw; 7662306a36Sopenharmony_ci hw->amixer_set_y(amixer->rsc.ctrl_blk, y); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return 0; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct hw *hw; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci hw = amixer->rsc.hw; 8662306a36Sopenharmony_ci hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int amixer_set_sum(struct amixer *amixer, struct sum *sum) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct hw *hw; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci hw = amixer->rsc.hw; 9662306a36Sopenharmony_ci amixer->sum = sum; 9762306a36Sopenharmony_ci if (!sum) { 9862306a36Sopenharmony_ci hw->amixer_set_se(amixer->rsc.ctrl_blk, 0); 9962306a36Sopenharmony_ci } else { 10062306a36Sopenharmony_ci hw->amixer_set_se(amixer->rsc.ctrl_blk, 1); 10162306a36Sopenharmony_ci hw->amixer_set_sadr(amixer->rsc.ctrl_blk, 10262306a36Sopenharmony_ci sum->rsc.ops->index(&sum->rsc)); 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int amixer_commit_write(struct amixer *amixer) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct hw *hw; 11162306a36Sopenharmony_ci unsigned int index; 11262306a36Sopenharmony_ci int i; 11362306a36Sopenharmony_ci struct rsc *input; 11462306a36Sopenharmony_ci struct sum *sum; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci hw = amixer->rsc.hw; 11762306a36Sopenharmony_ci input = amixer->input; 11862306a36Sopenharmony_ci sum = amixer->sum; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* Program master and conjugate resources */ 12162306a36Sopenharmony_ci amixer->rsc.ops->master(&amixer->rsc); 12262306a36Sopenharmony_ci if (input) 12362306a36Sopenharmony_ci input->ops->master(input); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (sum) 12662306a36Sopenharmony_ci sum->rsc.ops->master(&sum->rsc); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci for (i = 0; i < amixer->rsc.msr; i++) { 12962306a36Sopenharmony_ci hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk); 13062306a36Sopenharmony_ci if (input) { 13162306a36Sopenharmony_ci hw->amixer_set_x(amixer->rsc.ctrl_blk, 13262306a36Sopenharmony_ci input->ops->output_slot(input)); 13362306a36Sopenharmony_ci input->ops->next_conj(input); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci if (sum) { 13662306a36Sopenharmony_ci hw->amixer_set_sadr(amixer->rsc.ctrl_blk, 13762306a36Sopenharmony_ci sum->rsc.ops->index(&sum->rsc)); 13862306a36Sopenharmony_ci sum->rsc.ops->next_conj(&sum->rsc); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci index = amixer->rsc.ops->output_slot(&amixer->rsc); 14162306a36Sopenharmony_ci hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); 14262306a36Sopenharmony_ci amixer->rsc.ops->next_conj(&amixer->rsc); 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci amixer->rsc.ops->master(&amixer->rsc); 14562306a36Sopenharmony_ci if (input) 14662306a36Sopenharmony_ci input->ops->master(input); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (sum) 14962306a36Sopenharmony_ci sum->rsc.ops->master(&sum->rsc); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int amixer_commit_raw_write(struct amixer *amixer) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct hw *hw; 15762306a36Sopenharmony_ci unsigned int index; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci hw = amixer->rsc.hw; 16062306a36Sopenharmony_ci index = amixer->rsc.ops->output_slot(&amixer->rsc); 16162306a36Sopenharmony_ci hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int amixer_get_y(struct amixer *amixer) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct hw *hw; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci hw = amixer->rsc.hw; 17162306a36Sopenharmony_ci return hw->amixer_get_y(amixer->rsc.ctrl_blk); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int amixer_setup(struct amixer *amixer, struct rsc *input, 17562306a36Sopenharmony_ci unsigned int scale, struct sum *sum) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci amixer_set_input(amixer, input); 17862306a36Sopenharmony_ci amixer_set_y(amixer, scale); 17962306a36Sopenharmony_ci amixer_set_sum(amixer, sum); 18062306a36Sopenharmony_ci amixer_commit_write(amixer); 18162306a36Sopenharmony_ci return 0; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic const struct amixer_rsc_ops amixer_ops = { 18562306a36Sopenharmony_ci .set_input = amixer_set_input, 18662306a36Sopenharmony_ci .set_invalid_squash = amixer_set_invalid_squash, 18762306a36Sopenharmony_ci .set_scale = amixer_set_y, 18862306a36Sopenharmony_ci .set_sum = amixer_set_sum, 18962306a36Sopenharmony_ci .commit_write = amixer_commit_write, 19062306a36Sopenharmony_ci .commit_raw_write = amixer_commit_raw_write, 19162306a36Sopenharmony_ci .setup = amixer_setup, 19262306a36Sopenharmony_ci .get_scale = amixer_get_y, 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic int amixer_rsc_init(struct amixer *amixer, 19662306a36Sopenharmony_ci const struct amixer_desc *desc, 19762306a36Sopenharmony_ci struct amixer_mgr *mgr) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci int err; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci err = rsc_init(&amixer->rsc, amixer->idx[0], 20262306a36Sopenharmony_ci AMIXER, desc->msr, mgr->mgr.hw); 20362306a36Sopenharmony_ci if (err) 20462306a36Sopenharmony_ci return err; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* Set amixer specific operations */ 20762306a36Sopenharmony_ci amixer->rsc.ops = &amixer_basic_rsc_ops; 20862306a36Sopenharmony_ci amixer->ops = &amixer_ops; 20962306a36Sopenharmony_ci amixer->input = NULL; 21062306a36Sopenharmony_ci amixer->sum = NULL; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci amixer_setup(amixer, NULL, 0, NULL); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic int amixer_rsc_uninit(struct amixer *amixer) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci amixer_setup(amixer, NULL, 0, NULL); 22062306a36Sopenharmony_ci rsc_uninit(&amixer->rsc); 22162306a36Sopenharmony_ci amixer->ops = NULL; 22262306a36Sopenharmony_ci amixer->input = NULL; 22362306a36Sopenharmony_ci amixer->sum = NULL; 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic int get_amixer_rsc(struct amixer_mgr *mgr, 22862306a36Sopenharmony_ci const struct amixer_desc *desc, 22962306a36Sopenharmony_ci struct amixer **ramixer) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci int err, i; 23262306a36Sopenharmony_ci unsigned int idx; 23362306a36Sopenharmony_ci struct amixer *amixer; 23462306a36Sopenharmony_ci unsigned long flags; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci *ramixer = NULL; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Allocate mem for amixer resource */ 23962306a36Sopenharmony_ci amixer = kzalloc(sizeof(*amixer), GFP_KERNEL); 24062306a36Sopenharmony_ci if (!amixer) 24162306a36Sopenharmony_ci return -ENOMEM; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* Check whether there are sufficient 24462306a36Sopenharmony_ci * amixer resources to meet request. */ 24562306a36Sopenharmony_ci err = 0; 24662306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 24762306a36Sopenharmony_ci for (i = 0; i < desc->msr; i++) { 24862306a36Sopenharmony_ci err = mgr_get_resource(&mgr->mgr, 1, &idx); 24962306a36Sopenharmony_ci if (err) 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci amixer->idx[i] = idx; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 25562306a36Sopenharmony_ci if (err) { 25662306a36Sopenharmony_ci dev_err(mgr->card->dev, 25762306a36Sopenharmony_ci "Can't meet AMIXER resource request!\n"); 25862306a36Sopenharmony_ci goto error; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci err = amixer_rsc_init(amixer, desc, mgr); 26262306a36Sopenharmony_ci if (err) 26362306a36Sopenharmony_ci goto error; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci *ramixer = amixer; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cierror: 27062306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 27162306a36Sopenharmony_ci for (i--; i >= 0; i--) 27262306a36Sopenharmony_ci mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 27562306a36Sopenharmony_ci kfree(amixer); 27662306a36Sopenharmony_ci return err; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci unsigned long flags; 28262306a36Sopenharmony_ci int i; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 28562306a36Sopenharmony_ci for (i = 0; i < amixer->rsc.msr; i++) 28662306a36Sopenharmony_ci mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 28962306a36Sopenharmony_ci amixer_rsc_uninit(amixer); 29062306a36Sopenharmony_ci kfree(amixer); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ciint amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci int err; 29862306a36Sopenharmony_ci struct amixer_mgr *amixer_mgr; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci *ramixer_mgr = NULL; 30162306a36Sopenharmony_ci amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL); 30262306a36Sopenharmony_ci if (!amixer_mgr) 30362306a36Sopenharmony_ci return -ENOMEM; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw); 30662306a36Sopenharmony_ci if (err) 30762306a36Sopenharmony_ci goto error; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci spin_lock_init(&amixer_mgr->mgr_lock); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci amixer_mgr->get_amixer = get_amixer_rsc; 31262306a36Sopenharmony_ci amixer_mgr->put_amixer = put_amixer_rsc; 31362306a36Sopenharmony_ci amixer_mgr->card = hw->card; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci *ramixer_mgr = amixer_mgr; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cierror: 32062306a36Sopenharmony_ci kfree(amixer_mgr); 32162306a36Sopenharmony_ci return err; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ciint amixer_mgr_destroy(struct amixer_mgr *amixer_mgr) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci rsc_mgr_uninit(&amixer_mgr->mgr); 32762306a36Sopenharmony_ci kfree(amixer_mgr); 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/* SUM resource management */ 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic void sum_master(struct rsc *rsc) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci rsc->conj = 0; 33662306a36Sopenharmony_ci rsc->idx = container_of(rsc, struct sum, rsc)->idx[0]; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic void sum_next_conj(struct rsc *rsc) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci rsc->conj++; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int sum_index(const struct rsc *rsc) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int sum_output_slot(const struct rsc *rsc) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci return (sum_index(rsc) << 4) + 0xc; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic const struct rsc_ops sum_basic_rsc_ops = { 35562306a36Sopenharmony_ci .master = sum_master, 35662306a36Sopenharmony_ci .next_conj = sum_next_conj, 35762306a36Sopenharmony_ci .index = sum_index, 35862306a36Sopenharmony_ci .output_slot = sum_output_slot, 35962306a36Sopenharmony_ci}; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int sum_rsc_init(struct sum *sum, 36262306a36Sopenharmony_ci const struct sum_desc *desc, 36362306a36Sopenharmony_ci struct sum_mgr *mgr) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci int err; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw); 36862306a36Sopenharmony_ci if (err) 36962306a36Sopenharmony_ci return err; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci sum->rsc.ops = &sum_basic_rsc_ops; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci return 0; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic int sum_rsc_uninit(struct sum *sum) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci rsc_uninit(&sum->rsc); 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int get_sum_rsc(struct sum_mgr *mgr, 38362306a36Sopenharmony_ci const struct sum_desc *desc, 38462306a36Sopenharmony_ci struct sum **rsum) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci int err, i; 38762306a36Sopenharmony_ci unsigned int idx; 38862306a36Sopenharmony_ci struct sum *sum; 38962306a36Sopenharmony_ci unsigned long flags; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci *rsum = NULL; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* Allocate mem for sum resource */ 39462306a36Sopenharmony_ci sum = kzalloc(sizeof(*sum), GFP_KERNEL); 39562306a36Sopenharmony_ci if (!sum) 39662306a36Sopenharmony_ci return -ENOMEM; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* Check whether there are sufficient sum resources to meet request. */ 39962306a36Sopenharmony_ci err = 0; 40062306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 40162306a36Sopenharmony_ci for (i = 0; i < desc->msr; i++) { 40262306a36Sopenharmony_ci err = mgr_get_resource(&mgr->mgr, 1, &idx); 40362306a36Sopenharmony_ci if (err) 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci sum->idx[i] = idx; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 40962306a36Sopenharmony_ci if (err) { 41062306a36Sopenharmony_ci dev_err(mgr->card->dev, 41162306a36Sopenharmony_ci "Can't meet SUM resource request!\n"); 41262306a36Sopenharmony_ci goto error; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci err = sum_rsc_init(sum, desc, mgr); 41662306a36Sopenharmony_ci if (err) 41762306a36Sopenharmony_ci goto error; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci *rsum = sum; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cierror: 42462306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 42562306a36Sopenharmony_ci for (i--; i >= 0; i--) 42662306a36Sopenharmony_ci mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 42962306a36Sopenharmony_ci kfree(sum); 43062306a36Sopenharmony_ci return err; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci unsigned long flags; 43662306a36Sopenharmony_ci int i; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci spin_lock_irqsave(&mgr->mgr_lock, flags); 43962306a36Sopenharmony_ci for (i = 0; i < sum->rsc.msr; i++) 44062306a36Sopenharmony_ci mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci spin_unlock_irqrestore(&mgr->mgr_lock, flags); 44362306a36Sopenharmony_ci sum_rsc_uninit(sum); 44462306a36Sopenharmony_ci kfree(sum); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci return 0; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ciint sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci int err; 45262306a36Sopenharmony_ci struct sum_mgr *sum_mgr; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci *rsum_mgr = NULL; 45562306a36Sopenharmony_ci sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL); 45662306a36Sopenharmony_ci if (!sum_mgr) 45762306a36Sopenharmony_ci return -ENOMEM; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw); 46062306a36Sopenharmony_ci if (err) 46162306a36Sopenharmony_ci goto error; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci spin_lock_init(&sum_mgr->mgr_lock); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci sum_mgr->get_sum = get_sum_rsc; 46662306a36Sopenharmony_ci sum_mgr->put_sum = put_sum_rsc; 46762306a36Sopenharmony_ci sum_mgr->card = hw->card; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci *rsum_mgr = sum_mgr; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci return 0; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cierror: 47462306a36Sopenharmony_ci kfree(sum_mgr); 47562306a36Sopenharmony_ci return err; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ciint sum_mgr_destroy(struct sum_mgr *sum_mgr) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci rsc_mgr_uninit(&sum_mgr->mgr); 48162306a36Sopenharmony_ci kfree(sum_mgr); 48262306a36Sopenharmony_ci return 0; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 485