aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/pca953x.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@pengutronix.de>2008-02-06 04:39:02 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-06 13:41:15 -0500
commitd1c057e31734426ba385e02291d97bdf06ba0c1d (patch)
tree46d85c501626fdc8db60f30a7bc6c3c45eef89dd /drivers/gpio/pca953x.c
parentad8dc96e3b2c3e28854e0de4ab49351ed547b30c (diff)
gpio: rename pca9539 driver
First part of an extension to let the pca9539 driver support more chips, starting with pca9534, pca9535, pca9536, pca9537, and pca9538. This renames the files and modifies the Makefile. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> 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/pca953x.c')
-rw-r--r--drivers/gpio/pca953x.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
new file mode 100644
index 00000000000..7fae4e500df
--- /dev/null
+++ b/drivers/gpio/pca953x.c
@@ -0,0 +1,271 @@
1/*
2 * pca9539.c - 16-bit I/O port with interrupt and reset
3 *
4 * Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
5 * Copyright (C) 2007 Marvell International Ltd.
6 *
7 * Derived from drivers/i2c/chips/pca9539.c
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 */
13
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/i2c.h>
17#include <linux/i2c/pca953x.h>
18
19#include <asm/gpio.h>
20
21
22#define NR_PCA9539_GPIOS 16
23
24#define PCA9539_INPUT 0
25#define PCA9539_OUTPUT 2
26#define PCA9539_INVERT 4
27#define PCA9539_DIRECTION 6
28
29struct pca9539_chip {
30 unsigned gpio_start;
31 uint16_t reg_output;
32 uint16_t reg_direction;
33
34 struct i2c_client *client;
35 struct gpio_chip gpio_chip;
36};
37
38/* NOTE: we can't currently rely on fault codes to come from SMBus
39 * calls, so we map all errors to EIO here and return zero otherwise.
40 */
41static int pca9539_write_reg(struct pca9539_chip *chip, int reg, uint16_t val)
42{
43 if (i2c_smbus_write_word_data(chip->client, reg, val) < 0)
44 return -EIO;
45 else
46 return 0;
47}
48
49static int pca9539_read_reg(struct pca9539_chip *chip, int reg, uint16_t *val)
50{
51 int ret;
52
53 ret = i2c_smbus_read_word_data(chip->client, reg);
54 if (ret < 0) {
55 dev_err(&chip->client->dev, "failed reading register\n");
56 return -EIO;
57 }
58
59 *val = (uint16_t)ret;
60 return 0;
61}
62
63static int pca9539_gpio_direction_input(struct gpio_chip *gc, unsigned off)
64{
65 struct pca9539_chip *chip;
66 uint16_t reg_val;
67 int ret;
68
69 chip = container_of(gc, struct pca9539_chip, gpio_chip);
70
71 reg_val = chip->reg_direction | (1u << off);
72 ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val);
73 if (ret)
74 return ret;
75
76 chip->reg_direction = reg_val;
77 return 0;
78}
79
80static int pca9539_gpio_direction_output(struct gpio_chip *gc,
81 unsigned off, int val)
82{
83 struct pca9539_chip *chip;
84 uint16_t reg_val;
85 int ret;
86
87 chip = container_of(gc, struct pca9539_chip, gpio_chip);
88
89 /* set output level */
90 if (val)
91 reg_val = chip->reg_output | (1u << off);
92 else
93 reg_val = chip->reg_output & ~(1u << off);
94
95 ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val);
96 if (ret)
97 return ret;
98
99 chip->reg_output = reg_val;
100
101 /* then direction */
102 reg_val = chip->reg_direction & ~(1u << off);
103 ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val);
104 if (ret)
105 return ret;
106
107 chip->reg_direction = reg_val;
108 return 0;
109}
110
111static int pca9539_gpio_get_value(struct gpio_chip *gc, unsigned off)
112{
113 struct pca9539_chip *chip;
114 uint16_t reg_val;
115 int ret;
116
117 chip = container_of(gc, struct pca9539_chip, gpio_chip);
118
119 ret = pca9539_read_reg(chip, PCA9539_INPUT, &reg_val);
120 if (ret < 0) {
121 /* NOTE: diagnostic already emitted; that's all we should
122 * do unless gpio_*_value_cansleep() calls become different
123 * from their nonsleeping siblings (and report faults).
124 */
125 return 0;
126 }
127
128 return (reg_val & (1u << off)) ? 1 : 0;
129}
130
131static void pca9539_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
132{
133 struct pca9539_chip *chip;
134 uint16_t reg_val;
135 int ret;
136
137 chip = container_of(gc, struct pca9539_chip, gpio_chip);
138
139 if (val)
140 reg_val = chip->reg_output | (1u << off);
141 else
142 reg_val = chip->reg_output & ~(1u << off);
143
144 ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val);
145 if (ret)
146 return;
147
148 chip->reg_output = reg_val;
149}
150
151static int pca9539_init_gpio(struct pca9539_chip *chip)
152{
153 struct gpio_chip *gc;
154
155 gc = &chip->gpio_chip;
156
157 gc->direction_input = pca9539_gpio_direction_input;
158 gc->direction_output = pca9539_gpio_direction_output;
159 gc->get = pca9539_gpio_get_value;
160 gc->set = pca9539_gpio_set_value;
161
162 gc->base = chip->gpio_start;
163 gc->ngpio = NR_PCA9539_GPIOS;
164 gc->label = "pca9539";
165
166 return gpiochip_add(gc);
167}
168
169static int __devinit pca9539_probe(struct i2c_client *client)
170{
171 struct pca9539_platform_data *pdata;
172 struct pca9539_chip *chip;
173 int ret;
174
175 pdata = client->dev.platform_data;
176 if (pdata == NULL)
177 return -ENODEV;
178
179 chip = kzalloc(sizeof(struct pca9539_chip), GFP_KERNEL);
180 if (chip == NULL)
181 return -ENOMEM;
182
183 chip->client = client;
184
185 chip->gpio_start = pdata->gpio_base;
186
187 /* initialize cached registers from their original values.
188 * we can't share this chip with another i2c master.
189 */
190 ret = pca9539_read_reg(chip, PCA9539_OUTPUT, &chip->reg_output);
191 if (ret)
192 goto out_failed;
193
194 ret = pca9539_read_reg(chip, PCA9539_DIRECTION, &chip->reg_direction);
195 if (ret)
196 goto out_failed;
197
198 /* set platform specific polarity inversion */
199 ret = pca9539_write_reg(chip, PCA9539_INVERT, pdata->invert);
200 if (ret)
201 goto out_failed;
202
203 ret = pca9539_init_gpio(chip);
204 if (ret)
205 goto out_failed;
206
207 if (pdata->setup) {
208 ret = pdata->setup(client, chip->gpio_chip.base,
209 chip->gpio_chip.ngpio, pdata->context);
210 if (ret < 0)
211 dev_warn(&client->dev, "setup failed, %d\n", ret);
212 }
213
214 i2c_set_clientdata(client, chip);
215 return 0;
216
217out_failed:
218 kfree(chip);
219 return ret;
220}
221
222static int pca9539_remove(struct i2c_client *client)
223{
224 struct pca9539_platform_data *pdata = client->dev.platform_data;
225 struct pca9539_chip *chip = i2c_get_clientdata(client);
226 int ret = 0;
227
228 if (pdata->teardown) {
229 ret = pdata->teardown(client, chip->gpio_chip.base,
230 chip->gpio_chip.ngpio, pdata->context);
231 if (ret < 0) {
232 dev_err(&client->dev, "%s failed, %d\n",
233 "teardown", ret);
234 return ret;
235 }
236 }
237
238 ret = gpiochip_remove(&chip->gpio_chip);
239 if (ret) {
240 dev_err(&client->dev, "%s failed, %d\n",
241 "gpiochip_remove()", ret);
242 return ret;
243 }
244
245 kfree(chip);
246 return 0;
247}
248
249static struct i2c_driver pca9539_driver = {
250 .driver = {
251 .name = "pca9539",
252 },
253 .probe = pca9539_probe,
254 .remove = pca9539_remove,
255};
256
257static int __init pca9539_init(void)
258{
259 return i2c_add_driver(&pca9539_driver);
260}
261module_init(pca9539_init);
262
263static void __exit pca9539_exit(void)
264{
265 i2c_del_driver(&pca9539_driver);
266}
267module_exit(pca9539_exit);
268
269MODULE_AUTHOR("eric miao <eric.miao@marvell.com>");
270MODULE_DESCRIPTION("GPIO expander driver for PCA9539");
271MODULE_LICENSE("GPL");