Allow i2c child devices to register interrupt handlers to the smbus host

controller. Both interrupt context and process context type handlers are
supported.
This commit is contained in:
jmcneill 2007-02-05 23:31:37 +00:00
parent 8d344bc387
commit be9836eac7
2 changed files with 146 additions and 2 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: i2c.c,v 1.10 2006/11/16 01:32:50 christos Exp $ */
/* $NetBSD: i2c.c,v 1.11 2007/02/05 23:31:37 jmcneill Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@ -40,6 +40,10 @@
#include <sys/device.h>
#include <sys/event.h>
#include <sys/conf.h>
#include <sys/malloc.h>
#include <sys/kthread.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <dev/i2c/i2cvar.h>
@ -51,6 +55,9 @@ struct iic_softc {
int sc_type;
};
static void iic_smbus_intr_thread(void *);
static void iic_smbus_intr_thread1(void *);
int
iicbus_print(void *aux, const char *pnp)
{
@ -109,6 +116,9 @@ iic_attach(struct device *parent, struct device *self, void *aux)
sc->sc_tag = iba->iba_tag;
sc->sc_type = iba->iba_type;
sc->sc_tag->ic_devname = self->dv_xname;
kthread_create(iic_smbus_intr_thread, sc->sc_tag);
/*
* Attach all i2c devices described in the kernel
@ -117,5 +127,120 @@ iic_attach(struct device *parent, struct device *self, void *aux)
config_search_ia(iic_search, self, "iic", NULL);
}
static void
iic_smbus_intr_thread1(void *aux)
{
i2c_tag_t ic;
struct ic_intr_list *il;
int rv;
ic = (i2c_tag_t)aux;
ic->ic_running = 1;
ic->ic_pending = 0;
printf("iic_smbus_intr_thread1: started\n");
while (ic->ic_running) {
if (ic->ic_pending == 0)
rv = tsleep(ic, PZERO, "iicintr", hz);
if (ic->ic_pending > 0) {
LIST_FOREACH(il, &(ic->ic_proc_list), il_next) {
(*il->il_intr)(il->il_intrarg);
}
ic->ic_pending--;
}
}
kthread_exit(0);
}
static void
iic_smbus_intr_thread(void *aux)
{
i2c_tag_t ic;
int rv;
ic = (i2c_tag_t)aux;
rv = kthread_create1(iic_smbus_intr_thread1, ic, &ic->ic_intr_thread,
"%s", ic->ic_devname);
if (rv)
printf("%s: unable to create intr thread\n", ic->ic_devname);
}
void *
iic_smbus_intr_establish(i2c_tag_t ic, int (*intr)(void *), void *intrarg)
{
struct ic_intr_list *il;
il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK);
if (il == NULL)
return NULL;
il->il_intr = intr;
il->il_intrarg = intrarg;
LIST_INSERT_HEAD(&(ic->ic_list), il, il_next);
return il;
}
void
iic_smbus_intr_disestablish(i2c_tag_t ic, void *hdl)
{
struct ic_intr_list *il;
il = (struct ic_intr_list *)hdl;
LIST_REMOVE(il, il_next);
free(il, M_DEVBUF);
return;
}
void *
iic_smbus_intr_establish_proc(i2c_tag_t ic, int (*intr)(void *), void *intrarg)
{
struct ic_intr_list *il;
il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK);
if (il == NULL)
return NULL;
il->il_intr = intr;
il->il_intrarg = intrarg;
LIST_INSERT_HEAD(&(ic->ic_proc_list), il, il_next);
return il;
}
void
iic_smbus_intr_disestablish_proc(i2c_tag_t ic, void *hdl)
{
struct ic_intr_list *il;
il = (struct ic_intr_list *)hdl;
LIST_REMOVE(il, il_next);
free(il, M_DEVBUF);
return;
}
int
iic_smbus_intr(i2c_tag_t ic)
{
struct ic_intr_list *il;
LIST_FOREACH(il, &(ic->ic_list), il_next) {
(*il->il_intr)(il->il_intrarg);
}
ic->ic_pending++;
wakeup(ic);
return 1;
}
CFATTACH_DECL(iic, sizeof(struct iic_softc),
iic_match, iic_attach, NULL, NULL);

View File

@ -1,4 +1,4 @@
/* $NetBSD: i2cvar.h,v 1.4 2006/06/26 18:19:40 drochner Exp $ */
/* $NetBSD: i2cvar.h,v 1.5 2007/02/05 23:31:37 jmcneill Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@ -48,6 +48,12 @@
#define I2C_F_POLL 0x08 /* poll, don't sleep */
#define I2C_F_PEC 0x10 /* smbus packet error checking */
struct ic_intr_list {
LIST_ENTRY(ic_intr_list) il_next;
int (*il_intr)(void *);
void *il_intrarg;
};
/*
* This structure provides the interface between the i2c framework
* and the underlying i2c controller.
@ -88,6 +94,13 @@ typedef struct i2c_controller {
int (*ic_initiate_xfer)(void *, i2c_addr_t, int);
int (*ic_read_byte)(void *, uint8_t *, int);
int (*ic_write_byte)(void *, uint8_t, int);
LIST_HEAD(, ic_intr_list) ic_list;
LIST_HEAD(, ic_intr_list) ic_proc_list;
volatile int ic_running;
volatile int ic_pending;
struct proc *ic_intr_thread;
const char *ic_devname;
} *i2c_tag_t;
/* I2C bus types */
@ -154,4 +167,10 @@ int iic_smbus_block_read(i2c_tag_t, i2c_addr_t, uint8_t, uint8_t *,
int iic_smbus_block_write(i2c_tag_t, i2c_addr_t, uint8_t, uint8_t *,
size_t, int);
void * iic_smbus_intr_establish(i2c_tag_t, int (*)(void *), void *);
void * iic_smbus_intr_establish_proc(i2c_tag_t, int (*)(void *), void *);
void iic_smbus_intr_disestablish(i2c_tag_t, void *);
void iic_smbus_intr_disestablish_proc(i2c_tag_t, void *);
int iic_smbus_intr(i2c_tag_t);
#endif /* _DEV_I2C_I2CVAR_H_ */