Re: [PATCH v1] i2c-hid: introduce HID over i2c specification implementation

2012-10-02 Thread Shubhrajyoti Datta
On Fri, Sep 14, 2012 at 7:11 PM, benjamin.tissoires
 wrote:
> From: Benjamin Tissoires 
>
> Microsoft published the protocol specification of HID over i2c:
> http://msdn.microsoft.com/en-us/library/windows/hardware/hh852380.aspx
>
> This patch introduces an implementation of this protocol.
>
> This implementation does not includes the ACPI part of the specification.
> This will come when ACPI 5.0 devices will be available.
>
> Once the ACPI part will be done, OEM will not have to declare HID over I2C
> devices in their platform specific driver.
>
> Signed-off-by: Benjamin Tissoires 
> ---
>
> Hi,
>
> this is finally my first implementation of HID over I2C.
>
> This has been tested on an Elan Microelectronics HID over I2C device, with
> a Samsung Exynos 4412 board.
>
> Any comments are welcome.
>
> Cheers,
> Benjamin
>
>  drivers/i2c/Kconfig |8 +
>  drivers/i2c/Makefile|1 +
>  drivers/i2c/i2c-hid.c   | 1027 
> +++
>  include/linux/i2c/i2c-hid.h |   35 ++
>  4 files changed, 1071 insertions(+)
>  create mode 100644 drivers/i2c/i2c-hid.c
>  create mode 100644 include/linux/i2c/i2c-hid.h
>
> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
> index 5a3bb3d..5adf65a 100644
> --- a/drivers/i2c/Kconfig
> +++ b/drivers/i2c/Kconfig
> @@ -47,6 +47,14 @@ config I2C_CHARDEV
>   This support is also available as a module.  If so, the module
>   will be called i2c-dev.
>
> +config I2C_HID
> +   tristate "HID over I2C bus"
> +   help
> + Say Y here to use the HID over i2c protocol implementation.
> +
> + This support is also available as a module.  If so, the module
> + will be called i2c-hid.
> +
>  config I2C_MUX
> tristate "I2C bus multiplexing support"
> help
> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
> index beee6b2..8f38116 100644
> --- a/drivers/i2c/Makefile
> +++ b/drivers/i2c/Makefile
> @@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
>  obj-$(CONFIG_I2C)  += i2c-core.o
>  obj-$(CONFIG_I2C_SMBUS)+= i2c-smbus.o
>  obj-$(CONFIG_I2C_CHARDEV)  += i2c-dev.o
> +obj-$(CONFIG_I2C_HID)  += i2c-hid.o
>  obj-$(CONFIG_I2C_MUX)  += i2c-mux.o
>  obj-y  += algos/ busses/ muxes/
>
> diff --git a/drivers/i2c/i2c-hid.c b/drivers/i2c/i2c-hid.c
> new file mode 100644
> index 000..eb17d8c
> --- /dev/null
> +++ b/drivers/i2c/i2c-hid.c
> @@ -0,0 +1,1027 @@
> +/*
> + * HID over I2C protocol implementation
> + *
> + * Copyright (c) 2012 Benjamin Tissoires 
> + * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France
> + *
> + * This code is partly based on "USB HID support for Linux":
> + *
> + *  Copyright (c) 1999 Andreas Gal
> + *  Copyright (c) 2000-2005 Vojtech Pavlik 
> + *  Copyright (c) 2005 Michael Haboustak  for Concept2, 
> Inc
> + *  Copyright (c) 2007-2008 Oliver Neukum
> + *  Copyright (c) 2006-2010 Jiri Kosina
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License.  See the file COPYING in the main directory of this archive for
> + * more details.
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include 
> +
> +#include 
> +#include 
> +#include 
> +
> +#define DRIVER_NAME"i2chid"
> +#define DRIVER_DESC"HID over I2C core driver"
> +
> +#define I2C_HID_COMMAND_TRIES  3
> +
> +/* flags */
> +#define I2C_HID_STARTED(1 << 0)
> +#define I2C_HID_OUT_RUNNING(1 << 1)
> +#define I2C_HID_IN_RUNNING (1 << 2)
> +#define I2C_HID_RESET_PENDING  (1 << 3)
> +#define I2C_HID_SUSPENDED  (1 << 4)
> +
> +#define I2C_HID_PWR_ON 0x00
> +#define I2C_HID_PWR_SLEEP  0x01
> +
> +/* debug option */
> +static bool debug = false;
> +module_param(debug, bool, 0444);
> +MODULE_PARM_DESC(debug, "print a lot of debug informations");
> +
> +struct i2chid_desc {
> +   __le16 wHIDDescLength;
> +   __le16 bcdVersion;
> +   __le16 wReportDescLength;
> +   __le16 wReportDescRegister;
> +   __le16 wInputRegister;
> +   __le16 wMaxInputLength;
> +   __le16 wOutputRegister;
> +   __le16 wMaxOutputLength;
> +   __le16 wCommandRegister;
> +   __le16 wDataRegister;
> +   __le16 wVendorID;
> +   __le16 wProductID;
> +   __le16 wVersionID;
> +} __packed;
> +
> +struct i2chid_cmd {
> +   enum {
> +   /* fecth HID descriptor */
> +   HID_DESCR_CMD,
> +
> +   /* fetch report descriptors */
> +   HID_REPORT_DESCR_CMD,
> +
> +   /* commands */
> +   HID_RESET_CMD,
> +   HID_GET_REPORT_CMD,
> +   HID_SET_REPORT_CMD,
> +   HID_GET_IDLE_CMD,
> +   HID_SET_IDLE_CMD,
> +   HID_GET_PROTOCOL_CMD,
> +   HID_SET_PROTOCOL_CMD,
> +

Re: [PATCH v1] i2c-hid: introduce HID over i2c specification implementation

2012-10-02 Thread Jian-Jhong Ding
Hi Benjamin,

I have one little question about __i2chid_command(), please see below.

"benjamin.tissoires"  writes:
> From: Benjamin Tissoires 
>
> Microsoft published the protocol specification of HID over i2c:
> http://msdn.microsoft.com/en-us/library/windows/hardware/hh852380.aspx
>
> This patch introduces an implementation of this protocol.
>
> This implementation does not includes the ACPI part of the specification.
> This will come when ACPI 5.0 devices will be available.
>
> Once the ACPI part will be done, OEM will not have to declare HID over I2C
> devices in their platform specific driver.
>
> Signed-off-by: Benjamin Tissoires 
> ---
>
> Hi,
>
> this is finally my first implementation of HID over I2C.
>
> This has been tested on an Elan Microelectronics HID over I2C device, with
> a Samsung Exynos 4412 board.
>
> Any comments are welcome.
>
> Cheers,
> Benjamin
>
>  drivers/i2c/Kconfig |8 +
>  drivers/i2c/Makefile|1 +
>  drivers/i2c/i2c-hid.c   | 1027 
> +++
>  include/linux/i2c/i2c-hid.h |   35 ++
>  4 files changed, 1071 insertions(+)
>  create mode 100644 drivers/i2c/i2c-hid.c
>  create mode 100644 include/linux/i2c/i2c-hid.h
>
> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
> index 5a3bb3d..5adf65a 100644
> --- a/drivers/i2c/Kconfig
> +++ b/drivers/i2c/Kconfig
> @@ -47,6 +47,14 @@ config I2C_CHARDEV
> This support is also available as a module.  If so, the module 
> will be called i2c-dev.
>  
> +config I2C_HID
> + tristate "HID over I2C bus"
> + help
> +   Say Y here to use the HID over i2c protocol implementation.
> +
> +   This support is also available as a module.  If so, the module
> +   will be called i2c-hid.
> +
>  config I2C_MUX
>   tristate "I2C bus multiplexing support"
>   help
> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
> index beee6b2..8f38116 100644
> --- a/drivers/i2c/Makefile
> +++ b/drivers/i2c/Makefile
> @@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_BOARDINFO)   += i2c-boardinfo.o
>  obj-$(CONFIG_I2C)+= i2c-core.o
>  obj-$(CONFIG_I2C_SMBUS)  += i2c-smbus.o
>  obj-$(CONFIG_I2C_CHARDEV)+= i2c-dev.o
> +obj-$(CONFIG_I2C_HID)+= i2c-hid.o
>  obj-$(CONFIG_I2C_MUX)+= i2c-mux.o
>  obj-y+= algos/ busses/ muxes/
>  
> diff --git a/drivers/i2c/i2c-hid.c b/drivers/i2c/i2c-hid.c
> new file mode 100644
> index 000..eb17d8c
> --- /dev/null
> +++ b/drivers/i2c/i2c-hid.c
> @@ -0,0 +1,1027 @@
> +/*
> + * HID over I2C protocol implementation
> + *
> + * Copyright (c) 2012 Benjamin Tissoires 
> + * Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France
> + *
> + * This code is partly based on "USB HID support for Linux":
> + *
> + *  Copyright (c) 1999 Andreas Gal
> + *  Copyright (c) 2000-2005 Vojtech Pavlik 
> + *  Copyright (c) 2005 Michael Haboustak  for Concept2, 
> Inc
> + *  Copyright (c) 2007-2008 Oliver Neukum
> + *  Copyright (c) 2006-2010 Jiri Kosina
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License.  See the file COPYING in the main directory of this archive for
> + * more details.
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include 
> +
> +#include 
> +#include 
> +#include 
> +
> +#define DRIVER_NAME  "i2chid"
> +#define DRIVER_DESC  "HID over I2C core driver"
> +
> +#define I2C_HID_COMMAND_TRIES3
> +
> +/* flags */
> +#define I2C_HID_STARTED  (1 << 0)
> +#define I2C_HID_OUT_RUNNING  (1 << 1)
> +#define I2C_HID_IN_RUNNING   (1 << 2)
> +#define I2C_HID_RESET_PENDING(1 << 3)
> +#define I2C_HID_SUSPENDED(1 << 4)
> +
> +#define I2C_HID_PWR_ON   0x00
> +#define I2C_HID_PWR_SLEEP0x01
> +
> +/* debug option */
> +static bool debug = false;
> +module_param(debug, bool, 0444);
> +MODULE_PARM_DESC(debug, "print a lot of debug informations");
> +
> +struct i2chid_desc {
> + __le16 wHIDDescLength;
> + __le16 bcdVersion;
> + __le16 wReportDescLength;
> + __le16 wReportDescRegister;
> + __le16 wInputRegister;
> + __le16 wMaxInputLength;
> + __le16 wOutputRegister;
> + __le16 wMaxOutputLength;
> + __le16 wCommandRegister;
> + __le16 wDataRegister;
> + __le16 wVendorID;
> + __le16 wProductID;
> + __le16 wVersionID;
> +} __packed;
> +
> +struct i2chid_cmd {
> + enum {
> + /* fecth HID descriptor */
> + HID_DESCR_CMD,
> +
> + /* fetch report descriptors */
> + HID_REPORT_DESCR_CMD,
> +
> + /* commands */
> + HID_RESET_CMD,
> + HID_GET_REPORT_CMD,
> + HID_SET_REPORT_CMD,
> + HID_GET_IDLE_CMD,
> + HID_SET_IDLE_CMD,
> + HID_GET_PROTOCOL_CMD,
> + HID_SET_PROTOCOL_CMD,
> +   

[PATCH] i2c: s3c2410: use clk_prepare_enable and clk_disable_unprepare

2012-10-02 Thread Thomas Abraham
Convert clk_enable/clk_disable to clk_prepare_enable/clk_disable_unprepare
calls as required by common clock framework.

Signed-off-by: Thomas Abraham 
---
 drivers/i2c/busses/i2c-s3c2410.c |   18 +-
 1 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 4d07dea..3e0335f 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -601,14 +601,14 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
int ret;
 
pm_runtime_get_sync(&adap->dev);
-   clk_enable(i2c->clk);
+   clk_prepare_enable(i2c->clk);
 
for (retry = 0; retry < adap->retries; retry++) {
 
ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
 
if (ret != -EAGAIN) {
-   clk_disable(i2c->clk);
+   clk_disable_unprepare(i2c->clk);
pm_runtime_put(&adap->dev);
return ret;
}
@@ -618,7 +618,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
udelay(100);
}
 
-   clk_disable(i2c->clk);
+   clk_disable_unprepare(i2c->clk);
pm_runtime_put(&adap->dev);
return -EREMOTEIO;
 }
@@ -977,7 +977,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 
dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
 
-   clk_enable(i2c->clk);
+   clk_prepare_enable(i2c->clk);
 
/* map the registers */
 
@@ -1065,7 +1065,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
pm_runtime_enable(&i2c->adap.dev);
 
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
-   clk_disable(i2c->clk);
+   clk_disable_unprepare(i2c->clk);
return 0;
 
  err_cpufreq:
@@ -1082,7 +1082,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
kfree(i2c->ioarea);
 
  err_clk:
-   clk_disable(i2c->clk);
+   clk_disable_unprepare(i2c->clk);
clk_put(i2c->clk);
 
  err_noclk:
@@ -1106,7 +1106,7 @@ static int s3c24xx_i2c_remove(struct platform_device 
*pdev)
i2c_del_adapter(&i2c->adap);
free_irq(i2c->irq, i2c);
 
-   clk_disable(i2c->clk);
+   clk_disable_unprepare(i2c->clk);
clk_put(i2c->clk);
 
iounmap(i2c->regs);
@@ -1135,9 +1135,9 @@ static int s3c24xx_i2c_resume(struct device *dev)
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
 
i2c->suspended = 0;
-   clk_enable(i2c->clk);
+   clk_prepare_enable(i2c->clk);
s3c24xx_i2c_init(i2c);
-   clk_disable(i2c->clk);
+   clk_disable_unprepare(i2c->clk);
 
return 0;
 }
-- 
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] i2c-mux-gpio: Update documentation

