From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 31 Jan 2024 03:29:01 +0000 Subject: [PATCH] add lvds1024*800 --- kernel/sound/soc/rockchip/rockchip_spdif.c | 108 ++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 81 insertions(+), 27 deletions(-) diff --git a/kernel/sound/soc/rockchip/rockchip_spdif.c b/kernel/sound/soc/rockchip/rockchip_spdif.c index e8b6a2e..04d26d1 100644 --- a/kernel/sound/soc/rockchip/rockchip_spdif.c +++ b/kernel/sound/soc/rockchip/rockchip_spdif.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* sound/soc/rockchip/rk_spdif.c * * ALSA SoC Audio Layer - Rockchip I2S Controller driver @@ -6,10 +7,6 @@ * Author: Jianqun <jay.xu@rock-chips.com> * Copyright (c) 2015 Collabora Ltd. * Author: Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> @@ -20,6 +17,7 @@ #include <linux/mfd/syscon.h> #include <linux/regmap.h> #include <sound/pcm_params.h> +#include <sound/pcm_iec958.h> #include <sound/dmaengine_pcm.h> #include "rockchip_spdif.h" @@ -31,7 +29,25 @@ RK_SPDIF_RK3366, }; -#define RK3288_GRF_SOC_CON2 0x24c +/* + * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * CS0: | Mode | d | c | b | a | + * CS1: | Category Code | + * CS2: | Channel Number | Source Number | + * CS3: | Clock Accuracy | Sample Freq | + * CS4: | Ori Sample Freq | Word Length | + * CS5: | | CGMS-A | + * CS6~CS23: Reserved + * + * a: use of channel status block + * b: linear PCM identification: 0 for lpcm, 1 for nlpcm + * c: copyright information + * d: additional format information + */ +#define CS_BYTE 6 +#define CS_FRAME(c) ((c) << 16 | (c)) + +#define RK3288_GRF_SOC_CON2 0x24c struct rk_spdif_dev { struct device *dev; @@ -44,7 +60,7 @@ struct regmap *regmap; }; -static const struct of_device_id rk_spdif_match[] = { +static const struct of_device_id rk_spdif_match[] __maybe_unused = { { .compatible = "rockchip,rk3066-spdif", .data = (void *)RK_SPDIF_RK3066 }, { .compatible = "rockchip,rk3188-spdif", @@ -62,6 +78,8 @@ { .compatible = "rockchip,rk3399-spdif", .data = (void *)RK_SPDIF_RK3366 }, { .compatible = "rockchip,rk3568-spdif", + .data = (void *)RK_SPDIF_RK3366 }, + { .compatible = "rockchip,rk3588-spdif", .data = (void *)RK_SPDIF_RK3366 }, {}, }; @@ -91,6 +109,7 @@ ret = clk_prepare_enable(spdif->hclk); if (ret) { + clk_disable_unprepare(spdif->mclk); dev_err(spdif->dev, "hclk clock enable failed %d\n", ret); return ret; } @@ -113,11 +132,25 @@ { struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai); unsigned int val = SPDIF_CFGR_HALFWORD_ENABLE; - int srate, mclk; - int ret; + unsigned int mclk_rate = clk_get_rate(spdif->mclk); + int bmc, div, ret, i; + u8 cs[CS_BYTE]; + u16 *fc = (u16 *)cs; - srate = params_rate(params); - mclk = srate * 128; + ret = snd_pcm_create_iec958_consumer_hw_params(params, cs, sizeof(cs)); + if (ret < 0) + return ret; + + for (i = 0; i < CS_BYTE / 2; i++) + regmap_write(spdif->regmap, SPDIF_CHNSRn(i), CS_FRAME(fc[i])); + + regmap_update_bits(spdif->regmap, SPDIF_CFGR, SPDIF_CFGR_CSE_MASK, + SPDIF_CFGR_CSE_EN); + + /* bmc = 128fs */ + bmc = 128 * params_rate(params); + div = DIV_ROUND_CLOSEST(mclk_rate, bmc); + val |= SPDIF_CFGR_CLK_DIV(div); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -128,23 +161,25 @@ break; case SNDRV_PCM_FORMAT_S24_LE: val |= SPDIF_CFGR_VDW_24; + val |= SPDIF_CFGR_ADJ_RIGHT_J; + break; + case SNDRV_PCM_FORMAT_S32_LE: + val |= SPDIF_CFGR_VDW_24; + val |= SPDIF_CFGR_ADJ_LEFT_J; break; default: return -EINVAL; } - /* Set clock and calculate divider */ - ret = clk_set_rate(spdif->mclk, mclk); - if (ret != 0) { - dev_err(spdif->dev, "Failed to set module clock rate: %d\n", - ret); - return ret; - } + regmap_update_bits(spdif->regmap, SPDIF_CFGR, SPDIF_CFGR_CLR_MASK, + SPDIF_CFGR_CLR_EN); + udelay(1); ret = regmap_update_bits(spdif->regmap, SPDIF_CFGR, SPDIF_CFGR_CLK_DIV_MASK | SPDIF_CFGR_HALFWORD_ENABLE | - SDPIF_CFGR_VDW_MASK, val); + SDPIF_CFGR_VDW_MASK | + SPDIF_CFGR_ADJ_MASK, val); return ret; } @@ -203,7 +238,24 @@ return 0; } +static int rk_spdif_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct rk_spdif_dev *spdif = snd_soc_dai_get_drvdata(dai); + int ret = 0; + + if (!freq) + return 0; + + ret = clk_set_rate(spdif->mclk, freq); + if (ret) + dev_err(spdif->dev, "Failed to set mclk: %d\n", ret); + + return ret; +} + static const struct snd_soc_dai_ops rk_spdif_dai_ops = { + .set_sysclk = rk_spdif_set_sysclk, .hw_params = rk_spdif_hw_params, .trigger = rk_spdif_trigger, }; @@ -214,14 +266,11 @@ .stream_name = "Playback", .channels_min = 2, .channels_max = 2, - .rates = (SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000), + .rates = SNDRV_PCM_RATE_8000_192000, .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | - SNDRV_PCM_FMTBIT_S24_LE), + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), }, .ops = &rk_spdif_dai_ops, }; @@ -238,6 +287,9 @@ case SPDIF_INTCR: case SPDIF_XFER: case SPDIF_SMPDR: + case SPDIF_VLDFRn(0) ... SPDIF_VLDFRn(11): + case SPDIF_USRDRn(0) ... SPDIF_USRDRn(11): + case SPDIF_CHNSRn(0) ... SPDIF_CHNSRn(11): return true; default: return false; @@ -253,6 +305,9 @@ case SPDIF_INTSR: case SPDIF_XFER: case SPDIF_SMPDR: + case SPDIF_VLDFRn(0) ... SPDIF_VLDFRn(11): + case SPDIF_USRDRn(0) ... SPDIF_USRDRn(11): + case SPDIF_CHNSRn(0) ... SPDIF_CHNSRn(11): return true; default: return false; @@ -275,7 +330,7 @@ .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = SPDIF_SMPDR, + .max_register = SPDIF_VERSION, .writeable_reg = rk_spdif_wr_reg, .readable_reg = rk_spdif_rd_reg, .volatile_reg = rk_spdif_volatile_reg, @@ -320,8 +375,7 @@ if (IS_ERR(spdif->mclk)) return PTR_ERR(spdif->mclk); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs); -- Gitblit v1.6.2