Skip to content

Commit a987b78

Browse files
lhanlyuBartosz Golaszewski
authored andcommitted
gpio: mpfs: add polarfire soc gpio support
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 <[email protected]> Co-developed-by: Conor Dooley <[email protected]> Signed-off-by: Conor Dooley <[email protected]> Reviewed-by: Linus Walleij <[email protected]> Link: https://lore.kernel.org/r/20241104-tiny-evaluate-9336020b4b6a@spud Signed-off-by: Bartosz Golaszewski <[email protected]>
1 parent 50dded8 commit a987b78

File tree

3 files changed

+167
-0
lines changed

3 files changed

+167
-0
lines changed

drivers/gpio/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,12 @@ config GPIO_PL061
544544
help
545545
Say yes here to support the PrimeCell PL061 GPIO device.
546546

547+
config GPIO_POLARFIRE_SOC
548+
bool "Microchip FPGA GPIO support"
549+
select REGMAP_MMIO
550+
help
551+
Say yes here to support the GPIO controllers on Microchip FPGAs.
552+
547553
config GPIO_PXA
548554
bool "PXA GPIO support"
549555
depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST

drivers/gpio/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o
135135
obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
136136
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
137137
obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o
138+
obj-$(CONFIG_GPIO_POLARFIRE_SOC) += gpio-mpfs.o
138139
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
139140
obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
140141
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o