2012-10-02 Thread Jean Delvare
* Document the possibility to pass relative GPIO pin numbers.
* Document what platform device IDs to use, so that they do not
  collide.

Signed-off-by: Jean Delvare 
Cc: Peter Korsgaard 
---
 Documentation/i2c/muxes/i2c-mux-gpio |   18 ++
 1 file changed, 18 insertions(+)

--- linux-3.7-rc0.orig/Documentation/i2c/muxes/i2c-mux-gpio 2012-07-21 
22:58:29.0 +0200
+++ linux-3.7-rc0/Documentation/i2c/muxes/i2c-mux-gpio  2012-10-02 
23:06:15.131690033 +0200
@@ -63,3 +63,21 @@ static struct platform_device myboard_i2
.platform_data  = &myboard_i2cmux_data,
},
 };
+
+If you don't know the absolute GPIO pin numbers at registration time,
+you can instead provide a chip name (.chip_name) and relative GPIO pin
+numbers, and the i2c-gpio-mux driver will do the work for you,
+including deferred probing if the GPIO chip isn't immediately
+available.
+
+Device Registration
+---
+
+When registering your i2c-gpio-mux device, you should pass the number
+of any GPIO pin it uses as the device ID. This guarantees that every
+instance has a different ID.
+
+Alternatively, if you don't need a stable device name, you can simply
+pass PLATFORM_DEVID_AUTO as the device ID, and the platform core will
+assign a dynamic ID to your device. If you do not know the absolute
+GPIO pin numbers at registration time, this is even the only option.

