/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2025 Oxide Computer Company
 */

#ifndef _SYS_I2C_I2C_H
#define	_SYS_I2C_I2C_H

/*
 * General i2c definitions that should be shared between both userland and the
 * kernel. Kernel device drivers include <sys/i2c/controller.h>,
 * <sys/i2c/mux.h>, or <sys/i2c/client.h> depending on the type of device they
 * are. Userland should generally use <libi2c.h> or <sys/i2c/ui2c.h> if it's the
 * implementation of libi2c.
 */

#include <sys/stdint.h>
#include <sys/stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Different allowed values for I2C and SMBus speeds. In the future, we'll
 * determine how I3C based options like different supported clock rates and
 * SDR/DDR fit in here.
 */
typedef enum {
	/*
	 * 100 kHz Standard operation.
	 */
	I2C_SPEED_STD	= 1 << 0,
	/*
	 * 400 kHz Fast-mode operation.
	 */
	I2C_SPEED_FAST	= 1 << 1,
	/*
	 * 1000 MHz Fast-mode plus operation.
	 */
	I2C_SPEED_FPLUS	= 1 << 2,
	/*
	 * 3400 MHz High-speed mode operation.
	 */
	I2C_SPEED_HIGH	= 1 << 3,
	/*
	 * 5000 MHz Ultra-Fast mode operation.
	 */
	I2C_SPEED_ULTRA	= 1 << 4
} i2c_speed_t;

/*
 * Different types of controllers.
 */
typedef enum {
	I2C_CTRL_TYPE_I2C = 1,
	I2C_CTRL_TYPE_I3C,
	I2C_CTRL_TYPE_SMBUS
} i2c_ctrl_type_t;

/*
 * This represents the series of errors that can be generated by the various I2C
 * APIs. These are grouped into several different units that cover behavior
 * specific to the core (impacting everything) to properties, user-specific
 * behavior, kernel driver clients, etc.
 */
