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