diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-gpio.c')
| -rw-r--r-- | drivers/i2c/busses/i2c-gpio.c | 87 |
1 files changed, 51 insertions, 36 deletions
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index f3fa4332bbd..71a45b210a2 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -15,8 +15,8 @@ #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/gpio.h> +#include <linux/of.h> #include <linux/of_gpio.h> -#include <linux/of_i2c.h> struct i2c_gpio_private_data { struct i2c_adapter adap; @@ -85,23 +85,32 @@ static int i2c_gpio_getscl(void *data) return gpio_get_value(pdata->scl_pin); } -static int of_i2c_gpio_probe(struct device_node *np, - struct i2c_gpio_platform_data *pdata) +static int of_i2c_gpio_get_pins(struct device_node *np, + unsigned int *sda_pin, unsigned int *scl_pin) { - u32 reg; - if (of_gpio_count(np) < 2) return -ENODEV; - pdata->sda_pin = of_get_gpio(np, 0); - pdata->scl_pin = of_get_gpio(np, 1); + *sda_pin = of_get_gpio(np, 0); + *scl_pin = of_get_gpio(np, 1); - if (!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin)) { + if (*sda_pin == -EPROBE_DEFER || *scl_pin == -EPROBE_DEFER) + return -EPROBE_DEFER; + + if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) { pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n", - np->full_name, pdata->sda_pin, pdata->scl_pin); + np->full_name, *sda_pin, *scl_pin); return -ENODEV; } + return 0; +} + +static void of_i2c_gpio_get_props(struct device_node *np, + struct i2c_gpio_platform_data *pdata) +{ + u32 reg; + of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay); if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®)) @@ -113,8 +122,6 @@ static int of_i2c_gpio_probe(struct device_node *np, of_property_read_bool(np, "i2c-gpio,scl-open-drain"); pdata->scl_is_output_only = of_property_read_bool(np, "i2c-gpio,scl-output-only"); - - return 0; } static int i2c_gpio_probe(struct platform_device *pdev) @@ -123,8 +130,36 @@ static int i2c_gpio_probe(struct platform_device *pdev) struct i2c_gpio_platform_data *pdata; struct i2c_algo_bit_data *bit_data; struct i2c_adapter *adap; + unsigned int sda_pin, scl_pin; int ret; + /* First get the GPIO pins; if it fails, we'll defer the probe. */ + if (pdev->dev.of_node) { + ret = of_i2c_gpio_get_pins(pdev->dev.of_node, + &sda_pin, &scl_pin); + if (ret) + return ret; + } else { + if (!dev_get_platdata(&pdev->dev)) + return -ENXIO; + pdata = dev_get_platdata(&pdev->dev); + sda_pin = pdata->sda_pin; + scl_pin = pdata->scl_pin; + } + + ret = devm_gpio_request(&pdev->dev, sda_pin, "sda"); + if (ret) { + if (ret == -EINVAL) + ret = -EPROBE_DEFER; /* Try again later */ + return ret; + } + ret = devm_gpio_request(&pdev->dev, scl_pin, "scl"); + if (ret) { + if (ret == -EINVAL) + ret = -EPROBE_DEFER; /* Try again later */ + return ret; + } + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -133,22 +168,13 @@ static int i2c_gpio_probe(struct platform_device *pdev) pdata = &priv->pdata; if (pdev->dev.of_node) { - ret = of_i2c_gpio_probe(pdev->dev.of_node, pdata); - if (ret) - return ret; + pdata->sda_pin = sda_pin; + pdata->scl_pin = scl_pin; + of_i2c_gpio_get_props(pdev->dev.of_node, pdata); } else { - if (!pdev->dev.platform_data) - return -ENXIO; - memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); + memcpy(pdata, dev_get_platdata(&pdev->dev), sizeof(*pdata)); } - ret = gpio_request(pdata->sda_pin, "sda"); - if (ret) - goto err_request_sda; - ret = gpio_request(pdata->scl_pin, "scl"); - if (ret) - goto err_request_scl; - if (pdata->sda_is_open_drain) { gpio_direction_output(pdata->sda_pin, 1); bit_data->setsda = i2c_gpio_setsda_val; @@ -197,9 +223,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) adap->nr = pdev->id; ret = i2c_bit_add_numbered_bus(adap); if (ret) - goto err_add_bus; - - of_i2c_register_devices(adap); + return ret; platform_set_drvdata(pdev, priv); @@ -209,13 +233,6 @@ static int i2c_gpio_probe(struct platform_device *pdev) ? ", no clock stretching" : ""); return 0; - -err_add_bus: - gpio_free(pdata->scl_pin); -err_request_scl: - gpio_free(pdata->sda_pin); -err_request_sda: - return ret; } static int i2c_gpio_remove(struct platform_device *pdev) @@ -229,8 +246,6 @@ static int i2c_gpio_remove(struct platform_device *pdev) pdata = &priv->pdata; i2c_del_adapter(adap); - gpio_free(pdata->scl_pin); - gpio_free(pdata->sda_pin); return 0; } |
