brcm2708: switch to linux 4.4 and update patches
[openwrt.git] / target / linux / brcm2708 / patches-4.1 / 0119-Merge-pull-request-1059-from-pelwell-rpi-4.0.y.patch
1 From a603c307f7348255d19b6031254aac0080e99c37 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/222] 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                      | 102 +++++++++++++++++++++-
11  3 files changed, 117 insertions(+), 2 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;