drivers/gpio/gpio-mpfs.c

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// SPDX-License-Identifier: (GPL-2.0)
2+
/*
3+
* Microchip PolarFire SoC (MPFS) GPIO controller driver
4+
*
5+
* Copyright (c) 2018-2024 Microchip Technology Inc. and its subsidiaries
6+
*/
7+
8+
#include <linux/clk.h>
9+
#include <linux/device.h>
10+
#include <linux/errno.h>
11+
#include <linux/gpio/driver.h>
12+
#include <linux/init.h>
13+
#include <linux/mod_devicetable.h>
14+
#include <linux/platform_device.h>
15+
#include <linux/regmap.h>
16+
#include <linux/spinlock.h>
17+
18+
#define MPFS_GPIO_CTRL(i) (0x4 * (i))
19+
#define MPFS_MAX_NUM_GPIO 32
20+
#define MPFS_GPIO_EN_INT 3
21+
#define MPFS_GPIO_EN_OUT_BUF BIT(2)
22+
#define MPFS_GPIO_EN_IN BIT(1)
23+
#define MPFS_GPIO_EN_OUT BIT(0)
24+
#define MPFS_GPIO_DIR_MASK GENMASK(2, 0)
25+
26+
#define MPFS_GPIO_TYPE_INT_EDGE_BOTH 0x80
27+
#define MPFS_GPIO_TYPE_INT_EDGE_NEG 0x60
28+
#define MPFS_GPIO_TYPE_INT_EDGE_POS 0x40
29+
#define MPFS_GPIO_TYPE_INT_LEVEL_LOW 0x20
30+
#define MPFS_GPIO_TYPE_INT_LEVEL_HIGH 0x00
31+
#define MPFS_GPIO_TYPE_INT_MASK GENMASK(7, 5)
32+
#define MPFS_IRQ_REG 0x80
33+
#define MPFS_INP_REG 0x84
34+
#define MPFS_OUTP_REG 0x88
35+
36+
struct mpfs_gpio_chip {
37+
struct regmap *regs;
38+
struct gpio_chip gc;
39+
};
40+
41+
static const struct regmap_config mpfs_gpio_regmap_config = {
42+
.reg_bits = 32,
43+
.reg_stride = 4,
44+
.val_bits = 32,
45+
};
46+
47+
static int mpfs_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio_index)
48+
{
49+
struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
50+
51+
regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
52+
MPFS_GPIO_DIR_MASK, MPFS_GPIO_EN_IN);
53+
54+
return 0;
55+
}
56+
57+
static int mpfs_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio_index, int value)
58+
{
59+
struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
60+
61+
regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index),
62+
MPFS_GPIO_DIR_MASK, MPFS_GPIO_EN_IN);
63+
regmap_update_bits(mpfs_gpio->regs, MPFS_OUTP_REG, BIT(gpio_index),
64+
value << gpio_index);
65+
66+
return 0;
67+
}
68+
69+
static int mpfs_gpio_get_direction(struct gpio_chip *gc,
70+
unsigned int gpio_index)
71+
{
72+
struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
73+
unsigned int gpio_cfg;
74+
75+
regmap_read(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index), &gpio_cfg);
76+
if (gpio_cfg & MPFS_GPIO_EN_IN)
77+
return GPIO_LINE_DIRECTION_IN;
78+
79+
return GPIO_LINE_DIRECTION_OUT;
80+
}
81+
82+
static int mpfs_gpio_get(struct gpio_chip *gc, unsigned int gpio_index)
83+
{
84+
struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
85+
86+
if (mpfs_gpio_get_direction(gc, gpio_index) == GPIO_LINE_DIRECTION_OUT)
87+
return regmap_test_bits(mpfs_gpio->regs, MPFS_OUTP_REG, BIT(gpio_index));
88+
else
89+
return regmap_test_bits(mpfs_gpio->regs, MPFS_INP_REG, BIT(gpio_index));
90+
}
91+
92+
static void mpfs_gpio_set(struct gpio_chip *gc, unsigned int gpio_index, int value)
93+
{
94+
struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc);
95+
96+
mpfs_gpio_get(gc, gpio_index);
97+
98+
regmap_update_bits(mpfs_gpio->regs, MPFS_OUTP_REG, BIT(gpio_index),
99+
value << gpio_index);
100+
101+
mpfs_gpio_get(gc, gpio_index);
102+
}
103+
104+
static int mpfs_gpio_probe(struct platform_device *pdev)
105+
{
106+
struct device *dev = &pdev->dev;
107+
struct mpfs_gpio_chip *mpfs_gpio;
108+
struct clk *clk;
109+
void __iomem *base;
110+
int ngpios;
111+
112+
mpfs_gpio = devm_kzalloc(dev, sizeof(*mpfs_gpio), GFP_KERNEL);
113+
if (!mpfs_gpio)
114+
return -ENOMEM;
115+
116+
base = devm_platform_ioremap_resource(pdev, 0);
117+
if (IS_ERR(base))
118+
return dev_err_probe(dev, PTR_ERR(base), "failed to ioremap memory resource\n");
119+
120+
mpfs_gpio->regs = devm_regmap_init_mmio(dev, base, &mpfs_gpio_regmap_config);
121+
if (IS_ERR(mpfs_gpio->regs))
122+
return dev_err_probe(dev, PTR_ERR(mpfs_gpio->regs),
123+
"failed to initialise regmap\n");
124+
125+
clk = devm_clk_get_enabled(dev, NULL);
126+
if (IS_ERR(clk))
127+
return dev_err_probe(dev, PTR_ERR(clk), "failed to get and enable clock\n");
128+
129+
ngpios = MPFS_MAX_NUM_GPIO;
130+
device_property_read_u32(dev, "ngpios", &ngpios);
131+
if (ngpios > MPFS_MAX_NUM_GPIO)
132+
ngpios = MPFS_MAX_NUM_GPIO;
133+
134+
mpfs_gpio->gc.direction_input = mpfs_gpio_direction_input;
135+
mpfs_gpio->gc.direction_output = mpfs_gpio_direction_output;
136+
mpfs_gpio->gc.get_direction = mpfs_gpio_get_direction;
137+
mpfs_gpio->gc.get = mpfs_gpio_get;
138+
mpfs_gpio->gc.set = mpfs_gpio_set;
139+
mpfs_gpio->gc.base = -1;
140+
mpfs_gpio->gc.ngpio = ngpios;
141+
mpfs_gpio->gc.label = dev_name(dev);
142+
mpfs_gpio->gc.parent = dev;
143+
mpfs_gpio->gc.owner = THIS_MODULE;
144+
145+
return devm_gpiochip_add_data(dev, &mpfs_gpio->gc, mpfs_gpio);
146+
}
147+
148+
static const struct of_device_id mpfs_gpio_of_ids[] = {
149+
{ .compatible = "microchip,mpfs-gpio", },
150+
{ /* end of list */ }
151+
};
152+
153+
static struct platform_driver mpfs_gpio_driver = {
154+
.probe = mpfs_gpio_probe,
155+
.driver = {
156+
.name = "microchip,mpfs-gpio",
157+
.of_match_table = mpfs_gpio_of_ids,
158+
},
159+
};
160+
builtin_platform_driver(mpfs_gpio_driver);

0 commit comments

Comments
 (0)