ixp425_iic.c revision 181303
1/* 2 * Copyright (c) 2006 Kevin Lo. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 15 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 * POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: head/sys/arm/xscale/ixp425/ixp425_iic.c 181303 2008-08-04 20:46:15Z jhb $"); 28 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/kernel.h> 32#include <sys/module.h> 33#include <sys/bus.h> 34#include <sys/uio.h> 35 36#include <arm/xscale/ixp425/ixp425reg.h> 37#include <arm/xscale/ixp425/ixp425var.h> 38#include <arm/xscale/ixp425/ixdp425reg.h> 39 40#include <dev/iicbus/iiconf.h> 41#include <dev/iicbus/iicbus.h> 42 43#include "iicbb_if.h" 44 45#define I2C_DELAY 10 46 47/* bit clr/set shorthands */ 48#define GPIO_CONF_CLR(sc, reg, mask) \ 49 GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) &~ (mask)) 50#define GPIO_CONF_SET(sc, reg, mask) \ 51 GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) | (mask)) 52 53struct ixpiic_softc { 54 device_t sc_dev; 55 bus_space_tag_t sc_iot; 56 bus_space_handle_t sc_gpio_ioh; 57 58 device_t iicbb; 59}; 60 61static struct ixpiic_softc *ixpiic_sc = NULL; 62 63static int 64ixpiic_probe(device_t dev) 65{ 66 device_set_desc(dev, "IXP425 GPIO-Based I2C Interface"); 67 return (0); 68} 69 70static int 71ixpiic_attach(device_t dev) 72{ 73 struct ixpiic_softc *sc = device_get_softc(dev); 74 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); 75 76 ixpiic_sc = sc; 77 78 sc->sc_dev = dev; 79 sc->sc_iot = sa->sc_iot; 80 sc->sc_gpio_ioh = sa->sc_gpio_ioh; 81 82 GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, 83 GPIO_I2C_SCL_BIT | GPIO_I2C_SDA_BIT); 84 GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, 85 GPIO_I2C_SCL_BIT | GPIO_I2C_SDA_BIT); 86 87 /* add generic bit-banging code */ 88 if ((sc->iicbb = device_add_child(dev, "iicbb", -1)) == NULL) 89 device_printf(dev, "could not add iicbb\n"); 90 91 /* probe and attach the bit-banging code */ 92 device_probe_and_attach(sc->iicbb); 93 94 return (0); 95} 96 97static int 98ixpiic_callback(device_t dev, int index, caddr_t *data) 99{ 100 return (0); 101} 102 103static int 104ixpiic_getscl(device_t dev) 105{ 106 struct ixpiic_softc *sc = ixpiic_sc; 107 uint32_t reg; 108 109 mtx_lock(&Giant); 110 GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT); 111 112 reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR); 113 mtx_unlock(&Giant); 114 return (reg & GPIO_I2C_SCL_BIT); 115} 116 117static int 118ixpiic_getsda(device_t dev) 119{ 120 struct ixpiic_softc *sc = ixpiic_sc; 121 uint32_t reg; 122 123 mtx_lock(&Giant); 124 GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT); 125 126 reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR); 127 mtx_unlock(&Giant); 128 return (reg & GPIO_I2C_SDA_BIT); 129} 130 131static void 132ixpiic_setsda(device_t dev, char val) 133{ 134 struct ixpiic_softc *sc = ixpiic_sc; 135 136 mtx_lock(&Giant); 137 GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SDA_BIT); 138 if (val) 139 GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT); 140 else 141 GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT); 142 mtx_unlock(&Giant); 143 DELAY(I2C_DELAY); 144} 145 146static void 147ixpiic_setscl(device_t dev, char val) 148{ 149 struct ixpiic_softc *sc = ixpiic_sc; 150 151 mtx_lock(&Giant); 152 GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SCL_BIT); 153 if (val) 154 GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT); 155 else 156 GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT); 157 mtx_unlock(&Giant); 158 DELAY(I2C_DELAY); 159} 160 161static int 162ixpiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 163{ 164 /* reset bus */ 165 ixpiic_setsda(dev, 1); 166 ixpiic_setscl(dev, 1); 167 168 return (IIC_ENOADDR); 169} 170 171static device_method_t ixpiic_methods[] = { 172 /* device interface */ 173 DEVMETHOD(device_probe, ixpiic_probe), 174 DEVMETHOD(device_attach, ixpiic_attach), 175 176 /* iicbb interface */ 177 DEVMETHOD(iicbb_callback, ixpiic_callback), 178 DEVMETHOD(iicbb_setsda, ixpiic_setsda), 179 DEVMETHOD(iicbb_setscl, ixpiic_setscl), 180 DEVMETHOD(iicbb_getsda, ixpiic_getsda), 181 DEVMETHOD(iicbb_getscl, ixpiic_getscl), 182 DEVMETHOD(iicbb_reset, ixpiic_reset), 183 184 { 0, 0 } 185}; 186 187static driver_t ixpiic_driver = { 188 "ixpiic", 189 ixpiic_methods, 190 sizeof(struct ixpiic_softc), 191}; 192static devclass_t ixpiic_devclass; 193 194DRIVER_MODULE(ixpiic, ixp, ixpiic_driver, ixpiic_devclass, 0, 0); 195DRIVER_MODULE(iicbb, ixpiic, iicbb_driver, iicbb_devclass, 0, 0); 196