]> Git Repo - J-linux.git/blob - drivers/gpio/gpio-mpfs.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / gpio / gpio-mpfs.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
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
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
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
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
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
102 static void 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
106         mpfs_gpio_get(gc, gpio_index);
107
108         regmap_update_bits(mpfs_gpio->regs, mpfs_gpio->offsets->outp, BIT(gpio_index),
109                            value << gpio_index);
110
111         mpfs_gpio_get(gc, gpio_index);
112 }
113
114 static int mpfs_gpio_probe(struct platform_device *pdev)
115 {
116         struct device *dev = &pdev->dev;
117         struct mpfs_gpio_chip *mpfs_gpio;
118         struct clk *clk;
119         void __iomem *base;
120         int ngpios;
121
122         mpfs_gpio = devm_kzalloc(dev, sizeof(*mpfs_gpio), GFP_KERNEL);
123         if (!mpfs_gpio)
124                 return -ENOMEM;
125
126         mpfs_gpio->offsets = device_get_match_data(&pdev->dev);
127
128         base = devm_platform_ioremap_resource(pdev, 0);
129         if (IS_ERR(base))
130                 return dev_err_probe(dev, PTR_ERR(base), "failed to ioremap memory resource\n");
131
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");
136
137         clk = devm_clk_get_enabled(dev, NULL);
138         if (IS_ERR(clk))
139                 return dev_err_probe(dev, PTR_ERR(clk), "failed to get and enable clock\n");
140
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;
145
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;
156
157         return devm_gpiochip_add_data(dev, &mpfs_gpio->gc, mpfs_gpio);
158 }
159
160 static const struct mpfs_gpio_reg_offsets mpfs_reg_offsets = {
161         .inp = MPFS_INP_REG,
162         .outp = MPFS_OUTP_REG,
163 };
164
165 static const struct mpfs_gpio_reg_offsets coregpio_reg_offsets = {
166         .inp = COREGPIO_INP_REG,
167         .outp = COREGPIO_OUTP_REG,
168 };
169
170 static const struct of_device_id mpfs_gpio_of_ids[] = {
171         {
172                 .compatible = "microchip,mpfs-gpio",
173                 .data = &mpfs_reg_offsets,
174         }, {
175                 .compatible = "microchip,coregpio-rtl-v3",
176                 .data = &coregpio_reg_offsets,
177         },
178         { /* end of list */ }
179 };
180
181 static struct platform_driver mpfs_gpio_driver = {
182         .probe = mpfs_gpio_probe,
183         .driver = {
184                 .name = "microchip,mpfs-gpio",
185                 .of_match_table = mpfs_gpio_of_ids,
186         },
187 };
188 builtin_platform_driver(mpfs_gpio_driver);
This page took 0.039372 seconds and 4 git commands to generate.