xref: /freebsd-12.1/sys/dev/pcf/envctrl.c (revision 718cf2cc)
1e0efc557SJoerg Wunsch /*-
2*718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*718cf2ccSPedro F. Giffuni  *
4e0efc557SJoerg Wunsch  * Copyright (c) 2004 Joerg Wunsch
5e0efc557SJoerg Wunsch  *
6e0efc557SJoerg Wunsch  * derived from sys/i386/isa/pcf.c which is:
7e0efc557SJoerg Wunsch  *
8e0efc557SJoerg Wunsch  * Copyright (c) 1998 Nicolas Souchu, Marc Bouget
9e0efc557SJoerg Wunsch  * All rights reserved.
10e0efc557SJoerg Wunsch  *
11e0efc557SJoerg Wunsch  * Redistribution and use in source and binary forms, with or without
12e0efc557SJoerg Wunsch  * modification, are permitted provided that the following conditions
13e0efc557SJoerg Wunsch  * are met:
14e0efc557SJoerg Wunsch  * 1. Redistributions of source code must retain the above copyright
15e0efc557SJoerg Wunsch  *    notice, this list of conditions and the following disclaimer.
16e0efc557SJoerg Wunsch  * 2. Redistributions in binary form must reproduce the above copyright
17e0efc557SJoerg Wunsch  *    notice, this list of conditions and the following disclaimer in the
18e0efc557SJoerg Wunsch  *    documentation and/or other materials provided with the distribution.
19e0efc557SJoerg Wunsch  *
20e0efc557SJoerg Wunsch  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21e0efc557SJoerg Wunsch  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22e0efc557SJoerg Wunsch  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23e0efc557SJoerg Wunsch  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24e0efc557SJoerg Wunsch  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25e0efc557SJoerg Wunsch  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26e0efc557SJoerg Wunsch  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27e0efc557SJoerg Wunsch  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28e0efc557SJoerg Wunsch  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29e0efc557SJoerg Wunsch  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30e0efc557SJoerg Wunsch  * SUCH DAMAGE.
31e0efc557SJoerg Wunsch  */
32e0efc557SJoerg Wunsch #include <sys/cdefs.h>
33e0efc557SJoerg Wunsch __FBSDID("$FreeBSD$");
34e0efc557SJoerg Wunsch 
35e0efc557SJoerg Wunsch /*
36e0efc557SJoerg Wunsch  * Device specific driver for the SUNW,envctrl device found on some
37e0efc557SJoerg Wunsch  * UltraSPARC Sun systems.  This device is a Philips PCF8584 sitting
38e0efc557SJoerg Wunsch  * on the Ebus2.
39e0efc557SJoerg Wunsch  */
40e0efc557SJoerg Wunsch 
41e0efc557SJoerg Wunsch #include <sys/param.h>
42e0efc557SJoerg Wunsch #include <sys/bus.h>
43e0efc557SJoerg Wunsch #include <sys/conf.h>
44e0efc557SJoerg Wunsch #include <sys/kernel.h>
4513e3657bSJohn Baldwin #include <sys/lock.h>
46e0efc557SJoerg Wunsch #include <sys/malloc.h>
47a9f012c7SMarius Strobl #include <sys/module.h>
4813e3657bSJohn Baldwin #include <sys/mutex.h>
49e0efc557SJoerg Wunsch #include <sys/resource.h>
5013e3657bSJohn Baldwin #include <sys/systm.h>
51e0efc557SJoerg Wunsch #include <sys/uio.h>
52e0efc557SJoerg Wunsch 
5326280d88SMarius Strobl #include <dev/ofw/ofw_bus.h>
5426280d88SMarius Strobl 
55e0efc557SJoerg Wunsch #include <machine/bus.h>
56e0efc557SJoerg Wunsch #include <machine/resource.h>
57e0efc557SJoerg Wunsch 
58e0efc557SJoerg Wunsch #include <sys/rman.h>
59e0efc557SJoerg Wunsch 
609e58d59fSJohn Baldwin #include <dev/iicbus/iicbus.h>
61e0efc557SJoerg Wunsch #include <dev/iicbus/iiconf.h>
62e0efc557SJoerg Wunsch #include <dev/pcf/pcfvar.h>
63e0efc557SJoerg Wunsch #include "iicbus_if.h"
64e0efc557SJoerg Wunsch 
65e0efc557SJoerg Wunsch #undef PCF_DEFAULT_ADDR
66e0efc557SJoerg Wunsch #define PCF_DEFAULT_ADDR	0x55 /* SUNW,pcf default */
67e0efc557SJoerg Wunsch 
68e0efc557SJoerg Wunsch static int envctrl_probe(device_t);
69e0efc557SJoerg Wunsch static int envctrl_attach(device_t);
70e0efc557SJoerg Wunsch static int envctrl_detach(device_t);
71e0efc557SJoerg Wunsch 
72e0efc557SJoerg Wunsch static device_method_t envctrl_methods[] = {
73e0efc557SJoerg Wunsch 	/* device interface */
74e0efc557SJoerg Wunsch 	DEVMETHOD(device_probe,		envctrl_probe),
75e0efc557SJoerg Wunsch 	DEVMETHOD(device_attach,	envctrl_attach),
76e0efc557SJoerg Wunsch 	DEVMETHOD(device_detach,	envctrl_detach),
77e0efc557SJoerg Wunsch 
78e0efc557SJoerg Wunsch 	/* iicbus interface */
79e0efc557SJoerg Wunsch 	DEVMETHOD(iicbus_callback,	iicbus_null_callback),
80e0efc557SJoerg Wunsch 	DEVMETHOD(iicbus_repeated_start, pcf_repeated_start),
81e0efc557SJoerg Wunsch 	DEVMETHOD(iicbus_start,		pcf_start),
82e0efc557SJoerg Wunsch 	DEVMETHOD(iicbus_stop,		pcf_stop),
83e0efc557SJoerg Wunsch 	DEVMETHOD(iicbus_write,		pcf_write),
84e0efc557SJoerg Wunsch 	DEVMETHOD(iicbus_read,		pcf_read),
85e0efc557SJoerg Wunsch 	DEVMETHOD(iicbus_reset,		pcf_rst_card),
86e0efc557SJoerg Wunsch 	{ 0, 0 }
87e0efc557SJoerg Wunsch };
88e0efc557SJoerg Wunsch 
89e0efc557SJoerg Wunsch static devclass_t envctrl_devclass;
90e0efc557SJoerg Wunsch 
91e0efc557SJoerg Wunsch static driver_t envctrl_driver = {
92e0efc557SJoerg Wunsch 	"envctrl",
93e0efc557SJoerg Wunsch 	envctrl_methods,
94e0efc557SJoerg Wunsch 	sizeof(struct pcf_softc),
95e0efc557SJoerg Wunsch };
96e0efc557SJoerg Wunsch 
97e0efc557SJoerg Wunsch static int
envctrl_probe(device_t dev)98e0efc557SJoerg Wunsch envctrl_probe(device_t dev)
99e0efc557SJoerg Wunsch {
100e0efc557SJoerg Wunsch 
10126280d88SMarius Strobl 	if (strcmp("SUNW,envctrl", ofw_bus_get_name(dev)) == 0) {
102e0efc557SJoerg Wunsch 		device_set_desc(dev, "EBus SUNW,envctrl");
103e0efc557SJoerg Wunsch 		return (0);
104e0efc557SJoerg Wunsch 	}
105e0efc557SJoerg Wunsch 	return (ENXIO);
106e0efc557SJoerg Wunsch }
107e0efc557SJoerg Wunsch 
108e0efc557SJoerg Wunsch static int
envctrl_attach(device_t dev)109e0efc557SJoerg Wunsch envctrl_attach(device_t dev)
110e0efc557SJoerg Wunsch {
111e0efc557SJoerg Wunsch 	struct pcf_softc *sc;
112e0efc557SJoerg Wunsch 	int rv = ENXIO;
113e0efc557SJoerg Wunsch 
114e0efc557SJoerg Wunsch 	sc = DEVTOSOFTC(dev);
11513e3657bSJohn Baldwin 	mtx_init(&sc->pcf_lock, device_get_nameunit(dev), "pcf", MTX_DEF);
116e0efc557SJoerg Wunsch 
117e0efc557SJoerg Wunsch 	/* IO port is mandatory */
118fcff6919SMarius Strobl 	sc->res_ioport = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
119e0efc557SJoerg Wunsch 						&sc->rid_ioport, RF_ACTIVE);
120e0efc557SJoerg Wunsch 	if (sc->res_ioport == 0) {
121e0efc557SJoerg Wunsch 		device_printf(dev, "cannot reserve I/O port range\n");
122e0efc557SJoerg Wunsch 		goto error;
123e0efc557SJoerg Wunsch 	}
124e0efc557SJoerg Wunsch 
125e0efc557SJoerg Wunsch 	sc->pcf_flags = device_get_flags(dev);
126e0efc557SJoerg Wunsch 
127e0efc557SJoerg Wunsch 	if (!(sc->pcf_flags & IIC_POLLED)) {
128e0efc557SJoerg Wunsch 		sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->rid_irq,
129e0efc557SJoerg Wunsch 						     RF_ACTIVE);
130e0efc557SJoerg Wunsch 		if (sc->res_irq == 0) {
131e0efc557SJoerg Wunsch 			device_printf(dev, "can't reserve irq, polled mode.\n");
132e0efc557SJoerg Wunsch 			sc->pcf_flags |= IIC_POLLED;
133e0efc557SJoerg Wunsch 		}
134e0efc557SJoerg Wunsch 	}
135e0efc557SJoerg Wunsch 
136e0efc557SJoerg Wunsch 	/* reset the chip */
137e0efc557SJoerg Wunsch 	pcf_rst_card(dev, IIC_FASTEST, PCF_DEFAULT_ADDR, NULL);
138e0efc557SJoerg Wunsch 
13957fb5e60SJohn Baldwin 	rv = bus_setup_intr(dev, sc->res_irq,
14013e3657bSJohn Baldwin 			    INTR_TYPE_NET | INTR_MPSAFE /* | INTR_ENTROPY */,
141ef544f63SPaolo Pisati 			    NULL, pcf_intr, sc, &sc->intr_cookie);
142e0efc557SJoerg Wunsch 	if (rv) {
143e0efc557SJoerg Wunsch 		device_printf(dev, "could not setup IRQ\n");
144e0efc557SJoerg Wunsch 		goto error;
145e0efc557SJoerg Wunsch 	}
146e0efc557SJoerg Wunsch 
147e0efc557SJoerg Wunsch 	if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL)
148e0efc557SJoerg Wunsch 		device_printf(dev, "could not allocate iicbus instance\n");
149e0efc557SJoerg Wunsch 
150e0efc557SJoerg Wunsch 	/* probe and attach the iicbus */
151e0efc557SJoerg Wunsch 	bus_generic_attach(dev);
152e0efc557SJoerg Wunsch 
153e0efc557SJoerg Wunsch 	return (0);
154e0efc557SJoerg Wunsch 
155e0efc557SJoerg Wunsch error:
156e0efc557SJoerg Wunsch 	if (sc->res_irq != 0) {
157e0efc557SJoerg Wunsch 		bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq,
158e0efc557SJoerg Wunsch 				     sc->res_irq);
159e0efc557SJoerg Wunsch 	}
160e0efc557SJoerg Wunsch 	if (sc->res_ioport != 0) {
161fcff6919SMarius Strobl 		bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ioport,
162e0efc557SJoerg Wunsch 				     sc->res_ioport);
163e0efc557SJoerg Wunsch 	}
16413e3657bSJohn Baldwin 	mtx_destroy(&sc->pcf_lock);
165e0efc557SJoerg Wunsch 	return (rv);
166e0efc557SJoerg Wunsch }
167e0efc557SJoerg Wunsch 
168e0efc557SJoerg Wunsch static int
envctrl_detach(device_t dev)169e0efc557SJoerg Wunsch envctrl_detach(device_t dev)
170e0efc557SJoerg Wunsch {
171e0efc557SJoerg Wunsch 	struct pcf_softc *sc;
172e0efc557SJoerg Wunsch 	int rv;
173e0efc557SJoerg Wunsch 
174e0efc557SJoerg Wunsch 	sc = DEVTOSOFTC(dev);
175e0efc557SJoerg Wunsch 
176e0efc557SJoerg Wunsch 	if ((rv = bus_generic_detach(dev)) != 0)
177e0efc557SJoerg Wunsch 		return (rv);
178e0efc557SJoerg Wunsch 
179e0efc557SJoerg Wunsch 	if ((rv = device_delete_child(dev, sc->iicbus)) != 0)
180e0efc557SJoerg Wunsch 		return (rv);
181e0efc557SJoerg Wunsch 
182e0efc557SJoerg Wunsch 	if (sc->res_irq != 0) {
18357fb5e60SJohn Baldwin 		bus_teardown_intr(dev, sc->res_irq, sc->intr_cookie);
184e0efc557SJoerg Wunsch 		bus_release_resource(dev, SYS_RES_IRQ, sc->rid_irq, sc->res_irq);
185e0efc557SJoerg Wunsch 	}
186e0efc557SJoerg Wunsch 
187fcff6919SMarius Strobl 	bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ioport, sc->res_ioport);
18813e3657bSJohn Baldwin 	mtx_destroy(&sc->pcf_lock);
189e0efc557SJoerg Wunsch 
190e0efc557SJoerg Wunsch 	return (0);
191e0efc557SJoerg Wunsch }
192e0efc557SJoerg Wunsch 
193a9f012c7SMarius Strobl DRIVER_MODULE(envctrl, ebus, envctrl_driver, envctrl_devclass, 0, 0);
19413e3657bSJohn Baldwin DRIVER_MODULE(iicbus, envctrl, iicbus_driver, iicbus_devclass, 0, 0);
195