Implement a handful of missing smbus protocol functions. Proposed on

tech-kern: http://mail-index.netbsd.org/tech-kern/2006/03/16/0029.html
This commit is contained in:
jmcneill 2006-03-27 23:59:38 +00:00
parent f02decf866
commit 913f185f8f
3 changed files with 196 additions and 4 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: i2c.c,v 1.5 2005/12/11 12:21:22 christos Exp $ */
/* $NetBSD: i2c.c,v 1.6 2006/03/27 23:59:38 jmcneill Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@ -48,6 +48,7 @@
struct iic_softc {
struct device sc_dev;
i2c_tag_t sc_tag;
int sc_type;
};
int
@ -66,7 +67,8 @@ iic_print(void *aux, const char *pnp)
{
struct i2c_attach_args *ia = aux;
aprint_normal(" addr 0x%x", ia->ia_addr);
if (ia->ia_addr != (i2c_addr_t)-1)
aprint_normal(" addr 0x%x", ia->ia_addr);
return (UNCONF);
}
@ -81,6 +83,7 @@ iic_search(struct device *parent, struct cfdata *cf,
ia.ia_tag = sc->sc_tag;
ia.ia_addr = cf->cf_loc[IICCF_ADDR];
ia.ia_size = cf->cf_loc[IICCF_SIZE];
ia.ia_type = sc->sc_type;
if (config_match(parent, cf, &ia) > 0)
config_attach(parent, cf, &ia, iic_print);
@ -107,6 +110,7 @@ iic_attach(struct device *parent, struct device *self, void *aux)
aprint_normal(": I2C bus\n");
sc->sc_tag = iba->iba_tag;
sc->sc_type = iba->iba_type;
/*
* Attach all i2c devices described in the kernel

View File

@ -1,4 +1,4 @@
/* $NetBSD: i2c_exec.c,v 1.4 2005/12/11 12:21:22 christos Exp $ */
/* $NetBSD: i2c_exec.c,v 1.5 2006/03/27 23:59:38 jmcneill Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@ -44,6 +44,9 @@
#define _I2C_PRIVATE
#include <dev/i2c/i2cvar.h>
static uint8_t iic_smbus_crc8(uint16_t);
static uint8_t iic_smbus_pec(int, uint8_t *, uint8_t *);
/*
* iic_exec:
*
@ -63,6 +66,37 @@ iic_exec(i2c_tag_t tag, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
int error;
size_t len;
if ((flags & I2C_F_PEC) && cmdlen > 0 && tag->ic_exec != NULL) {
uint8_t data[33]; /* XXX */
uint8_t b[3];
b[0] = addr << 1;
b[1] = cmd[0];
switch (buflen) {
case 0:
data[0] = iic_smbus_pec(2, b, NULL);
buflen++;
break;
case 1:
b[2] = buf[0];
data[0] = iic_smbus_pec(3, b, NULL);
data[1] = b[2];
buflen++;
break;
case 2:
break;
default:
memcpy(data, vbuf, sizeof(vbuf));
data[sizeof(vbuf)] = iic_smbus_pec(2, b, data);
buflen++;
break;
}
return ((*tag->ic_exec)(tag->ic_cookie, op, addr, cmd,
cmdlen, data, buflen, flags));
}
/*
* Defer to the controller if it provides an exec function. Use
* it if it does.
@ -127,6 +161,24 @@ iic_smbus_write_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd,
&val, 1, flags));
}
/*
* iic_smbus_write_word:
*
* Perform an SMBus "write word" operation.
*/
int
iic_smbus_write_word(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd,
uint16_t val, int flags)
{
uint8_t vbuf[2];
vbuf[0] = val & 0xff;
vbuf[1] = (val >> 8) & 0xff;
return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &cmd, 1,
vbuf, 2, flags));
}
/*
* iic_smbus_read_byte:
*
@ -141,6 +193,20 @@ iic_smbus_read_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd,
valp, 1, flags));
}
/*
* iic_smbus_read_word:
*
* Perform an SMBus "read word" operation.
*/
int
iic_smbus_read_word(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd,
uint16_t *valp, int flags)
{
return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, &cmd, 1,
(uint8_t *)valp, 2, flags));
}
/*
* iic_smbus_receive_byte:
*
@ -154,3 +220,110 @@ iic_smbus_receive_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t *valp,
return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, NULL, 0,
valp, 1, flags));
}
/*
* iic_smbus_send_byte:
*
* Perform an SMBus "send byte" operation.
*/
int
iic_smbus_send_byte(i2c_tag_t tag, i2c_addr_t addr, uint8_t val, int flags)
{
return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, NULL, 0,
&val, 1, flags));
}
/*
* iic_smbus_quick_read:
*
* Perform an SMBus "quick read" operation.
*/
int
iic_smbus_quick_read(i2c_tag_t tag, i2c_addr_t addr, int flags)
{
return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, NULL, 0,
NULL, 0, flags));
}
/*
* iic_smbus_quick_write:
*
* Perform an SMBus "quick write" operation.
*/
int
iic_smbus_quick_write(i2c_tag_t tag, i2c_addr_t addr, int flags)
{
return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, NULL, 0,
NULL, 0, flags));
}
/*
* iic_smbus_block_read:
*
* Perform an SMBus "block read" operation.
*/
int
iic_smbus_block_read(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd,
uint8_t *vbuf, size_t buflen, int flags)
{
return (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, &cmd, 1,
vbuf, buflen, flags));
}
/*
* iic_smbus_block_write:
*
* Perform an SMBus "block write" operation.
*/
int
iic_smbus_block_write(i2c_tag_t tag, i2c_addr_t addr, uint8_t cmd,
uint8_t *vbuf, size_t buflen, int flags)
{
return (iic_exec(tag, I2C_OP_WRITE_WITH_STOP, addr, &cmd, 1,
vbuf, buflen, flags));
}
/*
* iic_smbus_crc8
*
* Private helper for calculating packet error checksum
*/
static uint8_t
iic_smbus_crc8(uint16_t data)
{
int i;
for (i = 0; i < 8; i++) {
if (data & 0x8000)
data = data ^ (0x1070U << 3);
data = data << 1;
}
return (uint8_t)(data >> 8);
}
/*
* iic_smbus_pec
*
* Private function for calculating packet error checking on SMBus
* packets.
*/
static uint8_t
iic_smbus_pec(int count, uint8_t *s, uint8_t *r)
{
int i;
uint8_t crc = 0;
for (i = 0; i < count; i++)
crc = iic_smbus_crc8((crc ^ s[i]) << 8);
if (r != NULL)
for (i = 0; i <= r[0]; i++)
crc = iic_smbus_crc8((crc ^ r[i]) << 8);
return crc;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: i2cvar.h,v 1.2 2005/12/11 12:21:22 christos Exp $ */
/* $NetBSD: i2cvar.h,v 1.3 2006/03/27 23:59:38 jmcneill Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@ -46,6 +46,7 @@
#define I2C_F_LAST 0x02 /* last byte of read */
#define I2C_F_STOP 0x04 /* send stop after byte */
#define I2C_F_POLL 0x08 /* poll, don't sleep */
#define I2C_F_PEC 0x10 /* smbus packet error checking */
/*
* This structure provides the interface between the i2c framework
@ -89,10 +90,14 @@ typedef struct i2c_controller {
int (*ic_write_byte)(void *, uint8_t, int);
} *i2c_tag_t;
/* I2C bus types */
#define I2C_TYPE_SMBUS 1
/* Used to attach the i2c framework to the controller. */
struct i2cbus_attach_args {
const char *iba_name; /* bus name ("iic") */
i2c_tag_t iba_tag; /* the controller */
int iba_type; /* bus type */
};
/* Used to attach devices on the i2c bus. */
@ -100,6 +105,7 @@ struct i2c_attach_args {
i2c_tag_t ia_tag; /* our controller */
i2c_addr_t ia_addr; /* address of device */
int ia_size; /* size (for EEPROMs) */
int ia_type; /* bus type */
};
/*
@ -137,7 +143,16 @@ int iic_exec(i2c_tag_t, i2c_op_t, i2c_addr_t, const void *,
size_t, void *, size_t, int);
int iic_smbus_write_byte(i2c_tag_t, i2c_addr_t, uint8_t, uint8_t, int);
int iic_smbus_write_word(i2c_tag_t, i2c_addr_t, uint8_t, uint16_t, int);
int iic_smbus_read_byte(i2c_tag_t, i2c_addr_t, uint8_t, uint8_t *, int);
int iic_smbus_read_word(i2c_tag_t, i2c_addr_t, uint8_t, uint16_t *, int);
int iic_smbus_receive_byte(i2c_tag_t, i2c_addr_t, uint8_t *, int);
int iic_smbus_send_byte(i2c_tag_t, i2c_addr_t, uint8_t, int);
int iic_smbus_quick_read(i2c_tag_t, i2c_addr_t, int);
int iic_smbus_quick_write(i2c_tag_t, i2c_addr_t, int);
int iic_smbus_block_read(i2c_tag_t, i2c_addr_t, uint8_t, uint8_t *,
size_t, int);
int iic_smbus_block_write(i2c_tag_t, i2c_addr_t, uint8_t, uint8_t *,
size_t, int);
#endif /* _DEV_I2C_I2CVAR_H_ */