1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2022 Microchip Technology Inc.
4 #include <linux/mfd/core.h>
5 #include <linux/module.h>
7 #include <linux/spinlock.h>
8 #include <linux/gpio/driver.h>
9 #include <linux/interrupt.h>
11 #include <linux/idr.h>
12 #include "mchp_pci1xxxx_gp.h"
14 struct aux_bus_device
{
15 struct auxiliary_device_wrapper
*aux_device_wrapper
[2];
18 static DEFINE_IDA(gp_client_ida
);
19 static const char aux_dev_otp_e2p_name
[15] = "gp_otp_e2p";
20 static const char aux_dev_gpio_name
[15] = "gp_gpio";
22 static void gp_auxiliary_device_release(struct device
*dev
)
24 struct auxiliary_device_wrapper
*aux_device_wrapper
=
25 (struct auxiliary_device_wrapper
*)container_of(dev
,
26 struct auxiliary_device_wrapper
, aux_dev
.dev
);
28 ida_free(&gp_client_ida
, aux_device_wrapper
->aux_dev
.id
);
29 kfree(aux_device_wrapper
);
32 static int gp_aux_bus_probe(struct pci_dev
*pdev
, const struct pci_device_id
*id
)
34 struct aux_bus_device
*aux_bus
;
37 retval
= pcim_enable_device(pdev
);
41 aux_bus
= devm_kzalloc(&pdev
->dev
, sizeof(*aux_bus
), GFP_KERNEL
);
45 aux_bus
->aux_device_wrapper
[0] = kzalloc(sizeof(*aux_bus
->aux_device_wrapper
[0]),
47 if (!aux_bus
->aux_device_wrapper
[0])
50 retval
= ida_alloc(&gp_client_ida
, GFP_KERNEL
);
54 aux_bus
->aux_device_wrapper
[0]->aux_dev
.name
= aux_dev_otp_e2p_name
;
55 aux_bus
->aux_device_wrapper
[0]->aux_dev
.dev
.parent
= &pdev
->dev
;
56 aux_bus
->aux_device_wrapper
[0]->aux_dev
.dev
.release
= gp_auxiliary_device_release
;
57 aux_bus
->aux_device_wrapper
[0]->aux_dev
.id
= retval
;
59 aux_bus
->aux_device_wrapper
[0]->gp_aux_data
.region_start
= pci_resource_start(pdev
, 0);
60 aux_bus
->aux_device_wrapper
[0]->gp_aux_data
.region_length
= pci_resource_end(pdev
, 0);
62 retval
= auxiliary_device_init(&aux_bus
->aux_device_wrapper
[0]->aux_dev
);
64 goto err_aux_dev_init_0
;
66 retval
= auxiliary_device_add(&aux_bus
->aux_device_wrapper
[0]->aux_dev
);
68 goto err_aux_dev_add_0
;
70 aux_bus
->aux_device_wrapper
[1] = kzalloc(sizeof(*aux_bus
->aux_device_wrapper
[1]),
72 if (!aux_bus
->aux_device_wrapper
[1]) {
74 goto err_aux_dev_add_0
;
77 retval
= ida_alloc(&gp_client_ida
, GFP_KERNEL
);
81 aux_bus
->aux_device_wrapper
[1]->aux_dev
.name
= aux_dev_gpio_name
;
82 aux_bus
->aux_device_wrapper
[1]->aux_dev
.dev
.parent
= &pdev
->dev
;
83 aux_bus
->aux_device_wrapper
[1]->aux_dev
.dev
.release
= gp_auxiliary_device_release
;
84 aux_bus
->aux_device_wrapper
[1]->aux_dev
.id
= retval
;
86 aux_bus
->aux_device_wrapper
[1]->gp_aux_data
.region_start
= pci_resource_start(pdev
, 0);
87 aux_bus
->aux_device_wrapper
[1]->gp_aux_data
.region_length
= pci_resource_end(pdev
, 0);
89 retval
= pci_alloc_irq_vectors(pdev
, 1, 1, PCI_IRQ_ALL_TYPES
);
92 goto err_aux_dev_init_1
;
94 retval
= pci_irq_vector(pdev
, 0);
96 goto err_aux_dev_init_1
;
99 aux_bus
->aux_device_wrapper
[1]->gp_aux_data
.irq_num
= pdev
->irq
;
101 retval
= auxiliary_device_init(&aux_bus
->aux_device_wrapper
[1]->aux_dev
);
103 goto err_aux_dev_init_1
;
105 retval
= auxiliary_device_add(&aux_bus
->aux_device_wrapper
[1]->aux_dev
);
107 goto err_aux_dev_add_1
;
109 pci_set_drvdata(pdev
, aux_bus
);
110 pci_set_master(pdev
);
115 auxiliary_device_uninit(&aux_bus
->aux_device_wrapper
[1]->aux_dev
);
116 goto err_aux_dev_add_0
;
119 ida_free(&gp_client_ida
, aux_bus
->aux_device_wrapper
[1]->aux_dev
.id
);
122 kfree(aux_bus
->aux_device_wrapper
[1]);
125 auxiliary_device_uninit(&aux_bus
->aux_device_wrapper
[0]->aux_dev
);
129 ida_free(&gp_client_ida
, aux_bus
->aux_device_wrapper
[0]->aux_dev
.id
);
132 kfree(aux_bus
->aux_device_wrapper
[0]);
138 static void gp_aux_bus_remove(struct pci_dev
*pdev
)
140 struct aux_bus_device
*aux_bus
= pci_get_drvdata(pdev
);
142 auxiliary_device_delete(&aux_bus
->aux_device_wrapper
[0]->aux_dev
);
143 auxiliary_device_uninit(&aux_bus
->aux_device_wrapper
[0]->aux_dev
);
144 auxiliary_device_delete(&aux_bus
->aux_device_wrapper
[1]->aux_dev
);
145 auxiliary_device_uninit(&aux_bus
->aux_device_wrapper
[1]->aux_dev
);
148 static const struct pci_device_id pci1xxxx_tbl
[] = {
149 { PCI_DEVICE(0x1055, 0xA005) },
150 { PCI_DEVICE(0x1055, 0xA015) },
151 { PCI_DEVICE(0x1055, 0xA025) },
152 { PCI_DEVICE(0x1055, 0xA035) },
153 { PCI_DEVICE(0x1055, 0xA045) },
154 { PCI_DEVICE(0x1055, 0xA055) },
157 MODULE_DEVICE_TABLE(pci
, pci1xxxx_tbl
);
159 static struct pci_driver pci1xxxx_gp_driver
= {
160 .name
= "PCI1xxxxGP",
161 .id_table
= pci1xxxx_tbl
,
162 .probe
= gp_aux_bus_probe
,
163 .remove
= gp_aux_bus_remove
,
166 module_pci_driver(pci1xxxx_gp_driver
);
168 MODULE_DESCRIPTION("Microchip Technology Inc. PCI1xxxx GP expander");
169 MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>");
170 MODULE_LICENSE("GPL");