-- 
Jean Delvare
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] i2c-i801: Let i2c-mux-gpio find the GPIO chip

2012-10-02 Thread Jean Delvare
Now that i2c-mux-gpio is able to find the GPIO chip by itself, we can
delegate this task. The great thing here is that i2c-mux-gpio can
defer device probing until the gpio chip is available, so we no longer
depend on the module loading order.

Signed-off-by: Jean Delvare 
---
 drivers/i2c/busses/i2c-i801.c |   37 -
 1 file changed, 4 insertions(+), 33 deletions(-)

--- linux-3.6-rc5.orig/drivers/i2c/busses/i2c-i801.c2012-09-13 
18:18:02.884008189 +0200
+++ linux-3.6-rc5/drivers/i2c/busses/i2c-i801.c 2012-09-13 18:18:12.031009849 
+0200
@@ -194,7 +194,6 @@ struct i801_priv {
 
 #if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
const struct i801_mux_config *mux_drvdata;
-   unsigned mux_priv[2];
struct platform_device *mux_pdev;
 #endif
 };
@@ -1008,60 +1007,32 @@ static struct dmi_system_id __devinitdat
{ }
 };
 
-static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip,
- void *data)
-{
-   return !strcmp(chip->label, data);
-}
-
 /* Setup multiplexing if needed */
 static int __devinit i801_add_mux(struct i801_priv *priv)
 {
struct device *dev = &priv->adapter.dev;
const struct i801_mux_config *mux_config;
-   struct gpio_chip *gpio;
struct i2c_mux_gpio_platform_data gpio_data;
-   int i, err;
+   int err;
 
if (!priv->mux_drvdata)
return 0;
mux_config = priv->mux_drvdata;
 
-   /* Find GPIO chip */
-   gpio = gpiochip_find(mux_config->gpio_chip, match_gpio_chip_by_label);
-   if (gpio) {
-   dev_info(dev,
-"GPIO chip %s found, SMBus multiplexing enabled\n",
-mux_config->gpio_chip);
-   } else {
-   dev_err(dev,
-   "GPIO chip %s not found, SMBus multiplexing disabled\n",
-   mux_config->gpio_chip);
-   return -ENODEV;
-   }
-
-   /* Find absolute GPIO pin numbers */
-   if (ARRAY_SIZE(priv->mux_priv) < mux_config->n_gpios) {
-   dev_err(dev, "i801_priv.mux_priv too small (%zu, need %d)\n",
-   ARRAY_SIZE(priv->mux_priv), mux_config->n_gpios);
-   return -ENODEV;
-   }
-   for (i = 0; i < mux_config->n_gpios; i++)
-   priv->mux_priv[i] = gpio->base + mux_config->gpios[i];
-
/* Prepare the platform data */
memset(&gpio_data, 0, sizeof(struct i2c_mux_gpio_platform_data));
gpio_data.parent = priv->adapter.nr;
gpio_data.values = mux_config->values;
gpio_data.n_values = mux_config->n_values;
gpio_data.classes = mux_config->classes;
-   gpio_data.gpios = priv->mux_priv;
+   gpio_data.gpio_chip = mux_config->gpio_chip;
+   gpio_data.gpios = mux_config->gpios;
gpio_data.n_gpios = mux_config->n_gpios;
gpio_data.idle = I2C_MUX_GPIO_NO_IDLE;
 
/* Register the mux device */
priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio",
-   priv->mux_priv[0], &gpio_data,
+   PLATFORM_DEVID_AUTO, &gpio_data,
sizeof(struct i2c_mux_gpio_platform_data));
if (IS_ERR(priv->mux_pdev)) {
err = PTR_ERR(priv->mux_pdev);


-- 
Jean Delvare
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] i2c-mux-gpio: Add support for dynamically allocated GPIO pins

