From: Conor Dooley <conor@kernel.org>
To: linux-gpio@vger.kernel.org
Cc: conor@kernel.org, Conor Dooley <conor.dooley@microchip.com>,
Daire McNamara <daire.mcnamara@microchip.com>,
valentina.fernandezalanis@microchip.com,
Linus Walleij <linus.walleij@linaro.org>,
Bartosz Golaszewski <brgl@bgdev.pl>,
Lewis Hanly <lewis.hanly@microchip.com>
Subject: [PATCH v8 1/1] gpio: mpfs: add polarfire soc gpio support
Date: Thu, 24 Oct 2024 10:20:32 +0100 [thread overview]
Message-ID: <20241024-dragster-research-0713e1733600@spud> (raw)
In-Reply-To: <20241024-tipping-browse-c0d582b16a47@spud>
From: Lewis Hanly <lewis.hanly@microchip.com>
Add a driver to support the Polarfire SoC gpio controller. Interrupt
controller support is unavailable for now and will be added at a later
date.
Signed-off-by: Lewis Hanly <lewis.hanly@microchip.com>
Co-developed-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
---
v8:
- drop interrupt support
- replace regular mmio acesses with regmap (nice complexity reduction)
- change mpfs_gpio_get() so that it can report non-zero when the line
direction is output.
---
drivers/gpio/Kconfig | 7 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-mpfs.c | 178 +++++++++++++++++++++++++++++++++++++++
3 files changed, 186 insertions(+)
create mode 100644 drivers/gpio/gpio-mpfs.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d93cd4f722b40..fab9c4f73f62b 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -549,6 +549,13 @@ config GPIO_PL061
help
Say yes here to support the PrimeCell PL061 GPIO device.
+config GPIO_POLARFIRE_SOC
+ bool "Microchip FPGA GPIO support"
+ depends on OF_GPIO
+ select REGMAP_MMIO
+ help
+ Say yes here to support the GPIO controllers on Microchip FPGAs.
+
config GPIO_PXA
bool "PXA GPIO support"
depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 1429e8c0229b9..fc66e6388c76c 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -133,6 +133,7 @@ obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o
obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o
+obj-$(CONFIG_GPIO_POLARFIRE_SOC) += gpio-mpfs.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
diff --git a/drivers/gpio/gpio-mpfs.c b/drivers/gpio/gpio-mpfs.c
new file mode 100644
index 0000000000000..eaf65ddb6ad73
--- /dev/null
+++ b/drivers/gpio/gpio-mpfs.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: (GPL-2.0)
+/*
+ * Microchip PolarFire SoC (MPFS) GPIO controller driver
+ *
+ * Copyright (c) 2018-2024 Microchip Technology Inc. and its subsidiaries
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+
+#define MPFS_GPIO_CTRL(i) (0x4 * (i))
+#define MAX_NUM_GPIO 32
+#define MPFS_GPIO_EN_INT 3
+#define MPFS_GPIO_EN_OUT_BUF BIT(2)
+#define MPFS_GPIO_EN_IN BIT(1)
+#define MPFS_GPIO_EN_OUT BIT(0)
+#define MPFS_GPIO_DIR_MASK GENMASK(2, 0)
+
+#define MPFS_GPIO_TYPE_INT_EDGE_BOTH 0x80
+#define MPFS_GPIO_TYPE_INT_EDGE_NEG 0x60
+#define MPFS_GPIO_TYPE_INT_EDGE_POS 0x40
+#define MPFS_GPIO_TYPE_INT_LEVEL_LOW 0x20
+#define MPFS_GPIO_TYPE_INT_LEVEL_HIGH 0x00
+#define MPFS_GPIO_TYPE_INT_MASK GENMASK(7, 5)
+#define MPFS_IRQ_REG 0x80
+#define MPFS_INP_REG 0x84
+#define MPFS_OUTP_REG 0x88
+
+struct mpfs_gpio_chip {
+ struct clk *clk;
+ struct regmap *regs;
+ struct gpio_chip gc;
+};
+
+static const struct regmap_config mpfs_gpio_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+};
+
+static int mpfs_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio_index)
+{
+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
+
+ regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
+ MPFS_GPIO_DIR_MASK, MPFS_GPIO_EN_IN);
+
+ return 0;
+}
+
+static int mpfs_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio_index, int value)
+{
+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
+
+ regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
+ MPFS_GPIO_DIR_MASK, MPFS_GPIO_EN_IN);
+ regmap_update_bits(mpfs_gpio->regs, MPFS_OUTP_REG, BIT(gpio_index),
+ value << gpio_index);
+
+ return 0;
+}
+
+static int mpfs_gpio_get_direction(struct gpio_chip *gc,
+ unsigned int gpio_index)
+{
+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
+ unsigned int gpio_cfg;
+
+ regmap_read(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index), &gpio_cfg);
+ if (gpio_cfg & MPFS_GPIO_EN_IN)
+ return GPIO_LINE_DIRECTION_IN;
+
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int mpfs_gpio_get(struct gpio_chip *gc, unsigned int gpio_index)
+{
+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
+
+ if (mpfs_gpio_get_direction(gc, gpio_index) == GPIO_LINE_DIRECTION_OUT)
+ return regmap_test_bits(mpfs_gpio->regs, MPFS_OUTP_REG, BIT(gpio_index));
+ else
+ return regmap_test_bits(mpfs_gpio->regs, MPFS_INP_REG, BIT(gpio_index));
+}
+
+static void mpfs_gpio_set(struct gpio_chip *gc, unsigned int gpio_index, int value)
+{
+ struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
+
+ mpfs_gpio_get(gc, gpio_index);
+
+ regmap_update_bits(mpfs_gpio->regs, MPFS_OUTP_REG, BIT(gpio_index),
+ value << gpio_index);
+
+ mpfs_gpio_get(gc, gpio_index);
+}
+
+static int mpfs_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mpfs_gpio_chip *mpfs_gpio;
+ struct clk *clk;
+ void __iomem *base;
+ int ret, ngpios;
+
+ mpfs_gpio = devm_kzalloc(dev, sizeof(*mpfs_gpio), GFP_KERNEL);
+ if (!mpfs_gpio)
+ return -ENOMEM;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return dev_err_probe(dev, PTR_ERR(base), "failed to ioremap memory resource\n");
+
+ mpfs_gpio->regs = devm_regmap_init_mmio(dev, base, &mpfs_gpio_regmap_config);
+ if (IS_ERR(mpfs_gpio->regs))
+ return dev_err_probe(dev, PTR_ERR(mpfs_gpio->regs),
+ "failed to initialise regmap\n");
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to get and enable clock\n");
+
+ mpfs_gpio->clk = clk;
+
+ ngpios = MAX_NUM_GPIO;
+ device_property_read_u32(dev, "ngpios", &ngpios);
+ if (ngpios > MAX_NUM_GPIO)
+ ngpios = MAX_NUM_GPIO;
+
+ mpfs_gpio->gc.direction_input = mpfs_gpio_direction_input;
+ mpfs_gpio->gc.direction_output = mpfs_gpio_direction_output;
+ mpfs_gpio->gc.get_direction = mpfs_gpio_get_direction;
+ mpfs_gpio->gc.get = mpfs_gpio_get;
+ mpfs_gpio->gc.set = mpfs_gpio_set;
+ mpfs_gpio->gc.base = -1;
+ mpfs_gpio->gc.ngpio = ngpios;
+ mpfs_gpio->gc.label = dev_name(dev);
+ mpfs_gpio->gc.parent = dev;
+ mpfs_gpio->gc.owner = THIS_MODULE;
+
+ ret = gpiochip_add_data(&mpfs_gpio->gc, mpfs_gpio);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, mpfs_gpio);
+
+ return 0;
+}
+
+static void mpfs_gpio_remove(struct platform_device *pdev)
+{
+ struct mpfs_gpio_chip *mpfs_gpio = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&mpfs_gpio->gc);
+}
+
+static const struct of_device_id mpfs_gpio_of_ids[] = {
+ { .compatible = "microchip,mpfs-gpio", },
+ { /* end of list */ }
+};
+
+static struct platform_driver mpfs_gpio_driver = {
+ .probe = mpfs_gpio_probe,
+ .driver = {
+ .name = "microchip,mpfs-gpio",
+ .of_match_table = mpfs_gpio_of_ids,
+ },
+ .remove = mpfs_gpio_remove,
+};
+builtin_platform_driver(mpfs_gpio_driver);
--
2.45.2
next prev parent reply other threads:[~2024-10-24 9:21 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-24 9:20 [PATCH v8 0/1] Polarfire SoC GPIO support Conor Dooley
2024-10-24 9:20 ` Conor Dooley [this message]
2024-10-24 9:57 ` [PATCH v8 1/1] gpio: mpfs: add polarfire soc gpio support Bartosz Golaszewski
2024-10-24 10:32 ` Conor Dooley
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241024-dragster-research-0713e1733600@spud \
--to=conor@kernel.org \
--cc=brgl@bgdev.pl \
--cc=conor.dooley@microchip.com \
--cc=daire.mcnamara@microchip.com \
--cc=lewis.hanly@microchip.com \
--cc=linus.walleij@linaro.org \
--cc=linux-gpio@vger.kernel.org \
--cc=valentina.fernandezalanis@microchip.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).