Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/sound/soc/codecs/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 54 kB image not shown  

Quelle  tas2781-i2c.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
//
// ALSA SoC Texas Instruments TAS2563/TAS2781 Audio Smart Amplifier
//
// Copyright (C) 2022 - 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>
// Author: Kevin Lu <kevin-lu@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_address.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>
#include <sound/tlv.h>
#include <sound/tas2563-tlv.h>
#include <sound/tas2781-tlv.h>
#include <linux/unaligned.h>

#define X2563_CL_STT_VAL(xreg, xval) \
{ .reg = xreg, \
 .val = { xval }, \
 .val_len = 1, }

#define X2563_CL_STT_4BYTS(xreg, byte0, byte1, byte2, byte3) \
{ .reg = xreg, \
 .val = { byte0, byte1, byte2, byte3 }, \
 .val_len = 4, }

static const struct bulk_reg_val tas2563_cali_start_reg[] = {
 X2563_CL_STT_VAL(TAS2563_IDLE, 0x00),
 X2563_CL_STT_4BYTS(TAS2563_PRM_ENFF_REG, 0x40, 0x00, 0x00, 0x00),
 X2563_CL_STT_4BYTS(TAS2563_PRM_DISTCK_REG, 0x40, 0x00, 0x00, 0x00),
 X2563_CL_STT_4BYTS(TAS2563_PRM_TE_SCTHR_REG, 0x7f, 0xff, 0xff, 0xff),
 X2563_CL_STT_4BYTS(TAS2563_PRM_PLT_FLAG_REG, 0x40, 0x00, 0x00, 0x00),
 X2563_CL_STT_4BYTS(TAS2563_PRM_SINEGAIN_REG, 0x0a, 0x3d, 0x70, 0xa4),
 X2563_CL_STT_4BYTS(TAS2563_TE_TA1_REG, 0x00, 0x36, 0x91, 0x5e),
 X2563_CL_STT_4BYTS(TAS2563_TE_TA1_AT_REG, 0x00, 0x36, 0x91, 0x5e),
 X2563_CL_STT_4BYTS(TAS2563_TE_TA2_REG, 0x00, 0x06, 0xd3, 0x72),
 X2563_CL_STT_4BYTS(TAS2563_TE_AT_REG, 0x00, 0x36, 0x91, 0x5e),
 X2563_CL_STT_4BYTS(TAS2563_TE_DT_REG, 0x00, 0x36, 0x91, 0x5e),
};

#define X2781_CL_STT_VAL(xreg, xval, xlocked) \
{ .reg = xreg, \
 .val = { xval }, \
 .val_len = 1, \
 .is_locked = xlocked, }

#define X2781_CL_STT_4BYTS_UNLOCKED(xreg, byte0, byte1, byte2, byte3) \
{ .reg = xreg, \
 .val = { byte0, byte1, byte2, byte3 }, \
 .val_len = 4, \
 .is_locked = false, }

#define X2781_CL_STT_LEN_UNLOCKED(xreg) \
{ .reg = xreg, \
 .val_len = 4, \
 .is_locked = false, }

static const struct bulk_reg_val tas2781_cali_start_reg[] = {
 X2781_CL_STT_VAL(TAS2781_PRM_INT_MASK_REG, 0xfe, false),
 X2781_CL_STT_VAL(TAS2781_PRM_CLK_CFG_REG, 0xdd, false),
 X2781_CL_STT_VAL(TAS2781_PRM_RSVD_REG, 0x20, false),
 X2781_CL_STT_VAL(TAS2781_PRM_TEST_57_REG, 0x14, true),
 X2781_CL_STT_VAL(TAS2781_PRM_TEST_62_REG, 0x45, true),
 X2781_CL_STT_VAL(TAS2781_PRM_PVDD_UVLO_REG, 0x03, false),
 X2781_CL_STT_VAL(TAS2781_PRM_CHNL_0_REG, 0xa8, false),
 X2781_CL_STT_VAL(TAS2781_PRM_NG_CFG0_REG, 0xb9, false),
 X2781_CL_STT_VAL(TAS2781_PRM_IDLE_CH_DET_REG, 0x92, false),
 /*
 * This register is pilot tone threshold, different with the
 * calibration tool version, it will be updated in
 * tas2781_calib_start_put(), set to 1mA.
 */

 X2781_CL_STT_4BYTS_UNLOCKED(0, 0x00, 0x00, 0x00, 0x56),
 X2781_CL_STT_4BYTS_UNLOCKED(TAS2781_PRM_PLT_FLAG_REG,
  0x40, 0x00, 0x00, 0x00),
 X2781_CL_STT_LEN_UNLOCKED(TAS2781_PRM_SINEGAIN_REG),
 X2781_CL_STT_LEN_UNLOCKED(TAS2781_PRM_SINEGAIN2_REG),
};

static const struct i2c_device_id tasdevice_id[] = {
 { "tas2563", TAS2563 },
 { "tas2781", TAS2781 },
 {}
};
MODULE_DEVICE_TABLE(i2c, tasdevice_id);

#ifdef CONFIG_OF
static const struct of_device_id tasdevice_of_match[] = {
 { .compatible = "ti,tas2563" },
 { .compatible = "ti,tas2781" },
 {},
};
MODULE_DEVICE_TABLE(of, tasdevice_of_match);
#endif

/**
 * tas2781_digital_getvol - get the volum control
 * @kcontrol: control pointer
 * @ucontrol: User data
 * Customer Kcontrol for tas2781 is primarily for regmap booking, paging
 * depends on internal regmap mechanism.
 * tas2781 contains book and page two-level register map, especially
 * book switching will set the register BXXP00R7F, after switching to the
 * correct book, then leverage the mechanism for paging to access the
 * register.
 */

static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 struct soc_mixer_control *mc =
  (struct soc_mixer_control *)kcontrol->private_value;

 return tasdevice_digital_getvol(tas_priv, ucontrol, mc);
}

static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 struct soc_mixer_control *mc =
  (struct soc_mixer_control *)kcontrol->private_value;

 return tasdevice_digital_putvol(tas_priv, ucontrol, mc);
}

static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 struct soc_mixer_control *mc =
  (struct soc_mixer_control *)kcontrol->private_value;

 return tasdevice_amp_getvol(tas_priv, ucontrol, mc);
}

static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv =
  snd_soc_component_get_drvdata(codec);
 struct soc_mixer_control *mc =
  (struct soc_mixer_control *)kcontrol->private_value;

 return tasdevice_amp_putvol(tas_priv, ucontrol, mc);
}

static int tasdev_force_fwload_get(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *component =
  snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv =
  snd_soc_component_get_drvdata(component);

 ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
 dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
   tas_priv->force_fwload_status ? "ON" : "OFF");

 return 0;
}

static int tasdev_force_fwload_put(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *component =
  snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv =
  snd_soc_component_get_drvdata(component);
 bool change, val = (bool)ucontrol->value.integer.value[0];

 if (tas_priv->force_fwload_status == val)
  change = false;
 else {
  change = true;
  tas_priv->force_fwload_status = val;
 }
 dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
  tas_priv->force_fwload_status ? "ON" : "OFF");

 return change;
}

