aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.1/0119-Merge-pull-request-1059-from-pelwell-rpi-4.0.y.patch
blob: d95e564acbd43220f1e1dc215943de8b43f03d15 (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
From 35f9c869b55fa358e089d4394205082c5c825a27 Mon Sep 17 00:00:00 2001
From: Phil Elwell <pelwell@users.noreply.github.com>
Date: Mon, 13 Jul 2015 13:25:31 +0100
Subject: [PATCH 119/148] Merge pull request #1059 from pelwell/rpi-4.0.y

w1_therm: Back-port locking improvements from 4.2-rc1
---
 Documentation/ABI/stable/sysfs-driver-w1_ds28ea00 |   6 +
 Documentation/w1/slaves/w1_therm                  |  11 +-
 drivers/w1/slaves/w1_therm.c                      | 162 ++++++++++++++++++++--
 3 files changed, 163 insertions(+), 16 deletions(-)
 create mode 100644 Documentation/ABI/stable/sysfs-driver-w1_ds28ea00

--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-driver-w1_ds28ea00
@@ -0,0 +1,6 @@
+What:		/sys/bus/w1/devices/.../w1_seq
+Date:		Apr 2015
+Contact:	Matt Campbell <mattrcampbell@gmail.com>
+Description:	Support for the DS28EA00 chain sequence function
+		see Documentation/w1/slaves/w1_therm for detailed information
+Users:		any user space application which wants to communicate with DS28EA00
--- a/Documentation/w1/slaves/w1_therm
+++ b/Documentation/w1/slaves/w1_therm
@@ -11,12 +11,14 @@ Author: Evgeniy Polyakov <johnpol@2ka.mi
 Description
 -----------
 
-w1_therm provides basic temperature conversion for ds18*20 devices.
+w1_therm provides basic temperature conversion for ds18*20 devices, and the
+ds28ea00 device.
 supported family codes:
 W1_THERM_DS18S20	0x10
 W1_THERM_DS1822		0x22
 W1_THERM_DS18B20	0x28
 W1_THERM_DS1825		0x3B
+W1_THERM_DS28EA00	0x42
 
 Support is provided through the sysfs w1_slave file.  Each open and
 read sequence will initiate a temperature conversion then provide two
@@ -48,3 +50,10 @@ resistor).  The DS18b20 temperature sens
 maximum current draw of 1.5mA and that a 5k pullup resistor is not
 sufficient.  The strong pullup is designed to provide the additional
 current required.
