forked from Minki/linux
Merge branches 'topic/ad193x', 'topic/tlv320aic23', 'topic/tlv320aic32x4', 'topic/wm8991', 'fix/si476x' and 'fix/88pm860' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-io
This commit is contained in:
commit
db5a5ee7c7
30
Documentation/devicetree/bindings/sound/tlv320aic32x4.txt
Normal file
30
Documentation/devicetree/bindings/sound/tlv320aic32x4.txt
Normal file
@ -0,0 +1,30 @@
|
||||
Texas Instruments - tlv320aic32x4 Codec module
|
||||
|
||||
The tlv320aic32x4 serial control bus communicates through I2C protocols
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "ti,tlv320aic32x4"
|
||||
- reg: I2C slave address
|
||||
- supply-*: Required supply regulators are:
|
||||
"iov" - digital IO power supply
|
||||
"ldoin" - LDO power supply
|
||||
"dv" - Digital core power supply
|
||||
"av" - Analog core power supply
|
||||
If you supply ldoin, dv and av are optional. Otherwise they are required
|
||||
See regulator/regulator.txt for more information about the detailed binding
|
||||
format.
|
||||
|
||||
Optional properties:
|
||||
- reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt
|
||||
- clocks/clock-names: Clock named 'mclk' for the master clock of the codec.
|
||||
See clock/clock-bindings.txt for information about the detailed format.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
codec: tlv320aic32x4@18 {
|
||||
compatible = "ti,tlv320aic32x4";
|
||||
reg = <0x18>;
|
||||
clocks = <&clks 201>;
|
||||
clock-names = "mclk";
|
||||
};
|
@ -45,6 +45,11 @@
|
||||
((unsigned long)&(struct soc_mixer_control) \
|
||||
{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
|
||||
.max = xmax, .platform_max = xmax, .invert = xinvert})
|
||||
#define SOC_DOUBLE_R_S_VALUE(xlreg, xrreg, xshift, xmin, xmax, xsign_bit, xinvert) \
|
||||
((unsigned long)&(struct soc_mixer_control) \
|
||||
{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
|
||||
.max = xmax, .min = xmin, .platform_max = xmax, .sign_bit = xsign_bit, \
|
||||
.invert = xinvert})
|
||||
#define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \
|
||||
((unsigned long)&(struct soc_mixer_control) \
|
||||
{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
|
||||
@ -152,6 +157,15 @@
|
||||
{.reg = xreg, .rreg = xrreg, \
|
||||
.shift = xshift, .rshift = xshift, \
|
||||
.max = xmax, .min = xmin} }
|
||||
#define SOC_DOUBLE_R_S_TLV(xname, reg_left, reg_right, xshift, xmin, xmax, xsign_bit, xinvert, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
|
||||
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
|
||||
.tlv.p = (tlv_array), \
|
||||
.info = snd_soc_info_volsw, \
|
||||
.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
|
||||
.private_value = SOC_DOUBLE_R_S_VALUE(reg_left, reg_right, xshift, \
|
||||
xmin, xmax, xsign_bit, xinvert) }
|
||||
#define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
|
||||
@ -1064,6 +1078,7 @@ struct soc_mixer_control {
|
||||
int min, max, platform_max;
|
||||
int reg, rreg;
|
||||
unsigned int shift, rshift;
|
||||
unsigned int sign_bit;
|
||||
unsigned int invert:1;
|
||||
unsigned int autodisable:1;
|
||||
};
|
||||
|
@ -58,6 +58,6 @@ config SND_AT91_SOC_AFEB9260
|
||||
depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
|
||||
select SND_ATMEL_SOC_PDC
|
||||
select SND_ATMEL_SOC_SSC
|
||||
select SND_SOC_TLV320AIC23
|
||||
select SND_SOC_TLV320AIC23_I2C
|
||||
help
|
||||
Say Y here to support sound on AFEB9260 board.
|
||||
|
@ -68,7 +68,8 @@ config SND_BF5XX_SOC_AD193X
|
||||
tristate "SoC AD193X Audio support for Blackfin"
|
||||
depends on SND_BF5XX_I2S
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_AD193X
|
||||
select SND_SOC_AD193X_I2C if I2C
|
||||
select SND_SOC_AD193X_SPI if SPI_MASTER
|
||||
help
|
||||
Say Y if you want to add support for AD193X codec on Blackfin.
|
||||
This driver supports AD1936, AD1937, AD1938 and AD1939.
|
||||
|
@ -18,7 +18,7 @@ config SND_EP93XX_SOC_SNAPPERCL15
|
||||
tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
|
||||
depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
|
||||
select SND_EP93XX_SOC_I2S
|
||||
select SND_SOC_TLV320AIC23
|
||||
select SND_SOC_TLV320AIC23_I2C
|
||||
help
|
||||
Say Y or M here if you want to add support for I2S audio on the
|
||||
Bluewater Systems Snapper CL15 module.
|
||||
|
@ -1328,6 +1328,9 @@ static int pm860x_probe(struct snd_soc_codec *codec)
|
||||
pm860x->codec = codec;
|
||||
|
||||
codec->control_data = pm860x->regmap;
|
||||
ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret = request_threaded_irq(pm860x->irq[i], NULL,
|
||||
|
@ -16,7 +16,8 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_AB8500_CODEC if ABX500_CORE
|
||||
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
|
||||
select SND_SOC_AD1836 if SPI_MASTER
|
||||
select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_AD193X_SPI if SPI_MASTER
|
||||
select SND_SOC_AD193X_I2C if I2C
|
||||
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_AD73311
|
||||
select SND_SOC_ADAU1373 if I2C
|
||||
@ -71,7 +72,8 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_STA529 if I2C
|
||||
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_TAS5086 if I2C
|
||||
select SND_SOC_TLV320AIC23 if I2C
|
||||
select SND_SOC_TLV320AIC23_I2C if I2C
|
||||
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
|
||||
select SND_SOC_TLV320AIC26 if SPI_MASTER
|
||||
select SND_SOC_TLV320AIC32X4 if I2C
|
||||
select SND_SOC_TLV320AIC3X if I2C
|
||||
@ -182,6 +184,14 @@ config SND_SOC_AD1836
|
||||
config SND_SOC_AD193X
|
||||
tristate
|
||||
|
||||
config SND_SOC_AD193X_SPI
|
||||
tristate
|
||||
select SND_SOC_AD193X
|
||||
|
||||
config SND_SOC_AD193X_I2C
|
||||
tristate
|
||||
select SND_SOC_AD193X
|
||||
|
||||
config SND_SOC_AD1980
|
||||
tristate
|
||||
|
||||
@ -357,6 +367,14 @@ config SND_SOC_TAS5086
|
||||
config SND_SOC_TLV320AIC23
|
||||
tristate
|
||||
|
||||
config SND_SOC_TLV320AIC23_I2C
|
||||
tristate
|
||||
select SND_SOC_TLV320AIC23
|
||||
|
||||
config SND_SOC_TLV320AIC23_SPI
|
||||
tristate
|
||||
select SND_SOC_TLV320AIC23
|
||||
|
||||
config SND_SOC_TLV320AIC26
|
||||
tristate
|
||||
depends on SPI
|
||||
|
@ -3,6 +3,8 @@ snd-soc-ab8500-codec-objs := ab8500-codec.o
|
||||
snd-soc-ac97-objs := ac97.o
|
||||
snd-soc-ad1836-objs := ad1836.o
|
||||
snd-soc-ad193x-objs := ad193x.o
|
||||
snd-soc-ad193x-spi-objs := ad193x-spi.o
|
||||
snd-soc-ad193x-i2c-objs := ad193x-i2c.o
|
||||
snd-soc-ad1980-objs := ad1980.o
|
||||
snd-soc-ad73311-objs := ad73311.o
|
||||
snd-soc-adau1701-objs := adau1701.o
|
||||
@ -63,9 +65,11 @@ snd-soc-sta529-objs := sta529.o
|
||||
snd-soc-stac9766-objs := stac9766.o
|
||||
snd-soc-tas5086-objs := tas5086.o
|
||||
snd-soc-tlv320aic23-objs := tlv320aic23.o
|
||||
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
|
||||
snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
|
||||
snd-soc-tlv320aic26-objs := tlv320aic26.o
|
||||
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
|
||||
snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
|
||||
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
|
||||
snd-soc-tlv320dac33-objs := tlv320dac33.o
|
||||
snd-soc-twl4030-objs := twl4030.o
|
||||
snd-soc-twl6040-objs := twl6040.o
|
||||
@ -134,6 +138,8 @@ obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o
|
||||
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
|
||||
obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
|
||||
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
|
||||
obj-$(CONFIG_SND_SOC_AD193X_SPI) += snd-soc-ad193x-spi.o
|
||||
obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
|
||||
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o
|
||||
@ -193,9 +199,11 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
|
||||
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
|
||||
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
|
||||
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
|
||||
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
|
||||
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
|
||||
|
54
sound/soc/codecs/ad193x-i2c.c
Normal file
54
sound/soc/codecs/ad193x-i2c.c
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* AD1936/AD1937 audio driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "ad193x.h"
|
||||
|
||||
static const struct i2c_device_id ad193x_id[] = {
|
||||
{ "ad1936", 0 },
|
||||
{ "ad1937", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ad193x_id);
|
||||
|
||||
static int ad193x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = ad193x_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 8;
|
||||
|
||||
return ad193x_probe(&client->dev, devm_regmap_init_i2c(client, &config));
|
||||
}
|
||||
|
||||
static int ad193x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver ad193x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ad193x",
|
||||
},
|
||||
.probe = ad193x_i2c_probe,
|
||||
.remove = ad193x_i2c_remove,
|
||||
.id_table = ad193x_id,
|
||||
};
|
||||
module_i2c_driver(ad193x_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC AD1936/AD1937 audio CODEC driver");
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
48
sound/soc/codecs/ad193x-spi.c
Normal file
48
sound/soc/codecs/ad193x-spi.c
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* AD1938/AD1939 audio driver
|
||||
*
|
||||
* Copyright 2014 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "ad193x.h"
|
||||
|
||||
static int ad193x_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct regmap_config config;
|
||||
|
||||
config = ad193x_regmap_config;
|
||||
config.val_bits = 8;
|
||||
config.reg_bits = 16;
|
||||
config.read_flag_mask = 0x09;
|
||||
config.write_flag_mask = 0x08;
|
||||
|
||||
return ad193x_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
|
||||
}
|
||||
|
||||
static int ad193x_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver ad193x_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ad193x",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad193x_spi_probe,
|
||||
.remove = ad193x_spi_remove,
|
||||
};
|
||||
module_spi_driver(ad193x_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC AD1938/AD1939 audio CODEC driver");
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -6,12 +6,10 @@
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
@ -19,6 +17,7 @@
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "ad193x.h"
|
||||
|
||||
/* codec private data */
|
||||
@ -32,8 +31,8 @@ struct ad193x_priv {
|
||||
*/
|
||||
static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
|
||||
|
||||
static const struct soc_enum ad193x_deemp_enum =
|
||||
SOC_ENUM_SINGLE(AD193X_DAC_CTRL2, 1, 4, ad193x_deemp);
|
||||
static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1,
|
||||
ad193x_deemp);
|
||||
|
||||
static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0);
|
||||
|
||||
@ -320,7 +319,7 @@ static struct snd_soc_dai_driver ad193x_dai = {
|
||||
.ops = &ad193x_dai_ops,
|
||||
};
|
||||
|
||||
static int ad193x_probe(struct snd_soc_codec *codec)
|
||||
static int ad193x_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
@ -352,7 +351,7 @@ static int ad193x_probe(struct snd_soc_codec *codec)
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
|
||||
.probe = ad193x_probe,
|
||||
.probe = ad193x_codec_probe,
|
||||
.controls = ad193x_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(ad193x_snd_controls),
|
||||
.dapm_widgets = ad193x_dapm_widgets,
|
||||
@ -366,140 +365,31 @@ static bool adau193x_reg_volatile(struct device *dev, unsigned int reg)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
|
||||
static const struct regmap_config ad193x_spi_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.reg_bits = 16,
|
||||
.read_flag_mask = 0x09,
|
||||
.write_flag_mask = 0x08,
|
||||
|
||||
const struct regmap_config ad193x_regmap_config = {
|
||||
.max_register = AD193X_NUM_REGS - 1,
|
||||
.volatile_reg = adau193x_reg_volatile,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ad193x_regmap_config);
|
||||
|
||||
static int ad193x_spi_probe(struct spi_device *spi)
|
||||
int ad193x_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct ad193x_priv *ad193x;
|
||||
|
||||
ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv),
|
||||
GFP_KERNEL);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL);
|
||||
if (ad193x == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ad193x->regmap = devm_regmap_init_spi(spi, &ad193x_spi_regmap_config);
|
||||
if (IS_ERR(ad193x->regmap))
|
||||
return PTR_ERR(ad193x->regmap);
|
||||
ad193x->regmap = regmap;
|
||||
|
||||
spi_set_drvdata(spi, ad193x);
|
||||
dev_set_drvdata(dev, ad193x);
|
||||
|
||||
return snd_soc_register_codec(&spi->dev, &soc_codec_dev_ad193x,
|
||||
&ad193x_dai, 1);
|
||||
return snd_soc_register_codec(dev, &soc_codec_dev_ad193x,
|
||||
&ad193x_dai, 1);
|
||||
}
|
||||
|
||||
static int ad193x_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver ad193x_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ad193x",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad193x_spi_probe,
|
||||
.remove = ad193x_spi_remove,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
|
||||
static const struct regmap_config ad193x_i2c_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.reg_bits = 8,
|
||||
|
||||
.max_register = AD193X_NUM_REGS - 1,
|
||||
.volatile_reg = adau193x_reg_volatile,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id ad193x_id[] = {
|
||||
{ "ad1936", 0 },
|
||||
{ "ad1937", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ad193x_id);
|
||||
|
||||
static int ad193x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ad193x_priv *ad193x;
|
||||
|
||||
ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv),
|
||||
GFP_KERNEL);
|
||||
if (ad193x == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ad193x->regmap = devm_regmap_init_i2c(client, &ad193x_i2c_regmap_config);
|
||||
if (IS_ERR(ad193x->regmap))
|
||||
return PTR_ERR(ad193x->regmap);
|
||||
|
||||
i2c_set_clientdata(client, ad193x);
|
||||
|
||||
return snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x,
|
||||
&ad193x_dai, 1);
|
||||
}
|
||||
|
||||
static int ad193x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver ad193x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ad193x",
|
||||
},
|
||||
.probe = ad193x_i2c_probe,
|
||||
.remove = ad193x_i2c_remove,
|
||||
.id_table = ad193x_id,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init ad193x_modinit(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
ret = i2c_add_driver(&ad193x_i2c_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
ret = spi_register_driver(&ad193x_spi_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register AD193X SPI driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
module_init(ad193x_modinit);
|
||||
|
||||
static void __exit ad193x_modexit(void)
|
||||
{
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&ad193x_spi_driver);
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
i2c_del_driver(&ad193x_i2c_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(ad193x_modexit);
|
||||
EXPORT_SYMBOL_GPL(ad193x_probe);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ad193x driver");
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
|
@ -9,6 +9,13 @@
|
||||
#ifndef __AD193X_H__
|
||||
#define __AD193X_H__
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct device;
|
||||
|
||||
extern const struct regmap_config ad193x_regmap_config;
|
||||
int ad193x_probe(struct device *dev, struct regmap *regmap);
|
||||
|
||||
#define AD193X_PLL_CLK_CTRL0 0x00
|
||||
#define AD193X_PLL_POWERDOWN 0x01
|
||||
#define AD193X_PLL_INPUT_MASK 0x6
|
||||
|
@ -210,7 +210,7 @@ out:
|
||||
static int si476x_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
|
||||
return 0;
|
||||
return snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops si476x_dai_ops = {
|
||||
|
59
sound/soc/codecs/tlv320aic23-i2c.c
Normal file
59
sound/soc/codecs/tlv320aic23-i2c.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* ALSA SoC TLV320AIC23 codec driver I2C interface
|
||||
*
|
||||
* Author: Arun KS, <arunks@mistralsolutions.com>
|
||||
* Copyright: (C) 2008 Mistral Solutions Pvt Ltd.,
|
||||
*
|
||||
* Based on sound/soc/codecs/wm8731.c by Richard Purdie
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "tlv320aic23.h"
|
||||
|
||||
static int tlv320aic23_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *i2c_id)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
|
||||
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EINVAL;
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap);
|
||||
return tlv320aic23_probe(&i2c->dev, regmap);
|
||||
}
|
||||
|
||||
static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tlv320aic23_id[] = {
|
||||
{"tlv320aic23", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
|
||||
|
||||
static struct i2c_driver tlv320aic23_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tlv320aic23-codec",
|
||||
},
|
||||
.probe = tlv320aic23_i2c_probe,
|
||||
.remove = __exit_p(tlv320aic23_i2c_remove),
|
||||
.id_table = tlv320aic23_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(tlv320aic23_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver I2C");
|
||||
MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
|
||||
MODULE_LICENSE("GPL");
|
57
sound/soc/codecs/tlv320aic23-spi.c
Normal file
57
sound/soc/codecs/tlv320aic23-spi.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* ALSA SoC TLV320AIC23 codec driver SPI interface
|
||||
*
|
||||
* Author: Arun KS, <arunks@mistralsolutions.com>
|
||||
* Copyright: (C) 2008 Mistral Solutions Pvt Ltd.,
|
||||
*
|
||||
* Based on sound/soc/codecs/wm8731.c by Richard Purdie
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include "tlv320aic23.h"
|
||||
|
||||
static int aic23_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
int ret;
|
||||
struct regmap *regmap;
|
||||
|
||||
dev_dbg(&spi->dev, "probing tlv320aic23 spi device\n");
|
||||
|
||||
spi->bits_per_word = 16;
|
||||
spi->mode = SPI_MODE_0;
|
||||
ret = spi_setup(spi);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &tlv320aic23_regmap);
|
||||
return tlv320aic23_probe(&spi->dev, regmap);
|
||||
}
|
||||
|
||||
static int aic23_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver aic23_spi = {
|
||||
.driver = {
|
||||
.name = "tlv320aic23",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = aic23_spi_probe,
|
||||
.remove = aic23_spi_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(aic23_spi);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver SPI");
|
||||
MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -23,7 +23,6 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
@ -51,7 +50,7 @@ static const struct reg_default tlv320aic23_reg[] = {
|
||||
{ 9, 0x0000 },
|
||||
};
|
||||
|
||||
static const struct regmap_config tlv320aic23_regmap = {
|
||||
const struct regmap_config tlv320aic23_regmap = {
|
||||
.reg_bits = 7,
|
||||
.val_bits = 9,
|
||||
|
||||
@ -60,20 +59,21 @@ static const struct regmap_config tlv320aic23_regmap = {
|
||||
.num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
EXPORT_SYMBOL(tlv320aic23_regmap);
|
||||
|
||||
static const char *rec_src_text[] = { "Line", "Mic" };
|
||||
static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
|
||||
|
||||
static const struct soc_enum rec_src_enum =
|
||||
SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
|
||||
static SOC_ENUM_SINGLE_DECL(rec_src_enum,
|
||||
TLV320AIC23_ANLG, 2, rec_src_text);
|
||||
|
||||
static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls =
|
||||
SOC_DAPM_ENUM("Input Select", rec_src_enum);
|
||||
|
||||
static const struct soc_enum tlv320aic23_rec_src =
|
||||
SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text);
|
||||
static const struct soc_enum tlv320aic23_deemph =
|
||||
SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text);
|
||||
static SOC_ENUM_SINGLE_DECL(tlv320aic23_rec_src,
|
||||
TLV320AIC23_ANLG, 2, rec_src_text);
|
||||
static SOC_ENUM_SINGLE_DECL(tlv320aic23_deemph,
|
||||
TLV320AIC23_DIGT, 1, deemph_text);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0);
|
||||
@ -557,7 +557,7 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tlv320aic23_probe(struct snd_soc_codec *codec)
|
||||
static int tlv320aic23_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -604,7 +604,7 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec)
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
|
||||
.probe = tlv320aic23_probe,
|
||||
.probe = tlv320aic23_codec_probe,
|
||||
.remove = tlv320aic23_remove,
|
||||
.suspend = tlv320aic23_suspend,
|
||||
.resume = tlv320aic23_resume,
|
||||
@ -617,56 +617,25 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
|
||||
.num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
|
||||
};
|
||||
|
||||
/*
|
||||
* If the i2c layer weren't so broken, we could pass this kind of data
|
||||
* around
|
||||
*/
|
||||
static int tlv320aic23_codec_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *i2c_id)
|
||||
int tlv320aic23_probe(struct device *dev, struct regmap *regmap)
|
||||
{
|
||||
struct aic23 *aic23;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EINVAL;
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
aic23 = devm_kzalloc(&i2c->dev, sizeof(struct aic23), GFP_KERNEL);
|
||||
aic23 = devm_kzalloc(dev, sizeof(struct aic23), GFP_KERNEL);
|
||||
if (aic23 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
aic23->regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap);
|
||||
if (IS_ERR(aic23->regmap))
|
||||
return PTR_ERR(aic23->regmap);
|
||||
aic23->regmap = regmap;
|
||||
|
||||
i2c_set_clientdata(i2c, aic23);
|
||||
dev_set_drvdata(dev, aic23);
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1);
|
||||
return ret;
|
||||
return snd_soc_register_codec(dev, &soc_codec_dev_tlv320aic23,
|
||||
&tlv320aic23_dai, 1);
|
||||
}
|
||||
static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
snd_soc_unregister_codec(&i2c->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tlv320aic23_id[] = {
|
||||
{"tlv320aic23", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
|
||||
|
||||
static struct i2c_driver tlv320aic23_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tlv320aic23-codec",
|
||||
},
|
||||
.probe = tlv320aic23_codec_probe,
|
||||
.remove = __exit_p(tlv320aic23_i2c_remove),
|
||||
.id_table = tlv320aic23_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(tlv320aic23_i2c_driver);
|
||||
EXPORT_SYMBOL(tlv320aic23_probe);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
|
||||
MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
|
||||
|
@ -12,6 +12,12 @@
|
||||
#ifndef _TLV320AIC23_H
|
||||
#define _TLV320AIC23_H
|
||||
|
||||
struct device;
|
||||
struct regmap_config;
|
||||
|
||||
extern const struct regmap_config tlv320aic23_regmap;
|
||||
int tlv320aic23_probe(struct device *dev, struct regmap *regmap);
|
||||
|
||||
/* Codec TLV320AIC23 */
|
||||
#define TLV320AIC23_LINVOL 0x00
|
||||
#define TLV320AIC23_RINVOL 0x01
|
||||
|
@ -29,9 +29,12 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <sound/tlv320aic32x4.h>
|
||||
#include <sound/core.h>
|
||||
@ -66,20 +69,32 @@ struct aic32x4_priv {
|
||||
u32 micpga_routing;
|
||||
bool swapdacs;
|
||||
int rstn_gpio;
|
||||
struct clk *mclk;
|
||||
|
||||
struct regulator *supply_ldo;
|
||||
struct regulator *supply_iov;
|
||||
struct regulator *supply_dv;
|
||||
struct regulator *supply_av;
|
||||
};
|
||||
|
||||
/* 0dB min, 1dB steps */
|
||||
static DECLARE_TLV_DB_SCALE(tlv_step_1, 0, 100, 0);
|
||||
/* 0dB min, 0.5dB steps */
|
||||
static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
|
||||
/* -63.5dB min, 0.5dB steps */
|
||||
static DECLARE_TLV_DB_SCALE(tlv_pcm, -6350, 50, 0);
|
||||
/* -6dB min, 1dB steps */
|
||||
static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0);
|
||||
/* -12dB min, 0.5dB steps */
|
||||
static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
|
||||
|
||||
static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
|
||||
AIC32X4_RDACVOL, 0, 0x30, 0, tlv_step_0_5),
|
||||
SOC_DOUBLE_R_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
|
||||
AIC32X4_HPRGAIN, 0, 0x1D, 0, tlv_step_1),
|
||||
SOC_DOUBLE_R_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
|
||||
AIC32X4_LORGAIN, 0, 0x1D, 0, tlv_step_1),
|
||||
SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
|
||||
AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
|
||||
SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
|
||||
AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
|
||||
tlv_driver_gain),
|
||||
SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
|
||||
AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0,
|
||||
tlv_driver_gain),
|
||||
SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
|
||||
AIC32X4_HPRGAIN, 6, 0x01, 1),
|
||||
SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
|
||||
@ -90,8 +105,8 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
|
||||
SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0),
|
||||
SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0),
|
||||
|
||||
SOC_DOUBLE_R_TLV("ADC Level Volume", AIC32X4_LADCVOL,
|
||||
AIC32X4_RADCVOL, 0, 0x28, 0, tlv_step_0_5),
|
||||
SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL,
|
||||
AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),
|
||||
SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL,
|
||||
AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
|
||||
|
||||
@ -480,8 +495,18 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
|
||||
static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
/* Switch on master clock */
|
||||
ret = clk_prepare_enable(aic32x4->mclk);
|
||||
if (ret) {
|
||||
dev_err(codec->dev, "Failed to enable master clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Switch on PLL */
|
||||
snd_soc_update_bits(codec, AIC32X4_PLLPR,
|
||||
AIC32X4_PLLEN, AIC32X4_PLLEN);
|
||||
@ -509,29 +534,32 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
/* Switch off PLL */
|
||||
snd_soc_update_bits(codec, AIC32X4_PLLPR,
|
||||
AIC32X4_PLLEN, 0);
|
||||
|
||||
/* Switch off NDAC Divider */
|
||||
snd_soc_update_bits(codec, AIC32X4_NDAC,
|
||||
AIC32X4_NDACEN, 0);
|
||||
|
||||
/* Switch off MDAC Divider */
|
||||
snd_soc_update_bits(codec, AIC32X4_MDAC,
|
||||
AIC32X4_MDACEN, 0);
|
||||
|
||||
/* Switch off NADC Divider */
|
||||
snd_soc_update_bits(codec, AIC32X4_NADC,
|
||||
AIC32X4_NADCEN, 0);
|
||||
/* Switch off BCLK_N Divider */
|
||||
snd_soc_update_bits(codec, AIC32X4_BCLKN,
|
||||
AIC32X4_BCLKEN, 0);
|
||||
|
||||
/* Switch off MADC Divider */
|
||||
snd_soc_update_bits(codec, AIC32X4_MADC,
|
||||
AIC32X4_MADCEN, 0);
|
||||
|
||||
/* Switch off BCLK_N Divider */
|
||||
snd_soc_update_bits(codec, AIC32X4_BCLKN,
|
||||
AIC32X4_BCLKEN, 0);
|
||||
/* Switch off NADC Divider */
|
||||
snd_soc_update_bits(codec, AIC32X4_NADC,
|
||||
AIC32X4_NADCEN, 0);
|
||||
|
||||
/* Switch off MDAC Divider */
|
||||
snd_soc_update_bits(codec, AIC32X4_MDAC,
|
||||
AIC32X4_MDACEN, 0);
|
||||
|
||||
/* Switch off NDAC Divider */
|
||||
snd_soc_update_bits(codec, AIC32X4_NDAC,
|
||||
AIC32X4_NDACEN, 0);
|
||||
|
||||
/* Switch off PLL */
|
||||
snd_soc_update_bits(codec, AIC32X4_PLLPR,
|
||||
AIC32X4_PLLEN, 0);
|
||||
|
||||
/* Switch off master clock */
|
||||
clk_disable_unprepare(aic32x4->mclk);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
break;
|
||||
@ -588,7 +616,7 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
|
||||
|
||||
snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
|
||||
|
||||
if (aic32x4->rstn_gpio >= 0) {
|
||||
if (gpio_is_valid(aic32x4->rstn_gpio)) {
|
||||
ndelay(10);
|
||||
gpio_set_value(aic32x4->rstn_gpio, 1);
|
||||
}
|
||||
@ -663,11 +691,122 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
|
||||
.num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
|
||||
};
|
||||
|
||||
static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
|
||||
struct device_node *np)
|
||||
{
|
||||
aic32x4->swapdacs = false;
|
||||
aic32x4->micpga_routing = 0;
|
||||
aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4)
|
||||
{
|
||||
regulator_disable(aic32x4->supply_iov);
|
||||
|
||||
if (!IS_ERR(aic32x4->supply_ldo))
|
||||
regulator_disable(aic32x4->supply_ldo);
|
||||
|
||||
if (!IS_ERR(aic32x4->supply_dv))
|
||||
regulator_disable(aic32x4->supply_dv);
|
||||
|
||||
if (!IS_ERR(aic32x4->supply_av))
|
||||
regulator_disable(aic32x4->supply_av);
|
||||
}
|
||||
|
||||
static int aic32x4_setup_regulators(struct device *dev,
|
||||
struct aic32x4_priv *aic32x4)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin");
|
||||
aic32x4->supply_iov = devm_regulator_get(dev, "iov");
|
||||
aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv");
|
||||
aic32x4->supply_av = devm_regulator_get_optional(dev, "av");
|
||||
|
||||
/* Check if the regulator requirements are fulfilled */
|
||||
|
||||
if (IS_ERR(aic32x4->supply_iov)) {
|
||||
dev_err(dev, "Missing supply 'iov'\n");
|
||||
return PTR_ERR(aic32x4->supply_iov);
|
||||
}
|
||||
|
||||
if (IS_ERR(aic32x4->supply_ldo)) {
|
||||
if (PTR_ERR(aic32x4->supply_ldo) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (IS_ERR(aic32x4->supply_dv)) {
|
||||
dev_err(dev, "Missing supply 'dv' or 'ldoin'\n");
|
||||
return PTR_ERR(aic32x4->supply_dv);
|
||||
}
|
||||
if (IS_ERR(aic32x4->supply_av)) {
|
||||
dev_err(dev, "Missing supply 'av' or 'ldoin'\n");
|
||||
return PTR_ERR(aic32x4->supply_av);
|
||||
}
|
||||
} else {
|
||||
if (IS_ERR(aic32x4->supply_dv) &&
|
||||
PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
if (IS_ERR(aic32x4->supply_av) &&
|
||||
PTR_ERR(aic32x4->supply_av) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ret = regulator_enable(aic32x4->supply_iov);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable regulator iov\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!IS_ERR(aic32x4->supply_ldo)) {
|
||||
ret = regulator_enable(aic32x4->supply_ldo);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable regulator ldo\n");
|
||||
goto error_ldo;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ERR(aic32x4->supply_dv)) {
|
||||
ret = regulator_enable(aic32x4->supply_dv);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable regulator dv\n");
|
||||
goto error_dv;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ERR(aic32x4->supply_av)) {
|
||||
ret = regulator_enable(aic32x4->supply_av);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable regulator av\n");
|
||||
goto error_av;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av))
|
||||
aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE;
|
||||
|
||||
return 0;
|
||||
|
||||
error_av:
|
||||
if (!IS_ERR(aic32x4->supply_dv))
|
||||
regulator_disable(aic32x4->supply_dv);
|
||||
|
||||
error_dv:
|
||||
if (!IS_ERR(aic32x4->supply_ldo))
|
||||
regulator_disable(aic32x4->supply_ldo);
|
||||
|
||||
error_ldo:
|
||||
regulator_disable(aic32x4->supply_iov);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aic32x4_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct aic32x4_pdata *pdata = i2c->dev.platform_data;
|
||||
struct aic32x4_priv *aic32x4;
|
||||
struct device_node *np = i2c->dev.of_node;
|
||||
int ret;
|
||||
|
||||
aic32x4 = devm_kzalloc(&i2c->dev, sizeof(struct aic32x4_priv),
|
||||
@ -686,6 +825,12 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,
|
||||
aic32x4->swapdacs = pdata->swapdacs;
|
||||
aic32x4->micpga_routing = pdata->micpga_routing;
|
||||
aic32x4->rstn_gpio = pdata->rstn_gpio;
|
||||
} else if (np) {
|
||||
ret = aic32x4_parse_dt(aic32x4, np);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to parse DT node\n");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
aic32x4->power_cfg = 0;
|
||||
aic32x4->swapdacs = false;
|
||||
@ -693,20 +838,44 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,
|
||||
aic32x4->rstn_gpio = -1;
|
||||
}
|
||||
|
||||
if (aic32x4->rstn_gpio >= 0) {
|
||||
aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk");
|
||||
if (IS_ERR(aic32x4->mclk)) {
|
||||
dev_err(&i2c->dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n");
|
||||
return PTR_ERR(aic32x4->mclk);
|
||||
}
|
||||
|
||||
if (gpio_is_valid(aic32x4->rstn_gpio)) {
|
||||
ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aic32x4_setup_regulators(&i2c->dev, aic32x4);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to setup regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_aic32x4, &aic32x4_dai, 1);
|
||||
return ret;
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to register codec\n");
|
||||
aic32x4_disable_regulators(aic32x4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c, aic32x4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aic32x4_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct aic32x4_priv *aic32x4 = i2c_get_clientdata(client);
|
||||
|
||||
aic32x4_disable_regulators(aic32x4);
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
return 0;
|
||||
}
|
||||
@ -717,10 +886,17 @@ static const struct i2c_device_id aic32x4_i2c_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id);
|
||||
|
||||
static const struct of_device_id aic32x4_of_id[] = {
|
||||
{ .compatible = "ti,tlv320aic32x4", },
|
||||
{ /* senitel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aic32x4_of_id);
|
||||
|
||||
static struct i2c_driver aic32x4_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "tlv320aic32x4",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = aic32x4_of_id,
|
||||
},
|
||||
.probe = aic32x4_i2c_probe,
|
||||
.remove = aic32x4_i2c_remove,
|
||||
|
@ -171,26 +171,23 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
|
||||
static const char *wm8991_digital_sidetone[] =
|
||||
{"None", "Left ADC", "Right ADC", "Reserved"};
|
||||
|
||||
static const struct soc_enum wm8991_left_digital_sidetone_enum =
|
||||
SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE,
|
||||
WM8991_ADC_TO_DACL_SHIFT,
|
||||
WM8991_ADC_TO_DACL_MASK,
|
||||
wm8991_digital_sidetone);
|
||||
static SOC_ENUM_SINGLE_DECL(wm8991_left_digital_sidetone_enum,
|
||||
WM8991_DIGITAL_SIDE_TONE,
|
||||
WM8991_ADC_TO_DACL_SHIFT,
|
||||
wm8991_digital_sidetone);
|
||||
|
||||
static const struct soc_enum wm8991_right_digital_sidetone_enum =
|
||||
SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE,
|
||||
WM8991_ADC_TO_DACR_SHIFT,
|
||||
WM8991_ADC_TO_DACR_MASK,
|
||||
wm8991_digital_sidetone);
|
||||
static SOC_ENUM_SINGLE_DECL(wm8991_right_digital_sidetone_enum,
|
||||
WM8991_DIGITAL_SIDE_TONE,
|
||||
WM8991_ADC_TO_DACR_SHIFT,
|
||||
wm8991_digital_sidetone);
|
||||
|
||||
static const char *wm8991_adcmode[] =
|
||||
{"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
|
||||
|
||||
static const struct soc_enum wm8991_right_adcmode_enum =
|
||||
SOC_ENUM_SINGLE(WM8991_ADC_CTRL,
|
||||
WM8991_ADC_HPF_CUT_SHIFT,
|
||||
WM8991_ADC_HPF_CUT_MASK,
|
||||
wm8991_adcmode);
|
||||
static SOC_ENUM_SINGLE_DECL(wm8991_right_adcmode_enum,
|
||||
WM8991_ADC_CTRL,
|
||||
WM8991_ADC_HPF_CUT_SHIFT,
|
||||
wm8991_adcmode);
|
||||
|
||||
static const struct snd_kcontrol_new wm8991_snd_controls[] = {
|
||||
/* INMIXL */
|
||||
@ -486,9 +483,9 @@ static const struct snd_kcontrol_new wm8991_dapm_inmixr_controls[] = {
|
||||
static const char *wm8991_ainlmux[] =
|
||||
{"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
|
||||
|
||||
static const struct soc_enum wm8991_ainlmux_enum =
|
||||
SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT,
|
||||
ARRAY_SIZE(wm8991_ainlmux), wm8991_ainlmux);
|
||||
static SOC_ENUM_SINGLE_DECL(wm8991_ainlmux_enum,
|
||||
WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT,
|
||||
wm8991_ainlmux);
|
||||
|
||||
static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =
|
||||
SOC_DAPM_ENUM("Route", wm8991_ainlmux_enum);
|
||||
@ -499,9 +496,9 @@ static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =
|
||||
static const char *wm8991_ainrmux[] =
|
||||
{"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
|
||||
|
||||
static const struct soc_enum wm8991_ainrmux_enum =
|
||||
SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT,
|
||||
ARRAY_SIZE(wm8991_ainrmux), wm8991_ainrmux);
|
||||
static SOC_ENUM_SINGLE_DECL(wm8991_ainrmux_enum,
|
||||
WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT,
|
||||
wm8991_ainrmux);
|
||||
|
||||
static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls =
|
||||
SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum);
|
||||
@ -1251,11 +1248,8 @@ static int wm8991_remove(struct snd_soc_codec *codec)
|
||||
|
||||
static int wm8991_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8991_priv *wm8991;
|
||||
int ret;
|
||||
|
||||
wm8991 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
|
||||
|
@ -170,7 +170,7 @@ config SND_SOC_EUKREA_TLV320
|
||||
|| MACH_EUKREA_MBIMXSD35_BASEBOARD \
|
||||
|| MACH_EUKREA_MBIMXSD51_BASEBOARD
|
||||
depends on I2C
|
||||
select SND_SOC_TLV320AIC23
|
||||
select SND_SOC_TLV320AIC23_I2C
|
||||
select SND_SOC_IMX_PCM_FIQ
|
||||
select SND_SOC_IMX_AUDMUX
|
||||
select SND_SOC_IMX_SSI
|
||||
|
@ -58,7 +58,7 @@ config SND_OMAP_SOC_OSK5912
|
||||
tristate "SoC Audio support for omap osk5912"
|
||||
depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C
|
||||
select SND_OMAP_SOC_MCBSP
|
||||
select SND_SOC_TLV320AIC23
|
||||
select SND_SOC_TLV320AIC23_I2C
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on osk5912.
|
||||
|
||||
@ -66,7 +66,7 @@ config SND_OMAP_SOC_AM3517EVM
|
||||
tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
|
||||
depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C
|
||||
select SND_OMAP_SOC_MCBSP
|
||||
select SND_SOC_TLV320AIC23
|
||||
select SND_SOC_TLV320AIC23_I2C
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517
|
||||
EVM.
|
||||
|
@ -117,7 +117,7 @@ config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
|
||||
tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
|
||||
depends on SND_SOC_SAMSUNG && ARCH_S3C24XX
|
||||
select SND_S3C24XX_I2S
|
||||
select SND_SOC_TLV320AIC23
|
||||
select SND_SOC_TLV320AIC23_I2C
|
||||
select SND_SOC_SAMSUNG_SIMTEC
|
||||
|
||||
config SND_SOC_SAMSUNG_SIMTEC_HERMES
|
||||
|
@ -2715,6 +2715,48 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
|
||||
|
||||
/**
|
||||
* snd_soc_read_signed - Read a codec register and interprete as signed value
|
||||
* @codec: codec
|
||||
* @reg: Register to read
|
||||
* @mask: Mask to use after shifting the register value
|
||||
* @shift: Right shift of register value
|
||||
* @sign_bit: Bit that describes if a number is negative or not.
|
||||
*
|
||||
* This functions reads a codec register. The register value is shifted right
|
||||
* by 'shift' bits and masked with the given 'mask'. Afterwards it translates
|
||||
* the given registervalue into a signed integer if sign_bit is non-zero.
|
||||
*
|
||||
* Returns the register value as signed int.
|
||||
*/
|
||||
static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int mask, unsigned int shift, unsigned int sign_bit)
|
||||
{
|
||||
int ret;
|
||||
unsigned int val;
|
||||
|
||||
val = (snd_soc_read(codec, reg) >> shift) & mask;
|
||||
|
||||
if (!sign_bit)
|
||||
return val;
|
||||
|
||||
/* non-negative number */
|
||||
if (!(val & BIT(sign_bit)))
|
||||
return val;
|
||||
|
||||
ret = val;
|
||||
|
||||
/*
|
||||
* The register most probably does not contain a full-sized int.
|
||||
* Instead we have an arbitrary number of bits in a signed
|
||||
* representation which has to be translated into a full-sized int.
|
||||
* This is done by filling up all bits above the sign-bit.
|
||||
*/
|
||||
ret |= ~((int)(BIT(sign_bit) - 1));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_info_volsw - single mixer info callback
|
||||
* @kcontrol: mixer control
|
||||
@ -2743,7 +2785,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
|
||||
|
||||
uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = platform_max;
|
||||
uinfo->value.integer.max = platform_max - mc->min;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
|
||||
@ -2769,11 +2811,16 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
unsigned int shift = mc->shift;
|
||||
unsigned int rshift = mc->rshift;
|
||||
int max = mc->max;
|
||||
int min = mc->min;
|
||||
int sign_bit = mc->sign_bit;
|
||||
unsigned int mask = (1 << fls(max)) - 1;
|
||||
unsigned int invert = mc->invert;
|
||||
|
||||
ucontrol->value.integer.value[0] =
|
||||
(snd_soc_read(codec, reg) >> shift) & mask;
|
||||
if (sign_bit)
|
||||
mask = BIT(sign_bit + 1) - 1;
|
||||
|
||||
ucontrol->value.integer.value[0] = snd_soc_read_signed(codec, reg, mask,
|
||||
shift, sign_bit) - min;
|
||||
if (invert)
|
||||
ucontrol->value.integer.value[0] =
|
||||
max - ucontrol->value.integer.value[0];
|
||||
@ -2781,10 +2828,12 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
if (snd_soc_volsw_is_stereo(mc)) {
|
||||
if (reg == reg2)
|
||||
ucontrol->value.integer.value[1] =
|
||||
(snd_soc_read(codec, reg) >> rshift) & mask;
|
||||
snd_soc_read_signed(codec, reg, mask, rshift,
|
||||
sign_bit) - min;
|
||||
else
|
||||
ucontrol->value.integer.value[1] =
|
||||
(snd_soc_read(codec, reg2) >> shift) & mask;
|
||||
snd_soc_read_signed(codec, reg2, mask, shift,
|
||||
sign_bit) - min;
|
||||
if (invert)
|
||||
ucontrol->value.integer.value[1] =
|
||||
max - ucontrol->value.integer.value[1];
|
||||
@ -2815,6 +2864,8 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
|
||||
unsigned int shift = mc->shift;
|
||||
unsigned int rshift = mc->rshift;
|
||||
int max = mc->max;
|
||||
int min = mc->min;
|
||||
unsigned int sign_bit = mc->sign_bit;
|
||||
unsigned int mask = (1 << fls(max)) - 1;
|
||||
unsigned int invert = mc->invert;
|
||||
int err;
|
||||
@ -2822,13 +2873,16 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
|
||||
unsigned int val2 = 0;
|
||||
unsigned int val, val_mask;
|
||||
|
||||
val = (ucontrol->value.integer.value[0] & mask);
|
||||
if (sign_bit)
|
||||
mask = BIT(sign_bit + 1) - 1;
|
||||
|
||||
val = ((ucontrol->value.integer.value[0] + min) & mask);
|
||||
if (invert)
|
||||
val = max - val;
|
||||
val_mask = mask << shift;
|
||||
val = val << shift;
|
||||
if (snd_soc_volsw_is_stereo(mc)) {
|
||||
val2 = (ucontrol->value.integer.value[1] & mask);
|
||||
val2 = ((ucontrol->value.integer.value[1] + min) & mask);
|
||||
if (invert)
|
||||
val2 = max - val2;
|
||||
if (reg == reg2) {
|
||||
|
@ -105,7 +105,7 @@ config SND_SOC_TEGRA_TRIMSLICE
|
||||
tristate "SoC Audio support for TrimSlice board"
|
||||
depends on SND_SOC_TEGRA && I2C
|
||||
select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
|
||||
select SND_SOC_TLV320AIC23
|
||||
select SND_SOC_TLV320AIC23_I2C
|
||||
help
|
||||
Say Y or M here if you want to add support for SoC audio on the
|
||||
TrimSlice platform.
|
||||
|
Loading…
Reference in New Issue
Block a user