static int tasdev_cali_data_get(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
 struct soc_bytes_ext *bytes_ext =
  (struct soc_bytes_ext *) kcontrol->private_value;
 struct calidata *cali_data = &priv->cali_data;
 struct cali_reg *p = &cali_data->cali_reg_array;
 unsigned char *dst = ucontrol->value.bytes.data;
 unsigned char *data = cali_data->data;
 unsigned int i = 0;
 unsigned int j, k;
 int rc;

 guard(mutex)(&priv->codec_lock);
 if (!priv->is_user_space_calidata)
  return -1;

 if (!p->r0_reg)
  return -1;

 dst[i++] = bytes_ext->max;
 dst[i++] = 'r';

 dst[i++] = TASDEVICE_BOOK_ID(p->r0_reg);
 dst[i++] = TASDEVICE_PAGE_ID(p->r0_reg);
 dst[i++] = TASDEVICE_PAGE_REG(p->r0_reg);

 dst[i++] = TASDEVICE_BOOK_ID(p->r0_low_reg);
 dst[i++] = TASDEVICE_PAGE_ID(p->r0_low_reg);
 dst[i++] = TASDEVICE_PAGE_REG(p->r0_low_reg);

 dst[i++] = TASDEVICE_BOOK_ID(p->invr0_reg);
 dst[i++] = TASDEVICE_PAGE_ID(p->invr0_reg);
 dst[i++] = TASDEVICE_PAGE_REG(p->invr0_reg);

 dst[i++] = TASDEVICE_BOOK_ID(p->pow_reg);
 dst[i++] = TASDEVICE_PAGE_ID(p->pow_reg);
 dst[i++] = TASDEVICE_PAGE_REG(p->pow_reg);

 dst[i++] = TASDEVICE_BOOK_ID(p->tlimit_reg);
 dst[i++] = TASDEVICE_PAGE_ID(p->tlimit_reg);
 dst[i++] = TASDEVICE_PAGE_REG(p->tlimit_reg);

 for (j = 0, k = 0; j < priv->ndev; j++) {
  if (j == data[k]) {
   dst[i++] = j;
   k++;
  } else {
   dev_err(priv->dev, "chn %d device %u not match\n",
    j, data[k]);
   k += 21;
   continue;
  }
  rc = tasdevice_dev_bulk_read(priv, j, p->r0_reg, &dst[i], 4);
  if (rc < 0) {
   dev_err(priv->dev, "chn %d r0_reg bulk_rd err = %d\n",
    j, rc);
   i += 20;
   k += 20;
   continue;
  }
  rc = memcmp(&dst[i], &data[k], 4);
  if (rc != 0)
   dev_dbg(priv->dev, "chn %d r0_data is not same\n", j);
  k += 4;
  i += 4;
  rc = tasdevice_dev_bulk_read(priv, j, p->r0_low_reg,
   &dst[i], 4);
  if (rc < 0) {
   dev_err(priv->dev, "chn %d r0_low bulk_rd err = %d\n",
    j, rc);
   i += 16;
   k += 16;
   continue;
  }
  rc = memcmp(&dst[i], &data[k], 4);
  if (rc != 0)
   dev_dbg(priv->dev, "chn %d r0_low is not same\n", j);
  i += 4;
  k += 4;
  rc = tasdevice_dev_bulk_read(priv, j, p->invr0_reg,
   &dst[i], 4);
  if (rc < 0) {
   dev_err(priv->dev, "chn %d invr0 bulk_rd err = %d\n",
    j, rc);
   i += 12;
   k += 12;
   continue;
  }
  rc = memcmp(&dst[i], &data[k], 4);
  if (rc != 0)
   dev_dbg(priv->dev, "chn %d invr0 is not same\n", j);
  i += 4;
  k += 4;
  rc = tasdevice_dev_bulk_read(priv, j, p->pow_reg, &dst[i], 4);
  if (rc < 0) {
   dev_err(priv->dev, "chn %d pow_reg bulk_rd err = %d\n",
    j, rc);
   i += 8;
   k += 8;
   continue;
  }
  rc = memcmp(&dst[i], &data[k], 4);
  if (rc != 0)
   dev_dbg(priv->dev, "chn %d pow_reg is not same\n", j);
  i += 4;
  k += 4;
  rc = tasdevice_dev_bulk_read(priv, j, p->tlimit_reg,
   &dst[i], 4);
  if (rc < 0) {
   dev_err(priv->dev, "chn %d tlimit bulk_rd err = %d\n",
    j, rc);
  }
  rc = memcmp(&dst[i], &data[k], 4);
  if (rc != 0)
   dev_dbg(priv->dev, "chn %d tlimit is not same\n", j);
  i += 4;
  k += 4;
 }
 return 0;
}

static int calib_data_get(struct tasdevice_priv *tas_priv, int reg,
 unsigned char *dst)
{
 struct i2c_client *clt = (struct i2c_client *)tas_priv->client;
 struct tasdevice *tasdev = tas_priv->tasdevice;
 int rc = -1;
 int i;

 for (i = 0; i < tas_priv->ndev; i++) {
  if (clt->addr == tasdev[i].dev_addr) {
   /* First byte is the device index. */
   dst[0] = i;
   rc = tasdevice_dev_bulk_read(tas_priv, i, reg, &dst[1],
    4);
   break;
  }
 }

 return rc;
}

static int partial_cali_data_update(int *reg, int j)
{
 switch (tas2781_cali_start_reg[j].reg) {
 case 0:
  return reg[0];
 case TAS2781_PRM_PLT_FLAG_REG:
  return reg[1];
 case TAS2781_PRM_SINEGAIN_REG:
  return reg[2];
 case TAS2781_PRM_SINEGAIN2_REG:
  return reg[3];
 default:
  return 0;
 }
}

static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i,
 int *reg, unsigned char *dat)
{
 struct tasdevice *tasdev = tas_priv->tasdevice;
 struct bulk_reg_val *p = tasdev[i].cali_data_backup;
 struct bulk_reg_val *t = &tasdev[i].alp_cali_bckp;
 const int sum = ARRAY_SIZE(tas2781_cali_start_reg);
 unsigned char val[4];
 int j, r;

 if (p == NULL)
  return;

 /* Store the current setting from the chip */
 for (j = 0; j < sum; j++) {
  if (p[j].val_len == 1) {
   if (p[j].is_locked)
    tasdevice_dev_write(tas_priv, i,
     TAS2781_TEST_UNLOCK_REG,
     TAS2781_TEST_PAGE_UNLOCK);
   tasdevice_dev_read(tas_priv, i, p[j].reg,
    (int *)&p[j].val[0]);
  } else {
   if (!tas_priv->dspbin_typ) {
    r = partial_cali_data_update(reg, j);
    if (r)
     p[j].reg = r;
   }

   if (p[j].reg)
    tasdevice_dev_bulk_read(tas_priv, i, p[j].reg,
     p[j].val, 4);
  }
 }

 if (tas_priv->dspbin_typ == TASDEV_ALPHA)
  tasdevice_dev_bulk_read(tas_priv, i, t->reg, t->val, 4);

 /* Update the setting for calibration */
 for (j = 0; j < sum - 4; j++) {
  if (p[j].val_len == 1) {
   if (p[j].is_locked)
    tasdevice_dev_write(tas_priv, i,
     TAS2781_TEST_UNLOCK_REG,
     TAS2781_TEST_PAGE_UNLOCK);
   tasdevice_dev_write(tas_priv, i, p[j].reg,
    tas2781_cali_start_reg[j].val[0]);
  }
 }

 if (tas_priv->dspbin_typ == TASDEV_ALPHA) {
  val[0] = 0x00;
  val[1] = 0x00;
  val[2] = 0x21;
  val[3] = 0x8e;
 } else {
  val[0] = tas2781_cali_start_reg[j].val[0];
  val[1] = tas2781_cali_start_reg[j].val[1];
  val[2] = tas2781_cali_start_reg[j].val[2];
  val[3] = tas2781_cali_start_reg[j].val[3];
 }
 tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, val, 4);
 tasdevice_dev_bulk_write(tas_priv, i, p[j + 1].reg,
  (unsigned char *)tas2781_cali_start_reg[j + 1].val, 4);
 tasdevice_dev_bulk_write(tas_priv, i, p[j + 2].reg, &dat[1], 4);
 tasdevice_dev_bulk_write(tas_priv, i, p[j + 3].reg, &dat[5], 4);
 if (tas_priv->dspbin_typ == TASDEV_ALPHA) {
  val[0] = 0x00;
  val[1] = 0x00;
  val[2] = 0x2a;
  val[3] = 0x0b;

  tasdevice_dev_bulk_read(tas_priv, i, t->reg, val, 4);
 }
}

