aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpio/pca953x.c75
1 files changed, 70 insertions, 5 deletions
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 2dae94fbabf4..e9d6d5bdd300 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -15,6 +15,10 @@
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/i2c.h> 16#include <linux/i2c.h>
17#include <linux/i2c/pca953x.h> 17#include <linux/i2c/pca953x.h>
18#ifdef CONFIG_OF_GPIO
19#include <linux/of_platform.h>
20#include <linux/of_gpio.h>
21#endif
18 22
19#include <asm/gpio.h> 23#include <asm/gpio.h>
20 24
@@ -49,6 +53,7 @@ struct pca953x_chip {
49 uint16_t reg_direction; 53 uint16_t reg_direction;
50 54
51 struct i2c_client *client; 55 struct i2c_client *client;
56 struct pca953x_platform_data *dyn_pdata;
52 struct gpio_chip gpio_chip; 57 struct gpio_chip gpio_chip;
53 char **names; 58 char **names;
54}; 59};
@@ -196,6 +201,54 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
196 gc->names = chip->names; 201 gc->names = chip->names;
197} 202}
198 203
204/*
205 * Handlers for alternative sources of platform_data
206 */
207#ifdef CONFIG_OF_GPIO
208/*
209 * Translate OpenFirmware node properties into platform_data
210 */
211static struct pca953x_platform_data *
212pca953x_get_alt_pdata(struct i2c_client *client)
213{
214 struct pca953x_platform_data *pdata;
215 struct device_node *node;
216 const uint16_t *val;
217
218 node = dev_archdata_get_node(&client->dev.archdata);
219 if (node == NULL)
220 return NULL;
221
222 pdata = kzalloc(sizeof(struct pca953x_platform_data), GFP_KERNEL);
223 if (pdata == NULL) {
224 dev_err(&client->dev, "Unable to allocate platform_data\n");
225 return NULL;
226 }
227
228 pdata->gpio_base = -1;
229 val = of_get_property(node, "linux,gpio-base", NULL);
230 if (val) {
231 if (*val < 0)
232 dev_warn(&client->dev,
233 "invalid gpio-base in device tree\n");
234 else
235 pdata->gpio_base = *val;
236 }
237
238 val = of_get_property(node, "polarity", NULL);
239 if (val)
240 pdata->invert = *val;
241
242 return pdata;
243}
244#else
245static struct pca953x_platform_data *
246pca953x_get_alt_pdata(struct i2c_client *client)
247{
248 return NULL;
249}
250#endif
251
199static int __devinit pca953x_probe(struct i2c_client *client, 252static int __devinit pca953x_probe(struct i2c_client *client,
200 const struct i2c_device_id *id) 253 const struct i2c_device_id *id)
201{ 254{
@@ -203,15 +256,25 @@ static int __devinit pca953x_probe(struct i2c_client *client,
203 struct pca953x_chip *chip; 256 struct pca953x_chip *chip;
204 int ret; 257 int ret;
205 258
259 chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
260 if (chip == NULL)
261 return -ENOMEM;
262
206 pdata = client->dev.platform_data; 263 pdata = client->dev.platform_data;
207 if (pdata == NULL) { 264 if (pdata == NULL) {
208 dev_dbg(&client->dev, "no platform data\n"); 265 pdata = pca953x_get_alt_pdata(client);
209 return -EINVAL; 266 /*
267 * Unlike normal platform_data, this is allocated
268 * dynamically and must be freed in the driver
269 */
270 chip->dyn_pdata = pdata;
210 } 271 }
211 272
212 chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); 273 if (pdata == NULL) {
213 if (chip == NULL) 274 dev_dbg(&client->dev, "no platform data\n");
214 return -ENOMEM; 275 ret = -EINVAL;
276 goto out_failed;
277 }
215 278
216 chip->client = client; 279 chip->client = client;
217 280
@@ -253,6 +316,7 @@ static int __devinit pca953x_probe(struct i2c_client *client,
253 return 0; 316 return 0;
254 317
255out_failed: 318out_failed:
319 kfree(chip->dyn_pdata);
256 kfree(chip); 320 kfree(chip);
257 return ret; 321 return ret;
258} 322}
@@ -280,6 +344,7 @@ static int pca953x_remove(struct i2c_client *client)
280 return ret; 344 return ret;
281 } 345 }
282 346
347 kfree(chip->dyn_pdata);
283 kfree(chip); 348 kfree(chip);
284 return 0; 349 return 0;
285} 350}