brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · da91dd3 Raw
393 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// Renesas R-Car DVC support4//5// Copyright (C) 2014 Renesas Solutions Corp.6// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>7 8/*9 * Playback Volume10 *	amixer set "DVC Out" 100%11 *12 * Capture Volume13 *	amixer set "DVC In" 100%14 *15 * Playback Mute16 *	amixer set "DVC Out Mute" on17 *18 * Capture Mute19 *	amixer set "DVC In Mute" on20 *21 * Volume Ramp22 *	amixer set "DVC Out Ramp Up Rate"   "0.125 dB/64 steps"23 *	amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps"24 *	amixer set "DVC Out Ramp" on25 *	aplay xxx.wav &26 *	amixer set "DVC Out"  80%  // Volume Down27 *	amixer set "DVC Out" 100%  // Volume Up28 */29 30#include "rsnd.h"31 32#define RSND_DVC_NAME_SIZE	1633 34#define DVC_NAME "dvc"35 36struct rsnd_dvc {37	struct rsnd_mod mod;38	struct rsnd_kctrl_cfg_m volume;39	struct rsnd_kctrl_cfg_m mute;40	struct rsnd_kctrl_cfg_s ren;	/* Ramp Enable */41	struct rsnd_kctrl_cfg_s rup;	/* Ramp Rate Up */42	struct rsnd_kctrl_cfg_s rdown;	/* Ramp Rate Down */43};44 45#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)46#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)47 48#define rsnd_mod_to_dvc(_mod)	\49	container_of((_mod), struct rsnd_dvc, mod)50 51#define for_each_rsnd_dvc(pos, priv, i)				\52	for ((i) = 0;						\53	     ((i) < rsnd_dvc_nr(priv)) &&			\54	     ((pos) = (struct rsnd_dvc *)(priv)->dvc + i);	\55	     i++)56 57static void rsnd_dvc_activation(struct rsnd_mod *mod)58{59	rsnd_mod_write(mod, DVC_SWRSR, 0);60	rsnd_mod_write(mod, DVC_SWRSR, 1);61}62 63static void rsnd_dvc_halt(struct rsnd_mod *mod)64{65	rsnd_mod_write(mod, DVC_DVUIR, 1);66	rsnd_mod_write(mod, DVC_SWRSR, 0);67}68 69#define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \70				 rsnd_kctrl_vals(dvc->rdown))71#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (rsnd_kctrl_valm(dvc->volume, 0) >> 13))72 73static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,74					      struct rsnd_mod *mod)75{76	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);77	u32 val[RSND_MAX_CHANNELS];78	int i;79 80	/* Enable Ramp */81	if (rsnd_kctrl_vals(dvc->ren))82		for (i = 0; i < RSND_MAX_CHANNELS; i++)83			val[i] = rsnd_kctrl_max(dvc->volume);84	else85		for (i = 0; i < RSND_MAX_CHANNELS; i++)86			val[i] = rsnd_kctrl_valm(dvc->volume, i);87 88	/* Enable Digital Volume */89	for (i = 0; i < RSND_MAX_CHANNELS; i++)90		rsnd_mod_write(mod, DVC_VOLxR(i), val[i]);91}92 93static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,94				 struct rsnd_mod *mod)95{96	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);97	u32 adinr = 0;98	u32 dvucr = 0;99	u32 vrctr = 0;100	u32 vrpdr = 0;101	u32 vrdbr = 0;102 103	adinr = rsnd_get_adinr_bit(mod, io) |104		rsnd_runtime_channel_after_ctu(io);105 106	/* Enable Digital Volume, Zero Cross Mute Mode */107	dvucr |= 0x101;108 109	/* Enable Ramp */110	if (rsnd_kctrl_vals(dvc->ren)) {111		dvucr |= 0x10;112 113		/*114		 * FIXME !!115		 * use scale-downed Digital Volume116		 * as Volume Ramp117		 * 7F FFFF -> 3FF118		 */119		vrctr = 0xff;120		vrpdr = rsnd_dvc_get_vrpdr(dvc);121		vrdbr = rsnd_dvc_get_vrdbr(dvc);122	}123 124	/* Initialize operation */125	rsnd_mod_write(mod, DVC_DVUIR, 1);126 127	/* General Information */128	rsnd_mod_write(mod, DVC_ADINR, adinr);129	rsnd_mod_write(mod, DVC_DVUCR, dvucr);130 131	/* Volume Ramp Parameter */132	rsnd_mod_write(mod, DVC_VRCTR, vrctr);133	rsnd_mod_write(mod, DVC_VRPDR, vrpdr);134	rsnd_mod_write(mod, DVC_VRDBR, vrdbr);135 136	/* Digital Volume Function Parameter */137	rsnd_dvc_volume_parameter(io, mod);138 139	/* cancel operation */140	rsnd_mod_write(mod, DVC_DVUIR, 0);141}142 143static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,144				   struct rsnd_mod *mod)145{146	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);147	u32 zcmcr = 0;148	u32 vrpdr = 0;149	u32 vrdbr = 0;150	int i;151 152	for (i = 0; i < rsnd_kctrl_size(dvc->mute); i++)153		zcmcr |= (!!rsnd_kctrl_valm(dvc->mute, i)) << i;154 155	if (rsnd_kctrl_vals(dvc->ren)) {156		vrpdr = rsnd_dvc_get_vrpdr(dvc);157		vrdbr = rsnd_dvc_get_vrdbr(dvc);158	}159 160	/* Disable DVC Register access */161	rsnd_mod_write(mod, DVC_DVUER, 0);162 163	/* Zero Cross Mute Function */164	rsnd_mod_write(mod, DVC_ZCMCR, zcmcr);165 166	/* Volume Ramp Function */167	rsnd_mod_write(mod, DVC_VRPDR, vrpdr);168	rsnd_mod_write(mod, DVC_VRDBR, vrdbr);169	/* add DVC_VRWTR here */170 171	/* Digital Volume Function Parameter */172	rsnd_dvc_volume_parameter(io, mod);173 174	/* Enable DVC Register access */175	rsnd_mod_write(mod, DVC_DVUER, 1);176}177 178static int rsnd_dvc_probe_(struct rsnd_mod *mod,179			   struct rsnd_dai_stream *io,180			   struct rsnd_priv *priv)181{182	return rsnd_cmd_attach(io, rsnd_mod_id(mod));183}184 185static int rsnd_dvc_init(struct rsnd_mod *mod,186			 struct rsnd_dai_stream *io,187			 struct rsnd_priv *priv)188{189	int ret;190 191	ret = rsnd_mod_power_on(mod);192	if (ret < 0)193		return ret;194 195	rsnd_dvc_activation(mod);196 197	rsnd_dvc_volume_init(io, mod);198 199	rsnd_dvc_volume_update(io, mod);200 201	return 0;202}203 204static int rsnd_dvc_quit(struct rsnd_mod *mod,205			 struct rsnd_dai_stream *io,206			 struct rsnd_priv *priv)207{208	rsnd_dvc_halt(mod);209 210	rsnd_mod_power_off(mod);211 212	return 0;213}214 215static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,216			    struct rsnd_dai_stream *io,217			    struct snd_soc_pcm_runtime *rtd)218{219	struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);220	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);221	int is_play = rsnd_io_is_play(io);222	int channels = rsnd_rdai_channels_get(rdai);223	int ret;224 225	/* Volume */226	ret = rsnd_kctrl_new_m(mod, io, rtd,227			is_play ?228			"DVC Out Playback Volume" : "DVC In Capture Volume",229			rsnd_kctrl_accept_anytime,230			rsnd_dvc_volume_update,231			&dvc->volume, channels,232			0x00800000 - 1);233	if (ret < 0)234		return ret;235 236	/* Mute */237	ret = rsnd_kctrl_new_m(mod, io, rtd,238			is_play ?239			"DVC Out Mute Switch" : "DVC In Mute Switch",240			rsnd_kctrl_accept_anytime,241			rsnd_dvc_volume_update,242			&dvc->mute, channels,243			1);244	if (ret < 0)245		return ret;246 247	/* Ramp */248	ret = rsnd_kctrl_new_s(mod, io, rtd,249			is_play ?250			"DVC Out Ramp Switch" : "DVC In Ramp Switch",251			rsnd_kctrl_accept_anytime,252			rsnd_dvc_volume_update,253			&dvc->ren, 1);254	if (ret < 0)255		return ret;256 257	ret = rsnd_kctrl_new_e(mod, io, rtd,258			is_play ?259			"DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate",260			rsnd_kctrl_accept_anytime,261			rsnd_dvc_volume_update,262			&dvc->rup,263			volume_ramp_rate,264			VOLUME_RAMP_MAX_DVC);265	if (ret < 0)266		return ret;267 268	ret = rsnd_kctrl_new_e(mod, io, rtd,269			is_play ?270			"DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate",271			rsnd_kctrl_accept_anytime,272			rsnd_dvc_volume_update,273			&dvc->rdown,274			volume_ramp_rate,275			VOLUME_RAMP_MAX_DVC);276 277	if (ret < 0)278		return ret;279 280	return 0;281}282 283static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io,284					 struct rsnd_mod *mod)285{286	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);287 288	return rsnd_dma_request_channel(rsnd_dvc_of_node(priv),289					DVC_NAME, mod, "tx");290}291 292#ifdef CONFIG_DEBUG_FS293static void rsnd_dvc_debug_info(struct seq_file *m,294				struct rsnd_dai_stream *io,295				struct rsnd_mod *mod)296{297	rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU,298				  0xe00 + rsnd_mod_id(mod) * 0x100, 0x60);299}300#define DEBUG_INFO .debug_info = rsnd_dvc_debug_info301#else302#define DEBUG_INFO303#endif304 305static struct rsnd_mod_ops rsnd_dvc_ops = {306	.name		= DVC_NAME,307	.dma_req	= rsnd_dvc_dma_req,308	.probe		= rsnd_dvc_probe_,309	.init		= rsnd_dvc_init,310	.quit		= rsnd_dvc_quit,311	.pcm_new	= rsnd_dvc_pcm_new,312	.get_status	= rsnd_mod_get_status,313	DEBUG_INFO314};315 316struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)317{318	if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))319		id = 0;320 321	return rsnd_mod_get(rsnd_dvc_get(priv, id));322}323 324int rsnd_dvc_probe(struct rsnd_priv *priv)325{326	struct device_node *node;327	struct device_node *np;328	struct device *dev = rsnd_priv_to_dev(priv);329	struct rsnd_dvc *dvc;330	struct clk *clk;331	char name[RSND_DVC_NAME_SIZE];332	int i, nr, ret;333 334	node = rsnd_dvc_of_node(priv);335	if (!node)336		return 0; /* not used is not error */337 338	nr = of_get_child_count(node);339	if (!nr) {340		ret = -EINVAL;341		goto rsnd_dvc_probe_done;342	}343 344	dvc	= devm_kcalloc(dev, nr, sizeof(*dvc), GFP_KERNEL);345	if (!dvc) {346		ret = -ENOMEM;347		goto rsnd_dvc_probe_done;348	}349 350	priv->dvc_nr	= nr;351	priv->dvc	= dvc;352 353	i = 0;354	ret = 0;355	for_each_child_of_node(node, np) {356		dvc = rsnd_dvc_get(priv, i);357 358		snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",359			 DVC_NAME, i);360 361		clk = devm_clk_get(dev, name);362		if (IS_ERR(clk)) {363			ret = PTR_ERR(clk);364			of_node_put(np);365			goto rsnd_dvc_probe_done;366		}367 368		ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,369				    clk, RSND_MOD_DVC, i);370		if (ret) {371			of_node_put(np);372			goto rsnd_dvc_probe_done;373		}374 375		i++;376	}377 378rsnd_dvc_probe_done:379	of_node_put(node);380 381	return ret;382}383 384void rsnd_dvc_remove(struct rsnd_priv *priv)385{386	struct rsnd_dvc *dvc;387	int i;388 389	for_each_rsnd_dvc(dvc, priv, i) {390		rsnd_mod_quit(rsnd_mod_get(dvc));391	}392}393