blob: 1107bfc7d5a33d552e4e9bce2c83c0b534bd397f [file] [log] [blame]
/*
* (C) Copyright 2014 Google, Inc.
* All rights reserved.
*
*/
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/types.h>
#include <unistd.h>
#include "i2c.h"
extern int ioctl(int, int, void *);
int i2cr(int controller, uint8_t device_addr, uint32_t cell_addr,
uint32_t addr_len, uint32_t data_len, uint8_t *buf) {
char filename[FILENAME_SIZE];
int file;
int i;
uint32_t temp;
unsigned char addrbuf[4]; /* up to 4 byte addressing ! */
int return_code = 0;
struct i2c_msg message[2];
struct i2c_rdwr_ioctl_data rdwr_arg;
unsigned int read_data_len;
/* open the I2C adapter */
snprintf(filename, sizeof(filename), I2C_DEV_FILE, controller);
if ((file = open(filename, O_RDWR)) < 0) {
printf("I2C Error open file %s: %s", filename, strerror(errno));
return -1;
}
if ((return_code = flock(file, LOCK_EX)) < 0) {
printf("I2C Error lock file %s: %s", filename, strerror(errno));
goto i2cr_cleanup;
}
/* if we need to send addr, use combined transaction */
if (addr_len > 0) {
/* build struct i2c_msg 0 */
message[0].addr = device_addr;
message[0].flags = 0;
message[0].len = addr_len;
temp = cell_addr;
/* store addr into buffer */
for (i = addr_len - 1; i >= 0; i--) {
addrbuf[i] = temp & 0xff;
temp >>= 8;
}
message[0].buf = addrbuf;
/* build struct i2c_msg 1 */
message[1].addr = device_addr;
message[1].flags = I2C_M_RD;
message[1].len = data_len;
message[1].buf = buf;
/* build arg */
rdwr_arg.msgs = message;
rdwr_arg.nmsgs = 2;
return_code = ioctl(file, I2C_RDWR, &rdwr_arg);
/* since we pass in rdwr_arg.nmsgs = 2, expect a return of 2 on success */
if (return_code == 2) {
return_code = 0;
}
goto i2cr_cleanup;
}
/* setup device address */
if ((return_code = ioctl(file, I2C_SLAVE, (void *)(uintptr_t)device_addr)) <
0) {
printf("I2C Error: Could not set device address to %x: %s", device_addr,
strerror(errno));
goto i2cr_cleanup;
}
/* now read data out of the device */
read_data_len = read(file, buf, data_len);
if (read_data_len == data_len) {
return_code = 0;
}
i2cr_cleanup:
flock(file, LOCK_UN);
close(file);
return return_code;
}
int i2cw(int controller, uint8_t device_addr, uint32_t cell_addr,
uint32_t addr_len, uint32_t data_len, uint8_t *buf) {
char filename[FILENAME_SIZE];
int file;
int i;
uint32_t temp;
uint8_t tempbuf[I2C_PAGE_SIZE + 4];
int return_code;
uint8_t *writebuf = buf;
unsigned int write_data_len;
/* check data len */
if (data_len > I2C_PAGE_SIZE) {
return -1;
}
/* open the corrrsponding I2C adapter */
snprintf(filename, sizeof(filename), I2C_DEV_FILE, controller);
if ((file = open(filename, O_RDWR)) < 0) {
printf("I2C Error open file %s: %s", filename, strerror(errno));
return -1;
}
if ((return_code = flock(file, LOCK_EX)) < 0) {
printf("I2C Error lock file %s: %s", filename, strerror(errno));
goto i2cw_cleanup;
}
/* setup device address */
if ((return_code =
ioctl(file, I2C_SLAVE_FORCE, (void *)(uintptr_t)device_addr)) < 0) {
printf("I2C Error: Could not set device address to %x: %s", device_addr,
strerror(errno));
goto i2cw_cleanup;
}
/* if we need to send addr */
if (addr_len > 0) {
temp = cell_addr;
/* store addr into buffer */
for (i = (int)(addr_len - 1); i >= 0; i--) {
tempbuf[i] = temp & 0xff;
temp >>= 8;
}
/* copy data over into tempbuf, right after the cell address */
for (i = 0; i < (int)(data_len); i++) {
tempbuf[addr_len + i] = buf[i];
}
writebuf = tempbuf;
}
/* now write addr + data out to the device */
write_data_len = write(file, writebuf, addr_len + data_len);
if (write_data_len == (addr_len + data_len)) {
return_code = 0;
}
i2cw_cleanup:
flock(file, LOCK_UN);
close(file);
return return_code;
}