757 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.4 *5 * @File ctdaio.c6 *7 * @Brief8 * This file contains the implementation of Digital Audio Input Output9 * resource management object.10 *11 * @Author Liu Chun12 * @Date May 23 200813 */14 15#include "ctdaio.h"16#include "cthardware.h"17#include "ctimap.h"18#include <linux/slab.h>19#include <linux/kernel.h>20 21#define DAIO_OUT_MAX SPDIFOO22 23struct daio_usage {24 unsigned short data;25};26 27struct daio_rsc_idx {28 unsigned short left;29 unsigned short right;30};31 32static const struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = {33 [LINEO1] = {.left = 0x00, .right = 0x01},34 [LINEO2] = {.left = 0x18, .right = 0x19},35 [LINEO3] = {.left = 0x08, .right = 0x09},36 [LINEO4] = {.left = 0x10, .right = 0x11},37 [LINEIM] = {.left = 0x1b5, .right = 0x1bd},38 [SPDIFOO] = {.left = 0x20, .right = 0x21},39 [SPDIFIO] = {.left = 0x15, .right = 0x1d},40 [SPDIFI1] = {.left = 0x95, .right = 0x9d},41};42 43static const struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {44 [LINEO1] = {.left = 0x40, .right = 0x41},45 [LINEO2] = {.left = 0x60, .right = 0x61},46 [LINEO3] = {.left = 0x50, .right = 0x51},47 [LINEO4] = {.left = 0x70, .right = 0x71},48 [LINEIM] = {.left = 0x45, .right = 0xc5},49 [MIC] = {.left = 0x55, .right = 0xd5},50 [SPDIFOO] = {.left = 0x00, .right = 0x01},51 [SPDIFIO] = {.left = 0x05, .right = 0x85},52};53 54static void daio_master(struct rsc *rsc)55{56 /* Actually, this is not the resource index of DAIO.57 * For DAO, it is the input mapper index. And, for DAI,58 * it is the output time-slot index. */59 rsc->conj = rsc->idx;60}61 62static int daio_index(const struct rsc *rsc)63{64 return rsc->conj;65}66 67static void daio_out_next_conj(struct rsc *rsc)68{69 rsc->conj += 2;70}71 72static void daio_in_next_conj_20k1(struct rsc *rsc)73{74 rsc->conj += 0x200;75}76 77static void daio_in_next_conj_20k2(struct rsc *rsc)78{79 rsc->conj += 0x100;80}81 82static const struct rsc_ops daio_out_rsc_ops = {83 .master = daio_master,84 .next_conj = daio_out_next_conj,85 .index = daio_index,86 .output_slot = NULL,87};88 89static const struct rsc_ops daio_in_rsc_ops_20k1 = {90 .master = daio_master,91 .next_conj = daio_in_next_conj_20k1,92 .index = NULL,93 .output_slot = daio_index,94};95 96static const struct rsc_ops daio_in_rsc_ops_20k2 = {97 .master = daio_master,98 .next_conj = daio_in_next_conj_20k2,99 .index = NULL,100 .output_slot = daio_index,101};102 103static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)104{105 switch (hw->chip_type) {106 case ATC20K1:107 switch (type) {108 case SPDIFOO: return 0;109 case SPDIFIO: return 0;110 case SPDIFI1: return 1;111 case LINEO1: return 4;112 case LINEO2: return 7;113 case LINEO3: return 5;114 case LINEO4: return 6;115 case LINEIM: return 7;116 default: return -EINVAL;117 }118 case ATC20K2:119 switch (type) {120 case SPDIFOO: return 0;121 case SPDIFIO: return 0;122 case LINEO1: return 4;123 case LINEO2: return 7;124 case LINEO3: return 5;125 case LINEO4: return 6;126 case LINEIM: return 4;127 case MIC: return 5;128 default: return -EINVAL;129 }130 default:131 return -EINVAL;132 }133}134 135static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc);136 137static int dao_spdif_get_spos(struct dao *dao, unsigned int *spos)138{139 dao->hw->dao_get_spos(dao->ctrl_blk, spos);140 return 0;141}142 143static int dao_spdif_set_spos(struct dao *dao, unsigned int spos)144{145 dao->hw->dao_set_spos(dao->ctrl_blk, spos);146 return 0;147}148 149static int dao_commit_write(struct dao *dao)150{151 dao->hw->dao_commit_write(dao->hw,152 daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk);153 return 0;154}155 156static int dao_set_left_input(struct dao *dao, struct rsc *input)157{158 struct imapper *entry;159 struct daio *daio = &dao->daio;160 int i;161 162 entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL);163 if (!entry)164 return -ENOMEM;165 166 dao->ops->clear_left_input(dao);167 /* Program master and conjugate resources */168 input->ops->master(input);169 daio->rscl.ops->master(&daio->rscl);170 for (i = 0; i < daio->rscl.msr; i++, entry++) {171 entry->slot = input->ops->output_slot(input);172 entry->user = entry->addr = daio->rscl.ops->index(&daio->rscl);173 dao->mgr->imap_add(dao->mgr, entry);174 dao->imappers[i] = entry;175 176 input->ops->next_conj(input);177 daio->rscl.ops->next_conj(&daio->rscl);178 }179 input->ops->master(input);180 daio->rscl.ops->master(&daio->rscl);181 182 return 0;183}184 185static int dao_set_right_input(struct dao *dao, struct rsc *input)186{187 struct imapper *entry;188 struct daio *daio = &dao->daio;189 int i;190 191 entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL);192 if (!entry)193 return -ENOMEM;194 195 dao->ops->clear_right_input(dao);196 /* Program master and conjugate resources */197 input->ops->master(input);198 daio->rscr.ops->master(&daio->rscr);199 for (i = 0; i < daio->rscr.msr; i++, entry++) {200 entry->slot = input->ops->output_slot(input);201 entry->user = entry->addr = daio->rscr.ops->index(&daio->rscr);202 dao->mgr->imap_add(dao->mgr, entry);203 dao->imappers[daio->rscl.msr + i] = entry;204 205 input->ops->next_conj(input);206 daio->rscr.ops->next_conj(&daio->rscr);207 }208 input->ops->master(input);209 daio->rscr.ops->master(&daio->rscr);210 211 return 0;212}213 214static int dao_clear_left_input(struct dao *dao)215{216 struct imapper *entry;217 struct daio *daio = &dao->daio;218 int i;219 220 if (!dao->imappers[0])221 return 0;222 223 entry = dao->imappers[0];224 dao->mgr->imap_delete(dao->mgr, entry);225 /* Program conjugate resources */226 for (i = 1; i < daio->rscl.msr; i++) {227 entry = dao->imappers[i];228 dao->mgr->imap_delete(dao->mgr, entry);229 dao->imappers[i] = NULL;230 }231 232 kfree(dao->imappers[0]);233 dao->imappers[0] = NULL;234 235 return 0;236}237 238static int dao_clear_right_input(struct dao *dao)239{240 struct imapper *entry;241 struct daio *daio = &dao->daio;242 int i;243 244 if (!dao->imappers[daio->rscl.msr])245 return 0;246 247 entry = dao->imappers[daio->rscl.msr];248 dao->mgr->imap_delete(dao->mgr, entry);249 /* Program conjugate resources */250 for (i = 1; i < daio->rscr.msr; i++) {251 entry = dao->imappers[daio->rscl.msr + i];252 dao->mgr->imap_delete(dao->mgr, entry);253 dao->imappers[daio->rscl.msr + i] = NULL;254 }255 256 kfree(dao->imappers[daio->rscl.msr]);257 dao->imappers[daio->rscl.msr] = NULL;258 259 return 0;260}261 262static const struct dao_rsc_ops dao_ops = {263 .set_spos = dao_spdif_set_spos,264 .commit_write = dao_commit_write,265 .get_spos = dao_spdif_get_spos,266 .reinit = dao_rsc_reinit,267 .set_left_input = dao_set_left_input,268 .set_right_input = dao_set_right_input,269 .clear_left_input = dao_clear_left_input,270 .clear_right_input = dao_clear_right_input,271};272 273static int dai_set_srt_srcl(struct dai *dai, struct rsc *src)274{275 src->ops->master(src);276 dai->hw->dai_srt_set_srcm(dai->ctrl_blk, src->ops->index(src));277 return 0;278}279 280static int dai_set_srt_srcr(struct dai *dai, struct rsc *src)281{282 src->ops->master(src);283 dai->hw->dai_srt_set_srco(dai->ctrl_blk, src->ops->index(src));284 return 0;285}286 287static int dai_set_srt_msr(struct dai *dai, unsigned int msr)288{289 unsigned int rsr;290 291 for (rsr = 0; msr > 1; msr >>= 1)292 rsr++;293 294 dai->hw->dai_srt_set_rsr(dai->ctrl_blk, rsr);295 return 0;296}297 298static int dai_set_enb_src(struct dai *dai, unsigned int enb)299{300 dai->hw->dai_srt_set_ec(dai->ctrl_blk, enb);301 return 0;302}303 304static int dai_set_enb_srt(struct dai *dai, unsigned int enb)305{306 dai->hw->dai_srt_set_et(dai->ctrl_blk, enb);307 return 0;308}309 310static int dai_commit_write(struct dai *dai)311{312 dai->hw->dai_commit_write(dai->hw,313 daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);314 return 0;315}316 317static const struct dai_rsc_ops dai_ops = {318 .set_srt_srcl = dai_set_srt_srcl,319 .set_srt_srcr = dai_set_srt_srcr,320 .set_srt_msr = dai_set_srt_msr,321 .set_enb_src = dai_set_enb_src,322 .set_enb_srt = dai_set_enb_srt,323 .commit_write = dai_commit_write,324};325 326static int daio_rsc_init(struct daio *daio,327 const struct daio_desc *desc,328 struct hw *hw)329{330 int err;331 unsigned int idx_l, idx_r;332 333 switch (hw->chip_type) {334 case ATC20K1:335 idx_l = idx_20k1[desc->type].left;336 idx_r = idx_20k1[desc->type].right;337 break;338 case ATC20K2:339 idx_l = idx_20k2[desc->type].left;340 idx_r = idx_20k2[desc->type].right;341 break;342 default:343 return -EINVAL;344 }345 err = rsc_init(&daio->rscl, idx_l, DAIO, desc->msr, hw);346 if (err)347 return err;348 349 err = rsc_init(&daio->rscr, idx_r, DAIO, desc->msr, hw);350 if (err)351 goto error1;352 353 /* Set daio->rscl/r->ops to daio specific ones */354 if (desc->type <= DAIO_OUT_MAX) {355 daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;356 } else {357 switch (hw->chip_type) {358 case ATC20K1:359 daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1;360 break;361 case ATC20K2:362 daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k2;363 break;364 default:365 break;366 }367 }368 daio->type = desc->type;369 370 return 0;371 372error1:373 rsc_uninit(&daio->rscl);374 return err;375}376 377static int daio_rsc_uninit(struct daio *daio)378{379 rsc_uninit(&daio->rscl);380 rsc_uninit(&daio->rscr);381 382 return 0;383}384 385static int dao_rsc_init(struct dao *dao,386 const struct daio_desc *desc,387 struct daio_mgr *mgr)388{389 struct hw *hw = mgr->mgr.hw;390 unsigned int conf;391 int err;392 393 err = daio_rsc_init(&dao->daio, desc, mgr->mgr.hw);394 if (err)395 return err;396 397 dao->imappers = kzalloc(array3_size(sizeof(void *), desc->msr, 2),398 GFP_KERNEL);399 if (!dao->imappers) {400 err = -ENOMEM;401 goto error1;402 }403 dao->ops = &dao_ops;404 dao->mgr = mgr;405 dao->hw = hw;406 err = hw->dao_get_ctrl_blk(&dao->ctrl_blk);407 if (err)408 goto error2;409 410 hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,411 daio_device_index(dao->daio.type, hw));412 hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);413 414 conf = (desc->msr & 0x7) | (desc->passthru << 3);415 hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk,416 daio_device_index(dao->daio.type, hw), conf);417 hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,418 daio_device_index(dao->daio.type, hw));419 hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);420 421 return 0;422 423error2:424 kfree(dao->imappers);425 dao->imappers = NULL;426error1:427 daio_rsc_uninit(&dao->daio);428 return err;429}430 431static int dao_rsc_uninit(struct dao *dao)432{433 if (dao->imappers) {434 if (dao->imappers[0])435 dao_clear_left_input(dao);436 437 if (dao->imappers[dao->daio.rscl.msr])438 dao_clear_right_input(dao);439 440 kfree(dao->imappers);441 dao->imappers = NULL;442 }443 dao->hw->dao_put_ctrl_blk(dao->ctrl_blk);444 dao->hw = dao->ctrl_blk = NULL;445 daio_rsc_uninit(&dao->daio);446 447 return 0;448}449 450static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc)451{452 struct daio_mgr *mgr = dao->mgr;453 struct daio_desc dsc = {0};454 455 dsc.type = dao->daio.type;456 dsc.msr = desc->msr;457 dsc.passthru = desc->passthru;458 dao_rsc_uninit(dao);459 return dao_rsc_init(dao, &dsc, mgr);460}461 462static int dai_rsc_init(struct dai *dai,463 const struct daio_desc *desc,464 struct daio_mgr *mgr)465{466 int err;467 struct hw *hw = mgr->mgr.hw;468 unsigned int rsr, msr;469 470 err = daio_rsc_init(&dai->daio, desc, mgr->mgr.hw);471 if (err)472 return err;473 474 dai->ops = &dai_ops;475 dai->hw = mgr->mgr.hw;476 err = hw->dai_get_ctrl_blk(&dai->ctrl_blk);477 if (err)478 goto error1;479 480 for (rsr = 0, msr = desc->msr; msr > 1; msr >>= 1)481 rsr++;482 483 hw->dai_srt_set_rsr(dai->ctrl_blk, rsr);484 hw->dai_srt_set_drat(dai->ctrl_blk, 0);485 /* default to disabling control of a SRC */486 hw->dai_srt_set_ec(dai->ctrl_blk, 0);487 hw->dai_srt_set_et(dai->ctrl_blk, 0); /* default to disabling SRT */488 hw->dai_commit_write(hw,489 daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);490 491 return 0;492 493error1:494 daio_rsc_uninit(&dai->daio);495 return err;496}497 498static int dai_rsc_uninit(struct dai *dai)499{500 dai->hw->dai_put_ctrl_blk(dai->ctrl_blk);501 dai->hw = dai->ctrl_blk = NULL;502 daio_rsc_uninit(&dai->daio);503 return 0;504}505 506static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)507{508 if (((struct daio_usage *)mgr->rscs)->data & (0x1 << type))509 return -ENOENT;510 511 ((struct daio_usage *)mgr->rscs)->data |= (0x1 << type);512 513 return 0;514}515 516static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)517{518 ((struct daio_usage *)mgr->rscs)->data &= ~(0x1 << type);519 520 return 0;521}522 523static int get_daio_rsc(struct daio_mgr *mgr,524 const struct daio_desc *desc,525 struct daio **rdaio)526{527 int err;528 unsigned long flags;529 530 *rdaio = NULL;531 532 /* Check whether there are sufficient daio resources to meet request. */533 spin_lock_irqsave(&mgr->mgr_lock, flags);534 err = daio_mgr_get_rsc(&mgr->mgr, desc->type);535 spin_unlock_irqrestore(&mgr->mgr_lock, flags);536 if (err) {537 dev_err(mgr->card->dev,538 "Can't meet DAIO resource request!\n");539 return err;540 }541 542 err = -ENOMEM;543 /* Allocate mem for daio resource */544 if (desc->type <= DAIO_OUT_MAX) {545 struct dao *dao = kzalloc(sizeof(*dao), GFP_KERNEL);546 if (!dao)547 goto error;548 549 err = dao_rsc_init(dao, desc, mgr);550 if (err) {551 kfree(dao);552 goto error;553 }554 555 *rdaio = &dao->daio;556 } else {557 struct dai *dai = kzalloc(sizeof(*dai), GFP_KERNEL);558 if (!dai)559 goto error;560 561 err = dai_rsc_init(dai, desc, mgr);562 if (err) {563 kfree(dai);564 goto error;565 }566 567 *rdaio = &dai->daio;568 }569 570 mgr->daio_enable(mgr, *rdaio);571 mgr->commit_write(mgr);572 573 return 0;574 575error:576 spin_lock_irqsave(&mgr->mgr_lock, flags);577 daio_mgr_put_rsc(&mgr->mgr, desc->type);578 spin_unlock_irqrestore(&mgr->mgr_lock, flags);579 return err;580}581 582static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio)583{584 unsigned long flags;585 586 mgr->daio_disable(mgr, daio);587 mgr->commit_write(mgr);588 589 spin_lock_irqsave(&mgr->mgr_lock, flags);590 daio_mgr_put_rsc(&mgr->mgr, daio->type);591 spin_unlock_irqrestore(&mgr->mgr_lock, flags);592 593 if (daio->type <= DAIO_OUT_MAX) {594 dao_rsc_uninit(container_of(daio, struct dao, daio));595 kfree(container_of(daio, struct dao, daio));596 } else {597 dai_rsc_uninit(container_of(daio, struct dai, daio));598 kfree(container_of(daio, struct dai, daio));599 }600 601 return 0;602}603 604static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio)605{606 struct hw *hw = mgr->mgr.hw;607 608 if (DAIO_OUT_MAX >= daio->type) {609 hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,610 daio_device_index(daio->type, hw));611 } else {612 hw->daio_mgr_enb_dai(mgr->mgr.ctrl_blk,613 daio_device_index(daio->type, hw));614 }615 return 0;616}617 618static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio)619{620 struct hw *hw = mgr->mgr.hw;621 622 if (DAIO_OUT_MAX >= daio->type) {623 hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,624 daio_device_index(daio->type, hw));625 } else {626 hw->daio_mgr_dsb_dai(mgr->mgr.ctrl_blk,627 daio_device_index(daio->type, hw));628 }629 return 0;630}631 632static int daio_map_op(void *data, struct imapper *entry)633{634 struct rsc_mgr *mgr = &((struct daio_mgr *)data)->mgr;635 struct hw *hw = mgr->hw;636 637 hw->daio_mgr_set_imaparc(mgr->ctrl_blk, entry->slot);638 hw->daio_mgr_set_imapnxt(mgr->ctrl_blk, entry->next);639 hw->daio_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr);640 hw->daio_mgr_commit_write(mgr->hw, mgr->ctrl_blk);641 642 return 0;643}644 645static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry)646{647 unsigned long flags;648 int err;649 650 spin_lock_irqsave(&mgr->imap_lock, flags);651 if (!entry->addr && mgr->init_imap_added) {652 input_mapper_delete(&mgr->imappers, mgr->init_imap,653 daio_map_op, mgr);654 mgr->init_imap_added = 0;655 }656 err = input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr);657 spin_unlock_irqrestore(&mgr->imap_lock, flags);658 659 return err;660}661 662static int daio_imap_delete(struct daio_mgr *mgr, struct imapper *entry)663{664 unsigned long flags;665 int err;666 667 spin_lock_irqsave(&mgr->imap_lock, flags);668 err = input_mapper_delete(&mgr->imappers, entry, daio_map_op, mgr);669 if (list_empty(&mgr->imappers)) {670 input_mapper_add(&mgr->imappers, mgr->init_imap,671 daio_map_op, mgr);672 mgr->init_imap_added = 1;673 }674 spin_unlock_irqrestore(&mgr->imap_lock, flags);675 676 return err;677}678 679static int daio_mgr_commit_write(struct daio_mgr *mgr)680{681 struct hw *hw = mgr->mgr.hw;682 683 hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);684 return 0;685}686 687int daio_mgr_create(struct hw *hw, void **rdaio_mgr)688{689 int err, i;690 struct daio_mgr *daio_mgr;691 struct imapper *entry;692 693 *rdaio_mgr = NULL;694 daio_mgr = kzalloc(sizeof(*daio_mgr), GFP_KERNEL);695 if (!daio_mgr)696 return -ENOMEM;697 698 err = rsc_mgr_init(&daio_mgr->mgr, DAIO, NUM_DAIOTYP, hw);699 if (err)700 goto error1;701 702 spin_lock_init(&daio_mgr->mgr_lock);703 spin_lock_init(&daio_mgr->imap_lock);704 INIT_LIST_HEAD(&daio_mgr->imappers);705 entry = kzalloc(sizeof(*entry), GFP_KERNEL);706 if (!entry) {707 err = -ENOMEM;708 goto error2;709 }710 entry->slot = entry->addr = entry->next = entry->user = 0;711 list_add(&entry->list, &daio_mgr->imappers);712 daio_mgr->init_imap = entry;713 daio_mgr->init_imap_added = 1;714 715 daio_mgr->get_daio = get_daio_rsc;716 daio_mgr->put_daio = put_daio_rsc;717 daio_mgr->daio_enable = daio_mgr_enb_daio;718 daio_mgr->daio_disable = daio_mgr_dsb_daio;719 daio_mgr->imap_add = daio_imap_add;720 daio_mgr->imap_delete = daio_imap_delete;721 daio_mgr->commit_write = daio_mgr_commit_write;722 daio_mgr->card = hw->card;723 724 for (i = 0; i < 8; i++) {725 hw->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i);726 hw->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i);727 }728 hw->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk);729 730 *rdaio_mgr = daio_mgr;731 732 return 0;733 734error2:735 rsc_mgr_uninit(&daio_mgr->mgr);736error1:737 kfree(daio_mgr);738 return err;739}740 741int daio_mgr_destroy(void *ptr)742{743 struct daio_mgr *daio_mgr = ptr;744 unsigned long flags;745 746 /* free daio input mapper list */747 spin_lock_irqsave(&daio_mgr->imap_lock, flags);748 free_input_mapper_list(&daio_mgr->imappers);749 spin_unlock_irqrestore(&daio_mgr->imap_lock, flags);750 751 rsc_mgr_uninit(&daio_mgr->mgr);752 kfree(daio_mgr);753 754 return 0;755}756 757