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