nslu2_iic.c revision 1.3
1/* $NetBSD: nslu2_iic.c,v 1.3 2007/12/06 17:00:32 ad Exp $ */ 2 3/*- 4 * Copyright (c) 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Steve C. Woodford. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/kernel.h> 42#include <sys/device.h> 43#include <sys/mutex.h> 44#include <sys/bus.h> 45 46#include <dev/i2c/i2cvar.h> 47#include <dev/i2c/i2c_bitbang.h> 48 49#include <arm/xscale/ixp425reg.h> 50#include <arm/xscale/ixp425var.h> 51 52#include <evbarm/nslu2/nslu2reg.h> 53 54struct slugiic_softc { 55 struct device sc_dev; 56 struct i2c_controller sc_ic; 57 struct i2c_bitbang_ops sc_ibo; 58 kmutex_t sc_lock; 59 uint32_t sc_dirout; 60}; 61 62static int 63slugiic_acquire_bus(void *arg, int flags) 64{ 65 struct slugiic_softc *sc = arg; 66 67 if (flags & I2C_F_POLL) 68 return (0); 69 70 mutex_enter(&sc->sc_lock); 71 return (0); 72} 73 74static void 75slugiic_release_bus(void *arg, int flags) 76{ 77 struct slugiic_softc *sc = arg; 78 79 if (flags & I2C_F_POLL) 80 return; 81 82 mutex_exit(&sc->sc_lock); 83} 84 85static int 86slugiic_send_start(void *arg, int flags) 87{ 88 struct slugiic_softc *sc = arg; 89 90 return (i2c_bitbang_send_start(sc, flags, &sc->sc_ibo)); 91} 92 93static int 94slugiic_send_stop(void *arg, int flags) 95{ 96 struct slugiic_softc *sc = arg; 97 98 return (i2c_bitbang_send_stop(sc, flags, &sc->sc_ibo)); 99} 100 101static int 102slugiic_initiate_xfer(void *arg, i2c_addr_t addr, int flags) 103{ 104 struct slugiic_softc *sc = arg; 105 106 return (i2c_bitbang_initiate_xfer(sc, addr, flags, &sc->sc_ibo)); 107} 108 109static int 110slugiic_read_byte(void *arg, uint8_t *vp, int flags) 111{ 112 struct slugiic_softc *sc = arg; 113 114 return (i2c_bitbang_read_byte(sc, vp, flags, &sc->sc_ibo)); 115} 116 117static int 118slugiic_write_byte(void *arg, uint8_t v, int flags) 119{ 120 struct slugiic_softc *sc = arg; 121 122 return (i2c_bitbang_write_byte(sc, v, flags, &sc->sc_ibo)); 123} 124 125static void 126slugiic_set_dir(void *arg, uint32_t bits) 127{ 128 struct slugiic_softc *sc = arg; 129 uint32_t reg; 130 int s; 131 132 if (sc->sc_dirout == (bits ^ GPIO_I2C_SDA_BIT)) 133 return; 134 135 s = splhigh(); 136 137 sc->sc_dirout = bits ^ GPIO_I2C_SDA_BIT; 138 139 reg = GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPOER); 140 reg &= ~GPIO_I2C_SDA_BIT; 141 GPIO_CONF_WRITE_4(ixp425_softc, IXP425_GPIO_GPOER, reg | bits); 142 143 splx(s); 144} 145 146static void 147slugiic_set_bits(void *arg, uint32_t bits) 148{ 149 struct slugiic_softc *sc = arg; 150 uint32_t reg; 151 int s; 152 153 if (sc->sc_dirout == 0 && !(bits & GPIO_I2C_SDA_BIT)) 154 bits |= GPIO_I2C_SDA_BIT; 155 156 s = splhigh(); 157 158 reg = GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPOUTR); 159 reg &= ~(GPIO_I2C_SDA_BIT | GPIO_I2C_SCL_BIT); 160 GPIO_CONF_WRITE_4(ixp425_softc, IXP425_GPIO_GPOUTR, reg | bits); 161 162 splx(s); 163} 164 165static uint32_t 166slugiic_read_bits(void *arg) 167{ 168 uint32_t reg; 169 170 reg = GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPINR); 171 return (reg & (GPIO_I2C_SDA_BIT | GPIO_I2C_SCL_BIT)); 172} 173 174static void 175slugiic_deferred_attach(struct device *device) 176{ 177 struct slugiic_softc *sc = (struct slugiic_softc *)device; 178 struct i2cbus_attach_args iba; 179 uint32_t reg; 180 181 reg = GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPOUTR); 182 reg |= GPIO_I2C_SDA_BIT | GPIO_I2C_SCL_BIT; 183 GPIO_CONF_WRITE_4(ixp425_softc, IXP425_GPIO_GPOUTR, reg); 184 185 reg = GPIO_CONF_READ_4(ixp425_softc, IXP425_GPIO_GPOER); 186 reg &= ~GPIO_I2C_SCL_BIT; 187 reg |= GPIO_I2C_SDA_BIT; 188 GPIO_CONF_WRITE_4(ixp425_softc, IXP425_GPIO_GPOER, reg); 189 190 iba.iba_tag = &sc->sc_ic; 191 (void) config_found_ia(&sc->sc_dev, "i2cbus", &iba, iicbus_print); 192} 193 194static int 195slugiic_match(struct device *parent, struct cfdata *cf, void *arg) 196{ 197 198 return (1); 199} 200 201static void 202slugiic_attach(struct device *parent, struct device *self, void *arg) 203{ 204 struct slugiic_softc *sc = (struct slugiic_softc *)self; 205 206 aprint_naive("\n"); 207 aprint_normal(": I2C bus\n"); 208 209 sc->sc_ic.ic_cookie = sc; 210 sc->sc_ic.ic_acquire_bus = slugiic_acquire_bus; 211 sc->sc_ic.ic_release_bus = slugiic_release_bus; 212 sc->sc_ic.ic_exec = NULL; 213 sc->sc_ic.ic_send_start = slugiic_send_start; 214 sc->sc_ic.ic_send_stop = slugiic_send_stop; 215 sc->sc_ic.ic_initiate_xfer = slugiic_initiate_xfer; 216 sc->sc_ic.ic_read_byte = slugiic_read_byte; 217 sc->sc_ic.ic_write_byte = slugiic_write_byte; 218 219 sc->sc_ibo.ibo_set_dir = slugiic_set_dir; 220 sc->sc_ibo.ibo_set_bits = slugiic_set_bits; 221 sc->sc_ibo.ibo_read_bits = slugiic_read_bits; 222 sc->sc_ibo.ibo_bits[I2C_BIT_SDA] = GPIO_I2C_SDA_BIT; 223 sc->sc_ibo.ibo_bits[I2C_BIT_SCL] = GPIO_I2C_SCL_BIT; 224 sc->sc_ibo.ibo_bits[I2C_BIT_OUTPUT] = 0; 225 sc->sc_ibo.ibo_bits[I2C_BIT_INPUT] = GPIO_I2C_SDA_BIT; 226 227 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 228 229 sc->sc_dirout = 0; 230 231 /* 232 * Defer until ixp425_softc has been initialised 233 */ 234 config_interrupts(self, slugiic_deferred_attach); 235} 236 237CFATTACH_DECL(slugiic, sizeof(struct slugiic_softc), 238 slugiic_match, slugiic_attach, NULL, NULL); 239