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'x OTP & EEPROM. This patch adds an
auxiliary bus driver that enumerates separate child devices for gpio and
OTP/EEPROM interface and the gpio controller driver for the first child.
Kumaravel Thiagarajan (5):
misc: microchip: pci1xxxx: load auxiliary bus driver for the PIO
function in the multi-function endpoint of pci1xxxx device.
misc: microchip: pci1xxxx: load gpio driver for the gpio controller
auxiliary device enumerated by the auxiliary bus driver.
misc: microchip: pci1xxxx: Add functions to configure gpio pins as
input / output, get status, handle I/O for gpio pins.
misc: microchip: pci1xxxx: Add gpio irq handler and irq helper
functions irq_ack, irq_mask, irq_unmask and irq_set_type of
irq_chip.
misc: microchip: pci1xxxx: Add power management functions - suspend &
resume handlers.
MAINTAINERS | 9 +
drivers/misc/Kconfig | 1 +
drivers/misc/Makefile | 3 +-
drivers/misc/mchp_pci1xxxx/Kconfig | 10 +
drivers/misc/mchp_pci1xxxx/Makefile | 1 +
drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c | 167 +++++++
drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h | 28 ++
.../misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c | 438 ++++++++++++++++++
8 files changed, 656 insertions(+), 1 deletion(-)
create mode 100644 drivers/misc/mchp_pci1xxxx/Kconfig
create mode 100644 drivers/misc/mchp_pci1xxxx/Makefile
create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c
create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h
create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
--
2.25.1
direction_input and direction_output functions configures a gpio pin as
input and output respectively. get_direction function returns if a gpio
pin is output or input. get function returns the value of a gpio pin
whereas set function assigns output value for a gpio pin.
Signed-off-by: Kumaravel Thiagarajan <[email protected]>
---
.../misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c | 79 +++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
index f2e3b3794ba3..ff94b0f239c7 100644
--- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
+++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
@@ -13,6 +13,10 @@
#include "mchp_pci1xxxx_gp.h"
#define PCI1XXXX_NR_PINS 93
+#define OUT_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400)
+#define INP_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x10)
+#define OUT_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x20)
+#define INP_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x30)
#define PULLUP_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x40)
#define PULLDOWN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x50)
#define OPENDRAIN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x60)
@@ -30,6 +34,24 @@ struct pci1xxxx_gpio {
int irq_base;
};
+static int pci1xxxx_gpio_get_direction(struct gpio_chip *gpio, unsigned int nr)
+{
+ struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);
+ u32 data;
+ int ret = -EINVAL;
+
+ data = readl(priv->reg_base + INP_EN_OFFSET(nr));
+ if (data & BIT(nr % 32)) {
+ ret = 1;
+ } else {
+ data = readl(priv->reg_base + OUT_EN_OFFSET(nr));
+ if (data & BIT(nr % 32))
+ ret = 0;
+ }
+
+ return ret;
+}
+
static inline void pci1xxx_assign_bit(void __iomem *base_addr, unsigned int reg_offset,
unsigned int bitpos, bool set)
{
@@ -43,6 +65,58 @@ static inline void pci1xxx_assign_bit(void __iomem *base_addr, unsigned int reg_
writel(data, base_addr + reg_offset);
}
+static int pci1xxxx_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
+{
+ struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pci1xxx_assign_bit(priv->reg_base, INP_EN_OFFSET(nr), (nr % 32), true);
+ pci1xxx_assign_bit(priv->reg_base, OUT_EN_OFFSET(nr), (nr % 32), false);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int pci1xxxx_gpio_get(struct gpio_chip *gpio, unsigned int nr)
+{
+ struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);
+
+ return (readl(priv->reg_base + INP_OFFSET(nr)) >> (nr % 32)) & 1;
+}
+
+static int pci1xxxx_gpio_direction_output(struct gpio_chip *gpio,
+ unsigned int nr, int val)
+{
+ struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);
+ unsigned long flags;
+ u32 data;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pci1xxx_assign_bit(priv->reg_base, INP_EN_OFFSET(nr), (nr % 32), false);
+ pci1xxx_assign_bit(priv->reg_base, OUT_EN_OFFSET(nr), (nr % 32), true);
+ data = readl(priv->reg_base + OUT_OFFSET(nr));
+ if (val)
+ data |= (1 << (nr % 32));
+ else
+ data &= ~(1 << (nr % 32));
+ writel(data, priv->reg_base + OUT_OFFSET(nr));
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static void pci1xxxx_gpio_set(struct gpio_chip *gpio,
+ unsigned int nr, int val)
+{
+ struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pci1xxx_assign_bit(priv->reg_base, OUT_OFFSET(nr), (nr % 32), val);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
static int pci1xxxx_gpio_set_config(struct gpio_chip *gpio, unsigned int offset,
unsigned long config)
{
@@ -81,6 +155,11 @@ static int pci1xxxx_gpio_setup(struct pci1xxxx_gpio *priv, int irq)
gchip->label = dev_name(&priv->aux_dev->dev);
gchip->parent = &priv->aux_dev->dev;
gchip->owner = THIS_MODULE;
+ gchip->direction_input = pci1xxxx_gpio_direction_input;
+ gchip->direction_output = pci1xxxx_gpio_direction_output;
+ gchip->get_direction = pci1xxxx_gpio_get_direction;
+ gchip->get = pci1xxxx_gpio_get;
+ gchip->set = pci1xxxx_gpio_set;
gchip->set_config = pci1xxxx_gpio_set_config;
gchip->dbg_show = NULL;
gchip->base = -1;
--
2.25.1
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]>
---
MAINTAINERS | 8 +
drivers/misc/Kconfig | 1 +
drivers/misc/Makefile | 3 +-
drivers/misc/mchp_pci1xxxx/Kconfig | 10 ++
drivers/misc/mchp_pci1xxxx/Makefile | 1 +
drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c | 167 ++++++++++++++++++
drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h | 28 +++
7 files changed, 217 insertions(+), 1 deletion(-)
create mode 100644 drivers/misc/mchp_pci1xxxx/Kconfig
create mode 100644 drivers/misc/mchp_pci1xxxx/Makefile
create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c
create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 285ffe0df5cf..ba491e4fc35f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13244,6 +13244,14 @@ S: Supported
F: Documentation/devicetree/bindings/mtd/atmel-nand.txt
F: drivers/mtd/nand/raw/atmel/*
+MICROCHIP PCI1XXXX GP DRIVER
+M: Kumaravel Thiagarajan <[email protected]>
+M: [email protected]
+L: [email protected]
+S: Supported
+F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c
+F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h
+
MICROCHIP OTPC DRIVER
M: Claudiu Beznea <[email protected]>
L: [email protected] (moderated for non-subscribers)
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 94e9fb4cdd76..358ad56f6524 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -513,4 +513,5 @@ source "drivers/misc/cardreader/Kconfig"
source "drivers/misc/habanalabs/Kconfig"
source "drivers/misc/uacce/Kconfig"
source "drivers/misc/pvpanic/Kconfig"
+source "drivers/misc/mchp_pci1xxxx/Kconfig"
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2be8542616dd..ac9b3e757ba1 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -60,4 +60,5 @@ obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o
obj-$(CONFIG_HI6421V600_IRQ) += hi6421v600-irq.o
obj-$(CONFIG_OPEN_DICE) += open-dice.o
-obj-$(CONFIG_VCPU_STALL_DETECTOR) += vcpu_stall_detector.o
\ No newline at end of file
+obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/
+obj-$(CONFIG_VCPU_STALL_DETECTOR) += vcpu_stall_detector.o
diff --git a/drivers/misc/mchp_pci1xxxx/Kconfig b/drivers/misc/mchp_pci1xxxx/Kconfig
new file mode 100644
index 000000000000..387a88addfb0
--- /dev/null
+++ b/drivers/misc/mchp_pci1xxxx/Kconfig
@@ -0,0 +1,10 @@
+config GP_PCI1XXXX
+ tristate "Microchip PCI1XXXX PCIe to GPIO Expander + OTP/EEPROM manager"
+ select GPIOLIB_IRQCHIP
+ help
+ PCI1XXXX is a PCIe GEN 3 switch with one of the endpoints having
+ multiple functions and one of the functions is a GPIO controller
+ which also has registers to interface with the OTP and EEPROM.
+ Select yes, no or module here to include or exclude the driver
+ for the GPIO function.
+
diff --git a/drivers/misc/mchp_pci1xxxx/Makefile b/drivers/misc/mchp_pci1xxxx/Makefile
new file mode 100644
index 000000000000..23927ab251c4
--- /dev/null
+++ b/drivers/misc/mchp_pci1xxxx/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_GP_PCI1XXXX) := mchp_pci1xxxx_gp.o
diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c
new file mode 100644
index 000000000000..577f0fb456de
--- /dev/null
+++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (C) 2022 Microchip Technology Inc.
+
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/idr.h>
+#include "mchp_pci1xxxx_gp.h"
+
+struct aux_bus_device {
+ struct auxiliary_device_wrapper *aux_device_wrapper[2];
+};
+
+DEFINE_IDA(gp_client_ida);
+static const char aux_dev_otp_e2p_name[15] = "gp_otp_e2p";
+static const char aux_dev_gpio_name[15] = "gp_gpio";
+
+static void gp_auxiliary_device_release(struct device *dev)
+{
+ struct auxiliary_device_wrapper *aux_device_wrapper =
+ (struct auxiliary_device_wrapper *)container_of(dev,
+ struct auxiliary_device_wrapper, aux_dev.dev);
+
+ ida_free(&gp_client_ida, aux_device_wrapper->aux_dev.id);
+ kfree(aux_device_wrapper);
+}
+
+static int gp_aux_bus_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct aux_bus_device *aux_bus;
+ int retval;
+
+ retval = pcim_enable_device(pdev);
+ if (retval)
+ return retval;
+
+ aux_bus = kzalloc(sizeof(*aux_bus), GFP_KERNEL);
+ if (!aux_bus)
+ return -ENOMEM;
+
+ aux_bus->aux_device_wrapper[0] = kzalloc(sizeof(*aux_bus->aux_device_wrapper[0]),
+ GFP_KERNEL);
+ if (!aux_bus->aux_device_wrapper[0])
+ return -ENOMEM;
+
+ retval = ida_alloc(&gp_client_ida, GFP_KERNEL);
+ if (retval < 0)
+ goto err_ida_alloc_0;
+
+ aux_bus->aux_device_wrapper[0]->aux_dev.name = aux_dev_otp_e2p_name;
+ aux_bus->aux_device_wrapper[0]->aux_dev.dev.parent = &pdev->dev;
+ aux_bus->aux_device_wrapper[0]->aux_dev.dev.release = gp_auxiliary_device_release;
+ aux_bus->aux_device_wrapper[0]->aux_dev.id = retval;
+
+ aux_bus->aux_device_wrapper[0]->gp_aux_data.region_start = pci_resource_start(pdev, 0);
+ aux_bus->aux_device_wrapper[0]->gp_aux_data.region_length = pci_resource_end(pdev, 0);
+
+ retval = auxiliary_device_init(&aux_bus->aux_device_wrapper[0]->aux_dev);
+ if (retval < 0)
+ goto err_aux_dev_init_0;
+
+ retval = auxiliary_device_add(&aux_bus->aux_device_wrapper[0]->aux_dev);
+ if (retval)
+ goto err_aux_dev_add_0;
+
+ aux_bus->aux_device_wrapper[1] = kzalloc(sizeof(*aux_bus->aux_device_wrapper[1]),
+ GFP_KERNEL);
+ if (!aux_bus->aux_device_wrapper[1])
+ return -ENOMEM;
+
+ retval = ida_alloc(&gp_client_ida, GFP_KERNEL);
+ if (retval < 0)
+ goto err_ida_alloc_1;
+
+
+ aux_bus->aux_device_wrapper[1]->aux_dev.name = aux_dev_gpio_name;
+ aux_bus->aux_device_wrapper[1]->aux_dev.dev.parent = &pdev->dev;
+ aux_bus->aux_device_wrapper[1]->aux_dev.dev.release = gp_auxiliary_device_release;
+ aux_bus->aux_device_wrapper[1]->aux_dev.id = retval;
+
+ aux_bus->aux_device_wrapper[1]->gp_aux_data.region_start = pci_resource_start(pdev, 0);
+ aux_bus->aux_device_wrapper[1]->gp_aux_data.region_length = pci_resource_end(pdev, 0);
+
+ retval = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+
+ if (retval < 0)
+ return retval;
+
+ pdev->irq = pci_irq_vector(pdev, 0);
+ if (pdev->irq < 0)
+ return retval;
+
+ aux_bus->aux_device_wrapper[1]->gp_aux_data.irq_num = pdev->irq;
+
+ retval = auxiliary_device_init(&aux_bus->aux_device_wrapper[1]->aux_dev);
+ if (retval < 0)
+ goto err_aux_dev_init_1;
+
+ retval = auxiliary_device_add(&aux_bus->aux_device_wrapper[1]->aux_dev);
+ if (retval)
+ goto err_aux_dev_add_1;
+
+ pci_set_drvdata(pdev, aux_bus);
+ pci_set_master(pdev);
+
+ return 0;
+
+err_aux_dev_add_1:
+ auxiliary_device_uninit(&aux_bus->aux_device_wrapper[1]->aux_dev);
+
+err_aux_dev_init_1:
+ ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[1]->aux_dev.id);
+
+err_ida_alloc_1:
+ kfree(aux_bus->aux_device_wrapper[1]);
+
+err_aux_dev_add_0:
+ auxiliary_device_uninit(&aux_bus->aux_device_wrapper[0]->aux_dev);
+
+err_aux_dev_init_0:
+ ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[0]->aux_dev.id);
+
+err_ida_alloc_0:
+ kfree(aux_bus->aux_device_wrapper[0]);
+
+ return retval;
+}
+
+static void gp_aux_bus_remove(struct pci_dev *pdev)
+{
+ struct aux_bus_device *aux_bus = pci_get_drvdata(pdev);
+
+ auxiliary_device_delete(&aux_bus->aux_device_wrapper[0]->aux_dev);
+ auxiliary_device_uninit(&aux_bus->aux_device_wrapper[0]->aux_dev);
+ auxiliary_device_delete(&aux_bus->aux_device_wrapper[1]->aux_dev);
+ auxiliary_device_uninit(&aux_bus->aux_device_wrapper[1]->aux_dev);
+ kfree(aux_bus);
+ pci_disable_device(pdev);
+}
+
+static const struct pci_device_id pci1xxxx_tbl[] = {
+ { PCI_DEVICE(0x1055, 0xA005) },
+ { PCI_DEVICE(0x1055, 0xA015) },
+ { PCI_DEVICE(0x1055, 0xA025) },
+ { PCI_DEVICE(0x1055, 0xA035) },
+ { PCI_DEVICE(0x1055, 0xA045) },
+ { PCI_DEVICE(0x1055, 0xA055) },
+ {0,}
+};
+MODULE_DEVICE_TABLE(pci, pci1xxxx_tbl);
+
+static struct pci_driver pci1xxxx_gp_driver = {
+ .name = "PCI1xxxxGP",
+ .id_table = pci1xxxx_tbl,
+ .probe = gp_aux_bus_probe,
+ .remove = gp_aux_bus_remove,
+};
+
+module_pci_driver(pci1xxxx_gp_driver);
+
+MODULE_DESCRIPTION("Microchip Technology Inc. PCI1xxxx GP expander");
+MODULE_AUTHOR("Kumaravel Thiagarajan <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h
new file mode 100644
index 000000000000..ee6ba118a12c
--- /dev/null
+++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2022 Microchip Technology Inc. */
+
+#ifndef _GPIO_PCI1XXXX_H
+#define _GPIO_PCI1XXXX_H
+
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/auxiliary_bus.h>
+
+/* Perform operations like variable length write, read and write with read back for OTP / EEPROM
+ * Perform bit mode write in OTP
+ */
+
+struct gp_aux_data_type {
+ int irq_num;
+ resource_size_t region_start;
+ resource_size_t region_length;
+};
+
+struct auxiliary_device_wrapper {
+ struct auxiliary_device aux_dev;
+ struct gp_aux_data_type gp_aux_data;
+};
+
+#endif
--
2.25.1
The helper functions irq_set_type, irq_mask, irq_unmask and
irq_ack configure the interrupt type, mask, unmask and
acknowledge the interrupts.
Signed-off-by: Kumaravel Thiagarajan <[email protected]>
---
.../misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c | 159 ++++++++++++++++++
1 file changed, 159 insertions(+)
diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
index ff94b0f239c7..c58d27407c4d 100644
--- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
+++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
@@ -9,6 +9,7 @@
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/kthread.h>
+#include <linux/interrupt.h>
#include "mchp_pci1xxxx_gp.h"
@@ -20,6 +21,13 @@
#define PULLUP_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x40)
#define PULLDOWN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x50)
#define OPENDRAIN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x60)
+#define WAKEMASK_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x70)
+#define MODE_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x80)
+#define INTR_LO_TO_HI_EDGE_CONFIG(x) ((((x) / 32) * 4) + 0x400 + 0x90)
+#define INTR_HI_TO_LO_EDGE_CONFIG(x) ((((x) / 32) * 4) + 0x400 + 0xA0)
+#define INTR_LEVEL_CONFIG_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0xB0)
+#define INTR_LEVEL_MASK_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0xC0)
+#define INTR_STAT_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0xD0)
#define DEBOUNCE_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0xE0)
#define PIO_GLOBAL_CONFIG_OFFSET (0x400 + 0xF0)
#define PIO_PCI_CTRL_REG_OFFSET (0x400 + 0xF4)
@@ -148,9 +156,146 @@ static int pci1xxxx_gpio_set_config(struct gpio_chip *gpio, unsigned int offset,
return ret;
}
+static void pci1xxxx_gpio_irq_ack(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct pci1xxxx_gpio *priv = gpiochip_get_data(chip);
+ unsigned int gpio = irqd_to_hwirq(data);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pci1xxx_assign_bit(priv->reg_base, INTR_STAT_OFFSET(gpio), (gpio % 32), true);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void pci1xxxx_gpio_irq_set_mask(struct irq_data *data, bool set)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct pci1xxxx_gpio *priv = gpiochip_get_data(chip);
+ unsigned int gpio = irqd_to_hwirq(data);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pci1xxx_assign_bit(priv->reg_base, INTR_MASK_OFFSET(gpio), (gpio % 32), set);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void pci1xxxx_gpio_irq_mask(struct irq_data *data)
+{
+ pci1xxxx_gpio_irq_set_mask(data, true);
+}
+
+static void pci1xxxx_gpio_irq_unmask(struct irq_data *data)
+{
+ pci1xxxx_gpio_irq_set_mask(data, false);
+}
+
+static int pci1xxxx_gpio_set_type(struct irq_data *data, unsigned int trigger_type)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct pci1xxxx_gpio *priv = gpiochip_get_data(chip);
+ unsigned int gpio = irqd_to_hwirq(data);
+ unsigned int bitpos = gpio % 32;
+
+ if (trigger_type & IRQ_TYPE_EDGE_FALLING) {
+ pci1xxx_assign_bit(priv->reg_base, INTR_HI_TO_LO_EDGE_CONFIG(gpio),
+ bitpos, false);
+ pci1xxx_assign_bit(priv->reg_base, MODE_OFFSET(gpio),
+ bitpos, false);
+ irq_set_handler_locked(data, handle_edge_irq);
+ } else {
+ pci1xxx_assign_bit(priv->reg_base, INTR_HI_TO_LO_EDGE_CONFIG(gpio),
+ bitpos, true);
+ }
+
+ if (trigger_type & IRQ_TYPE_EDGE_RISING) {
+ pci1xxx_assign_bit(priv->reg_base, INTR_LO_TO_HI_EDGE_CONFIG(gpio),
+ bitpos, false);
+ pci1xxx_assign_bit(priv->reg_base, MODE_OFFSET(gpio), bitpos,
+ false);
+ irq_set_handler_locked(data, handle_edge_irq);
+ } else {
+ pci1xxx_assign_bit(priv->reg_base, INTR_LO_TO_HI_EDGE_CONFIG(gpio),
+ bitpos, true);
+ }
+
+ if (trigger_type & IRQ_TYPE_LEVEL_LOW) {
+ pci1xxx_assign_bit(priv->reg_base, INTR_LEVEL_CONFIG_OFFSET(gpio),
+ bitpos, true);
+ pci1xxx_assign_bit(priv->reg_base, INTR_LEVEL_MASK_OFFSET(gpio),
+ bitpos, false);
+ pci1xxx_assign_bit(priv->reg_base, MODE_OFFSET(gpio), bitpos,
+ true);
+ irq_set_handler_locked(data, handle_edge_irq);
+ }
+
+ if (trigger_type & IRQ_TYPE_LEVEL_HIGH) {
+ pci1xxx_assign_bit(priv->reg_base, INTR_LEVEL_CONFIG_OFFSET(gpio),
+ bitpos, false);
+ pci1xxx_assign_bit(priv->reg_base, INTR_LEVEL_MASK_OFFSET(gpio),
+ bitpos, false);
+ pci1xxx_assign_bit(priv->reg_base, MODE_OFFSET(gpio), bitpos,
+ true);
+ irq_set_handler_locked(data, handle_edge_irq);
+ }
+
+ if ((!(trigger_type & IRQ_TYPE_LEVEL_LOW)) && (!(trigger_type & IRQ_TYPE_LEVEL_HIGH)))
+ pci1xxx_assign_bit(priv->reg_base, INTR_LEVEL_MASK_OFFSET(gpio), bitpos, true);
+
+ return true;
+}
+
+static irqreturn_t pci1xxxx_gpio_irq_handler(int irq, void *dev_id)
+{
+ struct pci1xxxx_gpio *priv = dev_id;
+ struct gpio_chip *gc = &priv->gpio;
+ unsigned long int_status = 0;
+ unsigned long flags;
+ u8 pincount;
+ int bit;
+ u8 gpiobank;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, 16, true);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ for (gpiobank = 0; gpiobank < 3; gpiobank++) {
+ spin_lock_irqsave(&priv->lock, flags);
+ int_status = readl(priv->reg_base + INTR_STATUS_OFFSET(gpiobank));
+ spin_unlock_irqrestore(&priv->lock, flags);
+ if (gpiobank == 2)
+ pincount = 29;
+ else
+ pincount = 32;
+ for_each_set_bit(bit, &int_status, pincount) {
+ unsigned int irq;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ writel(BIT(bit), priv->reg_base + INTR_STATUS_OFFSET(gpiobank));
+ spin_unlock_irqrestore(&priv->lock, flags);
+ irq = irq_find_mapping(gc->irq.domain, (bit + (gpiobank * 32)));
+ generic_handle_irq(irq);
+ }
+ }
+ spin_lock_irqsave(&priv->lock, flags);
+ pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, 16, false);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static struct irq_chip pci1xxxx_gpio_irqchip = {
+ .name = "pci1xxxx_gpio",
+ .irq_ack = pci1xxxx_gpio_irq_ack,
+ .irq_mask = pci1xxxx_gpio_irq_mask,
+ .irq_unmask = pci1xxxx_gpio_irq_unmask,
+ .irq_set_type = pci1xxxx_gpio_set_type,
+};
+
static int pci1xxxx_gpio_setup(struct pci1xxxx_gpio *priv, int irq)
{
struct gpio_chip *gchip = &priv->gpio;
+ struct gpio_irq_chip *girq;
+ int retval;
gchip->label = dev_name(&priv->aux_dev->dev);
gchip->parent = &priv->aux_dev->dev;
@@ -166,6 +311,20 @@ static int pci1xxxx_gpio_setup(struct pci1xxxx_gpio *priv, int irq)
gchip->ngpio = PCI1XXXX_NR_PINS;
gchip->can_sleep = false;
+ retval = devm_request_threaded_irq(&priv->aux_dev->dev, irq,
+ NULL, pci1xxxx_gpio_irq_handler,
+ IRQF_ONESHOT, "PCI1xxxxGPIO", priv);
+
+ if (retval)
+ return retval;
+
+ girq = &priv->gpio.irq;
+ girq->chip = &pci1xxxx_gpio_irqchip;
+ girq->parent_handler = NULL;
+ girq->num_parents = 0;
+ girq->parents = NULL;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
return 0;
}
--
2.25.1
PIO function's auxiliary bus driver enumerates separate child devices for
GPIO controller and OTP/EEPROM interface. This gpio driver implemented
based on the gpio framework is loaded for the gpio auxiliary device.
Signed-off-by: Kumaravel Thiagarajan <[email protected]>
---
MAINTAINERS | 1 +
drivers/misc/mchp_pci1xxxx/Makefile | 2 +-
.../misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c | 163 ++++++++++++++++++
3 files changed, 165 insertions(+), 1 deletion(-)
create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
diff --git a/MAINTAINERS b/MAINTAINERS
index ba491e4fc35f..cc4b6b4c2b9a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13251,6 +13251,7 @@ L: [email protected]
S: Supported
F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c
F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h
+F: drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
MICROCHIP OTPC DRIVER
M: Claudiu Beznea <[email protected]>
diff --git a/drivers/misc/mchp_pci1xxxx/Makefile b/drivers/misc/mchp_pci1xxxx/Makefile
index 23927ab251c4..fc4615cfe28b 100644
--- a/drivers/misc/mchp_pci1xxxx/Makefile
+++ b/drivers/misc/mchp_pci1xxxx/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_GP_PCI1XXXX) := mchp_pci1xxxx_gp.o
+obj-$(CONFIG_GP_PCI1XXXX) := mchp_pci1xxxx_gp.o mchp_pci1xxxx_gpio.o
diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
new file mode 100644
index 000000000000..f2e3b3794ba3
--- /dev/null
+++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (C) 2022 Microchip Technology Inc.
+// pci1xxxx gpio driver
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/gpio/driver.h>
+#include <linux/bio.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+
+#include "mchp_pci1xxxx_gp.h"
+
+#define PCI1XXXX_NR_PINS 93
+#define PULLUP_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x40)
+#define PULLDOWN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x50)
+#define OPENDRAIN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x60)
+#define DEBOUNCE_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0xE0)
+#define PIO_GLOBAL_CONFIG_OFFSET (0x400 + 0xF0)
+#define PIO_PCI_CTRL_REG_OFFSET (0x400 + 0xF4)
+#define INTR_MASK_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x100)
+#define INTR_STATUS_OFFSET(x) (((x) * 4) + 0x400 + 0xD0)
+
+struct pci1xxxx_gpio {
+ struct auxiliary_device *aux_dev;
+ void __iomem *reg_base;
+ struct gpio_chip gpio;
+ spinlock_t lock;
+ int irq_base;
+};
+
+static inline void pci1xxx_assign_bit(void __iomem *base_addr, unsigned int reg_offset,
+ unsigned int bitpos, bool set)
+{
+ u32 data;
+
+ data = readl(base_addr + reg_offset);
+ if (set)
+ data |= BIT(bitpos);
+ else
+ data &= ~BIT(bitpos);
+ writel(data, base_addr + reg_offset);
+}
+
+static int pci1xxxx_gpio_set_config(struct gpio_chip *gpio, unsigned int offset,
+ unsigned long config)
+{
+ struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_BIAS_PULL_UP:
+ pci1xxx_assign_bit(priv->reg_base, PULLUP_OFFSET(offset), (offset % 32), true);
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ pci1xxx_assign_bit(priv->reg_base, PULLDOWN_OFFSET(offset), (offset % 32), true);
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ pci1xxx_assign_bit(priv->reg_base, PULLUP_OFFSET(offset), (offset % 32), false);
+ pci1xxx_assign_bit(priv->reg_base, PULLDOWN_OFFSET(offset), (offset % 32), false);
+ break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ pci1xxx_assign_bit(priv->reg_base, OPENDRAIN_OFFSET(offset), (offset % 32), true);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return ret;
+}
+
+static int pci1xxxx_gpio_setup(struct pci1xxxx_gpio *priv, int irq)
+{
+ struct gpio_chip *gchip = &priv->gpio;
+
+ gchip->label = dev_name(&priv->aux_dev->dev);
+ gchip->parent = &priv->aux_dev->dev;
+ gchip->owner = THIS_MODULE;
+ gchip->set_config = pci1xxxx_gpio_set_config;
+ gchip->dbg_show = NULL;
+ gchip->base = -1;
+ gchip->ngpio = PCI1XXXX_NR_PINS;
+ gchip->can_sleep = false;
+
+ return 0;
+}
+
+static int pci1xxxx_gpio_probe(struct auxiliary_device *aux_dev,
+ const struct auxiliary_device_id *id)
+
+{
+ struct auxiliary_device_wrapper *aux_dev_wrapper;
+ struct gp_aux_data_type *pdata;
+ struct pci1xxxx_gpio *priv;
+ int retval;
+
+ aux_dev_wrapper = (struct auxiliary_device_wrapper *)
+ container_of(aux_dev, struct auxiliary_device_wrapper, aux_dev);
+
+ pdata = &(aux_dev_wrapper->gp_aux_data);
+
+ if (!pdata)
+ return -EINVAL;
+
+ priv = devm_kzalloc(&aux_dev->dev, sizeof(struct pci1xxxx_gpio), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->aux_dev = aux_dev;
+
+ if (!devm_request_mem_region(&aux_dev->dev, pdata->region_start, 0x800, aux_dev->name))
+ return -EBUSY;
+
+ priv->reg_base = devm_ioremap(&aux_dev->dev, pdata->region_start, 0x800);
+ if (!priv->reg_base)
+ return -ENOMEM;
+
+ writel(0x0264, (priv->reg_base + 0x400 + 0xF0));
+
+ retval = pci1xxxx_gpio_setup(priv, pdata->irq_num);
+
+ if (retval < 0)
+ return retval;
+
+ dev_set_drvdata(&(aux_dev->dev), priv);
+
+ return devm_gpiochip_add_data(&(aux_dev->dev), &priv->gpio, priv);
+}
+
+const struct auxiliary_device_id pci1xxxx_gpio_auxiliary_id_table[] = {
+ {.name = "mchp_pci1xxxx_gp.gp_gpio"},
+ {}
+};
+
+static struct auxiliary_driver pci1xxxx_gpio_driver = {
+ .driver = {
+ .name = "PCI1xxxxGPIO",
+ },
+ .probe = pci1xxxx_gpio_probe,
+ .id_table = pci1xxxx_gpio_auxiliary_id_table
+};
+
+static int __init pci1xxxx_gpio_driver_init(void)
+{
+ return auxiliary_driver_register(&pci1xxxx_gpio_driver);
+}
+
+static void __exit pci1xxxx_gpio_driver_exit(void)
+{
+ auxiliary_driver_unregister(&pci1xxxx_gpio_driver);
+}
+
+module_init(pci1xxxx_gpio_driver_init);
+module_exit(pci1xxxx_gpio_driver_exit);
+
+MODULE_DESCRIPTION("Microchip Technology Inc. PCI1xxxx GPIO controller");
+MODULE_AUTHOR("Kumaravel Thiagarajan <[email protected]>");
+MODULE_LICENSE("GPL");
--
2.25.1
Power event handlers suspend and resume are invoked by the operating
system to notify the driver about the power events. Wakeup is enabled
before entering suspend and disabled after resuming.
Signed-off-by: Kumaravel Thiagarajan <[email protected]>
---
.../misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
index c58d27407c4d..404633704d2f 100644
--- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
+++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
@@ -14,6 +14,7 @@
#include "mchp_pci1xxxx_gp.h"
#define PCI1XXXX_NR_PINS 93
+#define PERI_GEN_RESET 0
#define OUT_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400)
#define INP_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x10)
#define OUT_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x20)
@@ -291,6 +292,38 @@ static struct irq_chip pci1xxxx_gpio_irqchip = {
.irq_set_type = pci1xxxx_gpio_set_type,
};
+static int pci1xxxx_gpio_suspend(struct device *dev)
+{
+ struct pci1xxxx_gpio *priv = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET,
+ 16, true);
+ pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET,
+ 17, false);
+ pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 16, true);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int pci1xxxx_gpio_resume(struct device *dev)
+{
+ struct pci1xxxx_gpio *priv = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET,
+ 17, true);
+ pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET,
+ 16, false);
+ pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 16, false);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
static int pci1xxxx_gpio_setup(struct pci1xxxx_gpio *priv, int irq)
{
struct gpio_chip *gchip = &priv->gpio;
@@ -325,6 +358,7 @@ static int pci1xxxx_gpio_setup(struct pci1xxxx_gpio *priv, int irq)
girq->parents = NULL;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
+
return 0;
}
@@ -370,6 +404,8 @@ static int pci1xxxx_gpio_probe(struct auxiliary_device *aux_dev,
return devm_gpiochip_add_data(&(aux_dev->dev), &priv->gpio, priv);
}
+static SIMPLE_DEV_PM_OPS(pci1xxxx_gpio_pm_ops, pci1xxxx_gpio_suspend, pci1xxxx_gpio_resume);
+
const struct auxiliary_device_id pci1xxxx_gpio_auxiliary_id_table[] = {
{.name = "mchp_pci1xxxx_gp.gp_gpio"},
{}
@@ -378,6 +414,7 @@ const struct auxiliary_device_id pci1xxxx_gpio_auxiliary_id_table[] = {
static struct auxiliary_driver pci1xxxx_gpio_driver = {
.driver = {
.name = "PCI1xxxxGPIO",
+ .pm = &pci1xxxx_gpio_pm_ops,
},
.probe = pci1xxxx_gpio_probe,
.id_table = pci1xxxx_gpio_auxiliary_id_table
--
2.25.1
On Thu, Aug 04, 2022 at 10:02:15PM +0530, Kumaravel Thiagarajan wrote:
> +// SPDX-License-Identifier: GPL-2.0+
I have to ask, do you really mean "or any later version" like you are
saying here?
> +// Copyright (C) 2022 Microchip Technology Inc.
> +
> +#include <linux/mfd/core.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/spinlock.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/idr.h>
> +#include "mchp_pci1xxxx_gp.h"
> +
> +struct aux_bus_device {
> + struct auxiliary_device_wrapper *aux_device_wrapper[2];
> +};
> +
> +DEFINE_IDA(gp_client_ida);
Shouldn't this be static?
thanks,
greg k-h
On Thu, Aug 04, 2022 at 10:02:14PM +0530, Kumaravel Thiagarajan wrote:
> 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'x OTP & EEPROM. This patch adds an
> auxiliary bus driver that enumerates separate child devices for gpio and
> OTP/EEPROM interface and the gpio controller driver for the first child.
>
> Kumaravel Thiagarajan (5):
> misc: microchip: pci1xxxx: load auxiliary bus driver for the PIO
> function in the multi-function endpoint of pci1xxxx device.
> misc: microchip: pci1xxxx: load gpio driver for the gpio controller
> auxiliary device enumerated by the auxiliary bus driver.
> misc: microchip: pci1xxxx: Add functions to configure gpio pins as
> input / output, get status, handle I/O for gpio pins.
> misc: microchip: pci1xxxx: Add gpio irq handler and irq helper
> functions irq_ack, irq_mask, irq_unmask and irq_set_type of
> irq_chip.
> misc: microchip: pci1xxxx: Add power management functions - suspend &
> resume handlers.
>
> MAINTAINERS | 9 +
> drivers/misc/Kconfig | 1 +
> drivers/misc/Makefile | 3 +-
> drivers/misc/mchp_pci1xxxx/Kconfig | 10 +
> drivers/misc/mchp_pci1xxxx/Makefile | 1 +
> drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c | 167 +++++++
> drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h | 28 ++
> .../misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c | 438 ++++++++++++++++++
> 8 files changed, 656 insertions(+), 1 deletion(-)
> create mode 100644 drivers/misc/mchp_pci1xxxx/Kconfig
> create mode 100644 drivers/misc/mchp_pci1xxxx/Makefile
> create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c
> create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h
> create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
>
> --
> 2.25.1
>
This patch is marked as "RFC" but I don't see any questions that you
have here. Please resolve anything you think needs to be handled and
submit a "this series is ok to be merged" version.
thanks,
greg k-h
On Thu, Aug 04, 2022 at 10:02:15PM +0530, Kumaravel Thiagarajan wrote:
> 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]>
> ---
> MAINTAINERS | 8 +
> drivers/misc/Kconfig | 1 +
> drivers/misc/Makefile | 3 +-
> drivers/misc/mchp_pci1xxxx/Kconfig | 10 ++
> drivers/misc/mchp_pci1xxxx/Makefile | 1 +
> drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c | 167 ++++++++++++++++++
> drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h | 28 +++
> 7 files changed, 217 insertions(+), 1 deletion(-)
> create mode 100644 drivers/misc/mchp_pci1xxxx/Kconfig
> create mode 100644 drivers/misc/mchp_pci1xxxx/Makefile
> create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c
> create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 285ffe0df5cf..ba491e4fc35f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -13244,6 +13244,14 @@ S: Supported
> F: Documentation/devicetree/bindings/mtd/atmel-nand.txt
> F: drivers/mtd/nand/raw/atmel/*
>
> +MICROCHIP PCI1XXXX GP DRIVER
> +M: Kumaravel Thiagarajan <[email protected]>
> +M: [email protected]
Please do not add random email aliases to the MAINTAINERS file, use
people's names and email addresses, otherwise there is no sense of
ownership.
thanks,
greg k-h
On Tue, 2022-08-23 at 13:24 +0200, Greg KH wrote:
>
> On Thu, Aug 04, 2022 at 10:02:15PM +0530, Kumaravel Thiagarajan wrote:
> > +// SPDX-License-Identifier: GPL-2.0+
>
> I have to ask, do you really mean "or any later version" like you are
> saying here?
It has to be GPL-2.0 and I will modify that.
>
> > +// Copyright (C) 2022 Microchip Technology Inc.
> > +
> > +#include <linux/mfd/core.h>
> > +#include <linux/module.h>
> > +#include <linux/pci.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/gpio/driver.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/idr.h>
> > +#include "mchp_pci1xxxx_gp.h"
> > +
> > +struct aux_bus_device {
> > + struct auxiliary_device_wrapper *aux_device_wrapper[2];
> > +};
> > +
> > +DEFINE_IDA(gp_client_ida);
>
> Shouldn't this be static?
Yes. I will make the correction.
Thank You.
Regards,
Kumar
On Tue, 2022-08-23 at 13:22 +0200, Greg KH wrote:
>
> On Thu, Aug 04, 2022 at 10:02:14PM +0530, Kumaravel Thiagarajan wrote:
> > 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'x OTP & EEPROM. This patch adds an
> > auxiliary bus driver that enumerates separate child devices for gpio and
> > OTP/EEPROM interface and the gpio controller driver for the first child.
> >
> > Kumaravel Thiagarajan (5):
> > misc: microchip: pci1xxxx: load auxiliary bus driver for the PIO
> > function in the multi-function endpoint of pci1xxxx device.
> > misc: microchip: pci1xxxx: load gpio driver for the gpio controller
> > auxiliary device enumerated by the auxiliary bus driver.
> > misc: microchip: pci1xxxx: Add functions to configure gpio pins as
> > input / output, get status, handle I/O for gpio pins.
> > misc: microchip: pci1xxxx: Add gpio irq handler and irq helper
> > functions irq_ack, irq_mask, irq_unmask and irq_set_type of
> > irq_chip.
> > misc: microchip: pci1xxxx: Add power management functions - suspend &
> > resume handlers.
> >
> > MAINTAINERS | 9 +
> > drivers/misc/Kconfig | 1 +
> > drivers/misc/Makefile | 3 +-
> > drivers/misc/mchp_pci1xxxx/Kconfig | 10 +
> > drivers/misc/mchp_pci1xxxx/Makefile | 1 +
> > drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c | 167 +++++++
> > drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h | 28 ++
> > .../misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c | 438 ++++++++++++++++++
> > 8 files changed, 656 insertions(+), 1 deletion(-)
> > create mode 100644 drivers/misc/mchp_pci1xxxx/Kconfig
> > create mode 100644 drivers/misc/mchp_pci1xxxx/Makefile
> > create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.c
> > create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gp.h
> > create mode 100644 drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
> >
> > --
> > 2.25.1
> >
>
> This patch is marked as "RFC" but I don't see any questions that you
> have here. Please resolve anything you think needs to be handled and
> submit a "this series is ok to be merged" version.
Ok. I will do this.
Thank You.
Regards,
Kumar