10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7656SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License"). 6*7656SSherry.Moore@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*7656SSherry.Moore@Sun.COM 220Sstevel@tonic-gate /* 23*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*7656SSherry.Moore@Sun.COM * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/stat.h> /* ddi_create_minor_node S_IFCHR */ 300Sstevel@tonic-gate #include <sys/modctl.h> /* for modldrv */ 310Sstevel@tonic-gate #include <sys/open.h> /* for open params. */ 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/kmem.h> 340Sstevel@tonic-gate #include <sys/sunddi.h> 350Sstevel@tonic-gate #include <sys/conf.h> /* req. by dev_ops flags MTSAFE etc. */ 360Sstevel@tonic-gate #include <sys/ddi.h> 370Sstevel@tonic-gate #include <sys/file.h> 380Sstevel@tonic-gate #include <sys/note.h> 390Sstevel@tonic-gate 400Sstevel@tonic-gate #include <sys/i2c/clients/ltc1427_impl.h> 410Sstevel@tonic-gate 420Sstevel@tonic-gate static void *ltc1427soft_statep; 430Sstevel@tonic-gate 440Sstevel@tonic-gate 450Sstevel@tonic-gate static int ltc1427_do_attach(dev_info_t *); 460Sstevel@tonic-gate static int ltc1427_do_detach(dev_info_t *); 470Sstevel@tonic-gate static int ltc1427_do_resume(void); 480Sstevel@tonic-gate static int ltc1427_do_suspend(void); 490Sstevel@tonic-gate 500Sstevel@tonic-gate /* 510Sstevel@tonic-gate * cb ops (only need ioctl) 520Sstevel@tonic-gate */ 530Sstevel@tonic-gate static int ltc1427_open(dev_t *, int, int, cred_t *); 540Sstevel@tonic-gate static int ltc1427_close(dev_t, int, int, cred_t *); 550Sstevel@tonic-gate static int ltc1427_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 560Sstevel@tonic-gate 570Sstevel@tonic-gate static struct cb_ops ltc1427_cbops = { 580Sstevel@tonic-gate ltc1427_open, /* open */ 590Sstevel@tonic-gate ltc1427_close, /* close */ 600Sstevel@tonic-gate nodev, /* strategy */ 610Sstevel@tonic-gate nodev, /* print */ 620Sstevel@tonic-gate nodev, /* dump */ 630Sstevel@tonic-gate nodev, /* read */ 640Sstevel@tonic-gate nodev, /* write */ 650Sstevel@tonic-gate ltc1427_ioctl, /* ioctl */ 660Sstevel@tonic-gate nodev, /* devmap */ 670Sstevel@tonic-gate nodev, /* mmap */ 680Sstevel@tonic-gate nodev, /* segmap */ 690Sstevel@tonic-gate nochpoll, /* poll */ 700Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 710Sstevel@tonic-gate NULL, /* streamtab */ 720Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 730Sstevel@tonic-gate CB_REV, /* rev */ 740Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 750Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 760Sstevel@tonic-gate }; 770Sstevel@tonic-gate 780Sstevel@tonic-gate /* 790Sstevel@tonic-gate * dev ops 800Sstevel@tonic-gate */ 810Sstevel@tonic-gate static int ltc1427_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 820Sstevel@tonic-gate static int ltc1427_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 830Sstevel@tonic-gate 840Sstevel@tonic-gate static struct dev_ops ltc1427_ops = { 850Sstevel@tonic-gate DEVO_REV, 860Sstevel@tonic-gate 0, 870Sstevel@tonic-gate ddi_getinfo_1to1, 880Sstevel@tonic-gate nulldev, 890Sstevel@tonic-gate nulldev, 900Sstevel@tonic-gate ltc1427_attach, 910Sstevel@tonic-gate ltc1427_detach, 920Sstevel@tonic-gate nodev, 930Sstevel@tonic-gate <c1427_cbops, 94*7656SSherry.Moore@Sun.COM NULL, 95*7656SSherry.Moore@Sun.COM NULL, 96*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 970Sstevel@tonic-gate }; 980Sstevel@tonic-gate 990Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate static struct modldrv ltc1427_modldrv = { 1020Sstevel@tonic-gate &mod_driverops, /* type of module - driver */ 103*7656SSherry.Moore@Sun.COM "LTC1427 i2c device driver: v1.8", 1040Sstevel@tonic-gate <c1427_ops 1050Sstevel@tonic-gate }; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate static struct modlinkage ltc1427_modlinkage = { 1080Sstevel@tonic-gate MODREV_1, 1090Sstevel@tonic-gate <c1427_modldrv, 1100Sstevel@tonic-gate 0 1110Sstevel@tonic-gate }; 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate int 1150Sstevel@tonic-gate _init(void) 1160Sstevel@tonic-gate { 1170Sstevel@tonic-gate int error; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate error = mod_install(<c1427_modlinkage); 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate if (!error) 1220Sstevel@tonic-gate (void) ddi_soft_state_init(<c1427soft_statep, 123*7656SSherry.Moore@Sun.COM sizeof (struct ltc1427_unit), 1); 1240Sstevel@tonic-gate return (error); 1250Sstevel@tonic-gate } 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate int 1280Sstevel@tonic-gate _fini(void) 1290Sstevel@tonic-gate { 1300Sstevel@tonic-gate int error; 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate error = mod_remove(<c1427_modlinkage); 1330Sstevel@tonic-gate if (!error) 1340Sstevel@tonic-gate ddi_soft_state_fini(<c1427soft_statep); 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate return (error); 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate int 1400Sstevel@tonic-gate _info(struct modinfo *modinfop) 1410Sstevel@tonic-gate { 1420Sstevel@tonic-gate return (mod_info(<c1427_modlinkage, modinfop)); 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate static int 1460Sstevel@tonic-gate ltc1427_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1470Sstevel@tonic-gate { 1480Sstevel@tonic-gate _NOTE(ARGUNUSED(credp)) 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate struct ltc1427_unit *unitp; 1510Sstevel@tonic-gate int instance; 1520Sstevel@tonic-gate int error = 0; 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate instance = getminor(*devp); 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate if (instance < 0) { 1570Sstevel@tonic-gate return (ENXIO); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate unitp = (struct ltc1427_unit *) 161*7656SSherry.Moore@Sun.COM ddi_get_soft_state(ltc1427soft_statep, instance); 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate if (unitp == NULL) { 1640Sstevel@tonic-gate return (ENXIO); 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate if (otyp != OTYP_CHR) { 1680Sstevel@tonic-gate return (EINVAL); 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate mutex_enter(&unitp->ltc1427_mutex); 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate if (flags & FEXCL) { 1740Sstevel@tonic-gate if (unitp->ltc1427_oflag != 0) { 1750Sstevel@tonic-gate error = EBUSY; 1760Sstevel@tonic-gate } else { 1770Sstevel@tonic-gate unitp->ltc1427_oflag = FEXCL; 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate } else { 1800Sstevel@tonic-gate if (unitp->ltc1427_oflag == FEXCL) { 1810Sstevel@tonic-gate error = EBUSY; 1820Sstevel@tonic-gate } else { 1830Sstevel@tonic-gate unitp->ltc1427_oflag = FOPEN; 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate mutex_exit(&unitp->ltc1427_mutex); 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate return (error); 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate static int 1930Sstevel@tonic-gate ltc1427_close(dev_t dev, int flags, int otyp, cred_t *credp) 1940Sstevel@tonic-gate { 1950Sstevel@tonic-gate _NOTE(ARGUNUSED(flags, otyp, credp)) 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate struct ltc1427_unit *unitp; 1980Sstevel@tonic-gate int instance; 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate instance = getminor(dev); 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate if (instance < 0) { 2030Sstevel@tonic-gate return (ENXIO); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate unitp = (struct ltc1427_unit *) 207*7656SSherry.Moore@Sun.COM ddi_get_soft_state(ltc1427soft_statep, instance); 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate if (unitp == NULL) { 2100Sstevel@tonic-gate return (ENXIO); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate mutex_enter(&unitp->ltc1427_mutex); 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate unitp->ltc1427_oflag = 0; 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate mutex_exit(&unitp->ltc1427_mutex); 2180Sstevel@tonic-gate return (DDI_SUCCESS); 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate static int 2220Sstevel@tonic-gate ltc1427_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 2230Sstevel@tonic-gate cred_t *credp, int *rvalp) 2240Sstevel@tonic-gate { 2250Sstevel@tonic-gate _NOTE(ARGUNUSED(credp, rvalp)) 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate struct ltc1427_unit *unitp; 2280Sstevel@tonic-gate int instance; 2290Sstevel@tonic-gate int err = 0; 2300Sstevel@tonic-gate i2c_transfer_t *i2c_tran_pointer; 2310Sstevel@tonic-gate int32_t fan_speed; 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate if (arg == NULL) { 2340Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "LTC1427: ioctl: arg passed in to ioctl " 235*7656SSherry.Moore@Sun.COM "= NULL\n")); 2360Sstevel@tonic-gate err = EINVAL; 2370Sstevel@tonic-gate return (err); 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate instance = getminor(dev); 2400Sstevel@tonic-gate unitp = (struct ltc1427_unit *) 241*7656SSherry.Moore@Sun.COM ddi_get_soft_state(ltc1427soft_statep, instance); 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate mutex_enter(&unitp->ltc1427_mutex); 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate switch (cmd) { 2460Sstevel@tonic-gate case I2C_GET_OUTPUT: 2470Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, "current_set_flag = %d\n", 248*7656SSherry.Moore@Sun.COM unitp->current_set_flag)); 2490Sstevel@tonic-gate if (unitp->current_set_flag == 0) { 2500Sstevel@tonic-gate err = EIO; 2510Sstevel@tonic-gate break; 2520Sstevel@tonic-gate } else { 2530Sstevel@tonic-gate if (ddi_copyout((caddr_t)&unitp->current_value, 254*7656SSherry.Moore@Sun.COM (caddr_t)arg, sizeof (int32_t), 255*7656SSherry.Moore@Sun.COM mode) != DDI_SUCCESS) { 2560Sstevel@tonic-gate D2CMN_ERR((CE_WARN, 2570Sstevel@tonic-gate "%s: Failed in I2C_GET_OUTPUT " 2580Sstevel@tonic-gate "ddi_copyout routine\n", 259*7656SSherry.Moore@Sun.COM unitp->ltc1427_name)); 2600Sstevel@tonic-gate err = EFAULT; 2610Sstevel@tonic-gate break; 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate break; 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate case I2C_SET_OUTPUT: 2670Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, (caddr_t)&fan_speed, 268*7656SSherry.Moore@Sun.COM sizeof (int32_t), mode) != DDI_SUCCESS) { 2690Sstevel@tonic-gate D2CMN_ERR((CE_WARN, 270*7656SSherry.Moore@Sun.COM "%s: Failed in I2C_SET_OUTPUT " 271*7656SSherry.Moore@Sun.COM "ioctl before switch\n", 272*7656SSherry.Moore@Sun.COM unitp->ltc1427_name)); 2730Sstevel@tonic-gate err = EFAULT; 2740Sstevel@tonic-gate break; 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate (void) i2c_transfer_alloc(unitp->ltc1427_hdl, 2780Sstevel@tonic-gate &i2c_tran_pointer, 2, 0, I2C_SLEEP); 2790Sstevel@tonic-gate if (i2c_tran_pointer == NULL) { 2800Sstevel@tonic-gate D2CMN_ERR((CE_WARN, 281*7656SSherry.Moore@Sun.COM "%s: Failed in I2C_SET_OUTPUT " 282*7656SSherry.Moore@Sun.COM "i2c_transfer_pointer not allocated\n", 283*7656SSherry.Moore@Sun.COM unitp->ltc1427_name)); 2840Sstevel@tonic-gate err = ENOMEM; 2850Sstevel@tonic-gate break; 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate i2c_tran_pointer->i2c_flags = I2C_WR; 2880Sstevel@tonic-gate i2c_tran_pointer->i2c_wbuf[0] = 2890Sstevel@tonic-gate (uchar_t)((fan_speed >> 8) & 0x03); 2900Sstevel@tonic-gate i2c_tran_pointer->i2c_wbuf[1] = 2910Sstevel@tonic-gate (uchar_t)((fan_speed) & 0x000000ff); 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate err = i2c_transfer(unitp->ltc1427_hdl, i2c_tran_pointer); 2940Sstevel@tonic-gate if (!err) { 2950Sstevel@tonic-gate unitp->current_value = fan_speed; 2960Sstevel@tonic-gate unitp->current_set_flag = 1; 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate i2c_transfer_free(unitp->ltc1427_hdl, i2c_tran_pointer); 2990Sstevel@tonic-gate break; 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate default: 3020Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "%s: Invalid IOCTL cmd: %x\n", 303*7656SSherry.Moore@Sun.COM unitp->ltc1427_name, cmd)); 3040Sstevel@tonic-gate err = EINVAL; 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate mutex_exit(&unitp->ltc1427_mutex); 3080Sstevel@tonic-gate return (err); 3090Sstevel@tonic-gate } 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate static int 3120Sstevel@tonic-gate ltc1427_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3130Sstevel@tonic-gate { 3140Sstevel@tonic-gate switch (cmd) { 3150Sstevel@tonic-gate case DDI_ATTACH: 3160Sstevel@tonic-gate return (ltc1427_do_attach(dip)); 3170Sstevel@tonic-gate case DDI_RESUME: 3180Sstevel@tonic-gate return (ltc1427_do_resume()); 3190Sstevel@tonic-gate default: 3200Sstevel@tonic-gate return (DDI_FAILURE); 3210Sstevel@tonic-gate } 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate static int 3250Sstevel@tonic-gate ltc1427_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3260Sstevel@tonic-gate { 3270Sstevel@tonic-gate switch (cmd) { 3280Sstevel@tonic-gate case DDI_DETACH: 3290Sstevel@tonic-gate return (ltc1427_do_detach(dip)); 3300Sstevel@tonic-gate case DDI_SUSPEND: 3310Sstevel@tonic-gate return (ltc1427_do_suspend()); 3320Sstevel@tonic-gate default: 3330Sstevel@tonic-gate return (DDI_FAILURE); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate static int 3380Sstevel@tonic-gate ltc1427_do_attach(dev_info_t *dip) 3390Sstevel@tonic-gate { 3400Sstevel@tonic-gate struct ltc1427_unit *unitp; 3410Sstevel@tonic-gate int instance; 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate instance = ddi_get_instance(dip); 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate if (ddi_soft_state_zalloc(ltc1427soft_statep, instance) != 0) { 3460Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: failed to zalloc softstate\n", 347*7656SSherry.Moore@Sun.COM ddi_get_name(dip), instance); 3480Sstevel@tonic-gate return (DDI_FAILURE); 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate unitp = ddi_get_soft_state(ltc1427soft_statep, instance); 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate if (unitp == NULL) { 3540Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: unitp not filled\n", 355*7656SSherry.Moore@Sun.COM ddi_get_name(dip), instance); 3560Sstevel@tonic-gate return (ENOMEM); 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate (void) snprintf(unitp->ltc1427_name, sizeof (unitp->ltc1427_name), 360*7656SSherry.Moore@Sun.COM "%s%d", ddi_node_name(dip), instance); 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate if (ddi_create_minor_node(dip, "ltc1427", S_IFCHR, instance, 363*7656SSherry.Moore@Sun.COM "ddi_i2c:adio", NULL) == DDI_FAILURE) { 3640Sstevel@tonic-gate cmn_err(CE_WARN, "%s ddi_create_minor_node failed for " 365*7656SSherry.Moore@Sun.COM "%s\n", unitp->ltc1427_name, "ltc1427"); 3660Sstevel@tonic-gate ddi_soft_state_free(ltc1427soft_statep, instance); 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate return (DDI_FAILURE); 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate if (i2c_client_register(dip, &unitp->ltc1427_hdl) != I2C_SUCCESS) { 3720Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 3730Sstevel@tonic-gate ddi_soft_state_free(ltc1427soft_statep, instance); 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate return (DDI_FAILURE); 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate mutex_init(&unitp->ltc1427_mutex, NULL, MUTEX_DRIVER, NULL); 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate return (DDI_SUCCESS); 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate static int 3840Sstevel@tonic-gate ltc1427_do_resume() 3850Sstevel@tonic-gate { 3860Sstevel@tonic-gate int ret = DDI_SUCCESS; 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate return (ret); 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate static int 3920Sstevel@tonic-gate ltc1427_do_suspend() 3930Sstevel@tonic-gate { 3940Sstevel@tonic-gate int ret = DDI_SUCCESS; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate return (ret); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate static int 4000Sstevel@tonic-gate ltc1427_do_detach(dev_info_t *dip) 4010Sstevel@tonic-gate { 4020Sstevel@tonic-gate struct ltc1427_unit *unitp; 4030Sstevel@tonic-gate int instance; 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate instance = ddi_get_instance(dip); 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate unitp = ddi_get_soft_state(ltc1427soft_statep, instance); 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate if (unitp == NULL) { 4100Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: unitp not filled\n", 411*7656SSherry.Moore@Sun.COM ddi_get_name(dip), instance); 4120Sstevel@tonic-gate return (ENOMEM); 4130Sstevel@tonic-gate } 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate i2c_client_unregister(unitp->ltc1427_hdl); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate mutex_destroy(&unitp->ltc1427_mutex); 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate ddi_soft_state_free(ltc1427soft_statep, instance); 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate return (DDI_SUCCESS); 4240Sstevel@tonic-gate } 425