1d3e19cf9SMaxime Ripard // SPDX-License-Identifier: GPL-2.0+
2d3e19cf9SMaxime Ripard /*
3d3e19cf9SMaxime Ripard *
4d3e19cf9SMaxime Ripard * Copyright (c) 2015 Free Electrons
5d3e19cf9SMaxime Ripard * Copyright (c) 2015 NextThing Co.
6d3e19cf9SMaxime Ripard * Copyright (c) 2018 Microchip Technology, Inc.
7d3e19cf9SMaxime Ripard *
8d3e19cf9SMaxime Ripard * Maxime Ripard <maxime.ripard@free-electrons.com>
9d3e19cf9SMaxime Ripard * Eugen Hristev <eugen.hristev@microchip.com>
10d3e19cf9SMaxime Ripard *
11d3e19cf9SMaxime Ripard */
12d3e19cf9SMaxime Ripard
13d3e19cf9SMaxime Ripard #include <common.h>
14d3e19cf9SMaxime Ripard #include <dm.h>
15d3e19cf9SMaxime Ripard #include <w1.h>
16543b98c8SEugen Hristev #include <w1-eeprom.h>
17d3e19cf9SMaxime Ripard
18d3e19cf9SMaxime Ripard #include <dm/device-internal.h>
19d3e19cf9SMaxime Ripard
20d3e19cf9SMaxime Ripard #define W1_MATCH_ROM 0x55
21d3e19cf9SMaxime Ripard #define W1_SKIP_ROM 0xcc
22d3e19cf9SMaxime Ripard #define W1_SEARCH 0xf0
23d3e19cf9SMaxime Ripard
24d3e19cf9SMaxime Ripard struct w1_bus {
25d3e19cf9SMaxime Ripard u64 search_id;
26d3e19cf9SMaxime Ripard };
27d3e19cf9SMaxime Ripard
w1_enumerate(struct udevice * bus)28d3e19cf9SMaxime Ripard static int w1_enumerate(struct udevice *bus)
29d3e19cf9SMaxime Ripard {
30d3e19cf9SMaxime Ripard const struct w1_ops *ops = device_get_ops(bus);
31d3e19cf9SMaxime Ripard struct w1_bus *w1 = dev_get_uclass_priv(bus);
32d3e19cf9SMaxime Ripard u64 last_rn, rn = w1->search_id, tmp64;
33d3e19cf9SMaxime Ripard bool last_device = false;
34d3e19cf9SMaxime Ripard int search_bit, desc_bit = 64;
35d3e19cf9SMaxime Ripard int last_zero = -1;
36d3e19cf9SMaxime Ripard u8 triplet_ret = 0;
37d3e19cf9SMaxime Ripard int i;
38d3e19cf9SMaxime Ripard
39d3e19cf9SMaxime Ripard if (!ops->reset || !ops->write_byte || !ops->triplet)
40d3e19cf9SMaxime Ripard return -ENOSYS;
41d3e19cf9SMaxime Ripard
42d3e19cf9SMaxime Ripard while (!last_device) {
43d3e19cf9SMaxime Ripard last_rn = rn;
44d3e19cf9SMaxime Ripard rn = 0;
45d3e19cf9SMaxime Ripard
46d3e19cf9SMaxime Ripard /*
47d3e19cf9SMaxime Ripard * Reset bus and all 1-wire device state machines
48d3e19cf9SMaxime Ripard * so they can respond to our requests.
49d3e19cf9SMaxime Ripard *
50d3e19cf9SMaxime Ripard * Return 0 - device(s) present, 1 - no devices present.
51d3e19cf9SMaxime Ripard */
52d3e19cf9SMaxime Ripard if (ops->reset(bus)) {
53d3e19cf9SMaxime Ripard debug("%s: No devices present on the wire.\n",
54d3e19cf9SMaxime Ripard __func__);
55d3e19cf9SMaxime Ripard break;
56d3e19cf9SMaxime Ripard }
57d3e19cf9SMaxime Ripard
58d3e19cf9SMaxime Ripard /* Start the search */
59d3e19cf9SMaxime Ripard ops->write_byte(bus, W1_SEARCH);
60d3e19cf9SMaxime Ripard for (i = 0; i < 64; ++i) {
61d3e19cf9SMaxime Ripard /* Determine the direction/search bit */
62d3e19cf9SMaxime Ripard if (i == desc_bit)
63d3e19cf9SMaxime Ripard /* took the 0 path last time, so take the 1 path */
64d3e19cf9SMaxime Ripard search_bit = 1;
65d3e19cf9SMaxime Ripard else if (i > desc_bit)
66d3e19cf9SMaxime Ripard /* take the 0 path on the next branch */
67d3e19cf9SMaxime Ripard search_bit = 0;
68d3e19cf9SMaxime Ripard else
69d3e19cf9SMaxime Ripard search_bit = ((last_rn >> i) & 0x1);
70d3e19cf9SMaxime Ripard
71d3e19cf9SMaxime Ripard /* Read two bits and write one bit */
72d3e19cf9SMaxime Ripard triplet_ret = ops->triplet(bus, search_bit);
73d3e19cf9SMaxime Ripard
74d3e19cf9SMaxime Ripard /* quit if no device responded */
75d3e19cf9SMaxime Ripard if ((triplet_ret & 0x03) == 0x03)
76d3e19cf9SMaxime Ripard break;
77d3e19cf9SMaxime Ripard
78d3e19cf9SMaxime Ripard /* If both directions were valid, and we took the 0 path... */
79d3e19cf9SMaxime Ripard if (triplet_ret == 0)
80d3e19cf9SMaxime Ripard last_zero = i;
81d3e19cf9SMaxime Ripard
82d3e19cf9SMaxime Ripard /* extract the direction taken & update the device number */
83d3e19cf9SMaxime Ripard tmp64 = (triplet_ret >> 2);
84d3e19cf9SMaxime Ripard rn |= (tmp64 << i);
85d3e19cf9SMaxime Ripard }
86d3e19cf9SMaxime Ripard
87d3e19cf9SMaxime Ripard if ((triplet_ret & 0x03) != 0x03) {
88d3e19cf9SMaxime Ripard if (desc_bit == last_zero || last_zero < 0) {
89d3e19cf9SMaxime Ripard last_device = 1;
90d3e19cf9SMaxime Ripard w1->search_id = 0;
91d3e19cf9SMaxime Ripard } else {
92d3e19cf9SMaxime Ripard w1->search_id = rn;
93d3e19cf9SMaxime Ripard }
94d3e19cf9SMaxime Ripard desc_bit = last_zero;
95d3e19cf9SMaxime Ripard
96d3e19cf9SMaxime Ripard debug("%s: Detected new device 0x%llx (family 0x%x)\n",
97d3e19cf9SMaxime Ripard bus->name, rn, (u8)(rn & 0xff));
98543b98c8SEugen Hristev
99543b98c8SEugen Hristev /* attempt to register as w1-eeprom device */
100543b98c8SEugen Hristev w1_eeprom_register_new_device(rn);
101d3e19cf9SMaxime Ripard }
102d3e19cf9SMaxime Ripard }
103d3e19cf9SMaxime Ripard
104d3e19cf9SMaxime Ripard return 0;
105d3e19cf9SMaxime Ripard }
106d3e19cf9SMaxime Ripard
w1_get_bus(int busnum,struct udevice ** busp)107d3e19cf9SMaxime Ripard int w1_get_bus(int busnum, struct udevice **busp)
108d3e19cf9SMaxime Ripard {
109d3e19cf9SMaxime Ripard int ret, i = 0;
110d3e19cf9SMaxime Ripard
111d3e19cf9SMaxime Ripard struct udevice *dev;
112d3e19cf9SMaxime Ripard
113d3e19cf9SMaxime Ripard for (ret = uclass_first_device(UCLASS_W1, &dev);
114*65b60897SMartin Fuzzey dev && !ret;
115*65b60897SMartin Fuzzey ret = uclass_next_device(&dev), i++) {
116d3e19cf9SMaxime Ripard if (i == busnum) {
117d3e19cf9SMaxime Ripard *busp = dev;
118d3e19cf9SMaxime Ripard return 0;
119d3e19cf9SMaxime Ripard }
120d3e19cf9SMaxime Ripard }
121*65b60897SMartin Fuzzey
122*65b60897SMartin Fuzzey if (!ret) {
123*65b60897SMartin Fuzzey debug("Cannot find w1 bus %d\n", busnum);
124*65b60897SMartin Fuzzey ret = -ENODEV;
125*65b60897SMartin Fuzzey }
126*65b60897SMartin Fuzzey
127d3e19cf9SMaxime Ripard return ret;
128d3e19cf9SMaxime Ripard }
129d3e19cf9SMaxime Ripard
w1_get_device_family(struct udevice * dev)130d3e19cf9SMaxime Ripard u8 w1_get_device_family(struct udevice *dev)
131d3e19cf9SMaxime Ripard {
132d3e19cf9SMaxime Ripard struct w1_device *w1 = dev_get_parent_platdata(dev);
133d3e19cf9SMaxime Ripard
134d3e19cf9SMaxime Ripard return w1->id & 0xff;
135d3e19cf9SMaxime Ripard }
136d3e19cf9SMaxime Ripard
w1_reset_select(struct udevice * dev)137d3e19cf9SMaxime Ripard int w1_reset_select(struct udevice *dev)
138d3e19cf9SMaxime Ripard {
139d3e19cf9SMaxime Ripard struct w1_device *w1 = dev_get_parent_platdata(dev);
140d3e19cf9SMaxime Ripard struct udevice *bus = dev_get_parent(dev);
141d3e19cf9SMaxime Ripard const struct w1_ops *ops = device_get_ops(bus);
142d3e19cf9SMaxime Ripard int i;
143d3e19cf9SMaxime Ripard
144d3e19cf9SMaxime Ripard if (!ops->reset || !ops->write_byte)
145d3e19cf9SMaxime Ripard return -ENOSYS;
146d3e19cf9SMaxime Ripard
147d3e19cf9SMaxime Ripard ops->reset(bus);
148d3e19cf9SMaxime Ripard
149d3e19cf9SMaxime Ripard ops->write_byte(bus, W1_MATCH_ROM);
150d3e19cf9SMaxime Ripard
151d3e19cf9SMaxime Ripard for (i = 0; i < sizeof(w1->id); i++)
152d3e19cf9SMaxime Ripard ops->write_byte(bus, (w1->id >> (i * 8)) & 0xff);
153d3e19cf9SMaxime Ripard
154d3e19cf9SMaxime Ripard return 0;
155d3e19cf9SMaxime Ripard }
156d3e19cf9SMaxime Ripard
w1_read_byte(struct udevice * dev)157d3e19cf9SMaxime Ripard int w1_read_byte(struct udevice *dev)
158d3e19cf9SMaxime Ripard {
159d3e19cf9SMaxime Ripard struct udevice *bus = dev_get_parent(dev);
160d3e19cf9SMaxime Ripard const struct w1_ops *ops = device_get_ops(bus);
161d3e19cf9SMaxime Ripard
162d3e19cf9SMaxime Ripard if (!ops->read_byte)
163d3e19cf9SMaxime Ripard return -ENOSYS;
164d3e19cf9SMaxime Ripard
165d3e19cf9SMaxime Ripard return ops->read_byte(bus);
166d3e19cf9SMaxime Ripard }
167d3e19cf9SMaxime Ripard
w1_read_buf(struct udevice * dev,u8 * buf,unsigned int count)168d3e19cf9SMaxime Ripard int w1_read_buf(struct udevice *dev, u8 *buf, unsigned int count)
169d3e19cf9SMaxime Ripard {
170d3e19cf9SMaxime Ripard int i, ret;
171d3e19cf9SMaxime Ripard
172d3e19cf9SMaxime Ripard for (i = 0; i < count; i++) {
173d3e19cf9SMaxime Ripard ret = w1_read_byte(dev);
174d3e19cf9SMaxime Ripard if (ret < 0)
175d3e19cf9SMaxime Ripard return ret;
176d3e19cf9SMaxime Ripard
177d3e19cf9SMaxime Ripard buf[i] = ret & 0xff;
178d3e19cf9SMaxime Ripard }
179d3e19cf9SMaxime Ripard
180d3e19cf9SMaxime Ripard return 0;
181d3e19cf9SMaxime Ripard }
182d3e19cf9SMaxime Ripard
w1_write_byte(struct udevice * dev,u8 byte)183d3e19cf9SMaxime Ripard int w1_write_byte(struct udevice *dev, u8 byte)
184d3e19cf9SMaxime Ripard {
185d3e19cf9SMaxime Ripard struct udevice *bus = dev_get_parent(dev);
186d3e19cf9SMaxime Ripard const struct w1_ops *ops = device_get_ops(bus);
187d3e19cf9SMaxime Ripard
188d3e19cf9SMaxime Ripard if (!ops->write_byte)
189d3e19cf9SMaxime Ripard return -ENOSYS;
190d3e19cf9SMaxime Ripard
191d3e19cf9SMaxime Ripard ops->write_byte(bus, byte);
192d3e19cf9SMaxime Ripard
193d3e19cf9SMaxime Ripard return 0;
194d3e19cf9SMaxime Ripard }
195d3e19cf9SMaxime Ripard
w1_post_probe(struct udevice * bus)196d3e19cf9SMaxime Ripard static int w1_post_probe(struct udevice *bus)
197d3e19cf9SMaxime Ripard {
198d3e19cf9SMaxime Ripard w1_enumerate(bus);
199d3e19cf9SMaxime Ripard
200d3e19cf9SMaxime Ripard return 0;
201d3e19cf9SMaxime Ripard }
202d3e19cf9SMaxime Ripard
w1_init(void)203d3e19cf9SMaxime Ripard int w1_init(void)
204d3e19cf9SMaxime Ripard {
205d3e19cf9SMaxime Ripard struct udevice *bus;
206d3e19cf9SMaxime Ripard struct uclass *uc;
207d3e19cf9SMaxime Ripard int ret;
208d3e19cf9SMaxime Ripard
209d3e19cf9SMaxime Ripard ret = uclass_get(UCLASS_W1, &uc);
210d3e19cf9SMaxime Ripard if (ret)
211d3e19cf9SMaxime Ripard return ret;
212d3e19cf9SMaxime Ripard
213d3e19cf9SMaxime Ripard uclass_foreach_dev(bus, uc) {
214d3e19cf9SMaxime Ripard ret = device_probe(bus);
215d3e19cf9SMaxime Ripard if (ret == -ENODEV) { /* No such device. */
216d3e19cf9SMaxime Ripard printf("W1 controller not available.\n");
217d3e19cf9SMaxime Ripard continue;
218d3e19cf9SMaxime Ripard }
219d3e19cf9SMaxime Ripard
220d3e19cf9SMaxime Ripard if (ret) { /* Other error. */
221d3e19cf9SMaxime Ripard printf("W1 controller probe failed.\n");
222d3e19cf9SMaxime Ripard continue;
223d3e19cf9SMaxime Ripard }
224d3e19cf9SMaxime Ripard }
225d3e19cf9SMaxime Ripard return 0;
226d3e19cf9SMaxime Ripard }
227d3e19cf9SMaxime Ripard
228d3e19cf9SMaxime Ripard UCLASS_DRIVER(w1) = {
229d3e19cf9SMaxime Ripard .name = "w1",
230d3e19cf9SMaxime Ripard .id = UCLASS_W1,
231d3e19cf9SMaxime Ripard .flags = DM_UC_FLAG_SEQ_ALIAS,
232d3e19cf9SMaxime Ripard .per_device_auto_alloc_size = sizeof(struct w1_bus),
233d3e19cf9SMaxime Ripard .post_probe = w1_post_probe,
234d3e19cf9SMaxime Ripard #if CONFIG_IS_ENABLED(OF_CONTROL)
235d3e19cf9SMaxime Ripard .post_bind = dm_scan_fdt_dev,
236d3e19cf9SMaxime Ripard #endif
237d3e19cf9SMaxime Ripard .per_child_platdata_auto_alloc_size = sizeof(struct w1_device),
238d3e19cf9SMaxime Ripard };
239