/usr/src/uts/sun4u/io/envctrl_targets.c
C | 1127 lines | 641 code | 181 blank | 305 comment | 166 complexity | a89765b2c183f8cf7308409f3aea7bce MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, MPL-2.0-no-copyleft-exception, AGPL-3.0, BSD-3-Clause, GPL-2.0, LGPL-2.1, LGPL-3.0, AGPL-1.0, GPL-3.0, 0BSD, BSD-2-Clause
- /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
- /*
- * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
- #pragma ident "%Z%%M% %I% %E% SMI"
- /*
- * Low level environmental control routines.
- * These routines implement the I2C bus protocol.
- */
- #define EHC_SUCCESS 0
- #define EHC_FAILURE (-1)
- #define EHC_NO_SLAVE_ACK 3
- #define EHC_MAX_WAIT 100 /* decimal */
- #define EHC_S1_PIN 0x80
- #define EHC_S1_ES1 0x20
- #define EHC_S1_ES0 0x40
- #define EHC_S1_NBB 0x01
- #define EHC_S1_ACK 0x01
- #define EHC_S1_STA 0x04
- #define EHC_S1_STO 0x02
- #define EHC_S1_LRB 0x08
- #define EHC_S1_BER 0x10
- #define EHC_S1_LAB 0x02
- #define EHC_S1_AAS 0x04
- #define EHC_S1_AD0 0x08
- #define EHC_S1_STS 0x20
- #define EHC_S0_OWN 0x55
- #define EHC_S0_CLK 0x1d
- #define EHC_BYTE_READ 0x01
- #define EHC_LONGEST_MSG 200000 /* 200 ms */
- #define DUMMY_WRITE_ADDR 0x20
- #define DUMMY_WRITE_DATA 0x00
- /*
- * PCF8591 Chip Used for temperature sensors
- *
- * Addressing Register definition.
- * A0-A2 valid range is 0-7
- *
- * ------------------------------------------------
- * | 1 | 0 | 0 | 1 | A2 | A1 | A0 | R/W |
- * ------------------------------------------------
- */
- #define EHC_PCF8591_MAX_DEVS 0x08
- #define EHC_DEV0 0x00
- #define EHC_DEV1 0x02
- #define EHC_DEV2 0x04
- #define EHC_DEV3 0x06
- #define EHC_DEV4 0x08
- #define EHC_DEV5 0x0A
- #define EHC_DEV6 0x0C
- #define EHC_DEV7 0x0E
- /*
- * CONTROL OF CHIP
- * PCF8591 Temp sensing control register definitions
- *
- * ---------------------------------------------
- * | 0 | AOE | X | X | 0 | AIF | X | X |
- * ---------------------------------------------
- * AOE = Analog out enable.. not used on out implementation
- * 5 & 4 = Analog Input Programming.. see data sheet for bits..
- *
- * AIF = Auto increment flag
- * bits 1 & 0 are for the Chennel number.
- */
- #define EHC_PCF8591_ANALOG_OUTPUT_EN 0x40
- #define EHC_PCF8591_ANALOG_INPUT_EN 0x00
- #define EHC_PCF8591_READ_BIT 0x01
- #define EHC_PCF8591_AUTO_INCR 0x04
- #define EHC_PCF8591_OSCILATOR 0x40
- #define EHC_PCF8591_MAX_PORTS 0x04
- #define EHC_PCF8591_CH_0 0x00
- #define EHC_PCF8591_CH_1 0x01
- #define EHC_PCF8591_CH_2 0x02
- #define EHC_PCF8591_CH_3 0x03
- /*
- * PCF8574 Fan Fail, Power Supply Fail Detector
- * This device is driven by interrupts. Each time it interrupts
- * you must look at the CSR to see which ports caused the interrupt
- * they are indicated by a 1.
- *
- * Address map of this chip
- *
- * -------------------------------------------
- * | 0 | 1 | 1 | 1 | A2 | A1 | A0 | 0 |
- * -------------------------------------------
- *
- */
- #define EHC_PCF8574_PORT0 0x01
- #define EHC_PCF8574_PORT1 0x02
- #define EHC_PCF8574_PORT2 0x04
- #define EHC_PCF8574_PORT3 0x08
- #define EHC_PCF8574_PORT4 0x10
- #define EHC_PCF8574_PORT5 0x20
- #define EHC_PCF8574_PORT6 0x40
- #define EHC_PCF8574_PORT7 0x80
- /*
- * Defines for the PCF8583 Clock Calendar Chip.
- */
- #define EHC_PCF8583_READ_BIT 0x01
- struct ehc_pcd8584_regs {
- uint8_t s0; /* Own Address S0' */
- uint8_t s1; /* Control Status register */
- uint8_t clock_s2; /* Clock programming register */
- };
- struct ehc_envcunit {
- struct ehc_pcd8584_regs *bus_ctl_regs;
- ddi_acc_handle_t ctlr_handle;
- kmutex_t umutex;
- };
- int ehc_debug = 0;
- #define DCMN_ERR if (ehc_debug & 0x1) cmn_err
- #define DCMN2_ERR if (ehc_debug & 0x2) cmn_err
- /*
- * Prototypes for routines used in other modules.
- */
- void ehc_init_pcf8584(struct ehc_envcunit *);
- int ehc_read_tda8444(struct ehc_envcunit *ehcp);
- int ehc_write_tda8444(struct ehc_envcunit *, int, int, int, uint8_t *, int);
- int ehc_write_pcf8591(struct ehc_envcunit *, int, int, int, int, int,
- uint8_t *, int);
- int ehc_read_pcf8591(struct ehc_envcunit *, int, int, int, int, int,
- uint8_t *, int);
- int ehc_read_pcf8574a(struct ehc_envcunit *, int, uint8_t *, int);
- int ehc_write_pcf8574a(struct ehc_envcunit *, int, uint8_t *, int);
- int ehc_read_pcf8574(struct ehc_envcunit *, int, uint8_t *, int);
- int ehc_write_pcf8574(struct ehc_envcunit *, int, uint8_t *, int);
- int ehc_read_lm75(struct ehc_envcunit *, int, uint8_t *, int);
- int ehc_write_pcf8583(struct ehc_envcunit *, int, uint8_t *, int);
- /*
- * Prototypes for routines used only in this source module.
- */
- static int ehc_start_pcf8584(struct ehc_envcunit *, uint8_t);
- static void ehc_stop_pcf8584(struct ehc_envcunit *);
- static int ehc_read_pcf8584(struct ehc_envcunit *, uint8_t *);
- static int ehc_write_pcf8584(struct ehc_envcunit *, uint8_t);
- static int ehc_after_read_pcf8584(struct ehc_envcunit *, uint8_t *);
- /*
- * put host interface into master mode
- */
- static int
- ehc_start_pcf8584(struct ehc_envcunit *ehcp, uint8_t byteaddress)
- {
- uint8_t poll_status;
- uint8_t discard;
- int i;
- /* wait if bus is busy */
- i = 0;
- do {
- drv_usecwait(1000);
- poll_status =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
- i++;
- } while (((poll_status & EHC_S1_NBB) == 0) && i < EHC_MAX_WAIT);
- if (i == EHC_MAX_WAIT) {
- DCMN_ERR(CE_WARN, "ehc_start_pcf8584(): busy bit clear failed");
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_BER) {
- DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()1: Bus error");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_LAB) {
- DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()1: Lost Arbitration");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- /*
- * This is a dummy arbitration using the lowest unused address
- * possible. This step allows the PCF8584 to always win arbitration
- * except in the case of "general call" being issued by the other
- * master.
- */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, DUMMY_WRITE_ADDR);
- /* generate the "start condition" and clock out the slave address */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
- EHC_S1_PIN | EHC_S1_ES0 | EHC_S1_STA | EHC_S1_ACK);
- /* wait for completion of transmission */
- i = 0;
- do {
- drv_usecwait(1000);
- poll_status =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
- i++;
- } while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);
- if (i == EHC_MAX_WAIT) {
- DCMN_ERR(CE_WARN, "ehc_start_pcf8584_5(): read of S1 failed");
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_BER) {
- DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()5: Bus error");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_LAB) {
- DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()5: Lost Arbitration");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- /* dummy write */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, DUMMY_WRITE_DATA);
- /* wait for completion of transmission */
- i = 0;
- do {
- drv_usecwait(1000);
- poll_status =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
- i++;
- } while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);
- if (i == EHC_MAX_WAIT) {
- DCMN_ERR(CE_WARN, "ehc_start_pcf8584(): read of S1 failed");
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_BER) {
- DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()4: Bus error");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_LAB) {
- DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()4: Lost Arbitration");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- /*
- * generate the repeated "start condition" and
- * clock out the slave address
- */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
- EHC_S1_ES0 | EHC_S1_STA | EHC_S1_ACK);
- /* load the slave address */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, byteaddress);
- /* wait for completion of transmission */
- i = 0;
- do {
- drv_usecwait(1000);
- poll_status =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
- i++;
- } while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);
- if (i == EHC_MAX_WAIT) {
- DCMN_ERR(CE_WARN, "ehc_start_pcf8584(): read of S1 failed");
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_BER) {
- DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()2: Bus error");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_LAB) {
- DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()2: Lost Arbitration");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_LRB) {
- DCMN_ERR(CE_WARN, "ehc_start_pcf8584(): No slave ACK");
- return (EHC_NO_SLAVE_ACK);
- }
- /*
- * If this is a read we are setting up for (as indicated by
- * the least significant byte being set), read
- * and discard the first byte off the bus - this
- * is the slave address.
- */
- i = 0;
- if (byteaddress & EHC_BYTE_READ) {
- discard = ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);
- #ifdef lint
- discard = discard;
- #endif
- /* wait for completion of transmission */
- do {
- drv_usecwait(1000);
- poll_status =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
- i++;
- } while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);
- if (i == EHC_MAX_WAIT) {
- DCMN_ERR(CE_WARN,
- "ehc_start_pcf8584(): read of S1 failed");
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_BER) {
- DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()3: Bus error");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_LAB) {
- DCMN2_ERR(CE_WARN,
- "ehc_start_pcf8584()3: Lost Arbitration");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- }
- return (EHC_SUCCESS);
- }
- /*
- * put host interface into slave/receiver mode
- */
- static void
- ehc_stop_pcf8584(struct ehc_envcunit *ehcp)
- {
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
- EHC_S1_PIN | EHC_S1_ES0 | EHC_S1_STO | EHC_S1_ACK);
- }
- static int
- ehc_read_pcf8584(struct ehc_envcunit *ehcp, uint8_t *data)
- {
- uint8_t poll_status;
- int i = 0;
- /* Read the byte of interest */
- *data = ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);
- /* wait for completion of transmission */
- do {
- drv_usecwait(1000);
- poll_status =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
- i++;
- } while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);
- if (i == EHC_MAX_WAIT) {
- DCMN_ERR(CE_WARN, "ehc_read_pcf8584(): read of S1 failed");
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_BER) {
- DCMN2_ERR(CE_WARN, "ehc_read_pcf8584(): Bus error");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_LAB) {
- DCMN2_ERR(CE_WARN, "ehc_read_pcf8584(): Lost Arbitration");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- return (EHC_SUCCESS);
- }
- /*
- * host interface is in transmitter state, thus mode is master/transmitter
- * NOTE to Bill: this check the LRB bit (only done in transmit mode).
- */
- static int
- ehc_write_pcf8584(struct ehc_envcunit *ehcp, uint8_t data)
- {
- uint8_t poll_status;
- int i = 0;
- /* send the data, EHC_S1_PIN should go to "1" immediately */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, data);
- /* wait for completion of transmission */
- do {
- drv_usecwait(1000);
- poll_status =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
- i++;
- } while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);
- if (i == EHC_MAX_WAIT) {
- DCMN_ERR(CE_WARN, "ehc_write_pcf8584(): read of S1 failed");
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_BER) {
- DCMN2_ERR(CE_WARN, "ehc_write_pcf8584(): Bus error");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_LAB) {
- DCMN2_ERR(CE_WARN, "ehc_write_pcf8584(): Lost Arbitration");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_LRB) {
- DCMN_ERR(CE_WARN, "ehc_write_pcf8584(): No slave ACK");
- return (EHC_NO_SLAVE_ACK);
- }
- return (EHC_SUCCESS);
- }
- static int
- ehc_after_read_pcf8584(struct ehc_envcunit *ehcp, uint8_t *data)
- {
- uint8_t discard;
- uint8_t poll_status;
- int i = 0;
- /* set ACK in register S1 to 0 */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1, EHC_S1_ES0);
- /*
- * Read the "byte-before-the-last-byte" - sets PIN bit to '1'
- */
- *data = ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);
- /* wait for completion of transmission */
- do {
- drv_usecwait(1000);
- poll_status =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
- i++;
- } while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);
- if (i == EHC_MAX_WAIT) {
- DCMN_ERR(CE_WARN, "ehc_after_rd_pcf8584(): read of S1 failed");
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_BER) {
- DCMN2_ERR(CE_WARN, "ehc_after_rd_pcf8584(): Bus error");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (poll_status & EHC_S1_LAB) {
- DCMN2_ERR(CE_WARN, "ehc_after_rd_pcf8584(): Lost Arbitration");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- /*
- * Generate the "stop" condition.
- */
- ehc_stop_pcf8584(ehcp);
- /*
- * Read the "last" byte.
- */
- discard = ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);
- #ifdef lint
- discard = discard;
- #endif
- return (EHC_SUCCESS);
- }
- /*
- * Below this comment are the externally visible routines comprising the API
- */
- /*
- * Initialize the 8584 chip
- */
- void
- ehc_init_pcf8584(struct ehc_envcunit *ehcp)
- {
- /*
- * Writing PIN bit of S1 causes software reset.
- * The next write to S0 will be S0' "own address".
- */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1, EHC_S1_PIN);
- /*
- * Write the address which the controller chip will use
- * (when addressed as a slave) on the I2C bus.
- * DAF - should own address be passed as argument?
- */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, EHC_S0_OWN);
- /*
- * Writing PIN bit and ES1 bit of S1 causes software
- * reset and selects the S2 register for writing.
- * Now, the next write to S0 will be the S2 clock
- * control register.
- */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
- EHC_S1_PIN | EHC_S1_ES1);
- /*
- * Write the value into register that sets internal system clock
- * to 12 Mhz, and the I2C bus rate (SCL) to 9 Khz.
- * DAF - should these be parameters?
- */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, EHC_S0_CLK);
- /*
- * Writing PIN bit causes software reset and the ES0 bit
- * selects the (S0) register for reading/writing. The ACK
- * bit being set causes controller to send ACK after each
- * byte.
- */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
- EHC_S1_PIN | EHC_S1_ES0 | EHC_S1_ACK);
- /*
- * Multi-Master: Wait for a period of time equal to the
- * longest I2C message. This accounts for the case
- * where multiple controllers and, if this particular one
- * is "lagging", misses the BB (bus busy) condition.
- * DAF - What does this need?
- * We wait 200 ms since the longest transaction at this time
- * on the i2c bus is a 256 byte read from the seprom which takes
- * about 75 ms. Some additional buffer does no harm to the driver.
- */
- drv_usecwait(EHC_LONGEST_MSG);
- }
- int
- ehc_read_tda8444(struct ehc_envcunit *ehcp)
- {
- #ifdef lint
- ehcp = ehcp;
- #endif
- return (EHC_FAILURE);
- }
- /*
- * Write to the TDA8444 chip.
- * byteaddress = chip type base address | chip offset address.
- */
- int
- ehc_write_tda8444(struct ehc_envcunit *ehcp, int byteaddress, int instruction,
- int subaddress, uint8_t *buf, int size)
- {
- uint8_t control;
- int i, status;
- ASSERT((byteaddress & 0x1) == 0);
- ASSERT(subaddress < 8);
- ASSERT(instruction == 0xf || instruction == 0x0);
- ASSERT(MUTEX_HELD(&ehcp->umutex));
- control = (instruction << 4) | subaddress;
- if ((status = ehc_start_pcf8584(ehcp, byteaddress)) != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK) {
- /*
- * Send the "stop" condition.
- */
- ehc_stop_pcf8584(ehcp);
- }
- return (EHC_FAILURE);
- }
- if ((status = ehc_write_pcf8584(ehcp, control)) != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK) {
- /*
- * Send the "stop" condition.
- */
- ehc_stop_pcf8584(ehcp);
- }
- return (EHC_FAILURE);
- }
- for (i = 0; i < size; i++) {
- if ((status = ehc_write_pcf8584(ehcp, (buf[i] & 0x3f))) !=
- EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK)
- ehc_stop_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- }
- ehc_stop_pcf8584(ehcp);
- return (EHC_SUCCESS);
- }
- /*
- * Read from PCF8574A chip.
- * byteaddress = chip type base address | chip offset address.
- */
- int
- ehc_read_pcf8574a(struct ehc_envcunit *ehcp, int byteaddress, uint8_t *buf,
- int size)
- {
- int i;
- int status;
- uint8_t discard;
- ASSERT((byteaddress & 0x1) == 0);
- ASSERT(MUTEX_HELD(&ehcp->umutex));
- /*
- * Put the bus into the start condition
- */
- if ((status = ehc_start_pcf8584(ehcp, EHC_BYTE_READ | byteaddress)) !=
- EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK) {
- /*
- * Send the "stop" condition.
- */
- ehc_stop_pcf8584(ehcp);
- /*
- * Read the last byte - discard it.
- */
- discard =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);
- #ifdef lint
- discard = discard;
- #endif
- }
- return (EHC_FAILURE);
- }
- for (i = 0; i < size - 1; i++) {
- if ((status = ehc_read_pcf8584(ehcp, &buf[i])) != EHC_SUCCESS) {
- return (EHC_FAILURE);
- }
- }
- /*
- * Handle the part of the bus protocol which comes
- * after a read, including reading the last byte.
- */
- if (ehc_after_read_pcf8584(ehcp, &buf[i]) != EHC_SUCCESS) {
- return (EHC_FAILURE);
- }
- return (EHC_SUCCESS);
- }
- /*
- * Write to the PCF8574A chip.
- * byteaddress = chip type base address | chip offset address.
- */
- int
- ehc_write_pcf8574a(struct ehc_envcunit *ehcp, int byteaddress, uint8_t *buf,
- int size)
- {
- int i;
- int status;
- ASSERT((byteaddress & 0x1) == 0);
- ASSERT(MUTEX_HELD(&ehcp->umutex));
- /*
- * Put the bus into the start condition (write)
- */
- if ((status = ehc_start_pcf8584(ehcp, byteaddress)) != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK) {
- /*
- * Send the "stop" condition.
- */
- ehc_stop_pcf8584(ehcp);
- }
- return (EHC_FAILURE);
- }
- /*
- * Send the data - poll as needed.
- */
- for (i = 0; i < size; i++) {
- if ((status = ehc_write_pcf8584(ehcp, buf[i])) != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK)
- ehc_stop_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- }
- /*
- * Transmission complete - generate stop condition and
- * put device back into slave receiver mode.
- */
- ehc_stop_pcf8584(ehcp);
- return (EHC_SUCCESS);
- }
- /*
- * Read from the PCF8574 chip.
- * byteaddress = chip type base address | chip offset address.
- */
- int
- ehc_read_pcf8574(struct ehc_envcunit *ehcp, int byteaddress, uint8_t *buf,
- int size)
- {
- int i;
- int status;
- uint8_t discard;
- ASSERT((byteaddress & 0x1) == 0);
- ASSERT(MUTEX_HELD(&ehcp->umutex));
- /*
- * Put the bus into the start condition
- */
- if ((status = ehc_start_pcf8584(ehcp, EHC_BYTE_READ | byteaddress)) !=
- EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK) {
- /*
- * Send the "stop" condition.
- */
- ehc_stop_pcf8584(ehcp);
- /*
- * Read the last byte - discard it.
- */
- discard =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);
- #ifdef lint
- discard = discard;
- #endif
- }
- return (EHC_FAILURE);
- }
- for (i = 0; i < size - 1; i++) {
- if ((status = ehc_read_pcf8584(ehcp, &buf[i])) != EHC_SUCCESS) {
- return (EHC_FAILURE);
- }
- }
- /*
- * Handle the part of the bus protocol which comes
- * after a read.
- */
- if (ehc_after_read_pcf8584(ehcp, &buf[i]) != EHC_SUCCESS) {
- return (EHC_FAILURE);
- }
- return (EHC_SUCCESS);
- }
- /*
- * Write to the PCF8574 chip.
- * byteaddress = chip type base address | chip offset address.
- */
- int
- ehc_write_pcf8574(struct ehc_envcunit *ehcp, int byteaddress, uint8_t *buf,
- int size)
- {
- int i;
- int status;
- ASSERT((byteaddress & 0x1) == 0);
- ASSERT(MUTEX_HELD(&ehcp->umutex));
- /*
- * Put the bus into the start condition (write)
- */
- if ((status = ehc_start_pcf8584(ehcp, byteaddress)) != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK) {
- /*
- * Send the "stop" condition.
- */
- ehc_stop_pcf8584(ehcp);
- }
- return (EHC_FAILURE);
- }
- /*
- * Send the data - poll as needed.
- */
- for (i = 0; i < size; i++) {
- if ((status = ehc_write_pcf8584(ehcp, buf[i])) != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK)
- ehc_stop_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- }
- /*
- * Transmission complete - generate stop condition and
- * put device back into slave receiver mode.
- */
- ehc_stop_pcf8584(ehcp);
- return (EHC_SUCCESS);
- }
- /*
- * Read from the LM75
- * byteaddress = chip type base address | chip offset address.
- */
- int
- ehc_read_lm75(struct ehc_envcunit *ehcp, int byteaddress, uint8_t *buf,
- int size)
- {
- int i;
- int status;
- uint8_t discard;
- ASSERT((byteaddress & 0x1) == 0);
- ASSERT(MUTEX_HELD(&ehcp->umutex));
- /*
- * Put the bus into the start condition
- */
- if ((status = ehc_start_pcf8584(ehcp, EHC_BYTE_READ | byteaddress)) !=
- EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK) {
- /*
- * Send the stop condition.
- */
- ehc_stop_pcf8584(ehcp);
- /*
- * Read the last byte - discard it.
- */
- discard =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);
- #ifdef lint
- discard = discard;
- #endif
- }
- return (EHC_FAILURE);
- }
- for (i = 0; i < size - 1; i++) {
- if ((status = ehc_read_pcf8584(ehcp, &buf[i])) != EHC_SUCCESS) {
- return (EHC_FAILURE);
- }
- }
- /*
- * Handle the part of the bus protocol which comes
- * after a read.
- */
- if (ehc_after_read_pcf8584(ehcp, &buf[i]) != EHC_SUCCESS) {
- return (EHC_FAILURE);
- }
- return (EHC_SUCCESS);
- }
- /*
- * Write to the PCF8583 chip.
- * byteaddress = chip type base address | chip offset address.
- */
- int
- ehc_write_pcf8583(struct ehc_envcunit *ehcp, int byteaddress, uint8_t *buf,
- int size)
- {
- int i;
- int status;
- ASSERT((byteaddress & 0x1) == 0);
- ASSERT(MUTEX_HELD(&ehcp->umutex));
- if ((status = ehc_start_pcf8584(ehcp, byteaddress)) != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK) {
- /*
- * Send the "stop" condition.
- */
- ehc_stop_pcf8584(ehcp);
- }
- return (EHC_FAILURE);
- }
- /*
- * Send the data - poll as needed.
- */
- for (i = 0; i < size; i++) {
- if ((status = ehc_write_pcf8584(ehcp, buf[i])) != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK)
- ehc_stop_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- }
- /*
- * Transmission complete - generate stop condition and
- * put device back into slave receiver mode.
- */
- ehc_stop_pcf8584(ehcp);
- return (EHC_SUCCESS);
- }
- /*
- * Read from the PCF8591 chip.
- */
- int
- ehc_read_pcf8591(struct ehc_envcunit *ehcp, int byteaddress, int channel,
- int autoinc, int amode, int aenable, uint8_t *buf, int size)
- {
- int i;
- int status;
- register uint8_t control;
- uint8_t discard;
- ASSERT((byteaddress & 0x1) == 0);
- ASSERT(channel < 4);
- ASSERT(amode < 4);
- ASSERT(MUTEX_HELD(&ehcp->umutex));
- /*
- * Write the control word to the PCF8591.
- * Follow the control word with a repeated START byte
- * rather than a STOP so that reads can follow without giving
- * up the bus.
- */
- control = ((aenable << 6) | (amode << 4) | (autoinc << 2) | channel);
- if ((status = ehc_start_pcf8584(ehcp, byteaddress)) != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK) {
- ehc_stop_pcf8584(ehcp);
- }
- return (EHC_FAILURE);
- }
- if ((status = ehc_write_pcf8584(ehcp, control)) != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK)
- ehc_stop_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- /*
- * The following two operations, 0x45 to S1, and the byteaddress
- * to S0, will result in a repeated START being sent out on the bus.
- * Refer to Fig.8 of Philips Semiconductors PCF8584 product spec.
- */
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
- EHC_S1_ES0 | EHC_S1_STA | EHC_S1_ACK);
- ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0,
- EHC_BYTE_READ | byteaddress);
- i = 0;
- do {
- drv_usecwait(1000);
- status =
- ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
- i++;
- } while ((status & EHC_S1_PIN) && i < EHC_MAX_WAIT);
- if (i == EHC_MAX_WAIT) {
- DCMN_ERR(CE_WARN, "ehc_read_pcf8591(): read of S1 failed");
- return (EHC_FAILURE);
- }
- if (status & EHC_S1_BER) {
- DCMN2_ERR(CE_WARN, "ehc_read_pcf8591(): Bus error");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (status & EHC_S1_LAB) {
- DCMN2_ERR(CE_WARN, "ehc_read_pcf8591(): Lost Arbitration");
- ehc_init_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- if (status & EHC_S1_LRB) {
- DCMN_ERR(CE_WARN, "ehc_read_pcf8591(): No slave ACK");
- /*
- * Send the stop condition.
- */
- ehc_stop_pcf8584(ehcp);
- /*
- * Read the last byte - discard it.
- */
- discard = ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);
- #ifdef lint
- discard = discard;
- #endif
- return (EHC_FAILURE);
- }
- /*
- * Discard first read as per PCF8584 master receiver protocol.
- * This is normally done in the ehc_start_pcf8584() routine.
- */
- if ((status = ehc_read_pcf8584(ehcp, &discard)) != EHC_SUCCESS) {
- return (EHC_FAILURE);
- }
- /* Discard second read as per PCF8591 protocol */
- if ((status = ehc_read_pcf8584(ehcp, &discard)) != EHC_SUCCESS) {
- return (EHC_FAILURE);
- }
- for (i = 0; i < size - 1; i++) {
- if ((status = ehc_read_pcf8584(ehcp, &buf[i])) != EHC_SUCCESS) {
- return (EHC_FAILURE);
- }
- }
- if (ehc_after_read_pcf8584(ehcp, &buf[i]) != EHC_SUCCESS) {
- return (EHC_FAILURE);
- }
- return (EHC_SUCCESS);
- }
- /*
- * Write to the PCF8591 chip.
- * byteaddress = chip type base address | chip offset address.
- */
- int
- ehc_write_pcf8591(struct ehc_envcunit *ehcp, int byteaddress, int channel,
- int autoinc, int amode, int aenable, uint8_t *buf, int size)
- {
- int i, status;
- register uint8_t control;
- ASSERT((byteaddress & 0x1) == 0);
- ASSERT(MUTEX_HELD(&ehcp->umutex));
- control = ((aenable << 6) | (amode << 4) | (autoinc << 2) | channel);
- status = ehc_start_pcf8584(ehcp, byteaddress);
- if (status != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK) {
- /*
- * Send the "stop" condition.
- */
- ehc_stop_pcf8584(ehcp);
- }
- return (EHC_FAILURE);
- }
- if ((status = ehc_write_pcf8584(ehcp, control)) != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK)
- ehc_stop_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- for (i = 0; i < size; i++) {
- status = ehc_write_pcf8584(ehcp, buf[i]);
- if (status != EHC_SUCCESS) {
- if (status == EHC_NO_SLAVE_ACK)
- ehc_stop_pcf8584(ehcp);
- return (EHC_FAILURE);
- }
- }
- ehc_stop_pcf8584(ehcp);
- return (EHC_SUCCESS);
- }