aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-01-21 13:21:50 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-01-21 13:34:46 -0500
commitc23bb602af24a635d0894aa7091e184385bf8a9f (patch)
treedb50ee79409e361bcaaaeb5efb884d49beedf94e /drivers/mfd
parent2e95e51e184bd107380881502ea0f483c4500706 (diff)
MFD: ucb1x00-core: fix gpiolib direction_output handling
gpiolib drivers should first set the output data before setting the direction to avoid putting glitches on an output signal. As an additional bonus, we tweak the code to avoid unnecessary register writes to the output and direction registers if they have no need to be updated. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/ucb1x00-core.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 8ebda97981e1..febc90cdef7e 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -148,16 +148,22 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
148{ 148{
149 struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); 149 struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
150 unsigned long flags; 150 unsigned long flags;
151 unsigned old, mask = 1 << offset;
151 152
152 spin_lock_irqsave(&ucb->io_lock, flags); 153 spin_lock_irqsave(&ucb->io_lock, flags);
153 ucb->io_dir |= (1 << offset); 154 old = ucb->io_out;
154 ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
155
156 if (value) 155 if (value)
157 ucb->io_out |= 1 << offset; 156 ucb->io_out |= mask;
158 else 157 else
159 ucb->io_out &= ~(1 << offset); 158 ucb->io_out &= ~mask;
160 ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); 159
160 if (old != ucb->io_out)
161 ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
162
163 if (!(ucb->io_dir & mask)) {
164 ucb->io_dir |= mask;
165 ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
166 }
161 spin_unlock_irqrestore(&ucb->io_lock, flags); 167 spin_unlock_irqrestore(&ucb->io_lock, flags);
162 168
163 return 0; 169 return 0;