brintos

brintos / linux-shallow public Read only

0
0
Text · 16.9 KiB · 83aaf94 Raw
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