Commit | Line | Data |
---|---|---|
ad8dc96e VS |
1 | /* |
2 | * w1-gpio - GPIO w1 bus master driver | |
3 | * | |
4 | * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 | |
8 | * as published by the Free Software Foundation. | |
9 | */ | |
10 | ||
11 | #include <linux/init.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/platform_device.h> | |
5a0e3ad6 | 14 | #include <linux/slab.h> |
ad8dc96e | 15 | #include <linux/w1-gpio.h> |
e250b34e | 16 | #include <linux/gpio.h> |
5f3d1382 DM |
17 | #include <linux/of_platform.h> |
18 | #include <linux/of_gpio.h> | |
277ed0d5 | 19 | #include <linux/err.h> |
8a1861d9 | 20 | #include <linux/of.h> |
3089a4c8 | 21 | #include <linux/delay.h> |
ad8dc96e VS |
22 | |
23 | #include "../w1.h" | |
24 | #include "../w1_int.h" | |
25 | ||
3089a4c8 EB |
26 | static u8 w1_gpio_set_pullup(void *data, int delay) |
27 | { | |
28 | struct w1_gpio_platform_data *pdata = data; | |
29 | ||
30 | if (delay) { | |
31 | pdata->pullup_duration = delay; | |
32 | } else { | |
33 | if (pdata->pullup_duration) { | |
34 | gpio_direction_output(pdata->pin, 1); | |
35 | ||
36 | msleep(pdata->pullup_duration); | |
37 | ||
38 | gpio_direction_input(pdata->pin); | |
39 | } | |
40 | pdata->pullup_duration = 0; | |
41 | } | |
42 | ||
43 | return 0; | |
44 | } | |
45 | ||
ad8dc96e VS |
46 | static void w1_gpio_write_bit_dir(void *data, u8 bit) |
47 | { | |
48 | struct w1_gpio_platform_data *pdata = data; | |
49 | ||
50 | if (bit) | |
51 | gpio_direction_input(pdata->pin); | |
52 | else | |
53 | gpio_direction_output(pdata->pin, 0); | |
54 | } | |
55 | ||
56 | static void w1_gpio_write_bit_val(void *data, u8 bit) | |
57 | { | |
58 | struct w1_gpio_platform_data *pdata = data; | |
59 | ||
60 | gpio_set_value(pdata->pin, bit); | |
61 | } | |
62 | ||
63 | static u8 w1_gpio_read_bit(void *data) | |
64 | { | |
65 | struct w1_gpio_platform_data *pdata = data; | |
66 | ||
8d0df7a3 | 67 | return gpio_get_value(pdata->pin) ? 1 : 0; |
ad8dc96e VS |
68 | } |
69 | ||
34ccd873 | 70 | #if defined(CONFIG_OF) |
0a56c0e1 | 71 | static const struct of_device_id w1_gpio_dt_ids[] = { |
5f3d1382 DM |
72 | { .compatible = "w1-gpio" }, |
73 | {} | |
74 | }; | |
75 | MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids); | |
34ccd873 | 76 | #endif |
5f3d1382 DM |
77 | |
78 | static int w1_gpio_probe_dt(struct platform_device *pdev) | |
79 | { | |
c853b167 | 80 | struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); |
5f3d1382 | 81 | struct device_node *np = pdev->dev.of_node; |
7cf1a122 | 82 | int gpio; |
5f3d1382 DM |
83 | |
84 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | |
85 | if (!pdata) | |
86 | return -ENOMEM; | |
87 | ||
88 | if (of_get_property(np, "linux,open-drain", NULL)) | |
89 | pdata->is_open_drain = 1; | |
90 | ||
7cf1a122 | 91 | gpio = of_get_gpio(np, 0); |
0b336cea UKK |
92 | if (gpio < 0) { |
93 | if (gpio != -EPROBE_DEFER) | |
94 | dev_err(&pdev->dev, | |
95 | "Failed to parse gpio property for data pin (%d)\n", | |
96 | gpio); | |
97 | ||
7cf1a122 | 98 | return gpio; |
0b336cea | 99 | } |
7cf1a122 MP |
100 | pdata->pin = gpio; |
101 | ||
0b336cea UKK |
102 | gpio = of_get_gpio(np, 1); |
103 | if (gpio == -EPROBE_DEFER) | |
104 | return gpio; | |
105 | /* ignore other errors as the pullup gpio is optional */ | |
106 | pdata->ext_pullup_enable_pin = gpio; | |
107 | ||
5f3d1382 DM |
108 | pdev->dev.platform_data = pdata; |
109 | ||
110 | return 0; | |
111 | } | |
5f3d1382 | 112 | |
06a8f1fe | 113 | static int w1_gpio_probe(struct platform_device *pdev) |
ad8dc96e VS |
114 | { |
115 | struct w1_bus_master *master; | |
5f3d1382 | 116 | struct w1_gpio_platform_data *pdata; |
ad8dc96e VS |
117 | int err; |
118 | ||
8a1861d9 PA |
119 | if (of_have_populated_dt()) { |
120 | err = w1_gpio_probe_dt(pdev); | |
0b336cea | 121 | if (err < 0) |
8a1861d9 | 122 | return err; |
8a1861d9 | 123 | } |
5f3d1382 | 124 | |
c853b167 | 125 | pdata = dev_get_platdata(&pdev->dev); |
5f3d1382 | 126 | |
8a1861d9 PA |
127 | if (!pdata) { |
128 | dev_err(&pdev->dev, "No configuration data\n"); | |
ad8dc96e | 129 | return -ENXIO; |
8a1861d9 | 130 | } |
ad8dc96e | 131 | |
d27f25c9 MP |
132 | master = devm_kzalloc(&pdev->dev, sizeof(struct w1_bus_master), |
133 | GFP_KERNEL); | |
8a1861d9 PA |
134 | if (!master) { |
135 | dev_err(&pdev->dev, "Out of memory\n"); | |
ad8dc96e | 136 | return -ENOMEM; |
8a1861d9 | 137 | } |
ad8dc96e | 138 | |
d27f25c9 | 139 | err = devm_gpio_request(&pdev->dev, pdata->pin, "w1"); |
8a1861d9 PA |
140 | if (err) { |
141 | dev_err(&pdev->dev, "gpio_request (pin) failed\n"); | |
d27f25c9 | 142 | return err; |
8a1861d9 | 143 | } |
ad8dc96e | 144 | |
d2323cf7 | 145 | if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { |
d27f25c9 MP |
146 | err = devm_gpio_request_one(&pdev->dev, |
147 | pdata->ext_pullup_enable_pin, GPIOF_INIT_LOW, | |
148 | "w1 pullup"); | |
8a1861d9 PA |
149 | if (err < 0) { |
150 | dev_err(&pdev->dev, "gpio_request_one " | |
151 | "(ext_pullup_enable_pin) failed\n"); | |
d27f25c9 | 152 | return err; |
8a1861d9 | 153 | } |
d2323cf7 DM |
154 | } |
155 | ||
ad8dc96e VS |
156 | master->data = pdata; |
157 | master->read_bit = w1_gpio_read_bit; | |
158 | ||
159 | if (pdata->is_open_drain) { | |
160 | gpio_direction_output(pdata->pin, 1); | |
161 | master->write_bit = w1_gpio_write_bit_val; | |
162 | } else { | |
163 | gpio_direction_input(pdata->pin); | |
164 | master->write_bit = w1_gpio_write_bit_dir; | |
3089a4c8 | 165 | master->set_pullup = w1_gpio_set_pullup; |
ad8dc96e VS |
166 | } |
167 | ||
168 | err = w1_add_master_device(master); | |
8a1861d9 PA |
169 | if (err) { |
170 | dev_err(&pdev->dev, "w1_add_master device failed\n"); | |
d27f25c9 | 171 | return err; |
8a1861d9 | 172 | } |
ad8dc96e | 173 | |
c8a06c1e DM |
174 | if (pdata->enable_external_pullup) |
175 | pdata->enable_external_pullup(1); | |
176 | ||
d2323cf7 DM |
177 | if (gpio_is_valid(pdata->ext_pullup_enable_pin)) |
178 | gpio_set_value(pdata->ext_pullup_enable_pin, 1); | |
179 | ||
ad8dc96e VS |
180 | platform_set_drvdata(pdev, master); |
181 | ||
182 | return 0; | |
ad8dc96e VS |
183 | } |
184 | ||
01230551 | 185 | static int w1_gpio_remove(struct platform_device *pdev) |
ad8dc96e VS |
186 | { |
187 | struct w1_bus_master *master = platform_get_drvdata(pdev); | |
c853b167 | 188 | struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); |
ad8dc96e | 189 | |
c8a06c1e DM |
190 | if (pdata->enable_external_pullup) |
191 | pdata->enable_external_pullup(0); | |
192 | ||
d2323cf7 DM |
193 | if (gpio_is_valid(pdata->ext_pullup_enable_pin)) |
194 | gpio_set_value(pdata->ext_pullup_enable_pin, 0); | |
195 | ||
ad8dc96e | 196 | w1_remove_master_device(master); |
ad8dc96e VS |
197 | |
198 | return 0; | |
199 | } | |
200 | ||
c8a06c1e DM |
201 | #ifdef CONFIG_PM |
202 | ||
203 | static int w1_gpio_suspend(struct platform_device *pdev, pm_message_t state) | |
204 | { | |
c853b167 | 205 | struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); |
c8a06c1e DM |
206 | |
207 | if (pdata->enable_external_pullup) | |
208 | pdata->enable_external_pullup(0); | |
209 | ||
210 | return 0; | |
211 | } | |
212 | ||
213 | static int w1_gpio_resume(struct platform_device *pdev) | |
214 | { | |
c853b167 | 215 | struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); |
c8a06c1e DM |
216 | |
217 | if (pdata->enable_external_pullup) | |
218 | pdata->enable_external_pullup(1); | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
223 | #else | |
224 | #define w1_gpio_suspend NULL | |
225 | #define w1_gpio_resume NULL | |
226 | #endif | |
227 | ||
ad8dc96e VS |
228 | static struct platform_driver w1_gpio_driver = { |
229 | .driver = { | |
230 | .name = "w1-gpio", | |
5f3d1382 | 231 | .of_match_table = of_match_ptr(w1_gpio_dt_ids), |
ad8dc96e | 232 | }, |
8a1861d9 | 233 | .probe = w1_gpio_probe, |
01230551 | 234 | .remove = w1_gpio_remove, |
c8a06c1e DM |
235 | .suspend = w1_gpio_suspend, |
236 | .resume = w1_gpio_resume, | |
ad8dc96e VS |
237 | }; |
238 | ||
8a1861d9 | 239 | module_platform_driver(w1_gpio_driver); |
ad8dc96e VS |
240 | |
241 | MODULE_DESCRIPTION("GPIO w1 bus master driver"); | |
242 | MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>"); | |
243 | MODULE_LICENSE("GPL"); |