pcf_isa.c revision 130318
1217309Snwhitehorn/*- 2220749Snwhitehorn * Copyright (c) 2004 Joerg Wunsch 3217309Snwhitehorn * 4220749Snwhitehorn * derived from sys/i386/isa/pcf.c which is: 5217309Snwhitehorn * 6220749Snwhitehorn * Copyright (c) 1998 Nicolas Souchu, Marc Bouget 7217309Snwhitehorn * All rights reserved. 8217309Snwhitehorn * 9217309Snwhitehorn * Redistribution and use in source and binary forms, with or without 10217309Snwhitehorn * modification, are permitted provided that the following conditions 11217309Snwhitehorn * are met: 12217309Snwhitehorn * 1. Redistributions of source code must retain the above copyright 13217309Snwhitehorn * notice, this list of conditions and the following disclaimer. 14217309Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 15217309Snwhitehorn * notice, this list of conditions and the following disclaimer in the 16217309Snwhitehorn * documentation and/or other materials provided with the distribution. 17217309Snwhitehorn * 18217309Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19217309Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20217309Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21217309Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22217309Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23217309Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24217309Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25217309Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26217309Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27217309Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28217309Snwhitehorn * SUCH DAMAGE. 29217309Snwhitehorn */ 30217309Snwhitehorn#include <sys/cdefs.h> 31217309Snwhitehorn__FBSDID("$FreeBSD: head/sys/dev/pcf/pcf_isa.c 130318 2004-06-10 21:51:39Z marius $"); 32217309Snwhitehorn 33217309Snwhitehorn/* 34217309Snwhitehorn * Hardware driver for a Philips PCF8584 I2C bus controller sitting 35217309Snwhitehorn * on a generic ISA bus. 36217309Snwhitehorn */ 37217309Snwhitehorn 38217309Snwhitehorn#include <sys/param.h> 39217309Snwhitehorn#include <sys/systm.h> 40217309Snwhitehorn#include <sys/bus.h> 41217309Snwhitehorn#include <sys/kernel.h> 42217309Snwhitehorn#include <sys/module.h> 43217309Snwhitehorn#include <sys/resource.h> 44217309Snwhitehorn 45217309Snwhitehorn#include <machine/bus.h> 46217309Snwhitehorn#include <machine/resource.h> 47217309Snwhitehorn 48217309Snwhitehorn#include <sys/rman.h> 49217309Snwhitehorn 50217309Snwhitehorn#include <isa/isareg.h> 51217309Snwhitehorn#include <isa/isavar.h> 52217309Snwhitehorn 53217309Snwhitehorn#include <dev/iicbus/iiconf.h> 54217309Snwhitehorn#include <dev/pcf/pcfvar.h> 55217309Snwhitehorn#include "iicbus_if.h" 56217309Snwhitehorn 57217309Snwhitehorn#define PCF_NAME "pcf" 58217309Snwhitehorn 59217309Snwhitehornstatic void pcf_isa_identify(driver_t *, device_t); 60217309Snwhitehornstatic int pcf_isa_probe(device_t); 61217309Snwhitehornstatic int pcf_isa_attach(device_t); 62217309Snwhitehornstatic int pcf_isa_detach(device_t); 63217309Snwhitehorn 64217309Snwhitehornstatic device_method_t pcf_isa_methods[] = { 65217309Snwhitehorn /* device interface */ 66217309Snwhitehorn DEVMETHOD(device_identify, pcf_isa_identify), 67217309Snwhitehorn DEVMETHOD(device_probe, pcf_isa_probe), 68217309Snwhitehorn DEVMETHOD(device_attach, pcf_isa_attach), 69217309Snwhitehorn DEVMETHOD(device_detach, pcf_isa_detach), 70217309Snwhitehorn 71217309Snwhitehorn /* iicbus interface */ 72217309Snwhitehorn DEVMETHOD(iicbus_callback, iicbus_null_callback), 73217309Snwhitehorn DEVMETHOD(iicbus_repeated_start, pcf_repeated_start), 74217309Snwhitehorn DEVMETHOD(iicbus_start, pcf_start), 75217309Snwhitehorn DEVMETHOD(iicbus_stop, pcf_stop), 76217309Snwhitehorn DEVMETHOD(iicbus_write, pcf_write), 77217309Snwhitehorn DEVMETHOD(iicbus_read, pcf_read), 78217309Snwhitehorn DEVMETHOD(iicbus_reset, pcf_rst_card), 79217309Snwhitehorn { 0, 0 } 80217309Snwhitehorn}; 81217309Snwhitehorn 82217309Snwhitehornstatic devclass_t pcf_isa_devclass; 83217309Snwhitehorn 84217309Snwhitehornstatic driver_t pcf_isa_driver = { 85217309Snwhitehorn PCF_NAME, 86217309Snwhitehorn pcf_isa_methods, 87217309Snwhitehorn sizeof(struct pcf_softc), 88217309Snwhitehorn}; 89217309Snwhitehorn 90217309Snwhitehornstatic void 91217309Snwhitehornpcf_isa_identify(driver_t *driver, device_t parent) 92217309Snwhitehorn{ 93217309Snwhitehorn BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, PCF_NAME, 0); 94217309Snwhitehorn 95217309Snwhitehorn return; 96217309Snwhitehorn} 97217309Snwhitehorn 98217309Snwhitehornstatic int 99217309Snwhitehornpcf_isa_probe(device_t dev) 100217309Snwhitehorn{ 101217309Snwhitehorn u_long start, count; 102217309Snwhitehorn u_int rid = 0, port, error; 103217309Snwhitehorn 104217309Snwhitehorn bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count); 105217309Snwhitehorn 106217309Snwhitehorn /* The port address must be explicitly specified */ 107217309Snwhitehorn if ((error = resource_int_value(PCF_NAME, 0, "port", &port) != 0)) 108217309Snwhitehorn return (error); 109217309Snwhitehorn 110217309Snwhitehorn /* Probe is only successfull for the specified base io */ 111217309Snwhitehorn if (port != (u_int)start) 112217309Snwhitehorn return (ENXIO); 113217309Snwhitehorn 114217309Snwhitehorn device_set_desc(dev, "PCF8584 I2C bus controller"); 115217309Snwhitehorn 116217309Snwhitehorn return (0); 117217309Snwhitehorn} 118217309Snwhitehorn 119217309Snwhitehornstatic int 120217309Snwhitehornpcf_isa_attach(device_t dev) 121217309Snwhitehorn{ 122217309Snwhitehorn struct pcf_softc *sc; 123217309Snwhitehorn int rv = ENXIO; 124217309Snwhitehorn 125217309Snwhitehorn sc = DEVTOSOFTC(dev); 126217309Snwhitehorn bzero(sc, sizeof(struct pcf_softc)); 127217309Snwhitehorn 128217309Snwhitehorn /* IO port is mandatory */ 129217309Snwhitehorn sc->res_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 130217309Snwhitehorn &sc->rid_ioport, RF_ACTIVE); 131217309Snwhitehorn if (sc->res_ioport == 0) { 132217309Snwhitehorn device_printf(dev, "cannot reserve I/O port range\n"); 133217309Snwhitehorn goto error; 134217309Snwhitehorn } 135217309Snwhitehorn 136217309Snwhitehorn sc->pcf_flags = device_get_flags(dev); 137217309Snwhitehorn 138217309Snwhitehorn if (!(sc->pcf_flags & IIC_POLLED)) { 139217309Snwhitehorn sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rid_irq, 140217309Snwhitehorn RF_ACTIVE); 141217309Snwhitehorn if (sc->res_irq == 0) { 142217309Snwhitehorn device_printf(dev, "can't reserve irq, polled mode.\n"); 143217309Snwhitehorn sc->pcf_flags |= IIC_POLLED; 144217309Snwhitehorn } 145217309Snwhitehorn } 146217309Snwhitehorn 147217309Snwhitehorn /* reset the chip */ 148217309Snwhitehorn pcf_rst_card(dev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); 149217309Snwhitehorn 150217309Snwhitehorn if (sc->res_irq) { 151217309Snwhitehorn rv = BUS_SETUP_INTR(device_get_parent(dev), dev, sc->res_irq, 152217309Snwhitehorn INTR_TYPE_NET /* | INTR_ENTROPY */, 153217309Snwhitehorn pcf_intr, sc, &sc->intr_cookie); 154217309Snwhitehorn if (rv) { 155217309Snwhitehorn device_printf(dev, "could not setup IRQ\n"); 156217309Snwhitehorn goto error; 157217309Snwhitehorn } 158217309Snwhitehorn } 159217309Snwhitehorn 160217309Snwhitehorn if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) 161217309Snwhitehorn device_printf(dev, "could not allocate iicbus instance\n"); 162217309Snwhitehorn 163217309Snwhitehorn /* probe and attach the iicbus */ 164217309Snwhitehorn bus_generic_attach(dev); 165217309Snwhitehorn 166217309Snwhitehorn return (0); 167217309Snwhitehorn 168217309Snwhitehornerror: 169217309Snwhitehorn if (sc->res_irq != 0) { 170217309Snwhitehorn bus_deactivate_resource(dev, SYS_RES_IRQ, sc->rid_irq, 171217309Snwhitehorn sc->res_irq); 172217309Snwhitehorn bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, 173217309Snwhitehorn sc->res_irq); 174217309Snwhitehorn } 175217309Snwhitehorn if (sc->res_ioport != 0) { 176217309Snwhitehorn bus_deactivate_resource(dev, SYS_RES_IOPORT, sc->rid_ioport, 177217309Snwhitehorn sc->res_ioport); 178217309Snwhitehorn bus_release_resource(dev, SYS_RES_IOPORT, sc->rid_ioport, 179217309Snwhitehorn sc->res_ioport); 180217309Snwhitehorn } 181217309Snwhitehorn return (rv); 182217309Snwhitehorn} 183217309Snwhitehorn 184217309Snwhitehornstatic int 185217309Snwhitehornpcf_isa_detach(device_t dev) 186217309Snwhitehorn{ 187217309Snwhitehorn struct pcf_softc *sc; 188217309Snwhitehorn int rv; 189217309Snwhitehorn 190217309Snwhitehorn sc = DEVTOSOFTC(dev); 191217309Snwhitehorn 192217309Snwhitehorn if ((rv = bus_generic_detach(dev)) != 0) 193217309Snwhitehorn return (rv); 194217309Snwhitehorn 195217309Snwhitehorn if ((rv = device_delete_child(dev, sc->iicbus)) != 0) 196217309Snwhitehorn return (rv); 197217309Snwhitehorn 198217309Snwhitehorn if (sc->res_irq != 0) { 199217309Snwhitehorn BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->res_irq, 200217309Snwhitehorn sc->intr_cookie); 201217309Snwhitehorn bus_deactivate_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq); 202217309Snwhitehorn bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq); 203217309Snwhitehorn } 204217309Snwhitehorn 205217309Snwhitehorn bus_deactivate_resource(dev, SYS_RES_IOPORT, sc->rid_ioport, sc->res_ioport); 206217309Snwhitehorn bus_release_resource(dev, SYS_RES_IOPORT, sc->rid_ioport, sc->res_ioport); 207217309Snwhitehorn 208217309Snwhitehorn return (0); 209217309Snwhitehorn} 210217309Snwhitehorn 211217309SnwhitehornDRIVER_MODULE(pcf_isa, isa, pcf_isa_driver, pcf_isa_devclass, 0, 0); 212217309SnwhitehornMODULE_DEPEND(pcf_isa, iicbus, PCF_MINVER, PCF_PREFVER, PCF_MAXVER); 213217309SnwhitehornMODULE_VERSION(pcf_isa, PCF_MODVER); 214217309Snwhitehorn