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