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