diff options
Diffstat (limited to 'drivers/w1/masters/w1-gpio.c')
| -rw-r--r-- | drivers/w1/masters/w1-gpio.c | 66 | 
1 files changed, 64 insertions, 2 deletions
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index df600d14974..6012c4ea320 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -14,6 +14,8 @@  #include <linux/slab.h>  #include <linux/w1-gpio.h>  #include <linux/gpio.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h>  #include "../w1.h"  #include "../w1_int.h" @@ -42,12 +44,55 @@ static u8 w1_gpio_read_bit(void *data)  	return gpio_get_value(pdata->pin) ? 1 : 0;  } +#ifdef CONFIG_OF +static struct of_device_id w1_gpio_dt_ids[] = { +	{ .compatible = "w1-gpio" }, +	{} +}; +MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); + +static int w1_gpio_probe_dt(struct platform_device *pdev) +{ +	struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; +	struct device_node *np = pdev->dev.of_node; +	const struct of_device_id *of_id = +			of_match_device(w1_gpio_dt_ids, &pdev->dev); + +	if (!of_id) +		return 0; + +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) +		return -ENOMEM; + +	if (of_get_property(np, "linux,open-drain", NULL)) +		pdata->is_open_drain = 1; + +	pdata->pin = of_get_gpio(np, 0); +	pdata->ext_pullup_enable_pin = of_get_gpio(np, 1); +	pdev->dev.platform_data = pdata; + +	return 0; +} +#else +static int w1_gpio_probe_dt(struct platform_device *pdev) +{ +	return 0; +} +#endif +  static int __init w1_gpio_probe(struct platform_device *pdev)  {  	struct w1_bus_master *master; -	struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; +	struct w1_gpio_platform_data *pdata;  	int err; +	err = w1_gpio_probe_dt(pdev); +	if (err < 0) +		return err; + +	pdata = pdev->dev.platform_data; +  	if (!pdata)  		return -ENXIO; @@ -59,6 +104,13 @@ static int __init w1_gpio_probe(struct platform_device *pdev)  	if (err)  		goto free_master; +	if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { +		err = gpio_request_one(pdata->ext_pullup_enable_pin, +				       GPIOF_INIT_LOW, "w1 pullup"); +		if (err < 0) +			goto free_gpio; +	} +  	master->data = pdata;  	master->read_bit = w1_gpio_read_bit; @@ -72,15 +124,21 @@ static int __init w1_gpio_probe(struct platform_device *pdev)  	err = w1_add_master_device(master);  	if (err) -		goto free_gpio; +		goto free_gpio_ext_pu;  	if (pdata->enable_external_pullup)  		pdata->enable_external_pullup(1); +	if (gpio_is_valid(pdata->ext_pullup_enable_pin)) +		gpio_set_value(pdata->ext_pullup_enable_pin, 1); +  	platform_set_drvdata(pdev, master);  	return 0; + free_gpio_ext_pu: +	if (gpio_is_valid(pdata->ext_pullup_enable_pin)) +		gpio_free(pdata->ext_pullup_enable_pin);   free_gpio:  	gpio_free(pdata->pin);   free_master: @@ -97,6 +155,9 @@ static int __exit w1_gpio_remove(struct platform_device *pdev)  	if (pdata->enable_external_pullup)  		pdata->enable_external_pullup(0); +	if (gpio_is_valid(pdata->ext_pullup_enable_pin)) +		gpio_set_value(pdata->ext_pullup_enable_pin, 0); +  	w1_remove_master_device(master);  	gpio_free(pdata->pin);  	kfree(master); @@ -135,6 +196,7 @@ static struct platform_driver w1_gpio_driver = {  	.driver = {  		.name	= "w1-gpio",  		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(w1_gpio_dt_ids),  	},  	.remove	= __exit_p(w1_gpio_remove),  	.suspend = w1_gpio_suspend,  |