1 /*
2 * Copyright (C) 2017 STMicroelectronics
3 * Copyright (C) 2017 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <float.h>
21
22 #include <seos.h>
23 #include <i2c.h>
24 #include <timer.h>
25 #include <sensors.h>
26 #include <heap.h>
27 #include <hostIntf.h>
28 #include <nanohubPacket.h>
29 #include <eventnums.h>
30 #include <util.h>
31 #include <variant/variant.h>
32
33 #ifdef DEBUG
34 #undef ISL29034_DBG_ENABLED
35 #define ISL29034_DBG_ENABLED 1
36 #endif
37
38 #ifndef ISL29034_DBG_ENABLED
39 #define ISL29034_DBG_ENABLED 0
40 #endif /* ISL29034_DBG_ENABLED */
41
42 #define ISL29034_APP_VERSION 1
43
44 #define ISL29034_REG_CMD_1 0x00
45 #define ISL29034_REG_CMD_2 0x01
46 #define ISL29034_REG_DATA_L 0x02
47 #define ISL29034_REG_DATA_H 0x03
48 #define ISL29034_REG_ID 0x0f
49
50 #define ISL29034_CMD1_POWERDOWN (0 << 5)
51 #define ISL29034_CMD1_MEASURE (5 << 5)
52
53 #define ISL29034_CMD2_RANGE_1KLUX 0
54 #define ISL29034_CMD2_RANGE_4KLUX 1
55 #define ISL29034_CMD2_RANGE_16KLUX 2
56 #define ISL29034_CMD2_RANGE_64KLUX 3
57 #define ISL29034_CMD2_RES_16BIT (0 << 2)
58 #define ISL29034_CMD2_RES_12BIT (1 << 2)
59 #define ISL29034_CMD2_RES_8BIT (2 << 2)
60 #define ISL29034_CMD2_RES_4BIT (3 << 2)
61
62 #define ISL29034_ID (5 << 3)
63 #define ISL29034_ID_MASK (7 << 3)
64 #define ISL29034_ID_BOUT (1 << 7)
65
66 #define ISL29034_ALS_INVALID UINT32_MAX
67 #define ISL29034_MAX_PENDING_I2C_REQUESTS 4
68 #define ISL29034_MAX_I2C_TRANSFER_SIZE 3
69
70 /* Used when SENSOR_RATE_ONCHANGE is requested */
71 #define ISL29034_DEFAULT_RATE SENSOR_HZ(10)
72
73 #ifndef ISL29034_I2C_BUS_ID
74 #error "ISL29034_I2C_BUS_ID is not defined; please define in variant.h"
75 #endif
76
77 #ifndef ISL29034_I2C_SPEED
78 #error "ISL29034_I2C_SPEED is not defined; please define in variant.h"
79 #endif
80
81 #ifndef ISL29034_I2C_ADDR
82 #define ISL29034_I2C_ADDR 0x44
83 #endif
84
85 #define INFO_PRINT(fmt, ...) \
86 do { \
87 osLog(LOG_INFO, "%s " fmt, "[ISL29034]", ##__VA_ARGS__); \
88 } while (0);
89
90 #define DEBUG_PRINT(fmt, ...) \
91 do { \
92 if (ISL29034_DBG_ENABLED) { \
93 osLog(LOG_DEBUG, "%s " fmt, "[ISL29034]", ##__VA_ARGS__); \
94 } \
95 } while (0);
96
97 #define ERROR_PRINT(fmt, ...) \
98 do { \
99 osLog(LOG_ERROR, "%s " fmt, "[ISL29034]", ##__VA_ARGS__); \
100 } while (0);
101
102
103 /* Private driver events */
104 enum SensorEvents
105 {
106 EVT_SENSOR_I2C = EVT_APP_START + 1,
107 EVT_SENSOR_ALS_TIMER,
108 };
109
110 /* I2C state machine */
111 enum SensorState
112 {
113 SENSOR_STATE_VERIFY_ID,
114 SENSOR_STATE_CLEAR_BOUT,
115
116 SENSOR_STATE_ENABLING_ALS,
117 SENSOR_STATE_DISABLING_ALS,
118
119 SENSOR_STATE_IDLE,
120 SENSOR_STATE_SAMPLING,
121 };
122
123 struct I2cTransfer
124 {
125 size_t tx;
126 size_t rx;
127 int err;
128
129 uint8_t txrxBuf[ISL29034_MAX_I2C_TRANSFER_SIZE];
130
131 uint8_t state;
132 bool inUse;
133 };
134
135 struct SensorData
136 {
137 uint32_t tid;
138
139 uint32_t alsHandle;
140 uint32_t alsTimerHandle;
141
142 struct I2cTransfer transfers[ISL29034_MAX_PENDING_I2C_REQUESTS];
143
144 union EmbeddedDataPoint lastAlsSample;
145
146 bool alsOn;
147 bool alsReading;
148 };
149
150 static struct SensorData mData;
151
152 static const uint32_t supportedRates[] =
153 {
154 SENSOR_HZ(10),
155 SENSOR_RATE_ONCHANGE,
156 0
157 };
158
159 // should match "supported rates in length" and be the timer length for that rate in nanosecs
160 static const uint64_t rateTimerVals[] =
161 {
162 1000000000ULL / 10,
163 };
164
165 /*
166 * Helper functions
167 */
168
i2cCallback(void * cookie,size_t tx,size_t rx,int err)169 static void i2cCallback(void *cookie, size_t tx, size_t rx, int err)
170 {
171 struct I2cTransfer *xfer = cookie;
172
173 xfer->tx = tx;
174 xfer->rx = rx;
175 xfer->err = err;
176
177 osEnqueuePrivateEvt(EVT_SENSOR_I2C, cookie, NULL, mData.tid);
178 if (err != 0)
179 INFO_PRINT("i2c error (tx: %d, rx: %d, err: %d)\n", tx, rx, err);
180 }
181
182 // Allocate a buffer and mark it as in use with the given state, or return NULL
183 // if no buffers available. Must *not* be called from interrupt context.
allocXfer(uint8_t state)184 static struct I2cTransfer *allocXfer(uint8_t state)
185 {
186 size_t i;
187
188 for (i = 0; i < ARRAY_SIZE(mData.transfers); i++) {
189 if (!mData.transfers[i].inUse) {
190 mData.transfers[i].inUse = true;
191 mData.transfers[i].state = state;
192 return &mData.transfers[i];
193 }
194 }
195
196 ERROR_PRINT("Ran out of i2c buffers!");
197 return NULL;
198 }
199
200 // Helper function to write a one byte register. Returns true if we got a
201 // successful return value from i2cMasterTx().
writeRegister(uint8_t reg,uint8_t value,uint8_t state)202 static bool writeRegister(uint8_t reg, uint8_t value, uint8_t state)
203 {
204 struct I2cTransfer *xfer = allocXfer(state);
205 int ret = -1;
206
207 if (xfer != NULL) {
208 xfer->txrxBuf[0] = reg;
209 xfer->txrxBuf[1] = value;
210 ret = i2cMasterTx(ISL29034_I2C_BUS_ID, ISL29034_I2C_ADDR, xfer->txrxBuf, 2, i2cCallback, xfer);
211 }
212
213 return (ret == 0);
214 }
215
alsTimerCallback(uint32_t timerId,void * cookie)216 static void alsTimerCallback(uint32_t timerId, void *cookie)
217 {
218 osEnqueuePrivateEvt(EVT_SENSOR_ALS_TIMER, cookie, NULL, mData.tid);
219 }
220
getLuxFromAlsData(uint16_t als)221 static inline float getLuxFromAlsData(uint16_t als)
222 {
223 float range = 64000.0;
224 float resolution = 65536.0;
225
226 return range * als / resolution;
227 }
228
sensorPowerAls(bool on,void * cookie)229 static bool sensorPowerAls(bool on, void *cookie)
230 {
231 INFO_PRINT("sensorPowerAls: %d\n", on);
232
233 if (mData.alsTimerHandle) {
234 timTimerCancel(mData.alsTimerHandle);
235 mData.alsTimerHandle = 0;
236 mData.alsReading = false;
237 }
238
239 mData.lastAlsSample.idata = ISL29034_ALS_INVALID;
240 mData.alsOn = on;
241
242 writeRegister(ISL29034_REG_CMD_1,
243 on ? ISL29034_CMD1_MEASURE : ISL29034_CMD1_POWERDOWN,
244 on ? SENSOR_STATE_ENABLING_ALS : SENSOR_STATE_DISABLING_ALS);
245
246 return true;
247 }
248
sensorFirmwareAls(void * cookie)249 static bool sensorFirmwareAls(void *cookie)
250 {
251 sensorSignalInternalEvt(mData.alsHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
252 return true;
253 }
254
sensorRateAls(uint32_t rate,uint64_t latency,void * cookie)255 static bool sensorRateAls(uint32_t rate, uint64_t latency, void *cookie)
256 {
257 if (rate == SENSOR_RATE_ONCHANGE)
258 rate = ISL29034_DEFAULT_RATE;
259
260 INFO_PRINT("sensorRateAls: %ld/%lld\n", rate, latency);
261
262 if (mData.alsTimerHandle)
263 timTimerCancel(mData.alsTimerHandle);
264 mData.alsTimerHandle = timTimerSet(sensorTimerLookupCommon(supportedRates, rateTimerVals, rate), 0, 50, alsTimerCallback, NULL, false);
265 osEnqueuePrivateEvt(EVT_SENSOR_ALS_TIMER, NULL, NULL, mData.tid);
266 sensorSignalInternalEvt(mData.alsHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
267
268 return true;
269 }
270
sensorFlushAls(void * cookie)271 static bool sensorFlushAls(void *cookie)
272 {
273 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), SENSOR_DATA_EVENT_FLUSH, NULL);
274 }
275
sendLastSampleAls(void * cookie,uint32_t tid)276 static bool sendLastSampleAls(void *cookie, uint32_t tid)
277 {
278 bool result = true;
279
280 // If we don't end up doing anything here, the expectation is that we are powering up/haven't got the
281 // first sample yet, so a broadcast event will go out soon with the first sample
282 if (mData.lastAlsSample.idata != ISL29034_ALS_INVALID)
283 result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_ALS), mData.lastAlsSample.vptr, NULL, tid);
284
285 return result;
286 }
287
288 static const struct SensorInfo sensorInfoAls =
289 {
290 .sensorName = "ALS",
291 .supportedRates = supportedRates,
292 .sensorType = SENS_TYPE_ALS,
293 .numAxis = NUM_AXIS_EMBEDDED,
294 .interrupt = NANOHUB_INT_NONWAKEUP,
295 .minSamples = 20
296 };
297
298 static const struct SensorOps sensorOpsAls =
299 {
300 .sensorPower = sensorPowerAls,
301 .sensorFirmwareUpload = sensorFirmwareAls,
302 .sensorSetRate = sensorRateAls,
303 .sensorFlush = sensorFlushAls,
304 .sensorTriggerOndemand = NULL,
305 .sensorCalibrate = NULL,
306 .sensorSendOneDirectEvt = sendLastSampleAls
307 };
308
309 /*
310 * Sensor i2c state machine
311 */
312
handle_i2c_event(struct I2cTransfer * xfer)313 static void handle_i2c_event(struct I2cTransfer *xfer)
314 {
315 union EmbeddedDataPoint sample;
316 struct I2cTransfer *nextXfer;
317
318 switch (xfer->state) {
319 case SENSOR_STATE_VERIFY_ID:
320 /* Check the sensor ID */
321 if (xfer->err != 0 ||
322 (xfer->txrxBuf[0] & ISL29034_ID_MASK) != ISL29034_ID) {
323 INFO_PRINT("not detected\n");
324 sensorUnregister(mData.alsHandle);
325 break;
326 }
327 INFO_PRINT("detected\n")
328
329 if (xfer->txrxBuf[0] & ISL29034_ID_BOUT) {
330 INFO_PRINT("Brownout Condition\n");
331 writeRegister(ISL29034_REG_ID,
332 xfer->txrxBuf[0] ^ ISL29034_ID_BOUT,
333 SENSOR_STATE_CLEAR_BOUT);
334 break;
335 }
336 /* fallthrough */
337
338 case SENSOR_STATE_CLEAR_BOUT:
339 nextXfer = allocXfer(SENSOR_STATE_IDLE);
340 if (nextXfer != NULL) {
341 nextXfer->txrxBuf[0] = ISL29034_REG_CMD_1;
342 nextXfer->txrxBuf[1] = ISL29034_CMD1_POWERDOWN;
343 nextXfer->txrxBuf[2] = ISL29034_CMD2_RANGE_64KLUX | ISL29034_CMD2_RES_16BIT;
344 i2cMasterTx(ISL29034_I2C_BUS_ID, ISL29034_I2C_ADDR, nextXfer->txrxBuf, 3, i2cCallback, nextXfer);
345 }
346 break;
347
348 case SENSOR_STATE_IDLE:
349 sensorRegisterInitComplete(mData.alsHandle);
350 break;
351
352 case SENSOR_STATE_ENABLING_ALS:
353 sensorSignalInternalEvt(mData.alsHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, true, 0);
354 break;
355
356 case SENSOR_STATE_DISABLING_ALS:
357 sensorSignalInternalEvt(mData.alsHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, false, 0);
358 break;
359
360 case SENSOR_STATE_SAMPLING:
361 DEBUG_PRINT("sample ready: als0=%u als1=%u\n", xfer->txrxBuf[0], xfer->txrxBuf[1]);
362
363 if (mData.alsOn && mData.alsReading) {
364 /* Create event */
365 sample.fdata = getLuxFromAlsData(xfer->txrxBuf[0] | (xfer->txrxBuf[1] << 8));
366 if (mData.lastAlsSample.idata != sample.idata) {
367 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), sample.vptr, NULL);
368 mData.lastAlsSample.fdata = sample.fdata;
369 }
370 }
371
372 mData.alsReading = false;
373 break;
374 }
375
376 xfer->inUse = false;
377 }
378
379 /*
380 * Main driver entry points
381 */
382
init_app(uint32_t myTid)383 static bool init_app(uint32_t myTid)
384 {
385 INFO_PRINT("started\n");
386
387 /* Set up driver private data */
388 mData.tid = myTid;
389 mData.alsOn = false;
390 mData.alsReading = false;
391 mData.lastAlsSample.idata = ISL29034_ALS_INVALID;
392
393 i2cMasterRequest(ISL29034_I2C_BUS_ID, ISL29034_I2C_SPEED);
394
395 /* Register sensors */
396 mData.alsHandle = sensorRegister(&sensorInfoAls, &sensorOpsAls, NULL, false);
397
398 osEventSubscribe(myTid, EVT_APP_START);
399
400 return true;
401 }
402
end_app(void)403 static void end_app(void)
404 {
405 INFO_PRINT("ended\n");
406
407 sensorUnregister(mData.alsHandle);
408
409 i2cMasterRelease(ISL29034_I2C_BUS_ID);
410 }
411
handle_event(uint32_t evtType,const void * evtData)412 static void handle_event(uint32_t evtType, const void* evtData)
413 {
414 struct I2cTransfer *xfer;
415
416 switch (evtType) {
417 case EVT_APP_START:
418 osEventUnsubscribe(mData.tid, EVT_APP_START);
419
420 xfer = allocXfer(SENSOR_STATE_VERIFY_ID);
421 if (xfer != NULL) {
422 xfer->txrxBuf[0] = ISL29034_REG_ID;
423 i2cMasterTxRx(ISL29034_I2C_BUS_ID, ISL29034_I2C_ADDR, xfer->txrxBuf, 1, xfer->txrxBuf, 1, i2cCallback, xfer);
424 }
425 break;
426
427 case EVT_SENSOR_I2C:
428 handle_i2c_event((struct I2cTransfer *)evtData);
429 break;
430
431 case EVT_SENSOR_ALS_TIMER:
432 /* Start sampling for a value */
433 if (!mData.alsReading) {
434 xfer = allocXfer(SENSOR_STATE_SAMPLING);
435 if (xfer != NULL) {
436 xfer->txrxBuf[0] = ISL29034_REG_DATA_L;
437 i2cMasterTxRx(ISL29034_I2C_BUS_ID, ISL29034_I2C_ADDR, xfer->txrxBuf, 1, xfer->txrxBuf, 2, i2cCallback, xfer);
438 }
439 }
440
441 mData.alsReading = true;
442 break;
443 }
444 }
445
446 INTERNAL_APP_INIT(APP_ID_MAKE(NANOHUB_VENDOR_STMICRO, 4), ISL29034_APP_VERSION, init_app, end_app, handle_event);
447