ASoC: Updates for v5.2

This is a pretty huge set of changes, it's been a pretty active release
all round but the big thing with this release is the Sound Open Firmware
changes from Intel, providing another DSP framework for use with the
DSPs in their SoCs.  This one works with the firmware of the same name
which is free software (unlike the previous DSP firmwares and framework)
and there has been some interest in adoption by other systems already so
hopefully we will see adoption by other vendors in the future.

Other highlights include:

 - Support for MCLK/sample rate ratio setting in the generic cards.
 - Support for pin switches in the generic cards.
 - A big set of improvements to the TLV320AIC32x4 drivers from Annaliese
   McDermond.
 - New drivers for Freescale audio mixers, several Intel machines,
   several Mediatek machines, Meson G12A, Sound Open Firmware and
   Spreadtrum compressed audio and DMA devices.
This commit is contained in:
Takashi Iwai
2019-05-06 16:14:09 +02:00
1973 changed files with 50897 additions and 17679 deletions

View File

@@ -94,6 +94,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_JZ4725B_CODEC
select SND_SOC_LM4857 if I2C
select SND_SOC_LM49453 if I2C
select SND_SOC_LOCHNAGAR_SC if MFD_LOCHNAGAR
select SND_SOC_MAX98088 if I2C
select SND_SOC_MAX98090 if I2C
select SND_SOC_MAX98095 if I2C
@@ -179,8 +180,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
select SND_SOC_TLV320AIC26 if SPI_MASTER
select SND_SOC_TLV320AIC31XX if I2C
select SND_SOC_TLV320AIC32X4_I2C if I2C
select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER
select SND_SOC_TLV320AIC32X4_I2C if I2C && COMMON_CLK
select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER && COMMON_CLK
select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TPA6130A2 if I2C
select SND_SOC_TLV320DAC33 if I2C
@@ -688,6 +689,13 @@ config SND_SOC_ISABELLE
config SND_SOC_LM49453
tristate
config SND_SOC_LOCHNAGAR_SC
tristate "Lochnagar Sound Card"
depends on MFD_LOCHNAGAR
help
This driver support the sound card functionality of the Cirrus
Logic Lochnagar audio development board.
config SND_SOC_MAX98088
tristate "Maxim MAX98088/9 Low-Power, Stereo Audio Codec"
depends on I2C
@@ -1097,15 +1105,18 @@ config SND_SOC_TLV320AIC31XX
config SND_SOC_TLV320AIC32X4
tristate
depends on COMMON_CLK
config SND_SOC_TLV320AIC32X4_I2C
tristate "Texas Instruments TLV320AIC32x4 audio CODECs - I2C"
depends on I2C
depends on COMMON_CLK
select SND_SOC_TLV320AIC32X4
config SND_SOC_TLV320AIC32X4_SPI
tristate "Texas Instruments TLV320AIC32x4 audio CODECs - SPI"
depends on SPI_MASTER
depends on COMMON_CLK
select SND_SOC_TLV320AIC32X4
config SND_SOC_TLV320AIC3X

View File

@@ -91,6 +91,7 @@ snd-soc-jz4725b-codec-objs := jz4725b.o
snd-soc-l3-objs := l3.o
snd-soc-lm4857-objs := lm4857.o
snd-soc-lm49453-objs := lm49453.o
snd-soc-lochnagar-sc-objs := lochnagar-sc.o
snd-soc-max9759-objs := max9759.o
snd-soc-max9768-objs := max9768.o
snd-soc-max98088-objs := max98088.o
@@ -192,7 +193,7 @@ snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o tlv320aic32x4-clk.o
snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
@@ -364,6 +365,7 @@ obj-$(CONFIG_SND_SOC_JZ4725B_CODEC) += snd-soc-jz4725b-codec.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o
obj-$(CONFIG_SND_SOC_LOCHNAGAR_SC) += snd-soc-lochnagar-sc.o
obj-$(CONFIG_SND_SOC_MAX9759) += snd-soc-max9759.o
obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o
obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o

View File

@@ -29,18 +29,27 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c,
struct regmap_config config;
config = cs42l51_regmap;
config.val_bits = 8;
config.reg_bits = 8;
return cs42l51_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &config));
}
static int cs42l51_i2c_remove(struct i2c_client *i2c)
{
return cs42l51_remove(&i2c->dev);
}
static const struct dev_pm_ops cs42l51_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(cs42l51_suspend, cs42l51_resume)
};
static struct i2c_driver cs42l51_i2c_driver = {
.driver = {
.name = "cs42l51",
.of_match_table = cs42l51_of_match,
.pm = &cs42l51_pm_ops,
},
.probe = cs42l51_i2c_probe,
.remove = cs42l51_i2c_remove,
.id_table = cs42l51_i2c_id,
};

View File

@@ -30,7 +30,9 @@
#include <sound/initval.h>
#include <sound/pcm_params.h>
#include <sound/pcm.h>
#include <linux/gpio/consumer.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include "cs42l51.h"
@@ -40,11 +42,21 @@ enum master_slave_mode {
MODE_MASTER,
};
static const char * const cs42l51_supply_names[] = {
"VL",
"VD",
"VA",
"VAHP",
};
struct cs42l51_private {
unsigned int mclk;
struct clk *mclk_handle;
unsigned int audio_mode; /* The mode (I2S or left-justified) */
enum master_slave_mode func;
struct regulator_bulk_data supplies[ARRAY_SIZE(cs42l51_supply_names)];
struct gpio_desc *reset_gpio;
struct regmap *regmap;
};
#define CS42L51_FORMATS ( \
@@ -111,6 +123,7 @@ static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
static const DECLARE_TLV_DB_SCALE(aout_tlv, -10200, 50, 0);
static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
static const DECLARE_TLV_DB_SCALE(adc_boost_tlv, 2000, 2000, 0);
static const char *chan_mix[] = {
"L R",
"L+R",
@@ -139,6 +152,8 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
SOC_DOUBLE_TLV("Mic Boost Volume",
CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
SOC_DOUBLE_TLV("ADC Boost Volume",
CS42L51_MIC_CTL, 5, 6, 1, 0, adc_boost_tlv),
SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
SOC_ENUM_EXT("PCM channel mixer",
@@ -195,7 +210,8 @@ static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
SND_SOC_DAPM_SUPPLY("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1, NULL,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
@@ -329,6 +345,19 @@ static struct cs42l51_ratios slave_auto_ratios[] = {
{ 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 },
};
/*
* Master mode mclk/fs ratios.
* Recommended configurations are SSM for 4-50khz and DSM for 50-100kHz ranges
* The table below provides support of following ratios:
* 128: SSM (%128) with div2 disabled
* 256: SSM (%128) with div2 enabled
* In both cases, if sampling rate is above 50kHz, SSM is overridden
* with DSM (%128) configuration
*/
static struct cs42l51_ratios master_ratios[] = {
{ 128, CS42L51_SSM_MODE, 0 }, { 256, CS42L51_SSM_MODE, 1 },
};
static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
@@ -351,11 +380,13 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
unsigned int ratio;
struct cs42l51_ratios *ratios = NULL;
int nr_ratios = 0;
int intf_ctl, power_ctl, fmt;
int intf_ctl, power_ctl, fmt, mode;
switch (cs42l51->func) {
case MODE_MASTER:
return -EINVAL;
ratios = master_ratios;
nr_ratios = ARRAY_SIZE(master_ratios);
break;
case MODE_SLAVE:
ratios = slave_ratios;
nr_ratios = ARRAY_SIZE(slave_ratios);
@@ -391,7 +422,16 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
switch (cs42l51->func) {
case MODE_MASTER:
intf_ctl |= CS42L51_INTF_CTL_MASTER;
power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
mode = ratios[i].speed_mode;
/* Force DSM mode if sampling rate is above 50kHz */
if (rate > 50000)
mode = CS42L51_DSM_MODE;
power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(mode);
/*
* Auto detect mode is not applicable for master mode and has to
* be disabled. Otherwise SPEED[1:0] bits will be ignored.
*/
power_ctl &= ~CS42L51_MIC_POWER_CTL_AUTO;
break;
case MODE_SLAVE:
power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
@@ -464,6 +504,13 @@ static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
return snd_soc_component_write(component, CS42L51_DAC_OUT_CTL, reg);
}
static int cs42l51_of_xlate_dai_id(struct snd_soc_component *component,
struct device_node *endpoint)
{
/* return dai id 0, whatever the endpoint index */
return 0;
}
static const struct snd_soc_dai_ops cs42l51_dai_ops = {
.hw_params = cs42l51_hw_params,
.set_sysclk = cs42l51_set_dai_sysclk,
@@ -526,13 +573,113 @@ static const struct snd_soc_component_driver soc_component_device_cs42l51 = {
.num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets),
.dapm_routes = cs42l51_routes,
.num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
.of_xlate_dai_id = cs42l51_of_xlate_dai_id,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static bool cs42l51_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case CS42L51_POWER_CTL1:
case CS42L51_MIC_POWER_CTL:
case CS42L51_INTF_CTL:
case CS42L51_MIC_CTL:
case CS42L51_ADC_CTL:
case CS42L51_ADC_INPUT:
case CS42L51_DAC_OUT_CTL:
case CS42L51_DAC_CTL:
case CS42L51_ALC_PGA_CTL:
case CS42L51_ALC_PGB_CTL:
case CS42L51_ADCA_ATT:
case CS42L51_ADCB_ATT:
case CS42L51_ADCA_VOL:
case CS42L51_ADCB_VOL:
case CS42L51_PCMA_VOL:
case CS42L51_PCMB_VOL:
case CS42L51_BEEP_FREQ:
case CS42L51_BEEP_VOL:
case CS42L51_BEEP_CONF:
case CS42L51_TONE_CTL:
case CS42L51_AOUTA_VOL:
case CS42L51_AOUTB_VOL:
case CS42L51_PCM_MIXER:
case CS42L51_LIMIT_THRES_DIS:
case CS42L51_LIMIT_REL:
case CS42L51_LIMIT_ATT:
case CS42L51_ALC_EN:
case CS42L51_ALC_REL:
case CS42L51_ALC_THRES:
case CS42L51_NOISE_CONF:
case CS42L51_CHARGE_FREQ:
return true;
default:
return false;
}
}
static bool cs42l51_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case CS42L51_STATUS:
return true;
default:
return false;
}
}
static bool cs42l51_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case CS42L51_CHIP_REV_ID:
case CS42L51_POWER_CTL1:
case CS42L51_MIC_POWER_CTL:
case CS42L51_INTF_CTL:
case CS42L51_MIC_CTL:
case CS42L51_ADC_CTL:
case CS42L51_ADC_INPUT:
case CS42L51_DAC_OUT_CTL:
case CS42L51_DAC_CTL:
case CS42L51_ALC_PGA_CTL:
case CS42L51_ALC_PGB_CTL:
case CS42L51_ADCA_ATT:
case CS42L51_ADCB_ATT:
case CS42L51_ADCA_VOL:
case CS42L51_ADCB_VOL:
case CS42L51_PCMA_VOL:
case CS42L51_PCMB_VOL:
case CS42L51_BEEP_FREQ:
case CS42L51_BEEP_VOL:
case CS42L51_BEEP_CONF:
case CS42L51_TONE_CTL:
case CS42L51_AOUTA_VOL:
case CS42L51_AOUTB_VOL:
case CS42L51_PCM_MIXER:
case CS42L51_LIMIT_THRES_DIS:
case CS42L51_LIMIT_REL:
case CS42L51_LIMIT_ATT:
case CS42L51_ALC_EN:
case CS42L51_ALC_REL:
case CS42L51_ALC_THRES:
case CS42L51_NOISE_CONF:
case CS42L51_STATUS:
case CS42L51_CHARGE_FREQ:
return true;
default:
return false;
}
}
const struct regmap_config cs42l51_regmap = {
.reg_bits = 8,
.reg_stride = 1,
.val_bits = 8,
.use_single_write = true,
.readable_reg = cs42l51_readable_reg,
.volatile_reg = cs42l51_volatile_reg,
.writeable_reg = cs42l51_writeable_reg,
.max_register = CS42L51_CHARGE_FREQ,
.cache_type = REGCACHE_RBTREE,
};
@@ -542,7 +689,7 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
{
struct cs42l51_private *cs42l51;
unsigned int val;
int ret;
int ret, i;
if (IS_ERR(regmap))
return PTR_ERR(regmap);
@@ -553,6 +700,7 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
return -ENOMEM;
dev_set_drvdata(dev, cs42l51);
cs42l51->regmap = regmap;
cs42l51->mclk_handle = devm_clk_get(dev, "MCLK");
if (IS_ERR(cs42l51->mclk_handle)) {
@@ -561,6 +709,34 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
cs42l51->mclk_handle = NULL;
}
for (i = 0; i < ARRAY_SIZE(cs42l51->supplies); i++)
cs42l51->supplies[i].supply = cs42l51_supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs42l51->supplies),
cs42l51->supplies);
if (ret != 0) {
dev_err(dev, "Failed to request supplies: %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(cs42l51->supplies),
cs42l51->supplies);
if (ret != 0) {
dev_err(dev, "Failed to enable supplies: %d\n", ret);
return ret;
}
cs42l51->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(cs42l51->reset_gpio))
return PTR_ERR(cs42l51->reset_gpio);
if (cs42l51->reset_gpio) {
dev_dbg(dev, "Release reset gpio\n");
gpiod_set_value_cansleep(cs42l51->reset_gpio, 0);
mdelay(2);
}
/* Verify that we have a CS42L51 */
ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val);
if (ret < 0) {
@@ -579,11 +755,50 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap)
ret = devm_snd_soc_register_component(dev,
&soc_component_device_cs42l51, &cs42l51_dai, 1);
if (ret < 0)
goto error;
return 0;
error:
regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies),
cs42l51->supplies);
return ret;
}
EXPORT_SYMBOL_GPL(cs42l51_probe);
int cs42l51_remove(struct device *dev)
{
struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
gpiod_set_value_cansleep(cs42l51->reset_gpio, 1);
return regulator_bulk_disable(ARRAY_SIZE(cs42l51->supplies),
cs42l51->supplies);
}
EXPORT_SYMBOL_GPL(cs42l51_remove);
int __maybe_unused cs42l51_suspend(struct device *dev)
{
struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
regcache_cache_only(cs42l51->regmap, true);
regcache_mark_dirty(cs42l51->regmap);
return 0;
}
EXPORT_SYMBOL_GPL(cs42l51_suspend);
int __maybe_unused cs42l51_resume(struct device *dev)
{
struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
regcache_cache_only(cs42l51->regmap, false);
return regcache_sync(cs42l51->regmap);
}
EXPORT_SYMBOL_GPL(cs42l51_resume);
const struct of_device_id cs42l51_of_match[] = {
{ .compatible = "cirrus,cs42l51", },
{ }

View File

@@ -22,6 +22,9 @@ struct device;
extern const struct regmap_config cs42l51_regmap;
int cs42l51_probe(struct device *dev, struct regmap *regmap);
int cs42l51_remove(struct device *dev);
int __maybe_unused cs42l51_suspend(struct device *dev);
int __maybe_unused cs42l51_resume(struct device *dev);
extern const struct of_device_id cs42l51_of_match[];
#define CS42L51_CHIP_ID 0x1B

View File

@@ -2322,6 +2322,8 @@ static int cs43130_probe(struct snd_soc_component *component)
return ret;
cs43130->wq = create_singlethread_workqueue("cs43130_hp");
if (!cs43130->wq)
return -ENOMEM;
INIT_WORK(&cs43130->work, cs43130_imp_meas);
}

