[PATCH 2/2] Reorder initialization to better support device tree data

Bill Gatliff bgat at billgatliff.com
Wed Jan 6 15:30:36 EST 2010


This patch changes the initialization sequence implemented in
pca953x_probe(), so as to simplify the retrieval of device tree
data when device trees are used.  Incorporates the new
of_i2c_gpiochip_add() function to register the newly-added GPIOs.

Signed-off-by: Bill Gatliff <bgat at billgatliff.com>
---
 drivers/gpio/pca953x.c |  130 +++++++++++++++++++++--------------------------
 1 files changed, 58 insertions(+), 72 deletions(-)

diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 9c70963..3a20e2f 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2005 Ben Gardner <bgardner at wabtec.com>
  *  Copyright (C) 2007 Marvell International Ltd.
+ *  Copyright (C) 2010 Bill Gatliff <bgat at billgatliff.com>
  *
  *  Derived from drivers/i2c/chips/pca9539.c
  *
@@ -53,13 +54,13 @@ static const struct i2c_device_id pca953x_id[] = {
 MODULE_DEVICE_TABLE(i2c, pca953x_id);
 
 struct pca953x_chip {
-	unsigned gpio_start;
 	uint16_t reg_output;
 	uint16_t reg_direction;
+	uint16_t reg_invert;
 	struct gpio_chip *gpio_chip;
 
 	struct i2c_client *client;
-	struct pca953x_platform_data *dyn_pdata;
+	struct pca953x_platform_data *pdata;
 	char **names;
 
 #ifdef CONFIG_OF_GPIO
@@ -214,7 +215,6 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
 	gc->set = pca953x_gpio_set_value;
 	gc->can_sleep = 1;
 
-	gc->base = chip->gpio_start;
 	gc->ngpio = gpios;
 	gc->label = chip->client->name;
 	gc->dev = &chip->client->dev;
@@ -222,119 +222,107 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
 	gc->names = chip->names;
 }
 
-/*
- * Handlers for alternative sources of platform_data
- */
 #ifdef CONFIG_OF_GPIO
-/*
- * Translate OpenFirmware node properties into platform_data
- */
-static struct pca953x_platform_data *
-pca953x_get_alt_pdata(struct i2c_client *client)
+static int __devinit pca953x_get_of_pdata(struct pca953x_chip *chip)
 {
-	struct pca953x_platform_data *pdata;
 	struct device_node *node;
 	const uint16_t *val;
 
-	node = dev_archdata_get_node(&client->dev.archdata);
-	if (node == NULL)
-		return NULL;
+	node = dev_archdata_get_node(&chip->client->dev.archdata);
+	if (!node)
+		return -EINVAL;
 
-	pdata = kzalloc(sizeof(struct pca953x_platform_data), GFP_KERNEL);
-	if (pdata == NULL) {
-		dev_err(&client->dev, "Unable to allocate platform_data\n");
-		return NULL;
-	}
-
-	pdata->gpio_base = -1;
-	val = of_get_property(node, "linux,gpio-base", NULL);
-	if (val) {
-		if (*val < 0)
-			dev_warn(&client->dev,
-				 "invalid gpio-base in device tree\n");
-		else
-			pdata->gpio_base = *val;
-	}
+	chip->gpio_chip->base = -1;
+	chip->i2c_gc.of_gc.gpio_cells = 2;
 
 	val = of_get_property(node, "polarity", NULL);
 	if (val)
-		pdata->invert = *val;
+		chip->reg_invert = *val;
 
-	return pdata;
+	return 0;
 }
-#else
-static struct pca953x_platform_data *
-pca953x_get_alt_pdata(struct i2c_client *client)
+
+static int __devinit pca953x_gpiochip_add(struct pca953x_chip *chip)
 {
-	return NULL;
+	struct device_node *node;
+	node = dev_archdata_get_node(&chip->client->dev.archdata);
+	return of_i2c_gpiochip_add(node, &chip->i2c_gc);
 }
 #endif
 
+static int __devinit pca953x_get_pdata(struct pca953x_chip *chip)
+{
+	struct pca953x_platform_data *pdata;
+
+	pdata = dev_get_platdata(&chip->client->dev);
+	if (!pdata)
+		return -EINVAL;
+
+	chip->pdata = pdata;
+	chip->gpio_chip->base = pdata->gpio_base;
+	chip->reg_invert = pdata->invert;
+
+	return 0;
+}
+
 static int __devinit pca953x_probe(struct i2c_client *client,
 				   const struct i2c_device_id *id)
 {
-	struct pca953x_platform_data *pdata;
 	struct pca953x_chip *chip;
 	int ret;
 
 	chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
 	if (chip == NULL)
 		return -ENOMEM;
+	chip->client = client;
 
 #ifdef CONFIG_OF_GPIO
 	chip->gpio_chip = &chip->i2c_gc.of_gc.gc;
+	if (!dev_get_platdata(&client->dev))
+		pca953x_get_of_pdata(chip);
 #else
 	chip->gpio_chip = &chip->gc;
-#endif
-
-	pdata = client->dev.platform_data;
-	if (pdata == NULL) {
-		pdata = pca953x_get_alt_pdata(client);
-		/*
-		 * Unlike normal platform_data, this is allocated
-		 * dynamically and must be freed in the driver
-		 */
-		chip->dyn_pdata = pdata;
-	}
-
-	if (pdata == NULL) {
-		dev_dbg(&client->dev, "no platform data\n");
+	if (!client->dev.platform_data)
+	{
+		dev_err(&client->dev, "no platform data\n");
 		ret = -EINVAL;
 		goto out_failed;
 	}
+#endif
 
-	chip->client = client;
-
-	chip->gpio_start = pdata->gpio_base;
+	pca953x_setup_gpio(chip, id->driver_data);
 
-	chip->names = pdata->names;
+	if (dev_get_platdata(&client->dev))
+		pca953x_get_pdata(chip);
 
-	/* initialize cached registers from their original values.
-	 * we can't share this chip with another i2c master.
+	/*
+	 * Note: we cache the values of some registers locally; this
+	 * means that other i2c masters, if any, cannot share this
+	 * chip with us!
 	 */
-	pca953x_setup_gpio(chip, id->driver_data);
 
 	ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
 	if (ret)
 		goto out_failed;
-
 	ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &chip->reg_direction);
 	if (ret)
 		goto out_failed;
-
-	/* set platform specific polarity inversion */
-	ret = pca953x_write_reg(chip, PCA953X_INVERT, pdata->invert);
+	ret = pca953x_write_reg(chip, PCA953X_INVERT, chip->reg_invert);
 	if (ret)
 		goto out_failed;
 
-
+#ifdef CONFIG_OF_GPIO
+	ret = pca953x_gpiochip_add(chip);
+#else
 	ret = gpiochip_add(chip->gpio_chip);
+#endif
 	if (ret)
 		goto out_failed;
 
-	if (pdata->setup) {
-		ret = pdata->setup(client, chip->gpio_chip->base,
-				chip->gpio_chip->ngpio, pdata->context);
+	if (chip->pdata && chip->pdata->setup) {
+		ret = chip->pdata->setup(client, chip->gpio_chip->base,
+				chip->gpio_chip->ngpio,
+					 chip->pdata->context);
 		if (ret < 0)
 			dev_warn(&client->dev, "setup failed, %d\n", ret);
 	}
@@ -343,20 +331,19 @@ static int __devinit pca953x_probe(struct i2c_client *client,
 	return 0;
 
 out_failed:
-	kfree(chip->dyn_pdata);
 	kfree(chip);
 	return ret;
 }
 
 static int pca953x_remove(struct i2c_client *client)
 {
-	struct pca953x_platform_data *pdata = client->dev.platform_data;
 	struct pca953x_chip *chip = i2c_get_clientdata(client);
 	int ret = 0;
 
-	if (pdata->teardown) {
-		ret = pdata->teardown(client, chip->gpio_chip->base,
-				chip->gpio_chip->ngpio, pdata->context);
+	if (chip->pdata && chip->pdata->teardown) {
+		ret = chip->pdata->teardown(client, chip->gpio_chip->base,
+					    chip->gpio_chip->ngpio,
+					    chip->pdata->context);
 		if (ret < 0) {
 			dev_err(&client->dev, "%s failed, %d\n",
 					"teardown", ret);
@@ -371,7 +358,6 @@ static int pca953x_remove(struct i2c_client *client)
 		return ret;
 	}
 
-	kfree(chip->dyn_pdata);
 	kfree(chip);
 	return 0;
 }
-- 
1.6.5



More information about the Linuxppc-dev mailing list