i2c: gpio: Add support for deferred probing

GPIOs may not be available immediately when i2c-gpio looks for them.
Implement support for deferred probing so that probing can be
attempted again later when GPIO pins are finally available.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Tested-by: Bo Shen <voice.shen@atmel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
Jean Delvare 2013-02-28 01:01:40 +00:00 committed by Wolfram Sang
parent 7a6674dabf
commit 1b295c839b
1 changed files with 50 additions and 25 deletions

View File

@ -85,23 +85,29 @@ static int i2c_gpio_getscl(void *data)
return gpio_get_value(pdata->scl_pin); return gpio_get_value(pdata->scl_pin);
} }
static int of_i2c_gpio_probe(struct device_node *np, static int of_i2c_gpio_get_pins(struct device_node *np,
struct i2c_gpio_platform_data *pdata) unsigned int *sda_pin, unsigned int *scl_pin)
{ {
u32 reg;
if (of_gpio_count(np) < 2) if (of_gpio_count(np) < 2)
return -ENODEV; return -ENODEV;
pdata->sda_pin = of_get_gpio(np, 0); *sda_pin = of_get_gpio(np, 0);
pdata->scl_pin = of_get_gpio(np, 1); *scl_pin = of_get_gpio(np, 1);
if (!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin)) { if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) {
pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n", 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 -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); of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay);
if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", &reg)) if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", &reg))
@ -113,8 +119,6 @@ static int of_i2c_gpio_probe(struct device_node *np,
of_property_read_bool(np, "i2c-gpio,scl-open-drain"); of_property_read_bool(np, "i2c-gpio,scl-open-drain");
pdata->scl_is_output_only = pdata->scl_is_output_only =
of_property_read_bool(np, "i2c-gpio,scl-output-only"); of_property_read_bool(np, "i2c-gpio,scl-output-only");
return 0;
} }
static int i2c_gpio_probe(struct platform_device *pdev) static int i2c_gpio_probe(struct platform_device *pdev)
@ -123,31 +127,52 @@ static int i2c_gpio_probe(struct platform_device *pdev)
struct i2c_gpio_platform_data *pdata; struct i2c_gpio_platform_data *pdata;
struct i2c_algo_bit_data *bit_data; struct i2c_algo_bit_data *bit_data;
struct i2c_adapter *adap; struct i2c_adapter *adap;
unsigned int sda_pin, scl_pin;
int ret; int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); /* First get the GPIO pins; if it fails, we'll defer the probe. */
if (!priv)
return -ENOMEM;
adap = &priv->adap;
bit_data = &priv->bit_data;
pdata = &priv->pdata;
if (pdev->dev.of_node) { if (pdev->dev.of_node) {
ret = of_i2c_gpio_probe(pdev->dev.of_node, pdata); ret = of_i2c_gpio_get_pins(pdev->dev.of_node,
&sda_pin, &scl_pin);
if (ret) if (ret)
return ret; return ret;
} else { } else {
if (!pdev->dev.platform_data) if (!pdev->dev.platform_data)
return -ENXIO; return -ENXIO;
memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); pdata = pdev->dev.platform_data;
sda_pin = pdata->sda_pin;
scl_pin = pdata->scl_pin;
} }
ret = gpio_request(pdata->sda_pin, "sda"); ret = gpio_request(sda_pin, "sda");
if (ret) if (ret) {
if (ret == -EINVAL)
ret = -EPROBE_DEFER; /* Try again later */
goto err_request_sda; goto err_request_sda;
ret = gpio_request(pdata->scl_pin, "scl"); }
if (ret) ret = gpio_request(scl_pin, "scl");
if (ret) {
if (ret == -EINVAL)
ret = -EPROBE_DEFER; /* Try again later */
goto err_request_scl; goto err_request_scl;
}
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
goto err_add_bus;
}
adap = &priv->adap;
bit_data = &priv->bit_data;
pdata = &priv->pdata;
if (pdev->dev.of_node) {
pdata->sda_pin = sda_pin;
pdata->scl_pin = scl_pin;
of_i2c_gpio_get_props(pdev->dev.of_node, pdata);
} else {
memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
}
if (pdata->sda_is_open_drain) { if (pdata->sda_is_open_drain) {
gpio_direction_output(pdata->sda_pin, 1); gpio_direction_output(pdata->sda_pin, 1);
@ -211,9 +236,9 @@ static int i2c_gpio_probe(struct platform_device *pdev)
return 0; return 0;
err_add_bus: err_add_bus:
gpio_free(pdata->scl_pin); gpio_free(scl_pin);
err_request_scl: err_request_scl:
gpio_free(pdata->sda_pin); gpio_free(sda_pin);
err_request_sda: err_request_sda:
return ret; return ret;
} }