static int tas2781_calib_start_put(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
 struct soc_bytes_ext *bytes_ext =
  (struct soc_bytes_ext *) kcontrol->private_value;
 unsigned char *dat = ucontrol->value.bytes.data;
 int i, reg[4];
 int j = 0;

 guard(mutex)(&priv->codec_lock);
 if (priv->chip_id != TAS2781 || bytes_ext->max != dat[0] ||
  dat[1] != 'r') {
  dev_err(priv->dev, "%s: package fmt or chipid incorrect\n",
   __func__);
  return 0;
 }
 j += 2;
 /* refresh pilot tone and SineGain register */
 for (i = 0; i < ARRAY_SIZE(reg); i++) {
  reg[i] = TASDEVICE_REG(dat[j], dat[j + 1], dat[j + 2]);
  j += 3;
 }

 for (i = 0; i < priv->ndev; i++) {
  int k = i * 9 + j;

  if (dat[k] != i) {
   dev_err(priv->dev, "%s:no cal-setting for dev %d\n",
    __func__, i);
   continue;
  }
  sngl_calib_start(priv, i, reg, dat + k);
 }
 return 1;
}

static void tas2781_calib_stop_put(struct tasdevice_priv *priv)
{
 const int sum = ARRAY_SIZE(tas2781_cali_start_reg);
 int i, j;

 for (i = 0; i < priv->ndev; i++) {
  struct tasdevice *tasdev = priv->tasdevice;
  struct bulk_reg_val *p = tasdev[i].cali_data_backup;
  struct bulk_reg_val *t = &tasdev[i].alp_cali_bckp;

  if (p == NULL)
   continue;

  for (j = 0; j < sum; j++) {
   if (p[j].val_len == 1) {
    if (p[j].is_locked)
     tasdevice_dev_write(priv, i,
      TAS2781_TEST_UNLOCK_REG,
      TAS2781_TEST_PAGE_UNLOCK);
    tasdevice_dev_write(priv, i, p[j].reg,
     p[j].val[0]);
   } else {
    if (!p[j].reg)
     continue;
    tasdevice_dev_bulk_write(priv, i, p[j].reg,
     p[j].val, 4);
   }
  }

  if (priv->dspbin_typ == TASDEV_ALPHA)
   tasdevice_dev_bulk_write(priv, i, t->reg, t->val, 4);
 }
}

static int tas2563_calib_start_put(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct bulk_reg_val *q = (struct bulk_reg_val *)tas2563_cali_start_reg;
 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
 const int sum = ARRAY_SIZE(tas2563_cali_start_reg);
 int i, j;

 guard(mutex)(&tas_priv->codec_lock);
 if (tas_priv->chip_id != TAS2563)
  return -1;

 for (i = 0; i < tas_priv->ndev; i++) {
  struct tasdevice *tasdev = tas_priv->tasdevice;
  struct bulk_reg_val *p = tasdev[i].cali_data_backup;

  if (p == NULL)
   continue;
  for (j = 0; j < sum; j++) {
   if (p[j].val_len == 1)
    tasdevice_dev_read(tas_priv,
     i, p[j].reg,
     (unsigned int *)&p[j].val[0]);
   else
    tasdevice_dev_bulk_read(tas_priv,
     i, p[j].reg, p[j].val, 4);
  }

  for (j = 0; j < sum; j++) {
   if (p[j].val_len == 1)
    tasdevice_dev_write(tas_priv, i, p[j].reg,
     q[j].val[0]);
   else
    tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
     q[j].val, 4);
  }
 }

 return 1;
}

static void tas2563_calib_stop_put(struct tasdevice_priv *tas_priv)
{
 const int sum = ARRAY_SIZE(tas2563_cali_start_reg);
 int i, j;

 for (i = 0; i < tas_priv->ndev; i++) {
  struct tasdevice *tasdev = tas_priv->tasdevice;
  struct bulk_reg_val *p = tasdev[i].cali_data_backup;

  if (p == NULL)
   continue;

  for (j = 0; j < sum; j++) {
   if (p[j].val_len == 1)
    tasdevice_dev_write(tas_priv, i, p[j].reg,
     p[j].val[0]);
   else
    tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
     p[j].val, 4);
  }
 }
}

static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);

 guard(mutex)(&priv->codec_lock);
 if (priv->chip_id == TAS2563)
  tas2563_calib_stop_put(priv);
 else
  tas2781_calib_stop_put(priv);

 return 1;
}

static int tasdev_cali_data_put(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
 struct soc_bytes_ext *bytes_ext =
  (struct soc_bytes_ext *) kcontrol->private_value;
 struct calidata *cali_data = &priv->cali_data;
 struct cali_reg *p = &cali_data->cali_reg_array;
 unsigned char *src = ucontrol->value.bytes.data;
 unsigned char *dst = cali_data->data;
 int i = 0;
 int j;

 guard(mutex)(&priv->codec_lock);
 if (src[0] != bytes_ext->max || src[1] != 'r') {
  dev_err(priv->dev, "%s: pkg fmt invalid\n", __func__);
  return 0;
 }
 for (j = 0; j < priv->ndev; j++) {
  if (src[17 + j * 21] != j) {
   dev_err(priv->dev, "%s: pkg fmt invalid\n", __func__);
   return 0;
  }
 }
 i += 2;
 priv->is_user_space_calidata = true;

 if (priv->dspbin_typ == TASDEV_BASIC) {
  p->r0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
  i += 3;
  p->r0_low_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
  i += 3;
  p->invr0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
  i += 3;
  p->pow_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
  i += 3;
  p->tlimit_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
  i += 3;
 } else {
  i += 15;
 }

 memcpy(dst, &src[i], cali_data->total_sz);
 return 1;
}

static int tas2781_latch_reg_get(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
 struct i2c_client *clt = (struct i2c_client *)tas_priv->client;
 struct soc_bytes_ext *bytes_ext =
  (struct soc_bytes_ext *) kcontrol->private_value;
 struct tasdevice *tasdev = tas_priv->tasdevice;
 unsigned char *dst = ucontrol->value.bytes.data;
 int i, val, rc = -1;

 dst[0] = bytes_ext->max;
 guard(mutex)(&tas_priv->codec_lock);
 for (i = 0; i < tas_priv->ndev; i++) {
  if (clt->addr == tasdev[i].dev_addr) {
   /* First byte is the device index. */
   dst[1] = i;
   rc = tasdevice_dev_read(tas_priv, i,
    TAS2781_RUNTIME_LATCH_RE_REG, &val);
   if (rc < 0)
    dev_err(tas_priv->dev, "%s, get value error\n",
     __func__);
   else
    dst[2] = val;

   break;
  }
 }

 return rc;
}

static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
 struct soc_bytes_ext *bytes_ext =
  (struct soc_bytes_ext *) kcontrol->private_value;
 unsigned char *dst = ucontrol->value.bytes.data;
 unsigned int reg = TAS2781_RUNTIME_RE_REG_TF;

 if (tas_priv->chip_id == TAS2781) {
  struct tasdevice_fw *tas_fmw = tas_priv->fmw;
  struct fct_param_address *p = &(tas_fmw->fct_par_addr);

  reg = TAS2781_RUNTIME_RE_REG_TF;
  if (tas_priv->dspbin_typ)
   reg = TASDEVICE_REG(p->tf_reg[0], p->tf_reg[1],
    p->tf_reg[2]);
 } else {
  reg = TAS2563_RUNTIME_RE_REG_TF;
 }

 guard(mutex)(&tas_priv->codec_lock);
 dst[0] = bytes_ext->max;
 return calib_data_get(tas_priv, reg, &dst[1]);
}

static int tasdev_re_data_get(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
 struct soc_bytes_ext *bytes_ext =
  (struct soc_bytes_ext *) kcontrol->private_value;
 unsigned char *dst = ucontrol->value.bytes.data;
 unsigned int reg = TAS2781_RUNTIME_RE_REG;

 if (tas_priv->chip_id == TAS2781) {
  struct tasdevice_fw *tas_fmw = tas_priv->fmw;
  struct fct_param_address *p = &(tas_fmw->fct_par_addr);

  if (tas_priv->dspbin_typ)
   reg = TASDEVICE_REG(p->r0_reg[0], p->r0_reg[1],
    p->r0_reg[2]);
 } else {
  reg = TAS2563_RUNTIME_RE_REG;
 }

 guard(mutex)(&tas_priv->codec_lock);
 dst[0] = bytes_ext->max;
 return calib_data_get(tas_priv, reg, &dst[1]);
}

