Merge commit '1d32cf5ad0ef75fd639b1cf4061d736d099b9ef5'

* commit '1d32cf5ad0ef75fd639b1cf4061d736d099b9ef5':
  media: i2c: maxim4c: MIPI VC count does not affected by data lane count
  arm64: dts: rockchip: rk3588-vehicle-evb-maxim-max96712-dcphy0(/1): adjust Txphy DPLL
  mfd: rkx110_x120: fix dereference the error device node
  drm/rockchip: dsi2: support disable hold mode in cmd mode
  mfd: rkx110_x120: change video packet length
  mfd: rxk110_x120: support power supply config
  ASoC: rockchip: pdm: Add support for CLK-ALWAYS-ON quirks
  ASoC: rockchip: pdm: Add support for HPF control
  ASoC: rockchip: pdm: Use component kcontrol API
  ASoC: rockchip: i2s-tdm: Use component kcontrol API
  ASoC: rockchip: i2s: Use component kcontrol API
  ASoC: rk817: Fix L/R channel order
  arm64: configs: rockchip: Enable SND_SOC_ROCKCHIP_DLP_PCM
  arm64: configs: rockchip_linux: Enable SND_SOC_ROCKCHIP_DLP_PCM
  ASoC: rockchip: multi_dais: Add fifo count for SAI
  ASoC: rockchip: sai: Fix mclk rate check
  ASoC: rockchip: sai: Add support for DLP
  ASoC: rockchip: i2s: Add support for DLP

Change-Id: I1ab1f1509a1e9079767acb7e20df1d2e34a02a9f
This commit is contained in:
Tao Huang
2023-10-24 11:21:15 +08:00
20 changed files with 312 additions and 71 deletions

View File

@@ -127,7 +127,7 @@
max-fps-numerator = <10000>;
max-fps-denominator = <300000>;
bpp = <16>;
link-freq-idx = <12>;
link-freq-idx = <24>;
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
};
/* support mode config end */

View File

@@ -127,7 +127,7 @@
max-fps-numerator = <10000>;
max-fps-denominator = <300000>;
bpp = <16>;
link-freq-idx = <20>;
link-freq-idx = <24>;
vc-array = <0x10 0x20 0x40 0x80>; // VC0~3: bit4~7
};
/* support mode config end */

View File

@@ -697,6 +697,7 @@ CONFIG_SND_VERBOSE_PRINTK=y
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_ROCKCHIP=y
CONFIG_SND_SOC_ROCKCHIP_DLP_PCM=y
CONFIG_SND_SOC_ROCKCHIP_I2S=y
CONFIG_SND_SOC_ROCKCHIP_I2S_TDM=y
CONFIG_SND_SOC_ROCKCHIP_I2S_TDM_MULTI_LANES=y

View File

@@ -392,6 +392,7 @@ CONFIG_SND_SEQ_DUMMY=y
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_ROCKCHIP=y
CONFIG_SND_SOC_ROCKCHIP_DLP_PCM=y
CONFIG_SND_SOC_ROCKCHIP_I2S_TDM=y
CONFIG_SND_SOC_ROCKCHIP_MULTI_DAIS=y
CONFIG_SND_SOC_ROCKCHIP_PDM=y

View File

