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