envctrl.c revision 133522
10Sstevel@tonic-gate/*-
20Sstevel@tonic-gate * Copyright (c) 2004 Joerg Wunsch
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * derived from sys/i386/isa/pcf.c which is:
51663Spriyanka *
61663Spriyanka * Copyright (c) 1998 Nicolas Souchu, Marc Bouget
70Sstevel@tonic-gate * All rights reserved.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
100Sstevel@tonic-gate * modification, are permitted provided that the following conditions
110Sstevel@tonic-gate * are met:
120Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
130Sstevel@tonic-gate *    notice, this list of conditions and the following disclaimer.
140Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
150Sstevel@tonic-gate *    notice, this list of conditions and the following disclaimer in the
160Sstevel@tonic-gate *    documentation and/or other materials provided with the distribution.
170Sstevel@tonic-gate *
180Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
190Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
200Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
210Sstevel@tonic-gate * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
228485SPeter.Memishian@Sun.COM * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
230Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
240Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
250Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
260Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
270Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
280Sstevel@tonic-gate * SUCH DAMAGE.
290Sstevel@tonic-gate */
300Sstevel@tonic-gate#include <sys/cdefs.h>
310Sstevel@tonic-gate__FBSDID("$FreeBSD: head/sys/dev/pcf/envctrl.c 133522 2004-08-11 21:19:31Z marius $");
320Sstevel@tonic-gate
330Sstevel@tonic-gate/*
340Sstevel@tonic-gate * Device specific driver for the SUNW,envctrl device found on some
350Sstevel@tonic-gate * UltraSPARC Sun systems.  This device is a Philips PCF8584 sitting
360Sstevel@tonic-gate * on the Ebus2.
370Sstevel@tonic-gate */
380Sstevel@tonic-gate
390Sstevel@tonic-gate#include <sys/param.h>
400Sstevel@tonic-gate#include <sys/systm.h>
410Sstevel@tonic-gate#include <sys/bus.h>
420Sstevel@tonic-gate#include <sys/conf.h>
4311042SErik.Nordmark@Sun.COM#include <sys/kernel.h>
440Sstevel@tonic-gate#include <sys/malloc.h>
450Sstevel@tonic-gate#include <sys/module.h>
460Sstevel@tonic-gate#include <sys/resource.h>
470Sstevel@tonic-gate#include <sys/uio.h>
480Sstevel@tonic-gate
490Sstevel@tonic-gate#include <machine/bus.h>
500Sstevel@tonic-gate#include <machine/resource.h>
510Sstevel@tonic-gate
520Sstevel@tonic-gate#include <sys/rman.h>
530Sstevel@tonic-gate
5411042SErik.Nordmark@Sun.COM#include <dev/ofw/openfirm.h>
5511042SErik.Nordmark@Sun.COM
5611042SErik.Nordmark@Sun.COM#include <sparc64/ebus/ebusvar.h>
570Sstevel@tonic-gate
5811042SErik.Nordmark@Sun.COM#include <dev/iicbus/iiconf.h>
5911042SErik.Nordmark@Sun.COM#include <dev/pcf/pcfvar.h>
600Sstevel@tonic-gate#include "iicbus_if.h"
610Sstevel@tonic-gate
620Sstevel@tonic-gate#undef PCF_DEFAULT_ADDR
630Sstevel@tonic-gate#define PCF_DEFAULT_ADDR	0x55 /* SUNW,pcf default */
640Sstevel@tonic-gate
650Sstevel@tonic-gatestatic int envctrl_probe(device_t);
6611042SErik.Nordmark@Sun.COMstatic int envctrl_attach(device_t);
670Sstevel@tonic-gatestatic int envctrl_detach(device_t);
680Sstevel@tonic-gate
6911042SErik.Nordmark@Sun.COMstatic device_method_t envctrl_methods[] = {
7011042SErik.Nordmark@Sun.COM	/* device interface */
7111042SErik.Nordmark@Sun.COM	DEVMETHOD(device_probe,		envctrl_probe),
7211042SErik.Nordmark@Sun.COM	DEVMETHOD(device_attach,	envctrl_attach),
738612SAnders.Persson@Sun.COM	DEVMETHOD(device_detach,	envctrl_detach),
7411042SErik.Nordmark@Sun.COM
758612SAnders.Persson@Sun.COM	/* iicbus interface */
7611042SErik.Nordmark@Sun.COM	DEVMETHOD(iicbus_callback,	iicbus_null_callback),
770Sstevel@tonic-gate	DEVMETHOD(iicbus_repeated_start, pcf_repeated_start),
7811042SErik.Nordmark@Sun.COM	DEVMETHOD(iicbus_start,		pcf_start),
791673Sgt145670	DEVMETHOD(iicbus_stop,		pcf_stop),
8011042SErik.Nordmark@Sun.COM	DEVMETHOD(iicbus_write,		pcf_write),
812263Ssommerfe	DEVMETHOD(iicbus_read,		pcf_read),
8211042SErik.Nordmark@Sun.COM	DEVMETHOD(iicbus_reset,		pcf_rst_card),
8310934Ssommerfeld@sun.com	{ 0, 0 }
842263Ssommerfe};
8511042SErik.Nordmark@Sun.COM
862263Ssommerfestatic devclass_t envctrl_devclass;
8711042SErik.Nordmark@Sun.COM
880Sstevel@tonic-gatestatic driver_t envctrl_driver = {
890Sstevel@tonic-gate	"envctrl",
9011042SErik.Nordmark@Sun.COM	envctrl_methods,
918348SEric.Yu@Sun.COM	sizeof(struct pcf_softc),
920Sstevel@tonic-gate};
9311042SErik.Nordmark@Sun.COM
948348SEric.Yu@Sun.COMstatic int
950Sstevel@tonic-gateenvctrl_probe(device_t dev)
9611042SErik.Nordmark@Sun.COM{
970Sstevel@tonic-gate
9811042SErik.Nordmark@Sun.COM	if (strcmp("SUNW,envctrl", ebus_get_name(dev)) == 0) {
9911042SErik.Nordmark@Sun.COM		device_set_desc(dev, "EBus SUNW,envctrl");
10011042SErik.Nordmark@Sun.COM		return (0);
1010Sstevel@tonic-gate	}
10211042SErik.Nordmark@Sun.COM	return (ENXIO);
1030Sstevel@tonic-gate}
1040Sstevel@tonic-gate
10511042SErik.Nordmark@Sun.COMstatic int
1060Sstevel@tonic-gateenvctrl_attach(device_t dev)
1070Sstevel@tonic-gate{
10811042SErik.Nordmark@Sun.COM	struct pcf_softc *sc;
1090Sstevel@tonic-gate	int rv = ENXIO;
1100Sstevel@tonic-gate
11111042SErik.Nordmark@Sun.COM	sc = DEVTOSOFTC(dev);
1120Sstevel@tonic-gate	bzero(sc, sizeof(struct pcf_softc));
1130Sstevel@tonic-gate
11411042SErik.Nordmark@Sun.COM	/* IO port is mandatory */
1150Sstevel@tonic-gate	sc->res_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
1160Sstevel@tonic-gate						&sc->rid_ioport, RF_ACTIVE);
11711042SErik.Nordmark@Sun.COM	if (sc->res_ioport == 0) {
1180Sstevel@tonic-gate		device_printf(dev, "cannot reserve I/O port range\n");
1190Sstevel@tonic-gate		goto error;
12011042SErik.Nordmark@Sun.COM	}
1210Sstevel@tonic-gate	sc->bt_ioport = rman_get_bustag(sc->res_ioport);
1220Sstevel@tonic-gate	sc->bh_ioport = rman_get_bushandle(sc->res_ioport);
1230Sstevel@tonic-gate
12411042SErik.Nordmark@Sun.COM	sc->pcf_flags = device_get_flags(dev);
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate	if (!(sc->pcf_flags & IIC_POLLED)) {
12711042SErik.Nordmark@Sun.COM		sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rid_irq,
1280Sstevel@tonic-gate						     RF_ACTIVE);
12911042SErik.Nordmark@Sun.COM		if (sc->res_irq == 0) {
1300Sstevel@tonic-gate			device_printf(dev, "can't reserve irq, polled mode.\n");
1310Sstevel@tonic-gate			sc->pcf_flags |= IIC_POLLED;
13211042SErik.Nordmark@Sun.COM		}
1330Sstevel@tonic-gate	}
1340Sstevel@tonic-gate
13511042SErik.Nordmark@Sun.COM	/* reset the chip */
1360Sstevel@tonic-gate	pcf_rst_card(dev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL);
1370Sstevel@tonic-gate
1385455Smeem	rv = BUS_SETUP_INTR(device_get_parent(dev), dev, sc->res_irq,
1395455Smeem			    INTR_TYPE_NET /* | INTR_ENTROPY */,
1405455Smeem			    pcf_intr, sc, &sc->intr_cookie);
14111042SErik.Nordmark@Sun.COM	if (rv) {
1420Sstevel@tonic-gate		device_printf(dev, "could not setup IRQ\n");
1433318Srshoaib		goto error;
14411042SErik.Nordmark@Sun.COM	}
1453318Srshoaib
1463318Srshoaib	if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL)
14711042SErik.Nordmark@Sun.COM		device_printf(dev, "could not allocate iicbus instance\n");
14811042SErik.Nordmark@Sun.COM
14911042SErik.Nordmark@Sun.COM	/* probe and attach the iicbus */
1503318Srshoaib	bus_generic_attach(dev);
1511663Spriyanka
1520Sstevel@tonic-gate	return (0);
15311042SErik.Nordmark@Sun.COM
1540Sstevel@tonic-gateerror:
1550Sstevel@tonic-gate	if (sc->res_irq != 0) {
1560Sstevel@tonic-gate		bus_deactivate_resource(dev, SYS_RES_IRQ, sc->rid_irq,
15711042SErik.Nordmark@Sun.COM					sc->res_irq);
1580Sstevel@tonic-gate		bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq,
15911042SErik.Nordmark@Sun.COM				     sc->res_irq);
1600Sstevel@tonic-gate	}
1610Sstevel@tonic-gate	if (sc->res_ioport != 0) {
16211042SErik.Nordmark@Sun.COM		bus_deactivate_resource(dev, SYS_RES_IOPORT, sc->rid_ioport,
1630Sstevel@tonic-gate					sc->res_ioport);
1640Sstevel@tonic-gate		bus_release_resource(dev, SYS_RES_IOPORT, sc->rid_ioport,
16511042SErik.Nordmark@Sun.COM				     sc->res_ioport);
1660Sstevel@tonic-gate	}
1670Sstevel@tonic-gate	return (rv);
16811042SErik.Nordmark@Sun.COM}
1690Sstevel@tonic-gate
1700Sstevel@tonic-gatestatic int
17111042SErik.Nordmark@Sun.COMenvctrl_detach(device_t dev)
1720Sstevel@tonic-gate{
1730Sstevel@tonic-gate	struct pcf_softc *sc;
1740Sstevel@tonic-gate	int rv;
17511042SErik.Nordmark@Sun.COM
1760Sstevel@tonic-gate	sc = DEVTOSOFTC(dev);
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate	if ((rv = bus_generic_detach(dev)) != 0)
17911042SErik.Nordmark@Sun.COM		return (rv);
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate	if ((rv = device_delete_child(dev, sc->iicbus)) != 0)
18211042SErik.Nordmark@Sun.COM		return (rv);
1830Sstevel@tonic-gate
1840Sstevel@tonic-gate	if (sc->res_irq != 0) {
18511042SErik.Nordmark@Sun.COM		BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->res_irq,
1860Sstevel@tonic-gate				  sc->intr_cookie);
1870Sstevel@tonic-gate		bus_deactivate_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq);
18811042SErik.Nordmark@Sun.COM		bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq);
1890Sstevel@tonic-gate	}
1900Sstevel@tonic-gate
19111042SErik.Nordmark@Sun.COM	bus_deactivate_resource(dev, SYS_RES_IOPORT, sc->rid_ioport, sc->res_ioport);
1920Sstevel@tonic-gate	bus_release_resource(dev, SYS_RES_IOPORT, sc->rid_ioport, sc->res_ioport);
1930Sstevel@tonic-gate
19411042SErik.Nordmark@Sun.COM	return (0);
1950Sstevel@tonic-gate}
1960Sstevel@tonic-gate
19711042SErik.Nordmark@Sun.COMDRIVER_MODULE(envctrl, ebus, envctrl_driver, envctrl_devclass, 0, 0);
1980Sstevel@tonic-gateMODULE_DEPEND(envctrl, iicbus, PCF_MINVER, PCF_PREFVER, PCF_MAXVER);
1990Sstevel@tonic-gateMODULE_VERSION(envctrl, PCF_MODVER);
2000Sstevel@tonic-gate