libi2cdriver: library for i2c device drivers

Change-Id: Ib6d5617e4b62e0bc5b25e6fa92b44baf536b1961
This commit is contained in:
Thomas Cort 2013-07-15 10:29:24 -04:00
parent 3c59273c97
commit 8a643e5128
7 changed files with 228 additions and 2 deletions

View file

@ -97,6 +97,8 @@
./usr/lib/libclkconf_pic.a minix-sys
./usr/lib/libgpio.a minix-sys
./usr/lib/libgpio_pic.a minix-sys
./usr/lib/libi2cdriver.a minix-sys
./usr/lib/libi2cdriver_pic.a minix-sys
./usr/lib/libpadconf.a minix-sys
./usr/lib/libpadconf_pic.a minix-sys
./usr/mdec minix-sys

View file

@ -1073,6 +1073,7 @@
./usr/include/minix/hash.h minix-sys
./usr/include/minix/hgfs.h minix-sys
./usr/include/minix/i2c.h minix-sys
./usr/include/minix/i2cdriver.h minix-sys
./usr/include/minix/input.h minix-sys
./usr/include/minix/ioctl.h minix-sys
./usr/include/minix/ipcconst.h minix-sys

View file

@ -11,7 +11,7 @@ INCS+= acpi.h audio_fw.h bitmap.h \
debug.h devio.h devman.h dmap.h \
driver.h drivers.h drvlib.h ds.h \
endpoint.h fb.h fslib.h gpio.h gcov.h hash.h \
hgfs.h i2c.h ioctl.h input.h ipc.h ipcconst.h \
hgfs.h i2c.h i2cdriver.h ioctl.h input.h ipc.h ipcconst.h \
keymap.h log.h mmio.h mount.h mthread.h minlib.h \
netdriver.h optset.h padconf.h partition.h portio.h \
priv.h procfs.h profile.h queryparam.h \

21
include/minix/i2cdriver.h Normal file
View file

@ -0,0 +1,21 @@
/* Prototypes and definitions for i2c drivers. */
#ifndef _MINIX_I2CDRIVER_H
#define _MINIX_I2CDRIVER_H
#include <minix/endpoint.h>
#include <minix/i2c.h>
#include <minix/ipc.h>
/* Functions defined by i2cdriver.c: */
int i2cdriver_env_parse(uint32_t * bus, i2c_addr_t * address,
i2c_addr_t * valid_addrs);
void i2cdriver_announce(uint32_t bus);
endpoint_t i2cdriver_bus_endpoint(uint32_t bus);
int i2cdriver_subscribe_bus_updates(uint32_t bus);
void i2cdriver_handle_bus_update(endpoint_t * bus_endpoint, uint32_t bus,
i2c_addr_t address);
int i2cdriver_reserve_device(endpoint_t bus_endpoint, i2c_addr_t address);
int i2cdriver_exec(endpoint_t bus_endpoint, minix_i2c_ioctl_exec_t *ioctl_exec);
#endif /* _MINIX_I2CDRIVER_H */

View file

@ -54,7 +54,7 @@ SUBDIR += libvassert libhgfs libvboxfs libvirtio
.endif
.if (${MACHINE_ARCH} == "earm")
SUBDIR += libclkconf libgpio libpadconf
SUBDIR += libclkconf libgpio libi2cdriver libpadconf
.endif
.if (${MKRUMP} != "no")

View file

@ -0,0 +1,7 @@
# Makefile for libi2cdriver
LIB= i2cdriver
SRCS= i2cdriver.c
.include <bsd.lib.mk>

View file

