// SPDX-License-Identifier: GPL-2.0 // // TAS2563/TAS2781 Common functions for HDA and ASoC Audio drivers based on I2C // // Copyright 2025 Texas Instruments, Inc. // // Author: Shenghao Ding <shenghao-ding@ti.com>
if (client->addr != tasdev->dev_addr) {
client->addr = tasdev->dev_addr; /* All tas2781s share the same regmap, clear the page * inside regmap once switching to another tas2781. * Register 0 at any pages and any books inside tas2781 * is the same one for page-switching.
*/
ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0); if (ret < 0) {
dev_err(tas_priv->dev, "%s, E=%d channel:%d\n",
__func__, ret, chn); goto out;
}
}
if (tasdev->cur_book != book) {
ret = regmap_write(map, TASDEVICE_BOOKCTL_REG, book); if (ret < 0) {
dev_err(tas_priv->dev, "%s, E=%d\n",
__func__, ret); goto out;
}
tasdev->cur_book = book;
}
} else {
ret = -EINVAL;
dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
chn);
}
if (client->addr != tasdev->dev_addr) {
client->addr = tasdev->dev_addr; /* All devices share the same regmap, clear the page * inside regmap once switching to another device. * Register 0 at any pages and any books inside tas2781 * is the same one for page-switching.
*/
ret = regmap_write(map, TASDEVICE_PAGE_SELECT, 0); if (ret < 0) {
dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret); return ret;
} return 1;
} return 0;
}
EXPORT_SYMBOL_GPL(tasdev_chn_switch);
int tasdevice_dev_update_bits( struct tasdevice_priv *tas_priv, unsignedshort chn, unsignedint reg, unsignedint mask, unsignedint 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_update_bits(map, TASDEVICE_PGRG(reg),
mask, value); 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);
ret = -EINVAL;
}
staticint tasdevice_clamp(int val, int max, unsignedint invert)
{ if (val > max)
val = max; if (invert)
val = max - val; if (val < 0)
val = 0; return val;
}
int tasdevice_amp_putvol(struct tasdevice_priv *tas_priv, struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
{ unsignedint invert = mc->invert; unsignedchar mask; int max = mc->max; int err_cnt = 0; int val, i, ret;
mask = (1 << fls(max)) - 1;
mask <<= mc->shift;
val = tasdevice_clamp(ucontrol->value.integer.value[0], max, invert); for (i = 0; i < tas_priv->ndev; i++) {
ret = tasdevice_dev_update_bits(tas_priv, i,
mc->reg, mask, (unsignedint)(val << mc->shift)); if (!ret) continue;
err_cnt++;
dev_err(tas_priv->dev, "set AMP vol error in dev %d\n", i);
}
/* All the devices set error, return 0 */ return (err_cnt == tas_priv->ndev) ? 0 : 1;
}
EXPORT_SYMBOL_GPL(tasdevice_amp_putvol);
int tasdevice_amp_getvol(struct tasdevice_priv *tas_priv, struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
{ unsignedint invert = mc->invert; unsignedchar mask = 0; int max = mc->max; int ret = 0; int val;
/* Read the primary device */
ret = tasdevice_dev_read(tas_priv, 0, mc->reg, &val); if (ret) {
dev_err(tas_priv->dev, "%s, get AMP vol error\n", __func__); goto out;
}
int tasdevice_digital_getvol(struct tasdevice_priv *tas_priv, struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
{ unsignedint invert = mc->invert; int max = mc->max; int ret, val;
/* Read the primary device as the whole */
ret = tasdevice_dev_read(tas_priv, 0, mc->reg, &val); if (ret) {
dev_err(tas_priv->dev, "%s, get digital vol error\n",
__func__); goto out;
}
val = tasdevice_clamp(val, max, invert);
ucontrol->value.integer.value[0] = val;
out: return ret;
}
EXPORT_SYMBOL_GPL(tasdevice_digital_getvol);
int tasdevice_digital_putvol(struct tasdevice_priv *tas_priv, struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
{ unsignedint invert = mc->invert; int max = mc->max; int err_cnt = 0; int ret; int val, i;
val = tasdevice_clamp(ucontrol->value.integer.value[0], max, invert);
for (i = 0; i < tas_priv->ndev; i++) {
ret = tasdevice_dev_write(tas_priv, i, mc->reg,
(unsignedint)val); if (!ret) continue;
err_cnt++;
dev_err(tas_priv->dev, "set digital vol err in dev %d\n", i);
}
/* All the devices set error, return 0 */ return (err_cnt == tas_priv->ndev) ? 0 : 1;
}
EXPORT_SYMBOL_GPL(tasdevice_digital_putvol);
void tasdevice_reset(struct tasdevice_priv *tas_dev)
{ int ret, i;
if (tas_dev->reset) {
gpiod_set_value_cansleep(tas_dev->reset, 0);
usleep_range(500, 1000);
gpiod_set_value_cansleep(tas_dev->reset, 1);
} else { for (i = 0; i < tas_dev->ndev; i++) {
ret = tasdevice_dev_write(tas_dev, i,
TASDEVICE_REG_SWRESET,
TASDEVICE_REG_SWRESET_RESET); if (ret < 0)
dev_err(tas_dev->dev, "dev %d swreset fail, %d\n",
i, ret);
}
}
usleep_range(1000, 1050);
}
EXPORT_SYMBOL_GPL(tasdevice_reset);
int tascodec_init(struct tasdevice_priv *tas_priv, void *codec, struct module *module, void (*cont)(conststruct firmware *fw, void *context))
{ int ret = 0;
/* Codec Lock Hold to ensure that codec_probe and firmware parsing and * loading do not simultaneously execute.
*/
mutex_lock(&tas_priv->codec_lock);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.