Commit 1a946005 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/tas571x',...

Merge remote-tracking branches 'asoc/topic/tas571x', 'asoc/topic/tlv320aic31xx', 'asoc/topic/tpa6130a2', 'asoc/topic/twl6040' and 'asoc/topic/wm8731' into asoc-next
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/tlv.h> #include <sound/tlv.h>
#include <asm/unaligned.h>
#include "tas571x.h" #include "tas571x.h"
...@@ -63,6 +64,10 @@ static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) ...@@ -63,6 +64,10 @@ static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg)
case TAS571X_INPUT_MUX_REG: case TAS571X_INPUT_MUX_REG:
case TAS571X_CH4_SRC_SELECT_REG: case TAS571X_CH4_SRC_SELECT_REG:
case TAS571X_PWM_MUX_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; return 4;
default: default:
return 1; return 1;
...@@ -135,6 +140,129 @@ static int tas571x_reg_read(void *context, unsigned int reg, ...@@ -135,6 +140,129 @@ static int tas571x_reg_read(void *context, unsigned int reg,
return 0; 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) 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); 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 = { ...@@ -241,6 +369,15 @@ static const struct snd_soc_dai_ops tas571x_dai_ops = {
.digital_mute = tas571x_mute, .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[] = { static const char *const tas5711_supply_names[] = {
"AVDD", "AVDD",
"DVDD", "DVDD",
...@@ -264,6 +401,16 @@ static const struct snd_kcontrol_new tas5711_controls[] = { ...@@ -264,6 +401,16 @@ static const struct snd_kcontrol_new tas5711_controls[] = {
TAS571X_SOFT_MUTE_REG, TAS571X_SOFT_MUTE_REG,
TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
1, 1), 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[] = { static const struct regmap_range tas571x_readonly_regs_range[] = {
...@@ -340,6 +487,43 @@ static const struct snd_kcontrol_new tas5717_controls[] = { ...@@ -340,6 +487,43 @@ static const struct snd_kcontrol_new tas5717_controls[] = {
TAS571X_SOFT_MUTE_REG, TAS571X_SOFT_MUTE_REG,
TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
1, 1), 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[] = { static const struct reg_default tas5717_reg_defaults[] = {
...@@ -350,6 +534,10 @@ static const struct reg_default tas5717_reg_defaults[] = { ...@@ -350,6 +534,10 @@ static const struct reg_default tas5717_reg_defaults[] = {
{ 0x08, 0x00c0 }, { 0x08, 0x00c0 },
{ 0x09, 0x00c0 }, { 0x09, 0x00c0 },
{ 0x1b, 0x82 }, { 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 = { static const struct regmap_config tas5717_regmap_config = {
......
...@@ -52,4 +52,44 @@ ...@@ -52,4 +52,44 @@
#define TAS571X_CH4_SRC_SELECT_REG 0x21 #define TAS571X_CH4_SRC_SELECT_REG 0x21
#define TAS571X_PWM_MUX_REG 0x25 #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 */ #endif /* _TAS571X_H */
...@@ -38,141 +38,143 @@ struct aic31xx_pdata { ...@@ -38,141 +38,143 @@ struct aic31xx_pdata {
int micbias_vg; int micbias_vg;
}; };
#define AIC31XX_REG(page, reg) ((page * 128) + reg)
/* Page Control Register */ /* Page Control Register */
#define AIC31XX_PAGECTL 0x00 #define AIC31XX_PAGECTL AIC31XX_REG(0, 0)
/* Page 0 Registers */ /* Page 0 Registers */
/* Software reset register */ /* Software reset register */
#define AIC31XX_RESET 0x01 #define AIC31XX_RESET AIC31XX_REG(0, 1)
/* OT FLAG register */ /* OT FLAG register */
#define AIC31XX_OT_FLAG 0x03 #define AIC31XX_OT_FLAG AIC31XX_REG(0, 3)
/* Clock clock Gen muxing, Multiplexers*/ /* Clock clock Gen muxing, Multiplexers*/
#define AIC31XX_CLKMUX 0x04 #define AIC31XX_CLKMUX AIC31XX_REG(0, 4)
/* PLL P and R-VAL register */ /* PLL P and R-VAL register */
#define AIC31XX_PLLPR 0x05 #define AIC31XX_PLLPR AIC31XX_REG(0, 5)
/* PLL J-VAL register */ /* PLL J-VAL register */
#define AIC31XX_PLLJ 0x06 #define AIC31XX_PLLJ AIC31XX_REG(0, 6)
/* PLL D-VAL MSB register */ /* PLL D-VAL MSB register */
#define AIC31XX_PLLDMSB 0x07 #define AIC31XX_PLLDMSB AIC31XX_REG(0, 7)
/* PLL D-VAL LSB register */ /* PLL D-VAL LSB register */
#define AIC31XX_PLLDLSB 0x08 #define AIC31XX_PLLDLSB AIC31XX_REG(0, 8)
/* DAC NDAC_VAL register*/ /* DAC NDAC_VAL register*/
#define AIC31XX_NDAC 0x0B #define AIC31XX_NDAC AIC31XX_REG(0, 11)
/* DAC MDAC_VAL register */ /* DAC MDAC_VAL register */
#define AIC31XX_MDAC 0x0C #define AIC31XX_MDAC AIC31XX_REG(0, 12)
/* DAC OSR setting register 1, MSB value */ /* 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 */ /* DAC OSR setting register 2, LSB value */
#define AIC31XX_DOSRLSB 0x0E #define AIC31XX_DOSRLSB AIC31XX_REG(0, 14)
#define AIC31XX_MINI_DSP_INPOL 0x10 #define AIC31XX_MINI_DSP_INPOL AIC31XX_REG(0, 16)
/* Clock setting register 8, PLL */ /* Clock setting register 8, PLL */
#define AIC31XX_NADC 0x12 #define AIC31XX_NADC AIC31XX_REG(0, 18)
/* Clock setting register 9, PLL */ /* Clock setting register 9, PLL */
#define AIC31XX_MADC 0x13 #define AIC31XX_MADC AIC31XX_REG(0, 19)
/* ADC Oversampling (AOSR) Register */ /* ADC Oversampling (AOSR) Register */
#define AIC31XX_AOSR 0x14 #define AIC31XX_AOSR AIC31XX_REG(0, 20)
/* Clock setting register 9, Multiplexers */ /* Clock setting register 9, Multiplexers */
#define AIC31XX_CLKOUTMUX 0x19 #define AIC31XX_CLKOUTMUX AIC31XX_REG(0, 25)
/* Clock setting register 10, CLOCKOUT M divider value */ /* Clock setting register 10, CLOCKOUT M divider value */
#define AIC31XX_CLKOUTMVAL 0x1A #define AIC31XX_CLKOUTMVAL AIC31XX_REG(0, 26)
/* Audio Interface Setting Register 1 */ /* Audio Interface Setting Register 1 */
#define AIC31XX_IFACE1 0x1B #define AIC31XX_IFACE1 AIC31XX_REG(0, 27)
/* Audio Data Slot Offset Programming */ /* Audio Data Slot Offset Programming */
#define AIC31XX_DATA_OFFSET 0x1C #define AIC31XX_DATA_OFFSET AIC31XX_REG(0, 28)
/* Audio Interface Setting Register 2 */ /* Audio Interface Setting Register 2 */
#define AIC31XX_IFACE2 0x1D #define AIC31XX_IFACE2 AIC31XX_REG(0, 29)
/* Clock setting register 11, BCLK N Divider */ /* 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 */ /* Audio Interface Setting Register 3, Secondary Audio Interface */
#define AIC31XX_IFACESEC1 0x1F #define AIC31XX_IFACESEC1 AIC31XX_REG(0, 31)
/* Audio Interface Setting Register 4 */ /* Audio Interface Setting Register 4 */
#define AIC31XX_IFACESEC2 0x20 #define AIC31XX_IFACESEC2 AIC31XX_REG(0, 32)
/* Audio Interface Setting Register 5 */ /* Audio Interface Setting Register 5 */
#define AIC31XX_IFACESEC3 0x21 #define AIC31XX_IFACESEC3 AIC31XX_REG(0, 33)
/* I2C Bus Condition */ /* I2C Bus Condition */
#define AIC31XX_I2C 0x22 #define AIC31XX_I2C AIC31XX_REG(0, 34)
/* ADC FLAG */ /* ADC FLAG */
#define AIC31XX_ADCFLAG 0x24 #define AIC31XX_ADCFLAG AIC31XX_REG(0, 36)
/* DAC Flag Registers */ /* DAC Flag Registers */
#define AIC31XX_DACFLAG1 0x25 #define AIC31XX_DACFLAG1 AIC31XX_REG(0, 37)
#define AIC31XX_DACFLAG2 0x26 #define AIC31XX_DACFLAG2 AIC31XX_REG(0, 38)
/* Sticky Interrupt flag (overflow) */ /* Sticky Interrupt flag (overflow) */
#define AIC31XX_OFFLAG 0x27 #define AIC31XX_OFFLAG AIC31XX_REG(0, 39)
/* Sticy DAC Interrupt flags */ /* Sticy DAC Interrupt flags */
#define AIC31XX_INTRDACFLAG 0x2C #define AIC31XX_INTRDACFLAG AIC31XX_REG(0, 44)
/* Sticy ADC Interrupt flags */ /* Sticy ADC Interrupt flags */
#define AIC31XX_INTRADCFLAG 0x2D #define AIC31XX_INTRADCFLAG AIC31XX_REG(0, 45)
/* DAC Interrupt flags 2 */ /* DAC Interrupt flags 2 */
#define AIC31XX_INTRDACFLAG2 0x2E #define AIC31XX_INTRDACFLAG2 AIC31XX_REG(0, 46)
/* ADC Interrupt flags 2 */ /* ADC Interrupt flags 2 */
#define AIC31XX_INTRADCFLAG2 0x2F #define AIC31XX_INTRADCFLAG2 AIC31XX_REG(0, 47)
/* INT1 interrupt control */ /* INT1 interrupt control */
#define AIC31XX_INT1CTRL 0x30 #define AIC31XX_INT1CTRL AIC31XX_REG(0, 48)
/* INT2 interrupt control */ /* INT2 interrupt control */
#define AIC31XX_INT2CTRL 0x31 #define AIC31XX_INT2CTRL AIC31XX_REG(0, 49)
/* GPIO1 control */ /* 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 */ /* ADC Instruction Set Register */
#define AIC31XX_ADCPRB 0x3D #define AIC31XX_ADCPRB AIC31XX_REG(0, 61)
/* DAC channel setup register */ /* DAC channel setup register */
#define AIC31XX_DACSETUP 0x3F #define AIC31XX_DACSETUP AIC31XX_REG(0, 63)
/* DAC Mute and volume control register */ /* DAC Mute and volume control register */
#define AIC31XX_DACMUTE 0x40 #define AIC31XX_DACMUTE AIC31XX_REG(0, 64)
/* Left DAC channel digital volume control */ /* Left DAC channel digital volume control */
#define AIC31XX_LDACVOL 0x41 #define AIC31XX_LDACVOL AIC31XX_REG(0, 65)
/* Right DAC channel digital volume control */ /* Right DAC channel digital volume control */
#define AIC31XX_RDACVOL 0x42 #define AIC31XX_RDACVOL AIC31XX_REG(0, 66)
/* Headset detection */ /* Headset detection */
#define AIC31XX_HSDETECT 0x43 #define AIC31XX_HSDETECT AIC31XX_REG(0, 67)
/* ADC Digital Mic */ /* ADC Digital Mic */
#define AIC31XX_ADCSETUP 0x51 #define AIC31XX_ADCSETUP AIC31XX_REG(0, 81)
/* ADC Digital Volume Control Fine Adjust */ /* ADC Digital Volume Control Fine Adjust */
#define AIC31XX_ADCFGA 0x52 #define AIC31XX_ADCFGA AIC31XX_REG(0, 82)
/* ADC Digital Volume Control Coarse Adjust */ /* ADC Digital Volume Control Coarse Adjust */
#define AIC31XX_ADCVOL 0x53 #define AIC31XX_ADCVOL AIC31XX_REG(0, 83)
/* Page 1 Registers */ /* Page 1 Registers */
/* Headphone drivers */ /* Headphone drivers */
#define AIC31XX_HPDRIVER 0x9F #define AIC31XX_HPDRIVER AIC31XX_REG(1, 31)
/* Class-D Speakear Amplifier */ /* Class-D Speakear Amplifier */
#define AIC31XX_SPKAMP 0xA0 #define AIC31XX_SPKAMP AIC31XX_REG(1, 32)
/* HP Output Drivers POP Removal Settings */ /* HP Output Drivers POP Removal Settings */
#define AIC31XX_HPPOP 0xA1 #define AIC31XX_HPPOP AIC31XX_REG(1, 33)
/* Output Driver PGA Ramp-Down Period Control */ /* 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 */ /* DAC_L and DAC_R Output Mixer Routing */
#define AIC31XX_DACMIXERROUTE 0xA3 #define AIC31XX_DACMIXERROUTE AIC31XX_REG(1, 35)
/* Left Analog Vol to HPL */ /* Left Analog Vol to HPL */
#define AIC31XX_LANALOGHPL 0xA4 #define AIC31XX_LANALOGHPL AIC31XX_REG(1, 36)
/* Right Analog Vol to HPR */ /* Right Analog Vol to HPR */
#define AIC31XX_RANALOGHPR 0xA5 #define AIC31XX_RANALOGHPR AIC31XX_REG(1, 37)
/* Left Analog Vol to SPL */ /* Left Analog Vol to SPL */
#define AIC31XX_LANALOGSPL 0xA6 #define AIC31XX_LANALOGSPL AIC31XX_REG(1, 38)
/* Right Analog Vol to SPR */ /* Right Analog Vol to SPR */
#define AIC31XX_RANALOGSPR 0xA7 #define AIC31XX_RANALOGSPR AIC31XX_REG(1, 39)
/* HPL Driver */ /* HPL Driver */
#define AIC31XX_HPLGAIN 0xA8 #define AIC31XX_HPLGAIN AIC31XX_REG(1, 40)
/* HPR Driver */ /* HPR Driver */
#define AIC31XX_HPRGAIN 0xA9 #define AIC31XX_HPRGAIN AIC31XX_REG(1, 41)
/* SPL Driver */ /* SPL Driver */
#define AIC31XX_SPLGAIN 0xAA #define AIC31XX_SPLGAIN AIC31XX_REG(1, 42)
/* SPR Driver */ /* SPR Driver */
#define AIC31XX_SPRGAIN 0xAB #define AIC31XX_SPRGAIN AIC31XX_REG(1, 43)
/* HP Driver Control */ /* HP Driver Control */
#define AIC31XX_HPCONTROL 0xAC #define AIC31XX_HPCONTROL AIC31XX_REG(1, 44)
/* MIC Bias Control */ /* MIC Bias Control */
#define AIC31XX_MICBIAS 0xAE #define AIC31XX_MICBIAS AIC31XX_REG(1, 46)
/* MIC PGA*/ /* 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 */ /* 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 */ /* ADC Input Selection for M-Terminal */
#define AIC31XX_MICPGAMI 0xB1 #define AIC31XX_MICPGAMI AIC31XX_REG(1, 49)
/* Input CM Settings */ /* Input CM Settings */
#define AIC31XX_MICPGACM 0xB2 #define AIC31XX_MICPGACM AIC31XX_REG(1, 50)
/* Bits, masks and shifts */ /* Bits, masks and shifts */
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <sound/tlv.h> #include <sound/tlv.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/regmap.h>
#include "tpa6130a2.h" #include "tpa6130a2.h"
...@@ -40,219 +41,72 @@ enum tpa_model { ...@@ -40,219 +41,72 @@ enum tpa_model {
TPA6140A2, TPA6140A2,
}; };
static struct i2c_client *tpa6130a2_client;
/* This struct is used to save the context */ /* This struct is used to save the context */
struct tpa6130a2_data { struct tpa6130a2_data {
struct mutex mutex; struct device *dev;
unsigned char regs[TPA6130A2_CACHEREGNUM]; struct regmap *regmap;
struct regulator *supply; struct regulator *supply;
int power_gpio; int power_gpio;
u8 power_state:1;
enum tpa_model id; 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;
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; int ret;
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); ret = regulator_enable(data->supply);
if (ret != 0) { if (ret != 0) {
dev_err(&tpa6130a2_client->dev, dev_err(data->dev,
"Failed to enable supply: %d\n", ret); "Failed to enable supply: %d\n", ret);
goto exit; return ret;
} }
/* Power on */ /* Power on */
if (data->power_gpio >= 0) if (data->power_gpio >= 0)
gpio_set_value(data->power_gpio, 1); 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 { } else {
/* set SWS */
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
val |= TPA6130A2_SWS;
tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
/* Power off */ /* Power off */
if (data->power_gpio >= 0) if (data->power_gpio >= 0)
gpio_set_value(data->power_gpio, 0); gpio_set_value(data->power_gpio, 0);
ret = regulator_disable(data->supply); ret = regulator_disable(data->supply);
if (ret != 0) { if (ret != 0) {
dev_err(&tpa6130a2_client->dev, dev_err(data->dev,
"Failed to disable supply: %d\n", ret); "Failed to disable supply: %d\n", ret);
goto exit; return ret;
} }
data->power_state = 0; /* device regs does not match the cache state anymore */
regcache_mark_dirty(data->regmap);
} }
exit:
mutex_unlock(&data->mutex);
return ret; return ret;
} }
static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol, static int tpa6130a2_power_event(struct snd_soc_dapm_widget *w,
struct snd_ctl_elem_value *ucontrol) struct snd_kcontrol *kctrl, int event)
{ {
struct soc_mixer_control *mc = struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
(struct soc_mixer_control *)kcontrol->private_value; struct tpa6130a2_data *data = snd_soc_component_get_drvdata(c);
struct tpa6130a2_data *data; int ret;
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;
}
static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol, /* before widget power up */
struct snd_ctl_elem_value *ucontrol) if (SND_SOC_DAPM_EVENT_ON(event)) {
{ /* Turn on the chip */
struct soc_mixer_control *mc = tpa6130a2_power(data, true);
(struct soc_mixer_control *)kcontrol->private_value; /* Sync the registers */
struct tpa6130a2_data *data; ret = regcache_sync(data->regmap);
unsigned int reg = mc->reg; if (ret < 0) {
unsigned int shift = mc->shift; dev_err(c->dev, "Failed to initialize chip\n");
int max = mc->max; tpa6130a2_power(data, false);
unsigned int mask = (1 << fls(max)) - 1; return ret;
unsigned int invert = mc->invert; }
unsigned int val = (ucontrol->value.integer.value[0] & mask); /* after widget power down */
unsigned int val_reg; } else {
tpa6130a2_power(data, false);
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;
} }
val_reg &= ~(mask << shift); return 0;
val_reg |= val << shift;
tpa6130a2_i2c_write(reg, val_reg);
mutex_unlock(&data->mutex);
return 1;
} }
/* /*
...@@ -273,9 +127,8 @@ static const DECLARE_TLV_DB_RANGE(tpa6130_tlv, ...@@ -273,9 +127,8 @@ static const DECLARE_TLV_DB_RANGE(tpa6130_tlv,
); );
static const struct snd_kcontrol_new tpa6130a2_controls[] = { 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_REG_VOL_MUTE, 0, 0x3f, 0,
tpa6130a2_get_volsw, tpa6130a2_put_volsw,
tpa6130_tlv), tpa6130_tlv),
}; };
...@@ -286,85 +139,79 @@ static const DECLARE_TLV_DB_RANGE(tpa6140_tlv, ...@@ -286,85 +139,79 @@ static const DECLARE_TLV_DB_RANGE(tpa6140_tlv,
); );
static const struct snd_kcontrol_new tpa6140a2_controls[] = { 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_REG_VOL_MUTE, 1, 0x1f, 0,
tpa6130a2_get_volsw, tpa6130a2_put_volsw,
tpa6140_tlv), tpa6140_tlv),
}; };
/* static int tpa6130a2_component_probe(struct snd_soc_component *component)
* 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)
{ {
u8 val; struct tpa6130a2_data *data = snd_soc_component_get_drvdata(component);
if (enable) { if (data->id == TPA6140A2)
/* Enable channel */ return snd_soc_add_component_controls(component,
/* Enable amplifier */ tpa6140a2_controls, ARRAY_SIZE(tpa6140a2_controls));
val = tpa6130a2_read(TPA6130A2_REG_CONTROL); else
val |= channel; return snd_soc_add_component_controls(component,
val &= ~TPA6130A2_SWS; tpa6130a2_controls, ARRAY_SIZE(tpa6130a2_controls));
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) static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
{ SND_SOC_DAPM_INPUT("LEFTIN"),
int ret = 0; SND_SOC_DAPM_INPUT("RIGHTIN"),
if (enable) { SND_SOC_DAPM_OUTPUT("HPLEFT"),
ret = tpa6130a2_power(1); SND_SOC_DAPM_OUTPUT("HPRIGHT"),
if (ret < 0)
return ret; SND_SOC_DAPM_PGA("Left Mute", TPA6130A2_REG_VOL_MUTE,
tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L, TPA6130A2_HP_EN_L_SHIFT, 1, NULL, 0),
1); SND_SOC_DAPM_PGA("Right Mute", TPA6130A2_REG_VOL_MUTE,
} else { TPA6130A2_HP_EN_R_SHIFT, 1, NULL, 0),
tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L, SND_SOC_DAPM_PGA("Left PGA", TPA6130A2_REG_CONTROL,
0); TPA6130A2_HP_EN_L_SHIFT, 0, NULL, 0),
ret = tpa6130a2_power(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),
};
return ret; static const struct snd_soc_dapm_route tpa6130a2_dapm_routes[] = {
} { "Left PGA", NULL, "LEFTIN" },
EXPORT_SYMBOL_GPL(tpa6130a2_stereo_enable); { "Right PGA", NULL, "RIGHTIN" },
int tpa6130a2_add_controls(struct snd_soc_codec *codec) { "Left Mute", NULL, "Left PGA" },
{ { "Right Mute", NULL, "Right PGA" },
struct tpa6130a2_data *data;
if (tpa6130a2_client == NULL) { "HPLEFT", NULL, "Left Mute" },
return -ENODEV; { "HPRIGHT", NULL, "Right Mute" },
data = i2c_get_clientdata(tpa6130a2_client); { "Left PGA", NULL, "Power" },
{ "Right PGA", NULL, "Power" },
};
if (data->id == TPA6140A2) struct snd_soc_component_driver tpa6130a2_component_driver = {
return snd_soc_add_codec_controls(codec, tpa6140a2_controls, .name = "tpa6130a2",
ARRAY_SIZE(tpa6140a2_controls)); .probe = tpa6130a2_component_probe,
else .dapm_widgets = tpa6130a2_dapm_widgets,
return snd_soc_add_codec_controls(codec, tpa6130a2_controls, .num_dapm_widgets = ARRAY_SIZE(tpa6130a2_dapm_widgets),
ARRAY_SIZE(tpa6130a2_controls)); .dapm_routes = tpa6130a2_dapm_routes,
} .num_dapm_routes = ARRAY_SIZE(tpa6130a2_dapm_routes),
EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); };
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, static int tpa6130a2_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
...@@ -374,6 +221,7 @@ static int tpa6130a2_probe(struct i2c_client *client, ...@@ -374,6 +221,7 @@ static int tpa6130a2_probe(struct i2c_client *client,
struct tpa6130a2_platform_data *pdata = client->dev.platform_data; struct tpa6130a2_platform_data *pdata = client->dev.platform_data;
struct device_node *np = client->dev.of_node; struct device_node *np = client->dev.of_node;
const char *regulator; const char *regulator;
unsigned int version;
int ret; int ret;
dev = &client->dev; dev = &client->dev;
...@@ -382,6 +230,12 @@ static int tpa6130a2_probe(struct i2c_client *client, ...@@ -382,6 +230,12 @@ static int tpa6130a2_probe(struct i2c_client *client,
if (!data) if (!data)
return -ENOMEM; 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) { if (pdata) {
data->power_gpio = pdata->power_gpio; data->power_gpio = pdata->power_gpio;
} else if (np) { } else if (np) {
...@@ -392,26 +246,17 @@ static int tpa6130a2_probe(struct i2c_client *client, ...@@ -392,26 +246,17 @@ static int tpa6130a2_probe(struct i2c_client *client,
return -ENODEV; return -ENODEV;
} }
tpa6130a2_client = client; i2c_set_clientdata(client, data);
i2c_set_clientdata(tpa6130a2_client, data);
data->id = id->driver_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) { if (data->power_gpio >= 0) {
ret = devm_gpio_request(dev, data->power_gpio, ret = devm_gpio_request(dev, data->power_gpio,
"tpa6130a2 enable"); "tpa6130a2 enable");
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Failed to request power GPIO (%d)\n", dev_err(dev, "Failed to request power GPIO (%d)\n",
data->power_gpio); data->power_gpio);
goto err_gpio; return ret;
} }
gpio_direction_output(data->power_gpio, 0); gpio_direction_output(data->power_gpio, 0);
} }
...@@ -432,39 +277,27 @@ static int tpa6130a2_probe(struct i2c_client *client, ...@@ -432,39 +277,27 @@ static int tpa6130a2_probe(struct i2c_client *client,
if (IS_ERR(data->supply)) { if (IS_ERR(data->supply)) {
ret = PTR_ERR(data->supply); ret = PTR_ERR(data->supply);
dev_err(dev, "Failed to request supply: %d\n", ret); dev_err(dev, "Failed to request supply: %d\n", ret);
goto err_gpio; return ret;
} }
ret = tpa6130a2_power(1); ret = tpa6130a2_power(data, true);
if (ret != 0) if (ret != 0)
goto err_gpio; return ret;
/* Read version */ /* Read version */
ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) & regmap_read(data->regmap, TPA6130A2_REG_VERSION, &version);
TPA6130A2_VERSION_MASK; version &= TPA6130A2_VERSION_MASK;
if ((ret != 1) && (ret != 2)) if ((version != 1) && (version != 2))
dev_warn(dev, "UNTESTED version detected (%d)\n", ret); dev_warn(dev, "UNTESTED version detected (%d)\n", version);
/* Disable the chip */ /* Disable the chip */
ret = tpa6130a2_power(0); ret = tpa6130a2_power(data, false);
if (ret != 0) if (ret != 0)
goto err_gpio; return ret;
return 0;
err_gpio:
tpa6130a2_client = NULL;
return ret; return devm_snd_soc_register_component(&client->dev,
} &tpa6130a2_component_driver, NULL, 0);
static int tpa6130a2_remove(struct i2c_client *client)
{
tpa6130a2_power(0);
tpa6130a2_client = NULL;
return 0;
} }
static const struct i2c_device_id tpa6130a2_id[] = { static const struct i2c_device_id tpa6130a2_id[] = {
...@@ -489,7 +322,6 @@ static struct i2c_driver tpa6130a2_i2c_driver = { ...@@ -489,7 +322,6 @@ static struct i2c_driver tpa6130a2_i2c_driver = {
.of_match_table = of_match_ptr(tpa6130a2_of_match), .of_match_table = of_match_ptr(tpa6130a2_of_match),
}, },
.probe = tpa6130a2_probe, .probe = tpa6130a2_probe,
.remove = tpa6130a2_remove,
.id_table = tpa6130a2_id, .id_table = tpa6130a2_id,
}; };
......
...@@ -30,19 +30,20 @@ ...@@ -30,19 +30,20 @@
#define TPA6130A2_REG_OUT_IMPEDANCE 0x03 #define TPA6130A2_REG_OUT_IMPEDANCE 0x03
#define TPA6130A2_REG_VERSION 0x04 #define TPA6130A2_REG_VERSION 0x04
#define TPA6130A2_CACHEREGNUM (TPA6130A2_REG_VERSION + 1)
/* Register bits */ /* Register bits */
/* TPA6130A2_REG_CONTROL (0x01) */ /* 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_TERMAL (0x01 << 1)
#define TPA6130A2_MODE(x) (x << 4) #define TPA6130A2_MODE(x) (x << 4)
#define TPA6130A2_MODE_STEREO (0x00) #define TPA6130A2_MODE_STEREO (0x00)
#define TPA6130A2_MODE_DUAL_MONO (0x01) #define TPA6130A2_MODE_DUAL_MONO (0x01)
#define TPA6130A2_MODE_BRIDGE (0x02) #define TPA6130A2_MODE_BRIDGE (0x02)
#define TPA6130A2_MODE_MASK (0x03) #define TPA6130A2_MODE_MASK (0x03)
#define TPA6130A2_HP_EN_R (0x01 << 6) #define TPA6130A2_HP_EN_R_SHIFT 6
#define TPA6130A2_HP_EN_L (0x01 << 7) #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) */ /* TPA6130A2_REG_VOL_MUTE (0x02) */
#define TPA6130A2_VOLUME(x) ((x & 0x3f) << 0) #define TPA6130A2_VOLUME(x) ((x & 0x3f) << 0)
...@@ -56,7 +57,4 @@ ...@@ -56,7 +57,4 @@
/* TPA6130A2_REG_VERSION (0x04) */ /* TPA6130A2_REG_VERSION (0x04) */
#define TPA6130A2_VERSION_MASK (0x0f) #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__ */ #endif /* __TPA6130A2_H__ */
...@@ -358,6 +358,9 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, ...@@ -358,6 +358,9 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
case 24: case 24:
iface |= 0x0008; iface |= 0x0008;
break; break;
case 32:
iface |= 0x000c;
break;
} }
wm8731_set_deemph(codec); wm8731_set_deemph(codec);
...@@ -541,7 +544,7 @@ static int wm8731_startup(struct snd_pcm_substream *substream, ...@@ -541,7 +544,7 @@ static int wm8731_startup(struct snd_pcm_substream *substream,
#define WM8731_RATES SNDRV_PCM_RATE_8000_96000 #define WM8731_RATES SNDRV_PCM_RATE_8000_96000
#define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ #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 = { static const struct snd_soc_dai_ops wm8731_dai_ops = {
.startup = wm8731_startup, .startup = wm8731_startup,
......
...@@ -100,7 +100,7 @@ config SND_OMAP_SOC_OMAP_TWL4030 ...@@ -100,7 +100,7 @@ config SND_OMAP_SOC_OMAP_TWL4030
config SND_OMAP_SOC_OMAP_ABE_TWL6040 config SND_OMAP_SOC_OMAP_ABE_TWL6040
tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" 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 depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST
select SND_OMAP_SOC_DMIC select SND_OMAP_SOC_DMIC
select SND_OMAP_SOC_MCPDM select SND_OMAP_SOC_MCPDM
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <linux/platform_data/asoc-ti-mcbsp.h> #include <linux/platform_data/asoc-ti-mcbsp.h>
#include "../codecs/tpa6130a2.h"
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -164,19 +163,6 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w, ...@@ -164,19 +163,6 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w,
return 0; 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, static int rx51_get_input(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
...@@ -235,7 +221,7 @@ static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = { ...@@ -235,7 +221,7 @@ static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
SND_SOC_DAPM_MIC("DMic", NULL), 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_MIC("HS Mic", NULL),
SND_SOC_DAPM_LINE("FM Transmitter", NULL), SND_SOC_DAPM_LINE("FM Transmitter", NULL),
SND_SOC_DAPM_SPK("Earphone", NULL), SND_SOC_DAPM_SPK("Earphone", NULL),
...@@ -246,11 +232,14 @@ static const struct snd_soc_dapm_route audio_map[] = { ...@@ -246,11 +232,14 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Ext Spk", NULL, "HPROUT"}, {"Ext Spk", NULL, "HPROUT"},
{"Ext Spk", NULL, "HPLCOM"}, {"Ext Spk", NULL, "HPLCOM"},
{"Ext Spk", NULL, "HPRCOM"}, {"Ext Spk", NULL, "HPRCOM"},
{"Headphone Jack", NULL, "LLOUT"},
{"Headphone Jack", NULL, "RLOUT"},
{"FM Transmitter", NULL, "LLOUT"}, {"FM Transmitter", NULL, "LLOUT"},
{"FM Transmitter", NULL, "RLOUT"}, {"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 Rate 64", NULL, "DMic"},
{"DMic", NULL, "Mic Bias"}, {"DMic", NULL, "Mic Bias"},
...@@ -286,16 +275,10 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = { ...@@ -286,16 +275,10 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) 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 snd_soc_card *card = rtd->card;
struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card); struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
int err; 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); snd_soc_limit_volume(card, "TPA6130A2 Headphone Playback Volume", 42);
err = omap_mcbsp_st_add_controls(rtd, 2); err = omap_mcbsp_st_add_controls(rtd, 2);
...@@ -357,6 +340,10 @@ static struct snd_soc_aux_dev rx51_aux_dev[] = { ...@@ -357,6 +340,10 @@ static struct snd_soc_aux_dev rx51_aux_dev[] = {
.name = "TLV320AIC34b", .name = "TLV320AIC34b",
.codec_name = "tlv320aic3x-codec.2-0019", .codec_name = "tlv320aic3x-codec.2-0019",
}, },
{
.name = "TPA61320A2",
.codec_name = "tpa6130a2.2-0060",
},
}; };
static struct snd_soc_codec_conf rx51_codec_conf[] = { static struct snd_soc_codec_conf rx51_codec_conf[] = {
...@@ -364,6 +351,10 @@ 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", .dev_name = "tlv320aic3x-codec.2-0019",
.name_prefix = "b", .name_prefix = "b",
}, },
{
.dev_name = "tpa6130a2.2-0060",
.name_prefix = "TPA6130A2",
},
}; };
/* Audio card */ /* Audio card */
...@@ -435,11 +426,10 @@ static int rx51_soc_probe(struct platform_device *pdev) ...@@ -435,11 +426,10 @@ static int rx51_soc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Headphone amplifier node is not provided\n"); dev_err(&pdev->dev, "Headphone amplifier node is not provided\n");
return -EINVAL; return -EINVAL;
} }
rx51_aux_dev[1].codec_name = NULL;
/* TODO: tpa6130a2a driver supports only a single instance, so rx51_aux_dev[1].codec_of_node = dai_node;
* this driver ignores the headphone-amplifier node for now. rx51_codec_conf[1].dev_name = NULL;
* It's already mandatory in the DT binding to be future proof. rx51_codec_conf[1].of_node = dai_node;
*/
} }
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment