1258437Sbrooks// SPDX-License-Identifier: GPL-2.0 2244541Sbrooks// 3244541Sbrooks// loongson_i2s_pci.c -- Loongson I2S controller driver 4244541Sbrooks// 5244541Sbrooks// Copyright (C) 2023 Loongson Technology Corporation Limited 6244541Sbrooks// Author: Yingkun Meng <mengyingkun@loongson.cn> 7244541Sbrooks// 8244541Sbrooks 9244541Sbrooks#include <linux/module.h> 10244541Sbrooks#include <linux/delay.h> 11244541Sbrooks#include <linux/pm_runtime.h> 12244541Sbrooks#include <linux/dma-mapping.h> 13244541Sbrooks#include <linux/acpi.h> 14244541Sbrooks#include <linux/pci.h> 15244541Sbrooks#include <sound/soc.h> 16244541Sbrooks#include "loongson_i2s.h" 17244541Sbrooks#include "loongson_dma.h" 18244541Sbrooks 19244541Sbrooksstatic bool loongson_i2s_wr_reg(struct device *dev, unsigned int reg) 20244541Sbrooks{ 21244541Sbrooks switch (reg) { 22244541Sbrooks case LS_I2S_CFG: 23244541Sbrooks case LS_I2S_CTRL: 24244541Sbrooks case LS_I2S_RX_DATA: 25244541Sbrooks case LS_I2S_TX_DATA: 26244541Sbrooks case LS_I2S_CFG1: 27244541Sbrooks return true; 28244541Sbrooks default: 29244541Sbrooks return false; 30244541Sbrooks }; 31244541Sbrooks} 32244541Sbrooks 33244541Sbrooksstatic bool loongson_i2s_rd_reg(struct device *dev, unsigned int reg) 34244541Sbrooks{ 35244541Sbrooks switch (reg) { 36244541Sbrooks case LS_I2S_VER: 37244541Sbrooks case LS_I2S_CFG: 38244541Sbrooks case LS_I2S_CTRL: 39244541Sbrooks case LS_I2S_RX_DATA: 40244541Sbrooks case LS_I2S_TX_DATA: 41258437Sbrooks case LS_I2S_CFG1: 42244541Sbrooks return true; 43244541Sbrooks default: 44244541Sbrooks return false; 45244541Sbrooks }; 46244541Sbrooks} 47244541Sbrooks 48244541Sbrooksstatic bool loongson_i2s_volatile_reg(struct device *dev, unsigned int reg) 49244541Sbrooks{ 50258437Sbrooks switch (reg) { 51256687Sbrooks case LS_I2S_CFG: 52244541Sbrooks case LS_I2S_CTRL: 53244541Sbrooks case LS_I2S_RX_DATA: 54244541Sbrooks case LS_I2S_TX_DATA: 55244541Sbrooks case LS_I2S_CFG1: 56244541Sbrooks return true; 57244541Sbrooks default: 58244541Sbrooks return false; 59244541Sbrooks }; 60244541Sbrooks} 61244541Sbrooks 62244541Sbrooksstatic const struct regmap_config loongson_i2s_regmap_config = { 63244541Sbrooks .reg_bits = 32, 64244541Sbrooks .reg_stride = 4, 65244541Sbrooks .val_bits = 32, 66244541Sbrooks .max_register = LS_I2S_CFG1, 67244541Sbrooks .writeable_reg = loongson_i2s_wr_reg, 68244541Sbrooks .readable_reg = loongson_i2s_rd_reg, 69244541Sbrooks .volatile_reg = loongson_i2s_volatile_reg, 70244541Sbrooks .cache_type = REGCACHE_FLAT, 71244541Sbrooks}; 72244541Sbrooks 73244541Sbrooksstatic int loongson_i2s_pci_probe(struct pci_dev *pdev, 74244541Sbrooks const struct pci_device_id *pid) 75258437Sbrooks{ 76258437Sbrooks const struct fwnode_handle *fwnode = pdev->dev.fwnode; 77244541Sbrooks struct loongson_dma_data *tx_data, *rx_data; 78244541Sbrooks struct loongson_i2s *i2s; 79258437Sbrooks int ret; 80258437Sbrooks 81258437Sbrooks if (pcim_enable_device(pdev)) { 82258437Sbrooks dev_err(&pdev->dev, "pci_enable_device failed\n"); 83258437Sbrooks return -ENODEV; 84258437Sbrooks } 85258437Sbrooks 86258437Sbrooks i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); 87244541Sbrooks if (!i2s) 88244541Sbrooks return -ENOMEM; 89244541Sbrooks 90244541Sbrooks i2s->rev_id = pdev->revision; 91244541Sbrooks i2s->dev = &pdev->dev; 92244541Sbrooks pci_set_drvdata(pdev, i2s); 93244541Sbrooks 94244541Sbrooks ret = pcim_iomap_regions(pdev, 1 << 0, dev_name(&pdev->dev)); 95244541Sbrooks if (ret < 0) { 96244541Sbrooks dev_err(&pdev->dev, "iomap_regions failed\n"); 97244541Sbrooks return ret; 98244541Sbrooks } 99244541Sbrooks i2s->reg_base = pcim_iomap_table(pdev)[0]; 100244541Sbrooks i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->reg_base, 101244541Sbrooks &loongson_i2s_regmap_config); 102244541Sbrooks if (IS_ERR(i2s->regmap)) { 103244541Sbrooks dev_err(&pdev->dev, "regmap_init_mmio failed\n"); 104244541Sbrooks return PTR_ERR(i2s->regmap); 105244541Sbrooks } 106244541Sbrooks 107244541Sbrooks tx_data = &i2s->tx_dma_data; 108244541Sbrooks rx_data = &i2s->rx_dma_data; 109244541Sbrooks 110244541Sbrooks tx_data->dev_addr = pci_resource_start(pdev, 0) + LS_I2S_TX_DATA; 111244541Sbrooks tx_data->order_addr = i2s->reg_base + LS_I2S_TX_ORDER; 112244541Sbrooks 113244541Sbrooks rx_data->dev_addr = pci_resource_start(pdev, 0) + LS_I2S_RX_DATA; 114244541Sbrooks rx_data->order_addr = i2s->reg_base + LS_I2S_RX_ORDER; 115244541Sbrooks 116244541Sbrooks tx_data->irq = fwnode_irq_get_byname(fwnode, "tx"); 117244541Sbrooks if (tx_data->irq < 0) { 118244541Sbrooks dev_err(&pdev->dev, "dma tx irq invalid\n"); 119244541Sbrooks return tx_data->irq; 120244541Sbrooks } 121244541Sbrooks 122244541Sbrooks rx_data->irq = fwnode_irq_get_byname(fwnode, "rx"); 123244541Sbrooks if (rx_data->irq < 0) { 124244541Sbrooks dev_err(&pdev->dev, "dma rx irq invalid\n"); 125244541Sbrooks return rx_data->irq; 126244541Sbrooks } 127244541Sbrooks 128244541Sbrooks device_property_read_u32(&pdev->dev, "clock-frequency", &i2s->clk_rate); 129244541Sbrooks if (!i2s->clk_rate) { 130244541Sbrooks dev_err(&pdev->dev, "clock-frequency property invalid\n"); 131244541Sbrooks return -EINVAL; 132244541Sbrooks } 133244541Sbrooks 134244541Sbrooks dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 135244541Sbrooks 136244541Sbrooks if (i2s->rev_id == 1) { 137244541Sbrooks regmap_write(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_RESET); 138244541Sbrooks udelay(200); 139244541Sbrooks } 140244541Sbrooks 141244541Sbrooks ret = devm_snd_soc_register_component(&pdev->dev, 142244541Sbrooks &loongson_i2s_component, 143244541Sbrooks &loongson_i2s_dai, 1); 144244541Sbrooks if (ret) { 145244541Sbrooks dev_err(&pdev->dev, "register DAI failed %d\n", ret); 146244541Sbrooks return ret; 147244541Sbrooks } 148244541Sbrooks 149244541Sbrooks return 0; 150244541Sbrooks} 151244541Sbrooks 152244541Sbrooksstatic const struct pci_device_id loongson_i2s_ids[] = { 153244541Sbrooks { PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x7a27) }, 154244541Sbrooks { }, 155244541Sbrooks}; 156244541SbrooksMODULE_DEVICE_TABLE(pci, loongson_i2s_ids); 157244541Sbrooks 158244541Sbrooksstatic struct pci_driver loongson_i2s_driver = { 159244541Sbrooks .name = "loongson-i2s-pci", 160244541Sbrooks .id_table = loongson_i2s_ids, 161244541Sbrooks .probe = loongson_i2s_pci_probe, 162244541Sbrooks .driver = { 163244541Sbrooks .owner = THIS_MODULE, 164244541Sbrooks .pm = pm_sleep_ptr(&loongson_i2s_pm), 165244541Sbrooks }, 166244541Sbrooks}; 167244541Sbrooksmodule_pci_driver(loongson_i2s_driver); 168244541Sbrooks 169244541SbrooksMODULE_DESCRIPTION("Loongson I2S Master Mode ASoC Driver"); 170244541SbrooksMODULE_AUTHOR("Loongson Technology Corporation Limited"); 171244541SbrooksMODULE_LICENSE("GPL"); 172244541Sbrooks