1d5a932e5SVijendar Mukunda // SPDX-License-Identifier: GPL-2.0+
2d5a932e5SVijendar Mukunda //
3d5a932e5SVijendar Mukunda // AMD ACP PCI Driver
4d5a932e5SVijendar Mukunda //
5d5a932e5SVijendar Mukunda //Copyright 2016 Advanced Micro Devices, Inc.
6e30d9128SMaruthi Srinivas Bayyavarapu
7e30d9128SMaruthi Srinivas Bayyavarapu #include <linux/pci.h>
8e30d9128SMaruthi Srinivas Bayyavarapu #include <linux/module.h>
9e30d9128SMaruthi Srinivas Bayyavarapu #include <linux/io.h>
107894a7e7SVijendar Mukunda #include <linux/platform_device.h>
117894a7e7SVijendar Mukunda #include <linux/interrupt.h>
12535fd141SRavulapati Vishnu vardhan rao #include <linux/pm_runtime.h>
13535fd141SRavulapati Vishnu vardhan rao #include <linux/delay.h>
14e30d9128SMaruthi Srinivas Bayyavarapu
15e30d9128SMaruthi Srinivas Bayyavarapu #include "acp3x.h"
16e30d9128SMaruthi Srinivas Bayyavarapu
17e30d9128SMaruthi Srinivas Bayyavarapu struct acp3x_dev_data {
18e30d9128SMaruthi Srinivas Bayyavarapu void __iomem *acp3x_base;
197894a7e7SVijendar Mukunda bool acp3x_audio_mode;
207894a7e7SVijendar Mukunda struct resource *res;
215def0136SRavulapati Vishnu vardhan rao struct platform_device *pdev[ACP3x_DEVS];
221255296cSAkshu Agrawal u32 pme_en;
23e30d9128SMaruthi Srinivas Bayyavarapu };
24e30d9128SMaruthi Srinivas Bayyavarapu
acp3x_power_on(struct acp3x_dev_data * adata)251255296cSAkshu Agrawal static int acp3x_power_on(struct acp3x_dev_data *adata)
26535fd141SRavulapati Vishnu vardhan rao {
271255296cSAkshu Agrawal void __iomem *acp3x_base = adata->acp3x_base;
28535fd141SRavulapati Vishnu vardhan rao u32 val;
29535fd141SRavulapati Vishnu vardhan rao int timeout;
30535fd141SRavulapati Vishnu vardhan rao
31535fd141SRavulapati Vishnu vardhan rao val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
32535fd141SRavulapati Vishnu vardhan rao
33535fd141SRavulapati Vishnu vardhan rao if (val == 0)
34535fd141SRavulapati Vishnu vardhan rao return val;
35535fd141SRavulapati Vishnu vardhan rao
36535fd141SRavulapati Vishnu vardhan rao if (!((val & ACP_PGFSM_STATUS_MASK) ==
37535fd141SRavulapati Vishnu vardhan rao ACP_POWER_ON_IN_PROGRESS))
38535fd141SRavulapati Vishnu vardhan rao rv_writel(ACP_PGFSM_CNTL_POWER_ON_MASK,
39535fd141SRavulapati Vishnu vardhan rao acp3x_base + mmACP_PGFSM_CONTROL);
40535fd141SRavulapati Vishnu vardhan rao timeout = 0;
41535fd141SRavulapati Vishnu vardhan rao while (++timeout < 500) {
42535fd141SRavulapati Vishnu vardhan rao val = rv_readl(acp3x_base + mmACP_PGFSM_STATUS);
43911abf8bSAkshu Agrawal if (!val) {
441255296cSAkshu Agrawal /* ACP power On clears PME_EN.
451255296cSAkshu Agrawal * Restore the value to its prior state
46911abf8bSAkshu Agrawal */
471255296cSAkshu Agrawal rv_writel(adata->pme_en, acp3x_base + mmACP_PME_EN);
48535fd141SRavulapati Vishnu vardhan rao return 0;
49911abf8bSAkshu Agrawal }
50535fd141SRavulapati Vishnu vardhan rao udelay(1);
51535fd141SRavulapati Vishnu vardhan rao }
52535fd141SRavulapati Vishnu vardhan rao return -ETIMEDOUT;
53535fd141SRavulapati Vishnu vardhan rao }
54535fd141SRavulapati Vishnu vardhan rao
acp3x_reset(void __iomem * acp3x_base)55535fd141SRavulapati Vishnu vardhan rao static int acp3x_reset(void __iomem *acp3x_base)
56535fd141SRavulapati Vishnu vardhan rao {
57535fd141SRavulapati Vishnu vardhan rao u32 val;
58535fd141SRavulapati Vishnu vardhan rao int timeout;
59535fd141SRavulapati Vishnu vardhan rao
60535fd141SRavulapati Vishnu vardhan rao rv_writel(1, acp3x_base + mmACP_SOFT_RESET);
61535fd141SRavulapati Vishnu vardhan rao timeout = 0;
62535fd141SRavulapati Vishnu vardhan rao while (++timeout < 500) {
63535fd141SRavulapati Vishnu vardhan rao val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
64535fd141SRavulapati Vishnu vardhan rao if (val & ACP3x_SOFT_RESET__SoftResetAudDone_MASK)
65535fd141SRavulapati Vishnu vardhan rao break;
66535fd141SRavulapati Vishnu vardhan rao cpu_relax();
67535fd141SRavulapati Vishnu vardhan rao }
68535fd141SRavulapati Vishnu vardhan rao rv_writel(0, acp3x_base + mmACP_SOFT_RESET);
69535fd141SRavulapati Vishnu vardhan rao timeout = 0;
70535fd141SRavulapati Vishnu vardhan rao while (++timeout < 500) {
71535fd141SRavulapati Vishnu vardhan rao val = rv_readl(acp3x_base + mmACP_SOFT_RESET);
72535fd141SRavulapati Vishnu vardhan rao if (!val)
73535fd141SRavulapati Vishnu vardhan rao return 0;
74535fd141SRavulapati Vishnu vardhan rao cpu_relax();
75535fd141SRavulapati Vishnu vardhan rao }
76535fd141SRavulapati Vishnu vardhan rao return -ETIMEDOUT;
77535fd141SRavulapati Vishnu vardhan rao }
78535fd141SRavulapati Vishnu vardhan rao
acp3x_enable_interrupts(void __iomem * acp_base)79*6879e8e7SVijendar Mukunda static void acp3x_enable_interrupts(void __iomem *acp_base)
80*6879e8e7SVijendar Mukunda {
81*6879e8e7SVijendar Mukunda rv_writel(0x01, acp_base + mmACP_EXTERNAL_INTR_ENB);
82*6879e8e7SVijendar Mukunda }
83*6879e8e7SVijendar Mukunda
acp3x_disable_interrupts(void __iomem * acp_base)84*6879e8e7SVijendar Mukunda static void acp3x_disable_interrupts(void __iomem *acp_base)
85*6879e8e7SVijendar Mukunda {
86*6879e8e7SVijendar Mukunda rv_writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base +
87*6879e8e7SVijendar Mukunda mmACP_EXTERNAL_INTR_STAT);
88*6879e8e7SVijendar Mukunda rv_writel(0x00, acp_base + mmACP_EXTERNAL_INTR_CNTL);
89*6879e8e7SVijendar Mukunda rv_writel(0x00, acp_base + mmACP_EXTERNAL_INTR_ENB);
90*6879e8e7SVijendar Mukunda }
91*6879e8e7SVijendar Mukunda
acp3x_init(struct acp3x_dev_data * adata)921255296cSAkshu Agrawal static int acp3x_init(struct acp3x_dev_data *adata)
93535fd141SRavulapati Vishnu vardhan rao {
941255296cSAkshu Agrawal void __iomem *acp3x_base = adata->acp3x_base;
95535fd141SRavulapati Vishnu vardhan rao int ret;
96535fd141SRavulapati Vishnu vardhan rao
97535fd141SRavulapati Vishnu vardhan rao /* power on */
981255296cSAkshu Agrawal ret = acp3x_power_on(adata);
99535fd141SRavulapati Vishnu vardhan rao if (ret) {
100535fd141SRavulapati Vishnu vardhan rao pr_err("ACP3x power on failed\n");
101535fd141SRavulapati Vishnu vardhan rao return ret;
102535fd141SRavulapati Vishnu vardhan rao }
103535fd141SRavulapati Vishnu vardhan rao /* Reset */
104535fd141SRavulapati Vishnu vardhan rao ret = acp3x_reset(acp3x_base);
105535fd141SRavulapati Vishnu vardhan rao if (ret) {
106535fd141SRavulapati Vishnu vardhan rao pr_err("ACP3x reset failed\n");
107535fd141SRavulapati Vishnu vardhan rao return ret;
108535fd141SRavulapati Vishnu vardhan rao }
109*6879e8e7SVijendar Mukunda acp3x_enable_interrupts(acp3x_base);
110535fd141SRavulapati Vishnu vardhan rao return 0;
111535fd141SRavulapati Vishnu vardhan rao }
112535fd141SRavulapati Vishnu vardhan rao
acp3x_deinit(void __iomem * acp3x_base)113535fd141SRavulapati Vishnu vardhan rao static int acp3x_deinit(void __iomem *acp3x_base)
114535fd141SRavulapati Vishnu vardhan rao {
115535fd141SRavulapati Vishnu vardhan rao int ret;
116535fd141SRavulapati Vishnu vardhan rao
117*6879e8e7SVijendar Mukunda acp3x_disable_interrupts(acp3x_base);
118535fd141SRavulapati Vishnu vardhan rao /* Reset */
119535fd141SRavulapati Vishnu vardhan rao ret = acp3x_reset(acp3x_base);
120535fd141SRavulapati Vishnu vardhan rao if (ret) {
121535fd141SRavulapati Vishnu vardhan rao pr_err("ACP3x reset failed\n");
122535fd141SRavulapati Vishnu vardhan rao return ret;
123535fd141SRavulapati Vishnu vardhan rao }
124535fd141SRavulapati Vishnu vardhan rao return 0;
125535fd141SRavulapati Vishnu vardhan rao }
126535fd141SRavulapati Vishnu vardhan rao
snd_acp3x_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)127e30d9128SMaruthi Srinivas Bayyavarapu static int snd_acp3x_probe(struct pci_dev *pci,
128e30d9128SMaruthi Srinivas Bayyavarapu const struct pci_device_id *pci_id)
129e30d9128SMaruthi Srinivas Bayyavarapu {
130e30d9128SMaruthi Srinivas Bayyavarapu struct acp3x_dev_data *adata;
1315def0136SRavulapati Vishnu vardhan rao struct platform_device_info pdevinfo[ACP3x_DEVS];
1327894a7e7SVijendar Mukunda unsigned int irqflags;
1335def0136SRavulapati Vishnu vardhan rao int ret, i;
1345def0136SRavulapati Vishnu vardhan rao u32 addr, val;
135e30d9128SMaruthi Srinivas Bayyavarapu
13655d8e6a8SJaroslav Kysela /* Raven device detection */
13755d8e6a8SJaroslav Kysela if (pci->revision != 0x00)
13855d8e6a8SJaroslav Kysela return -ENODEV;
13955d8e6a8SJaroslav Kysela
140e30d9128SMaruthi Srinivas Bayyavarapu if (pci_enable_device(pci)) {
141e30d9128SMaruthi Srinivas Bayyavarapu dev_err(&pci->dev, "pci_enable_device failed\n");
142e30d9128SMaruthi Srinivas Bayyavarapu return -ENODEV;
143e30d9128SMaruthi Srinivas Bayyavarapu }
144e30d9128SMaruthi Srinivas Bayyavarapu
145e30d9128SMaruthi Srinivas Bayyavarapu ret = pci_request_regions(pci, "AMD ACP3x audio");
146e30d9128SMaruthi Srinivas Bayyavarapu if (ret < 0) {
147e30d9128SMaruthi Srinivas Bayyavarapu dev_err(&pci->dev, "pci_request_regions failed\n");
148e30d9128SMaruthi Srinivas Bayyavarapu goto disable_pci;
149e30d9128SMaruthi Srinivas Bayyavarapu }
150e30d9128SMaruthi Srinivas Bayyavarapu
151e30d9128SMaruthi Srinivas Bayyavarapu adata = devm_kzalloc(&pci->dev, sizeof(struct acp3x_dev_data),
152e30d9128SMaruthi Srinivas Bayyavarapu GFP_KERNEL);
153e30d9128SMaruthi Srinivas Bayyavarapu if (!adata) {
154e30d9128SMaruthi Srinivas Bayyavarapu ret = -ENOMEM;
155e30d9128SMaruthi Srinivas Bayyavarapu goto release_regions;
156e30d9128SMaruthi Srinivas Bayyavarapu }
157e30d9128SMaruthi Srinivas Bayyavarapu
1587894a7e7SVijendar Mukunda irqflags = IRQF_SHARED;
1597894a7e7SVijendar Mukunda
160e30d9128SMaruthi Srinivas Bayyavarapu addr = pci_resource_start(pci, 0);
1615def0136SRavulapati Vishnu vardhan rao adata->acp3x_base = devm_ioremap(&pci->dev, addr,
1625def0136SRavulapati Vishnu vardhan rao pci_resource_len(pci, 0));
163e30d9128SMaruthi Srinivas Bayyavarapu if (!adata->acp3x_base) {
164e30d9128SMaruthi Srinivas Bayyavarapu ret = -ENOMEM;
165a523e153SRavulapati Vishnu vardhan rao goto release_regions;
166e30d9128SMaruthi Srinivas Bayyavarapu }
167e30d9128SMaruthi Srinivas Bayyavarapu pci_set_master(pci);
168e30d9128SMaruthi Srinivas Bayyavarapu pci_set_drvdata(pci, adata);
1691255296cSAkshu Agrawal /* Save ACP_PME_EN state */
1701255296cSAkshu Agrawal adata->pme_en = rv_readl(adata->acp3x_base + mmACP_PME_EN);
1711255296cSAkshu Agrawal ret = acp3x_init(adata);
172535fd141SRavulapati Vishnu vardhan rao if (ret)
173a523e153SRavulapati Vishnu vardhan rao goto release_regions;
1747894a7e7SVijendar Mukunda
1757894a7e7SVijendar Mukunda val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
1767894a7e7SVijendar Mukunda switch (val) {
1777894a7e7SVijendar Mukunda case I2S_MODE:
1787894a7e7SVijendar Mukunda adata->res = devm_kzalloc(&pci->dev,
1795def0136SRavulapati Vishnu vardhan rao sizeof(struct resource) * 4,
1807894a7e7SVijendar Mukunda GFP_KERNEL);
1817894a7e7SVijendar Mukunda if (!adata->res) {
1827894a7e7SVijendar Mukunda ret = -ENOMEM;
183535fd141SRavulapati Vishnu vardhan rao goto de_init;
1847894a7e7SVijendar Mukunda }
1857894a7e7SVijendar Mukunda
1867894a7e7SVijendar Mukunda adata->res[0].name = "acp3x_i2s_iomem";
1877894a7e7SVijendar Mukunda adata->res[0].flags = IORESOURCE_MEM;
1887894a7e7SVijendar Mukunda adata->res[0].start = addr;
1897894a7e7SVijendar Mukunda adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START);
1907894a7e7SVijendar Mukunda
1915def0136SRavulapati Vishnu vardhan rao adata->res[1].name = "acp3x_i2s_sp";
1925def0136SRavulapati Vishnu vardhan rao adata->res[1].flags = IORESOURCE_MEM;
1935def0136SRavulapati Vishnu vardhan rao adata->res[1].start = addr + ACP3x_I2STDM_REG_START;
1945def0136SRavulapati Vishnu vardhan rao adata->res[1].end = addr + ACP3x_I2STDM_REG_END;
1955def0136SRavulapati Vishnu vardhan rao
1965def0136SRavulapati Vishnu vardhan rao adata->res[2].name = "acp3x_i2s_bt";
1975def0136SRavulapati Vishnu vardhan rao adata->res[2].flags = IORESOURCE_MEM;
1985def0136SRavulapati Vishnu vardhan rao adata->res[2].start = addr + ACP3x_BT_TDM_REG_START;
1995def0136SRavulapati Vishnu vardhan rao adata->res[2].end = addr + ACP3x_BT_TDM_REG_END;
2005def0136SRavulapati Vishnu vardhan rao
2015def0136SRavulapati Vishnu vardhan rao adata->res[3].name = "acp3x_i2s_irq";
2025def0136SRavulapati Vishnu vardhan rao adata->res[3].flags = IORESOURCE_IRQ;
2035def0136SRavulapati Vishnu vardhan rao adata->res[3].start = pci->irq;
2045def0136SRavulapati Vishnu vardhan rao adata->res[3].end = adata->res[3].start;
2057894a7e7SVijendar Mukunda
2067894a7e7SVijendar Mukunda adata->acp3x_audio_mode = ACP3x_I2S_MODE;
2077894a7e7SVijendar Mukunda
2087894a7e7SVijendar Mukunda memset(&pdevinfo, 0, sizeof(pdevinfo));
2095def0136SRavulapati Vishnu vardhan rao pdevinfo[0].name = "acp3x_rv_i2s_dma";
2105def0136SRavulapati Vishnu vardhan rao pdevinfo[0].id = 0;
2115def0136SRavulapati Vishnu vardhan rao pdevinfo[0].parent = &pci->dev;
2125def0136SRavulapati Vishnu vardhan rao pdevinfo[0].num_res = 4;
2135def0136SRavulapati Vishnu vardhan rao pdevinfo[0].res = &adata->res[0];
2145def0136SRavulapati Vishnu vardhan rao pdevinfo[0].data = &irqflags;
2155def0136SRavulapati Vishnu vardhan rao pdevinfo[0].size_data = sizeof(irqflags);
2167894a7e7SVijendar Mukunda
2175def0136SRavulapati Vishnu vardhan rao pdevinfo[1].name = "acp3x_i2s_playcap";
2185def0136SRavulapati Vishnu vardhan rao pdevinfo[1].id = 0;
2195def0136SRavulapati Vishnu vardhan rao pdevinfo[1].parent = &pci->dev;
2205def0136SRavulapati Vishnu vardhan rao pdevinfo[1].num_res = 1;
2215def0136SRavulapati Vishnu vardhan rao pdevinfo[1].res = &adata->res[1];
2225def0136SRavulapati Vishnu vardhan rao
2235def0136SRavulapati Vishnu vardhan rao pdevinfo[2].name = "acp3x_i2s_playcap";
2245def0136SRavulapati Vishnu vardhan rao pdevinfo[2].id = 1;
2255def0136SRavulapati Vishnu vardhan rao pdevinfo[2].parent = &pci->dev;
2265def0136SRavulapati Vishnu vardhan rao pdevinfo[2].num_res = 1;
227a174a6c2SRavulapati Vishnu vardhan rao pdevinfo[2].res = &adata->res[1];
228a174a6c2SRavulapati Vishnu vardhan rao
229a174a6c2SRavulapati Vishnu vardhan rao pdevinfo[3].name = "acp3x_i2s_playcap";
230a174a6c2SRavulapati Vishnu vardhan rao pdevinfo[3].id = 2;
231a174a6c2SRavulapati Vishnu vardhan rao pdevinfo[3].parent = &pci->dev;
232a174a6c2SRavulapati Vishnu vardhan rao pdevinfo[3].num_res = 1;
233a174a6c2SRavulapati Vishnu vardhan rao pdevinfo[3].res = &adata->res[2];
2345def0136SRavulapati Vishnu vardhan rao for (i = 0; i < ACP3x_DEVS; i++) {
2355def0136SRavulapati Vishnu vardhan rao adata->pdev[i] =
2365def0136SRavulapati Vishnu vardhan rao platform_device_register_full(&pdevinfo[i]);
2375def0136SRavulapati Vishnu vardhan rao if (IS_ERR(adata->pdev[i])) {
2387894a7e7SVijendar Mukunda dev_err(&pci->dev, "cannot register %s device\n",
2395def0136SRavulapati Vishnu vardhan rao pdevinfo[i].name);
2405def0136SRavulapati Vishnu vardhan rao ret = PTR_ERR(adata->pdev[i]);
2415def0136SRavulapati Vishnu vardhan rao goto unregister_devs;
2425def0136SRavulapati Vishnu vardhan rao }
2437894a7e7SVijendar Mukunda }
2447894a7e7SVijendar Mukunda break;
2457894a7e7SVijendar Mukunda default:
246efb38304SVijendar Mukunda dev_info(&pci->dev, "ACP audio mode : %d\n", val);
247e5879d98SMark Brown break;
2487894a7e7SVijendar Mukunda }
249535fd141SRavulapati Vishnu vardhan rao pm_runtime_set_autosuspend_delay(&pci->dev, 2000);
250535fd141SRavulapati Vishnu vardhan rao pm_runtime_use_autosuspend(&pci->dev);
251535fd141SRavulapati Vishnu vardhan rao pm_runtime_put_noidle(&pci->dev);
252535fd141SRavulapati Vishnu vardhan rao pm_runtime_allow(&pci->dev);
253e30d9128SMaruthi Srinivas Bayyavarapu return 0;
254e30d9128SMaruthi Srinivas Bayyavarapu
2555def0136SRavulapati Vishnu vardhan rao unregister_devs:
2565def0136SRavulapati Vishnu vardhan rao if (val == I2S_MODE)
2575def0136SRavulapati Vishnu vardhan rao for (i = 0; i < ACP3x_DEVS; i++)
2585def0136SRavulapati Vishnu vardhan rao platform_device_unregister(adata->pdev[i]);
259535fd141SRavulapati Vishnu vardhan rao de_init:
260535fd141SRavulapati Vishnu vardhan rao if (acp3x_deinit(adata->acp3x_base))
261535fd141SRavulapati Vishnu vardhan rao dev_err(&pci->dev, "ACP de-init failed\n");
262e30d9128SMaruthi Srinivas Bayyavarapu release_regions:
263e30d9128SMaruthi Srinivas Bayyavarapu pci_release_regions(pci);
264e30d9128SMaruthi Srinivas Bayyavarapu disable_pci:
265e30d9128SMaruthi Srinivas Bayyavarapu pci_disable_device(pci);
266e30d9128SMaruthi Srinivas Bayyavarapu
267e30d9128SMaruthi Srinivas Bayyavarapu return ret;
268e30d9128SMaruthi Srinivas Bayyavarapu }
269e30d9128SMaruthi Srinivas Bayyavarapu
snd_acp3x_suspend(struct device * dev)270535fd141SRavulapati Vishnu vardhan rao static int snd_acp3x_suspend(struct device *dev)
271535fd141SRavulapati Vishnu vardhan rao {
272535fd141SRavulapati Vishnu vardhan rao int ret;
273535fd141SRavulapati Vishnu vardhan rao struct acp3x_dev_data *adata;
274535fd141SRavulapati Vishnu vardhan rao
275535fd141SRavulapati Vishnu vardhan rao adata = dev_get_drvdata(dev);
276535fd141SRavulapati Vishnu vardhan rao ret = acp3x_deinit(adata->acp3x_base);
277535fd141SRavulapati Vishnu vardhan rao if (ret)
278535fd141SRavulapati Vishnu vardhan rao dev_err(dev, "ACP de-init failed\n");
279535fd141SRavulapati Vishnu vardhan rao else
280535fd141SRavulapati Vishnu vardhan rao dev_dbg(dev, "ACP de-initialized\n");
281535fd141SRavulapati Vishnu vardhan rao
282535fd141SRavulapati Vishnu vardhan rao return 0;
283535fd141SRavulapati Vishnu vardhan rao }
284535fd141SRavulapati Vishnu vardhan rao
snd_acp3x_resume(struct device * dev)285535fd141SRavulapati Vishnu vardhan rao static int snd_acp3x_resume(struct device *dev)
286535fd141SRavulapati Vishnu vardhan rao {
287535fd141SRavulapati Vishnu vardhan rao int ret;
288535fd141SRavulapati Vishnu vardhan rao struct acp3x_dev_data *adata;
289535fd141SRavulapati Vishnu vardhan rao
290535fd141SRavulapati Vishnu vardhan rao adata = dev_get_drvdata(dev);
2911255296cSAkshu Agrawal ret = acp3x_init(adata);
292535fd141SRavulapati Vishnu vardhan rao if (ret) {
293535fd141SRavulapati Vishnu vardhan rao dev_err(dev, "ACP init failed\n");
294535fd141SRavulapati Vishnu vardhan rao return ret;
295535fd141SRavulapati Vishnu vardhan rao }
296535fd141SRavulapati Vishnu vardhan rao return 0;
297535fd141SRavulapati Vishnu vardhan rao }
298535fd141SRavulapati Vishnu vardhan rao
299535fd141SRavulapati Vishnu vardhan rao static const struct dev_pm_ops acp3x_pm = {
300535fd141SRavulapati Vishnu vardhan rao .runtime_suspend = snd_acp3x_suspend,
301535fd141SRavulapati Vishnu vardhan rao .runtime_resume = snd_acp3x_resume,
302535fd141SRavulapati Vishnu vardhan rao .resume = snd_acp3x_resume,
303535fd141SRavulapati Vishnu vardhan rao };
304535fd141SRavulapati Vishnu vardhan rao
snd_acp3x_remove(struct pci_dev * pci)305e30d9128SMaruthi Srinivas Bayyavarapu static void snd_acp3x_remove(struct pci_dev *pci)
306e30d9128SMaruthi Srinivas Bayyavarapu {
307535fd141SRavulapati Vishnu vardhan rao struct acp3x_dev_data *adata;
308535fd141SRavulapati Vishnu vardhan rao int i, ret;
309e30d9128SMaruthi Srinivas Bayyavarapu
310535fd141SRavulapati Vishnu vardhan rao adata = pci_get_drvdata(pci);
3115def0136SRavulapati Vishnu vardhan rao if (adata->acp3x_audio_mode == ACP3x_I2S_MODE) {
3125def0136SRavulapati Vishnu vardhan rao for (i = 0; i < ACP3x_DEVS; i++)
3135def0136SRavulapati Vishnu vardhan rao platform_device_unregister(adata->pdev[i]);
3145def0136SRavulapati Vishnu vardhan rao }
315535fd141SRavulapati Vishnu vardhan rao ret = acp3x_deinit(adata->acp3x_base);
316535fd141SRavulapati Vishnu vardhan rao if (ret)
317535fd141SRavulapati Vishnu vardhan rao dev_err(&pci->dev, "ACP de-init failed\n");
318ad922ca1SRavulapati Vishnu vardhan rao pm_runtime_forbid(&pci->dev);
319535fd141SRavulapati Vishnu vardhan rao pm_runtime_get_noresume(&pci->dev);
320e30d9128SMaruthi Srinivas Bayyavarapu pci_release_regions(pci);
321e30d9128SMaruthi Srinivas Bayyavarapu pci_disable_device(pci);
322e30d9128SMaruthi Srinivas Bayyavarapu }
323e30d9128SMaruthi Srinivas Bayyavarapu
324e30d9128SMaruthi Srinivas Bayyavarapu static const struct pci_device_id snd_acp3x_ids[] = {
325e30d9128SMaruthi Srinivas Bayyavarapu { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x15e2),
326e30d9128SMaruthi Srinivas Bayyavarapu .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
327e30d9128SMaruthi Srinivas Bayyavarapu .class_mask = 0xffffff },
328e30d9128SMaruthi Srinivas Bayyavarapu { 0, },
329e30d9128SMaruthi Srinivas Bayyavarapu };
330e30d9128SMaruthi Srinivas Bayyavarapu MODULE_DEVICE_TABLE(pci, snd_acp3x_ids);
331e30d9128SMaruthi Srinivas Bayyavarapu
332e30d9128SMaruthi Srinivas Bayyavarapu static struct pci_driver acp3x_driver = {
333e30d9128SMaruthi Srinivas Bayyavarapu .name = KBUILD_MODNAME,
334e30d9128SMaruthi Srinivas Bayyavarapu .id_table = snd_acp3x_ids,
335e30d9128SMaruthi Srinivas Bayyavarapu .probe = snd_acp3x_probe,
336e30d9128SMaruthi Srinivas Bayyavarapu .remove = snd_acp3x_remove,
337535fd141SRavulapati Vishnu vardhan rao .driver = {
338535fd141SRavulapati Vishnu vardhan rao .pm = &acp3x_pm,
339535fd141SRavulapati Vishnu vardhan rao }
340e30d9128SMaruthi Srinivas Bayyavarapu };
341e30d9128SMaruthi Srinivas Bayyavarapu
342e30d9128SMaruthi Srinivas Bayyavarapu module_pci_driver(acp3x_driver);
343e30d9128SMaruthi Srinivas Bayyavarapu
3445def0136SRavulapati Vishnu vardhan rao MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com");
345e30d9128SMaruthi Srinivas Bayyavarapu MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
346e30d9128SMaruthi Srinivas Bayyavarapu MODULE_DESCRIPTION("AMD ACP3x PCI driver");
347e30d9128SMaruthi Srinivas Bayyavarapu MODULE_LICENSE("GPL v2");
348