aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorUwe Hermann2010-03-05 19:46:57 +0100
committerUwe Hermann2010-03-05 19:46:57 +0100
commitf1a6e56f5c41e239736c25633c36abef84f71f78 (patch)
tree894040e58f41418ce7b3869f81ac18e839b50eaf /lib
parent54dfb9199623d5c394a5f1c0b75095d6a8d70c82 (diff)
gpio: Fix some issues with gpio_set_mode().
This patch, a slightly modified version of a patch from Thomas Otto, should fix the following two issues: - It generally sets the submited config to the mentioned GPIO pins but kills configs for other pins on the same GPIO port. So if we want to set PB6 and PB7 to push-pull and I2C2 SDA and SCL (PB10 and PB11) to open drain it's simply impossible, because the second config try kills the first. - The floating-bit thing isn't working correctly. If we enable a config for PB6 for instance, the same config will also apply to all following pins of that port (i.e. PB7-PB15). That's because the shifting isn't only done if a pin isn't to configure, if you are hitting a matching bit the shiftig is missing. I think shifting isn't nessessary for a separate variable. We have the counting index from the for statement. Both issues should now be fixed.
Diffstat (limited to 'lib')
-rw-r--r--lib/gpio.c34
1 files changed, 25 insertions, 9 deletions
diff --git a/lib/gpio.c b/lib/gpio.c
index 6d1d21e..abf47cf 100644
--- a/lib/gpio.c
+++ b/lib/gpio.c
@@ -38,19 +38,35 @@
void gpio_set_mode(u32 gpioport, u8 mode, u8 cnf, u16 gpios)
{
- u16 i, movingbit = 1, offset = 0;
- u32 crl = 0, crh = 0;
+ u16 i, offset = 0;
+ u32 crl = 0, crh = 0, tmp32 = 0;
+ /*
+ * We want to set the config only for the pins mentioned in gpios,
+ * but keeping the others, so read out the actual config first.
+ */
+ crl = GPIO_CRL(gpioport);
+ crh = GPIO_CRH(gpioport);
+
+ /* Iterate over all bits, use i as the bitnumber. */
for (i = 0; i < 16; i++) {
- if ((movingbit & gpios) != movingbit) {
- movingbit <<= 1;
+ /* Only set the config if the bit is set in gpios. */
+ if (!((1 << i) & gpios))
continue;
- }
+
+ /* Calculate bit offset. */
offset = (i < 8) ? (i * 4) : ((i - 8) * 4);
- if (i < 8)
- crl |= (mode << offset) | (cnf << (offset + 2));
- else
- crh |= (mode << offset) | (cnf << (offset + 2));
+
+ /* Use tmp32 to either modify crl or crh. */
+ tmp32 = (i < 8) ? crl : crh;
+
+ /* Modify bits are needed. */
+ tmp32 &= ~(0b1111 << offset); /* Clear the bits first. */
+ tmp32 |= (mode << offset) | (cnf << (offset + 2));
+
+ /* Write tmp32 into crl or crh, leave the other unchanged. */
+ crl = (i < 8) ? tmp32 : crl;
+ crh = (i >= 8) ? tmp32 : crh;
}
GPIO_CRL(gpioport) = crl;