typedef enum {
	I2C_CORE_E_OK	= 0,
	/*
	 * Indicates that the controller I/O failed. The reason is specified in
	 * the controller error.
	 */
	I2C_CORE_E_CONTROLLER,
	/*
	 * The following pair indicate that a given address class or value for
	 * an address within a valid address class are wrong.
	 */
	I2C_CORE_E_BAD_ADDR_TYPE,
	I2C_CORE_E_BAD_ADDR,
	/*
	 * This indicates that the requested address type, while valid, is not
	 * supported. For example, trying to send to a 10-bit address on a
	 * controller that does not support it.
	 */
	I2C_CORE_E_UNSUP_ADDR_TYPE,
	/*
	 * Indicates that the address in question is reserved by a corresponding
	 * specification.
	 */
	I2C_CORE_E_ADDR_RSVD,
	/*
	 * Indicates that the address in question is already in use and
	 * therefore cannot be used.
	 */
	I2C_CORE_E_ADDR_IN_USE,
	/*
	 * Indicates that the address could be used, but it has exceeded the
	 * per-address usage count. This usually represents a place where the
	 * kernel can be improved.
	 */
	I2C_CORE_E_ADDR_REFCNT,
	/*
	 * Indicates that there is no device with the specified address.
	 */
	I2C_CORE_E_UNKNOWN_ADDR,
	/*
	 * Indicates that the request type can't be translated to something the
	 * underlying controller actually supports. For example, this would
	 * cover trying to translate certain kinds of I2C requests to an SMBus
	 * controller that supports limited types of operations or vice versa.
	 */
	I2C_CORE_E_CANT_XLATE_REQ,
	/*
	 * This indicates that a request had neither a read nor a write and
	 * therefore cannot continue. This constraint on I/O may be lifted in
	 * the future.
	 */
	I2C_CORE_E_NEED_READ_OR_WRITE,
	/*
	 * These indicate that invalid flags values, an invalid read length, or
	 * invalid write length was encountered.
	 */
	I2C_CORE_E_BAD_I2C_REQ_FLAGS,
	I2C_CORE_E_BAD_I2C_REQ_READ_LEN,
	I2C_CORE_E_BAD_I2C_REQ_WRITE_LEN,
	/*
	 * These indicate similar situations in the SMBus request field.
	 */
	I2C_CORE_E_BAD_SMBUS_REQ_FLAGS,
	I2C_CORE_E_BAD_SMBUS_READ_LEN,
	I2C_CORE_E_BAD_SMBUS_WRITE_LEN,
	I2C_CORE_E_BAD_SMBUS_OP,
	/*
	 * Indicates that the controller does not support the requested SMBus
	 * operation.
	 */
	I2C_CORE_E_UNSUP_SMBUS_OP,
	/*
	 * Indicates that the controller is already owned by someone and the
	 * caller asked not to block.
	 */
	I2C_CORE_E_LOCK_WOULD_BLOCK,
	/*
	 * Indicates that the caller took a signal while waiting to acquire the
	 * controller.
	 */
	I2C_CORE_E_LOCK_WAIT_SIGNAL,
	/*
	 * Indicates that a passed in nvlist was larger than the maximum value.
	 */
	I2C_IOCTL_E_NVL_TOO_BIG = 0x1000,
	/*
	 * Indicates that the nvlist was not parseable.
	 */
	I2C_IOCTL_E_NVL_INVALID,
	/*
	 * Indicates that the nvlist contained missing keys, keys that we don't
	 * know how to handle, and keys that are the wrong type. If this gets
	 * much more complex, the interface should change to the kgpio error
	 * style where there is an additional nvlist there.
	 */
	I2C_IOCTL_E_NVL_KEY_MISSING,
	I2C_IOCTL_E_NVL_KEY_UNKNOWN,
	I2C_IOCTL_E_NVL_KEY_BAD_TYPE,
	/*
	 * Indicates that a pointer to user data inside of an ioctl (not the
	 * overall ioctl itself) was not valid and generated a fault.
	 */
	I2C_IOCTL_E_BAD_USER_DATA,
	/*
	 * Indicates that there was no kernel memory available for the request.
	 */
	I2C_IOCTL_E_NO_KERN_MEM,
	/*
	 * Indicates that a string that is being used for a device name or
	 * compatible array contains illegal characters or is too long.
	 */
	I2C_IOCTL_E_BAD_DEV_NAME,
	/*
	 * Indicates that the length of the compatible range is longer than the
	 * system will allow to be set.
	 */
	I2C_IOCTL_E_COMPAT_LEN_RANGE,
	/*
	 * Indicates that something went wrong with trying to deal with nexus
	 * related operations on a child.
	 */
	I2C_IOCTL_E_NEXUS,
	/*
	 * Indicates that a nexus operations was attempted while trying to hold
	 * a bus lock.
	 */
	I2C_IOCTL_E_NO_BUS_LOCK_NEXUS,
	/*
	 * Indicates that an ioctl operation could not be started because the
	 * client in question already has one in flight that requires the
	 * controller lock.
	 */
	I2C_IOCTL_E_IN_PROGRESS,
	/*
	 * Indicates that the passed dev_info_t does not correspond to an i2c
	 * device.
	 */
	I2C_CLIENT_E_BAD_DIP = 0x2000,
	/*
	 * Indicates that the regs[] index is invalid for the device.
	 */
	I2C_CLIENT_E_BAD_REG_IDX,
	/*
	 * Indicates that the specific set of flags are invalid.
	 */
	I2C_CLIENT_E_BAD_CLAIM_FLAGS,
	I2C_CLIENT_E_BAD_IO_FLAGS,
	I2C_CLIENT_E_BAD_LOCK_FLAGS,
	/*
	 * Indicates that the caller was interrupted while trying to get access
	 * to the client for I/O.
	 */
	I2C_CLIENT_E_SIGNAL,
	/*
	 * Thee indicate that there are invalid values in the various register
	 * access attributes.
	 */
	I2C_CLIENT_E_BAD_REG_ATTR_VERS,
	I2C_CLIENT_E_BAD_REG_ATTR_FLAGS,
	I2C_CLIENT_E_BAD_REG_ATTR_RLEN,
	I2C_CLIENT_E_BAD_REG_ATTR_ALEN,
	I2C_CLIENT_E_BAD_REG_ATTR_ENDIAN,
	I2C_CLIENT_E_BAD_REG_ATTR_MAX,
	/*
	 * Indicates that while the register attributes are supported, the
	 * underlying hardware cannot support them.
	 */
	I2C_CLIENT_E_REG_ALEN_UNSUP_BY_CTRL,
	/*
	 * These indicate that I2C register operations were passed invalid
	 * values or that these values would lead to an overflow.
	 */
	I2C_CLIENT_E_BAD_REG_ADDR,
	I2C_CLIENT_E_BAD_REG_COUNT,
	I2C_CLIENT_E_REG_ADDR_OVERFLOW,
	I2C_CLIENT_E_REG_IO_TOO_LARGE,
	/*
	 * Indicates that the size in bytes is a partial number of registers.
	 */
	I2C_CLIENT_E_PARTIAL_REG,
	/*
	 * Indicates that the client has tried to claim a shared address, but
	 * they actually own the address directly.
	 */
	I2C_CLIENT_E_CLAIM_OWNED_ADDR,
	/*
	 * These two indicate that the property is unsupported by the device or
	 * a property ID that is unknown by the system.
	 */
	I2C_PROP_E_UNSUP = 0x3000,
	I2C_PROP_E_UNKNOWN,
	/*
	 * Indicates that the property can't be written to because it is
	 * read-only.
	 */
	I2C_PROP_E_READ_ONLY,
	/*
	 * Indicates that the property buffer is too small. The second indicates
	 * that the property buffer is too large and doesn't make sense for the
	 * property. The latter is only relevant when setting a property. The
	 * former can be triggered in all property interfaces.
	 */
	I2C_PROP_E_SMALL_BUF,
	I2C_PROP_E_TOO_BIG_BUF,
	/*
	 * Indicates that the property value is invalid.
	 */
	I2C_PROP_E_BAD_VAL,
	/*
	 * Indicates that the controller doesn't support setting properties.
	 */
	I2C_PROP_E_SET_UNSUP,
	/*
	 * Indicates that the mux flag is unknown.
	 */
	I2C_MUX_E_BAD_FLAG = 0x4000
} i2c_errno_t;