static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
 struct calidata *cali_data = &tas_priv->cali_data;
 struct soc_bytes_ext *bytes_ext =
  (struct soc_bytes_ext *) kcontrol->private_value;
 unsigned char *dst = ucontrol->value.bytes.data;
 unsigned int reg;

 guard(mutex)(&tas_priv->codec_lock);

 if (tas_priv->chip_id == TAS2563)
  reg = TAS2563_PRM_R0_REG;
 else if (cali_data->cali_reg_array.r0_reg)
  reg = cali_data->cali_reg_array.r0_reg;
 else
  return -1;
 dst[0] = bytes_ext->max;
 return calib_data_get(tas_priv, reg, &dst[1]);
}

static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
 struct tasdevice_fw *tas_fmw = tas_priv->fmw;
 struct fct_param_address *p = &(tas_fmw->fct_par_addr);
 struct soc_bytes_ext *bytes_ext =
  (struct soc_bytes_ext *) kcontrol->private_value;
 unsigned char *dst = ucontrol->value.bytes.data;
 unsigned int reg = TASDEVICE_XM_A1_REG;

 if (tas_priv->dspbin_typ)
  reg = TASDEVICE_REG(p->a1_reg[0], p->a1_reg[1], p->a1_reg[2]);

 guard(mutex)(&tas_priv->codec_lock);
 dst[0] = bytes_ext->max;
 return calib_data_get(tas_priv, reg, &dst[1]);
}

static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
 struct tasdevice_fw *tas_fmw = tas_priv->fmw;
 struct fct_param_address *p = &(tas_fmw->fct_par_addr);
 struct soc_bytes_ext *bytes_ext =
  (struct soc_bytes_ext *) kcontrol->private_value;
 unsigned char *dst = ucontrol->value.bytes.data;
 unsigned int reg = TASDEVICE_XM_A2_REG;

 if (tas_priv->dspbin_typ)
  reg = TASDEVICE_REG(p->a2_reg[0], p->a2_reg[1], p->a2_reg[2]);

 guard(mutex)(&tas_priv->codec_lock);
 dst[0] = bytes_ext->max;
 return calib_data_get(tas_priv, reg, &dst[1]);
}

static int tasdev_nop_get(
 struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 return 0;
}

static int tas2563_digital_gain_get(
 struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct soc_mixer_control *mc =
  (struct soc_mixer_control *)kcontrol->private_value;
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
 unsigned int l = 0, r = mc->max;
 unsigned int target, ar_mid, mid, ar_l, ar_r;
 unsigned int reg = mc->reg;
 unsigned char data[4];
 int ret;

 mutex_lock(&tas_dev->codec_lock);
 /* Read the primary device */
 ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
 if (ret) {
  dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
  goto out;
 }

 target = get_unaligned_be32(&data[0]);

 while (r > 1 + l) {
  mid = (l + r) / 2;
  ar_mid = get_unaligned_be32(tas2563_dvc_table[mid]);
  if (target < ar_mid)
   r = mid;
  else
   l = mid;
 }

 ar_l = get_unaligned_be32(tas2563_dvc_table[l]);
 ar_r = get_unaligned_be32(tas2563_dvc_table[r]);

 /* find out the member same as or closer to the current volume */
 ucontrol->value.integer.value[0] =
  abs(target - ar_l) <= abs(target - ar_r) ? l : r;
out:
 mutex_unlock(&tas_dev->codec_lock);
 return 0;
}

static int tas2563_digital_gain_put(
 struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct soc_mixer_control *mc =
  (struct soc_mixer_control *)kcontrol->private_value;
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
 int vol = ucontrol->value.integer.value[0];
 int status = 0, max = mc->max, rc = 1;
 int i, ret;
 unsigned int reg = mc->reg;
 unsigned int volrd, volwr;
 unsigned char data[4];

 vol = clamp(vol, 0, max);
 mutex_lock(&tas_dev->codec_lock);
 /* Read the primary device */
 ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
 if (ret) {
  dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
  rc = -1;
  goto out;
 }

 volrd = get_unaligned_be32(&data[0]);
 volwr = get_unaligned_be32(tas2563_dvc_table[vol]);

 if (volrd == volwr) {
  rc = 0;
  goto out;
 }

 for (i = 0; i < tas_dev->ndev; i++) {
  ret = tasdevice_dev_bulk_write(tas_dev, i, reg,
   (unsigned char *)tas2563_dvc_table[vol], 4);
  if (ret) {
   dev_err(tas_dev->dev,
    "%s, set digital vol error in dev %d\n",
    __func__, i);
   status |= BIT(i);
  }
 }

 if (status)
  rc = -1;
out:
 mutex_unlock(&tas_dev->codec_lock);
 return rc;
}

static const struct snd_kcontrol_new tasdevice_snd_controls[] = {
 SOC_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
  tasdev_force_fwload_get, tasdev_force_fwload_put),
};

static const struct snd_kcontrol_new tasdevice_cali_controls[] = {
 SOC_SINGLE_EXT("Calibration Stop", SND_SOC_NOPM, 0, 1, 0,
  tasdev_nop_get, tasdev_calib_stop_put),
 SND_SOC_BYTES_EXT("Amp TF Data", 6, tasdev_tf_data_get, NULL),
 SND_SOC_BYTES_EXT("Amp RE Data", 6, tasdev_re_data_get, NULL),
 SND_SOC_BYTES_EXT("Amp R0 Data", 6, tasdev_r0_data_get, NULL),
 SND_SOC_BYTES_EXT("Amp XMA1 Data", 6, tasdev_XMA1_data_get, NULL),
 SND_SOC_BYTES_EXT("Amp XMA2 Data", 6, tasdev_XMA2_data_get, NULL),
};

static const struct snd_kcontrol_new tas2781_snd_controls[] = {
 SOC_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2781_AMP_LEVEL,
  1, 0, 20, 0, tas2781_amp_getvol,
  tas2781_amp_putvol, tas2781_amp_tlv),
 SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2781_DVC_LVL,
  0, 0, 200, 1, tas2781_digital_getvol,
  tas2781_digital_putvol, tas2781_dvc_tlv),
};

static const struct snd_kcontrol_new tas2781_cali_controls[] = {
 SND_SOC_BYTES_EXT("Amp Latch Data", 3, tas2781_latch_reg_get, NULL),
};

static const struct snd_kcontrol_new tas2563_snd_controls[] = {
 SOC_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2563_DVC_LVL, 0,
  0, ARRAY_SIZE(tas2563_dvc_table) - 1, 0,
  tas2563_digital_gain_get, tas2563_digital_gain_put,
  tas2563_dvc_tlv),
};

static const struct snd_kcontrol_new tas2563_cali_controls[] = {
 SOC_SINGLE_EXT("Calibration Start", SND_SOC_NOPM, 0, 1, 0,
  tasdev_nop_get, tas2563_calib_start_put),
};

static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
  struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 int ret = 0;

 if (tas_priv->rcabin.profile_cfg_id !=
  ucontrol->value.integer.value[0]) {
  tas_priv->rcabin.profile_cfg_id =
   ucontrol->value.integer.value[0];
  ret = 1;
 }

 return ret;
}

static int tasdevice_info_active_num(struct snd_kcontrol *kcontrol,
   struct snd_ctl_elem_info *uinfo)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);

 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 uinfo->count = 1;
 uinfo->value.integer.min = 0;
 uinfo->value.integer.max = tas_priv->ndev - 1;

 return 0;
}

static int tasdevice_info_chip_id(struct snd_kcontrol *kcontrol,
   struct snd_ctl_elem_info *uinfo)
{
 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 uinfo->count = 1;
 uinfo->value.integer.min = TAS2563;
 uinfo->value.integer.max = TAS2781;

 return 0;
}

