xref: /freebsd/sys/dev/iicbus/sensor/max44009.c (revision 7c569caa0a6fffa7e1cc0a7f61e986dbc7c59074)
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 = &reghi;
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 = &reglo;
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