204 lines
5.2 KiB
C
204 lines
5.2 KiB
C
/***************************************************************************
|
|
copyright : (C) by 2003-2004 Stefano Barbato
|
|
email : stefano@codesink.org
|
|
|
|
$Id: 24cXX.c,v 1.5 2004/02/29 11:05:28 tat Exp $
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* 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. *
|
|
* *
|
|
***************************************************************************/
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <linux/fs.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include "24cXX.h"
|
|
|
|
static int i2c_write_1b(struct eeprom *e, __u8 buf)
|
|
{
|
|
int r;
|
|
// we must simulate a plain I2C byte write with SMBus functions
|
|
r = i2c_smbus_write_byte(e->fd, buf);
|
|
if(r < 0)
|
|
fprintf(stderr, "Error i2c_write_1b: %s\n", strerror(errno));
|
|
usleep(10);
|
|
return r;
|
|
}
|
|
|
|
static int i2c_write_2b(struct eeprom *e, __u8 buf[2])
|
|
{
|
|
int r;
|
|
// we must simulate a plain I2C byte write with SMBus functions
|
|
r = i2c_smbus_write_byte_data(e->fd, buf[0], buf[1]);
|
|
if(r < 0)
|
|
fprintf(stderr, "Error i2c_write_2b: %s\n", strerror(errno));
|
|
usleep(10000);
|
|
return r;
|
|
}
|
|
|
|
static int i2c_write_3b(struct eeprom *e, __u8 buf[3])
|
|
{
|
|
int r;
|
|
// we must simulate a plain I2C byte write with SMBus functions
|
|
// the __u16 data field will be byte swapped by the SMBus protocol
|
|
r = i2c_smbus_write_word_data(e->fd, buf[0], buf[2] << 8 | buf[1]);
|
|
if(r < 0)
|
|
fprintf(stderr, "Error i2c_write_3b: %s\n", strerror(errno));
|
|
usleep(10);
|
|
return r;
|
|
}
|
|
|
|
|
|
#define CHECK_I2C_FUNC( var, label ) \
|
|
do { if(0 == (var & label)) { \
|
|
fprintf(stderr, "\nError: " \
|
|
#label " function is required. Program halted.\n\n"); \
|
|
exit(1); } \
|
|
} while(0);
|
|
|
|
int eeprom_open(char *dev_fqn, int addr, int type, struct eeprom* e)
|
|
{
|
|
unsigned long funcs;
|
|
int fd, r;
|
|
e->fd = e->addr = 0;
|
|
e->dev = 0;
|
|
|
|
fd = open(dev_fqn, O_RDWR);
|
|
if(fd <= 0)
|
|
{
|
|
fprintf(stderr, "Error eeprom_open: %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
// get funcs list
|
|
if((r = ioctl(fd, I2C_FUNCS, &funcs) < 0))
|
|
{
|
|
fprintf(stderr, "Error eeprom_open: %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
|
|
// check for req funcs
|
|
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_QUICK );
|
|
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE );
|
|
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE );
|
|
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE_DATA );
|
|
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE_DATA );
|
|
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_WORD_DATA );
|
|
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_WORD_DATA );
|
|
|
|
// set working device
|
|
if( ( r = ioctl(fd, I2C_SLAVE, addr)) < 0)
|
|
{
|
|
fprintf(stderr, "Error eeprom_open: %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
e->fd = fd;
|
|
e->addr = addr;
|
|
e->dev = dev_fqn;
|
|
e->type = type;
|
|
return 0;
|
|
}
|
|
|
|
int eeprom_close(struct eeprom *e)
|
|
{
|
|
close(e->fd);
|
|
e->fd = -1;
|
|
e->dev = 0;
|
|
e->type = EEPROM_TYPE_UNKNOWN;
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
int eeprom_24c32_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data)
|
|
{
|
|
__u8 buf[3] = { (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data };
|
|
return i2c_write_3b(e, buf);
|
|
}
|
|
|
|
|
|
int eeprom_24c32_read_current_byte(struct eeprom* e)
|
|
{
|
|
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
|
|
return i2c_smbus_read_byte(e->fd);
|
|
}
|
|
|
|
int eeprom_24c32_read_byte(struct eeprom* e, __u16 mem_addr)
|
|
{
|
|
int r;
|
|
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
|
|
__u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff };
|
|
r = i2c_write_2b(e, buf);
|
|
if (r < 0)
|
|
return r;
|
|
r = i2c_smbus_read_byte(e->fd);
|
|
return r;
|
|
}
|
|
#endif
|
|
|
|
|
|
int eeprom_read_current_byte(struct eeprom* e)
|
|
{
|
|
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
|
|
return i2c_smbus_read_byte(e->fd);
|
|
}
|
|
|
|
int eeprom_read_byte(struct eeprom* e, __u16 mem_addr)
|
|
{
|
|
int r;
|
|
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
|
|
if(e->type == EEPROM_TYPE_8BIT_ADDR)
|
|
{
|
|
__u8 buf = mem_addr & 0x0ff;
|
|
r = i2c_write_1b(e, buf);
|
|
} else if(e->type == EEPROM_TYPE_16BIT_ADDR) {
|
|
__u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff };
|
|
r = i2c_write_2b(e, buf);
|
|
} else {
|
|
fprintf(stderr, "ERR: unknown eeprom type\n");
|
|
return -1;
|
|
}
|
|
if (r < 0)
|
|
return r;
|
|
r = i2c_smbus_read_byte(e->fd);
|
|
return r;
|
|
}
|
|
|
|
int eeprom_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data)
|
|
{
|
|
if(e->type == EEPROM_TYPE_8BIT_ADDR) {
|
|
__u8 buf[2] = { mem_addr & 0x00ff, data };
|
|
return i2c_write_2b(e, buf);
|
|
} else if(e->type == EEPROM_TYPE_16BIT_ADDR) {
|
|
__u8 buf[3] =
|
|
{ (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data };
|
|
return i2c_write_3b(e, buf);
|
|
}
|
|
fprintf(stderr, "ERR: unknown eeprom type\n");
|
|
return -1;
|
|
}
|
|
|
|
int eeprom_wait_ready(struct eeprom *e, int max_ms_to_wait)
|
|
{
|
|
while (max_ms_to_wait > 0) {
|
|
int r = i2c_smbus_write_quick(e->fd, 0);
|
|
if (r == 0) {
|
|
return r;
|
|
}
|
|
usleep(1000);
|
|
--max_ms_to_wait;
|
|
}
|
|
return -1;
|
|
}
|
|
|