static int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
   struct snd_ctl_elem_info *uinfo)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 struct tasdevice_fw *tas_fw = tas_priv->fmw;

 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 uinfo->count = 1;
 uinfo->value.integer.min = 0;
 uinfo->value.integer.max = (int)tas_fw->nr_programs;

 return 0;
}

static int tasdevice_info_configurations(
 struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
 struct snd_soc_component *codec =
  snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 struct tasdevice_fw *tas_fw = tas_priv->fmw;

 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 uinfo->count = 1;
 uinfo->value.integer.min = 0;
 uinfo->value.integer.max = (int)tas_fw->nr_configurations - 1;

 return 0;
}

static int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
   struct snd_ctl_elem_info *uinfo)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);

 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 uinfo->count = 1;
 uinfo->value.integer.min = 0;
 uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;

 return 0;
}

static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
   struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);

 ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;

 return 0;
}

static int tasdevice_get_chip_id(struct snd_kcontrol *kcontrol,
   struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);

 ucontrol->value.integer.value[0] = tas_priv->chip_id;

 return 0;
}

static int tasdevice_create_control(struct tasdevice_priv *tas_priv)
{
 struct snd_kcontrol_new *prof_ctrls;
 int nr_controls = 1;
 int mix_index = 0;
 int ret;
 char *name;

 prof_ctrls = devm_kcalloc(tas_priv->dev, nr_controls,
  sizeof(prof_ctrls[0]), GFP_KERNEL);
 if (!prof_ctrls) {
  ret = -ENOMEM;
  goto out;
 }

 /* Create a mixer item for selecting the active profile */
 name = devm_kstrdup(tas_priv->dev, "Speaker Profile Id", GFP_KERNEL);
 if (!name) {
  ret = -ENOMEM;
  goto out;
 }
 prof_ctrls[mix_index].name = name;
 prof_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 prof_ctrls[mix_index].info = tasdevice_info_profile;
 prof_ctrls[mix_index].get = tasdevice_get_profile_id;
 prof_ctrls[mix_index].put = tasdevice_set_profile_id;
 mix_index++;

 ret = snd_soc_add_component_controls(tas_priv->codec,
  prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index);

out:
 return ret;
}

static int tasdevice_program_get(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);

 ucontrol->value.integer.value[0] = tas_priv->cur_prog;

 return 0;
}

static int tasdevice_program_put(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 unsigned int nr_program = ucontrol->value.integer.value[0];
 int ret = 0;

 if (tas_priv->cur_prog != nr_program) {
  tas_priv->cur_prog = nr_program;
  ret = 1;
 }

 return ret;
}

static int tasdevice_configuration_get(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{

 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);

 ucontrol->value.integer.value[0] = tas_priv->cur_conf;

 return 0;
}

static int tasdevice_configuration_put(
 struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 unsigned int nr_configuration = ucontrol->value.integer.value[0];
 int ret = 0;

 if (tas_priv->cur_conf != nr_configuration) {
  tas_priv->cur_conf = nr_configuration;
  ret = 1;
 }

 return ret;
}

static int tasdevice_active_num_get(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 struct i2c_client *clt = (struct i2c_client *)tas_priv->client;
 struct tasdevice *tasdev = tas_priv->tasdevice;
 int i;

 for (i = 0; i < tas_priv->ndev; i++) {
  if (clt->addr == tasdev[i].dev_addr) {
   ucontrol->value.integer.value[0] = i;
   return 0;
  }
 }

 return -1;
}

static int tasdevice_active_num_put(struct snd_kcontrol *kcontrol,
 struct snd_ctl_elem_value *ucontrol)
{
 struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 int dev_id = ucontrol->value.integer.value[0];
 int max = tas_priv->ndev - 1;

 dev_id = clamp(dev_id, 0, max);

 guard(mutex)(&tas_priv->codec_lock);
 return tasdev_chn_switch(tas_priv, dev_id);
}

static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
{
 struct snd_kcontrol_new *dsp_ctrls;
 char *active_dev_num, *chip_id;
 char *conf_name, *prog_name;
 int nr_controls = 4;
 int mix_index = 0;

 /* Alloc kcontrol via devm_kzalloc, which don't manually
 * free the kcontrol
 */

 dsp_ctrls = devm_kcalloc(tas_priv->dev, nr_controls,
  sizeof(dsp_ctrls[0]), GFP_KERNEL);
 if (!dsp_ctrls)
  return -ENOMEM;

 /* Create mixer items for selecting the active Program and Config */
 prog_name = devm_kstrdup(tas_priv->dev, "Speaker Program Id",
  GFP_KERNEL);
 if (!prog_name)
  return -ENOMEM;

 dsp_ctrls[mix_index].name = prog_name;
 dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 dsp_ctrls[mix_index].info = tasdevice_info_programs;
 dsp_ctrls[mix_index].get = tasdevice_program_get;
 dsp_ctrls[mix_index].put = tasdevice_program_put;
 mix_index++;

 conf_name = devm_kstrdup(tas_priv->dev, "Speaker Config Id",
  GFP_KERNEL);
 if (!conf_name)
  return -ENOMEM;

 dsp_ctrls[mix_index].name = conf_name;
 dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 dsp_ctrls[mix_index].info = tasdevice_info_configurations;
 dsp_ctrls[mix_index].get = tasdevice_configuration_get;
 dsp_ctrls[mix_index].put = tasdevice_configuration_put;
 mix_index++;

 active_dev_num = devm_kstrdup(tas_priv->dev, "Activate Tasdevice Num",
  GFP_KERNEL);
 if (!active_dev_num)
  return -ENOMEM;

 dsp_ctrls[mix_index].name = active_dev_num;
 dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 dsp_ctrls[mix_index].info = tasdevice_info_active_num;
 dsp_ctrls[mix_index].get = tasdevice_active_num_get;
 dsp_ctrls[mix_index].put = tasdevice_active_num_put;
 mix_index++;

 chip_id = devm_kstrdup(tas_priv->dev, "Tasdevice Chip Id", GFP_KERNEL);
 if (!chip_id)
  return -ENOMEM;

 dsp_ctrls[mix_index].name = chip_id;
 dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 dsp_ctrls[mix_index].info = tasdevice_info_chip_id;
 dsp_ctrls[mix_index].get = tasdevice_get_chip_id;
 mix_index++;

 return snd_soc_add_component_controls(tas_priv->codec, dsp_ctrls,
  nr_controls < mix_index ? nr_controls : mix_index);
}

static void cali_reg_update(struct bulk_reg_val *p,
 struct fct_param_address *t)
{
 const int sum = ARRAY_SIZE(tas2781_cali_start_reg);
 int reg, j;

 for (j = 0; j < sum; j++) {
  switch (tas2781_cali_start_reg[j].reg) {
  case 0:
   reg = TASDEVICE_REG(t->thr[0], t->thr[1], t->thr[2]);
   break;
  case TAS2781_PRM_PLT_FLAG_REG:
   reg = TASDEVICE_REG(t->plt_flg[0], t->plt_flg[1],
    t->plt_flg[2]);
   break;
  case TAS2781_PRM_SINEGAIN_REG:
   reg = TASDEVICE_REG(t->sin_gn[0], t->sin_gn[1],
    t->sin_gn[2]);
   break;
  case TAS2781_PRM_SINEGAIN2_REG:
   reg = TASDEVICE_REG(t->sin_gn[0], t->sin_gn[1],
    t->sin_gn[2]);
   break;
  default:
   reg = 0;
   break;
  }
  if (reg)
   p[j].reg = reg;
 }
}

static void alpa_cali_update(struct bulk_reg_val *p,
 struct fct_param_address *t)
{
 p->is_locked = false;
 p->reg = TASDEVICE_REG(t->thr2[0], t->thr2[1], t->thr2[2]);
 p->val_len = 4;
}

