ASoC: loongson: Add Loongson-2K0300 I2S controller support

The Loongson-2K0300 I2S interface differs significantly from the
Loongson-2K1000. Although both utilize external DMA controllers, the
Loongson-2K0300 does not require additional registers for routing
configuration.

Due to hardware design flaw, an extra controller reset sequence is
required during probe.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
Link: https://patch.msgid.link/4d3caa62d4275e1495505387198408f4d30d453c.1782439646.git.zhoubinbin@loongson.cn
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Binbin Zhou 2026-06-26 10:27:05 +08:00 committed by Mark Brown
parent 914e95aaec
commit 41ab1f8a0e
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -2,7 +2,7 @@
//
// Loongson I2S controller master mode dirver(platform device)
//
// Copyright (C) 2023-2024 Loongson Technology Corporation Limited
// Copyright (C) 2023-2026 Loongson Technology Corporation Limited
//
// Author: Yingkun Meng <mengyingkun@loongson.cn>
// Binbin Zhou <zhoubinbin@loongson.cn>
@ -21,6 +21,7 @@
#include "loongson_i2s.h"
#include "loongson_dma.h"
/* Loongson-2K1000 APBDMA routing */
#define LOONGSON_I2S_RX_DMA_OFFSET 21
#define LOONGSON_I2S_TX_DMA_OFFSET 18
@ -30,6 +31,11 @@
#define LOONGSON_DMA3_CONF 0x3
#define LOONGSON_DMA4_CONF 0x4
struct loongson_i2s_plat_config {
int rev_id;
int (*i2s_dma_config)(struct platform_device *pdev);
};
static int loongson_i2s_apbdma_config(struct platform_device *pdev)
{
int val;
@ -47,8 +53,18 @@ static int loongson_i2s_apbdma_config(struct platform_device *pdev)
return 0;
}
static const struct loongson_i2s_plat_config ls2k0300_i2s_plat_config = {
.rev_id = 1,
};
static const struct loongson_i2s_plat_config ls2k1000_i2s_plat_config = {
.rev_id = 0,
.i2s_dma_config = loongson_i2s_apbdma_config,
};
static int loongson_i2s_plat_probe(struct platform_device *pdev)
{
const struct loongson_i2s_plat_config *plat_config;
struct device *dev = &pdev->dev;
struct loongson_i2s *i2s;
struct resource *res;
@ -59,12 +75,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
if (!i2s)
return -ENOMEM;
ret = loongson_i2s_apbdma_config(pdev);
if (ret)
return ret;
plat_config = device_get_match_data(dev);
if (!plat_config)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2s->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (plat_config->i2s_dma_config) {
ret = plat_config->i2s_dma_config(pdev);
if (ret)
return ret;
}
i2s->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(i2s->reg_base))
return dev_err_probe(dev, PTR_ERR(i2s->reg_base),
"devm_ioremap_resource failed\n");
@ -87,11 +108,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
if (IS_ERR(i2s_clk))
return dev_err_probe(dev, PTR_ERR(i2s_clk), "clock property invalid\n");
i2s->clk_rate = clk_get_rate(i2s_clk);
i2s->rev_id = plat_config->rev_id;
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
dev_set_name(dev, LS_I2S_DRVNAME);
dev_set_drvdata(dev, i2s);
if (i2s->rev_id == 1) {
regmap_update_bits(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_RESET, I2S_CTRL_RESET);
fsleep(200);
}
ret = devm_snd_soc_register_component(dev, &loongson_i2s_edma_component,
&loongson_i2s_dai, 1);
if (ret)
@ -102,7 +129,8 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
}
static const struct of_device_id loongson_i2s_ids[] = {
{ .compatible = "loongson,ls2k1000-i2s" },
{ .compatible = "loongson,ls2k0300-i2s", .data = &ls2k0300_i2s_plat_config },
{ .compatible = "loongson,ls2k1000-i2s", .data = &ls2k1000_i2s_plat_config },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, loongson_i2s_ids);