1 // SPDX-License-Identifier: (GPL-2.0)
3 * Microchip PolarFire SoC (MPFS) GPIO controller driver
5 * Copyright (c) 2018-2024 Microchip Technology Inc. and its subsidiaries
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>
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)
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
35 #define MPFS_INP_REG 0x84
36 #define COREGPIO_INP_REG 0x90
37 #define MPFS_OUTP_REG 0x88
38 #define COREGPIO_OUTP_REG 0xA0
40 struct mpfs_gpio_reg_offsets
{
45 struct mpfs_gpio_chip
{
47 const struct mpfs_gpio_reg_offsets
*offsets
;
51 static const struct regmap_config mpfs_gpio_regmap_config
= {
57 static int mpfs_gpio_direction_input(struct gpio_chip
*gc
, unsigned int gpio_index
)
59 struct mpfs_gpio_chip
*mpfs_gpio
= gpiochip_get_data(gc
);
61 regmap_update_bits(mpfs_gpio
->regs
, MPFS_GPIO_CTRL(gpio_index
),
62 MPFS_GPIO_DIR_MASK
, MPFS_GPIO_EN_IN
);
67 static int mpfs_gpio_direction_output(struct gpio_chip
*gc
, unsigned int gpio_index
, int value
)
69 struct mpfs_gpio_chip
*mpfs_gpio
= gpiochip_get_data(gc
);
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
),
79 static int mpfs_gpio_get_direction(struct gpio_chip
*gc
,
80 unsigned int gpio_index
)
82 struct mpfs_gpio_chip
*mpfs_gpio
= gpiochip_get_data(gc
);
83 unsigned int gpio_cfg
;
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
;
89 return GPIO_LINE_DIRECTION_OUT
;
92 static int mpfs_gpio_get(struct gpio_chip
*gc
, unsigned int gpio_index
)
94 struct mpfs_gpio_chip
*mpfs_gpio
= gpiochip_get_data(gc
);
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
));
99 return regmap_test_bits(mpfs_gpio
->regs
, mpfs_gpio
->offsets
->inp
, BIT(gpio_index
));
102 static void mpfs_gpio_set(struct gpio_chip
*gc
, unsigned int gpio_index
, int value
)
104 struct mpfs_gpio_chip
*mpfs_gpio
= gpiochip_get_data(gc
);
106 mpfs_gpio_get(gc
, gpio_index
);
108 regmap_update_bits(mpfs_gpio
->regs
, mpfs_gpio
->offsets
->outp
, BIT(gpio_index
),
109 value
<< gpio_index
);
111 mpfs_gpio_get(gc
, gpio_index
);
114 static int mpfs_gpio_probe(struct platform_device
*pdev
)
116 struct device
*dev
= &pdev
->dev
;
117 struct mpfs_gpio_chip
*mpfs_gpio
;
122 mpfs_gpio
= devm_kzalloc(dev
, sizeof(*mpfs_gpio
), GFP_KERNEL
);
126 mpfs_gpio
->offsets
= device_get_match_data(&pdev
->dev
);
128 base
= devm_platform_ioremap_resource(pdev
, 0);
130 return dev_err_probe(dev
, PTR_ERR(base
), "failed to ioremap memory resource\n");
132 mpfs_gpio
->regs
= devm_regmap_init_mmio(dev
, base
, &mpfs_gpio_regmap_config
);
133 if (IS_ERR(mpfs_gpio
->regs
))
134 return dev_err_probe(dev
, PTR_ERR(mpfs_gpio
->regs
),
135 "failed to initialise regmap\n");
137 clk
= devm_clk_get_enabled(dev
, NULL
);
139 return dev_err_probe(dev
, PTR_ERR(clk
), "failed to get and enable clock\n");
141 ngpios
= MPFS_MAX_NUM_GPIO
;
142 device_property_read_u32(dev
, "ngpios", &ngpios
);
143 if (ngpios
> MPFS_MAX_NUM_GPIO
)
144 ngpios
= MPFS_MAX_NUM_GPIO
;
146 mpfs_gpio
->gc
.direction_input
= mpfs_gpio_direction_input
;
147 mpfs_gpio
->gc
.direction_output
= mpfs_gpio_direction_output
;
148 mpfs_gpio
->gc
.get_direction
= mpfs_gpio_get_direction
;
149 mpfs_gpio
->gc
.get
= mpfs_gpio_get
;
150 mpfs_gpio
->gc
.set
= mpfs_gpio_set
;
151 mpfs_gpio
->gc
.base
= -1;
152 mpfs_gpio
->gc
.ngpio
= ngpios
;
153 mpfs_gpio
->gc
.label
= dev_name(dev
);
154 mpfs_gpio
->gc
.parent
= dev
;
155 mpfs_gpio
->gc
.owner
= THIS_MODULE
;
157 return devm_gpiochip_add_data(dev
, &mpfs_gpio
->gc
, mpfs_gpio
);
160 static const struct mpfs_gpio_reg_offsets mpfs_reg_offsets
= {
162 .outp
= MPFS_OUTP_REG
,
165 static const struct mpfs_gpio_reg_offsets coregpio_reg_offsets
= {
166 .inp
= COREGPIO_INP_REG
,
167 .outp
= COREGPIO_OUTP_REG
,
170 static const struct of_device_id mpfs_gpio_of_ids
[] = {
172 .compatible
= "microchip,mpfs-gpio",
173 .data
= &mpfs_reg_offsets
,
175 .compatible
= "microchip,coregpio-rtl-v3",
176 .data
= &coregpio_reg_offsets
,
178 { /* end of list */ }
181 static struct platform_driver mpfs_gpio_driver
= {
182 .probe
= mpfs_gpio_probe
,
184 .name
= "microchip,mpfs-gpio",
185 .of_match_table
= mpfs_gpio_of_ids
,
188 builtin_platform_driver(mpfs_gpio_driver
);