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