1129704Sjoerg/*- 2129704Sjoerg * Copyright (c) 2004 Joerg Wunsch 3129704Sjoerg * 4129704Sjoerg * derived from sys/i386/isa/pcf.c which is: 5129704Sjoerg * 6129704Sjoerg * Copyright (c) 1998 Nicolas Souchu, Marc Bouget 7129704Sjoerg * All rights reserved. 8129704Sjoerg * 9129704Sjoerg * Redistribution and use in source and binary forms, with or without 10129704Sjoerg * modification, are permitted provided that the following conditions 11129704Sjoerg * are met: 12129704Sjoerg * 1. Redistributions of source code must retain the above copyright 13129704Sjoerg * notice, this list of conditions and the following disclaimer. 14129704Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 15129704Sjoerg * notice, this list of conditions and the following disclaimer in the 16129704Sjoerg * documentation and/or other materials provided with the distribution. 17129704Sjoerg * 18129704Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19129704Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20129704Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21129704Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22129704Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23129704Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24129704Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25129704Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26129704Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27129704Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28129704Sjoerg * SUCH DAMAGE. 29129704Sjoerg */ 30129704Sjoerg#include <sys/cdefs.h> 31129704Sjoerg__FBSDID("$FreeBSD$"); 32129704Sjoerg 33129704Sjoerg/* 34129704Sjoerg * Device specific driver for the SUNW,envctrl device found on some 35129704Sjoerg * UltraSPARC Sun systems. This device is a Philips PCF8584 sitting 36129704Sjoerg * on the Ebus2. 37129704Sjoerg */ 38129704Sjoerg 39129704Sjoerg#include <sys/param.h> 40129704Sjoerg#include <sys/bus.h> 41129704Sjoerg#include <sys/conf.h> 42129704Sjoerg#include <sys/kernel.h> 43181303Sjhb#include <sys/lock.h> 44129704Sjoerg#include <sys/malloc.h> 45130319Smarius#include <sys/module.h> 46181303Sjhb#include <sys/mutex.h> 47129704Sjoerg#include <sys/resource.h> 48181303Sjhb#include <sys/systm.h> 49129704Sjoerg#include <sys/uio.h> 50129704Sjoerg 51133589Smarius#include <dev/ofw/ofw_bus.h> 52133589Smarius 53129704Sjoerg#include <machine/bus.h> 54129704Sjoerg#include <machine/resource.h> 55129704Sjoerg 56129704Sjoerg#include <sys/rman.h> 57129704Sjoerg 58181332Sjhb#include <dev/iicbus/iicbus.h> 59129704Sjoerg#include <dev/iicbus/iiconf.h> 60129704Sjoerg#include <dev/pcf/pcfvar.h> 61129704Sjoerg#include "iicbus_if.h" 62129704Sjoerg 63129704Sjoerg#undef PCF_DEFAULT_ADDR 64129704Sjoerg#define PCF_DEFAULT_ADDR 0x55 /* SUNW,pcf default */ 65129704Sjoerg 66129704Sjoergstatic int envctrl_probe(device_t); 67129704Sjoergstatic int envctrl_attach(device_t); 68129704Sjoergstatic int envctrl_detach(device_t); 69129704Sjoerg 70129704Sjoergstatic device_method_t envctrl_methods[] = { 71129704Sjoerg /* device interface */ 72129704Sjoerg DEVMETHOD(device_probe, envctrl_probe), 73129704Sjoerg DEVMETHOD(device_attach, envctrl_attach), 74129704Sjoerg DEVMETHOD(device_detach, envctrl_detach), 75129704Sjoerg 76129704Sjoerg /* iicbus interface */ 77129704Sjoerg DEVMETHOD(iicbus_callback, iicbus_null_callback), 78129704Sjoerg DEVMETHOD(iicbus_repeated_start, pcf_repeated_start), 79129704Sjoerg DEVMETHOD(iicbus_start, pcf_start), 80129704Sjoerg DEVMETHOD(iicbus_stop, pcf_stop), 81129704Sjoerg DEVMETHOD(iicbus_write, pcf_write), 82129704Sjoerg DEVMETHOD(iicbus_read, pcf_read), 83129704Sjoerg DEVMETHOD(iicbus_reset, pcf_rst_card), 84129704Sjoerg { 0, 0 } 85129704Sjoerg}; 86129704Sjoerg 87129704Sjoergstatic devclass_t envctrl_devclass; 88129704Sjoerg 89129704Sjoergstatic driver_t envctrl_driver = { 90129704Sjoerg "envctrl", 91129704Sjoerg envctrl_methods, 92129704Sjoerg sizeof(struct pcf_softc), 93129704Sjoerg}; 94129704Sjoerg 95129704Sjoergstatic int 96129704Sjoergenvctrl_probe(device_t dev) 97129704Sjoerg{ 98129704Sjoerg 99133589Smarius if (strcmp("SUNW,envctrl", ofw_bus_get_name(dev)) == 0) { 100129704Sjoerg device_set_desc(dev, "EBus SUNW,envctrl"); 101129704Sjoerg return (0); 102129704Sjoerg } 103129704Sjoerg return (ENXIO); 104129704Sjoerg} 105129704Sjoerg 106129704Sjoergstatic int 107129704Sjoergenvctrl_attach(device_t dev) 108129704Sjoerg{ 109129704Sjoerg struct pcf_softc *sc; 110129704Sjoerg int rv = ENXIO; 111129704Sjoerg 112129704Sjoerg sc = DEVTOSOFTC(dev); 113181303Sjhb mtx_init(&sc->pcf_lock, device_get_nameunit(dev), "pcf", MTX_DEF); 114129704Sjoerg 115129704Sjoerg /* IO port is mandatory */ 116146966Smarius sc->res_ioport = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 117129704Sjoerg &sc->rid_ioport, RF_ACTIVE); 118129704Sjoerg if (sc->res_ioport == 0) { 119129704Sjoerg device_printf(dev, "cannot reserve I/O port range\n"); 120129704Sjoerg goto error; 121129704Sjoerg } 122129704Sjoerg 123129704Sjoerg sc->pcf_flags = device_get_flags(dev); 124129704Sjoerg 125129704Sjoerg if (!(sc->pcf_flags & IIC_POLLED)) { 126129704Sjoerg sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rid_irq, 127129704Sjoerg RF_ACTIVE); 128129704Sjoerg if (sc->res_irq == 0) { 129129704Sjoerg device_printf(dev, "can't reserve irq, polled mode.\n"); 130129704Sjoerg sc->pcf_flags |= IIC_POLLED; 131129704Sjoerg } 132129704Sjoerg } 133129704Sjoerg 134129704Sjoerg /* reset the chip */ 135129704Sjoerg pcf_rst_card(dev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL); 136129704Sjoerg 137155921Sjhb rv = bus_setup_intr(dev, sc->res_irq, 138181303Sjhb INTR_TYPE_NET | INTR_MPSAFE /* | INTR_ENTROPY */, 139166901Spiso NULL, pcf_intr, sc, &sc->intr_cookie); 140129704Sjoerg if (rv) { 141129704Sjoerg device_printf(dev, "could not setup IRQ\n"); 142129704Sjoerg goto error; 143129704Sjoerg } 144129704Sjoerg 145129704Sjoerg if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) 146129704Sjoerg device_printf(dev, "could not allocate iicbus instance\n"); 147129704Sjoerg 148129704Sjoerg /* probe and attach the iicbus */ 149129704Sjoerg bus_generic_attach(dev); 150129704Sjoerg 151129704Sjoerg return (0); 152129704Sjoerg 153129704Sjoergerror: 154129704Sjoerg if (sc->res_irq != 0) { 155129704Sjoerg bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, 156129704Sjoerg sc->res_irq); 157129704Sjoerg } 158129704Sjoerg if (sc->res_ioport != 0) { 159146966Smarius bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ioport, 160129704Sjoerg sc->res_ioport); 161129704Sjoerg } 162181303Sjhb mtx_destroy(&sc->pcf_lock); 163129704Sjoerg return (rv); 164129704Sjoerg} 165129704Sjoerg 166129704Sjoergstatic int 167129704Sjoergenvctrl_detach(device_t dev) 168129704Sjoerg{ 169129704Sjoerg struct pcf_softc *sc; 170129704Sjoerg int rv; 171129704Sjoerg 172129704Sjoerg sc = DEVTOSOFTC(dev); 173129704Sjoerg 174129704Sjoerg if ((rv = bus_generic_detach(dev)) != 0) 175129704Sjoerg return (rv); 176129704Sjoerg 177129704Sjoerg if ((rv = device_delete_child(dev, sc->iicbus)) != 0) 178129704Sjoerg return (rv); 179129704Sjoerg 180129704Sjoerg if (sc->res_irq != 0) { 181155921Sjhb bus_teardown_intr(dev, sc->res_irq, sc->intr_cookie); 182129704Sjoerg bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq); 183129704Sjoerg } 184129704Sjoerg 185146966Smarius bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ioport, sc->res_ioport); 186181303Sjhb mtx_destroy(&sc->pcf_lock); 187129704Sjoerg 188129704Sjoerg return (0); 189129704Sjoerg} 190129704Sjoerg 191130319SmariusDRIVER_MODULE(envctrl, ebus, envctrl_driver, envctrl_devclass, 0, 0); 192181303SjhbDRIVER_MODULE(iicbus, envctrl, iicbus_driver, iicbus_devclass, 0, 0); 193