View File

@@ -75,7 +75,9 @@ static int cs47l24_adsp_power_ev(struct snd_soc_dapm_widget *w,
v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
return wm_adsp2_early_event(w, kcontrol, event, v);
wm_adsp2_set_dspclk(w, v);
return wm_adsp_early_event(w, kcontrol, event);
}
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);

View File

@@ -1305,7 +1305,10 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
/* By default only 64 BCLK per WCLK is supported */
dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_64;
snd_soc_component_write(component, DA7213_DAI_CLK_MODE, dai_clk_mode);
snd_soc_component_update_bits(component, DA7213_DAI_CLK_MODE,
DA7213_DAI_BCLKS_PER_WCLK_MASK |
DA7213_DAI_CLK_POL_MASK | DA7213_DAI_WCLK_POL_MASK,
dai_clk_mode);
snd_soc_component_update_bits(component, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK,
dai_ctrl);
snd_soc_component_write(component, DA7213_DAI_OFFSET, dai_offset);

View File

@@ -181,7 +181,9 @@
#define DA7213_DAI_BCLKS_PER_WCLK_256 (0x3 << 0)
#define DA7213_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0)
#define DA7213_DAI_CLK_POL_INV (0x1 << 2)
#define DA7213_DAI_CLK_POL_MASK (0x1 << 2)
#define DA7213_DAI_WCLK_POL_INV (0x1 << 3)
#define DA7213_DAI_WCLK_POL_MASK (0x1 << 3)
#define DA7213_DAI_CLK_EN_MASK (0x1 << 7)
/* DA7213_DAI_CTRL = 0x29 */

View File

