1*7c569caaSEmmanuel Vadot /*-
2*7c569caaSEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause
3*7c569caaSEmmanuel Vadot *
4*7c569caaSEmmanuel Vadot * Copyright (c) Andriy Gapon
5*7c569caaSEmmanuel Vadot *
6*7c569caaSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without
7*7c569caaSEmmanuel Vadot * modification, are permitted provided that the following conditions
8*7c569caaSEmmanuel Vadot * are met:
9*7c569caaSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright
10*7c569caaSEmmanuel Vadot * notice, this list of conditions, and the following disclaimer.
11*7c569caaSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright
12*7c569caaSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the
13*7c569caaSEmmanuel Vadot * documentation and/or other materials provided with the distribution.
14*7c569caaSEmmanuel Vadot *
15*7c569caaSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*7c569caaSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*7c569caaSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*7c569caaSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19*7c569caaSEmmanuel Vadot * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*7c569caaSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*7c569caaSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*7c569caaSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*7c569caaSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*7c569caaSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*7c569caaSEmmanuel Vadot * SUCH DAMAGE.
26*7c569caaSEmmanuel Vadot *
27*7c569caaSEmmanuel Vadot */
28*7c569caaSEmmanuel Vadot
29*7c569caaSEmmanuel Vadot #include <sys/cdefs.h>
30*7c569caaSEmmanuel Vadot #include "opt_platform.h"
31*7c569caaSEmmanuel Vadot
32*7c569caaSEmmanuel Vadot #include <sys/param.h>
33*7c569caaSEmmanuel Vadot #include <sys/bus.h>
34*7c569caaSEmmanuel Vadot #include <sys/kernel.h>
35*7c569caaSEmmanuel Vadot #include <sys/module.h>
36*7c569caaSEmmanuel Vadot #include <sys/sysctl.h>
37*7c569caaSEmmanuel Vadot #include <sys/systm.h>
38*7c569caaSEmmanuel Vadot
39*7c569caaSEmmanuel Vadot #include <machine/bus.h>
40*7c569caaSEmmanuel Vadot
41*7c569caaSEmmanuel Vadot #include <dev/iicbus/iicbus.h>
42*7c569caaSEmmanuel Vadot #include <dev/iicbus/iiconf.h>
43*7c569caaSEmmanuel Vadot
44*7c569caaSEmmanuel Vadot #ifdef FDT
45*7c569caaSEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
46*7c569caaSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
47*7c569caaSEmmanuel Vadot #endif
48*7c569caaSEmmanuel Vadot
49*7c569caaSEmmanuel Vadot /*
50*7c569caaSEmmanuel Vadot * Driver for MAX44009 Ambient Light Sensor with ADC.
51*7c569caaSEmmanuel Vadot */
52*7c569caaSEmmanuel Vadot #define REG_LUX_HIGH 0x03
53*7c569caaSEmmanuel Vadot #define REG_LUX_LOW 0x04
54*7c569caaSEmmanuel Vadot
55*7c569caaSEmmanuel Vadot struct max44009_softc {
56*7c569caaSEmmanuel Vadot device_t sc_dev;
57*7c569caaSEmmanuel Vadot uint8_t sc_addr;
58*7c569caaSEmmanuel Vadot };
59*7c569caaSEmmanuel Vadot
60*7c569caaSEmmanuel Vadot #ifdef FDT
61*7c569caaSEmmanuel Vadot static const struct ofw_compat_data compat_data[] = {
62*7c569caaSEmmanuel Vadot { "maxim,max44009", true },
63*7c569caaSEmmanuel Vadot { NULL, false },
64*7c569caaSEmmanuel Vadot };
65*7c569caaSEmmanuel Vadot #endif
66*7c569caaSEmmanuel Vadot
67*7c569caaSEmmanuel Vadot static int
max44009_get_reading(device_t dev,u_int * reading)68*7c569caaSEmmanuel Vadot max44009_get_reading(device_t dev, u_int *reading)
69*7c569caaSEmmanuel Vadot {
70*7c569caaSEmmanuel Vadot struct iic_msg msgs[4];
71*7c569caaSEmmanuel Vadot struct max44009_softc *sc;
72*7c569caaSEmmanuel Vadot u_int val;
73*7c569caaSEmmanuel Vadot uint8_t reghi, reglo, valhi, vallo;
74*7c569caaSEmmanuel Vadot int error;
75*7c569caaSEmmanuel Vadot
76*7c569caaSEmmanuel Vadot sc = device_get_softc(dev);
77*7c569caaSEmmanuel Vadot
78*7c569caaSEmmanuel Vadot reghi = REG_LUX_HIGH;
79*7c569caaSEmmanuel Vadot reglo = REG_LUX_LOW;
80*7c569caaSEmmanuel Vadot msgs[0].slave = sc->sc_addr;
81*7c569caaSEmmanuel Vadot msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP;
82*7c569caaSEmmanuel Vadot msgs[0].len = 1;
83*7c569caaSEmmanuel Vadot msgs[0].buf = ®hi;
84*7c569caaSEmmanuel Vadot msgs[1].slave = sc->sc_addr;
85*7c569caaSEmmanuel Vadot msgs[1].flags = IIC_M_RD | IIC_M_NOSTOP;
86*7c569caaSEmmanuel Vadot msgs[1].len = 1;
87*7c569caaSEmmanuel Vadot msgs[1].buf = &valhi;
88*7c569caaSEmmanuel Vadot msgs[2].slave = sc->sc_addr;
89*7c569caaSEmmanuel Vadot msgs[2].flags = IIC_M_WR | IIC_M_NOSTOP;
90*7c569caaSEmmanuel Vadot msgs[2].len = 1;
91*7c569caaSEmmanuel Vadot msgs[2].buf = ®lo;
92*7c569caaSEmmanuel Vadot msgs[3].slave = sc->sc_addr;
93*7c569caaSEmmanuel Vadot msgs[3].flags = IIC_M_RD;
94*7c569caaSEmmanuel Vadot msgs[3].len = 1;
95*7c569caaSEmmanuel Vadot msgs[3].buf = &vallo;
96*7c569caaSEmmanuel Vadot
97*7c569caaSEmmanuel Vadot error = iicbus_transfer_excl(dev, msgs, nitems(msgs), IIC_INTRWAIT);
98*7c569caaSEmmanuel Vadot if (error != 0)
99*7c569caaSEmmanuel Vadot return (error);
100*7c569caaSEmmanuel Vadot
101*7c569caaSEmmanuel Vadot val = ((valhi & 0x0f) << 4) | (vallo & 0x0f);
102*7c569caaSEmmanuel Vadot val <<= (valhi & 0xf0) >> 4;
103*7c569caaSEmmanuel Vadot val = val * 72 / 100;
104*7c569caaSEmmanuel Vadot *reading = val;
105*7c569caaSEmmanuel Vadot return (0);
106*7c569caaSEmmanuel Vadot }
107*7c569caaSEmmanuel Vadot
108*7c569caaSEmmanuel Vadot static int
max44009_lux_sysctl(SYSCTL_HANDLER_ARGS)109*7c569caaSEmmanuel Vadot max44009_lux_sysctl(SYSCTL_HANDLER_ARGS)
110*7c569caaSEmmanuel Vadot {
111*7c569caaSEmmanuel Vadot device_t dev;
112*7c569caaSEmmanuel Vadot u_int reading;
113*7c569caaSEmmanuel Vadot int error, val;
114*7c569caaSEmmanuel Vadot
115*7c569caaSEmmanuel Vadot if (req->oldptr != NULL) {
116*7c569caaSEmmanuel Vadot dev = arg1;
117*7c569caaSEmmanuel Vadot error = max44009_get_reading(dev, &reading);
118*7c569caaSEmmanuel Vadot if (error != 0)
119*7c569caaSEmmanuel Vadot return (EIO);
120*7c569caaSEmmanuel Vadot val = reading;
121*7c569caaSEmmanuel Vadot }
122*7c569caaSEmmanuel Vadot error = sysctl_handle_int(oidp, &val, 0, req);
123*7c569caaSEmmanuel Vadot return (error);
124*7c569caaSEmmanuel Vadot }
125*7c569caaSEmmanuel Vadot
126*7c569caaSEmmanuel Vadot static int
max44009_probe(device_t dev)127*7c569caaSEmmanuel Vadot max44009_probe(device_t dev)
128*7c569caaSEmmanuel Vadot {
129*7c569caaSEmmanuel Vadot int rc;
130*7c569caaSEmmanuel Vadot
131*7c569caaSEmmanuel Vadot #ifdef FDT
132*7c569caaSEmmanuel Vadot if (!ofw_bus_status_okay(dev))
133*7c569caaSEmmanuel Vadot return (ENXIO);
134*7c569caaSEmmanuel Vadot if (ofw_bus_search_compatible(dev, compat_data)->ocd_data)
135*7c569caaSEmmanuel Vadot rc = BUS_PROBE_GENERIC;
136*7c569caaSEmmanuel Vadot else
137*7c569caaSEmmanuel Vadot #endif
138*7c569caaSEmmanuel Vadot rc = BUS_PROBE_NOWILDCARD;
139*7c569caaSEmmanuel Vadot device_set_desc(dev, "MAX44009 light intensity sensor");
140*7c569caaSEmmanuel Vadot return (rc);
141*7c569caaSEmmanuel Vadot }
142*7c569caaSEmmanuel Vadot
143*7c569caaSEmmanuel Vadot static int
max44009_attach(device_t dev)144*7c569caaSEmmanuel Vadot max44009_attach(device_t dev)
145*7c569caaSEmmanuel Vadot {
146*7c569caaSEmmanuel Vadot struct max44009_softc *sc;
147*7c569caaSEmmanuel Vadot struct sysctl_ctx_list *ctx;
148*7c569caaSEmmanuel Vadot struct sysctl_oid *tree_node;
149*7c569caaSEmmanuel Vadot struct sysctl_oid_list *tree;
150*7c569caaSEmmanuel Vadot
151*7c569caaSEmmanuel Vadot sc = device_get_softc(dev);
152*7c569caaSEmmanuel Vadot sc->sc_dev = dev;
153*7c569caaSEmmanuel Vadot sc->sc_addr = iicbus_get_addr(dev);
154*7c569caaSEmmanuel Vadot
155*7c569caaSEmmanuel Vadot ctx = device_get_sysctl_ctx(dev);
156*7c569caaSEmmanuel Vadot tree_node = device_get_sysctl_tree(dev);
157*7c569caaSEmmanuel Vadot tree = SYSCTL_CHILDREN(tree_node);
158*7c569caaSEmmanuel Vadot
159*7c569caaSEmmanuel Vadot SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "illuminance",
160*7c569caaSEmmanuel Vadot CTLTYPE_INT | CTLFLAG_RD, dev, 0,
161*7c569caaSEmmanuel Vadot max44009_lux_sysctl, "I", "Light intensity, lux");
162*7c569caaSEmmanuel Vadot return (0);
163*7c569caaSEmmanuel Vadot }
164*7c569caaSEmmanuel Vadot
165*7c569caaSEmmanuel Vadot static int
max44009_detach(device_t dev)166*7c569caaSEmmanuel Vadot max44009_detach(device_t dev)
167*7c569caaSEmmanuel Vadot {
168*7c569caaSEmmanuel Vadot return (0);
169*7c569caaSEmmanuel Vadot }
170*7c569caaSEmmanuel Vadot
171*7c569caaSEmmanuel Vadot static device_method_t max44009_methods[] = {
172*7c569caaSEmmanuel Vadot /* Device interface */
173*7c569caaSEmmanuel Vadot DEVMETHOD(device_probe, max44009_probe),
174*7c569caaSEmmanuel Vadot DEVMETHOD(device_attach, max44009_attach),
175*7c569caaSEmmanuel Vadot DEVMETHOD(device_detach, max44009_detach),
176*7c569caaSEmmanuel Vadot
177*7c569caaSEmmanuel Vadot DEVMETHOD_END
178*7c569caaSEmmanuel Vadot };
179*7c569caaSEmmanuel Vadot
180*7c569caaSEmmanuel Vadot static driver_t max44009_driver = {
181*7c569caaSEmmanuel Vadot "max44009",
182*7c569caaSEmmanuel Vadot max44009_methods,
183*7c569caaSEmmanuel Vadot sizeof(struct max44009_softc)
184*7c569caaSEmmanuel Vadot };
185*7c569caaSEmmanuel Vadot
186*7c569caaSEmmanuel Vadot DRIVER_MODULE(max44009, iicbus, max44009_driver, 0, 0);
187*7c569caaSEmmanuel Vadot MODULE_DEPEND(max44009, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
188*7c569caaSEmmanuel Vadot MODULE_VERSION(max44009, 1);
189*7c569caaSEmmanuel Vadot IICBUS_FDT_PNP_INFO(compat_data);
190