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