Merge branch 'asoc-4.22' into asoc-5.0
This commit is contained in:
@@ -65,6 +65,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_CS4271_SPI if SPI_MASTER
|
||||
select SND_SOC_CS42XX8_I2C if I2C
|
||||
select SND_SOC_CS43130 if I2C
|
||||
select SND_SOC_CS4341 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_CS4349 if I2C
|
||||
select SND_SOC_CS47L24 if MFD_CS47L24
|
||||
select SND_SOC_CS53L30 if I2C
|
||||
@@ -129,6 +130,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_PCM5102A
|
||||
select SND_SOC_PCM512x_I2C if I2C
|
||||
select SND_SOC_PCM512x_SPI if SPI_MASTER
|
||||
select SND_SOC_RK3328
|
||||
select SND_SOC_RT274 if I2C
|
||||
select SND_SOC_RT286 if I2C
|
||||
select SND_SOC_RT298 if I2C
|
||||
@@ -542,6 +544,12 @@ config SND_SOC_CS43130
|
||||
tristate "Cirrus Logic CS43130 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_CS4341
|
||||
tristate "Cirrus Logic CS4341 CODEC"
|
||||
depends on I2C || SPI_MASTER
|
||||
select REGMAP_I2C if I2C
|
||||
select REGMAP_SPI if SPI_MASTER
|
||||
|
||||
# Cirrus Logic CS4349 HiFi DAC
|
||||
config SND_SOC_CS4349
|
||||
tristate "Cirrus Logic CS4349 CODEC"
|
||||
@@ -799,6 +807,10 @@ config SND_SOC_PCM512x_SPI
|
||||
select SND_SOC_PCM512x
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_RK3328
|
||||
tristate "Rockchip RK3328 audio CODEC"
|
||||
select REGMAP_MMIO
|
||||
|
||||
config SND_SOC_RL6231
|
||||
tristate
|
||||
default y if SND_SOC_RT5514=y
|
||||
@@ -1211,7 +1223,8 @@ config SND_SOC_WM8903
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_WM8904
|
||||
tristate
|
||||
tristate "Wolfson Microelectronics WM8904 CODEC"
|
||||
depends on I2C
|
||||
|
||||
config SND_SOC_WM8940
|
||||
tristate
|
||||
|
@@ -60,6 +60,7 @@ snd-soc-cs4271-spi-objs := cs4271-spi.o
|
||||
snd-soc-cs42xx8-objs := cs42xx8.o
|
||||
snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
|
||||
snd-soc-cs43130-objs := cs43130.o
|
||||
snd-soc-cs4341-objs := cs4341.o
|
||||
snd-soc-cs4349-objs := cs4349.o
|
||||
snd-soc-cs47l24-objs := cs47l24.o
|
||||
snd-soc-cs53l30-objs := cs53l30.o
|
||||
@@ -132,6 +133,7 @@ snd-soc-pcm5102a-objs := pcm5102a.o
|
||||
snd-soc-pcm512x-objs := pcm512x.o
|
||||
snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
|
||||
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
|
||||
snd-soc-rk3328-objs := rk3328_codec.o
|
||||
snd-soc-rl6231-objs := rl6231.o
|
||||
snd-soc-rl6347a-objs := rl6347a.o
|
||||
snd-soc-rt1305-objs := rt1305.o
|
||||
@@ -326,6 +328,7 @@ obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o
|
||||
obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
|
||||
obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_CS43130) += snd-soc-cs43130.o
|
||||
obj-$(CONFIG_SND_SOC_CS4341) += snd-soc-cs4341.o
|
||||
obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o
|
||||
obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o
|
||||
obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o
|
||||
@@ -398,6 +401,7 @@ obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o
|
||||
obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o
|
||||
obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
|
||||
obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o
|
||||
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
|
||||
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
|
||||
obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o
|
||||
|
346
sound/soc/codecs/cs4341.c
Normal file
346
sound/soc/codecs/cs4341.c
Normal file
@@ -0,0 +1,346 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Cirrus Logic CS4341A ALSA SoC Codec Driver
|
||||
* Author: Alexander Shiyan <shc_work@mail.ru>
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#define CS4341_REG_MODE1 0x00
|
||||
#define CS4341_REG_MODE2 0x01
|
||||
#define CS4341_REG_MIX 0x02
|
||||
#define CS4341_REG_VOLA 0x03
|
||||
#define CS4341_REG_VOLB 0x04
|
||||
|
||||
#define CS4341_MODE2_DIF (7 << 4)
|
||||
#define CS4341_MODE2_DIF_I2S_24 (0 << 4)
|
||||
#define CS4341_MODE2_DIF_I2S_16 (1 << 4)
|
||||
#define CS4341_MODE2_DIF_LJ_24 (2 << 4)
|
||||
#define CS4341_MODE2_DIF_RJ_24 (3 << 4)
|
||||
#define CS4341_MODE2_DIF_RJ_16 (5 << 4)
|
||||
#define CS4341_VOLX_MUTE (1 << 7)
|
||||
|
||||
struct cs4341_priv {
|
||||
unsigned int fmt;
|
||||
struct regmap *regmap;
|
||||
struct regmap_config regcfg;
|
||||
};
|
||||
|
||||
static const struct reg_default cs4341_reg_defaults[] = {
|
||||
{ CS4341_REG_MODE1, 0x00 },
|
||||
{ CS4341_REG_MODE2, 0x82 },
|
||||
{ CS4341_REG_MIX, 0x49 },
|
||||
{ CS4341_REG_VOLA, 0x80 },
|
||||
{ CS4341_REG_VOLB, 0x80 },
|
||||
};
|
||||
|
||||
static int cs4341_set_fmt(struct snd_soc_dai *dai, unsigned int format)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct cs4341_priv *cs4341 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (format & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
cs4341->fmt = format & SND_SOC_DAIFMT_FORMAT_MASK;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs4341_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 cs4341_priv *cs4341 = snd_soc_component_get_drvdata(component);
|
||||
unsigned int mode = 0;
|
||||
int b24 = 0;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
b24 = 1;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
break;
|
||||
default:
|
||||
dev_err(component->dev, "Unsupported PCM format 0x%08x.\n",
|
||||
params_format(params));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (cs4341->fmt) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
mode = b24 ? CS4341_MODE2_DIF_I2S_24 : CS4341_MODE2_DIF_I2S_16;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
mode = CS4341_MODE2_DIF_LJ_24;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
mode = b24 ? CS4341_MODE2_DIF_RJ_24 : CS4341_MODE2_DIF_RJ_16;
|
||||
break;
|
||||
default:
|
||||
dev_err(component->dev, "Unsupported DAI format 0x%08x.\n",
|
||||
cs4341->fmt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return snd_soc_component_update_bits(component, CS4341_REG_MODE2,
|
||||
CS4341_MODE2_DIF, mode);
|
||||
}
|
||||
|
||||
static int cs4341_digital_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_component_update_bits(component, CS4341_REG_VOLA,
|
||||
CS4341_VOLX_MUTE,
|
||||
mute ? CS4341_VOLX_MUTE : 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return snd_soc_component_update_bits(component, CS4341_REG_VOLB,
|
||||
CS4341_VOLX_MUTE,
|
||||
mute ? CS4341_VOLX_MUTE : 0);
|
||||
}
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(out_tlv, -9000, 100, 0);
|
||||
|
||||
static const char * const deemph[] = {
|
||||
"None", "44.1k", "48k", "32k",
|
||||
};
|
||||
|
||||
static const struct soc_enum deemph_enum =
|
||||
SOC_ENUM_SINGLE(CS4341_REG_MODE2, 2, 4, deemph);
|
||||
|
||||
static const char * const srzc[] = {
|
||||
"Immediate", "Zero Cross", "Soft Ramp", "SR on ZC",
|
||||
};
|
||||
|
||||
static const struct soc_enum srzc_enum =
|
||||
SOC_ENUM_SINGLE(CS4341_REG_MIX, 5, 4, srzc);
|
||||
|
||||
|
||||
static const struct snd_soc_dapm_widget cs4341_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("HiFi DAC", NULL, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_OUTPUT("OutA"),
|
||||
SND_SOC_DAPM_OUTPUT("OutB"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cs4341_routes[] = {
|
||||
{ "OutA", NULL, "HiFi DAC" },
|
||||
{ "OutB", NULL, "HiFi DAC" },
|
||||
{ "DAC Playback", NULL, "OutA" },
|
||||
{ "DAC Playback", NULL, "OutB" },
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new cs4341_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Master Playback Volume",
|
||||
CS4341_REG_VOLA, CS4341_REG_VOLB, 0, 90, 1, out_tlv),
|
||||
SOC_ENUM("De-Emphasis Control", deemph_enum),
|
||||
SOC_ENUM("Soft Ramp Zero Cross Control", srzc_enum),
|
||||
SOC_SINGLE("Auto-Mute Switch", CS4341_REG_MODE2, 7, 1, 0),
|
||||
SOC_SINGLE("Popguard Transient Switch", CS4341_REG_MODE2, 1, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops cs4341_dai_ops = {
|
||||
.set_fmt = cs4341_set_fmt,
|
||||
.hw_params = cs4341_hw_params,
|
||||
.digital_mute = cs4341_digital_mute,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver cs4341_dai = {
|
||||
.name = "cs4341a-hifi",
|
||||
.playback = {
|
||||
.stream_name = "DAC Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.ops = &cs4341_dai_ops,
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver soc_component_cs4341 = {
|
||||
.controls = cs4341_controls,
|
||||
.num_controls = ARRAY_SIZE(cs4341_controls),
|
||||
.dapm_widgets = cs4341_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cs4341_dapm_widgets),
|
||||
.dapm_routes = cs4341_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(cs4341_routes),
|
||||
.idle_bias_on = 1,
|
||||
.use_pmdown_time = 1,
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static const struct of_device_id __maybe_unused cs4341_dt_ids[] = {
|
||||
{ .compatible = "cirrus,cs4341a", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cs4341_dt_ids);
|
||||
|
||||
static int cs4341_probe(struct device *dev)
|
||||
{
|
||||
struct cs4341_priv *cs4341 = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cs4341_reg_defaults); i++)
|
||||
regmap_write(cs4341->regmap, cs4341_reg_defaults[i].reg,
|
||||
cs4341_reg_defaults[i].def);
|
||||
|
||||
return devm_snd_soc_register_component(dev, &soc_component_cs4341,
|
||||
&cs4341_dai, 1);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_I2C)
|
||||
static int cs4341_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct cs4341_priv *cs4341;
|
||||
|
||||
cs4341 = devm_kzalloc(&i2c->dev, sizeof(*cs4341), GFP_KERNEL);
|
||||
if (!cs4341)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(i2c, cs4341);
|
||||
|
||||
cs4341->regcfg.reg_bits = 8;
|
||||
cs4341->regcfg.val_bits = 8;
|
||||
cs4341->regcfg.max_register = CS4341_REG_VOLB;
|
||||
cs4341->regcfg.cache_type = REGCACHE_FLAT;
|
||||
cs4341->regcfg.reg_defaults = cs4341_reg_defaults;
|
||||
cs4341->regcfg.num_reg_defaults = ARRAY_SIZE(cs4341_reg_defaults);
|
||||
cs4341->regmap = devm_regmap_init_i2c(i2c, &cs4341->regcfg);
|
||||
if (IS_ERR(cs4341->regmap))
|
||||
return PTR_ERR(cs4341->regmap);
|
||||
|
||||
return cs4341_probe(&i2c->dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cs4341_i2c_id[] = {
|
||||
{ "cs4341", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cs4341_i2c_id);
|
||||
|
||||
static struct i2c_driver cs4341_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs4341-i2c",
|
||||
.of_match_table = of_match_ptr(cs4341_dt_ids),
|
||||
},
|
||||
.probe = cs4341_i2c_probe,
|
||||
.id_table = cs4341_i2c_id,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static bool cs4341_reg_readable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int cs4341_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct cs4341_priv *cs4341;
|
||||
int ret;
|
||||
|
||||
cs4341 = devm_kzalloc(&spi->dev, sizeof(*cs4341), GFP_KERNEL);
|
||||
if (!cs4341)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!spi->bits_per_word)
|
||||
spi->bits_per_word = 8;
|
||||
if (!spi->max_speed_hz)
|
||||
spi->max_speed_hz = 6000000;
|
||||
ret = spi_setup(spi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spi_set_drvdata(spi, cs4341);
|
||||
|
||||
cs4341->regcfg.reg_bits = 16;
|
||||
cs4341->regcfg.val_bits = 8;
|
||||
cs4341->regcfg.write_flag_mask = 0x20;
|
||||
cs4341->regcfg.max_register = CS4341_REG_VOLB;
|
||||
cs4341->regcfg.cache_type = REGCACHE_FLAT;
|
||||
cs4341->regcfg.readable_reg = cs4341_reg_readable;
|
||||
cs4341->regcfg.reg_defaults = cs4341_reg_defaults;
|
||||
cs4341->regcfg.num_reg_defaults = ARRAY_SIZE(cs4341_reg_defaults);
|
||||
cs4341->regmap = devm_regmap_init_spi(spi, &cs4341->regcfg);
|
||||
if (IS_ERR(cs4341->regmap))
|
||||
return PTR_ERR(cs4341->regmap);
|
||||
|
||||
return cs4341_probe(&spi->dev);
|
||||
}
|
||||
|
||||
static struct spi_driver cs4341_spi_driver = {
|
||||
.driver = {
|
||||
.name = "cs4341-spi",
|
||||
.of_match_table = of_match_ptr(cs4341_dt_ids),
|
||||
},
|
||||
.probe = cs4341_spi_probe,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init cs4341_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#if defined(CONFIG_I2C)
|
||||
ret = i2c_add_driver(&cs4341_i2c_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
ret = spi_register_driver(&cs4341_spi_driver);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(cs4341_init);
|
||||
|
||||
static void __exit cs4341_exit(void)
|
||||
{
|
||||
#if defined(CONFIG_I2C)
|
||||
i2c_del_driver(&cs4341_i2c_driver);
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&cs4341_spi_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(cs4341_exit);
|
||||
|
||||
MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
|
||||
MODULE_DESCRIPTION("Cirrus Logic CS4341 ALSA SoC Codec Driver");
|
||||
MODULE_LICENSE("GPL");
|
@@ -15,12 +15,14 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/jack.h>
|
||||
#include "es8316.h"
|
||||
|
||||
/* In slave mode at single speed, the codec is documented as accepting 5
|
||||
@@ -33,6 +35,11 @@ static const unsigned int supported_mclk_lrck_ratios[] = {
|
||||
};
|
||||
|
||||
struct es8316_priv {
|
||||
struct mutex lock;
|
||||
struct regmap *regmap;
|
||||
struct snd_soc_component *component;
|
||||
struct snd_soc_jack *jack;
|
||||
int irq;
|
||||
unsigned int sysclk;
|
||||
unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS];
|
||||
struct snd_pcm_hw_constraint_list sysclk_constraints;
|
||||
@@ -94,6 +101,7 @@ static const struct snd_kcontrol_new es8316_snd_controls[] = {
|
||||
SOC_SINGLE("DAC Notch Filter Switch", ES8316_DAC_SET2, 6, 1, 0),
|
||||
SOC_SINGLE("DAC Double Fs Switch", ES8316_DAC_SET2, 7, 1, 0),
|
||||
SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0),
|
||||
SOC_SINGLE("DAC Mono Mix Switch", ES8316_DAC_SET3, 3, 1, 0),
|
||||
|
||||
SOC_ENUM("Capture Polarity", adcpol),
|
||||
SOC_SINGLE("Mic Boost Switch", ES8316_ADC_D2SEPGA, 0, 1, 0),
|
||||
@@ -529,8 +537,162 @@ static struct snd_soc_dai_driver es8316_dai = {
|
||||
.symmetric_rates = 1,
|
||||
};
|
||||
|
||||
static void es8316_enable_micbias_for_mic_gnd_short_detect(
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
|
||||
|
||||
snd_soc_dapm_mutex_lock(dapm);
|
||||
snd_soc_dapm_force_enable_pin_unlocked(dapm, "Bias");
|
||||
snd_soc_dapm_force_enable_pin_unlocked(dapm, "Analog power");
|
||||
snd_soc_dapm_force_enable_pin_unlocked(dapm, "Mic Bias");
|
||||
snd_soc_dapm_sync_unlocked(dapm);
|
||||
snd_soc_dapm_mutex_unlock(dapm);
|
||||
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static void es8316_disable_micbias_for_mic_gnd_short_detect(
|
||||
struct snd_soc_component *component)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
|
||||
|
||||
snd_soc_dapm_mutex_lock(dapm);
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Bias");
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "Analog power");
|
||||
snd_soc_dapm_disable_pin_unlocked(dapm, "Bias");
|
||||
snd_soc_dapm_sync_unlocked(dapm);
|
||||
snd_soc_dapm_mutex_unlock(dapm);
|
||||
}
|
||||
|
||||
static irqreturn_t es8316_irq(int irq, void *data)
|
||||
{
|
||||
struct es8316_priv *es8316 = data;
|
||||
struct snd_soc_component *comp = es8316->component;
|
||||
unsigned int flags;
|
||||
|
||||
mutex_lock(&es8316->lock);
|
||||
|
||||
regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags);
|
||||
if (flags == 0x00)
|
||||
goto out; /* Powered-down / reset */
|
||||
|
||||
/* Catch spurious IRQ before set_jack is called */
|
||||
if (!es8316->jack)
|
||||
goto out;
|
||||
|
||||
dev_dbg(comp->dev, "gpio flags %#04x\n", flags);
|
||||
if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) {
|
||||
/* Jack removed, or spurious IRQ? */
|
||||
if (es8316->jack->status & SND_JACK_MICROPHONE)
|
||||
es8316_disable_micbias_for_mic_gnd_short_detect(comp);
|
||||
|
||||
if (es8316->jack->status & SND_JACK_HEADPHONE) {
|
||||
snd_soc_jack_report(es8316->jack, 0,
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0);
|
||||
dev_dbg(comp->dev, "jack unplugged\n");
|
||||
}
|
||||
} else if (!(es8316->jack->status & SND_JACK_HEADPHONE)) {
|
||||
/* Jack inserted, determine type */
|
||||
es8316_enable_micbias_for_mic_gnd_short_detect(comp);
|
||||
regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags);
|
||||
dev_dbg(comp->dev, "gpio flags %#04x\n", flags);
|
||||
if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) {
|
||||
/* Jack unplugged underneath us */
|
||||
es8316_disable_micbias_for_mic_gnd_short_detect(comp);
|
||||
} else if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) {
|
||||
/* Open, headset */
|
||||
snd_soc_jack_report(es8316->jack,
|
||||
SND_JACK_HEADSET,
|
||||
SND_JACK_HEADSET);
|
||||
/* Keep mic-gnd-short detection on for button press */
|
||||
} else {
|
||||
/* Shorted, headphones */
|
||||
snd_soc_jack_report(es8316->jack,
|
||||
SND_JACK_HEADPHONE,
|
||||
SND_JACK_HEADSET);
|
||||
/* No longer need mic-gnd-short detection */
|
||||
es8316_disable_micbias_for_mic_gnd_short_detect(comp);
|
||||
}
|
||||
} else if (es8316->jack->status & SND_JACK_MICROPHONE) {
|
||||
/* Interrupt while jack inserted, report button state */
|
||||
if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) {
|
||||
/* Open, button release */
|
||||
snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0);
|
||||
} else {
|
||||
/* Short, button press */
|
||||
snd_soc_jack_report(es8316->jack,
|
||||
SND_JACK_BTN_0,
|
||||
SND_JACK_BTN_0);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&es8316->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void es8316_enable_jack_detect(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack)
|
||||
{
|
||||
struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
mutex_lock(&es8316->lock);
|
||||
|
||||
es8316->jack = jack;
|
||||
|
||||
if (es8316->jack->status & SND_JACK_MICROPHONE)
|
||||
es8316_enable_micbias_for_mic_gnd_short_detect(component);
|
||||
|
||||
snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
|
||||
ES8316_GPIO_ENABLE_INTERRUPT,
|
||||
ES8316_GPIO_ENABLE_INTERRUPT);
|
||||
|
||||
mutex_unlock(&es8316->lock);
|
||||
|
||||
/* Enable irq and sync initial jack state */
|
||||
enable_irq(es8316->irq);
|
||||
es8316_irq(es8316->irq, es8316);
|
||||
}
|
||||
|
||||
static void es8316_disable_jack_detect(struct snd_soc_component *component)
|
||||
{
|
||||
struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
disable_irq(es8316->irq);
|
||||
|
||||
mutex_lock(&es8316->lock);
|
||||
|
||||
snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
|
||||
ES8316_GPIO_ENABLE_INTERRUPT, 0);
|
||||
|
||||
if (es8316->jack->status & SND_JACK_MICROPHONE) {
|
||||
es8316_disable_micbias_for_mic_gnd_short_detect(component);
|
||||
snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0);
|
||||
}
|
||||
|
||||
es8316->jack = NULL;
|
||||
|
||||
mutex_unlock(&es8316->lock);
|
||||
}
|
||||
|
||||
static int es8316_set_jack(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *jack, void *data)
|
||||
{
|
||||
if (jack)
|
||||
es8316_enable_jack_detect(component, jack);
|
||||
else
|
||||
es8316_disable_jack_detect(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es8316_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
es8316->component = component;
|
||||
|
||||
/* Reset codec and enable current state machine */
|
||||
snd_soc_component_write(component, ES8316_RESET, 0x3f);
|
||||
usleep_range(5000, 5500);
|
||||
@@ -555,6 +717,7 @@ static int es8316_probe(struct snd_soc_component *component)
|
||||
|
||||
static const struct snd_soc_component_driver soc_component_dev_es8316 = {
|
||||
.probe = es8316_probe,
|
||||
.set_jack = es8316_set_jack,
|
||||
.controls = es8316_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(es8316_snd_controls),
|
||||
.dapm_widgets = es8316_dapm_widgets,
|
||||
@@ -566,18 +729,29 @@ static const struct snd_soc_component_driver soc_component_dev_es8316 = {
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
|
||||
static const struct regmap_range es8316_volatile_ranges[] = {
|
||||
regmap_reg_range(ES8316_GPIO_FLAG, ES8316_GPIO_FLAG),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table es8316_volatile_table = {
|
||||
.yes_ranges = es8316_volatile_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(es8316_volatile_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config es8316_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x53,
|
||||
.volatile_table = &es8316_volatile_table,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int es8316_i2c_probe(struct i2c_client *i2c_client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &i2c_client->dev;
|
||||
struct es8316_priv *es8316;
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
|
||||
es8316 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8316_priv),
|
||||
GFP_KERNEL);
|
||||
@@ -586,9 +760,23 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client,
|
||||
|
||||
i2c_set_clientdata(i2c_client, es8316);
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
es8316->regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap);
|
||||
if (IS_ERR(es8316->regmap))
|
||||
return PTR_ERR(es8316->regmap);
|
||||
|
||||
es8316->irq = i2c_client->irq;
|
||||
mutex_init(&es8316->lock);
|
||||
|
||||
ret = devm_request_threaded_irq(dev, es8316->irq, NULL, es8316_irq,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
"es8316", es8316);
|
||||
if (ret == 0) {
|
||||
/* Gets re-enabled by es8316_set_jack() */
|
||||
disable_irq(es8316->irq);
|
||||
} else {
|
||||
dev_warn(dev, "Failed to get IRQ %d: %d\n", es8316->irq, ret);
|
||||
es8316->irq = -ENXIO;
|
||||
}
|
||||
|
||||
return devm_snd_soc_register_component(&i2c_client->dev,
|
||||
&soc_component_dev_es8316,
|
||||
|
@@ -126,4 +126,11 @@
|
||||
#define ES8316_SERDATA2_LEN_16 0x0c
|
||||
#define ES8316_SERDATA2_LEN_32 0x10
|
||||
|
||||
/* ES8316_GPIO_DEBOUNCE */
|
||||
#define ES8316_GPIO_ENABLE_INTERRUPT 0x02
|
||||
|
||||
/* ES8316_GPIO_FLAG */
|
||||
#define ES8316_GPIO_FLAG_GM_NOT_SHORTED 0x02
|
||||
#define ES8316_GPIO_FLAG_HP_NOT_INSERTED 0x04
|
||||
|
||||
#endif
|
||||
|
@@ -1400,24 +1400,20 @@ static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
|
||||
if (ret != 0) {
|
||||
dev_err(component->dev,
|
||||
"Failed to set digital mute: %d\n", ret);
|
||||
mutex_unlock(&pcm512x->mutex);
|
||||
return ret;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
regmap_read_poll_timeout(pcm512x->regmap,
|
||||
PCM512x_ANALOG_MUTE_DET,
|
||||
mute_det, (mute_det & 0x3) == 0,
|
||||
200, 10000);
|
||||
|
||||
mutex_unlock(&pcm512x->mutex);
|
||||
} else {
|
||||
pcm512x->mute &= ~0x1;
|
||||
ret = pcm512x_update_mute(pcm512x);
|
||||
if (ret != 0) {
|
||||
dev_err(component->dev,
|
||||
"Failed to update digital mute: %d\n", ret);
|
||||
mutex_unlock(&pcm512x->mutex);
|
||||
return ret;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
regmap_read_poll_timeout(pcm512x->regmap,
|
||||
@@ -1428,9 +1424,10 @@ static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
|
||||
200, 10000);
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&pcm512x->mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops pcm512x_dai_ops = {
|
||||
|
519
sound/soc/codecs/rk3328_codec.c
Normal file
519
sound/soc/codecs/rk3328_codec.c
Normal file
@@ -0,0 +1,519 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// rk3328 ALSA SoC Audio driver
|
||||
//
|
||||
// Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include "rk3328_codec.h"
|
||||
|
||||
/*
|
||||
* volume setting
|
||||
* 0: -39dB
|
||||
* 26: 0dB
|
||||
* 31: 6dB
|
||||
* Step: 1.5dB
|
||||
*/
|
||||
#define OUT_VOLUME (0x18)
|
||||
#define RK3328_GRF_SOC_CON2 (0x0408)
|
||||
#define RK3328_GRF_SOC_CON10 (0x0428)
|
||||
#define INITIAL_FREQ (11289600)
|
||||
|
||||
struct rk3328_codec_priv {
|
||||
struct regmap *regmap;
|
||||
struct regmap *grf;
|
||||
struct clk *mclk;
|
||||
struct clk *pclk;
|
||||
unsigned int sclk;
|
||||
int spk_depop_time; /* msec */
|
||||
};
|
||||
|
||||
static const struct reg_default rk3328_codec_reg_defaults[] = {
|
||||
{ CODEC_RESET, 0x03 },
|
||||
{ DAC_INIT_CTRL1, 0x00 },
|
||||
{ DAC_INIT_CTRL2, 0x50 },
|
||||
{ DAC_INIT_CTRL3, 0x0e },
|
||||
{ DAC_PRECHARGE_CTRL, 0x01 },
|
||||
{ DAC_PWR_CTRL, 0x00 },
|
||||
{ DAC_CLK_CTRL, 0x00 },
|
||||
{ HPMIX_CTRL, 0x00 },
|
||||
{ HPOUT_CTRL, 0x00 },
|
||||
{ HPOUTL_GAIN_CTRL, 0x00 },
|
||||
{ HPOUTR_GAIN_CTRL, 0x00 },
|
||||
{ HPOUT_POP_CTRL, 0x11 },
|
||||
};
|
||||
|
||||
static int rk3328_codec_reset(struct rk3328_codec_priv *rk3328)
|
||||
{
|
||||
regmap_write(rk3328->regmap, CODEC_RESET, 0x00);
|
||||
mdelay(10);
|
||||
regmap_write(rk3328->regmap, CODEC_RESET, 0x03);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
{
|
||||
struct rk3328_codec_priv *rk3328 =
|
||||
snd_soc_component_get_drvdata(dai->component);
|
||||
unsigned int val;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
val = PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL1,
|
||||
PIN_DIRECTION_MASK | DAC_I2S_MODE_MASK, val);
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
case SND_SOC_DAIFMT_DSP_B:
|
||||
val = DAC_MODE_PCM;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
val = DAC_MODE_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
val = DAC_MODE_RJM;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
val = DAC_MODE_LJM;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2,
|
||||
DAC_MODE_MASK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk3328_analog_output(struct rk3328_codec_priv *rk3328, int mute)
|
||||
{
|
||||
unsigned int val = BIT(17);
|
||||
|
||||
if (mute)
|
||||
val |= BIT(1);
|
||||
|
||||
regmap_write(rk3328->grf, RK3328_GRF_SOC_CON10, val);
|
||||
}
|
||||
|
||||
static int rk3328_digital_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct rk3328_codec_priv *rk3328 =
|
||||
snd_soc_component_get_drvdata(dai->component);
|
||||
unsigned int val;
|
||||
|
||||
if (mute)
|
||||
val = HPOUTL_MUTE | HPOUTR_MUTE;
|
||||
else
|
||||
val = HPOUTL_UNMUTE | HPOUTR_UNMUTE;
|
||||
|
||||
regmap_update_bits(rk3328->regmap, HPOUT_CTRL,
|
||||
HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk3328_codec_power_on(struct rk3328_codec_priv *rk3328, int wait_ms)
|
||||
{
|
||||
regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
|
||||
DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_PRECHARGE);
|
||||
mdelay(10);
|
||||
regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
|
||||
DAC_CHARGE_CURRENT_ALL_MASK,
|
||||
DAC_CHARGE_CURRENT_ALL_ON);
|
||||
mdelay(wait_ms);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk3328_codec_power_off(struct rk3328_codec_priv *rk3328, int wait_ms)
|
||||
{
|
||||
regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
|
||||
DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_DISCHARGE);
|
||||
mdelay(10);
|
||||
regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
|
||||
DAC_CHARGE_CURRENT_ALL_MASK,
|
||||
DAC_CHARGE_CURRENT_ALL_ON);
|
||||
mdelay(wait_ms);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rk3328_reg_msk_val playback_open_list[] = {
|
||||
{ DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_ON },
|
||||
{ DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,
|
||||
DACL_PATH_REFV_ON | DACR_PATH_REFV_ON },
|
||||
{ DAC_PWR_CTRL, HPOUTL_ZERO_CROSSING_MASK | HPOUTR_ZERO_CROSSING_MASK,
|
||||
HPOUTL_ZERO_CROSSING_ON | HPOUTR_ZERO_CROSSING_ON },
|
||||
{ HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,
|
||||
HPOUTR_POP_WORK | HPOUTL_POP_WORK },
|
||||
{ HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_EN | HPMIXR_EN },
|
||||
{ HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,
|
||||
HPMIXL_INIT_EN | HPMIXR_INIT_EN },
|
||||
{ HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_EN | HPOUTR_EN },
|
||||
{ HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,
|
||||
HPOUTL_INIT_EN | HPOUTR_INIT_EN },
|
||||
{ DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,
|
||||
DACL_REFV_ON | DACR_REFV_ON },
|
||||
{ DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,
|
||||
DACL_CLK_ON | DACR_CLK_ON },
|
||||
{ DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_ON | DACR_ON },
|
||||
{ DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,
|
||||
DACL_INIT_ON | DACR_INIT_ON },
|
||||
{ DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,
|
||||
DACL_SELECT | DACR_SELECT },
|
||||
{ HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,
|
||||
HPMIXL_INIT2_EN | HPMIXR_INIT2_EN },
|
||||
{ HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,
|
||||
HPOUTL_UNMUTE | HPOUTR_UNMUTE },
|
||||
};
|
||||
|
||||
static int rk3328_codec_open_playback(struct rk3328_codec_priv *rk3328)
|
||||
{
|
||||
int i;
|
||||
|
||||
regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
|
||||
DAC_CHARGE_CURRENT_ALL_MASK,
|
||||
DAC_CHARGE_CURRENT_I);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(playback_open_list); i++) {
|
||||
regmap_update_bits(rk3328->regmap,
|
||||
playback_open_list[i].reg,
|
||||
playback_open_list[i].msk,
|
||||
playback_open_list[i].val);
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
msleep(rk3328->spk_depop_time);
|
||||
rk3328_analog_output(rk3328, 1);
|
||||
|
||||
regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL,
|
||||
HPOUTL_GAIN_MASK, OUT_VOLUME);
|
||||
regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL,
|
||||
HPOUTR_GAIN_MASK, OUT_VOLUME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rk3328_reg_msk_val playback_close_list[] = {
|
||||
{ HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,
|
||||
HPMIXL_INIT2_DIS | HPMIXR_INIT2_DIS },
|
||||
{ DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,
|
||||
DACL_UNSELECT | DACR_UNSELECT },
|
||||
{ HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,
|
||||
HPOUTL_MUTE | HPOUTR_MUTE },
|
||||
{ HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,
|
||||
HPOUTL_INIT_DIS | HPOUTR_INIT_DIS },
|
||||
{ HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_DIS | HPOUTR_DIS },
|
||||
{ HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_DIS | HPMIXR_DIS },
|
||||
{ DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_OFF | DACR_OFF },
|
||||
{ DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,
|
||||
DACL_CLK_OFF | DACR_CLK_OFF },
|
||||
{ DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,
|
||||
DACL_REFV_OFF | DACR_REFV_OFF },
|
||||
{ HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,
|
||||
HPOUTR_POP_XCHARGE | HPOUTL_POP_XCHARGE },
|
||||
{ DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,
|
||||
DACL_PATH_REFV_OFF | DACR_PATH_REFV_OFF },
|
||||
{ DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_OFF },
|
||||
{ HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,
|
||||
HPMIXL_INIT_DIS | HPMIXR_INIT_DIS },
|
||||
{ DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,
|
||||
DACL_INIT_OFF | DACR_INIT_OFF },
|
||||
};
|
||||
|
||||
static int rk3328_codec_close_playback(struct rk3328_codec_priv *rk3328)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
rk3328_analog_output(rk3328, 0);
|
||||
|
||||
regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL,
|
||||
HPOUTL_GAIN_MASK, 0);
|
||||
regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL,
|
||||
HPOUTR_GAIN_MASK, 0);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(playback_close_list); i++) {
|
||||
regmap_update_bits(rk3328->regmap,
|
||||
playback_close_list[i].reg,
|
||||
playback_close_list[i].msk,
|
||||
playback_close_list[i].val);
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
/* Workaround for silence when changed Fs 48 -> 44.1kHz */
|
||||
rk3328_codec_reset(rk3328);
|
||||
|
||||
regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
|
||||
DAC_CHARGE_CURRENT_ALL_MASK,
|
||||
DAC_CHARGE_CURRENT_ALL_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk3328_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct rk3328_codec_priv *rk3328 =
|
||||
snd_soc_component_get_drvdata(dai->component);
|
||||
unsigned int val = 0;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
val = DAC_VDL_16BITS;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S20_3LE:
|
||||
val = DAC_VDL_20BITS;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
val = DAC_VDL_24BITS;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
val = DAC_VDL_32BITS;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2, DAC_VDL_MASK, val);
|
||||
|
||||
val = DAC_WL_32BITS | DAC_RST_DIS;
|
||||
regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL3,
|
||||
DAC_WL_MASK | DAC_RST_MASK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk3328_pcm_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct rk3328_codec_priv *rk3328 =
|
||||
snd_soc_component_get_drvdata(dai->component);
|
||||
|
||||
return rk3328_codec_open_playback(rk3328);
|
||||
}
|
||||
|
||||
static void rk3328_pcm_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct rk3328_codec_priv *rk3328 =
|
||||
snd_soc_component_get_drvdata(dai->component);
|
||||
|
||||
rk3328_codec_close_playback(rk3328);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops rk3328_dai_ops = {
|
||||
.hw_params = rk3328_hw_params,
|
||||
.set_fmt = rk3328_set_dai_fmt,
|
||||
.digital_mute = rk3328_digital_mute,
|
||||
.startup = rk3328_pcm_startup,
|
||||
.shutdown = rk3328_pcm_shutdown,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver rk3328_dai[] = {
|
||||
{
|
||||
.name = "rk3328-hifi",
|
||||
.id = RK3328_HIFI,
|
||||
.playback = {
|
||||
.stream_name = "HIFI Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE),
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "HIFI Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_96000,
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE),
|
||||
},
|
||||
.ops = &rk3328_dai_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int rk3328_codec_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct rk3328_codec_priv *rk3328 =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
|
||||
rk3328_codec_reset(rk3328);
|
||||
rk3328_codec_power_on(rk3328, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk3328_codec_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct rk3328_codec_priv *rk3328 =
|
||||
snd_soc_component_get_drvdata(component);
|
||||
|
||||
rk3328_codec_close_playback(rk3328);
|
||||
rk3328_codec_power_off(rk3328, 0);
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver soc_codec_rk3328 = {
|
||||
.probe = rk3328_codec_probe,
|
||||
.remove = rk3328_codec_remove,
|
||||
};
|
||||
|
||||
static bool rk3328_codec_write_read_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CODEC_RESET:
|
||||
case DAC_INIT_CTRL1:
|
||||
case DAC_INIT_CTRL2:
|
||||
case DAC_INIT_CTRL3:
|
||||
case DAC_PRECHARGE_CTRL:
|
||||
case DAC_PWR_CTRL:
|
||||
case DAC_CLK_CTRL:
|
||||
case HPMIX_CTRL:
|
||||
case DAC_SELECT:
|
||||
case HPOUT_CTRL:
|
||||
case HPOUTL_GAIN_CTRL:
|
||||
case HPOUTR_GAIN_CTRL:
|
||||
case HPOUT_POP_CTRL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool rk3328_codec_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CODEC_RESET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config rk3328_codec_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = HPOUT_POP_CTRL,
|
||||
.writeable_reg = rk3328_codec_write_read_reg,
|
||||
.readable_reg = rk3328_codec_write_read_reg,
|
||||
.volatile_reg = rk3328_codec_volatile_reg,
|
||||
.reg_defaults = rk3328_codec_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(rk3328_codec_reg_defaults),
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static int rk3328_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *rk3328_np = pdev->dev.of_node;
|
||||
struct rk3328_codec_priv *rk3328;
|
||||
struct resource *res;
|
||||
struct regmap *grf;
|
||||
void __iomem *base;
|
||||
int ret = 0;
|
||||
|
||||
rk3328 = devm_kzalloc(&pdev->dev, sizeof(*rk3328), GFP_KERNEL);
|
||||
if (!rk3328)
|
||||
return -ENOMEM;
|
||||
|
||||
grf = syscon_regmap_lookup_by_phandle(rk3328_np,
|
||||
"rockchip,grf");
|
||||
if (IS_ERR(grf)) {
|
||||
dev_err(&pdev->dev, "missing 'rockchip,grf'\n");
|
||||
return PTR_ERR(grf);
|
||||
}
|
||||
rk3328->grf = grf;
|
||||
/* enable i2s_acodec_en */
|
||||
regmap_write(grf, RK3328_GRF_SOC_CON2,
|
||||
(BIT(14) << 16 | BIT(14)));
|
||||
|
||||
ret = of_property_read_u32(rk3328_np, "spk-depop-time-ms",
|
||||
&rk3328->spk_depop_time);
|
||||
if (ret < 0) {
|
||||
dev_info(&pdev->dev, "spk_depop_time use default value.\n");
|
||||
rk3328->spk_depop_time = 200;
|
||||
}
|
||||
|
||||
rk3328_analog_output(rk3328, 0);
|
||||
|
||||
rk3328->mclk = devm_clk_get(&pdev->dev, "mclk");
|
||||
if (IS_ERR(rk3328->mclk))
|
||||
return PTR_ERR(rk3328->mclk);
|
||||
|
||||
ret = clk_prepare_enable(rk3328->mclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
clk_set_rate(rk3328->mclk, INITIAL_FREQ);
|
||||
|
||||
rk3328->pclk = devm_clk_get(&pdev->dev, "pclk");
|
||||
if (IS_ERR(rk3328->pclk)) {
|
||||
dev_err(&pdev->dev, "can't get acodec pclk\n");
|
||||
return PTR_ERR(rk3328->pclk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(rk3328->pclk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to enable acodec pclk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
rk3328->regmap = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
&rk3328_codec_regmap_config);
|
||||
if (IS_ERR(rk3328->regmap))
|
||||
return PTR_ERR(rk3328->regmap);
|
||||
|
||||
platform_set_drvdata(pdev, rk3328);
|
||||
|
||||
return devm_snd_soc_register_component(&pdev->dev, &soc_codec_rk3328,
|
||||
rk3328_dai,
|
||||
ARRAY_SIZE(rk3328_dai));
|
||||
}
|
||||
|
||||
static const struct of_device_id rk3328_codec_of_match[] = {
|
||||
{ .compatible = "rockchip,rk3328-codec", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk3328_codec_of_match);
|
||||
|
||||
static struct platform_driver rk3328_codec_driver = {
|
||||
.driver = {
|
||||
.name = "rk3328-codec",
|
||||
.of_match_table = of_match_ptr(rk3328_codec_of_match),
|
||||
},
|
||||
.probe = rk3328_platform_probe,
|
||||
};
|
||||
module_platform_driver(rk3328_codec_driver);
|
||||
|
||||
MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("ASoC rk3328 codec driver");
|
||||
MODULE_LICENSE("GPL v2");
|
210
sound/soc/codecs/rk3328_codec.h
Normal file
210
sound/soc/codecs/rk3328_codec.h
Normal file
@@ -0,0 +1,210 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* rk3328 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _RK3328_CODEC_H
|
||||
#define _RK3328_CODEC_H
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
/* codec register */
|
||||
#define CODEC_RESET (0x00 << 2)
|
||||
#define DAC_INIT_CTRL1 (0x03 << 2)
|
||||
#define DAC_INIT_CTRL2 (0x04 << 2)
|
||||
#define DAC_INIT_CTRL3 (0x05 << 2)
|
||||
#define DAC_PRECHARGE_CTRL (0x22 << 2)
|
||||
#define DAC_PWR_CTRL (0x23 << 2)
|
||||
#define DAC_CLK_CTRL (0x24 << 2)
|
||||
#define HPMIX_CTRL (0x25 << 2)
|
||||
#define DAC_SELECT (0x26 << 2)
|
||||
#define HPOUT_CTRL (0x27 << 2)
|
||||
#define HPOUTL_GAIN_CTRL (0x28 << 2)
|
||||
#define HPOUTR_GAIN_CTRL (0x29 << 2)
|
||||
#define HPOUT_POP_CTRL (0x2a << 2)
|
||||
|
||||
/* REG00: CODEC_RESET */
|
||||
#define PWR_RST_BYPASS_DIS (0x0 << 6)
|
||||
#define PWR_RST_BYPASS_EN (0x1 << 6)
|
||||
#define DIG_CORE_RST (0x0 << 1)
|
||||
#define DIG_CORE_WORK (0x1 << 1)
|
||||
#define SYS_RST (0x0 << 0)
|
||||
#define SYS_WORK (0x1 << 0)
|
||||
|
||||
/* REG03: DAC_INIT_CTRL1 */
|
||||
#define PIN_DIRECTION_MASK BIT(5)
|
||||
#define PIN_DIRECTION_IN (0x0 << 5)
|
||||
#define PIN_DIRECTION_OUT (0x1 << 5)
|
||||
#define DAC_I2S_MODE_MASK BIT(4)
|
||||
#define DAC_I2S_MODE_SLAVE (0x0 << 4)
|
||||
#define DAC_I2S_MODE_MASTER (0x1 << 4)
|
||||
|
||||
/* REG04: DAC_INIT_CTRL2 */
|
||||
#define DAC_I2S_LRP_MASK BIT(7)
|
||||
#define DAC_I2S_LRP_NORMAL (0x0 << 7)
|
||||
#define DAC_I2S_LRP_REVERSAL (0x1 << 7)
|
||||
#define DAC_VDL_MASK GENMASK(6, 5)
|
||||
#define DAC_VDL_16BITS (0x0 << 5)
|
||||
#define DAC_VDL_20BITS (0x1 << 5)
|
||||
#define DAC_VDL_24BITS (0x2 << 5)
|
||||
#define DAC_VDL_32BITS (0x3 << 5)
|
||||
#define DAC_MODE_MASK GENMASK(4, 3)
|
||||
#define DAC_MODE_RJM (0x0 << 3)
|
||||
#define DAC_MODE_LJM (0x1 << 3)
|
||||
#define DAC_MODE_I2S (0x2 << 3)
|
||||
#define DAC_MODE_PCM (0x3 << 3)
|
||||
#define DAC_LR_SWAP_MASK BIT(2)
|
||||
#define DAC_LR_SWAP_DIS (0x0 << 2)
|
||||
#define DAC_LR_SWAP_EN (0x1 << 2)
|
||||
|
||||
/* REG05: DAC_INIT_CTRL3 */
|
||||
#define DAC_WL_MASK GENMASK(3, 2)
|
||||
#define DAC_WL_16BITS (0x0 << 2)
|
||||
#define DAC_WL_20BITS (0x1 << 2)
|
||||
#define DAC_WL_24BITS (0x2 << 2)
|
||||
#define DAC_WL_32BITS (0x3 << 2)
|
||||
#define DAC_RST_MASK BIT(1)
|
||||
#define DAC_RST_EN (0x0 << 1)
|
||||
#define DAC_RST_DIS (0x1 << 1)
|
||||
#define DAC_BCP_MASK BIT(0)
|
||||
#define DAC_BCP_NORMAL (0x0 << 0)
|
||||
#define DAC_BCP_REVERSAL (0x1 << 0)
|
||||
|
||||
/* REG22: DAC_PRECHARGE_CTRL */
|
||||
#define DAC_CHARGE_XCHARGE_MASK BIT(7)
|
||||
#define DAC_CHARGE_DISCHARGE (0x0 << 7)
|
||||
#define DAC_CHARGE_PRECHARGE (0x1 << 7)
|
||||
#define DAC_CHARGE_CURRENT_64I_MASK BIT(6)
|
||||
#define DAC_CHARGE_CURRENT_64I (0x1 << 6)
|
||||
#define DAC_CHARGE_CURRENT_32I_MASK BIT(5)
|
||||
#define DAC_CHARGE_CURRENT_32I (0x1 << 5)
|
||||
#define DAC_CHARGE_CURRENT_16I_MASK BIT(4)
|
||||
#define DAC_CHARGE_CURRENT_16I (0x1 << 4)
|
||||
#define DAC_CHARGE_CURRENT_08I_MASK BIT(3)
|
||||
#define DAC_CHARGE_CURRENT_08I (0x1 << 3)
|
||||
#define DAC_CHARGE_CURRENT_04I_MASK BIT(2)
|
||||
#define DAC_CHARGE_CURRENT_04I (0x1 << 2)
|
||||
#define DAC_CHARGE_CURRENT_02I_MASK BIT(1)
|
||||
#define DAC_CHARGE_CURRENT_02I (0x1 << 1)
|
||||
#define DAC_CHARGE_CURRENT_I_MASK BIT(0)
|
||||
#define DAC_CHARGE_CURRENT_I (0x1 << 0)
|
||||
#define DAC_CHARGE_CURRENT_ALL_MASK GENMASK(6, 0)
|
||||
#define DAC_CHARGE_CURRENT_ALL_OFF 0x00
|
||||
#define DAC_CHARGE_CURRENT_ALL_ON 0x7f
|
||||
|
||||
/* REG23: DAC_PWR_CTRL */
|
||||
#define DAC_PWR_MASK BIT(6)
|
||||
#define DAC_PWR_OFF (0x0 << 6)
|
||||
#define DAC_PWR_ON (0x1 << 6)
|
||||
#define DACL_PATH_REFV_MASK BIT(5)
|
||||
#define DACL_PATH_REFV_OFF (0x0 << 5)
|
||||
#define DACL_PATH_REFV_ON (0x1 << 5)
|
||||
#define HPOUTL_ZERO_CROSSING_MASK BIT(4)
|
||||
#define HPOUTL_ZERO_CROSSING_OFF (0x0 << 4)
|
||||
#define HPOUTL_ZERO_CROSSING_ON (0x1 << 4)
|
||||
#define DACR_PATH_REFV_MASK BIT(1)
|
||||
#define DACR_PATH_REFV_OFF (0x0 << 1)
|
||||
#define DACR_PATH_REFV_ON (0x1 << 1)
|
||||
#define HPOUTR_ZERO_CROSSING_MASK BIT(0)
|
||||
#define HPOUTR_ZERO_CROSSING_OFF (0x0 << 0)
|
||||
#define HPOUTR_ZERO_CROSSING_ON (0x1 << 0)
|
||||
|
||||
/* REG24: DAC_CLK_CTRL */
|
||||
#define DACL_REFV_MASK BIT(7)
|
||||
#define DACL_REFV_OFF (0x0 << 7)
|
||||
#define DACL_REFV_ON (0x1 << 7)
|
||||
#define DACL_CLK_MASK BIT(6)
|
||||
#define DACL_CLK_OFF (0x0 << 6)
|
||||
#define DACL_CLK_ON (0x1 << 6)
|
||||
#define DACL_MASK BIT(5)
|
||||
#define DACL_OFF (0x0 << 5)
|
||||
#define DACL_ON (0x1 << 5)
|
||||
#define DACL_INIT_MASK BIT(4)
|
||||
#define DACL_INIT_OFF (0x0 << 4)
|
||||
#define DACL_INIT_ON (0x1 << 4)
|
||||
#define DACR_REFV_MASK BIT(3)
|
||||
#define DACR_REFV_OFF (0x0 << 3)
|
||||
#define DACR_REFV_ON (0x1 << 3)
|
||||
#define DACR_CLK_MASK BIT(2)
|
||||
#define DACR_CLK_OFF (0x0 << 2)
|
||||
#define DACR_CLK_ON (0x1 << 2)
|
||||
#define DACR_MASK BIT(1)
|
||||
#define DACR_OFF (0x0 << 1)
|
||||
#define DACR_ON (0x1 << 1)
|
||||
#define DACR_INIT_MASK BIT(0)
|
||||
#define DACR_INIT_OFF (0x0 << 0)
|
||||
#define DACR_INIT_ON (0x1 << 0)
|
||||
|
||||
/* REG25: HPMIX_CTRL*/
|
||||
#define HPMIXL_MASK BIT(6)
|
||||
#define HPMIXL_DIS (0x0 << 6)
|
||||
#define HPMIXL_EN (0x1 << 6)
|
||||
#define HPMIXL_INIT_MASK BIT(5)
|
||||
#define HPMIXL_INIT_DIS (0x0 << 5)
|
||||
#define HPMIXL_INIT_EN (0x1 << 5)
|
||||
#define HPMIXL_INIT2_MASK BIT(4)
|
||||
#define HPMIXL_INIT2_DIS (0x0 << 4)
|
||||
#define HPMIXL_INIT2_EN (0x1 << 4)
|
||||
#define HPMIXR_MASK BIT(2)
|
||||
#define HPMIXR_DIS (0x0 << 2)
|
||||
#define HPMIXR_EN (0x1 << 2)
|
||||
#define HPMIXR_INIT_MASK BIT(1)
|
||||
#define HPMIXR_INIT_DIS (0x0 << 1)
|
||||
#define HPMIXR_INIT_EN (0x1 << 1)
|
||||
#define HPMIXR_INIT2_MASK BIT(0)
|
||||
#define HPMIXR_INIT2_DIS (0x0 << 0)
|
||||
#define HPMIXR_INIT2_EN (0x1 << 0)
|
||||
|
||||
/* REG26: DAC_SELECT */
|
||||
#define DACL_SELECT_MASK BIT(4)
|
||||
#define DACL_UNSELECT (0x0 << 4)
|
||||
#define DACL_SELECT (0x1 << 4)
|
||||
#define DACR_SELECT_MASK BIT(0)
|
||||
#define DACR_UNSELECT (0x0 << 0)
|
||||
#define DACR_SELECT (0x1 << 0)
|
||||
|
||||
/* REG27: HPOUT_CTRL */
|
||||
#define HPOUTL_MASK BIT(7)
|
||||
#define HPOUTL_DIS (0x0 << 7)
|
||||
#define HPOUTL_EN (0x1 << 7)
|
||||
#define HPOUTL_INIT_MASK BIT(6)
|
||||
#define HPOUTL_INIT_DIS (0x0 << 6)
|
||||
#define HPOUTL_INIT_EN (0x1 << 6)
|
||||
#define HPOUTL_MUTE_MASK BIT(5)
|
||||
#define HPOUTL_MUTE (0x0 << 5)
|
||||
#define HPOUTL_UNMUTE (0x1 << 5)
|
||||
#define HPOUTR_MASK BIT(4)
|
||||
#define HPOUTR_DIS (0x0 << 4)
|
||||
#define HPOUTR_EN (0x1 << 4)
|
||||
#define HPOUTR_INIT_MASK BIT(3)
|
||||
#define HPOUTR_INIT_DIS (0x0 << 3)
|
||||
#define HPOUTR_INIT_EN (0x1 << 3)
|
||||
#define HPOUTR_MUTE_MASK BIT(2)
|
||||
#define HPOUTR_MUTE (0x0 << 2)
|
||||
#define HPOUTR_UNMUTE (0x1 << 2)
|
||||
|
||||
/* REG28: HPOUTL_GAIN_CTRL */
|
||||
#define HPOUTL_GAIN_MASK GENMASK(4, 0)
|
||||
|
||||
/* REG29: HPOUTR_GAIN_CTRL */
|
||||
#define HPOUTR_GAIN_MASK GENMASK(4, 0)
|
||||
|
||||
/* REG2a: HPOUT_POP_CTRL */
|
||||
#define HPOUTR_POP_MASK GENMASK(5, 4)
|
||||
#define HPOUTR_POP_XCHARGE (0x1 << 4)
|
||||
#define HPOUTR_POP_WORK (0x2 << 4)
|
||||
#define HPOUTL_POP_MASK GENMASK(1, 0)
|
||||
#define HPOUTL_POP_XCHARGE (0x1 << 0)
|
||||
#define HPOUTL_POP_WORK (0x2 << 0)
|
||||
|
||||
#define RK3328_HIFI 0
|
||||
|
||||
struct rk3328_reg_msk_val {
|
||||
unsigned int reg;
|
||||
unsigned int msk;
|
||||
unsigned int val;
|
||||
};
|
||||
|
||||
#endif
|
@@ -1128,8 +1128,11 @@ static int rt274_i2c_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
regmap_read(rt274->regmap,
|
||||
ret = regmap_read(rt274->regmap,
|
||||
RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val != RT274_VENDOR_ID) {
|
||||
dev_err(&i2c->dev,
|
||||
"Device with ID register %#x is not rt274\n", val);
|
||||
|
@@ -2512,6 +2512,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
|
||||
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000);
|
||||
regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x2000);
|
||||
regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005);
|
||||
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4);
|
||||
|
||||
mutex_unlock(&rt5682->calibrate_mutex);
|
||||
|
||||
|
@@ -1837,9 +1837,6 @@ static int wm8904_set_bias_level(struct snd_soc_component *component,
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
ret = clk_prepare_enable(wm8904->mclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
@@ -1864,6 +1861,15 @@ static int wm8904_set_bias_level(struct snd_soc_component *component,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(wm8904->mclk);
|
||||
if (ret) {
|
||||
dev_err(component->dev,
|
||||
"Failed to enable MCLK: %d\n", ret);
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies),
|
||||
wm8904->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regcache_cache_only(wm8904->regmap, false);
|
||||
regcache_sync(wm8904->regmap);
|
||||
|
||||
@@ -2108,16 +2114,13 @@ static const struct regmap_config wm8904_regmap = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static enum wm8904_type wm8904_data = WM8904;
|
||||
static enum wm8904_type wm8912_data = WM8912;
|
||||
|
||||
static const struct of_device_id wm8904_of_match[] = {
|
||||
{
|
||||
.compatible = "wlf,wm8904",
|
||||
.data = &wm8904_data,
|
||||
.data = (void *)WM8904,
|
||||
}, {
|
||||
.compatible = "wlf,wm8912",
|
||||
.data = &wm8912_data,
|
||||
.data = (void *)WM8912,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
@@ -2158,7 +2161,7 @@ static int wm8904_i2c_probe(struct i2c_client *i2c,
|
||||
match = of_match_node(wm8904_of_match, i2c->dev.of_node);
|
||||
if (match == NULL)
|
||||
return -EINVAL;
|
||||
wm8904->devtype = *((enum wm8904_type *)match->data);
|
||||
wm8904->devtype = (enum wm8904_type)match->data;
|
||||
} else {
|
||||
wm8904->devtype = id->driver_data;
|
||||
}
|
||||
|
Reference in New Issue
Block a user