Skip to content

Commit 393fc2f

Browse files
Kumaravel Thiagarajangregkh
authored andcommitted
misc: microchip: pci1xxxx: load auxiliary bus driver for the PIO function in the multi-function endpoint of pci1xxxx device.
pci1xxxx is a PCIe switch with a multi-function endpoint on one of its downstream ports. PIO function is one of the functions in the multi-function endpoint. PIO function combines a GPIO controller and also an interface to program pci1xxxx's OTP & EEPROM. This auxiliary bus driver is loaded for the PIO function and separate child devices are enumerated for GPIO controller and OTP/EEPROM interface. Signed-off-by: Kumaravel Thiagarajan <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent a68108c commit 393fc2f

File tree

7 files changed

+216
-1
lines changed

7 files changed

+216
-1
lines changed

MAINTAINERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13422,6 +13422,13 @@ S: Supported
1342213422
F: Documentation/devicetree/bindings/mtd/atmel-nand.txt
1342313423
F: drivers/mtd/nand/raw/atmel/*
1342413424

13425+
MICROCHIP PCI1XXXX GP DRIVER
13426+
M: Kumaravel Thiagarajan <[email protected]>
13427+
13428+
S: Supported
13429+
F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c
13430+
F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h
13431+
1342513432
MICROCHIP OTPC DRIVER
1342613433
M: Claudiu Beznea <[email protected]>
1342713434
L: [email protected] (moderated for non-subscribers)

drivers/misc/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,4 +513,5 @@ source "drivers/misc/cardreader/Kconfig"
513513
source "drivers/misc/habanalabs/Kconfig"
514514
source "drivers/misc/uacce/Kconfig"
515515
source "drivers/misc/pvpanic/Kconfig"
516+
source "drivers/misc/mchp_pci1xxxx/Kconfig"
516517
endmenu

drivers/misc/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,5 @@ obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
6060
obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o
6161
obj-$(CONFIG_HI6421V600_IRQ) += hi6421v600-irq.o
6262
obj-$(CONFIG_OPEN_DICE) += open-dice.o
63-
obj-$(CONFIG_VCPU_STALL_DETECTOR) += vcpu_stall_detector.o
63+
obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/
64+
obj-$(CONFIG_VCPU_STALL_DETECTOR) += vcpu_stall_detector.o

drivers/misc/mchp_pci1xxxx/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
config GP_PCI1XXXX
2+
tristate "Microchip PCI1XXXX PCIe to GPIO Expander + OTP/EEPROM manager"
3+
depends on PCI
4+
select GPIOLIB_IRQCHIP
5+
help
6+
PCI1XXXX is a PCIe GEN 3 switch with one of the endpoints having
7+
multiple functions and one of the functions is a GPIO controller
8+
which also has registers to interface with the OTP and EEPROM.
9+
Select yes, no or module here to include or exclude the driver
10+
for the GPIO function.
11+

drivers/misc/mchp_pci1xxxx/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj-$(CONFIG_GP_PCI1XXXX) := mchp_pci1xxxx_gp.o
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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 = kzalloc(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+
return retval;
91+
92+
pdev->irq = pci_irq_vector(pdev, 0);
93+
if (pdev->irq < 0)
94+
return retval;
95+
96+
aux_bus->aux_device_wrapper[1]->gp_aux_data.irq_num = pdev->irq;
97+
98+
retval = auxiliary_device_init(&aux_bus->aux_device_wrapper[1]->aux_dev);
99+
if (retval < 0)
100+
goto err_aux_dev_init_1;
101+
102+
retval = auxiliary_device_add(&aux_bus->aux_device_wrapper[1]->aux_dev);
103+
if (retval)
104+
goto err_aux_dev_add_1;
105+
106+
pci_set_drvdata(pdev, aux_bus);
107+
pci_set_master(pdev);
108+
109+
return 0;
110+
111+
err_aux_dev_add_1:
112+
auxiliary_device_uninit(&aux_bus->aux_device_wrapper[1]->aux_dev);
113+
114+
err_aux_dev_init_1:
115+
ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[1]->aux_dev.id);
116+
117+
err_ida_alloc_1:
118+
kfree(aux_bus->aux_device_wrapper[1]);
119+
120+
err_aux_dev_add_0:
121+
auxiliary_device_uninit(&aux_bus->aux_device_wrapper[0]->aux_dev);
122+
123+
err_aux_dev_init_0:
124+
ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[0]->aux_dev.id);
125+
126+
err_ida_alloc_0:
127+
kfree(aux_bus->aux_device_wrapper[0]);
128+
129+
return retval;
130+
}
131+
132+
static void gp_aux_bus_remove(struct pci_dev *pdev)
133+
{
134+
struct aux_bus_device *aux_bus = pci_get_drvdata(pdev);
135+
136+
auxiliary_device_delete(&aux_bus->aux_device_wrapper[0]->aux_dev);
137+
auxiliary_device_uninit(&aux_bus->aux_device_wrapper[0]->aux_dev);
138+
auxiliary_device_delete(&aux_bus->aux_device_wrapper[1]->aux_dev);
139+
auxiliary_device_uninit(&aux_bus->aux_device_wrapper[1]->aux_dev);
140+
kfree(aux_bus);
141+
pci_disable_device(pdev);
142+
}
143+
144+
static const struct pci_device_id pci1xxxx_tbl[] = {
145+
{ PCI_DEVICE(0x1055, 0xA005) },
146+
{ PCI_DEVICE(0x1055, 0xA015) },
147+
{ PCI_DEVICE(0x1055, 0xA025) },
148+
{ PCI_DEVICE(0x1055, 0xA035) },
149+
{ PCI_DEVICE(0x1055, 0xA045) },
150+
{ PCI_DEVICE(0x1055, 0xA055) },
151+
{0,}
152+
};
153+
MODULE_DEVICE_TABLE(pci, pci1xxxx_tbl);
154+
155+
static struct pci_driver pci1xxxx_gp_driver = {
156+
.name = "PCI1xxxxGP",
157+
.id_table = pci1xxxx_tbl,
158+
.probe = gp_aux_bus_probe,
159+
.remove = gp_aux_bus_remove,
160+
};
161+
162+
module_pci_driver(pci1xxxx_gp_driver);
163+
164+
MODULE_DESCRIPTION("Microchip Technology Inc. PCI1xxxx GP expander");
165+
MODULE_AUTHOR("Kumaravel Thiagarajan <[email protected]>");
166+
MODULE_LICENSE("GPL");
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/* Copyright (C) 2022 Microchip Technology Inc. */
3+
4+
#ifndef _GPIO_PCI1XXXX_H
5+
#define _GPIO_PCI1XXXX_H
6+
7+
#include <linux/spinlock.h>
8+
#include <linux/mutex.h>
9+
#include <linux/kthread.h>
10+
#include <linux/types.h>
11+
#include <linux/auxiliary_bus.h>
12+
13+
/* Perform operations like variable length write, read and write with read back for OTP / EEPROM
14+
* Perform bit mode write in OTP
15+
*/
16+
17+
struct gp_aux_data_type {
18+
int irq_num;
19+
resource_size_t region_start;
20+
resource_size_t region_length;
21+
};
22+
23+
struct auxiliary_device_wrapper {
24+
struct auxiliary_device aux_dev;
25+
struct gp_aux_data_type gp_aux_data;
26+
};
27+
28+
#endif

0 commit comments

Comments
 (0)