summaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-3.14/0019-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch
blob: bbbab67f13f975866b2885bacd6a5aee4c231d06 (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
From 370acd9248703fb8531cd87982fb02dcce32a2b4 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 8 May 2013 11:46:50 +0100
Subject: [PATCH 19/54] 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>
---
 arch/arm/mach-bcm2708/bcm2708.c | 29 +++++++++++++++++++++
 drivers/w1/masters/w1-gpio.c    | 57 ++++++++++++++++++++++++++++++++++++-----
 drivers/w1/w1.h                 |  6 +++++
 drivers/w1/w1_int.c             | 14 ++++++++++
 drivers/w1/w1_io.c              | 18 ++++++++++---
 5 files changed, 115 insertions(+), 9 deletions(-)

--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -32,6 +32,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/spi/spi.h>
+#include <linux/w1-gpio.h>
 
 #include <linux/version.h>
 #include <linux/clkdev.h>
@@ -76,12 +77,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;
 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 void __init bcm2708_init_led(void);
 
@@ -258,6 +266,20 @@ static struct platform_device bcm2708_dm
 	.num_resources = ARRAY_SIZE(bcm2708_dmaman_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 = {
@@ -680,6 +702,11 @@ void __init bcm2708_init(void)
 #ifdef CONFIG_BCM2708_GPIO
 	bcm_register_device(&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;
+	platform_device_register(&w1_device);
+#endif
 	bcm_register_device(&bcm2708_systemtimer_device);
 	bcm_register_device(&bcm2708_fb_device);
 	bcm_register_device(&bcm2708_usb_device);
@@ -883,3 +910,5 @@ 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);
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -23,6 +23,15 @@
 #include "../w1.h"
 #include "../w1_int.h"
 
+static int w1_gpio_pullup = -1;
+static int w1_gpio_pullup_orig = -1;
+module_param_named(pullup, w1_gpio_pullup, int, 0);
+MODULE_PARM_DESC(pullup, "GPIO pin pullup 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 +76,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 struct of_device_id w1_gpio_dt_ids[] = {
 	{ .compatible = "w1-gpio" },
@@ -102,14 +121,16 @@ 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) {
-			dev_err(&pdev->dev, "Failed to parse DT\n");
-			return err;
+	if(pdata == NULL) {
+		if (of_have_populated_dt()) {
+			err = w1_gpio_probe_dt(pdev);
+			if (err < 0) {
+				dev_err(&pdev->dev, "Failed to parse DT\n");
+				return err;
+			}
 		}
 	}
 
@@ -127,6 +148,19 @@ static int w1_gpio_probe(struct platform
 		return -ENOMEM;
 	}
 
+	w1_gpio_pin_orig = pdata->pin;
+	w1_gpio_pullup_orig = pdata->ext_pullup_enable_pin;
+
+	if(gpio_is_valid(w1_gpio_pin)) {
+		pdata->pin = w1_gpio_pin;
+		pdata->ext_pullup_enable_pin = -1;
+	}
+	if(gpio_is_valid(w1_gpio_pullup)) {
+		pdata->ext_pullup_enable_pin = w1_gpio_pullup;
+	}
+
+	dev_info(&pdev->dev, "gpio pin %d, gpio pullup pin %d\n", pdata->pin, pdata->ext_pullup_enable_pin);
+
 	err = devm_gpio_request(&pdev->dev, pdata->pin, "w1");
 	if (err) {
 		dev_err(&pdev->dev, "gpio_request (pin) failed\n");
@@ -156,6 +190,14 @@ static int w1_gpio_probe(struct platform
 		master->set_pullup = w1_gpio_set_pullup;
 	}
 
+	if (gpio_is_valid(w1_gpio_pullup)) {
+		if (pdata->is_open_drain)
+			printk(KERN_ERR "w1-gpio 'pullup' 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");
@@ -186,6 +228,9 @@ 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_orig;
+
 	return 0;
 }
 
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -148,6 +148,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);
+
 	/** Really nice hardware can handles the different types of ROM search
 	 *  w1_master* is passed to the slave found callback.
 	 */
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -118,6 +118,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
@@ -127,10 +127,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;
 	}
 }