mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 16:54:20 +08:00
ASoC: rt5682: split i2c driver into separate module
With SND_SOC_AMD_RV_RT5682_MACH using the i2c version of the driver, we can easily get a build failure when I2C is built-in but soundwire is not: WARNING: unmet direct dependencies detected for SND_SOC_RT5682 Depends on [m]: SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && (I2C [=y] || SOUNDWIRE [=m]) && (SOUNDWIRE [=m] || !SOUNDWIRE [=m]) && (I2C [=y] || !I2C [=y]) Selected by [y]: - SND_SOC_AMD_RV_RT5682_MACH [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_AMD_ACP3x [=y] && I2C [=y] && CROS_EC [=y] Selected by [m]: - SND_SOC_RT5682_SDW [=m] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SOUNDWIRE [=m] && (I2C [=y] || !I2C [=y]) Rework the driver to have three separate modules, with the main driver just dealing with the common bits and the actual initialization as part of i2c and sdw specific modules. The conversion is fairly mechanical to keep it easy to review, i.e. it moves code around with the minimal required renaming and changes. Fixes:6b8e4e7db3
("ASoC: amd: Add machine driver for Raven based platform") Fixes:fd443a20c2
("ASoC: rt5682: fix I2C/Soundwire dependencies") Signed-off-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Link: https://lore.kernel.org/r/20200528091851.2889754-1-arnd@arndb.de Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
2b1878afc8
commit
a50067d4f3
@ -29,7 +29,7 @@ config SND_SOC_AMD_ACP3x
|
||||
|
||||
config SND_SOC_AMD_RV_RT5682_MACH
|
||||
tristate "AMD RV support for RT5682"
|
||||
select SND_SOC_RT5682
|
||||
select SND_SOC_RT5682_I2C
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_CROS_EC_CODEC
|
||||
select I2C_CROS_EC_TUNNEL
|
||||
|
@ -168,7 +168,7 @@ config SND_SOC_ALL_CODECS
|
||||
imply SND_SOC_RT5668
|
||||
imply SND_SOC_RT5670
|
||||
imply SND_SOC_RT5677
|
||||
imply SND_SOC_RT5682
|
||||
imply SND_SOC_RT5682_I2C
|
||||
imply SND_SOC_RT5682_SDW
|
||||
imply SND_SOC_RT700_SDW
|
||||
imply SND_SOC_RT711_SDW
|
||||
@ -1143,14 +1143,15 @@ config SND_SOC_RT5677_SPI
|
||||
|
||||
config SND_SOC_RT5682
|
||||
tristate
|
||||
depends on I2C || SOUNDWIRE
|
||||
depends on SOUNDWIRE || !SOUNDWIRE
|
||||
depends on I2C || !I2C
|
||||
|
||||
config SND_SOC_RT5682_I2C
|
||||
tristate
|
||||
depends on I2C
|
||||
select SND_SOC_RT5682
|
||||
|
||||
config SND_SOC_RT5682_SDW
|
||||
tristate "Realtek RT5682 Codec - SDW"
|
||||
depends on SOUNDWIRE
|
||||
depends on I2C || !I2C
|
||||
select SND_SOC_RT5682
|
||||
select REGMAP_SOUNDWIRE
|
||||
|
||||
|
@ -179,6 +179,7 @@ snd-soc-rt5677-objs := rt5677.o
|
||||
snd-soc-rt5677-spi-objs := rt5677-spi.o
|
||||
snd-soc-rt5682-objs := rt5682.o
|
||||
snd-soc-rt5682-sdw-objs := rt5682-sdw.o
|
||||
snd-soc-rt5682-i2c-objs := rt5682-i2c.o
|
||||
snd-soc-rt700-objs := rt700.o rt700-sdw.o
|
||||
snd-soc-rt711-objs := rt711.o rt711-sdw.o
|
||||
snd-soc-rt715-objs := rt715.o rt715-sdw.o
|
||||
@ -481,6 +482,7 @@ obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
|
||||
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
|
||||
obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o
|
||||
obj-$(CONFIG_SND_SOC_RT5682) += snd-soc-rt5682.o
|
||||
obj-$(CONFIG_SND_SOC_RT5682_I2C) += snd-soc-rt5682-i2c.o
|
||||
obj-$(CONFIG_SND_SOC_RT5682_SDW) += snd-soc-rt5682-sdw.o
|
||||
obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o
|
||||
obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o
|
||||
|
306
sound/soc/codecs/rt5682-i2c.c
Normal file
306
sound/soc/codecs/rt5682-i2c.c
Normal file
@ -0,0 +1,306 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
// rt5682.c -- RT5682 ALSA SoC audio component driver
|
||||
//
|
||||
// Copyright 2018 Realtek Semiconductor Corp.
|
||||
// Author: Bard Liao <bardliao@realtek.com>
|
||||
//
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/rt5682.h>
|
||||
|
||||
#include "rl6231.h"
|
||||
#include "rt5682.h"
|
||||
|
||||
static const struct rt5682_platform_data i2s_default_platform_data = {
|
||||
.dmic1_data_pin = RT5682_DMIC1_DATA_GPIO2,
|
||||
.dmic1_clk_pin = RT5682_DMIC1_CLK_GPIO3,
|
||||
.jd_src = RT5682_JD1,
|
||||
.btndet_delay = 16,
|
||||
.dai_clk_names[RT5682_DAI_WCLK_IDX] = "rt5682-dai-wclk",
|
||||
.dai_clk_names[RT5682_DAI_BCLK_IDX] = "rt5682-dai-bclk",
|
||||
};
|
||||
|
||||
static const struct regmap_config rt5682_regmap = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 16,
|
||||
.max_register = RT5682_I2C_MODE,
|
||||
.volatile_reg = rt5682_volatile_register,
|
||||
.readable_reg = rt5682_readable_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.reg_defaults = rt5682_reg,
|
||||
.num_reg_defaults = RT5682_REG_NUM,
|
||||
.use_single_read = true,
|
||||
.use_single_write = true,
|
||||
};
|
||||
|
||||
static void rt5682_jd_check_handler(struct work_struct *work)
|
||||
{
|
||||
struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv,
|
||||
jd_check_work.work);
|
||||
|
||||
if (snd_soc_component_read32(rt5682->component, RT5682_AJD1_CTRL)
|
||||
& RT5682_JDH_RS_MASK) {
|
||||
/* jack out */
|
||||
rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
|
||||
|
||||
snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
|
||||
SND_JACK_HEADSET |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3);
|
||||
} else {
|
||||
schedule_delayed_work(&rt5682->jd_check_work, 500);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t rt5682_irq(int irq, void *data)
|
||||
{
|
||||
struct rt5682_priv *rt5682 = data;
|
||||
|
||||
mod_delayed_work(system_power_efficient_wq,
|
||||
&rt5682->jack_detect_work, msecs_to_jiffies(250));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver rt5682_dai[] = {
|
||||
{
|
||||
.name = "rt5682-aif1",
|
||||
.id = RT5682_AIF1,
|
||||
.playback = {
|
||||
.stream_name = "AIF1 Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "AIF1 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.ops = &rt5682_aif1_dai_ops,
|
||||
},
|
||||
{
|
||||
.name = "rt5682-aif2",
|
||||
.id = RT5682_AIF2,
|
||||
.capture = {
|
||||
.stream_name = "AIF2 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.ops = &rt5682_aif2_dai_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int rt5682_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct rt5682_platform_data *pdata = dev_get_platdata(&i2c->dev);
|
||||
struct rt5682_priv *rt5682;
|
||||
int i, ret;
|
||||
unsigned int val;
|
||||
|
||||
rt5682 = devm_kzalloc(&i2c->dev, sizeof(struct rt5682_priv),
|
||||
GFP_KERNEL);
|
||||
if (!rt5682)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(i2c, rt5682);
|
||||
|
||||
rt5682->pdata = i2s_default_platform_data;
|
||||
|
||||
if (pdata)
|
||||
rt5682->pdata = *pdata;
|
||||
else
|
||||
rt5682_parse_dt(rt5682, &i2c->dev);
|
||||
|
||||
rt5682->regmap = devm_regmap_init_i2c(i2c, &rt5682_regmap);
|
||||
if (IS_ERR(rt5682->regmap)) {
|
||||
ret = PTR_ERR(rt5682->regmap);
|
||||
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rt5682->supplies); i++)
|
||||
rt5682->supplies[i].supply = rt5682_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5682->supplies),
|
||||
rt5682->supplies);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(rt5682->supplies),
|
||||
rt5682->supplies);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(rt5682->pdata.ldo1_en)) {
|
||||
if (devm_gpio_request_one(&i2c->dev, rt5682->pdata.ldo1_en,
|
||||
GPIOF_OUT_INIT_HIGH, "rt5682"))
|
||||
dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
|
||||
}
|
||||
|
||||
/* Sleep for 300 ms miniumum */
|
||||
usleep_range(300000, 350000);
|
||||
|
||||
regmap_write(rt5682->regmap, RT5682_I2C_MODE, 0x1);
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
|
||||
if (val != DEVICE_ID) {
|
||||
dev_err(&i2c->dev,
|
||||
"Device with ID register %x is not rt5682\n", val);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_init(&rt5682->calibrate_mutex);
|
||||
rt5682_calibrate(rt5682);
|
||||
|
||||
rt5682_apply_patch_list(rt5682, &i2c->dev);
|
||||
|
||||
regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0000);
|
||||
|
||||
/* DMIC pin*/
|
||||
if (rt5682->pdata.dmic1_data_pin != RT5682_DMIC1_NULL) {
|
||||
switch (rt5682->pdata.dmic1_data_pin) {
|
||||
case RT5682_DMIC1_DATA_GPIO2: /* share with LRCK2 */
|
||||
regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
|
||||
RT5682_DMIC_1_DP_MASK, RT5682_DMIC_1_DP_GPIO2);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
|
||||
RT5682_GP2_PIN_MASK, RT5682_GP2_PIN_DMIC_SDA);
|
||||
break;
|
||||
|
||||
case RT5682_DMIC1_DATA_GPIO5: /* share with DACDAT1 */
|
||||
regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
|
||||
RT5682_DMIC_1_DP_MASK, RT5682_DMIC_1_DP_GPIO5);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
|
||||
RT5682_GP5_PIN_MASK, RT5682_GP5_PIN_DMIC_SDA);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(&i2c->dev, "invalid DMIC_DAT pin\n");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rt5682->pdata.dmic1_clk_pin) {
|
||||
case RT5682_DMIC1_CLK_GPIO1: /* share with IRQ */
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
|
||||
RT5682_GP1_PIN_MASK, RT5682_GP1_PIN_DMIC_CLK);
|
||||
break;
|
||||
|
||||
case RT5682_DMIC1_CLK_GPIO3: /* share with BCLK2 */
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
|
||||
RT5682_GP3_PIN_MASK, RT5682_GP3_PIN_DMIC_CLK);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(&i2c->dev, "invalid DMIC_CLK pin\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
|
||||
RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK,
|
||||
RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X);
|
||||
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
|
||||
RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK,
|
||||
RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1);
|
||||
regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8,
|
||||
RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1,
|
||||
RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1,
|
||||
RT5682_PM_HP_MASK, RT5682_PM_HP_HV);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
|
||||
RT5682_FIFO_CLK_DIV_MASK, RT5682_FIFO_CLK_DIV_2);
|
||||
|
||||
INIT_DELAYED_WORK(&rt5682->jack_detect_work,
|
||||
rt5682_jack_detect_handler);
|
||||
INIT_DELAYED_WORK(&rt5682->jd_check_work,
|
||||
rt5682_jd_check_handler);
|
||||
|
||||
if (i2c->irq) {
|
||||
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
|
||||
rt5682_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
|
||||
| IRQF_ONESHOT, "rt5682", rt5682);
|
||||
if (ret)
|
||||
dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
|
||||
}
|
||||
|
||||
return devm_snd_soc_register_component(&i2c->dev,
|
||||
&rt5682_soc_component_dev,
|
||||
rt5682_dai, ARRAY_SIZE(rt5682_dai));
|
||||
}
|
||||
|
||||
static void rt5682_i2c_shutdown(struct i2c_client *client)
|
||||
{
|
||||
struct rt5682_priv *rt5682 = i2c_get_clientdata(client);
|
||||
|
||||
rt5682_reset(rt5682);
|
||||
}
|
||||
|
||||
static const struct of_device_id rt5682_of_match[] = {
|
||||
{.compatible = "realtek,rt5682i"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rt5682_of_match);
|
||||
|
||||
static const struct acpi_device_id rt5682_acpi_match[] = {
|
||||
{"10EC5682", 0,},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rt5682_acpi_match);
|
||||
|
||||
static const struct i2c_device_id rt5682_i2c_id[] = {
|
||||
{"rt5682", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rt5682_i2c_id);
|
||||
|
||||
static struct i2c_driver rt5682_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "rt5682",
|
||||
.of_match_table = rt5682_of_match,
|
||||
.acpi_match_table = rt5682_acpi_match,
|
||||
},
|
||||
.probe = rt5682_i2c_probe,
|
||||
.shutdown = rt5682_i2c_shutdown,
|
||||
.id_table = rt5682_i2c_id,
|
||||
};
|
||||
module_i2c_driver(rt5682_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC RT5682 driver");
|
||||
MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -14,6 +14,7 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
@ -28,7 +29,461 @@
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "rt5682.h"
|
||||
#include "rt5682-sdw.h"
|
||||
|
||||
#define RT5682_SDW_ADDR_L 0x3000
|
||||
#define RT5682_SDW_ADDR_H 0x3001
|
||||
#define RT5682_SDW_DATA_L 0x3004
|
||||
#define RT5682_SDW_DATA_H 0x3005
|
||||
#define RT5682_SDW_CMD 0x3008
|
||||
|
||||
static int rt5682_sdw_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
|
||||
unsigned int data_l, data_h;
|
||||
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_CMD, 0);
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_H, (reg >> 8) & 0xff);
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_L, (reg & 0xff));
|
||||
regmap_read(rt5682->sdw_regmap, RT5682_SDW_DATA_H, &data_h);
|
||||
regmap_read(rt5682->sdw_regmap, RT5682_SDW_DATA_L, &data_l);
|
||||
|
||||
*val = (data_h << 8) | data_l;
|
||||
|
||||
dev_vdbg(dev, "[%s] %04x => %04x\n", __func__, reg, *val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5682_sdw_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
|
||||
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_CMD, 1);
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_H, (reg >> 8) & 0xff);
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_L, (reg & 0xff));
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_DATA_H, (val >> 8) & 0xff);
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_DATA_L, (val & 0xff));
|
||||
|
||||
dev_vdbg(dev, "[%s] %04x <= %04x\n", __func__, reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config rt5682_sdw_indirect_regmap = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 16,
|
||||
.max_register = RT5682_I2C_MODE,
|
||||
.volatile_reg = rt5682_volatile_register,
|
||||
.readable_reg = rt5682_readable_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.reg_defaults = rt5682_reg,
|
||||
.num_reg_defaults = RT5682_REG_NUM,
|
||||
.use_single_read = true,
|
||||
.use_single_write = true,
|
||||
.reg_read = rt5682_sdw_read,
|
||||
.reg_write = rt5682_sdw_write,
|
||||
};
|
||||
|
||||
struct sdw_stream_data {
|
||||
struct sdw_stream_runtime *sdw_stream;
|
||||
};
|
||||
|
||||
static int rt5682_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
|
||||
int direction)
|
||||
{
|
||||
struct sdw_stream_data *stream;
|
||||
|
||||
if (!sdw_stream)
|
||||
return 0;
|
||||
|
||||
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
|
||||
if (!stream)
|
||||
return -ENOMEM;
|
||||
|
||||
stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
|
||||
|
||||
/* Use tx_mask or rx_mask to configure stream tag and set dma_data */
|
||||
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
dai->playback_dma_data = stream;
|
||||
else
|
||||
dai->capture_dma_data = stream;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rt5682_sdw_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sdw_stream_data *stream;
|
||||
|
||||
stream = snd_soc_dai_get_dma_data(dai, substream);
|
||||
snd_soc_dai_set_dma_data(dai, substream, NULL);
|
||||
kfree(stream);
|
||||
}
|
||||
|
||||
static int rt5682_sdw_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 rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
|
||||
struct sdw_stream_config stream_config;
|
||||
struct sdw_port_config port_config;
|
||||
enum sdw_data_direction direction;
|
||||
struct sdw_stream_data *stream;
|
||||
int retval, port, num_channels;
|
||||
unsigned int val_p = 0, val_c = 0, osr_p = 0, osr_c = 0;
|
||||
|
||||
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
|
||||
|
||||
stream = snd_soc_dai_get_dma_data(dai, substream);
|
||||
if (!stream)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!rt5682->slave)
|
||||
return -EINVAL;
|
||||
|
||||
/* SoundWire specific configuration */
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
direction = SDW_DATA_DIR_RX;
|
||||
port = 1;
|
||||
} else {
|
||||
direction = SDW_DATA_DIR_TX;
|
||||
port = 2;
|
||||
}
|
||||
|
||||
stream_config.frame_rate = params_rate(params);
|
||||
stream_config.ch_count = params_channels(params);
|
||||
stream_config.bps = snd_pcm_format_width(params_format(params));
|
||||
stream_config.direction = direction;
|
||||
|
||||
num_channels = params_channels(params);
|
||||
port_config.ch_mask = (1 << (num_channels)) - 1;
|
||||
port_config.num = port;
|
||||
|
||||
retval = sdw_stream_add_slave(rt5682->slave, &stream_config,
|
||||
&port_config, 1, stream->sdw_stream);
|
||||
if (retval) {
|
||||
dev_err(dai->dev, "Unable to configure port\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
val_p = RT5682_SDW_REF_1_48K;
|
||||
val_c = RT5682_SDW_REF_2_48K;
|
||||
break;
|
||||
case 96000:
|
||||
val_p = RT5682_SDW_REF_1_96K;
|
||||
val_c = RT5682_SDW_REF_2_96K;
|
||||
break;
|
||||
case 192000:
|
||||
val_p = RT5682_SDW_REF_1_192K;
|
||||
val_c = RT5682_SDW_REF_2_192K;
|
||||
break;
|
||||
case 32000:
|
||||
val_p = RT5682_SDW_REF_1_32K;
|
||||
val_c = RT5682_SDW_REF_2_32K;
|
||||
break;
|
||||
case 24000:
|
||||
val_p = RT5682_SDW_REF_1_24K;
|
||||
val_c = RT5682_SDW_REF_2_24K;
|
||||
break;
|
||||
case 16000:
|
||||
val_p = RT5682_SDW_REF_1_16K;
|
||||
val_c = RT5682_SDW_REF_2_16K;
|
||||
break;
|
||||
case 12000:
|
||||
val_p = RT5682_SDW_REF_1_12K;
|
||||
val_c = RT5682_SDW_REF_2_12K;
|
||||
break;
|
||||
case 8000:
|
||||
val_p = RT5682_SDW_REF_1_8K;
|
||||
val_c = RT5682_SDW_REF_2_8K;
|
||||
break;
|
||||
case 44100:
|
||||
val_p = RT5682_SDW_REF_1_44K;
|
||||
val_c = RT5682_SDW_REF_2_44K;
|
||||
break;
|
||||
case 88200:
|
||||
val_p = RT5682_SDW_REF_1_88K;
|
||||
val_c = RT5682_SDW_REF_2_88K;
|
||||
break;
|
||||
case 176400:
|
||||
val_p = RT5682_SDW_REF_1_176K;
|
||||
val_c = RT5682_SDW_REF_2_176K;
|
||||
break;
|
||||
case 22050:
|
||||
val_p = RT5682_SDW_REF_1_22K;
|
||||
val_c = RT5682_SDW_REF_2_22K;
|
||||
break;
|
||||
case 11025:
|
||||
val_p = RT5682_SDW_REF_1_11K;
|
||||
val_c = RT5682_SDW_REF_2_11K;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params_rate(params) <= 48000) {
|
||||
osr_p = RT5682_DAC_OSR_D_8;
|
||||
osr_c = RT5682_ADC_OSR_D_8;
|
||||
} else if (params_rate(params) <= 96000) {
|
||||
osr_p = RT5682_DAC_OSR_D_4;
|
||||
osr_c = RT5682_ADC_OSR_D_4;
|
||||
} else {
|
||||
osr_p = RT5682_DAC_OSR_D_2;
|
||||
osr_c = RT5682_ADC_OSR_D_2;
|
||||
}
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
regmap_update_bits(rt5682->regmap, RT5682_SDW_REF_CLK,
|
||||
RT5682_SDW_REF_1_MASK, val_p);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_ADDA_CLK_1,
|
||||
RT5682_DAC_OSR_MASK, osr_p);
|
||||
} else {
|
||||
regmap_update_bits(rt5682->regmap, RT5682_SDW_REF_CLK,
|
||||
RT5682_SDW_REF_2_MASK, val_c);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_ADDA_CLK_1,
|
||||
RT5682_ADC_OSR_MASK, osr_c);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rt5682_sdw_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
|
||||
struct sdw_stream_data *stream =
|
||||
snd_soc_dai_get_dma_data(dai, substream);
|
||||
|
||||
if (!rt5682->slave)
|
||||
return -EINVAL;
|
||||
|
||||
sdw_stream_remove_slave(rt5682->slave, stream->sdw_stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops rt5682_sdw_ops = {
|
||||
.hw_params = rt5682_sdw_hw_params,
|
||||
.hw_free = rt5682_sdw_hw_free,
|
||||
.set_sdw_stream = rt5682_set_sdw_stream,
|
||||
.shutdown = rt5682_sdw_shutdown,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver rt5682_dai[] = {
|
||||
{
|
||||
.name = "rt5682-aif1",
|
||||
.id = RT5682_AIF1,
|
||||
.playback = {
|
||||
.stream_name = "AIF1 Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "AIF1 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.ops = &rt5682_aif1_dai_ops,
|
||||
},
|
||||
{
|
||||
.name = "rt5682-aif2",
|
||||
.id = RT5682_AIF2,
|
||||
.capture = {
|
||||
.stream_name = "AIF2 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.ops = &rt5682_aif2_dai_ops,
|
||||
},
|
||||
{
|
||||
.name = "rt5682-sdw",
|
||||
.id = RT5682_SDW,
|
||||
.playback = {
|
||||
.stream_name = "SDW Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "SDW Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.ops = &rt5682_sdw_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
|
||||
struct sdw_slave *slave)
|
||||
{
|
||||
struct rt5682_priv *rt5682;
|
||||
int ret;
|
||||
|
||||
rt5682 = devm_kzalloc(dev, sizeof(*rt5682), GFP_KERNEL);
|
||||
if (!rt5682)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, rt5682);
|
||||
rt5682->slave = slave;
|
||||
rt5682->sdw_regmap = regmap;
|
||||
rt5682->is_sdw = true;
|
||||
|
||||
rt5682->regmap = devm_regmap_init(dev, NULL, dev,
|
||||
&rt5682_sdw_indirect_regmap);
|
||||
if (IS_ERR(rt5682->regmap)) {
|
||||
ret = PTR_ERR(rt5682->regmap);
|
||||
dev_err(dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark hw_init to false
|
||||
* HW init will be performed when device reports present
|
||||
*/
|
||||
rt5682->hw_init = false;
|
||||
rt5682->first_hw_init = false;
|
||||
|
||||
mutex_init(&rt5682->calibrate_mutex);
|
||||
INIT_DELAYED_WORK(&rt5682->jack_detect_work,
|
||||
rt5682_jack_detect_handler);
|
||||
|
||||
ret = devm_snd_soc_register_component(dev,
|
||||
&rt5682_soc_component_dev,
|
||||
rt5682_dai, ARRAY_SIZE(rt5682_dai));
|
||||
dev_dbg(&slave->dev, "%s\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
{
|
||||
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
unsigned int val;
|
||||
|
||||
if (rt5682->hw_init)
|
||||
return 0;
|
||||
|
||||
regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
|
||||
if (val != DEVICE_ID) {
|
||||
dev_err(dev, "Device with ID register %x is not rt5682\n", val);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* PM runtime is only enabled when a Slave reports as Attached
|
||||
*/
|
||||
if (!rt5682->first_hw_init) {
|
||||
/* set autosuspend parameters */
|
||||
pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
|
||||
pm_runtime_use_autosuspend(&slave->dev);
|
||||
|
||||
/* update count of parent 'active' children */
|
||||
pm_runtime_set_active(&slave->dev);
|
||||
|
||||
/* make sure the device does not suspend immediately */
|
||||
pm_runtime_mark_last_busy(&slave->dev);
|
||||
|
||||
pm_runtime_enable(&slave->dev);
|
||||
}
|
||||
|
||||
pm_runtime_get_noresume(&slave->dev);
|
||||
|
||||
if (rt5682->first_hw_init) {
|
||||
regcache_cache_only(rt5682->regmap, false);
|
||||
regcache_cache_bypass(rt5682->regmap, true);
|
||||
}
|
||||
|
||||
rt5682_calibrate(rt5682);
|
||||
|
||||
if (rt5682->first_hw_init) {
|
||||
regcache_cache_bypass(rt5682->regmap, false);
|
||||
regcache_mark_dirty(rt5682->regmap);
|
||||
regcache_sync(rt5682->regmap);
|
||||
|
||||
/* volatile registers */
|
||||
regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2,
|
||||
RT5682_EXT_JD_SRC, RT5682_EXT_JD_SRC_MANUAL);
|
||||
|
||||
goto reinit;
|
||||
}
|
||||
|
||||
rt5682_apply_patch_list(rt5682, dev);
|
||||
|
||||
regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0000);
|
||||
|
||||
regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
|
||||
RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK,
|
||||
RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X);
|
||||
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
|
||||
regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8,
|
||||
RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1,
|
||||
RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1,
|
||||
RT5682_PM_HP_MASK, RT5682_PM_HP_HV);
|
||||
|
||||
/* Soundwire */
|
||||
regmap_write(rt5682->regmap, RT5682_PLL2_INTERNAL, 0xa266);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_1, 0x1700);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_2, 0x0006);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_3, 0x2600);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_4, 0x0c8f);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL_TRACK_2, 0x3000);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL_TRACK_3, 0x4000);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GLB_CLK,
|
||||
RT5682_SCLK_SRC_MASK | RT5682_PLL2_SRC_MASK,
|
||||
RT5682_SCLK_SRC_PLL2 | RT5682_PLL2_SRC_SDW);
|
||||
|
||||
regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2,
|
||||
RT5682_EXT_JD_SRC, RT5682_EXT_JD_SRC_MANUAL);
|
||||
regmap_write(rt5682->regmap, RT5682_CBJ_CTRL_1, 0xd042);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_3,
|
||||
RT5682_CBJ_IN_BUF_EN, RT5682_CBJ_IN_BUF_EN);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_SAR_IL_CMD_1,
|
||||
RT5682_SAR_POW_MASK, RT5682_SAR_POW_EN);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
|
||||
RT5682_POW_IRQ | RT5682_POW_JDH |
|
||||
RT5682_POW_ANA, RT5682_POW_IRQ |
|
||||
RT5682_POW_JDH | RT5682_POW_ANA);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_2,
|
||||
RT5682_PWR_JDH, RT5682_PWR_JDH);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
|
||||
RT5682_JD1_EN_MASK | RT5682_JD1_IRQ_MASK,
|
||||
RT5682_JD1_EN | RT5682_JD1_IRQ_PUL);
|
||||
|
||||
reinit:
|
||||
mod_delayed_work(system_power_efficient_wq,
|
||||
&rt5682->jack_detect_work, msecs_to_jiffies(250));
|
||||
|
||||
/* Mark Slave initialization complete */
|
||||
rt5682->hw_init = true;
|
||||
rt5682->first_hw_init = true;
|
||||
|
||||
pm_runtime_mark_last_busy(&slave->dev);
|
||||
pm_runtime_put_autosuspend(&slave->dev);
|
||||
|
||||
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool rt5682_sdw_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
@ -46,7 +501,7 @@ static bool rt5682_sdw_readable_register(struct device *dev, unsigned int reg)
|
||||
}
|
||||
}
|
||||
|
||||
const struct regmap_config rt5682_sdw_regmap = {
|
||||
static const struct regmap_config rt5682_sdw_regmap = {
|
||||
.name = "sdw",
|
||||
.reg_bits = 32,
|
||||
.val_bits = 8,
|
||||
|
@ -1,20 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* rt5682-sdw.h -- RT5682 SDW ALSA SoC audio driver
|
||||
*
|
||||
* Copyright 2019 Realtek Semiconductor Corp.
|
||||
* Author: Oder Chiou <oder_chiou@realtek.com>
|
||||
*/
|
||||
|
||||
#ifndef __RT5682_SDW_H__
|
||||
#define __RT5682_SDW_H__
|
||||
|
||||
#define RT5682_SDW_ADDR_L 0x3000
|
||||
#define RT5682_SDW_ADDR_H 0x3001
|
||||
#define RT5682_SDW_DATA_L 0x3004
|
||||
#define RT5682_SDW_DATA_H 0x3005
|
||||
#define RT5682_SDW_CMD 0x3008
|
||||
|
||||
#define RT5682_PROBE_TIMEOUT 2000
|
||||
|
||||
#endif /* __RT5682_SDW_H__ */
|
@ -1,10 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* rt5682.c -- RT5682 ALSA SoC audio component driver
|
||||
*
|
||||
* Copyright 2018 Realtek Semiconductor Corp.
|
||||
* Author: Bard Liao <bardliao@realtek.com>
|
||||
*/
|
||||
//
|
||||
// rt5682.c -- RT5682 ALSA SoC audio component driver
|
||||
//
|
||||
// Copyright 2018 Realtek Semiconductor Corp.
|
||||
// Author: Bard Liao <bardliao@realtek.com>
|
||||
//
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
@ -12,7 +12,6 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/acpi.h>
|
||||
@ -31,22 +30,13 @@
|
||||
|
||||
#include "rl6231.h"
|
||||
#include "rt5682.h"
|
||||
#include "rt5682-sdw.h"
|
||||
|
||||
static const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = {
|
||||
const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = {
|
||||
"AVDD",
|
||||
"MICVDD",
|
||||
"VBAT",
|
||||
};
|
||||
|
||||
static const struct rt5682_platform_data i2s_default_platform_data = {
|
||||
.dmic1_data_pin = RT5682_DMIC1_DATA_GPIO2,
|
||||
.dmic1_clk_pin = RT5682_DMIC1_CLK_GPIO3,
|
||||
.jd_src = RT5682_JD1,
|
||||
.btndet_delay = 16,
|
||||
.dai_clk_names[RT5682_DAI_WCLK_IDX] = "rt5682-dai-wclk",
|
||||
.dai_clk_names[RT5682_DAI_BCLK_IDX] = "rt5682-dai-bclk",
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(rt5682_supply_names);
|
||||
|
||||
static const struct reg_sequence patch_list[] = {
|
||||
{RT5682_HP_IMP_SENS_CTRL_19, 0x1000},
|
||||
@ -55,7 +45,18 @@ static const struct reg_sequence patch_list[] = {
|
||||
{RT5682_PLL2_INTERNAL, 0x8266},
|
||||
};
|
||||
|
||||
static const struct reg_default rt5682_reg[] = {
|
||||
void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_multi_reg_write(rt5682->regmap, patch_list,
|
||||
ARRAY_SIZE(patch_list));
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to apply regmap patch: %d\n", ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5682_apply_patch_list);
|
||||
|
||||
const struct reg_default rt5682_reg[RT5682_REG_NUM] = {
|
||||
{0x0002, 0x8080},
|
||||
{0x0003, 0x8000},
|
||||
{0x0005, 0x0000},
|
||||
@ -375,8 +376,9 @@ static const struct reg_default rt5682_reg[] = {
|
||||
{0x03f2, 0x0800},
|
||||
{0x03f3, 0x0800},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(rt5682_reg);
|
||||
|
||||
static bool rt5682_volatile_register(struct device *dev, unsigned int reg)
|
||||
bool rt5682_volatile_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case RT5682_RESET:
|
||||
@ -403,8 +405,9 @@ static bool rt5682_volatile_register(struct device *dev, unsigned int reg)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5682_volatile_register);
|
||||
|
||||
static bool rt5682_readable_register(struct device *dev, unsigned int reg)
|
||||
bool rt5682_readable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case RT5682_RESET:
|
||||
@ -733,6 +736,7 @@ static bool rt5682_readable_register(struct device *dev, unsigned int reg)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5682_readable_register);
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
|
||||
@ -800,12 +804,13 @@ static SOC_ENUM_SINGLE_DECL(rt5682_dacr_enum,
|
||||
static const struct snd_kcontrol_new rt5682_dac_r_mux =
|
||||
SOC_DAPM_ENUM("DAC R Mux", rt5682_dacr_enum);
|
||||
|
||||
static void rt5682_reset(struct rt5682_priv *rt5682)
|
||||
void rt5682_reset(struct rt5682_priv *rt5682)
|
||||
{
|
||||
regmap_write(rt5682->regmap, RT5682_RESET, 0);
|
||||
if (!rt5682->is_sdw)
|
||||
regmap_write(rt5682->regmap, RT5682_I2C_MODE, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5682_reset);
|
||||
|
||||
/**
|
||||
* rt5682_sel_asrc_clk_src - select ASRC clock source for a set of filters
|
||||
@ -910,8 +915,7 @@ static void rt5682_enable_push_button_irq(struct snd_soc_component *component,
|
||||
*
|
||||
* Returns detect status.
|
||||
*/
|
||||
static int rt5682_headset_detect(struct snd_soc_component *component,
|
||||
int jack_insert)
|
||||
int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
|
||||
{
|
||||
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
|
||||
struct snd_soc_dapm_context *dapm = &component->dapm;
|
||||
@ -972,35 +976,7 @@ static int rt5682_headset_detect(struct snd_soc_component *component,
|
||||
dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type);
|
||||
return rt5682->jack_type;
|
||||
}
|
||||
|
||||
static irqreturn_t rt5682_irq(int irq, void *data)
|
||||
{
|
||||
struct rt5682_priv *rt5682 = data;
|
||||
|
||||
mod_delayed_work(system_power_efficient_wq,
|
||||
&rt5682->jack_detect_work, msecs_to_jiffies(250));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void rt5682_jd_check_handler(struct work_struct *work)
|
||||
{
|
||||
struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv,
|
||||
jd_check_work.work);
|
||||
|
||||
if (snd_soc_component_read32(rt5682->component, RT5682_AJD1_CTRL)
|
||||
& RT5682_JDH_RS_MASK) {
|
||||
/* jack out */
|
||||
rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
|
||||
|
||||
snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
|
||||
SND_JACK_HEADSET |
|
||||
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3);
|
||||
} else {
|
||||
schedule_delayed_work(&rt5682->jd_check_work, 500);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5682_headset_detect);
|
||||
|
||||
static int rt5682_set_jack_detect(struct snd_soc_component *component,
|
||||
struct snd_soc_jack *hs_jack, void *data)
|
||||
@ -1077,7 +1053,7 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rt5682_jack_detect_handler(struct work_struct *work)
|
||||
void rt5682_jack_detect_handler(struct work_struct *work)
|
||||
{
|
||||
struct rt5682_priv *rt5682 =
|
||||
container_of(work, struct rt5682_priv, jack_detect_work.work);
|
||||
@ -1160,6 +1136,7 @@ static void rt5682_jack_detect_handler(struct work_struct *work)
|
||||
|
||||
mutex_unlock(&rt5682->calibrate_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler);
|
||||
|
||||
static const struct snd_kcontrol_new rt5682_snd_controls[] = {
|
||||
/* DAC Digital Volume */
|
||||
@ -2899,7 +2876,8 @@ static int rt5682_resume(struct snd_soc_component *component)
|
||||
regcache_cache_only(rt5682->regmap, false);
|
||||
regcache_sync(rt5682->regmap);
|
||||
|
||||
rt5682_irq(0, rt5682);
|
||||
mod_delayed_work(system_power_efficient_wq,
|
||||
&rt5682->jack_detect_work, msecs_to_jiffies(250));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2908,270 +2886,22 @@ static int rt5682_resume(struct snd_soc_component *component)
|
||||
#define rt5682_resume NULL
|
||||
#endif
|
||||
|
||||
#define RT5682_STEREO_RATES SNDRV_PCM_RATE_8000_192000
|
||||
#define RT5682_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
|
||||
|
||||
static const struct snd_soc_dai_ops rt5682_aif1_dai_ops = {
|
||||
const struct snd_soc_dai_ops rt5682_aif1_dai_ops = {
|
||||
.hw_params = rt5682_hw_params,
|
||||
.set_fmt = rt5682_set_dai_fmt,
|
||||
.set_tdm_slot = rt5682_set_tdm_slot,
|
||||
.set_bclk_ratio = rt5682_set_bclk1_ratio,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(rt5682_aif1_dai_ops);
|
||||
|
||||
static const struct snd_soc_dai_ops rt5682_aif2_dai_ops = {
|
||||
const struct snd_soc_dai_ops rt5682_aif2_dai_ops = {
|
||||
.hw_params = rt5682_hw_params,
|
||||
.set_fmt = rt5682_set_dai_fmt,
|
||||
.set_bclk_ratio = rt5682_set_bclk2_ratio,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(rt5682_aif2_dai_ops);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_RT5682_SDW)
|
||||
struct sdw_stream_data {
|
||||
struct sdw_stream_runtime *sdw_stream;
|
||||
};
|
||||
|
||||
static int rt5682_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
|
||||
int direction)
|
||||
{
|
||||
struct sdw_stream_data *stream;
|
||||
|
||||
if (!sdw_stream)
|
||||
return 0;
|
||||
|
||||
stream = kzalloc(sizeof(*stream), GFP_KERNEL);
|
||||
if (!stream)
|
||||
return -ENOMEM;
|
||||
|
||||
stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
|
||||
|
||||
/* Use tx_mask or rx_mask to configure stream tag and set dma_data */
|
||||
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
dai->playback_dma_data = stream;
|
||||
else
|
||||
dai->capture_dma_data = stream;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rt5682_sdw_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct sdw_stream_data *stream;
|
||||
|
||||
stream = snd_soc_dai_get_dma_data(dai, substream);
|
||||
snd_soc_dai_set_dma_data(dai, substream, NULL);
|
||||
kfree(stream);
|
||||
}
|
||||
|
||||
static int rt5682_sdw_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 rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
|
||||
struct sdw_stream_config stream_config;
|
||||
struct sdw_port_config port_config;
|
||||
enum sdw_data_direction direction;
|
||||
struct sdw_stream_data *stream;
|
||||
int retval, port, num_channels;
|
||||
unsigned int val_p = 0, val_c = 0, osr_p = 0, osr_c = 0;
|
||||
|
||||
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
|
||||
|
||||
stream = snd_soc_dai_get_dma_data(dai, substream);
|
||||
if (!stream)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!rt5682->slave)
|
||||
return -EINVAL;
|
||||
|
||||
/* SoundWire specific configuration */
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
direction = SDW_DATA_DIR_RX;
|
||||
port = 1;
|
||||
} else {
|
||||
direction = SDW_DATA_DIR_TX;
|
||||
port = 2;
|
||||
}
|
||||
|
||||
stream_config.frame_rate = params_rate(params);
|
||||
stream_config.ch_count = params_channels(params);
|
||||
stream_config.bps = snd_pcm_format_width(params_format(params));
|
||||
stream_config.direction = direction;
|
||||
|
||||
num_channels = params_channels(params);
|
||||
port_config.ch_mask = (1 << (num_channels)) - 1;
|
||||
port_config.num = port;
|
||||
|
||||
retval = sdw_stream_add_slave(rt5682->slave, &stream_config,
|
||||
&port_config, 1, stream->sdw_stream);
|
||||
if (retval) {
|
||||
dev_err(dai->dev, "Unable to configure port\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
val_p = RT5682_SDW_REF_1_48K;
|
||||
val_c = RT5682_SDW_REF_2_48K;
|
||||
break;
|
||||
case 96000:
|
||||
val_p = RT5682_SDW_REF_1_96K;
|
||||
val_c = RT5682_SDW_REF_2_96K;
|
||||
break;
|
||||
case 192000:
|
||||
val_p = RT5682_SDW_REF_1_192K;
|
||||
val_c = RT5682_SDW_REF_2_192K;
|
||||
break;
|
||||
case 32000:
|
||||
val_p = RT5682_SDW_REF_1_32K;
|
||||
val_c = RT5682_SDW_REF_2_32K;
|
||||
break;
|
||||
case 24000:
|
||||
val_p = RT5682_SDW_REF_1_24K;
|
||||
val_c = RT5682_SDW_REF_2_24K;
|
||||
break;
|
||||
case 16000:
|
||||
val_p = RT5682_SDW_REF_1_16K;
|
||||
val_c = RT5682_SDW_REF_2_16K;
|
||||
break;
|
||||
case 12000:
|
||||
val_p = RT5682_SDW_REF_1_12K;
|
||||
val_c = RT5682_SDW_REF_2_12K;
|
||||
break;
|
||||
case 8000:
|
||||
val_p = RT5682_SDW_REF_1_8K;
|
||||
val_c = RT5682_SDW_REF_2_8K;
|
||||
break;
|
||||
case 44100:
|
||||
val_p = RT5682_SDW_REF_1_44K;
|
||||
val_c = RT5682_SDW_REF_2_44K;
|
||||
break;
|
||||
case 88200:
|
||||
val_p = RT5682_SDW_REF_1_88K;
|
||||
val_c = RT5682_SDW_REF_2_88K;
|
||||
break;
|
||||
case 176400:
|
||||
val_p = RT5682_SDW_REF_1_176K;
|
||||
val_c = RT5682_SDW_REF_2_176K;
|
||||
break;
|
||||
case 22050:
|
||||
val_p = RT5682_SDW_REF_1_22K;
|
||||
val_c = RT5682_SDW_REF_2_22K;
|
||||
break;
|
||||
case 11025:
|
||||
val_p = RT5682_SDW_REF_1_11K;
|
||||
val_c = RT5682_SDW_REF_2_11K;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params_rate(params) <= 48000) {
|
||||
osr_p = RT5682_DAC_OSR_D_8;
|
||||
osr_c = RT5682_ADC_OSR_D_8;
|
||||
} else if (params_rate(params) <= 96000) {
|
||||
osr_p = RT5682_DAC_OSR_D_4;
|
||||
osr_c = RT5682_ADC_OSR_D_4;
|
||||
} else {
|
||||
osr_p = RT5682_DAC_OSR_D_2;
|
||||
osr_c = RT5682_ADC_OSR_D_2;
|
||||
}
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
regmap_update_bits(rt5682->regmap, RT5682_SDW_REF_CLK,
|
||||
RT5682_SDW_REF_1_MASK, val_p);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_ADDA_CLK_1,
|
||||
RT5682_DAC_OSR_MASK, osr_p);
|
||||
} else {
|
||||
regmap_update_bits(rt5682->regmap, RT5682_SDW_REF_CLK,
|
||||
RT5682_SDW_REF_2_MASK, val_c);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_ADDA_CLK_1,
|
||||
RT5682_ADC_OSR_MASK, osr_c);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rt5682_sdw_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
|
||||
struct sdw_stream_data *stream =
|
||||
snd_soc_dai_get_dma_data(dai, substream);
|
||||
|
||||
if (!rt5682->slave)
|
||||
return -EINVAL;
|
||||
|
||||
sdw_stream_remove_slave(rt5682->slave, stream->sdw_stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops rt5682_sdw_ops = {
|
||||
.hw_params = rt5682_sdw_hw_params,
|
||||
.hw_free = rt5682_sdw_hw_free,
|
||||
.set_sdw_stream = rt5682_set_sdw_stream,
|
||||
.shutdown = rt5682_sdw_shutdown,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct snd_soc_dai_driver rt5682_dai[] = {
|
||||
{
|
||||
.name = "rt5682-aif1",
|
||||
.id = RT5682_AIF1,
|
||||
.playback = {
|
||||
.stream_name = "AIF1 Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "AIF1 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.ops = &rt5682_aif1_dai_ops,
|
||||
},
|
||||
{
|
||||
.name = "rt5682-aif2",
|
||||
.id = RT5682_AIF2,
|
||||
.capture = {
|
||||
.stream_name = "AIF2 Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.ops = &rt5682_aif2_dai_ops,
|
||||
},
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_RT5682_SDW)
|
||||
{
|
||||
.name = "rt5682-sdw",
|
||||
.id = RT5682_SDW,
|
||||
.playback = {
|
||||
.stream_name = "SDW Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "SDW Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.rates = RT5682_STEREO_RATES,
|
||||
.formats = RT5682_FORMATS,
|
||||
},
|
||||
.ops = &rt5682_sdw_ops,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver soc_component_dev_rt5682 = {
|
||||
const struct snd_soc_component_driver rt5682_soc_component_dev = {
|
||||
.probe = rt5682_probe,
|
||||
.remove = rt5682_remove,
|
||||
.suspend = rt5682_suspend,
|
||||
@ -3190,27 +2920,9 @@ static const struct snd_soc_component_driver soc_component_dev_rt5682 = {
|
||||
.endianness = 1,
|
||||
.non_legacy_dai_naming = 1,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(rt5682_soc_component_dev);
|
||||
|
||||
static const struct regmap_config rt5682_regmap = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 16,
|
||||
.max_register = RT5682_I2C_MODE,
|
||||
.volatile_reg = rt5682_volatile_register,
|
||||
.readable_reg = rt5682_readable_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.reg_defaults = rt5682_reg,
|
||||
.num_reg_defaults = ARRAY_SIZE(rt5682_reg),
|
||||
.use_single_read = true,
|
||||
.use_single_write = true,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id rt5682_i2c_id[] = {
|
||||
{"rt5682", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rt5682_i2c_id);
|
||||
|
||||
static int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
|
||||
int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
|
||||
{
|
||||
|
||||
device_property_read_u32(dev, "realtek,dmic1-data-pin",
|
||||
@ -3238,8 +2950,9 @@ static int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5682_parse_dt);
|
||||
|
||||
static void rt5682_calibrate(struct rt5682_priv *rt5682)
|
||||
void rt5682_calibrate(struct rt5682_priv *rt5682)
|
||||
{
|
||||
int value, count;
|
||||
|
||||
@ -3289,407 +3002,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682)
|
||||
|
||||
mutex_unlock(&rt5682->calibrate_mutex);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_RT5682_SDW)
|
||||
static int rt5682_sdw_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
|
||||
unsigned int data_l, data_h;
|
||||
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_CMD, 0);
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_H, (reg >> 8) & 0xff);
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_L, (reg & 0xff));
|
||||
regmap_read(rt5682->sdw_regmap, RT5682_SDW_DATA_H, &data_h);
|
||||
regmap_read(rt5682->sdw_regmap, RT5682_SDW_DATA_L, &data_l);
|
||||
|
||||
*val = (data_h << 8) | data_l;
|
||||
|
||||
dev_vdbg(dev, "[%s] %04x => %04x\n", __func__, reg, *val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5682_sdw_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
|
||||
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_CMD, 1);
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_H, (reg >> 8) & 0xff);
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_L, (reg & 0xff));
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_DATA_H, (val >> 8) & 0xff);
|
||||
regmap_write(rt5682->sdw_regmap, RT5682_SDW_DATA_L, (val & 0xff));
|
||||
|
||||
dev_vdbg(dev, "[%s] %04x <= %04x\n", __func__, reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config rt5682_sdw_regmap = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 16,
|
||||
.max_register = RT5682_I2C_MODE,
|
||||
.volatile_reg = rt5682_volatile_register,
|
||||
.readable_reg = rt5682_readable_register,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.reg_defaults = rt5682_reg,
|
||||
.num_reg_defaults = ARRAY_SIZE(rt5682_reg),
|
||||
.use_single_read = true,
|
||||
.use_single_write = true,
|
||||
.reg_read = rt5682_sdw_read,
|
||||
.reg_write = rt5682_sdw_write,
|
||||
};
|
||||
|
||||
int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
|
||||
struct sdw_slave *slave)
|
||||
{
|
||||
struct rt5682_priv *rt5682;
|
||||
int ret;
|
||||
|
||||
rt5682 = devm_kzalloc(dev, sizeof(*rt5682), GFP_KERNEL);
|
||||
if (!rt5682)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, rt5682);
|
||||
rt5682->slave = slave;
|
||||
rt5682->sdw_regmap = regmap;
|
||||
rt5682->is_sdw = true;
|
||||
|
||||
rt5682->regmap = devm_regmap_init(dev, NULL, dev, &rt5682_sdw_regmap);
|
||||
if (IS_ERR(rt5682->regmap)) {
|
||||
ret = PTR_ERR(rt5682->regmap);
|
||||
dev_err(dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark hw_init to false
|
||||
* HW init will be performed when device reports present
|
||||
*/
|
||||
rt5682->hw_init = false;
|
||||
rt5682->first_hw_init = false;
|
||||
|
||||
mutex_init(&rt5682->calibrate_mutex);
|
||||
INIT_DELAYED_WORK(&rt5682->jack_detect_work,
|
||||
rt5682_jack_detect_handler);
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &soc_component_dev_rt5682,
|
||||
rt5682_dai, ARRAY_SIZE(rt5682_dai));
|
||||
|
||||
dev_dbg(&slave->dev, "%s\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5682_sdw_init);
|
||||
|
||||
int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
{
|
||||
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
unsigned int val;
|
||||
|
||||
if (rt5682->hw_init)
|
||||
return 0;
|
||||
|
||||
regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
|
||||
if (val != DEVICE_ID) {
|
||||
dev_err(dev, "Device with ID register %x is not rt5682\n", val);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* PM runtime is only enabled when a Slave reports as Attached
|
||||
*/
|
||||
if (!rt5682->first_hw_init) {
|
||||
/* set autosuspend parameters */
|
||||
pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
|
||||
pm_runtime_use_autosuspend(&slave->dev);
|
||||
|
||||
/* update count of parent 'active' children */
|
||||
pm_runtime_set_active(&slave->dev);
|
||||
|
||||
/* make sure the device does not suspend immediately */
|
||||
pm_runtime_mark_last_busy(&slave->dev);
|
||||
|
||||
pm_runtime_enable(&slave->dev);
|
||||
}
|
||||
|
||||
pm_runtime_get_noresume(&slave->dev);
|
||||
|
||||
if (rt5682->first_hw_init) {
|
||||
regcache_cache_only(rt5682->regmap, false);
|
||||
regcache_cache_bypass(rt5682->regmap, true);
|
||||
}
|
||||
|
||||
rt5682_calibrate(rt5682);
|
||||
|
||||
if (rt5682->first_hw_init) {
|
||||
regcache_cache_bypass(rt5682->regmap, false);
|
||||
regcache_mark_dirty(rt5682->regmap);
|
||||
regcache_sync(rt5682->regmap);
|
||||
|
||||
/* volatile registers */
|
||||
regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2,
|
||||
RT5682_EXT_JD_SRC, RT5682_EXT_JD_SRC_MANUAL);
|
||||
|
||||
goto reinit;
|
||||
}
|
||||
|
||||
ret = regmap_multi_reg_write(rt5682->regmap, patch_list,
|
||||
ARRAY_SIZE(patch_list));
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to apply regmap patch: %d\n", ret);
|
||||
|
||||
regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0000);
|
||||
|
||||
regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
|
||||
RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK,
|
||||
RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X);
|
||||
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
|
||||
regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8,
|
||||
RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1,
|
||||
RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1,
|
||||
RT5682_PM_HP_MASK, RT5682_PM_HP_HV);
|
||||
|
||||
/* Soundwire */
|
||||
regmap_write(rt5682->regmap, RT5682_PLL2_INTERNAL, 0xa266);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_1, 0x1700);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_2, 0x0006);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_3, 0x2600);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_4, 0x0c8f);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL_TRACK_2, 0x3000);
|
||||
regmap_write(rt5682->regmap, RT5682_PLL_TRACK_3, 0x4000);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GLB_CLK,
|
||||
RT5682_SCLK_SRC_MASK | RT5682_PLL2_SRC_MASK,
|
||||
RT5682_SCLK_SRC_PLL2 | RT5682_PLL2_SRC_SDW);
|
||||
|
||||
regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2,
|
||||
RT5682_EXT_JD_SRC, RT5682_EXT_JD_SRC_MANUAL);
|
||||
regmap_write(rt5682->regmap, RT5682_CBJ_CTRL_1, 0xd042);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_3,
|
||||
RT5682_CBJ_IN_BUF_EN, RT5682_CBJ_IN_BUF_EN);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_SAR_IL_CMD_1,
|
||||
RT5682_SAR_POW_MASK, RT5682_SAR_POW_EN);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
|
||||
RT5682_POW_IRQ | RT5682_POW_JDH |
|
||||
RT5682_POW_ANA, RT5682_POW_IRQ |
|
||||
RT5682_POW_JDH | RT5682_POW_ANA);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_2,
|
||||
RT5682_PWR_JDH, RT5682_PWR_JDH);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
|
||||
RT5682_JD1_EN_MASK | RT5682_JD1_IRQ_MASK,
|
||||
RT5682_JD1_EN | RT5682_JD1_IRQ_PUL);
|
||||
|
||||
reinit:
|
||||
mod_delayed_work(system_power_efficient_wq,
|
||||
&rt5682->jack_detect_work, msecs_to_jiffies(250));
|
||||
|
||||
/* Mark Slave initialization complete */
|
||||
rt5682->hw_init = true;
|
||||
rt5682->first_hw_init = true;
|
||||
|
||||
pm_runtime_mark_last_busy(&slave->dev);
|
||||
pm_runtime_put_autosuspend(&slave->dev);
|
||||
|
||||
dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt5682_io_init);
|
||||
#endif
|
||||
|
||||
static int rt5682_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct rt5682_platform_data *pdata = dev_get_platdata(&i2c->dev);
|
||||
struct rt5682_priv *rt5682;
|
||||
int i, ret;
|
||||
unsigned int val;
|
||||
|
||||
rt5682 = devm_kzalloc(&i2c->dev, sizeof(struct rt5682_priv),
|
||||
GFP_KERNEL);
|
||||
if (!rt5682)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(i2c, rt5682);
|
||||
|
||||
rt5682->pdata = i2s_default_platform_data;
|
||||
|
||||
if (pdata)
|
||||
rt5682->pdata = *pdata;
|
||||
else
|
||||
rt5682_parse_dt(rt5682, &i2c->dev);
|
||||
|
||||
rt5682->regmap = devm_regmap_init_i2c(i2c, &rt5682_regmap);
|
||||
if (IS_ERR(rt5682->regmap)) {
|
||||
ret = PTR_ERR(rt5682->regmap);
|
||||
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rt5682->supplies); i++)
|
||||
rt5682->supplies[i].supply = rt5682_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5682->supplies),
|
||||
rt5682->supplies);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(rt5682->supplies),
|
||||
rt5682->supplies);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(rt5682->pdata.ldo1_en)) {
|
||||
if (devm_gpio_request_one(&i2c->dev, rt5682->pdata.ldo1_en,
|
||||
GPIOF_OUT_INIT_HIGH, "rt5682"))
|
||||
dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
|
||||
}
|
||||
|
||||
/* Sleep for 300 ms miniumum */
|
||||
usleep_range(300000, 350000);
|
||||
|
||||
regmap_write(rt5682->regmap, RT5682_I2C_MODE, 0x1);
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
|
||||
if (val != DEVICE_ID) {
|
||||
dev_err(&i2c->dev,
|
||||
"Device with ID register %x is not rt5682\n", val);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_init(&rt5682->calibrate_mutex);
|
||||
rt5682_calibrate(rt5682);
|
||||
|
||||
ret = regmap_multi_reg_write(rt5682->regmap, patch_list,
|
||||
ARRAY_SIZE(patch_list));
|
||||
if (ret)
|
||||
dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
|
||||
|
||||
regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0000);
|
||||
|
||||
/* DMIC pin*/
|
||||
if (rt5682->pdata.dmic1_data_pin != RT5682_DMIC1_NULL) {
|
||||
switch (rt5682->pdata.dmic1_data_pin) {
|
||||
case RT5682_DMIC1_DATA_GPIO2: /* share with LRCK2 */
|
||||
regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
|
||||
RT5682_DMIC_1_DP_MASK, RT5682_DMIC_1_DP_GPIO2);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
|
||||
RT5682_GP2_PIN_MASK, RT5682_GP2_PIN_DMIC_SDA);
|
||||
break;
|
||||
|
||||
case RT5682_DMIC1_DATA_GPIO5: /* share with DACDAT1 */
|
||||
regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
|
||||
RT5682_DMIC_1_DP_MASK, RT5682_DMIC_1_DP_GPIO5);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
|
||||
RT5682_GP5_PIN_MASK, RT5682_GP5_PIN_DMIC_SDA);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(&i2c->dev, "invalid DMIC_DAT pin\n");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rt5682->pdata.dmic1_clk_pin) {
|
||||
case RT5682_DMIC1_CLK_GPIO1: /* share with IRQ */
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
|
||||
RT5682_GP1_PIN_MASK, RT5682_GP1_PIN_DMIC_CLK);
|
||||
break;
|
||||
|
||||
case RT5682_DMIC1_CLK_GPIO3: /* share with BCLK2 */
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
|
||||
RT5682_GP3_PIN_MASK, RT5682_GP3_PIN_DMIC_CLK);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(&i2c->dev, "invalid DMIC_CLK pin\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
|
||||
RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK,
|
||||
RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X);
|
||||
regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
|
||||
RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK,
|
||||
RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1);
|
||||
regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8,
|
||||
RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1,
|
||||
RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1,
|
||||
RT5682_PM_HP_MASK, RT5682_PM_HP_HV);
|
||||
regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
|
||||
RT5682_FIFO_CLK_DIV_MASK, RT5682_FIFO_CLK_DIV_2);
|
||||
|
||||
INIT_DELAYED_WORK(&rt5682->jack_detect_work,
|
||||
rt5682_jack_detect_handler);
|
||||
INIT_DELAYED_WORK(&rt5682->jd_check_work,
|
||||
rt5682_jd_check_handler);
|
||||
|
||||
if (i2c->irq) {
|
||||
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
|
||||
rt5682_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
|
||||
| IRQF_ONESHOT, "rt5682", rt5682);
|
||||
if (ret)
|
||||
dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
|
||||
}
|
||||
|
||||
return devm_snd_soc_register_component(&i2c->dev,
|
||||
&soc_component_dev_rt5682,
|
||||
rt5682_dai, ARRAY_SIZE(rt5682_dai));
|
||||
}
|
||||
|
||||
static void rt5682_i2c_shutdown(struct i2c_client *client)
|
||||
{
|
||||
struct rt5682_priv *rt5682 = i2c_get_clientdata(client);
|
||||
|
||||
rt5682_reset(rt5682);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id rt5682_of_match[] = {
|
||||
{.compatible = "realtek,rt5682i"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rt5682_of_match);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id rt5682_acpi_match[] = {
|
||||
{"10EC5682", 0,},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, rt5682_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver __maybe_unused rt5682_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "rt5682",
|
||||
.of_match_table = of_match_ptr(rt5682_of_match),
|
||||
.acpi_match_table = ACPI_PTR(rt5682_acpi_match),
|
||||
},
|
||||
.probe = rt5682_i2c_probe,
|
||||
.shutdown = rt5682_i2c_shutdown,
|
||||
.id_table = rt5682_i2c_id,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_I2C
|
||||
module_i2c_driver(rt5682_i2c_driver);
|
||||
#endif
|
||||
EXPORT_SYMBOL_GPL(rt5682_calibrate);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC RT5682 driver");
|
||||
MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
|
||||
|
@ -1337,6 +1337,13 @@
|
||||
#define RT5682_SAR_SOUR_BTN (0x3f)
|
||||
#define RT5682_SAR_SOUR_TYPE (0x0)
|
||||
|
||||
/* soundwire timeout */
|
||||
#define RT5682_PROBE_TIMEOUT 2000
|
||||
|
||||
|
||||
#define RT5682_STEREO_RATES SNDRV_PCM_RATE_8000_192000
|
||||
#define RT5682_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
|
||||
|
||||
/* System Clock Source */
|
||||
enum {
|
||||
@ -1418,10 +1425,29 @@ struct rt5682_priv {
|
||||
int jack_type;
|
||||
};
|
||||
|
||||
extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES];
|
||||
|
||||
int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
|
||||
unsigned int filter_mask, unsigned int clk_src);
|
||||
int rt5682_sdw_init(struct device *dev, struct regmap *regmap,
|
||||
struct sdw_slave *slave);
|
||||
int rt5682_io_init(struct device *dev, struct sdw_slave *slave);
|
||||
|
||||
void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev);
|
||||
|
||||
int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert);
|
||||
void rt5682_jack_detect_handler(struct work_struct *work);
|
||||
|
||||
bool rt5682_volatile_register(struct device *dev, unsigned int reg);
|
||||
bool rt5682_readable_register(struct device *dev, unsigned int reg);
|
||||
|
||||
int rt5682_register_component(struct device *dev);
|
||||
void rt5682_calibrate(struct rt5682_priv *rt5682);
|
||||
void rt5682_reset(struct rt5682_priv *rt5682);
|
||||
int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev);
|
||||
|
||||
#define RT5682_REG_NUM 318
|
||||
extern const struct reg_default rt5682_reg[RT5682_REG_NUM];
|
||||
|
||||
extern const struct snd_soc_dai_ops rt5682_aif1_dai_ops;
|
||||
extern const struct snd_soc_dai_ops rt5682_aif2_dai_ops;
|
||||
extern const struct snd_soc_component_driver rt5682_soc_component_dev;
|
||||
|
||||
#endif /* __RT5682_H__ */
|
||||
|
@ -430,7 +430,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
|
||||
depends on I2C && ACPI && GPIOLIB
|
||||
depends on MFD_INTEL_LPSS || COMPILE_TEST
|
||||
depends on SND_HDA_CODEC_HDMI
|
||||
select SND_SOC_RT5682
|
||||
select SND_SOC_RT5682_I2C
|
||||
select SND_SOC_MAX98357A
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_HDAC_HDMI
|
||||
@ -468,7 +468,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH
|
||||
depends on SND_HDA_CODEC_HDMI
|
||||
select SND_SOC_MAX98373
|
||||
select SND_SOC_RT1015
|
||||
select SND_SOC_RT5682
|
||||
select SND_SOC_RT5682_I2C
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_HDAC_HDMI
|
||||
help
|
||||
@ -511,7 +511,7 @@ config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH
|
||||
depends on MFD_INTEL_LPSS || COMPILE_TEST
|
||||
depends on SND_HDA_CODEC_HDMI
|
||||
select SND_SOC_RT1011
|
||||
select SND_SOC_RT5682
|
||||
select SND_SOC_RT5682_I2C
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_HDAC_HDMI
|
||||
help
|
||||
|
Loading…
Reference in New Issue
Block a user