]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
ad8dc96e VS |
2 | /* |
3 | * w1-gpio - GPIO w1 bus master driver | |
4 | * | |
5 | * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi> | |
ad8dc96e VS |
6 | */ |
7 | ||
8 | #include <linux/init.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/platform_device.h> | |
5a0e3ad6 | 11 | #include <linux/slab.h> |
ad8dc96e | 12 | #include <linux/w1-gpio.h> |
e0fc62a6 | 13 | #include <linux/gpio/consumer.h> |
5f3d1382 | 14 | #include <linux/of_platform.h> |
277ed0d5 | 15 | #include <linux/err.h> |
8a1861d9 | 16 | #include <linux/of.h> |
3089a4c8 | 17 | #include <linux/delay.h> |
ad8dc96e | 18 | |
de0d6dbd | 19 | #include <linux/w1.h> |
ad8dc96e | 20 | |
3089a4c8 EB |
21 | static u8 w1_gpio_set_pullup(void *data, int delay) |
22 | { | |
23 | struct w1_gpio_platform_data *pdata = data; | |
24 | ||
25 | if (delay) { | |
26 | pdata->pullup_duration = delay; | |
27 | } else { | |
28 | if (pdata->pullup_duration) { | |
e0fc62a6 LW |
29 | /* |
30 | * This will OVERRIDE open drain emulation and force-pull | |
31 | * the line high for some time. | |
32 | */ | |
33 | gpiod_set_raw_value(pdata->gpiod, 1); | |
3089a4c8 | 34 | msleep(pdata->pullup_duration); |
e0fc62a6 LW |
35 | /* |
36 | * This will simply set the line as input since we are doing | |
37 | * open drain emulation in the GPIO library. | |
38 | */ | |
39 | gpiod_set_value(pdata->gpiod, 1); | |
3089a4c8 EB |
40 | } |
41 | pdata->pullup_duration = 0; | |
42 | } | |
43 | ||
44 | return 0; | |
45 | } | |
46 | ||
e0fc62a6 | 47 | static void w1_gpio_write_bit(void *data, u8 bit) |
ad8dc96e VS |
48 | { |
49 | struct w1_gpio_platform_data *pdata = data; | |
50 | ||
e0fc62a6 | 51 | gpiod_set_value(pdata->gpiod, bit); |
ad8dc96e VS |
52 | } |
53 | ||
54 | static u8 w1_gpio_read_bit(void *data) | |
55 | { | |
56 | struct w1_gpio_platform_data *pdata = data; | |
57 | ||
e0fc62a6 | 58 | return gpiod_get_value(pdata->gpiod) ? 1 : 0; |
ad8dc96e VS |
59 | } |
60 | ||
34ccd873 | 61 | #if defined(CONFIG_OF) |
0a56c0e1 | 62 | static const struct of_device_id w1_gpio_dt_ids[] = { |
5f3d1382 DM |
63 | { .compatible = "w1-gpio" }, |
64 | {} | |
65 | }; | |
66 | MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); | |
34ccd873 | 67 | #endif |
5f3d1382 | 68 | |
06a8f1fe | 69 | static int w1_gpio_probe(struct platform_device *pdev) |
ad8dc96e VS |
70 | { |
71 | struct w1_bus_master *master; | |
5f3d1382 | 72 | struct w1_gpio_platform_data *pdata; |
e0fc62a6 LW |
73 | struct device *dev = &pdev->dev; |
74 | struct device_node *np = dev->of_node; | |
75 | /* Enforce open drain mode by default */ | |
76 | enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN; | |
ad8dc96e VS |
77 | int err; |
78 | ||
8a1861d9 | 79 | if (of_have_populated_dt()) { |
e0fc62a6 LW |
80 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
81 | if (!pdata) | |
82 | return -ENOMEM; | |
83 | ||
84 | /* | |
85 | * This parameter means that something else than the gpiolib has | |
86 | * already set the line into open drain mode, so we should just | |
87 | * driver it high/low like we are in full control of the line and | |
88 | * open drain will happen transparently. | |
89 | */ | |
90 | if (of_get_property(np, "linux,open-drain", NULL)) | |
91 | gflags = GPIOD_OUT_LOW; | |
92 | ||
93 | pdev->dev.platform_data = pdata; | |
8a1861d9 | 94 | } |
e0fc62a6 | 95 | pdata = dev_get_platdata(dev); |
5f3d1382 | 96 | |
8a1861d9 | 97 | if (!pdata) { |
e0fc62a6 | 98 | dev_err(dev, "No configuration data\n"); |
ad8dc96e | 99 | return -ENXIO; |
8a1861d9 | 100 | } |
ad8dc96e | 101 | |
e0fc62a6 | 102 | master = devm_kzalloc(dev, sizeof(struct w1_bus_master), |
d27f25c9 | 103 | GFP_KERNEL); |
8a1861d9 | 104 | if (!master) { |
e0fc62a6 | 105 | dev_err(dev, "Out of memory\n"); |
ad8dc96e | 106 | return -ENOMEM; |
8a1861d9 | 107 | } |
ad8dc96e | 108 | |
e0fc62a6 LW |
109 | pdata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags); |
110 | if (IS_ERR(pdata->gpiod)) { | |
111 | dev_err(dev, "gpio_request (pin) failed\n"); | |
112 | return PTR_ERR(pdata->gpiod); | |
8a1861d9 | 113 | } |
ad8dc96e | 114 | |
e0fc62a6 LW |
115 | pdata->pullup_gpiod = |
116 | devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_LOW); | |
117 | if (IS_ERR(pdata->pullup_gpiod)) { | |
118 | dev_err(dev, "gpio_request_one " | |
119 | "(ext_pullup_enable_pin) failed\n"); | |
120 | return PTR_ERR(pdata->pullup_gpiod); | |
d2323cf7 DM |
121 | } |
122 | ||
ad8dc96e VS |
123 | master->data = pdata; |
124 | master->read_bit = w1_gpio_read_bit; | |
e0fc62a6 LW |
125 | gpiod_direction_output(pdata->gpiod, 1); |
126 | master->write_bit = w1_gpio_write_bit; | |
127 | ||
128 | /* | |
129 | * If we are using open drain emulation from the GPIO library, | |
130 | * we need to use this pullup function that hammers the line | |
131 | * high using a raw accessor to provide pull-up for the w1 | |
132 | * line. | |
133 | */ | |
134 | if (gflags == GPIOD_OUT_LOW_OPEN_DRAIN) | |
3089a4c8 | 135 | master->set_pullup = w1_gpio_set_pullup; |
ad8dc96e VS |
136 | |
137 | err = w1_add_master_device(master); | |
8a1861d9 | 138 | if (err) { |
e0fc62a6 | 139 | dev_err(dev, "w1_add_master device failed\n"); |
d27f25c9 | 140 | return err; |
8a1861d9 | 141 | } |
ad8dc96e | 142 | |
c8a06c1e DM |
143 | if (pdata->enable_external_pullup) |
144 | pdata->enable_external_pullup(1); | |
145 | ||
e0fc62a6 LW |
146 | if (pdata->pullup_gpiod) |
147 | gpiod_set_value(pdata->pullup_gpiod, 1); | |
d2323cf7 | 148 | |
ad8dc96e VS |
149 | platform_set_drvdata(pdev, master); |
150 | ||
151 | return 0; | |
ad8dc96e VS |
152 | } |
153 | ||
01230551 | 154 | static int w1_gpio_remove(struct platform_device *pdev) |
ad8dc96e VS |
155 | { |
156 | struct w1_bus_master *master = platform_get_drvdata(pdev); | |
c853b167 | 157 | struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); |
ad8dc96e | 158 | |
c8a06c1e DM |
159 | if (pdata->enable_external_pullup) |
160 | pdata->enable_external_pullup(0); | |
161 | ||
e0fc62a6 LW |
162 | if (pdata->pullup_gpiod) |
163 | gpiod_set_value(pdata->pullup_gpiod, 0); | |
d2323cf7 | 164 | |
ad8dc96e | 165 | w1_remove_master_device(master); |
ad8dc96e VS |
166 | |
167 | return 0; | |
168 | } | |
169 | ||
36fccce0 | 170 | static int __maybe_unused w1_gpio_suspend(struct device *dev) |
c8a06c1e | 171 | { |
36fccce0 | 172 | struct w1_gpio_platform_data *pdata = dev_get_platdata(dev); |
c8a06c1e DM |
173 | |
174 | if (pdata->enable_external_pullup) | |
175 | pdata->enable_external_pullup(0); | |
176 | ||
177 | return 0; | |
178 | } | |
179 | ||
36fccce0 | 180 | static int __maybe_unused w1_gpio_resume(struct device *dev) |
c8a06c1e | 181 | { |
36fccce0 | 182 | struct w1_gpio_platform_data *pdata = dev_get_platdata(dev); |
c8a06c1e DM |
183 | |
184 | if (pdata->enable_external_pullup) | |
185 | pdata->enable_external_pullup(1); | |
186 | ||
187 | return 0; | |
188 | } | |
189 | ||
36fccce0 | 190 | static SIMPLE_DEV_PM_OPS(w1_gpio_pm_ops, w1_gpio_suspend, w1_gpio_resume); |
c8a06c1e | 191 | |
ad8dc96e VS |
192 | static struct platform_driver w1_gpio_driver = { |
193 | .driver = { | |
194 | .name = "w1-gpio", | |
36fccce0 | 195 | .pm = &w1_gpio_pm_ops, |
5f3d1382 | 196 | .of_match_table = of_match_ptr(w1_gpio_dt_ids), |
ad8dc96e | 197 | }, |
8a1861d9 | 198 | .probe = w1_gpio_probe, |
36fccce0 | 199 | .remove = w1_gpio_remove, |
ad8dc96e VS |
200 | }; |
201 | ||
8a1861d9 | 202 | module_platform_driver(w1_gpio_driver); |
ad8dc96e VS |
203 | |
204 | MODULE_DESCRIPTION("GPIO w1 bus master driver"); | |
205 | MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>"); | |
206 | MODULE_LICENSE("GPL"); |