libi2cdriver: add functions for IC register access

Many i2c device drivers used similar code to access registers on
the ICs they drive. This commit implements that functionality in
libi2cdriver and updates the drivers to use the library instead of
their own register access functions. The net result is 375+ fewer
lines of code and less work for people developing new drivers.

The two exceptions were cat24c256 and parts of tda19988. They access
the bus in uncommon ways. It doesn't make sense at this time to
move their read/write functions into libi2cdriver.

Change-Id: Id8280b71af33b710a49944d7f20a7262be9f5988
This commit is contained in:
Thomas Cort 2013-09-16 13:33:00 -04:00
parent 43471c3110
commit 75bd3009d3
10 changed files with 274 additions and 656 deletions

View file

@ -157,12 +157,6 @@ static int bmp085_transfer(endpoint_t endpt, int opcode, u64_t position,
unsigned int UNUSED(flags));
static int bmp085_other(message * m);
/* i2c bus access */
static int reg_read(uint8_t reg, uint8_t * val);
static int reg_read16(uint8_t reg, uint16_t * val);
static int reg_read24(uint8_t reg, uint32_t * val);
static int reg_write(uint8_t reg, uint8_t val);
/* SEF Function */
static int sef_cb_lu_state_save(int);
static int lu_state_restore(void);
@ -188,159 +182,6 @@ static struct device bmp085_device = {
.dv_size = 0
};
static int
reg_read(uint8_t reg, uint8_t * val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
if (val == NULL) {
log_warn(&log, "reg_read() called with NULL pointer\n");
return -1;
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from chip */
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
ioctl_exec.iie_addr = address;
/* write the register address */
ioctl_exec.iie_cmd[0] = reg;
ioctl_exec.iie_cmdlen = 1;
/* read 1 byte */
ioctl_exec.iie_buflen = 1;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_read() failed (r=%d)\n", r);
return -1;
}
*val = ioctl_exec.iie_buf[0];
log_trace(&log, "Read 0x%x from reg 0x%x\n", *val, reg);
return OK;
}
static int
reg_read16(uint8_t reg, uint16_t * val)
{
int r;
uint8_t msb, lsb;
minix_i2c_ioctl_exec_t ioctl_exec;
if (val == NULL) {
log_warn(&log, "reg_read16() called with NULL pointer\n");
return -1;
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from chip */
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
ioctl_exec.iie_addr = address;
/* write the register address */
ioctl_exec.iie_cmd[0] = reg;
ioctl_exec.iie_cmdlen = 1;
/* read 2 bytes */
ioctl_exec.iie_buflen = 2;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_read16() failed (r=%d)\n", r);
return -1;
}
msb = ioctl_exec.iie_buf[0];
lsb = ioctl_exec.iie_buf[1];
*val = ((msb << 8) | lsb);
log_trace(&log, "Read 0x%x from reg 0x%x\n", *val, reg);
return OK;
}
static int
reg_read24(uint8_t reg, uint32_t * val)
{
int r;
uint8_t msb, lsb, xlsb;
minix_i2c_ioctl_exec_t ioctl_exec;
if (val == NULL) {
log_warn(&log, "reg_read24() called with NULL pointer\n");
return -1;
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from chip */
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
ioctl_exec.iie_addr = address;
/* write the register address */
ioctl_exec.iie_cmd[0] = reg;
ioctl_exec.iie_cmdlen = 1;
/* read 3 bytes */
ioctl_exec.iie_buflen = 3;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_read24() failed (r=%d)\n", r);
return -1;
}
msb = ioctl_exec.iie_buf[0];
lsb = ioctl_exec.iie_buf[1];
xlsb = ioctl_exec.iie_buf[2];
*val = ((msb << 16) | (lsb << 8) | xlsb);
log_trace(&log, "Read 0x%x from reg 0x%x\n", *val, reg);
return OK;
}
static int
reg_write(uint8_t reg, uint8_t val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from chip */
ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
ioctl_exec.iie_addr = address;
/* no commands here */
ioctl_exec.iie_cmdlen = 0;
/* write register and value */
ioctl_exec.iie_buf[0] = reg;
ioctl_exec.iie_buf[1] = val;
ioctl_exec.iie_buflen = 2;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_write() failed (r=%d)\n", r);
return -1;
}
log_trace(&log, "Wrote 0x%x to reg 0x%x\n", val, reg);
return OK;
}
/*
* Initialize the driver. Checks the CHIPID against a known value and
* reads the calibration coefficients.
@ -373,7 +214,7 @@ version_check(void)
int r;
uint8_t chipid;
r = reg_read(CHIPID_REG, &chipid);
r = i2creg_read8(bus_endpoint, address, CHIPID_REG, &chipid);
if (r != OK) {
log_warn(&log, "Couldn't read CHIPID\n");
return -1;
@ -400,67 +241,67 @@ read_cal_coef(void)
int r;
/* Populate the calibration struct with values */
r = reg_read16(AC1_MSB_REG, &cal.ac1);
r = i2creg_read16(bus_endpoint, address, AC1_MSB_REG, &cal.ac1);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac1 = %d\n", cal.ac1);
r = reg_read16(AC2_MSB_REG, &cal.ac2);
r = i2creg_read16(bus_endpoint, address, AC2_MSB_REG, &cal.ac2);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac2 = %d\n", cal.ac2);
r = reg_read16(AC3_MSB_REG, &cal.ac3);
r = i2creg_read16(bus_endpoint, address, AC3_MSB_REG, &cal.ac3);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac3 = %d\n", cal.ac3);
r = reg_read16(AC4_MSB_REG, &cal.ac4);
r = i2creg_read16(bus_endpoint, address, AC4_MSB_REG, &cal.ac4);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac4 = %u\n", cal.ac4);
r = reg_read16(AC5_MSB_REG, &cal.ac5);
r = i2creg_read16(bus_endpoint, address, AC5_MSB_REG, &cal.ac5);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac5 = %u\n", cal.ac5);
r = reg_read16(AC6_MSB_REG, &cal.ac6);
r = i2creg_read16(bus_endpoint, address, AC6_MSB_REG, &cal.ac6);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac6 = %u\n", cal.ac6);
r = reg_read16(B1_MSB_REG, &cal.b1);
r = i2creg_read16(bus_endpoint, address, B1_MSB_REG, &cal.b1);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.b1 = %d\n", cal.b1);
r = reg_read16(B2_MSB_REG, &cal.b2);
r = i2creg_read16(bus_endpoint, address, B2_MSB_REG, &cal.b2);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.b2 = %d\n", cal.b2);
r = reg_read16(MB_MSB_REG, &cal.mb);
r = i2creg_read16(bus_endpoint, address, MB_MSB_REG, &cal.mb);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.mb = %d\n", cal.mb);
r = reg_read16(MC_MSB_REG, &cal.mc);
r = i2creg_read16(bus_endpoint, address, MC_MSB_REG, &cal.mc);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.mc = %d\n", cal.mc);
r = reg_read16(MD_MSB_REG, &cal.md);
r = i2creg_read16(bus_endpoint, address, MD_MSB_REG, &cal.md);
if (r != OK) {
return -1;
}
@ -516,7 +357,7 @@ measure(int32_t * temperature, int32_t * pressure)
log_debug(&log, "Triggering Temp Reading...\n");
/* trigger temperature reading */
r = reg_write(CTRL_REG, CMD_TRIG_T);
r = i2creg_write8(bus_endpoint, address, CTRL_REG, CMD_TRIG_T);
if (r != OK) {
log_warn(&log, "Failed to trigger temperature reading.\n");
return -1;
@ -526,7 +367,7 @@ measure(int32_t * temperature, int32_t * pressure)
micro_delay(UDELAY_T);
/* read the uncompensated temperature */
r = reg_read16(SENSOR_VAL_MSB_REG, &ut);
r = i2creg_read16(bus_endpoint, address, SENSOR_VAL_MSB_REG, &ut);
if (r != OK) {
log_warn(&log, "Failed to read temperature.\n");
return -1;
@ -537,7 +378,7 @@ measure(int32_t * temperature, int32_t * pressure)
log_debug(&log, "Triggering Pressure Reading...\n");
/* trigger pressure reading */
r = reg_write(CTRL_REG, p_cmd->cmd);
r = i2creg_write8(bus_endpoint, address, CTRL_REG, p_cmd->cmd);
if (r != OK) {
log_warn(&log, "Failed to trigger pressure reading.\n");
return -1;
@ -547,7 +388,7 @@ measure(int32_t * temperature, int32_t * pressure)
micro_delay(p_cmd->udelay);
/* read the uncompensated pressure */
r = reg_read24(SENSOR_VAL_MSB_REG, &up);
r = i2creg_read24(bus_endpoint, address, SENSOR_VAL_MSB_REG, &up);
if (r != OK) {
log_warn(&log, "Failed to read pressure.\n");
return -1;

View file

@ -106,8 +106,6 @@ static int32_t cached_rh = 0.0;
/* main driver functions */
static int sht21_init(void);
static int soft_reset(void);
static int usr_reg_read(uint8_t * usr_reg_val);
static int sensor_read(enum sht21_sensors sensor, int32_t * measurement);
static int measure(void);
@ -147,82 +145,6 @@ static struct device sht21_device = {
.dv_size = 0
};
/*
* Sends the chip a soft reset command and waits 15 ms for the chip to reset.
*/
static int
soft_reset(void)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Write to chip */
ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
ioctl_exec.iie_addr = address;
/* No command bytes for writing to this chip */
ioctl_exec.iie_cmdlen = 0;
/* Set the byte to write */
ioctl_exec.iie_buf[0] = CMD_SOFT_RESET;
ioctl_exec.iie_buflen = 1;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "soft_reset() failed (r=%d)\n", r);
return -1;
}
/* soft reset takes up to 15 ms to complete. */
micro_delay(15000);
log_debug(&log, "Soft Reset Complete\n");
return OK;
}
/*
* Obtain the contents of the usr register and store it in usr_reg_val.
*/
static int
usr_reg_read(uint8_t * usr_reg_val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
if (usr_reg_val == NULL) {
log_warn(&log, "usr_reg_read() called with NULL pointer\n");
return -1;
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from chip */
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
ioctl_exec.iie_addr = address;
/* Send the read from user register command */
ioctl_exec.iie_cmd[0] = CMD_RD_USR_REG;
ioctl_exec.iie_cmdlen = 1;
/* Read the register contents into iie_buf */
ioctl_exec.iie_buflen = 1;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "usr_reg_read() failed (r=%d)\n", r);
return -1;
}
*usr_reg_val = ioctl_exec.iie_buf[0];
log_trace(&log, "Read 0x%x from USR_REG\n", *usr_reg_val);
return OK;
}
/*
* Performs a soft reset and reads the contents of the user register to ensure
* that the chip is in a good state and working properly.
@ -233,12 +155,18 @@ sht21_init(void)
int r;
uint8_t usr_reg_val;
r = soft_reset();
/* Perform a soft-reset */
r = i2creg_raw_write8(bus_endpoint, address, CMD_SOFT_RESET);
if (r != OK) {
return -1;
}
r = usr_reg_read(&usr_reg_val);
/* soft reset takes up to 15 ms to complete. */
micro_delay(15000);
log_debug(&log, "Soft Reset Complete\n");
r = i2creg_read8(bus_endpoint, address, CMD_RD_USR_REG, &usr_reg_val);
if (r != OK) {
return -1;
}
@ -270,10 +198,10 @@ sensor_read(enum sht21_sensors sensor, int32_t * measurement)
{
int r;
uint8_t cmd;
uint8_t val_hi, val_lo;
uint16_t val;
uint8_t bytes[2];
uint32_t val32;
uint8_t expected_crc;
minix_i2c_ioctl_exec_t ioctl_exec;
switch (sensor) {
case SHT21_T:
@ -292,36 +220,23 @@ sensor_read(enum sht21_sensors sensor, int32_t * measurement)
return -1;
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from chip */
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
ioctl_exec.iie_addr = address;
/* Send the trigger command */
ioctl_exec.iie_cmd[0] = cmd;
ioctl_exec.iie_cmdlen = 1;
/* Read the results */
ioctl_exec.iie_buflen = 3;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
r = i2creg_read24(bus_endpoint, address, cmd, &val32);
if (r != OK) {
log_warn(&log, "sensor_read() failed (r=%d)\n", r);
return -1;
}
expected_crc = ioctl_exec.iie_buf[2];
expected_crc = val32 & 0xff;
val = (val32 >> 8) & 0xffff;
r = checksum(ioctl_exec.iie_buf, 2, expected_crc);
bytes[0] = (val >> 8) & 0xff;
bytes[1] = val & 0xff;
r = checksum(bytes, 2, expected_crc);
if (r != OK) {
return -1;
}
val_hi = ioctl_exec.iie_buf[0];
val_lo = ioctl_exec.iie_buf[1];
val = ((val_hi << 8) | val_lo);
val &= ~STATUS_BITS_MASK; /* clear status bits */
log_debug(&log, "Read VAL:0x%x CRC:0x%x\n", val, expected_crc);

View file

@ -375,28 +375,15 @@ static int
is_display_connected(void)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
uint8_t val;
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from CEC */
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
ioctl_exec.iie_addr = cec_address;
/* write the register address */
ioctl_exec.iie_cmd[0] = CEC_STATUS_REG;
ioctl_exec.iie_cmdlen = 1;
/* read 1 byte */
ioctl_exec.iie_buflen = 1;
r = i2cdriver_exec(cec_bus_endpoint, &ioctl_exec);
r = i2creg_read8(cec_bus_endpoint, cec_address, CEC_STATUS_REG, &val);
if (r != OK) {
log_warn(&log, "Reading connection status failed (r=%d)\n", r);
return -1;
}
if ((CEC_STATUS_CONNECTED_MASK & ioctl_exec.iie_buf[0]) == 0) {
if ((CEC_STATUS_CONNECTED_MASK & val) == 0) {
log_debug(&log, "No Display Detected\n");
return 0;
} else {
@ -412,20 +399,9 @@ static int
enable_hdmi_module(void)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Write to CEC */
ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
ioctl_exec.iie_addr = cec_address;
/* write the register address and value */
ioctl_exec.iie_buf[0] = CEC_ENABLE_REG;
ioctl_exec.iie_buf[1] = CEC_ENABLE_ALL_MASK;
ioctl_exec.iie_buflen = 2;
r = i2cdriver_exec(cec_bus_endpoint, &ioctl_exec);
r = i2creg_write8(cec_bus_endpoint, cec_address, CEC_ENABLE_REG,
CEC_ENABLE_ALL_MASK);
if (r != OK) {
log_warn(&log, "Writing enable bits failed (r=%d)\n", r);
return -1;
@ -444,7 +420,8 @@ set_page(uint8_t page)
if (page != current_page) {
r = hdmi_write(HDMI_PAGELESS, HDMI_PAGE_SELECT_REG, page);
r = i2creg_write8(hdmi_bus_endpoint, hdmi_address,
HDMI_PAGE_SELECT_REG, page);
if (r != OK) {
return r;
}
@ -508,7 +485,6 @@ hdmi_read(uint8_t page, uint8_t reg, uint8_t * val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
if (val == NULL) {
log_warn(&log, "Read called with NULL pointer\n");
@ -523,27 +499,12 @@ hdmi_read(uint8_t page, uint8_t reg, uint8_t * val)
}
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from HDMI */
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
ioctl_exec.iie_addr = hdmi_address;
/* write the register address */
ioctl_exec.iie_cmd[0] = reg;
ioctl_exec.iie_cmdlen = 1;
/* read 1 byte */
ioctl_exec.iie_buflen = 1;
r = i2cdriver_exec(hdmi_bus_endpoint, &ioctl_exec);
r = i2creg_read8(hdmi_bus_endpoint, hdmi_address, reg, val);
if (r != OK) {
log_warn(&log, "hdmi_read() failed (r=%d)\n", r);
return -1;
}
*val = ioctl_exec.iie_buf[0];
log_trace(&log, "Read 0x%x from reg 0x%x in page 0x%x\n", *val, reg,
page);
@ -553,9 +514,7 @@ hdmi_read(uint8_t page, uint8_t reg, uint8_t * val)
static int
hdmi_write(uint8_t page, uint8_t reg, uint8_t val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
if (page != HDMI_PAGELESS) {
r = set_page(page);
@ -565,18 +524,7 @@ hdmi_write(uint8_t page, uint8_t reg, uint8_t val)
}
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Write to HDMI */
ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
ioctl_exec.iie_addr = hdmi_address;
/* write the register address and value */
ioctl_exec.iie_buf[0] = reg;
ioctl_exec.iie_buf[1] = val;
ioctl_exec.iie_buflen = 2;
r = i2cdriver_exec(hdmi_bus_endpoint, &ioctl_exec);
r = i2creg_write8(hdmi_bus_endpoint, hdmi_address, reg, val);
if (r != OK) {
log_warn(&log, "hdmi_write() failed (r=%d)\n", r);
return -1;

View file

@ -101,10 +101,6 @@ static struct log log = {
.log_func = default_log
};
/* Register Access */
static int reg_read(uint8_t reg, uint8_t * val);
static int reg_write(uint8_t reg, uint8_t val);
/* Device Specific Functions */
static int check_revision(void);
static int enable_pwr_off(void);
@ -118,87 +114,13 @@ static int sef_cb_lu_state_save(int);
static int lu_state_restore(void);
static int sef_cb_init(int type, sef_init_info_t * info);
static int
reg_read(uint8_t reg, uint8_t * val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
if (val == NULL) {
log_warn(&log, "Read called with NULL pointer\n");
return EINVAL;
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from chip */
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
ioctl_exec.iie_addr = address;
/* write the register address */
ioctl_exec.iie_cmd[0] = reg;
ioctl_exec.iie_cmdlen = 1;
/* read 1 byte */
ioctl_exec.iie_buflen = 1;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_read() failed (r=%d)\n", r);
return -1;
}
*val = ioctl_exec.iie_buf[0];
log_trace(&log, "Read 0x%x from reg 0x%x", *val, reg);
return OK;
}
static int
reg_write(uint8_t reg, uint8_t val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
if (reg >= 0x0d) {
/* TODO: writes to password protected registers hasn't
* been implemented since nothing in this driver needs to
* write to them. When needed, it should be implemented.
*/
log_warn(&log, "Cannot write to protected registers.");
return -1;
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Write to chip */
ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
ioctl_exec.iie_addr = address;
/* write the register address and value */
ioctl_exec.iie_buf[0] = reg;
ioctl_exec.iie_buf[1] = val;
ioctl_exec.iie_buflen = 2;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_write() failed (r=%d)\n", r);
return -1;
}
log_trace(&log, "Successfully wrote 0x%x to reg 0x%x\n", val, reg);
return OK;
}
static int
check_revision(void)
{
int r;
uint8_t chipid;
r = reg_read(CHIPID_REG, &chipid);
r = i2creg_read8(bus_endpoint, address, CHIPID_REG, &chipid);
if (r != OK) {
log_warn(&log, "Failed to read CHIPID\n");
return -1;
@ -235,7 +157,7 @@ enable_pwr_off(void)
* system is ready to be powered off. Should be called during startup
* so that shutdown(8) can do power-off with reboot(RBT_POWEROFF).
*/
r = reg_write(STATUS_REG, PWR_OFF_MASK);
r = i2creg_write8(bus_endpoint, address, STATUS_REG, PWR_OFF_MASK);
if (r != OK) {
log_warn(&log, "Cannot set power off mask.");
return -1;
@ -274,14 +196,14 @@ intr_enable(void)
}
/* Enable/Disable interrupts in the TPS65217 */
r = reg_write(INT_REG, DEFAULT_INT_MASK);
r = i2creg_write8(bus_endpoint, address, INT_REG, DEFAULT_INT_MASK);
if (r != OK) {
log_warn(&log, "Failed to set interrupt mask.\n");
return -1;
}
/* Read from the interrupt register to clear any pending interrupts */
r = reg_read(INT_REG, &val);
r = i2creg_read8(bus_endpoint, address, INT_REG, &val);
if (r != OK) {
log_warn(&log, "Failed to read interrupt register.\n");
return -1;
@ -298,7 +220,7 @@ intr_handler(void)
struct tm t;
/* read interrupt register to get interrupt that fired and clear it */
r = reg_read(INT_REG, &val);
r = i2creg_read8(bus_endpoint, address, INT_REG, &val);
if (r != OK) {
log_warn(&log, "Failed to read interrupt register.\n");
return -1;

View file

@ -26,13 +26,14 @@ rtc_init(void)
uint8_t val;
struct tm t;
r = reg_set(ID4, RTC_CTRL_REG, (1 << STOP_RTC_BIT));
r = i2creg_set_bits8(bus_endpoint, addresses[ID4], RTC_CTRL_REG,
(1 << STOP_RTC_BIT));
if (r != OK) {
log_warn(&log, "Failed to start RTC\n");
return -1;
}
r = reg_read(ID4, RTC_STATUS_REG, &val);
r = i2creg_read8(bus_endpoint, addresses[ID4], RTC_STATUS_REG, &val);
if (r != OK) {
log_warn(&log, "Failed to read RTC_STATUS_REG\n");
return -1;
@ -59,7 +60,8 @@ rtc_get_time(struct tm *t, int flags)
/* Write GET_TIME_BIT to RTC_CTRL_REG to latch the RTC values into
* the RTC registers. This is required before each read.
*/
r = reg_set(ID4, RTC_CTRL_REG, (1 << GET_TIME_BIT));
r = i2creg_set_bits8(bus_endpoint, addresses[ID4], RTC_CTRL_REG,
(1 << GET_TIME_BIT));
if (r != OK) {
return -1;
}
@ -67,42 +69,42 @@ rtc_get_time(struct tm *t, int flags)
/* Read and Convert BCD to binary (default RTC mode). */
/* Seconds - 0 to 59 */
r = reg_read(ID4, SECONDS_REG, &val);
r = i2creg_read8(bus_endpoint, addresses[ID4], SECONDS_REG, &val);
if (r != OK) {
return -1;
}
t->tm_sec = bcd_to_dec(val & 0x7f);
/* Minutes - 0 to 59 */
r = reg_read(ID4, MINUTES_REG, &val);
r = i2creg_read8(bus_endpoint, addresses[ID4], MINUTES_REG, &val);
if (r != OK) {
return -1;
}
t->tm_min = bcd_to_dec(val & 0x7f);
/* Hours - 0 to 23 */
r = reg_read(ID4, HOURS_REG, &val);
r = i2creg_read8(bus_endpoint, addresses[ID4], HOURS_REG, &val);
if (r != OK) {
return -1;
}
t->tm_hour = bcd_to_dec(val & 0x3f);
/* Days - 1 to 31 */
r = reg_read(ID4, DAYS_REG, &val);
r = i2creg_read8(bus_endpoint, addresses[ID4], DAYS_REG, &val);
if (r != OK) {
return -1;
}
t->tm_mday = bcd_to_dec(val & 0x3f);
/* Months - Jan=1 to Dec=12 */
r = reg_read(ID4, MONTHS_REG, &val);
r = i2creg_read8(bus_endpoint, addresses[ID4], MONTHS_REG, &val);
if (r != OK) {
return -1;
}
t->tm_mon = bcd_to_dec(val & 0x1f) - 1;
/* Years - last 2 digits of year */
r = reg_read(ID4, YEARS_REG, &val);
r = i2creg_read8(bus_endpoint, addresses[ID4], YEARS_REG, &val);
if (r != OK) {
return -1;
}
@ -129,32 +131,38 @@ rtc_set_time(struct tm *t, int flags)
int r;
/* Write the date/time to the RTC registers. */
r = reg_write(ID4, SECONDS_REG, (dec_to_bcd(t->tm_sec) & 0x7f));
r = i2creg_write8(bus_endpoint, addresses[ID4], SECONDS_REG,
(dec_to_bcd(t->tm_sec) & 0x7f));
if (r != OK) {
return -1;
}
r = reg_write(ID4, MINUTES_REG, (dec_to_bcd(t->tm_min) & 0x7f));
r = i2creg_write8(bus_endpoint, addresses[ID4], MINUTES_REG,
(dec_to_bcd(t->tm_min) & 0x7f));
if (r != OK) {
return -1;
}
r = reg_write(ID4, HOURS_REG, (dec_to_bcd(t->tm_hour) & 0x3f));
r = i2creg_write8(bus_endpoint, addresses[ID4], HOURS_REG,
(dec_to_bcd(t->tm_hour) & 0x3f));
if (r != OK) {
return -1;
}
r = reg_write(ID4, DAYS_REG, (dec_to_bcd(t->tm_mday) & 0x3f));
r = i2creg_write8(bus_endpoint, addresses[ID4], DAYS_REG,
(dec_to_bcd(t->tm_mday) & 0x3f));
if (r != OK) {
return -1;
}
r = reg_write(ID4, MONTHS_REG, (dec_to_bcd(t->tm_mon + 1) & 0x1f));
r = i2creg_write8(bus_endpoint, addresses[ID4], MONTHS_REG,
(dec_to_bcd(t->tm_mon + 1) & 0x1f));
if (r != OK) {
return -1;
}
r = reg_write(ID4, YEARS_REG, (dec_to_bcd(t->tm_year % 100) & 0xff));
r = i2creg_write8(bus_endpoint, addresses[ID4], YEARS_REG,
(dec_to_bcd(t->tm_year % 100) & 0xff));
if (r != OK) {
return -1;
}

View file

@ -28,11 +28,10 @@ static i2c_addr_t valid_addrs[2] = {
static uint32_t bus;
/* endpoint for the driver for the bus itself. */
static endpoint_t bus_endpoint;
endpoint_t bus_endpoint;
/* slave addresses of the device */
#define NADDRESSES 4
static i2c_addr_t addresses[NADDRESSES] = {
i2c_addr_t addresses[NADDRESSES] = {
0x48, 0x49, 0x4a, 0x4b
};
@ -49,123 +48,6 @@ static int sef_cb_init(int type, sef_init_info_t * info);
static int fetch_t(endpoint_t ep, cp_grant_id_t gid, struct tm *t);
static int store_t(endpoint_t ep, cp_grant_id_t gid, struct tm *t);
int
reg_read(uint8_t id, uint8_t reg, uint8_t * val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
if (id < 0 || id >= NADDRESSES) {
log_warn(&log, "id parameter out of range.\n");
return EINVAL;
}
if (val == NULL) {
log_warn(&log, "Read called with NULL pointer\n");
return EINVAL;
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from chip */
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
ioctl_exec.iie_addr = addresses[id];
/* write the register address */
ioctl_exec.iie_cmd[0] = reg;
ioctl_exec.iie_cmdlen = 1;
/* read 1 byte */
ioctl_exec.iie_buflen = 1;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_read() failed (r=%d)\n", r);
return -1;
}
*val = ioctl_exec.iie_buf[0];
log_trace(&log, "Read 0x%x from reg 0x%x", *val, reg);
return OK;
}
int
reg_write(uint8_t id, uint8_t reg, uint8_t val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
if (id < 0 || id >= NADDRESSES) {
log_warn(&log, "id parameter out of range.\n");
return EINVAL;
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Write to chip */
ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
ioctl_exec.iie_addr = addresses[id];
/* write the register address and value */
ioctl_exec.iie_buf[0] = reg;
ioctl_exec.iie_buf[1] = val;
ioctl_exec.iie_buflen = 2;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_write() failed (r=%d)\n", r);
return -1;
}
log_trace(&log, "Successfully wrote 0x%x to reg 0x%x\n", val, reg);
return OK;
}
int
reg_set(uint8_t id, uint8_t reg, uint8_t mask)
{
int r;
uint8_t val;
r = reg_read(id, reg, &val);
if (r != OK) {
return -1;
}
val |= mask;
r = reg_write(id, reg, val);
if (r != OK) {
return -1;
}
return OK;
}
int
reg_clear(uint8_t id, uint8_t reg, uint8_t mask)
{
int r;
uint8_t val;
r = reg_read(id, reg, &val);
if (r != OK) {
return -1;
}
val &= ~mask;
r = reg_write(id, reg, val);
if (r != OK) {
return -1;
}
return OK;
}
static int
fetch_t(endpoint_t ep, cp_grant_id_t gid, struct tm *t)
{
@ -204,7 +86,8 @@ check_revision(void)
uint8_t idcode_7_0, idcode_15_8, idcode_23_16, idcode_31_24;
/* need to write a special code to unlock read protect on IDCODE */
r = reg_write(ID2, UNLOCK_TEST_REG, UNLOCK_TEST_CODE);
r = i2creg_write8(bus_endpoint, addresses[ID2], UNLOCK_TEST_REG,
UNLOCK_TEST_CODE);
if (r != OK) {
log_warn(&log, "Failed to write unlock code to UNLOCK_TEST\n");
return -1;
@ -213,22 +96,26 @@ check_revision(void)
/*
* read each part of the IDCODE
*/
r = reg_read(ID2, IDCODE_7_0_REG, &idcode_7_0);
r = i2creg_read8(bus_endpoint, addresses[ID2], IDCODE_7_0_REG,
&idcode_7_0);
if (r != OK) {
log_warn(&log, "Failed to read IDCODE part 1\n");
}
r = reg_read(ID2, IDCODE_15_8_REG, &idcode_15_8);
r = i2creg_read8(bus_endpoint, addresses[ID2], IDCODE_15_8_REG,
&idcode_15_8);
if (r != OK) {
log_warn(&log, "Failed to read IDCODE part 2\n");
}
r = reg_read(ID2, IDCODE_23_16_REG, &idcode_23_16);
r = i2creg_read8(bus_endpoint, addresses[ID2], IDCODE_23_16_REG,
&idcode_23_16);
if (r != OK) {
log_warn(&log, "Failed to read IDCODE part 3\n");
}
r = reg_read(ID2, IDCODE_31_24_REG, &idcode_31_24);
r = i2creg_read8(bus_endpoint, addresses[ID2], IDCODE_31_24_REG,
&idcode_31_24);
if (r != OK) {
log_warn(&log, "Failed to read IDCODE part 4\n");
}

View file

@ -63,10 +63,9 @@
#define RTC_STATUS_REG 0x0000002A
#define RUN_BIT 1
#define NADDRESSES 4
int reg_read(uint8_t id, uint8_t reg, uint8_t * val);
int reg_write(uint8_t id, uint8_t reg, uint8_t val);
int reg_set(uint8_t id, uint8_t reg, uint8_t mask);
int reg_clear(uint8_t id, uint8_t reg, uint8_t mask);
extern endpoint_t bus_endpoint;
extern i2c_addr_t addresses[NADDRESSES];
#endif /* __TPS65950_H */

View file

@ -59,10 +59,6 @@ static i2c_addr_t address;
/* endpoint for the driver for the bus itself. */
static endpoint_t bus_endpoint;
/* register access functions */
static int reg_read(uint8_t * val);
static int reg_write(uint8_t val);
/* main driver functions */
static int tsl2550_init(void);
static int adc_read(int adc, uint8_t * val);
@ -216,7 +212,7 @@ adc_read(int adc, uint8_t * val)
*val = (adc == 0) ? CMD_READ_ADC0 : CMD_READ_ADC1;
/* Select the ADC to read from */
r = reg_write(*val);
r = i2creg_raw_write8(bus_endpoint, address, *val);
if (r != OK) {
log_warn(&log, "Failed to write ADC read command.\n");
return -1;
@ -230,7 +226,7 @@ adc_read(int adc, uint8_t * val)
*/
spin_init(&spin, 400000);
do {
r = reg_read(val);
r = i2creg_raw_read8(bus_endpoint, address, val);
if (r != OK) {
log_warn(&log, "Failed to read ADC%d value.\n", adc);
return -1;
@ -247,7 +243,7 @@ adc_read(int adc, uint8_t * val)
* before 400 ms) and left the loop. To ensure there is a final read
* at or after the 400 ms mark, we try one last time here.
*/
r = reg_read(val);
r = i2creg_raw_read8(bus_endpoint, address, val);
if (r != OK) {
log_warn(&log, "Failed to read ADC%d value.\n", adc);
return -1;
@ -261,87 +257,6 @@ adc_read(int adc, uint8_t * val)
}
}
static int
reg_read(uint8_t * val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
if (val == NULL) {
log_warn(&log, "Read called with a NULL pointer.\n");
return EINVAL;
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from chip */
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
ioctl_exec.iie_addr = address;
/* No register address to write */
ioctl_exec.iie_cmdlen = 0;
/* Read one byte */
ioctl_exec.iie_buflen = 1;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_read() failed (r=%d)\n", r);
return -1;
}
*val = ioctl_exec.iie_buf[0];
log_trace(&log, "Read 0x%x from reg\n", *val);
return OK;
}
static int
reg_write(uint8_t val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
switch (val) {
case CMD_PWR_DOWN:
case CMD_PWR_UP:
case CMD_EXT_RANGE:
case CMD_NORM_RANGE:
case CMD_READ_ADC0:
case CMD_READ_ADC1:
/* Command is valid */
break;
default:
log_warn(&log,
"reg_write() called with invalid command 0x%x\n", val);
return EINVAL;
}
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Write to chip */
ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
ioctl_exec.iie_addr = address;
/* No command bytes for writing to this chip */
ioctl_exec.iie_cmdlen = 0;
/* Set the byte to write */
ioctl_exec.iie_buf[0] = val;
ioctl_exec.iie_buflen = 1;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_write() failed (r=%d)\n", r);
return -1;
}
log_trace(&log, "Wrote 0x%x to reg\n", val);
return OK;
}
static int
tsl2550_init(void)
{
@ -349,14 +264,14 @@ tsl2550_init(void)
uint8_t val;
/* Power on the device */
r = reg_write(CMD_PWR_UP);
r = i2creg_raw_write8(bus_endpoint, address, CMD_PWR_UP);
if (r != OK) {
log_warn(&log, "Power-up command failed.\n");
return -1;
}
/* Read power on test value */
r = reg_read(&val);
r = i2creg_raw_read8(bus_endpoint, address, &val);
if (r != OK) {
log_warn(&log, "Failed to read power on test value.\n");
return -1;
@ -370,7 +285,7 @@ tsl2550_init(void)
}
/* Set range to normal */
r = reg_write(CMD_NORM_RANGE);
r = i2creg_raw_write8(bus_endpoint, address, CMD_NORM_RANGE);
if (r != OK) {
log_warn(&log, "Normal range command failed.\n");
return -1;

View file

@ -18,4 +18,15 @@ void i2cdriver_handle_bus_update(endpoint_t * bus_endpoint, uint32_t bus,
int i2cdriver_reserve_device(endpoint_t bus_endpoint, i2c_addr_t address);
int i2cdriver_exec(endpoint_t bus_endpoint, minix_i2c_ioctl_exec_t *ioctl_exec);
int i2creg_raw_read8(endpoint_t bus, i2c_addr_t addr, uint8_t * val);
int i2creg_read8(endpoint_t bus, i2c_addr_t addr, uint8_t reg, uint8_t * val);
int i2creg_read16(endpoint_t bus, i2c_addr_t addr, uint8_t reg, uint16_t * val);
int i2creg_read24(endpoint_t bus, i2c_addr_t addr, uint8_t reg, uint32_t * val);
int i2creg_raw_write8(endpoint_t bus, i2c_addr_t addr, uint8_t val);
int i2creg_write8(endpoint_t bus, i2c_addr_t addr, uint8_t reg, uint8_t val);
int i2creg_set_bits8(endpoint_t bus, i2c_addr_t addr, uint8_t reg,
uint8_t bits);
int i2creg_clear_bits8(endpoint_t bus, i2c_addr_t addr, uint8_t reg,
uint8_t bits);
#endif /* _MINIX_I2CDRIVER_H */

View file

@ -1,5 +1,6 @@
/* This file contains device independent i2c device driver helpers. */
#include <assert.h>
#include <minix/drivers.h>
#include <minix/endpoint.h>
#include <minix/i2c.h>
@ -193,3 +194,174 @@ i2cdriver_exec(endpoint_t bus_endpoint, minix_i2c_ioctl_exec_t * ioctl_exec)
return m.REP_STATUS;
}
static int
__i2creg_read(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t raw,
uint8_t reg, uint32_t * val, size_t vallen)
{
int r, i;
minix_i2c_ioctl_exec_t ioctl_exec;
assert(val != NULL);
assert(vallen >= 1 && vallen <= 4);
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from chip */
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
ioctl_exec.iie_addr = address;
if (!raw) {
/* write the register address */
ioctl_exec.iie_cmd[0] = reg;
ioctl_exec.iie_cmdlen = 1;
}
/* read vallen bytes */
ioctl_exec.iie_buflen = vallen;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
return -1;
}
for (*val = 0, i = 0; i < vallen; i++) {
*val = ((*val) << 8) | ioctl_exec.iie_buf[i];
}
return OK;
}
int
i2creg_raw_read8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t * val)
{
int r;
uint32_t val32;
r = __i2creg_read(bus_endpoint, address, 1, 0, &val32, 1);
*val = val32 & 0xff;
return r;
}
int
i2creg_read8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
uint8_t * val)
{
int r;
uint32_t val32;
r = __i2creg_read(bus_endpoint, address, 0, reg, &val32, 1);
*val = val32 & 0xff;
return r;
}
int
i2creg_read16(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
uint16_t * val)
{
int r;
uint32_t val32;
r = __i2creg_read(bus_endpoint, address, 0, reg, &val32, 2);
*val = val32 & 0xffff;
return r;
}
int
i2creg_read24(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
uint32_t * val)
{
return __i2creg_read(bus_endpoint, address, 0, reg, val, 3);
}
static int
__i2creg_write(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t raw,
uint8_t reg, uint8_t val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Write to chip */
ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
ioctl_exec.iie_addr = address;
if (raw) {
/* write just the value */
ioctl_exec.iie_buf[0] = val;
ioctl_exec.iie_buflen = 1;
} else {
/* write the register address and value */
ioctl_exec.iie_buf[0] = reg;
ioctl_exec.iie_buf[1] = val;
ioctl_exec.iie_buflen = 2;
}
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
return -1;
}
return OK;
}
int
i2creg_write8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
uint8_t val)
{
return __i2creg_write(bus_endpoint, address, 0, reg, val);
}
int
i2creg_raw_write8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t val)
{
return __i2creg_write(bus_endpoint, address, 1, 0, val);
}
int
i2creg_set_bits8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
uint8_t bits)
{
int r;
uint8_t val;
r = i2creg_read8(bus_endpoint, address, reg, &val);
if (r != OK) {
return -1;
}
val |= bits;
r = i2creg_write8(bus_endpoint, address, reg, val);
if (r != OK) {
return -1;
}
return OK;
}
int
i2creg_clear_bits8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
uint8_t bits)
{
int r;
uint8_t val;
r = i2creg_read8(bus_endpoint, address, reg, &val);
if (r != OK) {
return -1;
}
val &= ~bits;
r = i2creg_write8(bus_endpoint, address, reg, val);
if (r != OK) {
return -1;
}
return OK;
}