/* $NetBSD: ds2482ow.c,v 1.2 2024/11/06 15:49:36 riastradh Exp $ */
/*
* Copyright (c) 2024 Brad Spencer <
[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ds2482ow.c,v 1.2 2024/11/06 15:49:36 riastradh Exp $");
/*
* Driver for the DS2482-100 and DS2482-800 I2C to Onewire bridge
*/
#include <sys/param.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <dev/i2c/ds2482owreg.h>
#include <dev/i2c/ds2482owvar.h>
#include <dev/i2c/i2cvar.h>
#include <dev/onewire/onewirevar.h>
#define DS2482_ONEWIRE_SINGLE_BIT_READ 0xF7 /* Artifical */
#define DS2482_ONEWIRE_SINGLE_BIT_WRITE 0xF8 /* Artifical */
static int ds2482_poke(i2c_tag_t, i2c_addr_t, bool);
static int ds2482_match(device_t, cfdata_t, void *);
static void ds2482_attach(device_t, device_t, void *);
static int ds2482_detach(device_t, int);
static int ds2482_verify_sysctl(SYSCTLFN_ARGS);
static int ds2482_ow_reset(void *);
static int ds2482_ow_read_bit(void *);
static void ds2482_ow_write_bit(void *, int);
static int ds2482_ow_read_byte(void *);
static void ds2482_ow_write_byte(void *, int);
static int ds2482_ow_triplet(void *, int);
#define DS2482_DEBUG
#ifdef DS2482_DEBUG
#define DPRINTF(s, l, x) \
do { \
if (l <= s->sc_ds2482debug) \
aprint_normal x; \
} while (/*CONSTCOND*/0)
#else
#define DPRINTF(s, l, x) __nothing
#endif
#ifdef DS2482_DEBUG
#define DPRINTF2(dl, l, x) \
do { \
if (l <= dl) \
aprint_normal x; \
} while (/*CONSTCOND*/0)
#else
#define DPRINTF2(dl, l, x) __nothing
#endif
CFATTACH_DECL_NEW(ds2482ow, sizeof(struct ds2482ow_sc),
ds2482_match, ds2482_attach, ds2482_detach, NULL);
#define DS2482_QUICK_DELAY 18
#define DS2482_SLOW_DELAY 35
int
ds2482_verify_sysctl(SYSCTLFN_ARGS)
{
int error, t;
struct sysctlnode node;
node = *rnode;
t = *(int *)rnode->sysctl_data;
node.sysctl_data = &t;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
return error;
if (t < 0)
return EINVAL;
*(int *)rnode->sysctl_data = t;
return 0;
}
static int
ds2482_set_pullup(i2c_tag_t tag, i2c_addr_t addr, bool activepullup,
bool strongpullup, int debuglevel)
{
int error;
uint8_t cmd = DS2482_WRITE_CONFIG;
uint8_t pu = 0;
uint8_t pux;
if (activepullup)
pu = pu | DS2482_CONFIG_APU;
if (strongpullup)
pu = pu | DS2482_CONFIG_SPU;
/*
* The Write Config command wants the top bits of the config
* buffer to be the ones complement of the lower bits.
*/
pux = ~(pu << 4);
pux = pux & 0xf0;
pu = pu | pux;
error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &cmd, 1, &pu, 1,
0);
DPRINTF2(debuglevel, 4, ("ds2482_set_pullup: pu: %02x; error: %x %d\n",
pu, error, error));
return error;
}
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)
{
int error = 0;
uint8_t xcmd, xbuf;
DPRINTF2(debuglevel, 5, ("ds2482_wait_with_status: start\n"));
xcmd = DS2482_SET_READ_POINTER;
xbuf = DS2482_REGISTER_STATUS;
if (set_pointer) {
error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
&xbuf, 1, 0);
}
if (!error) {
error = iic_exec(tag, I2C_OP_READ, addr, NULL, 0, status, 1,
0);
if ((*status & DS2482_STATUS_1WB) && !error) {
do {
delay(d);
error = iic_exec(tag, I2C_OP_READ, addr,
NULL, 0, status, 1, 0);
} while ((*status & DS2482_STATUS_1WB) && !error);
}
}
DPRINTF2(debuglevel, 5,
("ds2482_wait_with_status: end ; status: %02x %d ; error: %x %d\n",
*status, *status, error, error));
return error;
}
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)
{
int error;
uint8_t xcmd;
uint8_t xbuf;
switch (*cmd) {
/*
* The datasheet says that none of these are effected
* by what sort of pullup is set and only the Write
* Config command needs to happen when idle.
*/
case DS2482_SET_READ_POINTER:
case DS2482_WRITE_CONFIG:
case DS2482_SELECT_CHANNEL:
KASSERT(cmdarg != NULL);
error = 0;
if (*cmd == DS2482_WRITE_CONFIG) {
error = ds2482_wait_with_status(tag, addr, &xbuf,
DS2482_QUICK_DELAY, /*set_pointer*/true,
debuglevel);
}
if (!error) {
error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr,
cmd, 1, cmdarg, 1, 0);
}
DPRINTF2(debuglevel, 4,
("ds2482_cmd: cmd: %02x ; error: %x %d\n",
*cmd, error, error));
break;
case DS2482_DEVICE_RESET:
case DS2482_ONEWIRE_RESET:
/*
* Device reset resets everything, including pullup
* configuration settings, but that doesn't matter as
* we will always set the config before doing anything
* that actions on the 1-Wire bus.
*
* The data sheet warns about using the strong pull up
* feature with a 1-Wire reset, so we will simply not
* allow that combination.
*
* The data sheet does not mention if the 1-Wire reset
* effects just a single channel all channels. It
* seems likely that it is the currently active
* channel, and the driver works on that assumption.
*/
error = 0;
if (*cmd == DS2482_ONEWIRE_RESET) {
error = ds2482_wait_with_status(tag, addr, &xbuf,
DS2482_QUICK_DELAY, /*set_pointer*/true,
debuglevel);
if (!error) {
error = ds2482_set_pullup(tag, addr,
activepullup, /*strongpullup*/false,
debuglevel);
}
}
if (!error) {
error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr,
cmd, 1, NULL, 0, 0);
}
DPRINTF2(debuglevel, 4,
("ds2482_cmd: cmd: %02x ; error: %x %d\n",
*cmd, error, error));
if (*cmd == DS2482_DEVICE_RESET)
delay(1);
if (*cmd == DS2482_ONEWIRE_RESET)
delay(1300);
break;
case DS2482_ONEWIRE_SINGLE_BIT_WRITE:
KASSERT(cmdarg != NULL);
DPRINTF2(debuglevel, 4,
("ds2482_cmd: DS2482_ONEWIRE_SINGLE_BIT_WRITE:"
" cmdarg: %02x %d\n", *cmdarg, *cmdarg));
xcmd = DS2482_SET_READ_POINTER;
xbuf = DS2482_REGISTER_STATUS;
error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
&xbuf, 1, 0);
if (!error) {
error = ds2482_wait_with_status(tag, addr, &xbuf,
DS2482_QUICK_DELAY, /*set_pointer*/false,
debuglevel);
}
if (!error) {
xcmd = DS2482_ONEWIRE_SINGLE_BIT;
xbuf = DS2482_ONEWIRE_BIT_ZERO;
if (*cmdarg & 0x01)
xbuf = DS2482_ONEWIRE_BIT_ONE;
error = ds2482_set_pullup(tag, addr,
activepullup, strongpullup, debuglevel);
if (!error) {
error = iic_exec(tag, I2C_OP_WRITE, addr,
&xcmd, 1, &xbuf, 1, 0);
}
if (!error) {
xbuf = 0xff;
error = ds2482_wait_with_status(tag, addr,
&xbuf, DS2482_SLOW_DELAY,
/*set_pointer*/false, debuglevel);
}
}
break;
case DS2482_ONEWIRE_SINGLE_BIT_READ:
KASSERT(obuf != NULL);
KASSERT(obuflen == 1);
DPRINTF2(debuglevel, 4,
("ds2482_cmd: DS2482_ONEWIRE_SINGLE_BIT_READ\n"));
xcmd = DS2482_SET_READ_POINTER;
xbuf = DS2482_REGISTER_STATUS;
error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
&xbuf, 1, 0);
if (!error) {
error = ds2482_wait_with_status(tag, addr, &xbuf,
DS2482_QUICK_DELAY, /*set_pointer*/false,
debuglevel);
}
if (!error) {
xcmd = DS2482_ONEWIRE_SINGLE_BIT;
xbuf = DS2482_ONEWIRE_BIT_ONE;
error = ds2482_set_pullup(tag, addr,
activepullup, strongpullup, debuglevel);
if (!error) {
error = iic_exec(tag, I2C_OP_WRITE, addr,
&xcmd, 1, &xbuf, 1, 0);
}
if (!error) {
xbuf = 0xff;
error = ds2482_wait_with_status(tag, addr,
&xbuf, DS2482_SLOW_DELAY,
/*set_pointer*/false, debuglevel);
if (!error) {
*obuf = (xbuf & DS2482_STATUS_SBR) >>
DS2482_STATUS_SBR_SHIFT;
}
}
}
break;
case DS2482_ONEWIRE_WRITE_BYTE:
KASSERT(cmdarg != NULL);
DPRINTF2(debuglevel, 4,
("ds2482_cmd: DS2482_ONEWIRE_WRITE_BYTE:"
" cmdarg: %02x %d\n", *cmdarg, *cmdarg));
xcmd = DS2482_SET_READ_POINTER;
xbuf = DS2482_REGISTER_STATUS;
error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
&xbuf, 1, 0);
if (!error) {
error = ds2482_wait_with_status(tag, addr, &xbuf,
DS2482_QUICK_DELAY, /*set_pointer*/false,
debuglevel);
}
if (!error) {
error = ds2482_set_pullup(tag, addr,
activepullup, strongpullup, debuglevel);
if (!error) {
error = iic_exec(tag, I2C_OP_WRITE, addr,
cmd, 1, cmdarg, 1, 0);
}
if (!error) {
xbuf = 0xff;
error = ds2482_wait_with_status(tag, addr,
&xbuf, DS2482_SLOW_DELAY,
/*set_pointer*/false, debuglevel);
}
}
break;
case DS2482_ONEWIRE_READ_BYTE:
KASSERT(obuf != NULL);
KASSERT(obuflen == 1);
DPRINTF2(debuglevel, 4,
("ds2482_cmd: DS2482_ONEWIRE_READ_BYTE\n"));
xcmd = DS2482_SET_READ_POINTER;
xbuf = DS2482_REGISTER_STATUS;
error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
&xbuf, 1, 0);
if (!error) {
error = ds2482_wait_with_status(tag, addr, &xbuf,
DS2482_QUICK_DELAY, /*set_pointer*/false,
debuglevel);
}
if (!error) {
error = ds2482_set_pullup(tag, addr,
activepullup, strongpullup, debuglevel);
if (!error) {
error = iic_exec(tag, I2C_OP_WRITE, addr,
cmd, 1, NULL, 0, 0);
}
if (!error) {
xbuf = 0xff;
error = ds2482_wait_with_status(tag, addr,
&xbuf, DS2482_SLOW_DELAY,
/*set_pointer*/false, debuglevel);
if (!error) {
xcmd = DS2482_SET_READ_POINTER;
xbuf = DS2482_REGISTER_DATA;
error = iic_exec(tag,
I2C_OP_WRITE_WITH_STOP, addr,
&xcmd, 1, &xbuf, 1, 0);
if (!error) {
xbuf = 0xff;
error = iic_exec(tag,
I2C_OP_READ_WITH_STOP,
addr, NULL, 0,
&xbuf, 1, 0);
if (!error) {
*obuf = xbuf;
}
}
}
}
}
break;
case DS2482_ONEWIRE_TRIPLET:
KASSERT(cmdarg != NULL);
KASSERT(obuf != NULL);
KASSERT(obuflen == 1);
DPRINTF2(debuglevel, 4,
("ds2482_cmd: DS2482_ONEWIRE_TRIPLET: cmdarg: %02x %d\n",
*cmdarg, *cmdarg));
xcmd = DS2482_SET_READ_POINTER;
xbuf = DS2482_REGISTER_STATUS;
error = iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &xcmd, 1,
&xbuf, 1, 0);
if (!error) {
error = ds2482_wait_with_status(tag, addr, &xbuf,
DS2482_QUICK_DELAY, /*set_pointer*/false,
debuglevel);
}
if (!error) {
xbuf = DS2482_TRIPLET_DIR_ZERO;
if (*cmdarg & 0x01) {
xbuf = DS2482_TRIPLET_DIR_ONE;
}
error = ds2482_set_pullup(tag, addr,
activepullup, strongpullup, debuglevel);
if (!error) {
error = iic_exec(tag, I2C_OP_WRITE, addr,
cmd, 1, &xbuf, 1, 0);
}
if (!error) {
xbuf = 0xff;
error = ds2482_wait_with_status(tag, addr,
&xbuf, DS2482_SLOW_DELAY,
/*set_pointer*/false, debuglevel);
if (!error) {
/*
* This is undocumented
* anywhere I could find, but
* what has to be returned is
* 0x01 is the triplet path was
* taken, 0x02 is the
* Not-triplet path was taken,
* and 0x00 is neither was
* taken. The DIR bit in the
* status of the DS2482 may
* help with this some, but
* what is below seems to work.
*/
*obuf = 0;
if (xbuf & DS2482_STATUS_TSB) {
*obuf = 0x01;
} else {
if (xbuf & DS2482_STATUS_SBR) {
*obuf = 0x02;
}
}
}
}
}
break;
default:
error = EINVAL;
break;
}
return error;
}
static int
ds2482_cmdr(struct ds2482ow_sc *sc, uint8_t cmd, uint8_t cmdarg,
uint8_t *buf, size_t blen)
{
DPRINTF(sc, 3, ("%s: ds2482_cmdr: cmd: %02x\n",
device_xname(sc->sc_dev), cmd));
return ds2482_cmd(sc->sc_tag, sc->sc_addr, &cmd, &cmdarg, buf, blen,
sc->sc_activepullup, sc->sc_strongpullup, sc->sc_ds2482debug);
}
static const uint8_t ds2482_channels[] = {
DS2482_CHANNEL_IO0,
DS2482_CHANNEL_IO1,
DS2482_CHANNEL_IO2,
DS2482_CHANNEL_IO3,
DS2482_CHANNEL_IO4,
DS2482_CHANNEL_IO5,
DS2482_CHANNEL_IO6,
DS2482_CHANNEL_IO7
};
static int
ds2482_set_channel(struct ds2482ow_sc *sc, int channel)
{
int error = 0;
KASSERT(channel >= 0 && channel < DS2482_NUM_INSTANCES);
if (sc->sc_is_800) {
error = ds2482_cmdr(sc, DS2482_SELECT_CHANNEL,
ds2482_channels[channel], NULL, 0);
}
return error;
}
static int
ds2482_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
{
uint8_t reg = DS2482_SET_READ_POINTER;
uint8_t rbuf = DS2482_REGISTER_STATUS;
uint8_t obuf;
int error;
error = ds2482_cmd(tag, addr, ®, &rbuf, &obuf, 1,
/*activepullup*/false, /*strongpullup*/false, 0);
if (matchdebug) {
printf("poke X 1: %d\n", error);
}
return error;
}
static int
ds2482_match(device_t parent, cfdata_t match, void *aux)
{
struct i2c_attach_args *ia = aux;
int error, match_result;
const bool matchdebug = false;
if (iic_use_direct_match(ia, match, NULL, &match_result))
return match_result;
/* indirect config - check for configured address */
if (!(ia->ia_addr >= DS2482_LOWEST_ADDR &&
ia->ia_addr <= DS2482_HIGHEST_ADDR))
return 0;
/*
* Check to see if something is really at this i2c address. This will
* keep phantom devices from appearing
*/
if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
if (matchdebug)
printf("in match acquire bus failed\n");
return 0;
}
error = ds2482_poke(ia->ia_tag, ia->ia_addr, matchdebug);
iic_release_bus(ia->ia_tag, 0);
return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
}
static void
ds2482_attach(device_t parent, device_t self, void *aux)
{
struct ds2482ow_sc *sc;
struct i2c_attach_args *ia;
int error, i, num_channels = 1;
struct onewirebus_attach_args oba;
const struct sysctlnode *cnode;
int sysctlroot_num, pullup_num;
ia = aux;
sc = device_private(self);
sc->sc_dev = self;
sc->sc_tag = ia->ia_tag;
sc->sc_addr = ia->ia_addr;
sc->sc_ds2482debug = 0;
sc->sc_activepullup = false;
sc->sc_strongpullup = false;
sc->sc_is_800 = false;
aprint_normal("\n");
mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
if ((error = sysctl_createv(&sc->sc_ds2482log, 0, NULL, &cnode,
0, CTLTYPE_NODE, device_xname(sc->sc_dev),
SYSCTL_DESCR("DS2482 controls"), NULL, 0, NULL, 0, CTL_HW,
CTL_CREATE, CTL_EOL)) != 0)
goto out;
sysctlroot_num = cnode->sysctl_num;
#ifdef DS2482_DEBUG
if ((error = sysctl_createv(&sc->sc_ds2482log, 0, NULL, &cnode,
CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
SYSCTL_DESCR("Debug level"), ds2482_verify_sysctl, 0,
&sc->sc_ds2482debug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
CTL_EOL)) != 0)
goto out;
#endif
if ((error = sysctl_createv(&sc->sc_ds2482log, 0, NULL, &cnode,
0, CTLTYPE_NODE, "pullup",
SYSCTL_DESCR("Pullup controls"), NULL, 0, NULL, 0, CTL_HW,
sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
goto out;
pullup_num = cnode->sysctl_num;
if ((error = sysctl_createv(&sc->sc_ds2482log, 0, NULL, &cnode,
CTLFLAG_READWRITE, CTLTYPE_BOOL, "active",
SYSCTL_DESCR("Active pullup"), NULL, 0, &sc->sc_activepullup,
0, CTL_HW, sysctlroot_num, pullup_num, CTL_CREATE, CTL_EOL)) != 0)
goto out;
if ((error = sysctl_createv(&sc->sc_ds2482log, 0, NULL, &cnode,
CTLFLAG_READWRITE, CTLTYPE_BOOL, "strong",
SYSCTL_DESCR("Strong pullup"), NULL, 0, &sc->sc_strongpullup,
0, CTL_HW, sysctlroot_num, pullup_num, CTL_CREATE, CTL_EOL)) != 0)
goto out;
error = iic_acquire_bus(sc->sc_tag, 0);
if (error) {
aprint_error_dev(self, "Could not acquire iic bus: %d\n",
error);
goto out;
}
error = ds2482_cmdr(sc, DS2482_DEVICE_RESET, 0, NULL, 0);
if (error != 0)
aprint_error_dev(self, "Reset failed: %d\n", error);
if (!error) {
int xerror;
xerror = ds2482_cmdr(sc, DS2482_SELECT_CHANNEL,
DS2482_CHANNEL_IO0, NULL, 0);
if (!xerror)
sc->sc_is_800 = true;
}
iic_release_bus(sc->sc_tag, 0);
if (error != 0) {
aprint_error_dev(self, "Unable to setup device\n");
goto out;
}
if (sc->sc_is_800) {
num_channels = DS2482_NUM_INSTANCES;
}
aprint_normal_dev(self, "Maxim DS2482-%s I2C to 1-Wire bridge,"
" Channels available: %d\n",
sc->sc_is_800 ? "800" : "100",
num_channels);
for (i = 0; i < num_channels; i++) {
sc->sc_instances[i].sc_i_channel = i;
sc->sc_instances[i].sc = sc;
sc->sc_instances[i].sc_i_ow_bus.bus_cookie =
&sc->sc_instances[i];
sc->sc_instances[i].sc_i_ow_bus.bus_reset = ds2482_ow_reset;
sc->sc_instances[i].sc_i_ow_bus.bus_read_bit =
ds2482_ow_read_bit;
sc->sc_instances[i].sc_i_ow_bus.bus_write_bit =
ds2482_ow_write_bit;
sc->sc_instances[i].sc_i_ow_bus.bus_read_byte =
ds2482_ow_read_byte;
sc->sc_instances[i].sc_i_ow_bus.bus_write_byte =
ds2482_ow_write_byte;
sc->sc_instances[i].sc_i_ow_bus.bus_triplet =
ds2482_ow_triplet;
memset(&oba, 0, sizeof(oba));
oba.oba_bus = &sc->sc_instances[i].sc_i_ow_bus;
sc->sc_instances[i].sc_i_ow_dev =
config_found(self, &oba, onewirebus_print, CFARGS_NONE);
}
out:
return;
}
/*
* Hmmm... except in the case of reset, there really doesn't seem to
* be any way with the onewire(4) API to indicate an error condition.
*/
static int
ds2482_generic_action(struct ds2482_instance *sci, uint8_t cmd, uint8_t cmdarg,
uint8_t *buf, size_t blen)
{
struct ds2482ow_sc *sc = sci->sc;
int rv;
mutex_enter(&sc->sc_mutex);
rv = iic_acquire_bus(sc->sc_tag, 0);
if (!rv) {
rv = ds2482_set_channel(sc, sci->sc_i_channel);
if (!rv)
rv = ds2482_cmdr(sc, cmd, cmdarg, buf, blen);
}
iic_release_bus(sc->sc_tag, 0);
mutex_exit(&sc->sc_mutex);
return rv;
}
static int
ds2482_ow_reset(void *arg)
{
struct ds2482_instance *sci = arg;
struct ds2482ow_sc *sc = sci->sc;
int rv;
rv = ds2482_generic_action(sci, DS2482_ONEWIRE_RESET, 0, NULL, 0);
DPRINTF(sc, 3, ("%s: ds2482_ow_reset: channel: %d ; rv: %x %d\n",
device_xname(sc->sc_dev), sci->sc_i_channel, rv, rv));
return rv;
}
static int
ds2482_ow_read_bit(void *arg)
{
struct ds2482_instance *sci = arg;
struct ds2482ow_sc *sc = sci->sc;
int rv;
uint8_t buf = 0x55;
rv = ds2482_generic_action(sci, DS2482_ONEWIRE_SINGLE_BIT_READ, 0,
&buf, 1);
DPRINTF(sc, 3,
("%s: ds2482_read_bit: channel: %d ; rv: %x %d ; buf: %02x %d\n",
device_xname(sc->sc_dev), sci->sc_i_channel, rv, rv, buf, buf));
return (int)buf;
}
static void
ds2482_ow_write_bit(void *arg, int value)
{
struct ds2482_instance *sci = arg;
struct ds2482ow_sc *sc = sci->sc;
int rv;
rv = ds2482_generic_action(sci, DS2482_ONEWIRE_SINGLE_BIT_WRITE,
(uint8_t)value, NULL, 0);
DPRINTF(sc, 3, ("%s: ds2482_write_bit: channel: %d ;"
" rv: %x %d ; value: %02x %d\n",
device_xname(sc->sc_dev), sci->sc_i_channel,
rv, rv, (uint8_t)value, (uint8_t)value));
}
static int
ds2482_ow_read_byte(void *arg)
{
struct ds2482_instance *sci = arg;
uint8_t buf = 0x55;
struct ds2482ow_sc *sc = sci->sc;
int rv;
rv = ds2482_generic_action(sci, DS2482_ONEWIRE_READ_BYTE, 0, &buf, 1);
DPRINTF(sc, 3,
("%s: ds2482_read_byte: channel: %d ; rv: %x %d ; buf: %02x %d\n",
device_xname(sc->sc_dev), sci->sc_i_channel, rv, rv, buf, buf));
return (int)buf;
}
static void
ds2482_ow_write_byte(void *arg, int value)
{
struct ds2482_instance *sci = arg;
struct ds2482ow_sc *sc = sci->sc;
int rv;
rv = ds2482_generic_action(sci, DS2482_ONEWIRE_WRITE_BYTE,
(uint8_t)value, NULL, 0);
DPRINTF(sc, 3, ("%s: ds2482_write_byte: channel: %d ;"
" rv: %x %d ; value: %02x %d\n",
device_xname(sc->sc_dev), sci->sc_i_channel,
rv, rv, (uint8_t)value, (uint8_t)value));
}
static int
ds2482_ow_triplet(void *arg, int dir)
{
struct ds2482_instance *sci = arg;
uint8_t buf = 0x55;
struct ds2482ow_sc *sc = sci->sc;
int rv;
rv = ds2482_generic_action(sci, DS2482_ONEWIRE_TRIPLET, (uint8_t)dir,
&buf, 1);
DPRINTF(sc, 3, ("%s: ds2482_triplet: channel: %d ;"
" rv: %x %d ; dir: %x %d ; buf: %02x %d\n",
device_xname(sc->sc_dev), sci->sc_i_channel, rv, rv,
dir, dir, (uint8_t)buf, (uint8_t)buf));
return (int)buf;
}
static int
ds2482_detach(device_t self, int flags)
{
struct ds2482ow_sc *sc;
sc = device_private(self);
/* Remove the sysctl tree */
sysctl_teardown(&sc->sc_ds2482log);
/* Remove the mutex */
mutex_destroy(&sc->sc_mutex);
return 0;
}
MODULE(MODULE_CLASS_DRIVER, ds2482ow, "iic,onewire");
#ifdef _MODULE
#include "ioconf.c"
#endif
static int
ds2482ow_modcmd(modcmd_t cmd, void *opaque)
{
switch (cmd) {
case MODULE_CMD_INIT:
#ifdef _MODULE
return config_init_component(cfdriver_ioconf_ds2482ow,
cfattach_ioconf_ds2482ow, cfdata_ioconf_ds2482ow);
#else
return 0;
#endif
case MODULE_CMD_FINI:
#ifdef _MODULE
return config_fini_component(cfdriver_ioconf_ds2482ow,
cfattach_ioconf_ds2482ow, cfdata_ioconf_ds2482ow);
#else
return 0;
#endif
default:
return ENOTTY;
}
}