@ -0,0 +1,195 @@
/* This file contains device independent i2c device driver helpers. */
#include <minix/drivers.h>
#include <minix/endpoint.h>
#include <minix/i2c.h>
#include <minix/i2cdriver.h>
#include <minix/ipc.h>
#include <minix/ds.h>
void
i2cdriver_announce(uint32_t bus)
{
/* Announce we are up after a fresh start or restart. */
int r;
char key[DS_MAX_KEYLEN];
char label[DS_MAX_KEYLEN];
char *driver_prefix = "drv.i2c.";
/* Callers are allowed to use sendrec to communicate with drivers.
* For this reason, there may blocked callers when a driver restarts.
* Ask the kernel to unblock them (if any).
*/
#if USE_STATECTL
if ((r = sys_statectl(SYS_STATE_CLEAR_IPC_REFS)) != OK) {
panic("chardriver_init: sys_statectl failed: %d", r);
}
#endif
/* Publish a driver up event. */
r = ds_retrieve_label_name(label, getprocnr());
if (r != OK) {
panic("unable to get own label: %d\n", r);
}
/* example key: drv.i2c.1.cat24c245.0x50 */
snprintf(key, DS_MAX_KEYLEN, "%s%d.%s", driver_prefix, bus, label);
r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE);
if (r != OK) {
panic("unable to publish driver up event: %d\n", r);
}
}
int
i2cdriver_env_parse(uint32_t * bus, i2c_addr_t * address,
i2c_addr_t * valid_addrs)
{
/* fill in bus and address with the values passed on the command line */
int r;
int found;
long int busl;
long int addressl;
r = env_parse("bus", "d", 0, &busl, 1, 3);
if (r != EP_SET) {
return -1;
}
*bus = (uint32_t) busl;
r = env_parse("address", "x", 0, &addressl, 0x0000, 0x03ff);
if (r != EP_SET) {
return -1;
}
*address = addressl;
found = 0;
while (*valid_addrs != 0x0000) {
if (*address == *valid_addrs) {
found = 1;
break;
}
valid_addrs++;
}
if (!found) {
return 1;
}
return 0;
}
endpoint_t
i2cdriver_bus_endpoint(uint32_t bus)
{
/* locate the driver for the i2c bus itself */
int r;
char *label_prefix = "i2c.";
char label[DS_MAX_KEYLEN];
endpoint_t bus_endpoint;
snprintf(label, DS_MAX_KEYLEN, "%s%d", label_prefix, bus);
r = ds_retrieve_label_endpt(label, &bus_endpoint);
if (r != OK) {
return 0;
}
return bus_endpoint;
}
int
i2cdriver_subscribe_bus_updates(uint32_t bus)
{
int r;
char regex[DS_MAX_KEYLEN];
/* only capture events for the specified bus */
snprintf(regex, DS_MAX_KEYLEN, "drv\\.chr\\.i2c\\.%d", bus);
/* Subscribe to driver events from the i2c bus */
r = ds_subscribe(regex, DSF_INITIAL | DSF_OVERWRITE);
if (r != OK) {
return r;
}
return OK;
}
void
i2cdriver_handle_bus_update(endpoint_t * bus_endpoint, uint32_t bus,
i2c_addr_t address)
{
char key[DS_MAX_KEYLEN];
u32_t value;
int type;
endpoint_t owner_endpoint, old_endpoint;
int r;
/* check for pending events */
while ((r = ds_check(key, &type, &owner_endpoint)) == OK) {
r = ds_retrieve_u32(key, &value);
if (r != OK) {
return;
}
if (value == DS_DRIVER_UP) {
old_endpoint = *bus_endpoint;
/* look up the bus's (potentially new) endpoint */
*bus_endpoint = i2cdriver_bus_endpoint(bus);
/* was updated endpoint? */
if (old_endpoint != *bus_endpoint) {
/* re-reserve device to allow the driver to
* continue working, even through a manual
* down/up.
*/
i2cdriver_reserve_device(*bus_endpoint,
address);
}
}
}
}
int
i2cdriver_reserve_device(endpoint_t bus_endpoint, i2c_addr_t address)
{
int r;
message m;
m.m_type = BUSC_I2C_RESERVE;
m.DEVICE = address;
r = sendrec(bus_endpoint, &m);
if (r != OK) {
return EIO;
}
return m.REP_STATUS; /* return reply code OK, EBUSY, EINVAL, etc. */
}
int
i2cdriver_exec(endpoint_t bus_endpoint, minix_i2c_ioctl_exec_t * ioctl_exec)
{
int r;
message m;
cp_grant_id_t grant_nr;
grant_nr = cpf_grant_direct(bus_endpoint, (vir_bytes) ioctl_exec,
sizeof(minix_i2c_ioctl_exec_t), CPF_READ | CPF_WRITE);
memset(&m, '\0', sizeof(message));
m.m_type = BUSC_I2C_EXEC;
m.IO_GRANT = (char *) grant_nr;
r = sendrec(bus_endpoint, &m);
cpf_revoke(grant_nr);
if (r != OK) {
return EIO;
}
return m.REP_STATUS;
}