summaryrefslogtreecommitdiff
path: root/target/linux/brcm2708/patches-4.1/0031-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch
blob: 34136abe83074adb187b61345a3fd622c227b65a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
From 4a703aa1cc152189682c173bb4d89ef8f9da6c21 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 8 May 2013 11:46:50 +0100
Subject: [PATCH 031/148] enabling the realtime clock 1-wire chip DS1307 and
 1-wire on GPIO4 (as a module)

1-wire: Add support for configuring pin for w1-gpio kernel module
See: https://github.com/raspberrypi/linux/pull/457

Add bitbanging pullups, use them for w1-gpio

Allows parasite power to work, uses module option pullup=1

bcm2708: Ensure 1-wire pullup is disabled by default, and expose as module parameter

Signed-off-by: Alex J Lennon <ajlennon@dynamicdevices.co.uk>

w1-gpio: Add gpiopin module parameter and correctly free up gpio pull-up pin, if set

Signed-off-by: Alex J Lennon <ajlennon@dynamicdevices.co.uk>

w1-gpio: Sort out the pullup/parasitic power tangle
---
 arch/arm/mach-bcm2708/bcm2708.c | 29 +++++++++++++++++
 arch/arm/mach-bcm2709/bcm2709.c | 29 +++++++++++++++++
 drivers/w1/masters/w1-gpio.c    | 69 +++++++++++++++++++++++++++++++++++++----
 drivers/w1/w1.h                 |  6 ++++
 drivers/w1/w1_int.c             | 14 +++++++++
 drivers/w1/w1_io.c              | 18 +++++++++--
 include/linux/w1-gpio.h         |  1 +
 7 files changed, 157 insertions(+), 9 deletions(-)

--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -36,6 +36,7 @@
 #include <linux/of_platform.h>
 #include <linux/spi/spi.h>
 #include <linux/gpio/machine.h>
+#include <linux/w1-gpio.h>
 
 #include <linux/version.h>
 #include <linux/clkdev.h>
@@ -77,12 +78,19 @@
  */
 #define DMA_MASK_BITS_COMMON 32
 
+// use GPIO 4 for the one-wire GPIO pin, if enabled
+#define W1_GPIO 4
+// ensure one-wire GPIO pullup is disabled by default
+#define W1_PULLUP -1
+
 /* command line parameters */
 static unsigned boardrev, serial;
 static unsigned uart_clock = UART0_CLOCK;
 static unsigned disk_led_gpio = 16;
 static unsigned disk_led_active_low = 1;
 static unsigned reboot_part = 0;
+static unsigned w1_gpio_pin = W1_GPIO;
+static unsigned w1_gpio_pullup = W1_PULLUP;
 static bool vc_i2c_override = false;
 
 static unsigned use_dt = 0;
@@ -303,6 +311,20 @@ static struct platform_device bcm2708_dm
 	.num_resources = ARRAY_SIZE(bcm2708_dmaengine_resources),
 };
 
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+static struct w1_gpio_platform_data w1_gpio_pdata = {
+	.pin = W1_GPIO,
+        .ext_pullup_enable_pin = W1_PULLUP,
+	.is_open_drain = 0,
+};
+
+static struct platform_device w1_device = {
+	.name = "w1-gpio",
+	.id = -1,
+	.dev.platform_data = &w1_gpio_pdata,
+};
+#endif
+
 static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
 
 static struct platform_device bcm2708_fb_device = {
@@ -729,6 +751,11 @@ void __init bcm2708_init(void)
 #ifdef CONFIG_BCM2708_GPIO
 	bcm_register_device_dt(&bcm2708_gpio_device);
 #endif
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+	w1_gpio_pdata.pin = w1_gpio_pin;
+	w1_gpio_pdata.ext_pullup_enable_pin = w1_gpio_pullup;
+	bcm_register_device_dt(&w1_device);
+#endif
 	bcm_register_device_dt(&bcm2708_fb_device);
 	bcm_register_device_dt(&bcm2708_usb_device);
 
@@ -942,5 +969,7 @@ module_param(uart_clock, uint, 0644);
 module_param(disk_led_gpio, uint, 0644);
 module_param(disk_led_active_low, uint, 0644);
 module_param(reboot_part, uint, 0644);
+module_param(w1_gpio_pin, uint, 0644);
+module_param(w1_gpio_pullup, uint, 0644);
 module_param(vc_i2c_override, bool, 0644);
 MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral.");
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -36,6 +36,7 @@
 #include <linux/of_platform.h>
 #include <linux/spi/spi.h>
 #include <linux/gpio/machine.h>
+#include <linux/w1-gpio.h>
 
 #include <linux/version.h>
 #include <linux/clkdev.h>
@@ -79,12 +80,19 @@
  */
 #define DMA_MASK_BITS_COMMON 32
 
+// use GPIO 4 for the one-wire GPIO pin, if enabled
+#define W1_GPIO 4
+// ensure one-wire GPIO pullup is disabled by default
+#define W1_PULLUP -1
+
 /* command line parameters */
 static unsigned boardrev, serial;
 static unsigned uart_clock = UART0_CLOCK;
 static unsigned disk_led_gpio = 16;
 static unsigned disk_led_active_low = 1;
 static unsigned reboot_part = 0;
+static unsigned w1_gpio_pin = W1_GPIO;
+static unsigned w1_gpio_pullup = W1_PULLUP;
 static bool vc_i2c_override = false;
 
 static unsigned use_dt = 0;
@@ -313,6 +321,20 @@ static struct platform_device bcm2708_dm
 	.num_resources = ARRAY_SIZE(bcm2708_dmaengine_resources),
 };
 
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+static struct w1_gpio_platform_data w1_gpio_pdata = {
+	.pin = W1_GPIO,
+        .ext_pullup_enable_pin = W1_PULLUP,
+	.is_open_drain = 0,
+};
+
+static struct platform_device w1_device = {
+	.name = "w1-gpio",
+	.id = -1,
+	.dev.platform_data = &w1_gpio_pdata,
+};
+#endif
+
 static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
 
 static struct platform_device bcm2708_fb_device = {
@@ -749,6 +771,11 @@ void __init bcm2709_init(void)
 #ifdef CONFIG_BCM2708_GPIO
 	bcm_register_device_dt(&bcm2708_gpio_device);
 #endif
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+	w1_gpio_pdata.pin = w1_gpio_pin;
+	w1_gpio_pdata.ext_pullup_enable_pin = w1_gpio_pullup;
+	bcm_register_device_dt(&w1_device);
+#endif
 	bcm_register_device_dt(&bcm2708_fb_device);
 	bcm_register_device_dt(&bcm2708_usb_device);
 
@@ -1110,5 +1137,7 @@ module_param(uart_clock, uint, 0644);
 module_param(disk_led_gpio, uint, 0644);
 module_param(disk_led_active_low, uint, 0644);
 module_param(reboot_part, uint, 0644);
+module_param(w1_gpio_pin, uint, 0644);
+module_param(w1_gpio_pullup, uint, 0644);
 module_param(vc_i2c_override, bool, 0644);
 MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral.");
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -23,6 +23,19 @@
 #include "../w1.h"
 #include "../w1_int.h"
 
+static int w1_gpio_pullup = 0;
+static int w1_gpio_pullup_orig = 0;
+module_param_named(pullup, w1_gpio_pullup, int, 0);
+MODULE_PARM_DESC(pullup, "Enable parasitic power (power on data) mode");
+static int w1_gpio_pullup_pin = -1;
+static int w1_gpio_pullup_pin_orig = -1;
+module_param_named(extpullup, w1_gpio_pullup_pin, int, 0);
+MODULE_PARM_DESC(extpullup, "GPIO external pullup pin number");
+static int w1_gpio_pin = -1;
+static int w1_gpio_pin_orig = -1;
+module_param_named(gpiopin, w1_gpio_pin, int, 0);
+MODULE_PARM_DESC(gpiopin, "GPIO pin number");
+
 static u8 w1_gpio_set_pullup(void *data, int delay)
 {
 	struct w1_gpio_platform_data *pdata = data;
@@ -67,6 +80,16 @@ static u8 w1_gpio_read_bit(void *data)
 	return gpio_get_value(pdata->pin) ? 1 : 0;
 }
 
+static void w1_gpio_bitbang_pullup(void *data, u8 on)
+{
+	struct w1_gpio_platform_data *pdata = data;
+
+	if (on)
+		gpio_direction_output(pdata->pin, 1);
+	else
+		gpio_direction_input(pdata->pin);
+}
+
 #if defined(CONFIG_OF)
 static const struct of_device_id w1_gpio_dt_ids[] = {
 	{ .compatible = "w1-gpio" },
@@ -80,6 +103,7 @@ static int w1_gpio_probe_dt(struct platf
 	struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct device_node *np = pdev->dev.of_node;
 	int gpio;
+	u32 value;
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
@@ -88,6 +112,9 @@ static int w1_gpio_probe_dt(struct platf
 	if (of_get_property(np, "linux,open-drain", NULL))
 		pdata->is_open_drain = 1;
 
+	if (of_property_read_u32(np, "rpi,parasitic-power", &value) == 0)
+	    pdata->parasitic_power = (value != 0);
+
 	gpio = of_get_gpio(np, 0);
 	if (gpio < 0) {
 		if (gpio != -EPROBE_DEFER)
@@ -103,7 +130,7 @@ static int w1_gpio_probe_dt(struct platf
 	if (gpio == -EPROBE_DEFER)
 		return gpio;
 	/* ignore other errors as the pullup gpio is optional */
-	pdata->ext_pullup_enable_pin = gpio;
+	pdata->ext_pullup_enable_pin = (gpio >= 0) ? gpio : -1;
 
 	pdev->dev.platform_data = pdata;
 
@@ -113,13 +140,15 @@ static int w1_gpio_probe_dt(struct platf
 static int w1_gpio_probe(struct platform_device *pdev)
 {
 	struct w1_bus_master *master;
-	struct w1_gpio_platform_data *pdata;
+	struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
 	int err;
 
-	if (of_have_populated_dt()) {
-		err = w1_gpio_probe_dt(pdev);
-		if (err < 0)
-			return err;
+	if(pdata == NULL) {
+		if (of_have_populated_dt()) {
+			err = w1_gpio_probe_dt(pdev);
+			if (err < 0)
+				return err;
+		}
 	}
 
 	pdata = dev_get_platdata(&pdev->dev);
@@ -136,6 +165,22 @@ static int w1_gpio_probe(struct platform
 		return -ENOMEM;
 	}
 
+	w1_gpio_pin_orig = pdata->pin;
+	w1_gpio_pullup_pin_orig = pdata->ext_pullup_enable_pin;
+	w1_gpio_pullup_orig = pdata->parasitic_power;
+
+	if(gpio_is_valid(w1_gpio_pin)) {
+		pdata->pin = w1_gpio_pin;
+		pdata->ext_pullup_enable_pin = -1;
+		pdata->parasitic_power = -1;
+	}
+	pdata->parasitic_power |= w1_gpio_pullup;
+	if(gpio_is_valid(w1_gpio_pullup_pin)) {
+		pdata->ext_pullup_enable_pin = w1_gpio_pullup_pin;
+	}
+
+	dev_info(&pdev->dev, "gpio pin %d, external pullup pin %d, parasitic power %d\n", pdata->pin, pdata->ext_pullup_enable_pin, pdata->parasitic_power);
+
 	err = devm_gpio_request(&pdev->dev, pdata->pin, "w1");
 	if (err) {
 		dev_err(&pdev->dev, "gpio_request (pin) failed\n");
@@ -165,6 +210,14 @@ static int w1_gpio_probe(struct platform
 		master->set_pullup = w1_gpio_set_pullup;
 	}
 
+	if (pdata->parasitic_power) {
+		if (pdata->is_open_drain)
+			printk(KERN_ERR "w1-gpio 'pullup'(parasitic power) "
+			       "option doesn't work with open drain GPIO\n");
+		else
+			master->bitbang_pullup = w1_gpio_bitbang_pullup;
+	}
+
 	err = w1_add_master_device(master);
 	if (err) {
 		dev_err(&pdev->dev, "w1_add_master device failed\n");
@@ -195,6 +248,10 @@ static int w1_gpio_remove(struct platfor
 
 	w1_remove_master_device(master);
 
+	pdata->pin = w1_gpio_pin_orig;
+	pdata->ext_pullup_enable_pin = w1_gpio_pullup_pin_orig;
+	pdata->parasitic_power = w1_gpio_pullup_orig;
+
 	return 0;
 }
 
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -171,6 +171,12 @@ struct w1_bus_master
 
 	u8		(*set_pullup)(void *, int);
 
+	/**
+	 * Turns the pullup on/off in bitbanging mode, takes an on/off argument.
+	 * @return -1=Error, 0=completed
+	 */
+	void (*bitbang_pullup) (void *, u8);
+
 	void		(*search)(void *, struct w1_master *,
 		u8, w1_slave_found_callback);
 };
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -123,6 +123,20 @@ int w1_add_master_device(struct w1_bus_m
 		return(-EINVAL);
 	}
 
+	/* bitbanging hardware uses bitbang_pullup, other hardware uses set_pullup
+	 * and takes care of timing itself */
+	if (!master->write_byte && !master->touch_bit && master->set_pullup) {
+		printk(KERN_ERR "w1_add_master_device: set_pullup requires "
+			"write_byte or touch_bit, disabling\n");
+		master->set_pullup = NULL;
+	}
+
+	if (master->set_pullup && master->bitbang_pullup) {
+		printk(KERN_ERR "w1_add_master_device: set_pullup should not "
+		       "be set when bitbang_pullup is used, disabling\n");
+		master->set_pullup = NULL;
+	}
+
 	/* Lock until the device is added (or not) to w1_masters. */
 	mutex_lock(&w1_mlock);
 	/* Search for the first available id (starting at 1). */
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -134,10 +134,22 @@ static void w1_pre_write(struct w1_maste
 static void w1_post_write(struct w1_master *dev)
 {
 	if (dev->pullup_duration) {
-		if (dev->enable_pullup && dev->bus_master->set_pullup)
-			dev->bus_master->set_pullup(dev->bus_master->data, 0);
-		else
+		if (dev->enable_pullup) {
+			if (dev->bus_master->set_pullup) {
+				dev->bus_master->set_pullup(dev->
+							    bus_master->data,
+							    0);
+			} else if (dev->bus_master->bitbang_pullup) {
+				dev->bus_master->
+				    bitbang_pullup(dev->bus_master->data, 1);
 			msleep(dev->pullup_duration);
+				dev->bus_master->
+				    bitbang_pullup(dev->bus_master->data, 0);
+			}
+		} else {
+			msleep(dev->pullup_duration);
+		}
+
 		dev->pullup_duration = 0;
 	}
 }
--- a/include/linux/w1-gpio.h
+++ b/include/linux/w1-gpio.h
@@ -18,6 +18,7 @@
 struct w1_gpio_platform_data {
 	unsigned int pin;
 	unsigned int is_open_drain:1;
+	unsigned int parasitic_power:1;
 	void (*enable_external_pullup)(int enable);
 	unsigned int ext_pullup_enable_pin;
 	unsigned int pullup_duration;