1 /*        $NetBSD: ds2482ow.c,v 1.2 2024/11/06 15:49:36 riastradh Exp $         */
2 
3 /*
4  * Copyright (c) 2024 Brad Spencer <brad@anduin.eldar.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/cdefs.h>
20 __KERNEL_RCSID(0, "$NetBSD: ds2482ow.c,v 1.2 2024/11/06 15:49:36 riastradh Exp $");
21 
22 /*
23  * Driver for the DS2482-100 and DS2482-800 I2C to Onewire bridge
24  */
25 
26 #include <sys/param.h>
27 
28 #include <sys/device.h>
29 #include <sys/kernel.h>
30 #include <sys/module.h>
31 #include <sys/mutex.h>
32 #include <sys/sysctl.h>
33 #include <sys/systm.h>
34 
35 #include <dev/i2c/ds2482owreg.h>
36 #include <dev/i2c/ds2482owvar.h>
37 #include <dev/i2c/i2cvar.h>
38 #include <dev/onewire/onewirevar.h>
39 
40 #define DS2482_ONEWIRE_SINGLE_BIT_READ  0xF7 /* Artifical */
41 #define DS2482_ONEWIRE_SINGLE_BIT_WRITE 0xF8 /* Artifical */
42 
43 static int          ds2482_poke(i2c_tag_t, i2c_addr_t, bool);
44 static int          ds2482_match(device_t, cfdata_t, void *);
45 static void         ds2482_attach(device_t, device_t, void *);
46 static int          ds2482_detach(device_t, int);
47 static int          ds2482_verify_sysctl(SYSCTLFN_ARGS);
48 
49 static int          ds2482_ow_reset(void *);
50 static int          ds2482_ow_read_bit(void *);
51 static void         ds2482_ow_write_bit(void *, int);
52 static int          ds2482_ow_read_byte(void *);
53 static void         ds2482_ow_write_byte(void *, int);
54 static int          ds2482_ow_triplet(void *, int);
55 
56 #define DS2482_DEBUG
57 
58 #ifdef DS2482_DEBUG
59 #define DPRINTF(s, l, x)                                                              \
60           do {                                                                                  \
61                     if (l <= s->sc_ds2482debug)                                       \
62                               aprint_normal x;                                        \
63           } while (/*CONSTCOND*/0)
64 #else
65 #define DPRINTF(s, l, x)      __nothing
66 #endif
67 
68 #ifdef DS2482_DEBUG
69 #define DPRINTF2(dl, l, x)                                                            \
70           do {                                                                                  \
71                     if (l <= dl)                                                                \
72                               aprint_normal x;                                        \
73           } while (/*CONSTCOND*/0)
74 #else
75 #define DPRINTF2(dl, l, x)    __nothing
76 #endif
77 
78 CFATTACH_DECL_NEW(ds2482ow, sizeof(struct ds2482ow_sc),
79     ds2482_match, ds2482_attach, ds2482_detach, NULL);
80 
81 #define DS2482_QUICK_DELAY 18
82 #define DS2482_SLOW_DELAY 35
83 
84 int
ds2482_verify_sysctl(SYSCTLFN_ARGS)85 ds2482_verify_sysctl(SYSCTLFN_ARGS)
86 {
87           int error, t;
88           struct sysctlnode node;
89 
90           node = *rnode;
91           t = *(int *)rnode->sysctl_data;
92           node.sysctl_data = &t;
93           error = sysctl_lookup(SYSCTLFN_CALL(&node));
94           if (error || newp == NULL)
95                     return error;
96 
97           if (t < 0)
98                     return EINVAL;
99 
100           *(int *)rnode->sysctl_data = t;
101 
102           return 0;
103 }
104 
105 static int
ds2482_set_pullup(i2c_tag_t tag,i2c_addr_t addr,bool activepullup,bool strongpullup,int debuglevel)106 ds2482_set_pullup(i2c_tag_t tag, i2c_addr_t addr, bool activepullup,
107     bool strongpullup, int debuglevel)
108 {
109           int error;
110           uint8_t cmd = DS2482_WRITE_CONFIG;
111           uint8_t pu = 0;
112           uint8_t pux;
113 
114           if (activepullup)
115                     pu = pu | DS2482_CONFIG_APU;
116           if (strongpullup)
117                     pu = pu | DS2482_CONFIG_SPU;
118 
119           /*
120            * The Write Config command wants the top bits of the config
121            * buffer to be the ones complement of the lower bits.
122            */
123 
124           pux = ~(pu << 4);
125           pux = pux & 0xf0;
126           pu = pu | pux;
127 
128           error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &cmd, 1, &pu, 1,
129               0);
130           DPRINTF2(debuglevel, 4, ("ds2482_set_pullup: pu: %02x; error: %x %d\n",
131               pu, error, error));
132 
133           return error;
134 }
135 
136 static int
ds2482_wait_with_status(i2c_tag_t tag,i2c_addr_t addr,uint8_t * status,unsigned int d,bool set_pointer,int debuglevel)137 ds2482_wait_with_status(i2c_tag_t tag, i2c_addr_t addr, uint8_t *status,
138     unsigned int d, bool set_pointer, int debuglevel)
139 {
140           int error = 0;
141           uint8_t xcmd, xbuf;
142 
143           DPRINTF2(debuglevel, 5, ("ds2482_wait_with_status: start\n"));
144 
145           xcmd = DS2482_SET_READ_POINTER;
146           xbuf = DS2482_REGISTER_STATUS;
147           if (set_pointer) {
148                     error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
149                         &xbuf, 1, 0);
150           }
151           if (!error) {
152                     error = iic_exec(tag, I2C_OP_READ, addr, NULL, 0, status, 1,
153                         0);
154                     if ((*status & DS2482_STATUS_1WB) && !error) {
155                               do {
156                                         delay(d);
157                                         error = iic_exec(tag, I2C_OP_READ, addr,
158                                             NULL, 0, status, 1, 0);
159                               } while ((*status & DS2482_STATUS_1WB) && !error);
160                     }
161           }
162 
163           DPRINTF2(debuglevel, 5,
164               ("ds2482_wait_with_status: end ; status: %02x %d ; error: %x %d\n",
165               *status, *status, error, error));
166 
167           return error;
168 }
169 
170 static int
ds2482_cmd(i2c_tag_t tag,i2c_addr_t addr,uint8_t * cmd,uint8_t * cmdarg,uint8_t * obuf,size_t obuflen,bool activepullup,bool strongpullup,int debuglevel)171 ds2482_cmd(i2c_tag_t tag, i2c_addr_t addr, uint8_t *cmd,
172     uint8_t *cmdarg, uint8_t *obuf, size_t obuflen, bool activepullup,
173     bool strongpullup, int debuglevel)
174 {
175           int error;
176           uint8_t xcmd;
177           uint8_t xbuf;
178 
179           switch (*cmd) {
180                     /*
181                      * The datasheet says that none of these are effected
182                      * by what sort of pullup is set and only the Write
183                      * Config command needs to happen when idle.
184                      */
185           case DS2482_SET_READ_POINTER:
186           case DS2482_WRITE_CONFIG:
187           case DS2482_SELECT_CHANNEL:
188                     KASSERT(cmdarg != NULL);
189 
190                     error = 0;
191                     if (*cmd == DS2482_WRITE_CONFIG) {
192                               error = ds2482_wait_with_status(tag, addr, &xbuf,
193                                   DS2482_QUICK_DELAY, /*set_pointer*/true,
194                                   debuglevel);
195                     }
196                     if (!error) {
197                               error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr,
198                                   cmd, 1, cmdarg, 1, 0);
199                     }
200                     DPRINTF2(debuglevel, 4,
201                         ("ds2482_cmd: cmd: %02x ; error: %x %d\n",
202                         *cmd, error, error));
203                     break;
204 
205           case DS2482_DEVICE_RESET:
206           case DS2482_ONEWIRE_RESET:
207                     /*
208                      * Device reset resets everything, including pullup
209                      * configuration settings, but that doesn't matter as
210                      * we will always set the config before doing anything
211                      * that actions on the 1-Wire bus.
212                      *
213                      * The data sheet warns about using the strong pull up
214                      * feature with a 1-Wire reset, so we will simply not
215                      * allow that combination.
216                      *
217                      * The data sheet does not mention if the 1-Wire reset
218                      * effects just a single channel all channels.  It
219                      * seems likely that it is the currently active
220                      * channel, and the driver works on that assumption.
221                      */
222                     error = 0;
223                     if (*cmd == DS2482_ONEWIRE_RESET) {
224                               error = ds2482_wait_with_status(tag, addr, &xbuf,
225                                   DS2482_QUICK_DELAY, /*set_pointer*/true,
226                                   debuglevel);
227                               if (!error) {
228                                         error = ds2482_set_pullup(tag, addr,
229                                             activepullup, /*strongpullup*/false,
230                                             debuglevel);
231                               }
232                     }
233                     if (!error) {
234                               error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr,
235                                   cmd, 1, NULL, 0, 0);
236                     }
237                     DPRINTF2(debuglevel, 4,
238                         ("ds2482_cmd: cmd: %02x ; error: %x %d\n",
239                         *cmd, error, error));
240                     if (*cmd == DS2482_DEVICE_RESET)
241                               delay(1);
242                     if (*cmd == DS2482_ONEWIRE_RESET)
243                               delay(1300);
244                     break;
245 
246           case DS2482_ONEWIRE_SINGLE_BIT_WRITE:
247                     KASSERT(cmdarg != NULL);
248 
249                     DPRINTF2(debuglevel, 4,
250                         ("ds2482_cmd: DS2482_ONEWIRE_SINGLE_BIT_WRITE:"
251                         " cmdarg: %02x %d\n", *cmdarg, *cmdarg));
252 
253                     xcmd = DS2482_SET_READ_POINTER;
254                     xbuf = DS2482_REGISTER_STATUS;
255                     error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
256                         &xbuf, 1, 0);
257                     if (!error) {
258                               error = ds2482_wait_with_status(tag, addr, &xbuf,
259                                   DS2482_QUICK_DELAY, /*set_pointer*/false,
260                                   debuglevel);
261                     }
262                     if (!error) {
263                               xcmd = DS2482_ONEWIRE_SINGLE_BIT;
264                               xbuf = DS2482_ONEWIRE_BIT_ZERO;
265                               if (*cmdarg & 0x01)
266                                         xbuf = DS2482_ONEWIRE_BIT_ONE;
267                               error = ds2482_set_pullup(tag, addr,
268                                   activepullup, strongpullup, debuglevel);
269                               if (!error) {
270                                         error = iic_exec(tag, I2C_OP_WRITE, addr,
271                                             &xcmd, 1, &xbuf, 1, 0);
272                               }
273                               if (!error) {
274                                         xbuf = 0xff;
275                                         error = ds2482_wait_with_status(tag, addr,
276                                             &xbuf, DS2482_SLOW_DELAY,
277                                             /*set_pointer*/false, debuglevel);
278                               }
279                     }
280                     break;
281 
282           case DS2482_ONEWIRE_SINGLE_BIT_READ:
283                     KASSERT(obuf != NULL);
284                     KASSERT(obuflen == 1);
285 
286                     DPRINTF2(debuglevel, 4,
287                         ("ds2482_cmd: DS2482_ONEWIRE_SINGLE_BIT_READ\n"));
288 
289                     xcmd = DS2482_SET_READ_POINTER;
290                     xbuf = DS2482_REGISTER_STATUS;
291                     error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
292                         &xbuf, 1, 0);
293                     if (!error) {
294                               error = ds2482_wait_with_status(tag, addr, &xbuf,
295                                   DS2482_QUICK_DELAY, /*set_pointer*/false,
296                                   debuglevel);
297                     }
298                     if (!error) {
299                               xcmd = DS2482_ONEWIRE_SINGLE_BIT;
300                               xbuf = DS2482_ONEWIRE_BIT_ONE;
301                               error = ds2482_set_pullup(tag, addr,
302                                   activepullup, strongpullup, debuglevel);
303                               if (!error) {
304                                         error = iic_exec(tag, I2C_OP_WRITE, addr,
305                                             &xcmd, 1, &xbuf, 1, 0);
306                               }
307                               if (!error) {
308                                         xbuf = 0xff;
309                                         error = ds2482_wait_with_status(tag, addr,
310                                             &xbuf, DS2482_SLOW_DELAY,
311                                             /*set_pointer*/false, debuglevel);
312                                         if (!error) {
313                                                   *obuf = (xbuf & DS2482_STATUS_SBR) >>
314                                                       DS2482_STATUS_SBR_SHIFT;
315                                         }
316                               }
317                     }
318                     break;
319 
320           case DS2482_ONEWIRE_WRITE_BYTE:
321                     KASSERT(cmdarg != NULL);
322 
323                     DPRINTF2(debuglevel, 4,
324                         ("ds2482_cmd: DS2482_ONEWIRE_WRITE_BYTE:"
325                         " cmdarg: %02x %d\n", *cmdarg, *cmdarg));
326 
327                     xcmd = DS2482_SET_READ_POINTER;
328                     xbuf = DS2482_REGISTER_STATUS;
329                     error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
330                         &xbuf, 1, 0);
331                     if (!error) {
332                               error = ds2482_wait_with_status(tag, addr, &xbuf,
333                                   DS2482_QUICK_DELAY, /*set_pointer*/false,
334                                   debuglevel);
335                     }
336                     if (!error) {
337                               error = ds2482_set_pullup(tag, addr,
338                                   activepullup, strongpullup, debuglevel);
339                               if (!error) {
340                                         error = iic_exec(tag, I2C_OP_WRITE, addr,
341                                             cmd, 1, cmdarg, 1, 0);
342                               }
343                               if (!error) {
344                                         xbuf = 0xff;
345                                         error = ds2482_wait_with_status(tag, addr,
346                                             &xbuf, DS2482_SLOW_DELAY,
347                                             /*set_pointer*/false, debuglevel);
348                               }
349                     }
350                     break;
351 
352           case DS2482_ONEWIRE_READ_BYTE:
353                     KASSERT(obuf != NULL);
354                     KASSERT(obuflen == 1);
355 
356                     DPRINTF2(debuglevel, 4,
357                         ("ds2482_cmd: DS2482_ONEWIRE_READ_BYTE\n"));
358 
359                     xcmd = DS2482_SET_READ_POINTER;
360                     xbuf = DS2482_REGISTER_STATUS;
361                     error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
362                         &xbuf, 1, 0);
363                     if (!error) {
364                               error = ds2482_wait_with_status(tag, addr, &xbuf,
365                                   DS2482_QUICK_DELAY, /*set_pointer*/false,
366                                   debuglevel);
367                     }
368                     if (!error) {
369                               error = ds2482_set_pullup(tag, addr,
370                                   activepullup, strongpullup, debuglevel);
371                               if (!error) {
372                                         error = iic_exec(tag, I2C_OP_WRITE, addr,
373                                             cmd, 1, NULL, 0, 0);
374                               }
375                               if (!error) {
376                                         xbuf = 0xff;
377                                         error = ds2482_wait_with_status(tag, addr,
378                                             &xbuf, DS2482_SLOW_DELAY,
379                                             /*set_pointer*/false, debuglevel);
380                                         if (!error) {
381                                                   xcmd = DS2482_SET_READ_POINTER;
382                                                   xbuf = DS2482_REGISTER_DATA;
383                                                   error = iic_exec(tag,
384                                                       I2C_OP_WRITE_WITH_STOP, addr,
385                                                       &xcmd, 1, &xbuf, 1, 0);
386                                                   if (!error) {
387                                                             xbuf = 0xff;
388                                                             error = iic_exec(tag,
389                                                                 I2C_OP_READ_WITH_STOP,
390                                                                 addr, NULL, 0,
391                                                                 &xbuf, 1, 0);
392                                                             if (!error) {
393                                                                       *obuf = xbuf;
394                                                             }
395                                                   }
396                                         }
397                               }
398                     }
399                     break;
400 
401           case DS2482_ONEWIRE_TRIPLET:
402                     KASSERT(cmdarg != NULL);
403                     KASSERT(obuf != NULL);
404                     KASSERT(obuflen == 1);
405 
406                     DPRINTF2(debuglevel, 4,
407                         ("ds2482_cmd: DS2482_ONEWIRE_TRIPLET: cmdarg: %02x %d\n",
408                         *cmdarg, *cmdarg));
409 
410                     xcmd = DS2482_SET_READ_POINTER;
411                     xbuf = DS2482_REGISTER_STATUS;
412                     error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
413                         &xbuf, 1, 0);
414                     if (!error) {
415                               error = ds2482_wait_with_status(tag, addr, &xbuf,
416                                   DS2482_QUICK_DELAY, /*set_pointer*/false,
417                                   debuglevel);
418                     }
419                     if (!error) {
420                               xbuf = DS2482_TRIPLET_DIR_ZERO;
421                               if (*cmdarg & 0x01) {
422                                         xbuf = DS2482_TRIPLET_DIR_ONE;
423                               }
424                               error = ds2482_set_pullup(tag, addr,
425                                   activepullup, strongpullup, debuglevel);
426                               if (!error) {
427                                         error = iic_exec(tag, I2C_OP_WRITE, addr,
428                                             cmd, 1, &xbuf, 1, 0);
429                               }
430                               if (!error) {
431                                         xbuf = 0xff;
432                                         error = ds2482_wait_with_status(tag, addr,
433                                             &xbuf, DS2482_SLOW_DELAY,
434                                             /*set_pointer*/false, debuglevel);
435                                         if (!error) {
436                                                   /*
437                                                    * This is undocumented
438                                                    * anywhere I could find, but
439                                                    * what has to be returned is
440                                                    * 0x01 is the triplet path was
441                                                    * taken, 0x02 is the
442                                                    * Not-triplet path was taken,
443                                                    * and 0x00 is neither was
444                                                    * taken.  The DIR bit in the
445                                                    * status of the DS2482 may
446                                                    * help with this some, but
447                                                    * what is below seems to work.
448                                                    */
449                                                   *obuf = 0;
450                                                   if (xbuf & DS2482_STATUS_TSB) {
451                                                             *obuf = 0x01;
452                                                   } else {
453                                                             if (xbuf & DS2482_STATUS_SBR) {
454                                                                       *obuf = 0x02;
455                                                             }
456                                                   }
457                                         }
458                               }
459                     }
460                     break;
461 
462           default:
463                     error = EINVAL;
464                     break;
465           }
466 
467           return error;
468 }
469 
470 static int
ds2482_cmdr(struct ds2482ow_sc * sc,uint8_t cmd,uint8_t cmdarg,uint8_t * buf,size_t blen)471 ds2482_cmdr(struct ds2482ow_sc *sc, uint8_t cmd, uint8_t cmdarg,
472     uint8_t *buf, size_t blen)
473 {
474 
475           DPRINTF(sc, 3, ("%s: ds2482_cmdr: cmd: %02x\n",
476               device_xname(sc->sc_dev), cmd));
477           return ds2482_cmd(sc->sc_tag, sc->sc_addr, &cmd, &cmdarg, buf, blen,
478               sc->sc_activepullup, sc->sc_strongpullup, sc->sc_ds2482debug);
479 }
480 
481 static const uint8_t ds2482_channels[] = {
482           DS2482_CHANNEL_IO0,
483           DS2482_CHANNEL_IO1,
484           DS2482_CHANNEL_IO2,
485           DS2482_CHANNEL_IO3,
486           DS2482_CHANNEL_IO4,
487           DS2482_CHANNEL_IO5,
488           DS2482_CHANNEL_IO6,
489           DS2482_CHANNEL_IO7
490 };
491 
492 static int
ds2482_set_channel(struct ds2482ow_sc * sc,int channel)493 ds2482_set_channel(struct ds2482ow_sc *sc, int channel)
494 {
495           int error = 0;
496 
497           KASSERT(channel >= 0 && channel < DS2482_NUM_INSTANCES);
498 
499           if (sc->sc_is_800) {
500                     error = ds2482_cmdr(sc, DS2482_SELECT_CHANNEL,
501                         ds2482_channels[channel], NULL, 0);
502           }
503 
504           return error;
505 }
506 
507 static int
ds2482_poke(i2c_tag_t tag,i2c_addr_t addr,bool matchdebug)508 ds2482_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
509 {
510           uint8_t reg = DS2482_SET_READ_POINTER;
511           uint8_t rbuf = DS2482_REGISTER_STATUS;
512           uint8_t obuf;
513           int error;
514 
515           error = ds2482_cmd(tag, addr, &reg, &rbuf, &obuf, 1,
516               /*activepullup*/false, /*strongpullup*/false, 0);
517           if (matchdebug) {
518                     printf("poke X 1: %d\n", error);
519           }
520           return error;
521 }
522 
523 static int
ds2482_match(device_t parent,cfdata_t match,void * aux)524 ds2482_match(device_t parent, cfdata_t match, void *aux)
525 {
526           struct i2c_attach_args *ia = aux;
527           int error, match_result;
528           const bool matchdebug = false;
529 
530           if (iic_use_direct_match(ia, match, NULL, &match_result))
531                     return match_result;
532 
533           /* indirect config - check for configured address */
534           if (!(ia->ia_addr >= DS2482_LOWEST_ADDR &&
535               ia->ia_addr <= DS2482_HIGHEST_ADDR))
536                     return 0;
537 
538           /*
539            * Check to see if something is really at this i2c address. This will
540            * keep phantom devices from appearing
541            */
542           if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
543                     if (matchdebug)
544                               printf("in match acquire bus failed\n");
545                     return 0;
546           }
547 
548           error = ds2482_poke(ia->ia_tag, ia->ia_addr, matchdebug);
549           iic_release_bus(ia->ia_tag, 0);
550 
551           return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
552 }
553 
554 static void
ds2482_attach(device_t parent,device_t self,void * aux)555 ds2482_attach(device_t parent, device_t self, void *aux)
556 {
557           struct ds2482ow_sc *sc;
558           struct i2c_attach_args *ia;
559           int error, i, num_channels = 1;
560           struct onewirebus_attach_args oba;
561           const struct sysctlnode *cnode;
562           int sysctlroot_num, pullup_num;
563 
564           ia = aux;
565           sc = device_private(self);
566 
567           sc->sc_dev = self;
568           sc->sc_tag = ia->ia_tag;
569           sc->sc_addr = ia->ia_addr;
570           sc->sc_ds2482debug = 0;
571           sc->sc_activepullup = false;
572           sc->sc_strongpullup = false;
573           sc->sc_is_800 = false;
574 
575           aprint_normal("\n");
576 
577           mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
578 
579           if ((error = sysctl_createv(&sc->sc_ds2482log, 0, NULL, &cnode,
580               0, CTLTYPE_NODE, device_xname(sc->sc_dev),
581               SYSCTL_DESCR("DS2482 controls"), NULL, 0, NULL, 0, CTL_HW,
582               CTL_CREATE, CTL_EOL)) != 0)
583                     goto out;
584 
585           sysctlroot_num = cnode->sysctl_num;
586 
587 #ifdef DS2482_DEBUG
588           if ((error = sysctl_createv(&sc->sc_ds2482log, 0, NULL, &cnode,
589               CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
590               SYSCTL_DESCR("Debug level"), ds2482_verify_sysctl, 0,
591               &sc->sc_ds2482debug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
592               CTL_EOL)) != 0)
593                     goto out;
594 #endif
595 
596           if ((error = sysctl_createv(&sc->sc_ds2482log, 0, NULL, &cnode,
597               0, CTLTYPE_NODE, "pullup",
598               SYSCTL_DESCR("Pullup controls"), NULL, 0, NULL, 0, CTL_HW,
599               sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
600                     goto out;
601 
602           pullup_num = cnode->sysctl_num;
603 
604           if ((error = sysctl_createv(&sc->sc_ds2482log, 0, NULL, &cnode,
605               CTLFLAG_READWRITE, CTLTYPE_BOOL, "active",
606               SYSCTL_DESCR("Active pullup"), NULL, 0, &sc->sc_activepullup,
607               0, CTL_HW, sysctlroot_num, pullup_num, CTL_CREATE, CTL_EOL)) != 0)
608                     goto out;
609 
610           if ((error = sysctl_createv(&sc->sc_ds2482log, 0, NULL, &cnode,
611               CTLFLAG_READWRITE, CTLTYPE_BOOL, "strong",
612               SYSCTL_DESCR("Strong pullup"), NULL, 0, &sc->sc_strongpullup,
613               0, CTL_HW, sysctlroot_num, pullup_num, CTL_CREATE, CTL_EOL)) != 0)
614                     goto out;
615 
616           error = iic_acquire_bus(sc->sc_tag, 0);
617           if (error) {
618                     aprint_error_dev(self, "Could not acquire iic bus: %d\n",
619                         error);
620                     goto out;
621           }
622 
623           error = ds2482_cmdr(sc, DS2482_DEVICE_RESET, 0, NULL, 0);
624           if (error != 0)
625                     aprint_error_dev(self, "Reset failed: %d\n", error);
626 
627           if (!error) {
628                     int xerror;
629                     xerror = ds2482_cmdr(sc, DS2482_SELECT_CHANNEL,
630                         DS2482_CHANNEL_IO0, NULL, 0);
631                     if (!xerror)
632                               sc->sc_is_800 = true;
633           }
634 
635           iic_release_bus(sc->sc_tag, 0);
636 
637           if (error != 0) {
638                     aprint_error_dev(self, "Unable to setup device\n");
639                     goto out;
640           }
641 
642           if (sc->sc_is_800) {
643                     num_channels = DS2482_NUM_INSTANCES;
644           }
645 
646           aprint_normal_dev(self, "Maxim DS2482-%s I2C to 1-Wire bridge,"
647               " Channels available: %d\n",
648               sc->sc_is_800 ? "800" : "100",
649               num_channels);
650 
651           for (i = 0; i < num_channels; i++) {
652                     sc->sc_instances[i].sc_i_channel = i;
653                     sc->sc_instances[i].sc = sc;
654                     sc->sc_instances[i].sc_i_ow_bus.bus_cookie =
655                         &sc->sc_instances[i];
656                     sc->sc_instances[i].sc_i_ow_bus.bus_reset = ds2482_ow_reset;
657                     sc->sc_instances[i].sc_i_ow_bus.bus_read_bit =
658                         ds2482_ow_read_bit;
659                     sc->sc_instances[i].sc_i_ow_bus.bus_write_bit =
660                         ds2482_ow_write_bit;
661                     sc->sc_instances[i].sc_i_ow_bus.bus_read_byte =
662                         ds2482_ow_read_byte;
663                     sc->sc_instances[i].sc_i_ow_bus.bus_write_byte =
664                         ds2482_ow_write_byte;
665                     sc->sc_instances[i].sc_i_ow_bus.bus_triplet =
666                         ds2482_ow_triplet;
667 
668                     memset(&oba, 0, sizeof(oba));
669                     oba.oba_bus = &sc->sc_instances[i].sc_i_ow_bus;
670                     sc->sc_instances[i].sc_i_ow_dev =
671                         config_found(self, &oba, onewirebus_print, CFARGS_NONE);
672           }
673 
674 out:
675           return;
676 }
677 
678 /*
679  * Hmmm...  except in the case of reset, there really doesn't seem to
680  * be any way with the onewire(4) API to indicate an error condition.
681  */
682 
683 static int
ds2482_generic_action(struct ds2482_instance * sci,uint8_t cmd,uint8_t cmdarg,uint8_t * buf,size_t blen)684 ds2482_generic_action(struct ds2482_instance *sci, uint8_t cmd, uint8_t cmdarg,
685     uint8_t *buf, size_t blen)
686 {
687           struct ds2482ow_sc *sc = sci->sc;
688           int rv;
689 
690           mutex_enter(&sc->sc_mutex);
691           rv = iic_acquire_bus(sc->sc_tag, 0);
692           if (!rv) {
693                     rv = ds2482_set_channel(sc, sci->sc_i_channel);
694                     if (!rv)
695                               rv = ds2482_cmdr(sc, cmd, cmdarg, buf, blen);
696           }
697           iic_release_bus(sc->sc_tag, 0);
698           mutex_exit(&sc->sc_mutex);
699 
700           return rv;
701 }
702 
703 static int
ds2482_ow_reset(void * arg)704 ds2482_ow_reset(void *arg)
705 {
706           struct ds2482_instance *sci = arg;
707           struct ds2482ow_sc *sc = sci->sc;
708           int rv;
709 
710           rv = ds2482_generic_action(sci, DS2482_ONEWIRE_RESET, 0, NULL, 0);
711 
712           DPRINTF(sc, 3, ("%s: ds2482_ow_reset: channel: %d ; rv: %x %d\n",
713               device_xname(sc->sc_dev), sci->sc_i_channel, rv, rv));
714 
715           return rv;
716 }
717 
718 static int
ds2482_ow_read_bit(void * arg)719 ds2482_ow_read_bit(void *arg)
720 {
721           struct ds2482_instance *sci = arg;
722           struct ds2482ow_sc *sc = sci->sc;
723           int rv;
724           uint8_t buf = 0x55;
725 
726           rv = ds2482_generic_action(sci, DS2482_ONEWIRE_SINGLE_BIT_READ, 0,
727               &buf, 1);
728 
729           DPRINTF(sc, 3,
730               ("%s: ds2482_read_bit: channel: %d ; rv: %x %d ; buf: %02x %d\n",
731               device_xname(sc->sc_dev), sci->sc_i_channel, rv, rv, buf, buf));
732 
733           return (int)buf;
734 }
735 
736 static void
ds2482_ow_write_bit(void * arg,int value)737 ds2482_ow_write_bit(void *arg, int value)
738 {
739           struct ds2482_instance *sci = arg;
740           struct ds2482ow_sc *sc = sci->sc;
741           int rv;
742 
743           rv = ds2482_generic_action(sci, DS2482_ONEWIRE_SINGLE_BIT_WRITE,
744               (uint8_t)value, NULL, 0);
745 
746           DPRINTF(sc, 3, ("%s: ds2482_write_bit: channel: %d ;"
747               " rv: %x %d ; value: %02x %d\n",
748               device_xname(sc->sc_dev), sci->sc_i_channel,
749               rv, rv, (uint8_t)value, (uint8_t)value));
750 }
751 
752 static int
ds2482_ow_read_byte(void * arg)753 ds2482_ow_read_byte(void *arg)
754 {
755           struct ds2482_instance *sci = arg;
756           uint8_t buf = 0x55;
757           struct ds2482ow_sc *sc = sci->sc;
758           int rv;
759 
760           rv = ds2482_generic_action(sci, DS2482_ONEWIRE_READ_BYTE, 0, &buf, 1);
761 
762           DPRINTF(sc, 3,
763               ("%s: ds2482_read_byte: channel: %d ; rv: %x %d ; buf: %02x %d\n",
764               device_xname(sc->sc_dev), sci->sc_i_channel, rv, rv, buf, buf));
765 
766           return (int)buf;
767 }
768 
769 static void
ds2482_ow_write_byte(void * arg,int value)770 ds2482_ow_write_byte(void *arg, int value)
771 {
772           struct ds2482_instance *sci = arg;
773           struct ds2482ow_sc *sc = sci->sc;
774           int rv;
775 
776           rv = ds2482_generic_action(sci, DS2482_ONEWIRE_WRITE_BYTE,
777               (uint8_t)value, NULL, 0);
778 
779           DPRINTF(sc, 3, ("%s: ds2482_write_byte: channel: %d ;"
780               " rv: %x %d ; value: %02x %d\n",
781               device_xname(sc->sc_dev), sci->sc_i_channel,
782               rv, rv, (uint8_t)value, (uint8_t)value));
783 }
784 
785 static int
ds2482_ow_triplet(void * arg,int dir)786 ds2482_ow_triplet(void *arg, int dir)
787 {
788           struct ds2482_instance *sci = arg;
789           uint8_t buf = 0x55;
790           struct ds2482ow_sc *sc = sci->sc;
791           int rv;
792 
793           rv = ds2482_generic_action(sci, DS2482_ONEWIRE_TRIPLET, (uint8_t)dir,
794               &buf, 1);
795 
796           DPRINTF(sc, 3, ("%s: ds2482_triplet: channel: %d ;"
797               " rv: %x %d ; dir: %x %d ; buf: %02x %d\n",
798               device_xname(sc->sc_dev), sci->sc_i_channel, rv, rv,
799               dir, dir, (uint8_t)buf, (uint8_t)buf));
800 
801           return (int)buf;
802 }
803 
804 static int
ds2482_detach(device_t self,int flags)805 ds2482_detach(device_t self, int flags)
806 {
807           struct ds2482ow_sc *sc;
808 
809           sc = device_private(self);
810 
811           /* Remove the sysctl tree */
812           sysctl_teardown(&sc->sc_ds2482log);
813 
814           /* Remove the mutex */
815           mutex_destroy(&sc->sc_mutex);
816 
817           return 0;
818 }
819 
820 MODULE(MODULE_CLASS_DRIVER, ds2482ow, "iic,onewire");
821 
822 #ifdef _MODULE
823 #include "ioconf.c"
824 #endif
825 
826 static int
ds2482ow_modcmd(modcmd_t cmd,void * opaque)827 ds2482ow_modcmd(modcmd_t cmd, void *opaque)
828 {
829 
830           switch (cmd) {
831           case MODULE_CMD_INIT:
832 #ifdef _MODULE
833                     return config_init_component(cfdriver_ioconf_ds2482ow,
834                         cfattach_ioconf_ds2482ow, cfdata_ioconf_ds2482ow);
835 #else
836                     return 0;
837 #endif
838           case MODULE_CMD_FINI:
839 #ifdef _MODULE
840                     return config_fini_component(cfdriver_ioconf_ds2482ow,
841                           cfattach_ioconf_ds2482ow, cfdata_ioconf_ds2482ow);
842 #else
843                     return 0;
844 #endif
845           default:
846                     return ENOTTY;
847           }
848 }
849