aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-mmio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpio-mmio.c')
-rw-r--r--drivers/gpio/gpio-mmio.c108
1 files changed, 63 insertions, 45 deletions
diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c
index 7b14d6280e44..935292a30c99 100644
--- a/drivers/gpio/gpio-mmio.c
+++ b/drivers/gpio/gpio-mmio.c
@@ -136,8 +136,20 @@ static unsigned long bgpio_line2mask(struct gpio_chip *gc, unsigned int line)
136static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio) 136static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
137{ 137{
138 unsigned long pinmask = bgpio_line2mask(gc, gpio); 138 unsigned long pinmask = bgpio_line2mask(gc, gpio);
139 bool dir = !!(gc->bgpio_dir & pinmask);
139 140
140 if (gc->bgpio_dir & pinmask) 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 if (dir)
141 return !!(gc->read_reg(gc->reg_set) & pinmask); 153 return !!(gc->read_reg(gc->reg_set) & pinmask);
142 else 154 else
143 return !!(gc->read_reg(gc->reg_dat) & pinmask); 155 return !!(gc->read_reg(gc->reg_dat) & pinmask);
@@ -157,8 +169,13 @@ static int bgpio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask,
157 *bits &= ~*mask; 169 *bits &= ~*mask;
158 170
159 /* Exploit the fact that we know which directions are set */ 171 /* Exploit the fact that we know which directions are set */
160 set_mask = *mask & gc->bgpio_dir; 172 if (gc->bgpio_dir_inverted) {
161 get_mask = *mask & ~gc->bgpio_dir; 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 }
162 179
163 if (set_mask) 180 if (set_mask)
164 *bits |= gc->read_reg(gc->reg_set) & set_mask; 181 *bits |= gc->read_reg(gc->reg_set) & set_mask;
@@ -359,7 +376,10 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
359 376
360 spin_lock_irqsave(&gc->bgpio_lock, flags); 377 spin_lock_irqsave(&gc->bgpio_lock, flags);
361 378
362 gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); 379 if (gc->bgpio_dir_inverted)
380 gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
381 else
382 gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio);
363 gc->write_reg(gc->reg_dir, gc->bgpio_dir); 383 gc->write_reg(gc->reg_dir, gc->bgpio_dir);
364 384
365 spin_unlock_irqrestore(&gc->bgpio_lock, flags); 385 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
@@ -370,7 +390,10 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
370static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) 390static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
371{ 391{
372 /* Return 0 if output, 1 of input */ 392 /* Return 0 if output, 1 of input */
373 return !(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio)); 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));
374} 397}
375 398
376static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 399static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
@@ -381,37 +404,10 @@ static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
381 404
382 spin_lock_irqsave(&gc->bgpio_lock, flags); 405 spin_lock_irqsave(&gc->bgpio_lock, flags);
383 406
384 gc->bgpio_dir |= bgpio_line2mask(gc, gpio); 407 if (gc->bgpio_dir_inverted)
385 gc->write_reg(gc->reg_dir, gc->bgpio_dir); 408 gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio);
386 409 else
387 spin_unlock_irqrestore(&gc->bgpio_lock, flags); 410 gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
388
389 return 0;
390}
391
392static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio)
393{
394 unsigned long flags;
395
396 spin_lock_irqsave(&gc->bgpio_lock, flags);
397
398 gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
399 gc->write_reg(gc->reg_dir, gc->bgpio_dir);
400
401 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
402
403 return 0;
404}
405
406static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
407{
408 unsigned long flags;
409
410 gc->set(gc, gpio, val);
411
412 spin_lock_irqsave(&gc->bgpio_lock, flags);
413
414 gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio);
415 gc->write_reg(gc->reg_dir, gc->bgpio_dir); 411 gc->write_reg(gc->reg_dir, gc->bgpio_dir);
416 412
417 spin_unlock_irqrestore(&gc->bgpio_lock, flags); 413 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
@@ -419,12 +415,6 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
419 return 0; 415 return 0;
420} 416}
421 417
422static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio)
423{
424 /* Return 0 if output, 1 if input */
425 return !!(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio));
426}
427
428static int bgpio_setup_accessors(struct device *dev, 418static int bgpio_setup_accessors(struct device *dev,
429 struct gpio_chip *gc, 419 struct gpio_chip *gc,
430 bool byte_be) 420 bool byte_be)
@@ -560,9 +550,10 @@ static int bgpio_setup_direction(struct gpio_chip *gc,
560 gc->get_direction = bgpio_get_dir; 550 gc->get_direction = bgpio_get_dir;
561 } else if (dirin) { 551 } else if (dirin) {
562 gc->reg_dir = dirin; 552 gc->reg_dir = dirin;
563 gc->direction_output = bgpio_dir_out_inv; 553 gc->direction_output = bgpio_dir_out;
564 gc->direction_input = bgpio_dir_in_inv; 554 gc->direction_input = bgpio_dir_in;
565 gc->get_direction = bgpio_get_dir_inv; 555 gc->get_direction = bgpio_get_dir;
556 gc->bgpio_dir_inverted = true;
566 } else { 557 } else {
567 if (flags & BGPIOF_NO_OUTPUT) 558 if (flags & BGPIOF_NO_OUTPUT)
568 gc->direction_output = bgpio_dir_out_err; 559 gc->direction_output = bgpio_dir_out_err;
@@ -582,6 +573,33 @@ static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin)
582 return -EINVAL; 573 return -EINVAL;
583} 574}
584 575
576/**
577 * bgpio_init() - Initialize generic GPIO accessor functions
578 * @gc: the GPIO chip to set up
579 * @dev: the parent device of the new GPIO chip (compulsory)
580 * @sz: the size (width) of the MMIO registers in bytes, typically 1, 2 or 4
581 * @dat: MMIO address for the register to READ the value of the GPIO lines, it
582 * is expected that a 1 in the corresponding bit in this register means the
583 * line is asserted
584 * @set: MMIO address for the register to SET the value of the GPIO lines, it is
585 * expected that we write the line with 1 in this register to drive the GPIO line
586 * high.
587 * @clr: MMIO address for the register to CLEAR the value of the GPIO lines, it is
588 * expected that we write the line with 1 in this register to drive the GPIO line
589 * low. It is allowed to leave this address as NULL, in that case the SET register
590 * will be assumed to also clear the GPIO lines, by actively writing the line
591 * with 0.
592 * @dirout: MMIO address for the register to set the line as OUTPUT. It is assumed
593 * that setting a line to 1 in this register will turn that line into an
594 * 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.
596 * @dirin: MMIO address for the register to set this line as INPUT. It is assumed
597 * that setting a line to 1 in this register will turn that line into an
598 * 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.
600 * @flags: Different flags that will affect the behaviour of the device, such as
601 * endianness etc.
602 */
585int bgpio_init(struct gpio_chip *gc, struct device *dev, 603int bgpio_init(struct gpio_chip *gc, struct device *dev,
586 unsigned long sz, void __iomem *dat, void __iomem *set, 604 unsigned long sz, void __iomem *dat, void __iomem *set,
587 void __iomem *clr, void __iomem *dirout, void __iomem *dirin, 605 void __iomem *clr, void __iomem *dirout, void __iomem *dirin,