1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oleksij Rempel <linux@rempel-privat.de>
5 * Driver for Alcor Micro AU6601 and AU6621 controllers
8 #include <linux/delay.h>
9 #include <linux/interrupt.h>
11 #include <linux/irq.h>
12 #include <linux/mfd/core.h>
13 #include <linux/module.h>
14 #include <linux/pci.h>
15 #include <linux/platform_device.h>
18 #include <linux/alcor_pci.h>
20 static DEFINE_IDA(alcor_pci_idr
);
22 static struct mfd_cell alcor_pci_cells
[] = {
24 .name
= DRV_NAME_ALCOR_PCI_SDMMC
,
27 .name
= DRV_NAME_ALCOR_PCI_MS
,
31 static const struct alcor_dev_cfg alcor_cfg
= {
35 static const struct alcor_dev_cfg au6621_cfg
= {
39 static const struct alcor_dev_cfg au6625_cfg
= {
43 static const struct pci_device_id pci_ids
[] = {
44 { PCI_DEVICE(PCI_ID_ALCOR_MICRO
, PCI_ID_AU6601
),
45 .driver_data
= (kernel_ulong_t
)&alcor_cfg
},
46 { PCI_DEVICE(PCI_ID_ALCOR_MICRO
, PCI_ID_AU6621
),
47 .driver_data
= (kernel_ulong_t
)&au6621_cfg
},
48 { PCI_DEVICE(PCI_ID_ALCOR_MICRO
, PCI_ID_AU6625
),
49 .driver_data
= (kernel_ulong_t
)&au6625_cfg
},
52 MODULE_DEVICE_TABLE(pci
, pci_ids
);
54 void alcor_write8(struct alcor_pci_priv
*priv
, u8 val
, unsigned int addr
)
56 writeb(val
, priv
->iobase
+ addr
);
58 EXPORT_SYMBOL_GPL(alcor_write8
);
60 void alcor_write16(struct alcor_pci_priv
*priv
, u16 val
, unsigned int addr
)
62 writew(val
, priv
->iobase
+ addr
);
64 EXPORT_SYMBOL_GPL(alcor_write16
);
66 void alcor_write32(struct alcor_pci_priv
*priv
, u32 val
, unsigned int addr
)
68 writel(val
, priv
->iobase
+ addr
);
70 EXPORT_SYMBOL_GPL(alcor_write32
);
72 void alcor_write32be(struct alcor_pci_priv
*priv
, u32 val
, unsigned int addr
)
74 iowrite32be(val
, priv
->iobase
+ addr
);
76 EXPORT_SYMBOL_GPL(alcor_write32be
);
78 u8
alcor_read8(struct alcor_pci_priv
*priv
, unsigned int addr
)
80 return readb(priv
->iobase
+ addr
);
82 EXPORT_SYMBOL_GPL(alcor_read8
);
84 u32
alcor_read32(struct alcor_pci_priv
*priv
, unsigned int addr
)
86 return readl(priv
->iobase
+ addr
);
88 EXPORT_SYMBOL_GPL(alcor_read32
);
90 u32
alcor_read32be(struct alcor_pci_priv
*priv
, unsigned int addr
)
92 return ioread32be(priv
->iobase
+ addr
);
94 EXPORT_SYMBOL_GPL(alcor_read32be
);
96 static int alcor_pci_probe(struct pci_dev
*pdev
,
97 const struct pci_device_id
*ent
)
99 struct alcor_dev_cfg
*cfg
;
100 struct alcor_pci_priv
*priv
;
103 cfg
= (void *)ent
->driver_data
;
105 ret
= pcim_enable_device(pdev
);
109 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
113 ret
= ida_alloc(&alcor_pci_idr
, GFP_KERNEL
);
119 priv
->parent_pdev
= pdev
->bus
->self
;
120 priv
->dev
= &pdev
->dev
;
122 priv
->irq
= pdev
->irq
;
124 ret
= pci_request_regions(pdev
, DRV_NAME_ALCOR_PCI
);
126 dev_err(&pdev
->dev
, "Cannot request region\n");
131 if (!(pci_resource_flags(pdev
, bar
) & IORESOURCE_MEM
)) {
132 dev_err(&pdev
->dev
, "BAR %d is not iomem. Aborting.\n", bar
);
134 goto error_release_regions
;
137 priv
->iobase
= pcim_iomap(pdev
, bar
, 0);
140 goto error_release_regions
;
143 /* make sure irqs are disabled */
144 alcor_write32(priv
, 0, AU6601_REG_INT_ENABLE
);
145 alcor_write32(priv
, 0, AU6601_MS_INT_ENABLE
);
147 ret
= dma_set_mask_and_coherent(priv
->dev
, AU6601_SDMA_MASK
);
149 dev_err(priv
->dev
, "Failed to set DMA mask\n");
150 goto error_release_regions
;
153 pci_set_master(pdev
);
154 pci_set_drvdata(pdev
, priv
);
156 for (i
= 0; i
< ARRAY_SIZE(alcor_pci_cells
); i
++) {
157 alcor_pci_cells
[i
].platform_data
= priv
;
158 alcor_pci_cells
[i
].pdata_size
= sizeof(*priv
);
160 ret
= mfd_add_devices(&pdev
->dev
, priv
->id
, alcor_pci_cells
,
161 ARRAY_SIZE(alcor_pci_cells
), NULL
, 0, NULL
);
163 goto error_clear_drvdata
;
165 pci_disable_link_state(pdev
, PCIE_LINK_STATE_L0S
| PCIE_LINK_STATE_L1
);
170 pci_clear_master(pdev
);
171 pci_set_drvdata(pdev
, NULL
);
172 error_release_regions
:
173 pci_release_regions(pdev
);
175 ida_free(&alcor_pci_idr
, priv
->id
);
179 static void alcor_pci_remove(struct pci_dev
*pdev
)
181 struct alcor_pci_priv
*priv
;
183 priv
= pci_get_drvdata(pdev
);
185 mfd_remove_devices(&pdev
->dev
);
187 ida_free(&alcor_pci_idr
, priv
->id
);
189 pci_release_regions(pdev
);
190 pci_clear_master(pdev
);
191 pci_set_drvdata(pdev
, NULL
);
194 #ifdef CONFIG_PM_SLEEP
195 static int alcor_suspend(struct device
*dev
)
200 static int alcor_resume(struct device
*dev
)
202 struct alcor_pci_priv
*priv
= dev_get_drvdata(dev
);
204 pci_disable_link_state(priv
->pdev
,
205 PCIE_LINK_STATE_L0S
| PCIE_LINK_STATE_L1
);
209 #endif /* CONFIG_PM_SLEEP */
211 static SIMPLE_DEV_PM_OPS(alcor_pci_pm_ops
, alcor_suspend
, alcor_resume
);
213 static struct pci_driver alcor_driver
= {
214 .name
= DRV_NAME_ALCOR_PCI
,
216 .probe
= alcor_pci_probe
,
217 .remove
= alcor_pci_remove
,
219 .pm
= &alcor_pci_pm_ops
223 module_pci_driver(alcor_driver
);
225 MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
226 MODULE_DESCRIPTION("PCI driver for Alcor Micro AU6601 Secure Digital Host Controller Interface");
227 MODULE_LICENSE("GPL");