diff options
Diffstat (limited to 'usr/src/uts/sun4u/io/i2c/clients/max1617.c')
| -rw-r--r-- | usr/src/uts/sun4u/io/i2c/clients/max1617.c | 843 |
1 files changed, 843 insertions, 0 deletions
diff --git a/usr/src/uts/sun4u/io/i2c/clients/max1617.c b/usr/src/uts/sun4u/io/i2c/clients/max1617.c new file mode 100644 index 0000000000..14f1c1b677 --- /dev/null +++ b/usr/src/uts/sun4u/io/i2c/clients/max1617.c @@ -0,0 +1,843 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * The max1617 I2C is a temp acquisition device. As implemented on some + * processor modules, it contains both a local and a remote temp. The + * local temp measures the ambient (room) temperature, while the remote + * sensor is connected to the processor die. There are ioctl's for retrieving + * temperatures, and setting temperature alarm ranges. + */ + +#include <sys/stat.h> +#include <sys/modctl.h> +#include <sys/open.h> +#include <sys/types.h> +#include <sys/kmem.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/note.h> + +#include <sys/i2c/misc/i2c_svc.h> +#include <sys/i2c/clients/i2c_client.h> +#include <sys/i2c/clients/max1617.h> +#include <sys/i2c/clients/max1617_impl.h> + +/* + * cb ops (only need ioctl) + */ +static int max1617_open(dev_t *, int, int, cred_t *); +static int max1617_close(dev_t, int, int, cred_t *); +static int max1617_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); + +/* + * dev ops + */ +static int max1617_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, + void **result); +static int max1617_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); +static int max1617_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); + +static struct cb_ops max1617_cbops = { + max1617_open, /* open */ + max1617_close, /* close */ + nodev, /* strategy */ + nodev, /* print */ + nodev, /* dump */ + nodev, /* read */ + nodev, /* write */ + max1617_ioctl, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + nochpoll, /* poll */ + ddi_prop_op, /* cb_prop_op */ + NULL, /* streamtab */ + D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ + CB_REV, /* rev */ + nodev, /* int (*cb_aread)() */ + nodev /* int (*cb_awrite)() */ +}; + +static struct dev_ops max1617_ops = { + DEVO_REV, + 0, + max1617_info, + nulldev, + nulldev, + max1617_attach, + max1617_detach, + nodev, + &max1617_cbops, + NULL +}; + +static struct modldrv max1617_modldrv = { + &mod_driverops, /* type of module - driver */ + "max1617 device driver v%I%", + &max1617_ops, +}; + +static struct modlinkage max1617_modlinkage = { + MODREV_1, + &max1617_modldrv, + 0 +}; + +static int max1617_debug = 0; + +static void *max1617_soft_statep; + +int +_init(void) +{ + int error; + + error = mod_install(&max1617_modlinkage); + if (error == 0) { + (void) ddi_soft_state_init(&max1617_soft_statep, + sizeof (struct max1617_unit), 1); + } + + return (error); +} + +int +_fini(void) +{ + int error; + + error = mod_remove(&max1617_modlinkage); + if (error == 0) { + ddi_soft_state_fini(&max1617_soft_statep); + } + + return (error); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&max1617_modlinkage, modinfop)); +} + +/* ARGSUSED */ +static int +max1617_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +{ + dev_t dev; + int instance; + + if (infocmd == DDI_INFO_DEVT2INSTANCE) { + dev = (dev_t)arg; + instance = MAX1617_MINOR_TO_INST(getminor(dev)); + *result = (void *)(uintptr_t)instance; + return (DDI_SUCCESS); + } + return (DDI_FAILURE); +} + +static int +max1617_do_attach(dev_info_t *dip) +{ + struct max1617_unit *unitp; + int instance; + char minor_name[MAXNAMELEN]; + minor_t minor_number; + + instance = ddi_get_instance(dip); + + if (ddi_soft_state_zalloc(max1617_soft_statep, instance) != 0) { + cmn_err(CE_WARN, "%s%d: failed to zalloc softstate", + ddi_get_name(dip), instance); + + return (DDI_FAILURE); + } + + unitp = ddi_get_soft_state(max1617_soft_statep, instance); + + (void) snprintf(unitp->max1617_name, sizeof (unitp->max1617_name), + "%sd", ddi_node_name(dip), instance); + + (void) sprintf(minor_name, "die_temp"); + minor_number = MAX1617_INST_TO_MINOR(instance) | + MAX1617_FCN_TO_MINOR(MAX1617_CPU_TEMP); + + if (ddi_create_minor_node(dip, minor_name, S_IFCHR, + minor_number, MAX1617_NODE_TYPE, NULL) == DDI_FAILURE) { + cmn_err(CE_WARN, "%s ddi_create_minor_node failed for minor " + " name '%s'", unitp->max1617_name, minor_name); + ddi_soft_state_free(max1617_soft_statep, instance); + + return (DDI_FAILURE); + } + + (void) sprintf(minor_name, "amb_temp"); + minor_number = MAX1617_INST_TO_MINOR(instance) | + MAX1617_FCN_TO_MINOR(MAX1617_AMB_TEMP); + + if (ddi_create_minor_node(dip, minor_name, S_IFCHR, + minor_number, MAX1617_NODE_TYPE, NULL) == DDI_FAILURE) { + cmn_err(CE_WARN, "%s ddi_create_minor_node failed for %s", + unitp->max1617_name, minor_name); + ddi_remove_minor_node(dip, NULL); + ddi_soft_state_free(max1617_soft_statep, instance); + + return (DDI_FAILURE); + } + + if (i2c_client_register(dip, &unitp->max1617_hdl) != I2C_SUCCESS) { + ddi_remove_minor_node(dip, NULL); + ddi_soft_state_free(max1617_soft_statep, instance); + + return (DDI_FAILURE); + } + + mutex_init(&unitp->max1617_mutex, NULL, MUTEX_DRIVER, NULL); + cv_init(&unitp->max1617_cv, NULL, CV_DRIVER, NULL); + + return (DDI_SUCCESS); +} + +static int +max1617_do_resume(dev_info_t *dip) +{ + int ret = DDI_SUCCESS; + int instance = ddi_get_instance(dip); + i2c_transfer_t *i2ctp; + struct max1617_unit *unitp; + + if ((unitp = ddi_get_soft_state(max1617_soft_statep, instance)) == + NULL) { + return (DDI_FAILURE); + } + + (void) i2c_transfer_alloc(unitp->max1617_hdl, + &i2ctp, 2, 0, I2C_SLEEP); + i2ctp->i2c_version = I2C_XFER_REV; + i2ctp->i2c_flags = I2C_WR; + + + i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_WR_REG; + i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_config; + + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + + i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_WR_REG; + i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_conv_rate; + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + + i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_HIGH_WR_REG; + i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_lcl_hlimit; + + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + + i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_HIGH_WR_REG; + i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_remote_hlimit; + + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + + i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_LOW_REG; + i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_lcl_llimit; + + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + + i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_LOW_REG; + i2ctp->i2c_wbuf[1] = unitp->max1617_cpr_state.max1617_remote_llimit; + + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + + done: + mutex_enter(&unitp->max1617_mutex); + unitp->max1617_flags = 0; + cv_signal(&unitp->max1617_cv); + mutex_exit(&unitp->max1617_mutex); + + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + return (ret); +} + +static int +max1617_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + switch (cmd) { + case DDI_ATTACH: + + return (max1617_do_attach(dip)); + case DDI_RESUME: + + return (max1617_do_resume(dip)); + default: + + return (DDI_FAILURE); + } +} + +static int +max1617_do_detach(dev_info_t *dip) +{ + struct max1617_unit *unitp; + int instance; + + instance = ddi_get_instance(dip); + + unitp = ddi_get_soft_state(max1617_soft_statep, instance); + + if (unitp == NULL) { + return (DDI_FAILURE); + } + + i2c_client_unregister(unitp->max1617_hdl); + + ddi_remove_minor_node(dip, NULL); + + mutex_destroy(&unitp->max1617_mutex); + cv_destroy(&unitp->max1617_cv); + ddi_soft_state_free(max1617_soft_statep, instance); + + return (DDI_SUCCESS); +} + +static int +max1617_do_suspend(dev_info_t *dip) +{ + int ret = DDI_SUCCESS; + int instance = ddi_get_instance(dip); + i2c_transfer_t *i2ctp; + struct max1617_unit *unitp; + + if ((unitp = ddi_get_soft_state(max1617_soft_statep, instance)) == + NULL) { + return (DDI_FAILURE); + } + + (void) i2c_transfer_alloc(unitp->max1617_hdl, + &i2ctp, 1, 1, I2C_SLEEP); + + + /* + * Block new transactions during CPR + */ + mutex_enter(&unitp->max1617_mutex); + while (unitp->max1617_flags == MAX1617_BUSY) { + cv_wait(&unitp->max1617_cv, &unitp->max1617_mutex); + } + unitp->max1617_flags = MAX1617_BUSY; + mutex_exit(&unitp->max1617_mutex); + + i2ctp->i2c_version = I2C_XFER_REV; + i2ctp->i2c_flags = I2C_WR_RD; + i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_REG; + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + unitp->max1617_cpr_state.max1617_config = i2ctp->i2c_rbuf[0]; + + i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_REG; + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + unitp->max1617_cpr_state.max1617_conv_rate = i2ctp->i2c_rbuf[0]; + + i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_HIGH_REG; + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + unitp->max1617_cpr_state.max1617_lcl_hlimit = i2ctp->i2c_rbuf[0]; + + i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_HIGH_REG; + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + unitp->max1617_cpr_state.max1617_remote_hlimit = i2ctp->i2c_rbuf[0]; + + i2ctp->i2c_wbuf[0] = MAX1617_LOCALTEMP_LOW_REG; + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + unitp->max1617_cpr_state.max1617_lcl_llimit = i2ctp->i2c_rbuf[0]; + + i2ctp->i2c_wbuf[0] = MAX1617_REMOTETEMP_LOW_REG; + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + ret = DDI_FAILURE; + goto done; + } + unitp->max1617_cpr_state.max1617_remote_llimit = i2ctp->i2c_rbuf[0]; + + done: + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + + if (ret == DDI_FAILURE) { + mutex_enter(&unitp->max1617_mutex); + unitp->max1617_flags = 0; + cv_broadcast(&unitp->max1617_cv); + mutex_exit(&unitp->max1617_mutex); + } + return (ret); +} + +static int +max1617_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + switch (cmd) { + case DDI_DETACH: + + return (max1617_do_detach(dip)); + case DDI_SUSPEND: + + return (max1617_do_suspend(dip)); + + default: + + return (DDI_FAILURE); + } +} + +static int +max1617_open(dev_t *devp, int flags, int otyp, cred_t *credp) +{ + _NOTE(ARGUNUSED(credp)) + + struct max1617_unit *unitp; + int instance; + int err = 0; + + instance = MAX1617_MINOR_TO_INST(getminor(*devp)); + + if (instance < 0) { + + return (ENXIO); + } + + unitp = (struct max1617_unit *) + ddi_get_soft_state(max1617_soft_statep, instance); + + if (unitp == NULL) { + + return (ENXIO); + } + + if (otyp != OTYP_CHR) { + + return (EINVAL); + } + + mutex_enter(&unitp->max1617_mutex); + + if (flags & FEXCL) { + if (unitp->max1617_oflag != 0) { + err = EBUSY; + } else { + unitp->max1617_oflag = FEXCL; + } + } else { + if (unitp->max1617_oflag == FEXCL) { + err = EBUSY; + } else { + unitp->max1617_oflag = FOPEN; + } + } + +done: + mutex_exit(&unitp->max1617_mutex); + + return (err); +} + +static int +max1617_close(dev_t dev, int flags, int otyp, cred_t *credp) +{ + _NOTE(ARGUNUSED(flags, otyp, credp)) + + struct max1617_unit *unitp; + int instance = MAX1617_MINOR_TO_INST(getminor(dev)); + + if (instance < 0) { + + return (ENXIO); + } + + unitp = (struct max1617_unit *) + ddi_get_soft_state(max1617_soft_statep, instance); + + if (unitp == NULL) { + + return (ENXIO); + } + + mutex_enter(&unitp->max1617_mutex); + + unitp->max1617_oflag = 0; + + mutex_exit(&unitp->max1617_mutex); + + return (DDI_SUCCESS); +} + +int +set_temp_limit(struct max1617_unit *unitp, + uchar_t device_reg, + caddr_t arg, + int mode) +{ + int err = 0; + i2c_transfer_t *i2ctp; + int16_t temp; + + (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 2, 0, I2C_SLEEP); + i2ctp->i2c_version = I2C_XFER_REV; + i2ctp->i2c_flags = I2C_WR; + i2ctp->i2c_wbuf[0] = device_reg; + + if (ddi_copyin(arg, (caddr_t)&temp, sizeof (int16_t), mode) != + DDI_SUCCESS) { + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + + return (EFAULT); + } + + i2ctp->i2c_wbuf[1] = (int8_t)temp; + + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + err = EIO; + } + + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + + return (err); +} + +int +get_temp_limit(struct max1617_unit *unitp, + uchar_t reg, + caddr_t arg, + int mode) +{ + int err = 0; + i2c_transfer_t *i2ctp; + int16_t temp16; + + (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 1, I2C_SLEEP); + i2ctp->i2c_version = I2C_XFER_REV; + i2ctp->i2c_flags = I2C_WR_RD; + i2ctp->i2c_wbuf[0] = reg; + if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) { + /* + * This double cast is required so that the sign is preserved + * when expanding the 8 bit value to 16. + */ + temp16 = (int16_t)((int8_t)i2ctp->i2c_rbuf[0]); + if (ddi_copyout((caddr_t)&temp16, arg, sizeof (int16_t), + mode) != DDI_SUCCESS) { + err = EFAULT; + } + } else { + err = EIO; + } + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + + return (err); +} + +static int +max1617_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *credp, int *rvalp) +{ + _NOTE(ARGUNUSED(credp, rvalp)) + struct max1617_unit *unitp; + int err = 0; + i2c_transfer_t *i2ctp; + int fcn = MAX1617_MINOR_TO_FCN(getminor(dev)); + int instance = MAX1617_MINOR_TO_INST(getminor(dev)); + uchar_t reg; + + unitp = (struct max1617_unit *) + ddi_get_soft_state(max1617_soft_statep, instance); + + if (max1617_debug) { + printf("max1617_ioctl: fcn=%d instance=%d\n", fcn, instance); + } + + /* + * Serialize here, in order to block transacations during CPR. + * This is not a bottle neck since i2c_transfer would serialize + * anyway. + */ + mutex_enter(&unitp->max1617_mutex); + while (unitp->max1617_flags == MAX1617_BUSY) { + if (cv_wait_sig(&unitp->max1617_cv, + &unitp->max1617_mutex) <= 0) { + mutex_exit(&unitp->max1617_mutex); + return (EINTR); + } + } + unitp->max1617_flags = MAX1617_BUSY; + mutex_exit(&unitp->max1617_mutex); + + switch (cmd) { + + /* + * I2C_GET_TEMPERATURE reads a temperature from the device and + * copies a single byte representing the celcius temp + * to user space. + */ + case I2C_GET_TEMPERATURE: + switch (fcn) { + case MAX1617_AMB_TEMP: + reg = MAX1617_LOCAL_TEMP_REG; + break; + case MAX1617_CPU_TEMP: + reg = MAX1617_REMOTE_TEMP_REG; + break; + default: + err = EINVAL; + goto done; + } + + (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, + 1, 1, I2C_SLEEP); + i2ctp->i2c_version = I2C_XFER_REV; + i2ctp->i2c_flags = I2C_WR_RD; + i2ctp->i2c_wbuf[0] = reg; + + if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) { + + /* + * This double cast is needed so that the sign bit + * is preserved when casting from unsigned char to + * signed 16 bit value. + */ + int16_t temp = (int16_t)((int8_t)i2ctp->i2c_rbuf[0]); + if (ddi_copyout((caddr_t)&temp, (caddr_t)arg, + sizeof (int16_t), mode) != DDI_SUCCESS) { + err = EFAULT; + } + } else { + err = EIO; + } + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + break; + + case MAX1617_GET_STATUS: + (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, + 1, 1, I2C_SLEEP); + i2ctp->i2c_version = I2C_XFER_REV; + i2ctp->i2c_flags = I2C_WR_RD; + i2ctp->i2c_wbuf[0] = MAX1617_STATUS_REG; + + if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) { + if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg, + sizeof (uint8_t), mode) != DDI_SUCCESS) { + err = EFAULT; + } + } else { + err = EIO; + } + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + break; + case MAX1617_GET_CONFIG: + (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 1, + I2C_SLEEP); + i2ctp->i2c_version = I2C_XFER_REV; + i2ctp->i2c_flags = I2C_WR_RD; + i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_REG; + if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) { + if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg, + sizeof (uint8_t), mode) != DDI_SUCCESS) { + err = EFAULT; + } + } else { + err = EIO; + } + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + break; + case MAX1617_GET_CONV_RATE: + (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, + 1, 1, I2C_SLEEP); + i2ctp->i2c_version = I2C_XFER_REV; + i2ctp->i2c_flags = I2C_WR_RD; + i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_REG; + if (i2c_transfer(unitp->max1617_hdl, i2ctp) == I2C_SUCCESS) { + if (ddi_copyout((caddr_t)i2ctp->i2c_rbuf, (caddr_t)arg, + sizeof (uint8_t), mode) != DDI_SUCCESS) { + err = EFAULT; + } + } else { + err = EIO; + } + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + break; + + case MAX1617_GET_HIGH_LIMIT: + switch (fcn) { + case MAX1617_AMB_TEMP: + err = get_temp_limit(unitp, MAX1617_LOCALTEMP_HIGH_REG, + (caddr_t)arg, mode); + break; + case MAX1617_CPU_TEMP: + err = get_temp_limit(unitp, MAX1617_REMOTETEMP_HIGH_REG, + (caddr_t)arg, mode); + break; + default: + err = EINVAL; + break; + } + break; + + case MAX1617_GET_LOW_LIMIT: + + switch (fcn) { + case MAX1617_AMB_TEMP: + err = get_temp_limit(unitp, MAX1617_LOCALTEMP_LOW_REG, + (caddr_t)arg, mode); + break; + case MAX1617_CPU_TEMP: + err = get_temp_limit(unitp, MAX1617_REMOTETEMP_LOW_REG, + (caddr_t)arg, mode); + break; + default: + err = EINVAL; + } + break; + + case MAX1617_SET_CONV_RATE: + (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, + 2, 0, I2C_SLEEP); + i2ctp->i2c_version = I2C_XFER_REV; + i2ctp->i2c_flags = I2C_WR; + i2ctp->i2c_wbuf[0] = MAX1617_CONV_RATE_WR_REG; + if (ddi_copyin((caddr_t)arg, (caddr_t)&i2ctp->i2c_wbuf[1], + sizeof (uint8_t), mode) != DDI_SUCCESS) { + err = EFAULT; + break; + } + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + err = EIO; + } + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + break; + + case MAX1617_SET_CONFIG: + (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, + 2, 0, I2C_SLEEP); + i2ctp->i2c_version = I2C_XFER_REV; + i2ctp->i2c_flags = I2C_WR; + i2ctp->i2c_wbuf[0] = MAX1617_CONFIG_WR_REG; + if (ddi_copyin((caddr_t)arg, (caddr_t)&i2ctp->i2c_wbuf[1], + sizeof (uint8_t), mode) != DDI_SUCCESS) { + err = EFAULT; + break; + } + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + err = EIO; + } + + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + break; + + case MAX1617_SET_HIGH_LIMIT: + switch (fcn) { + case MAX1617_AMB_TEMP: + err = set_temp_limit(unitp, + MAX1617_LOCALTEMP_HIGH_WR_REG, (caddr_t)arg, mode); + break; + case MAX1617_CPU_TEMP: + err = set_temp_limit(unitp, + MAX1617_REMOTETEMP_HIGH_WR_REG, (caddr_t)arg, mode); + break; + default: + err = EINVAL; + } + break; + + case MAX1617_SET_LOW_LIMIT: + switch (fcn) { + case MAX1617_AMB_TEMP: + err = set_temp_limit(unitp, + MAX1617_LOCALTEMP_LOW_WR_REG, (caddr_t)arg, mode); + break; + case MAX1617_CPU_TEMP: + err = set_temp_limit(unitp, + MAX1617_REMOTETEMP_LOW_WR_REG, (caddr_t)arg, mode); + break; + default: + err = EINVAL; + } + break; + + case MAX1617_ONE_SHOT_CMD: + (void) i2c_transfer_alloc(unitp->max1617_hdl, &i2ctp, 1, 0, + I2C_SLEEP); + i2ctp->i2c_version = I2C_XFER_REV; + i2ctp->i2c_flags = I2C_WR; + i2ctp->i2c_wbuf[0] = MAX1617_ONE_SHOT_CMD_REG; + if (i2c_transfer(unitp->max1617_hdl, i2ctp) != I2C_SUCCESS) { + err = EIO; + } + + i2c_transfer_free(unitp->max1617_hdl, i2ctp); + break; + + default: + err = EINVAL; + } + + done: + + mutex_enter(&unitp->max1617_mutex); + unitp->max1617_flags = 0; + cv_signal(&unitp->max1617_cv); + mutex_exit(&unitp->max1617_mutex); + + return (err); +} |
