| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Generic driver for memory-mapped GPIO controllers. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2008 MontaVista Software, Inc. |
|---|
| 5 | 6 | * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 8 | | - * under the terms of the GNU General Public License as published by the |
|---|
| 9 | | - * Free Software Foundation; either version 2 of the License, or (at your |
|---|
| 10 | | - * option) any later version. |
|---|
| 11 | 7 | * |
|---|
| 12 | 8 | * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`....... |
|---|
| 13 | 9 | * ...`` ```````.. |
|---|
| .. | .. |
|---|
| 138 | 134 | unsigned long pinmask = bgpio_line2mask(gc, gpio); |
|---|
| 139 | 135 | bool dir = !!(gc->bgpio_dir & pinmask); |
|---|
| 140 | 136 | |
|---|
| 141 | | - /* |
|---|
| 142 | | - * If the direction is OUT we read the value from the SET |
|---|
| 143 | | - * register, and if the direction is IN we read the value |
|---|
| 144 | | - * from the DAT register. |
|---|
| 145 | | - * |
|---|
| 146 | | - * If the direction bits are inverted, naturally this gets |
|---|
| 147 | | - * inverted too. |
|---|
| 148 | | - */ |
|---|
| 149 | | - if (gc->bgpio_dir_inverted) |
|---|
| 150 | | - dir = !dir; |
|---|
| 151 | | - |
|---|
| 152 | 137 | if (dir) |
|---|
| 153 | 138 | return !!(gc->read_reg(gc->reg_set) & pinmask); |
|---|
| 154 | 139 | else |
|---|
| .. | .. |
|---|
| 168 | 153 | /* Make sure we first clear any bits that are zero when we read the register */ |
|---|
| 169 | 154 | *bits &= ~*mask; |
|---|
| 170 | 155 | |
|---|
| 171 | | - /* Exploit the fact that we know which directions are set */ |
|---|
| 172 | | - if (gc->bgpio_dir_inverted) { |
|---|
| 173 | | - set_mask = *mask & ~gc->bgpio_dir; |
|---|
| 174 | | - get_mask = *mask & gc->bgpio_dir; |
|---|
| 175 | | - } else { |
|---|
| 176 | | - set_mask = *mask & gc->bgpio_dir; |
|---|
| 177 | | - get_mask = *mask & ~gc->bgpio_dir; |
|---|
| 178 | | - } |
|---|
| 156 | + set_mask = *mask & gc->bgpio_dir; |
|---|
| 157 | + get_mask = *mask & ~gc->bgpio_dir; |
|---|
| 179 | 158 | |
|---|
| 180 | 159 | if (set_mask) |
|---|
| 181 | 160 | *bits |= gc->read_reg(gc->reg_set) & set_mask; |
|---|
| .. | .. |
|---|
| 216 | 195 | *bits &= ~*mask; |
|---|
| 217 | 196 | |
|---|
| 218 | 197 | /* Create a mirrored mask */ |
|---|
| 219 | | - bit = -1; |
|---|
| 220 | | - while ((bit = find_next_bit(mask, gc->ngpio, bit + 1)) < gc->ngpio) |
|---|
| 198 | + for_each_set_bit(bit, mask, gc->ngpio) |
|---|
| 221 | 199 | readmask |= bgpio_line2mask(gc, bit); |
|---|
| 222 | 200 | |
|---|
| 223 | 201 | /* Read the register */ |
|---|
| .. | .. |
|---|
| 227 | 205 | * Mirror the result into the "bits" result, this will give line 0 |
|---|
| 228 | 206 | * in bit 0 ... line 31 in bit 31 for a 32bit register. |
|---|
| 229 | 207 | */ |
|---|
| 230 | | - bit = -1; |
|---|
| 231 | | - while ((bit = find_next_bit(&val, gc->ngpio, bit + 1)) < gc->ngpio) |
|---|
| 208 | + for_each_set_bit(bit, &val, gc->ngpio) |
|---|
| 232 | 209 | *bits |= bgpio_line2mask(gc, bit); |
|---|
| 233 | 210 | |
|---|
| 234 | 211 | return 0; |
|---|
| .. | .. |
|---|
| 293 | 270 | *set_mask = 0; |
|---|
| 294 | 271 | *clear_mask = 0; |
|---|
| 295 | 272 | |
|---|
| 296 | | - for (i = 0; i < gc->bgpio_bits; i++) { |
|---|
| 297 | | - if (*mask == 0) |
|---|
| 298 | | - break; |
|---|
| 299 | | - if (__test_and_clear_bit(i, mask)) { |
|---|
| 300 | | - if (test_bit(i, bits)) |
|---|
| 301 | | - *set_mask |= bgpio_line2mask(gc, i); |
|---|
| 302 | | - else |
|---|
| 303 | | - *clear_mask |= bgpio_line2mask(gc, i); |
|---|
| 304 | | - } |
|---|
| 273 | + for_each_set_bit(i, mask, gc->bgpio_bits) { |
|---|
| 274 | + if (test_bit(i, bits)) |
|---|
| 275 | + *set_mask |= bgpio_line2mask(gc, i); |
|---|
| 276 | + else |
|---|
| 277 | + *clear_mask |= bgpio_line2mask(gc, i); |
|---|
| 305 | 278 | } |
|---|
| 306 | 279 | } |
|---|
| 307 | 280 | |
|---|
| .. | .. |
|---|
| 376 | 349 | |
|---|
| 377 | 350 | spin_lock_irqsave(&gc->bgpio_lock, flags); |
|---|
| 378 | 351 | |
|---|
| 379 | | - if (gc->bgpio_dir_inverted) |
|---|
| 380 | | - gc->bgpio_dir |= bgpio_line2mask(gc, gpio); |
|---|
| 381 | | - else |
|---|
| 382 | | - gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); |
|---|
| 383 | | - gc->write_reg(gc->reg_dir, gc->bgpio_dir); |
|---|
| 352 | + gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); |
|---|
| 353 | + |
|---|
| 354 | + if (gc->reg_dir_in) |
|---|
| 355 | + gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); |
|---|
| 356 | + if (gc->reg_dir_out) |
|---|
| 357 | + gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); |
|---|
| 384 | 358 | |
|---|
| 385 | 359 | spin_unlock_irqrestore(&gc->bgpio_lock, flags); |
|---|
| 386 | 360 | |
|---|
| .. | .. |
|---|
| 389 | 363 | |
|---|
| 390 | 364 | static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) |
|---|
| 391 | 365 | { |
|---|
| 392 | | - /* Return 0 if output, 1 of input */ |
|---|
| 393 | | - if (gc->bgpio_dir_inverted) |
|---|
| 394 | | - return !!(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio)); |
|---|
| 395 | | - else |
|---|
| 396 | | - return !(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio)); |
|---|
| 366 | + /* Return 0 if output, 1 if input */ |
|---|
| 367 | + if (gc->bgpio_dir_unreadable) { |
|---|
| 368 | + if (gc->bgpio_dir & bgpio_line2mask(gc, gpio)) |
|---|
| 369 | + return GPIO_LINE_DIRECTION_OUT; |
|---|
| 370 | + return GPIO_LINE_DIRECTION_IN; |
|---|
| 371 | + } |
|---|
| 372 | + |
|---|
| 373 | + if (gc->reg_dir_out) { |
|---|
| 374 | + if (gc->read_reg(gc->reg_dir_out) & bgpio_line2mask(gc, gpio)) |
|---|
| 375 | + return GPIO_LINE_DIRECTION_OUT; |
|---|
| 376 | + return GPIO_LINE_DIRECTION_IN; |
|---|
| 377 | + } |
|---|
| 378 | + |
|---|
| 379 | + if (gc->reg_dir_in) |
|---|
| 380 | + if (!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio))) |
|---|
| 381 | + return GPIO_LINE_DIRECTION_OUT; |
|---|
| 382 | + |
|---|
| 383 | + return GPIO_LINE_DIRECTION_IN; |
|---|
| 397 | 384 | } |
|---|
| 398 | 385 | |
|---|
| 399 | | -static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) |
|---|
| 386 | +static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) |
|---|
| 400 | 387 | { |
|---|
| 401 | 388 | unsigned long flags; |
|---|
| 402 | 389 | |
|---|
| 403 | | - gc->set(gc, gpio, val); |
|---|
| 404 | | - |
|---|
| 405 | 390 | spin_lock_irqsave(&gc->bgpio_lock, flags); |
|---|
| 406 | 391 | |
|---|
| 407 | | - if (gc->bgpio_dir_inverted) |
|---|
| 408 | | - gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); |
|---|
| 409 | | - else |
|---|
| 410 | | - gc->bgpio_dir |= bgpio_line2mask(gc, gpio); |
|---|
| 411 | | - gc->write_reg(gc->reg_dir, gc->bgpio_dir); |
|---|
| 392 | + gc->bgpio_dir |= bgpio_line2mask(gc, gpio); |
|---|
| 393 | + |
|---|
| 394 | + if (gc->reg_dir_in) |
|---|
| 395 | + gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); |
|---|
| 396 | + if (gc->reg_dir_out) |
|---|
| 397 | + gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); |
|---|
| 412 | 398 | |
|---|
| 413 | 399 | spin_unlock_irqrestore(&gc->bgpio_lock, flags); |
|---|
| 400 | +} |
|---|
| 414 | 401 | |
|---|
| 402 | +static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio, |
|---|
| 403 | + int val) |
|---|
| 404 | +{ |
|---|
| 405 | + bgpio_dir_out(gc, gpio, val); |
|---|
| 406 | + gc->set(gc, gpio, val); |
|---|
| 407 | + return 0; |
|---|
| 408 | +} |
|---|
| 409 | + |
|---|
| 410 | +static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio, |
|---|
| 411 | + int val) |
|---|
| 412 | +{ |
|---|
| 413 | + gc->set(gc, gpio, val); |
|---|
| 414 | + bgpio_dir_out(gc, gpio, val); |
|---|
| 415 | 415 | return 0; |
|---|
| 416 | 416 | } |
|---|
| 417 | 417 | |
|---|
| .. | .. |
|---|
| 541 | 541 | void __iomem *dirin, |
|---|
| 542 | 542 | unsigned long flags) |
|---|
| 543 | 543 | { |
|---|
| 544 | | - if (dirout && dirin) { |
|---|
| 545 | | - return -EINVAL; |
|---|
| 546 | | - } else if (dirout) { |
|---|
| 547 | | - gc->reg_dir = dirout; |
|---|
| 548 | | - gc->direction_output = bgpio_dir_out; |
|---|
| 544 | + if (dirout || dirin) { |
|---|
| 545 | + gc->reg_dir_out = dirout; |
|---|
| 546 | + gc->reg_dir_in = dirin; |
|---|
| 547 | + if (flags & BGPIOF_NO_SET_ON_INPUT) |
|---|
| 548 | + gc->direction_output = bgpio_dir_out_dir_first; |
|---|
| 549 | + else |
|---|
| 550 | + gc->direction_output = bgpio_dir_out_val_first; |
|---|
| 549 | 551 | gc->direction_input = bgpio_dir_in; |
|---|
| 550 | 552 | gc->get_direction = bgpio_get_dir; |
|---|
| 551 | | - } else if (dirin) { |
|---|
| 552 | | - gc->reg_dir = dirin; |
|---|
| 553 | | - gc->direction_output = bgpio_dir_out; |
|---|
| 554 | | - gc->direction_input = bgpio_dir_in; |
|---|
| 555 | | - gc->get_direction = bgpio_get_dir; |
|---|
| 556 | | - gc->bgpio_dir_inverted = true; |
|---|
| 557 | 553 | } else { |
|---|
| 558 | 554 | if (flags & BGPIOF_NO_OUTPUT) |
|---|
| 559 | 555 | gc->direction_output = bgpio_dir_out_err; |
|---|
| .. | .. |
|---|
| 592 | 588 | * @dirout: MMIO address for the register to set the line as OUTPUT. It is assumed |
|---|
| 593 | 589 | * that setting a line to 1 in this register will turn that line into an |
|---|
| 594 | 590 | * output line. Conversely, setting the line to 0 will turn that line into |
|---|
| 595 | | - * an input. Either this or @dirin can be defined, but never both. |
|---|
| 591 | + * an input. |
|---|
| 596 | 592 | * @dirin: MMIO address for the register to set this line as INPUT. It is assumed |
|---|
| 597 | 593 | * that setting a line to 1 in this register will turn that line into an |
|---|
| 598 | 594 | * input line. Conversely, setting the line to 0 will turn that line into |
|---|
| 599 | | - * an output. Either this or @dirout can be defined, but never both. |
|---|
| 595 | + * an output. |
|---|
| 600 | 596 | * @flags: Different flags that will affect the behaviour of the device, such as |
|---|
| 601 | 597 | * endianness etc. |
|---|
| 602 | 598 | */ |
|---|
| .. | .. |
|---|
| 638 | 634 | if (gc->set == bgpio_set_set && |
|---|
| 639 | 635 | !(flags & BGPIOF_UNREADABLE_REG_SET)) |
|---|
| 640 | 636 | gc->bgpio_data = gc->read_reg(gc->reg_set); |
|---|
| 641 | | - if (gc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR)) |
|---|
| 642 | | - gc->bgpio_dir = gc->read_reg(gc->reg_dir); |
|---|
| 637 | + |
|---|
| 638 | + if (flags & BGPIOF_UNREADABLE_REG_DIR) |
|---|
| 639 | + gc->bgpio_dir_unreadable = true; |
|---|
| 640 | + |
|---|
| 641 | + /* |
|---|
| 642 | + * Inspect hardware to find initial direction setting. |
|---|
| 643 | + */ |
|---|
| 644 | + if ((gc->reg_dir_out || gc->reg_dir_in) && |
|---|
| 645 | + !(flags & BGPIOF_UNREADABLE_REG_DIR)) { |
|---|
| 646 | + if (gc->reg_dir_out) |
|---|
| 647 | + gc->bgpio_dir = gc->read_reg(gc->reg_dir_out); |
|---|
| 648 | + else if (gc->reg_dir_in) |
|---|
| 649 | + gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in); |
|---|
| 650 | + /* |
|---|
| 651 | + * If we have two direction registers, synchronise |
|---|
| 652 | + * input setting to output setting, the library |
|---|
| 653 | + * can not handle a line being input and output at |
|---|
| 654 | + * the same time. |
|---|
| 655 | + */ |
|---|
| 656 | + if (gc->reg_dir_out && gc->reg_dir_in) |
|---|
| 657 | + gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); |
|---|
| 658 | + } |
|---|
| 643 | 659 | |
|---|
| 644 | 660 | return ret; |
|---|
| 645 | 661 | } |
|---|