linux/sound/soc/codecs/tas2781-comlib.c
Shenghao Ding 4fe2385134 ALSA: hda/tas2781: Move and unified the calibrated-data getting function for SPI and I2C into the tas2781_hda lib
Calibration data getting function for SPI and I2C HDA drivers are almost
same, which read the calibration data from UEFI. To put them into
tas2781_hda lib for code cleanup is more reasonable than to still keep
them in the codec driver. For tas2781 codec driver, there're two different
sources for calibrated data, one is from bin file, generated in factory
test, requested and read in codec driver side; the other is from user
space during device bootup.

Signed-off-by: Shenghao Ding <shenghao-ding@ti.com>

Link: https://patch.msgid.link/20250522014347.1163-1-shenghao-ding@ti.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2025-05-22 09:09:40 +02:00

221 lines
4.7 KiB
C

// SPDX-License-Identifier: GPL-2.0
//
// TAS2563/TAS2781 Common functions for HDA and ASoC Audio drivers
//
// Copyright 2023 - 2025 Texas Instruments, Inc.
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
#include <linux/crc8.h>
#include <linux/dev_printk.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/tas2781.h>
int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int *val)
{
int ret = 0;
if (chn < tas_priv->ndev) {
struct regmap *map = tas_priv->regmap;
ret = tas_priv->change_chn_book(tas_priv, chn,
TASDEVICE_BOOK_ID(reg));
if (ret < 0)
goto out;
ret = regmap_read(map, TASDEVICE_PGRG(reg), val);
if (ret < 0)
dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
} else {
ret = -EINVAL;
dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
chn);
}
out:
return ret;
}
EXPORT_SYMBOL_GPL(tasdevice_dev_read);
int tasdevice_dev_bulk_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned char *data,
unsigned int len)
{
int ret = 0;
if (chn < tas_priv->ndev) {
struct regmap *map = tas_priv->regmap;
ret = tas_priv->change_chn_book(tas_priv, chn,
TASDEVICE_BOOK_ID(reg));
if (ret < 0)
goto out;
ret = regmap_bulk_read(map, TASDEVICE_PGRG(reg), data, len);
if (ret < 0)
dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
} else
dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
chn);
out:
return ret;
}
EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_read);
int tasdevice_dev_write(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int value)
{
int ret = 0;
if (chn < tas_priv->ndev) {
struct regmap *map = tas_priv->regmap;
ret = tas_priv->change_chn_book(tas_priv, chn,
TASDEVICE_BOOK_ID(reg));
if (ret < 0)
goto out;
ret = regmap_write(map, TASDEVICE_PGRG(reg),
value);
if (ret < 0)
dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
} else {
ret = -EINVAL;
dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
chn);
}
out:
return ret;
}
EXPORT_SYMBOL_GPL(tasdevice_dev_write);
int tasdevice_dev_bulk_write(
struct tasdevice_priv *tas_priv, unsigned short chn,
unsigned int reg, unsigned char *data,
unsigned int len)
{
int ret = 0;
if (chn < tas_priv->ndev) {
struct regmap *map = tas_priv->regmap;
ret = tas_priv->change_chn_book(tas_priv, chn,
TASDEVICE_BOOK_ID(reg));
if (ret < 0)
goto out;
ret = regmap_bulk_write(map, TASDEVICE_PGRG(reg),
data, len);
if (ret < 0)
dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
} else {
ret = -EINVAL;
dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
chn);
}
out:
return ret;
}
EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_write);
static void tasdev_dsp_prog_blk_remove(struct tasdevice_prog *prog)
{
struct tasdevice_data *tas_dt;
struct tasdev_blk *blk;
unsigned int i;
if (!prog)
return;
tas_dt = &(prog->dev_data);
if (!tas_dt->dev_blks)
return;
for (i = 0; i < tas_dt->nr_blk; i++) {
blk = &(tas_dt->dev_blks[i]);
kfree(blk->data);
}
kfree(tas_dt->dev_blks);
}
static void tasdev_dsp_prog_remove(struct tasdevice_prog *prog,
unsigned short nr)
{
int i;
for (i = 0; i < nr; i++)
tasdev_dsp_prog_blk_remove(&prog[i]);
kfree(prog);
}
static void tasdev_dsp_cfg_blk_remove(struct tasdevice_config *cfg)
{
struct tasdevice_data *tas_dt;
struct tasdev_blk *blk;
unsigned int i;
if (cfg) {
tas_dt = &(cfg->dev_data);
if (!tas_dt->dev_blks)
return;
for (i = 0; i < tas_dt->nr_blk; i++) {
blk = &(tas_dt->dev_blks[i]);
kfree(blk->data);
}
kfree(tas_dt->dev_blks);
}
}
static void tasdev_dsp_cfg_remove(struct tasdevice_config *config,
unsigned short nr)
{
int i;
for (i = 0; i < nr; i++)
tasdev_dsp_cfg_blk_remove(&config[i]);
kfree(config);
}
void tasdevice_dsp_remove(void *context)
{
struct tasdevice_priv *tas_dev = (struct tasdevice_priv *) context;
struct tasdevice_fw *tas_fmw = tas_dev->fmw;
if (!tas_dev->fmw)
return;
if (tas_fmw->programs)
tasdev_dsp_prog_remove(tas_fmw->programs,
tas_fmw->nr_programs);
if (tas_fmw->configs)
tasdev_dsp_cfg_remove(tas_fmw->configs,
tas_fmw->nr_configurations);
kfree(tas_fmw);
tas_dev->fmw = NULL;
}
EXPORT_SYMBOL_GPL(tasdevice_dsp_remove);
void tasdevice_remove(struct tasdevice_priv *tas_priv)
{
mutex_destroy(&tas_priv->codec_lock);
}
EXPORT_SYMBOL_GPL(tasdevice_remove);
MODULE_DESCRIPTION("TAS2781 common library");
MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
MODULE_LICENSE("GPL");