Commit 3f8fe9be authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/tas6424', 'asoc/topic/tfa9879',...

Merge remote-tracking branches 'asoc/topic/tas6424', 'asoc/topic/tfa9879', 'asoc/topic/tlv320aic31xx', 'asoc/topic/tlv320aic32x4' and 'asoc/topic/tlv320aic3x' into asoc-next
...@@ -6,15 +6,15 @@ Required properties: ...@@ -6,15 +6,15 @@ Required properties:
- reg : the I2C address of the device - reg : the I2C address of the device
- #sound-dai-cells : must be 0.
Example: Example:
&i2c1 { &i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>; pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
codec: tfa9879@6c { amp: amp@6c {
#sound-dai-cells = <0>; #sound-dai-cells = <0>;
compatible = "nxp,tfa9879"; compatible = "nxp,tfa9879";
reg = <0x6c>; reg = <0x6c>;
......
Texas Instruments TAS6424 Quad-Channel Audio amplifier
The TAS6424 serial control bus communicates through I2C protocols.
Required properties:
- compatible: "ti,tas6424" - TAS6424
- reg: I2C slave address
- sound-dai-cells: must be equal to 0
Example:
tas6424: tas6424@6a {
compatible = "ti,tas6424";
reg = <0x6a>;
#sound-dai-cells = <0>;
};
For more product information please see the link below:
http://www.ti.com/product/TAS6424-Q1
...@@ -22,7 +22,7 @@ Required properties: ...@@ -22,7 +22,7 @@ Required properties:
Optional properties: Optional properties:
- gpio-reset - gpio pin number used for codec reset - reset-gpios - GPIO specification for the active low RESET input.
- ai31xx-micbias-vg - MicBias Voltage setting - ai31xx-micbias-vg - MicBias Voltage setting
1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V 1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V
2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V 2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V
...@@ -30,6 +30,10 @@ Optional properties: ...@@ -30,6 +30,10 @@ Optional properties:
If this node is not mentioned or if the value is unknown, then If this node is not mentioned or if the value is unknown, then
micbias is set to 2.0V. micbias is set to 2.0V.
Deprecated properties:
- gpio-reset - gpio pin number used for codec reset
CODEC output pins: CODEC output pins:
* HPL * HPL
* HPR * HPR
...@@ -48,6 +52,7 @@ CODEC input pins: ...@@ -48,6 +52,7 @@ CODEC input pins:
The pins can be used in referring sound node's audio-routing property. The pins can be used in referring sound node's audio-routing property.
Example: Example:
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/sound/tlv320aic31xx-micbias.h> #include <dt-bindings/sound/tlv320aic31xx-micbias.h>
tlv320aic31xx: tlv320aic31xx@18 { tlv320aic31xx: tlv320aic31xx@18 {
...@@ -56,6 +61,8 @@ tlv320aic31xx: tlv320aic31xx@18 { ...@@ -56,6 +61,8 @@ tlv320aic31xx: tlv320aic31xx@18 {
ai31xx-micbias-vg = <MICBIAS_OFF>; ai31xx-micbias-vg = <MICBIAS_OFF>;
reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
HPVDD-supply = <&regulator>; HPVDD-supply = <&regulator>;
SPRVDD-supply = <&regulator>; SPRVDD-supply = <&regulator>;
SPLVDD-supply = <&regulator>; SPLVDD-supply = <&regulator>;
......
...@@ -17,7 +17,7 @@ Required properties: ...@@ -17,7 +17,7 @@ Required properties:
Optional properties: Optional properties:
- gpio-reset - gpio pin number used for codec reset - reset-gpios - GPIO specification for the active low RESET input.
- ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality - ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
- Not supported on tlv320aic3104 - Not supported on tlv320aic3104
- ai3x-micbias-vg - MicBias Voltage required. - ai3x-micbias-vg - MicBias Voltage required.
...@@ -34,6 +34,10 @@ Optional properties: ...@@ -34,6 +34,10 @@ Optional properties:
- AVDD-supply, IOVDD-supply, DRVDD-supply, DVDD-supply : power supplies for the - AVDD-supply, IOVDD-supply, DRVDD-supply, DVDD-supply : power supplies for the
device as covered in Documentation/devicetree/bindings/regulator/regulator.txt device as covered in Documentation/devicetree/bindings/regulator/regulator.txt
Deprecated properties:
- gpio-reset - gpio pin number used for codec reset
CODEC output pins: CODEC output pins:
* LLOUT * LLOUT
* RLOUT * RLOUT
...@@ -61,10 +65,14 @@ The pins can be used in referring sound node's audio-routing property. ...@@ -61,10 +65,14 @@ The pins can be used in referring sound node's audio-routing property.
Example: Example:
#include <dt-bindings/gpio/gpio.h>
tlv320aic3x: tlv320aic3x@1b { tlv320aic3x: tlv320aic3x@1b {
compatible = "ti,tlv320aic3x"; compatible = "ti,tlv320aic3x";
reg = <0x1b>; reg = <0x1b>;
reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
AVDD-supply = <&regulator>; AVDD-supply = <&regulator>;
IOVDD-supply = <&regulator>; IOVDD-supply = <&regulator>;
DRVDD-supply = <&regulator>; DRVDD-supply = <&regulator>;
......
...@@ -9803,6 +9803,7 @@ NXP TFA9879 DRIVER ...@@ -9803,6 +9803,7 @@ NXP TFA9879 DRIVER
M: Peter Rosin <peda@axentia.se> M: Peter Rosin <peda@axentia.se>
L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/sound/tfa9879.txt
F: sound/soc/codecs/tfa9879* F: sound/soc/codecs/tfa9879*
NXP-NCI NFC DRIVER NXP-NCI NFC DRIVER
......
...@@ -150,6 +150,7 @@ config SND_SOC_ALL_CODECS ...@@ -150,6 +150,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TAS5086 if I2C select SND_SOC_TAS5086 if I2C
select SND_SOC_TAS571X if I2C select SND_SOC_TAS571X if I2C
select SND_SOC_TAS5720 if I2C select SND_SOC_TAS5720 if I2C
select SND_SOC_TAS6424 if I2C
select SND_SOC_TFA9879 if I2C select SND_SOC_TFA9879 if I2C
select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_I2C if I2C
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
...@@ -901,6 +902,13 @@ config SND_SOC_TAS5720 ...@@ -901,6 +902,13 @@ config SND_SOC_TAS5720
Enable support for Texas Instruments TAS5720L/M high-efficiency mono Enable support for Texas Instruments TAS5720L/M high-efficiency mono
Class-D audio power amplifiers. Class-D audio power amplifiers.
config SND_SOC_TAS6424
tristate "Texas Instruments TAS6424 Quad-Channel Audio amplifier"
depends on I2C
help
Enable support for Texas Instruments TAS6424 high-efficiency
digital input quad-channel Class-D audio power amplifiers.
config SND_SOC_TFA9879 config SND_SOC_TFA9879
tristate "NXP Semiconductors TFA9879 amplifier" tristate "NXP Semiconductors TFA9879 amplifier"
depends on I2C depends on I2C
...@@ -931,12 +939,12 @@ config SND_SOC_TLV320AIC32X4 ...@@ -931,12 +939,12 @@ config SND_SOC_TLV320AIC32X4
tristate tristate
config SND_SOC_TLV320AIC32X4_I2C config SND_SOC_TLV320AIC32X4_I2C
tristate tristate "Texas Instruments TLV320AIC32x4 audio CODECs - I2C"
depends on I2C depends on I2C
select SND_SOC_TLV320AIC32X4 select SND_SOC_TLV320AIC32X4
config SND_SOC_TLV320AIC32X4_SPI config SND_SOC_TLV320AIC32X4_SPI
tristate tristate "Texas Instruments TLV320AIC32x4 audio CODECs - SPI"
depends on SPI_MASTER depends on SPI_MASTER
select SND_SOC_TLV320AIC32X4 select SND_SOC_TLV320AIC32X4
......
...@@ -159,6 +159,7 @@ snd-soc-sti-sas-objs := sti-sas.o ...@@ -159,6 +159,7 @@ snd-soc-sti-sas-objs := sti-sas.o
snd-soc-tas5086-objs := tas5086.o snd-soc-tas5086-objs := tas5086.o
snd-soc-tas571x-objs := tas571x.o snd-soc-tas571x-objs := tas571x.o
snd-soc-tas5720-objs := tas5720.o snd-soc-tas5720-objs := tas5720.o
snd-soc-tas6424-objs := tas6424.o
snd-soc-tfa9879-objs := tfa9879.o snd-soc-tfa9879-objs := tfa9879.o
snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
...@@ -402,6 +403,7 @@ obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o ...@@ -402,6 +403,7 @@ obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o
obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o
obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.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_I2C) += snd-soc-tlv320aic23-i2c.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* ALSA SoC Texas Instruments TAS6424 Quad-Channel Audio Amplifier
*
* Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
* Author: Andreas Dannenberg <dannenberg@ti.com>
* Andrew F. Davis <afd@ti.com>
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include "tas6424.h"
/* Define how often to check (and clear) the fault status register (in ms) */
#define TAS6424_FAULT_CHECK_INTERVAL 200
static const char * const tas6424_supply_names[] = {
"dvdd", /* Digital power supply. Connect to 3.3-V supply. */
"vbat", /* Supply used for higher voltage analog circuits. */
"pvdd", /* Class-D amp output FETs supply. */
};
#define TAS6424_NUM_SUPPLIES ARRAY_SIZE(tas6424_supply_names)
struct tas6424_data {
struct device *dev;
struct regmap *regmap;
struct regulator_bulk_data supplies[TAS6424_NUM_SUPPLIES];
struct delayed_work fault_check_work;
unsigned int last_fault1;
unsigned int last_fault2;
unsigned int last_warn;
};
/*
* DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that
* setting the gain below -100 dB (register value <0x7) is effectively a MUTE
* as per device datasheet.
*/
static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0);
static const struct snd_kcontrol_new tas6424_snd_controls[] = {
SOC_SINGLE_TLV("Speaker Driver CH1 Playback Volume",
TAS6424_CH1_VOL_CTRL, 0, 0xff, 0, dac_tlv),
SOC_SINGLE_TLV("Speaker Driver CH2 Playback Volume",
TAS6424_CH2_VOL_CTRL, 0, 0xff, 0, dac_tlv),
SOC_SINGLE_TLV("Speaker Driver CH3 Playback Volume",
TAS6424_CH3_VOL_CTRL, 0, 0xff, 0, dac_tlv),
SOC_SINGLE_TLV("Speaker Driver CH4 Playback Volume",
TAS6424_CH4_VOL_CTRL, 0, 0xff, 0, dac_tlv),
};
static int tas6424_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec);
dev_dbg(codec->dev, "%s() event=0x%0x\n", __func__, event);
if (event & SND_SOC_DAPM_POST_PMU) {
/* Observe codec shutdown-to-active time */
msleep(12);
/* Turn on TAS6424 periodic fault checking/handling */
tas6424->last_fault1 = 0;
tas6424->last_fault2 = 0;
tas6424->last_warn = 0;
schedule_delayed_work(&tas6424->fault_check_work,
msecs_to_jiffies(TAS6424_FAULT_CHECK_INTERVAL));
} else if (event & SND_SOC_DAPM_PRE_PMD) {
/* Disable TAS6424 periodic fault checking/handling */
cancel_delayed_work_sync(&tas6424->fault_check_work);
}
return 0;
}
static const struct snd_soc_dapm_widget tas6424_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas6424_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_OUTPUT("OUT")
};
static const struct snd_soc_dapm_route tas6424_audio_map[] = {
{ "DAC", NULL, "DAC IN" },
{ "OUT", NULL, "DAC" },
};
static int tas6424_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
unsigned int rate = params_rate(params);
unsigned int width = params_width(params);
u8 sap_ctrl = 0;
dev_dbg(codec->dev, "%s() rate=%u width=%u\n", __func__, rate, width);
switch (rate) {
case 44100:
sap_ctrl |= TAS6424_SAP_RATE_44100;
break;
case 48000:
sap_ctrl |= TAS6424_SAP_RATE_48000;
break;
case 96000:
sap_ctrl |= TAS6424_SAP_RATE_96000;
break;
default:
dev_err(codec->dev, "unsupported sample rate: %u\n", rate);
return -EINVAL;
}
switch (width) {
case 16:
sap_ctrl |= TAS6424_SAP_TDM_SLOT_SZ_16;
break;
case 24:
break;
default:
dev_err(codec->dev, "unsupported sample width: %u\n", width);
return -EINVAL;
}
snd_soc_update_bits(codec, TAS6424_SAP_CTRL,
TAS6424_SAP_RATE_MASK |
TAS6424_SAP_TDM_SLOT_SZ_16,
sap_ctrl);
return 0;
}
static int tas6424_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
u8 serial_format = 0;
dev_dbg(codec->dev, "%s() fmt=0x%0x\n", __func__, fmt);
/* clock masters */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
break;
default:
dev_err(codec->dev, "Invalid DAI master/slave interface\n");
return -EINVAL;
}
/* signal polarity */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
default:
dev_err(codec->dev, "Invalid DAI clock signal polarity\n");
return -EINVAL;
}
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
serial_format |= TAS6424_SAP_I2S;
break;
case SND_SOC_DAIFMT_DSP_A:
serial_format |= TAS6424_SAP_DSP;
break;
case SND_SOC_DAIFMT_DSP_B:
/*
* We can use the fact that the TAS6424 does not care about the
* LRCLK duty cycle during TDM to receive DSP_B formatted data
* in LEFTJ mode (no delaying of the 1st data bit).
*/
serial_format |= TAS6424_SAP_LEFTJ;
break;
case SND_SOC_DAIFMT_LEFT_J:
serial_format |= TAS6424_SAP_LEFTJ;
break;
default:
dev_err(codec->dev, "Invalid DAI interface format\n");
return -EINVAL;
}
snd_soc_update_bits(codec, TAS6424_SAP_CTRL,
TAS6424_SAP_FMT_MASK, serial_format);
return 0;
}
static int tas6424_set_dai_tdm_slot(struct snd_soc_dai *dai,
unsigned int tx_mask, unsigned int rx_mask,
int slots, int slot_width)
{
struct snd_soc_codec *codec = dai->codec;
unsigned int first_slot, last_slot;
bool sap_tdm_slot_last;
dev_dbg(codec->dev, "%s() tx_mask=%d rx_mask=%d\n", __func__,
tx_mask, rx_mask);
if (!tx_mask || !rx_mask)
return 0; /* nothing needed to disable TDM mode */
/*
* Determine the first slot and last slot that is being requested so
* we'll be able to more easily enforce certain constraints as the
* TAS6424's TDM interface is not fully configurable.
*/
first_slot = __ffs(tx_mask);
last_slot = __fls(rx_mask);
if (last_slot - first_slot != 4) {
dev_err(codec->dev, "tdm mask must cover 4 contiguous slots\n");
return -EINVAL;
}
switch (first_slot) {
case 0:
sap_tdm_slot_last = false;
break;
case 4:
sap_tdm_slot_last = true;
break;
default:
dev_err(codec->dev, "tdm mask must start at slot 0 or 4\n");
return -EINVAL;
}
snd_soc_update_bits(codec, TAS6424_SAP_CTRL, TAS6424_SAP_TDM_SLOT_LAST,
sap_tdm_slot_last ? TAS6424_SAP_TDM_SLOT_LAST : 0);
return 0;
}
static int tas6424_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
unsigned int val;
dev_dbg(codec->dev, "%s() mute=%d\n", __func__, mute);
if (mute)
val = TAS6424_ALL_STATE_MUTE;
else
val = TAS6424_ALL_STATE_PLAY;
snd_soc_write(codec, TAS6424_CH_STATE_CTRL, val);
return 0;
}
static int tas6424_power_off(struct snd_soc_codec *codec)
{
struct tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec);
int ret;
snd_soc_write(codec, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_HIZ);
regcache_cache_only(tas6424->regmap, true);
regcache_mark_dirty(tas6424->regmap);
ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies),
tas6424->supplies);
if (ret < 0) {
dev_err(codec->dev, "failed to disable supplies: %d\n", ret);
return ret;
}
return 0;
}
static int tas6424_power_on(struct snd_soc_codec *codec)
{
struct tas6424_data *tas6424 = snd_soc_codec_get_drvdata(codec);
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(tas6424->supplies),
tas6424->supplies);
if (ret < 0) {
dev_err(codec->dev, "failed to enable supplies: %d\n", ret);
return ret;
}
regcache_cache_only(tas6424->regmap, false);
ret = regcache_sync(tas6424->regmap);
if (ret < 0) {
dev_err(codec->dev, "failed to sync regcache: %d\n", ret);
return ret;
}
snd_soc_write(codec, TAS6424_CH_STATE_CTRL, TAS6424_ALL_STATE_MUTE);
/* any time we come out of HIZ, the output channels automatically run DC
* load diagnostics, wait here until this completes
*/
msleep(230);
return 0;
}
static int tas6424_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
dev_dbg(codec->dev, "%s() level=%d\n", __func__, level);
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
tas6424_power_on(codec);
break;
case SND_SOC_BIAS_OFF:
tas6424_power_off(codec);
break;
}
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_tas6424 = {
.set_bias_level = tas6424_set_bias_level,
.idle_bias_off = true,
.component_driver = {
.controls = tas6424_snd_controls,
.num_controls = ARRAY_SIZE(tas6424_snd_controls),
.dapm_widgets = tas6424_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tas6424_dapm_widgets),
.dapm_routes = tas6424_audio_map,
.num_dapm_routes = ARRAY_SIZE(tas6424_audio_map),
},
};
static struct snd_soc_dai_ops tas6424_speaker_dai_ops = {
.hw_params = tas6424_hw_params,
.set_fmt = tas6424_set_dai_fmt,
.set_tdm_slot = tas6424_set_dai_tdm_slot,
.digital_mute = tas6424_mute,
};
static struct snd_soc_dai_driver tas6424_dai[] = {
{
.name = "tas6424-amplifier",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 4,
.rates = TAS6424_RATES,
.formats = TAS6424_FORMATS,
},
.ops = &tas6424_speaker_dai_ops,
},
};
static void tas6424_fault_check_work(struct work_struct *work)
{
struct tas6424_data *tas6424 = container_of(work, struct tas6424_data,
fault_check_work.work);
struct device *dev = tas6424->dev;
unsigned int reg;
int ret;
ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT1, &reg);
if (ret < 0) {
dev_err(dev, "failed to read FAULT1 register: %d\n", ret);
goto out;
}
/*
* Ignore any clock faults as there is no clean way to check for them.
* We would need to start checking for those faults *after* the SAIF
* stream has been setup, and stop checking *before* the stream is
* stopped to avoid any false-positives. However there are no
* appropriate hooks to monitor these events.
*/
reg &= TAS6424_FAULT_PVDD_OV |
TAS6424_FAULT_VBAT_OV |
TAS6424_FAULT_PVDD_UV |
TAS6424_FAULT_VBAT_UV;
if (reg)
goto check_global_fault2_reg;
/*
* Only flag errors once for a given occurrence. This is needed as
* the TAS6424 will take time clearing the fault condition internally
* during which we don't want to bombard the system with the same
* error message over and over.
*/
if ((reg & TAS6424_FAULT_PVDD_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_OV))
dev_crit(dev, "experienced a PVDD overvoltage fault\n");
if ((reg & TAS6424_FAULT_VBAT_OV) && !(tas6424->last_fault1 & TAS6424_FAULT_VBAT_OV))
dev_crit(dev, "experienced a VBAT overvoltage fault\n");
if ((reg & TAS6424_FAULT_PVDD_UV) && !(tas6424->last_fault1 & TAS6424_FAULT_PVDD_UV))
dev_crit(dev, "experienced a PVDD undervoltage fault\n");
if ((reg & TAS6424_FAULT_VBAT_UV) && !(tas6424->last_fault1 & TAS6424_FAULT_VBAT_UV))
dev_crit(dev, "experienced a VBAT undervoltage fault\n");
/* Store current fault1 value so we can detect any changes next time */
tas6424->last_fault1 = reg;
check_global_fault2_reg:
ret = regmap_read(tas6424->regmap, TAS6424_GLOB_FAULT2, &reg);
if (ret < 0) {
dev_err(dev, "failed to read FAULT2 register: %d\n", ret);
goto out;
}
reg &= TAS6424_FAULT_OTSD |
TAS6424_FAULT_OTSD_CH1 |
TAS6424_FAULT_OTSD_CH2 |
TAS6424_FAULT_OTSD_CH3 |
TAS6424_FAULT_OTSD_CH4;
if (!reg)
goto check_warn_reg;
if ((reg & TAS6424_FAULT_OTSD) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD))
dev_crit(dev, "experienced a global overtemp shutdown\n");
if ((reg & TAS6424_FAULT_OTSD_CH1) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH1))
dev_crit(dev, "experienced an overtemp shutdown on CH1\n");
if ((reg & TAS6424_FAULT_OTSD_CH2) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH2))
dev_crit(dev, "experienced an overtemp shutdown on CH2\n");
if ((reg & TAS6424_FAULT_OTSD_CH3) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH3))
dev_crit(dev, "experienced an overtemp shutdown on CH3\n");
if ((reg & TAS6424_FAULT_OTSD_CH4) && !(tas6424->last_fault2 & TAS6424_FAULT_OTSD_CH4))
dev_crit(dev, "experienced an overtemp shutdown on CH4\n");
/* Store current fault2 value so we can detect any changes next time */
tas6424->last_fault2 = reg;
check_warn_reg:
ret = regmap_read(tas6424->regmap, TAS6424_WARN, &reg);
if (ret < 0) {
dev_err(dev, "failed to read WARN register: %d\n", ret);
goto out;
}
reg &= TAS6424_WARN_VDD_UV |
TAS6424_WARN_VDD_POR |
TAS6424_WARN_VDD_OTW |
TAS6424_WARN_VDD_OTW_CH1 |
TAS6424_WARN_VDD_OTW_CH2 |
TAS6424_WARN_VDD_OTW_CH3 |
TAS6424_WARN_VDD_OTW_CH4;
if (!reg)
goto out;
if ((reg & TAS6424_WARN_VDD_UV) && !(tas6424->last_warn & TAS6424_WARN_VDD_UV))
dev_warn(dev, "experienced a VDD under voltage condition\n");
if ((reg & TAS6424_WARN_VDD_POR) && !(tas6424->last_warn & TAS6424_WARN_VDD_POR))
dev_warn(dev, "experienced a VDD POR condition\n");
if ((reg & TAS6424_WARN_VDD_OTW) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW))
dev_warn(dev, "experienced a global overtemp warning\n");
if ((reg & TAS6424_WARN_VDD_OTW_CH1) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH1))
dev_warn(dev, "experienced an overtemp warning on CH1\n");
if ((reg & TAS6424_WARN_VDD_OTW_CH2) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH2))
dev_warn(dev, "experienced an overtemp warning on CH2\n");
if ((reg & TAS6424_WARN_VDD_OTW_CH3) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH3))
dev_warn(dev, "experienced an overtemp warning on CH3\n");
if ((reg & TAS6424_WARN_VDD_OTW_CH4) && !(tas6424->last_warn & TAS6424_WARN_VDD_OTW_CH4))
dev_warn(dev, "experienced an overtemp warning on CH4\n");
/* Store current warn value so we can detect any changes next time */
tas6424->last_warn = reg;
/* Clear any faults by toggling the CLEAR_FAULT control bit */
ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3,
TAS6424_CLEAR_FAULT, TAS6424_CLEAR_FAULT);
if (ret < 0)
dev_err(dev, "failed to write MISC_CTRL3 register: %d\n", ret);
ret = regmap_write_bits(tas6424->regmap, TAS6424_MISC_CTRL3,
TAS6424_CLEAR_FAULT, 0);
if (ret < 0)
dev_err(dev, "failed to write MISC_CTRL3 register: %d\n", ret);
out:
/* Schedule the next fault check at the specified interval */
schedule_delayed_work(&tas6424->fault_check_work,
msecs_to_jiffies(TAS6424_FAULT_CHECK_INTERVAL));
}
static const struct reg_default tas6424_reg_defaults[] = {
{ TAS6424_MODE_CTRL, 0x00 },
{ TAS6424_MISC_CTRL1, 0x32 },
{ TAS6424_MISC_CTRL2, 0x62 },
{ TAS6424_SAP_CTRL, 0x04 },
{ TAS6424_CH_STATE_CTRL, 0x55 },
{ TAS6424_CH1_VOL_CTRL, 0xcf },
{ TAS6424_CH2_VOL_CTRL, 0xcf },
{ TAS6424_CH3_VOL_CTRL, 0xcf },
{ TAS6424_CH4_VOL_CTRL, 0xcf },
{ TAS6424_DC_DIAG_CTRL1, 0x00 },
{ TAS6424_DC_DIAG_CTRL2, 0x11 },
{ TAS6424_DC_DIAG_CTRL3, 0x11 },
{ TAS6424_PIN_CTRL, 0xff },
{ TAS6424_AC_DIAG_CTRL1, 0x00 },
{ TAS6424_MISC_CTRL3, 0x00 },
{ TAS6424_CLIP_CTRL, 0x01 },
{ TAS6424_CLIP_WINDOW, 0x14 },
{ TAS6424_CLIP_WARN, 0x00 },
{ TAS6424_CBC_STAT, 0x00 },
{ TAS6424_MISC_CTRL4, 0x40 },
};
static bool tas6424_is_writable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case TAS6424_MODE_CTRL:
case TAS6424_MISC_CTRL1:
case TAS6424_MISC_CTRL2:
case TAS6424_SAP_CTRL:
case TAS6424_CH_STATE_CTRL:
case TAS6424_CH1_VOL_CTRL:
case TAS6424_CH2_VOL_CTRL:
case TAS6424_CH3_VOL_CTRL:
case TAS6424_CH4_VOL_CTRL:
case TAS6424_DC_DIAG_CTRL1:
case TAS6424_DC_DIAG_CTRL2:
case TAS6424_DC_DIAG_CTRL3:
case TAS6424_PIN_CTRL:
case TAS6424_AC_DIAG_CTRL1:
case TAS6424_MISC_CTRL3:
case TAS6424_CLIP_CTRL:
case TAS6424_CLIP_WINDOW:
case TAS6424_CLIP_WARN:
case TAS6424_CBC_STAT:
case TAS6424_MISC_CTRL4:
return true;
default:
return false;
}
}
static bool tas6424_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case TAS6424_DC_LOAD_DIAG_REP12:
case TAS6424_DC_LOAD_DIAG_REP34:
case TAS6424_DC_LOAD_DIAG_REPLO:
case TAS6424_CHANNEL_STATE:
case TAS6424_CHANNEL_FAULT:
case TAS6424_GLOB_FAULT1:
case TAS6424_GLOB_FAULT2:
case TAS6424_WARN:
case TAS6424_AC_LOAD_DIAG_REP1:
case TAS6424_AC_LOAD_DIAG_REP2:
case TAS6424_AC_LOAD_DIAG_REP3:
case TAS6424_AC_LOAD_DIAG_REP4:
return true;
default:
return false;
}
}
static const struct regmap_config tas6424_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.writeable_reg = tas6424_is_writable_reg,
.volatile_reg = tas6424_is_volatile_reg,
.max_register = TAS6424_MAX,
.reg_defaults = tas6424_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(tas6424_reg_defaults),
.cache_type = REGCACHE_RBTREE,
};
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id tas6424_of_ids[] = {
{ .compatible = "ti,tas6424", },
{ },
};
MODULE_DEVICE_TABLE(of, tas6424_of_ids);
#endif
static int tas6424_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct tas6424_data *tas6424;
int ret;
int i;
tas6424 = devm_kzalloc(dev, sizeof(*tas6424), GFP_KERNEL);
if (!tas6424)
return -ENOMEM;
dev_set_drvdata(dev, tas6424);
tas6424->dev = dev;
tas6424->regmap = devm_regmap_init_i2c(client, &tas6424_regmap_config);
if (IS_ERR(tas6424->regmap)) {
ret = PTR_ERR(tas6424->regmap);
dev_err(dev, "unable to allocate register map: %d\n", ret);
return ret;
}
for (i = 0; i < ARRAY_SIZE(tas6424->supplies); i++)
tas6424->supplies[i].supply = tas6424_supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(tas6424->supplies),
tas6424->supplies);
if (ret) {
dev_err(dev, "unable to request supplies: %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(tas6424->supplies),
tas6424->supplies);
if (ret) {
dev_err(dev, "unable to enable supplies: %d\n", ret);
return ret;
}
/* Reset device to establish well-defined startup state */
ret = regmap_update_bits(tas6424->regmap, TAS6424_MODE_CTRL,
TAS6424_RESET, TAS6424_RESET);
if (ret) {
dev_err(dev, "unable to reset device: %d\n", ret);
return ret;
}
INIT_DELAYED_WORK(&tas6424->fault_check_work, tas6424_fault_check_work);
ret = snd_soc_register_codec(dev, &soc_codec_dev_tas6424,
tas6424_dai, ARRAY_SIZE(tas6424_dai));
if (ret < 0) {
dev_err(dev, "unable to register codec: %d\n", ret);
return ret;
}
return 0;
}
static int tas6424_i2c_remove(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct tas6424_data *tas6424 = dev_get_drvdata(dev);
int ret;
snd_soc_unregister_codec(dev);
cancel_delayed_work_sync(&tas6424->fault_check_work);
ret = regulator_bulk_disable(ARRAY_SIZE(tas6424->supplies),
tas6424->supplies);
if (ret < 0) {
dev_err(dev, "unable to disable supplies: %d\n", ret);
return ret;
}
return 0;
}
static const struct i2c_device_id tas6424_i2c_ids[] = {
{ "tas6424", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tas6424_i2c_ids);
static struct i2c_driver tas6424_i2c_driver = {
.driver = {
.name = "tas6424",
.of_match_table = of_match_ptr(tas6424_of_ids),
},
.probe = tas6424_i2c_probe,
.remove = tas6424_i2c_remove,
.id_table = tas6424_i2c_ids,
};
module_i2c_driver(tas6424_i2c_driver);
MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
MODULE_DESCRIPTION("TAS6424 Audio amplifier driver");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/*
* ALSA SoC Texas Instruments TAS6424 Quad-Channel Audio Amplifier
*
* Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
* Author: Andreas Dannenberg <dannenberg@ti.com>
* Andrew F. Davis <afd@ti.com>
*/
#ifndef __TAS6424_H__
#define __TAS6424_H__
#define TAS6424_RATES (SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_96000)
#define TAS6424_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE)
/* Register Address Map */
#define TAS6424_MODE_CTRL 0x00
#define TAS6424_MISC_CTRL1 0x01
#define TAS6424_MISC_CTRL2 0x02
#define TAS6424_SAP_CTRL 0x03
#define TAS6424_CH_STATE_CTRL 0x04
#define TAS6424_CH1_VOL_CTRL 0x05
#define TAS6424_CH2_VOL_CTRL 0x06
#define TAS6424_CH3_VOL_CTRL 0x07
#define TAS6424_CH4_VOL_CTRL 0x08
#define TAS6424_DC_DIAG_CTRL1 0x09
#define TAS6424_DC_DIAG_CTRL2 0x0a
#define TAS6424_DC_DIAG_CTRL3 0x0b
#define TAS6424_DC_LOAD_DIAG_REP12 0x0c
#define TAS6424_DC_LOAD_DIAG_REP34 0x0d
#define TAS6424_DC_LOAD_DIAG_REPLO 0x0e
#define TAS6424_CHANNEL_STATE 0x0f
#define TAS6424_CHANNEL_FAULT 0x10
#define TAS6424_GLOB_FAULT1 0x11
#define TAS6424_GLOB_FAULT2 0x12
#define TAS6424_WARN 0x13
#define TAS6424_PIN_CTRL 0x14
#define TAS6424_AC_DIAG_CTRL1 0x15
#define TAS6424_AC_DIAG_CTRL2 0x16
#define TAS6424_AC_LOAD_DIAG_REP1 0x17
#define TAS6424_AC_LOAD_DIAG_REP2 0x18
#define TAS6424_AC_LOAD_DIAG_REP3 0x19
#define TAS6424_AC_LOAD_DIAG_REP4 0x1a
#define TAS6424_MISC_CTRL3 0x21
#define TAS6424_CLIP_CTRL 0x22
#define TAS6424_CLIP_WINDOW 0x23
#define TAS6424_CLIP_WARN 0x24
#define TAS6424_CBC_STAT 0x25
#define TAS6424_MISC_CTRL4 0x26
#define TAS6424_MAX TAS6424_MISC_CTRL4
/* TAS6424_MODE_CTRL_REG */
#define TAS6424_RESET BIT(7)
/* TAS6424_SAP_CTRL_REG */
#define TAS6424_SAP_RATE_MASK GENMASK(7, 6)
#define TAS6424_SAP_RATE_44100 (0x00 << 6)
#define TAS6424_SAP_RATE_48000 (0x01 << 6)
#define TAS6424_SAP_RATE_96000 (0x02 << 6)
#define TAS6424_SAP_TDM_SLOT_LAST BIT(5)
#define TAS6424_SAP_TDM_SLOT_SZ_16 BIT(4)
#define TAS6424_SAP_TDM_SLOT_SWAP BIT(3)
#define TAS6424_SAP_FMT_MASK GENMASK(2, 0)
#define TAS6424_SAP_RIGHTJ_24 (0x00 << 0)
#define TAS6424_SAP_RIGHTJ_20 (0x01 << 0)
#define TAS6424_SAP_RIGHTJ_18 (0x02 << 0)
#define TAS6424_SAP_RIGHTJ_16 (0x03 << 0)
#define TAS6424_SAP_I2S (0x04 << 0)
#define TAS6424_SAP_LEFTJ (0x05 << 0)
#define TAS6424_SAP_DSP (0x06 << 0)
/* TAS6424_CH_STATE_CTRL_REG */
#define TAS6424_CH1_STATE_MASK GENMASK(7, 6)
#define TAS6424_CH1_STATE_PLAY (0x00 << 6)
#define TAS6424_CH1_STATE_HIZ (0x01 << 6)
#define TAS6424_CH1_STATE_MUTE (0x02 << 6)
#define TAS6424_CH1_STATE_DIAG (0x03 << 6)
#define TAS6424_CH2_STATE_MASK GENMASK(5, 4)
#define TAS6424_CH2_STATE_PLAY (0x00 << 4)
#define TAS6424_CH2_STATE_HIZ (0x01 << 4)
#define TAS6424_CH2_STATE_MUTE (0x02 << 4)
#define TAS6424_CH2_STATE_DIAG (0x03 << 4)
#define TAS6424_CH3_STATE_MASK GENMASK(3, 2)
#define TAS6424_CH3_STATE_PLAY (0x00 << 2)
#define TAS6424_CH3_STATE_HIZ (0x01 << 2)
#define TAS6424_CH3_STATE_MUTE (0x02 << 2)
#define TAS6424_CH3_STATE_DIAG (0x03 << 2)
#define TAS6424_CH4_STATE_MASK GENMASK(1, 0)
#define TAS6424_CH4_STATE_PLAY (0x00 << 0)
#define TAS6424_CH4_STATE_HIZ (0x01 << 0)
#define TAS6424_CH4_STATE_MUTE (0x02 << 0)
#define TAS6424_CH4_STATE_DIAG (0x03 << 0)
#define TAS6424_ALL_STATE_PLAY (TAS6424_CH1_STATE_PLAY | \
TAS6424_CH2_STATE_PLAY | \
TAS6424_CH3_STATE_PLAY | \
TAS6424_CH4_STATE_PLAY)
#define TAS6424_ALL_STATE_HIZ (TAS6424_CH1_STATE_HIZ | \
TAS6424_CH2_STATE_HIZ | \
TAS6424_CH3_STATE_HIZ | \
TAS6424_CH4_STATE_HIZ)
#define TAS6424_ALL_STATE_MUTE (TAS6424_CH1_STATE_MUTE | \
TAS6424_CH2_STATE_MUTE | \
TAS6424_CH3_STATE_MUTE | \
TAS6424_CH4_STATE_MUTE)
#define TAS6424_ALL_STATE_DIAG (TAS6424_CH1_STATE_DIAG | \
TAS6424_CH2_STATE_DIAG | \
TAS6424_CH3_STATE_DIAG | \
TAS6424_CH4_STATE_DIAG)
/* TAS6424_GLOB_FAULT1_REG */
#define TAS6424_FAULT_CLOCK BIT(4)
#define TAS6424_FAULT_PVDD_OV BIT(3)
#define TAS6424_FAULT_VBAT_OV BIT(2)
#define TAS6424_FAULT_PVDD_UV BIT(1)
#define TAS6424_FAULT_VBAT_UV BIT(0)
/* TAS6424_GLOB_FAULT2_REG */
#define TAS6424_FAULT_OTSD BIT(4)
#define TAS6424_FAULT_OTSD_CH1 BIT(3)
#define TAS6424_FAULT_OTSD_CH2 BIT(2)
#define TAS6424_FAULT_OTSD_CH3 BIT(1)
#define TAS6424_FAULT_OTSD_CH4 BIT(0)
/* TAS6424_WARN_REG */
#define TAS6424_WARN_VDD_UV BIT(6)
#define TAS6424_WARN_VDD_POR BIT(5)
#define TAS6424_WARN_VDD_OTW BIT(4)
#define TAS6424_WARN_VDD_OTW_CH1 BIT(3)
#define TAS6424_WARN_VDD_OTW_CH2 BIT(2)
#define TAS6424_WARN_VDD_OTW_CH3 BIT(1)
#define TAS6424_WARN_VDD_OTW_CH4 BIT(0)
/* TAS6424_MISC_CTRL3_REG */
#define TAS6424_CLEAR_FAULT BIT(7)
#define TAS6424_PBTL_CH_SEL BIT(6)
#define TAS6424_MASK_CBC_WARN BIT(5)
#define TAS6424_MASK_VDD_UV BIT(4)
#define TAS6424_OTSD_AUTO_RECOVERY BIT(3)
#endif /* __TAS6424_H__ */
...@@ -316,6 +316,7 @@ static const struct of_device_id tfa9879_of_match[] = { ...@@ -316,6 +316,7 @@ static const struct of_device_id tfa9879_of_match[] = {
{ .compatible = "nxp,tfa9879", }, { .compatible = "nxp,tfa9879", },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, tfa9879_of_match);
static struct i2c_driver tfa9879_i2c_driver = { static struct i2c_driver tfa9879_i2c_driver = {
.driver = { .driver = {
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* ALSA SoC TLV320AIC31XX codec driver * ALSA SoC TLV320AIC31xx CODEC Driver
* *
* Copyright (C) 2014 Texas Instruments, Inc. * Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/
* * Jyri Sarha <jsarha@ti.com>
* Author: Jyri Sarha <jsarha@ti.com>
* *
* Based on ground work by: Ajit Kulkarni <x0175765@ti.com> * Based on ground work by: Ajit Kulkarni <x0175765@ti.com>
* *
* This package is free software; you can redistribute it and/or modify * The TLV320AIC31xx series of audio codecs are low-power, highly integrated
* it under the terms of the GNU General Public License version 2 as * high performance codecs which provides a stereo DAC, a mono ADC,
* published by the Free Software Foundation.
*
* THIS PACKAGE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* The TLV320AIC31xx series of audio codec is a low-power, highly integrated
* high performance codec which provides a stereo DAC, a mono ADC,
* and mono/stereo Class-D speaker driver. * and mono/stereo Class-D speaker driver.
*/ */
...@@ -26,7 +18,7 @@ ...@@ -26,7 +18,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/gpio.h> #include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -144,8 +136,7 @@ static const struct regmap_config aic31xx_i2c_regmap = { ...@@ -144,8 +136,7 @@ static const struct regmap_config aic31xx_i2c_regmap = {
.max_register = 12 * 128, .max_register = 12 * 128,
}; };
#define AIC31XX_NUM_SUPPLIES 6 static const char * const aic31xx_supply_names[] = {
static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = {
"HPVDD", "HPVDD",
"SPRVDD", "SPRVDD",
"SPLVDD", "SPLVDD",
...@@ -154,6 +145,8 @@ static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = { ...@@ -154,6 +145,8 @@ static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = {
"DVDD", "DVDD",
}; };
#define AIC31XX_NUM_SUPPLIES ARRAY_SIZE(aic31xx_supply_names)
struct aic31xx_disable_nb { struct aic31xx_disable_nb {
struct notifier_block nb; struct notifier_block nb;
struct aic31xx_priv *aic31xx; struct aic31xx_priv *aic31xx;
...@@ -164,6 +157,9 @@ struct aic31xx_priv { ...@@ -164,6 +157,9 @@ struct aic31xx_priv {
u8 i2c_regs_status; u8 i2c_regs_status;
struct device *dev; struct device *dev;
struct regmap *regmap; struct regmap *regmap;
enum aic31xx_type codec_type;
struct gpio_desc *gpio_reset;
int micbias_vg;
struct aic31xx_pdata pdata; struct aic31xx_pdata pdata;
struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
...@@ -185,7 +181,7 @@ struct aic31xx_rate_divs { ...@@ -185,7 +181,7 @@ struct aic31xx_rate_divs {
u8 madc; u8 madc;
}; };
/* ADC dividers can be disabled by cofiguring them to 0 */ /* ADC dividers can be disabled by configuring them to 0 */
static const struct aic31xx_rate_divs aic31xx_divs[] = { static const struct aic31xx_rate_divs aic31xx_divs[] = {
/* mclk/p rate pll: j d dosr ndac mdac aors nadc madc */ /* mclk/p rate pll: j d dosr ndac mdac aors nadc madc */
/* 8k rate */ /* 8k rate */
...@@ -456,7 +452,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, ...@@ -456,7 +452,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
/* change mic bias voltage to user defined */ /* change mic bias voltage to user defined */
snd_soc_update_bits(codec, AIC31XX_MICBIAS, snd_soc_update_bits(codec, AIC31XX_MICBIAS,
AIC31XX_MICBIAS_MASK, AIC31XX_MICBIAS_MASK,
aic31xx->pdata.micbias_vg << aic31xx->micbias_vg <<
AIC31XX_MICBIAS_SHIFT); AIC31XX_MICBIAS_SHIFT);
dev_dbg(codec->dev, "%s: turned on\n", __func__); dev_dbg(codec->dev, "%s: turned on\n", __func__);
break; break;
...@@ -679,14 +675,14 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec) ...@@ -679,14 +675,14 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec)
int ret = 0; int ret = 0;
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
if (!(aic31xx->pdata.codec_type & DAC31XX_BIT)) if (!(aic31xx->codec_type & DAC31XX_BIT))
ret = snd_soc_add_codec_controls( ret = snd_soc_add_codec_controls(
codec, aic31xx_snd_controls, codec, aic31xx_snd_controls,
ARRAY_SIZE(aic31xx_snd_controls)); ARRAY_SIZE(aic31xx_snd_controls));
if (ret) if (ret)
return ret; return ret;
if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT)
ret = snd_soc_add_codec_controls( ret = snd_soc_add_codec_controls(
codec, aic311x_snd_controls, codec, aic311x_snd_controls,
ARRAY_SIZE(aic311x_snd_controls)); ARRAY_SIZE(aic311x_snd_controls));
...@@ -704,7 +700,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec) ...@@ -704,7 +700,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec)
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
int ret = 0; int ret = 0;
if (aic31xx->pdata.codec_type & DAC31XX_BIT) { if (aic31xx->codec_type & DAC31XX_BIT) {
ret = snd_soc_dapm_new_controls( ret = snd_soc_dapm_new_controls(
dapm, dac31xx_dapm_widgets, dapm, dac31xx_dapm_widgets,
ARRAY_SIZE(dac31xx_dapm_widgets)); ARRAY_SIZE(dac31xx_dapm_widgets));
...@@ -728,7 +724,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec) ...@@ -728,7 +724,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec)
return ret; return ret;
} }
if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) { if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
ret = snd_soc_dapm_new_controls( ret = snd_soc_dapm_new_controls(
dapm, aic311x_dapm_widgets, dapm, aic311x_dapm_widgets,
ARRAY_SIZE(aic311x_dapm_widgets)); ARRAY_SIZE(aic311x_dapm_widgets));
...@@ -760,11 +756,17 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, ...@@ -760,11 +756,17 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
{ {
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
int bclk_score = snd_soc_params_to_frame_size(params); int bclk_score = snd_soc_params_to_frame_size(params);
int mclk_p = aic31xx->sysclk / aic31xx->p_div; int mclk_p;
int bclk_n = 0; int bclk_n = 0;
int match = -1; int match = -1;
int i; int i;
if (!aic31xx->sysclk || !aic31xx->p_div) {
dev_err(codec->dev, "Master clock not supplied\n");
return -EINVAL;
}
mclk_p = aic31xx->sysclk / aic31xx->p_div;
/* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */ /* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
snd_soc_update_bits(codec, AIC31XX_CLKMUX, snd_soc_update_bits(codec, AIC31XX_CLKMUX,
AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL); AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
...@@ -840,11 +842,17 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, ...@@ -840,11 +842,17 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec,
dev_dbg(codec->dev, dev_dbg(codec->dev,
"pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n", "pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d, aic31xx_divs[i].pll_j,
aic31xx->p_div, aic31xx_divs[i].dosr, aic31xx_divs[i].pll_d,
aic31xx_divs[i].ndac, aic31xx_divs[i].mdac, aic31xx->p_div,
aic31xx_divs[i].aosr, aic31xx_divs[i].nadc, aic31xx_divs[i].dosr,
aic31xx_divs[i].madc, bclk_n); aic31xx_divs[i].ndac,
aic31xx_divs[i].mdac,
aic31xx_divs[i].aosr,
aic31xx_divs[i].nadc,
aic31xx_divs[i].madc,
bclk_n
);
return 0; return 0;
} }
...@@ -919,28 +927,44 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, ...@@ -919,28 +927,44 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_CBM_CFM:
iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER; iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
break; break;
case SND_SOC_DAIFMT_CBS_CFM:
iface_reg1 |= AIC31XX_WCLK_MASTER;
break;
case SND_SOC_DAIFMT_CBM_CFS:
iface_reg1 |= AIC31XX_BCLK_MASTER;
break;
case SND_SOC_DAIFMT_CBS_CFS:
break;
default: default:
dev_alert(codec->dev, "Invalid DAI master/slave interface\n"); dev_err(codec->dev, "Invalid DAI master/slave interface\n");
return -EINVAL; return -EINVAL;
} }
/* interface format */ /* signal polarity */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
break;
case SND_SOC_DAIFMT_DSP_A:
dsp_a_val = 0x1; /* fall through */
case SND_SOC_DAIFMT_DSP_B:
/* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) { switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF: case SND_SOC_DAIFMT_NB_NF:
iface_reg2 |= AIC31XX_BCLKINV_MASK;
break; break;
case SND_SOC_DAIFMT_IB_NF: case SND_SOC_DAIFMT_IB_NF:
iface_reg2 |= AIC31XX_BCLKINV_MASK;
break; break;
default: default:
dev_err(codec->dev, "Invalid DAI clock signal polarity\n");
return -EINVAL; return -EINVAL;
} }
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
break;
case SND_SOC_DAIFMT_DSP_A:
dsp_a_val = 0x1; /* fall through */
case SND_SOC_DAIFMT_DSP_B:
/*
* NOTE: This CODEC samples on the falling edge of BCLK in
* DSP mode, this is inverted compared to what most DAIs
* expect, so we invert for this mode
*/
iface_reg2 ^= AIC31XX_BCLKINV_MASK;
iface_reg1 |= (AIC31XX_DSP_MODE << iface_reg1 |= (AIC31XX_DSP_MODE <<
AIC31XX_IFACE1_DATATYPE_SHIFT); AIC31XX_IFACE1_DATATYPE_SHIFT);
break; break;
...@@ -981,8 +1005,9 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, ...@@ -981,8 +1005,9 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n", dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
__func__, clk_id, freq, dir); __func__, clk_id, freq, dir);
for (i = 1; freq/i > 20000000 && i < 8; i++) for (i = 1; i < 8; i++)
; if (freq / i <= 20000000)
break;
if (freq/i > 20000000) { if (freq/i > 20000000) {
dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n", dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n",
__func__, freq); __func__, freq);
...@@ -990,9 +1015,9 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, ...@@ -990,9 +1015,9 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
} }
aic31xx->p_div = i; aic31xx->p_div = i;
for (i = 0; i < ARRAY_SIZE(aic31xx_divs) && for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++)
aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) if (aic31xx_divs[i].mclk_p == freq / aic31xx->p_div)
; break;
if (i == ARRAY_SIZE(aic31xx_divs)) { if (i == ARRAY_SIZE(aic31xx_divs)) {
dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
__func__, freq); __func__, freq);
...@@ -1004,6 +1029,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, ...@@ -1004,6 +1029,7 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
clk_id << AIC31XX_PLL_CLKIN_SHIFT); clk_id << AIC31XX_PLL_CLKIN_SHIFT);
aic31xx->sysclk = freq; aic31xx->sysclk = freq;
return 0; return 0;
} }
...@@ -1019,8 +1045,8 @@ static int aic31xx_regulator_event(struct notifier_block *nb, ...@@ -1019,8 +1045,8 @@ static int aic31xx_regulator_event(struct notifier_block *nb,
* Put codec to reset and as at least one of the * Put codec to reset and as at least one of the
* supplies was disabled. * supplies was disabled.
*/ */
if (gpio_is_valid(aic31xx->pdata.gpio_reset)) if (aic31xx->gpio_reset)
gpio_set_value(aic31xx->pdata.gpio_reset, 0); gpiod_set_value(aic31xx->gpio_reset, 1);
regcache_mark_dirty(aic31xx->regmap); regcache_mark_dirty(aic31xx->regmap);
dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__); dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__);
...@@ -1029,6 +1055,22 @@ static int aic31xx_regulator_event(struct notifier_block *nb, ...@@ -1029,6 +1055,22 @@ static int aic31xx_regulator_event(struct notifier_block *nb,
return 0; return 0;
} }
static int aic31xx_reset(struct aic31xx_priv *aic31xx)
{
int ret = 0;
if (aic31xx->gpio_reset) {
gpiod_set_value(aic31xx->gpio_reset, 1);
ndelay(10); /* At least 10ns */
gpiod_set_value(aic31xx->gpio_reset, 0);
} else {
ret = regmap_write(aic31xx->regmap, AIC31XX_RESET, 1);
}
mdelay(1); /* At least 1ms */
return ret;
}
static void aic31xx_clk_on(struct snd_soc_codec *codec) static void aic31xx_clk_on(struct snd_soc_codec *codec)
{ {
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
...@@ -1065,20 +1107,22 @@ static void aic31xx_clk_off(struct snd_soc_codec *codec) ...@@ -1065,20 +1107,22 @@ static void aic31xx_clk_off(struct snd_soc_codec *codec)
static int aic31xx_power_on(struct snd_soc_codec *codec) static int aic31xx_power_on(struct snd_soc_codec *codec)
{ {
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
int ret = 0; int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies), ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies),
aic31xx->supplies); aic31xx->supplies);
if (ret) if (ret)
return ret; return ret;
if (gpio_is_valid(aic31xx->pdata.gpio_reset)) {
gpio_set_value(aic31xx->pdata.gpio_reset, 1);
udelay(100);
}
regcache_cache_only(aic31xx->regmap, false); regcache_cache_only(aic31xx->regmap, false);
/* Reset device registers for a consistent power-on like state */
ret = aic31xx_reset(aic31xx);
if (ret < 0)
dev_err(aic31xx->dev, "Could not reset device: %d\n", ret);
ret = regcache_sync(aic31xx->regmap); ret = regcache_sync(aic31xx->regmap);
if (ret != 0) { if (ret) {
dev_err(codec->dev, dev_err(codec->dev,
"Failed to restore cache: %d\n", ret); "Failed to restore cache: %d\n", ret);
regcache_cache_only(aic31xx->regmap, true); regcache_cache_only(aic31xx->regmap, true);
...@@ -1086,19 +1130,17 @@ static int aic31xx_power_on(struct snd_soc_codec *codec) ...@@ -1086,19 +1130,17 @@ static int aic31xx_power_on(struct snd_soc_codec *codec)
aic31xx->supplies); aic31xx->supplies);
return ret; return ret;
} }
return 0; return 0;
} }
static int aic31xx_power_off(struct snd_soc_codec *codec) static void aic31xx_power_off(struct snd_soc_codec *codec)
{ {
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
int ret = 0;
regcache_cache_only(aic31xx->regmap, true); regcache_cache_only(aic31xx->regmap, true);
ret = regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies), regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
aic31xx->supplies); aic31xx->supplies);
return ret;
} }
static int aic31xx_set_bias_level(struct snd_soc_codec *codec, static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
...@@ -1137,14 +1179,11 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec, ...@@ -1137,14 +1179,11 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
static int aic31xx_codec_probe(struct snd_soc_codec *codec) static int aic31xx_codec_probe(struct snd_soc_codec *codec)
{ {
int ret = 0;
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
int i; int i, ret;
dev_dbg(aic31xx->dev, "## %s\n", __func__); dev_dbg(aic31xx->dev, "## %s\n", __func__);
aic31xx = snd_soc_codec_get_drvdata(codec);
aic31xx->codec = codec; aic31xx->codec = codec;
for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) { for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
...@@ -1169,8 +1208,10 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec) ...@@ -1169,8 +1208,10 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec)
return ret; return ret;
ret = aic31xx_add_widgets(codec); ret = aic31xx_add_widgets(codec);
if (ret)
return ret; return ret;
return 0;
} }
static int aic31xx_codec_remove(struct snd_soc_codec *codec) static int aic31xx_codec_remove(struct snd_soc_codec *codec)
...@@ -1258,89 +1299,31 @@ static const struct of_device_id tlv320aic31xx_of_match[] = { ...@@ -1258,89 +1299,31 @@ static const struct of_device_id tlv320aic31xx_of_match[] = {
{}, {},
}; };
MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match); MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match);
static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
{
struct device_node *np = aic31xx->dev->of_node;
unsigned int value = MICBIAS_2_0V;
int ret;
of_property_read_u32(np, "ai31xx-micbias-vg", &value);
switch (value) {
case MICBIAS_2_0V:
case MICBIAS_2_5V:
case MICBIAS_AVDDV:
aic31xx->pdata.micbias_vg = value;
break;
default:
dev_err(aic31xx->dev,
"Bad ai31xx-micbias-vg value %d DT\n",
value);
aic31xx->pdata.micbias_vg = MICBIAS_2_0V;
}
ret = of_get_named_gpio(np, "gpio-reset", 0);
if (ret > 0)
aic31xx->pdata.gpio_reset = ret;
}
#else /* CONFIG_OF */
static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
{
}
#endif /* CONFIG_OF */ #endif /* CONFIG_OF */
static int aic31xx_device_init(struct aic31xx_priv *aic31xx) #ifdef CONFIG_ACPI
{ static const struct acpi_device_id aic31xx_acpi_match[] = {
int ret, i; { "10TI3100", 0 },
{ }
dev_set_drvdata(aic31xx->dev, aic31xx); };
MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
if (dev_get_platdata(aic31xx->dev)) #endif
memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev),
sizeof(aic31xx->pdata));
else if (aic31xx->dev->of_node)
aic31xx_pdata_from_of(aic31xx);
if (aic31xx->pdata.gpio_reset) {
ret = devm_gpio_request_one(aic31xx->dev,
aic31xx->pdata.gpio_reset,
GPIOF_OUT_INIT_HIGH,
"aic31xx-reset-pin");
if (ret < 0) {
dev_err(aic31xx->dev, "not able to acquire gpio\n");
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
aic31xx->supplies[i].supply = aic31xx_supply_names[i];
ret = devm_regulator_bulk_get(aic31xx->dev,
ARRAY_SIZE(aic31xx->supplies),
aic31xx->supplies);
if (ret != 0)
dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
static int aic31xx_i2c_probe(struct i2c_client *i2c, static int aic31xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct aic31xx_priv *aic31xx; struct aic31xx_priv *aic31xx;
int ret; unsigned int micbias_value = MICBIAS_2_0V;
const struct regmap_config *regmap_config; int i, ret;
dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__, dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__,
id->name, (int) id->driver_data); id->name, (int)id->driver_data);
regmap_config = &aic31xx_i2c_regmap;
aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL); aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL);
if (aic31xx == NULL) if (!aic31xx)
return -ENOMEM; return -ENOMEM;
aic31xx->regmap = devm_regmap_init_i2c(i2c, regmap_config); aic31xx->regmap = devm_regmap_init_i2c(i2c, &aic31xx_i2c_regmap);
if (IS_ERR(aic31xx->regmap)) { if (IS_ERR(aic31xx->regmap)) {
ret = PTR_ERR(aic31xx->regmap); ret = PTR_ERR(aic31xx->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n", dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
...@@ -1349,13 +1332,49 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, ...@@ -1349,13 +1332,49 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
} }
aic31xx->dev = &i2c->dev; aic31xx->dev = &i2c->dev;
aic31xx->pdata.codec_type = id->driver_data; aic31xx->codec_type = id->driver_data;
ret = aic31xx_device_init(aic31xx); dev_set_drvdata(aic31xx->dev, aic31xx);
if (ret)
fwnode_property_read_u32(aic31xx->dev->fwnode, "ai31xx-micbias-vg",
&micbias_value);
switch (micbias_value) {
case MICBIAS_2_0V:
case MICBIAS_2_5V:
case MICBIAS_AVDDV:
aic31xx->micbias_vg = micbias_value;
break;
default:
dev_err(aic31xx->dev, "Bad ai31xx-micbias-vg value %d\n",
micbias_value);
aic31xx->micbias_vg = MICBIAS_2_0V;
}
if (dev_get_platdata(aic31xx->dev)) {
memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev), sizeof(aic31xx->pdata));
aic31xx->codec_type = aic31xx->pdata.codec_type;
aic31xx->micbias_vg = aic31xx->pdata.micbias_vg;
}
aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(aic31xx->gpio_reset)) {
dev_err(aic31xx->dev, "not able to acquire gpio\n");
return PTR_ERR(aic31xx->gpio_reset);
}
for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
aic31xx->supplies[i].supply = aic31xx_supply_names[i];
ret = devm_regulator_bulk_get(aic31xx->dev,
ARRAY_SIZE(aic31xx->supplies),
aic31xx->supplies);
if (ret) {
dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret);
return ret; return ret;
}
if (aic31xx->pdata.codec_type & DAC31XX_BIT) if (aic31xx->codec_type & DAC31XX_BIT)
return snd_soc_register_codec(&i2c->dev, return snd_soc_register_codec(&i2c->dev,
&soc_codec_driver_aic31xx, &soc_codec_driver_aic31xx,
dac31xx_dai_driver, dac31xx_dai_driver,
...@@ -1386,14 +1405,6 @@ static const struct i2c_device_id aic31xx_i2c_id[] = { ...@@ -1386,14 +1405,6 @@ static const struct i2c_device_id aic31xx_i2c_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id aic31xx_acpi_match[] = {
{ "10TI3100", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match);
#endif
static struct i2c_driver aic31xx_i2c_driver = { static struct i2c_driver aic31xx_i2c_driver = {
.driver = { .driver = {
.name = "tlv320aic31xx-codec", .name = "tlv320aic31xx-codec",
...@@ -1404,9 +1415,8 @@ static struct i2c_driver aic31xx_i2c_driver = { ...@@ -1404,9 +1415,8 @@ static struct i2c_driver aic31xx_i2c_driver = {
.remove = aic31xx_i2c_remove, .remove = aic31xx_i2c_remove,
.id_table = aic31xx_i2c_id, .id_table = aic31xx_i2c_id,
}; };
module_i2c_driver(aic31xx_i2c_driver); module_i2c_driver(aic31xx_i2c_driver);
MODULE_DESCRIPTION("ASoC TLV320AIC3111 codec driver"); MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
MODULE_AUTHOR("Jyri Sarha"); MODULE_DESCRIPTION("ASoC TLV320AIC31xx CODEC Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/* /*
* ALSA SoC TLV320AIC31XX codec driver * ALSA SoC TLV320AIC31xx CODEC Driver Definitions
*
* Copyright (C) 2013 Texas Instruments, Inc.
*
* This package 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.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* *
* Copyright (C) 2014-2017 Texas Instruments Incorporated - http://www.ti.com/
*/ */
#ifndef _TLV320AIC31XX_H #ifndef _TLV320AIC31XX_H
#define _TLV320AIC31XX_H #define _TLV320AIC31XX_H
#define AIC31XX_RATES SNDRV_PCM_RATE_8000_192000 #define AIC31XX_RATES SNDRV_PCM_RATE_8000_192000
#define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ #define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
| SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE \ SNDRV_PCM_FMTBIT_S20_3LE | \
| SNDRV_PCM_FMTBIT_S32_LE) SNDRV_PCM_FMTBIT_S24_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
#define AIC31XX_STEREO_CLASS_D_BIT 0x1 #define AIC31XX_STEREO_CLASS_D_BIT BIT(1)
#define AIC31XX_MINIDSP_BIT 0x2 #define AIC31XX_MINIDSP_BIT BIT(2)
#define DAC31XX_BIT 0x4 #define DAC31XX_BIT BIT(3)
enum aic31xx_type { enum aic31xx_type {
AIC3100 = 0, AIC3100 = 0,
AIC3110 = AIC31XX_STEREO_CLASS_D_BIT, AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
AIC3120 = AIC31XX_MINIDSP_BIT, AIC3120 = AIC31XX_MINIDSP_BIT,
AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT), AIC3111 = AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT,
DAC3100 = DAC31XX_BIT, DAC3100 = DAC31XX_BIT,
DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT, DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT,
}; };
...@@ -43,222 +37,167 @@ struct aic31xx_pdata { ...@@ -43,222 +37,167 @@ struct aic31xx_pdata {
#define AIC31XX_REG(page, reg) ((page * 128) + reg) #define AIC31XX_REG(page, reg) ((page * 128) + reg)
/* Page Control Register */ #define AIC31XX_PAGECTL AIC31XX_REG(0, 0) /* Page Control Register */
#define AIC31XX_PAGECTL AIC31XX_REG(0, 0)
/* Page 0 Registers */ /* Page 0 Registers */
/* Software reset register */ #define AIC31XX_RESET AIC31XX_REG(0, 1) /* Software reset register */
#define AIC31XX_RESET AIC31XX_REG(0, 1) #define AIC31XX_OT_FLAG AIC31XX_REG(0, 3) /* OT FLAG register */
/* OT FLAG register */ #define AIC31XX_CLKMUX AIC31XX_REG(0, 4) /* Clock clock Gen muxing, Multiplexers*/
#define AIC31XX_OT_FLAG AIC31XX_REG(0, 3) #define AIC31XX_PLLPR AIC31XX_REG(0, 5) /* PLL P and R-VAL register */
/* Clock clock Gen muxing, Multiplexers*/ #define AIC31XX_PLLJ AIC31XX_REG(0, 6) /* PLL J-VAL register */
#define AIC31XX_CLKMUX AIC31XX_REG(0, 4) #define AIC31XX_PLLDMSB AIC31XX_REG(0, 7) /* PLL D-VAL MSB register */
/* PLL P and R-VAL register */ #define AIC31XX_PLLDLSB AIC31XX_REG(0, 8) /* PLL D-VAL LSB register */
#define AIC31XX_PLLPR AIC31XX_REG(0, 5) #define AIC31XX_NDAC AIC31XX_REG(0, 11) /* DAC NDAC_VAL register*/
/* PLL J-VAL register */ #define AIC31XX_MDAC AIC31XX_REG(0, 12) /* DAC MDAC_VAL register */
#define AIC31XX_PLLJ AIC31XX_REG(0, 6) #define AIC31XX_DOSRMSB AIC31XX_REG(0, 13) /* DAC OSR setting register 1, MSB value */
/* PLL D-VAL MSB register */ #define AIC31XX_DOSRLSB AIC31XX_REG(0, 14) /* DAC OSR setting register 2, LSB value */
#define AIC31XX_PLLDMSB AIC31XX_REG(0, 7)
/* PLL D-VAL LSB register */
#define AIC31XX_PLLDLSB AIC31XX_REG(0, 8)
/* DAC NDAC_VAL register*/
#define AIC31XX_NDAC AIC31XX_REG(0, 11)
/* DAC MDAC_VAL register */
#define AIC31XX_MDAC AIC31XX_REG(0, 12)
/* DAC OSR setting register 1, MSB value */
#define AIC31XX_DOSRMSB AIC31XX_REG(0, 13)
/* DAC OSR setting register 2, LSB value */
#define AIC31XX_DOSRLSB AIC31XX_REG(0, 14)
#define AIC31XX_MINI_DSP_INPOL AIC31XX_REG(0, 16) #define AIC31XX_MINI_DSP_INPOL AIC31XX_REG(0, 16)
/* Clock setting register 8, PLL */ #define AIC31XX_NADC AIC31XX_REG(0, 18) /* Clock setting register 8, PLL */
#define AIC31XX_NADC AIC31XX_REG(0, 18) #define AIC31XX_MADC AIC31XX_REG(0, 19) /* Clock setting register 9, PLL */
/* Clock setting register 9, PLL */ #define AIC31XX_AOSR AIC31XX_REG(0, 20) /* ADC Oversampling (AOSR) Register */
#define AIC31XX_MADC AIC31XX_REG(0, 19) #define AIC31XX_CLKOUTMUX AIC31XX_REG(0, 25) /* Clock setting register 9, Multiplexers */
/* ADC Oversampling (AOSR) Register */ #define AIC31XX_CLKOUTMVAL AIC31XX_REG(0, 26) /* Clock setting register 10, CLOCKOUT M divider value */
#define AIC31XX_AOSR AIC31XX_REG(0, 20) #define AIC31XX_IFACE1 AIC31XX_REG(0, 27) /* Audio Interface Setting Register 1 */
/* Clock setting register 9, Multiplexers */ #define AIC31XX_DATA_OFFSET AIC31XX_REG(0, 28) /* Audio Data Slot Offset Programming */
#define AIC31XX_CLKOUTMUX AIC31XX_REG(0, 25) #define AIC31XX_IFACE2 AIC31XX_REG(0, 29) /* Audio Interface Setting Register 2 */
/* Clock setting register 10, CLOCKOUT M divider value */ #define AIC31XX_BCLKN AIC31XX_REG(0, 30) /* Clock setting register 11, BCLK N Divider */
#define AIC31XX_CLKOUTMVAL AIC31XX_REG(0, 26) #define AIC31XX_IFACESEC1 AIC31XX_REG(0, 31) /* Audio Interface Setting Register 3, Secondary Audio Interface */
/* Audio Interface Setting Register 1 */ #define AIC31XX_IFACESEC2 AIC31XX_REG(0, 32) /* Audio Interface Setting Register 4 */
#define AIC31XX_IFACE1 AIC31XX_REG(0, 27) #define AIC31XX_IFACESEC3 AIC31XX_REG(0, 33) /* Audio Interface Setting Register 5 */
/* Audio Data Slot Offset Programming */ #define AIC31XX_I2C AIC31XX_REG(0, 34) /* I2C Bus Condition */
#define AIC31XX_DATA_OFFSET AIC31XX_REG(0, 28) #define AIC31XX_ADCFLAG AIC31XX_REG(0, 36) /* ADC FLAG */
/* Audio Interface Setting Register 2 */ #define AIC31XX_DACFLAG1 AIC31XX_REG(0, 37) /* DAC Flag Registers */
#define AIC31XX_IFACE2 AIC31XX_REG(0, 29)
/* Clock setting register 11, BCLK N Divider */
#define AIC31XX_BCLKN AIC31XX_REG(0, 30)
/* Audio Interface Setting Register 3, Secondary Audio Interface */
#define AIC31XX_IFACESEC1 AIC31XX_REG(0, 31)
/* Audio Interface Setting Register 4 */
#define AIC31XX_IFACESEC2 AIC31XX_REG(0, 32)
/* Audio Interface Setting Register 5 */
#define AIC31XX_IFACESEC3 AIC31XX_REG(0, 33)
/* I2C Bus Condition */
#define AIC31XX_I2C AIC31XX_REG(0, 34)
/* ADC FLAG */
#define AIC31XX_ADCFLAG AIC31XX_REG(0, 36)
/* DAC Flag Registers */
#define AIC31XX_DACFLAG1 AIC31XX_REG(0, 37)
#define AIC31XX_DACFLAG2 AIC31XX_REG(0, 38) #define AIC31XX_DACFLAG2 AIC31XX_REG(0, 38)
/* Sticky Interrupt flag (overflow) */ #define AIC31XX_OFFLAG AIC31XX_REG(0, 39) /* Sticky Interrupt flag (overflow) */
#define AIC31XX_OFFLAG AIC31XX_REG(0, 39) #define AIC31XX_INTRDACFLAG AIC31XX_REG(0, 44) /* Sticy DAC Interrupt flags */
/* Sticy DAC Interrupt flags */ #define AIC31XX_INTRADCFLAG AIC31XX_REG(0, 45) /* Sticy ADC Interrupt flags */
#define AIC31XX_INTRDACFLAG AIC31XX_REG(0, 44) #define AIC31XX_INTRDACFLAG2 AIC31XX_REG(0, 46) /* DAC Interrupt flags 2 */
/* Sticy ADC Interrupt flags */ #define AIC31XX_INTRADCFLAG2 AIC31XX_REG(0, 47) /* ADC Interrupt flags 2 */
#define AIC31XX_INTRADCFLAG AIC31XX_REG(0, 45) #define AIC31XX_INT1CTRL AIC31XX_REG(0, 48) /* INT1 interrupt control */
/* DAC Interrupt flags 2 */ #define AIC31XX_INT2CTRL AIC31XX_REG(0, 49) /* INT2 interrupt control */
#define AIC31XX_INTRDACFLAG2 AIC31XX_REG(0, 46) #define AIC31XX_GPIO1 AIC31XX_REG(0, 51) /* GPIO1 control */
/* ADC Interrupt flags 2 */
#define AIC31XX_INTRADCFLAG2 AIC31XX_REG(0, 47)
/* INT1 interrupt control */
#define AIC31XX_INT1CTRL AIC31XX_REG(0, 48)
/* INT2 interrupt control */
#define AIC31XX_INT2CTRL AIC31XX_REG(0, 49)
/* GPIO1 control */
#define AIC31XX_GPIO1 AIC31XX_REG(0, 51)
#define AIC31XX_DACPRB AIC31XX_REG(0, 60) #define AIC31XX_DACPRB AIC31XX_REG(0, 60)
/* ADC Instruction Set Register */ #define AIC31XX_ADCPRB AIC31XX_REG(0, 61) /* ADC Instruction Set Register */
#define AIC31XX_ADCPRB AIC31XX_REG(0, 61) #define AIC31XX_DACSETUP AIC31XX_REG(0, 63) /* DAC channel setup register */
/* DAC channel setup register */ #define AIC31XX_DACMUTE AIC31XX_REG(0, 64) /* DAC Mute and volume control register */
#define AIC31XX_DACSETUP AIC31XX_REG(0, 63) #define AIC31XX_LDACVOL AIC31XX_REG(0, 65) /* Left DAC channel digital volume control */
/* DAC Mute and volume control register */ #define AIC31XX_RDACVOL AIC31XX_REG(0, 66) /* Right DAC channel digital volume control */
#define AIC31XX_DACMUTE AIC31XX_REG(0, 64) #define AIC31XX_HSDETECT AIC31XX_REG(0, 67) /* Headset detection */
/* Left DAC channel digital volume control */ #define AIC31XX_ADCSETUP AIC31XX_REG(0, 81) /* ADC Digital Mic */
#define AIC31XX_LDACVOL AIC31XX_REG(0, 65) #define AIC31XX_ADCFGA AIC31XX_REG(0, 82) /* ADC Digital Volume Control Fine Adjust */
/* Right DAC channel digital volume control */ #define AIC31XX_ADCVOL AIC31XX_REG(0, 83) /* ADC Digital Volume Control Coarse Adjust */
#define AIC31XX_RDACVOL AIC31XX_REG(0, 66)
/* Headset detection */
#define AIC31XX_HSDETECT AIC31XX_REG(0, 67)
/* ADC Digital Mic */
#define AIC31XX_ADCSETUP AIC31XX_REG(0, 81)
/* ADC Digital Volume Control Fine Adjust */
#define AIC31XX_ADCFGA AIC31XX_REG(0, 82)
/* ADC Digital Volume Control Coarse Adjust */
#define AIC31XX_ADCVOL AIC31XX_REG(0, 83)
/* Page 1 Registers */ /* Page 1 Registers */
/* Headphone drivers */ #define AIC31XX_HPDRIVER AIC31XX_REG(1, 31) /* Headphone drivers */
#define AIC31XX_HPDRIVER AIC31XX_REG(1, 31) #define AIC31XX_SPKAMP AIC31XX_REG(1, 32) /* Class-D Speakear Amplifier */
/* Class-D Speakear Amplifier */ #define AIC31XX_HPPOP AIC31XX_REG(1, 33) /* HP Output Drivers POP Removal Settings */
#define AIC31XX_SPKAMP AIC31XX_REG(1, 32) #define AIC31XX_SPPGARAMP AIC31XX_REG(1, 34) /* Output Driver PGA Ramp-Down Period Control */
/* HP Output Drivers POP Removal Settings */ #define AIC31XX_DACMIXERROUTE AIC31XX_REG(1, 35) /* DAC_L and DAC_R Output Mixer Routing */
#define AIC31XX_HPPOP AIC31XX_REG(1, 33) #define AIC31XX_LANALOGHPL AIC31XX_REG(1, 36) /* Left Analog Vol to HPL */
/* Output Driver PGA Ramp-Down Period Control */ #define AIC31XX_RANALOGHPR AIC31XX_REG(1, 37) /* Right Analog Vol to HPR */
#define AIC31XX_SPPGARAMP AIC31XX_REG(1, 34) #define AIC31XX_LANALOGSPL AIC31XX_REG(1, 38) /* Left Analog Vol to SPL */
/* DAC_L and DAC_R Output Mixer Routing */ #define AIC31XX_RANALOGSPR AIC31XX_REG(1, 39) /* Right Analog Vol to SPR */
#define AIC31XX_DACMIXERROUTE AIC31XX_REG(1, 35) #define AIC31XX_HPLGAIN AIC31XX_REG(1, 40) /* HPL Driver */
/* Left Analog Vol to HPL */ #define AIC31XX_HPRGAIN AIC31XX_REG(1, 41) /* HPR Driver */
#define AIC31XX_LANALOGHPL AIC31XX_REG(1, 36) #define AIC31XX_SPLGAIN AIC31XX_REG(1, 42) /* SPL Driver */
/* Right Analog Vol to HPR */ #define AIC31XX_SPRGAIN AIC31XX_REG(1, 43) /* SPR Driver */
#define AIC31XX_RANALOGHPR AIC31XX_REG(1, 37) #define AIC31XX_HPCONTROL AIC31XX_REG(1, 44) /* HP Driver Control */
/* Left Analog Vol to SPL */ #define AIC31XX_MICBIAS AIC31XX_REG(1, 46) /* MIC Bias Control */
#define AIC31XX_LANALOGSPL AIC31XX_REG(1, 38) #define AIC31XX_MICPGA AIC31XX_REG(1, 47) /* MIC PGA*/
/* Right Analog Vol to SPR */ #define AIC31XX_MICPGAPI AIC31XX_REG(1, 48) /* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
#define AIC31XX_RANALOGSPR AIC31XX_REG(1, 39) #define AIC31XX_MICPGAMI AIC31XX_REG(1, 49) /* ADC Input Selection for M-Terminal */
/* HPL Driver */ #define AIC31XX_MICPGACM AIC31XX_REG(1, 50) /* Input CM Settings */
#define AIC31XX_HPLGAIN AIC31XX_REG(1, 40)
/* HPR Driver */ /* Bits, masks, and shifts */
#define AIC31XX_HPRGAIN AIC31XX_REG(1, 41)
/* SPL Driver */
#define AIC31XX_SPLGAIN AIC31XX_REG(1, 42)
/* SPR Driver */
#define AIC31XX_SPRGAIN AIC31XX_REG(1, 43)
/* HP Driver Control */
#define AIC31XX_HPCONTROL AIC31XX_REG(1, 44)
/* MIC Bias Control */
#define AIC31XX_MICBIAS AIC31XX_REG(1, 46)
/* MIC PGA*/
#define AIC31XX_MICPGA AIC31XX_REG(1, 47)
/* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
#define AIC31XX_MICPGAPI AIC31XX_REG(1, 48)
/* ADC Input Selection for M-Terminal */
#define AIC31XX_MICPGAMI AIC31XX_REG(1, 49)
/* Input CM Settings */
#define AIC31XX_MICPGACM AIC31XX_REG(1, 50)
/* Bits, masks and shifts */
/* AIC31XX_CLKMUX */ /* AIC31XX_CLKMUX */
#define AIC31XX_PLL_CLKIN_MASK 0x0c #define AIC31XX_PLL_CLKIN_MASK GENMASK(3, 2)
#define AIC31XX_PLL_CLKIN_SHIFT 2 #define AIC31XX_PLL_CLKIN_SHIFT (2)
#define AIC31XX_PLL_CLKIN_MCLK 0 #define AIC31XX_PLL_CLKIN_MCLK 0x00
#define AIC31XX_CODEC_CLKIN_MASK 0x03 #define AIC31XX_PLL_CLKIN_BCKL 0x01
#define AIC31XX_CODEC_CLKIN_SHIFT 0 #define AIC31XX_PLL_CLKIN_GPIO1 0x02
#define AIC31XX_CODEC_CLKIN_PLL 3 #define AIC31XX_PLL_CLKIN_DIN 0x03
#define AIC31XX_CODEC_CLKIN_BCLK 1 #define AIC31XX_CODEC_CLKIN_MASK GENMASK(1, 0)
#define AIC31XX_CODEC_CLKIN_SHIFT (0)
/* AIC31XX_PLLPR, AIC31XX_NDAC, AIC31XX_MDAC, AIC31XX_NADC, AIC31XX_MADC, #define AIC31XX_CODEC_CLKIN_MCLK 0x00
AIC31XX_BCLKN */ #define AIC31XX_CODEC_CLKIN_BCLK 0x01
#define AIC31XX_PLL_MASK 0x7f #define AIC31XX_CODEC_CLKIN_GPIO1 0x02
#define AIC31XX_PM_MASK 0x80 #define AIC31XX_CODEC_CLKIN_PLL 0x03
/* AIC31XX_PLLPR */
/* AIC31XX_NDAC */
/* AIC31XX_MDAC */
/* AIC31XX_NADC */
/* AIC31XX_MADC */
/* AIC31XX_BCLKN */
#define AIC31XX_PLL_MASK GENMASK(6, 0)
#define AIC31XX_PM_MASK BIT(7)
/* AIC31XX_IFACE1 */ /* AIC31XX_IFACE1 */
#define AIC31XX_WORD_LEN_16BITS 0x00 #define AIC31XX_IFACE1_DATATYPE_MASK GENMASK(7, 6)
#define AIC31XX_WORD_LEN_20BITS 0x01
#define AIC31XX_WORD_LEN_24BITS 0x02
#define AIC31XX_WORD_LEN_32BITS 0x03
#define AIC31XX_IFACE1_DATALEN_MASK 0x30
#define AIC31XX_IFACE1_DATALEN_SHIFT (4)
#define AIC31XX_IFACE1_DATATYPE_MASK 0xC0
#define AIC31XX_IFACE1_DATATYPE_SHIFT (6) #define AIC31XX_IFACE1_DATATYPE_SHIFT (6)
#define AIC31XX_I2S_MODE 0x00 #define AIC31XX_I2S_MODE 0x00
#define AIC31XX_DSP_MODE 0x01 #define AIC31XX_DSP_MODE 0x01
#define AIC31XX_RIGHT_JUSTIFIED_MODE 0x02 #define AIC31XX_RIGHT_JUSTIFIED_MODE 0x02
#define AIC31XX_LEFT_JUSTIFIED_MODE 0x03 #define AIC31XX_LEFT_JUSTIFIED_MODE 0x03
#define AIC31XX_IFACE1_MASTER_MASK 0x0C #define AIC31XX_IFACE1_DATALEN_MASK GENMASK(5, 4)
#define AIC31XX_BCLK_MASTER 0x08 #define AIC31XX_IFACE1_DATALEN_SHIFT (4)
#define AIC31XX_WCLK_MASTER 0x04 #define AIC31XX_WORD_LEN_16BITS 0x00
#define AIC31XX_WORD_LEN_20BITS 0x01
#define AIC31XX_WORD_LEN_24BITS 0x02
#define AIC31XX_WORD_LEN_32BITS 0x03
#define AIC31XX_IFACE1_MASTER_MASK GENMASK(3, 2)
#define AIC31XX_BCLK_MASTER BIT(2)
#define AIC31XX_WCLK_MASTER BIT(3)
/* AIC31XX_DATA_OFFSET */ /* AIC31XX_DATA_OFFSET */
#define AIC31XX_DATA_OFFSET_MASK 0xFF #define AIC31XX_DATA_OFFSET_MASK GENMASK(7, 0)
/* AIC31XX_IFACE2 */ /* AIC31XX_IFACE2 */
#define AIC31XX_BCLKINV_MASK 0x08 #define AIC31XX_BCLKINV_MASK BIT(3)
#define AIC31XX_BDIVCLK_MASK 0x03 #define AIC31XX_BDIVCLK_MASK GENMASK(1, 0)
#define AIC31XX_DAC2BCLK 0x00 #define AIC31XX_DAC2BCLK 0x00
#define AIC31XX_DACMOD2BCLK 0x01 #define AIC31XX_DACMOD2BCLK 0x01
#define AIC31XX_ADC2BCLK 0x02 #define AIC31XX_ADC2BCLK 0x02
#define AIC31XX_ADCMOD2BCLK 0x03 #define AIC31XX_ADCMOD2BCLK 0x03
/* AIC31XX_ADCFLAG */ /* AIC31XX_ADCFLAG */
#define AIC31XX_ADCPWRSTATUS_MASK 0x40 #define AIC31XX_ADCPWRSTATUS_MASK BIT(6)
/* AIC31XX_DACFLAG1 */ /* AIC31XX_DACFLAG1 */
#define AIC31XX_LDACPWRSTATUS_MASK 0x80 #define AIC31XX_LDACPWRSTATUS_MASK BIT(7)
#define AIC31XX_RDACPWRSTATUS_MASK 0x08 #define AIC31XX_HPLDRVPWRSTATUS_MASK BIT(5)
#define AIC31XX_HPLDRVPWRSTATUS_MASK 0x20 #define AIC31XX_SPLDRVPWRSTATUS_MASK BIT(4)
#define AIC31XX_HPRDRVPWRSTATUS_MASK 0x02 #define AIC31XX_RDACPWRSTATUS_MASK BIT(3)
#define AIC31XX_SPLDRVPWRSTATUS_MASK 0x10 #define AIC31XX_HPRDRVPWRSTATUS_MASK BIT(1)
#define AIC31XX_SPRDRVPWRSTATUS_MASK 0x01 #define AIC31XX_SPRDRVPWRSTATUS_MASK BIT(0)
/* AIC31XX_INTRDACFLAG */ /* AIC31XX_INTRDACFLAG */
#define AIC31XX_HPSCDETECT_MASK 0x80 #define AIC31XX_HPLSCDETECT BIT(7)
#define AIC31XX_BUTTONPRESS_MASK 0x20 #define AIC31XX_HPRSCDETECT BIT(6)
#define AIC31XX_HSPLUG_MASK 0x10 #define AIC31XX_BUTTONPRESS BIT(5)
#define AIC31XX_LDRCTHRES_MASK 0x08 #define AIC31XX_HSPLUG BIT(4)
#define AIC31XX_RDRCTHRES_MASK 0x04 #define AIC31XX_LDRCTHRES BIT(3)
#define AIC31XX_DACSINT_MASK 0x02 #define AIC31XX_RDRCTHRES BIT(2)
#define AIC31XX_DACAINT_MASK 0x01 #define AIC31XX_DACSINT BIT(1)
#define AIC31XX_DACAINT BIT(0)
/* AIC31XX_INT1CTRL */ /* AIC31XX_INT1CTRL */
#define AIC31XX_HSPLUGDET_MASK 0x80 #define AIC31XX_HSPLUGDET BIT(7)
#define AIC31XX_BUTTONPRESSDET_MASK 0x40 #define AIC31XX_BUTTONPRESSDET BIT(6)
#define AIC31XX_DRCTHRES_MASK 0x20 #define AIC31XX_DRCTHRES BIT(5)
#define AIC31XX_AGCNOISE_MASK 0x10 #define AIC31XX_AGCNOISE BIT(4)
#define AIC31XX_OC_MASK 0x08 #define AIC31XX_SC BIT(3)
#define AIC31XX_ENGINE_MASK 0x04 #define AIC31XX_ENGINE BIT(2)
/* AIC31XX_DACSETUP */ /* AIC31XX_DACSETUP */
#define AIC31XX_SOFTSTEP_MASK 0x03 #define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0)
/* AIC31XX_DACMUTE */ /* AIC31XX_DACMUTE */
#define AIC31XX_DACMUTE_MASK 0x0C #define AIC31XX_DACMUTE_MASK GENMASK(3, 2)
/* AIC31XX_MICBIAS */ /* AIC31XX_MICBIAS */
#define AIC31XX_MICBIAS_MASK 0x03 #define AIC31XX_MICBIAS_MASK GENMASK(1, 0)
#define AIC31XX_MICBIAS_SHIFT 0 #define AIC31XX_MICBIAS_SHIFT 0
#endif /* _TLV320AIC31XX_H */ #endif /* _TLV320AIC31XX_H */
...@@ -281,34 +281,34 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = { ...@@ -281,34 +281,34 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
static const struct aic32x4_rate_divs aic32x4_divs[] = { static const struct aic32x4_rate_divs aic32x4_divs[] = {
/* 8k rate */ /* 8k rate */
{AIC32X4_FREQ_12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24}, {12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
{AIC32X4_FREQ_24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24}, {24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
{AIC32X4_FREQ_25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24}, {25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
/* 11.025k rate */ /* 11.025k rate */
{AIC32X4_FREQ_12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16}, {12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
{AIC32X4_FREQ_24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16}, {24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
/* 16k rate */ /* 16k rate */
{AIC32X4_FREQ_12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12}, {12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
{AIC32X4_FREQ_24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12}, {24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
{AIC32X4_FREQ_25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12}, {25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
/* 22.05k rate */ /* 22.05k rate */
{AIC32X4_FREQ_12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8}, {12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
{AIC32X4_FREQ_24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8}, {24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
{AIC32X4_FREQ_25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8}, {25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
/* 32k rate */ /* 32k rate */
{AIC32X4_FREQ_12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6}, {12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
{AIC32X4_FREQ_24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6}, {24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
/* 44.1k rate */ /* 44.1k rate */
{AIC32X4_FREQ_12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4}, {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
{AIC32X4_FREQ_24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4}, {24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
{AIC32X4_FREQ_25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4}, {25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
/* 48k rate */ /* 48k rate */
{AIC32X4_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4}, {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
{AIC32X4_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4}, {24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
{AIC32X4_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4}, {25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
/* 96k rate */ /* 96k rate */
{AIC32X4_FREQ_25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1}, {25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1},
}; };
static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
...@@ -601,9 +601,9 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, ...@@ -601,9 +601,9 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
switch (freq) { switch (freq) {
case AIC32X4_FREQ_12000000: case 12000000:
case AIC32X4_FREQ_24000000: case 24000000:
case AIC32X4_FREQ_25000000: case 25000000:
aic32x4->sysclk = freq; aic32x4->sysclk = freq;
return 0; return 0;
} }
...@@ -614,16 +614,9 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, ...@@ -614,16 +614,9 @@ static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{ {
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
u8 iface_reg_1; u8 iface_reg_1 = 0;
u8 iface_reg_2; u8 iface_reg_2 = 0;
u8 iface_reg_3; u8 iface_reg_3 = 0;
iface_reg_1 = snd_soc_read(codec, AIC32X4_IFACE1);
iface_reg_1 = iface_reg_1 & ~(3 << 6 | 3 << 2);
iface_reg_2 = snd_soc_read(codec, AIC32X4_IFACE2);
iface_reg_2 = 0;
iface_reg_3 = snd_soc_read(codec, AIC32X4_IFACE3);
iface_reg_3 = iface_reg_3 & ~(1 << 3);
/* set master/slave audio interface */ /* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
...@@ -641,30 +634,37 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) ...@@ -641,30 +634,37 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
break; break;
case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_A:
iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT); iface_reg_1 |= (AIC32X4_DSP_MODE <<
iface_reg_3 |= (1 << 3); /* invert bit clock */ AIC32X4_IFACE1_DATATYPE_SHIFT);
iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
iface_reg_2 = 0x01; /* add offset 1 */ iface_reg_2 = 0x01; /* add offset 1 */
break; break;
case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_DSP_B:
iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT); iface_reg_1 |= (AIC32X4_DSP_MODE <<
iface_reg_3 |= (1 << 3); /* invert bit clock */ AIC32X4_IFACE1_DATATYPE_SHIFT);
iface_reg_3 |= AIC32X4_BCLKINV_MASK; /* invert bit clock */
break; break;
case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_RIGHT_J:
iface_reg_1 |= iface_reg_1 |= (AIC32X4_RIGHT_JUSTIFIED_MODE <<
(AIC32X4_RIGHT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT); AIC32X4_IFACE1_DATATYPE_SHIFT);
break; break;
case SND_SOC_DAIFMT_LEFT_J: case SND_SOC_DAIFMT_LEFT_J:
iface_reg_1 |= iface_reg_1 |= (AIC32X4_LEFT_JUSTIFIED_MODE <<
(AIC32X4_LEFT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT); AIC32X4_IFACE1_DATATYPE_SHIFT);
break; break;
default: default:
printk(KERN_ERR "aic32x4: invalid DAI interface format\n"); printk(KERN_ERR "aic32x4: invalid DAI interface format\n");
return -EINVAL; return -EINVAL;
} }
snd_soc_write(codec, AIC32X4_IFACE1, iface_reg_1); snd_soc_update_bits(codec, AIC32X4_IFACE1,
snd_soc_write(codec, AIC32X4_IFACE2, iface_reg_2); AIC32X4_IFACE1_DATATYPE_MASK |
snd_soc_write(codec, AIC32X4_IFACE3, iface_reg_3); AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
snd_soc_update_bits(codec, AIC32X4_IFACE2,
AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
snd_soc_update_bits(codec, AIC32X4_IFACE3,
AIC32X4_BCLKINV_MASK, iface_reg_3);
return 0; return 0;
} }
...@@ -674,7 +674,8 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, ...@@ -674,7 +674,8 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
u8 data; u8 iface1_reg = 0;
u8 dacsetup_reg = 0;
int i; int i;
i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params)); i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params));
...@@ -683,82 +684,88 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, ...@@ -683,82 +684,88 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
return i; return i;
} }
/* Use PLL as CODEC_CLKIN and DAC_MOD_CLK as BDIV_CLKIN */ /* MCLK as PLL_CLKIN */
snd_soc_write(codec, AIC32X4_CLKMUX, AIC32X4_PLLCLKIN); snd_soc_update_bits(codec, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK,
snd_soc_write(codec, AIC32X4_IFACE3, AIC32X4_DACMOD2BCLK); AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT);
/* PLL as CODEC_CLKIN */
snd_soc_update_bits(codec, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_MASK,
AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
/* DAC_MOD_CLK as BDIV_CLKIN */
snd_soc_update_bits(codec, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
/* We will fix R value to 1 and will make P & J=K.D as variable */
snd_soc_update_bits(codec, AIC32X4_PLLPR, AIC32X4_PLL_R_MASK, 0x01);
/* We will fix R value to 1 and will make P & J=K.D as varialble */ /* PLL P value */
data = snd_soc_read(codec, AIC32X4_PLLPR); snd_soc_update_bits(codec, AIC32X4_PLLPR, AIC32X4_PLL_P_MASK,
data &= ~(7 << 4); aic32x4_divs[i].p_val << AIC32X4_PLL_P_SHIFT);
snd_soc_write(codec, AIC32X4_PLLPR,
(data | (aic32x4_divs[i].p_val << 4) | 0x01));
/* PLL J value */
snd_soc_write(codec, AIC32X4_PLLJ, aic32x4_divs[i].pll_j); snd_soc_write(codec, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);
/* PLL D value */
snd_soc_write(codec, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8)); snd_soc_write(codec, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
snd_soc_write(codec, AIC32X4_PLLDLSB, snd_soc_write(codec, AIC32X4_PLLDLSB, (aic32x4_divs[i].pll_d & 0xff));
(aic32x4_divs[i].pll_d & 0xff));
/* NDAC divider value */ /* NDAC divider value */
data = snd_soc_read(codec, AIC32X4_NDAC); snd_soc_update_bits(codec, AIC32X4_NDAC,
data &= ~(0x7f); AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
snd_soc_write(codec, AIC32X4_NDAC, data | aic32x4_divs[i].ndac);
/* MDAC divider value */ /* MDAC divider value */
data = snd_soc_read(codec, AIC32X4_MDAC); snd_soc_update_bits(codec, AIC32X4_MDAC,
data &= ~(0x7f); AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
snd_soc_write(codec, AIC32X4_MDAC, data | aic32x4_divs[i].mdac);
/* DOSR MSB & LSB values */ /* DOSR MSB & LSB values */
snd_soc_write(codec, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8); snd_soc_write(codec, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
snd_soc_write(codec, AIC32X4_DOSRLSB, snd_soc_write(codec, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
(aic32x4_divs[i].dosr & 0xff));
/* NADC divider value */ /* NADC divider value */
data = snd_soc_read(codec, AIC32X4_NADC); snd_soc_update_bits(codec, AIC32X4_NADC,
data &= ~(0x7f); AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
snd_soc_write(codec, AIC32X4_NADC, data | aic32x4_divs[i].nadc);
/* MADC divider value */ /* MADC divider value */
data = snd_soc_read(codec, AIC32X4_MADC); snd_soc_update_bits(codec, AIC32X4_MADC,
data &= ~(0x7f); AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
snd_soc_write(codec, AIC32X4_MADC, data | aic32x4_divs[i].madc);
/* AOSR value */ /* AOSR value */
snd_soc_write(codec, AIC32X4_AOSR, aic32x4_divs[i].aosr); snd_soc_write(codec, AIC32X4_AOSR, aic32x4_divs[i].aosr);
/* BCLK N divider */ /* BCLK N divider */
data = snd_soc_read(codec, AIC32X4_BCLKN); snd_soc_update_bits(codec, AIC32X4_BCLKN,
data &= ~(0x7f); AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
snd_soc_write(codec, AIC32X4_BCLKN, data | aic32x4_divs[i].blck_N);
data = snd_soc_read(codec, AIC32X4_IFACE1);
data = data & ~(3 << 4);
switch (params_width(params)) { switch (params_width(params)) {
case 16: case 16:
iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
AIC32X4_IFACE1_DATALEN_SHIFT);
break; break;
case 20: case 20:
data |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_DOSRMSB_SHIFT); iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
AIC32X4_IFACE1_DATALEN_SHIFT);
break; break;
case 24: case 24:
data |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_DOSRMSB_SHIFT); iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
AIC32X4_IFACE1_DATALEN_SHIFT);
break; break;
case 32: case 32:
data |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_DOSRMSB_SHIFT); iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
AIC32X4_IFACE1_DATALEN_SHIFT);
break; break;
} }
snd_soc_write(codec, AIC32X4_IFACE1, data); snd_soc_update_bits(codec, AIC32X4_IFACE1,
AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
if (params_channels(params) == 1) { if (params_channels(params) == 1) {
data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN; dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
} else { } else {
if (aic32x4->swapdacs) if (aic32x4->swapdacs)
data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN; dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN;
else else
data = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN; dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
} }
snd_soc_update_bits(codec, AIC32X4_DACSETUP, AIC32X4_DAC_CHAN_MASK, snd_soc_update_bits(codec, AIC32X4_DACSETUP,
data); AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
return 0; return 0;
} }
...@@ -766,13 +773,10 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream, ...@@ -766,13 +773,10 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
static int aic32x4_mute(struct snd_soc_dai *dai, int mute) static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u8 dac_reg;
dac_reg = snd_soc_read(codec, AIC32X4_DACMUTE) & ~AIC32X4_MUTEON; snd_soc_update_bits(codec, AIC32X4_DACMUTE,
if (mute) AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg | AIC32X4_MUTEON);
else
snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg);
return 0; return 0;
} }
......
...@@ -19,141 +19,189 @@ int aic32x4_remove(struct device *dev); ...@@ -19,141 +19,189 @@ int aic32x4_remove(struct device *dev);
/* tlv320aic32x4 register space (in decimal to match datasheet) */ /* tlv320aic32x4 register space (in decimal to match datasheet) */
#define AIC32X4_PAGE1 128 #define AIC32X4_REG(page, reg) ((page * 128) + reg)
#define AIC32X4_PSEL 0 #define AIC32X4_PSEL AIC32X4_REG(0, 0)
#define AIC32X4_RESET 1
#define AIC32X4_CLKMUX 4 #define AIC32X4_RESET AIC32X4_REG(0, 1)
#define AIC32X4_PLLPR 5 #define AIC32X4_CLKMUX AIC32X4_REG(0, 4)
#define AIC32X4_PLLJ 6 #define AIC32X4_PLLPR AIC32X4_REG(0, 5)
#define AIC32X4_PLLDMSB 7 #define AIC32X4_PLLJ AIC32X4_REG(0, 6)
#define AIC32X4_PLLDLSB 8 #define AIC32X4_PLLDMSB AIC32X4_REG(0, 7)
#define AIC32X4_NDAC 11 #define AIC32X4_PLLDLSB AIC32X4_REG(0, 8)
#define AIC32X4_MDAC 12 #define AIC32X4_NDAC AIC32X4_REG(0, 11)
#define AIC32X4_DOSRMSB 13 #define AIC32X4_MDAC AIC32X4_REG(0, 12)
#define AIC32X4_DOSRLSB 14 #define AIC32X4_DOSRMSB AIC32X4_REG(0, 13)
#define AIC32X4_NADC 18 #define AIC32X4_DOSRLSB AIC32X4_REG(0, 14)
#define AIC32X4_MADC 19 #define AIC32X4_NADC AIC32X4_REG(0, 18)
#define AIC32X4_AOSR 20 #define AIC32X4_MADC AIC32X4_REG(0, 19)
#define AIC32X4_CLKMUX2 25 #define AIC32X4_AOSR AIC32X4_REG(0, 20)
#define AIC32X4_CLKOUTM 26 #define AIC32X4_CLKMUX2 AIC32X4_REG(0, 25)
#define AIC32X4_IFACE1 27 #define AIC32X4_CLKOUTM AIC32X4_REG(0, 26)
#define AIC32X4_IFACE2 28 #define AIC32X4_IFACE1 AIC32X4_REG(0, 27)
#define AIC32X4_IFACE3 29 #define AIC32X4_IFACE2 AIC32X4_REG(0, 28)
#define AIC32X4_BCLKN 30 #define AIC32X4_IFACE3 AIC32X4_REG(0, 29)
#define AIC32X4_IFACE4 31 #define AIC32X4_BCLKN AIC32X4_REG(0, 30)
#define AIC32X4_IFACE5 32 #define AIC32X4_IFACE4 AIC32X4_REG(0, 31)
#define AIC32X4_IFACE6 33 #define AIC32X4_IFACE5 AIC32X4_REG(0, 32)
#define AIC32X4_GPIOCTL 52 #define AIC32X4_IFACE6 AIC32X4_REG(0, 33)
#define AIC32X4_DOUTCTL 53 #define AIC32X4_GPIOCTL AIC32X4_REG(0, 52)
#define AIC32X4_DINCTL 54 #define AIC32X4_DOUTCTL AIC32X4_REG(0, 53)
#define AIC32X4_MISOCTL 55 #define AIC32X4_DINCTL AIC32X4_REG(0, 54)
#define AIC32X4_SCLKCTL 56 #define AIC32X4_MISOCTL AIC32X4_REG(0, 55)
#define AIC32X4_DACSPB 60 #define AIC32X4_SCLKCTL AIC32X4_REG(0, 56)
#define AIC32X4_ADCSPB 61 #define AIC32X4_DACSPB AIC32X4_REG(0, 60)
#define AIC32X4_DACSETUP 63 #define AIC32X4_ADCSPB AIC32X4_REG(0, 61)
#define AIC32X4_DACMUTE 64 #define AIC32X4_DACSETUP AIC32X4_REG(0, 63)
#define AIC32X4_LDACVOL 65 #define AIC32X4_DACMUTE AIC32X4_REG(0, 64)
#define AIC32X4_RDACVOL 66 #define AIC32X4_LDACVOL AIC32X4_REG(0, 65)
#define AIC32X4_ADCSETUP 81 #define AIC32X4_RDACVOL AIC32X4_REG(0, 66)
#define AIC32X4_ADCFGA 82 #define AIC32X4_ADCSETUP AIC32X4_REG(0, 81)
#define AIC32X4_LADCVOL 83 #define AIC32X4_ADCFGA AIC32X4_REG(0, 82)
#define AIC32X4_RADCVOL 84 #define AIC32X4_LADCVOL AIC32X4_REG(0, 83)
#define AIC32X4_LAGC1 86 #define AIC32X4_RADCVOL AIC32X4_REG(0, 84)
#define AIC32X4_LAGC2 87 #define AIC32X4_LAGC1 AIC32X4_REG(0, 86)
#define AIC32X4_LAGC3 88 #define AIC32X4_LAGC2 AIC32X4_REG(0, 87)
#define AIC32X4_LAGC4 89 #define AIC32X4_LAGC3 AIC32X4_REG(0, 88)
#define AIC32X4_LAGC5 90 #define AIC32X4_LAGC4 AIC32X4_REG(0, 89)
#define AIC32X4_LAGC6 91 #define AIC32X4_LAGC5 AIC32X4_REG(0, 90)
#define AIC32X4_LAGC7 92 #define AIC32X4_LAGC6 AIC32X4_REG(0, 91)
#define AIC32X4_RAGC1 94 #define AIC32X4_LAGC7 AIC32X4_REG(0, 92)
#define AIC32X4_RAGC2 95 #define AIC32X4_RAGC1 AIC32X4_REG(0, 94)
#define AIC32X4_RAGC3 96 #define AIC32X4_RAGC2 AIC32X4_REG(0, 95)
#define AIC32X4_RAGC4 97 #define AIC32X4_RAGC3 AIC32X4_REG(0, 96)
#define AIC32X4_RAGC5 98 #define AIC32X4_RAGC4 AIC32X4_REG(0, 97)
#define AIC32X4_RAGC6 99 #define AIC32X4_RAGC5 AIC32X4_REG(0, 98)
#define AIC32X4_RAGC7 100 #define AIC32X4_RAGC6 AIC32X4_REG(0, 99)
#define AIC32X4_PWRCFG (AIC32X4_PAGE1 + 1) #define AIC32X4_RAGC7 AIC32X4_REG(0, 100)
#define AIC32X4_LDOCTL (AIC32X4_PAGE1 + 2)
#define AIC32X4_OUTPWRCTL (AIC32X4_PAGE1 + 9) #define AIC32X4_PWRCFG AIC32X4_REG(1, 1)
#define AIC32X4_CMMODE (AIC32X4_PAGE1 + 10) #define AIC32X4_LDOCTL AIC32X4_REG(1, 2)
#define AIC32X4_HPLROUTE (AIC32X4_PAGE1 + 12) #define AIC32X4_OUTPWRCTL AIC32X4_REG(1, 9)
#define AIC32X4_HPRROUTE (AIC32X4_PAGE1 + 13) #define AIC32X4_CMMODE AIC32X4_REG(1, 10)
#define AIC32X4_LOLROUTE (AIC32X4_PAGE1 + 14) #define AIC32X4_HPLROUTE AIC32X4_REG(1, 12)
#define AIC32X4_LORROUTE (AIC32X4_PAGE1 + 15) #define AIC32X4_HPRROUTE AIC32X4_REG(1, 13)
#define AIC32X4_HPLGAIN (AIC32X4_PAGE1 + 16) #define AIC32X4_LOLROUTE AIC32X4_REG(1, 14)
#define AIC32X4_HPRGAIN (AIC32X4_PAGE1 + 17) #define AIC32X4_LORROUTE AIC32X4_REG(1, 15)
#define AIC32X4_LOLGAIN (AIC32X4_PAGE1 + 18) #define AIC32X4_HPLGAIN AIC32X4_REG(1, 16)
#define AIC32X4_LORGAIN (AIC32X4_PAGE1 + 19) #define AIC32X4_HPRGAIN AIC32X4_REG(1, 17)
#define AIC32X4_HEADSTART (AIC32X4_PAGE1 + 20) #define AIC32X4_LOLGAIN AIC32X4_REG(1, 18)
#define AIC32X4_MICBIAS (AIC32X4_PAGE1 + 51) #define AIC32X4_LORGAIN AIC32X4_REG(1, 19)
#define AIC32X4_LMICPGAPIN (AIC32X4_PAGE1 + 52) #define AIC32X4_HEADSTART AIC32X4_REG(1, 20)
#define AIC32X4_LMICPGANIN (AIC32X4_PAGE1 + 54) #define AIC32X4_MICBIAS AIC32X4_REG(1, 51)
#define AIC32X4_RMICPGAPIN (AIC32X4_PAGE1 + 55) #define AIC32X4_LMICPGAPIN AIC32X4_REG(1, 52)
#define AIC32X4_RMICPGANIN (AIC32X4_PAGE1 + 57) #define AIC32X4_LMICPGANIN AIC32X4_REG(1, 54)
#define AIC32X4_FLOATINGINPUT (AIC32X4_PAGE1 + 58) #define AIC32X4_RMICPGAPIN AIC32X4_REG(1, 55)
#define AIC32X4_LMICPGAVOL (AIC32X4_PAGE1 + 59) #define AIC32X4_RMICPGANIN AIC32X4_REG(1, 57)
#define AIC32X4_RMICPGAVOL (AIC32X4_PAGE1 + 60) #define AIC32X4_FLOATINGINPUT AIC32X4_REG(1, 58)
#define AIC32X4_LMICPGAVOL AIC32X4_REG(1, 59)
#define AIC32X4_FREQ_12000000 12000000 #define AIC32X4_RMICPGAVOL AIC32X4_REG(1, 60)
#define AIC32X4_FREQ_24000000 24000000
#define AIC32X4_FREQ_25000000 25000000 /* Bits, masks, and shifts */
#define AIC32X4_WORD_LEN_16BITS 0x00 /* AIC32X4_CLKMUX */
#define AIC32X4_WORD_LEN_20BITS 0x01 #define AIC32X4_PLL_CLKIN_MASK GENMASK(3, 2)
#define AIC32X4_WORD_LEN_24BITS 0x02 #define AIC32X4_PLL_CLKIN_SHIFT (2)
#define AIC32X4_WORD_LEN_32BITS 0x03 #define AIC32X4_PLL_CLKIN_MCLK (0x00)
#define AIC32X4_PLL_CLKIN_BCKL (0x01)
#define AIC32X4_LADC_EN (1 << 7) #define AIC32X4_PLL_CLKIN_GPIO1 (0x02)
#define AIC32X4_RADC_EN (1 << 6) #define AIC32X4_PLL_CLKIN_DIN (0x03)
#define AIC32X4_CODEC_CLKIN_MASK GENMASK(1, 0)
#define AIC32X4_I2S_MODE 0x00 #define AIC32X4_CODEC_CLKIN_SHIFT (0)
#define AIC32X4_DSP_MODE 0x01 #define AIC32X4_CODEC_CLKIN_MCLK (0x00)
#define AIC32X4_RIGHT_JUSTIFIED_MODE 0x02 #define AIC32X4_CODEC_CLKIN_BCLK (0x01)
#define AIC32X4_LEFT_JUSTIFIED_MODE 0x03 #define AIC32X4_CODEC_CLKIN_GPIO1 (0x02)
#define AIC32X4_CODEC_CLKIN_PLL (0x03)
#define AIC32X4_AVDDWEAKDISABLE 0x08
#define AIC32X4_LDOCTLEN 0x01 /* AIC32X4_PLLPR */
#define AIC32X4_PLLEN BIT(7)
#define AIC32X4_LDOIN_18_36 0x01 #define AIC32X4_PLL_P_MASK GENMASK(6, 4)
#define AIC32X4_LDOIN2HP 0x02 #define AIC32X4_PLL_P_SHIFT (4)
#define AIC32X4_PLL_R_MASK GENMASK(3, 0)
#define AIC32X4_DACSPBLOCK_MASK 0x1f
#define AIC32X4_ADCSPBLOCK_MASK 0x1f /* AIC32X4_NDAC */
#define AIC32X4_NDACEN BIT(7)
#define AIC32X4_PLLJ_SHIFT 6 #define AIC32X4_NDAC_MASK GENMASK(6, 0)
#define AIC32X4_DOSRMSB_SHIFT 4
/* AIC32X4_MDAC */
#define AIC32X4_PLLCLKIN 0x03 #define AIC32X4_MDACEN BIT(7)
#define AIC32X4_MDAC_MASK GENMASK(6, 0)
#define AIC32X4_MICBIAS_LDOIN 0x08
/* AIC32X4_NADC */
#define AIC32X4_NADCEN BIT(7)
#define AIC32X4_NADC_MASK GENMASK(6, 0)
/* AIC32X4_MADC */
#define AIC32X4_MADCEN BIT(7)
#define AIC32X4_MADC_MASK GENMASK(6, 0)
/* AIC32X4_BCLKN */
#define AIC32X4_BCLKEN BIT(7)
#define AIC32X4_BCLK_MASK GENMASK(6, 0)
/* AIC32X4_IFACE1 */
#define AIC32X4_IFACE1_DATATYPE_MASK GENMASK(7, 6)
#define AIC32X4_IFACE1_DATATYPE_SHIFT (6)
#define AIC32X4_I2S_MODE (0x00)
#define AIC32X4_DSP_MODE (0x01)
#define AIC32X4_RIGHT_JUSTIFIED_MODE (0x02)
#define AIC32X4_LEFT_JUSTIFIED_MODE (0x03)
#define AIC32X4_IFACE1_DATALEN_MASK GENMASK(5, 4)
#define AIC32X4_IFACE1_DATALEN_SHIFT (4)
#define AIC32X4_WORD_LEN_16BITS (0x00)
#define AIC32X4_WORD_LEN_20BITS (0x01)
#define AIC32X4_WORD_LEN_24BITS (0x02)
#define AIC32X4_WORD_LEN_32BITS (0x03)
#define AIC32X4_IFACE1_MASTER_MASK GENMASK(3, 2)
#define AIC32X4_BCLKMASTER BIT(2)
#define AIC32X4_WCLKMASTER BIT(3)
/* AIC32X4_IFACE2 */
#define AIC32X4_DATA_OFFSET_MASK GENMASK(7, 0)
/* AIC32X4_IFACE3 */
#define AIC32X4_BCLKINV_MASK BIT(3)
#define AIC32X4_BDIVCLK_MASK GENMASK(1, 0)
#define AIC32X4_BDIVCLK_SHIFT (0)
#define AIC32X4_DAC2BCLK (0x00)
#define AIC32X4_DACMOD2BCLK (0x01)
#define AIC32X4_ADC2BCLK (0x02)
#define AIC32X4_ADCMOD2BCLK (0x03)
/* AIC32X4_DACSETUP */
#define AIC32X4_DAC_CHAN_MASK GENMASK(5, 2)
#define AIC32X4_LDAC2RCHN BIT(5)
#define AIC32X4_LDAC2LCHN BIT(4)
#define AIC32X4_RDAC2LCHN BIT(3)
#define AIC32X4_RDAC2RCHN BIT(2)
/* AIC32X4_DACMUTE */
#define AIC32X4_MUTEON 0x0C
/* AIC32X4_ADCSETUP */
#define AIC32X4_LADC_EN BIT(7)
#define AIC32X4_RADC_EN BIT(6)
/* AIC32X4_PWRCFG */
#define AIC32X4_AVDDWEAKDISABLE BIT(3)
/* AIC32X4_LDOCTL */
#define AIC32X4_LDOCTLEN BIT(0)
/* AIC32X4_CMMODE */
#define AIC32X4_LDOIN_18_36 BIT(0)
#define AIC32X4_LDOIN2HP BIT(1)
/* AIC32X4_MICBIAS */
#define AIC32X4_MICBIAS_LDOIN BIT(3)
#define AIC32X4_MICBIAS_2075V 0x60 #define AIC32X4_MICBIAS_2075V 0x60
/* AIC32X4_LMICPGANIN */
#define AIC32X4_LMICPGANIN_IN2R_10K 0x10 #define AIC32X4_LMICPGANIN_IN2R_10K 0x10
#define AIC32X4_LMICPGANIN_CM1L_10K 0x40 #define AIC32X4_LMICPGANIN_CM1L_10K 0x40
/* AIC32X4_RMICPGANIN */
#define AIC32X4_RMICPGANIN_IN1L_10K 0x10 #define AIC32X4_RMICPGANIN_IN1L_10K 0x10
#define AIC32X4_RMICPGANIN_CM1R_10K 0x40 #define AIC32X4_RMICPGANIN_CM1R_10K 0x40
#define AIC32X4_LMICPGAVOL_NOGAIN 0x80
#define AIC32X4_RMICPGAVOL_NOGAIN 0x80
#define AIC32X4_BCLKMASTER 0x08
#define AIC32X4_WCLKMASTER 0x04
#define AIC32X4_PLLEN (0x01 << 7)
#define AIC32X4_NDACEN (0x01 << 7)
#define AIC32X4_MDACEN (0x01 << 7)
#define AIC32X4_NADCEN (0x01 << 7)
#define AIC32X4_MADCEN (0x01 << 7)
#define AIC32X4_BCLKEN (0x01 << 7)
#define AIC32X4_DACEN (0x03 << 6)
#define AIC32X4_RDAC2LCHN (0x02 << 2)
#define AIC32X4_LDAC2RCHN (0x02 << 4)
#define AIC32X4_LDAC2LCHN (0x01 << 4)
#define AIC32X4_RDAC2RCHN (0x01 << 2)
#define AIC32X4_DAC_CHAN_MASK 0x3c
#define AIC32X4_SSTEP2WCLK 0x01
#define AIC32X4_MUTEON 0x0C
#define AIC32X4_DACMOD2BCLK 0x01
#endif /* _TLV320AIC32X4_H */ #endif /* _TLV320AIC32X4_H */
...@@ -1804,11 +1804,18 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, ...@@ -1804,11 +1804,18 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
if (!ai3x_setup) if (!ai3x_setup)
return -ENOMEM; return -ENOMEM;
ret = of_get_named_gpio(np, "reset-gpios", 0);
if (ret >= 0) {
aic3x->gpio_reset = ret;
} else {
ret = of_get_named_gpio(np, "gpio-reset", 0); ret = of_get_named_gpio(np, "gpio-reset", 0);
if (ret >= 0) if (ret > 0) {
dev_warn(&i2c->dev, "Using deprecated property \"gpio-reset\", please update your DT");
aic3x->gpio_reset = ret; aic3x->gpio_reset = ret;
else } else {
aic3x->gpio_reset = -1; aic3x->gpio_reset = -1;
}
}
if (of_property_read_u32_array(np, "ai3x-gpio-func", if (of_property_read_u32_array(np, "ai3x-gpio-func",
ai3x_setup->gpio_func, 2) >= 0) { ai3x_setup->gpio_func, 2) >= 0) {
......
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