Merge remote-tracking branches 'asoc/topic/tas571x', 'asoc/topic/tlv320aic31xx', 'asoc/topic/tpa6130a2', 'asoc/topic/twl6040' and 'asoc/topic/wm8731' into asoc-next
This commit is contained in:
commit
1a946005b3
|
@ -28,6 +28,7 @@
|
|||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "tas571x.h"
|
||||
|
||||
|
@ -63,6 +64,10 @@ static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg)
|
|||
case TAS571X_INPUT_MUX_REG:
|
||||
case TAS571X_CH4_SRC_SELECT_REG:
|
||||
case TAS571X_PWM_MUX_REG:
|
||||
case TAS5717_CH1_RIGHT_CH_MIX_REG:
|
||||
case TAS5717_CH1_LEFT_CH_MIX_REG:
|
||||
case TAS5717_CH2_LEFT_CH_MIX_REG:
|
||||
case TAS5717_CH2_RIGHT_CH_MIX_REG:
|
||||
return 4;
|
||||
default:
|
||||
return 1;
|
||||
|
@ -135,6 +140,129 @@ static int tas571x_reg_read(void *context, unsigned int reg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* register write for 8- and 20-byte registers
|
||||
*/
|
||||
static int tas571x_reg_write_multiword(struct i2c_client *client,
|
||||
unsigned int reg, const long values[], size_t len)
|
||||
{
|
||||
size_t i;
|
||||
uint8_t *buf, *p;
|
||||
int ret;
|
||||
size_t send_size = 1 + len * sizeof(uint32_t);
|
||||
|
||||
buf = kzalloc(send_size, GFP_KERNEL | GFP_DMA);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
buf[0] = reg;
|
||||
|
||||
for (i = 0, p = buf + 1; i < len; i++, p += sizeof(uint32_t))
|
||||
put_unaligned_be32(values[i], p);
|
||||
|
||||
ret = i2c_master_send(client, buf, send_size);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
if (ret == send_size)
|
||||
return 0;
|
||||
else if (ret < 0)
|
||||
return ret;
|
||||
else
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* register read for 8- and 20-byte registers
|
||||
*/
|
||||
static int tas571x_reg_read_multiword(struct i2c_client *client,
|
||||
unsigned int reg, long values[], size_t len)
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t send_buf;
|
||||
uint8_t *recv_buf, *p;
|
||||
struct i2c_msg msgs[2];
|
||||
unsigned int recv_size = len * sizeof(uint32_t);
|
||||
int ret;
|
||||
|
||||
recv_buf = kzalloc(recv_size, GFP_KERNEL | GFP_DMA);
|
||||
if (!recv_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
send_buf = reg;
|
||||
|
||||
msgs[0].addr = client->addr;
|
||||
msgs[0].len = sizeof(send_buf);
|
||||
msgs[0].buf = &send_buf;
|
||||
msgs[0].flags = 0;
|
||||
|
||||
msgs[1].addr = client->addr;
|
||||
msgs[1].len = recv_size;
|
||||
msgs[1].buf = recv_buf;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret < 0)
|
||||
goto err_ret;
|
||||
else if (ret != ARRAY_SIZE(msgs)) {
|
||||
ret = -EIO;
|
||||
goto err_ret;
|
||||
}
|
||||
|
||||
for (i = 0, p = recv_buf; i < len; i++, p += sizeof(uint32_t))
|
||||
values[i] = get_unaligned_be32(p);
|
||||
|
||||
err_ret:
|
||||
kfree(recv_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Integer array controls for setting biquad, mixer, DRC coefficients.
|
||||
* According to the datasheet each coefficient is effectively 26bits,
|
||||
* i.e. stored as 32bits, where bits [31:26] are ignored.
|
||||
* TI's TAS57xx Graphical Development Environment tool however produces
|
||||
* coefficients with more than 26 bits. For this reason we allow values
|
||||
* in the full 32-bits reange.
|
||||
* The coefficients are ordered as given in the TAS571x data sheet:
|
||||
* b0, b1, b2, a1, a2
|
||||
*/
|
||||
|
||||
static int tas571x_coefficient_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
int numcoef = kcontrol->private_value >> 16;
|
||||
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = numcoef;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 0xffffffff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tas571x_coefficient_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct i2c_client *i2c = to_i2c_client(codec->dev);
|
||||
int numcoef = kcontrol->private_value >> 16;
|
||||
int index = kcontrol->private_value & 0xffff;
|
||||
|
||||
return tas571x_reg_read_multiword(i2c, index,
|
||||
ucontrol->value.integer.value, numcoef);
|
||||
}
|
||||
|
||||
static int tas571x_coefficient_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
|
||||
struct i2c_client *i2c = to_i2c_client(codec->dev);
|
||||
int numcoef = kcontrol->private_value >> 16;
|
||||
int index = kcontrol->private_value & 0xffff;
|
||||
|
||||
return tas571x_reg_write_multiword(i2c, index,
|
||||
ucontrol->value.integer.value, numcoef);
|
||||
}
|
||||
|
||||
static int tas571x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
|
||||
{
|
||||
struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
|
||||
|
@ -241,6 +369,15 @@ static const struct snd_soc_dai_ops tas571x_dai_ops = {
|
|||
.digital_mute = tas571x_mute,
|
||||
};
|
||||
|
||||
|
||||
#define BIQUAD_COEFS(xname, reg) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = tas571x_coefficient_info, \
|
||||
.get = tas571x_coefficient_get,\
|
||||
.put = tas571x_coefficient_put, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
|
||||
.private_value = reg | (5 << 16) }
|
||||
|
||||
static const char *const tas5711_supply_names[] = {
|
||||
"AVDD",
|
||||
"DVDD",
|
||||
|
@ -264,6 +401,16 @@ static const struct snd_kcontrol_new tas5711_controls[] = {
|
|||
TAS571X_SOFT_MUTE_REG,
|
||||
TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
|
||||
1, 1),
|
||||
|
||||
SOC_DOUBLE_R_RANGE("CH1 Mixer Volume",
|
||||
TAS5717_CH1_LEFT_CH_MIX_REG,
|
||||
TAS5717_CH1_RIGHT_CH_MIX_REG,
|
||||
16, 0, 0x80, 0),
|
||||
|
||||
SOC_DOUBLE_R_RANGE("CH2 Mixer Volume",
|
||||
TAS5717_CH2_LEFT_CH_MIX_REG,
|
||||
TAS5717_CH2_RIGHT_CH_MIX_REG,
|
||||
16, 0, 0x80, 0),
|
||||
};
|
||||
|
||||
static const struct regmap_range tas571x_readonly_regs_range[] = {
|
||||
|
@ -340,6 +487,43 @@ static const struct snd_kcontrol_new tas5717_controls[] = {
|
|||
TAS571X_SOFT_MUTE_REG,
|
||||
TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
|
||||
1, 1),
|
||||
|
||||
/*
|
||||
* The biquads are named according to the register names.
|
||||
* Please note that TI's TAS57xx Graphical Development Environment
|
||||
* tool names them different.
|
||||
*/
|
||||
BIQUAD_COEFS("CH1 - Biquad 0", TAS5717_CH1_BQ0_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 1", TAS5717_CH1_BQ1_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 2", TAS5717_CH1_BQ2_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 3", TAS5717_CH1_BQ3_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 4", TAS5717_CH1_BQ4_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 5", TAS5717_CH1_BQ5_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 6", TAS5717_CH1_BQ6_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 7", TAS5717_CH1_BQ7_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 8", TAS5717_CH1_BQ8_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 9", TAS5717_CH1_BQ9_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 10", TAS5717_CH1_BQ10_REG),
|
||||
BIQUAD_COEFS("CH1 - Biquad 11", TAS5717_CH1_BQ11_REG),
|
||||
|
||||
BIQUAD_COEFS("CH2 - Biquad 0", TAS5717_CH2_BQ0_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 1", TAS5717_CH2_BQ1_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 2", TAS5717_CH2_BQ2_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 3", TAS5717_CH2_BQ3_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 4", TAS5717_CH2_BQ4_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 5", TAS5717_CH2_BQ5_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 6", TAS5717_CH2_BQ6_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 7", TAS5717_CH2_BQ7_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 8", TAS5717_CH2_BQ8_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 9", TAS5717_CH2_BQ9_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 10", TAS5717_CH2_BQ10_REG),
|
||||
BIQUAD_COEFS("CH2 - Biquad 11", TAS5717_CH2_BQ11_REG),
|
||||
|
||||
BIQUAD_COEFS("CH3 - Biquad 0", TAS5717_CH3_BQ0_REG),
|
||||
BIQUAD_COEFS("CH3 - Biquad 1", TAS5717_CH3_BQ1_REG),
|
||||
|
||||
BIQUAD_COEFS("CH4 - Biquad 0", TAS5717_CH4_BQ0_REG),
|
||||
BIQUAD_COEFS("CH4 - Biquad 1", TAS5717_CH4_BQ1_REG),
|
||||
};
|
||||
|
||||
static const struct reg_default tas5717_reg_defaults[] = {
|
||||
|
@ -350,6 +534,10 @@ static const struct reg_default tas5717_reg_defaults[] = {
|
|||
{ 0x08, 0x00c0 },
|
||||
{ 0x09, 0x00c0 },
|
||||
{ 0x1b, 0x82 },
|
||||
{ TAS5717_CH1_RIGHT_CH_MIX_REG, 0x0 },
|
||||
{ TAS5717_CH1_LEFT_CH_MIX_REG, 0x800000},
|
||||
{ TAS5717_CH2_LEFT_CH_MIX_REG, 0x0 },
|
||||
{ TAS5717_CH2_RIGHT_CH_MIX_REG, 0x800000},
|
||||
};
|
||||
|
||||
static const struct regmap_config tas5717_regmap_config = {
|
||||
|
|
|
@ -52,4 +52,44 @@
|
|||
#define TAS571X_CH4_SRC_SELECT_REG 0x21
|
||||
#define TAS571X_PWM_MUX_REG 0x25
|
||||
|
||||
/* 20-byte biquad registers */
|
||||
#define TAS5717_CH1_BQ0_REG 0x26
|
||||
#define TAS5717_CH1_BQ1_REG 0x27
|
||||
#define TAS5717_CH1_BQ2_REG 0x28
|
||||
#define TAS5717_CH1_BQ3_REG 0x29
|
||||
#define TAS5717_CH1_BQ4_REG 0x2a
|
||||
#define TAS5717_CH1_BQ5_REG 0x2b
|
||||
#define TAS5717_CH1_BQ6_REG 0x2c
|
||||
#define TAS5717_CH1_BQ7_REG 0x2d
|
||||
#define TAS5717_CH1_BQ8_REG 0x2e
|
||||
#define TAS5717_CH1_BQ9_REG 0x2f
|
||||
|
||||
#define TAS5717_CH2_BQ0_REG 0x30
|
||||
#define TAS5717_CH2_BQ1_REG 0x31
|
||||
#define TAS5717_CH2_BQ2_REG 0x32
|
||||
#define TAS5717_CH2_BQ3_REG 0x33
|
||||
#define TAS5717_CH2_BQ4_REG 0x34
|
||||
#define TAS5717_CH2_BQ5_REG 0x35
|
||||
#define TAS5717_CH2_BQ6_REG 0x36
|
||||
#define TAS5717_CH2_BQ7_REG 0x37
|
||||
#define TAS5717_CH2_BQ8_REG 0x38
|
||||
#define TAS5717_CH2_BQ9_REG 0x39
|
||||
|
||||
#define TAS5717_CH1_BQ10_REG 0x58
|
||||
#define TAS5717_CH1_BQ11_REG 0x59
|
||||
|
||||
#define TAS5717_CH4_BQ0_REG 0x5a
|
||||
#define TAS5717_CH4_BQ1_REG 0x5b
|
||||
|
||||
#define TAS5717_CH2_BQ10_REG 0x5c
|
||||
#define TAS5717_CH2_BQ11_REG 0x5d
|
||||
|
||||
#define TAS5717_CH3_BQ0_REG 0x5e
|
||||
#define TAS5717_CH3_BQ1_REG 0x5f
|
||||
|
||||
#define TAS5717_CH1_RIGHT_CH_MIX_REG 0x72
|
||||
#define TAS5717_CH1_LEFT_CH_MIX_REG 0x73
|
||||
#define TAS5717_CH2_LEFT_CH_MIX_REG 0x76
|
||||
#define TAS5717_CH2_RIGHT_CH_MIX_REG 0x77
|
||||
|
||||
#endif /* _TAS571X_H */
|
||||
|
|
|
@ -38,141 +38,143 @@ struct aic31xx_pdata {
|
|||
int micbias_vg;
|
||||
};
|
||||
|
||||
#define AIC31XX_REG(page, reg) ((page * 128) + reg)
|
||||
|
||||
/* Page Control Register */
|
||||
#define AIC31XX_PAGECTL 0x00
|
||||
#define AIC31XX_PAGECTL AIC31XX_REG(0, 0)
|
||||
|
||||
/* Page 0 Registers */
|
||||
/* Software reset register */
|
||||
#define AIC31XX_RESET 0x01
|
||||
#define AIC31XX_RESET AIC31XX_REG(0, 1)
|
||||
/* OT FLAG register */
|
||||
#define AIC31XX_OT_FLAG 0x03
|
||||
#define AIC31XX_OT_FLAG AIC31XX_REG(0, 3)
|
||||
/* Clock clock Gen muxing, Multiplexers*/
|
||||
#define AIC31XX_CLKMUX 0x04
|
||||
#define AIC31XX_CLKMUX AIC31XX_REG(0, 4)
|
||||
/* PLL P and R-VAL register */
|
||||
#define AIC31XX_PLLPR 0x05
|
||||
#define AIC31XX_PLLPR AIC31XX_REG(0, 5)
|
||||
/* PLL J-VAL register */
|
||||
#define AIC31XX_PLLJ 0x06
|
||||
#define AIC31XX_PLLJ AIC31XX_REG(0, 6)
|
||||
/* PLL D-VAL MSB register */
|
||||
#define AIC31XX_PLLDMSB 0x07
|
||||
#define AIC31XX_PLLDMSB AIC31XX_REG(0, 7)
|
||||
/* PLL D-VAL LSB register */
|
||||
#define AIC31XX_PLLDLSB 0x08
|
||||
#define AIC31XX_PLLDLSB AIC31XX_REG(0, 8)
|
||||
/* DAC NDAC_VAL register*/
|
||||
#define AIC31XX_NDAC 0x0B
|
||||
#define AIC31XX_NDAC AIC31XX_REG(0, 11)
|
||||
/* DAC MDAC_VAL register */
|
||||
#define AIC31XX_MDAC 0x0C
|
||||
#define AIC31XX_MDAC AIC31XX_REG(0, 12)
|
||||
/* DAC OSR setting register 1, MSB value */
|
||||
#define AIC31XX_DOSRMSB 0x0D
|
||||
#define AIC31XX_DOSRMSB AIC31XX_REG(0, 13)
|
||||
/* DAC OSR setting register 2, LSB value */
|
||||
#define AIC31XX_DOSRLSB 0x0E
|
||||
#define AIC31XX_MINI_DSP_INPOL 0x10
|
||||
#define AIC31XX_DOSRLSB AIC31XX_REG(0, 14)
|
||||
#define AIC31XX_MINI_DSP_INPOL AIC31XX_REG(0, 16)
|
||||
/* Clock setting register 8, PLL */
|
||||
#define AIC31XX_NADC 0x12
|
||||
#define AIC31XX_NADC AIC31XX_REG(0, 18)
|
||||
/* Clock setting register 9, PLL */
|
||||
#define AIC31XX_MADC 0x13
|
||||
#define AIC31XX_MADC AIC31XX_REG(0, 19)
|
||||
/* ADC Oversampling (AOSR) Register */
|
||||
#define AIC31XX_AOSR 0x14
|
||||
#define AIC31XX_AOSR AIC31XX_REG(0, 20)
|
||||
/* Clock setting register 9, Multiplexers */
|
||||
#define AIC31XX_CLKOUTMUX 0x19
|
||||
#define AIC31XX_CLKOUTMUX AIC31XX_REG(0, 25)
|
||||
/* Clock setting register 10, CLOCKOUT M divider value */
|
||||
#define AIC31XX_CLKOUTMVAL 0x1A
|
||||
#define AIC31XX_CLKOUTMVAL AIC31XX_REG(0, 26)
|
||||
/* Audio Interface Setting Register 1 */
|
||||
#define AIC31XX_IFACE1 0x1B
|
||||
#define AIC31XX_IFACE1 AIC31XX_REG(0, 27)
|
||||
/* Audio Data Slot Offset Programming */
|
||||
#define AIC31XX_DATA_OFFSET 0x1C
|
||||
#define AIC31XX_DATA_OFFSET AIC31XX_REG(0, 28)
|
||||
/* Audio Interface Setting Register 2 */
|
||||
#define AIC31XX_IFACE2 0x1D
|
||||
#define AIC31XX_IFACE2 AIC31XX_REG(0, 29)
|
||||
/* Clock setting register 11, BCLK N Divider */
|
||||
#define AIC31XX_BCLKN 0x1E
|
||||
#define AIC31XX_BCLKN AIC31XX_REG(0, 30)
|
||||
/* Audio Interface Setting Register 3, Secondary Audio Interface */
|
||||
#define AIC31XX_IFACESEC1 0x1F
|
||||
#define AIC31XX_IFACESEC1 AIC31XX_REG(0, 31)
|
||||
/* Audio Interface Setting Register 4 */
|
||||
#define AIC31XX_IFACESEC2 0x20
|
||||
#define AIC31XX_IFACESEC2 AIC31XX_REG(0, 32)
|
||||
/* Audio Interface Setting Register 5 */
|
||||
#define AIC31XX_IFACESEC3 0x21
|
||||
#define AIC31XX_IFACESEC3 AIC31XX_REG(0, 33)
|
||||
/* I2C Bus Condition */
|
||||
#define AIC31XX_I2C 0x22
|
||||
#define AIC31XX_I2C AIC31XX_REG(0, 34)
|
||||
/* ADC FLAG */
|
||||
#define AIC31XX_ADCFLAG 0x24
|
||||
#define AIC31XX_ADCFLAG AIC31XX_REG(0, 36)
|
||||
/* DAC Flag Registers */
|
||||
#define AIC31XX_DACFLAG1 0x25
|
||||
#define AIC31XX_DACFLAG2 0x26
|
||||
#define AIC31XX_DACFLAG1 AIC31XX_REG(0, 37)
|
||||
#define AIC31XX_DACFLAG2 AIC31XX_REG(0, 38)
|
||||
/* Sticky Interrupt flag (overflow) */
|
||||
#define AIC31XX_OFFLAG 0x27
|
||||
#define AIC31XX_OFFLAG AIC31XX_REG(0, 39)
|
||||
/* Sticy DAC Interrupt flags */
|
||||
#define AIC31XX_INTRDACFLAG 0x2C
|
||||
#define AIC31XX_INTRDACFLAG AIC31XX_REG(0, 44)
|
||||
/* Sticy ADC Interrupt flags */
|
||||
#define AIC31XX_INTRADCFLAG 0x2D
|
||||
#define AIC31XX_INTRADCFLAG AIC31XX_REG(0, 45)
|
||||
/* DAC Interrupt flags 2 */
|
||||
#define AIC31XX_INTRDACFLAG2 0x2E
|
||||
#define AIC31XX_INTRDACFLAG2 AIC31XX_REG(0, 46)
|
||||
/* ADC Interrupt flags 2 */
|
||||
#define AIC31XX_INTRADCFLAG2 0x2F
|
||||
#define AIC31XX_INTRADCFLAG2 AIC31XX_REG(0, 47)
|
||||
/* INT1 interrupt control */
|
||||
#define AIC31XX_INT1CTRL 0x30
|
||||
#define AIC31XX_INT1CTRL AIC31XX_REG(0, 48)
|
||||
/* INT2 interrupt control */
|
||||
#define AIC31XX_INT2CTRL 0x31
|
||||
#define AIC31XX_INT2CTRL AIC31XX_REG(0, 49)
|
||||
/* GPIO1 control */
|
||||
#define AIC31XX_GPIO1 0x33
|
||||
#define AIC31XX_GPIO1 AIC31XX_REG(0, 50)
|
||||
|
||||
#define AIC31XX_DACPRB 0x3C
|
||||
#define AIC31XX_DACPRB AIC31XX_REG(0, 60)
|
||||
/* ADC Instruction Set Register */
|
||||
#define AIC31XX_ADCPRB 0x3D
|
||||
#define AIC31XX_ADCPRB AIC31XX_REG(0, 61)
|
||||
/* DAC channel setup register */
|
||||
#define AIC31XX_DACSETUP 0x3F
|
||||
#define AIC31XX_DACSETUP AIC31XX_REG(0, 63)
|
||||
/* DAC Mute and volume control register */
|
||||
#define AIC31XX_DACMUTE 0x40
|
||||
#define AIC31XX_DACMUTE AIC31XX_REG(0, 64)
|
||||
/* Left DAC channel digital volume control */
|
||||
#define AIC31XX_LDACVOL 0x41
|
||||
#define AIC31XX_LDACVOL AIC31XX_REG(0, 65)
|
||||
/* Right DAC channel digital volume control */
|
||||
#define AIC31XX_RDACVOL 0x42
|
||||
#define AIC31XX_RDACVOL AIC31XX_REG(0, 66)
|
||||
/* Headset detection */
|
||||
#define AIC31XX_HSDETECT 0x43
|
||||
#define AIC31XX_HSDETECT AIC31XX_REG(0, 67)
|
||||
/* ADC Digital Mic */
|
||||
#define AIC31XX_ADCSETUP 0x51
|
||||
#define AIC31XX_ADCSETUP AIC31XX_REG(0, 81)
|
||||
/* ADC Digital Volume Control Fine Adjust */
|
||||
#define AIC31XX_ADCFGA 0x52
|
||||
#define AIC31XX_ADCFGA AIC31XX_REG(0, 82)
|
||||
/* ADC Digital Volume Control Coarse Adjust */
|
||||
#define AIC31XX_ADCVOL 0x53
|
||||
#define AIC31XX_ADCVOL AIC31XX_REG(0, 83)
|
||||
|
||||
|
||||
/* Page 1 Registers */
|
||||
/* Headphone drivers */
|
||||
#define AIC31XX_HPDRIVER 0x9F
|
||||
#define AIC31XX_HPDRIVER AIC31XX_REG(1, 31)
|
||||
/* Class-D Speakear Amplifier */
|
||||
#define AIC31XX_SPKAMP 0xA0
|
||||
#define AIC31XX_SPKAMP AIC31XX_REG(1, 32)
|
||||
/* HP Output Drivers POP Removal Settings */
|
||||
#define AIC31XX_HPPOP 0xA1
|
||||
#define AIC31XX_HPPOP AIC31XX_REG(1, 33)
|
||||
/* Output Driver PGA Ramp-Down Period Control */
|
||||
#define AIC31XX_SPPGARAMP 0xA2
|
||||
#define AIC31XX_SPPGARAMP AIC31XX_REG(1, 34)
|
||||
/* DAC_L and DAC_R Output Mixer Routing */
|
||||
#define AIC31XX_DACMIXERROUTE 0xA3
|
||||
#define AIC31XX_DACMIXERROUTE AIC31XX_REG(1, 35)
|
||||
/* Left Analog Vol to HPL */
|
||||
#define AIC31XX_LANALOGHPL 0xA4
|
||||
#define AIC31XX_LANALOGHPL AIC31XX_REG(1, 36)
|
||||
/* Right Analog Vol to HPR */
|
||||
#define AIC31XX_RANALOGHPR 0xA5
|
||||
#define AIC31XX_RANALOGHPR AIC31XX_REG(1, 37)
|
||||
/* Left Analog Vol to SPL */
|
||||
#define AIC31XX_LANALOGSPL 0xA6
|
||||
#define AIC31XX_LANALOGSPL AIC31XX_REG(1, 38)
|
||||
/* Right Analog Vol to SPR */
|
||||
#define AIC31XX_RANALOGSPR 0xA7
|
||||
#define AIC31XX_RANALOGSPR AIC31XX_REG(1, 39)
|
||||
/* HPL Driver */
|
||||
#define AIC31XX_HPLGAIN 0xA8
|
||||
#define AIC31XX_HPLGAIN AIC31XX_REG(1, 40)
|
||||
/* HPR Driver */
|
||||
#define AIC31XX_HPRGAIN 0xA9
|
||||
#define AIC31XX_HPRGAIN AIC31XX_REG(1, 41)
|
||||
/* SPL Driver */
|
||||
#define AIC31XX_SPLGAIN 0xAA
|
||||
#define AIC31XX_SPLGAIN AIC31XX_REG(1, 42)
|
||||
/* SPR Driver */
|
||||
#define AIC31XX_SPRGAIN 0xAB
|
||||
#define AIC31XX_SPRGAIN AIC31XX_REG(1, 43)
|
||||
/* HP Driver Control */
|
||||
#define AIC31XX_HPCONTROL 0xAC
|
||||
#define AIC31XX_HPCONTROL AIC31XX_REG(1, 44)
|
||||
/* MIC Bias Control */
|
||||
#define AIC31XX_MICBIAS 0xAE
|
||||
#define AIC31XX_MICBIAS AIC31XX_REG(1, 46)
|
||||
/* MIC PGA*/
|
||||
#define AIC31XX_MICPGA 0xAF
|
||||
#define AIC31XX_MICPGA AIC31XX_REG(1, 47)
|
||||
/* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
|
||||
#define AIC31XX_MICPGAPI 0xB0
|
||||
#define AIC31XX_MICPGAPI AIC31XX_REG(1, 48)
|
||||
/* ADC Input Selection for M-Terminal */
|
||||
#define AIC31XX_MICPGAMI 0xB1
|
||||
#define AIC31XX_MICPGAMI AIC31XX_REG(1, 49)
|
||||
/* Input CM Settings */
|
||||
#define AIC31XX_MICPGACM 0xB2
|
||||
#define AIC31XX_MICPGACM AIC31XX_REG(1, 50)
|
||||
|
||||
/* Bits, masks and shifts */
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <sound/tlv.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "tpa6130a2.h"
|
||||
|
||||
|
@ -40,219 +41,72 @@ enum tpa_model {
|
|||
TPA6140A2,
|
||||
};
|
||||
|
||||
static struct i2c_client *tpa6130a2_client;
|
||||
|
||||
/* This struct is used to save the context */
|
||||
struct tpa6130a2_data {
|
||||
struct mutex mutex;
|
||||
unsigned char regs[TPA6130A2_CACHEREGNUM];
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regulator *supply;
|
||||
int power_gpio;
|
||||
u8 power_state:1;
|
||||
enum tpa_model id;
|
||||
};
|
||||
|
||||
static int tpa6130a2_i2c_read(int reg)
|
||||
static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable)
|
||||
{
|
||||
struct tpa6130a2_data *data;
|
||||
int val;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!tpa6130a2_client))
|
||||
return -EINVAL;
|
||||
data = i2c_get_clientdata(tpa6130a2_client);
|
||||
|
||||
/* If powered off, return the cached value */
|
||||
if (data->power_state) {
|
||||
val = i2c_smbus_read_byte_data(tpa6130a2_client, reg);
|
||||
if (val < 0)
|
||||
dev_err(&tpa6130a2_client->dev, "Read failed\n");
|
||||
else
|
||||
data->regs[reg] = val;
|
||||
} else {
|
||||
val = data->regs[reg];
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int tpa6130a2_i2c_write(int reg, u8 value)
|
||||
{
|
||||
struct tpa6130a2_data *data;
|
||||
int val = 0;
|
||||
|
||||
if (WARN_ON(!tpa6130a2_client))
|
||||
return -EINVAL;
|
||||
data = i2c_get_clientdata(tpa6130a2_client);
|
||||
|
||||
if (data->power_state) {
|
||||
val = i2c_smbus_write_byte_data(tpa6130a2_client, reg, value);
|
||||
if (val < 0) {
|
||||
dev_err(&tpa6130a2_client->dev, "Write failed\n");
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
/* Either powered on or off, we save the context */
|
||||
data->regs[reg] = value;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static u8 tpa6130a2_read(int reg)
|
||||
{
|
||||
struct tpa6130a2_data *data;
|
||||
|
||||
if (WARN_ON(!tpa6130a2_client))
|
||||
return 0;
|
||||
data = i2c_get_clientdata(tpa6130a2_client);
|
||||
|
||||
return data->regs[reg];
|
||||
}
|
||||
|
||||
static int tpa6130a2_initialize(void)
|
||||
{
|
||||
struct tpa6130a2_data *data;
|
||||
int i, ret = 0;
|
||||
|
||||
if (WARN_ON(!tpa6130a2_client))
|
||||
return -EINVAL;
|
||||
data = i2c_get_clientdata(tpa6130a2_client);
|
||||
|
||||
for (i = 1; i < TPA6130A2_REG_VERSION; i++) {
|
||||
ret = tpa6130a2_i2c_write(i, data->regs[i]);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tpa6130a2_power(u8 power)
|
||||
{
|
||||
struct tpa6130a2_data *data;
|
||||
u8 val;
|
||||
int ret = 0;
|
||||
|
||||
if (WARN_ON(!tpa6130a2_client))
|
||||
return -EINVAL;
|
||||
data = i2c_get_clientdata(tpa6130a2_client);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
if (power == data->power_state)
|
||||
goto exit;
|
||||
|
||||
if (power) {
|
||||
if (enable) {
|
||||
ret = regulator_enable(data->supply);
|
||||
if (ret != 0) {
|
||||
dev_err(&tpa6130a2_client->dev,
|
||||
dev_err(data->dev,
|
||||
"Failed to enable supply: %d\n", ret);
|
||||
goto exit;
|
||||
return ret;
|
||||
}
|
||||
/* Power on */
|
||||
if (data->power_gpio >= 0)
|
||||
gpio_set_value(data->power_gpio, 1);
|
||||
|
||||
data->power_state = 1;
|
||||
ret = tpa6130a2_initialize();
|
||||
if (ret < 0) {
|
||||
dev_err(&tpa6130a2_client->dev,
|
||||
"Failed to initialize chip\n");
|
||||
if (data->power_gpio >= 0)
|
||||
gpio_set_value(data->power_gpio, 0);
|
||||
regulator_disable(data->supply);
|
||||
data->power_state = 0;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
/* set SWS */
|
||||
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
|
||||
val |= TPA6130A2_SWS;
|
||||
tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
|
||||
|
||||
/* Power off */
|
||||
if (data->power_gpio >= 0)
|
||||
gpio_set_value(data->power_gpio, 0);
|
||||
|
||||
ret = regulator_disable(data->supply);
|
||||
if (ret != 0) {
|
||||
dev_err(&tpa6130a2_client->dev,
|
||||
dev_err(data->dev,
|
||||
"Failed to disable supply: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
data->power_state = 0;
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct tpa6130a2_data *data;
|
||||
unsigned int reg = mc->reg;
|
||||
unsigned int shift = mc->shift;
|
||||
int max = mc->max;
|
||||
unsigned int mask = (1 << fls(max)) - 1;
|
||||
unsigned int invert = mc->invert;
|
||||
|
||||
if (WARN_ON(!tpa6130a2_client))
|
||||
return -EINVAL;
|
||||
data = i2c_get_clientdata(tpa6130a2_client);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
ucontrol->value.integer.value[0] =
|
||||
(tpa6130a2_read(reg) >> shift) & mask;
|
||||
|
||||
if (invert)
|
||||
ucontrol->value.integer.value[0] =
|
||||
max - ucontrol->value.integer.value[0];
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
return 0;
|
||||
/* device regs does not match the cache state anymore */
|
||||
regcache_mark_dirty(data->regmap);
|
||||
}
|
||||
|
||||
static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct tpa6130a2_data *data;
|
||||
unsigned int reg = mc->reg;
|
||||
unsigned int shift = mc->shift;
|
||||
int max = mc->max;
|
||||
unsigned int mask = (1 << fls(max)) - 1;
|
||||
unsigned int invert = mc->invert;
|
||||
unsigned int val = (ucontrol->value.integer.value[0] & mask);
|
||||
unsigned int val_reg;
|
||||
|
||||
if (WARN_ON(!tpa6130a2_client))
|
||||
return -EINVAL;
|
||||
data = i2c_get_clientdata(tpa6130a2_client);
|
||||
|
||||
if (invert)
|
||||
val = max - val;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
val_reg = tpa6130a2_read(reg);
|
||||
if (((val_reg >> shift) & mask) == val) {
|
||||
mutex_unlock(&data->mutex);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
val_reg &= ~(mask << shift);
|
||||
val_reg |= val << shift;
|
||||
tpa6130a2_i2c_write(reg, val_reg);
|
||||
static int tpa6130a2_power_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kctrl, int event)
|
||||
{
|
||||
struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
|
||||
struct tpa6130a2_data *data = snd_soc_component_get_drvdata(c);
|
||||
int ret;
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
/* before widget power up */
|
||||
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
||||
/* Turn on the chip */
|
||||
tpa6130a2_power(data, true);
|
||||
/* Sync the registers */
|
||||
ret = regcache_sync(data->regmap);
|
||||
if (ret < 0) {
|
||||
dev_err(c->dev, "Failed to initialize chip\n");
|
||||
tpa6130a2_power(data, false);
|
||||
return ret;
|
||||
}
|
||||
/* after widget power down */
|
||||
} else {
|
||||
tpa6130a2_power(data, false);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -273,9 +127,8 @@ static const DECLARE_TLV_DB_RANGE(tpa6130_tlv,
|
|||
);
|
||||
|
||||
static const struct snd_kcontrol_new tpa6130a2_controls[] = {
|
||||
SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume",
|
||||
SOC_SINGLE_TLV("Headphone Playback Volume",
|
||||
TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0,
|
||||
tpa6130a2_get_volsw, tpa6130a2_put_volsw,
|
||||
tpa6130_tlv),
|
||||
};
|
||||
|
||||
|
@ -286,85 +139,79 @@ static const DECLARE_TLV_DB_RANGE(tpa6140_tlv,
|
|||
);
|
||||
|
||||
static const struct snd_kcontrol_new tpa6140a2_controls[] = {
|
||||
SOC_SINGLE_EXT_TLV("TPA6140A2 Headphone Playback Volume",
|
||||
SOC_SINGLE_TLV("Headphone Playback Volume",
|
||||
TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0,
|
||||
tpa6130a2_get_volsw, tpa6130a2_put_volsw,
|
||||
tpa6140_tlv),
|
||||
};
|
||||
|
||||
/*
|
||||
* Enable or disable channel (left or right)
|
||||
* The bit number for mute and amplifier are the same per channel:
|
||||
* bit 6: Right channel
|
||||
* bit 7: Left channel
|
||||
* in both registers.
|
||||
*/
|
||||
static void tpa6130a2_channel_enable(u8 channel, int enable)
|
||||
static int tpa6130a2_component_probe(struct snd_soc_component *component)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
if (enable) {
|
||||
/* Enable channel */
|
||||
/* Enable amplifier */
|
||||
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
|
||||
val |= channel;
|
||||
val &= ~TPA6130A2_SWS;
|
||||
tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
|
||||
|
||||
/* Unmute channel */
|
||||
val = tpa6130a2_read(TPA6130A2_REG_VOL_MUTE);
|
||||
val &= ~channel;
|
||||
tpa6130a2_i2c_write(TPA6130A2_REG_VOL_MUTE, val);
|
||||
} else {
|
||||
/* Disable channel */
|
||||
/* Mute channel */
|
||||
val = tpa6130a2_read(TPA6130A2_REG_VOL_MUTE);
|
||||
val |= channel;
|
||||
tpa6130a2_i2c_write(TPA6130A2_REG_VOL_MUTE, val);
|
||||
|
||||
/* Disable amplifier */
|
||||
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
|
||||
val &= ~channel;
|
||||
tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
|
||||
}
|
||||
}
|
||||
|
||||
int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
if (enable) {
|
||||
ret = tpa6130a2_power(1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
|
||||
1);
|
||||
} else {
|
||||
tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
|
||||
0);
|
||||
ret = tpa6130a2_power(0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpa6130a2_stereo_enable);
|
||||
|
||||
int tpa6130a2_add_controls(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tpa6130a2_data *data;
|
||||
|
||||
if (tpa6130a2_client == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
data = i2c_get_clientdata(tpa6130a2_client);
|
||||
struct tpa6130a2_data *data = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (data->id == TPA6140A2)
|
||||
return snd_soc_add_codec_controls(codec, tpa6140a2_controls,
|
||||
ARRAY_SIZE(tpa6140a2_controls));
|
||||
return snd_soc_add_component_controls(component,
|
||||
tpa6140a2_controls, ARRAY_SIZE(tpa6140a2_controls));
|
||||
else
|
||||
return snd_soc_add_codec_controls(codec, tpa6130a2_controls,
|
||||
ARRAY_SIZE(tpa6130a2_controls));
|
||||
return snd_soc_add_component_controls(component,
|
||||
tpa6130a2_controls, ARRAY_SIZE(tpa6130a2_controls));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpa6130a2_add_controls);
|
||||
|
||||
static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("LEFTIN"),
|
||||
SND_SOC_DAPM_INPUT("RIGHTIN"),
|
||||
SND_SOC_DAPM_OUTPUT("HPLEFT"),
|
||||
SND_SOC_DAPM_OUTPUT("HPRIGHT"),
|
||||
|
||||
SND_SOC_DAPM_PGA("Left Mute", TPA6130A2_REG_VOL_MUTE,
|
||||
TPA6130A2_HP_EN_L_SHIFT, 1, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Right Mute", TPA6130A2_REG_VOL_MUTE,
|
||||
TPA6130A2_HP_EN_R_SHIFT, 1, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Left PGA", TPA6130A2_REG_CONTROL,
|
||||
TPA6130A2_HP_EN_L_SHIFT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("Right PGA", TPA6130A2_REG_CONTROL,
|
||||
TPA6130A2_HP_EN_R_SHIFT, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("Power", TPA6130A2_REG_CONTROL,
|
||||
TPA6130A2_SWS_SHIFT, 1, tpa6130a2_power_event,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route tpa6130a2_dapm_routes[] = {
|
||||
{ "Left PGA", NULL, "LEFTIN" },
|
||||
{ "Right PGA", NULL, "RIGHTIN" },
|
||||
|
||||
{ "Left Mute", NULL, "Left PGA" },
|
||||
{ "Right Mute", NULL, "Right PGA" },
|
||||
|
||||
{ "HPLEFT", NULL, "Left Mute" },
|
||||
{ "HPRIGHT", NULL, "Right Mute" },
|
||||
|
||||
{ "Left PGA", NULL, "Power" },
|
||||
{ "Right PGA", NULL, "Power" },
|
||||
};
|
||||
|
||||
struct snd_soc_component_driver tpa6130a2_component_driver = {
|
||||
.name = "tpa6130a2",
|
||||
.probe = tpa6130a2_component_probe,
|
||||
.dapm_widgets = tpa6130a2_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(tpa6130a2_dapm_widgets),
|
||||
.dapm_routes = tpa6130a2_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(tpa6130a2_dapm_routes),
|
||||
};
|
||||
|
||||
static const struct reg_default tpa6130a2_reg_defaults[] = {
|
||||
{ TPA6130A2_REG_CONTROL, TPA6130A2_SWS },
|
||||
{ TPA6130A2_REG_VOL_MUTE, TPA6130A2_MUTE_R | TPA6130A2_MUTE_L },
|
||||
};
|
||||
|
||||
static const struct regmap_config tpa6130a2_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = TPA6130A2_REG_VERSION,
|
||||
.reg_defaults = tpa6130a2_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(tpa6130a2_reg_defaults),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int tpa6130a2_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
|
@ -374,6 +221,7 @@ static int tpa6130a2_probe(struct i2c_client *client,
|
|||
struct tpa6130a2_platform_data *pdata = client->dev.platform_data;
|
||||
struct device_node *np = client->dev.of_node;
|
||||
const char *regulator;
|
||||
unsigned int version;
|
||||
int ret;
|
||||
|
||||
dev = &client->dev;
|
||||
|
@ -382,6 +230,12 @@ static int tpa6130a2_probe(struct i2c_client *client,
|
|||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->dev = dev;
|
||||
|
||||
data->regmap = devm_regmap_init_i2c(client, &tpa6130a2_regmap_config);
|
||||
if (IS_ERR(data->regmap))
|
||||
return PTR_ERR(data->regmap);
|
||||
|
||||
if (pdata) {
|
||||
data->power_gpio = pdata->power_gpio;
|
||||
} else if (np) {
|
||||
|
@ -392,26 +246,17 @@ static int tpa6130a2_probe(struct i2c_client *client,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
tpa6130a2_client = client;
|
||||
|
||||
i2c_set_clientdata(tpa6130a2_client, data);
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
data->id = id->driver_data;
|
||||
|
||||
mutex_init(&data->mutex);
|
||||
|
||||
/* Set default register values */
|
||||
data->regs[TPA6130A2_REG_CONTROL] = TPA6130A2_SWS;
|
||||
data->regs[TPA6130A2_REG_VOL_MUTE] = TPA6130A2_MUTE_R |
|
||||
TPA6130A2_MUTE_L;
|
||||
|
||||
if (data->power_gpio >= 0) {
|
||||
ret = devm_gpio_request(dev, data->power_gpio,
|
||||
"tpa6130a2 enable");
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to request power GPIO (%d)\n",
|
||||
data->power_gpio);
|
||||
goto err_gpio;
|
||||
return ret;
|
||||
}
|
||||
gpio_direction_output(data->power_gpio, 0);
|
||||
}
|
||||
|
@ -432,39 +277,27 @@ static int tpa6130a2_probe(struct i2c_client *client,
|
|||
if (IS_ERR(data->supply)) {
|
||||
ret = PTR_ERR(data->supply);
|
||||
dev_err(dev, "Failed to request supply: %d\n", ret);
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
ret = tpa6130a2_power(1);
|
||||
if (ret != 0)
|
||||
goto err_gpio;
|
||||
|
||||
|
||||
/* Read version */
|
||||
ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) &
|
||||
TPA6130A2_VERSION_MASK;
|
||||
if ((ret != 1) && (ret != 2))
|
||||
dev_warn(dev, "UNTESTED version detected (%d)\n", ret);
|
||||
|
||||
/* Disable the chip */
|
||||
ret = tpa6130a2_power(0);
|
||||
if (ret != 0)
|
||||
goto err_gpio;
|
||||
|
||||
return 0;
|
||||
|
||||
err_gpio:
|
||||
tpa6130a2_client = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tpa6130a2_remove(struct i2c_client *client)
|
||||
{
|
||||
tpa6130a2_power(0);
|
||||
tpa6130a2_client = NULL;
|
||||
ret = tpa6130a2_power(data, true);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
/* Read version */
|
||||
regmap_read(data->regmap, TPA6130A2_REG_VERSION, &version);
|
||||
version &= TPA6130A2_VERSION_MASK;
|
||||
if ((version != 1) && (version != 2))
|
||||
dev_warn(dev, "UNTESTED version detected (%d)\n", version);
|
||||
|
||||
/* Disable the chip */
|
||||
ret = tpa6130a2_power(data, false);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
return devm_snd_soc_register_component(&client->dev,
|
||||
&tpa6130a2_component_driver, NULL, 0);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tpa6130a2_id[] = {
|
||||
|
@ -489,7 +322,6 @@ static struct i2c_driver tpa6130a2_i2c_driver = {
|
|||
.of_match_table = of_match_ptr(tpa6130a2_of_match),
|
||||
},
|
||||
.probe = tpa6130a2_probe,
|
||||
.remove = tpa6130a2_remove,
|
||||
.id_table = tpa6130a2_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -30,19 +30,20 @@
|
|||
#define TPA6130A2_REG_OUT_IMPEDANCE 0x03
|
||||
#define TPA6130A2_REG_VERSION 0x04
|
||||
|
||||
#define TPA6130A2_CACHEREGNUM (TPA6130A2_REG_VERSION + 1)
|
||||
|
||||
/* Register bits */
|
||||
/* TPA6130A2_REG_CONTROL (0x01) */
|
||||
#define TPA6130A2_SWS (0x01 << 0)
|
||||
#define TPA6130A2_SWS_SHIFT 0
|
||||
#define TPA6130A2_SWS (0x01 << TPA6130A2_SWS_SHIFT)
|
||||
#define TPA6130A2_TERMAL (0x01 << 1)
|
||||
#define TPA6130A2_MODE(x) (x << 4)
|
||||
#define TPA6130A2_MODE_STEREO (0x00)
|
||||
#define TPA6130A2_MODE_DUAL_MONO (0x01)
|
||||
#define TPA6130A2_MODE_BRIDGE (0x02)
|
||||
#define TPA6130A2_MODE_MASK (0x03)
|
||||
#define TPA6130A2_HP_EN_R (0x01 << 6)
|
||||
#define TPA6130A2_HP_EN_L (0x01 << 7)
|
||||
#define TPA6130A2_HP_EN_R_SHIFT 6
|
||||
#define TPA6130A2_HP_EN_R (0x01 << TPA6130A2_HP_EN_R_SHIFT)
|
||||
#define TPA6130A2_HP_EN_L_SHIFT 7
|
||||
#define TPA6130A2_HP_EN_L (0x01 << TPA6130A2_HP_EN_L_SHIFT)
|
||||
|
||||
/* TPA6130A2_REG_VOL_MUTE (0x02) */
|
||||
#define TPA6130A2_VOLUME(x) ((x & 0x3f) << 0)
|
||||
|
@ -56,7 +57,4 @@
|
|||
/* TPA6130A2_REG_VERSION (0x04) */
|
||||
#define TPA6130A2_VERSION_MASK (0x0f)
|
||||
|
||||
extern int tpa6130a2_add_controls(struct snd_soc_codec *codec);
|
||||
extern int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable);
|
||||
|
||||
#endif /* __TPA6130A2_H__ */
|
||||
|
|
|
@ -358,6 +358,9 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
|
|||
case 24:
|
||||
iface |= 0x0008;
|
||||
break;
|
||||
case 32:
|
||||
iface |= 0x000c;
|
||||
break;
|
||||
}
|
||||
|
||||
wm8731_set_deemph(codec);
|
||||
|
@ -541,7 +544,7 @@ static int wm8731_startup(struct snd_pcm_substream *substream,
|
|||
#define WM8731_RATES SNDRV_PCM_RATE_8000_96000
|
||||
|
||||
#define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE)
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
static const struct snd_soc_dai_ops wm8731_dai_ops = {
|
||||
.startup = wm8731_startup,
|
||||
|
|
|
@ -100,7 +100,7 @@ config SND_OMAP_SOC_OMAP_TWL4030
|
|||
|
||||
config SND_OMAP_SOC_OMAP_ABE_TWL6040
|
||||
tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
|
||||
depends on TWL6040_CORE && SND_OMAP_SOC
|
||||
depends on TWL6040_CORE && SND_OMAP_SOC && COMMON_CLK
|
||||
depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
|
||||
select SND_OMAP_SOC_DMIC
|
||||
select SND_OMAP_SOC_MCPDM
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <linux/platform_data/asoc-ti-mcbsp.h>
|
||||
#include "../codecs/tpa6130a2.h"
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
|
@ -164,19 +163,6 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rx51_hp_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *k, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
|
||||
|
||||
if (SND_SOC_DAPM_EVENT_ON(event))
|
||||
tpa6130a2_stereo_enable(codec, 1);
|
||||
else
|
||||
tpa6130a2_stereo_enable(codec, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx51_get_input(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
|
@ -235,7 +221,7 @@ static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
|
|||
static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
|
||||
SND_SOC_DAPM_MIC("DMic", NULL),
|
||||
SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event),
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("HS Mic", NULL),
|
||||
SND_SOC_DAPM_LINE("FM Transmitter", NULL),
|
||||
SND_SOC_DAPM_SPK("Earphone", NULL),
|
||||
|
@ -246,11 +232,14 @@ static const struct snd_soc_dapm_route audio_map[] = {
|
|||
{"Ext Spk", NULL, "HPROUT"},
|
||||
{"Ext Spk", NULL, "HPLCOM"},
|
||||
{"Ext Spk", NULL, "HPRCOM"},
|
||||
{"Headphone Jack", NULL, "LLOUT"},
|
||||
{"Headphone Jack", NULL, "RLOUT"},
|
||||
{"FM Transmitter", NULL, "LLOUT"},
|
||||
{"FM Transmitter", NULL, "RLOUT"},
|
||||
|
||||
{"Headphone Jack", NULL, "TPA6130A2 HPLEFT"},
|
||||
{"Headphone Jack", NULL, "TPA6130A2 HPRIGHT"},
|
||||
{"TPA6130A2 LEFTIN", NULL, "LLOUT"},
|
||||
{"TPA6130A2 RIGHTIN", NULL, "RLOUT"},
|
||||
|
||||
{"DMic Rate 64", NULL, "DMic"},
|
||||
{"DMic", NULL, "Mic Bias"},
|
||||
|
||||
|
@ -286,16 +275,10 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
|
|||
|
||||
static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
|
||||
int err;
|
||||
|
||||
err = tpa6130a2_add_controls(codec);
|
||||
if (err < 0) {
|
||||
dev_err(card->dev, "Failed to add TPA6130A2 controls\n");
|
||||
return err;
|
||||
}
|
||||
snd_soc_limit_volume(card, "TPA6130A2 Headphone Playback Volume", 42);
|
||||
|
||||
err = omap_mcbsp_st_add_controls(rtd, 2);
|
||||
|
@ -357,6 +340,10 @@ static struct snd_soc_aux_dev rx51_aux_dev[] = {
|
|||
.name = "TLV320AIC34b",
|
||||
.codec_name = "tlv320aic3x-codec.2-0019",
|
||||
},
|
||||
{
|
||||
.name = "TPA61320A2",
|
||||
.codec_name = "tpa6130a2.2-0060",
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_codec_conf rx51_codec_conf[] = {
|
||||
|
@ -364,6 +351,10 @@ static struct snd_soc_codec_conf rx51_codec_conf[] = {
|
|||
.dev_name = "tlv320aic3x-codec.2-0019",
|
||||
.name_prefix = "b",
|
||||
},
|
||||
{
|
||||
.dev_name = "tpa6130a2.2-0060",
|
||||
.name_prefix = "TPA6130A2",
|
||||
},
|
||||
};
|
||||
|
||||
/* Audio card */
|
||||
|
@ -435,11 +426,10 @@ static int rx51_soc_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "Headphone amplifier node is not provided\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* TODO: tpa6130a2a driver supports only a single instance, so
|
||||
* this driver ignores the headphone-amplifier node for now.
|
||||
* It's already mandatory in the DT binding to be future proof.
|
||||
*/
|
||||
rx51_aux_dev[1].codec_name = NULL;
|
||||
rx51_aux_dev[1].codec_of_node = dai_node;
|
||||
rx51_codec_conf[1].dev_name = NULL;
|
||||
rx51_codec_conf[1].of_node = dai_node;
|
||||
}
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
|
|
Loading…
Reference in New Issue