0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/pci.h>
0009 #include <linux/module.h>
0010 #include <linux/io.h>
0011 #include <linux/delay.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/interrupt.h>
0014 #include <sound/pcm_params.h>
0015 #include <linux/pm_runtime.h>
0016
0017 #include "acp6x.h"
0018
0019 struct acp6x_dev_data {
0020 void __iomem *acp6x_base;
0021 struct resource *res;
0022 bool acp6x_audio_mode;
0023 struct platform_device *pdev[ACP6x_DEVS];
0024 };
0025
0026 static int acp6x_power_on(void __iomem *acp_base)
0027 {
0028 u32 val;
0029 int timeout;
0030
0031 val = acp6x_readl(acp_base + ACP_PGFSM_STATUS);
0032
0033 if (!val)
0034 return val;
0035
0036 if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)
0037 acp6x_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
0038 timeout = 0;
0039 while (++timeout < 500) {
0040 val = acp6x_readl(acp_base + ACP_PGFSM_STATUS);
0041 if (!val)
0042 return 0;
0043 udelay(1);
0044 }
0045 return -ETIMEDOUT;
0046 }
0047
0048 static int acp6x_reset(void __iomem *acp_base)
0049 {
0050 u32 val;
0051 int timeout;
0052
0053 acp6x_writel(1, acp_base + ACP_SOFT_RESET);
0054 timeout = 0;
0055 while (++timeout < 500) {
0056 val = acp6x_readl(acp_base + ACP_SOFT_RESET);
0057 if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
0058 break;
0059 cpu_relax();
0060 }
0061 acp6x_writel(0, acp_base + ACP_SOFT_RESET);
0062 timeout = 0;
0063 while (++timeout < 500) {
0064 val = acp6x_readl(acp_base + ACP_SOFT_RESET);
0065 if (!val)
0066 return 0;
0067 cpu_relax();
0068 }
0069 return -ETIMEDOUT;
0070 }
0071
0072 static void acp6x_enable_interrupts(void __iomem *acp_base)
0073 {
0074 acp6x_writel(0x01, acp_base + ACP_EXTERNAL_INTR_ENB);
0075 }
0076
0077 static void acp6x_disable_interrupts(void __iomem *acp_base)
0078 {
0079 acp6x_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base +
0080 ACP_EXTERNAL_INTR_STAT);
0081 acp6x_writel(0x00, acp_base + ACP_EXTERNAL_INTR_CNTL);
0082 acp6x_writel(0x00, acp_base + ACP_EXTERNAL_INTR_ENB);
0083 }
0084
0085 static int acp6x_init(void __iomem *acp_base)
0086 {
0087 int ret;
0088
0089
0090 ret = acp6x_power_on(acp_base);
0091 if (ret) {
0092 pr_err("ACP power on failed\n");
0093 return ret;
0094 }
0095 acp6x_writel(0x01, acp_base + ACP_CONTROL);
0096
0097 ret = acp6x_reset(acp_base);
0098 if (ret) {
0099 pr_err("ACP reset failed\n");
0100 return ret;
0101 }
0102 acp6x_writel(0x03, acp_base + ACP_CLKMUX_SEL);
0103 acp6x_enable_interrupts(acp_base);
0104 return 0;
0105 }
0106
0107 static int acp6x_deinit(void __iomem *acp_base)
0108 {
0109 int ret;
0110
0111 acp6x_disable_interrupts(acp_base);
0112
0113 ret = acp6x_reset(acp_base);
0114 if (ret) {
0115 pr_err("ACP reset failed\n");
0116 return ret;
0117 }
0118 acp6x_writel(0x00, acp_base + ACP_CLKMUX_SEL);
0119 acp6x_writel(0x00, acp_base + ACP_CONTROL);
0120 return 0;
0121 }
0122
0123 static irqreturn_t acp6x_irq_handler(int irq, void *dev_id)
0124 {
0125 struct acp6x_dev_data *adata;
0126 struct pdm_dev_data *yc_pdm_data;
0127 u32 val;
0128
0129 adata = dev_id;
0130 if (!adata)
0131 return IRQ_NONE;
0132
0133 val = acp6x_readl(adata->acp6x_base + ACP_EXTERNAL_INTR_STAT);
0134 if (val & BIT(PDM_DMA_STAT)) {
0135 yc_pdm_data = dev_get_drvdata(&adata->pdev[0]->dev);
0136 acp6x_writel(BIT(PDM_DMA_STAT), adata->acp6x_base + ACP_EXTERNAL_INTR_STAT);
0137 if (yc_pdm_data->capture_stream)
0138 snd_pcm_period_elapsed(yc_pdm_data->capture_stream);
0139 return IRQ_HANDLED;
0140 }
0141 return IRQ_NONE;
0142 }
0143
0144 static int snd_acp6x_probe(struct pci_dev *pci,
0145 const struct pci_device_id *pci_id)
0146 {
0147 struct acp6x_dev_data *adata;
0148 struct platform_device_info pdevinfo[ACP6x_DEVS];
0149 int index = 0;
0150 int val = 0x00;
0151 u32 addr;
0152 unsigned int irqflags;
0153 int ret;
0154
0155 irqflags = IRQF_SHARED;
0156
0157 switch (pci->revision) {
0158 case 0x60:
0159 case 0x6f:
0160 break;
0161 default:
0162 dev_dbg(&pci->dev, "acp6x pci device not found\n");
0163 return -ENODEV;
0164 }
0165 if (pci_enable_device(pci)) {
0166 dev_err(&pci->dev, "pci_enable_device failed\n");
0167 return -ENODEV;
0168 }
0169
0170 ret = pci_request_regions(pci, "AMD ACP3x audio");
0171 if (ret < 0) {
0172 dev_err(&pci->dev, "pci_request_regions failed\n");
0173 goto disable_pci;
0174 }
0175
0176 adata = devm_kzalloc(&pci->dev, sizeof(struct acp6x_dev_data),
0177 GFP_KERNEL);
0178 if (!adata) {
0179 ret = -ENOMEM;
0180 goto release_regions;
0181 }
0182
0183 addr = pci_resource_start(pci, 0);
0184 adata->acp6x_base = devm_ioremap(&pci->dev, addr,
0185 pci_resource_len(pci, 0));
0186 if (!adata->acp6x_base) {
0187 ret = -ENOMEM;
0188 goto release_regions;
0189 }
0190 pci_set_master(pci);
0191 pci_set_drvdata(pci, adata);
0192 ret = acp6x_init(adata->acp6x_base);
0193 if (ret)
0194 goto release_regions;
0195 val = acp6x_readl(adata->acp6x_base + ACP_PIN_CONFIG);
0196 switch (val) {
0197 case ACP_CONFIG_0:
0198 case ACP_CONFIG_1:
0199 case ACP_CONFIG_2:
0200 case ACP_CONFIG_3:
0201 case ACP_CONFIG_9:
0202 case ACP_CONFIG_15:
0203 dev_info(&pci->dev, "Audio Mode %d\n", val);
0204 break;
0205 default:
0206 adata->res = devm_kzalloc(&pci->dev,
0207 sizeof(struct resource),
0208 GFP_KERNEL);
0209 if (!adata->res) {
0210 ret = -ENOMEM;
0211 goto de_init;
0212 }
0213
0214 adata->res->name = "acp_iomem";
0215 adata->res->flags = IORESOURCE_MEM;
0216 adata->res->start = addr;
0217 adata->res->end = addr + (ACP6x_REG_END - ACP6x_REG_START);
0218
0219 adata->acp6x_audio_mode = ACP6x_PDM_MODE;
0220
0221 memset(&pdevinfo, 0, sizeof(pdevinfo));
0222 pdevinfo[0].name = "acp_yc_pdm_dma";
0223 pdevinfo[0].id = 0;
0224 pdevinfo[0].parent = &pci->dev;
0225 pdevinfo[0].num_res = 1;
0226 pdevinfo[0].res = adata->res;
0227
0228 pdevinfo[1].name = "dmic-codec";
0229 pdevinfo[1].id = 0;
0230 pdevinfo[1].parent = &pci->dev;
0231
0232 pdevinfo[2].name = "acp_yc_mach";
0233 pdevinfo[2].id = 0;
0234 pdevinfo[2].parent = &pci->dev;
0235
0236 for (index = 0; index < ACP6x_DEVS; index++) {
0237 adata->pdev[index] =
0238 platform_device_register_full(&pdevinfo[index]);
0239 if (IS_ERR(adata->pdev[index])) {
0240 dev_err(&pci->dev, "cannot register %s device\n",
0241 pdevinfo[index].name);
0242 ret = PTR_ERR(adata->pdev[index]);
0243 goto unregister_devs;
0244 }
0245 }
0246 break;
0247 }
0248 ret = devm_request_irq(&pci->dev, pci->irq, acp6x_irq_handler,
0249 irqflags, "ACP_PCI_IRQ", adata);
0250 if (ret) {
0251 dev_err(&pci->dev, "ACP PCI IRQ request failed\n");
0252 goto unregister_devs;
0253 }
0254 pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
0255 pm_runtime_use_autosuspend(&pci->dev);
0256 pm_runtime_put_noidle(&pci->dev);
0257 pm_runtime_allow(&pci->dev);
0258
0259 return 0;
0260 unregister_devs:
0261 for (--index; index >= 0; index--)
0262 platform_device_unregister(adata->pdev[index]);
0263 de_init:
0264 if (acp6x_deinit(adata->acp6x_base))
0265 dev_err(&pci->dev, "ACP de-init failed\n");
0266 release_regions:
0267 pci_release_regions(pci);
0268 disable_pci:
0269 pci_disable_device(pci);
0270
0271 return ret;
0272 }
0273
0274 static int __maybe_unused snd_acp6x_suspend(struct device *dev)
0275 {
0276 struct acp6x_dev_data *adata;
0277 int ret;
0278
0279 adata = dev_get_drvdata(dev);
0280 ret = acp6x_deinit(adata->acp6x_base);
0281 if (ret)
0282 dev_err(dev, "ACP de-init failed\n");
0283 return ret;
0284 }
0285
0286 static int __maybe_unused snd_acp6x_resume(struct device *dev)
0287 {
0288 struct acp6x_dev_data *adata;
0289 int ret;
0290
0291 adata = dev_get_drvdata(dev);
0292 ret = acp6x_init(adata->acp6x_base);
0293 if (ret)
0294 dev_err(dev, "ACP init failed\n");
0295 return ret;
0296 }
0297
0298 static const struct dev_pm_ops acp6x_pm = {
0299 SET_RUNTIME_PM_OPS(snd_acp6x_suspend, snd_acp6x_resume, NULL)
0300 SET_SYSTEM_SLEEP_PM_OPS(snd_acp6x_suspend, snd_acp6x_resume)
0301 };
0302
0303 static void snd_acp6x_remove(struct pci_dev *pci)
0304 {
0305 struct acp6x_dev_data *adata;
0306 int ret, index;
0307
0308 adata = pci_get_drvdata(pci);
0309 if (adata->acp6x_audio_mode == ACP6x_PDM_MODE) {
0310 for (index = 0; index < ACP6x_DEVS; index++)
0311 platform_device_unregister(adata->pdev[index]);
0312 }
0313 ret = acp6x_deinit(adata->acp6x_base);
0314 if (ret)
0315 dev_err(&pci->dev, "ACP de-init failed\n");
0316 pm_runtime_forbid(&pci->dev);
0317 pm_runtime_get_noresume(&pci->dev);
0318 pci_release_regions(pci);
0319 pci_disable_device(pci);
0320 }
0321
0322 static const struct pci_device_id snd_acp6x_ids[] = {
0323 { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
0324 .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
0325 .class_mask = 0xffffff },
0326 { 0, },
0327 };
0328 MODULE_DEVICE_TABLE(pci, snd_acp6x_ids);
0329
0330 static struct pci_driver yc_acp6x_driver = {
0331 .name = KBUILD_MODNAME,
0332 .id_table = snd_acp6x_ids,
0333 .probe = snd_acp6x_probe,
0334 .remove = snd_acp6x_remove,
0335 .driver = {
0336 .pm = &acp6x_pm,
0337 }
0338 };
0339
0340 module_pci_driver(yc_acp6x_driver);
0341
0342 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
0343 MODULE_DESCRIPTION("AMD ACP Yellow Carp PCI driver");
0344 MODULE_LICENSE("GPL v2");