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 ctresource.c
68cc72361SWai Yew CHAY *
78cc72361SWai Yew CHAY * @Brief
88cc72361SWai Yew CHAY * This file contains the implementation of some generic helper functions.
98cc72361SWai Yew CHAY *
108cc72361SWai Yew CHAY * @Author Liu Chun
118cc72361SWai Yew CHAY * @Date May 15 2008
128cc72361SWai Yew CHAY */
138cc72361SWai Yew CHAY
148cc72361SWai Yew CHAY #include "ctresource.h"
158cc72361SWai Yew CHAY #include "cthardware.h"
168cc72361SWai Yew CHAY #include <linux/err.h>
178cc72361SWai Yew CHAY #include <linux/slab.h>
188cc72361SWai Yew CHAY
198cc72361SWai Yew CHAY #define AUDIO_SLOT_BLOCK_NUM 256
208cc72361SWai Yew CHAY
218cc72361SWai Yew CHAY /* Resource allocation based on bit-map management mechanism */
228cc72361SWai Yew CHAY static int
get_resource(u8 * rscs,unsigned int amount,unsigned int multi,unsigned int * ridx)238cc72361SWai Yew CHAY get_resource(u8 *rscs, unsigned int amount,
248cc72361SWai Yew CHAY unsigned int multi, unsigned int *ridx)
258cc72361SWai Yew CHAY {
26514eef9cSTakashi Iwai int i, j, k, n;
278cc72361SWai Yew CHAY
288cc72361SWai Yew CHAY /* Check whether there are sufficient resources to meet request. */
298cc72361SWai Yew CHAY for (i = 0, n = multi; i < amount; i++) {
308cc72361SWai Yew CHAY j = i / 8;
318cc72361SWai Yew CHAY k = i % 8;
328cc72361SWai Yew CHAY if (rscs[j] & ((u8)1 << k)) {
338cc72361SWai Yew CHAY n = multi;
348cc72361SWai Yew CHAY continue;
358cc72361SWai Yew CHAY }
368cc72361SWai Yew CHAY if (!(--n))
378cc72361SWai Yew CHAY break; /* found sufficient contiguous resources */
388cc72361SWai Yew CHAY }
398cc72361SWai Yew CHAY
408cc72361SWai Yew CHAY if (i >= amount) {
418cc72361SWai Yew CHAY /* Can not find sufficient contiguous resources */
428cc72361SWai Yew CHAY return -ENOENT;
438cc72361SWai Yew CHAY }
448cc72361SWai Yew CHAY
458cc72361SWai Yew CHAY /* Mark the contiguous bits in resource bit-map as used */
468cc72361SWai Yew CHAY for (n = multi; n > 0; n--) {
478cc72361SWai Yew CHAY j = i / 8;
488cc72361SWai Yew CHAY k = i % 8;
498cc72361SWai Yew CHAY rscs[j] |= ((u8)1 << k);
508cc72361SWai Yew CHAY i--;
518cc72361SWai Yew CHAY }
528cc72361SWai Yew CHAY
538cc72361SWai Yew CHAY *ridx = i + 1;
548cc72361SWai Yew CHAY
558cc72361SWai Yew CHAY return 0;
568cc72361SWai Yew CHAY }
578cc72361SWai Yew CHAY
put_resource(u8 * rscs,unsigned int multi,unsigned int idx)588cc72361SWai Yew CHAY static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx)
598cc72361SWai Yew CHAY {
60514eef9cSTakashi Iwai unsigned int i, j, k, n;
618cc72361SWai Yew CHAY
628cc72361SWai Yew CHAY /* Mark the contiguous bits in resource bit-map as used */
638cc72361SWai Yew CHAY for (n = multi, i = idx; n > 0; n--) {
648cc72361SWai Yew CHAY j = i / 8;
658cc72361SWai Yew CHAY k = i % 8;
668cc72361SWai Yew CHAY rscs[j] &= ~((u8)1 << k);
678cc72361SWai Yew CHAY i++;
688cc72361SWai Yew CHAY }
698cc72361SWai Yew CHAY
708cc72361SWai Yew CHAY return 0;
718cc72361SWai Yew CHAY }
728cc72361SWai Yew CHAY
mgr_get_resource(struct rsc_mgr * mgr,unsigned int n,unsigned int * ridx)738cc72361SWai Yew CHAY int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx)
748cc72361SWai Yew CHAY {
75514eef9cSTakashi Iwai int err;
768cc72361SWai Yew CHAY
778cc72361SWai Yew CHAY if (n > mgr->avail)
788cc72361SWai Yew CHAY return -ENOENT;
798cc72361SWai Yew CHAY
808cc72361SWai Yew CHAY err = get_resource(mgr->rscs, mgr->amount, n, ridx);
818cc72361SWai Yew CHAY if (!err)
828cc72361SWai Yew CHAY mgr->avail -= n;
838cc72361SWai Yew CHAY
848cc72361SWai Yew CHAY return err;
858cc72361SWai Yew CHAY }
868cc72361SWai Yew CHAY
mgr_put_resource(struct rsc_mgr * mgr,unsigned int n,unsigned int idx)878cc72361SWai Yew CHAY int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx)
888cc72361SWai Yew CHAY {
898cc72361SWai Yew CHAY put_resource(mgr->rscs, n, idx);
908cc72361SWai Yew CHAY mgr->avail += n;
918cc72361SWai Yew CHAY
928cc72361SWai Yew CHAY return 0;
938cc72361SWai Yew CHAY }
948cc72361SWai Yew CHAY
956e0e75d9STakashi Iwai static const unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = {
968cc72361SWai Yew CHAY /* SRC channel is at Audio Ring slot 1 every 16 slots. */
978cc72361SWai Yew CHAY [SRC] = 0x1,
988cc72361SWai Yew CHAY [AMIXER] = 0x4,
998cc72361SWai Yew CHAY [SUM] = 0xc,
1008cc72361SWai Yew CHAY };
1018cc72361SWai Yew CHAY
rsc_index(const struct rsc * rsc)1028cc72361SWai Yew CHAY static int rsc_index(const struct rsc *rsc)
1038cc72361SWai Yew CHAY {
1048cc72361SWai Yew CHAY return rsc->conj;
1058cc72361SWai Yew CHAY }
1068cc72361SWai Yew CHAY
audio_ring_slot(const struct rsc * rsc)1078cc72361SWai Yew CHAY static int audio_ring_slot(const struct rsc *rsc)
1088cc72361SWai Yew CHAY {
1098cc72361SWai Yew CHAY return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type];
1108cc72361SWai Yew CHAY }
1118cc72361SWai Yew CHAY
rsc_next_conj(struct rsc * rsc)112*76c47183STakashi Iwai static void rsc_next_conj(struct rsc *rsc)
1138cc72361SWai Yew CHAY {
1148cc72361SWai Yew CHAY unsigned int i;
1158cc72361SWai Yew CHAY for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); )
1168cc72361SWai Yew CHAY i++;
1178cc72361SWai Yew CHAY rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i);
1188cc72361SWai Yew CHAY }
1198cc72361SWai Yew CHAY
rsc_master(struct rsc * rsc)120*76c47183STakashi Iwai static void rsc_master(struct rsc *rsc)
1218cc72361SWai Yew CHAY {
122*76c47183STakashi Iwai rsc->conj = rsc->idx;
1238cc72361SWai Yew CHAY }
1248cc72361SWai Yew CHAY
12543f2cdebSJulia Lawall static const struct rsc_ops rsc_generic_ops = {
1268cc72361SWai Yew CHAY .index = rsc_index,
1278cc72361SWai Yew CHAY .output_slot = audio_ring_slot,
1288cc72361SWai Yew CHAY .master = rsc_master,
1298cc72361SWai Yew CHAY .next_conj = rsc_next_conj,
1308cc72361SWai Yew CHAY };
1318cc72361SWai Yew CHAY
13266640898SSudip Mukherjee int
rsc_init(struct rsc * rsc,u32 idx,enum RSCTYP type,u32 msr,struct hw * hw)13366640898SSudip Mukherjee rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw)
1348cc72361SWai Yew CHAY {
1358cc72361SWai Yew CHAY int err = 0;
1368cc72361SWai Yew CHAY
1378cc72361SWai Yew CHAY rsc->idx = idx;
1388cc72361SWai Yew CHAY rsc->conj = idx;
1398cc72361SWai Yew CHAY rsc->type = type;
1408cc72361SWai Yew CHAY rsc->msr = msr;
1418cc72361SWai Yew CHAY rsc->hw = hw;
1428cc72361SWai Yew CHAY rsc->ops = &rsc_generic_ops;
14335ebf6e7STakashi Iwai if (!hw) {
1448cc72361SWai Yew CHAY rsc->ctrl_blk = NULL;
1458cc72361SWai Yew CHAY return 0;
1468cc72361SWai Yew CHAY }
1478cc72361SWai Yew CHAY
1488cc72361SWai Yew CHAY switch (type) {
1498cc72361SWai Yew CHAY case SRC:
150b6bfe86fSSudip Mukherjee err = hw->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);
1518cc72361SWai Yew CHAY break;
1528cc72361SWai Yew CHAY case AMIXER:
153b6bfe86fSSudip Mukherjee err = hw->amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);
1548cc72361SWai Yew CHAY break;
1558cc72361SWai Yew CHAY case SRCIMP:
1568cc72361SWai Yew CHAY case SUM:
1578cc72361SWai Yew CHAY case DAIO:
1588cc72361SWai Yew CHAY break;
1598cc72361SWai Yew CHAY default:
1600cae90a9SSudip Mukherjee dev_err(((struct hw *)hw)->card->dev,
1610cae90a9SSudip Mukherjee "Invalid resource type value %d!\n", type);
1628cc72361SWai Yew CHAY return -EINVAL;
1638cc72361SWai Yew CHAY }
1648cc72361SWai Yew CHAY
1658cc72361SWai Yew CHAY if (err) {
1660cae90a9SSudip Mukherjee dev_err(((struct hw *)hw)->card->dev,
1670cae90a9SSudip Mukherjee "Failed to get resource control block!\n");
1688cc72361SWai Yew CHAY return err;
1698cc72361SWai Yew CHAY }
1708cc72361SWai Yew CHAY
1718cc72361SWai Yew CHAY return 0;
1728cc72361SWai Yew CHAY }
1738cc72361SWai Yew CHAY
rsc_uninit(struct rsc * rsc)1748cc72361SWai Yew CHAY int rsc_uninit(struct rsc *rsc)
1758cc72361SWai Yew CHAY {
1768cc72361SWai Yew CHAY if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) {
1778cc72361SWai Yew CHAY switch (rsc->type) {
1788cc72361SWai Yew CHAY case SRC:
179b6bfe86fSSudip Mukherjee rsc->hw->src_rsc_put_ctrl_blk(rsc->ctrl_blk);
1808cc72361SWai Yew CHAY break;
1818cc72361SWai Yew CHAY case AMIXER:
182b6bfe86fSSudip Mukherjee rsc->hw->amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);
1838cc72361SWai Yew CHAY break;
1848cc72361SWai Yew CHAY case SUM:
1858cc72361SWai Yew CHAY case DAIO:
1868cc72361SWai Yew CHAY break;
1878cc72361SWai Yew CHAY default:
1880cae90a9SSudip Mukherjee dev_err(((struct hw *)rsc->hw)->card->dev,
1890cae90a9SSudip Mukherjee "Invalid resource type value %d!\n",
19062afa853SSudip Mukherjee rsc->type);
1918cc72361SWai Yew CHAY break;
1928cc72361SWai Yew CHAY }
1938cc72361SWai Yew CHAY
1948cc72361SWai Yew CHAY rsc->hw = rsc->ctrl_blk = NULL;
1958cc72361SWai Yew CHAY }
1968cc72361SWai Yew CHAY
1978cc72361SWai Yew CHAY rsc->idx = rsc->conj = 0;
1988cc72361SWai Yew CHAY rsc->type = NUM_RSCTYP;
1998cc72361SWai Yew CHAY rsc->msr = 0;
2008cc72361SWai Yew CHAY
2018cc72361SWai Yew CHAY return 0;
2028cc72361SWai Yew CHAY }
2038cc72361SWai Yew CHAY
rsc_mgr_init(struct rsc_mgr * mgr,enum RSCTYP type,unsigned int amount,struct hw * hw)2048cc72361SWai Yew CHAY int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
205b6bfe86fSSudip Mukherjee unsigned int amount, struct hw *hw)
2068cc72361SWai Yew CHAY {
2078cc72361SWai Yew CHAY int err = 0;
2088cc72361SWai Yew CHAY
2098cc72361SWai Yew CHAY mgr->type = NUM_RSCTYP;
2108cc72361SWai Yew CHAY
2117ca4282aSLars-Peter Clausen mgr->rscs = kzalloc(DIV_ROUND_UP(amount, 8), GFP_KERNEL);
21235ebf6e7STakashi Iwai if (!mgr->rscs)
2138cc72361SWai Yew CHAY return -ENOMEM;
2148cc72361SWai Yew CHAY
2158cc72361SWai Yew CHAY switch (type) {
2168cc72361SWai Yew CHAY case SRC:
2178cc72361SWai Yew CHAY err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk);
2188cc72361SWai Yew CHAY break;
2198cc72361SWai Yew CHAY case SRCIMP:
2208cc72361SWai Yew CHAY err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk);
2218cc72361SWai Yew CHAY break;
2228cc72361SWai Yew CHAY case AMIXER:
2238cc72361SWai Yew CHAY err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk);
2248cc72361SWai Yew CHAY break;
2258cc72361SWai Yew CHAY case DAIO:
2268cc72361SWai Yew CHAY err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk);
2278cc72361SWai Yew CHAY break;
2288cc72361SWai Yew CHAY case SUM:
2298cc72361SWai Yew CHAY break;
2308cc72361SWai Yew CHAY default:
2310cae90a9SSudip Mukherjee dev_err(hw->card->dev,
2320cae90a9SSudip Mukherjee "Invalid resource type value %d!\n", type);
2338cc72361SWai Yew CHAY err = -EINVAL;
2348cc72361SWai Yew CHAY goto error;
2358cc72361SWai Yew CHAY }
2368cc72361SWai Yew CHAY
2378cc72361SWai Yew CHAY if (err) {
2380cae90a9SSudip Mukherjee dev_err(hw->card->dev,
2390cae90a9SSudip Mukherjee "Failed to get manager control block!\n");
2408cc72361SWai Yew CHAY goto error;
2418cc72361SWai Yew CHAY }
2428cc72361SWai Yew CHAY
2438cc72361SWai Yew CHAY mgr->type = type;
2448cc72361SWai Yew CHAY mgr->avail = mgr->amount = amount;
2458cc72361SWai Yew CHAY mgr->hw = hw;
2468cc72361SWai Yew CHAY
2478cc72361SWai Yew CHAY return 0;
2488cc72361SWai Yew CHAY
2498cc72361SWai Yew CHAY error:
2508cc72361SWai Yew CHAY kfree(mgr->rscs);
2518cc72361SWai Yew CHAY return err;
2528cc72361SWai Yew CHAY }
2538cc72361SWai Yew CHAY
rsc_mgr_uninit(struct rsc_mgr * mgr)2548cc72361SWai Yew CHAY int rsc_mgr_uninit(struct rsc_mgr *mgr)
2558cc72361SWai Yew CHAY {
2568cc72361SWai Yew CHAY kfree(mgr->rscs);
2578cc72361SWai Yew CHAY mgr->rscs = NULL;
2588cc72361SWai Yew CHAY
2598cc72361SWai Yew CHAY if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) {
2608cc72361SWai Yew CHAY switch (mgr->type) {
2618cc72361SWai Yew CHAY case SRC:
262b6bfe86fSSudip Mukherjee mgr->hw->src_mgr_put_ctrl_blk(mgr->ctrl_blk);
2638cc72361SWai Yew CHAY break;
2648cc72361SWai Yew CHAY case SRCIMP:
265b6bfe86fSSudip Mukherjee mgr->hw->srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);
2668cc72361SWai Yew CHAY break;
2678cc72361SWai Yew CHAY case AMIXER:
268b6bfe86fSSudip Mukherjee mgr->hw->amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);
2698cc72361SWai Yew CHAY break;
2708cc72361SWai Yew CHAY case DAIO:
271b6bfe86fSSudip Mukherjee mgr->hw->daio_mgr_put_ctrl_blk(mgr->ctrl_blk);
2728cc72361SWai Yew CHAY break;
2738cc72361SWai Yew CHAY case SUM:
2748cc72361SWai Yew CHAY break;
2758cc72361SWai Yew CHAY default:
2760cae90a9SSudip Mukherjee dev_err(((struct hw *)mgr->hw)->card->dev,
2770cae90a9SSudip Mukherjee "Invalid resource type value %d!\n",
27862afa853SSudip Mukherjee mgr->type);
2798cc72361SWai Yew CHAY break;
2808cc72361SWai Yew CHAY }
2818cc72361SWai Yew CHAY
2828cc72361SWai Yew CHAY mgr->hw = mgr->ctrl_blk = NULL;
2838cc72361SWai Yew CHAY }
2848cc72361SWai Yew CHAY
2858cc72361SWai Yew CHAY mgr->type = NUM_RSCTYP;
2868cc72361SWai Yew CHAY mgr->avail = mgr->amount = 0;
2878cc72361SWai Yew CHAY
2888cc72361SWai Yew CHAY return 0;
2898cc72361SWai Yew CHAY }
290