static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
{
 struct calidata *cali_data = &priv->cali_data;
 struct tasdevice *tasdev = priv->tasdevice;
 struct tasdevice_fw *fmw = priv->fmw;
 struct soc_bytes_ext *ext_cali_data;
 struct snd_kcontrol_new *cali_ctrls;
 unsigned int nctrls;
 char *cali_name;
 int rc, i;

 rc = snd_soc_add_component_controls(priv->codec,
  tasdevice_cali_controls, ARRAY_SIZE(tasdevice_cali_controls));
 if (rc < 0) {
  dev_err(priv->dev, "%s: Add cali controls err rc = %d",
   __func__, rc);
  return rc;
 }

 if (priv->chip_id == TAS2781) {
  struct fct_param_address *t = &(fmw->fct_par_addr);

  cali_ctrls = (struct snd_kcontrol_new *)tas2781_cali_controls;
  nctrls = ARRAY_SIZE(tas2781_cali_controls);
  for (i = 0; i < priv->ndev; i++) {
   struct bulk_reg_val *p;

   p = tasdev[i].cali_data_backup =
    kmemdup(tas2781_cali_start_reg,
    sizeof(tas2781_cali_start_reg), GFP_KERNEL);
   if (!tasdev[i].cali_data_backup)
    return -ENOMEM;
   if (priv->dspbin_typ) {
    cali_reg_update(p, t);
    if (priv->dspbin_typ == TASDEV_ALPHA) {
     p = &tasdev[i].alp_cali_bckp;
     alpa_cali_update(p, t);
    }
   }
  }
 } else {
  cali_ctrls = (struct snd_kcontrol_new *)tas2563_cali_controls;
  nctrls = ARRAY_SIZE(tas2563_cali_controls);
  for (i = 0; i < priv->ndev; i++) {
   tasdev[i].cali_data_backup =
    kmemdup(tas2563_cali_start_reg,
    sizeof(tas2563_cali_start_reg), GFP_KERNEL);
   if (!tasdev[i].cali_data_backup)
    return -ENOMEM;
  }
 }

 rc = snd_soc_add_component_controls(priv->codec, cali_ctrls, nctrls);
 if (rc < 0) {
  dev_err(priv->dev, "%s: Add chip cali ctrls err rc = %d",
   __func__, rc);
  return rc;
 }

 /* index for cali_ctrls */
 i = 0;
 if (priv->chip_id == TAS2781)
  nctrls = 2;
 else
  nctrls = 1;

 /*
 * Alloc kcontrol via devm_kzalloc(), which don't manually
 * free the kcontrol。
 */

 cali_ctrls = devm_kcalloc(priv->dev, nctrls,
  sizeof(cali_ctrls[0]), GFP_KERNEL);
 if (!cali_ctrls)
  return -ENOMEM;

 ext_cali_data = devm_kzalloc(priv->dev, sizeof(*ext_cali_data),
  GFP_KERNEL);
 if (!ext_cali_data)
  return -ENOMEM;

 cali_name = devm_kstrdup(priv->dev, "Speaker Calibrated Data",
  GFP_KERNEL);
 if (!cali_name)
  return -ENOMEM;
 /* the number of calibrated data per tas2563/tas2781 */
 cali_data->cali_dat_sz_per_dev = 20;
 /*
 * Data structure for tas2563/tas2781 calibrated data:
 * Pkg len (1 byte)
 * Reg id (1 byte, constant 'r')
 * book, page, register array for calibrated data (15 bytes)
 * for (i = 0; i < Device-Sum; i++) {
 * Device #i index_info (1 byte)
 * Calibrated data for Device #i (20 bytes)
 * }
 */

 ext_cali_data->max = priv->ndev *
  (cali_data->cali_dat_sz_per_dev + 1) + 1 + 15 + 1;
 priv->cali_data.total_sz = priv->ndev *
  (cali_data->cali_dat_sz_per_dev + 1);
 cali_ctrls[i].name = cali_name;
 cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 cali_ctrls[i].info = snd_soc_bytes_info_ext;
 cali_ctrls[i].get = tasdev_cali_data_get;
 cali_ctrls[i].put = tasdev_cali_data_put;
 cali_ctrls[i].private_value = (unsigned long)ext_cali_data;
 i++;

 cali_data->data = devm_kzalloc(priv->dev, cali_data->total_sz,
  GFP_KERNEL);
 if (!cali_data->data)
  return -ENOMEM;

 if (priv->chip_id == TAS2781) {
  struct soc_bytes_ext *ext_cali_start;
  char *cali_start_name;

  ext_cali_start = devm_kzalloc(priv->dev,
   sizeof(*ext_cali_start), GFP_KERNEL);
  if (!ext_cali_start)
   return -ENOMEM;

  cali_start_name = devm_kstrdup(priv->dev,
   "Calibration Start", GFP_KERNEL);
  if (!cali_start_name)
   return -ENOMEM;
  /*
 * package structure for tas2781 ftc start:
 * Pkg len (1 byte)
 * Reg id (1 byte, constant 'r')
 * book, page, register for pilot threshold, pilot tone
 * and sine gain (12 bytes)
 * for (i = 0; i < Device-Sum; i++) {
 * Device #i index_info (1 byte)
 * Sine gain for Device #i (8 bytes)
 * }
 */

  ext_cali_start->max = 14 + priv->ndev * 9;
  cali_ctrls[i].name = cali_start_name;
  cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
  cali_ctrls[i].info = snd_soc_bytes_info_ext;
  cali_ctrls[i].put = tas2781_calib_start_put;
  cali_ctrls[i].get = tasdev_nop_get;
  cali_ctrls[i].private_value = (unsigned long)ext_cali_start;
  i++;
 }

 return snd_soc_add_component_controls(priv->codec, cali_ctrls,
  nctrls < i ? nctrls : i);
}

#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
/*
 * This debugfs node is a bridge to the acoustic tuning application
 * tool which can tune the chips' acoustic effect.
 *
 * package structure for PPC3 communications:
 * Pkg len (1 byte)
 * Pkg id (1 byte, 'r' or 'w')
 * Dev id (1 byte, i2c address)
 * Book id (1 byte)
 * Page id (1 byte)
 * Reg id (1 byte)
 * switch (pkg id) {
 * case 'w':
 * 1 byte, length of data to read
 * case 'r':
 * data payload (1~128 bytes)
 * }
 */

static ssize_t acoustic_ctl_read(struct file *file, char __user *to,
 size_t count, loff_t *ppos)
{
 struct snd_soc_component *comp = file->private_data;
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
 struct acoustic_data *p = &tas_priv->acou_data;
 int ret = -1;

 if (p->id == 'r' && p->len == count && count <= sizeof(*p))
  ret = simple_read_from_buffer(to, count, ppos, p, p->len);
 else
  dev_err(tas_priv->dev, "Not ready for get.\n");
 return ret;
}

static ssize_t acoustic_ctl_write(struct file *file,
 const char __user *from, size_t count, loff_t *ppos)
{
 struct snd_soc_component *comp = file->private_data;
 struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
 struct acoustic_data *p = &priv->acou_data;
 unsigned int max_pkg_len = sizeof(*p);
 unsigned char *src;
 int j, len, reg, val;
 unsigned short chn;
 int ret = -1;

 if (count > sizeof(*p)) {
  dev_err(priv->dev, "count(%u) is larger than max(%u).\n",
   (unsigned int)count, max_pkg_len);
  return ret;
 }

 src = memdup_user(from, count);
 if (IS_ERR(src))
  return PTR_ERR(src);

 if (src[0] > max_pkg_len && src[0] != count) {
  dev_err(priv->dev, "pkg(%u), max(%u), count(%u) mismatch.\n",
   src[0], max_pkg_len, (unsigned int)count);
  ret = 0;
  goto exit;
 }

 switch (src[1]) {
 case 'r':
  /* length of data to read */
  len = src[6];
  break;
 case 'w':
  /* Skip 6 bytes for package type and register address */
  len = src[0] - 6;
  break;
 default:
  dev_err(priv->dev, "%s Wrong code %02x.\n", __func__, src[1]);
  ret = 0;
  goto exit;
 }

 if (len < 1) {
  dev_err(priv->dev, "pkg fmt invalid %02x.\n", len);
  ret = 0;
  goto exit;
 }

 for (j = 0; j < priv->ndev; j++)
  if (src[2] == priv->tasdevice[j].dev_addr) {
   chn = j;
   break;
  }
 if (j >= priv->ndev) {
  dev_err(priv->dev, "no such device 0x%02x.\n", src[2]);
  ret = 0;
  goto exit;
 }

 reg = TASDEVICE_REG(src[3], src[4], src[5]);

 guard(mutex)(&priv->codec_lock);

 if (src[1] == 'w') {
  if (len > 1)
   ret = tasdevice_dev_bulk_write(priv, chn, reg,
     &src[6], len);
  else
   ret = tasdevice_dev_write(priv, chn, reg, src[6]);
 } else {
  struct acoustic_data *p = &priv->acou_data;

  memcpy(p, src, 6);
  if (len > 1) {
   ret = tasdevice_dev_bulk_read(priv, chn, reg,
    p->data, len);
  } else {
   ret = tasdevice_dev_read(priv, chn, reg, &val);
   p->data[0] = val;
  }
  p->len = len + 6;
 }

 if (ret)
  dev_err(priv->dev, "i2c communication error.\n");
 else
  ret = count;
exit:
 kfree(src);
 return ret;
}

