d95e564acbd43220f1e1dc215943de8b43f03d15
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-4.1 / 0119-Merge-pull-request-1059-from-pelwell-rpi-4.0.y.patch
1 From 35f9c869b55fa358e089d4394205082c5c825a27 Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <pelwell@users.noreply.github.com>
3 Date: Mon, 13 Jul 2015 13:25:31 +0100
4 Subject: [PATCH 119/148] Merge pull request #1059 from pelwell/rpi-4.0.y
5
6 w1_therm: Back-port locking improvements from 4.2-rc1
7 ---
8 Documentation/ABI/stable/sysfs-driver-w1_ds28ea00 | 6 +
9 Documentation/w1/slaves/w1_therm | 11 +-
10 drivers/w1/slaves/w1_therm.c | 162 ++++++++++++++++++++--
11 3 files changed, 163 insertions(+), 16 deletions(-)
12 create mode 100644 Documentation/ABI/stable/sysfs-driver-w1_ds28ea00
13
14 --- /dev/null
15 +++ b/Documentation/ABI/stable/sysfs-driver-w1_ds28ea00
16 @@ -0,0 +1,6 @@
17 +What: /sys/bus/w1/devices/.../w1_seq
18 +Date: Apr 2015
19 +Contact: Matt Campbell <mattrcampbell@gmail.com>
20 +Description: Support for the DS28EA00 chain sequence function
21 + see Documentation/w1/slaves/w1_therm for detailed information
22 +Users: any user space application which wants to communicate with DS28EA00
23 --- a/Documentation/w1/slaves/w1_therm
24 +++ b/Documentation/w1/slaves/w1_therm
25 @@ -11,12 +11,14 @@ Author: Evgeniy Polyakov <johnpol@2ka.mi
26 Description
27 -----------
28
29 -w1_therm provides basic temperature conversion for ds18*20 devices.
30 +w1_therm provides basic temperature conversion for ds18*20 devices, and the
31 +ds28ea00 device.
32 supported family codes:
33 W1_THERM_DS18S20 0x10
34 W1_THERM_DS1822 0x22
35 W1_THERM_DS18B20 0x28
36 W1_THERM_DS1825 0x3B
37 +W1_THERM_DS28EA00 0x42
38
39 Support is provided through the sysfs w1_slave file. Each open and
40 read sequence will initiate a temperature conversion then provide two
41 @@ -48,3 +50,10 @@ resistor). The DS18b20 temperature sens
42 maximum current draw of 1.5mA and that a 5k pullup resistor is not
43 sufficient. The strong pullup is designed to provide the additional
44 current required.
45 +
46 +The DS28EA00 provides an additional two pins for implementing a sequence
47 +detection algorithm. This feature allows you to determine the physical
48 +location of the chip in the 1-wire bus without needing pre-existing
49 +knowledge of the bus ordering. Support is provided through the sysfs
50 +w1_seq file. The file will contain a single line with an integer value
51 +representing the device index in the bus starting at 0.
52 --- a/drivers/w1/slaves/w1_therm.c
53 +++ b/drivers/w1/slaves/w1_therm.c
54 @@ -92,13 +92,24 @@ static void w1_therm_remove_slave(struct
55 static ssize_t w1_slave_show(struct device *device,
56 struct device_attribute *attr, char *buf);
57
58 +static ssize_t w1_seq_show(struct device *device,
59 + struct device_attribute *attr, char *buf);
60 +
61 static DEVICE_ATTR_RO(w1_slave);
62 +static DEVICE_ATTR_RO(w1_seq);
63
64 static struct attribute *w1_therm_attrs[] = {
65 &dev_attr_w1_slave.attr,
66 NULL,
67 };
68 +
69 +static struct attribute *w1_ds28ea00_attrs[] = {
70 + &dev_attr_w1_slave.attr,
71 + &dev_attr_w1_seq.attr,
72 + NULL,
73 +};
74 ATTRIBUTE_GROUPS(w1_therm);
75 +ATTRIBUTE_GROUPS(w1_ds28ea00);
76
77 static struct w1_family_ops w1_therm_fops = {
78 .add_slave = w1_therm_add_slave,
79 @@ -106,6 +117,12 @@ static struct w1_family_ops w1_therm_fop
80 .groups = w1_therm_groups,
81 };
82
83 +static struct w1_family_ops w1_ds28ea00_fops = {
84 + .add_slave = w1_therm_add_slave,
85 + .remove_slave = w1_therm_remove_slave,
86 + .groups = w1_ds28ea00_groups,
87 +};
88 +
89 static struct w1_family w1_therm_family_DS18S20 = {
90 .fid = W1_THERM_DS18S20,
91 .fops = &w1_therm_fops,
92 @@ -123,7 +140,7 @@ static struct w1_family w1_therm_family_
93
94 static struct w1_family w1_therm_family_DS28EA00 = {
95 .fid = W1_THERM_DS28EA00,
96 - .fops = &w1_therm_fops,
97 + .fops = &w1_ds28ea00_fops,
98 };
99
100 static struct w1_family w1_therm_family_DS1825 = {
101 @@ -316,6 +333,89 @@ post_unlock:
102 return ret;
103 }
104
105 +#define W1_42_CHAIN 0x99
106 +#define W1_42_CHAIN_OFF 0x3C
107 +#define W1_42_CHAIN_OFF_INV 0xC3
108 +#define W1_42_CHAIN_ON 0x5A
109 +#define W1_42_CHAIN_ON_INV 0xA5
110 +#define W1_42_CHAIN_DONE 0x96
111 +#define W1_42_CHAIN_DONE_INV 0x69
112 +#define W1_42_COND_READ 0x0F
113 +#define W1_42_SUCCESS_CONFIRM_BYTE 0xAA
114 +#define W1_42_FINISHED_BYTE 0xFF
115 +static ssize_t w1_seq_show(struct device *device,
116 + struct device_attribute *attr, char *buf)
117 +{
118 + struct w1_slave *sl = dev_to_w1_slave(device);
119 + ssize_t c = PAGE_SIZE;
120 + int rv;
121 + int i;
122 + u8 ack;
123 + u64 rn;
124 + struct w1_reg_num *reg_num;
125 + int seq = 0;
126 +
127 + mutex_lock(&sl->master->bus_mutex);
128 + /* Place all devices in CHAIN state */
129 + if (w1_reset_bus(sl->master))
130 + goto error;
131 + w1_write_8(sl->master, W1_SKIP_ROM);
132 + w1_write_8(sl->master, W1_42_CHAIN);
133 + w1_write_8(sl->master, W1_42_CHAIN_ON);
134 + w1_write_8(sl->master, W1_42_CHAIN_ON_INV);
135 + msleep(sl->master->pullup_duration);
136 +
137 + /* check for acknowledgment */
138 + ack = w1_read_8(sl->master);
139 + if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
140 + goto error;
141 +
142 + /* In case the bus fails to send 0xFF, limit*/
143 + for (i = 0; i <= 64; i++) {
144 + if (w1_reset_bus(sl->master))
145 + goto error;
146 +
147 + w1_write_8(sl->master, W1_42_COND_READ);
148 + rv = w1_read_block(sl->master, (u8 *)&rn, 8);
149 + reg_num = (struct w1_reg_num *) &rn;
150 + if (reg_num->family == W1_42_FINISHED_BYTE)
151 + break;
152 + if (sl->reg_num.id == reg_num->id)
153 + seq = i;
154 +
155 + w1_write_8(sl->master, W1_42_CHAIN);
156 + w1_write_8(sl->master, W1_42_CHAIN_DONE);
157 + w1_write_8(sl->master, W1_42_CHAIN_DONE_INV);
158 + w1_read_block(sl->master, &ack, sizeof(ack));
159 +
160 + /* check for acknowledgment */
161 + ack = w1_read_8(sl->master);
162 + if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
163 + goto error;
164 +
165 + }
166 +
167 + /* Exit from CHAIN state */
168 + if (w1_reset_bus(sl->master))
169 + goto error;
170 + w1_write_8(sl->master, W1_SKIP_ROM);
171 + w1_write_8(sl->master, W1_42_CHAIN);
172 + w1_write_8(sl->master, W1_42_CHAIN_OFF);
173 + w1_write_8(sl->master, W1_42_CHAIN_OFF_INV);
174 +
175 + /* check for acknowledgment */
176 + ack = w1_read_8(sl->master);
177 + if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
178 + goto error;
179 + mutex_unlock(&sl->master->bus_mutex);
180 +
181 + c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", seq);
182 + return PAGE_SIZE - c;
183 +error:
184 + mutex_unlock(&sl->master->bus_mutex);
185 + return -EIO;
186 +}
187 +
188 static int __init w1_therm_init(void)
189 {
190 int err, i;