예제 #1
0
/*
 * register ds1307 client device with i2c services, and
 * allocate & initialize soft state structure.
 */
static int
todds1307_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
    static ds1307_state_t	*statep = NULL;
    i2c_transfer_t	*i2c_tp = NULL;
    uint8_t tempVal = (uint8_t)0;
    switch (cmd) {

    case DDI_ATTACH:
        break;
    case DDI_RESUME:
        return (DDI_SUCCESS);
    default:
        return (DDI_FAILURE);
    }

    if (instance != -1) {
        return (DDI_FAILURE);
    }

    instance = ddi_get_instance(dip);

    /*
     * Allocate soft state structure
     */
    if (ddi_soft_state_zalloc(ds1307_statep, instance) != DDI_SUCCESS) {
        return (DDI_FAILURE);
    }

    statep = ddi_get_soft_state(ds1307_statep, instance);
    if (statep == NULL) {
        return (DDI_FAILURE);
    }

    statep->dip = dip;

    if (i2c_client_register(dip, &statep->ds1307_i2c_hdl) != I2C_SUCCESS) {
        ddi_soft_state_free(ds1307_statep, instance);
        delay(drv_usectohz(I2C_DELAY));
        return (DDI_FAILURE);
    }

    /* check and initialize the oscillator */

    (void) i2c_transfer_alloc(statep->ds1307_i2c_hdl,
                              &i2c_tp, 1, 1, I2C_SLEEP);
    i2c_tp->i2c_version = I2C_XFER_REV;
    i2c_tp->i2c_flags = I2C_WR_RD;
    i2c_tp->i2c_wbuf[0] = (uchar_t)0x00; /* Read 00h */
    i2c_tp->i2c_wlen = 1;
    i2c_tp->i2c_rlen = 1;

    if ((i2c_transfer(statep->ds1307_i2c_hdl, i2c_tp)) != I2C_SUCCESS) {
        (void) i2c_transfer_free(statep->ds1307_i2c_hdl, i2c_tp);
        ddi_soft_state_free(ds1307_statep, instance);
        delay(drv_usectohz(I2C_DELAY));
        return (DDI_FAILURE);
    }

    tempVal = i2c_tp->i2c_rbuf[0];

    (void) i2c_transfer_free(statep->ds1307_i2c_hdl, i2c_tp);

    if (tempVal & 0x80) {			 /* check Oscillator */
        (void) i2c_transfer_alloc(statep->ds1307_i2c_hdl, &i2c_tp,
                                  2, 1, I2C_SLEEP);
        i2c_tp->i2c_version = I2C_XFER_REV;
        i2c_tp->i2c_flags = I2C_WR;
        i2c_tp->i2c_wbuf[0] = 0x00;
        i2c_tp->i2c_wbuf[1] =
            (uchar_t)(i2c_tp->i2c_rbuf[0]& 0x7f);
        i2c_tp->i2c_wlen = 2;
        /* Enable oscillator */
        if ((i2c_transfer(statep->ds1307_i2c_hdl, i2c_tp))
                != I2C_SUCCESS) {
            (void) i2c_transfer_free(statep->ds1307_i2c_hdl,
                                     i2c_tp);
            ddi_soft_state_free(ds1307_statep, instance);
            return (DDI_FAILURE);
        }
        (void) i2c_transfer_free(statep->ds1307_i2c_hdl, i2c_tp);
    }

    /*
     * Create a periodical handler to read TOD.
     */
    ASSERT(statep->cycid == NULL);
    statep->cycid = ddi_periodic_add(todds1307_cyclic, &soft_rtc,
                                     i2c_cyclic_timeout, DDI_IPL_1);

    statep->state = TOD_ATTACHED;
    todds1307_attach_done = 1;
    ddi_report_dev(dip);

    return (DDI_SUCCESS);
}
예제 #2
0
static int
pca9556_attach(dev_info_t *dip)
{
	pca9556_unit_t 		*pcap;
	int 			instance = ddi_get_instance(dip);
	char			name[MAXNAMELEN];
	char *device_name;
	minor_t 		minor;
	int			i, num_ports;

	if (ddi_soft_state_zalloc(pca9556_soft_statep, instance) != 0) {
		cmn_err(CE_WARN, "%s%d failed to zalloc softstate",
		    ddi_get_name(dip), instance);
		return (DDI_FAILURE);
	}

	pcap = ddi_get_soft_state(pca9556_soft_statep, instance);

	if (pcap == NULL)
		return (DDI_FAILURE);

	mutex_init(&pcap->pca9556_mutex, NULL, MUTEX_DRIVER, NULL);
	cv_init(&pcap->pca9556_cv, NULL, CV_DRIVER, NULL);

	(void) snprintf(pcap->pca9556_name, sizeof (pcap->pca9556_name),
	    "%s_%d", ddi_driver_name(dip), instance);

	device_name = ddi_get_name(dip);

	if (strcmp(device_name, "i2c-pca9555") == 0) {
		num_ports = PCA9555_NUM_PORTS;
		pcap->pca9555_device = B_TRUE;
	} else {
		num_ports = PCA9556_NUM_PORTS;
		pcap->pca9555_device = B_FALSE;
		minor = INST_TO_MINOR(instance);
	}

	for (i = 0; i < num_ports; i++) {
		if (!(pcap->pca9555_device)) {
			(void) snprintf(pcap->pca9556_name,
			    sizeof (pcap->pca9556_name), "%s_%d",
			    ddi_driver_name(dip), instance);
			(void) snprintf(name, sizeof (name), "%s",
			    pcap->pca9556_name);
		} else {
			(void) sprintf(name, "port_%d", i);
			minor = INST_TO_MINOR(instance) |
			    PORT_TO_MINOR(I2C_PORT(i));
		}

		if (ddi_create_minor_node(dip, name, S_IFCHR, minor,
		    PCA9556_NODE_TYPE, NULL) == DDI_FAILURE) {
			cmn_err(CE_WARN, "%s: failed to create node for %s",
			    pcap->pca9556_name, name);
			pca9556_detach(dip);
			return (DDI_FAILURE);
		}
	}
	pcap->pca9556_flags |= PCA9556_MINORFLAG;

	/*
	 * Add a zero-length attribute to tell the world we support
	 * kernel ioctls (for layered drivers)
	 */
	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
	    DDI_KERNEL_IOCTL, NULL, 0);


	/*
	 * preallocate a single buffer for all reads and writes
	 */
	if (i2c_transfer_alloc(pcap->pca9556_hdl, &pcap->pca9556_transfer,
	    2, 2, I2C_SLEEP) != I2C_SUCCESS) {
		cmn_err(CE_WARN, "%s i2c_transfer_alloc failed",
		    pcap->pca9556_name);
		pca9556_detach(dip);
		return (DDI_FAILURE);
	}
	pcap->pca9556_flags |= PCA9556_TBUFFLAG;
	pcap->pca9556_transfer->i2c_version = I2C_XFER_REV;

	if (i2c_client_register(dip, &pcap->pca9556_hdl) != I2C_SUCCESS) {
		ddi_remove_minor_node(dip, NULL);
		cmn_err(CE_WARN, "%s i2c_client_register failed",
		    pcap->pca9556_name);
		pca9556_detach(dip);
		return (DDI_FAILURE);
	}
	pcap->pca9556_flags |= PCA9556_REGFLAG;

	/*
	 * Store the dip for future dip.
	 */
	pcap->pca9556_dip = dip;
	return (DDI_SUCCESS);
}