xref: /openbmc/linux/drivers/w1/masters/w1-gpio.c (revision e0fc62a6552f3d9c21e73cc65844f9aad1892cf7)
1ad8dc96eSVille Syrjala /*
2ad8dc96eSVille Syrjala  * w1-gpio - GPIO w1 bus master driver
3ad8dc96eSVille Syrjala  *
4ad8dc96eSVille Syrjala  * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi>
5ad8dc96eSVille Syrjala  *
6ad8dc96eSVille Syrjala  * This program is free software; you can redistribute it and/or modify
7ad8dc96eSVille Syrjala  * it under the terms of the GNU General Public License version 2
8ad8dc96eSVille Syrjala  * as published by the Free Software Foundation.
9ad8dc96eSVille Syrjala  */
10ad8dc96eSVille Syrjala 
11ad8dc96eSVille Syrjala #include <linux/init.h>
12ad8dc96eSVille Syrjala #include <linux/module.h>
13ad8dc96eSVille Syrjala #include <linux/platform_device.h>
145a0e3ad6STejun Heo #include <linux/slab.h>
15ad8dc96eSVille Syrjala #include <linux/w1-gpio.h>
16*e0fc62a6SLinus Walleij #include <linux/gpio/consumer.h>
175f3d1382SDaniel Mack #include <linux/of_platform.h>
18277ed0d5SPantelis Antoniou #include <linux/err.h>
198a1861d9SPantelis Antoniou #include <linux/of.h>
203089a4c8SEvgeny Boger #include <linux/delay.h>
21ad8dc96eSVille Syrjala 
22de0d6dbdSAndrew F. Davis #include <linux/w1.h>
23ad8dc96eSVille Syrjala 
243089a4c8SEvgeny Boger static u8 w1_gpio_set_pullup(void *data, int delay)
253089a4c8SEvgeny Boger {
263089a4c8SEvgeny Boger 	struct w1_gpio_platform_data *pdata = data;
273089a4c8SEvgeny Boger 
283089a4c8SEvgeny Boger 	if (delay) {
293089a4c8SEvgeny Boger 		pdata->pullup_duration = delay;
303089a4c8SEvgeny Boger 	} else {
313089a4c8SEvgeny Boger 		if (pdata->pullup_duration) {
32*e0fc62a6SLinus Walleij 			/*
33*e0fc62a6SLinus Walleij 			 * This will OVERRIDE open drain emulation and force-pull
34*e0fc62a6SLinus Walleij 			 * the line high for some time.
35*e0fc62a6SLinus Walleij 			 */
36*e0fc62a6SLinus Walleij 			gpiod_set_raw_value(pdata->gpiod, 1);
373089a4c8SEvgeny Boger 			msleep(pdata->pullup_duration);
38*e0fc62a6SLinus Walleij 			/*
39*e0fc62a6SLinus Walleij 			 * This will simply set the line as input since we are doing
40*e0fc62a6SLinus Walleij 			 * open drain emulation in the GPIO library.
41*e0fc62a6SLinus Walleij 			 */
42*e0fc62a6SLinus Walleij 			gpiod_set_value(pdata->gpiod, 1);
433089a4c8SEvgeny Boger 		}
443089a4c8SEvgeny Boger 		pdata->pullup_duration = 0;
453089a4c8SEvgeny Boger 	}
463089a4c8SEvgeny Boger 
473089a4c8SEvgeny Boger 	return 0;
483089a4c8SEvgeny Boger }
493089a4c8SEvgeny Boger 
50*e0fc62a6SLinus Walleij static void w1_gpio_write_bit(void *data, u8 bit)
51ad8dc96eSVille Syrjala {
52ad8dc96eSVille Syrjala 	struct w1_gpio_platform_data *pdata = data;
53ad8dc96eSVille Syrjala 
54*e0fc62a6SLinus Walleij 	gpiod_set_value(pdata->gpiod, bit);
55ad8dc96eSVille Syrjala }
56ad8dc96eSVille Syrjala 
57ad8dc96eSVille Syrjala static u8 w1_gpio_read_bit(void *data)
58ad8dc96eSVille Syrjala {
59ad8dc96eSVille Syrjala 	struct w1_gpio_platform_data *pdata = data;
60ad8dc96eSVille Syrjala 
61*e0fc62a6SLinus Walleij 	return gpiod_get_value(pdata->gpiod) ? 1 : 0;
62ad8dc96eSVille Syrjala }
63ad8dc96eSVille Syrjala 
6434ccd873SJohan Hovold #if defined(CONFIG_OF)
650a56c0e1SFabian Frederick static const struct of_device_id w1_gpio_dt_ids[] = {
665f3d1382SDaniel Mack 	{ .compatible = "w1-gpio" },
675f3d1382SDaniel Mack 	{}
685f3d1382SDaniel Mack };
695f3d1382SDaniel Mack MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids);
7034ccd873SJohan Hovold #endif
715f3d1382SDaniel Mack 
7206a8f1feSHauke Mehrtens static int w1_gpio_probe(struct platform_device *pdev)
73ad8dc96eSVille Syrjala {
74ad8dc96eSVille Syrjala 	struct w1_bus_master *master;
755f3d1382SDaniel Mack 	struct w1_gpio_platform_data *pdata;
76*e0fc62a6SLinus Walleij 	struct device *dev = &pdev->dev;
77*e0fc62a6SLinus Walleij 	struct device_node *np = dev->of_node;
78*e0fc62a6SLinus Walleij 	/* Enforce open drain mode by default */
79*e0fc62a6SLinus Walleij 	enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
80ad8dc96eSVille Syrjala 	int err;
81ad8dc96eSVille Syrjala 
828a1861d9SPantelis Antoniou 	if (of_have_populated_dt()) {
83*e0fc62a6SLinus Walleij 		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
84*e0fc62a6SLinus Walleij 		if (!pdata)
85*e0fc62a6SLinus Walleij 			return -ENOMEM;
865f3d1382SDaniel Mack 
87*e0fc62a6SLinus Walleij 		/*
88*e0fc62a6SLinus Walleij 		 * This parameter means that something else than the gpiolib has
89*e0fc62a6SLinus Walleij 		 * already set the line into open drain mode, so we should just
90*e0fc62a6SLinus Walleij 		 * driver it high/low like we are in full control of the line and
91*e0fc62a6SLinus Walleij 		 * open drain will happen transparently.
92*e0fc62a6SLinus Walleij 		 */
93*e0fc62a6SLinus Walleij 		if (of_get_property(np, "linux,open-drain", NULL))
94*e0fc62a6SLinus Walleij 			gflags = GPIOD_OUT_LOW;
95*e0fc62a6SLinus Walleij 
96*e0fc62a6SLinus Walleij 		pdev->dev.platform_data = pdata;
97*e0fc62a6SLinus Walleij 	}
98*e0fc62a6SLinus Walleij 	pdata = dev_get_platdata(dev);
995f3d1382SDaniel Mack 
1008a1861d9SPantelis Antoniou 	if (!pdata) {
101*e0fc62a6SLinus Walleij 		dev_err(dev, "No configuration data\n");
102ad8dc96eSVille Syrjala 		return -ENXIO;
1038a1861d9SPantelis Antoniou 	}
104ad8dc96eSVille Syrjala 
105*e0fc62a6SLinus Walleij 	master = devm_kzalloc(dev, sizeof(struct w1_bus_master),
106d27f25c9SMarkus Pargmann 			GFP_KERNEL);
1078a1861d9SPantelis Antoniou 	if (!master) {
108*e0fc62a6SLinus Walleij 		dev_err(dev, "Out of memory\n");
109ad8dc96eSVille Syrjala 		return -ENOMEM;
1108a1861d9SPantelis Antoniou 	}
111ad8dc96eSVille Syrjala 
112*e0fc62a6SLinus Walleij 	pdata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags);
113*e0fc62a6SLinus Walleij 	if (IS_ERR(pdata->gpiod)) {
114*e0fc62a6SLinus Walleij 		dev_err(dev, "gpio_request (pin) failed\n");
115*e0fc62a6SLinus Walleij 		return PTR_ERR(pdata->gpiod);
1168a1861d9SPantelis Antoniou 	}
117ad8dc96eSVille Syrjala 
118*e0fc62a6SLinus Walleij 	pdata->pullup_gpiod =
119*e0fc62a6SLinus Walleij 		devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_LOW);
120*e0fc62a6SLinus Walleij 	if (IS_ERR(pdata->pullup_gpiod)) {
121*e0fc62a6SLinus Walleij 		dev_err(dev, "gpio_request_one "
1228a1861d9SPantelis Antoniou 			"(ext_pullup_enable_pin) failed\n");
123*e0fc62a6SLinus Walleij 		return PTR_ERR(pdata->pullup_gpiod);
1248a1861d9SPantelis Antoniou 	}
125d2323cf7SDaniel Mack 
126ad8dc96eSVille Syrjala 	master->data = pdata;
127ad8dc96eSVille Syrjala 	master->read_bit = w1_gpio_read_bit;
128*e0fc62a6SLinus Walleij 	gpiod_direction_output(pdata->gpiod, 1);
129*e0fc62a6SLinus Walleij 	master->write_bit = w1_gpio_write_bit;
130ad8dc96eSVille Syrjala 
131*e0fc62a6SLinus Walleij 	/*
132*e0fc62a6SLinus Walleij 	 * If we are using open drain emulation from the GPIO library,
133*e0fc62a6SLinus Walleij 	 * we need to use this pullup function that hammers the line
134*e0fc62a6SLinus Walleij 	 * high using a raw accessor to provide pull-up for the w1
135*e0fc62a6SLinus Walleij 	 * line.
136*e0fc62a6SLinus Walleij 	 */
137*e0fc62a6SLinus Walleij 	if (gflags == GPIOD_OUT_LOW_OPEN_DRAIN)
1383089a4c8SEvgeny Boger 		master->set_pullup = w1_gpio_set_pullup;
139ad8dc96eSVille Syrjala 
140ad8dc96eSVille Syrjala 	err = w1_add_master_device(master);
1418a1861d9SPantelis Antoniou 	if (err) {
142*e0fc62a6SLinus Walleij 		dev_err(dev, "w1_add_master device failed\n");
143d27f25c9SMarkus Pargmann 		return err;
1448a1861d9SPantelis Antoniou 	}
145ad8dc96eSVille Syrjala 
146c8a06c1eSDaniel Mack 	if (pdata->enable_external_pullup)
147c8a06c1eSDaniel Mack 		pdata->enable_external_pullup(1);
148c8a06c1eSDaniel Mack 
149*e0fc62a6SLinus Walleij 	if (pdata->pullup_gpiod)
150*e0fc62a6SLinus Walleij 		gpiod_set_value(pdata->pullup_gpiod, 1);
151d2323cf7SDaniel Mack 
152ad8dc96eSVille Syrjala 	platform_set_drvdata(pdev, master);
153ad8dc96eSVille Syrjala 
154ad8dc96eSVille Syrjala 	return 0;
155ad8dc96eSVille Syrjala }
156ad8dc96eSVille Syrjala 
15701230551SJohan Hovold static int w1_gpio_remove(struct platform_device *pdev)
158ad8dc96eSVille Syrjala {
159ad8dc96eSVille Syrjala 	struct w1_bus_master *master = platform_get_drvdata(pdev);
160c853b167SJingoo Han 	struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
161ad8dc96eSVille Syrjala 
162c8a06c1eSDaniel Mack 	if (pdata->enable_external_pullup)
163c8a06c1eSDaniel Mack 		pdata->enable_external_pullup(0);
164c8a06c1eSDaniel Mack 
165*e0fc62a6SLinus Walleij 	if (pdata->pullup_gpiod)
166*e0fc62a6SLinus Walleij 		gpiod_set_value(pdata->pullup_gpiod, 0);
167d2323cf7SDaniel Mack 
168ad8dc96eSVille Syrjala 	w1_remove_master_device(master);
169ad8dc96eSVille Syrjala 
170ad8dc96eSVille Syrjala 	return 0;
171ad8dc96eSVille Syrjala }
172ad8dc96eSVille Syrjala 
17336fccce0SDmitry Torokhov static int __maybe_unused w1_gpio_suspend(struct device *dev)
174c8a06c1eSDaniel Mack {
17536fccce0SDmitry Torokhov 	struct w1_gpio_platform_data *pdata = dev_get_platdata(dev);
176c8a06c1eSDaniel Mack 
177c8a06c1eSDaniel Mack 	if (pdata->enable_external_pullup)
178c8a06c1eSDaniel Mack 		pdata->enable_external_pullup(0);
179c8a06c1eSDaniel Mack 
180c8a06c1eSDaniel Mack 	return 0;
181c8a06c1eSDaniel Mack }
182c8a06c1eSDaniel Mack 
18336fccce0SDmitry Torokhov static int __maybe_unused w1_gpio_resume(struct device *dev)
184c8a06c1eSDaniel Mack {
18536fccce0SDmitry Torokhov 	struct w1_gpio_platform_data *pdata = dev_get_platdata(dev);
186c8a06c1eSDaniel Mack 
187c8a06c1eSDaniel Mack 	if (pdata->enable_external_pullup)
188c8a06c1eSDaniel Mack 		pdata->enable_external_pullup(1);
189c8a06c1eSDaniel Mack 
190c8a06c1eSDaniel Mack 	return 0;
191c8a06c1eSDaniel Mack }
192c8a06c1eSDaniel Mack 
19336fccce0SDmitry Torokhov static SIMPLE_DEV_PM_OPS(w1_gpio_pm_ops, w1_gpio_suspend, w1_gpio_resume);
194c8a06c1eSDaniel Mack 
195ad8dc96eSVille Syrjala static struct platform_driver w1_gpio_driver = {
196ad8dc96eSVille Syrjala 	.driver = {
197ad8dc96eSVille Syrjala 		.name	= "w1-gpio",
19836fccce0SDmitry Torokhov 		.pm	= &w1_gpio_pm_ops,
1995f3d1382SDaniel Mack 		.of_match_table = of_match_ptr(w1_gpio_dt_ids),
200ad8dc96eSVille Syrjala 	},
2018a1861d9SPantelis Antoniou 	.probe = w1_gpio_probe,
20201230551SJohan Hovold 	.remove = w1_gpio_remove,
203ad8dc96eSVille Syrjala };
204ad8dc96eSVille Syrjala 
2058a1861d9SPantelis Antoniou module_platform_driver(w1_gpio_driver);
206ad8dc96eSVille Syrjala 
207ad8dc96eSVille Syrjala MODULE_DESCRIPTION("GPIO w1 bus master driver");
208ad8dc96eSVille Syrjala MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
209ad8dc96eSVille Syrjala MODULE_LICENSE("GPL");
210