/*
 * These represent errors that the controller generates and/or detects while
 * attempting to perform I/O. Some controllers provide relatively rich
 * diagnostics as to what went wrong. Others, provide only generic classes of
 * errors. Try to use the most specific error possible.
 */
typedef enum {
	I2C_CTRL_E_OK = 0,
	/*
	 * This is a generic class that represents something happened internal
	 * to the controller. In general, this should be used sparingly and only
	 * for something that only makes semantic sense on a single controller.
	 * This should not be a property of something related to I2C/SMBus/I3C
	 * directly.
	 */
	I2C_CTRL_E_INTERNAL,
	/*
	 * This is a variant of the above that indicates a driver programming
	 * error violated a controller condition.
	 */
	I2C_CTRL_E_DRIVER,
	/*
	 * Indicates that the controller was given a type of command that it
	 * does not support. For example, an SMBus 1.0 controller given an SMBus
	 * 2.0 command. The framework generally is the only tying that will
	 * return this error as drivers should not have to encounter them.
	 */
	I2C_CTRL_E_UNSUP_CMD,
	/*
	 * Indicates that prior to trying to perform the operation, the
	 * controller detected that the bus was busy and after a timeout was
	 * unable to get control of the bus.
	 */
	I2C_CTRL_E_BUS_BUSY,
	/*
	 * This error indicates that there was a no acknowledgement condition.
	 * This should be used both for 7-bit and 10-bit cases. Similarly, for
	 * now this should also be used for cases where no one acknowledges a
	 * general call.
	 */
	I2C_CTRL_E_ADDR_NACK,
	/*
	 * This is a variant on the address NACK. This is used when the address
	 * has been acknowledged, but subsequent data has not been. Some devices
	 * may not be able to make the distinction. If they cannot, use the
	 * catch-all NACK below.
	 */
	I2C_CTRL_E_DATA_NACK,
	/*
	 * This is a case where no NACK occurred, but the controller cannot be
	 * more specific as to where in the process it occurred.
	 */
	I2C_CTRL_E_NACK,
	/*
	 * Indicates that the controller lost arbitration on the bus. A common
	 * cause for this is a data collision.
	 */
	I2C_CTRL_E_ARB_LOST,
	/*
	 * Indicates that a device incorrectly issued an ACK when it was not
	 * expected in the operation.
	 */
	I2C_CTRL_E_BAD_ACK,
	/*
	 * Indicates that the controller failed to successfully finish
	 * transmitting the command within the default request timeout. This
	 * results in the controller aborting the command. Callers cannot assume
	 * anything about the number of bytes that made it out onto the bus.
	 */
	I2C_CTRL_E_REQ_TO,
	/*
	 * Indicates that an SMBus device returned a block read length that
	 * could not be supported by the device or is illegal according to the
	 * specification. For example, a 0 byte length or a length exceeding 32
	 * bytes for an SMBus 2.0 controller.
	 */
	I2C_CTRL_E_BAD_SMBUS_RLEN,
	/*
	 * Indicates that an SMBus device held the clock low for too long to
	 * effectively trime out the transaction. This is different from the
	 * request timeout as it indicates something the target did.
	 */
	I2C_CTRL_E_SMBUS_CLOCK_LOW
} i2c_ctrl_error_t;

