arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / drivers / misc / mchp_pci1xxxx / mchp_pci1xxxx_gp.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2022 Microchip Technology Inc.
3
4 #include <linux/mfd/core.h>
5 #include <linux/module.h>
6 #include <linux/pci.h>
7 #include <linux/spinlock.h>
8 #include <linux/gpio/driver.h>
9 #include <linux/interrupt.h>
10 #include <linux/io.h>
11 #include <linux/idr.h>
12 #include "mchp_pci1xxxx_gp.h"
13
14 struct aux_bus_device {
15         struct auxiliary_device_wrapper *aux_device_wrapper[2];
16 };
17
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";
21
22 static void gp_auxiliary_device_release(struct device *dev)
23 {
24         struct auxiliary_device_wrapper *aux_device_wrapper =
25                 (struct auxiliary_device_wrapper *)container_of(dev,
26                                 struct auxiliary_device_wrapper, aux_dev.dev);
27
28         ida_free(&gp_client_ida, aux_device_wrapper->aux_dev.id);
29         kfree(aux_device_wrapper);
30 }
31
32 static int gp_aux_bus_probe(struct pci_dev *pdev, const struct pci_device_id *id)
33 {
34         struct aux_bus_device *aux_bus;
35         int retval;
36
37         retval = pcim_enable_device(pdev);
38         if (retval)
39                 return retval;
40
41         aux_bus = devm_kzalloc(&pdev->dev, sizeof(*aux_bus), GFP_KERNEL);
42         if (!aux_bus)
43                 return -ENOMEM;
44
45         aux_bus->aux_device_wrapper[0] = kzalloc(sizeof(*aux_bus->aux_device_wrapper[0]),
46                                                  GFP_KERNEL);
47         if (!aux_bus->aux_device_wrapper[0])
48                 return -ENOMEM;
49
50         retval = ida_alloc(&gp_client_ida, GFP_KERNEL);
51         if (retval < 0)
52                 goto err_ida_alloc_0;
53
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;
58
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);
61
62         retval = auxiliary_device_init(&aux_bus->aux_device_wrapper[0]->aux_dev);
63         if (retval < 0)
64                 goto err_aux_dev_init_0;
65
66         retval = auxiliary_device_add(&aux_bus->aux_device_wrapper[0]->aux_dev);
67         if (retval)
68                 goto err_aux_dev_add_0;
69
70         aux_bus->aux_device_wrapper[1] = kzalloc(sizeof(*aux_bus->aux_device_wrapper[1]),
71                                                  GFP_KERNEL);
72         if (!aux_bus->aux_device_wrapper[1])
73                 return -ENOMEM;
74
75         retval = ida_alloc(&gp_client_ida, GFP_KERNEL);
76         if (retval < 0)
77                 goto err_ida_alloc_1;
78
79         aux_bus->aux_device_wrapper[1]->aux_dev.name = aux_dev_gpio_name;
80         aux_bus->aux_device_wrapper[1]->aux_dev.dev.parent = &pdev->dev;
81         aux_bus->aux_device_wrapper[1]->aux_dev.dev.release = gp_auxiliary_device_release;
82         aux_bus->aux_device_wrapper[1]->aux_dev.id = retval;
83
84         aux_bus->aux_device_wrapper[1]->gp_aux_data.region_start = pci_resource_start(pdev, 0);
85         aux_bus->aux_device_wrapper[1]->gp_aux_data.region_length = pci_resource_end(pdev, 0);
86
87         retval = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
88
89         if (retval < 0)
90                 goto err_aux_dev_init_1;
91
92         retval = pci_irq_vector(pdev, 0);
93         if (retval < 0)
94                 goto err_aux_dev_init_1;
95
96         pdev->irq = retval;
97         aux_bus->aux_device_wrapper[1]->gp_aux_data.irq_num = pdev->irq;
98
99         retval = auxiliary_device_init(&aux_bus->aux_device_wrapper[1]->aux_dev);
100         if (retval < 0)
101                 goto err_aux_dev_init_1;
102
103         retval = auxiliary_device_add(&aux_bus->aux_device_wrapper[1]->aux_dev);
104         if (retval)
105                 goto err_aux_dev_add_1;
106
107         pci_set_drvdata(pdev, aux_bus);
108         pci_set_master(pdev);
109
110         return 0;
111
112 err_aux_dev_add_1:
113         auxiliary_device_uninit(&aux_bus->aux_device_wrapper[1]->aux_dev);
114
115 err_aux_dev_init_1:
116         ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[1]->aux_dev.id);
117
118 err_ida_alloc_1:
119         kfree(aux_bus->aux_device_wrapper[1]);
120
121 err_aux_dev_add_0:
122         auxiliary_device_uninit(&aux_bus->aux_device_wrapper[0]->aux_dev);
123
124 err_aux_dev_init_0:
125         ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[0]->aux_dev.id);
126
127 err_ida_alloc_0:
128         kfree(aux_bus->aux_device_wrapper[0]);
129
130         return retval;
131 }
132
133 static void gp_aux_bus_remove(struct pci_dev *pdev)
134 {
135         struct aux_bus_device *aux_bus = pci_get_drvdata(pdev);
136
137         auxiliary_device_delete(&aux_bus->aux_device_wrapper[0]->aux_dev);
138         auxiliary_device_uninit(&aux_bus->aux_device_wrapper[0]->aux_dev);
139         auxiliary_device_delete(&aux_bus->aux_device_wrapper[1]->aux_dev);
140         auxiliary_device_uninit(&aux_bus->aux_device_wrapper[1]->aux_dev);
141 }
142
143 static const struct pci_device_id pci1xxxx_tbl[] = {
144         { PCI_DEVICE(0x1055, 0xA005) },
145         { PCI_DEVICE(0x1055, 0xA015) },
146         { PCI_DEVICE(0x1055, 0xA025) },
147         { PCI_DEVICE(0x1055, 0xA035) },
148         { PCI_DEVICE(0x1055, 0xA045) },
149         { PCI_DEVICE(0x1055, 0xA055) },
150         {0,}
151 };
152 MODULE_DEVICE_TABLE(pci, pci1xxxx_tbl);
153
154 static struct pci_driver pci1xxxx_gp_driver = {
155         .name = "PCI1xxxxGP",
156         .id_table = pci1xxxx_tbl,
157         .probe = gp_aux_bus_probe,
158         .remove = gp_aux_bus_remove,
159 };
160
161 module_pci_driver(pci1xxxx_gp_driver);
162
163 MODULE_DESCRIPTION("Microchip Technology Inc. PCI1xxxx GP expander");
164 MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>");
165 MODULE_LICENSE("GPL");