File Index
Files and directories
Sign in
FILE

loongson_i2s_pci.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/loongson/loongson_i2s_pci.c C
  1// SPDX-License-Identifier: GPL-2.0
  2//
  3// loongson_i2s_pci.c -- Loongson I2S controller driver
  4//
  5// Copyright (C) 2023 Loongson Technology Corporation Limited
  6// Author: Yingkun Meng <mengyingkun@loongson.cn>
  7//
  8
  9#include <linux/module.h>
 10#include <linux/delay.h>
 11#include <linux/pm_runtime.h>
 12#include <linux/dma-mapping.h>
 13#include <linux/acpi.h>
 14#include <linux/pci.h>
 15#include <sound/soc.h>
 16#include "loongson_i2s.h"
 17#include "loongson_dma.h"
 18
 19#define DRIVER_NAME "loongson-i2s-pci"
 20
 21static bool loongson_i2s_wr_reg(struct device *dev, unsigned int reg)
 22{
 23	switch (reg) {
 24	case LS_I2S_CFG:
 25	case LS_I2S_CTRL:
 26	case LS_I2S_RX_DATA:
 27	case LS_I2S_TX_DATA:
 28	case LS_I2S_CFG1:
 29		return true;
 30	default:
 31		return false;
 32	};
 33}
 34
 35static bool loongson_i2s_rd_reg(struct device *dev, unsigned int reg)
 36{
 37	switch (reg) {
 38	case LS_I2S_VER:
 39	case LS_I2S_CFG:
 40	case LS_I2S_CTRL:
 41	case LS_I2S_RX_DATA:
 42	case LS_I2S_TX_DATA:
 43	case LS_I2S_CFG1:
 44		return true;
 45	default:
 46		return false;
 47	};
 48}
 49
 50static bool loongson_i2s_volatile_reg(struct device *dev, unsigned int reg)
 51{
 52	switch (reg) {
 53	case LS_I2S_CFG:
 54	case LS_I2S_CTRL:
 55	case LS_I2S_RX_DATA:
 56	case LS_I2S_TX_DATA:
 57	case LS_I2S_CFG1:
 58		return true;
 59	default:
 60		return false;
 61	};
 62}
 63
 64static const struct regmap_config loongson_i2s_regmap_config = {
 65	.reg_bits = 32,
 66	.reg_stride = 4,
 67	.val_bits = 32,
 68	.max_register = LS_I2S_CFG1,
 69	.writeable_reg = loongson_i2s_wr_reg,
 70	.readable_reg = loongson_i2s_rd_reg,
 71	.volatile_reg = loongson_i2s_volatile_reg,
 72	.cache_type = REGCACHE_FLAT,
 73};
 74
 75static int loongson_i2s_pci_probe(struct pci_dev *pdev,
 76				  const struct pci_device_id *pid)
 77{
 78	const struct fwnode_handle *fwnode = pdev->dev.fwnode;
 79	struct loongson_dma_data *tx_data, *rx_data;
 80	struct device *dev = &pdev->dev;
 81	struct loongson_i2s *i2s;
 82	int ret;
 83
 84	if (pcim_enable_device(pdev)) {
 85		dev_err(dev, "pci_enable_device failed\n");
 86		return -ENODEV;
 87	}
 88
 89	i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
 90	if (!i2s)
 91		return -ENOMEM;
 92
 93	i2s->rev_id = pdev->revision;
 94	i2s->dev = dev;
 95	pci_set_drvdata(pdev, i2s);
 96
 97	i2s->reg_base = pcim_iomap_region(pdev, 0, DRIVER_NAME);
 98	if (IS_ERR(i2s->reg_base)) {
 99		dev_err(dev, "iomap_region failed\n");
100		return PTR_ERR(i2s->reg_base);
101	}
102
103	i2s->regmap = devm_regmap_init_mmio(dev, i2s->reg_base,
104					    &loongson_i2s_regmap_config);
105	if (IS_ERR(i2s->regmap))
106		return dev_err_probe(dev, PTR_ERR(i2s->regmap), "regmap_init_mmio failed\n");
107
108	tx_data = &i2s->tx_dma_data;
109	rx_data = &i2s->rx_dma_data;
110
111	tx_data->dev_addr = pci_resource_start(pdev, 0) + LS_I2S_TX_DATA;
112	tx_data->order_addr = i2s->reg_base + LS_I2S_TX_ORDER;
113
114	rx_data->dev_addr = pci_resource_start(pdev, 0) + LS_I2S_RX_DATA;
115	rx_data->order_addr = i2s->reg_base + LS_I2S_RX_ORDER;
116
117	tx_data->irq = fwnode_irq_get_byname(fwnode, "tx");
118	if (tx_data->irq < 0)
119		return dev_err_probe(dev, tx_data->irq, "dma tx irq invalid\n");
120
121	rx_data->irq = fwnode_irq_get_byname(fwnode, "rx");
122	if (rx_data->irq < 0)
123		return dev_err_probe(dev, rx_data->irq, "dma rx irq invalid\n");
124
125	ret = device_property_read_u32(dev, "clock-frequency", &i2s->clk_rate);
126	if (ret)
127		return dev_err_probe(dev, ret, "clock-frequency property invalid\n");
128
129	dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
130
131	if (i2s->rev_id == 1) {
132		regmap_write(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_RESET);
133		udelay(200);
134	}
135
136	ret = devm_snd_soc_register_component(dev, &loongson_i2s_component,
137					      &loongson_i2s_dai, 1);
138	if (ret)
139		return dev_err_probe(dev, ret, "register DAI failed\n");
140
141	return 0;
142}
143
144static const struct pci_device_id loongson_i2s_ids[] = {
145	{ PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x7a27) },
146	{ },
147};
148MODULE_DEVICE_TABLE(pci, loongson_i2s_ids);
149
150static struct pci_driver loongson_i2s_driver = {
151	.name = DRIVER_NAME,
152	.id_table = loongson_i2s_ids,
153	.probe = loongson_i2s_pci_probe,
154	.driver = {
155		.pm = pm_sleep_ptr(&loongson_i2s_pm),
156	},
157};
158module_pci_driver(loongson_i2s_driver);
159
160MODULE_DESCRIPTION("Loongson I2S Master Mode ASoC Driver");
161MODULE_AUTHOR("Loongson Technology Corporation Limited");
162MODULE_LICENSE("GPL");
~/ Read-only file preview.