File Index
Files and directories
Sign in
FILE

gpio-mpfs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpio/gpio-mpfs.c C
  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
 40struct mpfs_gpio_reg_offsets {
 41	u8 inp;
 42	u8 outp;
 43};
 44
 45struct mpfs_gpio_chip {
 46	struct regmap *regs;
 47	const struct mpfs_gpio_reg_offsets *offsets;
 48	struct gpio_chip gc;
 49};
 50
 51static const struct regmap_config mpfs_gpio_regmap_config = {
 52	.reg_bits = 32,
 53	.reg_stride = 4,
 54	.val_bits = 32,
 55};
 56
 57static 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
 67static 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_OUT | MPFS_GPIO_EN_OUT_BUF);
 73	regmap_update_bits(mpfs_gpio->regs, mpfs_gpio->offsets->outp, BIT(gpio_index),
 74			   value << gpio_index);
 75
 76	return 0;
 77}
 78
 79static 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
 92static 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
102static 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
117static 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
163static const struct mpfs_gpio_reg_offsets mpfs_reg_offsets = {
164	.inp = MPFS_INP_REG,
165	.outp = MPFS_OUTP_REG,
166};
167
168static const struct mpfs_gpio_reg_offsets coregpio_reg_offsets = {
169	.inp = COREGPIO_INP_REG,
170	.outp = COREGPIO_OUTP_REG,
171};
172
173static 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
184static 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};
191builtin_platform_driver(mpfs_gpio_driver);
~/ Read-only file preview.