brintos

brintos / linux-shallow public Read only

0
0
Text · 12.1 KiB · bd8007c Raw
434 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// tegra210_peq.c - Tegra210 PEQ driver4//5// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.6 7#include <linux/clk.h>8#include <linux/device.h>9#include <linux/io.h>10#include <linux/module.h>11#include <linux/of.h>12#include <linux/of_address.h>13#include <linux/platform_device.h>14#include <linux/pm_runtime.h>15#include <linux/regmap.h>16#include <sound/core.h>17#include <sound/pcm.h>18#include <sound/pcm_params.h>19#include <sound/soc.h>20 21#include "tegra210_ope.h"22#include "tegra210_peq.h"23 24static const struct reg_default tegra210_peq_reg_defaults[] = {25	{ TEGRA210_PEQ_CFG, 0x00000013},26	{ TEGRA210_PEQ_CFG_RAM_CTRL, 0x00004000},27	{ TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL, 0x00004000},28};29 30static const u32 biquad_init_gains[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH] = {31	1495012349, /* Pre-gain */32 33	/* Gains : b0, b1, a0, a1, a2 */34	536870912, -1073741824, 536870912, 2143508246, -1069773768, /* Band-0 */35	134217728, -265414508, 131766272, 2140402222, -1071252997,  /* Band-1 */36	268435456, -233515765, -33935948, 1839817267, -773826124,   /* Band-2 */37	536870912, -672537913, 139851540, 1886437554, -824433167,   /* Band-3 */38	268435456, -114439279, 173723964, 205743566, 278809729,     /* Band-4 */39	1, 0, 0, 0, 0, /* Band-5 */40	1, 0, 0, 0, 0, /* Band-6 */41	1, 0, 0, 0, 0, /* Band-7 */42	1, 0, 0, 0, 0, /* Band-8 */43	1, 0, 0, 0, 0, /* Band-9 */44	1, 0, 0, 0, 0, /* Band-10 */45	1, 0, 0, 0, 0, /* Band-11 */46 47	963423114, /* Post-gain */48};49 50static const u32 biquad_init_shifts[TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH] = {51	23, /* Pre-shift */52	30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, /* Shift for bands */53	28, /* Post-shift */54};55 56static s32 biquad_coeff_buffer[TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH];57 58static void tegra210_peq_read_ram(struct regmap *regmap, unsigned int reg_ctrl,59				  unsigned int reg_data, unsigned int ram_offset,60				  unsigned int *data, size_t size)61{62	unsigned int val;63	unsigned int i;64 65	val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;66	val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;67	val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;68	val |= TEGRA210_PEQ_RAM_CTRL_RW_READ;69 70	regmap_write(regmap, reg_ctrl, val);71 72	/*73	 * Since all ahub non-io modules work under same ahub clock it is not74	 * necessary to check ahub read busy bit after every read.75	 */76	for (i = 0; i < size; i++)77		regmap_read(regmap, reg_data, &data[i]);78}79 80static void tegra210_peq_write_ram(struct regmap *regmap, unsigned int reg_ctrl,81				   unsigned int reg_data, unsigned int ram_offset,82				   unsigned int *data, size_t size)83{84	unsigned int val;85	unsigned int i;86 87	val = ram_offset & TEGRA210_PEQ_RAM_CTRL_RAM_ADDR_MASK;88	val |= TEGRA210_PEQ_RAM_CTRL_ADDR_INIT_EN;89	val |= TEGRA210_PEQ_RAM_CTRL_SEQ_ACCESS_EN;90	val |= TEGRA210_PEQ_RAM_CTRL_RW_WRITE;91 92	regmap_write(regmap, reg_ctrl, val);93 94	for (i = 0; i < size; i++)95		regmap_write(regmap, reg_data, data[i]);96}97 98static int tegra210_peq_get(struct snd_kcontrol *kcontrol,99			    struct snd_ctl_elem_value *ucontrol)100{101	struct soc_mixer_control *mc =102		(struct soc_mixer_control *)kcontrol->private_value;103	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);104	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);105	unsigned int mask = (1 << fls(mc->max)) - 1;106	unsigned int val;107 108	regmap_read(ope->peq_regmap, mc->reg, &val);109 110	ucontrol->value.integer.value[0] = (val >> mc->shift) & mask;111 112	if (!mc->invert)113		return 0;114 115	ucontrol->value.integer.value[0] =116		mc->max - ucontrol->value.integer.value[0];117 118	return 0;119}120 121static int tegra210_peq_put(struct snd_kcontrol *kcontrol,122			    struct snd_ctl_elem_value *ucontrol)123{124	struct soc_mixer_control *mc =125		(struct soc_mixer_control *)kcontrol->private_value;126	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);127	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);128	unsigned int mask = (1 << fls(mc->max)) - 1;129	bool change = false;130	unsigned int val;131 132	val = (ucontrol->value.integer.value[0] & mask);133 134	if (mc->invert)135		val = mc->max - val;136 137	val = val << mc->shift;138 139	regmap_update_bits_check(ope->peq_regmap, mc->reg, (mask << mc->shift),140				 val, &change);141 142	return change ? 1 : 0;143}144 145static int tegra210_peq_ram_get(struct snd_kcontrol *kcontrol,146				struct snd_ctl_elem_value *ucontrol)147{148	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;149	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);150	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);151	u32 i, reg_ctrl = params->soc.base;152	u32 reg_data = reg_ctrl + cmpnt->val_bytes;153	s32 *data = (s32 *)biquad_coeff_buffer;154 155	pm_runtime_get_sync(cmpnt->dev);156 157	tegra210_peq_read_ram(ope->peq_regmap, reg_ctrl, reg_data,158			      params->shift, data, params->soc.num_regs);159 160	pm_runtime_put_sync(cmpnt->dev);161 162	for (i = 0; i < params->soc.num_regs; i++)163		ucontrol->value.integer.value[i] = (long)data[i];164 165	return 0;166}167 168static int tegra210_peq_ram_put(struct snd_kcontrol *kcontrol,169				     struct snd_ctl_elem_value *ucontrol)170{171	struct tegra_soc_bytes *params = (void *)kcontrol->private_value;172	struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);173	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);174	u32 i, reg_ctrl = params->soc.base;175	u32 reg_data = reg_ctrl + cmpnt->val_bytes;176	s32 *data = (s32 *)biquad_coeff_buffer;177 178	for (i = 0; i < params->soc.num_regs; i++)179		data[i] = (s32)ucontrol->value.integer.value[i];180 181	pm_runtime_get_sync(cmpnt->dev);182 183	tegra210_peq_write_ram(ope->peq_regmap, reg_ctrl, reg_data,184			       params->shift, data, params->soc.num_regs);185 186	pm_runtime_put_sync(cmpnt->dev);187 188	return 1;189}190 191static int tegra210_peq_param_info(struct snd_kcontrol *kcontrol,192				   struct snd_ctl_elem_info *uinfo)193{194	struct soc_bytes *params = (void *)kcontrol->private_value;195 196	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;197	uinfo->value.integer.min = INT_MIN;198	uinfo->value.integer.max = INT_MAX;199	uinfo->count = params->num_regs;200 201	return 0;202}203 204#define TEGRA210_PEQ_GAIN_PARAMS_CTRL(chan)				  \205	TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Gain Params",	  \206		TEGRA210_PEQ_CFG_RAM_CTRL,				  \207		TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH,			  \208		(TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH * chan), 0xffffffff, \209		tegra210_peq_ram_get, tegra210_peq_ram_put,		  \210		tegra210_peq_param_info)211 212#define TEGRA210_PEQ_SHIFT_PARAMS_CTRL(chan)				  \213	TEGRA_SOC_BYTES_EXT("PEQ Channel-" #chan " Biquad Shift Params",  \214		TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,			  \215		TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH,			  \216		(TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH * chan), 0x1f,	  \217		tegra210_peq_ram_get, tegra210_peq_ram_put,		  \218		tegra210_peq_param_info)219 220static const struct snd_kcontrol_new tegra210_peq_controls[] = {221	SOC_SINGLE_EXT("PEQ Active", TEGRA210_PEQ_CFG,222		       TEGRA210_PEQ_CFG_MODE_SHIFT, 1, 0,223		       tegra210_peq_get, tegra210_peq_put),224 225	SOC_SINGLE_EXT("PEQ Biquad Stages", TEGRA210_PEQ_CFG,226		       TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT,227		       TEGRA210_PEQ_MAX_BIQUAD_STAGES - 1, 0,228		       tegra210_peq_get, tegra210_peq_put),229 230	TEGRA210_PEQ_GAIN_PARAMS_CTRL(0),231	TEGRA210_PEQ_GAIN_PARAMS_CTRL(1),232	TEGRA210_PEQ_GAIN_PARAMS_CTRL(2),233	TEGRA210_PEQ_GAIN_PARAMS_CTRL(3),234	TEGRA210_PEQ_GAIN_PARAMS_CTRL(4),235	TEGRA210_PEQ_GAIN_PARAMS_CTRL(5),236	TEGRA210_PEQ_GAIN_PARAMS_CTRL(6),237	TEGRA210_PEQ_GAIN_PARAMS_CTRL(7),238 239	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(0),240	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(1),241	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(2),242	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(3),243	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(4),244	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(5),245	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(6),246	TEGRA210_PEQ_SHIFT_PARAMS_CTRL(7),247};248 249static bool tegra210_peq_wr_reg(struct device *dev, unsigned int reg)250{251	switch (reg) {252	case TEGRA210_PEQ_SOFT_RESET:253	case TEGRA210_PEQ_CG:254	case TEGRA210_PEQ_CFG ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:255		return true;256	default:257		return false;258	}259}260 261static bool tegra210_peq_rd_reg(struct device *dev, unsigned int reg)262{263	if (tegra210_peq_wr_reg(dev, reg))264		return true;265 266	switch (reg) {267	case TEGRA210_PEQ_STATUS:268		return true;269	default:270		return false;271	}272}273 274static bool tegra210_peq_volatile_reg(struct device *dev, unsigned int reg)275{276	switch (reg) {277	case TEGRA210_PEQ_SOFT_RESET:278	case TEGRA210_PEQ_STATUS:279	case TEGRA210_PEQ_CFG_RAM_CTRL ... TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:280		return true;281	default:282		return false;283	}284}285 286static bool tegra210_peq_precious_reg(struct device *dev, unsigned int reg)287{288	switch (reg) {289	case TEGRA210_PEQ_CFG_RAM_DATA:290	case TEGRA210_PEQ_CFG_RAM_SHIFT_DATA:291		return true;292	default:293		return false;294	}295}296 297static const struct regmap_config tegra210_peq_regmap_config = {298	.name			= "peq",299	.reg_bits		= 32,300	.reg_stride		= 4,301	.val_bits		= 32,302	.max_register		= TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,303	.writeable_reg		= tegra210_peq_wr_reg,304	.readable_reg		= tegra210_peq_rd_reg,305	.volatile_reg		= tegra210_peq_volatile_reg,306	.precious_reg		= tegra210_peq_precious_reg,307	.reg_defaults		= tegra210_peq_reg_defaults,308	.num_reg_defaults	= ARRAY_SIZE(tegra210_peq_reg_defaults),309	.cache_type		= REGCACHE_FLAT,310};311 312void tegra210_peq_restore(struct regmap *regmap, u32 *biquad_gains,313			  u32 *biquad_shifts)314{315	unsigned int i;316 317	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {318		tegra210_peq_write_ram(regmap, TEGRA210_PEQ_CFG_RAM_CTRL,319			TEGRA210_PEQ_CFG_RAM_DATA,320			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),321			biquad_gains,322			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);323 324		tegra210_peq_write_ram(regmap,325			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,326			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,327			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),328			biquad_shifts,329			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);330 331	}332}333 334void tegra210_peq_save(struct regmap *regmap, u32 *biquad_gains,335		       u32 *biquad_shifts)336{337	unsigned int i;338 339	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {340		tegra210_peq_read_ram(regmap,341			TEGRA210_PEQ_CFG_RAM_CTRL,342			TEGRA210_PEQ_CFG_RAM_DATA,343			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),344			biquad_gains,345			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);346 347		tegra210_peq_read_ram(regmap,348			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,349			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,350			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),351			biquad_shifts,352			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);353	}354}355 356int tegra210_peq_component_init(struct snd_soc_component *cmpnt)357{358	struct tegra210_ope *ope = snd_soc_component_get_drvdata(cmpnt);359	unsigned int i;360 361	pm_runtime_get_sync(cmpnt->dev);362	regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,363		TEGRA210_PEQ_CFG_MODE_MASK,364		0 << TEGRA210_PEQ_CFG_MODE_SHIFT);365	regmap_update_bits(ope->peq_regmap, TEGRA210_PEQ_CFG,366		TEGRA210_PEQ_CFG_BIQUAD_STAGES_MASK,367		(TEGRA210_PEQ_BIQUAD_INIT_STAGE - 1) <<368		TEGRA210_PEQ_CFG_BIQUAD_STAGES_SHIFT);369 370	/* Initialize PEQ AHUB RAM with default params */371	for (i = 0; i < TEGRA210_PEQ_MAX_CHANNELS; i++) {372 373		/* Set default gain params */374		tegra210_peq_write_ram(ope->peq_regmap,375			TEGRA210_PEQ_CFG_RAM_CTRL,376			TEGRA210_PEQ_CFG_RAM_DATA,377			(i * TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH),378			(u32 *)&biquad_init_gains,379			TEGRA210_PEQ_GAIN_PARAM_SIZE_PER_CH);380 381		/* Set default shift params */382		tegra210_peq_write_ram(ope->peq_regmap,383			TEGRA210_PEQ_CFG_RAM_SHIFT_CTRL,384			TEGRA210_PEQ_CFG_RAM_SHIFT_DATA,385			(i * TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH),386			(u32 *)&biquad_init_shifts,387			TEGRA210_PEQ_SHIFT_PARAM_SIZE_PER_CH);388 389	}390 391	pm_runtime_put_sync(cmpnt->dev);392 393	snd_soc_add_component_controls(cmpnt, tegra210_peq_controls,394				       ARRAY_SIZE(tegra210_peq_controls));395 396	return 0;397}398 399int tegra210_peq_regmap_init(struct platform_device *pdev)400{401	struct device *dev = &pdev->dev;402	struct tegra210_ope *ope = dev_get_drvdata(dev);403	struct device_node *child;404	struct resource mem;405	void __iomem *regs;406	int err;407 408	child = of_get_child_by_name(dev->of_node, "equalizer");409	if (!child)410		return -ENODEV;411 412	err = of_address_to_resource(child, 0, &mem);413	of_node_put(child);414	if (err < 0) {415		dev_err(dev, "fail to get PEQ resource\n");416		return err;417	}418 419	mem.flags = IORESOURCE_MEM;420	regs = devm_ioremap_resource(dev, &mem);421	if (IS_ERR(regs))422		return PTR_ERR(regs);423	ope->peq_regmap = devm_regmap_init_mmio(dev, regs,424						&tegra210_peq_regmap_config);425	if (IS_ERR(ope->peq_regmap)) {426		dev_err(dev, "regmap init failed\n");427		return PTR_ERR(ope->peq_regmap);428	}429 430	regcache_cache_only(ope->peq_regmap, true);431 432	return 0;433}434