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:
parent
8d344bc387
commit
be9836eac7
|
@ -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);
|
||||
|
|
|
@ -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_ */
|
||||
|
|
Loading…
Reference in New Issue