@@ -245,6 +245,7 @@ struct dw_mipi_dsi2 {
struct phy *dcphy;
union phy_configure_opts phy_opts;
bool disable_hold_mode;
bool c_option;
bool scrambling_en;
unsigned int slice_width;
@@ -953,7 +954,7 @@ dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder,
if (!(dsi2->mode_flags & MIPI_DSI_MODE_VIDEO)) {
s->output_flags |= ROCKCHIP_OUTPUT_MIPI_DS_MODE;
s->soft_te = dsi2->te_gpio ? true : false;
s->hold_mode = true;
s->hold_mode = dsi2->disable_hold_mode ? false : true;
}
if (dsi2->slave) {
@@ -1638,6 +1639,9 @@ static int dw_mipi_dsi2_probe(struct platform_device *pdev)
dsi2->pdata = of_device_get_match_data(dev);
platform_set_drvdata(pdev, dsi2);
if (device_property_read_bool(dev, "disable-hold-mode"))
dsi2->disable_hold_mode = true;
if (device_property_read_bool(dev, "dual-connector-split")) {
dsi2->dual_connector_split = true;

View File

@@ -29,12 +29,13 @@
* V2.03.00
* 1. remote device add the maxim4c prefix to driver name.
*
* V2.04.03
* V2.04.04
* 1. Add regulator supplier dependencies.
* 2. Add config ssc-ratio property
* 3. Add debugfs entry to change MIPI timing
* 4. Use PM runtime autosuspend feature
* 5. Fix unbalanced disabling for PoC regulator
* 6. MIPI VC count does not affected by data lane count
*
*/
#include <linux/clk.h>
@@ -65,7 +66,7 @@
#include "maxim4c_api.h"
#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x03)
#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x04)
#define MAXIM4C_XVCLK_FREQ 25000000

View File

@@ -786,21 +786,9 @@ static int maxim4c_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
val |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
val |= (1 << (data_lanes - 1));
switch (data_lanes) {
case 4:
val |= V4L2_MBUS_CSI2_CHANNEL_3;
fallthrough;
case 3:
val |= V4L2_MBUS_CSI2_CHANNEL_2;
fallthrough;
case 2:
val |= V4L2_MBUS_CSI2_CHANNEL_1;
fallthrough;
case 1:
default:
val |= V4L2_MBUS_CSI2_CHANNEL_0;
break;
}
val |= V4L2_MBUS_CSI2_CHANNEL_3 | V4L2_MBUS_CSI2_CHANNEL_2 |
V4L2_MBUS_CSI2_CHANNEL_1 | V4L2_MBUS_CSI2_CHANNEL_0;
config->type = V4L2_MBUS_CSI2_DPHY;
config->flags = val;

View File

@@ -428,9 +428,11 @@ static int rk_serdes_link_tx_ctrl_enable(struct rk_serdes *serdes,
{
struct hwclk *hwclk = serdes->chip[remote_id].hwclk;
struct i2c_client *client;
struct videomode *vm = &route->vm;
u32 ctrl_val, val;
u32 rx_src;
u32 stream_type;
u32 length;
if (route->stream_type == STREAM_DISPLAY) {
client = serdes->chip[DEVICE_LOCAL].client;
@@ -459,6 +461,18 @@ static int rk_serdes_link_tx_ctrl_enable(struct rk_serdes *serdes,
serdes->i2c_read_reg(client, RKLINK_TX_VIDEO_CTRL, &val);
rx_src = rk_serdes_get_stream_source(serdes, route->local_port0);
val |= rx_src;
if (serdes->version == SERDES_V1) {
/*
* The serdes v1 have a bug when enable video suspend function, which
* is used to enhance the i2c frequency. A workaround ways to do it is
* reducing the video packet length:
* length = ((hactive x 24 / 32 / 16) + 15) / 16 * 16
*/
length = vm->hactive * 24 / 32 / 16;
length = (length + 15) / 16 * 16;
val &= ~VIDEO_REPKT_LENGTH(0xffff);
val |= VIDEO_REPKT_LENGTH(length);
}
serdes->i2c_write_reg(client, RKLINK_TX_VIDEO_CTRL, val);
if (route->local_port0 & RK_SERDES_DUAL_LVDS_RX) {

View File

@@ -259,6 +259,7 @@ struct rk_serdes_pt {
struct rk_serdes {
struct device *dev;
struct rk_serdes_chip chip[DEVICE_MAX];
struct regulator *supply;
struct gpio_desc *reset;
struct gpio_desc *enable;

View File

@@ -11,6 +11,7 @@
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/mfd/core.h>
#include "rkx110_x120.h"
#include "rkx110_reg.h"
@@ -958,6 +959,7 @@ static int rk_serdes_pinctrl_init(struct rk_serdes *serdes)
static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *disp_np;
struct rk_serdes *serdes;
int ret;
@@ -988,6 +990,16 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic
serdes->rate = RATE_2GBPS_83M;
serdes->supply = devm_regulator_get_optional(dev, "power");
if (IS_ERR(serdes->supply)) {
ret = PTR_ERR(serdes->supply);
if (ret != -ENODEV)
return dev_err_probe(dev, ret, "failed to request regulator\n");
serdes->supply = NULL;
}
serdes->enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(serdes->enable)) {
ret = PTR_ERR(serdes->enable);
@@ -1002,15 +1014,10 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic
return ret;
}
gpiod_set_value(serdes->enable, 1);
gpiod_set_value(serdes->reset, 1);
usleep_range(10000, 11000);
gpiod_set_value(serdes->reset, 0);
if (of_get_child_by_name(dev->of_node, "serdes-panel")) {
disp_np = of_get_child_by_name(dev->of_node, "serdes-panel");
if (disp_np) {
serdes->stream_type = STREAM_DISPLAY;
of_node_put(dev->of_node);
of_node_put(disp_np);
dev_info(dev, "serdes display stream");
} else {
serdes->stream_type = STREAM_CAMERA;
@@ -1021,8 +1028,6 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic
if (ret)
return ret;
msleep(20);
ret = mfd_add_devices(dev, -1, rkx110_x120_devs, ARRAY_SIZE(rkx110_x120_devs),
NULL, 0, NULL);
if (ret) {
@@ -1030,13 +1035,29 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic
return ret;
}
if (serdes->supply) {
ret = regulator_enable(serdes->supply);
if (ret < 0) {
dev_err(serdes->dev, "failed to enable supply: %d\n", ret);
return ret;
}
}
gpiod_set_value(serdes->enable, 1);
gpiod_set_value(serdes->reset, 1);
usleep_range(10000, 11000);
gpiod_set_value(serdes->reset, 0);
msleep(20);
rk_serdes_wait_link_ready(serdes);
rk_serdes_read_chip_id(serdes);
ret = rk_serdes_add_hwclk(serdes);
if (ret < 0)
return ret;
goto err;
rk_serdes_set_rate(serdes, RATE_4GBPS_83M);
rk_serdes_pinctrl_init(serdes);
@@ -1045,12 +1066,21 @@ out:
rk_serdes_debugfs_init(serdes);
return 0;
err:
if (serdes->supply)
ret = regulator_disable(serdes->supply);
return ret;
}
static void rk_serdes_i2c_remove(struct i2c_client *client)
{
struct rk_serdes *rk_serdes = i2c_get_clientdata(client);
if (rk_serdes->supply)
regulator_disable(rk_serdes->supply);
mfd_remove_devices(rk_serdes->dev);
}

View File

@@ -104,6 +104,9 @@
#define LANE0_LANE_ID(x) UPDATE(x, 1, 1)
#define LNAE0_ID_SEL(x) UPDATE(x, 0, 0)
#define DES_RKLINK_REC01_PKT_LENGTH LINK_REG(0x0028)
#define E1_REPKT_LENGTH(x) UPDATE(x, 29, 16)
#define E0_REPKT_LENGTH(x) UPDATE(x, 13, 0)
#define RKLINK_DES_REG01_ENGIN_DEL 0x0030
#define E1_ENGINE_DELAY(x) UPDATE(x, 31, 16)
#define E0_ENGINE_DELAY(x) UPDATE(x, 15, 0)
@@ -476,12 +479,14 @@ static int rk120_link_rx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r
{
struct hwclk *hwclk = serdes->chip[remote_id].hwclk;
struct i2c_client *client;
struct videomode *vm = &route->vm;
u32 stream_type;
u32 rx_src;
u32 ctrl_val, mask, val;
u32 lane0_dsource_id, lane1_dsource_id;
bool is_rx_dual_lanes;
bool is_rx_dual_channels;
u32 length;
if (route->stream_type == STREAM_DISPLAY) {
client = serdes->chip[remote_id].client;
@@ -530,6 +535,19 @@ static int rk120_link_rx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r
serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_DST, mask, val);
if (serdes->version == SERDES_V1) {
/*
* The serdes v1 have a bug when enable video suspend function, which
* is used to enhance the i2c frequency. A workaround ways to do it is
* reducing the video packet length:
* length = ((hactive x 24 / 32 / 16) + 15) / 16 * 16
*/
length = vm->hactive * 24 / 32 / 16;
length = (length + 15) / 16 * 16;
serdes->i2c_write_reg(client, DES_RKLINK_REC01_PKT_LENGTH, E0_REPKT_LENGTH(length) |
E1_REPKT_LENGTH(length));
}
serdes->i2c_read_reg(client, RKLINK_DES_SOURCE_CFG, &val);
val &= ~(LANE0_ENGINE_ID(1) | LANE0_LANE_ID(1) | LANE1_ENGINE_ID(1) |

View File

@@ -415,7 +415,7 @@ static int rk817_codec_power_up(struct snd_soc_component *component, int type)
}
snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE,
ADC_DIG_CLK_MASK, DAC_DIG_CLK_DIS);
ADC_DIG_CLK_MASK, ADC_DIG_CLK_DIS);
usleep_range(2000, 2500);
snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE,
ADC_DIG_CLK_MASK, ADC_DIG_CLK_EN);
@@ -1027,7 +1027,7 @@ static int rk817_hw_params(struct snd_pcm_substream *substream,
return 0;
}
static int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
static int rk817_digital_mute_dac(struct snd_soc_dai *dai, int mute, int stream)
{
struct snd_soc_component *component = dai->component;
struct rk817_codec_priv *rk817 = snd_soc_component_get_drvdata(component);
@@ -1049,7 +1049,11 @@ static int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
DAC_DIG_CLK_EN, DAC_DIG_CLK_DIS);
snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE,
DAC_DIG_CLK_EN, DAC_DIG_CLK_EN);
snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE,
I2SRX_EN_MASK, I2SRX_DIS);
} else {
snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE,
I2SRX_EN_MASK, I2SRX_EN);
snd_soc_component_update_bits(component,
RK817_CODEC_DDAC_MUTE_MIXCTL,
DACMT_ENABLE, DACMT_DISABLE);
@@ -1099,6 +1103,28 @@ static int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
static int rk817_digital_mute_adc(struct snd_soc_dai *dai, int mute, int stream)
{
struct snd_soc_component *component = dai->component;
if (mute)
snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE,
I2STX_EN_MASK, I2STX_DIS);
else
snd_soc_component_update_bits(component, RK817_CODEC_DTOP_DIGEN_CLKE,
I2STX_EN_MASK, I2STX_EN);
return 0;
}
static int rk817_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
{
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
return rk817_digital_mute_dac(dai, mute, stream);
else
return rk817_digital_mute_adc(dai, mute, stream);
}
#define RK817_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\
SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_32000 | \
@@ -1143,7 +1169,6 @@ static const struct snd_soc_dai_ops rk817_dai_ops = {
.set_sysclk = rk817_set_dai_sysclk,
.mute_stream = rk817_digital_mute,
.shutdown = rk817_codec_shutdown,
.no_capture_mute = 1,
};
static struct snd_soc_dai_driver rk817_dai[] = {

View File

@@ -25,7 +25,7 @@
#define ADC_DIG_CLK_MASK (0xf << 4)
#define ADC_DIG_CLK_SFT 4
#define ADC_DIG_CLK_DIS (0x0 << 4)
#define ADC_DIG_CLK_EN (0xf << 4)
#define ADC_DIG_CLK_EN (0xe << 4)
#define I2STX_CKE_EN (0x1 << 6)
#define I2STX_CKE_DIS (0x0 << 6)
@@ -33,7 +33,15 @@
#define DAC_DIG_CLK_MASK (0xf << 0)
#define DAC_DIG_CLK_SFT 0
#define DAC_DIG_CLK_DIS (0x0 << 0)
#define DAC_DIG_CLK_EN (0xf << 0)
#define DAC_DIG_CLK_EN (0xe << 0)
#define I2STX_EN_MASK BIT(4)
#define I2STX_EN BIT(4)
#define I2STX_DIS 0
#define I2SRX_EN_MASK BIT(0)
#define I2SRX_EN BIT(0)
#define I2SRX_DIS 0
/* RK817_CODEC_APLL_CFG5 */
#define PLL_PW_DOWN (0x01 << 0)

View File

@@ -22,6 +22,7 @@
#include <sound/dmaengine_pcm.h>
#include "rockchip_i2s.h"
#include "rockchip_dlp_pcm.h"
#define DRV_NAME "rockchip-i2s"
@@ -635,8 +636,8 @@ static int rockchip_i2s_clk_compensation_info(struct snd_kcontrol *kcontrol,
static int rockchip_i2s_clk_compensation_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt);
ucontrol->value.integer.value[0] = i2s->clk_ppm;
@@ -646,8 +647,8 @@ static int rockchip_i2s_clk_compensation_get(struct snd_kcontrol *kcontrol,
static int rockchip_i2s_clk_compensation_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(compnt);
int ppm = ucontrol->value.integer.value[0];
if ((ucontrol->value.integer.value[0] < CLK_PPM_MIN) ||
@@ -863,7 +864,8 @@ static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg)
case I2S_CLR:
case I2S_TXDR:
case I2S_RXDR:
case I2S_FIFOLR:
case I2S_TXFIFOLR:
case I2S_RXFIFOLR:
case I2S_INTSR:
return true;
default:
@@ -876,7 +878,8 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg)
switch (reg) {
case I2S_INTSR:
case I2S_CLR:
case I2S_FIFOLR:
case I2S_TXFIFOLR:
case I2S_RXFIFOLR:
case I2S_TXDR:
case I2S_RXDR:
return true;
@@ -1081,6 +1084,36 @@ static int rockchip_i2s_keep_clk_always_on(struct rk_i2s_dev *i2s)
return 0;
}
static int rockchip_i2s_get_fifo_count(struct device *dev,
struct snd_pcm_substream *substream)
{
struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
unsigned int tx, rx;
int val = 0;
regmap_read(i2s->regmap, I2S_TXFIFOLR, &tx);
regmap_read(i2s->regmap, I2S_RXFIFOLR, &rx);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
val = I2S_FIFOLR_XFL3(tx) +
I2S_FIFOLR_XFL2(tx) +
I2S_FIFOLR_XFL1(tx) +
I2S_FIFOLR_XFL0(tx);
else
/* XFL4 is compatible for old version */
val = I2S_FIFOLR_XFL4(tx) +
I2S_FIFOLR_XFL3(rx) +
I2S_FIFOLR_XFL2(rx) +
I2S_FIFOLR_XFL1(rx) +
I2S_FIFOLR_XFL0(rx);
return val;
}
static const struct snd_dlp_config dconfig = {
.get_fifo_count = rockchip_i2s_get_fifo_count,
};
static int rockchip_i2s_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -1221,7 +1254,11 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
return 0;
}
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (device_property_read_bool(&pdev->dev, "rockchip,digital-loopback"))
ret = devm_snd_dmaengine_dlp_register(&pdev->dev, &dconfig);
else
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret) {
dev_err(&pdev->dev, "Could not register PCM\n");
goto err_suspend;

View File

@@ -229,7 +229,7 @@ enum {
#define I2S_TXCR (0x0000)
#define I2S_RXCR (0x0004)
#define I2S_CKR (0x0008)
#define I2S_FIFOLR (0x000c)
#define I2S_TXFIFOLR (0x000c)
#define I2S_DMACR (0x0010)
#define I2S_INTCR (0x0014)
#define I2S_INTSR (0x0018)
@@ -237,6 +237,7 @@ enum {
#define I2S_CLR (0x0020)
#define I2S_TXDR (0x0024)
#define I2S_RXDR (0x0028)
#define I2S_RXFIFOLR (0x002c)
/* io direction cfg register */
#define I2S_IO_DIRECTION_MASK (7)
@@ -245,4 +246,11 @@ enum {
#define I2S_IO_4CH_OUT_6CH_IN (6)
#define I2S_IO_2CH_OUT_8CH_IN (7)
/* XFL4 is compatible for old version */
#define I2S_FIFOLR_XFL4(v) (((v) & GENMASK(29, 24)) >> 24)
#define I2S_FIFOLR_XFL3(v) (((v) & GENMASK(23, 18)) >> 18)
#define I2S_FIFOLR_XFL2(v) (((v) & GENMASK(17, 12)) >> 12)
#define I2S_FIFOLR_XFL1(v) (((v) & GENMASK(11, 6)) >> 6)
#define I2S_FIFOLR_XFL0(v) (((v) & GENMASK(5, 0)) >> 0)
#endif /* _ROCKCHIP_IIS_H */

View File

@@ -1898,8 +1898,8 @@ static int rockchip_i2s_tdm_clk_compensation_info(struct snd_kcontrol *kcontrol,
static int rockchip_i2s_tdm_clk_compensation_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = i2s_tdm->clk_ppm;
@@ -1909,8 +1909,8 @@ static int rockchip_i2s_tdm_clk_compensation_get(struct snd_kcontrol *kcontrol,
static int rockchip_i2s_tdm_clk_compensation_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_component_get_drvdata(component);
int ret = 0, ppm = 0;
int changed = 0;
unsigned long old_rate;

View File

@@ -20,6 +20,8 @@
#define I2S_TXFIFOLR 0xc
#define I2S_RXFIFOLR 0x2c
#define SAI_TXFIFOLR 0x1c
#define SAI_RXFIFOLR 0x20
/* XFL4 is compatible for old version */
#define I2S_FIFOLR_XFL4(v) (((v) & GENMASK(29, 24)) >> 24)
@@ -28,6 +30,12 @@
#define I2S_FIFOLR_XFL1(v) (((v) & GENMASK(11, 6)) >> 6)
#define I2S_FIFOLR_XFL0(v) (((v) & GENMASK(5, 0)) >> 0)
/* XFIFOLR: Transfer / Receive FIFO Level Register */
#define SAI_FIFOLR_XFL3(v) (((v) & GENMASK(23, 18)) >> 18)
#define SAI_FIFOLR_XFL2(v) (((v) & GENMASK(17, 12)) >> 12)
#define SAI_FIFOLR_XFL1(v) (((v) & GENMASK(11, 6)) >> 6)
#define SAI_FIFOLR_XFL0(v) (((v) & GENMASK(5, 0)) >> 0)
#define MAX_FIFO_SIZE 32 /* max fifo size in frames */
#define SND_DMAENGINE_MPCM_DRV_NAME "snd_dmaengine_mpcm"
@@ -862,7 +870,7 @@ static int dmaengine_mpcm_get_fifo_count(struct device *dev,
struct rk_mdais_dev *mdais = dev_get_drvdata(dev);
struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream);
struct snd_soc_component *component;
unsigned int tx, rx;
unsigned int tx, rx, reg;
int val = 0;
if (unlikely(!prtd))
@@ -889,6 +897,13 @@ static int dmaengine_mpcm_get_fifo_count(struct device *dev,
I2S_FIFOLR_XFL2(rx) +
I2S_FIFOLR_XFL1(rx) +
I2S_FIFOLR_XFL0(rx);
} else if (strstr(dev_driver_string(component->dev), "sai")) {
reg = substream->stream ? SAI_RXFIFOLR : SAI_TXFIFOLR;
val = SAI_FIFOLR_XFL3(reg) +
SAI_FIFOLR_XFL2(reg) +
SAI_FIFOLR_XFL1(reg) +
SAI_FIFOLR_XFL0(reg);
}
return val;

View File

@@ -31,8 +31,10 @@
#define PDM_FILTER_DELAY_MS_MIN (20)
#define PDM_FILTER_DELAY_MS_MAX (1000)
#define PDM_CLK_SHIFT_PPM_MAX (1000000) /* 1 ppm */
#define CLK_PPM_MIN (-1000)
#define CLK_PPM_MAX (1000)
#define CLK_PPM_MIN (-1000)
#define CLK_PPM_MAX (1000)
#define QUIRK_ALWAYS_ON BIT(0)
enum rk_pdm_version {
RK_PDM_RK3229,
@@ -56,6 +58,7 @@ struct rk_pdm_dev {
enum rk_pdm_version version;
unsigned int clk_root_rate;
unsigned int clk_root_initial_rate;
unsigned int quirks;
int clk_ppm;
bool clk_calibrate;
};
@@ -97,6 +100,16 @@ static struct rk_pdm_ds_ratio ds_ratio[] = {
{ 4, 8000 },
};
static const struct pdm_of_quirks {
char *quirk;
int id;
} of_quirks[] = {
{
.quirk = "rockchip,always-on",
.id = QUIRK_ALWAYS_ON,
},
};
static unsigned int get_pdm_clk(struct rk_pdm_dev *pdm, unsigned int sr,
unsigned int *clk_src, unsigned int *clk_out,
unsigned int signoff)
@@ -508,8 +521,8 @@ static int rockchip_pdm_start_delay_info(struct snd_kcontrol *kcontrol,
static int rockchip_pdm_start_delay_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = pdm->start_delay_ms;
@@ -519,8 +532,8 @@ static int rockchip_pdm_start_delay_get(struct snd_kcontrol *kcontrol,
static int rockchip_pdm_start_delay_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component);
if ((ucontrol->value.integer.value[0] < PDM_START_DELAY_MS_MIN) ||
(ucontrol->value.integer.value[0] > PDM_START_DELAY_MS_MAX))
@@ -546,8 +559,8 @@ static int rockchip_pdm_filter_delay_info(struct snd_kcontrol *kcontrol,
static int rockchip_pdm_filter_delay_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = pdm->filter_delay_ms;
@@ -557,8 +570,8 @@ static int rockchip_pdm_filter_delay_get(struct snd_kcontrol *kcontrol,
static int rockchip_pdm_filter_delay_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component);
if ((ucontrol->value.integer.value[0] < PDM_FILTER_DELAY_MS_MIN) ||
(ucontrol->value.integer.value[0] > PDM_FILTER_DELAY_MS_MAX))
@@ -577,12 +590,23 @@ static SOC_ENUM_SINGLE_DECL(rpath2_enum, PDM_CLK_CTRL, 12, rpaths_text);
static SOC_ENUM_SINGLE_DECL(rpath1_enum, PDM_CLK_CTRL, 10, rpaths_text);
static SOC_ENUM_SINGLE_DECL(rpath0_enum, PDM_CLK_CTRL, 8, rpaths_text);
static const char * const hpf_cutoff_text[] = {
"3.79Hz", "60Hz", "243Hz", "493Hz",
};
static SOC_ENUM_SINGLE_DECL(hpf_cutoff_enum, PDM_HPF_CTRL,
0, hpf_cutoff_text);
static const struct snd_kcontrol_new rockchip_pdm_controls[] = {
SOC_ENUM("Receive PATH3 Source Select", rpath3_enum),
SOC_ENUM("Receive PATH2 Source Select", rpath2_enum),
SOC_ENUM("Receive PATH1 Source Select", rpath1_enum),
SOC_ENUM("Receive PATH0 Source Select", rpath0_enum),
SOC_ENUM("HPF Cutoff", hpf_cutoff_enum),
SOC_SINGLE("HPFL Switch", PDM_HPF_CTRL, 3, 1, 0),
SOC_SINGLE("HPFR Switch", PDM_HPF_CTRL, 2, 1, 0),
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "PDM Start Delay Ms",
@@ -616,8 +640,8 @@ static int rockchip_pdm_clk_compensation_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component);
ucontrol->value.integer.value[0] = pdm->clk_ppm;
@@ -627,8 +651,8 @@ static int rockchip_pdm_clk_compensation_get(struct snd_kcontrol *kcontrol,
static int rockchip_pdm_clk_compensation_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_dai_get_drvdata(dai);
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct rk_pdm_dev *pdm = snd_soc_component_get_drvdata(component);
int ppm = ucontrol->value.integer.value[0];
@@ -947,6 +971,29 @@ static int rockchip_pdm_path_parse(struct rk_pdm_dev *pdm, struct device_node *n
return 0;
}
static int rockchip_pdm_keep_clk_always_on(struct rk_pdm_dev *pdm)
{
pm_runtime_forbid(pdm->dev);
dev_info(pdm->dev, "CLK-ALWAYS-ON: samplerate: %d\n", PDM_DEFAULT_RATE);
return 0;
}
static int rockchip_pdm_parse_quirks(struct rk_pdm_dev *pdm)
{
int ret = 0, i = 0;
for (i = 0; i < ARRAY_SIZE(of_quirks); i++)
if (device_property_read_bool(pdm->dev, of_quirks[i].quirk))
pdm->quirks |= of_quirks[i].id;
if (pdm->quirks & QUIRK_ALWAYS_ON)
ret = rockchip_pdm_keep_clk_always_on(pdm);
return ret;
}
static int rockchip_pdm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -1028,6 +1075,10 @@ static int rockchip_pdm_probe(struct platform_device *pdev)
if (ret != 0 && ret != -ENOENT)
goto err_clk;
ret = rockchip_pdm_parse_quirks(pdm);
if (ret)
goto err_clk;
/*
* MUST: after pm_runtime_enable step, any register R/W
* should be wrapped with pm_runtime_get_sync/put.

View File

@@ -19,10 +19,11 @@
#include <sound/tlv.h>
#include "rockchip_sai.h"
#include "rockchip_dlp_pcm.h"
#define DRV_NAME "rockchip-sai"
#define CLK_SHIFT_RATE_HZ_MAX 1 /* 1 Hz */
#define CLK_SHIFT_RATE_HZ_MAX 5
#define FW_RATIO_MAX 8
#define FW_RATIO_MIN 1
#define MAXBURST_PER_FIFO 8
@@ -422,7 +423,7 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
{
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
struct snd_dmaengine_dai_dma_data *dma_data;
unsigned int mclk_rate, bclk_rate, div_bclk;
unsigned int mclk_rate, mclk_req_rate, bclk_rate, div_bclk;
unsigned int ch_per_lane, lanes, slot_width;
unsigned int val, fscr, reg;
@@ -497,15 +498,16 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
if (sai->is_clk_auto)
clk_set_rate(sai->mclk, bclk_rate);
mclk_rate = clk_get_rate(sai->mclk);
if (mclk_rate < bclk_rate - CLK_SHIFT_RATE_HZ_MAX ||
mclk_rate > bclk_rate + CLK_SHIFT_RATE_HZ_MAX) {
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
mclk_req_rate = bclk_rate * div_bclk;
if (mclk_rate < mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
mclk_rate > mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
dev_err(sai->dev, "Mismatch mclk: %u, expected %u (+/- %dHz)\n",
mclk_rate, bclk_rate, CLK_SHIFT_RATE_HZ_MAX);
mclk_rate, mclk_req_rate, CLK_SHIFT_RATE_HZ_MAX);
return -EINVAL;
}
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK,
SAI_CKR_MDIV(div_bclk));
}
@@ -1345,6 +1347,29 @@ static int rockchip_sai_parse_quirks(struct rk_sai_dev *sai)
return ret;
}
static int rockchip_sai_get_fifo_count(struct device *dev,
struct snd_pcm_substream *substream)
{
struct rk_sai_dev *sai = dev_get_drvdata(dev);
int val = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
regmap_read(sai->regmap, SAI_TXFIFOLR, &val);
else
regmap_read(sai->regmap, SAI_RXFIFOLR, &val);
val = ((val & SAI_FIFOLR_XFL3_MASK) >> SAI_FIFOLR_XFL3_SHIFT) +
((val & SAI_FIFOLR_XFL2_MASK) >> SAI_FIFOLR_XFL2_SHIFT) +
((val & SAI_FIFOLR_XFL1_MASK) >> SAI_FIFOLR_XFL1_SHIFT) +
((val & SAI_FIFOLR_XFL0_MASK) >> SAI_FIFOLR_XFL0_SHIFT);
return val;
}
static const struct snd_dlp_config dconfig = {
.get_fifo_count = rockchip_sai_get_fifo_count,
};
static int rockchip_sai_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -1439,7 +1464,11 @@ static int rockchip_sai_probe(struct platform_device *pdev)
return 0;
}
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (device_property_read_bool(&pdev->dev, "rockchip,digital-loopback"))
ret = devm_snd_dmaengine_dlp_register(&pdev->dev, &dconfig);
else
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret)
goto err_runtime_suspend;

View File

@@ -120,6 +120,16 @@
#define SAI_XSHIFT_SEL_MASK GENMASK(23, 0)
#define SAI_XSHIFT_SEL(x) (x)
/* XFIFOLR: Transfer / Receive FIFO Level Register */
#define SAI_FIFOLR_XFL3_SHIFT 18
#define SAI_FIFOLR_XFL3_MASK GENMASK(23, 18)
#define SAI_FIFOLR_XFL2_SHIFT 12
#define SAI_FIFOLR_XFL2_MASK GENMASK(17, 12)
#define SAI_FIFOLR_XFL1_SHIFT 6
#define SAI_FIFOLR_XFL1_MASK GENMASK(11, 6)
#define SAI_FIFOLR_XFL0_SHIFT 0
#define SAI_FIFOLR_XFL0_MASK GENMASK(5, 0)
/* SAI Registers */
#define SAI_TXCR (0x0000)
#define SAI_FSCR (0x0004)