typedef struct {
	i2c_errno_t i2c_error;
	i2c_ctrl_error_t i2c_ctrl;
} i2c_error_t;

/*
 * General maximum length for an i2c related name, including the NUL.
 */
#define	I2C_NAME_MAX	32

typedef enum i2c_addr_type {
	I2C_ADDR_7BIT = 0,
	I2C_ADDR_10BIT
} i2c_addr_type_t;

/*
 * This represents the general form of our i2c addresses and what the nexus will
 * give client devices and drivers in the form of regs[].
 */
typedef struct i2c_addr {
	uint16_t ia_type;
	uint16_t ia_addr;
} i2c_addr_t;

/*
 * This indicates where an address came from.
 */
typedef enum i2c_addr_source {
	/*
	 * Indicates that this came from the devices reg[] array. It was either
	 * put there as part of discovering information about the system by the
	 * platform (e.g. ACPI, device tree, etc.) or based on a user's specific
	 * device creation.
	 */
	I2C_ADDR_SOURCE_REG = 1,
	/*
	 * Indicates that the address was one that the driver claimed.
	 */
	I2C_ADDR_SOURCE_CLAIMED,
	/*
	 * Indicates that the address was one that the driver claimed and is
	 * shared across multiple instances.
	 */
	I2C_ADDR_SOURCE_SHARED
} i2c_addr_source_t;

/*
 * Well-known and other special addresses. I2C reserves several addresses for
 * special purposes. SMBus has a more extensive of nominal assignments, but
 * things definitely stomp in that space.
 */
typedef enum {
	I2C_RSVD_ADDR_GEN_CALL	= 0x00,
	I2C_RSVD_ADDR_C_BUS	= 0x01,
	I2C_RSVD_ADDR_DIFF_BUS	= 0x02,
	I2C_RSVD_ADDR_FUTURE	= 0x03,
	I2C_RSVD_ADDR_HS_0	= 0x04,
	I2C_RSVD_ADDR_HS_1	= 0x05,
	I2C_RSVD_ADDR_HS_2	= 0x06,
	I2C_RSVD_ADDR_HS_3	= 0x07,
	I2C_RSVD_ADDR_10B_0	= 0x78,
	I2C_RSVD_ADDR_10B_1	= 0x79,
	I2C_RSVD_ADDR_10B_2	= 0x7a,
	I2C_RSVD_ADDR_10B_3	= 0x7b,
	I2C_RSVD_ADDR_DID_0	= 0x7c,
	I2C_RSVD_ADDR_DID_1	= 0x7d,
	I2C_RSVD_ADDR_DID_2	= 0x7e,
	I2C_RSVD_ADDR_DID_3	= 0x7f
} i2c_rsvd_addr_t;

