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:
Mark Brown 2016-07-24 22:07:46 +01:00
8 changed files with 442 additions and 389 deletions

View File

@ -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 = {

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
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;
}
static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
static int tpa6130a2_power_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kctrl, int event)
{
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;
struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
struct tpa6130a2_data *data = snd_soc_component_get_drvdata(c);
int ret;
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,
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;
/* 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);
}
val_reg &= ~(mask << shift);
val_reg |= val << shift;
tpa6130a2_i2c_write(reg, val_reg);
mutex_unlock(&data->mutex);
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;
return ret;
}
ret = tpa6130a2_power(1);
ret = tpa6130a2_power(data, true);
if (ret != 0)
goto err_gpio;
return ret;
/* 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);
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(0);
ret = tpa6130a2_power(data, false);
if (ret != 0)
goto err_gpio;
return ret;
return 0;
err_gpio:
tpa6130a2_client = NULL;
return ret;
}
static int tpa6130a2_remove(struct i2c_client *client)
{
tpa6130a2_power(0);
tpa6130a2_client = NULL;
return 0;
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,
};

View File

@ -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__ */

View File

@ -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,

View File

@ -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

View File

@ -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);