brintos

brintos / linux-shallow public Read only

0
0
Text · 14.9 KiB · e7f86db Raw
733 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Renesas R-Car SRC support4//5// Copyright (C) 2013 Renesas Solutions Corp.6// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>7 8/*9 * You can use Synchronous Sampling Rate Convert (if no DVC)10 *11 *	amixer set "SRC Out Rate" on12 *	aplay xxx.wav &13 *	amixer set "SRC Out Rate" 96000 // convert rate to 96000Hz14 *	amixer set "SRC Out Rate" 22050 // convert rate to 22050Hz15 */16 17/*18 * you can enable below define if you don't need19 * SSI interrupt status debug message when debugging20 * see rsnd_print_irq_status()21 *22 * #define RSND_DEBUG_NO_IRQ_STATUS 123 */24 25#include <linux/of_irq.h>26#include "rsnd.h"27 28#define SRC_NAME "src"29 30/* SCU_SYSTEM_STATUS0/1 */31#define OUF_SRC(id)	((1 << (id + 16)) | (1 << id))32 33struct rsnd_src {34	struct rsnd_mod mod;35	struct rsnd_mod *dma;36	struct rsnd_kctrl_cfg_s sen;  /* sync convert enable */37	struct rsnd_kctrl_cfg_s sync; /* sync convert */38	int irq;39};40 41#define RSND_SRC_NAME_SIZE 1642 43#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id)44#define rsnd_src_nr(priv) ((priv)->src_nr)45#define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val)46 47#define rsnd_mod_to_src(_mod)				\48	container_of((_mod), struct rsnd_src, mod)49 50#define for_each_rsnd_src(pos, priv, i)				\51	for ((i) = 0;						\52	     ((i) < rsnd_src_nr(priv)) &&			\53	     ((pos) = (struct rsnd_src *)(priv)->src + i);	\54	     i++)55 56 57/*58 *		image of SRC (Sampling Rate Converter)59 *60 * 96kHz   <-> +-----+	48kHz	+-----+	 48kHz	+-------+61 * 48kHz   <-> | SRC | <------>	| SSI |	<----->	| codec |62 * 44.1kHz <-> +-----+		+-----+		+-------+63 * ...64 *65 */66 67static void rsnd_src_activation(struct rsnd_mod *mod)68{69	rsnd_mod_write(mod, SRC_SWRSR, 0);70	rsnd_mod_write(mod, SRC_SWRSR, 1);71}72 73static void rsnd_src_halt(struct rsnd_mod *mod)74{75	rsnd_mod_write(mod, SRC_SRCIR, 1);76	rsnd_mod_write(mod, SRC_SWRSR, 0);77}78 79static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,80					 struct rsnd_mod *mod)81{82	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);83	int is_play = rsnd_io_is_play(io);84 85	return rsnd_dma_request_channel(rsnd_src_of_node(priv),86					SRC_NAME, mod,87					is_play ? "rx" : "tx");88}89 90static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,91				 struct rsnd_mod *mod)92{93	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);94	struct rsnd_src *src = rsnd_mod_to_src(mod);95	u32 convert_rate;96 97	if (!runtime)98		return 0;99 100	if (!rsnd_src_sync_is_enabled(mod))101		return rsnd_io_converted_rate(io);102 103	convert_rate = src->sync.val;104 105	if (!convert_rate)106		convert_rate = rsnd_io_converted_rate(io);107 108	if (!convert_rate)109		convert_rate = runtime->rate;110 111	return convert_rate;112}113 114unsigned int rsnd_src_get_rate(struct rsnd_priv *priv,115			       struct rsnd_dai_stream *io,116			       int is_in)117{118	struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);119	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);120	unsigned int rate = 0;121	int is_play = rsnd_io_is_play(io);122 123	/*124	 * Playback125	 * runtime_rate -> [SRC] -> convert_rate126	 *127	 * Capture128	 * convert_rate -> [SRC] -> runtime_rate129	 */130 131	if (is_play == is_in)132		return runtime->rate;133 134	/*135	 * return convert rate if SRC is used,136	 * otherwise, return runtime->rate as usual137	 */138	if (src_mod)139		rate = rsnd_src_convert_rate(io, src_mod);140 141	if (!rate)142		rate = runtime->rate;143 144	return rate;145}146 147static const u32 bsdsr_table_pattern1[] = {148	0x01800000, /* 6 - 1/6 */149	0x01000000, /* 6 - 1/4 */150	0x00c00000, /* 6 - 1/3 */151	0x00800000, /* 6 - 1/2 */152	0x00600000, /* 6 - 2/3 */153	0x00400000, /* 6 - 1   */154};155 156static const u32 bsdsr_table_pattern2[] = {157	0x02400000, /* 6 - 1/6 */158	0x01800000, /* 6 - 1/4 */159	0x01200000, /* 6 - 1/3 */160	0x00c00000, /* 6 - 1/2 */161	0x00900000, /* 6 - 2/3 */162	0x00600000, /* 6 - 1   */163};164 165static const u32 bsisr_table[] = {166	0x00100060, /* 6 - 1/6 */167	0x00100040, /* 6 - 1/4 */168	0x00100030, /* 6 - 1/3 */169	0x00100020, /* 6 - 1/2 */170	0x00100020, /* 6 - 2/3 */171	0x00100020, /* 6 - 1   */172};173 174static const u32 chan288888[] = {175	0x00000006, /* 1 to 2 */176	0x000001fe, /* 1 to 8 */177	0x000001fe, /* 1 to 8 */178	0x000001fe, /* 1 to 8 */179	0x000001fe, /* 1 to 8 */180	0x000001fe, /* 1 to 8 */181};182 183static const u32 chan244888[] = {184	0x00000006, /* 1 to 2 */185	0x0000001e, /* 1 to 4 */186	0x0000001e, /* 1 to 4 */187	0x000001fe, /* 1 to 8 */188	0x000001fe, /* 1 to 8 */189	0x000001fe, /* 1 to 8 */190};191 192static const u32 chan222222[] = {193	0x00000006, /* 1 to 2 */194	0x00000006, /* 1 to 2 */195	0x00000006, /* 1 to 2 */196	0x00000006, /* 1 to 2 */197	0x00000006, /* 1 to 2 */198	0x00000006, /* 1 to 2 */199};200 201static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,202				      struct rsnd_mod *mod)203{204	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);205	struct device *dev = rsnd_priv_to_dev(priv);206	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);207	int is_play = rsnd_io_is_play(io);208	int use_src = 0;209	u32 fin, fout;210	u32 ifscr, fsrate, adinr;211	u32 cr, route;212	u32 i_busif, o_busif, tmp;213	const u32 *bsdsr_table;214	const u32 *chptn;215	uint ratio;216	int chan;217	int idx;218 219	if (!runtime)220		return;221 222	fin  = rsnd_src_get_in_rate(priv, io);223	fout = rsnd_src_get_out_rate(priv, io);224 225	chan = rsnd_runtime_channel_original(io);226 227	/* 6 - 1/6 are very enough ratio for SRC_BSDSR */228	if (fin == fout)229		ratio = 0;230	else if (fin > fout)231		ratio = 100 * fin / fout;232	else233		ratio = 100 * fout / fin;234 235	if (ratio > 600) {236		dev_err(dev, "FSO/FSI ratio error\n");237		return;238	}239 240	use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod);241 242	/*243	 * SRC_ADINR244	 */245	adinr = rsnd_get_adinr_bit(mod, io) | chan;246 247	/*248	 * SRC_IFSCR / SRC_IFSVR249	 */250	ifscr = 0;251	fsrate = 0;252	if (use_src) {253		u64 n;254 255		ifscr = 1;256		n = (u64)0x0400000 * fin;257		do_div(n, fout);258		fsrate = n;259	}260 261	/*262	 * SRC_SRCCR / SRC_ROUTE_MODE0263	 */264	cr	= 0x00011110;265	route	= 0x0;266	if (use_src) {267		route	= 0x1;268 269		if (rsnd_src_sync_is_enabled(mod)) {270			cr |= 0x1;271			route |= rsnd_io_is_play(io) ?272				(0x1 << 24) : (0x1 << 25);273		}274	}275 276	/*277	 * SRC_BSDSR / SRC_BSISR278	 *279	 * see280	 *	Combination of Register Setting Related to281	 *	FSO/FSI Ratio and Channel, Latency282	 */283	switch (rsnd_mod_id(mod)) {284	case 0:285		chptn		= chan288888;286		bsdsr_table	= bsdsr_table_pattern1;287		break;288	case 1:289	case 3:290	case 4:291		chptn		= chan244888;292		bsdsr_table	= bsdsr_table_pattern1;293		break;294	case 2:295	case 9:296		chptn		= chan222222;297		bsdsr_table	= bsdsr_table_pattern1;298		break;299	case 5:300	case 6:301	case 7:302	case 8:303		chptn		= chan222222;304		bsdsr_table	= bsdsr_table_pattern2;305		break;306	default:307		goto convert_rate_err;308	}309 310	/*311	 * E3 need to overwrite312	 */313	if (rsnd_is_gen3_e3(priv))314		switch (rsnd_mod_id(mod)) {315		case 0:316		case 4:317			chptn	= chan222222;318		}319 320	for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++)321		if (chptn[idx] & (1 << chan))322			break;323 324	if (chan > 8 ||325	    idx >= ARRAY_SIZE(chan222222))326		goto convert_rate_err;327 328	/* BUSIF_MODE */329	tmp = rsnd_get_busif_shift(io, mod);330	i_busif = ( is_play ? tmp : 0) | 1;331	o_busif = (!is_play ? tmp : 0) | 1;332 333	rsnd_mod_write(mod, SRC_ROUTE_MODE0, route);334 335	rsnd_mod_write(mod, SRC_SRCIR, 1);	/* initialize */336	rsnd_mod_write(mod, SRC_ADINR, adinr);337	rsnd_mod_write(mod, SRC_IFSCR, ifscr);338	rsnd_mod_write(mod, SRC_IFSVR, fsrate);339	rsnd_mod_write(mod, SRC_SRCCR, cr);340	rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]);341	rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]);342	rsnd_mod_write(mod, SRC_SRCIR, 0);	/* cancel initialize */343 344	rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif);345	rsnd_mod_write(mod, SRC_O_BUSIF_MODE, o_busif);346 347	rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));348 349	rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);350 351	return;352 353convert_rate_err:354	dev_err(dev, "unknown BSDSR/BSDIR settings\n");355}356 357static int rsnd_src_irq(struct rsnd_mod *mod,358			struct rsnd_dai_stream *io,359			struct rsnd_priv *priv,360			int enable)361{362	struct rsnd_src *src = rsnd_mod_to_src(mod);363	u32 sys_int_val, int_val, sys_int_mask;364	int irq = src->irq;365	int id = rsnd_mod_id(mod);366 367	sys_int_val =368	sys_int_mask = OUF_SRC(id);369	int_val = 0x3300;370 371	/*372	 * IRQ is not supported on non-DT373	 * see374	 *	rsnd_src_probe_()375	 */376	if ((irq <= 0) || !enable) {377		sys_int_val = 0;378		int_val = 0;379	}380 381	/*382	 * WORKAROUND383	 *384	 * ignore over flow error when rsnd_src_sync_is_enabled()385	 */386	if (rsnd_src_sync_is_enabled(mod))387		sys_int_val = sys_int_val & 0xffff;388 389	rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val);390	rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val);391	rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);392 393	return 0;394}395 396static void rsnd_src_status_clear(struct rsnd_mod *mod)397{398	u32 val = OUF_SRC(rsnd_mod_id(mod));399 400	rsnd_mod_write(mod, SCU_SYS_STATUS0, val);401	rsnd_mod_write(mod, SCU_SYS_STATUS1, val);402}403 404static bool rsnd_src_error_occurred(struct rsnd_mod *mod)405{406	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);407	struct device *dev = rsnd_priv_to_dev(priv);408	u32 val0, val1;409	u32 status0, status1;410	bool ret = false;411 412	val0 = val1 = OUF_SRC(rsnd_mod_id(mod));413 414	/*415	 * WORKAROUND416	 *417	 * ignore over flow error when rsnd_src_sync_is_enabled()418	 */419	if (rsnd_src_sync_is_enabled(mod))420		val0 = val0 & 0xffff;421 422	status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0);423	status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1);424	if ((status0 & val0) || (status1 & val1)) {425		rsnd_print_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n",426				      rsnd_mod_name(mod), status0, status1);427 428		ret = true;429	}430 431	return ret;432}433 434static int rsnd_src_start(struct rsnd_mod *mod,435			  struct rsnd_dai_stream *io,436			  struct rsnd_priv *priv)437{438	u32 val;439 440	/*441	 * WORKAROUND442	 *443	 * Enable SRC output if you want to use sync convert together with DVC444	 */445	val = (rsnd_io_to_mod_dvc(io) && !rsnd_src_sync_is_enabled(mod)) ?446		0x01 : 0x11;447 448	rsnd_mod_write(mod, SRC_CTRL, val);449 450	return 0;451}452 453static int rsnd_src_stop(struct rsnd_mod *mod,454			 struct rsnd_dai_stream *io,455			 struct rsnd_priv *priv)456{457	rsnd_mod_write(mod, SRC_CTRL, 0);458 459	return 0;460}461 462static int rsnd_src_init(struct rsnd_mod *mod,463			 struct rsnd_dai_stream *io,464			 struct rsnd_priv *priv)465{466	struct rsnd_src *src = rsnd_mod_to_src(mod);467	int ret;468 469	/* reset sync convert_rate */470	src->sync.val = 0;471 472	ret = rsnd_mod_power_on(mod);473	if (ret < 0)474		return ret;475 476	rsnd_src_activation(mod);477 478	rsnd_src_set_convert_rate(io, mod);479 480	rsnd_src_status_clear(mod);481 482	return 0;483}484 485static int rsnd_src_quit(struct rsnd_mod *mod,486			 struct rsnd_dai_stream *io,487			 struct rsnd_priv *priv)488{489	struct rsnd_src *src = rsnd_mod_to_src(mod);490 491	rsnd_src_halt(mod);492 493	rsnd_mod_power_off(mod);494 495	/* reset sync convert_rate */496	src->sync.val = 0;497 498	return 0;499}500 501static void __rsnd_src_interrupt(struct rsnd_mod *mod,502				 struct rsnd_dai_stream *io)503{504	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);505	bool stop = false;506 507	spin_lock(&priv->lock);508 509	/* ignore all cases if not working */510	if (!rsnd_io_is_working(io))511		goto rsnd_src_interrupt_out;512 513	if (rsnd_src_error_occurred(mod))514		stop = true;515 516	rsnd_src_status_clear(mod);517rsnd_src_interrupt_out:518 519	spin_unlock(&priv->lock);520 521	if (stop)522		snd_pcm_stop_xrun(io->substream);523}524 525static irqreturn_t rsnd_src_interrupt(int irq, void *data)526{527	struct rsnd_mod *mod = data;528 529	rsnd_mod_interrupt(mod, __rsnd_src_interrupt);530 531	return IRQ_HANDLED;532}533 534static int rsnd_src_probe_(struct rsnd_mod *mod,535			   struct rsnd_dai_stream *io,536			   struct rsnd_priv *priv)537{538	struct rsnd_src *src = rsnd_mod_to_src(mod);539	struct device *dev = rsnd_priv_to_dev(priv);540	int irq = src->irq;541	int ret;542 543	if (irq > 0) {544		/*545		 * IRQ is not supported on non-DT546		 * see547		 *	rsnd_src_irq()548		 */549		ret = devm_request_irq(dev, irq,550				       rsnd_src_interrupt,551				       IRQF_SHARED,552				       dev_name(dev), mod);553		if (ret)554			return ret;555	}556 557	ret = rsnd_dma_attach(io, mod, &src->dma);558 559	return ret;560}561 562static int rsnd_src_pcm_new(struct rsnd_mod *mod,563			    struct rsnd_dai_stream *io,564			    struct snd_soc_pcm_runtime *rtd)565{566	struct rsnd_src *src = rsnd_mod_to_src(mod);567	int ret;568 569	/*570	 * enable SRC sync convert if possible571	 */572 573	/*574	 * It can't use SRC Synchronous convert575	 * when Capture if it uses CMD576	 */577	if (rsnd_io_to_mod_cmd(io) && !rsnd_io_is_play(io))578		return 0;579 580	/*581	 * enable sync convert582	 */583	ret = rsnd_kctrl_new_s(mod, io, rtd,584			       rsnd_io_is_play(io) ?585			       "SRC Out Rate Switch" :586			       "SRC In Rate Switch",587			       rsnd_kctrl_accept_anytime,588			       rsnd_src_set_convert_rate,589			       &src->sen, 1);590	if (ret < 0)591		return ret;592 593	ret = rsnd_kctrl_new_s(mod, io, rtd,594			       rsnd_io_is_play(io) ?595			       "SRC Out Rate" :596			       "SRC In Rate",597			       rsnd_kctrl_accept_runtime,598			       rsnd_src_set_convert_rate,599			       &src->sync, 192000);600 601	return ret;602}603 604#ifdef CONFIG_DEBUG_FS605static void rsnd_src_debug_info(struct seq_file *m,606				struct rsnd_dai_stream *io,607				struct rsnd_mod *mod)608{609	rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,610				  rsnd_mod_id(mod) * 0x20, 0x20);611	seq_puts(m, "\n");612	rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,613				  0x1c0, 0x20);614	seq_puts(m, "\n");615	rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,616				  0x200 + rsnd_mod_id(mod) * 0x40, 0x40);617}618#define DEBUG_INFO .debug_info = rsnd_src_debug_info619#else620#define DEBUG_INFO621#endif622 623static struct rsnd_mod_ops rsnd_src_ops = {624	.name		= SRC_NAME,625	.dma_req	= rsnd_src_dma_req,626	.probe		= rsnd_src_probe_,627	.init		= rsnd_src_init,628	.quit		= rsnd_src_quit,629	.start		= rsnd_src_start,630	.stop		= rsnd_src_stop,631	.irq		= rsnd_src_irq,632	.pcm_new	= rsnd_src_pcm_new,633	.get_status	= rsnd_mod_get_status,634	DEBUG_INFO635};636 637struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id)638{639	if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv)))640		id = 0;641 642	return rsnd_mod_get(rsnd_src_get(priv, id));643}644 645int rsnd_src_probe(struct rsnd_priv *priv)646{647	struct device_node *node;648	struct device_node *np;649	struct device *dev = rsnd_priv_to_dev(priv);650	struct rsnd_src *src;651	struct clk *clk;652	char name[RSND_SRC_NAME_SIZE];653	int i, nr, ret;654 655	node = rsnd_src_of_node(priv);656	if (!node)657		return 0; /* not used is not error */658 659	nr = rsnd_node_count(priv, node, SRC_NAME);660	if (!nr) {661		ret = -EINVAL;662		goto rsnd_src_probe_done;663	}664 665	src	= devm_kcalloc(dev, nr, sizeof(*src), GFP_KERNEL);666	if (!src) {667		ret = -ENOMEM;668		goto rsnd_src_probe_done;669	}670 671	priv->src_nr	= nr;672	priv->src	= src;673 674	i = 0;675	for_each_child_of_node(node, np) {676		if (!of_device_is_available(np))677			goto skip;678 679		i = rsnd_node_fixed_index(dev, np, SRC_NAME, i);680		if (i < 0) {681			ret = -EINVAL;682			of_node_put(np);683			goto rsnd_src_probe_done;684		}685 686		src = rsnd_src_get(priv, i);687 688		snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d",689			 SRC_NAME, i);690 691		src->irq = irq_of_parse_and_map(np, 0);692		if (!src->irq) {693			ret = -EINVAL;694			of_node_put(np);695			goto rsnd_src_probe_done;696		}697 698		clk = devm_clk_get(dev, name);699		if (IS_ERR(clk)) {700			ret = PTR_ERR(clk);701			of_node_put(np);702			goto rsnd_src_probe_done;703		}704 705		ret = rsnd_mod_init(priv, rsnd_mod_get(src),706				    &rsnd_src_ops, clk, RSND_MOD_SRC, i);707		if (ret) {708			of_node_put(np);709			goto rsnd_src_probe_done;710		}711 712skip:713		i++;714	}715 716	ret = 0;717 718rsnd_src_probe_done:719	of_node_put(node);720 721	return ret;722}723 724void rsnd_src_remove(struct rsnd_priv *priv)725{726	struct rsnd_src *src;727	int i;728 729	for_each_rsnd_src(src, priv, i) {730		rsnd_mod_quit(rsnd_mod_get(src));731	}732}733