static const struct file_operations acoustic_ctl_fops = {
 .open = simple_open,
 .read = acoustic_ctl_read,
 .write = acoustic_ctl_write,
};
#endif

static void tasdevice_fw_ready(const struct firmware *fmw,
 void *context)
{
 struct tasdevice_priv *tas_priv = context;
#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
 struct snd_soc_component *comp = tas_priv->codec;
 struct dentry *debugfs_root = comp->debugfs_root;
 char *acoustic_debugfs_node;
#endif
 int ret = 0;
 int i;

 mutex_lock(&tas_priv->codec_lock);

 ret = tasdevice_rca_parser(tas_priv, fmw);
 if (ret) {
  tasdevice_config_info_remove(tas_priv);
  goto out;
 }
 tasdevice_create_control(tas_priv);

 tasdevice_dsp_remove(tas_priv);
 tasdevice_calbin_remove(tas_priv);
 /*
 * The baseline is the RCA-only case, and then the code attempts to
 * load DSP firmware but in case of failures just keep going, i.e.
 * failing to load DSP firmware is NOT an error.
 */

 tas_priv->fw_state = TASDEVICE_RCA_FW_OK;
 if (tas_priv->name_prefix)
  scnprintf(tas_priv->coef_binaryname, 64, "%s-%s_coef.bin",
   tas_priv->name_prefix, tas_priv->dev_name);
 else
  scnprintf(tas_priv->coef_binaryname, 64, "%s_coef.bin",
   tas_priv->dev_name);
 ret = tasdevice_dsp_parser(tas_priv);
 if (ret) {
  dev_err(tas_priv->dev, "dspfw load %s error\n",
   tas_priv->coef_binaryname);
  goto out;
 }

 /*
 * If no dsp-related kcontrol created, the dsp resource will be freed.
 */

 ret = tasdevice_dsp_create_ctrls(tas_priv);
 if (ret) {
  dev_err(tas_priv->dev, "dsp controls error\n");
  goto out;
 }

 ret = tasdevice_create_cali_ctrls(tas_priv);
 if (ret) {
  dev_err(tas_priv->dev, "cali controls error\n");
  goto out;
 }

 tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;

 /* If calibrated data occurs error, dsp will still works with default
 * calibrated data inside algo.
 */

 for (i = 0; i < tas_priv->ndev; i++) {
  if (tas_priv->name_prefix)
   scnprintf(tas_priv->cal_binaryname[i], 64,
    "%s-%s_cal_0x%02x.bin", tas_priv->name_prefix,
    tas_priv->dev_name,
    tas_priv->tasdevice[i].dev_addr);
  else
   scnprintf(tas_priv->cal_binaryname[i], 64,
    "%s_cal_0x%02x.bin", tas_priv->dev_name,
    tas_priv->tasdevice[i].dev_addr);
  ret = tas2781_load_calibration(tas_priv,
   tas_priv->cal_binaryname[i], i);
  if (ret != 0)
   dev_err(tas_priv->dev,
    "%s: load %s error, default will effect\n",
    __func__, tas_priv->cal_binaryname[i]);
 }

 tasdevice_prmg_load(tas_priv, 0);
 tas_priv->cur_prog = 0;

 /* Init common setting for different audio profiles */
 if (tas_priv->rcabin.init_profile_id >= 0)
  tasdevice_select_cfg_blk(tas_priv,
   tas_priv->rcabin.init_profile_id,
   TASDEVICE_BIN_BLK_PRE_POWER_UP);

#ifdef CONFIG_SND_SOC_TAS2781_ACOUST_I2C
 if (tas_priv->name_prefix)
  acoustic_debugfs_node = devm_kasprintf(tas_priv->dev,
   GFP_KERNEL, "%s_acoustic_ctl", tas_priv->name_prefix);
 else
  acoustic_debugfs_node = devm_kstrdup(tas_priv->dev,
   "acoustic_ctl", GFP_KERNEL);
 debugfs_create_file(acoustic_debugfs_node, 0644, debugfs_root,
  comp, &acoustic_ctl_fops);
#endif
out:
 if (tas_priv->fw_state == TASDEVICE_RCA_FW_OK) {
  /* If DSP FW fail, DSP kcontrol won't be created. */
  tasdevice_dsp_remove(tas_priv);
 }
 mutex_unlock(&tas_priv->codec_lock);
 release_firmware(fmw);
}

static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w,
   struct snd_kcontrol *kcontrol, int event)
{
 struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 int state = 0;

 /* Codec Lock Hold */
 mutex_lock(&tas_priv->codec_lock);
 if (event == SND_SOC_DAPM_PRE_PMD)
  state = 1;
 tasdevice_tuning_switch(tas_priv, state);
 /* Codec Lock Release*/
 mutex_unlock(&tas_priv->codec_lock);

 return 0;
}

static const struct snd_soc_dapm_widget tasdevice_dapm_widgets[] = {
 SND_SOC_DAPM_AIF_IN("ASI""ASI Playback", 0, SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_AIF_OUT_E("ASI OUT""ASI Capture", 0, SND_SOC_NOPM,
  0, 0, tasdevice_dapm_event,
  SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 SND_SOC_DAPM_SPK("SPK", tasdevice_dapm_event),
 SND_SOC_DAPM_OUTPUT("OUT"),
 SND_SOC_DAPM_INPUT("DMIC"),
};

static const struct snd_soc_dapm_route tasdevice_audio_map[] = {
 {"SPK", NULL, "ASI"},
 {"OUT", NULL, "SPK"},
 {"ASI OUT", NULL, "DMIC"},
};

static int tasdevice_startup(struct snd_pcm_substream *substream,
      struct snd_soc_dai *dai)
{
 struct snd_soc_component *codec = dai->component;
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);

 switch (tas_priv->fw_state) {
 case TASDEVICE_RCA_FW_OK:
 case TASDEVICE_DSP_FW_ALL_OK:
  return 0;
 default:
  return -EINVAL;
 }
}

static int tasdevice_hw_params(struct snd_pcm_substream *substream,
 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
 struct tasdevice_priv *tas_priv = snd_soc_dai_get_drvdata(dai);
 unsigned int slot_width;
 unsigned int fsrate;
 int bclk_rate;

 fsrate = params_rate(params);
 switch (fsrate) {
 case 48000:
 case 44100:
  break;
 default:
  dev_err(tas_priv->dev, "%s: incorrect sample rate = %u\n",
   __func__, fsrate);
  return -EINVAL;
 }

 slot_width = params_width(params);
 switch (slot_width) {
 case 16:
 case 20:
 case 24:
 case 32:
  break;
 default:
  dev_err(tas_priv->dev, "%s: incorrect slot width = %u\n",
   __func__, slot_width);
  return -EINVAL;
 }

 bclk_rate = snd_soc_params_to_bclk(params);
 if (bclk_rate < 0) {
  dev_err(tas_priv->dev, "%s: incorrect bclk rate = %d\n",
   __func__, bclk_rate);
  return bclk_rate;
 }

 return 0;
}

static int tasdevice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 int clk_id, unsigned int freq, int dir)
{
 struct tasdevice_priv *tas_priv = snd_soc_dai_get_drvdata(codec_dai);

 tas_priv->sysclk = freq;

 return 0;
}

