195e43a17SSyed Saba Kareem // SPDX-License-Identifier: GPL-2.0+
295e43a17SSyed Saba Kareem /*
395e43a17SSyed Saba Kareem * AMD Pink Sardine ACP PCI Driver
495e43a17SSyed Saba Kareem *
595e43a17SSyed Saba Kareem * Copyright 2022 Advanced Micro Devices, Inc.
695e43a17SSyed Saba Kareem */
795e43a17SSyed Saba Kareem
895e43a17SSyed Saba Kareem #include <linux/pci.h>
9d1351c30SVijendar Mukunda #include <linux/bitops.h>
1095e43a17SSyed Saba Kareem #include <linux/module.h>
1195e43a17SSyed Saba Kareem #include <linux/io.h>
129766bb62SSyed Saba Kareem #include <linux/delay.h>
13515ee257SSyed Saba Kareem #include <linux/platform_device.h>
14515ee257SSyed Saba Kareem #include <linux/acpi.h>
155bbeca60SSyed Saba Kareem #include <linux/interrupt.h>
165bbeca60SSyed Saba Kareem #include <sound/pcm_params.h>
173a543d56SSyed Saba Kareem #include <linux/pm_runtime.h>
18ea79b0a6SSyed Saba Kareem #include <linux/iopoll.h>
19d1351c30SVijendar Mukunda #include <linux/soundwire/sdw_amd.h>
2095e43a17SSyed Saba Kareem
214b192114Ssyed saba kareem #include "acp63.h"
2295e43a17SSyed Saba Kareem
acp63_power_on(void __iomem * acp_base)234b192114Ssyed saba kareem static int acp63_power_on(void __iomem *acp_base)
249766bb62SSyed Saba Kareem {
259766bb62SSyed Saba Kareem u32 val;
269766bb62SSyed Saba Kareem
27ec54f810SSyed Saba Kareem val = readl(acp_base + ACP_PGFSM_STATUS);
289766bb62SSyed Saba Kareem
299766bb62SSyed Saba Kareem if (!val)
309766bb62SSyed Saba Kareem return val;
319766bb62SSyed Saba Kareem
329766bb62SSyed Saba Kareem if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)
33ec54f810SSyed Saba Kareem writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
34ea79b0a6SSyed Saba Kareem
35ea79b0a6SSyed Saba Kareem return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT);
369766bb62SSyed Saba Kareem }
379766bb62SSyed Saba Kareem
acp63_reset(void __iomem * acp_base)384b192114Ssyed saba kareem static int acp63_reset(void __iomem *acp_base)
399766bb62SSyed Saba Kareem {
409766bb62SSyed Saba Kareem u32 val;
41ea79b0a6SSyed Saba Kareem int ret;
429766bb62SSyed Saba Kareem
43ec54f810SSyed Saba Kareem writel(1, acp_base + ACP_SOFT_RESET);
44ea79b0a6SSyed Saba Kareem
45ea79b0a6SSyed Saba Kareem ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val,
46ea79b0a6SSyed Saba Kareem val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK,
47ea79b0a6SSyed Saba Kareem DELAY_US, ACP_TIMEOUT);
48ea79b0a6SSyed Saba Kareem if (ret)
49ea79b0a6SSyed Saba Kareem return ret;
50ea79b0a6SSyed Saba Kareem
51ec54f810SSyed Saba Kareem writel(0, acp_base + ACP_SOFT_RESET);
52ea79b0a6SSyed Saba Kareem
53ea79b0a6SSyed Saba Kareem return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);
549766bb62SSyed Saba Kareem }
559766bb62SSyed Saba Kareem
acp63_enable_interrupts(void __iomem * acp_base)564b192114Ssyed saba kareem static void acp63_enable_interrupts(void __iomem *acp_base)
579766bb62SSyed Saba Kareem {
58ec54f810SSyed Saba Kareem writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
59e1cb3506SVijendar Mukunda writel(ACP_ERROR_IRQ, acp_base + ACP_EXTERNAL_INTR_CNTL);
609766bb62SSyed Saba Kareem }
619766bb62SSyed Saba Kareem
acp63_disable_interrupts(void __iomem * acp_base)624b192114Ssyed saba kareem static void acp63_disable_interrupts(void __iomem *acp_base)
639766bb62SSyed Saba Kareem {
64ec54f810SSyed Saba Kareem writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + ACP_EXTERNAL_INTR_STAT);
65ec54f810SSyed Saba Kareem writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL);
66ec54f810SSyed Saba Kareem writel(0, acp_base + ACP_EXTERNAL_INTR_ENB);
679766bb62SSyed Saba Kareem }
689766bb62SSyed Saba Kareem
acp63_init(void __iomem * acp_base,struct device * dev)694b192114Ssyed saba kareem static int acp63_init(void __iomem *acp_base, struct device *dev)
709766bb62SSyed Saba Kareem {
719766bb62SSyed Saba Kareem int ret;
729766bb62SSyed Saba Kareem
734b192114Ssyed saba kareem ret = acp63_power_on(acp_base);
749766bb62SSyed Saba Kareem if (ret) {
759766bb62SSyed Saba Kareem dev_err(dev, "ACP power on failed\n");
769766bb62SSyed Saba Kareem return ret;
779766bb62SSyed Saba Kareem }
78ec54f810SSyed Saba Kareem writel(0x01, acp_base + ACP_CONTROL);
794b192114Ssyed saba kareem ret = acp63_reset(acp_base);
809766bb62SSyed Saba Kareem if (ret) {
819766bb62SSyed Saba Kareem dev_err(dev, "ACP reset failed\n");
829766bb62SSyed Saba Kareem return ret;
839766bb62SSyed Saba Kareem }
844b192114Ssyed saba kareem acp63_enable_interrupts(acp_base);
859766bb62SSyed Saba Kareem return 0;
869766bb62SSyed Saba Kareem }
879766bb62SSyed Saba Kareem
acp63_deinit(void __iomem * acp_base,struct device * dev)884b192114Ssyed saba kareem static int acp63_deinit(void __iomem *acp_base, struct device *dev)
899766bb62SSyed Saba Kareem {
909766bb62SSyed Saba Kareem int ret;
919766bb62SSyed Saba Kareem
924b192114Ssyed saba kareem acp63_disable_interrupts(acp_base);
934b192114Ssyed saba kareem ret = acp63_reset(acp_base);
949766bb62SSyed Saba Kareem if (ret) {
959766bb62SSyed Saba Kareem dev_err(dev, "ACP reset failed\n");
969766bb62SSyed Saba Kareem return ret;
979766bb62SSyed Saba Kareem }
98ec54f810SSyed Saba Kareem writel(0, acp_base + ACP_CONTROL);
999766bb62SSyed Saba Kareem return 0;
1009766bb62SSyed Saba Kareem }
1019766bb62SSyed Saba Kareem
acp63_irq_thread(int irq,void * context)102298d4f7bSVijendar Mukunda static irqreturn_t acp63_irq_thread(int irq, void *context)
103298d4f7bSVijendar Mukunda {
104298d4f7bSVijendar Mukunda struct sdw_dma_dev_data *sdw_dma_data;
105298d4f7bSVijendar Mukunda struct acp63_dev_data *adata = context;
106298d4f7bSVijendar Mukunda u32 stream_index;
107298d4f7bSVijendar Mukunda u16 pdev_index;
108298d4f7bSVijendar Mukunda
109298d4f7bSVijendar Mukunda pdev_index = adata->sdw_dma_dev_index;
110298d4f7bSVijendar Mukunda sdw_dma_data = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
111298d4f7bSVijendar Mukunda
112298d4f7bSVijendar Mukunda for (stream_index = 0; stream_index < ACP63_SDW0_DMA_MAX_STREAMS; stream_index++) {
113298d4f7bSVijendar Mukunda if (adata->sdw0_dma_intr_stat[stream_index]) {
114298d4f7bSVijendar Mukunda if (sdw_dma_data->sdw0_dma_stream[stream_index])
115298d4f7bSVijendar Mukunda snd_pcm_period_elapsed(sdw_dma_data->sdw0_dma_stream[stream_index]);
116298d4f7bSVijendar Mukunda adata->sdw0_dma_intr_stat[stream_index] = 0;
117298d4f7bSVijendar Mukunda }
118298d4f7bSVijendar Mukunda }
119298d4f7bSVijendar Mukunda for (stream_index = 0; stream_index < ACP63_SDW1_DMA_MAX_STREAMS; stream_index++) {
120298d4f7bSVijendar Mukunda if (adata->sdw1_dma_intr_stat[stream_index]) {
121298d4f7bSVijendar Mukunda if (sdw_dma_data->sdw1_dma_stream[stream_index])
122298d4f7bSVijendar Mukunda snd_pcm_period_elapsed(sdw_dma_data->sdw1_dma_stream[stream_index]);
123298d4f7bSVijendar Mukunda adata->sdw1_dma_intr_stat[stream_index] = 0;
124298d4f7bSVijendar Mukunda }
125298d4f7bSVijendar Mukunda }
126298d4f7bSVijendar Mukunda return IRQ_HANDLED;
127298d4f7bSVijendar Mukunda }
128298d4f7bSVijendar Mukunda
acp63_irq_handler(int irq,void * dev_id)1294b192114Ssyed saba kareem static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
1305bbeca60SSyed Saba Kareem {
1314b192114Ssyed saba kareem struct acp63_dev_data *adata;
1325bbeca60SSyed Saba Kareem struct pdm_dev_data *ps_pdm_data;
133e1cb3506SVijendar Mukunda struct amd_sdw_manager *amd_manager;
134e1cb3506SVijendar Mukunda u32 ext_intr_stat, ext_intr_stat1;
135298d4f7bSVijendar Mukunda u32 stream_id = 0;
136e1cb3506SVijendar Mukunda u16 irq_flag = 0;
137298d4f7bSVijendar Mukunda u16 sdw_dma_irq_flag = 0;
1389d327a44SVijendar Mukunda u16 pdev_index;
139298d4f7bSVijendar Mukunda u16 index;
1405bbeca60SSyed Saba Kareem
1415bbeca60SSyed Saba Kareem adata = dev_id;
1425bbeca60SSyed Saba Kareem if (!adata)
1435bbeca60SSyed Saba Kareem return IRQ_NONE;
144e1cb3506SVijendar Mukunda /* ACP interrupts will be cleared by reading particular bit and writing
145e1cb3506SVijendar Mukunda * same value to the status register. writing zero's doesn't have any
146e1cb3506SVijendar Mukunda * effect.
147e1cb3506SVijendar Mukunda * Bit by bit checking of IRQ field is implemented.
148e1cb3506SVijendar Mukunda */
149e1cb3506SVijendar Mukunda ext_intr_stat = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
150e1cb3506SVijendar Mukunda if (ext_intr_stat & ACP_SDW0_STAT) {
151e1cb3506SVijendar Mukunda writel(ACP_SDW0_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
152e1cb3506SVijendar Mukunda pdev_index = adata->sdw0_dev_index;
153e1cb3506SVijendar Mukunda amd_manager = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
154e1cb3506SVijendar Mukunda if (amd_manager)
155e1cb3506SVijendar Mukunda schedule_work(&amd_manager->amd_sdw_irq_thread);
156e1cb3506SVijendar Mukunda irq_flag = 1;
157e1cb3506SVijendar Mukunda }
1585bbeca60SSyed Saba Kareem
159e1cb3506SVijendar Mukunda ext_intr_stat1 = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
160e1cb3506SVijendar Mukunda if (ext_intr_stat1 & ACP_SDW1_STAT) {
161e1cb3506SVijendar Mukunda writel(ACP_SDW1_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
162e1cb3506SVijendar Mukunda pdev_index = adata->sdw1_dev_index;
163e1cb3506SVijendar Mukunda amd_manager = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
164e1cb3506SVijendar Mukunda if (amd_manager)
165e1cb3506SVijendar Mukunda schedule_work(&amd_manager->amd_sdw_irq_thread);
166e1cb3506SVijendar Mukunda irq_flag = 1;
167e1cb3506SVijendar Mukunda }
168e1cb3506SVijendar Mukunda
169e1cb3506SVijendar Mukunda if (ext_intr_stat & ACP_ERROR_IRQ) {
170e1cb3506SVijendar Mukunda writel(ACP_ERROR_IRQ, adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
171e1cb3506SVijendar Mukunda /* TODO: Report SoundWire Manager instance errors */
172e1cb3506SVijendar Mukunda writel(0, adata->acp63_base + ACP_SW0_I2S_ERROR_REASON);
173e1cb3506SVijendar Mukunda writel(0, adata->acp63_base + ACP_SW1_I2S_ERROR_REASON);
174e1cb3506SVijendar Mukunda writel(0, adata->acp63_base + ACP_ERROR_STATUS);
175e1cb3506SVijendar Mukunda irq_flag = 1;
176e1cb3506SVijendar Mukunda }
177e1cb3506SVijendar Mukunda
178e1cb3506SVijendar Mukunda if (ext_intr_stat & BIT(PDM_DMA_STAT)) {
1799d327a44SVijendar Mukunda pdev_index = adata->pdm_dev_index;
1809d327a44SVijendar Mukunda ps_pdm_data = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
181ec54f810SSyed Saba Kareem writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
1825bbeca60SSyed Saba Kareem if (ps_pdm_data->capture_stream)
1835bbeca60SSyed Saba Kareem snd_pcm_period_elapsed(ps_pdm_data->capture_stream);
184e1cb3506SVijendar Mukunda irq_flag = 1;
1855bbeca60SSyed Saba Kareem }
186298d4f7bSVijendar Mukunda if (ext_intr_stat & ACP_SDW_DMA_IRQ_MASK) {
187298d4f7bSVijendar Mukunda for (index = ACP_AUDIO2_RX_THRESHOLD; index <= ACP_AUDIO0_TX_THRESHOLD; index++) {
188298d4f7bSVijendar Mukunda if (ext_intr_stat & BIT(index)) {
189298d4f7bSVijendar Mukunda writel(BIT(index), adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
190298d4f7bSVijendar Mukunda switch (index) {
191298d4f7bSVijendar Mukunda case ACP_AUDIO0_TX_THRESHOLD:
192298d4f7bSVijendar Mukunda stream_id = ACP_SDW0_AUDIO0_TX;
193298d4f7bSVijendar Mukunda break;
194298d4f7bSVijendar Mukunda case ACP_AUDIO1_TX_THRESHOLD:
195298d4f7bSVijendar Mukunda stream_id = ACP_SDW0_AUDIO1_TX;
196298d4f7bSVijendar Mukunda break;
197298d4f7bSVijendar Mukunda case ACP_AUDIO2_TX_THRESHOLD:
198298d4f7bSVijendar Mukunda stream_id = ACP_SDW0_AUDIO2_TX;
199298d4f7bSVijendar Mukunda break;
200298d4f7bSVijendar Mukunda case ACP_AUDIO0_RX_THRESHOLD:
201298d4f7bSVijendar Mukunda stream_id = ACP_SDW0_AUDIO0_RX;
202298d4f7bSVijendar Mukunda break;
203298d4f7bSVijendar Mukunda case ACP_AUDIO1_RX_THRESHOLD:
204298d4f7bSVijendar Mukunda stream_id = ACP_SDW0_AUDIO1_RX;
205298d4f7bSVijendar Mukunda break;
206298d4f7bSVijendar Mukunda case ACP_AUDIO2_RX_THRESHOLD:
207298d4f7bSVijendar Mukunda stream_id = ACP_SDW0_AUDIO2_RX;
208298d4f7bSVijendar Mukunda break;
209298d4f7bSVijendar Mukunda }
210298d4f7bSVijendar Mukunda
211298d4f7bSVijendar Mukunda adata->sdw0_dma_intr_stat[stream_id] = 1;
212298d4f7bSVijendar Mukunda sdw_dma_irq_flag = 1;
213298d4f7bSVijendar Mukunda }
214298d4f7bSVijendar Mukunda }
215298d4f7bSVijendar Mukunda }
216298d4f7bSVijendar Mukunda
217298d4f7bSVijendar Mukunda if (ext_intr_stat1 & ACP_P1_AUDIO1_RX_THRESHOLD) {
218298d4f7bSVijendar Mukunda writel(ACP_P1_AUDIO1_RX_THRESHOLD,
219298d4f7bSVijendar Mukunda adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
220298d4f7bSVijendar Mukunda adata->sdw1_dma_intr_stat[ACP_SDW1_AUDIO1_RX] = 1;
221298d4f7bSVijendar Mukunda sdw_dma_irq_flag = 1;
222298d4f7bSVijendar Mukunda }
223298d4f7bSVijendar Mukunda
224298d4f7bSVijendar Mukunda if (ext_intr_stat1 & ACP_P1_AUDIO1_TX_THRESHOLD) {
225298d4f7bSVijendar Mukunda writel(ACP_P1_AUDIO1_TX_THRESHOLD,
226298d4f7bSVijendar Mukunda adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
227298d4f7bSVijendar Mukunda adata->sdw1_dma_intr_stat[ACP_SDW1_AUDIO1_TX] = 1;
228298d4f7bSVijendar Mukunda sdw_dma_irq_flag = 1;
229298d4f7bSVijendar Mukunda }
230298d4f7bSVijendar Mukunda
231298d4f7bSVijendar Mukunda if (sdw_dma_irq_flag)
232298d4f7bSVijendar Mukunda return IRQ_WAKE_THREAD;
233298d4f7bSVijendar Mukunda
234e1cb3506SVijendar Mukunda if (irq_flag)
235e1cb3506SVijendar Mukunda return IRQ_HANDLED;
236e1cb3506SVijendar Mukunda else
2375bbeca60SSyed Saba Kareem return IRQ_NONE;
2385bbeca60SSyed Saba Kareem }
2395bbeca60SSyed Saba Kareem
sdw_amd_scan_controller(struct device * dev)240d1351c30SVijendar Mukunda static int sdw_amd_scan_controller(struct device *dev)
241d1351c30SVijendar Mukunda {
242d1351c30SVijendar Mukunda struct acp63_dev_data *acp_data;
243d1351c30SVijendar Mukunda struct fwnode_handle *link;
244d1351c30SVijendar Mukunda char name[32];
245d1351c30SVijendar Mukunda u32 sdw_manager_bitmap;
246d1351c30SVijendar Mukunda u8 count = 0;
247d1351c30SVijendar Mukunda u32 acp_sdw_power_mode = 0;
248d1351c30SVijendar Mukunda int index;
249d1351c30SVijendar Mukunda int ret;
250d1351c30SVijendar Mukunda
251d1351c30SVijendar Mukunda acp_data = dev_get_drvdata(dev);
252d1351c30SVijendar Mukunda /*
253d1351c30SVijendar Mukunda * Current implementation is based on MIPI DisCo 2.0 spec.
254d1351c30SVijendar Mukunda * Found controller, find links supported.
255d1351c30SVijendar Mukunda */
256d1351c30SVijendar Mukunda ret = fwnode_property_read_u32_array((acp_data->sdw_fw_node), "mipi-sdw-manager-list",
257d1351c30SVijendar Mukunda &sdw_manager_bitmap, 1);
258d1351c30SVijendar Mukunda
259d1351c30SVijendar Mukunda if (ret) {
260*cd710900SMario Limonciello dev_dbg(dev, "Failed to read mipi-sdw-manager-list: %d\n", ret);
261d1351c30SVijendar Mukunda return -EINVAL;
262d1351c30SVijendar Mukunda }
263d1351c30SVijendar Mukunda count = hweight32(sdw_manager_bitmap);
264d1351c30SVijendar Mukunda /* Check count is within bounds */
265d1351c30SVijendar Mukunda if (count > AMD_SDW_MAX_MANAGERS) {
266d1351c30SVijendar Mukunda dev_err(dev, "Manager count %d exceeds max %d\n", count, AMD_SDW_MAX_MANAGERS);
267d1351c30SVijendar Mukunda return -EINVAL;
268d1351c30SVijendar Mukunda }
269d1351c30SVijendar Mukunda
270d1351c30SVijendar Mukunda if (!count) {
271d1351c30SVijendar Mukunda dev_dbg(dev, "No SoundWire Managers detected\n");
272d1351c30SVijendar Mukunda return -EINVAL;
273d1351c30SVijendar Mukunda }
274d1351c30SVijendar Mukunda dev_dbg(dev, "ACPI reports %d SoundWire Manager devices\n", count);
275d1351c30SVijendar Mukunda acp_data->sdw_manager_count = count;
276d1351c30SVijendar Mukunda for (index = 0; index < count; index++) {
277d1351c30SVijendar Mukunda snprintf(name, sizeof(name), "mipi-sdw-link-%d-subproperties", index);
278d1351c30SVijendar Mukunda link = fwnode_get_named_child_node(acp_data->sdw_fw_node, name);
279d1351c30SVijendar Mukunda if (!link) {
280d1351c30SVijendar Mukunda dev_err(dev, "Manager node %s not found\n", name);
281d1351c30SVijendar Mukunda return -EIO;
282d1351c30SVijendar Mukunda }
283d1351c30SVijendar Mukunda
284d1351c30SVijendar Mukunda ret = fwnode_property_read_u32(link, "amd-sdw-power-mode", &acp_sdw_power_mode);
285d1351c30SVijendar Mukunda if (ret)
286d1351c30SVijendar Mukunda return ret;
287d1351c30SVijendar Mukunda /*
288d1351c30SVijendar Mukunda * when SoundWire configuration is selected from acp pin config,
289d1351c30SVijendar Mukunda * based on manager instances count, acp init/de-init sequence should be
290d1351c30SVijendar Mukunda * executed as part of PM ops only when Bus reset is applied for the active
291d1351c30SVijendar Mukunda * SoundWire manager instances.
292d1351c30SVijendar Mukunda */
293d1351c30SVijendar Mukunda if (acp_sdw_power_mode != AMD_SDW_POWER_OFF_MODE) {
294d1351c30SVijendar Mukunda acp_data->acp_reset = false;
295d1351c30SVijendar Mukunda return 0;
296d1351c30SVijendar Mukunda }
297d1351c30SVijendar Mukunda }
298d1351c30SVijendar Mukunda return 0;
299d1351c30SVijendar Mukunda }
300d1351c30SVijendar Mukunda
get_acp63_device_config(u32 config,struct pci_dev * pci,struct acp63_dev_data * acp_data)301d1351c30SVijendar Mukunda static int get_acp63_device_config(u32 config, struct pci_dev *pci, struct acp63_dev_data *acp_data)
3022cdabbdeSVijendar Mukunda {
3032cdabbdeSVijendar Mukunda struct acpi_device *dmic_dev;
304d1351c30SVijendar Mukunda struct acpi_device *sdw_dev;
3052cdabbdeSVijendar Mukunda const union acpi_object *obj;
3062cdabbdeSVijendar Mukunda bool is_dmic_dev = false;
307d1351c30SVijendar Mukunda bool is_sdw_dev = false;
308d1351c30SVijendar Mukunda int ret;
3092cdabbdeSVijendar Mukunda
3102cdabbdeSVijendar Mukunda dmic_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP63_DMIC_ADDR, 0);
3112cdabbdeSVijendar Mukunda if (dmic_dev) {
312d1351c30SVijendar Mukunda /* is_dmic_dev flag will be set when ACP PDM controller device exists */
3132cdabbdeSVijendar Mukunda if (!acpi_dev_get_property(dmic_dev, "acp-audio-device-type",
3142cdabbdeSVijendar Mukunda ACPI_TYPE_INTEGER, &obj) &&
3152cdabbdeSVijendar Mukunda obj->integer.value == ACP_DMIC_DEV)
3162cdabbdeSVijendar Mukunda is_dmic_dev = true;
3172cdabbdeSVijendar Mukunda }
3182cdabbdeSVijendar Mukunda
319d1351c30SVijendar Mukunda sdw_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP63_SDW_ADDR, 0);
320d1351c30SVijendar Mukunda if (sdw_dev) {
321d1351c30SVijendar Mukunda acp_data->sdw_fw_node = acpi_fwnode_handle(sdw_dev);
322d1351c30SVijendar Mukunda ret = sdw_amd_scan_controller(&pci->dev);
323d1351c30SVijendar Mukunda /* is_sdw_dev flag will be set when SoundWire Manager device exists */
324d1351c30SVijendar Mukunda if (!ret)
325d1351c30SVijendar Mukunda is_sdw_dev = true;
326d1351c30SVijendar Mukunda }
327d1351c30SVijendar Mukunda if (!is_dmic_dev && !is_sdw_dev)
328d1351c30SVijendar Mukunda return -ENODEV;
3292cdabbdeSVijendar Mukunda dev_dbg(&pci->dev, "Audio Mode %d\n", config);
330d1351c30SVijendar Mukunda switch (config) {
331d1351c30SVijendar Mukunda case ACP_CONFIG_4:
332d1351c30SVijendar Mukunda case ACP_CONFIG_5:
333d1351c30SVijendar Mukunda case ACP_CONFIG_10:
334d1351c30SVijendar Mukunda case ACP_CONFIG_11:
3352cdabbdeSVijendar Mukunda if (is_dmic_dev) {
336d1351c30SVijendar Mukunda acp_data->pdev_config = ACP63_PDM_DEV_CONFIG;
3372cdabbdeSVijendar Mukunda acp_data->pdev_count = ACP63_PDM_MODE_DEVS;
3382cdabbdeSVijendar Mukunda }
3392cdabbdeSVijendar Mukunda break;
340d1351c30SVijendar Mukunda case ACP_CONFIG_2:
341d1351c30SVijendar Mukunda case ACP_CONFIG_3:
342d1351c30SVijendar Mukunda if (is_sdw_dev) {
343d1351c30SVijendar Mukunda switch (acp_data->sdw_manager_count) {
344d1351c30SVijendar Mukunda case 1:
345d1351c30SVijendar Mukunda acp_data->pdev_config = ACP63_SDW_DEV_CONFIG;
346d1351c30SVijendar Mukunda acp_data->pdev_count = ACP63_SDW0_MODE_DEVS;
347d1351c30SVijendar Mukunda break;
348d1351c30SVijendar Mukunda case 2:
349d1351c30SVijendar Mukunda acp_data->pdev_config = ACP63_SDW_DEV_CONFIG;
350d1351c30SVijendar Mukunda acp_data->pdev_count = ACP63_SDW0_SDW1_MODE_DEVS;
351d1351c30SVijendar Mukunda break;
352d1351c30SVijendar Mukunda default:
353d1351c30SVijendar Mukunda return -EINVAL;
3542cdabbdeSVijendar Mukunda }
3552cdabbdeSVijendar Mukunda }
356d1351c30SVijendar Mukunda break;
357d1351c30SVijendar Mukunda case ACP_CONFIG_6:
358d1351c30SVijendar Mukunda case ACP_CONFIG_7:
359d1351c30SVijendar Mukunda case ACP_CONFIG_12:
360d1351c30SVijendar Mukunda case ACP_CONFIG_8:
361d1351c30SVijendar Mukunda case ACP_CONFIG_13:
362d1351c30SVijendar Mukunda case ACP_CONFIG_14:
363d1351c30SVijendar Mukunda if (is_dmic_dev && is_sdw_dev) {
364d1351c30SVijendar Mukunda switch (acp_data->sdw_manager_count) {
365d1351c30SVijendar Mukunda case 1:
366d1351c30SVijendar Mukunda acp_data->pdev_config = ACP63_SDW_PDM_DEV_CONFIG;
367d1351c30SVijendar Mukunda acp_data->pdev_count = ACP63_SDW0_PDM_MODE_DEVS;
368d1351c30SVijendar Mukunda break;
369d1351c30SVijendar Mukunda case 2:
370d1351c30SVijendar Mukunda acp_data->pdev_config = ACP63_SDW_PDM_DEV_CONFIG;
371d1351c30SVijendar Mukunda acp_data->pdev_count = ACP63_SDW0_SDW1_PDM_MODE_DEVS;
372d1351c30SVijendar Mukunda break;
373d1351c30SVijendar Mukunda default:
374d1351c30SVijendar Mukunda return -EINVAL;
375d1351c30SVijendar Mukunda }
376d1351c30SVijendar Mukunda } else if (is_dmic_dev) {
377d1351c30SVijendar Mukunda acp_data->pdev_config = ACP63_PDM_DEV_CONFIG;
378d1351c30SVijendar Mukunda acp_data->pdev_count = ACP63_PDM_MODE_DEVS;
379d1351c30SVijendar Mukunda } else if (is_sdw_dev) {
380d1351c30SVijendar Mukunda switch (acp_data->sdw_manager_count) {
381d1351c30SVijendar Mukunda case 1:
382d1351c30SVijendar Mukunda acp_data->pdev_config = ACP63_SDW_DEV_CONFIG;
383d1351c30SVijendar Mukunda acp_data->pdev_count = ACP63_SDW0_MODE_DEVS;
384d1351c30SVijendar Mukunda break;
385d1351c30SVijendar Mukunda case 2:
386d1351c30SVijendar Mukunda acp_data->pdev_config = ACP63_SDW_DEV_CONFIG;
387d1351c30SVijendar Mukunda acp_data->pdev_count = ACP63_SDW0_SDW1_MODE_DEVS;
388d1351c30SVijendar Mukunda break;
389d1351c30SVijendar Mukunda default:
390d1351c30SVijendar Mukunda return -EINVAL;
391d1351c30SVijendar Mukunda }
392d1351c30SVijendar Mukunda }
393d1351c30SVijendar Mukunda break;
394d1351c30SVijendar Mukunda default:
395d1351c30SVijendar Mukunda break;
396d1351c30SVijendar Mukunda }
397d1351c30SVijendar Mukunda return 0;
398d1351c30SVijendar Mukunda }
3992cdabbdeSVijendar Mukunda
acp63_fill_platform_dev_info(struct platform_device_info * pdevinfo,struct device * parent,struct fwnode_handle * fw_node,char * name,unsigned int id,const struct resource * res,unsigned int num_res,const void * data,size_t size_data)400b1184589SPierre-Louis Bossart static void acp63_fill_platform_dev_info(struct platform_device_info *pdevinfo,
401b1184589SPierre-Louis Bossart struct device *parent,
402b1184589SPierre-Louis Bossart struct fwnode_handle *fw_node,
403b1184589SPierre-Louis Bossart char *name, unsigned int id,
404b1184589SPierre-Louis Bossart const struct resource *res,
405b1184589SPierre-Louis Bossart unsigned int num_res,
406b1184589SPierre-Louis Bossart const void *data,
407b1184589SPierre-Louis Bossart size_t size_data)
4081d325cdaSVijendar Mukunda {
4091d325cdaSVijendar Mukunda pdevinfo->name = name;
4101d325cdaSVijendar Mukunda pdevinfo->id = id;
4111d325cdaSVijendar Mukunda pdevinfo->parent = parent;
4121d325cdaSVijendar Mukunda pdevinfo->num_res = num_res;
4131d325cdaSVijendar Mukunda pdevinfo->res = res;
4141d325cdaSVijendar Mukunda pdevinfo->data = data;
4151d325cdaSVijendar Mukunda pdevinfo->size_data = size_data;
4161d325cdaSVijendar Mukunda pdevinfo->fwnode = fw_node;
4171d325cdaSVijendar Mukunda }
4181d325cdaSVijendar Mukunda
create_acp63_platform_devs(struct pci_dev * pci,struct acp63_dev_data * adata,u32 addr)4191d325cdaSVijendar Mukunda static int create_acp63_platform_devs(struct pci_dev *pci, struct acp63_dev_data *adata, u32 addr)
4201d325cdaSVijendar Mukunda {
421d1351c30SVijendar Mukunda struct acp_sdw_pdata *sdw_pdata;
4221d325cdaSVijendar Mukunda struct platform_device_info pdevinfo[ACP63_DEVS];
4231d325cdaSVijendar Mukunda struct device *parent;
4241d325cdaSVijendar Mukunda int index;
4251d325cdaSVijendar Mukunda int ret;
4261d325cdaSVijendar Mukunda
4271d325cdaSVijendar Mukunda parent = &pci->dev;
4281d325cdaSVijendar Mukunda dev_dbg(&pci->dev,
429d1351c30SVijendar Mukunda "%s pdev_config:0x%x pdev_count:0x%x\n", __func__, adata->pdev_config,
4301d325cdaSVijendar Mukunda adata->pdev_count);
431d1351c30SVijendar Mukunda if (adata->pdev_config) {
4321d325cdaSVijendar Mukunda adata->res = devm_kzalloc(&pci->dev, sizeof(struct resource), GFP_KERNEL);
4331d325cdaSVijendar Mukunda if (!adata->res) {
4341d325cdaSVijendar Mukunda ret = -ENOMEM;
4351d325cdaSVijendar Mukunda goto de_init;
4361d325cdaSVijendar Mukunda }
4371d325cdaSVijendar Mukunda adata->res->flags = IORESOURCE_MEM;
4381d325cdaSVijendar Mukunda adata->res->start = addr;
4391d325cdaSVijendar Mukunda adata->res->end = addr + (ACP63_REG_END - ACP63_REG_START);
4401d325cdaSVijendar Mukunda memset(&pdevinfo, 0, sizeof(pdevinfo));
4411d325cdaSVijendar Mukunda }
4421d325cdaSVijendar Mukunda
443d1351c30SVijendar Mukunda switch (adata->pdev_config) {
444d1351c30SVijendar Mukunda case ACP63_PDM_DEV_CONFIG:
4451d325cdaSVijendar Mukunda adata->pdm_dev_index = 0;
4461d325cdaSVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[0], parent, NULL, "acp_ps_pdm_dma",
447b6b5c642SVijendar Mukunda 0, adata->res, 1, NULL, 0);
4481d325cdaSVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[1], parent, NULL, "dmic-codec",
4491d325cdaSVijendar Mukunda 0, NULL, 0, NULL, 0);
4501d325cdaSVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[2], parent, NULL, "acp_ps_mach",
4511d325cdaSVijendar Mukunda 0, NULL, 0, NULL, 0);
4521d325cdaSVijendar Mukunda break;
453d1351c30SVijendar Mukunda case ACP63_SDW_DEV_CONFIG:
454d1351c30SVijendar Mukunda if (adata->pdev_count == ACP63_SDW0_MODE_DEVS) {
455d1351c30SVijendar Mukunda sdw_pdata = devm_kzalloc(&pci->dev, sizeof(struct acp_sdw_pdata),
456d1351c30SVijendar Mukunda GFP_KERNEL);
457d1351c30SVijendar Mukunda if (!sdw_pdata) {
458d1351c30SVijendar Mukunda ret = -ENOMEM;
459d1351c30SVijendar Mukunda goto de_init;
460d1351c30SVijendar Mukunda }
461d1351c30SVijendar Mukunda
462d1351c30SVijendar Mukunda sdw_pdata->instance = 0;
463d1351c30SVijendar Mukunda sdw_pdata->acp_sdw_lock = &adata->acp_lock;
464d1351c30SVijendar Mukunda adata->sdw0_dev_index = 0;
465d1351c30SVijendar Mukunda adata->sdw_dma_dev_index = 1;
466d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[0], parent, adata->sdw_fw_node,
467d1351c30SVijendar Mukunda "amd_sdw_manager", 0, adata->res, 1,
468d1351c30SVijendar Mukunda sdw_pdata, sizeof(struct acp_sdw_pdata));
469d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[1], parent, NULL, "amd_ps_sdw_dma",
470d1351c30SVijendar Mukunda 0, adata->res, 1, NULL, 0);
471d1351c30SVijendar Mukunda } else if (adata->pdev_count == ACP63_SDW0_SDW1_MODE_DEVS) {
472d1351c30SVijendar Mukunda sdw_pdata = devm_kzalloc(&pci->dev, sizeof(struct acp_sdw_pdata) * 2,
473d1351c30SVijendar Mukunda GFP_KERNEL);
474d1351c30SVijendar Mukunda if (!sdw_pdata) {
475d1351c30SVijendar Mukunda ret = -ENOMEM;
476d1351c30SVijendar Mukunda goto de_init;
477d1351c30SVijendar Mukunda }
478d1351c30SVijendar Mukunda
479d1351c30SVijendar Mukunda sdw_pdata[0].instance = 0;
480d1351c30SVijendar Mukunda sdw_pdata[1].instance = 1;
481d1351c30SVijendar Mukunda sdw_pdata[0].acp_sdw_lock = &adata->acp_lock;
482d1351c30SVijendar Mukunda sdw_pdata[1].acp_sdw_lock = &adata->acp_lock;
483d1351c30SVijendar Mukunda sdw_pdata->acp_sdw_lock = &adata->acp_lock;
484d1351c30SVijendar Mukunda adata->sdw0_dev_index = 0;
485d1351c30SVijendar Mukunda adata->sdw1_dev_index = 1;
486d1351c30SVijendar Mukunda adata->sdw_dma_dev_index = 2;
487d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[0], parent, adata->sdw_fw_node,
488d1351c30SVijendar Mukunda "amd_sdw_manager", 0, adata->res, 1,
489d1351c30SVijendar Mukunda &sdw_pdata[0], sizeof(struct acp_sdw_pdata));
490d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[1], parent, adata->sdw_fw_node,
491d1351c30SVijendar Mukunda "amd_sdw_manager", 1, adata->res, 1,
492d1351c30SVijendar Mukunda &sdw_pdata[1], sizeof(struct acp_sdw_pdata));
493d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[2], parent, NULL, "amd_ps_sdw_dma",
494d1351c30SVijendar Mukunda 0, adata->res, 1, NULL, 0);
495d1351c30SVijendar Mukunda }
496d1351c30SVijendar Mukunda break;
497d1351c30SVijendar Mukunda case ACP63_SDW_PDM_DEV_CONFIG:
498d1351c30SVijendar Mukunda if (adata->pdev_count == ACP63_SDW0_PDM_MODE_DEVS) {
499d1351c30SVijendar Mukunda sdw_pdata = devm_kzalloc(&pci->dev, sizeof(struct acp_sdw_pdata),
500d1351c30SVijendar Mukunda GFP_KERNEL);
501d1351c30SVijendar Mukunda if (!sdw_pdata) {
502d1351c30SVijendar Mukunda ret = -ENOMEM;
503d1351c30SVijendar Mukunda goto de_init;
504d1351c30SVijendar Mukunda }
505d1351c30SVijendar Mukunda
506d1351c30SVijendar Mukunda sdw_pdata->instance = 0;
507d1351c30SVijendar Mukunda sdw_pdata->acp_sdw_lock = &adata->acp_lock;
508d1351c30SVijendar Mukunda adata->pdm_dev_index = 0;
509d1351c30SVijendar Mukunda adata->sdw0_dev_index = 1;
510d1351c30SVijendar Mukunda adata->sdw_dma_dev_index = 2;
511d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[0], parent, NULL, "acp_ps_pdm_dma",
512d1351c30SVijendar Mukunda 0, adata->res, 1, NULL, 0);
513d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[1], parent, adata->sdw_fw_node,
514d1351c30SVijendar Mukunda "amd_sdw_manager", 0, adata->res, 1,
515d1351c30SVijendar Mukunda sdw_pdata, sizeof(struct acp_sdw_pdata));
516d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[2], parent, NULL, "amd_ps_sdw_dma",
517d1351c30SVijendar Mukunda 0, adata->res, 1, NULL, 0);
518d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[3], parent, NULL, "dmic-codec",
519d1351c30SVijendar Mukunda 0, NULL, 0, NULL, 0);
520d1351c30SVijendar Mukunda } else if (adata->pdev_count == ACP63_SDW0_SDW1_PDM_MODE_DEVS) {
521d1351c30SVijendar Mukunda sdw_pdata = devm_kzalloc(&pci->dev, sizeof(struct acp_sdw_pdata) * 2,
522d1351c30SVijendar Mukunda GFP_KERNEL);
523d1351c30SVijendar Mukunda if (!sdw_pdata) {
524d1351c30SVijendar Mukunda ret = -ENOMEM;
525d1351c30SVijendar Mukunda goto de_init;
526d1351c30SVijendar Mukunda }
527d1351c30SVijendar Mukunda sdw_pdata[0].instance = 0;
528d1351c30SVijendar Mukunda sdw_pdata[1].instance = 1;
529d1351c30SVijendar Mukunda sdw_pdata[0].acp_sdw_lock = &adata->acp_lock;
530d1351c30SVijendar Mukunda sdw_pdata[1].acp_sdw_lock = &adata->acp_lock;
531d1351c30SVijendar Mukunda adata->pdm_dev_index = 0;
532d1351c30SVijendar Mukunda adata->sdw0_dev_index = 1;
533d1351c30SVijendar Mukunda adata->sdw1_dev_index = 2;
534d1351c30SVijendar Mukunda adata->sdw_dma_dev_index = 3;
535d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[0], parent, NULL, "acp_ps_pdm_dma",
536d1351c30SVijendar Mukunda 0, adata->res, 1, NULL, 0);
537d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[1], parent, adata->sdw_fw_node,
538d1351c30SVijendar Mukunda "amd_sdw_manager", 0, adata->res, 1,
539d1351c30SVijendar Mukunda &sdw_pdata[0], sizeof(struct acp_sdw_pdata));
540d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[2], parent, adata->sdw_fw_node,
541d1351c30SVijendar Mukunda "amd_sdw_manager", 1, adata->res, 1,
542d1351c30SVijendar Mukunda &sdw_pdata[1], sizeof(struct acp_sdw_pdata));
543d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[3], parent, NULL, "amd_ps_sdw_dma",
544d1351c30SVijendar Mukunda 0, adata->res, 1, NULL, 0);
545d1351c30SVijendar Mukunda acp63_fill_platform_dev_info(&pdevinfo[4], parent, NULL, "dmic-codec",
546d1351c30SVijendar Mukunda 0, NULL, 0, NULL, 0);
547d1351c30SVijendar Mukunda }
548d1351c30SVijendar Mukunda break;
5491d325cdaSVijendar Mukunda default:
550d1351c30SVijendar Mukunda dev_dbg(&pci->dev, "No PDM or SoundWire manager devices found\n");
551de1cae22SNathan Chancellor return 0;
5521d325cdaSVijendar Mukunda }
5531d325cdaSVijendar Mukunda
5541d325cdaSVijendar Mukunda for (index = 0; index < adata->pdev_count; index++) {
5551d325cdaSVijendar Mukunda adata->pdev[index] = platform_device_register_full(&pdevinfo[index]);
5561d325cdaSVijendar Mukunda if (IS_ERR(adata->pdev[index])) {
5571d325cdaSVijendar Mukunda dev_err(&pci->dev,
5581d325cdaSVijendar Mukunda "cannot register %s device\n", pdevinfo[index].name);
5591d325cdaSVijendar Mukunda ret = PTR_ERR(adata->pdev[index]);
5601d325cdaSVijendar Mukunda goto unregister_devs;
5611d325cdaSVijendar Mukunda }
5621d325cdaSVijendar Mukunda }
5631d325cdaSVijendar Mukunda return 0;
5641d325cdaSVijendar Mukunda unregister_devs:
5651d325cdaSVijendar Mukunda for (--index; index >= 0; index--)
5661d325cdaSVijendar Mukunda platform_device_unregister(adata->pdev[index]);
5671d325cdaSVijendar Mukunda de_init:
5681d325cdaSVijendar Mukunda if (acp63_deinit(adata->acp63_base, &pci->dev))
5691d325cdaSVijendar Mukunda dev_err(&pci->dev, "ACP de-init failed\n");
5701d325cdaSVijendar Mukunda return ret;
5711d325cdaSVijendar Mukunda }
5721d325cdaSVijendar Mukunda
snd_acp63_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)5734b192114Ssyed saba kareem static int snd_acp63_probe(struct pci_dev *pci,
57495e43a17SSyed Saba Kareem const struct pci_device_id *pci_id)
57595e43a17SSyed Saba Kareem {
5764b192114Ssyed saba kareem struct acp63_dev_data *adata;
57795e43a17SSyed Saba Kareem u32 addr;
578bddcfb08SSyed Saba Kareem u32 irqflags, flag;
5791d325cdaSVijendar Mukunda int val;
5801d325cdaSVijendar Mukunda int ret;
58195e43a17SSyed Saba Kareem
5825bbeca60SSyed Saba Kareem irqflags = IRQF_SHARED;
583bddcfb08SSyed Saba Kareem
584bddcfb08SSyed Saba Kareem /* Return if acp config flag is defined */
585bddcfb08SSyed Saba Kareem flag = snd_amd_acp_find_config(pci);
586bddcfb08SSyed Saba Kareem if (flag)
587bddcfb08SSyed Saba Kareem return -ENODEV;
588bddcfb08SSyed Saba Kareem
58995e43a17SSyed Saba Kareem /* Pink Sardine device check */
59095e43a17SSyed Saba Kareem switch (pci->revision) {
59195e43a17SSyed Saba Kareem case 0x63:
59295e43a17SSyed Saba Kareem break;
59395e43a17SSyed Saba Kareem default:
5944b192114Ssyed saba kareem dev_dbg(&pci->dev, "acp63 pci device not found\n");
59595e43a17SSyed Saba Kareem return -ENODEV;
59695e43a17SSyed Saba Kareem }
59795e43a17SSyed Saba Kareem if (pci_enable_device(pci)) {
59895e43a17SSyed Saba Kareem dev_err(&pci->dev, "pci_enable_device failed\n");
59995e43a17SSyed Saba Kareem return -ENODEV;
60095e43a17SSyed Saba Kareem }
60195e43a17SSyed Saba Kareem
60295e43a17SSyed Saba Kareem ret = pci_request_regions(pci, "AMD ACP6.2 audio");
60395e43a17SSyed Saba Kareem if (ret < 0) {
60495e43a17SSyed Saba Kareem dev_err(&pci->dev, "pci_request_regions failed\n");
60595e43a17SSyed Saba Kareem goto disable_pci;
60695e43a17SSyed Saba Kareem }
6074b192114Ssyed saba kareem adata = devm_kzalloc(&pci->dev, sizeof(struct acp63_dev_data),
60895e43a17SSyed Saba Kareem GFP_KERNEL);
60995e43a17SSyed Saba Kareem if (!adata) {
61095e43a17SSyed Saba Kareem ret = -ENOMEM;
61195e43a17SSyed Saba Kareem goto release_regions;
61295e43a17SSyed Saba Kareem }
61395e43a17SSyed Saba Kareem
61495e43a17SSyed Saba Kareem addr = pci_resource_start(pci, 0);
6154b192114Ssyed saba kareem adata->acp63_base = devm_ioremap(&pci->dev, addr,
61695e43a17SSyed Saba Kareem pci_resource_len(pci, 0));
6174b192114Ssyed saba kareem if (!adata->acp63_base) {
61895e43a17SSyed Saba Kareem ret = -ENOMEM;
61995e43a17SSyed Saba Kareem goto release_regions;
62095e43a17SSyed Saba Kareem }
621d1351c30SVijendar Mukunda /*
622d1351c30SVijendar Mukunda * By default acp_reset flag is set to true. i.e acp_deinit() and acp_init()
623d1351c30SVijendar Mukunda * will be invoked for all ACP configurations during suspend/resume callbacks.
624d1351c30SVijendar Mukunda * This flag should be set to false only when SoundWire manager power mode
625d1351c30SVijendar Mukunda * set to ClockStopMode.
626d1351c30SVijendar Mukunda */
627d1351c30SVijendar Mukunda adata->acp_reset = true;
62895e43a17SSyed Saba Kareem pci_set_master(pci);
62995e43a17SSyed Saba Kareem pci_set_drvdata(pci, adata);
630f763fb2fSVijendar Mukunda mutex_init(&adata->acp_lock);
6314b192114Ssyed saba kareem ret = acp63_init(adata->acp63_base, &pci->dev);
6329766bb62SSyed Saba Kareem if (ret)
6339766bb62SSyed Saba Kareem goto release_regions;
634298d4f7bSVijendar Mukunda ret = devm_request_threaded_irq(&pci->dev, pci->irq, acp63_irq_handler,
635298d4f7bSVijendar Mukunda acp63_irq_thread, irqflags, "ACP_PCI_IRQ", adata);
636966ef755SVijendar Mukunda if (ret) {
637966ef755SVijendar Mukunda dev_err(&pci->dev, "ACP PCI IRQ request failed\n");
638966ef755SVijendar Mukunda goto de_init;
639966ef755SVijendar Mukunda }
640ec54f810SSyed Saba Kareem val = readl(adata->acp63_base + ACP_PIN_CONFIG);
641d1351c30SVijendar Mukunda ret = get_acp63_device_config(val, pci, adata);
642d1351c30SVijendar Mukunda /* ACP PCI driver probe should be continued even PDM or SoundWire Devices are not found */
643d1351c30SVijendar Mukunda if (ret) {
644*cd710900SMario Limonciello dev_dbg(&pci->dev, "get acp device config failed:%d\n", ret);
645d1351c30SVijendar Mukunda goto skip_pdev_creation;
646d1351c30SVijendar Mukunda }
6471d325cdaSVijendar Mukunda ret = create_acp63_platform_devs(pci, adata, addr);
6481d325cdaSVijendar Mukunda if (ret < 0) {
6491d325cdaSVijendar Mukunda dev_err(&pci->dev, "ACP platform devices creation failed\n");
650515ee257SSyed Saba Kareem goto de_init;
651515ee257SSyed Saba Kareem }
652d1351c30SVijendar Mukunda skip_pdev_creation:
6533a543d56SSyed Saba Kareem pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS);
6543a543d56SSyed Saba Kareem pm_runtime_use_autosuspend(&pci->dev);
6553a543d56SSyed Saba Kareem pm_runtime_put_noidle(&pci->dev);
6563a543d56SSyed Saba Kareem pm_runtime_allow(&pci->dev);
65795e43a17SSyed Saba Kareem return 0;
658515ee257SSyed Saba Kareem de_init:
6594b192114Ssyed saba kareem if (acp63_deinit(adata->acp63_base, &pci->dev))
660515ee257SSyed Saba Kareem dev_err(&pci->dev, "ACP de-init failed\n");
66195e43a17SSyed Saba Kareem release_regions:
66295e43a17SSyed Saba Kareem pci_release_regions(pci);
66395e43a17SSyed Saba Kareem disable_pci:
66495e43a17SSyed Saba Kareem pci_disable_device(pci);
66595e43a17SSyed Saba Kareem
66695e43a17SSyed Saba Kareem return ret;
66795e43a17SSyed Saba Kareem }
66895e43a17SSyed Saba Kareem
snd_acp63_suspend(struct device * dev)6694b192114Ssyed saba kareem static int __maybe_unused snd_acp63_suspend(struct device *dev)
6703a543d56SSyed Saba Kareem {
6714b192114Ssyed saba kareem struct acp63_dev_data *adata;
672198c93e2SVijendar Mukunda int ret = 0;
6733a543d56SSyed Saba Kareem
6743a543d56SSyed Saba Kareem adata = dev_get_drvdata(dev);
675198c93e2SVijendar Mukunda if (adata->acp_reset) {
6764b192114Ssyed saba kareem ret = acp63_deinit(adata->acp63_base, dev);
6773a543d56SSyed Saba Kareem if (ret)
6783a543d56SSyed Saba Kareem dev_err(dev, "ACP de-init failed\n");
679198c93e2SVijendar Mukunda }
6803a543d56SSyed Saba Kareem return ret;
6813a543d56SSyed Saba Kareem }
6823a543d56SSyed Saba Kareem
snd_acp63_resume(struct device * dev)6834b192114Ssyed saba kareem static int __maybe_unused snd_acp63_resume(struct device *dev)
6843a543d56SSyed Saba Kareem {
6854b192114Ssyed saba kareem struct acp63_dev_data *adata;
686198c93e2SVijendar Mukunda int ret = 0;
6873a543d56SSyed Saba Kareem
6883a543d56SSyed Saba Kareem adata = dev_get_drvdata(dev);
689198c93e2SVijendar Mukunda if (adata->acp_reset) {
6904b192114Ssyed saba kareem ret = acp63_init(adata->acp63_base, dev);
6913a543d56SSyed Saba Kareem if (ret)
6923a543d56SSyed Saba Kareem dev_err(dev, "ACP init failed\n");
693198c93e2SVijendar Mukunda }
6943a543d56SSyed Saba Kareem return ret;
6953a543d56SSyed Saba Kareem }
6963a543d56SSyed Saba Kareem
6974b192114Ssyed saba kareem static const struct dev_pm_ops acp63_pm_ops = {
6984b192114Ssyed saba kareem SET_RUNTIME_PM_OPS(snd_acp63_suspend, snd_acp63_resume, NULL)
6994b192114Ssyed saba kareem SET_SYSTEM_SLEEP_PM_OPS(snd_acp63_suspend, snd_acp63_resume)
7003a543d56SSyed Saba Kareem };
7013a543d56SSyed Saba Kareem
snd_acp63_remove(struct pci_dev * pci)7024b192114Ssyed saba kareem static void snd_acp63_remove(struct pci_dev *pci)
70395e43a17SSyed Saba Kareem {
7044b192114Ssyed saba kareem struct acp63_dev_data *adata;
705515ee257SSyed Saba Kareem int ret, index;
7069766bb62SSyed Saba Kareem
7079766bb62SSyed Saba Kareem adata = pci_get_drvdata(pci);
7081d325cdaSVijendar Mukunda for (index = 0; index < adata->pdev_count; index++)
709515ee257SSyed Saba Kareem platform_device_unregister(adata->pdev[index]);
7104b192114Ssyed saba kareem ret = acp63_deinit(adata->acp63_base, &pci->dev);
7119766bb62SSyed Saba Kareem if (ret)
7129766bb62SSyed Saba Kareem dev_err(&pci->dev, "ACP de-init failed\n");
7133a543d56SSyed Saba Kareem pm_runtime_forbid(&pci->dev);
7143a543d56SSyed Saba Kareem pm_runtime_get_noresume(&pci->dev);
71595e43a17SSyed Saba Kareem pci_release_regions(pci);
71695e43a17SSyed Saba Kareem pci_disable_device(pci);
71795e43a17SSyed Saba Kareem }
71895e43a17SSyed Saba Kareem
7194b192114Ssyed saba kareem static const struct pci_device_id snd_acp63_ids[] = {
72095e43a17SSyed Saba Kareem { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID),
72195e43a17SSyed Saba Kareem .class = PCI_CLASS_MULTIMEDIA_OTHER << 8,
72295e43a17SSyed Saba Kareem .class_mask = 0xffffff },
72395e43a17SSyed Saba Kareem { 0, },
72495e43a17SSyed Saba Kareem };
7254b192114Ssyed saba kareem MODULE_DEVICE_TABLE(pci, snd_acp63_ids);
72695e43a17SSyed Saba Kareem
7274b192114Ssyed saba kareem static struct pci_driver ps_acp63_driver = {
72895e43a17SSyed Saba Kareem .name = KBUILD_MODNAME,
7294b192114Ssyed saba kareem .id_table = snd_acp63_ids,
7304b192114Ssyed saba kareem .probe = snd_acp63_probe,
7314b192114Ssyed saba kareem .remove = snd_acp63_remove,
7323a543d56SSyed Saba Kareem .driver = {
7334b192114Ssyed saba kareem .pm = &acp63_pm_ops,
7343a543d56SSyed Saba Kareem }
73595e43a17SSyed Saba Kareem };
73695e43a17SSyed Saba Kareem
7374b192114Ssyed saba kareem module_pci_driver(ps_acp63_driver);
73895e43a17SSyed Saba Kareem
73995e43a17SSyed Saba Kareem MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
74095e43a17SSyed Saba Kareem MODULE_AUTHOR("Syed.SabaKareem@amd.com");
74195e43a17SSyed Saba Kareem MODULE_DESCRIPTION("AMD ACP Pink Sardine PCI driver");
74295e43a17SSyed Saba Kareem MODULE_LICENSE("GPL v2");
743