From a6ce012ca35ca862034d25533379bf988898c6da Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Wed, 11 Mar 2009 21:57:57 +0100 Subject: [PATCH] using smbus ioctl() --- Host/i2c-dev.h | 337 ++++++++++++++++++++++++++++++++++++++++++++++++ Host/i2c-test.c | 81 +++++------- alix-usv.c | 63 +++++---- 3 files changed, 407 insertions(+), 74 deletions(-) create mode 100644 Host/i2c-dev.h diff --git a/Host/i2c-dev.h b/Host/i2c-dev.h new file mode 100644 index 0000000..aba8791 --- /dev/null +++ b/Host/i2c-dev.h @@ -0,0 +1,337 @@ +/* + i2c-dev.h - i2c-bus driver, char device interface + + Copyright (C) 1995-97 Simon G. Vogl + Copyright (C) 1998-99 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* $Id: i2c-dev.h 4948 2007-10-14 11:21:00Z khali $ */ + +#ifndef LIB_I2CDEV_H +#define LIB_I2CDEV_H + +#include +#include + + +/* -- i2c.h -- */ + + +/* + * I2C Message - used for pure i2c transaction, also from /dev interface + */ +struct i2c_msg { + __u16 addr; /* slave address */ + unsigned short flags; +#define I2C_M_TEN 0x10 /* we have a ten bit chip address */ +#define I2C_M_RD 0x01 +#define I2C_M_NOSTART 0x4000 +#define I2C_M_REV_DIR_ADDR 0x2000 +#define I2C_M_IGNORE_NAK 0x1000 +#define I2C_M_NO_RD_ACK 0x0800 + short len; /* msg length */ + char *buf; /* pointer to msg data */ +}; + +/* To determine what functionality is present */ + +#define I2C_FUNC_I2C 0x00000001 +#define I2C_FUNC_10BIT_ADDR 0x00000002 +#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ +#define I2C_FUNC_SMBUS_PEC 0x00000008 +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_QUICK 0x00010000 +#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 +#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 +#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 +#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 +#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 +#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 +#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 +#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 +#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */ +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */ + +#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ + I2C_FUNC_SMBUS_WRITE_BYTE) +#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ + I2C_FUNC_SMBUS_WRITE_BYTE_DATA) +#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ + I2C_FUNC_SMBUS_WRITE_WORD_DATA) +#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) +#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) +#define I2C_FUNC_SMBUS_I2C_BLOCK_2 (I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2) + +/* Old name, for compatibility */ +#define I2C_FUNC_SMBUS_HWPEC_CALC I2C_FUNC_SMBUS_PEC + +/* + * Data for SMBus Messages + */ +#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ +#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ +union i2c_smbus_data { + __u8 byte; + __u16 word; + __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ + /* and one more for PEC */ +}; + +/* smbus_access read or write markers */ +#define I2C_SMBUS_READ 1 +#define I2C_SMBUS_WRITE 0 + +/* SMBus transaction types (size parameter in the above functions) + Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ +#define I2C_SMBUS_QUICK 0 +#define I2C_SMBUS_BYTE 1 +#define I2C_SMBUS_BYTE_DATA 2 +#define I2C_SMBUS_WORD_DATA 3 +#define I2C_SMBUS_PROC_CALL 4 +#define I2C_SMBUS_BLOCK_DATA 5 +#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 +#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ +#define I2C_SMBUS_I2C_BLOCK_DATA 8 + + +/* ----- commands for the ioctl like i2c_command call: + * note that additional calls are defined in the algorithm and hw + * dependent layers - these can be listed here, or see the + * corresponding header files. + */ + /* -> bit-adapter specific ioctls */ +#define I2C_RETRIES 0x0701 /* number of times a device address */ + /* should be polled when not */ + /* acknowledging */ +#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */ + + +/* this is for i2c-dev.c */ +#define I2C_SLAVE 0x0703 /* Change slave address */ + /* Attn.: Slave address is 7 or 10 bits */ +#define I2C_SLAVE_FORCE 0x0706 /* Change slave address */ + /* Attn.: Slave address is 7 or 10 bits */ + /* This changes the address, even if it */ + /* is already taken! */ +#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */ + +#define I2C_FUNCS 0x0705 /* Get the adapter functionality */ +#define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/ +#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */ + +#define I2C_SMBUS 0x0720 /* SMBus-level access */ + +/* -- i2c.h -- */ + + +/* Note: 10-bit addresses are NOT supported! */ + +/* This is the structure as used in the I2C_SMBUS ioctl call */ +struct i2c_smbus_ioctl_data { + char read_write; + __u8 command; + int size; + union i2c_smbus_data *data; +}; + +/* This is the structure as used in the I2C_RDWR ioctl call */ +struct i2c_rdwr_ioctl_data { + struct i2c_msg *msgs; /* pointers to i2c_msgs */ + int nmsgs; /* number of i2c_msgs */ +}; + + +static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, + int size, union i2c_smbus_data *data) +{ + struct i2c_smbus_ioctl_data args; + + args.read_write = read_write; + args.command = command; + args.size = size; + args.data = data; + return ioctl(file,I2C_SMBUS,&args); +} + + +static inline __s32 i2c_smbus_write_quick(int file, __u8 value) +{ + return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL); +} + +static inline __s32 i2c_smbus_read_byte(int file) +{ + union i2c_smbus_data data; + if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data)) + return -1; + else + return 0x0FF & data.byte; +} + +static inline __s32 i2c_smbus_write_byte(int file, __u8 value) +{ + return i2c_smbus_access(file,I2C_SMBUS_WRITE,value, + I2C_SMBUS_BYTE,NULL); +} + +static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) +{ + union i2c_smbus_data data; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + I2C_SMBUS_BYTE_DATA,&data)) + return -1; + else + return 0x0FF & data.byte; +} + +static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, + __u8 value) +{ + union i2c_smbus_data data; + data.byte = value; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_BYTE_DATA, &data); +} + +static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) +{ + union i2c_smbus_data data; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + I2C_SMBUS_WORD_DATA,&data)) + return -1; + else + return 0x0FFFF & data.word; +} + +static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, + __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_WORD_DATA, &data); +} + +static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_PROC_CALL,&data)) + return -1; + else + return 0x0FFFF & data.word; +} + + +/* Returns the number of read bytes */ +static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, + __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + I2C_SMBUS_BLOCK_DATA,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } +} + +static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, + __u8 length, __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > 32) + length = 32; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_BLOCK_DATA, &data); +} + +/* Returns the number of read bytes */ +/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you + ask for less than 32 bytes, your code will only work with kernels + 2.6.23 and later. */ +static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, + __u8 length, __u8 *values) +{ + union i2c_smbus_data data; + int i; + + if (length > 32) + length = 32; + data.block[0] = length; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN : + I2C_SMBUS_I2C_BLOCK_DATA,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } +} + +static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, + __u8 length, __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > 32) + length = 32; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_I2C_BLOCK_BROKEN, &data); +} + +/* Returns the number of read bytes */ +static inline __s32 i2c_smbus_block_process_call(int file, __u8 command, + __u8 length, __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > 32) + length = 32; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_BLOCK_PROC_CALL,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } +} + + +#endif /* LIB_I2CDEV_H */ diff --git a/Host/i2c-test.c b/Host/i2c-test.c index 44f08d6..6dc2e92 100644 --- a/Host/i2c-test.c +++ b/Host/i2c-test.c @@ -28,11 +28,26 @@ #include #include -#include -#include +#include "i2c-dev.h" -struct read_data { - uint8_t sys_state; +enum { + REG_STATUS = 0x00, + + REG_CURRENT = 0x10, + REG_UBAT = 0x11, + REG_UIN = 0x12, + + REG_UIN_LOSS = 0x20, + REG_UIN_RESTORE = 0x21, + REG_UBAT_FULL = 0x22, + REG_UBAT_LOW = 0x23, + REG_UBAT_CRIT = 0x24, + REG_IBAT_FULL = 0x25, + REG_CRC = 0x26, +}; + +struct usv_data { + uint16_t sys_state; int16_t adc_current; int16_t adc_ubat; @@ -45,19 +60,7 @@ struct read_data { int16_t ubat_critical; int16_t ibat_full; uint16_t crc16; -} __attribute__((__packed__)); - -struct write_data { - uint8_t sys_state; - - int16_t uin_loss; - int16_t uin_restore; - int16_t ubat_full; - int16_t ubat_low; - int16_t ubat_critical; - int16_t ibat_full; - uint16_t crc16; -} __attribute__((__packed__)); +}; enum { STATE_IDLE = 0x01, @@ -105,8 +108,8 @@ static int i2c_open(const char *path) return -1; } - if (!(funcs & I2C_FUNC_I2C)) { - fprintf(stderr, "I2C_FUNC_I2C not supported!\n"); + if ((funcs & I2C_FUNC_SMBUS_WORD_DATA) != I2C_FUNC_SMBUS_WORD_DATA) { + fprintf(stderr, "I2C_FUNC_SMBUS_WORD_DATA not supported!\n"); close(fd); return -1; } @@ -133,41 +136,23 @@ int main(int argc, char *argv[]) if (i2c_setaddress(fd, 0x10) < 0) exit(-1); - int cnt = 0; - while (1) { - struct read_data rdbuf; - memset(&rdbuf, 0, sizeof(rdbuf)); + struct usv_data usv; + memset(&usv, 0, sizeof(usv)); - int ret = read(fd, &rdbuf, sizeof(rdbuf)); - if (ret <= 0) - perror("read()"); + usv.sys_state = i2c_smbus_read_word_data(fd, REG_STATUS); + usv.adc_current = i2c_smbus_read_word_data(fd, REG_CURRENT); + usv.adc_ubat = i2c_smbus_read_word_data(fd, REG_UBAT); + usv.adc_uin = i2c_smbus_read_word_data(fd, REG_UIN); printf("state:0x%02x I:%5dmA Ubat:%5dmV Usup:%5dmV (%s) [%5d,%5d,%5d,%5d,%5d,%5d,0x%04x]\n", - rdbuf.sys_state, rdbuf.adc_current, rdbuf.adc_ubat, - rdbuf.adc_uin, state2str(rdbuf.sys_state), - rdbuf.uin_loss, rdbuf.uin_restore, rdbuf.ubat_full, - rdbuf.ubat_low, rdbuf.ubat_critical, rdbuf.ibat_full, - rdbuf.crc16); + usv.sys_state, usv.adc_current, usv.adc_ubat, + usv.adc_uin, state2str(usv.sys_state), + usv.uin_loss, usv.uin_restore, usv.ubat_full, + usv.ubat_low, usv.ubat_critical, usv.ibat_full, + usv.crc16); sleep(1); - cnt++; - - if (cnt == 5) { - struct write_data wrbuf = { - .sys_state = STATE_CHARGE, - .uin_loss = 12000, - .uin_restore = 14000, - .ubat_full = 13300, - .ubat_low = 12000, - .ubat_critical = 10800, - .ibat_full = 150, - .crc16 = 0x0000, - }; - -// write (fd, &wrbuf, sizeof(wrbuf)); - write (fd, &wrbuf, 1); - } } close(fd); diff --git a/alix-usv.c b/alix-usv.c index c8b99b8..d618ab0 100644 --- a/alix-usv.c +++ b/alix-usv.c @@ -87,9 +87,20 @@ ISR(ADC_vect) ADCSRA |= (1< write control */ + if (i2c_reg == 0x00 && bcnt == 0x00) { /* poweroff is always allowed */ if (data & STATE_POWEROFF) sys_state = data; @@ -102,44 +113,44 @@ void usi_write(uint8_t data, uint8_t bcnt) else if (sys_state != STATE_DISCHARGE) sys_state = data; - } else { - uint8_t index = (bcnt -1); + /* register word 0x20 - 0x26 eeprom parameters */ + } else if (i2c_reg >= 0x20 && i2c_reg <= 0x26) { uint8_t *ptr = (uint8_t *)¶ms; - if (index < sizeof(params)) - ptr[index] = data; + uint8_t index = ((i2c_reg - 0x20) << 1) + (bcnt & 0x01); + ptr[index] = data; - if (index == (sizeof(params) -1)) + /* crc field */ + if (i2c_reg == 0x26 && bcnt == 0x01) write_parameters(); } } uint8_t usi_read(uint8_t bcnt) { - static int16_t adc_copy[3]; + /* snapshot of adc value */ + static int16_t adc_copy; - /* first byte read is sys_state */ - if (bcnt == 0) { - /* take a snapshot in interrupt-mode */ - adc_copy[ADC_CURRENT] = adc_value[ADC_CURRENT]; - adc_copy[ADC_UBAT] = adc_value[ADC_UBAT]; - adc_copy[ADC_UIN] = adc_value[ADC_UIN]; + /* reg 0x00, lowbyte -> read status */ + if (i2c_reg == 0 && bcnt == 0) { return sys_state; + + /* register word 0x10 - 0x12 adc values */ + } else if (i2c_reg >= 0x10 && i2c_reg <= 0x12) { + if (bcnt == 0x00) { + adc_copy = adc_value[i2c_reg - 0x10]; + return adc_copy & 0xFF; + + } else { + return (adc_copy >> 8) & 0xFF; + } + + /* register word 0x20 - 0x25 eeprom parameters */ + } else if (i2c_reg >= 0x20 && i2c_reg <= 0x25) { + uint8_t *ptr = (uint8_t *)¶ms; + uint8_t index = ((i2c_reg - 0x20) << 1) + (bcnt & 0x01); + return ptr[index]; } - uint8_t index = (bcnt -1); - uint8_t *ptr = (uint8_t *)adc_copy; - - /* Current and Voltages (in mA/mV) */ - if (index < sizeof(adc_copy)) - return ptr[index]; - - index -= sizeof(adc_copy); - ptr = (uint8_t *)¶ms; - - /* eeprom parameters (no snapshot needed, changed only in usi_write) */ - if (index < sizeof(params)) - return ptr[index]; - return 0xFF; }