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:
Родитель
7a6674dabf
Коммит
1b295c839b
|
@ -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", ®))
|
if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®))
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче