Module Name: src Committed By: nonaka Date: Fri Apr 9 10:09:50 UTC 2010
Modified Files: src/sys/conf: files Added Files: src/sys/dev/ic: pca9564.c pca9564reg.h pca9564var.h Log Message: Added PCA9564 I2C Controller driver. To generate a diff of this commit: cvs rdiff -u -r1.984 -r1.985 src/sys/conf/files cvs rdiff -u -r0 -r1.1 src/sys/dev/ic/pca9564.c src/sys/dev/ic/pca9564reg.h \ src/sys/dev/ic/pca9564var.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/conf/files diff -u src/sys/conf/files:1.984 src/sys/conf/files:1.985 --- src/sys/conf/files:1.984 Wed Mar 24 00:31:41 2010 +++ src/sys/conf/files Fri Apr 9 10:09:49 2010 @@ -1,4 +1,4 @@ -# $NetBSD: files,v 1.984 2010/03/24 00:31:41 pgoyette Exp $ +# $NetBSD: files,v 1.985 2010/04/09 10:09:49 nonaka Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 version 20090313 @@ -1043,6 +1043,10 @@ define pcf8584 file dev/ic/pcf8584.c pcf8584 +# PCA9564 i2c controller +define pca9564 +file dev/ic/pca9564.c pca9564 + # ACPI power management timer (hardware access, independent of ACPI) # define acpipmtimer Added files: Index: src/sys/dev/ic/pca9564.c diff -u /dev/null src/sys/dev/ic/pca9564.c:1.1 --- /dev/null Fri Apr 9 10:09:50 2010 +++ src/sys/dev/ic/pca9564.c Fri Apr 9 10:09:50 2010 @@ -0,0 +1,305 @@ +/* $NetBSD: pca9564.c,v 1.1 2010/04/09 10:09:50 nonaka Exp $ */ + +/* + * Copyright (c) 2010 NONAKA Kimihiro <non...@netbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: pca9564.c,v 1.1 2010/04/09 10:09:50 nonaka Exp $"); + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/mutex.h> +#include <sys/bus.h> + +#include <dev/i2c/i2cvar.h> + +#include <dev/ic/pca9564reg.h> +#include <dev/ic/pca9564var.h> + +#if defined(PCA9564_DEBUG) +int pca9564debug = 0; +#define DPRINTF(s) if (pca9564debug) printf s +#else +#define DPRINTF(s) +#endif + +static int pca9564_acquire_bus(void *, int); +static void pca9564_release_bus(void *, int); + +static int pca9564_send_start(void *, int); +static int pca9564_send_stop(void *, int); +static int pca9564_initiate_xfer(void *, uint16_t, int); +static int pca9564_read_byte(void *, uint8_t *, int); +static int pca9564_write_byte(void *, uint8_t, int); + +static int pca9564_ack(void *, bool, int); + +#define CSR_READ(sc, r) (*sc->sc_ios.read_byte)(sc->sc_dev, r) +#define CSR_WRITE(sc, r, v) (*sc->sc_ios.write_byte)(sc->sc_dev, r, v) + +void +pca9564_attach(struct pca9564_softc *sc) +{ + struct i2cbus_attach_args iba; + + aprint_naive("\n"); + aprint_normal(": PCA9564 I2C Controller\n"); + + mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE); + + sc->sc_i2c.ic_cookie = sc; + sc->sc_i2c.ic_acquire_bus = pca9564_acquire_bus; + sc->sc_i2c.ic_release_bus = pca9564_release_bus; + sc->sc_i2c.ic_send_start = pca9564_send_start; + sc->sc_i2c.ic_send_stop = pca9564_send_stop; + sc->sc_i2c.ic_initiate_xfer = pca9564_initiate_xfer; + sc->sc_i2c.ic_read_byte = pca9564_read_byte; + sc->sc_i2c.ic_write_byte = pca9564_write_byte; + sc->sc_i2c.ic_exec = NULL; + + /* set serial clock rate */ + switch (sc->sc_i2c_clock) { + case 330000: /* 330kHz */ + sc->sc_i2c_clock = I2CCON_CR_330KHZ; + break; + case 288000: /* 288kHz */ + sc->sc_i2c_clock = I2CCON_CR_288KHZ; + break; + case 217000: /* 217kHz */ + sc->sc_i2c_clock = I2CCON_CR_217KHZ; + break; + case 146000: /* 146kHz */ + sc->sc_i2c_clock = I2CCON_CR_146KHZ; + break; + case 88000: /* 88kHz */ + sc->sc_i2c_clock = I2CCON_CR_88KHZ; + break; + case 0: /* default */ + case 59000: /* 59kHz */ + sc->sc_i2c_clock = I2CCON_CR_59KHZ; + break; + case 44000: /* 44kHz */ + sc->sc_i2c_clock = I2CCON_CR_44KHZ; + break; + case 36000: /* 36kHz */ + sc->sc_i2c_clock = I2CCON_CR_36KHZ; + break; + default: + aprint_error_dev(sc->sc_dev, "unknown i2c clock %dHz\n", + sc->sc_i2c_clock); + sc->sc_i2c_clock = I2CCON_CR_59KHZ; + break; + } + + iba.iba_tag = &sc->sc_i2c; + (void) config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print); +} + +static int +pca9564_acquire_bus(void *cookie, int flags) +{ + struct pca9564_softc *sc = cookie; + uint8_t control; + + mutex_enter(&sc->sc_buslock); + + /* Enable SIO and set clock */ + control = CSR_READ(sc, PCA9564_I2CCON); + control |= I2CCON_ENSIO; + control &= ~(I2CCON_STA|I2CCON_STO|I2CCON_SI|I2CCON_AA); + control &= ~I2CCON_CR_MASK; + control |= sc->sc_i2c_clock; + CSR_WRITE(sc, PCA9564_I2CCON, control); + delay(500); + + return 0; +} + +static void +pca9564_release_bus(void *cookie, int flags) +{ + struct pca9564_softc *sc = cookie; + uint8_t control; + + /* Disable SIO */ + control = CSR_READ(sc, PCA9564_I2CCON); + control &= ~I2CCON_ENSIO; + CSR_WRITE(sc, PCA9564_I2CCON, control); + + mutex_exit(&sc->sc_buslock); +} + +#define PCA9564_TIMEOUT 100 /* protocol timeout, in uSecs */ + +static int +pca9564_wait(struct pca9564_softc *sc, int flags) +{ + int timeout; + + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + for (timeout = PCA9564_TIMEOUT; timeout > 0; timeout--) { + if (CSR_READ(sc, PCA9564_I2CCON) & I2CCON_SI) + break; + delay(1); + } + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + if (timeout == 0) { + aprint_error_dev(sc->sc_dev, "timeout\n"); + return ETIMEDOUT; + } + return 0; +} + +static int +pca9564_send_start(void *cookie, int flags) +{ + struct pca9564_softc *sc = cookie; + uint8_t control; + + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + control = CSR_READ(sc, PCA9564_I2CCON); + control |= I2CCON_STA; + control &= ~(I2CCON_STO|I2CCON_SI); + CSR_WRITE(sc, PCA9564_I2CCON, control); + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + + return pca9564_wait(sc, flags); +} + +static int +pca9564_send_stop(void *cookie, int flags) +{ + struct pca9564_softc *sc = cookie; + uint8_t control; + + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + control = CSR_READ(sc, PCA9564_I2CCON); + control |= I2CCON_STO; + control &= ~(I2CCON_STA|I2CCON_SI); + CSR_WRITE(sc, PCA9564_I2CCON, control); + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + + return 0; +} + +static int +pca9564_initiate_xfer(void *cookie, uint16_t addr, int flags) +{ + struct pca9564_softc *sc = cookie; + int error, rd_req = (flags & I2C_F_READ) != 0; + uint8_t data, control; + + error = pca9564_send_start(sc, flags); + if (error) { + aprint_error_dev(sc->sc_dev, "failed to send start %s xfer\n", + rd_req ? "read" : "write"); + return error; + } + + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + control = CSR_READ(sc, PCA9564_I2CCON); + + data = (addr << 1) | (rd_req ? 1 : 0); + CSR_WRITE(sc, PCA9564_I2CDAT, data); + + control &= ~(I2CCON_STO|I2CCON_STA|I2CCON_SI); + CSR_WRITE(sc, PCA9564_I2CCON, control); + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + + error = pca9564_wait(sc, flags); + if (error) + aprint_error_dev(sc->sc_dev, "failed to initiate %s xfer\n", + rd_req ? "read" : "write"); + return error; +} + +static int +pca9564_read_byte(void *cookie, uint8_t *bytep, int flags) +{ + struct pca9564_softc *sc = cookie; + int send_stop = (flags & I2C_F_STOP) != 0; + int error; + + error = pca9564_ack(sc, !send_stop, flags); + if (error) { + aprint_error_dev(sc->sc_dev, "failed to ack\n"); + return error; + } + + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + *bytep = CSR_READ(sc, PCA9564_I2CDAT); + DPRINTF(("%s: status=%#x, byte=%#x\n", __func__, + CSR_READ(sc, PCA9564_I2CSTA), *bytep)); + + if (send_stop) + pca9564_send_stop(sc, flags); + + return 0; +} + +static int +pca9564_write_byte(void *cookie, uint8_t byte, int flags) +{ + struct pca9564_softc *sc = cookie; + int send_stop = (flags & I2C_F_STOP) != 0; + int error; + uint8_t control; + + DPRINTF(("%s: status=%#x, byte=%#x\n", __func__, + CSR_READ(sc, PCA9564_I2CSTA), byte)); + control = CSR_READ(sc, PCA9564_I2CCON); + + CSR_WRITE(sc, PCA9564_I2CDAT, byte); + + control &= ~(I2CCON_STO|I2CCON_STA|I2CCON_SI); + CSR_WRITE(sc, PCA9564_I2CCON, control); + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + + error = pca9564_wait(sc, flags); + if (error) + aprint_error_dev(sc->sc_dev, "write byte failed\n"); + + if (send_stop) + pca9564_send_stop(sc, flags); + + return error; +} + +static int +pca9564_ack(void *cookie, bool ack, int flags) +{ + struct pca9564_softc *sc = cookie; + uint8_t control; + + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + control = CSR_READ(sc, PCA9564_I2CCON); + control &= ~(I2CCON_STO|I2CCON_STA|I2CCON_SI|I2CCON_AA); + if (ack) + control |= I2CCON_AA; + CSR_WRITE(sc, PCA9564_I2CCON, control); + DPRINTF(("%s: status=%#x\n", __func__, CSR_READ(sc, PCA9564_I2CSTA))); + + return pca9564_wait(sc, flags); +} Index: src/sys/dev/ic/pca9564reg.h diff -u /dev/null src/sys/dev/ic/pca9564reg.h:1.1 --- /dev/null Fri Apr 9 10:09:50 2010 +++ src/sys/dev/ic/pca9564reg.h Fri Apr 9 10:09:50 2010 @@ -0,0 +1,56 @@ +/* $NetBSD: pca9564reg.h,v 1.1 2010/04/09 10:09:50 nonaka Exp $ */ + +/* + * Copyright (c) 2010 NONAKA Kimihiro <non...@netbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_IC_PCA9564REG_H_ +#define _DEV_IC_PCA9564REG_H_ + +#define PCA9564_I2CSTA 0x00 /* R: Status */ +#define PCA9564_I2CCTO 0x00 /* W: Time-out */ +#define PCA9564_I2CDAT 0x01 /* R/W: Data */ +#define PCA9564_I2CADR 0x02 /* R/W: Own address */ +#define PCA9564_I2CCON 0x03 /* R/W: Control */ + +/* Control */ +#define I2CCON_CR0 (1 << 0) /* Clock Rate Bit0 */ +#define I2CCON_CR1 (1 << 1) /* Clock Rate Bit1 */ +#define I2CCON_CR2 (1 << 2) /* Clock Rate Bit2 */ +#define I2CCON_CR_330KHZ (0x0) +#define I2CCON_CR_288KHZ (0x1) +#define I2CCON_CR_217KHZ (0x2) +#define I2CCON_CR_146KHZ (0x3) +#define I2CCON_CR_88KHZ (0x4) +#define I2CCON_CR_59KHZ (0x5) +#define I2CCON_CR_44KHZ (0x6) +#define I2CCON_CR_36KHZ (0x7) +#define I2CCON_CR_MASK (0x7) +#define I2CCON_SI (1 << 3) /* Serial Interrupt Flag */ +#define I2CCON_STO (1 << 4) /* Stop Flag */ +#define I2CCON_STA (1 << 5) /* Start Flag */ +#define I2CCON_ENSIO (1 << 6) /* SIO Enable Bit */ +#define I2CCON_AA (1 << 7) /* Assert Acknowledge Flag */ + +#endif /* _DEV_IC_PCA9564REG_H_ */ Index: src/sys/dev/ic/pca9564var.h diff -u /dev/null src/sys/dev/ic/pca9564var.h:1.1 --- /dev/null Fri Apr 9 10:09:50 2010 +++ src/sys/dev/ic/pca9564var.h Fri Apr 9 10:09:50 2010 @@ -0,0 +1,49 @@ +/* $NetBSD: pca9564var.h,v 1.1 2010/04/09 10:09:50 nonaka Exp $ */ + +/* + * Copyright (c) 2010 NONAKA Kimihiro <non...@netbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_IC_PCA9564VAR_H_ +#define _DEV_IC_PCA9564VAR_H_ + +struct pca9564_ios { + uint8_t (*read_byte)(device_t, int reg); + void (*write_byte)(device_t, int reg, uint8_t val); +}; + +struct pca9564_softc { + device_t sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + struct pca9564_ios sc_ios; + int sc_i2c_clock; + + struct i2c_controller sc_i2c; + kmutex_t sc_buslock; +}; + +void pca9564_attach(struct pca9564_softc *); + +#endif /* _DEV_IC_PCA9564VAR_H_ */