static const struct snd_soc_dai_ops tasdevice_dai_ops = {
 .startup = tasdevice_startup,
 .hw_params = tasdevice_hw_params,
 .set_sysclk = tasdevice_set_dai_sysclk,
};

static struct snd_soc_dai_driver tasdevice_dai_driver[] = {
 {
  .name = "tasdev_codec",
  .id = 0,
  .playback = {
   .stream_name = "Playback",
   .channels_min = 1,
   .channels_max = 4,
   .rates  = TASDEVICE_RATES,
   .formats = TASDEVICE_FORMATS,
  },
  .capture = {
   .stream_name = "Capture",
   .channels_min = 1,
   .channels_max = 4,
   .rates  = TASDEVICE_RATES,
   .formats = TASDEVICE_FORMATS,
  },
  .ops = &tasdevice_dai_ops,
  .symmetric_rate = 1,
 },
};

static int tasdevice_codec_probe(struct snd_soc_component *codec)
{
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
 struct snd_kcontrol_new *p;
 unsigned int size;
 int rc;

 switch (tas_priv->chip_id) {
 case TAS2781:
  p = (struct snd_kcontrol_new *)tas2781_snd_controls;
  size = ARRAY_SIZE(tas2781_snd_controls);
  break;
 default:
  p = (struct snd_kcontrol_new *)tas2563_snd_controls;
  size = ARRAY_SIZE(tas2563_snd_controls);
 }

 rc = snd_soc_add_component_controls(codec, p, size);
 if (rc < 0) {
  dev_err(tas_priv->dev, "%s: Add control err rc = %d",
   __func__, rc);
  return rc;
 }

 tas_priv->name_prefix = codec->name_prefix;
 return tascodec_init(tas_priv, codec, THIS_MODULE, tasdevice_fw_ready);
}

static void tasdevice_deinit(void *context)
{
 struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
 struct tasdevice *tasdev = tas_priv->tasdevice;
 int i;

 for (i = 0; i < tas_priv->ndev; i++)
  kfree(tasdev[i].cali_data_backup);

 tasdevice_config_info_remove(tas_priv);
 tasdevice_dsp_remove(tas_priv);
 tasdevice_calbin_remove(tas_priv);
 tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
}

static void tasdevice_codec_remove(struct snd_soc_component *codec)
{
 struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);

 tasdevice_deinit(tas_priv);
}

static const struct snd_soc_component_driver
 soc_codec_driver_tasdevice = {
 .probe   = tasdevice_codec_probe,
 .remove   = tasdevice_codec_remove,
 .controls  = tasdevice_snd_controls,
 .num_controls  = ARRAY_SIZE(tasdevice_snd_controls),
 .dapm_widgets  = tasdevice_dapm_widgets,
 .num_dapm_widgets = ARRAY_SIZE(tasdevice_dapm_widgets),
 .dapm_routes  = tasdevice_audio_map,
 .num_dapm_routes = ARRAY_SIZE(tasdevice_audio_map),
 .idle_bias_on  = 1,
 .endianness  = 1,
};

static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv)
{
 struct i2c_client *client = (struct i2c_client *)tas_priv->client;
 unsigned int dev_addrs[TASDEVICE_MAX_CHANNELS];
 int ndev = 0;
 int i, rc;

 if (tas_priv->isacpi) {
  ndev = device_property_read_u32_array(&client->dev,
   "ti,audio-slots", NULL, 0);
  if (ndev <= 0) {
   ndev = 1;
   dev_addrs[0] = client->addr;
  } else {
   ndev = (ndev < ARRAY_SIZE(dev_addrs))
    ? ndev : ARRAY_SIZE(dev_addrs);
   rc = device_property_read_u32_array(&client->dev,
    "ti,audio-slots", dev_addrs, ndev);
   if (rc != 0) {
    ndev = 1;
    dev_addrs[0] = client->addr;
   }
  }

  tas_priv->irq =
   acpi_dev_gpio_irq_get(ACPI_COMPANION(&client->dev), 0);
 } else if (IS_ENABLED(CONFIG_OF)) {
  struct device_node *np = tas_priv->dev->of_node;
  u64 addr;

  for (i = 0; i < TASDEVICE_MAX_CHANNELS; i++) {
   if (of_property_read_reg(np, i, &addr, NULL))
    break;
   dev_addrs[ndev++] = addr;
  }

  tas_priv->irq = of_irq_get(np, 0);
 } else {
  ndev = 1;
  dev_addrs[0] = client->addr;
 }
 tas_priv->ndev = ndev;
 for (i = 0; i < ndev; i++)
  tas_priv->tasdevice[i].dev_addr = dev_addrs[i];

 tas_priv->reset = devm_gpiod_get_optional(&client->dev,
   "reset", GPIOD_OUT_HIGH);
 if (IS_ERR(tas_priv->reset))
  dev_err(tas_priv->dev, "%s Can't get reset GPIO\n",
   __func__);

 strcpy(tas_priv->dev_name, tasdevice_id[tas_priv->chip_id].name);
}

static int tasdevice_i2c_probe(struct i2c_client *i2c)
{
 const struct acpi_device_id *acpi_id;
 struct tasdevice_priv *tas_priv;
 int ret;

 tas_priv = tasdevice_kzalloc(i2c);
 if (!tas_priv)
  return -ENOMEM;

 dev_set_drvdata(&i2c->dev, tas_priv);

 if (ACPI_HANDLE(&i2c->dev)) {
  acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table,
    &i2c->dev);
  if (!acpi_id) {
   dev_err(&i2c->dev, "No driver data\n");
   ret = -EINVAL;
   goto err;
  }
  tas_priv->chip_id = acpi_id->driver_data;
  tas_priv->isacpi = true;
 } else {
  tas_priv->chip_id = (uintptr_t)i2c_get_match_data(i2c);
  tas_priv->isacpi = false;
 }

 tasdevice_parse_dt(tas_priv);

 ret = tasdevice_init(tas_priv);
 if (ret)
  goto err;

 tasdevice_reset(tas_priv);

 ret = devm_snd_soc_register_component(tas_priv->dev,
  &soc_codec_driver_tasdevice,
  tasdevice_dai_driver, ARRAY_SIZE(tasdevice_dai_driver));
 if (ret) {
  dev_err(tas_priv->dev, "%s: codec register error:0x%08x\n",
   __func__, ret);
  goto err;
 }
err:
 if (ret < 0)
  tasdevice_remove(tas_priv);
 return ret;
}

static void tasdevice_i2c_remove(struct i2c_client *client)
{
 struct tasdevice_priv *tas_priv = i2c_get_clientdata(client);

 tasdevice_remove(tas_priv);
}

#ifdef CONFIG_ACPI
static const struct acpi_device_id tasdevice_acpi_match[] = {
 { "TAS2781", TAS2781 },
 {},
};

MODULE_DEVICE_TABLE(acpi, tasdevice_acpi_match);
#endif

static struct i2c_driver tasdevice_i2c_driver = {
 .driver = {
  .name = "tasdev-codec",
  .of_match_table = of_match_ptr(tasdevice_of_match),
#ifdef CONFIG_ACPI
  .acpi_match_table = ACPI_PTR(tasdevice_acpi_match),
#endif
 },
 .probe = tasdevice_i2c_probe,
 .remove = tasdevice_i2c_remove,
 .id_table = tasdevice_id,
};

module_i2c_driver(tasdevice_i2c_driver);

MODULE_AUTHOR("Shenghao Ding ");
MODULE_AUTHOR("Kevin Lu ");
MODULE_DESCRIPTION("ASoC TAS2781 Driver");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");

Messung V0.5
C=98 H=92 G=94

¤ Dauer der Verarbeitung: 0.25 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.