File: [local] / sys / dev / i2c / pca9532.c (download)
Revision 1.1.1.1 (vendor branch), Tue Mar 4 16:09:59 2008 UTC (16 years, 5 months ago) by nbrk
Branch: OPENBSD_4_2_BASE, MAIN
CVS Tags: jornada-partial-support-wip, HEAD Changes since 1.1: +0 -0 lines
Import of OpenBSD 4.2 release kernel tree with initial code to support
Jornada 720/728, StrongARM 1110-based handheld PC.
At this point kernel roots on NFS and boots into vfs_mountroot() and traps.
What is supported:
- glass console, Jornada framebuffer (jfb) works in 16bpp direct color mode
(needs some palette tweaks for non black/white/blue colors, i think)
- saic, SA11x0 interrupt controller (needs cleanup)
- sacom, SA11x0 UART (supported only as boot console for now)
- SA11x0 GPIO controller fully supported (but can't handle multiple interrupt
handlers on one gpio pin)
- sassp, SSP port on SA11x0 that attaches spibus
- Jornada microcontroller (jmcu) to control kbd, battery, etc throught
the SPI bus (wskbd attaches on jmcu, but not tested)
- tod functions seem work
- initial code for SA-1111 (chip companion) : this is TODO
Next important steps, i think:
- gpio and intc on sa1111
- pcmcia support for sa11x0 (and sa1111 help logic)
- REAL root on nfs when we have PCMCIA support (we may use any of supported pccard NICs)
- root on wd0! (using already supported PCMCIA-ATA)
|
/* $OpenBSD: pca9532.c,v 1.2 2006/06/17 23:00:47 drahn Exp $ */
/*
* Copyright (c) 2006 Dale Rahn <drahn@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/fcntl.h>
#include <sys/uio.h>
#include <sys/conf.h>
#include <sys/gpio.h>
#include <dev/i2c/i2cvar.h>
#include <dev/gpio/gpiovar.h>
#include "gpio.h"
/* driver for PCA 9532 */
#define PCALED_ADDR 0x60
#define PCALED_GPIO_NPINS 16
struct pcaled_softc {
struct device sc_dev;
i2c_tag_t sc_tag;
int sc_addr;
struct gpio_chipset_tag sc_gpio_gc;
struct gpio_pin sc_gpio_pin[PCALED_GPIO_NPINS];
};
int pcaled_match(struct device *, void *, void *);
void pcaled_attach(struct device *, struct device *, void *);
int pcaled_gpio_pin_read(void *arg, int pin);
void pcaled_gpio_pin_write (void *arg, int pin, int value);
void pcaled_gpio_pin_ctl (void *arg, int pin, int flags);
struct cfattach pcaled_ca = {
sizeof(struct pcaled_softc), pcaled_match, pcaled_attach
};
struct cfdriver pcaled_cd = {
NULL, "pcaled", DV_DULL
};
int
pcaled_match(struct device *parent, void *v, void *arg)
{
struct i2c_attach_args *ia = arg;
int ok = 0;
uint8_t cmd, data;
if (ia->ia_addr != PCALED_ADDR)
return (0);
/* attempt to read input register 0 */
iic_acquire_bus(ia->ia_tag, I2C_F_POLL);
cmd = 0;
if (iic_exec(ia->ia_tag, I2C_OP_READ_WITH_STOP, ia->ia_addr,
&cmd, 1, &data, 1, I2C_F_POLL))
goto fail;
cmd = 9;
if (iic_exec(ia->ia_tag, I2C_OP_READ_WITH_STOP, ia->ia_addr,
&cmd, 1, &data, 1, I2C_F_POLL))
goto fail;
ok = 1;
fail:
iic_release_bus(ia->ia_tag, I2C_F_POLL);
return (ok);
}
void
pcaled_attach(struct device *parent, struct device *self, void *arg)
{
struct pcaled_softc *sc = (void *)self;
struct i2c_attach_args *ia = arg;
struct gpiobus_attach_args gba;
int i;
uint8_t cmd, data;
sc->sc_tag = ia->ia_tag;
sc->sc_addr = ia->ia_addr;
iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
for (i = 0; i < PCALED_GPIO_NPINS; i++) {
sc->sc_gpio_pin[i].pin_num = i;
sc->sc_gpio_pin[i].pin_caps = GPIO_PIN_INOUT;
if (i < 8)
cmd = 0;
else
cmd = 1;
if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
&cmd, 1, &data, 1, I2C_F_POLL))
goto fail; /* XXX */
sc->sc_gpio_pin[i].pin_state = (data >> (i & 3)) & 1;
}
sc->sc_gpio_gc.gp_cookie = sc;
sc->sc_gpio_gc.gp_pin_read = pcaled_gpio_pin_read;
sc->sc_gpio_gc.gp_pin_write = pcaled_gpio_pin_write;
sc->sc_gpio_gc.gp_pin_ctl = pcaled_gpio_pin_ctl;
printf(": PCA9532 LED controller\n");
gba.gba_name = "gpio";
gba.gba_gc = &sc->sc_gpio_gc;
gba.gba_pins = sc->sc_gpio_pin;
gba.gba_npins = PCALED_GPIO_NPINS;
#if NGPIO > 0
config_found(&sc->sc_dev, &gba, gpiobus_print);
#endif
fail:
iic_release_bus(sc->sc_tag, I2C_F_POLL);
}
int
pcaled_gpio_pin_read(void *arg, int pin)
{
struct pcaled_softc *sc = arg;
iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
uint8_t cmd, data;
if (pin < 8)
cmd = 0;
else
cmd = 1;
if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
&cmd, 1, &data, 1, I2C_F_POLL))
goto fail; /* XXX */
fail:
iic_release_bus(sc->sc_tag, I2C_F_POLL);
return (data >> (pin & 3)) & 1;
}
void
pcaled_gpio_pin_write (void *arg, int pin, int value)
{
struct pcaled_softc *sc = arg;
uint8_t cmd, data;
if (pin < 4)
cmd = 6;
else if (pin < 8)
cmd = 7;
else if (pin < 12)
cmd = 8;
else
cmd = 9;
if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
&cmd, 1, &data, 1, I2C_F_POLL))
goto fail; /* XXX */
data &= ~(0x3 << (2*(pin & 3)));
data |= (value << (2*(pin & 3)));
if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
&cmd, 1, &data, 1, I2C_F_POLL))
goto fail; /* XXX */
fail:
iic_release_bus(sc->sc_tag, I2C_F_POLL);
}
void
pcaled_gpio_pin_ctl (void *arg, int pin, int flags)
{
/* XXX all pins are inout */
}