summaryrefslogtreecommitdiff
path: root/drivers/i2c/muxes/i2c-mux-gpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/muxes/i2c-mux-gpio.c')
-rw-r--r--drivers/i2c/muxes/i2c-mux-gpio.c56
1 files changed, 40 insertions, 16 deletions
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index 68b1f8ec3436..566a6757a33d 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -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 struct gpiomux *mux, unsigned val)
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 i2c_adapter *adap, void *data, u32 chan)
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(struct platform_device *pdev)
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",
@@ -71,7 +96,7 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
- mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
if (!mux) {
ret = -ENOMEM;
goto alloc_failed;
@@ -79,11 +104,13 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev)
mux->parent = parent;
mux->data = *pdata;
- mux->adap = kzalloc(sizeof(struct i2c_adapter *) * pdata->n_values,
- GFP_KERNEL);
+ mux->gpio_base = gpio_base;
+ mux->adap = devm_kzalloc(&pdev->dev,
+ sizeof(*mux->adap) * pdata->n_values,
+ GFP_KERNEL);
if (!mux->adap) {
ret = -ENOMEM;
- goto alloc_failed2;
+ goto alloc_failed;
}
if (pdata->idle != I2C_MUX_GPIO_NO_IDLE) {
@@ -95,17 +122,19 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev)
}
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));
}
for (i = 0; i < pdata->n_values; i++) {
u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0;
+ unsigned int class = pdata->classes ? pdata->classes[i] : 0;
- mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, i,
+ mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr,
+ i, class,
i2c_mux_gpio_select, deselect);
if (!mux->adap[i]) {
ret = -ENODEV;
@@ -127,10 +156,7 @@ add_adapter_failed:
i = pdata->n_gpios;
err_request_gpio:
for (; i > 0; i--)
- gpio_free(pdata->gpios[i - 1]);
- kfree(mux->adap);
-alloc_failed2:
- kfree(mux);
+ gpio_free(gpio_base + pdata->gpios[i - 1]);
alloc_failed:
i2c_put_adapter(parent);
@@ -146,12 +172,10 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev)
i2c_del_mux_adapter(mux->adap[i]);
for (i = 0; i < mux->data.n_gpios; i++)
- gpio_free(mux->data.gpios[i]);
+ gpio_free(mux->gpio_base + mux->data.gpios[i]);
platform_set_drvdata(pdev, NULL);
i2c_put_adapter(mux->parent);
- kfree(mux->adap);
- kfree(mux);
return 0;
}