/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#ifndef	_PCF8574_H
#define	_PCF8574_H

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#ifdef	__cplusplus
extern "C" {
#endif

#define	PCF8574_NODE_TYPE  "adc_i2c:gpio"
#define	I2C_PCF8574_NAME "gpio"

#define	I2C_KSTAT_CPUVOLTAGE 	"gpio_cpuvoltage"
#define	I2C_KSTAT_PWRSUPPLY  	"gpio_pwrsupply"
#define	I2C_KSTAT_FANTRAY		"gpio_fantray"

/*
 * PCF8574 ioctls for fantray and powersupplies.
 */

#define	ENVC_IOC_GETTEMP	0x10
#define	ENVC_IOC_SETFAN 	0x11
#define	ENVC_IOC_GETFAN 	0x12
#define	ENVC_IOC_GETSTATUS	0x15
#define	ENVC_IOC_GETTYPE	0x16
#define	ENVC_IOC_GETFAULT	0x17
#define	ENVC_IOC_PSTEMPOK	0x18
#define	ENVC_IOC_PSFANOK	0x1A
#define	ENVC_IOC_PSONOFF	0x1B
#define	ENVC_IOC_SETSTATUS	0x1C

#define	ENVC_IOC_INTRMASK	0x1D

#define	ENVCTRL_INTRMASK_SET	1
#define	ENVCTRL_INTRMASK_CLEAR	0

#define	ENVCTRL_FANSPEED_LOW	0
#define	ENVCTRL_FANSPEED_HIGH	1

/*
 * Could not find a definition for CPU voltage monitoring in Javelin
 * Code. So writing a structure here.
 */

typedef struct envctrl_cpuvoltage {
	int value;
} envctrl_cpuvoltage_t;

/*
 * ps_present and fan_present fields modified for FRU callback and status
 * See sys/scsb_cbi.h and definitions in scsb.c
 */
typedef struct envctrl_pwrsupply {
	scsb_fru_status_t ps_present; /* Is powersupply present */
	boolean_t ps_ok;	/* Is powersupply ok */
	boolean_t temp_ok;	/* Is temperature ok */
	boolean_t psfan_ok;	/* Is fan ok */
	boolean_t on_state;	/* Powersupply on/off */
	int ps_ver;			/* Pwr supply version and type */
} envctrl_pwrsupp_t;

typedef struct envctrl_fantray {
	scsb_fru_status_t fan_present;	/* fan1 present */
	boolean_t fan_ok;	/* fan1 ok */
	boolean_t fanspeed;		/* to set speed, input */
	int fan_ver;		/* Fan version and type */
} envctrl_fantray_t;

#ifdef	_KERNEL

#ifndef	I2CDEV_TRAN
#define	I2CDEV_TRAN 1
#endif

#define	PCF8574_MAX_DEVS	0x08
#define	PCF8574_MAX_CHANS	0x01
#define	PCF8574_BUSY		0x01
#define	PCF8574_NAMELEN		12
#define	PCF8574_INTR_ON		0x1
#define	PCF8574_INTR_ENABLED	0x2

#define	PCF8574_MINOR_TO_DEVINST(x) (((x) & 0x700) >> 8)
#define	PCF8574_MINOR_TO_CHANNEL(x) ((x) & 0x3)

#define	PCF8574_CHANNEL_TO_MINOR(x) ((x) & 0x3)
#define	PCF8574_DEVINST_TO_MINOR(x) ((x) << 8)


#define	PCF8574_TRAN_SIZE 1
#ifndef	PCF8574
#define	PCF8574 0
#endif

#ifndef	PCF8574A
#define	PCF8574A 1
#endif

#define	PCF8574_SET	('A' << 8)
#define	PCF8574_GET	('B' << 8)

#define	NUM_OF_PCF8574_DEVICES	8
#define	PCF8574_MAXPORTS	8

#define	PCF8574_TYPE_CPUVOLTAGE 	0
#define	PCF8574_TYPE_FANTRAY		1
#define	PCF8574_TYPE_PWRSUPP		2

#define	PCF8574_ADR_CPUVOLTAGE 	0x70
#define	PCF8574_ADR_PWRSUPPLY1 	0x7C
#define	PCF8574_ADR_PWRSUPPLY2 	0x7E
#define	PCF8574_ADR_FANTRAY1	0x74
#define	PCF8574_ADR_FANTRAY2	0x76

/*
 * 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	I2C_PCF8574_PORT0	0x01
#define	I2C_PCF8574_PORT1	0x02
#define	I2C_PCF8574_PORT2	0x04
#define	I2C_PCF8574_PORT3	0x08
#define	I2C_PCF8574_PORT4	0x10
#define	I2C_PCF8574_PORT5	0x20
#define	I2C_PCF8574_PORT6	0x40
#define	I2C_PCF8574_PORT7	0x80

#define	MAX_WLEN	64
#define	MAX_RLEN	64

/*
 * Following property information taken from the
 *   "SPARCengine ASM Reference Manual"
 * Property pointers are to DDI allocated space
 *  which must be freed in the detach() routine.
 */
/*
 * for pcf8574_properties_t.channels_in_use->io_dir
 */
#define	I2C_PROP_IODIR_IN	0
#define	I2C_PROP_IODIR_OUT	1
#define	I2C_PROP_IODIR_INOUT	2

/*
 * for pcf8574_properties_t.channels_in_use->type
 */
#define	I2C_PROP_TYPE_NOCARE	0
#define	I2C_PROP_TYPE_TEMP	1
#define	I2C_PROP_TYPE_VOLT	2
#define	I2C_PROP_TYPE_FANSTATS	3
#define	I2C_PROP_TYPE_FANSPEED	4

/*
 * These are now defined in sys/netract_gen.h
 *
 * #define	ENVC_IOC_GETMODE	0x1C
 * #define	ENVC_IOC_SETMODE	0x1D
 */


/*
 * Bit positions for the pcf8574 registers.
 */

#define	PCF8574_PS_TYPE(X) 		((X) & 0x3)
#define	PCF8574_PS_INTMASK(X) 	(((X) >> 2) & 0x1)
#define	PCF8574_PS_ONOFF(X)		(((X) >> 3)& 0x1)
#define	PCF8574_PS_FANOK(X)		(((X) >> 4) & 0x1)
#define	PCF8574_PS_TEMPOK(X)	(((X) >> 6) & 0x1)
#define	PCF8574_PS_FAULT(X)		(((X) >> 7) & 0x1)

#define	PCF8574_FAN_TYPE(X) 	((X) & 0x3)
#define	PCF8574_FAN_INTMASK(X)	(((X) >> 2) & 0x1)
#define	PCF8574_FAN_FANSPD(X)	(((X) >> 3) & 0x1)
#define	PCF8574_FAN_FAULT(X)	(((X) >> 7) & 0x1)

/* Constructs the reg byte from bit value */
#define	PCF8574_FAN_SPEED(bit)	((bit) << 3)
#define	PCF8574_INT_MASK(bit)	((bit) << 2)

/*
 * To tell the write_chip routine which bits to modify, a
 * 1 in the corresponding position selects that bit for
 * writing, a 0 ignores it.
 */
#define	PCF8574_FANSPEED_BIT	0x08
#define	PCF8574_INTRMASK_BIT	0x04

/*
 * Read and write masks for the fan and power supply.
 * These masks indicate which ports attached to the
 * PCF8574/A are input/output. We should construct the
 * read and writemasks from the channels-in-use property
 * for each pcf8574 device. In case the property is
 * absent, we can assign them with these default values.
 * While writing to the chip, we must or with the readmask,
 * else that port will be disabled.
 */

#define	PCF8574_FAN_WRITEMASK 0x0c
#define	PCF8574_FAN_READMASK  0xff
#define	PCF8574_PS_WRITEMASK  0x04
#define	PCF8574_PS_READMASK   0xff
#define	PCF8584_CPUVOLTAGE_WRITEMASK 0x88
#define	PCF8584_CPUVOLTAGE_READMASK  0x41

/*
 * Default values of the Fan and PS registers.
 * interrupt enabled.
 */
#define	PCF8574_FAN_DEFAULT 0xfb
#define	PCF8574_PS_DEFAULT  0xfb

#define	PCF8574_FAN_MASKINTR 0x04

#define	PCF8574_PS_MASKINTR	 0x04

#define	PCF8574_FAN_SPEED60  0x00
#define	PCF8574_FAN_SPEED100 0x80

#define	PCF8574_NUM_FANTRAY 2
#define	PCF8574_NUM_PWRSUPP 2

#define	PCF8574_FAN_SPEED_LOW  0
#define	PCF8574_FAN_SPEED_HIGH 1

/*
 * Stage of attachment.
 */
#define	PCF8574_SOFT_STATE_ALLOC	0x0001
#define	PCF8574_PROPS_READ		0x0002
#define	PCF8574_MINORS_CREATED		0x0004
#define	PCF8574_ALLOC_TRANSFER		0x0008
#define	PCF8574_REGISTER_CLIENT		0x0010
#define	PCF8574_LOCK_INIT		0x0020
#define	PCF8574_INTR_MUTEX		0x0040
#define	PCF8574_INTR_ADDED		0x0080
#define	PCF8574_KSTAT_INIT		0x0100

/*
 * PCF8574 ioctls for CPU Voltage (Nordica).
 */


typedef struct {
	uint8_t			port;
	uint8_t			io_dir;
	uint8_t			type;
	uint8_t			last_data;	/* N/A */
} pcf8574_channel_t;

typedef struct {
	char 			*name;
	uint16_t		i2c_bus;
	uint16_t		slave_address;
	uint_t			num_chans_used;
	char			**channels_description;
	pcf8574_channel_t	*channels_in_use;
} pcf8574_properties_t;

struct pcf8574_unit {
	kmutex_t		umutex;
	int				instance;
	dev_info_t		*dip;
	kcondvar_t		pcf8574_cv;
	i2c_transfer_t	*i2c_tran;
	i2c_client_hdl_t    pcf8574_hdl;
	char			pcf8574_name[PCF8574_NAMELEN];
	pcf8574_properties_t	props;
	uint8_t			pcf8574_flags;
	int				pcf8574_oflag;
	uint8_t			readmask;
	uint8_t			writemask;
	ddi_iblock_cookie_t	iblock;
	kmutex_t		intr_mutex;
	uint8_t			pcf8574_canintr;
	void 			*envctrl_kstat;
	uint8_t			current_mode;
	int				sensor_type;
	int				pcf8574_type;
	struct pollhead poll;
	int				poll_event;
	uint_t			attach_flag;
	kstat_t			*kstatp;
	int				i2c_status;
};

#endif	/* _KERNEL */

#ifdef	__cplusplus
}
#endif

#endif	/* _PCF8574_H */