Blame view
drivers/gpio/gpio-xilinx.c
10.3 KB
6e75fc040 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
0bcb6069a GPIO: add new Xil... |
2 |
/* |
74600ee01 GPIO: xilinx: Add... |
3 |
* Xilinx gpio driver for xps/axi_gpio IP. |
0bcb6069a GPIO: add new Xil... |
4 |
* |
74600ee01 GPIO: xilinx: Add... |
5 |
* Copyright 2008 - 2013 Xilinx, Inc. |
0bcb6069a GPIO: add new Xil... |
6 |
*/ |
74600ee01 GPIO: xilinx: Add... |
7 |
#include <linux/bitops.h> |
0bcb6069a GPIO: add new Xil... |
8 9 |
#include <linux/init.h> #include <linux/errno.h> |
bb207ef1e drivers/gpio: Fix... |
10 |
#include <linux/module.h> |
0bcb6069a GPIO: add new Xil... |
11 12 |
#include <linux/of_device.h> #include <linux/of_platform.h> |
0bcb6069a GPIO: add new Xil... |
13 |
#include <linux/io.h> |
516df4eb2 gpio: xilinx: Use... |
14 |
#include <linux/gpio/driver.h> |
5a0e3ad6a include cleanup: ... |
15 |
#include <linux/slab.h> |
0bcb6069a GPIO: add new Xil... |
16 17 18 19 |
/* Register Offset Definitions */ #define XGPIO_DATA_OFFSET (0x0) /* Data register */ #define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */ |
74600ee01 GPIO: xilinx: Add... |
20 21 22 |
#define XGPIO_CHANNEL_OFFSET 0x8 /* Read/Write access to the GPIO registers */ |
c54c58bad gpio/xilinx: Add ... |
23 |
#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86) |
cc090d61d GPIO: xilinx: Use... |
24 25 26 27 28 29 |
# define xgpio_readreg(offset) readl(offset) # define xgpio_writereg(offset, val) writel(val, offset) #else # define xgpio_readreg(offset) __raw_readl(offset) # define xgpio_writereg(offset, val) __raw_writel(val, offset) #endif |
74600ee01 GPIO: xilinx: Add... |
30 31 32 |
/** * struct xgpio_instance - Stores information about GPIO device |
1ebd06871 gpio: xilinx: con... |
33 34 |
* @gc: GPIO chip * @regs: register block |
3c1b5c9bd gpio: xilinx: Fix... |
35 |
* @gpio_width: GPIO width for every channel |
4ae798fae gpio/xilinx: Fix ... |
36 37 38 |
* @gpio_state: GPIO state shadow register * @gpio_dir: GPIO direction shadow register * @gpio_lock: Lock used for synchronization |
74600ee01 GPIO: xilinx: Add... |
39 |
*/ |
0bcb6069a GPIO: add new Xil... |
40 |
struct xgpio_instance { |
1ebd06871 gpio: xilinx: con... |
41 42 |
struct gpio_chip gc; void __iomem *regs; |
1d6902d3a gpio/xilinx: Crea... |
43 44 45 46 |
unsigned int gpio_width[2]; u32 gpio_state[2]; u32 gpio_dir[2]; spinlock_t gpio_lock[2]; |
749564ffd gpio/xilinx: Conv... |
47 |
}; |
1d6902d3a gpio/xilinx: Crea... |
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
static inline int xgpio_index(struct xgpio_instance *chip, int gpio) { if (gpio >= chip->gpio_width[0]) return 1; return 0; } static inline int xgpio_regoffset(struct xgpio_instance *chip, int gpio) { if (xgpio_index(chip, gpio)) return XGPIO_CHANNEL_OFFSET; return 0; } static inline int xgpio_offset(struct xgpio_instance *chip, int gpio) { if (xgpio_index(chip, gpio)) return gpio - chip->gpio_width[0]; return gpio; } |
0bcb6069a GPIO: add new Xil... |
71 72 73 74 75 76 |
/** * xgpio_get - Read the specified signal of the GPIO device. * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * |
4ae798fae gpio/xilinx: Fix ... |
77 78 79 80 81 |
* This function reads the specified signal of the GPIO device. * * Return: * 0 if direction of GPIO signals is set as input otherwise it * returns negative error value. |
0bcb6069a GPIO: add new Xil... |
82 83 84 |
*/ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) { |
097d88e94 gpio: xilinx: use... |
85 |
struct xgpio_instance *chip = gpiochip_get_data(gc); |
1d6902d3a gpio/xilinx: Crea... |
86 |
u32 val; |
0bcb6069a GPIO: add new Xil... |
87 |
|
1ebd06871 gpio: xilinx: con... |
88 |
val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET + |
1d6902d3a gpio/xilinx: Crea... |
89 90 91 |
xgpio_regoffset(chip, gpio)); return !!(val & BIT(xgpio_offset(chip, gpio))); |
0bcb6069a GPIO: add new Xil... |
92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
} /** * xgpio_set - Write the specified signal of the GPIO device. * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * @val: Value to be written to specified signal. * * This function writes the specified value in to the specified signal of the * GPIO device. */ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { unsigned long flags; |
097d88e94 gpio: xilinx: use... |
106 |
struct xgpio_instance *chip = gpiochip_get_data(gc); |
1d6902d3a gpio/xilinx: Crea... |
107 108 |
int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); |
0bcb6069a GPIO: add new Xil... |
109 |
|
1d6902d3a gpio/xilinx: Crea... |
110 |
spin_lock_irqsave(&chip->gpio_lock[index], flags); |
0bcb6069a GPIO: add new Xil... |
111 112 113 |
/* Write to GPIO signal and set its direction to output */ if (val) |
1d6902d3a gpio/xilinx: Crea... |
114 |
chip->gpio_state[index] |= BIT(offset); |
0bcb6069a GPIO: add new Xil... |
115 |
else |
1d6902d3a gpio/xilinx: Crea... |
116 |
chip->gpio_state[index] &= ~BIT(offset); |
74600ee01 GPIO: xilinx: Add... |
117 |
|
1ebd06871 gpio: xilinx: con... |
118 |
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + |
1d6902d3a gpio/xilinx: Crea... |
119 |
xgpio_regoffset(chip, gpio), chip->gpio_state[index]); |
0bcb6069a GPIO: add new Xil... |
120 |
|
1d6902d3a gpio/xilinx: Crea... |
121 |
spin_unlock_irqrestore(&chip->gpio_lock[index], flags); |
0bcb6069a GPIO: add new Xil... |
122 123 124 |
} /** |
8e7c1b803 gpio: xilinx: Add... |
125 126 127 128 129 130 131 132 133 134 135 136 |
* xgpio_set_multiple - Write the specified signals of the GPIO device. * @gc: Pointer to gpio_chip device structure. * @mask: Mask of the GPIOS to modify. * @bits: Value to be wrote on each GPIO * * This function writes the specified values into the specified signals of the * GPIO devices. */ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, unsigned long *bits) { unsigned long flags; |
8e7c1b803 gpio: xilinx: Add... |
137 138 139 140 141 142 143 144 145 146 |
struct xgpio_instance *chip = gpiochip_get_data(gc); int index = xgpio_index(chip, 0); int offset, i; spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Write to GPIO signals */ for (i = 0; i < gc->ngpio; i++) { if (*mask == 0) break; |
c3afa804c gpio: xilinx: Fix... |
147 |
/* Once finished with an index write it out to the register */ |
8e7c1b803 gpio: xilinx: Add... |
148 |
if (index != xgpio_index(chip, i)) { |
1ebd06871 gpio: xilinx: con... |
149 |
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + |
c3afa804c gpio: xilinx: Fix... |
150 |
index * XGPIO_CHANNEL_OFFSET, |
8e7c1b803 gpio: xilinx: Add... |
151 152 153 154 155 156 157 158 159 160 161 162 163 |
chip->gpio_state[index]); spin_unlock_irqrestore(&chip->gpio_lock[index], flags); index = xgpio_index(chip, i); spin_lock_irqsave(&chip->gpio_lock[index], flags); } if (__test_and_clear_bit(i, mask)) { offset = xgpio_offset(chip, i); if (test_bit(i, bits)) chip->gpio_state[index] |= BIT(offset); else chip->gpio_state[index] &= ~BIT(offset); } } |
1ebd06871 gpio: xilinx: con... |
164 |
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + |
c3afa804c gpio: xilinx: Fix... |
165 |
index * XGPIO_CHANNEL_OFFSET, chip->gpio_state[index]); |
8e7c1b803 gpio: xilinx: Add... |
166 167 168 169 170 |
spin_unlock_irqrestore(&chip->gpio_lock[index], flags); } /** |
0bcb6069a GPIO: add new Xil... |
171 172 173 174 |
* xgpio_dir_in - Set the direction of the specified GPIO signal as input. * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * |
4ae798fae gpio/xilinx: Fix ... |
175 176 177 |
* Return: * 0 - if direction of GPIO signals is set as input * otherwise it returns negative error value. |
0bcb6069a GPIO: add new Xil... |
178 179 180 181 |
*/ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { unsigned long flags; |
097d88e94 gpio: xilinx: use... |
182 |
struct xgpio_instance *chip = gpiochip_get_data(gc); |
1d6902d3a gpio/xilinx: Crea... |
183 184 |
int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); |
0bcb6069a GPIO: add new Xil... |
185 |
|
1d6902d3a gpio/xilinx: Crea... |
186 |
spin_lock_irqsave(&chip->gpio_lock[index], flags); |
0bcb6069a GPIO: add new Xil... |
187 188 |
/* Set the GPIO bit in shadow register and set direction as input */ |
1d6902d3a gpio/xilinx: Crea... |
189 |
chip->gpio_dir[index] |= BIT(offset); |
1ebd06871 gpio: xilinx: con... |
190 |
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + |
1d6902d3a gpio/xilinx: Crea... |
191 |
xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); |
0bcb6069a GPIO: add new Xil... |
192 |
|
1d6902d3a gpio/xilinx: Crea... |
193 |
spin_unlock_irqrestore(&chip->gpio_lock[index], flags); |
0bcb6069a GPIO: add new Xil... |
194 195 196 197 198 199 200 201 202 203 |
return 0; } /** * xgpio_dir_out - Set the direction of the specified GPIO signal as output. * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * @val: Value to be written to specified signal. * |
4ae798fae gpio/xilinx: Fix ... |
204 205 206 207 |
* This function sets the direction of specified GPIO signal as output. * * Return: * If all GPIO signals of GPIO chip is configured as input then it returns |
0bcb6069a GPIO: add new Xil... |
208 209 210 211 212 |
* error otherwise it returns 0. */ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { unsigned long flags; |
097d88e94 gpio: xilinx: use... |
213 |
struct xgpio_instance *chip = gpiochip_get_data(gc); |
1d6902d3a gpio/xilinx: Crea... |
214 215 |
int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); |
0bcb6069a GPIO: add new Xil... |
216 |
|
1d6902d3a gpio/xilinx: Crea... |
217 |
spin_lock_irqsave(&chip->gpio_lock[index], flags); |
0bcb6069a GPIO: add new Xil... |
218 219 220 |
/* Write state of GPIO signal */ if (val) |
1d6902d3a gpio/xilinx: Crea... |
221 |
chip->gpio_state[index] |= BIT(offset); |
0bcb6069a GPIO: add new Xil... |
222 |
else |
1d6902d3a gpio/xilinx: Crea... |
223 |
chip->gpio_state[index] &= ~BIT(offset); |
1ebd06871 gpio: xilinx: con... |
224 |
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + |
1d6902d3a gpio/xilinx: Crea... |
225 |
xgpio_regoffset(chip, gpio), chip->gpio_state[index]); |
0bcb6069a GPIO: add new Xil... |
226 227 |
/* Clear the GPIO bit in shadow register and set direction as output */ |
1d6902d3a gpio/xilinx: Crea... |
228 |
chip->gpio_dir[index] &= ~BIT(offset); |
1ebd06871 gpio: xilinx: con... |
229 |
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + |
1d6902d3a gpio/xilinx: Crea... |
230 |
xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); |
0bcb6069a GPIO: add new Xil... |
231 |
|
1d6902d3a gpio/xilinx: Crea... |
232 |
spin_unlock_irqrestore(&chip->gpio_lock[index], flags); |
0bcb6069a GPIO: add new Xil... |
233 234 235 236 237 238 |
return 0; } /** * xgpio_save_regs - Set initial values of GPIO pins |
1ebd06871 gpio: xilinx: con... |
239 |
* @chip: Pointer to GPIO instance |
0bcb6069a GPIO: add new Xil... |
240 |
*/ |
1ebd06871 gpio: xilinx: con... |
241 |
static void xgpio_save_regs(struct xgpio_instance *chip) |
0bcb6069a GPIO: add new Xil... |
242 |
{ |
1ebd06871 gpio: xilinx: con... |
243 244 |
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]); xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]); |
1d6902d3a gpio/xilinx: Crea... |
245 246 247 |
if (!chip->gpio_width[1]) return; |
1ebd06871 gpio: xilinx: con... |
248 |
xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET, |
1d6902d3a gpio/xilinx: Crea... |
249 |
chip->gpio_state[1]); |
1ebd06871 gpio: xilinx: con... |
250 |
xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET, |
1d6902d3a gpio/xilinx: Crea... |
251 |
chip->gpio_dir[1]); |
0bcb6069a GPIO: add new Xil... |
252 253 254 255 |
} /** * xgpio_of_probe - Probe method for the GPIO device. |
749564ffd gpio/xilinx: Conv... |
256 |
* @pdev: pointer to the platform device |
0bcb6069a GPIO: add new Xil... |
257 |
* |
4ae798fae gpio/xilinx: Fix ... |
258 259 260 |
* Return: * It returns 0, if the driver is bound to the GPIO device, or * a negative value if there is an error. |
0bcb6069a GPIO: add new Xil... |
261 |
*/ |
749564ffd gpio/xilinx: Conv... |
262 |
static int xgpio_probe(struct platform_device *pdev) |
0bcb6069a GPIO: add new Xil... |
263 264 |
{ struct xgpio_instance *chip; |
0bcb6069a GPIO: add new Xil... |
265 |
int status = 0; |
749564ffd gpio/xilinx: Conv... |
266 |
struct device_node *np = pdev->dev.of_node; |
1d6902d3a gpio/xilinx: Crea... |
267 |
u32 is_dual; |
0bcb6069a GPIO: add new Xil... |
268 |
|
1d6902d3a gpio/xilinx: Crea... |
269 270 |
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) |
0bcb6069a GPIO: add new Xil... |
271 |
return -ENOMEM; |
0bcb6069a GPIO: add new Xil... |
272 |
|
1d6902d3a gpio/xilinx: Crea... |
273 |
platform_set_drvdata(pdev, chip); |
749564ffd gpio/xilinx: Conv... |
274 |
|
0bcb6069a GPIO: add new Xil... |
275 |
/* Update GPIO state shadow register with default value */ |
1d6902d3a gpio/xilinx: Crea... |
276 |
of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]); |
0bcb6069a GPIO: add new Xil... |
277 278 |
/* Update GPIO direction shadow register with default value */ |
1d6902d3a gpio/xilinx: Crea... |
279 280 |
if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0])) chip->gpio_dir[0] = 0xFFFFFFFF; |
6f8bf5003 GPIO: xilinx: Sim... |
281 |
|
1b4c5a6e6 gpio: Fix ngpio i... |
282 283 284 285 |
/* * Check device node and parent device node for device width * and assume default width of 32 */ |
1d6902d3a gpio/xilinx: Crea... |
286 287 288 289 290 291 292 |
if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0])) chip->gpio_width[0] = 32; spin_lock_init(&chip->gpio_lock[0]); if (of_property_read_u32(np, "xlnx,is-dual", &is_dual)) is_dual = 0; |
0bcb6069a GPIO: add new Xil... |
293 |
|
1d6902d3a gpio/xilinx: Crea... |
294 295 296 297 298 299 300 301 302 |
if (is_dual) { /* Update GPIO state shadow register with default value */ of_property_read_u32(np, "xlnx,dout-default-2", &chip->gpio_state[1]); /* Update GPIO direction shadow register with default value */ if (of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir[1])) chip->gpio_dir[1] = 0xFFFFFFFF; |
0bcb6069a GPIO: add new Xil... |
303 |
|
1d6902d3a gpio/xilinx: Crea... |
304 305 306 307 308 309 310 311 312 313 |
/* * Check device node and parent device node for device width * and assume default width of 32 */ if (of_property_read_u32(np, "xlnx,gpio2-width", &chip->gpio_width[1])) chip->gpio_width[1] = 32; spin_lock_init(&chip->gpio_lock[1]); } |
1ebd06871 gpio: xilinx: con... |
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
chip->gc.base = -1; chip->gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1]; chip->gc.parent = &pdev->dev; chip->gc.direction_input = xgpio_dir_in; chip->gc.direction_output = xgpio_dir_out; chip->gc.get = xgpio_get; chip->gc.set = xgpio_set; chip->gc.set_multiple = xgpio_set_multiple; chip->gc.label = dev_name(&pdev->dev); chip->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(chip->regs)) { dev_err(&pdev->dev, "failed to ioremap memory resource "); return PTR_ERR(chip->regs); } |
0bcb6069a GPIO: add new Xil... |
331 |
|
1ebd06871 gpio: xilinx: con... |
332 |
xgpio_save_regs(chip); |
0bcb6069a GPIO: add new Xil... |
333 |
|
1ebd06871 gpio: xilinx: con... |
334 |
status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); |
0bcb6069a GPIO: add new Xil... |
335 |
if (status) { |
1ebd06871 gpio: xilinx: con... |
336 337 |
dev_err(&pdev->dev, "failed to add GPIO chip "); |
0bcb6069a GPIO: add new Xil... |
338 339 |
return status; } |
74600ee01 GPIO: xilinx: Add... |
340 |
|
0bcb6069a GPIO: add new Xil... |
341 342 |
return 0; } |
9992bc95e gpio: xilinx: Mak... |
343 |
static const struct of_device_id xgpio_of_match[] = { |
0bcb6069a GPIO: add new Xil... |
344 345 346 |
{ .compatible = "xlnx,xps-gpio-1.00.a", }, { /* end of list */ }, }; |
749564ffd gpio/xilinx: Conv... |
347 |
MODULE_DEVICE_TABLE(of, xgpio_of_match); |
0bcb6069a GPIO: add new Xil... |
348 |
|
749564ffd gpio/xilinx: Conv... |
349 350 |
static struct platform_driver xgpio_plat_driver = { .probe = xgpio_probe, |
749564ffd gpio/xilinx: Conv... |
351 352 353 354 355 |
.driver = { .name = "gpio-xilinx", .of_match_table = xgpio_of_match, }, }; |
0bcb6069a GPIO: add new Xil... |
356 |
|
749564ffd gpio/xilinx: Conv... |
357 358 359 |
static int __init xgpio_init(void) { return platform_driver_register(&xgpio_plat_driver); |
0bcb6069a GPIO: add new Xil... |
360 |
} |
0bcb6069a GPIO: add new Xil... |
361 |
subsys_initcall(xgpio_init); |
749564ffd gpio/xilinx: Conv... |
362 363 364 365 366 367 |
static void __exit xgpio_exit(void) { platform_driver_unregister(&xgpio_plat_driver); } module_exit(xgpio_exit); |
0bcb6069a GPIO: add new Xil... |
368 369 370 371 |
MODULE_AUTHOR("Xilinx, Inc."); MODULE_DESCRIPTION("Xilinx GPIO driver"); MODULE_LICENSE("GPL"); |