IIC(4)
π IIC(4) β Kernel Interfaces Manual π
okay bestie, sit DOWN because we're talking about the iic driver and honestly? it's giving legend behavior. this is the I2C generic I/O device driver, and it lives in the Kernel Interfaces Manual. let's get into it β¨
πΈ NAME πΈ
iic β the I2C generic I/O device driver. that's it, that's the whole name, no cap.
β¨ SYNOPSIS β¨
device iic
#include <dev/iicbus/iic.h>
π¦ DESCRIPTION π¦
so the iic device driver is your generic I/O plug to literally any iicbus(4) instance. it's the main character that lets you talk to your I2C devices.
to actually control I2C devices, you use /dev/iic? with these ioctls, and each one is a whole vibe:
I2CSTARTβ takes a(struct iiccmd). this one sends the start condition to the slave specified by theslaveelement, out to the bus. now theslaveelement is a 7-bit address plus a read/write bit β meaning it's7-bit address << 1 | r/w. if that read/write bit is set, you're initiating a read operation; if it's cleared, it's a write operation. all the other elements? ignored, bestie, they're not invited. and if this works, the file descriptor gets exclusive ownership of the underlyingiicbusinstance. iconic.I2CRPTSTARTβ takes a(struct iiccmd). sends the repeated start condition to the slave specified by theslaveelement to the bus. specify the slave address the same way you do inI2CSTART. all the other elements are ignored. heads up though:I2CSTARTmust have already been issued on the same file descriptor before this one, no skipping steps πI2CSTOPβ no argument gets passed here. it sends the stop condition to the bus. ifI2CSTARTwas previously issued on the file descriptor, the current transaction gets terminated and exclusive ownership of the underlyingiicbusinstance is released. if it wasn't issued? nothing happens. no action performed, we simply move on.I2CRSTCARDβ takes a(struct iiccmd). this one resets the bus, and the argument is completely and utterly ignored, so don't even stress about it. this command does not requireI2CSTARTto have been previously issued on the file descriptor. but if it was previously issued, then exclusive ownership of the underlyingiicbusinstance gets released. either way we're fine β¨I2CWRITEβ takes a(struct iiccmd). writes data to theiicbus(4). the bus must already be started by a previousI2CSTARTon the file descriptor β no starting from scratch. theslaveelement is ignored. thecountelement is the number of bytes to write. thelastelement is a boolean flag, and it must be zero when additional read commands will follow, or non-zero if this is the last command. thebufelement is a pointer to the data you're writing to the bus. slay.I2CREADβ takes a(struct iiccmd). reads data from theiicbus(4). same deal: the bus must already be started by a previousI2CSTARTon the file descriptor. theslaveelement is ignored. thecountelement is the number of bytes to read. thelastelement is a boolean flag β zero when additional read commands will follow, non-zero if this is the last command. thebufelement is a pointer to where the data read from the bus gets stored.
β οΈ real talk: short reads on the bus produce undefined results. that's not a vibe, that's a warning. protect your peace (and your buffers).
I2CRDWRβ takes a(struct iic_rdwr_data). this is the generic read/write interface, and it's lowkey powerful: it allows an arbitrary number of commands to be sent to an arbitrary number of devices on the bus. but listen β any previous transaction started byI2CSTARTmust be terminated byI2CSTOPorI2CRSTCARDbeforeI2CRDWRcan be issued on the same file descriptor. no loose ends. a read transfer is specified ifIIC_M_RDis set inflags; otherwise it's a write transfer. theslaveelement specifies the 7-bit address along with the read/write bit for the transfer, and the read/write bit gets handled by theiicbusstack based on the specified transfer operation (so you don't gotta do it yourself, king). thelenelement is the number of(struct iic_msg)messages encoded on(struct iic_rdwr_data). thebufelement is a buffer for that data. this ioctl is intended to be Linux compatible, iykyk.I2CSADDRβ takes a(uint8_t). this associates the specified address with the file descriptor so it can be used by subsequentread(2)orwrite(2)calls. the argument is an 8-bit address β that's7-bit address << 1. the read/write bit in the least-significant position is ignored, and any subsequent read or write operation will set or clear that bit as needed. so considerate of it honestly.
π the data structures π
these following data structures are defined in <dev/iicbus/iic.h> and were referenced up above, so here they are in all their glory:
struct iiccmd {
u_char slave;
int count;
int last;
char *buf;
};
/* Designed to be compatible with linux's struct i2c_msg */
struct iic_msg
{
uint16_t slave;
uint16_t flags;
#define IIC_M_WR 0 /* Fake flag for write */
#define IIC_M_RD 0x0001 /* read vs write */
#define IIC_M_NOSTOP 0x0002 /* do not send a I2C stop after message */
#define IIC_M_NOSTART 0x0004 /* do not send a I2C start before message */
uint16_t len; /* msg length */
uint8_t * buf;
};
struct iic_rdwr_data {
struct iic_msg *msgs;
uint32_t nmsgs;
};
π read(2) and write(2), the casual route π
you can also just use read(2) or write(2), in which case the I2C start/stop handshake is managed by iicbus(4) for you. the address used for the read/write operation is the one passed to the most recent I2CSTART ioctl(2) or I2CSADDR ioctl(2) on the open /dev/iic? file descriptor.
and here's the part where it gets cute: closing the file descriptor clears any addressing state established by a previous I2CSTART or I2CSADDR, stops any transaction established by a not-yet-terminated I2CSTART, and releases iicbus ownership. clean slate, we love a fresh start π«Ά
and because addressing state is stored on a per-file-descriptor basis, it's totally permissible for multiple file descriptors to be simultaneously open on the same /dev/iic? device. concurrent transactions on those descriptors are synchronized by the exclusive-ownership requests issued to the underlying iicbus instance. teamwork, but make it synchronized.
π SEE ALSO π
ioctl(2), read(2), write(2), iicbus(4)
π HISTORY π
the iic manual page first appeared in FreeBSD 3.0. a true elder, respect the lineage β¨
π AUTHORS π
this manual page was written by Nicolas Souchu and M. Warner Losh. absolute icons, thank you for your service π«‘
and that's the whole page bestie!! this beauty comes from the Debian distribution, dated May 15, 2015, and ngl it still eats. go forth and talk to your I2C devices responsibly πβ¨ππ¦πΈπ
π¦ where this page comes from
- debian bookworm: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- debian trixie: freebsd-manpages 12.2-2 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu jammy: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu noble: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu questing: freebsd-manpages 12.2-2
- ubuntu resolute: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu stonking: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- Copyright (c) 2006, M. Warner Losh
- Copyright (c) 1998, Nicolas Souchu
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms