1 // SPDX-License-Identifier: GPL-2.0
3 // loongson_i2s_pci.c -- Loongson I2S controller driver
5 // Copyright (C) 2023 Loongson Technology Corporation Limited
6 // Author: Yingkun Meng <mengyingkun@loongson.cn>
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"
19 static bool loongson_i2s_wr_reg(struct device
*dev
, unsigned int reg
)
33 static bool loongson_i2s_rd_reg(struct device
*dev
, unsigned int reg
)
48 static bool loongson_i2s_volatile_reg(struct device
*dev
, unsigned int reg
)
62 static const struct regmap_config loongson_i2s_regmap_config
= {
66 .max_register
= LS_I2S_CFG1
,
67 .writeable_reg
= loongson_i2s_wr_reg
,
68 .readable_reg
= loongson_i2s_rd_reg
,
69 .volatile_reg
= loongson_i2s_volatile_reg
,
70 .cache_type
= REGCACHE_FLAT
,
73 static int loongson_i2s_pci_probe(struct pci_dev
*pdev
,
74 const struct pci_device_id
*pid
)
76 const struct fwnode_handle
*fwnode
= pdev
->dev
.fwnode
;
77 struct loongson_dma_data
*tx_data
, *rx_data
;
78 struct device
*dev
= &pdev
->dev
;
79 struct loongson_i2s
*i2s
;
82 if (pcim_enable_device(pdev
)) {
83 dev_err(dev
, "pci_enable_device failed\n");
87 i2s
= devm_kzalloc(dev
, sizeof(*i2s
), GFP_KERNEL
);
91 i2s
->rev_id
= pdev
->revision
;
93 pci_set_drvdata(pdev
, i2s
);
95 ret
= pcim_iomap_regions(pdev
, 1 << 0, dev_name(dev
));
97 dev_err(dev
, "iomap_regions failed\n");
101 i2s
->reg_base
= pcim_iomap_table(pdev
)[0];
102 i2s
->regmap
= devm_regmap_init_mmio(dev
, i2s
->reg_base
,
103 &loongson_i2s_regmap_config
);
104 if (IS_ERR(i2s
->regmap
))
105 return dev_err_probe(dev
, PTR_ERR(i2s
->regmap
), "regmap_init_mmio failed\n");
107 tx_data
= &i2s
->tx_dma_data
;
108 rx_data
= &i2s
->rx_dma_data
;
110 tx_data
->dev_addr
= pci_resource_start(pdev
, 0) + LS_I2S_TX_DATA
;
111 tx_data
->order_addr
= i2s
->reg_base
+ LS_I2S_TX_ORDER
;
113 rx_data
->dev_addr
= pci_resource_start(pdev
, 0) + LS_I2S_RX_DATA
;
114 rx_data
->order_addr
= i2s
->reg_base
+ LS_I2S_RX_ORDER
;
116 tx_data
->irq
= fwnode_irq_get_byname(fwnode
, "tx");
117 if (tx_data
->irq
< 0)
118 return dev_err_probe(dev
, tx_data
->irq
, "dma tx irq invalid\n");
120 rx_data
->irq
= fwnode_irq_get_byname(fwnode
, "rx");
121 if (rx_data
->irq
< 0)
122 return dev_err_probe(dev
, rx_data
->irq
, "dma rx irq invalid\n");
124 ret
= device_property_read_u32(dev
, "clock-frequency", &i2s
->clk_rate
);
126 return dev_err_probe(dev
, ret
, "clock-frequency property invalid\n");
128 dma_set_mask_and_coherent(dev
, DMA_BIT_MASK(64));
130 if (i2s
->rev_id
== 1) {
131 regmap_write(i2s
->regmap
, LS_I2S_CTRL
, I2S_CTRL_RESET
);
135 ret
= devm_snd_soc_register_component(dev
, &loongson_i2s_component
,
136 &loongson_i2s_dai
, 1);
138 return dev_err_probe(dev
, ret
, "register DAI failed\n");
143 static const struct pci_device_id loongson_i2s_ids
[] = {
144 { PCI_DEVICE(PCI_VENDOR_ID_LOONGSON
, 0x7a27) },
147 MODULE_DEVICE_TABLE(pci
, loongson_i2s_ids
);
149 static struct pci_driver loongson_i2s_driver
= {
150 .name
= "loongson-i2s-pci",
151 .id_table
= loongson_i2s_ids
,
152 .probe
= loongson_i2s_pci_probe
,
154 .pm
= pm_sleep_ptr(&loongson_i2s_pm
),
157 module_pci_driver(loongson_i2s_driver
);
159 MODULE_DESCRIPTION("Loongson I2S Master Mode ASoC Driver");
160 MODULE_AUTHOR("Loongson Technology Corporation Limited");
161 MODULE_LICENSE("GPL");