ALSA: hda/tas2781: Remove tas2781_spi_fwlib.c and leverage SND_SOC_TAS2781_FMWLIB

Most codes in tas2781_spi_fwlib.c are same as tas2781-fmwlib.c, mainly for
firmware parsing, only differece is the register reading, bit update and
book switching in i2c and spi. The main purpose of this patch is for code
cleaup and arrange the shared part for i2c and spi.

Signed-off-by: Shenghao Ding <shenghao-ding@ti.com>
Acked-by: Mark Brown <broonie@kernel.org>
Link: https://patch.msgid.link/20250429111055.567-1-shenghao-ding@ti.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Shenghao Ding
2025-04-30 07:36:25 +02:00
committed by Takashi Iwai
parent 849c83fe49
commit 9fa6a693ad
15 changed files with 779 additions and 2874 deletions
+37
View File
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0 */
//
// ALSA SoC Texas Instruments TAS2563/TAS2781 Audio Smart Amplifier
//
// Copyright (C) 2025 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2563/TAS2781 driver implements a flexible and configurable
// algo coefficient setting for one, two, or even multiple
// TAS2563/TAS2781 chips.
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
//
#ifndef __TAS2781_COMLIB_I2C_H__
#define __TAS2781_COMLIB_I2C_H__
void tasdevice_reset(struct tasdevice_priv *tas_dev);
int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
struct module *module,
void (*cont)(const struct firmware *fw, void *context));
struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c);
int tasdevice_init(struct tasdevice_priv *tas_priv);
int tasdev_chn_switch(struct tasdevice_priv *tas_priv,
unsigned short chn);
int tasdevice_dev_update_bits(
struct tasdevice_priv *tasdevice, unsigned short chn,
unsigned int reg, unsigned int mask, unsigned int value);
int tasdevice_amp_putvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
int tasdevice_amp_getvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
int tasdevice_digital_getvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
int tasdevice_digital_putvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
#endif /* __TAS2781_COMLIB_I2C_H__ */
+19 -26
View File
@@ -32,6 +32,8 @@
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
#define TASDEVICE_CRC8_POLYNOMIAL 0x4d
/* PAGE Control Register (available in page0 of each book) */
#define TASDEVICE_PAGE_SELECT 0x00
#define TASDEVICE_BOOKCTL_PAGE 0x00
@@ -193,6 +195,7 @@ struct tasdevice_priv {
bool force_fwload_status;
bool playback_started;
bool isacpi;
bool isspi;
bool is_user_space_calidata;
unsigned int global_addr;
@@ -210,41 +213,31 @@ struct tasdevice_priv {
int (*tasdevice_load_block)(struct tasdevice_priv *tas_priv,
struct tasdev_blk *block);
int (*change_chn_book)(struct tasdevice_priv *tas_priv,
unsigned short chn, int book);
int (*update_bits)(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int mask,
unsigned int value);
int (*dev_read)(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int *value);
int (*dev_bulk_read)(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned char *p_data,
unsigned int n_length);
int (*save_calibration)(struct tasdevice_priv *tas_priv);
void (*apply_calibration)(struct tasdevice_priv *tas_priv);
};
void tasdevice_reset(struct tasdevice_priv *tas_dev);
int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
struct module *module,
void (*cont)(const struct firmware *fw, void *context));
struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c);
int tasdevice_init(struct tasdevice_priv *tas_priv);
void tasdevice_remove(struct tasdevice_priv *tas_priv);
int tasdevice_save_calibration(struct tasdevice_priv *tas_priv);
void tasdevice_apply_calibration(struct tasdevice_priv *tas_priv);
int tasdev_chn_switch(struct tasdevice_priv *tas_priv,
unsigned short chn);
int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int *value);
int tasdevice_dev_bulk_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned char *p_data,
unsigned int n_length);
int tasdevice_dev_write(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int value);
int tasdevice_dev_bulk_write(
struct tasdevice_priv *tas_priv, unsigned short chn,
unsigned int reg, unsigned char *p_data, unsigned int n_length);
int tasdevice_dev_bulk_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned char *p_data,
unsigned int n_length);
int tasdevice_dev_update_bits(
struct tasdevice_priv *tasdevice, unsigned short chn,
unsigned int reg, unsigned int mask, unsigned int value);
int tasdevice_amp_putvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
int tasdevice_amp_getvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
int tasdevice_digital_putvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
int tasdevice_digital_getvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc);
void tasdevice_remove(struct tasdevice_priv *tas_priv);
int tasdevice_save_calibration(struct tasdevice_priv *tas_priv);
void tasdevice_apply_calibration(struct tasdevice_priv *tas_priv);
#endif /* __TAS2781_H__ */
+3 -1
View File
@@ -186,7 +186,7 @@ config SND_HDA_SCODEC_TAS2781_I2C
depends on ACPI
depends on EFI
depends on SND_SOC
select SND_SOC_TAS2781_COMLIB
select SND_SOC_TAS2781_COMLIB_I2C
select SND_SOC_TAS2781_FMWLIB
select CRC32
help
@@ -202,6 +202,8 @@ config SND_HDA_SCODEC_TAS2781_SPI
depends on ACPI
depends on EFI
depends on SND_SOC
select SND_SOC_TAS2781_FMWLIB
select CRC8
select CRC32
help
Say Y or M here to include TAS2781 SPI HD-audio side codec support
+1 -1
View File
@@ -39,7 +39,7 @@ snd-hda-scodec-cs35l56-i2c-y := cs35l56_hda_i2c.o
snd-hda-scodec-cs35l56-spi-y := cs35l56_hda_spi.o
snd-hda-scodec-component-y := hda_component.o
snd-hda-scodec-tas2781-i2c-y := tas2781_hda_i2c.o
snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o tas2781_spi_fwlib.o
snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o
# common driver
obj-$(CONFIG_SND_HDA) := snd-hda-codec.o
-157
View File
@@ -1,157 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
//
// ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier
//
// Copyright (C) 2024 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2781 driver implements a flexible and configurable
// algo coefficient setting for TAS2781 chips.
//
// Author: Baojun Xu <baojun.xu@ti.com>
//
#ifndef __TAS2781_SPI_H__
#define __TAS2781_SPI_H__
#define TASDEVICE_RATES \
(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200)
#define TASDEVICE_FORMATS \
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
#define TASDEVICE_MAX_BOOK_NUM 256
#define TASDEVICE_MAX_PAGE 256
#define TASDEVICE_MAX_SIZE (TASDEVICE_MAX_BOOK_NUM * TASDEVICE_MAX_PAGE)
/* PAGE Control Register (available in page0 of each book) */
#define TASDEVICE_PAGE_SELECT 0x00
#define TASDEVICE_BOOKCTL_PAGE 0x00
#define TASDEVICE_BOOKCTL_REG GENMASK(7, 1)
#define TASDEVICE_BOOK_ID(reg) (((reg) & GENMASK(24, 16)) >> 16)
#define TASDEVICE_PAGE_ID(reg) (((reg) & GENMASK(15, 8)) >> 8)
#define TASDEVICE_REG_ID(reg) (((reg) & GENMASK(7, 1)) >> 1)
#define TASDEVICE_PAGE_REG(reg) ((reg) & GENMASK(15, 1))
#define TASDEVICE_REG(book, page, reg) \
(((book) << 16) | ((page) << 8) | ((reg) << 1))
/* Software Reset */
#define TAS2781_REG_SWRESET TASDEVICE_REG(0x0, 0x0, 0x01)
#define TAS2781_REG_SWRESET_RESET BIT(0)
/* System Reset Check Register */
#define TAS2781_REG_CLK_CONFIG TASDEVICE_REG(0x0, 0x0, 0x5c)
#define TAS2781_REG_CLK_CONFIG_RESET (0x19)
#define TAS2781_PRE_POST_RESET_CFG 3
/* Block Checksum */
#define TASDEVICE_CHECKSUM TASDEVICE_REG(0x0, 0x0, 0x7e)
/* Volume control */
#define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1a)
#define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03)
#define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1)
#define TASDEVICE_CMD_SING_W 0x1
#define TASDEVICE_CMD_BURST 0x2
#define TASDEVICE_CMD_DELAY 0x3
#define TASDEVICE_CMD_FIELD_W 0x4
#define TAS2781_SPI_MAX_FREQ (4 * HZ_PER_MHZ)
#define TASDEVICE_CRC8_POLYNOMIAL 0x4d
#define TASDEVICE_SPEAKER_CALIBRATION_SIZE 20
/* Flag of calibration registers address. */
#define TASDEVICE_CALIBRATION_REG_ADDRESS BIT(7)
#define TASDEVICE_CALIBRATION_DATA_NAME L"CALI_DATA"
#define TASDEVICE_CALIBRATION_DATA_SIZE 256
enum calib_data {
R0_VAL = 0,
INV_R0,
R0LOW,
POWER,
TLIM,
CALIB_MAX
};
struct tasdevice_priv {
struct tasdevice_fw *cali_data_fmw;
struct tasdevice_rca rcabin;
struct tasdevice_fw *fmw;
struct gpio_desc *reset;
struct mutex codec_lock;
struct regmap *regmap;
struct device *dev;
unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE];
unsigned char coef_binaryname[64];
unsigned char rca_binaryname[64];
unsigned char dev_name[32];
bool force_fwload_status;
bool playback_started;
bool is_loading;
bool is_loaderr;
unsigned int cali_reg_array[CALIB_MAX];
unsigned int cali_data[CALIB_MAX];
unsigned int err_code;
void *codec;
int cur_book;
int cur_prog;
int cur_conf;
int fw_state;
int index;
int irq;
int (*fw_parse_variable_header)(struct tasdevice_priv *tas_priv,
const struct firmware *fmw,
int offset);
int (*fw_parse_program_data)(struct tasdevice_priv *tas_priv,
struct tasdevice_fw *tas_fmw,
const struct firmware *fmw, int offset);
int (*fw_parse_configuration_data)(struct tasdevice_priv *tas_priv,
struct tasdevice_fw *tas_fmw,
const struct firmware *fmw,
int offset);
int (*tasdevice_load_block)(struct tasdevice_priv *tas_priv,
struct tasdev_blk *block);
int (*save_calibration)(struct tasdevice_priv *tas_priv);
void (*apply_calibration)(struct tasdevice_priv *tas_priv);
};
int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv,
unsigned int reg, unsigned int *value);
int tasdevice_spi_dev_write(struct tasdevice_priv *tas_priv,
unsigned int reg, unsigned int value);
int tasdevice_spi_dev_bulk_write(struct tasdevice_priv *tas_priv,
unsigned int reg, unsigned char *p_data,
unsigned int n_length);
int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv,
unsigned int reg, unsigned char *p_data,
unsigned int n_length);
int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tasdevice,
unsigned int reg, unsigned int mask,
unsigned int value);
void tasdevice_spi_select_cfg_blk(void *context, int conf_no,
unsigned char block_type);
void tasdevice_spi_config_info_remove(void *context);
int tasdevice_spi_dsp_parser(void *context);
int tasdevice_spi_rca_parser(void *context, const struct firmware *fmw);
void tasdevice_spi_dsp_remove(void *context);
void tasdevice_spi_calbin_remove(void *context);
int tasdevice_spi_select_tuningprm_cfg(void *context, int prm, int cfg_no,
int rca_conf_no);
int tasdevice_spi_prmg_load(void *context, int prm_no);
int tasdevice_spi_prmg_calibdata_load(void *context, int prm_no);
void tasdevice_spi_tuning_switch(void *context, int state);
int tas2781_spi_load_calibration(void *context, char *file_name,
unsigned short i);
#endif /* __TAS2781_SPI_H__ */
+3
View File
@@ -9,6 +9,9 @@
#include <sound/asound.h>
#define TASDEVICE_CALIBRATION_DATA_NAME L"CALI_DATA"
#define TASDEV_CALIB_N 5
/*
* No standard control callbacks for SNDRV_CTL_ELEM_IFACE_CARD
* Define two controls, one is Volume control callbacks, the other is
+8 -18
View File
@@ -22,6 +22,7 @@
#include <sound/hda_codec.h>
#include <sound/soc.h>
#include <sound/tas2781.h>
#include <sound/tas2781-comlib-i2c.h>
#include <sound/tlv.h>
#include <sound/tas2781-tlv.h>
@@ -34,15 +35,6 @@
#define TASDEVICE_SPEAKER_CALIBRATION_SIZE 20
enum calib_data {
R0_VAL = 0,
INV_R0,
R0LOW,
POWER,
TLIM,
CALIB_MAX
};
#define TAS2563_MAX_CHANNELS 4
#define TAS2563_CAL_POWER TASDEVICE_REG(0, 0x0d, 0x3c)
@@ -50,17 +42,15 @@ enum calib_data {
#define TAS2563_CAL_INVR0 TASDEVICE_REG(0, 0x0f, 0x40)
#define TAS2563_CAL_R0_LOW TASDEVICE_REG(0, 0x0f, 0x48)
#define TAS2563_CAL_TLIM TASDEVICE_REG(0, 0x10, 0x14)
#define TAS2563_CAL_N 5
#define TAS2563_CAL_DATA_SIZE 4
#define TAS2563_CAL_CH_SIZE 20
#define TAS2563_CAL_ARRAY_SIZE 80
static unsigned int cal_regs[TAS2563_CAL_N] = {
static unsigned int cal_regs[TASDEV_CALIB_N] = {
TAS2563_CAL_POWER, TAS2563_CAL_R0, TAS2563_CAL_INVR0,
TAS2563_CAL_R0_LOW, TAS2563_CAL_TLIM,
};
struct tas2781_hda {
struct device *dev;
struct tasdevice_priv *priv;
@@ -475,7 +465,7 @@ static void tas2563_apply_calib(struct tasdevice_priv *tas_priv)
int ret;
for (int i = 0; i < tas_priv->ndev; i++) {
for (int j = 0; j < TAS2563_CAL_N; ++j) {
for (int j = 0; j < TASDEV_CALIB_N; ++j) {
data = cpu_to_be32(
*(uint32_t *)&tas_priv->cali_data.data[offset]);
ret = tasdevice_dev_bulk_write(tas_priv, i, cal_regs[j],
@@ -493,7 +483,7 @@ static int tas2563_save_calibration(struct tasdevice_priv *tas_priv)
static efi_guid_t efi_guid = EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc,
0x09, 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92);
static efi_char16_t *efi_vars[TAS2563_MAX_CHANNELS][TAS2563_CAL_N] = {
static efi_char16_t *efi_vars[TAS2563_MAX_CHANNELS][TASDEV_CALIB_N] = {
{ L"Power_1", L"R0_1", L"InvR0_1", L"R0_Low_1", L"TLim_1" },
{ L"Power_2", L"R0_2", L"InvR0_2", L"R0_Low_2", L"TLim_2" },
{ L"Power_3", L"R0_3", L"InvR0_3", L"R0_Low_3", L"TLim_3" },
@@ -511,7 +501,7 @@ static int tas2563_save_calibration(struct tasdevice_priv *tas_priv)
return -ENOMEM;
for (int i = 0; i < tas_priv->ndev; ++i) {
for (int j = 0; j < TAS2563_CAL_N; ++j) {
for (int j = 0; j < TASDEV_CALIB_N; ++j) {
status = efi.get_variable(efi_vars[i][j],
&efi_guid, &attr, &max_size,
&tas_priv->cali_data.data[offset]);
@@ -535,7 +525,7 @@ static void tas2781_apply_calib(struct tasdevice_priv *tas_priv)
{
struct calidata *cali_data = &tas_priv->cali_data;
struct cali_reg *r = &cali_data->cali_reg_array;
unsigned int cali_reg[CALIB_MAX] = {
unsigned int cali_reg[TASDEV_CALIB_N] = {
TASDEVICE_REG(0, 0x17, 0x74),
TASDEVICE_REG(0, 0x18, 0x0c),
TASDEVICE_REG(0, 0x18, 0x14),
@@ -555,7 +545,7 @@ static void tas2781_apply_calib(struct tasdevice_priv *tas_priv)
}
for (i = 0; i < tas_priv->ndev; i++) {
for (j = 0; j < CALIB_MAX; j++) {
for (j = 0; j < TASDEV_CALIB_N; j++) {
data = cpu_to_be32(
*(uint32_t *)&tas_priv->cali_data.data[oft]);
rc = tasdevice_dev_bulk_write(tas_priv, i,
@@ -578,7 +568,7 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv)
{
efi_guid_t efi_guid = EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d,
0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3);
static efi_char16_t efi_name[] = L"CALI_DATA";
static efi_char16_t efi_name[] = TASDEVICE_CALIBRATION_DATA_NAME;
unsigned int attr, crc;
unsigned int *tmp_val;
efi_status_t status;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+6 -2
View File
@@ -260,6 +260,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_TAS2770
imply SND_SOC_TAS2780
imply SND_SOC_TAS2781_COMLIB
imply SND_SOC_TAS2781_COMLIB_I2C
imply SND_SOC_TAS2781_FMWLIB
imply SND_SOC_TAS2781_I2C
imply SND_SOC_TAS5086
@@ -1991,20 +1992,23 @@ config SND_SOC_TAS2780
digital input mono Class-D audio power amplifiers.
config SND_SOC_TAS2781_COMLIB
tristate
config SND_SOC_TAS2781_COMLIB_I2C
depends on I2C
select CRC8
select REGMAP_I2C
tristate
config SND_SOC_TAS2781_FMWLIB
depends on SND_SOC_TAS2781_COMLIB
select SND_SOC_TAS2781_COMLIB
tristate
default n
config SND_SOC_TAS2781_I2C
tristate "Texas Instruments TAS2781 speaker amplifier based on I2C"
depends on I2C
select SND_SOC_TAS2781_COMLIB
select SND_SOC_TAS2781_COMLIB_I2C
select SND_SOC_TAS2781_FMWLIB
help
Enable support for Texas Instruments TAS2781 Smart Amplifier
+2
View File
@@ -305,6 +305,7 @@ snd-soc-tas6424-y := tas6424.o
snd-soc-tda7419-y := tda7419.o
snd-soc-tas2770-y := tas2770.o
snd-soc-tas2781-comlib-y := tas2781-comlib.o
snd-soc-tas2781-comlib-i2c-y := tas2781-comlib-i2c.o
snd-soc-tas2781-fmwlib-y := tas2781-fmwlib.o
snd-soc-tas2781-i2c-y := tas2781-i2c.o
snd-soc-tfa9879-y := tfa9879.o
@@ -713,6 +714,7 @@ obj-$(CONFIG_SND_SOC_TAS2562) += snd-soc-tas2562.o
obj-$(CONFIG_SND_SOC_TAS2764) += snd-soc-tas2764.o
obj-$(CONFIG_SND_SOC_TAS2780) += snd-soc-tas2780.o
obj-$(CONFIG_SND_SOC_TAS2781_COMLIB) += snd-soc-tas2781-comlib.o
obj-$(CONFIG_SND_SOC_TAS2781_COMLIB_I2C) += snd-soc-tas2781-comlib-i2c.o
obj-$(CONFIG_SND_SOC_TAS2781_FMWLIB) += snd-soc-tas2781-fmwlib.o
obj-$(CONFIG_SND_SOC_TAS2781_I2C) += snd-soc-tas2781-i2c.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
+375
View File
@@ -0,0 +1,375 @@
// 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>
#include <linux/crc8.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.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/pcm_params.h>
#include <sound/soc.h>
#include <sound/tas2781.h>
#include <sound/tas2781-comlib-i2c.h>
static const struct regmap_range_cfg tasdevice_ranges[] = {
{
.range_min = 0,
.range_max = 256 * 128,
.selector_reg = TASDEVICE_PAGE_SELECT,
.selector_mask = 0xff,
.selector_shift = 0,
.window_start = 0,
.window_len = 128,
},
};
static const struct regmap_config tasdevice_regmap = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_NONE,
.ranges = tasdevice_ranges,
.num_ranges = ARRAY_SIZE(tasdevice_ranges),
.max_register = 256 * 128,
};
static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv,
unsigned short chn, int book)
{
struct i2c_client *client = (struct i2c_client *)tas_priv->client;
int ret = 0;
if (chn < tas_priv->ndev) {
struct tasdevice *tasdev = &tas_priv->tasdevice[chn];
struct regmap *map = tas_priv->regmap;
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);
}
out:
return ret;
}
int tasdev_chn_switch(struct tasdevice_priv *tas_priv,
unsigned short chn)
{
struct i2c_client *client = (struct i2c_client *)tas_priv->client;
struct tasdevice *tasdev = &tas_priv->tasdevice[chn];
struct regmap *map = tas_priv->regmap;
int ret;
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, unsigned short chn,
unsigned int reg, unsigned int mask, 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_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;
}
out:
return ret;
}
EXPORT_SYMBOL_GPL(tasdevice_dev_update_bits);
struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c)
{
struct tasdevice_priv *tas_priv;
tas_priv = devm_kzalloc(&i2c->dev, sizeof(*tas_priv), GFP_KERNEL);
if (!tas_priv)
return NULL;
tas_priv->dev = &i2c->dev;
tas_priv->client = (void *)i2c;
return tas_priv;
}
EXPORT_SYMBOL_GPL(tasdevice_kzalloc);
int tasdevice_init(struct tasdevice_priv *tas_priv)
{
int ret = 0;
int i;
tas_priv->regmap = devm_regmap_init_i2c(tas_priv->client,
&tasdevice_regmap);
if (IS_ERR(tas_priv->regmap)) {
ret = PTR_ERR(tas_priv->regmap);
dev_err(tas_priv->dev, "Failed to allocate register map: %d\n",
ret);
goto out;
}
tas_priv->cur_prog = -1;
tas_priv->cur_conf = -1;
tas_priv->isspi = false;
for (i = 0; i < tas_priv->ndev; i++) {
tas_priv->tasdevice[i].cur_book = -1;
tas_priv->tasdevice[i].cur_prog = -1;
tas_priv->tasdevice[i].cur_conf = -1;
}
tas_priv->update_bits = tasdevice_dev_update_bits;
tas_priv->change_chn_book = tasdevice_change_chn_book;
tas_priv->dev_read = tasdevice_dev_read;
tas_priv->dev_bulk_read = tasdevice_dev_bulk_read;
mutex_init(&tas_priv->codec_lock);
out:
return ret;
}
EXPORT_SYMBOL_GPL(tasdevice_init);
static int tasdevice_clamp(int val, int max, unsigned int 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)
{
unsigned int invert = mc->invert;
unsigned char 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, (unsigned int)(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)
{
unsigned int invert = mc->invert;
unsigned char 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;
}
mask = (1 << fls(max)) - 1;
mask <<= mc->shift;
val = (val & mask) >> mc->shift;
val = tasdevice_clamp(val, max, invert);
ucontrol->value.integer.value[0] = val;
out:
return ret;
}
EXPORT_SYMBOL_GPL(tasdevice_amp_getvol);
int tasdevice_digital_getvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
{
unsigned int 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)
{
unsigned int 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,
(unsigned int)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)(const struct 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);
if (tas_priv->name_prefix)
scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin",
tas_priv->name_prefix, tas_priv->dev_name,
tas_priv->ndev);
else
scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin",
tas_priv->dev_name, tas_priv->ndev);
crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL);
tas_priv->codec = codec;
ret = request_firmware_nowait(module, FW_ACTION_UEVENT,
tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv,
cont);
if (ret)
dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n",
ret);
/* Codec Lock Release*/
mutex_unlock(&tas_priv->codec_lock);
return ret;
}
EXPORT_SYMBOL_GPL(tascodec_init);
void tasdevice_remove(struct tasdevice_priv *tas_priv)
{
mutex_destroy(&tas_priv->codec_lock);
}
EXPORT_SYMBOL_GPL(tasdevice_remove);
MODULE_DESCRIPTION("TAS2781 common library for I2C");
MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
MODULE_LICENSE("GPL");
+40 -386
View File
@@ -2,14 +2,14 @@
//
// TAS2563/TAS2781 Common functions for HDA and ASoC Audio drivers
//
// Copyright 2023 - 2024 Texas Instruments, Inc.
// 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/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -17,103 +17,8 @@
#include <linux/of_irq.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tas2781.h>
#define TASDEVICE_CRC8_POLYNOMIAL 0x4d
static const struct regmap_range_cfg tasdevice_ranges[] = {
{
.range_min = 0,
.range_max = 256 * 128,
.selector_reg = TASDEVICE_PAGE_SELECT,
.selector_mask = 0xff,
.selector_shift = 0,
.window_start = 0,
.window_len = 128,
},
};
static const struct regmap_config tasdevice_regmap = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_NONE,
.ranges = tasdevice_ranges,
.num_ranges = ARRAY_SIZE(tasdevice_ranges),
.max_register = 256 * 128,
};
static int tasdevice_change_chn_book(struct tasdevice_priv *tas_priv,
unsigned short chn, int book)
{
struct i2c_client *client = (struct i2c_client *)tas_priv->client;
int ret = 0;
if (chn < tas_priv->ndev) {
struct tasdevice *tasdev = &tas_priv->tasdevice[chn];
struct regmap *map = tas_priv->regmap;
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);
}
out:
return ret;
}
int tasdev_chn_switch(struct tasdevice_priv *tas_priv,
unsigned short chn)
{
struct i2c_client *client = (struct i2c_client *)tas_priv->client;
struct tasdevice *tasdev = &tas_priv->tasdevice[chn];
struct regmap *map = tas_priv->regmap;
int ret;
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_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int *val)
{
@@ -122,7 +27,7 @@ int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
if (chn < tas_priv->ndev) {
struct regmap *map = tas_priv->regmap;
ret = tasdevice_change_chn_book(tas_priv, chn,
ret = tas_priv->change_chn_book(tas_priv, chn,
TASDEVICE_BOOK_ID(reg));
if (ret < 0)
goto out;
@@ -141,6 +46,32 @@ out:
}
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)
{
@@ -149,7 +80,7 @@ int tasdevice_dev_write(struct tasdevice_priv *tas_priv,
if (chn < tas_priv->ndev) {
struct regmap *map = tas_priv->regmap;
ret = tasdevice_change_chn_book(tas_priv, chn,
ret = tas_priv->change_chn_book(tas_priv, chn,
TASDEVICE_BOOK_ID(reg));
if (ret < 0)
goto out;
@@ -179,7 +110,7 @@ int tasdevice_dev_bulk_write(
if (chn < tas_priv->ndev) {
struct regmap *map = tas_priv->regmap;
ret = tasdevice_change_chn_book(tas_priv, chn,
ret = tas_priv->change_chn_book(tas_priv, chn,
TASDEVICE_BOOK_ID(reg));
if (ret < 0)
goto out;
@@ -199,160 +130,20 @@ out:
}
EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_write);
int tasdevice_dev_bulk_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned char *data,
unsigned int len)
int tasdevice_save_calibration(struct tasdevice_priv *tas_priv)
{
int ret = 0;
if (chn < tas_priv->ndev) {
struct regmap *map = tas_priv->regmap;
ret = tasdevice_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;
if (tas_priv->save_calibration)
return tas_priv->save_calibration(tas_priv);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_read);
EXPORT_SYMBOL_GPL(tasdevice_save_calibration);
int tasdevice_dev_update_bits(
struct tasdevice_priv *tas_priv, unsigned short chn,
unsigned int reg, unsigned int mask, unsigned int value)
void tasdevice_apply_calibration(struct tasdevice_priv *tas_priv)
{
int ret = 0;
if (chn < tas_priv->ndev) {
struct regmap *map = tas_priv->regmap;
ret = tasdevice_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;
}
out:
return ret;
if (tas_priv->apply_calibration && tas_priv->cali_data.total_sz)
tas_priv->apply_calibration(tas_priv);
}
EXPORT_SYMBOL_GPL(tasdevice_dev_update_bits);
struct tasdevice_priv *tasdevice_kzalloc(struct i2c_client *i2c)
{
struct tasdevice_priv *tas_priv;
tas_priv = devm_kzalloc(&i2c->dev, sizeof(*tas_priv), GFP_KERNEL);
if (!tas_priv)
return NULL;
tas_priv->dev = &i2c->dev;
tas_priv->client = (void *)i2c;
return tas_priv;
}
EXPORT_SYMBOL_GPL(tasdevice_kzalloc);
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)(const struct 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);
if (tas_priv->name_prefix)
scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin",
tas_priv->name_prefix, tas_priv->dev_name,
tas_priv->ndev);
else
scnprintf(tas_priv->rca_binaryname, 64, "%sRCA%d.bin",
tas_priv->dev_name, tas_priv->ndev);
crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL);
tas_priv->codec = codec;
ret = request_firmware_nowait(module, FW_ACTION_UEVENT,
tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv,
cont);
if (ret)
dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n",
ret);
/* Codec Lock Release*/
mutex_unlock(&tas_priv->codec_lock);
return ret;
}
EXPORT_SYMBOL_GPL(tascodec_init);
int tasdevice_init(struct tasdevice_priv *tas_priv)
{
int ret = 0;
int i;
tas_priv->regmap = devm_regmap_init_i2c(tas_priv->client,
&tasdevice_regmap);
if (IS_ERR(tas_priv->regmap)) {
ret = PTR_ERR(tas_priv->regmap);
dev_err(tas_priv->dev, "Failed to allocate register map: %d\n",
ret);
goto out;
}
tas_priv->cur_prog = -1;
tas_priv->cur_conf = -1;
for (i = 0; i < tas_priv->ndev; i++) {
tas_priv->tasdevice[i].cur_book = -1;
tas_priv->tasdevice[i].cur_prog = -1;
tas_priv->tasdevice[i].cur_conf = -1;
}
mutex_init(&tas_priv->codec_lock);
out:
return ret;
}
EXPORT_SYMBOL_GPL(tasdevice_init);
EXPORT_SYMBOL_GPL(tasdevice_apply_calibration);
static void tasdev_dsp_prog_blk_remove(struct tasdevice_prog *prog)
{
@@ -434,143 +225,6 @@ void tasdevice_dsp_remove(void *context)
}
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);
int tasdevice_save_calibration(struct tasdevice_priv *tas_priv)
{
if (tas_priv->save_calibration)
return tas_priv->save_calibration(tas_priv);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(tasdevice_save_calibration);
void tasdevice_apply_calibration(struct tasdevice_priv *tas_priv)
{
if (tas_priv->apply_calibration && tas_priv->cali_data.total_sz)
tas_priv->apply_calibration(tas_priv);
}
EXPORT_SYMBOL_GPL(tasdevice_apply_calibration);
static int tasdevice_clamp(int val, int max, unsigned int 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)
{
unsigned int invert = mc->invert;
unsigned char 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, (unsigned int)(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)
{
unsigned int invert = mc->invert;
unsigned char 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;
}
mask = (1 << fls(max)) - 1;
mask <<= mc->shift;
val = (val & mask) >> mc->shift;
val = tasdevice_clamp(val, max, invert);
ucontrol->value.integer.value[0] = val;
out:
return ret;
}
EXPORT_SYMBOL_GPL(tasdevice_amp_getvol);
int tasdevice_digital_putvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
{
unsigned int 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,
(unsigned int)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);
int tasdevice_digital_getvol(struct tasdevice_priv *tas_priv,
struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
{
unsigned int 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);
MODULE_DESCRIPTION("TAS2781 common library");
MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
MODULE_LICENSE("GPL");
+11 -6
View File
@@ -803,8 +803,13 @@ static int tasdevice_process_block(void *context, unsigned char *data,
chn = idx - 1;
chnend = idx;
} else {
chn = 0;
chnend = tas_priv->ndev;
if (tas_priv->isspi) {
chn = tas_priv->index;
chnend = chn + 1;
} else {
chn = 0;
chnend = tas_priv->ndev;
}
}
for (; chn < chnend; chn++) {
@@ -896,7 +901,7 @@ static int tasdevice_process_block(void *context, unsigned char *data,
is_err = true;
break;
}
rc = tasdevice_dev_update_bits(tas_priv, chn,
rc = tas_priv->update_bits(tas_priv, chn,
TASDEVICE_REG(data[subblk_offset + 2],
data[subblk_offset + 3],
data[subblk_offset + 4]),
@@ -1461,7 +1466,7 @@ static int tasdev_multibytes_chksum(struct tasdevice_priv *tasdevice,
goto end;
}
ret = tasdevice_dev_bulk_read(tasdevice, chn,
ret = tasdevice->dev_bulk_read(tasdevice, chn,
TASDEVICE_REG(book, page, crc_data.offset),
nBuf1, crc_data.len);
if (ret < 0)
@@ -1511,7 +1516,7 @@ static int do_singlereg_checksum(struct tasdevice_priv *tasdevice,
in = check_yram(&crc_data, book, page, reg, 1);
if (!in)
goto end;
ret = tasdevice_dev_read(tasdevice, chl,
ret = tasdevice->dev_read(tasdevice, chl,
TASDEVICE_REG(book, page, reg), &nData1);
if (ret < 0)
goto end;
@@ -1615,7 +1620,7 @@ static int tasdev_block_chksum(struct tasdevice_priv *tas_priv,
unsigned int nr_value;
int ret;
ret = tasdevice_dev_read(tas_priv, chn, TASDEVICE_CHECKSUM_REG,
ret = tas_priv->dev_read(tas_priv, chn, TASDEVICE_CHECKSUM_REG,
&nr_value);
if (ret < 0) {
dev_err(tas_priv->dev, "%s: Chn %d\n", __func__, chn);
+1
View File
@@ -28,6 +28,7 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tas2781.h>
#include <sound/tas2781-comlib-i2c.h>
#include <sound/tlv.h>
#include <sound/tas2563-tlv.h>
#include <sound/tas2781-tlv.h>