@@ -797,6 +797,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX];
u8 pll_ctrl, pll_status;
int i = 0, ret;
bool srm_lock = false;
@@ -805,11 +806,11 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_PRE_PMU:
if (da7219->master) {
/* Enable DAI clks for master mode */
if (da7219->dai_clks) {
ret = clk_prepare_enable(da7219->dai_clks);
if (bclk) {
ret = clk_prepare_enable(bclk);
if (ret) {
dev_err(component->dev,
"Failed to enable dai_clks\n");
"Failed to enable DAI clks\n");
return ret;
}
} else {
@@ -852,8 +853,8 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w,
/* Disable DAI clks if in master mode */
if (da7219->master) {
if (da7219->dai_clks)
clk_disable_unprepare(da7219->dai_clks);
if (bclk)
clk_disable_unprepare(bclk);
else
snd_soc_component_update_bits(component,
DA7219_DAI_CLK_MODE,
@@ -1385,17 +1386,50 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return 0;
}
static int da7219_set_bclks_per_wclk(struct snd_soc_component *component,
unsigned long factor)
{
u8 bclks_per_wclk;
switch (factor) {
case 32:
bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
break;
case 64:
bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64;
break;
case 128:
bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128;
break;
case 256:
bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256;
break;
default:
return -EINVAL;
}
snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
DA7219_DAI_BCLKS_PER_WCLK_MASK,
bclks_per_wclk);
return 0;
}
static int da7219_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_component *component = dai->component;
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
struct clk *wclk = da7219->dai_clks[DA7219_DAI_WCLK_IDX];
struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX];
unsigned int ch_mask;
u8 dai_bclks_per_wclk, slot_offset;
unsigned long sr, bclk_rate;
u8 slot_offset;
u16 offset;
__le16 dai_offset;
u32 frame_size;
int ret;
/* No channels enabled so disable TDM */
if (!tx_mask) {
@@ -1432,28 +1466,26 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
*/
if (da7219->master) {
frame_size = slots * slot_width;
switch (frame_size) {
case 32:
dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
break;
case 64:
dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64;
break;
case 128:
dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128;
break;
case 256:
dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256;
break;
default:
dev_err(component->dev, "Invalid frame size %d\n",
frame_size);
return -EINVAL;
}
snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
DA7219_DAI_BCLKS_PER_WCLK_MASK,
dai_bclks_per_wclk);
if (bclk) {
sr = clk_get_rate(wclk);
bclk_rate = sr * frame_size;
ret = clk_set_rate(bclk, bclk_rate);
if (ret) {
dev_err(component->dev,
"Failed to set TDM BCLK rate %lu: %d\n",
bclk_rate, ret);
return ret;
}
} else {
ret = da7219_set_bclks_per_wclk(component, frame_size);
if (ret) {
dev_err(component->dev,
"Failed to set TDM BCLKs per WCLK %d: %d\n",
frame_size, ret);
return ret;
}
}
}
dai_offset = cpu_to_le16(offset);
@@ -1471,44 +1503,12 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
static int da7219_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
static int da7219_set_sr(struct snd_soc_component *component,
unsigned long rate)
{
struct snd_soc_component *component = dai->component;
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
u8 dai_ctrl = 0, dai_bclks_per_wclk = 0, fs;
unsigned int channels;
int word_len = params_width(params);
int frame_size;
u8 fs;
switch (word_len) {
case 16:
dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE;
break;
case 20:
dai_ctrl |= DA7219_DAI_WORD_LENGTH_S20_LE;
break;
case 24:
dai_ctrl |= DA7219_DAI_WORD_LENGTH_S24_LE;
break;
case 32:
dai_ctrl |= DA7219_DAI_WORD_LENGTH_S32_LE;
break;
default:
return -EINVAL;
}
channels = params_channels(params);
if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) {
dev_err(component->dev,
"Invalid number of channels, only 1 to %d supported\n",
DA7219_DAI_CH_NUM_MAX);
return -EINVAL;
}
dai_ctrl |= channels << DA7219_DAI_CH_NUM_SHIFT;
switch (params_rate(params)) {
switch (rate) {
case 8000:
fs = DA7219_SR_8000;
break;
@@ -1546,28 +1546,118 @@ static int da7219_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
snd_soc_component_write(component, DA7219_SR, fs);
return 0;
}
static int da7219_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
struct clk *wclk = da7219->dai_clks[DA7219_DAI_WCLK_IDX];
struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX];
u8 dai_ctrl = 0;
unsigned int channels;
unsigned long sr, bclk_rate;
int word_len = params_width(params);
int frame_size, ret;
switch (word_len) {
case 16:
dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE;
break;
case 20:
dai_ctrl |= DA7219_DAI_WORD_LENGTH_S20_LE;
break;
case 24:
dai_ctrl |= DA7219_DAI_WORD_LENGTH_S24_LE;
break;
case 32:
dai_ctrl |= DA7219_DAI_WORD_LENGTH_S32_LE;
break;
default:
return -EINVAL;
}
channels = params_channels(params);
if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) {
dev_err(component->dev,
"Invalid number of channels, only 1 to %d supported\n",
DA7219_DAI_CH_NUM_MAX);
return -EINVAL;
}
dai_ctrl |= channels << DA7219_DAI_CH_NUM_SHIFT;
sr = params_rate(params);
if (da7219->master && wclk) {
ret = clk_set_rate(wclk, sr);
if (ret) {
dev_err(component->dev,
"Failed to set WCLK SR %lu: %d\n", sr, ret);
return ret;
}
} else {
ret = da7219_set_sr(component, sr);
if (ret) {
dev_err(component->dev,
"Failed to set SR %lu: %d\n", sr, ret);
return ret;
}
}
/*
* If we're master, then we have a limited set of BCLK rates we
* support. For slave mode this isn't the case and the codec can detect
* the BCLK rate automatically.
*/
if (da7219->master && !da7219->tdm_en) {
frame_size = word_len * 2;
if (frame_size <= 32)
dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
if ((word_len * DA7219_DAI_CH_NUM_MAX) <= 32)
frame_size = 32;
else
dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64;
frame_size = 64;
snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
DA7219_DAI_BCLKS_PER_WCLK_MASK,
dai_bclks_per_wclk);
if (bclk) {
bclk_rate = frame_size * sr;
/*
* Rounding the rate here avoids failure trying to set a
* new rate on an already enabled bclk. In that
* instance this will just set the same rate as is
* currently in use, and so should continue without
* problem, as long as the BCLK rate is suitable for the
* desired frame size.
*/
bclk_rate = clk_round_rate(bclk, bclk_rate);
if ((bclk_rate / sr) < frame_size) {
dev_err(component->dev,
"BCLK rate mismatch against frame size");
return -EINVAL;
}
ret = clk_set_rate(bclk, bclk_rate);
if (ret) {
dev_err(component->dev,
"Failed to set BCLK rate %lu: %d\n",
bclk_rate, ret);
return ret;
}
} else {
ret = da7219_set_bclks_per_wclk(component, frame_size);
if (ret) {
dev_err(component->dev,
"Failed to set BCLKs per WCLK %d: %d\n",
frame_size, ret);
return ret;
}
}
}
snd_soc_component_update_bits(component, DA7219_DAI_CTRL,
DA7219_DAI_WORD_LENGTH_MASK |
DA7219_DAI_CH_NUM_MASK,
dai_ctrl);
snd_soc_component_write(component, DA7219_SR, fs);
return 0;
}
@@ -1583,20 +1673,26 @@ static const struct snd_soc_dai_ops da7219_dai_ops = {
#define DA7219_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
#define DA7219_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
SNDRV_PCM_RATE_96000)
static struct snd_soc_dai_driver da7219_dai = {
.name = "da7219-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = DA7219_DAI_CH_NUM_MAX,
.rates = SNDRV_PCM_RATE_8000_96000,
.rates = DA7219_RATES,
.formats = DA7219_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = DA7219_DAI_CH_NUM_MAX,
.rates = SNDRV_PCM_RATE_8000_96000,
.rates = DA7219_RATES,
.formats = DA7219_FORMATS,
},
.ops = &da7219_dai_ops,
@@ -1672,11 +1768,14 @@ static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_component *compone
pdata->wakeup_source = device_property_read_bool(dev, "wakeup-source");
pdata->dai_clks_name = "da7219-dai-clks";
if (device_property_read_string(dev, "clock-output-names",
&pdata->dai_clks_name))
dev_warn(dev, "Using default clk name: %s\n",
pdata->dai_clks_name);
pdata->dai_clk_names[DA7219_DAI_WCLK_IDX] = "da7219-dai-wclk";
pdata->dai_clk_names[DA7219_DAI_BCLK_IDX] = "da7219-dai-bclk";
if (device_property_read_string_array(dev, "clock-output-names",
pdata->dai_clk_names,
DA7219_DAI_NUM_CLKS) < 0)
dev_warn(dev, "Using default DAI clk names: %s, %s\n",
pdata->dai_clk_names[DA7219_DAI_WCLK_IDX],
pdata->dai_clk_names[DA7219_DAI_BCLK_IDX]);
if (device_property_read_u32(dev, "dlg,micbias-lvl", &of_val32) >= 0)
pdata->micbias_lvl = da7219_fw_micbias_lvl(dev, of_val32);
@@ -1793,12 +1892,16 @@ static int da7219_handle_supplies(struct snd_soc_component *component)
}
#ifdef CONFIG_COMMON_CLK
static int da7219_dai_clks_prepare(struct clk_hw *hw)
static int da7219_wclk_prepare(struct clk_hw *hw)
{
struct da7219_priv *da7219 =
container_of(hw, struct da7219_priv, dai_clks_hw);
container_of(hw, struct da7219_priv,
dai_clks_hw[DA7219_DAI_WCLK_IDX]);
struct snd_soc_component *component = da7219->component;
if (!da7219->master)
return -EINVAL;
snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
DA7219_DAI_CLK_EN_MASK,
DA7219_DAI_CLK_EN_MASK);
@@ -1806,33 +1909,42 @@ static int da7219_dai_clks_prepare(struct clk_hw *hw)
return 0;
}
static void da7219_dai_clks_unprepare(struct clk_hw *hw)
static void da7219_wclk_unprepare(struct clk_hw *hw)
{
struct da7219_priv *da7219 =
container_of(hw, struct da7219_priv, dai_clks_hw);
container_of(hw, struct da7219_priv,
dai_clks_hw[DA7219_DAI_WCLK_IDX]);
struct snd_soc_component *component = da7219->component;
if (!da7219->master)
return;
snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
DA7219_DAI_CLK_EN_MASK, 0);
}
static int da7219_dai_clks_is_prepared(struct clk_hw *hw)
static int da7219_wclk_is_prepared(struct clk_hw *hw)
{
struct da7219_priv *da7219 =
container_of(hw, struct da7219_priv, dai_clks_hw);
container_of(hw, struct da7219_priv,
dai_clks_hw[DA7219_DAI_WCLK_IDX]);
struct snd_soc_component *component = da7219->component;
u8 clk_reg;
if (!da7219->master)
return -EINVAL;
clk_reg = snd_soc_component_read32(component, DA7219_DAI_CLK_MODE);
return !!(clk_reg & DA7219_DAI_CLK_EN_MASK);
}
static unsigned long da7219_dai_clks_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
static unsigned long da7219_wclk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct da7219_priv *da7219 =
container_of(hw, struct da7219_priv, dai_clks_hw);
container_of(hw, struct da7219_priv,
dai_clks_hw[DA7219_DAI_WCLK_IDX]);
struct snd_soc_component *component = da7219->component;
u8 fs = snd_soc_component_read32(component, DA7219_SR);
@@ -1864,11 +1976,148 @@ static unsigned long da7219_dai_clks_recalc_rate(struct clk_hw *hw,
}
}
static const struct clk_ops da7219_dai_clks_ops = {
.prepare = da7219_dai_clks_prepare,
.unprepare = da7219_dai_clks_unprepare,
.is_prepared = da7219_dai_clks_is_prepared,
.recalc_rate = da7219_dai_clks_recalc_rate,
static long da7219_wclk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct da7219_priv *da7219 =
container_of(hw, struct da7219_priv,
dai_clks_hw[DA7219_DAI_WCLK_IDX]);
if (!da7219->master)
return -EINVAL;
if (rate < 11025)
return 8000;
else if (rate < 12000)
return 11025;
else if (rate < 16000)
return 12000;
else if (rate < 22050)
return 16000;
else if (rate < 24000)
return 22050;
else if (rate < 32000)
return 24000;
else if (rate < 44100)
return 32000;
else if (rate < 48000)
return 44100;
else if (rate < 88200)
return 48000;
else if (rate < 96000)
return 88200;
else
return 96000;
}
static int da7219_wclk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct da7219_priv *da7219 =
container_of(hw, struct da7219_priv,
dai_clks_hw[DA7219_DAI_WCLK_IDX]);
struct snd_soc_component *component = da7219->component;
if (!da7219->master)
return -EINVAL;
return da7219_set_sr(component, rate);
}
static unsigned long da7219_bclk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct da7219_priv *da7219 =
container_of(hw, struct da7219_priv,
dai_clks_hw[DA7219_DAI_BCLK_IDX]);
struct snd_soc_component *component = da7219->component;
u8 bclks_per_wclk = snd_soc_component_read32(component,
DA7219_DAI_CLK_MODE);
switch (bclks_per_wclk & DA7219_DAI_BCLKS_PER_WCLK_MASK) {
case DA7219_DAI_BCLKS_PER_WCLK_32:
return parent_rate * 32;
case DA7219_DAI_BCLKS_PER_WCLK_64:
return parent_rate * 64;
case DA7219_DAI_BCLKS_PER_WCLK_128:
return parent_rate * 128;
case DA7219_DAI_BCLKS_PER_WCLK_256:
return parent_rate * 256;
default:
return 0;
}
}
static unsigned long da7219_bclk_get_factor(unsigned long rate,
unsigned long parent_rate)
{
unsigned long factor;
factor = rate / parent_rate;
if (factor < 64)
return 32;
else if (factor < 128)
return 64;
else if (factor < 256)
return 128;
else
return 256;
}
static long da7219_bclk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct da7219_priv *da7219 =
container_of(hw, struct da7219_priv,
dai_clks_hw[DA7219_DAI_BCLK_IDX]);
unsigned long factor;
if (!*parent_rate || !da7219->master)
return -EINVAL;
/*
* We don't allow changing the parent rate as some BCLK rates can be
* derived from multiple parent WCLK rates (BCLK rates are set as a
* multiplier of WCLK in HW). We just do some rounding down based on the
* parent WCLK rate set and find the appropriate multiplier of BCLK to
* get the rounded down BCLK value.
*/
factor = da7219_bclk_get_factor(rate, *parent_rate);
return *parent_rate * factor;
}
static int da7219_bclk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct da7219_priv *da7219 =
container_of(hw, struct da7219_priv,
dai_clks_hw[DA7219_DAI_BCLK_IDX]);
struct snd_soc_component *component = da7219->component;
unsigned long factor;
if (!da7219->master)
return -EINVAL;
factor = da7219_bclk_get_factor(rate, parent_rate);
return da7219_set_bclks_per_wclk(component, factor);
}
static const struct clk_ops da7219_dai_clk_ops[DA7219_DAI_NUM_CLKS] = {
[DA7219_DAI_WCLK_IDX] = {
.prepare = da7219_wclk_prepare,
.unprepare = da7219_wclk_unprepare,
.is_prepared = da7219_wclk_is_prepared,
.recalc_rate = da7219_wclk_recalc_rate,
.round_rate = da7219_wclk_round_rate,
.set_rate = da7219_wclk_set_rate,
},
[DA7219_DAI_BCLK_IDX] = {
.recalc_rate = da7219_bclk_recalc_rate,
.round_rate = da7219_bclk_round_rate,
.set_rate = da7219_bclk_set_rate,
},
};
static int da7219_register_dai_clks(struct snd_soc_component *component)
@@ -1876,47 +2125,81 @@ static int da7219_register_dai_clks(struct snd_soc_component *component)
struct device *dev = component->dev;
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
struct da7219_pdata *pdata = da7219->pdata;
struct clk_init_data init = {};
struct clk *dai_clks;
struct clk_lookup *dai_clks_lookup;
const char *parent_name;
int i, ret;
if (da7219->mclk) {
parent_name = __clk_get_name(da7219->mclk);
init.parent_names = &parent_name;
init.num_parents = 1;
} else {
init.parent_names = NULL;
init.num_parents = 0;
}
for (i = 0; i < DA7219_DAI_NUM_CLKS; ++i) {
struct clk_init_data init = {};
struct clk *dai_clk;
struct clk_lookup *dai_clk_lookup;
struct clk_hw *dai_clk_hw = &da7219->dai_clks_hw[i];
init.name = pdata->dai_clks_name;
init.ops = &da7219_dai_clks_ops;
init.flags = CLK_GET_RATE_NOCACHE;
da7219->dai_clks_hw.init = &init;
switch (i) {
case DA7219_DAI_WCLK_IDX:
/*
* If we can, make MCLK the parent of WCLK to ensure
* it's enabled as required.
*/
if (da7219->mclk) {
parent_name = __clk_get_name(da7219->mclk);
init.parent_names = &parent_name;
init.num_parents = 1;
} else {
init.parent_names = NULL;
init.num_parents = 0;
}
break;
case DA7219_DAI_BCLK_IDX:
/* Make WCLK the parent of BCLK */
parent_name = __clk_get_name(da7219->dai_clks[DA7219_DAI_WCLK_IDX]);
init.parent_names = &parent_name;
init.num_parents = 1;
break;
default:
dev_err(dev, "Invalid clock index\n");
ret = -EINVAL;
goto err;
}
dai_clks = devm_clk_register(dev, &da7219->dai_clks_hw);
if (IS_ERR(dai_clks)) {
dev_warn(dev, "Failed to register DAI clocks: %ld\n",
PTR_ERR(dai_clks));
return PTR_ERR(dai_clks);
}
da7219->dai_clks = dai_clks;
init.name = pdata->dai_clk_names[i];
init.ops = &da7219_dai_clk_ops[i];
init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE;
dai_clk_hw->init = &init;
/* If we're using DT, then register as provider accordingly */
if (dev->of_node) {
devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
&da7219->dai_clks_hw);
} else {
dai_clks_lookup = clkdev_create(dai_clks, pdata->dai_clks_name,
"%s", dev_name(dev));
if (!dai_clks_lookup)
return -ENOMEM;
else
da7219->dai_clks_lookup = dai_clks_lookup;
dai_clk = devm_clk_register(dev, dai_clk_hw);
if (IS_ERR(dai_clk)) {
dev_warn(dev, "Failed to register %s: %ld\n",
init.name, PTR_ERR(dai_clk));
ret = PTR_ERR(dai_clk);
goto err;
}
da7219->dai_clks[i] = dai_clk;
/* If we're using DT, then register as provider accordingly */
if (dev->of_node) {
devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
dai_clk_hw);
} else {
dai_clk_lookup = clkdev_create(dai_clk, init.name,
"%s", dev_name(dev));
if (!dai_clk_lookup) {
ret = -ENOMEM;
goto err;
} else {
da7219->dai_clks_lookup[i] = dai_clk_lookup;
}
}
}
return 0;
err:
do {
if (da7219->dai_clks_lookup[i])
clkdev_drop(da7219->dai_clks_lookup[i]);
} while (i-- > 0);
return ret;
}
#else
static inline int da7219_register_dai_clks(struct snd_soc_component *component)
@@ -2080,12 +2363,15 @@ err_disable_reg:
static void da7219_remove(struct snd_soc_component *component)
{
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
int i;
da7219_aad_exit(component);
#ifdef CONFIG_COMMON_CLK
if (da7219->dai_clks_lookup)
clkdev_drop(da7219->dai_clks_lookup);
for (i = DA7219_DAI_NUM_CLKS - 1; i >= 0; --i) {
if (da7219->dai_clks_lookup[i])
clkdev_drop(da7219->dai_clks_lookup[i]);
}
#endif
/* Supplies */

View File

@@ -820,10 +820,10 @@ struct da7219_priv {
struct mutex pll_lock;
#ifdef CONFIG_COMMON_CLK
struct clk_hw dai_clks_hw;
struct clk_hw dai_clks_hw[DA7219_DAI_NUM_CLKS];
#endif
struct clk_lookup *dai_clks_lookup;
struct clk *dai_clks;
struct clk_lookup *dai_clks_lookup[DA7219_DAI_NUM_CLKS];
struct clk *dai_clks[DA7219_DAI_NUM_CLKS];
struct clk *mclk;
unsigned int mclk_rate;

View File

@@ -43,6 +43,7 @@ struct es8316_priv {
unsigned int sysclk;
unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS];
struct snd_pcm_hw_constraint_list sysclk_constraints;
bool jd_inverted;
};
/*
@@ -577,6 +578,9 @@ static irqreturn_t es8316_irq(int irq, void *data)
if (!es8316->jack)
goto out;
if (es8316->jd_inverted)
flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED;
dev_dbg(comp->dev, "gpio flags %#04x\n", flags);
if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) {
/* Jack removed, or spurious IRQ? */
@@ -592,6 +596,8 @@ static irqreturn_t es8316_irq(int irq, void *data)
/* Jack inserted, determine type */
es8316_enable_micbias_for_mic_gnd_short_detect(comp);
regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags);
if (es8316->jd_inverted)
flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED;
dev_dbg(comp->dev, "gpio flags %#04x\n", flags);
if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) {
/* Jack unplugged underneath us */
@@ -633,6 +639,14 @@ static void es8316_enable_jack_detect(struct snd_soc_component *component,
{
struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
/*
* Init es8316->jd_inverted here and not in the probe, as we cannot
* guarantee that the bytchr-es8316 driver, which might set this
* property, will probe before us.
*/
es8316->jd_inverted = device_property_read_bool(component->dev,
"everest,jack-detect-inverted");
mutex_lock(&es8316->lock);
es8316->jack = jack;

View File

@@ -1854,6 +1854,17 @@ static int hdmi_codec_probe(struct snd_soc_component *component)
/* Imp: Store the card pointer in hda_codec */
hdmi->card = dapm->card->snd_card;
/*
* Setup a device_link between card device and HDMI codec device.
* The card device is the consumer and the HDMI codec device is
* the supplier. With this setting, we can make sure that the audio
* domain in display power will be always turned on before operating
* on the HDMI audio codec registers.
* Let's use the flag DL_FLAG_AUTOREMOVE_CONSUMER. This can make
* sure the device link is freed when the machine driver is removed.
*/
device_link_add(component->card->dev, &hdev->dev, DL_FLAG_RPM_ACTIVE |
DL_FLAG_AUTOREMOVE_CONSUMER);
/*
* hdac_device core already sets the state to active and calls
* get_noresume. So enable runtime and set the device to suspend.

View File

@@ -439,8 +439,12 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
if (!ret) {
ret = snd_pcm_hw_constraint_eld(substream->runtime,
hcp->eld);
if (ret)
if (ret) {
mutex_lock(&hcp->current_stream_lock);
hcp->current_stream = NULL;
mutex_unlock(&hcp->current_stream_lock);
return ret;
}
}
/* Select chmap supported */
hdmi_codec_eld_chmap(hcp);
@@ -492,10 +496,6 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
return ret;
}
ret = hdmi_codec_new_stream(substream, dai);
if (ret)
return ret;
hdmi_audio_infoframe_init(&hp.cea);
hp.cea.channels = params_channels(params);
hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
@@ -757,7 +757,7 @@ static int hdmi_codec_probe(struct platform_device *pdev)
dev_dbg(dev, "%s()\n", __func__);
if (!hcd) {
dev_err(dev, "%s: No plalform data\n", __func__);
dev_err(dev, "%s: No platform data\n", __func__);
return -EINVAL;
}

View File

@@ -0,0 +1,266 @@
// SPDX-License-Identifier: GPL-2.0
//
// Lochnagar sound card driver
//
// Copyright (c) 2017-2019 Cirrus Logic, Inc. and
// Cirrus Logic International Semiconductor Ltd.
//
// Author: Charles Keepax <ckeepax@opensource.cirrus.com>
// Piotr Stankiewicz <piotrs@opensource.cirrus.com>
#include <linux/clk.h>
#include <linux/module.h>
#include <sound/soc.h>
#include <linux/mfd/lochnagar.h>
#include <linux/mfd/lochnagar1_regs.h>
#include <linux/mfd/lochnagar2_regs.h>
struct lochnagar_sc_priv {
struct clk *mclk;
};
static const struct snd_soc_dapm_widget lochnagar_sc_widgets[] = {
SND_SOC_DAPM_LINE("Line Jack", NULL),
SND_SOC_DAPM_LINE("USB Audio", NULL),
};
static const struct snd_soc_dapm_route lochnagar_sc_routes[] = {
{ "Line Jack", NULL, "AIF1 Playback" },
{ "AIF1 Capture", NULL, "Line Jack" },
{ "USB Audio", NULL, "USB1 Playback" },
{ "USB Audio", NULL, "USB2 Playback" },
{ "USB1 Capture", NULL, "USB Audio" },
{ "USB2 Capture", NULL, "USB Audio" },
};
static const unsigned int lochnagar_sc_chan_vals[] = {
4, 8,
};
static const struct snd_pcm_hw_constraint_list lochnagar_sc_chan_constraint = {
.count = ARRAY_SIZE(lochnagar_sc_chan_vals),
.list = lochnagar_sc_chan_vals,
};
static const unsigned int lochnagar_sc_rate_vals[] = {
8000, 16000, 24000, 32000, 48000, 96000, 192000,
22050, 44100, 88200, 176400,
};
static const struct snd_pcm_hw_constraint_list lochnagar_sc_rate_constraint = {
.count = ARRAY_SIZE(lochnagar_sc_rate_vals),
.list = lochnagar_sc_rate_vals,
};
static int lochnagar_sc_hw_rule_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct snd_interval range = {
.min = 8000,
.max = 24576000 / hw_param_interval(params, rule->deps[0])->max,
};
return snd_interval_refine(hw_param_interval(params, rule->var),
&range);
}
static int lochnagar_sc_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *comp = dai->component;
struct lochnagar_sc_priv *priv = snd_soc_component_get_drvdata(comp);
int ret;
ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&lochnagar_sc_rate_constraint);
if (ret)
return ret;
return snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
lochnagar_sc_hw_rule_rate, priv,
SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
}
static int lochnagar_sc_line_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *comp = dai->component;
struct lochnagar_sc_priv *priv = snd_soc_component_get_drvdata(comp);
int ret;
ret = clk_prepare_enable(priv->mclk);
if (ret < 0) {
dev_err(dai->dev, "Failed to enable MCLK: %d\n", ret);
return ret;
}
ret = lochnagar_sc_startup(substream, dai);
if (ret)
return ret;
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
&lochnagar_sc_chan_constraint);
}
static void lochnagar_sc_line_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *comp = dai->component;
struct lochnagar_sc_priv *priv = snd_soc_component_get_drvdata(comp);
clk_disable_unprepare(priv->mclk);
}
static int lochnagar_sc_check_fmt(struct snd_soc_dai *dai, unsigned int fmt,
unsigned int tar)
{
tar |= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF;
if ((fmt & ~SND_SOC_DAIFMT_CLOCK_MASK) != tar)
return -EINVAL;
return 0;
}
static int lochnagar_sc_set_line_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBS_CFS);
}
static int lochnagar_sc_set_usb_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBM_CFM);
}
static const struct snd_soc_dai_ops lochnagar_sc_line_ops = {
.startup = lochnagar_sc_line_startup,
.shutdown = lochnagar_sc_line_shutdown,
.set_fmt = lochnagar_sc_set_line_fmt,
};
static const struct snd_soc_dai_ops lochnagar_sc_usb_ops = {
.startup = lochnagar_sc_startup,
.set_fmt = lochnagar_sc_set_usb_fmt,
};
static struct snd_soc_dai_driver lochnagar_sc_dai[] = {
{
.name = "lochnagar-line",
.playback = {
.stream_name = "AIF1 Playback",
.channels_min = 4,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
},
.capture = {
.stream_name = "AIF1 Capture",
.channels_min = 4,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &lochnagar_sc_line_ops,
.symmetric_rates = true,
.symmetric_samplebits = true,
},
{
.name = "lochnagar-usb1",
.playback = {
.stream_name = "USB1 Playback",
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
},
.capture = {
.stream_name = "USB1 Capture",
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &lochnagar_sc_usb_ops,
.symmetric_rates = true,
.symmetric_samplebits = true,
},
{
.name = "lochnagar-usb2",
.playback = {
.stream_name = "USB2 Playback",
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
},
.capture = {
.stream_name = "USB2 Capture",
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
},
.ops = &lochnagar_sc_usb_ops,
.symmetric_rates = true,
.symmetric_samplebits = true,
},
};
static const struct snd_soc_component_driver lochnagar_sc_driver = {
.non_legacy_dai_naming = 1,
.dapm_widgets = lochnagar_sc_widgets,
.num_dapm_widgets = ARRAY_SIZE(lochnagar_sc_widgets),
.dapm_routes = lochnagar_sc_routes,
.num_dapm_routes = ARRAY_SIZE(lochnagar_sc_routes),
};
static int lochnagar_sc_probe(struct platform_device *pdev)
{
struct lochnagar_sc_priv *priv;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->mclk = devm_clk_get(&pdev->dev, "mclk");
if (IS_ERR(priv->mclk)) {
ret = PTR_ERR(priv->mclk);
dev_err(&pdev->dev, "Failed to get MCLK: %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, priv);
return devm_snd_soc_register_component(&pdev->dev,
&lochnagar_sc_driver,
lochnagar_sc_dai,
ARRAY_SIZE(lochnagar_sc_dai));
}
static const struct of_device_id lochnagar_of_match[] = {
{ .compatible = "cirrus,lochnagar2-soundcard" },
{}
};
MODULE_DEVICE_TABLE(of, lochnagar_of_match);
static struct platform_driver lochnagar_sc_codec_driver = {
.driver = {
.name = "lochnagar-soundcard",
.of_match_table = of_match_ptr(lochnagar_of_match),
},
.probe = lochnagar_sc_probe,
};
module_platform_driver(lochnagar_sc_codec_driver);
MODULE_DESCRIPTION("ASoC Lochnagar Sound Card Driver");
MODULE_AUTHOR("Piotr Stankiewicz <piotrs@opensource.cirrus.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:lochnagar-soundcard");

View File

@@ -97,7 +97,10 @@ static struct snd_soc_dai_driver max98357a_dai_driver = {
SNDRV_PCM_FMTBIT_S32,
.rates = SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000,
.rate_min = 8000,
.rate_max = 96000,

View File

@@ -493,7 +493,7 @@ static int nau8810_set_sysclk(struct snd_soc_dai *dai,
return 0;
}
static int nau88l0_calc_pll(unsigned int pll_in,
static int nau8810_calc_pll(unsigned int pll_in,
unsigned int fs, struct nau8810_pll *pll_param)
{
u64 f2, f2_max, pll_ratio;
@@ -505,7 +505,8 @@ static int nau88l0_calc_pll(unsigned int pll_in,
f2_max = 0;
scal_sel = ARRAY_SIZE(nau8810_mclk_scaler);
for (i = 0; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) {
f2 = 256 * fs * 4 * nau8810_mclk_scaler[i] / 10;
f2 = 256ULL * fs * 4 * nau8810_mclk_scaler[i];
f2 = div_u64(f2, 10);
if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX &&
f2_max < f2) {
f2_max = f2;
@@ -542,7 +543,7 @@ static int nau8810_set_pll(struct snd_soc_dai *codec_dai, int pll_id,
int ret, fs;
fs = freq_out / 256;
ret = nau88l0_calc_pll(freq_in, fs, pll_param);
ret = nau8810_calc_pll(freq_in, fs, pll_param);
if (ret < 0) {
dev_err(nau8810->dev, "Unsupported input clock %d\n", freq_in);
return ret;
@@ -667,6 +668,24 @@ static int nau8810_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component);
int val_len = 0, val_rate = 0, ret = 0;
unsigned int ctrl_val, bclk_fs, bclk_div;
/* Select BCLK configuration if the codec as master. */
regmap_read(nau8810->regmap, NAU8810_REG_CLOCK, &ctrl_val);
if (ctrl_val & NAU8810_CLKIO_MASTER) {
/* get the bclk and fs ratio */
bclk_fs = snd_soc_params_to_bclk(params) / params_rate(params);
if (bclk_fs <= 32)
bclk_div = NAU8810_BCLKDIV_8;
else if (bclk_fs <= 64)
bclk_div = NAU8810_BCLKDIV_4;
else if (bclk_fs <= 128)
bclk_div = NAU8810_BCLKDIV_2;
else
return -EINVAL;
regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK,
NAU8810_BCLKSEL_MASK, bclk_div);
}
switch (params_width(params)) {
case 16:

View File

@@ -457,13 +457,16 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
if (chan > 2) {
switch (fmt) {
case PCM3168A_FMT_I2S:
case PCM3168A_FMT_DSP_A:
fmt = PCM3168A_FMT_I2S_TDM;
break;
case PCM3168A_FMT_LEFT_J:
case PCM3168A_FMT_DSP_B:
fmt = PCM3168A_FMT_LEFT_J_TDM;
break;
default:
dev_err(component->dev, "TDM is supported under I2S/Left_J only\n");
dev_err(component->dev,
"TDM is supported under DSP/I2S/Left_J only\n");
return -EINVAL;
}
}
@@ -526,6 +529,8 @@ static int pcm3168a_startup(struct snd_pcm_substream *substream,
break;
case PCM3168A_FMT_LEFT_J:
case PCM3168A_FMT_I2S:
case PCM3168A_FMT_DSP_A:
case PCM3168A_FMT_DSP_B:
sample_min = 24;
channel_max = channel_maxs[tx];
break;

View File

@@ -3419,6 +3419,9 @@ static int rt5645_probe(struct snd_soc_component *component)
RT5645_HWEQ_NUM, sizeof(struct rt5645_eq_param_s),
GFP_KERNEL);
if (!rt5645->eq_param)
return -ENOMEM;
return 0;
}
@@ -3631,6 +3634,11 @@ static const struct rt5645_platform_data jd_mode3_platform_data = {
.jd_mode = 3,
};
static const struct rt5645_platform_data lattepanda_board_platform_data = {
.jd_mode = 2,
.inv_jd1_1 = true
};
static const struct dmi_system_id dmi_platform_data[] = {
{
.ident = "Chrome Buddy",
@@ -3728,6 +3736,15 @@ static const struct dmi_system_id dmi_platform_data[] = {
},
.driver_data = (void *)&intel_braswell_platform_data,
},
{
.ident = "LattePanda board",
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
DMI_EXACT_MATCH(DMI_BOARD_VERSION, "Default string"),
},
.driver_data = (void *)&lattepanda_board_platform_data,
},
{ }
};

View File

@@ -1645,7 +1645,10 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component)
break;
}
return val == 0;
if (rt5651->jd_active_high)
return val != 0;
else
return val == 0;
}
/* Jack detect and button-press timings */
@@ -1868,20 +1871,47 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component,
case RT5651_JD1_1:
snd_soc_component_update_bits(component, RT5651_JD_CTRL2,
RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1);
snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1,
RT5651_JD1_1_IRQ_EN, RT5651_JD1_1_IRQ_EN);
/* active-low is normal, set inv flag for active-high */
if (rt5651->jd_active_high)
snd_soc_component_update_bits(component,
RT5651_IRQ_CTRL1,
RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV,
RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV);
else
snd_soc_component_update_bits(component,
RT5651_IRQ_CTRL1,
RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV,
RT5651_JD1_1_IRQ_EN);
break;
case RT5651_JD1_2:
snd_soc_component_update_bits(component, RT5651_JD_CTRL2,
RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_2);
snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1,
RT5651_JD1_2_IRQ_EN, RT5651_JD1_2_IRQ_EN);
/* active-low is normal, set inv flag for active-high */
if (rt5651->jd_active_high)
snd_soc_component_update_bits(component,
RT5651_IRQ_CTRL1,
RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV,
RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV);
else
snd_soc_component_update_bits(component,
RT5651_IRQ_CTRL1,
RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV,
RT5651_JD1_2_IRQ_EN);
break;
case RT5651_JD2:
snd_soc_component_update_bits(component, RT5651_JD_CTRL2,
RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD2);
snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1,
RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN);
/* active-low is normal, set inv flag for active-high */
if (rt5651->jd_active_high)
snd_soc_component_update_bits(component,
RT5651_IRQ_CTRL1,
RT5651_JD2_IRQ_EN | RT5651_JD2_INV,
RT5651_JD2_IRQ_EN | RT5651_JD2_INV);
else
snd_soc_component_update_bits(component,
RT5651_IRQ_CTRL1,
RT5651_JD2_IRQ_EN | RT5651_JD2_INV,
RT5651_JD2_IRQ_EN);
break;
default:
dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n");
@@ -1986,6 +2016,9 @@ static void rt5651_apply_properties(struct snd_soc_component *component)
"realtek,jack-detect-source", &val) == 0)
rt5651->jd_src = val;
if (device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted"))
rt5651->jd_active_high = true;
/*
* Testing on various boards has shown that good defaults for the OVCD
* threshold and scale-factor are 2000µA and 0.75. For an effective

View File

@@ -2083,6 +2083,7 @@ struct rt5651_priv {
int release_count;
int poll_count;
unsigned int jd_src;
bool jd_active_high;
unsigned int ovcd_th;
unsigned int ovcd_sf;

View File

@@ -25,6 +25,7 @@
#include <linux/sysfs.h>
#include <linux/clk.h>
#include <linux/firmware.h>
#include <linux/acpi.h>
#include "rt5677-spi.h"
@@ -226,9 +227,16 @@ static int rt5677_spi_probe(struct spi_device *spi)
return 0;
}
static const struct acpi_device_id rt5677_spi_acpi_id[] = {
{ "RT5677AA", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, rt5677_spi_acpi_id);
static struct spi_driver rt5677_spi_driver = {
.driver = {
.name = "rt5677",
.acpi_match_table = ACPI_PTR(rt5677_spi_acpi_id),
},
.probe = rt5677_spi_probe,
};

View File

@@ -2588,6 +2588,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
rt5682_reset(rt5682->regmap);
mutex_init(&rt5682->calibrate_mutex);
rt5682_calibrate(rt5682);
ret = regmap_multi_reg_write(rt5682->regmap, patch_list,
@@ -2654,7 +2655,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
INIT_DELAYED_WORK(&rt5682->jd_check_work,
rt5682_jd_check_handler);
mutex_init(&rt5682->calibrate_mutex);
if (i2c->irq) {
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,

View File

@@ -89,7 +89,8 @@ static int simple_amp_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
priv->gpiod_enable = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
priv->gpiod_enable = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR(priv->gpiod_enable)) {
err = PTR_ERR(priv->gpiod_enable);
if (err != -EPROBE_DEFER)

View File

@@ -461,9 +461,6 @@ static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
struct sirf_audio_codec *sirf_audio_codec;
void __iomem *base;
struct resource *mem_res;
const struct of_device_id *match;
match = of_match_node(sirf_audio_codec_of_match, pdev->dev.of_node);
sirf_audio_codec = devm_kzalloc(&pdev->dev,
sizeof(struct sirf_audio_codec), GFP_KERNEL);

View File

@@ -25,6 +25,7 @@
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -89,6 +90,7 @@ static bool aic31xx_volatile(struct device *dev, unsigned int reg)
case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
case AIC31XX_INTRDACFLAG2:
case AIC31XX_INTRADCFLAG2:
case AIC31XX_HSDETECT:
return true;
}
return false;
@@ -163,6 +165,7 @@ struct aic31xx_priv {
struct aic31xx_pdata pdata;
struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
struct snd_soc_jack *jack;
unsigned int sysclk;
u8 p_div;
int rate_div_line;
@@ -1261,6 +1264,20 @@ static int aic31xx_set_bias_level(struct snd_soc_component *component,
return 0;
}
static int aic31xx_set_jack(struct snd_soc_component *component,
struct snd_soc_jack *jack, void *data)
{
struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
aic31xx->jack = jack;
/* Enable/Disable jack detection */
regmap_write(aic31xx->regmap, AIC31XX_HSDETECT,
jack ? AIC31XX_HSD_ENABLE : 0);
return 0;
}
static int aic31xx_codec_probe(struct snd_soc_component *component)
{
struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
@@ -1301,6 +1318,7 @@ static int aic31xx_codec_probe(struct snd_soc_component *component)
static const struct snd_soc_component_driver soc_codec_driver_aic31xx = {
.probe = aic31xx_codec_probe,
.set_jack = aic31xx_set_jack,
.set_bias_level = aic31xx_set_bias_level,
.controls = common31xx_snd_controls,
.num_controls = ARRAY_SIZE(common31xx_snd_controls),
@@ -1405,8 +1423,47 @@ static irqreturn_t aic31xx_irq(int irq, void *data)
dev_err(dev, "Short circuit on Left output is detected\n");
if (value & AIC31XX_HPRSCDETECT)
dev_err(dev, "Short circuit on Right output is detected\n");
if (value & (AIC31XX_HSPLUG | AIC31XX_BUTTONPRESS)) {
unsigned int val;
int status = 0;
ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG2,
&val);
if (ret) {
dev_err(dev, "Failed to read interrupt mask: %d\n",
ret);
goto exit;
}
if (val & AIC31XX_BUTTONPRESS)
status |= SND_JACK_BTN_0;
ret = regmap_read(aic31xx->regmap, AIC31XX_HSDETECT, &val);
if (ret) {
dev_err(dev, "Failed to read headset type: %d\n", ret);
goto exit;
}
switch ((val & AIC31XX_HSD_TYPE_MASK) >>
AIC31XX_HSD_TYPE_SHIFT) {
case AIC31XX_HSD_HP:
status |= SND_JACK_HEADPHONE;
break;
case AIC31XX_HSD_HS:
status |= SND_JACK_HEADSET;
break;
default:
break;
}
if (aic31xx->jack)
snd_soc_jack_report(aic31xx->jack, status,
AIC31XX_JACK_MASK);
}
if (value & ~(AIC31XX_HPLSCDETECT |
AIC31XX_HPRSCDETECT))
AIC31XX_HPRSCDETECT |
AIC31XX_HSPLUG |
AIC31XX_BUTTONPRESS))
dev_err(dev, "Unknown DAC interrupt flags: 0x%08x\n", value);
read_overflow:
@@ -1518,6 +1575,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
AIC31XX_GPIO1_FUNC_SHIFT);
regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL,
AIC31XX_HSPLUGDET |
AIC31XX_BUTTONPRESSDET |
AIC31XX_SC |
AIC31XX_ENGINE);