+
+The DS28EA00 provides an additional two pins for implementing a sequence
+detection algorithm.  This feature allows you to determine the physical
+location of the chip in the 1-wire bus without needing pre-existing
+knowledge of the bus ordering.  Support is provided through the sysfs
+w1_seq file.  The file will contain a single line with an integer value
+representing the device index in the bus starting at 0.
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -92,13 +92,24 @@ static void w1_therm_remove_slave(struct
 static ssize_t w1_slave_show(struct device *device,
 	struct device_attribute *attr, char *buf);
 
+static ssize_t w1_seq_show(struct device *device,
+	struct device_attribute *attr, char *buf);
+
 static DEVICE_ATTR_RO(w1_slave);
+static DEVICE_ATTR_RO(w1_seq);
 
 static struct attribute *w1_therm_attrs[] = {
 	&dev_attr_w1_slave.attr,
 	NULL,
 };
+
+static struct attribute *w1_ds28ea00_attrs[] = {
+	&dev_attr_w1_slave.attr,
+	&dev_attr_w1_seq.attr,
+	NULL,
+};
 ATTRIBUTE_GROUPS(w1_therm);
+ATTRIBUTE_GROUPS(w1_ds28ea00);
 
 static struct w1_family_ops w1_therm_fops = {
 	.add_slave	= w1_therm_add_slave,
@@ -106,6 +117,12 @@ static struct w1_family_ops w1_therm_fop
 	.groups		= w1_therm_groups,
 };
 
+static struct w1_family_ops w1_ds28ea00_fops = {
+	.add_slave	= w1_therm_add_slave,
+	.remove_slave	= w1_therm_remove_slave,
+	.groups		= w1_ds28ea00_groups,
+};
+
 static struct w1_family w1_therm_family_DS18S20 = {
 	.fid = W1_THERM_DS18S20,
 	.fops = &w1_therm_fops,
@@ -123,7 +140,7 @@ static struct w1_family w1_therm_family_
 
 static struct w1_family w1_therm_family_DS28EA00 = {
 	.fid = W1_THERM_DS28EA00,
-	.fops = &w1_therm_fops,
+	.fops = &w1_ds28ea00_fops,
 };
 
 static struct w1_family w1_therm_family_DS1825 = {
@@ -316,6 +333,89 @@ post_unlock:
 	return ret;
 }
 
+#define W1_42_CHAIN	0x99
+#define W1_42_CHAIN_OFF	0x3C
+#define W1_42_CHAIN_OFF_INV	0xC3
+#define W1_42_CHAIN_ON	0x5A
+#define W1_42_CHAIN_ON_INV	0xA5
+#define W1_42_CHAIN_DONE 0x96
+#define W1_42_CHAIN_DONE_INV 0x69
+#define W1_42_COND_READ	0x0F
+#define W1_42_SUCCESS_CONFIRM_BYTE 0xAA
+#define W1_42_FINISHED_BYTE 0xFF
+static ssize_t w1_seq_show(struct device *device,
+	struct device_attribute *attr, char *buf)
+{
+	struct w1_slave *sl = dev_to_w1_slave(device);
+	ssize_t c = PAGE_SIZE;
+	int rv;
+	int i;
+	u8 ack;
+	u64 rn;
+	struct w1_reg_num *reg_num;
+	int seq = 0;
+
+	mutex_lock(&sl->master->bus_mutex);
+	/* Place all devices in CHAIN state */
+	if (w1_reset_bus(sl->master))
+		goto error;
+	w1_write_8(sl->master, W1_SKIP_ROM);
+	w1_write_8(sl->master, W1_42_CHAIN);
+	w1_write_8(sl->master, W1_42_CHAIN_ON);
+	w1_write_8(sl->master, W1_42_CHAIN_ON_INV);
+	msleep(sl->master->pullup_duration);
+
+	/* check for acknowledgment */
+	ack = w1_read_8(sl->master);
+	if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
+		goto error;
+
+	/* In case the bus fails to send 0xFF, limit*/
+	for (i = 0; i <= 64; i++) {
+		if (w1_reset_bus(sl->master))
+			goto error;
+
+		w1_write_8(sl->master, W1_42_COND_READ);
+		rv = w1_read_block(sl->master, (u8 *)&rn, 8);
+		reg_num = (struct w1_reg_num *) &rn;
+		if (reg_num->family == W1_42_FINISHED_BYTE)
+			break;
+		if (sl->reg_num.id == reg_num->id)
+			seq = i;
+
+		w1_write_8(sl->master, W1_42_CHAIN);
+		w1_write_8(sl->master, W1_42_CHAIN_DONE);
+		w1_write_8(sl->master, W1_42_CHAIN_DONE_INV);
+		w1_read_block(sl->master, &ack, sizeof(ack));
+
+		/* check for acknowledgment */
+		ack = w1_read_8(sl->master);
+		if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
+			goto error;
+
+	}
+
+	/* Exit from CHAIN state */
+	if (w1_reset_bus(sl->master))
+		goto error;
+	w1_write_8(sl->master, W1_SKIP_ROM);
+	w1_write_8(sl->master, W1_42_CHAIN);
+	w1_write_8(sl->master, W1_42_CHAIN_OFF);
+	w1_write_8(sl->master, W1_42_CHAIN_OFF_INV);
+
+	/* check for acknowledgment */
+	ack = w1_read_8(sl->master);
+	if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
+		goto error;
+	mutex_unlock(&sl->master->bus_mutex);
+
+	c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", seq);
+	return PAGE_SIZE - c;
+error:
+	mutex_unlock(&sl->master->bus_mutex);
+	return -EIO;
+}
+
 static int __init w1_therm_init(void)
 {
 	int err, i;