/*
 * SMBus 2.0 controllers have a maximum byte size of 32 bytes. SMBus 3.0
 * increases that to a maximum of 255 bytes. As such we size our maximum request
 * sizes at 256 bytes in our structures.
 */
#define	SMBUS_V2_MAX_BLOCK	32
#define	SMBUS_V3_MAX_BLOCK	255
#define	I2C_REQ_MAX		256

typedef enum smbus_op {
	SMBUS_OP_QUICK_COMMAND,
	SMBUS_OP_SEND_BYTE,
	SMBUS_OP_RECV_BYTE,
	SMBUS_OP_WRITE_BYTE,
	SMBUS_OP_READ_BYTE,
	SMBUS_OP_WRITE_WORD,
	SMBUS_OP_READ_WORD,
	SMBUS_OP_PROCESS_CALL,
	SMBUS_OP_WRITE_BLOCK,
	SMBUS_OP_READ_BLOCK,
	/* Added in SMBUS 2.0 */
	SMBUS_OP_HOST_NOTIFY,
	SMBUS_OP_BLOCK_PROCESS_CALL,
	/* Added in SMBUS 3.x */
	SMBUS_OP_WRITE_U32,
	SMBUS_OP_READ_U32,
	SMBUS_OP_WRITE_U64,
	SMBUS_OP_READ_U64,
	/* I2C Compatibility */
	SMBUS_OP_I2C_WRITE_BLOCK,
	SMBUS_OP_I2C_READ_BLOCK
} smbus_op_t;

typedef enum {
	/*
	 * Indicates that regardless of whether or not interrupts are supported,
	 * this request should be polled.
	 */
	I2C_IO_REQ_F_POLL		= 1 << 0,
	/*
	 * Indicates that this zero-byte I/O quick command is a write. If this
	 * flag is not set then a quick command is a read.
	 */
	I2C_IO_REQ_F_QUICK_WRITE	= 1 << 1,
} i2c_req_flags_t;

typedef struct smbus_req {
	i2c_error_t smbr_error;
	smbus_op_t smbr_op;
	i2c_req_flags_t smbr_flags;
	i2c_addr_t smbr_addr;
	uint16_t smbr_wlen;
	uint16_t smbr_rlen;
	uint8_t smbr_cmd;
	uint8_t smbr_wdata[I2C_REQ_MAX];
	uint8_t smbr_rdata[I2C_REQ_MAX];
} smbus_req_t;

typedef struct i2c_req {
	i2c_error_t ir_error;
	i2c_req_flags_t ir_flags;
	i2c_addr_t ir_addr;
	uint16_t ir_wlen;
	uint16_t ir_rlen;
	uint8_t ir_wdata[I2C_REQ_MAX];
	uint8_t ir_rdata[I2C_REQ_MAX];
} i2c_req_t;

typedef enum i2c_prop_type {
	/*
	 * A property that is a standard, scalar uint32_t.
	 */
	I2C_PROP_TYPE_U32,
	/*
	 * A property that fits in a uint32_t, but represents a bitfield of
	 * values.
	 */
	I2C_PROP_TYPE_BIT32
} i2c_prop_type_t;

typedef enum i2c_prop_perm {
	I2C_PROP_PERM_RO,
	I2C_PROP_PERM_RW
} i2c_prop_perm_t;

typedef struct i2c_prop_u32_range {
	uint32_t ipur_min;
	uint32_t ipur_max;
} i2c_prop_u32_range_t;

typedef union i2c_prop_val_range {
	uint32_t ipvr_bit32;
	i2c_prop_u32_range_t ipvr_u32;
} i2c_prop_val_range_t;

typedef struct i2c_prop_range {
	uint32_t ipr_count;
	i2c_prop_type_t ipr_type;
	i2c_prop_val_range_t ipr_range[];
} i2c_prop_range_t;

/*
 * This enumeration contains a list of the properties that are supported.
 *
 * In earlier designs we had an initial set of properties for setup and hold
 * time related aspects, but controllers don't really have a uniform design
 * here. Some offer different values for RX and TX. Some offer only a single
 * value.
 */
