Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
0002 //
0003 // This file is provided under a dual BSD/GPLv2 license. When using or
0004 // redistributing this file, you may do so under either license.
0005 //
0006 // Copyright(c) 2022 Advanced Micro Devices, Inc. All rights reserved.
0007 //
0008 // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
0009 
0010 /*
0011  * Generic PCI interface for ACP device
0012  */
0013 
0014 #include <linux/delay.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/pci.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/pm_runtime.h>
0019 #include <linux/module.h>
0020 
0021 #include "amd.h"
0022 #include "../mach-config.h"
0023 
0024 #define DRV_NAME "acp_pci"
0025 
0026 #define ACP3x_REG_START 0x1240000
0027 #define ACP3x_REG_END   0x125C000
0028 
0029 static struct platform_device *dmic_dev;
0030 static struct platform_device *pdev;
0031 
0032 static const struct resource acp_res[] = {
0033     {
0034         .start = 0,
0035         .end = ACP3x_REG_END - ACP3x_REG_START,
0036         .name = "acp_mem",
0037         .flags = IORESOURCE_MEM,
0038     },
0039     {
0040         .start = 0,
0041         .end = 0,
0042         .name = "acp_dai_irq",
0043         .flags = IORESOURCE_IRQ,
0044     },
0045 };
0046 
0047 static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
0048 {
0049     struct platform_device_info pdevinfo;
0050     struct device *dev = &pci->dev;
0051     const struct resource *res_acp;
0052     struct acp_chip_info *chip;
0053     struct resource *res;
0054     unsigned int flag, addr, num_res, i;
0055     int ret;
0056 
0057     flag = snd_amd_acp_find_config(pci);
0058     if (flag != FLAG_AMD_LEGACY)
0059         return -ENODEV;
0060 
0061     chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
0062     if (!chip)
0063         return -ENOMEM;
0064 
0065     if (pci_enable_device(pci)) {
0066         dev_err(&pci->dev, "pci_enable_device failed\n");
0067         return -ENODEV;
0068     }
0069 
0070     ret = pci_request_regions(pci, "AMD ACP3x audio");
0071     if (ret < 0) {
0072         dev_err(&pci->dev, "pci_request_regions failed\n");
0073         ret = -ENOMEM;
0074         goto disable_pci;
0075     }
0076 
0077     pci_set_master(pci);
0078 
0079     res_acp = acp_res;
0080     num_res = ARRAY_SIZE(acp_res);
0081 
0082     switch (pci->revision) {
0083     case 0x01:
0084         chip->name = "acp_asoc_renoir";
0085         chip->acp_rev = ACP3X_DEV;
0086         break;
0087     case 0x6f:
0088         chip->name = "acp_asoc_rembrandt";
0089         chip->acp_rev = ACP6X_DEV;
0090         break;
0091     default:
0092         dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision);
0093         ret = -EINVAL;
0094         goto release_regions;
0095     }
0096 
0097     dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
0098     if (IS_ERR(dmic_dev)) {
0099         dev_err(dev, "failed to create DMIC device\n");
0100         ret = PTR_ERR(dmic_dev);
0101         goto release_regions;
0102     }
0103 
0104     addr = pci_resource_start(pci, 0);
0105     chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0));
0106     if (!chip->base) {
0107         ret = -ENOMEM;
0108         goto release_regions;
0109     }
0110 
0111     res = devm_kzalloc(&pci->dev, sizeof(struct resource) * num_res, GFP_KERNEL);
0112     if (!res) {
0113         platform_device_unregister(dmic_dev);
0114         ret = -ENOMEM;
0115         goto release_regions;
0116     }
0117 
0118     for (i = 0; i < num_res; i++, res_acp++) {
0119         res[i].name = res_acp->name;
0120         res[i].flags = res_acp->flags;
0121         res[i].start = addr + res_acp->start;
0122         res[i].end = addr + res_acp->end;
0123         if (res_acp->flags == IORESOURCE_IRQ) {
0124             res[i].start = pci->irq;
0125             res[i].end = res[i].start;
0126         }
0127     }
0128 
0129     memset(&pdevinfo, 0, sizeof(pdevinfo));
0130 
0131     pdevinfo.name = chip->name;
0132     pdevinfo.id = 0;
0133     pdevinfo.parent = &pci->dev;
0134     pdevinfo.num_res = num_res;
0135     pdevinfo.res = &res[0];
0136     pdevinfo.data = chip;
0137     pdevinfo.size_data = sizeof(*chip);
0138 
0139     pdev = platform_device_register_full(&pdevinfo);
0140     if (IS_ERR(pdev)) {
0141         dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name);
0142         platform_device_unregister(dmic_dev);
0143         ret = PTR_ERR(pdev);
0144         goto release_regions;
0145     }
0146 
0147     return ret;
0148 
0149 release_regions:
0150     pci_release_regions(pci);
0151 disable_pci:
0152     pci_disable_device(pci);
0153 
0154     return ret;
0155 };
0156 
0157 static void acp_pci_remove(struct pci_dev *pci)
0158 {
0159     if (dmic_dev)
0160         platform_device_unregister(dmic_dev);
0161     if (pdev)
0162         platform_device_unregister(pdev);
0163 }
0164 
0165 /* PCI IDs */
0166 static const struct pci_device_id acp_pci_ids[] = {
0167     { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID)},
0168     { 0, }
0169 };
0170 MODULE_DEVICE_TABLE(pci, acp_pci_ids);
0171 
0172 /* pci_driver definition */
0173 static struct pci_driver snd_amd_acp_pci_driver = {
0174     .name = KBUILD_MODNAME,
0175     .id_table = acp_pci_ids,
0176     .probe = acp_pci_probe,
0177     .remove = acp_pci_remove,
0178 };
0179 module_pci_driver(snd_amd_acp_pci_driver);
0180 
0181 MODULE_LICENSE("Dual BSD/GPL");
0182 MODULE_ALIAS(DRV_NAME);