#ifndef _I2CNEX_H
#define _I2CNEX_H
#include <sys/id_space.h>
#include <sys/avl.h>
#include <sys/list.h>
#include <sys/types.h>
#include <sys/mkdev.h>
#include <sys/i2c/controller.h>
#include <sys/i2c/client.h>
#include <sys/i2c/mux.h>
#include <sys/i2c/ioctl.h>
#ifdef __cplusplus
extern "C" {
#endif
#define I2C_MAX_PORTS 16
#define I2C_DEV_MINOR_MIN 1
#define I2C_DEV_MINOR_MAX MAXMIN32
#define I2C_USER_MINOR_MIN (MAXMIN32 + 1)
#define I2C_USER_MINOR_MAX (MAXMIN32 + (2 << 19))
typedef struct i2cnex_minors {
kmutex_t im_mutex;
id_space_t *im_ids;
id_space_t *im_user_ids;
avl_tree_t im_nexi;
avl_tree_t im_users;
list_t im_roots;
} i2cnex_minors_t;
typedef struct i2c_root i2c_root_t;
typedef struct i2c_ctrl i2c_ctrl_t;
typedef struct i2c_port i2c_port_t;
typedef struct i2c_dev i2c_dev_t;
typedef struct i2c_mux i2c_mux_t;
typedef struct i2c_nexus i2c_nexus_t;
typedef struct i2c_addr_track {
bool at_downstream[1 << 10];
uint8_t at_refcnt[1 << 10];
major_t at_major[1 << 10];
} i2c_addr_track_t;
struct i2c_port {
uint32_t ip_portno;
uint32_t ip_ndevs_ds;
i2c_nexus_t *ip_nex;
i2c_addr_track_t ip_track_7b;
avl_tree_t ip_devices;
list_node_t ip_ctrl_link;
};
struct i2c_dev {
avl_node_t id_link;
i2c_addr_t id_addr;
char **id_ucompat;
uint_t id_nucompat;
i2c_nexus_t *id_nex;
i2c_mux_t *id_mux;
list_t id_clients;
};
struct i2c_mux {
i2c_nexus_t *im_nex;
const i2c_mux_ops_t *im_ops;
void *im_drv;
uint32_t im_nports;
uint32_t im_curport;
i2c_port_t im_ports[I2C_MAX_PORTS];
};
typedef enum {
I2C_CTRL_MA_NONE,
I2C_CTRL_MA_DESELECT,
I2C_CTRL_MA_UPDATE
} i2c_ctrl_mux_act_t;
typedef struct i2c_ctrl_lock {
kmutex_t cl_mutex;
i2c_txn_t *cl_owner;
list_t cl_waiters;
uintptr_t cl_nexus_thr;
list_t cl_stack;
uint32_t cl_nlocks;
uint32_t cl_nwait;
uint32_t cl_nnonblock;
uint32_t cl_nsig;
uint32_t cl_nsig_block;
uint32_t cl_nsig_acq;
uint32_t cl_nstack;
uint32_t cl_nnexus;
} i2c_ctrl_lock_t;
typedef struct i2c_ctrl_limit {
uint32_t lim_i2c_read;
uint32_t lim_i2c_write;
smbus_prop_op_t lim_smbus_ops;
uint32_t lim_smbus_block;
} i2c_ctrl_limit_t;
struct i2c_ctrl {
list_node_t ic_link;
i2c_root_t *ic_root;
void *ic_drv;
const i2c_ctrl_ops_t *ic_ops;
i2c_ctrl_type_t ic_type;
i2c_nexus_t *ic_nexus;
uint32_t ic_nports;
i2c_port_t ic_ports[I2C_MAX_PORTS];
i2c_ctrl_lock_t ic_lock;
i2c_ctrl_limit_t ic_limit;
union {
smbus_req_t req_smbus;
i2c_req_t req_i2c;
} ic_reqs;
list_t ic_mux_active;
list_t ic_mux_plan;
i2c_ctrl_mux_act_t ic_mux_state;
kmutex_t ic_txn_lock;
list_t ic_txns;
};
typedef enum {
I2C_NEXUS_T_CTRL,
I2C_NEXUS_T_PORT,
I2C_NEXUS_T_DEV,
I2C_NEXUS_T_MUX
} i2c_nexus_type_t;
typedef enum {
I2C_NEXUS_F_DISC = 1 << 0
} i2c_nexus_flags_t;
struct i2c_nexus {
avl_node_t in_avl;
i2c_nexus_type_t in_type;
i2c_nexus_flags_t in_flags;
i2c_ctrl_t *in_ctrl;
char in_name[I2C_NAME_MAX];
char in_addr[I2C_NAME_MAX];
id_t in_minor;
dev_info_t *in_dip;
dev_info_t *in_pdip;
i2c_nexus_t *in_pnex;
union {
i2c_port_t *in_port;
i2c_dev_t *in_dev;
i2c_mux_t *in_mux;
} in_data;
};
struct i2c_root {
list_node_t ir_link;
dev_info_t *ir_dip;
kmutex_t ir_mutex;
list_t ir_ctrls;
};
typedef enum {
I2C_LOCK_TAG_MUX_REG,
I2C_LOCK_TAG_MUX_UNREG,
I2C_LOCK_TAG_BUS_CONFIG,
I2C_LOCK_TAG_BUS_UNCONFIG,
I2C_LOCK_TAG_DIP_DETACH,
I2C_LOCK_TAG_CLIENT_LOCK,
I2C_LOCK_TAG_CLIENT_ALLOC,
I2C_LOCK_TAG_CLIENT_ADDR,
I2C_LOCK_TAG_CLIENT_DESTROY,
I2C_LOCK_TAG_USER_IO,
I2C_LOCK_TAG_USER_DEV_ADD,
I2C_LOCK_TAG_USER_DEV_INFO,
I2C_LOCK_TAG_USER_DEV_RM,
I2C_LOCK_TAG_USER_PROP_INFO,
I2C_LOCK_TAG_USER_PROP_SET
} i2c_txn_tag_t;
typedef enum {
I2C_TXN_STATE_UNLOCKED = 0,
I2C_TXN_STATE_BLOCKED,
I2C_TXN_STATE_ACQUIRED
} i2c_txn_state_t;
typedef struct i2c_txn {
list_node_t txn_link;
list_node_t txn_wait_link;
list_node_t txn_stack_link;
i2c_ctrl_t *txn_ctrl;
kcondvar_t txn_cv;
i2c_txn_state_t txn_state;
i2c_errno_t txn_err;
i2c_txn_tag_t txn_tag;
const void *txn_debug;
hrtime_t txn_last_change;
uintptr_t txn_alloc_kthread;
uintptr_t txn_acq_kthread;
pid_t txn_acq_pid;
} i2c_txn_t;
typedef enum {
I2C_USER_F_CTRL_LOCK = 1 << 0,
I2C_USER_F_ACTIVE = 1 << 1,
I2C_USER_F_LOCK = 1 << 2
} i2c_user_flags_t;
typedef struct i2c_user {
avl_node_t iu_avl;
id_t iu_minor;
i2c_nexus_t *iu_nexus;
kmutex_t iu_mutex;
i2c_txn_t *iu_txn;
i2c_user_flags_t iu_flags;
uintptr_t iu_thread;
} i2c_user_t;
typedef enum {
I2C_CLIENT_F_CLAIM_ADDR = 1 << 0,
I2C_CLIENT_F_SHARED_ADDR = 1 << 1,
I2C_CLIENT_F_ALLOC_TXN = 1 << 2
} i2c_client_flags_t;
typedef struct i2c_client {
list_node_t icli_dev_link;
dev_info_t *icli_dip;
i2c_addr_t icli_addr;
i2c_dev_t *icli_dev;
i2c_ctrl_t *icli_ctrl;
i2c_port_t *icli_io_port;
kmutex_t icli_mutex;
i2c_client_flags_t icli_flags;
list_t icli_regs;
i2c_txn_t *icli_txn;
uintptr_t icli_curthread;
union {
smbus_req_t req_smbus;
i2c_req_t req_i2c;
} icli_reqs;
} i2c_client_t;
struct i2c_reg_hdl {
list_node_t reg_link;
i2c_client_t *reg_client;
i2c_reg_acc_attr_t reg_attr;
uint32_t reg_max_nread;
uint32_t reg_max_nwrite;
};
extern i2cnex_minors_t i2cnex_minors;
extern struct bus_ops i2c_nex_bus_ops;
extern i2c_root_t *i2c_dip_to_root(dev_info_t *);
extern i2c_root_t *i2c_root_init(dev_info_t *);
extern void i2c_root_fini(i2c_root_t *);
extern i2c_nexus_t *i2cnex_nex_alloc(i2c_nexus_type_t, dev_info_t *,
i2c_nexus_t *, const char *, const char *, i2c_ctrl_t *);
extern void i2cnex_nex_free(i2c_nexus_t *);
extern i2c_nexus_t *i2c_nex_find_by_minor(minor_t);
typedef struct {
bool inbc_matched;
ddi_bus_config_op_t inbc_op;
const void *inbc_arg;
int inbc_ret;
char *inbc_dup;
size_t inbc_duplen;
const char *inbc_name;
const char *inbc_addr;
} i2c_nex_bus_config_t;
extern int i2c_nex_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
void *);
extern bool i2c_nex_bus_config_init(i2c_nex_bus_config_t *, ddi_bus_config_op_t,
const void *);
extern void i2c_nex_bus_config_fini(i2c_nex_bus_config_t *);
extern void i2c_nex_bus_config_one(i2c_nexus_t *, i2c_nex_bus_config_t *);
extern void i2c_nex_bus_unconfig_one(i2c_nexus_t *, i2c_nex_bus_config_t *);
extern void i2c_nex_dev_cleanup(i2c_nexus_t *);
extern int i2c_nex_open(dev_t *, int, int, cred_t *);
extern int i2c_nex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
extern int i2c_nex_close(dev_t, int, int, cred_t *);
extern bool i2c_error(i2c_error_t *, i2c_errno_t, i2c_ctrl_error_t);
extern void i2c_success(i2c_error_t *);
extern i2c_txn_t *i2c_txn_alloc(i2c_ctrl_t *, i2c_txn_tag_t, const void *);
extern i2c_errno_t i2c_txn_ctrl_lock(i2c_txn_t *, bool);
extern bool i2c_txn_held(i2c_txn_t *);
extern void i2c_txn_nexus_op_begin(i2c_txn_t *);
extern void i2c_txn_nexus_op_end(i2c_txn_t *);
extern void i2c_txn_ctrl_unlock(i2c_txn_t *);
extern void i2c_txn_free(i2c_txn_t *);
extern bool i2c_ctrl_io_smbus(i2c_txn_t *, i2c_ctrl_t *, i2c_port_t *,
smbus_req_t *);
extern bool i2c_ctrl_io_i2c(i2c_txn_t *, i2c_ctrl_t *, i2c_port_t *,
i2c_req_t *);
extern bool i2c_mux_update(i2c_txn_t *, i2c_ctrl_t *, i2c_port_t *,
i2c_error_t *);
extern void i2c_mux_remove_port(i2c_txn_t *, i2c_ctrl_t *, i2c_port_t *);
extern bool i2c_addr_alloc(i2c_port_t *, const i2c_addr_t *,
i2c_error_t *);
extern void i2c_addr_free(i2c_port_t *, const i2c_addr_t *);
extern bool i2c_addr_alloc_shared(i2c_port_t *, const i2c_addr_t *,
major_t, i2c_error_t *);
extern void i2c_addr_free_shared(i2c_port_t *, const i2c_addr_t *,
major_t);
extern void i2c_addr_info_7b(const i2c_port_t *, ui2c_port_info_t *);
extern i2c_dev_t *i2c_device_find_by_addr(i2c_txn_t *, i2c_port_t *,
const i2c_addr_t *);
extern i2c_dev_t *i2c_device_init(i2c_txn_t *, i2c_port_t *, const i2c_addr_t *,
const char *, char *const *, uint_t, i2c_error_t *);
extern bool i2c_device_config(i2c_port_t *, i2c_dev_t *);
extern bool i2c_device_unconfig(i2c_port_t *, i2c_dev_t *);
extern void i2c_device_fini(i2c_txn_t *, i2c_port_t *, i2c_dev_t *);
extern bool i2c_dip_is_dev(dev_info_t *);
extern i2c_nexus_t *i2c_dev_to_nexus(dev_info_t *);
extern bool i2c_addr_validate(const i2c_addr_t *, i2c_error_t *);
typedef bool (*i2c_port_f)(i2c_port_t *, void *);
extern void i2c_port_parent_iter(i2c_port_t *, i2c_port_f, void *);
extern void i2c_port_iter(i2c_port_t *, i2c_port_f, void *);
extern uint16_t i2c_prop_nstd();
extern const char *i2c_prop_name(i2c_prop_t);
extern bool i2c_prop_info(i2c_ctrl_t *, ui2c_prop_info_t *);
extern bool i2c_prop_get(i2c_ctrl_t *, i2c_prop_t, void *, uint32_t *,
i2c_error_t *);
extern bool i2c_prop_set(i2c_txn_t *, i2c_ctrl_t *, i2c_prop_t, const void *,
uint32_t, i2c_error_t *);
#ifdef __cplusplus
}
#endif
#endif