typedef enum i2c_prop {
	/*
	 * This is a uint32_t that is covered by the i2c_speed_t.
	 */
	I2C_PROP_BUS_SPEED	= 0,
	/*
	 * This is a uint32_t that indicates the number of ports the device has.
	 */
	I2C_PROP_NPORTS,
	/*
	 * This indicates the controller's type, which is covered by the
	 * i2c_ctrl_type_t.
	 */
	I2C_PROP_TYPE,
	/*
	 * SMBus operations that are supported by the controller. This is a
	 * uint32_t that covers smbus_prop_op_t.
	 */
	SMBUS_PROP_SUP_OPS,
	/*
	 * Maximum sizes that a controller can support for performing different
	 * kinds of I/O. We expect that most I2C controllers will only support a
	 *
	 * single read/write buffer. For SMBus controllers, they should specify
	 * the maximum block size. This covers block reads, writes, and calls.
	 * If a controller supports an I2C mode with a different maximum, then
	 * it can additionally specify the I2c properties.
	 */
	I2C_PROP_MAX_READ,
	I2C_PROP_MAX_WRITE,
	SMBUS_PROP_MAX_BLOCK,
	/*
	 * Properties for different timing parameters in I2C devices. These are
	 * all uint32_t values generally in clock cycles.
	 */
	I2C_PROP_STD_SCL_HIGH,
	I2C_PROP_STD_SCL_LOW,
	I2C_PROP_FAST_SCL_HIGH,
	I2C_PROP_FAST_SCL_LOW,
	I2C_PROP_HIGH_SCL_HIGH,
	I2C_PROP_HIGH_SCL_LOW
} i2c_prop_t;

typedef enum smbus_prop_op {
	SMBUS_PROP_OP_QUICK_COMMAND = 1 << SMBUS_OP_QUICK_COMMAND,
	SMBUS_PROP_OP_SEND_BYTE = 1 << SMBUS_OP_SEND_BYTE,
	SMBUS_PROP_OP_RECV_BYTE = 1 << SMBUS_OP_RECV_BYTE,
	SMBUS_PROP_OP_WRITE_BYTE = 1 << SMBUS_OP_WRITE_BYTE,
	SMBUS_PROP_OP_READ_BYTE = 1 << SMBUS_OP_READ_BYTE,
	SMBUS_PROP_OP_WRITE_WORD = 1 << SMBUS_OP_WRITE_WORD,
	SMBUS_PROP_OP_READ_WORD = 1 << SMBUS_OP_READ_WORD,
	SMBUS_PROP_OP_PROCESS_CALL = 1 << SMBUS_OP_PROCESS_CALL,
	SMBUS_PROP_OP_WRITE_BLOCK = 1 << SMBUS_OP_WRITE_BLOCK,
	SMBUS_PROP_OP_READ_BLOCK = 1 << SMBUS_OP_READ_BLOCK,
	SMBUS_PROP_OP_HOST_NOTIFY = 1 << SMBUS_OP_HOST_NOTIFY,
	SMBUS_PROP_OP_BLOCK_PROCESS_CALL = 1 << SMBUS_OP_BLOCK_PROCESS_CALL,
	SMBUS_PROP_OP_WRITE_U32 = 1 << SMBUS_OP_WRITE_U32,
	SMBUS_PROP_OP_READ_U32 = 1 << SMBUS_OP_READ_U32,
	SMBUS_PROP_OP_WRITE_U64 = 1 << SMBUS_OP_WRITE_U64,
	SMBUS_PROP_OP_READ_U64 = 1 << SMBUS_OP_READ_U64,
	SMBUS_PROP_OP_I2C_WRITE_BLOCK = 1 << SMBUS_OP_I2C_WRITE_BLOCK,
	SMBUS_PROP_OP_I2C_READ_BLOCK = 1 << SMBUS_OP_I2C_READ_BLOCK
} smbus_prop_op_t;

/*
 * The size in bytes of the maximum property name (including the NUL) and the
 * largest data size.
 */
#define	I2C_PROP_NAME_MAX	32
#define	I2C_PROP_SIZE_MAX	256

#ifdef __cplusplus
}
#endif

#endif /* _SYS_I2C_I2C_H */