2012-10-02 Thread Jean Delvare
The code instantiating an i2c-mux-gpio platform device doesn't
necessarily know in advance the GPIO pin numbers it wants to use. If
pins are on a GPIO device which gets its base GPIO number assigned
dynamically at run-time, the values can't be hard-coded.

In that case, let the caller tell i2c-mux-gpio the name of the GPIO
chip and the (relative) GPIO pin numbers to use. At probe time, the
i2c-mux-gpio driver will look for the chip and apply the proper offset
to turn relative GPIO pin numbers to absolute GPIO pin numbers.

The same could be (and was so far) done on the caller's end, however
doing it in i2c-mux-gpio has two benefits:
* It avoids duplicating the code on every caller's side (about 30
  lines of code.)
* It allows for deferred probing for the muxed part of the I2C bus
  only. If finding the GPIO chip is the caller's responsibility, then
  deferred probing (if the GPIO chip isn't there yet) will not only
  affect the mux and the I2C bus segments behind it, but also the I2C
  bus trunk.

Signed-off-by: Jean Delvare 
Cc: Peter Korsgaard 
---
Unfortunately this is not compatible with my idea of letting the
caller set the platform device ID based on one GPIO pin number, as
these numbers are no longer known in advance. So callers will instead
have to use a new platform core feature: automatic platform device ID.
This is enabled by passing PLATFORM_DEVID_AUTO as the platform device
ID.

 drivers/i2c/muxes/i2c-mux-gpio.c |   38 --
 include/linux/i2c-mux-gpio.h |3 +++
 2 files changed, 35 insertions(+), 6 deletions(-)

--- linux-3.6-rc6.orig/drivers/i2c/muxes/i2c-mux-gpio.c 2012-09-22 
15:11:30.0 +0200
+++ linux-3.6-rc6/drivers/i2c/muxes/i2c-mux-gpio.c  2012-09-22 
15:12:48.189053050 +0200
@@ -21,6 +21,7 @@ struct gpiomux {
struct i2c_adapter *parent;
struct i2c_adapter **adap; /* child busses */
struct i2c_mux_gpio_platform_data data;
+   unsigned gpio_base;
 };
 
 static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
@@ -28,7 +29,8 @@ static void i2c_mux_gpio_set(const struc
int i;
 
for (i = 0; i < mux->data.n_gpios; i++)
-   gpio_set_value(mux->data.gpios[i], val & (1 << i));
+   gpio_set_value(mux->gpio_base + mux->data.gpios[i],
+  val & (1 << i));
 }
 
 static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan)
