diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2008-07-21 17:21:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-22 12:59:41 -0400 |
commit | 1673ad52bd9a3c747e596a76e65c55981ea651e3 (patch) | |
tree | 9e018b1d511a96f745fc870bfdf8bf53759c25ae /drivers/gpio | |
parent | 0c36ec31473593aa937ff04f3b3b630e81512734 (diff) |
gpio: pcf857x: add lock and handle more chips
Two small updates to the pcf857x driver: (a) the max732[89] chips are
also second sources for the pcf8574/a, and (b) add a mutex to prevent
trashing the cached state. Adding the lock is effectively a bugfix,
although it seems unlikely that anyone would have run into the issue it
protects against.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 5 | ||||
-rw-r--r-- | drivers/gpio/pcf857x.c | 33 |
2 files changed, 32 insertions, 6 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9e0c4fbfc51a..fced1909cbba 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -45,7 +45,7 @@ config GPIO_PCA953X | |||
45 | will be called pca953x. | 45 | will be called pca953x. |
46 | 46 | ||
47 | config GPIO_PCF857X | 47 | config GPIO_PCF857X |
48 | tristate "PCF857x, PCA857x, and PCA967x I2C GPIO expanders" | 48 | tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders" |
49 | depends on I2C | 49 | depends on I2C |
50 | help | 50 | help |
51 | Say yes here to provide access to most "quasi-bidirectional" I2C | 51 | Say yes here to provide access to most "quasi-bidirectional" I2C |
@@ -54,7 +54,8 @@ config GPIO_PCF857X | |||
54 | some of them. Compatible models include: | 54 | some of them. Compatible models include: |
55 | 55 | ||
56 | 8 bits: pcf8574, pcf8574a, pca8574, pca8574a, | 56 | 8 bits: pcf8574, pcf8574a, pca8574, pca8574a, |
57 | pca9670, pca9672, pca9674, pca9674a | 57 | pca9670, pca9672, pca9674, pca9674a, |
58 | max7328, max7329 | ||
58 | 59 | ||
59 | 16 bits: pcf8575, pcf8575c, pca8575, | 60 | 16 bits: pcf8575, pcf8575c, pca8575, |
60 | pca9671, pca9673, pca9675 | 61 | pca9671, pca9673, pca9675 |
diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c index aa6cc8b2a2bc..d25d356c4f20 100644 --- a/drivers/gpio/pcf857x.c +++ b/drivers/gpio/pcf857x.c | |||
@@ -37,6 +37,8 @@ static const struct i2c_device_id pcf857x_id[] = { | |||
37 | { "pca9671", 16 }, | 37 | { "pca9671", 16 }, |
38 | { "pca9673", 16 }, | 38 | { "pca9673", 16 }, |
39 | { "pca9675", 16 }, | 39 | { "pca9675", 16 }, |
40 | { "max7328", 8 }, | ||
41 | { "max7329", 8 }, | ||
40 | { } | 42 | { } |
41 | }; | 43 | }; |
42 | MODULE_DEVICE_TABLE(i2c, pcf857x_id); | 44 | MODULE_DEVICE_TABLE(i2c, pcf857x_id); |
@@ -56,6 +58,7 @@ MODULE_DEVICE_TABLE(i2c, pcf857x_id); | |||
56 | struct pcf857x { | 58 | struct pcf857x { |
57 | struct gpio_chip chip; | 59 | struct gpio_chip chip; |
58 | struct i2c_client *client; | 60 | struct i2c_client *client; |
61 | struct mutex lock; /* protect 'out' */ | ||
59 | unsigned out; /* software latch */ | 62 | unsigned out; /* software latch */ |
60 | }; | 63 | }; |
61 | 64 | ||
@@ -66,9 +69,14 @@ struct pcf857x { | |||
66 | static int pcf857x_input8(struct gpio_chip *chip, unsigned offset) | 69 | static int pcf857x_input8(struct gpio_chip *chip, unsigned offset) |
67 | { | 70 | { |
68 | struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); | 71 | struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); |
72 | int status; | ||
69 | 73 | ||
74 | mutex_lock(&gpio->lock); | ||
70 | gpio->out |= (1 << offset); | 75 | gpio->out |= (1 << offset); |
71 | return i2c_smbus_write_byte(gpio->client, gpio->out); | 76 | status = i2c_smbus_write_byte(gpio->client, gpio->out); |
77 | mutex_unlock(&gpio->lock); | ||
78 | |||
79 | return status; | ||
72 | } | 80 | } |
73 | 81 | ||
74 | static int pcf857x_get8(struct gpio_chip *chip, unsigned offset) | 82 | static int pcf857x_get8(struct gpio_chip *chip, unsigned offset) |
@@ -84,12 +92,17 @@ static int pcf857x_output8(struct gpio_chip *chip, unsigned offset, int value) | |||
84 | { | 92 | { |
85 | struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); | 93 | struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); |
86 | unsigned bit = 1 << offset; | 94 | unsigned bit = 1 << offset; |
95 | int status; | ||
87 | 96 | ||
97 | mutex_lock(&gpio->lock); | ||
88 | if (value) | 98 | if (value) |
89 | gpio->out |= bit; | 99 | gpio->out |= bit; |
90 | else | 100 | else |
91 | gpio->out &= ~bit; | 101 | gpio->out &= ~bit; |
92 | return i2c_smbus_write_byte(gpio->client, gpio->out); | 102 | status = i2c_smbus_write_byte(gpio->client, gpio->out); |
103 | mutex_unlock(&gpio->lock); | ||
104 | |||
105 | return status; | ||
93 | } | 106 | } |
94 | 107 | ||
95 | static void pcf857x_set8(struct gpio_chip *chip, unsigned offset, int value) | 108 | static void pcf857x_set8(struct gpio_chip *chip, unsigned offset, int value) |
@@ -124,9 +137,14 @@ static int i2c_read_le16(struct i2c_client *client) | |||
124 | static int pcf857x_input16(struct gpio_chip *chip, unsigned offset) | 137 | static int pcf857x_input16(struct gpio_chip *chip, unsigned offset) |
125 | { | 138 | { |
126 | struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); | 139 | struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); |
140 | int status; | ||
127 | 141 | ||
142 | mutex_lock(&gpio->lock); | ||
128 | gpio->out |= (1 << offset); | 143 | gpio->out |= (1 << offset); |
129 | return i2c_write_le16(gpio->client, gpio->out); | 144 | status = i2c_write_le16(gpio->client, gpio->out); |
145 | mutex_unlock(&gpio->lock); | ||
146 | |||
147 | return status; | ||
130 | } | 148 | } |
131 | 149 | ||
132 | static int pcf857x_get16(struct gpio_chip *chip, unsigned offset) | 150 | static int pcf857x_get16(struct gpio_chip *chip, unsigned offset) |
@@ -142,12 +160,17 @@ static int pcf857x_output16(struct gpio_chip *chip, unsigned offset, int value) | |||
142 | { | 160 | { |
143 | struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); | 161 | struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); |
144 | unsigned bit = 1 << offset; | 162 | unsigned bit = 1 << offset; |
163 | int status; | ||
145 | 164 | ||
165 | mutex_lock(&gpio->lock); | ||
146 | if (value) | 166 | if (value) |
147 | gpio->out |= bit; | 167 | gpio->out |= bit; |
148 | else | 168 | else |
149 | gpio->out &= ~bit; | 169 | gpio->out &= ~bit; |
150 | return i2c_write_le16(gpio->client, gpio->out); | 170 | status = i2c_write_le16(gpio->client, gpio->out); |
171 | mutex_unlock(&gpio->lock); | ||
172 | |||
173 | return status; | ||
151 | } | 174 | } |
152 | 175 | ||
153 | static void pcf857x_set16(struct gpio_chip *chip, unsigned offset, int value) | 176 | static void pcf857x_set16(struct gpio_chip *chip, unsigned offset, int value) |
@@ -173,6 +196,8 @@ static int pcf857x_probe(struct i2c_client *client, | |||
173 | if (!gpio) | 196 | if (!gpio) |
174 | return -ENOMEM; | 197 | return -ENOMEM; |
175 | 198 | ||
199 | mutex_init(&gpio->lock); | ||
200 | |||
176 | gpio->chip.base = pdata->gpio_base; | 201 | gpio->chip.base = pdata->gpio_base; |
177 | gpio->chip.can_sleep = 1; | 202 | gpio->chip.can_sleep = 1; |
178 | gpio->chip.owner = THIS_MODULE; | 203 | gpio->chip.owner = THIS_MODULE; |