pcf_isa.c revision 181332
1151937Sjkim/*-
2151937Sjkim * Copyright (c) 2004 Joerg Wunsch
3151937Sjkim *
4151937Sjkim * derived from sys/i386/isa/pcf.c which is:
5151937Sjkim *
6151937Sjkim * Copyright (c) 1998 Nicolas Souchu, Marc Bouget
7217365Sjkim * All rights reserved.
8298714Sjkim *
9151937Sjkim * Redistribution and use in source and binary forms, with or without
10151937Sjkim * modification, are permitted provided that the following conditions
11217365Sjkim * are met:
12217365Sjkim * 1. Redistributions of source code must retain the above copyright
13217365Sjkim *    notice, this list of conditions and the following disclaimer.
14217365Sjkim * 2. Redistributions in binary form must reproduce the above copyright
15217365Sjkim *    notice, this list of conditions and the following disclaimer in the
16217365Sjkim *    documentation and/or other materials provided with the distribution.
17217365Sjkim *
18217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19217365Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21217365Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22217365Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25151937Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26217365Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27217365Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28217365Sjkim * SUCH DAMAGE.
29151937Sjkim */
30217365Sjkim#include <sys/cdefs.h>
31217365Sjkim__FBSDID("$FreeBSD: head/sys/dev/pcf/pcf_isa.c 181332 2008-08-05 17:39:37Z jhb $");
32217365Sjkim
33217365Sjkim/*
34217365Sjkim * Hardware driver for a Philips PCF8584 I2C bus controller sitting
35217365Sjkim * on a generic ISA bus.
36217365Sjkim */
37217365Sjkim
38217365Sjkim#include <sys/param.h>
39217365Sjkim#include <sys/bus.h>
40217365Sjkim#include <sys/lock.h>
41217365Sjkim#include <sys/kernel.h>
42217365Sjkim#include <sys/module.h>
43151937Sjkim#include <sys/mutex.h>
44151937Sjkim#include <sys/resource.h>
45151937Sjkim#include <sys/systm.h>
46151937Sjkim
47151937Sjkim#include <machine/bus.h>
48151937Sjkim#include <machine/resource.h>
49151937Sjkim
50151937Sjkim#include <sys/rman.h>
51151937Sjkim
52151937Sjkim#include <isa/isareg.h>
53151937Sjkim#include <isa/isavar.h>
54151937Sjkim
55151937Sjkim#include <dev/iicbus/iiconf.h>
56151937Sjkim#include <dev/pcf/pcfvar.h>
57241973Sjkim#include "iicbus_if.h"
58151937Sjkim
59151937Sjkim#define	PCF_NAME	"pcf"
60151937Sjkim
61151937Sjkimstatic void pcf_isa_identify(driver_t *, device_t);
62151937Sjkimstatic int pcf_isa_probe(device_t);
63151937Sjkimstatic int pcf_isa_attach(device_t);
64151937Sjkimstatic int pcf_isa_detach(device_t);
65151937Sjkim
66151937Sjkimstatic device_method_t pcf_isa_methods[] = {
67241973Sjkim	/* device interface */
68151937Sjkim	DEVMETHOD(device_identify,	pcf_isa_identify),
69151937Sjkim	DEVMETHOD(device_probe,		pcf_isa_probe),
70151937Sjkim	DEVMETHOD(device_attach,	pcf_isa_attach),
71151937Sjkim	DEVMETHOD(device_detach,	pcf_isa_detach),
72151937Sjkim
73151937Sjkim	/* iicbus interface */
74151937Sjkim	DEVMETHOD(iicbus_callback,	iicbus_null_callback),
75151937Sjkim	DEVMETHOD(iicbus_repeated_start, pcf_repeated_start),
76151937Sjkim	DEVMETHOD(iicbus_start,		pcf_start),
77151937Sjkim	DEVMETHOD(iicbus_stop,		pcf_stop),
78151937Sjkim	DEVMETHOD(iicbus_write,		pcf_write),
79151937Sjkim	DEVMETHOD(iicbus_read,		pcf_read),
80151937Sjkim	DEVMETHOD(iicbus_reset,		pcf_rst_card),
81151937Sjkim	{ 0, 0 }
82151937Sjkim};
83151937Sjkim
84151937Sjkimstatic devclass_t pcf_isa_devclass;
85151937Sjkim
86151937Sjkimstatic driver_t pcf_isa_driver = {
87151937Sjkim	PCF_NAME,
88151937Sjkim	pcf_isa_methods,
89151937Sjkim	sizeof(struct pcf_softc),
90151937Sjkim};
91151937Sjkim
92151937Sjkimstatic void
93151937Sjkimpcf_isa_identify(driver_t *driver, device_t parent)
94151937Sjkim{
95151937Sjkim	BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, PCF_NAME, 0);
96298714Sjkim
97228110Sjkim	return;
98151937Sjkim}
99167802Sjkim
100151937Sjkimstatic int
101151937Sjkimpcf_isa_probe(device_t dev)
102151937Sjkim{
103151937Sjkim	u_long		start, count;
104151937Sjkim	u_int		rid = 0, port, error;
105151937Sjkim
106151937Sjkim	/* skip PnP probes */
107151937Sjkim	if (isa_get_logicalid(dev))
108151937Sjkim		return (ENXIO);
109151937Sjkim
110151937Sjkim	/* The port address must be explicitly specified */
111151937Sjkim	bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count);
112151937Sjkim	if ((error = resource_int_value(PCF_NAME, 0, "port", &port) != 0))
113151937Sjkim		return (error);
114151937Sjkim
115281396Sjkim	/* Probe is only successfull for the specified base io */
116151937Sjkim	if (port != (u_int)start)
117151937Sjkim		return (ENXIO);
118151937Sjkim
119151937Sjkim	device_set_desc(dev, "PCF8584 I2C bus controller");
120151937Sjkim
121151937Sjkim	return (0);
122151937Sjkim}
123151937Sjkim
124151937Sjkimstatic int
125151937Sjkimpcf_isa_attach(device_t dev)
126151937Sjkim{
127151937Sjkim	struct pcf_softc *sc;
128151937Sjkim	int rv = ENXIO;
129151937Sjkim
130151937Sjkim	sc = DEVTOSOFTC(dev);
131151937Sjkim	mtx_init(&sc->pcf_lock, device_get_nameunit(dev), "pcf", MTX_DEF);
132151937Sjkim
133151937Sjkim	/* IO port is mandatory */
134151937Sjkim	sc->res_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
135151937Sjkim						&sc->rid_ioport, RF_ACTIVE);
136151937Sjkim	if (sc->res_ioport == 0) {
137151937Sjkim		device_printf(dev, "cannot reserve I/O port range\n");
138151937Sjkim		goto error;
139151937Sjkim	}
140151937Sjkim
141151937Sjkim	sc->pcf_flags = device_get_flags(dev);
142151937Sjkim
143151937Sjkim	if (!(sc->pcf_flags & IIC_POLLED)) {
144151937Sjkim		sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rid_irq,
145151937Sjkim						     RF_ACTIVE);
146151937Sjkim		if (sc->res_irq == 0) {
147151937Sjkim			device_printf(dev, "can't reserve irq, polled mode.\n");
148151937Sjkim			sc->pcf_flags |= IIC_POLLED;
149151937Sjkim		}
150151937Sjkim	}
151151937Sjkim
152151937Sjkim	/* reset the chip */
153151937Sjkim	pcf_rst_card(dev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL);
154151937Sjkim
155151937Sjkim	if (sc->res_irq) {
156298714Sjkim		rv = bus_setup_intr(dev, sc->res_irq,
157151937Sjkim				    INTR_TYPE_NET /* | INTR_ENTROPY */,
158151937Sjkim				    NULL, pcf_intr, sc, &sc->intr_cookie);
159151937Sjkim		if (rv) {
160151937Sjkim			device_printf(dev, "could not setup IRQ\n");
161151937Sjkim			goto error;
162151937Sjkim		}
163298714Sjkim	}
164151937Sjkim
165151937Sjkim	if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL)
166151937Sjkim		device_printf(dev, "could not allocate iicbus instance\n");
167151937Sjkim
168151937Sjkim	/* probe and attach the iicbus */
169151937Sjkim	bus_generic_attach(dev);
170151937Sjkim
171228110Sjkim	return (0);
172151937Sjkim
173151937Sjkimerror:
174151937Sjkim	if (sc->res_irq != 0) {
175151937Sjkim		bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq,
176151937Sjkim				     sc->res_irq);
177151937Sjkim	}
178151937Sjkim	if (sc->res_ioport != 0) {
179151937Sjkim		bus_release_resource(dev, SYS_RES_IOPORT, sc->rid_ioport,
180151937Sjkim				     sc->res_ioport);
181151937Sjkim	}
182151937Sjkim	mtx_destroy(&sc->pcf_lock);
183151937Sjkim	return (rv);
184151937Sjkim}
185151937Sjkim
186151937Sjkimstatic int
187151937Sjkimpcf_isa_detach(device_t dev)
188151937Sjkim{
189151937Sjkim	struct pcf_softc *sc;
190151937Sjkim	int rv;
191151937Sjkim
192151937Sjkim	sc = DEVTOSOFTC(dev);
193151937Sjkim
194151937Sjkim	if ((rv = bus_generic_detach(dev)) != 0)
195151937Sjkim		return (rv);
196151937Sjkim
197151937Sjkim	if ((rv = device_delete_child(dev, sc->iicbus)) != 0)
198151937Sjkim		return (rv);
199241973Sjkim
200151937Sjkim	if (sc->res_irq != 0) {
201151937Sjkim		bus_teardown_intr(dev, sc->res_irq, sc->intr_cookie);
202151937Sjkim		bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq);
203151937Sjkim	}
204151937Sjkim
205151937Sjkim	bus_release_resource(dev, SYS_RES_IOPORT, sc->rid_ioport, sc->res_ioport);
206151937Sjkim	mtx_destroy(&sc->pcf_lock);
207151937Sjkim
208151937Sjkim	return (0);
209151937Sjkim}
210151937Sjkim
211151937SjkimDRIVER_MODULE(pcf_isa, isa, pcf_isa_driver, pcf_isa_devclass, 0, 0);
212151937Sjkim