View File

@@ -20,6 +20,10 @@
#define AIC31XX_MINIDSP_BIT BIT(2)
#define DAC31XX_BIT BIT(3)
#define AIC31XX_JACK_MASK (SND_JACK_HEADPHONE | \
SND_JACK_HEADSET | \
SND_JACK_BTN_0)
enum aic31xx_type {
AIC3100 = 0,
AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
@@ -220,6 +224,14 @@ struct aic31xx_pdata {
/* AIC31XX_DACMUTE */
#define AIC31XX_DACMUTE_MASK GENMASK(3, 2)
/* AIC31XX_HSDETECT */
#define AIC31XX_HSD_ENABLE BIT(7)
#define AIC31XX_HSD_TYPE_MASK GENMASK(6, 5)
#define AIC31XX_HSD_TYPE_SHIFT 5
#define AIC31XX_HSD_NONE 0x00
#define AIC31XX_HSD_HP 0x01
#define AIC31XX_HSD_HS 0x03
/* AIC31XX_MICBIAS */
#define AIC31XX_MICBIAS_MASK GENMASK(1, 0)
#define AIC31XX_MICBIAS_SHIFT 0

View File

@@ -0,0 +1,483 @@
/* SPDX-License-Identifier: GPL-2.0
*
* Clock Tree for the Texas Instruments TLV320AIC32x4
*
* Copyright 2019 Annaliese McDermond
*
* Author: Annaliese McDermond <nh6z@nh6z.net>
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/regmap.h>
#include <linux/device.h>
#include "tlv320aic32x4.h"
#define to_clk_aic32x4(_hw) container_of(_hw, struct clk_aic32x4, hw)
struct clk_aic32x4 {
struct clk_hw hw;
struct device *dev;
struct regmap *regmap;
unsigned int reg;
};
/*
* struct clk_aic32x4_pll_muldiv - Multiplier/divider settings
* @p: Divider
* @r: first multiplier
* @j: integer part of second multiplier
* @d: decimal part of second multiplier
*/
struct clk_aic32x4_pll_muldiv {
u8 p;
u16 r;
u8 j;
u16 d;
};
struct aic32x4_clkdesc {
const char *name;
const char * const *parent_names;
unsigned int num_parents;
const struct clk_ops *ops;
unsigned int reg;
};
static int clk_aic32x4_pll_prepare(struct clk_hw *hw)
{
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
return regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
AIC32X4_PLLEN, AIC32X4_PLLEN);
}
static void clk_aic32x4_pll_unprepare(struct clk_hw *hw)
{
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
AIC32X4_PLLEN, 0);
}
static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw)
{
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
unsigned int val;
int ret;
ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
if (ret < 0)
return ret;
return !!(val & AIC32X4_PLLEN);
}
static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
struct clk_aic32x4_pll_muldiv *settings)
{
/* Change to use regmap_bulk_read? */
unsigned int val;
int ret;
ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
if (ret < 0)
return ret;
settings->r = val & AIC32X4_PLL_R_MASK;
settings->p = (val & AIC32X4_PLL_P_MASK) >> AIC32X4_PLL_P_SHIFT;
ret = regmap_read(pll->regmap, AIC32X4_PLLJ, &val);
if (ret < 0)
return ret;
settings->j = val;
ret = regmap_read(pll->regmap, AIC32X4_PLLDMSB, &val);
if (ret < 0)
return ret;
settings->d = val << 8;
ret = regmap_read(pll->regmap, AIC32X4_PLLDLSB, &val);
if (ret < 0)
return ret;
settings->d |= val;
return 0;
}
static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
struct clk_aic32x4_pll_muldiv *settings)
{
int ret;
/* Change to use regmap_bulk_write for some if not all? */
ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
AIC32X4_PLL_R_MASK, settings->r);
if (ret < 0)
return ret;
ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
AIC32X4_PLL_P_MASK,
settings->p << AIC32X4_PLL_P_SHIFT);
if (ret < 0)
return ret;
ret = regmap_write(pll->regmap, AIC32X4_PLLJ, settings->j);
if (ret < 0)
return ret;
ret = regmap_write(pll->regmap, AIC32X4_PLLDMSB, (settings->d >> 8));
if (ret < 0)
return ret;
ret = regmap_write(pll->regmap, AIC32X4_PLLDLSB, (settings->d & 0xff));
if (ret < 0)
return ret;
return 0;
}
static unsigned long clk_aic32x4_pll_calc_rate(
struct clk_aic32x4_pll_muldiv *settings,
unsigned long parent_rate)
{
u64 rate;
/*
* We scale j by 10000 to account for the decimal part of P and divide
* it back out later.
*/
rate = (u64) parent_rate * settings->r *
((settings->j * 10000) + settings->d);
return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000);
}
static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
unsigned long rate, unsigned long parent_rate)
{
u64 multiplier;
settings->p = parent_rate / AIC32X4_MAX_PLL_CLKIN + 1;
if (settings->p > 8)
return -1;
/*
* We scale this figure by 10000 so that we can get the decimal part
* of the multiplier. This is because we can't do floating point
* math in the kernel.
*/
multiplier = (u64) rate * settings->p * 10000;
do_div(multiplier, parent_rate);
/*
* J can't be over 64, so R can scale this.
* R can't be greater than 4.
*/
settings->r = ((u32) multiplier / 640000) + 1;
if (settings->r > 4)
return -1;
do_div(multiplier, settings->r);
/*
* J can't be < 1.
*/
if (multiplier < 10000)
return -1;
/* Figure out the integer part, J, and the fractional part, D. */
settings->j = (u32) multiplier / 10000;
settings->d = (u32) multiplier % 10000;
return 0;
}
static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
struct clk_aic32x4_pll_muldiv settings;
int ret;
ret = clk_aic32x4_pll_get_muldiv(pll, &settings);
if (ret < 0)
return 0;
return clk_aic32x4_pll_calc_rate(&settings, parent_rate);
}
static long clk_aic32x4_pll_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate)
{
struct clk_aic32x4_pll_muldiv settings;
int ret;
ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, *parent_rate);
if (ret < 0)
return 0;
return clk_aic32x4_pll_calc_rate(&settings, *parent_rate);
}
static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
{
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
struct clk_aic32x4_pll_muldiv settings;
int ret;
ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, parent_rate);
if (ret < 0)
return -EINVAL;
return clk_aic32x4_pll_set_muldiv(pll, &settings);
}
static int clk_aic32x4_pll_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
return regmap_update_bits(pll->regmap,
AIC32X4_CLKMUX,
AIC32X4_PLL_CLKIN_MASK,
index << AIC32X4_PLL_CLKIN_SHIFT);
}
static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw)
{
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
unsigned int val;
regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT;
}
static const struct clk_ops aic32x4_pll_ops = {
.prepare = clk_aic32x4_pll_prepare,
.unprepare = clk_aic32x4_pll_unprepare,
.is_prepared = clk_aic32x4_pll_is_prepared,
.recalc_rate = clk_aic32x4_pll_recalc_rate,
.round_rate = clk_aic32x4_pll_round_rate,
.set_rate = clk_aic32x4_pll_set_rate,
.set_parent = clk_aic32x4_pll_set_parent,
.get_parent = clk_aic32x4_pll_get_parent,
};
static int clk_aic32x4_codec_clkin_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
return regmap_update_bits(mux->regmap,
AIC32X4_CLKMUX,
AIC32X4_CODEC_CLKIN_MASK, index << AIC32X4_CODEC_CLKIN_SHIFT);
}
static u8 clk_aic32x4_codec_clkin_get_parent(struct clk_hw *hw)
{
struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
unsigned int val;
regmap_read(mux->regmap, AIC32X4_CLKMUX, &val);
return (val & AIC32X4_CODEC_CLKIN_MASK) >> AIC32X4_CODEC_CLKIN_SHIFT;
}
static const struct clk_ops aic32x4_codec_clkin_ops = {
.set_parent = clk_aic32x4_codec_clkin_set_parent,
.get_parent = clk_aic32x4_codec_clkin_get_parent,
};
static int clk_aic32x4_div_prepare(struct clk_hw *hw)
{
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
return regmap_update_bits(div->regmap, div->reg,
AIC32X4_DIVEN, AIC32X4_DIVEN);
}
static void clk_aic32x4_div_unprepare(struct clk_hw *hw)
{
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
regmap_update_bits(div->regmap, div->reg,
AIC32X4_DIVEN, 0);
}
static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
u8 divisor;
divisor = DIV_ROUND_UP(parent_rate, rate);
if (divisor > 128)
return -EINVAL;
return regmap_update_bits(div->regmap, div->reg,
AIC32X4_DIV_MASK, divisor);
}
static long clk_aic32x4_div_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
unsigned long divisor;
divisor = DIV_ROUND_UP(*parent_rate, rate);
if (divisor > 128)
return -EINVAL;
return DIV_ROUND_UP(*parent_rate, divisor);
}
static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
unsigned int val;
regmap_read(div->regmap, div->reg, &val);
return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK);
}
static const struct clk_ops aic32x4_div_ops = {
.prepare = clk_aic32x4_div_prepare,
.unprepare = clk_aic32x4_div_unprepare,
.set_rate = clk_aic32x4_div_set_rate,
.round_rate = clk_aic32x4_div_round_rate,
.recalc_rate = clk_aic32x4_div_recalc_rate,
};
static int clk_aic32x4_bdiv_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
return regmap_update_bits(mux->regmap, AIC32X4_IFACE3,
AIC32X4_BDIVCLK_MASK, index);
}
static u8 clk_aic32x4_bdiv_get_parent(struct clk_hw *hw)
{
struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
unsigned int val;
regmap_read(mux->regmap, AIC32X4_IFACE3, &val);
return val & AIC32X4_BDIVCLK_MASK;
}
static const struct clk_ops aic32x4_bdiv_ops = {
.prepare = clk_aic32x4_div_prepare,
.unprepare = clk_aic32x4_div_unprepare,
.set_parent = clk_aic32x4_bdiv_set_parent,
.get_parent = clk_aic32x4_bdiv_get_parent,
.set_rate = clk_aic32x4_div_set_rate,
.round_rate = clk_aic32x4_div_round_rate,
.recalc_rate = clk_aic32x4_div_recalc_rate,
};
static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
{
.name = "pll",
.parent_names =
(const char* []) { "mclk", "bclk", "gpio", "din" },
.num_parents = 4,
.ops = &aic32x4_pll_ops,
.reg = 0,
},
{
.name = "codec_clkin",
.parent_names =
(const char *[]) { "mclk", "bclk", "gpio", "pll" },
.num_parents = 4,
.ops = &aic32x4_codec_clkin_ops,
.reg = 0,
},
{
.name = "ndac",
.parent_names = (const char * []) { "codec_clkin" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_NDAC,
},
{
.name = "mdac",
.parent_names = (const char * []) { "ndac" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_MDAC,
},
{
.name = "nadc",
.parent_names = (const char * []) { "codec_clkin" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_NADC,
},
{
.name = "madc",
.parent_names = (const char * []) { "nadc" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_MADC,
},
{
.name = "bdiv",
.parent_names =
(const char *[]) { "ndac", "mdac", "nadc", "madc" },
.num_parents = 4,
.ops = &aic32x4_bdiv_ops,
.reg = AIC32X4_BCLKN,
},
};
static struct clk *aic32x4_register_clk(struct device *dev,
struct aic32x4_clkdesc *desc)
{
struct clk_init_data init;
struct clk_aic32x4 *priv;
const char *devname = dev_name(dev);
init.ops = desc->ops;
init.name = desc->name;
init.parent_names = desc->parent_names;
init.num_parents = desc->num_parents;
init.flags = 0;
priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL);
if (priv == NULL)
return (struct clk *) -ENOMEM;
priv->dev = dev;
priv->hw.init = &init;
priv->regmap = dev_get_regmap(dev, NULL);
priv->reg = desc->reg;
clk_hw_register_clkdev(&priv->hw, desc->name, devname);
return devm_clk_register(dev, &priv->hw);
}
int aic32x4_register_clocks(struct device *dev, const char *mclk_name)
{
int i;
/*
* These lines are here to preserve the current functionality of
* the driver with regard to the DT. These should eventually be set
* by DT nodes so that the connections can be set up in configuration
* rather than code.
*/
aic32x4_clkdesc_array[0].parent_names =
(const char* []) { mclk_name, "bclk", "gpio", "din" };
aic32x4_clkdesc_array[1].parent_names =
(const char *[]) { mclk_name, "bclk", "gpio", "pll" };
for (i = 0; i < ARRAY_SIZE(aic32x4_clkdesc_array); ++i)
aic32x4_register_clk(dev, &aic32x4_clkdesc_array[i]);
return 0;
}
EXPORT_SYMBOL_GPL(aic32x4_register_clocks);

View File

@@ -1,21 +1,11 @@
/*
* linux/sound/soc/codecs/tlv320aic32x4-i2c.c
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright 2011 NW Digital Radio
* Copyright 2011-2019 NW Digital Radio
*
* Author: Annaliese McDermond <nh6z@nh6z.net>
*
* Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/i2c.h>

View File

@@ -1,21 +1,11 @@
/*
* linux/sound/soc/codecs/tlv320aic32x4-spi.c
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright 2011 NW Digital Radio
* Copyright 2011-2019 NW Digital Radio
*
* Author: Annaliese McDermond <nh6z@nh6z.net>
*
* Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/spi/spi.h>

View File

@@ -14,7 +14,7 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
@@ -33,6 +33,7 @@
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/of_clk.h>
#include <linux/regulator/consumer.h>
#include <sound/tlv320aic32x4.h>
@@ -46,29 +47,13 @@
#include "tlv320aic32x4.h"
struct aic32x4_rate_divs {
u32 mclk;
u32 rate;
u8 p_val;
u8 pll_j;
u16 pll_d;
u16 dosr;
u8 ndac;
u8 mdac;
u8 aosr;
u8 nadc;
u8 madc;
u8 blck_N;
};
struct aic32x4_priv {
struct regmap *regmap;
u32 sysclk;
u32 power_cfg;
u32 micpga_routing;
bool swapdacs;
int rstn_gpio;
struct clk *mclk;
const char *mclk_name;
struct regulator *supply_ldo;
struct regulator *supply_iov;
@@ -257,9 +242,24 @@ static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0);
/* -12dB min, 0.5dB steps */
static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
static const char * const lo_cm_text[] = {
"Full Chip", "1.65V",
};
static SOC_ENUM_SINGLE_DECL(lo_cm_enum, AIC32X4_CMMODE, 3, lo_cm_text);
static const char * const ptm_text[] = {
"P3", "P2", "P1",
};
static SOC_ENUM_SINGLE_DECL(l_ptm_enum, AIC32X4_LPLAYBACK, 2, ptm_text);
static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text);
static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum),
SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum),
SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
tlv_driver_gain),
@@ -270,6 +270,7 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
AIC32X4_HPRGAIN, 6, 0x01, 1),
SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
AIC32X4_LORGAIN, 6, 0x01, 1),
SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum),
SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL,
AIC32X4_RMICPGAVOL, 7, 0x01, 1),
@@ -305,38 +306,6 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
0, 0x0F, 0),
};
static const struct aic32x4_rate_divs aic32x4_divs[] = {
/* 8k rate */
{12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
{24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
{25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
/* 11.025k rate */
{12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
{24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
/* 16k rate */
{12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
{24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
{25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
/* 22.05k rate */
{12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
{24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
{25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
/* 32k rate */
{12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
{24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
/* 44.1k rate */
{12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
{24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
{25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
/* 48k rate */
{12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
{24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
{25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
/* 96k rate */
{25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1},
};
static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0),
@@ -391,7 +360,7 @@ static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum),
};
/* Right mixer pins */
/* Right mixer pins */
static SOC_ENUM_SINGLE_DECL(in1r_rpga_p_enum, AIC32X4_RMICPGAPIN, 6, resistor_text);
static SOC_ENUM_SINGLE_DECL(in2r_rpga_p_enum, AIC32X4_RMICPGAPIN, 4, resistor_text);
static SOC_ENUM_SINGLE_DECL(in3r_rpga_p_enum, AIC32X4_RMICPGAPIN, 2, resistor_text);
@@ -595,7 +564,7 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
{
.selector_reg = 0,
.selector_mask = 0xff,
.selector_mask = 0xff,
.window_start = 0,
.window_len = 128,
.range_min = 0,
@@ -610,35 +579,17 @@ const struct regmap_config aic32x4_regmap_config = {
};
EXPORT_SYMBOL(aic32x4_regmap_config);
static inline int aic32x4_get_divs(int mclk, int rate)
{
int i;
for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) {
if ((aic32x4_divs[i].rate == rate)
&& (aic32x4_divs[i].mclk == mclk)) {
return i;
}
}
printk(KERN_ERR "aic32x4: master clock and sample rate is not supported\n");
return -EINVAL;
}
static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_component *component = codec_dai->component;
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
struct clk *mclk;
struct clk *pll;
switch (freq) {
case 12000000:
case 24000000:
case 25000000:
aic32x4->sysclk = freq;
return 0;
}
printk(KERN_ERR "aic32x4: invalid frequency to set DAI system clock\n");
return -EINVAL;
pll = devm_clk_get(component->dev, "pll");
mclk = clk_get_parent(pll);
return clk_set_rate(mclk, freq);
}
static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
@@ -688,103 +639,175 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
}
snd_soc_component_update_bits(component, AIC32X4_IFACE1,
AIC32X4_IFACE1_DATATYPE_MASK |
AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
AIC32X4_IFACE1_DATATYPE_MASK |
AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
snd_soc_component_update_bits(component, AIC32X4_IFACE2,
AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
snd_soc_component_update_bits(component, AIC32X4_IFACE3,
AIC32X4_BCLKINV_MASK, iface_reg_3);
AIC32X4_BCLKINV_MASK, iface_reg_3);
return 0;
}
static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr)
{
return snd_soc_component_write(component, AIC32X4_AOSR, aosr);
}
static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
{
snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8);
snd_soc_component_write(component, AIC32X4_DOSRLSB,
(dosr & 0xff));
return 0;
}
static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
u8 r_block, u8 p_block)
{
if (r_block > 18 || p_block > 25)
return -EINVAL;
snd_soc_component_write(component, AIC32X4_ADCSPB, r_block);
snd_soc_component_write(component, AIC32X4_DACSPB, p_block);
return 0;
}
static int aic32x4_setup_clocks(struct snd_soc_component *component,
unsigned int sample_rate)
{
u8 aosr;
u16 dosr;
u8 adc_resource_class, dac_resource_class;
u8 madc, nadc, mdac, ndac, max_nadc, min_mdac, max_ndac;
u8 dosr_increment;
u16 max_dosr, min_dosr;
unsigned long adc_clock_rate, dac_clock_rate;
int ret;
struct clk_bulk_data clocks[] = {
{ .id = "pll" },
{ .id = "nadc" },
{ .id = "madc" },
{ .id = "ndac" },
{ .id = "mdac" },
{ .id = "bdiv" },
};
ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
if (ret)
return ret;
if (sample_rate <= 48000) {
aosr = 128;
adc_resource_class = 6;
dac_resource_class = 8;
dosr_increment = 8;
aic32x4_set_processing_blocks(component, 1, 1);
} else if (sample_rate <= 96000) {
aosr = 64;
adc_resource_class = 6;
dac_resource_class = 8;
dosr_increment = 4;
aic32x4_set_processing_blocks(component, 1, 9);
} else if (sample_rate == 192000) {
aosr = 32;
adc_resource_class = 3;
dac_resource_class = 4;
dosr_increment = 2;
aic32x4_set_processing_blocks(component, 13, 19);
} else {
dev_err(component->dev, "Sampling rate not supported\n");
return -EINVAL;
}
madc = DIV_ROUND_UP((32 * adc_resource_class), aosr);
max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) *
dosr_increment;
min_dosr = (AIC32X4_MIN_DOSR_FREQ / sample_rate / dosr_increment) *
dosr_increment;
max_nadc = AIC32X4_MAX_CODEC_CLKIN_FREQ / (madc * aosr * sample_rate);
for (nadc = max_nadc; nadc > 0; --nadc) {
adc_clock_rate = nadc * madc * aosr * sample_rate;
for (dosr = max_dosr; dosr >= min_dosr;
dosr -= dosr_increment) {
min_mdac = DIV_ROUND_UP((32 * dac_resource_class), dosr);
max_ndac = AIC32X4_MAX_CODEC_CLKIN_FREQ /
(min_mdac * dosr * sample_rate);
for (mdac = min_mdac; mdac <= 128; ++mdac) {
for (ndac = max_ndac; ndac > 0; --ndac) {
dac_clock_rate = ndac * mdac * dosr *
sample_rate;
if (dac_clock_rate == adc_clock_rate) {
if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
continue;
clk_set_rate(clocks[0].clk,
dac_clock_rate);
clk_set_rate(clocks[1].clk,
sample_rate * aosr *
madc);
clk_set_rate(clocks[2].clk,
sample_rate * aosr);
aic32x4_set_aosr(component,
aosr);
clk_set_rate(clocks[3].clk,
sample_rate * dosr *
mdac);
clk_set_rate(clocks[4].clk,
sample_rate * dosr);
aic32x4_set_dosr(component,
dosr);
clk_set_rate(clocks[5].clk,
sample_rate * 32);
return 0;
}
}
}
}
}
dev_err(component->dev,
"Could not set clocks to support sample rate.\n");
return -EINVAL;
}
static int aic32x4_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
u8 iface1_reg = 0;
u8 dacsetup_reg = 0;
int i;
i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params));
if (i < 0) {
printk(KERN_ERR "aic32x4: sampling rate not supported\n");
return i;
}
/* MCLK as PLL_CLKIN */
snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK,
AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT);
/* PLL as CODEC_CLKIN */
snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_MASK,
AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
/* DAC_MOD_CLK as BDIV_CLKIN */
snd_soc_component_update_bits(component, 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_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_R_MASK, 0x01);
/* PLL P value */
snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_P_MASK,
aic32x4_divs[i].p_val << AIC32X4_PLL_P_SHIFT);
/* PLL J value */
snd_soc_component_write(component, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);
/* PLL D value */
snd_soc_component_write(component, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
snd_soc_component_write(component, AIC32X4_PLLDLSB, (aic32x4_divs[i].pll_d & 0xff));
/* NDAC divider value */
snd_soc_component_update_bits(component, AIC32X4_NDAC,
AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
/* MDAC divider value */
snd_soc_component_update_bits(component, AIC32X4_MDAC,
AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
/* DOSR MSB & LSB values */
snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
/* NADC divider value */
snd_soc_component_update_bits(component, AIC32X4_NADC,
AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
/* MADC divider value */
snd_soc_component_update_bits(component, AIC32X4_MADC,
AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
/* AOSR value */
snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
/* BCLK N divider */
snd_soc_component_update_bits(component, AIC32X4_BCLKN,
AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
aic32x4_setup_clocks(component, params_rate(params));
switch (params_width(params)) {
case 16:
iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
AIC32X4_IFACE1_DATALEN_SHIFT);
AIC32X4_IFACE1_DATALEN_SHIFT);
break;
case 20:
iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
AIC32X4_IFACE1_DATALEN_SHIFT);
AIC32X4_IFACE1_DATALEN_SHIFT);
break;
case 24:
iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
AIC32X4_IFACE1_DATALEN_SHIFT);
AIC32X4_IFACE1_DATALEN_SHIFT);
break;
case 32:
iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
AIC32X4_IFACE1_DATALEN_SHIFT);
AIC32X4_IFACE1_DATALEN_SHIFT);
break;
}
snd_soc_component_update_bits(component, AIC32X4_IFACE1,
AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
if (params_channels(params) == 1) {
dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
@@ -795,7 +818,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
}
snd_soc_component_update_bits(component, AIC32X4_DACSETUP,
AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
return 0;
}
@@ -805,7 +828,7 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
struct snd_soc_component *component = dai->component;
snd_soc_component_update_bits(component, AIC32X4_DACMUTE,
AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
return 0;
}
@@ -813,41 +836,25 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
static int aic32x4_set_bias_level(struct snd_soc_component *component,
enum snd_soc_bias_level level)
{
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
int ret;
struct clk_bulk_data clocks[] = {
{ .id = "madc" },
{ .id = "mdac" },
{ .id = "bdiv" },
};
ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
if (ret)
return ret;
switch (level) {
case SND_SOC_BIAS_ON:
/* Switch on master clock */
ret = clk_prepare_enable(aic32x4->mclk);
ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks);
if (ret) {
dev_err(component->dev, "Failed to enable master clock\n");
dev_err(component->dev, "Failed to enable clocks\n");
return ret;
}
/* Switch on PLL */
snd_soc_component_update_bits(component, AIC32X4_PLLPR,
AIC32X4_PLLEN, AIC32X4_PLLEN);
/* Switch on NDAC Divider */
snd_soc_component_update_bits(component, AIC32X4_NDAC,
AIC32X4_NDACEN, AIC32X4_NDACEN);
/* Switch on MDAC Divider */
snd_soc_component_update_bits(component, AIC32X4_MDAC,
AIC32X4_MDACEN, AIC32X4_MDACEN);
/* Switch on NADC Divider */
snd_soc_component_update_bits(component, AIC32X4_NADC,
AIC32X4_NADCEN, AIC32X4_NADCEN);
/* Switch on MADC Divider */
snd_soc_component_update_bits(component, AIC32X4_MADC,
AIC32X4_MADCEN, AIC32X4_MADCEN);
/* Switch on BCLK_N Divider */
snd_soc_component_update_bits(component, AIC32X4_BCLKN,
AIC32X4_BCLKEN, AIC32X4_BCLKEN);
break;
case SND_SOC_BIAS_PREPARE:
break;
@@ -856,32 +863,7 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
break;
/* Switch off BCLK_N Divider */
snd_soc_component_update_bits(component, AIC32X4_BCLKN,
AIC32X4_BCLKEN, 0);
/* Switch off MADC Divider */
snd_soc_component_update_bits(component, AIC32X4_MADC,
AIC32X4_MADCEN, 0);
/* Switch off NADC Divider */
snd_soc_component_update_bits(component, AIC32X4_NADC,
AIC32X4_NADCEN, 0);
/* Switch off MDAC Divider */
snd_soc_component_update_bits(component, AIC32X4_MDAC,
AIC32X4_MDACEN, 0);
/* Switch off NDAC Divider */
snd_soc_component_update_bits(component, AIC32X4_NDAC,
AIC32X4_NDACEN, 0);
/* Switch off PLL */
snd_soc_component_update_bits(component, AIC32X4_PLLPR,
AIC32X4_PLLEN, 0);
/* Switch off master clock */
clk_disable_unprepare(aic32x4->mclk);
clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks);
break;
case SND_SOC_BIAS_OFF:
break;
@@ -889,8 +871,8 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
return 0;
}
#define AIC32X4_RATES SNDRV_PCM_RATE_8000_96000
#define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
#define AIC32X4_RATES SNDRV_PCM_RATE_8000_192000
#define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
| SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops aic32x4_ops = {
@@ -903,17 +885,17 @@ static const struct snd_soc_dai_ops aic32x4_ops = {
static struct snd_soc_dai_driver aic32x4_dai = {
.name = "tlv320aic32x4-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = AIC32X4_RATES,
.formats = AIC32X4_FORMATS,},
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = AIC32X4_RATES,
.formats = AIC32X4_FORMATS,},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = AIC32X4_RATES,
.formats = AIC32X4_FORMATS,},
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = AIC32X4_RATES,
.formats = AIC32X4_FORMATS,},
.ops = &aic32x4_ops,
.symmetric_rates = 1,
};
@@ -926,7 +908,7 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
/* MFP1 */
if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
snd_soc_component_write(component, AIC32X4_DINCTL,
aic32x4->setup->gpio_func[0]);
aic32x4->setup->gpio_func[0]);
snd_soc_add_component_controls(component, aic32x4_mfp1,
ARRAY_SIZE(aic32x4_mfp1));
}
@@ -934,7 +916,7 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
/* MFP2 */
if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
snd_soc_component_write(component, AIC32X4_DOUTCTL,
aic32x4->setup->gpio_func[1]);
aic32x4->setup->gpio_func[1]);
snd_soc_add_component_controls(component, aic32x4_mfp2,
ARRAY_SIZE(aic32x4_mfp2));
}
@@ -942,7 +924,7 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
/* MFP3 */
if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
snd_soc_component_write(component, AIC32X4_SCLKCTL,
aic32x4->setup->gpio_func[2]);
aic32x4->setup->gpio_func[2]);
snd_soc_add_component_controls(component, aic32x4_mfp3,
ARRAY_SIZE(aic32x4_mfp3));
}
@@ -950,7 +932,7 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
/* MFP4 */
if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
snd_soc_component_write(component, AIC32X4_MISOCTL,
aic32x4->setup->gpio_func[3]);
aic32x4->setup->gpio_func[3]);
snd_soc_add_component_controls(component, aic32x4_mfp4,
ARRAY_SIZE(aic32x4_mfp4));
}
@@ -958,7 +940,7 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
/* MFP5 */
if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
snd_soc_component_write(component, AIC32X4_GPIOCTL,
aic32x4->setup->gpio_func[4]);
aic32x4->setup->gpio_func[4]);
snd_soc_add_component_controls(component, aic32x4_mfp5,
ARRAY_SIZE(aic32x4_mfp5));
}
@@ -968,6 +950,18 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
{
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
u32 tmp_reg;
int ret;
struct clk_bulk_data clocks[] = {
{ .id = "codec_clkin" },
{ .id = "pll" },
{ .id = "bdiv" },
{ .id = "mdac" },
};
ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
if (ret)
return ret;
if (gpio_is_valid(aic32x4->rstn_gpio)) {
ndelay(10);
@@ -980,10 +974,13 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
if (aic32x4->setup)
aic32x4_setup_gpios(component);
clk_set_parent(clocks[0].clk, clocks[1].clk);
clk_set_parent(clocks[2].clk, clocks[3].clk);
/* Power platform configuration */
if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
snd_soc_component_write(component, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN |
AIC32X4_MICBIAS_2075V);
snd_soc_component_write(component, AIC32X4_MICBIAS,
AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
}
if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
@@ -1046,12 +1043,18 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
struct device_node *np)
{
struct aic32x4_setup_data *aic32x4_setup;
int ret;
aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
GFP_KERNEL);
if (!aic32x4_setup)
return -ENOMEM;
ret = of_property_match_string(np, "clock-names", "mclk");
if (ret < 0)
return -EINVAL;
aic32x4->mclk_name = of_clk_get_parent_name(np, ret);
aic32x4->swapdacs = false;
aic32x4->micpga_routing = 0;
aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
@@ -1173,7 +1176,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
return PTR_ERR(regmap);
aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv),
GFP_KERNEL);
GFP_KERNEL);
if (aic32x4 == NULL)
return -ENOMEM;
@@ -1185,6 +1188,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
aic32x4->swapdacs = pdata->swapdacs;
aic32x4->micpga_routing = pdata->micpga_routing;
aic32x4->rstn_gpio = pdata->rstn_gpio;
aic32x4->mclk_name = "mclk";
} else if (np) {
ret = aic32x4_parse_dt(aic32x4, np);
if (ret) {
@@ -1196,13 +1200,12 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
aic32x4->swapdacs = false;
aic32x4->micpga_routing = 0;
aic32x4->rstn_gpio = -1;
aic32x4->mclk_name = "mclk";
}
aic32x4->mclk = devm_clk_get(dev, "mclk");
if (IS_ERR(aic32x4->mclk)) {
dev_err(dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n");
return PTR_ERR(aic32x4->mclk);
}
ret = aic32x4_register_clocks(dev, aic32x4->mclk_name);
if (ret)
return ret;
if (gpio_is_valid(aic32x4->rstn_gpio)) {
ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio,

View File

@@ -16,6 +16,7 @@ struct regmap_config;
extern const struct regmap_config aic32x4_regmap_config;
int aic32x4_probe(struct device *dev, struct regmap *regmap);
int aic32x4_remove(struct device *dev);
int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
/* tlv320aic32x4 register space (in decimal to match datasheet) */
@@ -77,6 +78,8 @@ int aic32x4_remove(struct device *dev);
#define AIC32X4_PWRCFG AIC32X4_REG(1, 1)
#define AIC32X4_LDOCTL AIC32X4_REG(1, 2)
#define AIC32X4_LPLAYBACK AIC32X4_REG(1, 3)
#define AIC32X4_RPLAYBACK AIC32X4_REG(1, 4)
#define AIC32X4_OUTPWRCTL AIC32X4_REG(1, 9)
#define AIC32X4_CMMODE AIC32X4_REG(1, 10)
#define AIC32X4_HPLROUTE AIC32X4_REG(1, 12)
@@ -205,4 +208,14 @@ int aic32x4_remove(struct device *dev);
#define AIC32X4_RMICPGANIN_IN1L_10K 0x10
#define AIC32X4_RMICPGANIN_CM1R_10K 0x40
/* Common mask and enable for all of the dividers */
#define AIC32X4_DIVEN BIT(7)
#define AIC32X4_DIV_MASK GENMASK(6, 0)
/* Clock Limits */
#define AIC32X4_MAX_DOSR_FREQ 6200000
#define AIC32X4_MIN_DOSR_FREQ 2800000
#define AIC32X4_MAX_CODEC_CLKIN_FREQ 110000000
#define AIC32X4_MAX_PLL_CLKIN 20000000
#endif /* _TLV320AIC32X4_H */

View File

@@ -5188,6 +5188,7 @@ static int wcd9335_slim_status(struct slim_device *sdev,
wcd->slim = sdev;
wcd->slim_ifc_dev = of_slim_get_device(sdev->ctrl, ifc_dev_np);
of_node_put(ifc_dev_np);
if (!wcd->slim_ifc_dev) {
dev_err(dev, "Unable to get SLIM Interface device\n");
return -EINVAL;

View File

@@ -646,6 +646,8 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
return ret;
}
}
wm_adsp2_set_dspclk(w, v);
break;
case SND_SOC_DAPM_POST_PMD:
@@ -659,7 +661,7 @@ static int wm5102_adsp_power_ev(struct snd_soc_dapm_widget *w,
break;
}
return wm_adsp2_early_event(w, kcontrol, event, v);
return wm_adsp_early_event(w, kcontrol, event);
}
static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,

View File

@@ -211,7 +211,9 @@ static int wm5110_adsp_power_ev(struct snd_soc_dapm_widget *w,
v = (v & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT;
return wm_adsp2_early_event(w, kcontrol, event, v);
wm_adsp2_set_dspclk(w, v);
return wm_adsp_early_event(w, kcontrol, event);
}
static const struct reg_sequence wm5110_no_dre_left_enable[] = {

File diff suppressed because it is too large Load Diff

View File

@@ -54,6 +54,7 @@ struct wm_adsp_alg_region {
struct wm_adsp_compr;
struct wm_adsp_compr_buf;
struct wm_adsp_ops;
struct wm_adsp {
const char *part;
@@ -66,7 +67,10 @@ struct wm_adsp {
struct regmap *regmap;
struct snd_soc_component *component;
struct wm_adsp_ops *ops;
unsigned int base;
unsigned int base_sysinfo;
unsigned int sysclk_reg;
unsigned int sysclk_mask;
unsigned int sysclk_shift;
@@ -75,6 +79,7 @@ struct wm_adsp {
unsigned int fw_id;
unsigned int fw_id_version;
unsigned int fw_vendor_id;
const struct wm_adsp_region *mem;
int num_mems;
@@ -106,6 +111,32 @@ struct wm_adsp {
};
struct wm_adsp_ops {
unsigned int sys_config_size;
bool (*validate_version)(struct wm_adsp *dsp, unsigned int version);
unsigned int (*parse_sizes)(struct wm_adsp *dsp,
const char * const file,
unsigned int pos,
const struct firmware *firmware);
int (*setup_algs)(struct wm_adsp *dsp);
unsigned int (*region_to_reg)(struct wm_adsp_region const *mem,
unsigned int offset);
void (*show_fw_status)(struct wm_adsp *dsp);
void (*stop_watchdog)(struct wm_adsp *dsp);
int (*enable_memory)(struct wm_adsp *dsp);
void (*disable_memory)(struct wm_adsp *dsp);
int (*lock_memory)(struct wm_adsp *dsp, unsigned int lock_regions);
int (*enable_core)(struct wm_adsp *dsp);
void (*disable_core)(struct wm_adsp *dsp);
int (*start_core)(struct wm_adsp *dsp);
void (*stop_core)(struct wm_adsp *dsp);
};
#define WM_ADSP1(wname, num) \
SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
@@ -121,7 +152,7 @@ struct wm_adsp {
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \
.subseq = 100, /* Ensure we run after SYSCLK supply widget */ }, \
{ .id = snd_soc_dapm_out_drv, .name = wname, \
.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp_event, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
#define WM_ADSP_FW_CONTROL(dspname, num) \
@@ -135,17 +166,22 @@ int wm_adsp2_init(struct wm_adsp *dsp);
void wm_adsp2_remove(struct wm_adsp *dsp);
int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *component);
int wm_adsp2_component_remove(struct wm_adsp *dsp, struct snd_soc_component *component);
int wm_halo_init(struct wm_adsp *dsp);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event,
unsigned int freq);
int wm_adsp2_lock(struct wm_adsp *adsp, unsigned int regions);
int wm_adsp_early_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp);
irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp);
irqreturn_t wm_halo_wdt_expire(int irq, void *data);
int wm_adsp2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
int wm_adsp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
int wm_adsp2_set_dspclk(struct snd_soc_dapm_widget *w, unsigned int freq);
int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);

View File

@@ -73,6 +73,14 @@ struct wmfw_id_hdr {
__be32 ver;
} __packed;
struct wmfw_v3_id_hdr {
__be32 core_id;
__be32 block_rev;
__be32 vendor_id;
__be32 id;
__be32 ver;
} __packed;
struct wmfw_adsp1_id_hdr {
struct wmfw_id_hdr fw;
__be32 zm;
@@ -88,6 +96,15 @@ struct wmfw_adsp2_id_hdr {
__be32 n_algs;
} __packed;
struct wmfw_halo_id_hdr {
struct wmfw_v3_id_hdr fw;
__be32 xm_base;
__be32 xm_size;
__be32 ym_base;
__be32 ym_size;
__be32 n_algs;
} __packed;
struct wmfw_alg_hdr {
__be32 id;
__be32 ver;
@@ -106,6 +123,14 @@ struct wmfw_adsp2_alg_hdr {
__be32 ym;
} __packed;
struct wmfw_halo_alg_hdr {
struct wmfw_alg_hdr alg;
__be32 xm_base;
__be32 xm_size;
__be32 ym_base;
__be32 ym_size;
} __packed;
struct wmfw_adsp_alg_data {
__le32 id;
u8 name[WMFW_MAX_ALG_NAME];
@@ -154,6 +179,7 @@ struct wmfw_coeff_item {
#define WMFW_ADSP1 1
#define WMFW_ADSP2 2
#define WMFW_HALO 4
#define WMFW_ABSOLUTE 0xf0
#define WMFW_ALGORITHM_DATA 0xf2
@@ -169,4 +195,8 @@ struct wmfw_coeff_item {
#define WMFW_ADSP2_XM 5
#define WMFW_ADSP2_YM 6
#define WMFW_HALO_PM_PACKED 0x10
#define WMFW_HALO_XM_PACKED 0x11
#define WMFW_HALO_YM_PACKED 0x12
#endif