summaryrefslogtreecommitdiffstats
path: root/sound/soc/loongson/loongson_i2s_pci.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2023-06-26 15:38:02 +0200
committerTakashi Iwai <tiwai@suse.de>2023-06-26 15:38:02 +0200
commitd6048fdc870240e5020343f8af0c825829c232bd (patch)
treed83ca76eaac5f8bf1c4c16f003aad64baa8fae62 /sound/soc/loongson/loongson_i2s_pci.c
parenta15b51375684c2bfa6017bb185139477e7a3b96c (diff)
parent2d0cad0473bd1ffbc5842be0b9f2546265acb011 (diff)
downloadlinux-stable-d6048fdc870240e5020343f8af0c825829c232bd.tar.gz
linux-stable-d6048fdc870240e5020343f8af0c825829c232bd.tar.bz2
linux-stable-d6048fdc870240e5020343f8af0c825829c232bd.zip
Merge tag 'asoc-v6.5' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v6.5 A fairly quiet release from a core and framework point of view, but a very big one from the point of view of new drivers: - More refectoring from Morimoto-san, this time mainly around DAI links and how we control the ordering of trigger() callbacks. - Convert a lot of drivers to use maple tree based caches. - Lots of work on the x86 driver stack. - Compressed audio support for Qualcomm. - Support for AMD SoundWire, Analog Devices SSM3515, Google Chameleon, Ingenic X1000, Intel systems with various CODECs, Longsoon platforms, Maxim MAX98388, Mediatek MT8188, Nuvoton NAU8825C, NXP platforms with NAU8822, Qualcomm WSA884x, StarFive JH7110, Texas Instruments TAS2781.
Diffstat (limited to 'sound/soc/loongson/loongson_i2s_pci.c')
-rw-r--r--sound/soc/loongson/loongson_i2s_pci.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/sound/soc/loongson/loongson_i2s_pci.c b/sound/soc/loongson/loongson_i2s_pci.c
new file mode 100644
index 000000000000..fa90361865c6
--- /dev/null
+++ b/sound/soc/loongson/loongson_i2s_pci.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// loongson_i2s_pci.c -- Loongson I2S controller driver
+//
+// Copyright (C) 2023 Loongson Technology Corporation Limited
+// Author: Yingkun Meng <mengyingkun@loongson.cn>
+//
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include <sound/soc.h>
+#include "loongson_i2s.h"
+#include "loongson_dma.h"
+
+static bool loongson_i2s_wr_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LS_I2S_CFG:
+ case LS_I2S_CTRL:
+ case LS_I2S_RX_DATA:
+ case LS_I2S_TX_DATA:
+ case LS_I2S_CFG1:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool loongson_i2s_rd_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LS_I2S_VER:
+ case LS_I2S_CFG:
+ case LS_I2S_CTRL:
+ case LS_I2S_RX_DATA:
+ case LS_I2S_TX_DATA:
+ case LS_I2S_CFG1:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool loongson_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LS_I2S_CFG:
+ case LS_I2S_CTRL:
+ case LS_I2S_RX_DATA:
+ case LS_I2S_TX_DATA:
+ case LS_I2S_CFG1:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config loongson_i2s_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = LS_I2S_CFG1,
+ .writeable_reg = loongson_i2s_wr_reg,
+ .readable_reg = loongson_i2s_rd_reg,
+ .volatile_reg = loongson_i2s_volatile_reg,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static int loongson_i2s_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pid)
+{
+ const struct fwnode_handle *fwnode = pdev->dev.fwnode;
+ struct loongson_dma_data *tx_data, *rx_data;
+ struct loongson_i2s *i2s;
+ int ret;
+
+ if (pcim_enable_device(pdev)) {
+ dev_err(&pdev->dev, "pci_enable_device failed\n");
+ return -ENODEV;
+ }
+
+ i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
+ if (!i2s)
+ return -ENOMEM;
+
+ i2s->rev_id = pdev->revision;
+ i2s->dev = &pdev->dev;
+ pci_set_drvdata(pdev, i2s);
+
+ ret = pcim_iomap_regions(pdev, 1 << 0, dev_name(&pdev->dev));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "iomap_regions failed\n");
+ return ret;
+ }
+ i2s->reg_base = pcim_iomap_table(pdev)[0];
+ i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->reg_base,
+ &loongson_i2s_regmap_config);
+ if (IS_ERR(i2s->regmap)) {
+ dev_err(&pdev->dev, "regmap_init_mmio failed\n");
+ return PTR_ERR(i2s->regmap);
+ }
+
+ tx_data = &i2s->tx_dma_data;
+ rx_data = &i2s->rx_dma_data;
+
+ tx_data->dev_addr = pci_resource_start(pdev, 0) + LS_I2S_TX_DATA;
+ tx_data->order_addr = i2s->reg_base + LS_I2S_TX_ORDER;
+
+ rx_data->dev_addr = pci_resource_start(pdev, 0) + LS_I2S_RX_DATA;
+ rx_data->order_addr = i2s->reg_base + LS_I2S_RX_ORDER;
+
+ tx_data->irq = fwnode_irq_get_byname(fwnode, "tx");
+ if (tx_data->irq < 0) {
+ dev_err(&pdev->dev, "dma tx irq invalid\n");
+ return tx_data->irq;
+ }
+
+ rx_data->irq = fwnode_irq_get_byname(fwnode, "rx");
+ if (rx_data->irq < 0) {
+ dev_err(&pdev->dev, "dma rx irq invalid\n");
+ return rx_data->irq;
+ }
+
+ device_property_read_u32(&pdev->dev, "clock-frequency", &i2s->clk_rate);
+ if (!i2s->clk_rate) {
+ dev_err(&pdev->dev, "clock-frequency property invalid\n");
+ return -EINVAL;
+ }
+
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+
+ if (i2s->rev_id == 1) {
+ regmap_write(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_RESET);
+ udelay(200);
+ }
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &loongson_i2s_component,
+ &loongson_i2s_dai, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "register DAI failed %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pci_device_id loongson_i2s_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x7a27) },
+ { },
+};
+MODULE_DEVICE_TABLE(pci, loongson_i2s_ids);
+
+static struct pci_driver loongson_i2s_driver = {
+ .name = "loongson-i2s-pci",
+ .id_table = loongson_i2s_ids,
+ .probe = loongson_i2s_pci_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ .pm = pm_sleep_ptr(&loongson_i2s_pm),
+ },
+};
+module_pci_driver(loongson_i2s_driver);
+
+MODULE_DESCRIPTION("Loongson I2S Master Mode ASoC Driver");
+MODULE_AUTHOR("Loongson Technology Corporation Limited");
+MODULE_LICENSE("GPL");