@@ -49,13 +51,19 @@ static int i2c_mux_gpio_deselect(struct
return 0;
 }
 
+static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip,
+ void *data)
+{
+   return !strcmp(chip->label, data);
+}
+
 static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev)
 {
struct gpiomux *mux;
struct i2c_mux_gpio_platform_data *pdata;
struct i2c_adapter *parent;
int (*deselect) (struct i2c_adapter *, void *, u32);
-   unsigned initial_state;
+   unsigned initial_state, gpio_base;
int i, ret;
 
pdata = pdev->dev.platform_data;
@@ -64,6 +72,23 @@ static int __devinit i2c_mux_gpio_probe(
return -ENODEV;
}
 
+   /*
+* If a GPIO chip name is provided, the GPIO pin numbers provided are
+* relative to its base GPIO number. Otherwise they are absolute.
+*/
+   if (pdata->gpio_chip) {
+   struct gpio_chip *gpio;
+
+   gpio = gpiochip_find(pdata->gpio_chip,
+match_gpio_chip_by_label);
+   if (!gpio)
+   return -EPROBE_DEFER;
+
+   gpio_base = gpio->base;
+   } else {
+   gpio_base = 0;
+   }
+
parent = i2c_get_adapter(pdata->parent);
if (!parent) {
dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
@@ -79,6 +104,7 @@ static int __devinit i2c_mux_gpio_probe(
 
mux->parent = parent;
mux->data = *pdata;
+   mux->gpio_base = gpio_base;
mux->adap = devm_kzalloc(&pdev->dev,
 sizeof(struct i2c_adapter *) * pdata->n_values,
 GFP_KERNEL);
@@ -96,10 +122,10 @@ static int __devinit i2c_mux_gpio_probe(
}
 
for (i = 0; i < pdata->n_gpios; i++) {
-   ret = gpio_request(pdata->gpios[i], "i2c-mux-gpio");
+   ret = gpio_request(gpio_base + pdata->gpios[i], "i2c-mux-gpio");
if (ret)
goto err_request_gpio;
-   gpio_direction_output(pdata->gpios[i],
+   gpio_direction_output(gpio_base + pdata->gpios[i],
  initial_state & (1 << i));
}
 
@@ -130,7 +156,7 @@ add_adapter_failed:
i = pdata->n_gpios;
 err_request_gpio:
for (; i > 0; i--)
-   gpio_free(pdata->gpios[i - 1]);
+   gpio_free(gpio_base + pdata->gpios[i - 1]);
 alloc_failed: