03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * CDDL HEADER START
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The contents of this file are subject to the terms of the
193974072f41a843678abf5f61979c748687e66bSherry Moore * Common Development and Distribution License (the "License").
193974072f41a843678abf5f61979c748687e66bSherry Moore * You may not use this file except in compliance with the License.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
03831d35f7499c87d51205817c93e9a8d42c4baestevel * or http://www.opensolaris.org/os/licensing.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * See the License for the specific language governing permissions
03831d35f7499c87d51205817c93e9a8d42c4baestevel * and limitations under the License.
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * When distributing Covered Code, include this CDDL HEADER in each
03831d35f7499c87d51205817c93e9a8d42c4baestevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If applicable, add the following below this CDDL HEADER, with the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * fields enclosed by brackets "[]" replaced with your own identifying
03831d35f7499c87d51205817c93e9a8d42c4baestevel * information: Portions Copyright [yyyy] [name of copyright owner]
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * CDDL HEADER END
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Use is subject to license terms.
89b43686db1fe9681d80a7cf5662730cb9378caeBayard Bell * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * I2C leaf driver for the PCF8591
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/param.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/types.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/signal.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/errno.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/file.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/termio.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/termios.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/cmn_err.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/stream.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/strsun.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/stropts.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/strtty.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/debug.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/eucioctl.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/cred.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/uio.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/stat.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/kmem.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/ddi.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/sunddi.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/obpdefs.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/conf.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/modctl.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/stat.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/open.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/uio.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/i2c/misc/i2c_svc.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/envctrl_gen.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/netract_gen.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel#include <sys/pcf8591_nct.h>
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * CONTROL OF CHIP
03831d35f7499c87d51205817c93e9a8d42c4baestevel * PCF8591 Temp sensing control register definitions
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * ---------------------------------------------
03831d35f7499c87d51205817c93e9a8d42c4baestevel * | 0 | AOE | X | X | 0 | AIF | X | X |
03831d35f7499c87d51205817c93e9a8d42c4baestevel * ---------------------------------------------
03831d35f7499c87d51205817c93e9a8d42c4baestevel * AOE = Analog out enable.. not used on out implementation
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 5 & 4 = Analog Input Programming.. see data sheet for bits..
03831d35f7499c87d51205817c93e9a8d42c4baestevel *
03831d35f7499c87d51205817c93e9a8d42c4baestevel * AIF = Auto increment flag
03831d35f7499c87d51205817c93e9a8d42c4baestevel * bits 1 & 0 are for the Chennel number.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#define I2CTRANS_DATA 0
03831d35f7499c87d51205817c93e9a8d42c4baestevel#define I2CRAW_DATA 1
03831d35f7499c87d51205817c93e9a8d42c4baestevel#define TEMP_TABLE_SIZE 256
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#define SHUTDOWN_TEMP_MIN 55
03831d35f7499c87d51205817c93e9a8d42c4baestevel#define SHUTDOWN_TEMP_MAX 85
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#ifdef DEBUG
03831d35f7499c87d51205817c93e9a8d42c4baestevel#define dbg_print(level, str) cmn_err(level, str);
03831d35f7499c87d51205817c93e9a8d42c4baestevel#else
03831d35f7499c87d51205817c93e9a8d42c4baestevel#define dbg_print(level, str) {; }
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelextern int nct_i2c_transfer(i2c_client_hdl_t i2c_hdl, i2c_transfer_t *i2c_tran);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic uchar_t _cpu_temps[TEMP_TABLE_SIZE + 4]; /* see attach */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic void *pcf8591_soft_statep;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * cb ops (only need ioctl)
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pcf8591_open(dev_t *, int, int, cred_t *);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pcf8591_close(dev_t, int, int, cred_t *);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pcf8591_read(dev_t dev, struct uio *uiop, cred_t *cred_p);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pcf8591_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic struct cb_ops pcf8591_cbops = {
03831d35f7499c87d51205817c93e9a8d42c4baestevel pcf8591_open, /* open */
03831d35f7499c87d51205817c93e9a8d42c4baestevel pcf8591_close, /* close */
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodev, /* strategy */
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodev, /* print */
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodev, /* dump */
03831d35f7499c87d51205817c93e9a8d42c4baestevel pcf8591_read, /* read */
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodev, /* write */
03831d35f7499c87d51205817c93e9a8d42c4baestevel pcf8591_ioctl, /* ioctl */
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodev, /* devmap */
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodev, /* mmap */
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodev, /* segmap */
03831d35f7499c87d51205817c93e9a8d42c4baestevel nochpoll, /* poll */
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_prop_op, /* cb_prop_op */
03831d35f7499c87d51205817c93e9a8d42c4baestevel NULL, /* streamtab */
03831d35f7499c87d51205817c93e9a8d42c4baestevel D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */
03831d35f7499c87d51205817c93e9a8d42c4baestevel CB_REV, /* rev */
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodev, /* int (*cb_aread)() */
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodev /* int (*cb_awrite)() */
03831d35f7499c87d51205817c93e9a8d42c4baestevel};
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * dev ops
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pcf8591_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
03831d35f7499c87d51205817c93e9a8d42c4baestevel void **result);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pcf8591_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pcf8591_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/* kstat routines */
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pcf8591_add_kstats(struct pcf8591_unit *);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic void pcf8591_delete_kstats(struct pcf8591_unit *);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pcf8591_temp_kstat_update(kstat_t *, int);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pcf8591_read_chip(struct pcf8591_unit *, uint8_t, int);
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int pcf8591_read_props(struct pcf8591_unit *unitp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic struct dev_ops pcf8591_ops = {
03831d35f7499c87d51205817c93e9a8d42c4baestevel DEVO_REV,
03831d35f7499c87d51205817c93e9a8d42c4baestevel 0,
03831d35f7499c87d51205817c93e9a8d42c4baestevel pcf8591_info,
03831d35f7499c87d51205817c93e9a8d42c4baestevel nulldev,
03831d35f7499c87d51205817c93e9a8d42c4baestevel nulldev,
03831d35f7499c87d51205817c93e9a8d42c4baestevel pcf8591_attach,
03831d35f7499c87d51205817c93e9a8d42c4baestevel pcf8591_detach,
03831d35f7499c87d51205817c93e9a8d42c4baestevel nodev,
03831d35f7499c87d51205817c93e9a8d42c4baestevel &pcf8591_cbops,
193974072f41a843678abf5f61979c748687e66bSherry Moore NULL,
193974072f41a843678abf5f61979c748687e66bSherry Moore NULL,
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */
03831d35f7499c87d51205817c93e9a8d42c4baestevel};
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelextern struct mod_ops mod_driverops;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic struct modldrv pcf8591_modldrv = {
03831d35f7499c87d51205817c93e9a8d42c4baestevel &mod_driverops, /* type of module - driver */
193974072f41a843678abf5f61979c748687e66bSherry Moore "Netract pcf8591 (adio)",
03831d35f7499c87d51205817c93e9a8d42c4baestevel &pcf8591_ops,
03831d35f7499c87d51205817c93e9a8d42c4baestevel};
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic struct modlinkage pcf8591_modlinkage = {
03831d35f7499c87d51205817c93e9a8d42c4baestevel MODREV_1,
03831d35f7499c87d51205817c93e9a8d42c4baestevel &pcf8591_modldrv,
03831d35f7499c87d51205817c93e9a8d42c4baestevel 0
03831d35f7499c87d51205817c93e9a8d42c4baestevel};
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelint pcf8591_debug = 0x02;
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic uint8_t translate_cputemp(uint8_t value);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelint
03831d35f7499c87d51205817c93e9a8d42c4baestevel_init(void)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel register int error;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel error = mod_install(&pcf8591_modlinkage);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (error == 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel (void) ddi_soft_state_init(&pcf8591_soft_statep,
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (struct pcf8591_unit), PCF8591_MAX_DEVS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (error);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelint
03831d35f7499c87d51205817c93e9a8d42c4baestevel_fini(void)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel register int error;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel error = mod_remove(&pcf8591_modlinkage);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (error == 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_soft_state_fini(&pcf8591_soft_statep);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (error);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelint
03831d35f7499c87d51205817c93e9a8d42c4baestevel_info(struct modinfo *modinfop)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (mod_info(&pcf8591_modlinkage, modinfop));
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*ARGSUSED*/
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_open(dev_t *devp, int flags, int otyp, cred_t *credp)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel int err = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct pcf8591_unit *unitp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel minor_t minor = getminor(*devp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel int instance = PCF8591_MINOR_TO_DEVINST(minor);
03831d35f7499c87d51205817c93e9a8d42c4baestevel int channel = PCF8591_MINOR_TO_CHANNEL(minor);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (instance < 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (ENXIO);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp = (struct pcf8591_unit *)
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_get_soft_state(pcf8591_soft_statep, instance);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (unitp == NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (ENXIO);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (otyp != OTYP_CHR) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EINVAL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_enter(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (flags & FEXCL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (unitp->pcf8591_oflag[channel] != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EBUSY;
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_oflag[channel] = FEXCL;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (unitp->pcf8591_oflag[channel] == FEXCL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EBUSY;
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_oflag[channel] = FOPEN;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (err);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*ARGSUSED*/
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_close(dev_t devp, int flags, int otyp, cred_t *credp)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct pcf8591_unit *unitp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel minor_t minor = getminor(devp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel int instance = PCF8591_MINOR_TO_DEVINST(minor);
03831d35f7499c87d51205817c93e9a8d42c4baestevel int channel = PCF8591_MINOR_TO_CHANNEL(minor);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#ifdef lint
03831d35f7499c87d51205817c93e9a8d42c4baestevel flags = flags;
03831d35f7499c87d51205817c93e9a8d42c4baestevel otyp = otyp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (instance < 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (ENXIO);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp = (struct pcf8591_unit *)
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_get_soft_state(pcf8591_soft_statep, instance);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (unitp == NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (ENXIO);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_enter(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_oflag[channel] = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_SUCCESS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_io(dev_t dev, struct uio *uiop, int rw)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel int err = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct pcf8591_unit *unitp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel minor_t minor = getminor(dev);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel int instance = PCF8591_MINOR_TO_DEVINST(minor);
03831d35f7499c87d51205817c93e9a8d42c4baestevel int channel = PCF8591_MINOR_TO_CHANNEL(minor);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel int bytes_to_rw;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int translate = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * At this point we don't have a write operation to pcf8591.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (rw == B_WRITE) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EACCES);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (instance < 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (ENXIO);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp = (struct pcf8591_unit *)
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_get_soft_state(pcf8591_soft_statep, instance);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (unitp == NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (ENXIO);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((bytes_to_rw = uiop->uio_resid) > PCF8591_TRAN_SIZE) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EINVAL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Need to serialize all read operations, since there is a single
03831d35f7499c87d51205817c93e9a8d42c4baestevel * i2c_transfer_t structure allocated for all read and write ops.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * We can't share the i2c bus among multiple transactions anyway,
03831d35f7499c87d51205817c93e9a8d42c4baestevel * so this does not affect performance.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_enter(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel while (unitp->pcf8591_flags == PCF8591_BUSY) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (cv_wait_sig(&unitp->pcf8591_cv, &unitp->umutex) <= 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EINTR);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_flags = PCF8591_BUSY;
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (bytes_to_rw == 1)
03831d35f7499c87d51205817c93e9a8d42c4baestevel translate = 1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Event sequence:
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 1. set up the control register write, for now we'll always read
03831d35f7499c87d51205817c93e9a8d42c4baestevel * channel 0, which is the only active 8591 port on the Nordica
03831d35f7499c87d51205817c93e9a8d42c4baestevel * TODO: We'll need a minor node for each port that is used.
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 2. increment read count to read the throw-away byte
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 3. start the write/read of control/data registers
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 4. throw the first byte away
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 5. then return the data
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->i2c_tran->i2c_flags = I2C_WR_RD;
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->i2c_tran->i2c_wlen = 1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->i2c_tran->i2c_wbuf[0] = (unitp->pcf8591_inprog |
193974072f41a843678abf5f61979c748687e66bSherry Moore channel);
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * read extra byte to throw away the first, (PCF8591 datasheet)
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->i2c_tran->i2c_rlen = bytes_to_rw + 1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (nct_i2c_transfer(unitp->pcf8591_hdl,
193974072f41a843678abf5f61979c748687e66bSherry Moore unitp->i2c_tran) != I2C_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EIO;
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Throw away the first byte according to PCF8591 datasheet
03831d35f7499c87d51205817c93e9a8d42c4baestevel * If translating, use the second byte.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (translate) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->i2c_tran->i2c_rbuf[0] =
193974072f41a843678abf5f61979c748687e66bSherry Moore translate_cputemp(unitp->i2c_tran->i2c_rbuf[1]);
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->i2c_tran->i2c_rbuf[0] =
193974072f41a843678abf5f61979c748687e66bSherry Moore unitp->i2c_tran->i2c_rbuf[1];
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->i2c_tran->i2c_rbuf[1] = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = uiomove(unitp->i2c_tran->i2c_rbuf,
193974072f41a843678abf5f61979c748687e66bSherry Moore bytes_to_rw,
193974072f41a843678abf5f61979c748687e66bSherry Moore UIO_READ,
193974072f41a843678abf5f61979c748687e66bSherry Moore uiop);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_enter(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_flags = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel cv_signal(&unitp->pcf8591_cv);
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (err);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*ARGSUSED*/
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_read(dev_t dev, struct uio *uiop, cred_t *cred_p)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (pcf8591_io(dev, uiop, B_READ));
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelcall_copyin(caddr_t arg, struct pcf8591_unit *unitp, int mode)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel uchar_t *wbuf;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uchar_t *rbuf;
03831d35f7499c87d51205817c93e9a8d42c4baestevel i2c_transfer_t i2ct;
03831d35f7499c87d51205817c93e9a8d42c4baestevel i2c_transfer_t *i2ctp = unitp->i2c_tran;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_copyin((void *)arg, (caddr_t)&i2ct,
03831d35f7499c87d51205817c93e9a8d42c4baestevel sizeof (i2c_transfer_t), mode) != DDI_SUCCESS) {
193974072f41a843678abf5f61979c748687e66bSherry Moore return (I2C_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Save the read and write buffer pointers in the transfer
03831d35f7499c87d51205817c93e9a8d42c4baestevel * structure, otherwise these will get overwritten when we
03831d35f7499c87d51205817c93e9a8d42c4baestevel * do a bcopy. Restore once done.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel wbuf = i2ctp->i2c_wbuf;
03831d35f7499c87d51205817c93e9a8d42c4baestevel rbuf = i2ctp->i2c_rbuf;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel bcopy(&i2ct, i2ctp, sizeof (i2c_transfer_t));
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel i2ctp->i2c_wbuf = wbuf;
03831d35f7499c87d51205817c93e9a8d42c4baestevel i2ctp->i2c_rbuf = rbuf;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * copyin the read and write buffers to the saved buffers.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (i2ct.i2c_wlen != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_copyin(i2ct.i2c_wbuf, (caddr_t)i2ctp->i2c_wbuf,
193974072f41a843678abf5f61979c748687e66bSherry Moore i2ct.i2c_wlen, mode) != DDI_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (I2C_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (I2C_SUCCESS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelcall_copyout(caddr_t arg, struct pcf8591_unit *unitp, int mode)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel i2c_transfer_t i2ct;
03831d35f7499c87d51205817c93e9a8d42c4baestevel i2c_transfer_t *i2ctp = unitp->i2c_tran;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint16_t i2c_actlen;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * We will copyout the last three fields only, skipping
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the remaining ones, before copying the rbuf to the
03831d35f7499c87d51205817c93e9a8d42c4baestevel * user buffer.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel int uskip = sizeof (i2c_transfer_t) - 3*sizeof (int16_t),
193974072f41a843678abf5f61979c748687e66bSherry Moore kskip = sizeof (i2c_transfer_t) - 3*sizeof (int16_t);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * First copyin the user structure to the temporary i2ct,
03831d35f7499c87d51205817c93e9a8d42c4baestevel * so that we have the wbuf and rbuf addresses in it.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel uskip = sizeof (i2c_transfer_t) - 3 * (sizeof (uint16_t));
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * copyout the last three out fields now.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_copyout((void *)((intptr_t)i2ctp+kskip), (void *)
193974072f41a843678abf5f61979c748687e66bSherry Moore ((intptr_t)arg + uskip), 3*sizeof (uint16_t), mode)
193974072f41a843678abf5f61979c748687e66bSherry Moore != DDI_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (I2C_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * In case we have something to write, get the address of the read
03831d35f7499c87d51205817c93e9a8d42c4baestevel * buffer.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (i2ctp->i2c_rlen - i2ctp->i2c_r_resid > 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_copyin((void *)arg, &i2ct,
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (i2c_transfer_t), mode) != DDI_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (I2C_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * copyout the read buffer to the saved user buffer in i2ct.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel i2c_actlen = i2ctp->i2c_rlen - i2ctp->i2c_r_resid;
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_copyout(i2ctp->i2c_rbuf, i2ct.i2c_rbuf,
193974072f41a843678abf5f61979c748687e66bSherry Moore i2c_actlen, mode) != DDI_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (I2C_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (I2C_SUCCESS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The ioctls will use the same name as the Javelin ioctls. We
03831d35f7499c87d51205817c93e9a8d42c4baestevel * will have a very restricted set for MC, and unlike Javelin
03831d35f7499c87d51205817c93e9a8d42c4baestevel * will not have a envctrl_chip structure to return values
03831d35f7499c87d51205817c93e9a8d42c4baestevel * from the driver. All we will have is a uint8_t value to
03831d35f7499c87d51205817c93e9a8d42c4baestevel * get or set values from the driver. Also, unlike the Javelin,
03831d35f7499c87d51205817c93e9a8d42c4baestevel * where 'index' is used to specify the input port from where
03831d35f7499c87d51205817c93e9a8d42c4baestevel * temperature is collected, here different minor nodes will be
03831d35f7499c87d51205817c93e9a8d42c4baestevel * created by the driver for each port, eliminating the need for
03831d35f7499c87d51205817c93e9a8d42c4baestevel * 'index' - leaving us with only the value to pass.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*ARGSUSED*/
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
03831d35f7499c87d51205817c93e9a8d42c4baestevel cred_t *credp, int *rvalp)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel int err = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct pcf8591_unit *unitp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel minor_t minor = getminor(dev);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel int instance = PCF8591_MINOR_TO_DEVINST(minor);
03831d35f7499c87d51205817c93e9a8d42c4baestevel int channel = PCF8591_MINOR_TO_CHANNEL(minor);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp = (struct pcf8591_unit *)
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_get_soft_state(pcf8591_soft_statep, instance);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_enter(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel while (unitp->pcf8591_flags == PCF8591_BUSY) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (cv_wait_sig(&unitp->pcf8591_cv, &unitp->umutex) <= 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EINTR);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_flags = PCF8591_BUSY;
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel switch (cmd) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel case ENVC_IOC_GETTEMP: {
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Read the status byte from pcf8591 chip. The value will
03831d35f7499c87d51205817c93e9a8d42c4baestevel * be already converted to Celcius by translate_cputemp.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) pcf8591_read_chip(unitp, channel, 1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_copyout(unitp->i2c_tran->i2c_rbuf,
193974072f41a843678abf5f61979c748687e66bSherry Moore (caddr_t)arg, sizeof (uint8_t), mode) != DDI_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EFAULT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel case ENVC_IOC_GETMODE: {
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint8_t curr_mode = unitp->current_mode;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_copyout((caddr_t)&curr_mode, (caddr_t)arg,
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (uint8_t), mode) != DDI_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EFAULT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel case ENVC_IOC_SETMODE: {
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint8_t curr_mode;
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_copyin((caddr_t)arg, (caddr_t)&curr_mode,
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (uint8_t), mode) != DDI_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EFAULT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (curr_mode == ENVCTRL_DIAG_MODE ||
193974072f41a843678abf5f61979c748687e66bSherry Moore curr_mode == ENVCTRL_NORMAL_MODE) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->current_mode = curr_mode; /* Don't do anything */
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /* Testing, may be removed */
03831d35f7499c87d51205817c93e9a8d42c4baestevel case I2CDEV_TRAN:
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (call_copyin((caddr_t)arg, unitp, mode) != I2C_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EFAULT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (nct_i2c_transfer(unitp->pcf8591_hdl, unitp->i2c_tran)
193974072f41a843678abf5f61979c748687e66bSherry Moore != I2C_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EFAULT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (call_copyout((caddr_t)arg, unitp, mode) != I2C_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EFAULT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * TESTING TRANSLATION from "adc" "table" property
03831d35f7499c87d51205817c93e9a8d42c4baestevel * translate thermistor index into temp Celcius
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel case I2CDEV_GETTEMP: {
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct i2c_transfer *tp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (call_copyin((caddr_t)arg, unitp, mode) != I2C_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EFAULT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel tp = unitp->i2c_tran;
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (tp->i2c_rlen != 1) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EINVAL;
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Throw away the first byte according to PCF8591 datasheet,
03831d35f7499c87d51205817c93e9a8d42c4baestevel * so read two bytes
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel tp->i2c_rlen = 2;
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (nct_i2c_transfer(unitp->pcf8591_hdl, unitp->i2c_tran)
193974072f41a843678abf5f61979c748687e66bSherry Moore != I2C_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EFAULT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel#ifdef DEBUG
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (pcf8591_debug & 0x0010)
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_NOTE,
193974072f41a843678abf5f61979c748687e66bSherry Moore "pcf8591_ioctl: i2c_rlen=%d; "
193974072f41a843678abf5f61979c748687e66bSherry Moore "i2c_rbuf[0,1]=0x%x,0x%x\n",
193974072f41a843678abf5f61979c748687e66bSherry Moore tp->i2c_rlen, tp->i2c_rbuf[0], tp->i2c_rbuf[1]);
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif /* DEBUG */
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Throw away the first byte according to PCF8591 datasheet
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((tp->i2c_rbuf[0] = translate_cputemp(tp->i2c_rbuf[1]))
193974072f41a843678abf5f61979c748687e66bSherry Moore == 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EINVAL;
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel tp->i2c_rbuf[1] = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (call_copyout((caddr_t)arg, unitp, mode) != I2C_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EFAULT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel case I2CDEV_GETTABLES: {
03831d35f7499c87d51205817c93e9a8d42c4baestevel break;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel default:
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EINVAL;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_enter(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_flags = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel cv_signal(&unitp->pcf8591_cv);
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (err);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_do_detach(dev_info_t *dip)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel register struct pcf8591_unit *unitp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int instance;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint_t attach_flag;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel instance = ddi_get_instance(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp = ddi_get_soft_state(pcf8591_soft_statep, instance);
03831d35f7499c87d51205817c93e9a8d42c4baestevel attach_flag = unitp->attach_flag;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (attach_flag & PCF8591_KSTAT_INIT) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel pcf8591_delete_kstats(unitp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (attach_flag & PCF8591_LOCK_INIT) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_destroy(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel cv_destroy(&unitp->pcf8591_cv);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Restore the lengths of the rbuf and wbuf, which was originally
03831d35f7499c87d51205817c93e9a8d42c4baestevel * allocated so that the appropriate amount of rbuf and wbuf are
03831d35f7499c87d51205817c93e9a8d42c4baestevel * freed.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (attach_flag & PCF8591_ALLOC_TRANSFER) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->i2c_tran->i2c_wlen = MAX_WLEN;
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->i2c_tran->i2c_rlen = MAX_RLEN;
03831d35f7499c87d51205817c93e9a8d42c4baestevel i2c_transfer_free(unitp->pcf8591_hdl, unitp->i2c_tran);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (attach_flag & PCF8591_REGISTER_CLIENT) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel i2c_client_unregister(unitp->pcf8591_hdl);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (attach_flag & PCF8591_MINORS_CREATED) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_remove_minor_node(dip, NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Free the memory allocated for the properties.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (attach_flag & PCF8591_PROPS_READ) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_prop_free(unitp->props.name);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (unitp->props.num_chans_used) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_prop_free(unitp->props.channels_in_use);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (unitp->props.channels_description) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_prop_free(unitp->props.channels_description);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (attach_flag & PCF8591_SOFT_STATE_ALLOC) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_soft_state_free(pcf8591_soft_statep, instance);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_SUCCESS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_do_suspend(dev_info_t *dip)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel int instance = ddi_get_instance(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct pcf8591_unit *unitp = (struct pcf8591_unit *)
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_get_soft_state(pcf8591_soft_statep, instance);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (unitp == NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (ENXIO);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Set the busy flag so that future transactions block
03831d35f7499c87d51205817c93e9a8d42c4baestevel * until resume.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_enter(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel while (unitp->pcf8591_flags == PCF8591_BUSY) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (cv_wait_sig(&unitp->pcf8591_cv,
193974072f41a843678abf5f61979c748687e66bSherry Moore &unitp->umutex) <= 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_flags = PCF8591_BUSY;
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_SUCCESS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_do_resume(dev_info_t *dip)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel int instance = ddi_get_instance(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct pcf8591_unit *unitp = (struct pcf8591_unit *)
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_get_soft_state(pcf8591_soft_statep, instance);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (unitp == NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (ENXIO);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_enter(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_flags = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel cv_signal(&unitp->pcf8591_cv);
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_SUCCESS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_do_attach(dev_info_t *dip)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel register struct pcf8591_unit *unitp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int i, instance;
03831d35f7499c87d51205817c93e9a8d42c4baestevel char name[MAXNAMELEN];
03831d35f7499c87d51205817c93e9a8d42c4baestevel minor_t minor;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel instance = ddi_get_instance(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_soft_state_zalloc(pcf8591_soft_statep, instance) != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp = ddi_get_soft_state(pcf8591_soft_statep, instance);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (unitp == NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->dip = dip;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->attach_flag = PCF8591_SOFT_STATE_ALLOC;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (pcf8591_read_props(unitp) != DDI_PROP_SUCCESS) {
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) pcf8591_do_detach(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->attach_flag |= PCF8591_PROPS_READ;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Set the current operating mode to NORMAL_MODE.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->current_mode = ENVCTRL_NORMAL_MODE; /* normal mode */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) snprintf(unitp->pcf8591_name, PCF8591_NAMELEN,
193974072f41a843678abf5f61979c748687e66bSherry Moore "%s%d", ddi_driver_name(dip), instance);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Create a minor node corresponding to channel 0 to 3
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (i = 0; i < PCF8591_MAX_CHANS; i++) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (i == 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel (void) sprintf(name, "cputemp");
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel (void) sprintf(name, "%d", i);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel minor = PCF8591_MINOR_NUM(instance, i);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_create_minor_node(dip, name, S_IFCHR, minor,
193974072f41a843678abf5f61979c748687e66bSherry Moore PCF8591_NODE_TYPE, NULL) == DDI_FAILURE) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_remove_minor_node(dip, NULL);
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) pcf8591_do_detach(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->attach_flag |= PCF8591_MINORS_CREATED;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (i2c_client_register(dip, &unitp->pcf8591_hdl)
193974072f41a843678abf5f61979c748687e66bSherry Moore != I2C_SUCCESS) {
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) pcf8591_do_detach(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->attach_flag |= PCF8591_REGISTER_CLIENT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * We allocate a single i2c_transfer_t structure for all
03831d35f7499c87d51205817c93e9a8d42c4baestevel * i2c transactions.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (i2c_transfer_alloc(unitp->pcf8591_hdl, &unitp->i2c_tran,
193974072f41a843678abf5f61979c748687e66bSherry Moore MAX_WLEN, MAX_RLEN, KM_SLEEP) != I2C_SUCCESS) {
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) pcf8591_do_detach(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->attach_flag |= PCF8591_ALLOC_TRANSFER;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The flags will be set to I2C_WR because for all reads from
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the 8591 we need to also write the control byte.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->i2c_tran->i2c_flags = I2C_WR;
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->i2c_tran->i2c_version = I2C_XFER_REV;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Set the analog programming mode to default. Upper nibble
03831d35f7499c87d51205817c93e9a8d42c4baestevel * in control byte. Four single ended inputs, output not enabled.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_inprog = PCF8591_4SINGLE | PCF8591_ANALOG_INPUT_EN;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Set the open flag for each channel to 0.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (i = 0; i < PCF8591_MAX_CHANS; i++) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_oflag[i] = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Set the busy flag to 0.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_flags = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_init(&unitp->umutex, NULL, MUTEX_DRIVER, NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel cv_init(&unitp->pcf8591_cv, NULL, CV_DRIVER, NULL);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->attach_flag |= PCF8591_LOCK_INIT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (pcf8591_add_kstats(unitp) != DDI_SUCCESS) {
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) pcf8591_do_detach(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->attach_flag |= PCF8591_KSTAT_INIT;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_report_dev(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_SUCCESS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/* ARGSUSED */
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel dev_t dev;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int instance;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (infocmd == DDI_INFO_DEVT2INSTANCE) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel dev = (dev_t)arg;
03831d35f7499c87d51205817c93e9a8d42c4baestevel instance = PCF8591_MINOR_TO_DEVINST(getminor(dev));
03831d35f7499c87d51205817c93e9a8d42c4baestevel *result = (void *)(uintptr_t)instance;
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_SUCCESS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel switch (cmd) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel case DDI_ATTACH:
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (pcf8591_do_attach(dip));
03831d35f7499c87d51205817c93e9a8d42c4baestevel case DDI_RESUME:
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (pcf8591_do_resume(dip));
03831d35f7499c87d51205817c93e9a8d42c4baestevel default:
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel switch (cmd) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel case DDI_DETACH:
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (pcf8591_do_detach(dip));
03831d35f7499c87d51205817c93e9a8d42c4baestevel case DDI_SUSPEND:
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (pcf8591_do_suspend(dip));
03831d35f7499c87d51205817c93e9a8d42c4baestevel default:
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic uint8_t
03831d35f7499c87d51205817c93e9a8d42c4baesteveltranslate_cputemp(uint8_t value)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (_cpu_temps[value]);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_add_kstats(struct pcf8591_unit *unitp)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel if ((unitp->tempksp = kstat_create(I2C_PCF8591_NAME,
193974072f41a843678abf5f61979c748687e66bSherry Moore unitp->instance, I2C_KSTAT_CPUTEMP, "misc",
193974072f41a843678abf5f61979c748687e66bSherry Moore KSTAT_TYPE_RAW, sizeof (unitp->temp_kstats),
193974072f41a843678abf5f61979c748687e66bSherry Moore KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_WRITABLE)) == NULL) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The kstat fields are already initialized in the attach routine..
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->tempksp->ks_update = pcf8591_temp_kstat_update;
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->tempksp->ks_private = (void *)unitp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) strcpy(unitp->temp_kstats.label,
193974072f41a843678abf5f61979c748687e66bSherry Moore unitp->props.channels_description[0]);
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->temp_kstats.type = ENVC_NETRACT_CPU_SENSOR;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel kstat_install(unitp->tempksp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_SUCCESS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic void
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_delete_kstats(struct pcf8591_unit *unitp)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel kstat_delete(unitp->tempksp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_temp_kstat_update(kstat_t *ksp, int rw)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel struct pcf8591_unit *unitp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel char *kstatp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int err = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int channel = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int warn_temp = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int shutdown_temp = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp = (struct pcf8591_unit *)ksp->ks_private;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_enter(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel while (unitp->pcf8591_flags == PCF8591_BUSY) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (cv_wait_sig(&unitp->pcf8591_cv,
193974072f41a843678abf5f61979c748687e66bSherry Moore &unitp->umutex) <= 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (EINTR);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_flags = PCF8591_BUSY;
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel kstatp = (char *)ksp->ks_data;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (rw == KSTAT_WRITE) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /* check for the size of buffer */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ksp->ks_data_size != sizeof (unitp->temp_kstats)) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EIO;
03831d35f7499c87d51205817c93e9a8d42c4baestevel goto bail;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel warn_temp = ((envctrl_temp_t *)kstatp)->warning_threshold;
03831d35f7499c87d51205817c93e9a8d42c4baestevel shutdown_temp = ((envctrl_temp_t *)kstatp)->shutdown_threshold;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (shutdown_temp < SHUTDOWN_TEMP_MIN || shutdown_temp >
193974072f41a843678abf5f61979c748687e66bSherry Moore SHUTDOWN_TEMP_MAX) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EIO;
03831d35f7499c87d51205817c93e9a8d42c4baestevel goto bail;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (warn_temp < 0 || shutdown_temp <= warn_temp) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel err = EIO;
03831d35f7499c87d51205817c93e9a8d42c4baestevel goto bail;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /* write into kstat fields */
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->temp_kstats.warning_threshold = warn_temp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->temp_kstats.shutdown_threshold = shutdown_temp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) pcf8591_read_chip(unitp, channel, 1);
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->temp_kstats.value =
193974072f41a843678abf5f61979c748687e66bSherry Moore unitp->i2c_tran->i2c_rbuf[0];
03831d35f7499c87d51205817c93e9a8d42c4baestevel bcopy((caddr_t)&unitp->temp_kstats, kstatp,
193974072f41a843678abf5f61979c748687e66bSherry Moore sizeof (unitp->temp_kstats));
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelbail:
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_enter(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->pcf8591_flags = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel cv_signal(&unitp->pcf8591_cv);
03831d35f7499c87d51205817c93e9a8d42c4baestevel mutex_exit(&unitp->umutex);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (err);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_read_chip(struct pcf8591_unit *unitp, uint8_t channel,
03831d35f7499c87d51205817c93e9a8d42c4baestevelint size)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel int retval = I2C_SUCCESS;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * We need to read an extra byte, since as per specification
03831d35f7499c87d51205817c93e9a8d42c4baestevel * the first byte read should be discarded.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel i2c_transfer_t *tp = unitp->i2c_tran;
03831d35f7499c87d51205817c93e9a8d42c4baestevel tp->i2c_flags = I2C_WR_RD;
03831d35f7499c87d51205817c93e9a8d42c4baestevel tp->i2c_rlen = size+1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel tp->i2c_wlen = 1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel tp->i2c_wbuf[0] = (unitp->pcf8591_inprog |
193974072f41a843678abf5f61979c748687e66bSherry Moore channel);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel retval = nct_i2c_transfer(unitp->pcf8591_hdl, tp);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (retval == I2C_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel tp->i2c_rbuf[0] = translate_cputemp(tp->i2c_rbuf[1]);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (tp->i2c_rbuf[0] == 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel retval = I2C_FAILURE;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (retval);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel/*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Reads the properties of the pcf8591 device.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevelstatic int
03831d35f7499c87d51205817c93e9a8d42c4baestevelpcf8591_read_props(struct pcf8591_unit *unitp)
03831d35f7499c87d51205817c93e9a8d42c4baestevel{
03831d35f7499c87d51205817c93e9a8d42c4baestevel dev_info_t *dip = unitp->dip;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int i, retval = 0, prop_len;
03831d35f7499c87d51205817c93e9a8d42c4baestevel int instance = ddi_get_instance(dip);
03831d35f7499c87d51205817c93e9a8d42c4baestevel int warning_temp, shutdown_temp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint32_t *prop_value = NULL;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uchar_t *creg_prop;
03831d35f7499c87d51205817c93e9a8d42c4baestevel char *function;
03831d35f7499c87d51205817c93e9a8d42c4baestevel uint_t tblsz;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#ifdef lint
03831d35f7499c87d51205817c93e9a8d42c4baestevel instance = instance;
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Check for the pcf8591_function property, and make sure it's
03831d35f7499c87d51205817c93e9a8d42c4baestevel * cputemp.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
193974072f41a843678abf5f61979c748687e66bSherry Moore "pcf8591_function", &function) != DDI_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel dbg_print(CE_WARN, "Couldn't find pcf8591_function property");
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (strcmp(function, "cputemp") != 0) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel dbg_print(CE_WARN, "pcf8591_function is not cputemp");
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_prop_free(function);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_FAILURE);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_prop_free(function);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel retval = ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
193974072f41a843678abf5f61979c748687e66bSherry Moore "name", &unitp->props.name);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (retval != DDI_PROP_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (retval);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel#ifdef DEBUG
03831d35f7499c87d51205817c93e9a8d42c4baestevel else if (pcf8591_debug & 0x02)
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_NOTE,
193974072f41a843678abf5f61979c748687e66bSherry Moore "pcf8591_read_props:ddi_prop_lookup_string(%s): \
03831d35f7499c87d51205817c93e9a8d42c4baestevel found %s ", "name", unitp->props.name);
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif /* DEBUG */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel retval = ddi_getlongprop(DDI_DEV_T_ANY, dip,
193974072f41a843678abf5f61979c748687e66bSherry Moore DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP,
193974072f41a843678abf5f61979c748687e66bSherry Moore "reg", (caddr_t)&prop_value, &prop_len);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (retval == DDI_PROP_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->props.i2c_bus = (uint16_t)prop_value[0];
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->props.slave_address = (uint16_t)prop_value[1];
03831d35f7499c87d51205817c93e9a8d42c4baestevel kmem_free(prop_value, prop_len);
03831d35f7499c87d51205817c93e9a8d42c4baestevel#ifdef DEBUG
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (pcf8591_debug & 0x02)
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_NOTE,
193974072f41a843678abf5f61979c748687e66bSherry Moore "pcf8591:ddi_getlongprop(%s) returns %d,"
193974072f41a843678abf5f61979c748687e66bSherry Moore " i2c_bus,slave=0x%x,0x%x",
193974072f41a843678abf5f61979c748687e66bSherry Moore "reg", retval, unitp->props.i2c_bus,
193974072f41a843678abf5f61979c748687e66bSherry Moore unitp->props.slave_address);
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif /* DEBUG */
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->props.i2c_bus = (uint16_t)-1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->props.slave_address = (uint16_t)-1;
03831d35f7499c87d51205817c93e9a8d42c4baestevel#ifdef DEBUG
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN,
193974072f41a843678abf5f61979c748687e66bSherry Moore "pcf8591_read_props:ddi_getlongprop(%s) returns %d,"
193974072f41a843678abf5f61979c748687e66bSherry Moore " default it to 0x%x:0x%X",
193974072f41a843678abf5f61979c748687e66bSherry Moore "reg", retval, unitp->props.i2c_bus,
193974072f41a843678abf5f61979c748687e66bSherry Moore unitp->props.slave_address);
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif /* DEBUG */
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
07d06da50d310a325b457d6330165aebab1e0064Surya Prakki (void) ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
193974072f41a843678abf5f61979c748687e66bSherry Moore "channels-in-use", &prop_len);
03831d35f7499c87d51205817c93e9a8d42c4baestevel retval = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY,
193974072f41a843678abf5f61979c748687e66bSherry Moore dip, DDI_PROP_DONTPASS,
193974072f41a843678abf5f61979c748687e66bSherry Moore "channels-in-use",
193974072f41a843678abf5f61979c748687e66bSherry Moore (uchar_t **)&unitp->props.channels_in_use,
193974072f41a843678abf5f61979c748687e66bSherry Moore &unitp->props.num_chans_used);
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (retval == DDI_PROP_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->props.num_chans_used /= sizeof (pcf8591_channel_t);
03831d35f7499c87d51205817c93e9a8d42c4baestevel } else {
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->props.num_chans_used = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#ifdef DEBUG
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (pcf8591_debug & 0x0002)
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_NOTE,
193974072f41a843678abf5f61979c748687e66bSherry Moore "pcf8591_read_props:ddi_prop_lookup_byte_array(%s)"
193974072f41a843678abf5f61979c748687e66bSherry Moore "returns %d\n"
193974072f41a843678abf5f61979c748687e66bSherry Moore "\t\tlength=%d, #elements=%d",
193974072f41a843678abf5f61979c748687e66bSherry Moore "channels-in-use", retval,
193974072f41a843678abf5f61979c748687e66bSherry Moore prop_len, unitp->props.num_chans_used);
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif /* DEBUG */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel retval = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
193974072f41a843678abf5f61979c748687e66bSherry Moore DDI_PROP_DONTPASS, "channels-description",
193974072f41a843678abf5f61979c748687e66bSherry Moore (char ***)&unitp->props.channels_description,
193974072f41a843678abf5f61979c748687e66bSherry Moore (uint_t *)&prop_len);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (retval != DDI_PROP_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel prop_len = 0;
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->props.channels_description = NULL;
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel#ifdef DEBUG
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (pcf8591_debug & 0x0002) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_NOTE,
193974072f41a843678abf5f61979c748687e66bSherry Moore "pcf8591_read_props:ddi_prop_lookup_string_array(%s)"
193974072f41a843678abf5f61979c748687e66bSherry Moore "returns %d, length=%d",
193974072f41a843678abf5f61979c748687e66bSherry Moore "channels-description", retval, prop_len);
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (i = 0; i < prop_len; ++i) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_NOTE, "channels-description[%d]=<%s>",
193974072f41a843678abf5f61979c748687e66bSherry Moore i, unitp->props.channels_description[i]);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif /* DEBUG */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * The following code was borrowed from envctrltwo.c
03831d35f7499c87d51205817c93e9a8d42c4baestevel * I haven't yet investigated why the copy target is index + 2
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel retval = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
193974072f41a843678abf5f61979c748687e66bSherry Moore DDI_PROP_DONTPASS, "tables", &creg_prop, (uint_t *)&prop_len);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (retval != DDI_PROP_SUCCESS) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel#ifdef DEBUG
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_WARN, "%s%d: Unable to read pcf8591 tables property",
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_get_name(dip), instance);
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif /* DEBUG */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_NOT_WELL_FORMED);
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel tblsz = (sizeof (_cpu_temps) / sizeof (uchar_t));
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (prop_len <= tblsz) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel for (i = 0; i < prop_len; i++) {
03831d35f7499c87d51205817c93e9a8d42c4baestevel _cpu_temps[i] = creg_prop[i];
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel }
03831d35f7499c87d51205817c93e9a8d42c4baestevel#ifdef DEBUG
03831d35f7499c87d51205817c93e9a8d42c4baestevel if (pcf8591_debug & 0x0002)
03831d35f7499c87d51205817c93e9a8d42c4baestevel cmn_err(CE_NOTE, "pcf8591_read_props: _cpu_temps size=%d; "
193974072f41a843678abf5f61979c748687e66bSherry Moore "tables prop_len=%d\n", tblsz, prop_len);
03831d35f7499c87d51205817c93e9a8d42c4baestevel#endif /* DEBUG */
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel ddi_prop_free(creg_prop);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Read shutdown temp and warning temp properties.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel warning_temp = (int)ddi_getprop(DDI_DEV_T_ANY, dip,
193974072f41a843678abf5f61979c748687e66bSherry Moore DDI_PROP_DONTPASS, "warning-temp", PCF8591_WARNING_TEMP);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel shutdown_temp = (int)ddi_getprop(DDI_DEV_T_ANY, dip,
193974072f41a843678abf5f61979c748687e66bSherry Moore DDI_PROP_DONTPASS, "shutdown-temp", PCF8591_SHUTDOWN_TEMP);
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel /*
03831d35f7499c87d51205817c93e9a8d42c4baestevel * Fill up the warning and shutdown temp values in kstat structure.
03831d35f7499c87d51205817c93e9a8d42c4baestevel */
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->temp_kstats.warning_threshold = warning_temp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel unitp->temp_kstats.shutdown_threshold = shutdown_temp;
03831d35f7499c87d51205817c93e9a8d42c4baestevel
03831d35f7499c87d51205817c93e9a8d42c4baestevel return (DDI_PROP_SUCCESS);
03831d35f7499c87d51205817c93e9a8d42c4baestevel}