• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdlib.h>
18 #include <string.h>
19 #include <float.h>
20 
21 #include <seos.h>
22 #include <i2c.h>
23 #include <timer.h>
24 #include <sensors.h>
25 #include <heap.h>
26 #include <hostIntf.h>
27 #include <nanohubPacket.h>
28 #include <eventnums.h>
29 
30 #define  TMD2772_APP_VERSION 1
31 
32 #define DRIVER_NAME                            "AMS: "
33 
34 #define I2C_BUS_ID                             0
35 #define I2C_SPEED                              400000
36 #define I2C_ADDR                               0x39
37 
38 #define AMS_TMD2772_ID                         0x39
39 
40 #define AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT    0xa0
41 
42 #define AMS_TMD2772_REG_ENABLE                 (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x00)
43 #define AMS_TMD2772_REG_ATIME                  (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x01)
44 #define AMS_TMD2772_REG_PTIME                  (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x02)
45 #define AMS_TMD2772_REG_WTIME                  (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x03)
46 #define AMS_TMD2772_REG_AILTL                  (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x04)
47 #define AMS_TMD2772_REG_AILTH                  (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x05)
48 #define AMS_TMD2772_REG_AIHTL                  (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x06)
49 #define AMS_TMD2772_REG_AIHTH                  (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x07)
50 #define AMS_TMD2772_REG_PILTL                  (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x08)
51 #define AMS_TMD2772_REG_PILTH                  (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x09)
52 #define AMS_TMD2772_REG_PIHTL                  (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x0a)
53 #define AMS_TMD2772_REG_PIHTH                  (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x0b)
54 #define AMS_TMD2772_REG_PERS                   (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x0c)
55 #define AMS_TMD2772_REG_CONFIG                 (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x0d)
56 #define AMS_TMD2772_REG_PPULSE                 (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x0e)
57 #define AMS_TMD2772_REG_CONTROL                (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x0f)
58 #define AMS_TMD2772_REG_ID                     (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x12)
59 #define AMS_TMD2772_REG_STATUS                 (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x13)
60 #define AMS_TMD2772_REG_C0DATA                 (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x14)
61 #define AMS_TMD2772_REG_C0DATAH                (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x15)
62 #define AMS_TMD2772_REG_C1DATA                 (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x16)
63 #define AMS_TMD2772_REG_C1DATAH                (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x17)
64 #define AMS_TMD2772_REG_PDATAL                 (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x18)
65 #define AMS_TMD2772_REG_PDATAH                 (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x19)
66 #define AMS_TMD2772_REG_POFFSET                (AMS_TMD2772_CMD_TYPE_AUTO_INCREMENT | 0x1E)
67 
68 #define AMS_TMD2772_ATIME_SETTING              0xdb
69 #define AMS_TMD2772_ATIME_MS                   ((256 - AMS_TMD2772_ATIME_SETTING) * 2.73) // in milliseconds
70 #define AMS_TMD2772_PTIME_SETTING              0xff
71 #define AMS_TMD2772_PTIME_MS                   ((256 - AMS_TMD2772_PTIME_SETTING) * 2.73) // in milliseconds
72 #define AMS_TMD2772_WTIME_SETTING_ALS_ON       0xdd // (256 - 221) * 2.73 ms = 95.55 ms
73 #define AMS_TMD2772_WTIME_SETTING_ALS_OFF      0xb8 // (256 - 184) * 2.73 ms = 196.56 ms
74 #define AMS_TMD2772_PPULSE_SETTING             8
75 
76 #define AMS_TMD2772_CAL_DEFAULT_OFFSET         0
77 #define AMS_TMD2772_CAL_MAX_OFFSET             500
78 
79 /* AMS_TMD2772_REG_ENABLE */
80 #define POWER_ON_BIT                           (1 << 0)
81 #define ALS_ENABLE_BIT                         (1 << 1)
82 #define PROX_ENABLE_BIT                        (1 << 2)
83 #define WAIT_ENABLE_BIT                        (1 << 3)
84 
85 /* AMS_TMD2772_REG_STATUS */
86 #define PROX_INT_BIT                           (1 << 5)
87 #define ALS_INT_BIT                            (1 << 4)
88 #define PROX_VALID_BIT                         (1 << 1)
89 #define ALS_VALID_BIT                          (1 << 0)
90 
91 #define AMS_TMD2772_REPORT_NEAR_VALUE          0.0f // centimeters
92 #define AMS_TMD2772_REPORT_FAR_VALUE           5.0f // centimeters
93 
94 #define AMS_TMD2772_THRESHOLD_ASSERT_NEAR      213  // in PS units
95 #define AMS_TMD2772_THRESHOLD_DEASSERT_NEAR    96   // in PS units
96 
97 #define AMS_TMD2772_ALS_MAX_CHANNEL_COUNT      37888 // in raw data
98 #define AMS_TMD2772_ALS_MAX_REPORT_VALUE       10000 // in lux
99 
100 #define AMS_TMD2772_ALS_INVALID                UINT32_MAX
101 
102 /* Used when SENSOR_RATE_ONCHANGE is requested */
103 #define AMS_TMD2772_DEFAULT_RATE               SENSOR_HZ(5)
104 
105 /* Private driver events */
106 enum SensorEvents
107 {
108     EVT_SENSOR_I2C = EVT_APP_START + 1,
109     EVT_SENSOR_ALS_TIMER,
110     EVT_SENSOR_PROX_TIMER,
111 };
112 
113 /* I2C state machine */
114 enum SensorState
115 {
116     SENSOR_STATE_VERIFY_ID,
117     SENSOR_STATE_INIT,
118 
119     SENSOR_STATE_CALIBRATE_RESET,
120     SENSOR_STATE_CALIBRATE_START,
121     SENSOR_STATE_CALIBRATE_ENABLING,
122     SENSOR_STATE_CALIBRATE_POLLING_STATUS,
123     SENSOR_STATE_CALIBRATE_AWAITING_SAMPLE,
124     SENSOR_STATE_CALIBRATE_DISABLING,
125 
126     SENSOR_STATE_ENABLING_ALS,
127     SENSOR_STATE_ENABLING_PROX,
128     SENSOR_STATE_DISABLING_ALS,
129     SENSOR_STATE_DISABLING_PROX,
130 
131     SENSOR_STATE_IDLE,
132     SENSOR_STATE_SAMPLING,
133 };
134 
135 enum ProxState
136 {
137     PROX_STATE_INIT,
138     PROX_STATE_NEAR,
139     PROX_STATE_FAR,
140 };
141 
142 struct SensorData
143 {
144     union {
145         uint8_t bytes[16];
146         struct {
147             uint8_t status;
148             uint16_t als[2];
149             uint16_t prox;
150         } __attribute__((packed)) sample;
151         struct {
152             uint16_t prox;
153         } calibration;
154     } txrxBuf;
155 
156     uint32_t tid;
157 
158     uint32_t alsHandle;
159     uint32_t proxHandle;
160     uint32_t alsTimerHandle;
161     uint32_t proxTimerHandle;
162     uint32_t calibrationSampleTotal;
163 
164     union EmbeddedDataPoint lastAlsSample;
165 
166     uint8_t calibrationSampleCount;
167     uint8_t proxState; // enum ProxState
168 
169     bool alsOn;
170     bool alsReading;
171     bool proxOn;
172     bool proxReading;
173 };
174 
175 static struct SensorData mData;
176 
177 /* TODO: check rates are supported */
178 static const uint32_t supportedRates[] =
179 {
180     SENSOR_HZ(0.1),
181     SENSOR_HZ(1),
182     SENSOR_HZ(4),
183     SENSOR_HZ(5),
184     SENSOR_RATE_ONCHANGE,
185     0
186 };
187 
188 static const uint64_t rateTimerVals[] = //should match "supported rates in length" and be the timer length for that rate in nanosecs
189 {
190     10 * 1000000000ULL,
191      1 * 1000000000ULL,
192     1000000000ULL / 4,
193     1000000000ULL / 5,
194 };
195 
196 /*
197  * Helper functions
198  */
199 
i2cCallback(void * cookie,size_t tx,size_t rx,int err)200 static void i2cCallback(void *cookie, size_t tx, size_t rx, int err)
201 {
202     if (err == 0)
203         osEnqueuePrivateEvt(EVT_SENSOR_I2C, cookie, NULL, mData.tid);
204     else
205         osLog(LOG_INFO, DRIVER_NAME "i2c error (%d)\n", err);
206 }
207 
alsTimerCallback(uint32_t timerId,void * cookie)208 static void alsTimerCallback(uint32_t timerId, void *cookie)
209 {
210     osEnqueuePrivateEvt(EVT_SENSOR_ALS_TIMER, cookie, NULL, mData.tid);
211 }
212 
proxTimerCallback(uint32_t timerId,void * cookie)213 static void proxTimerCallback(uint32_t timerId, void *cookie)
214 {
215     osEnqueuePrivateEvt(EVT_SENSOR_PROX_TIMER, cookie, NULL, mData.tid);
216 }
217 
getLuxFromAlsData(uint16_t als0,uint16_t als1)218 static inline float getLuxFromAlsData(uint16_t als0, uint16_t als1)
219 {
220     float cpl = 1.0f / AMS_TMD2772_ATIME_MS;
221     float GA;
222 
223     if ((als0 * 10) < (als1 * 21)) {
224         // A light
225         GA = 0.274f;
226     } else if (((als0 * 10) >= (als1 * 21)) && ((als0 * 10) <= (als1 * 43)) && (als0 > 300)) {
227         // D65
228         GA = 0.592f;
229     } else {
230         // cool white
231         GA = 1.97f;
232     }
233 
234     float lux1 = GA * 207 * (als0 - (1.799 * als1)) * cpl;
235     float lux2 = GA * 207 * ((0.188f * als0) - (0.303 * als1)) * cpl;
236 
237     if ((als0 >= AMS_TMD2772_ALS_MAX_CHANNEL_COUNT) ||
238         (als1 >= AMS_TMD2772_ALS_MAX_CHANNEL_COUNT)) {
239         return AMS_TMD2772_ALS_MAX_REPORT_VALUE;
240     } else if ((lux1 > lux2) && (lux1 > 0.0f)) {
241         return lux1 > AMS_TMD2772_ALS_MAX_REPORT_VALUE ? AMS_TMD2772_ALS_MAX_REPORT_VALUE : lux1;
242     } else if (lux2 > 0.0f) {
243         return lux2 > AMS_TMD2772_ALS_MAX_REPORT_VALUE ? AMS_TMD2772_ALS_MAX_REPORT_VALUE : lux2;
244     } else {
245         return 0.0f;
246     }
247 }
248 
setMode(bool alsOn,bool proxOn,void * cookie)249 static void setMode(bool alsOn, bool proxOn, void *cookie)
250 {
251     mData.txrxBuf.bytes[0] = AMS_TMD2772_REG_ENABLE;
252     mData.txrxBuf.bytes[1] = POWER_ON_BIT | WAIT_ENABLE_BIT |
253                             (alsOn ? ALS_ENABLE_BIT : 0) | (proxOn ? PROX_ENABLE_BIT : 0);
254     mData.txrxBuf.bytes[2] = AMS_TMD2772_ATIME_SETTING;
255     mData.txrxBuf.bytes[3] = AMS_TMD2772_PTIME_SETTING;
256     mData.txrxBuf.bytes[4] = alsOn ? AMS_TMD2772_WTIME_SETTING_ALS_ON : AMS_TMD2772_WTIME_SETTING_ALS_OFF;
257     i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mData.txrxBuf.bytes, 5,
258                 &i2cCallback, cookie);
259 }
260 
sensorPowerAls(bool on,void * cookie)261 static bool sensorPowerAls(bool on, void *cookie)
262 {
263     osLog(LOG_INFO, DRIVER_NAME "sensorPowerAls: %d\n", on);
264 
265     if (mData.alsTimerHandle) {
266         timTimerCancel(mData.alsTimerHandle);
267         mData.alsTimerHandle = 0;
268         mData.alsReading = false;
269     }
270 
271     mData.lastAlsSample.idata = AMS_TMD2772_ALS_INVALID;
272     mData.alsOn = on;
273     setMode(on, mData.proxOn, (void *)(on ? SENSOR_STATE_ENABLING_ALS : SENSOR_STATE_DISABLING_ALS));
274 
275     return true;
276 }
277 
sensorFirmwareAls(void * cookie)278 static bool sensorFirmwareAls(void *cookie)
279 {
280     sensorSignalInternalEvt(mData.alsHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
281     return true;
282 }
283 
sensorRateAls(uint32_t rate,uint64_t latency,void * cookie)284 static bool sensorRateAls(uint32_t rate, uint64_t latency, void *cookie)
285 {
286     if (rate == SENSOR_RATE_ONCHANGE) {
287         rate = AMS_TMD2772_DEFAULT_RATE;
288     }
289     osLog(LOG_INFO, DRIVER_NAME "sensorRateAls: %ld/%lld\n", rate, latency);
290 
291     if (mData.alsTimerHandle)
292         timTimerCancel(mData.alsTimerHandle);
293     mData.alsTimerHandle = timTimerSet(sensorTimerLookupCommon(supportedRates, rateTimerVals, rate), 0, 50, alsTimerCallback, NULL, false);
294     osEnqueuePrivateEvt(EVT_SENSOR_ALS_TIMER, NULL, NULL, mData.tid);
295     sensorSignalInternalEvt(mData.alsHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
296 
297     return true;
298 }
299 
sensorFlushAls(void * cookie)300 static bool sensorFlushAls(void *cookie)
301 {
302     return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), SENSOR_DATA_EVENT_FLUSH, NULL);
303 }
304 
sendLastSampleAls(void * cookie,uint32_t tid)305 static bool sendLastSampleAls(void *cookie, uint32_t tid) {
306     bool result = true;
307 
308     // If we don't end up doing anything here, the expectation is that we are powering up/haven't got the
309     // first sample yet, so a broadcast event will go out soon with the first sample
310     if (mData.lastAlsSample.idata != AMS_TMD2772_ALS_INVALID) {
311         result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_ALS), mData.lastAlsSample.vptr, NULL, tid);
312     }
313     return result;
314 }
315 
sensorPowerProx(bool on,void * cookie)316 static bool sensorPowerProx(bool on, void *cookie)
317 {
318     osLog(LOG_INFO, DRIVER_NAME "sensorPowerProx: %d\n", on);
319 
320     if (mData.proxTimerHandle) {
321         timTimerCancel(mData.proxTimerHandle);
322         mData.proxTimerHandle = 0;
323         mData.proxReading = false;
324     }
325 
326     mData.proxState = PROX_STATE_INIT;
327     mData.proxOn = on;
328     setMode(mData.alsOn, on, (void *)(on ? SENSOR_STATE_ENABLING_PROX : SENSOR_STATE_DISABLING_PROX));
329 
330     return true;
331 }
332 
sensorFirmwareProx(void * cookie)333 static bool sensorFirmwareProx(void *cookie)
334 {
335     sensorSignalInternalEvt(mData.proxHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
336     return true;
337 }
338 
sensorRateProx(uint32_t rate,uint64_t latency,void * cookie)339 static bool sensorRateProx(uint32_t rate, uint64_t latency, void *cookie)
340 {
341     if (rate == SENSOR_RATE_ONCHANGE) {
342         rate = AMS_TMD2772_DEFAULT_RATE;
343     }
344     osLog(LOG_INFO, DRIVER_NAME "sensorRateProx: %ld/%lld\n", rate, latency);
345 
346     if (mData.proxTimerHandle)
347         timTimerCancel(mData.proxTimerHandle);
348     mData.proxTimerHandle = timTimerSet(sensorTimerLookupCommon(supportedRates, rateTimerVals, rate), 0, 50, proxTimerCallback, NULL, false);
349     osEnqueuePrivateEvt(EVT_SENSOR_PROX_TIMER, NULL, NULL, mData.tid);
350     sensorSignalInternalEvt(mData.proxHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
351 
352     return true;
353 }
354 
sensorFlushProx(void * cookie)355 static bool sensorFlushProx(void *cookie)
356 {
357     return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), SENSOR_DATA_EVENT_FLUSH, NULL);
358 }
359 
sendLastSampleProx(void * cookie,uint32_t tid)360 static bool sendLastSampleProx(void *cookie, uint32_t tid) {
361     union EmbeddedDataPoint sample;
362     bool result = true;
363 
364     // See note in sendLastSampleAls
365     if (mData.proxState != PROX_STATE_INIT) {
366         sample.fdata = (mData.proxState == PROX_STATE_NEAR) ?
367             AMS_TMD2772_REPORT_NEAR_VALUE : AMS_TMD2772_REPORT_FAR_VALUE;
368         result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL, tid);
369     }
370     return result;
371 }
372 
373 static const struct SensorInfo sensorInfoAls =
374 {
375     .sensorName = "ALS",
376     .supportedRates = supportedRates,
377     .sensorType = SENS_TYPE_ALS,
378     .numAxis = NUM_AXIS_EMBEDDED,
379     .interrupt = NANOHUB_INT_NONWAKEUP,
380     .minSamples = 20
381 };
382 
383 static const struct SensorOps sensorOpsAls =
384 {
385     .sensorPower = sensorPowerAls,
386     .sensorFirmwareUpload = sensorFirmwareAls,
387     .sensorSetRate = sensorRateAls,
388     .sensorFlush = sensorFlushAls,
389     .sensorTriggerOndemand = NULL,
390     .sensorCalibrate = NULL,
391     .sensorSendOneDirectEvt = sendLastSampleAls
392 };
393 
394 static const struct SensorInfo sensorInfoProx =
395 {
396     .sensorName = "Proximity",
397     .supportedRates = supportedRates,
398     .sensorType = SENS_TYPE_PROX,
399     .numAxis = NUM_AXIS_EMBEDDED,
400     .interrupt = NANOHUB_INT_WAKEUP,
401     .minSamples = 300
402 };
403 
404 static const struct SensorOps sensorOpsProx =
405 {
406     .sensorPower = sensorPowerProx,
407     .sensorFirmwareUpload = sensorFirmwareProx,
408     .sensorSetRate = sensorRateProx,
409     .sensorFlush = sensorFlushProx,
410     .sensorTriggerOndemand = NULL,
411     .sensorCalibrate = NULL,
412     .sensorSendOneDirectEvt = sendLastSampleProx
413 };
414 
415 /*
416  * Sensor i2c state machine
417  */
418 
handle_calibration_event(int state)419 static void handle_calibration_event(int state) {
420     switch (state) {
421     case SENSOR_STATE_CALIBRATE_RESET:
422         mData.calibrationSampleCount = 0;
423         mData.calibrationSampleTotal = 0;
424         /* Intentional fall-through */
425 
426     case SENSOR_STATE_CALIBRATE_START:
427         mData.txrxBuf.bytes[0] = AMS_TMD2772_REG_ENABLE;
428         mData.txrxBuf.bytes[1] = POWER_ON_BIT | PROX_ENABLE_BIT;
429         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mData.txrxBuf.bytes, 2,
430                     &i2cCallback, (void *)SENSOR_STATE_CALIBRATE_ENABLING);
431         break;
432 
433     case SENSOR_STATE_CALIBRATE_ENABLING:
434         mData.txrxBuf.bytes[0] = AMS_TMD2772_REG_STATUS;
435         i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, mData.txrxBuf.bytes, 1,
436                       mData.txrxBuf.bytes, 1, &i2cCallback,
437                       (void *)SENSOR_STATE_CALIBRATE_POLLING_STATUS);
438         break;
439 
440     case SENSOR_STATE_CALIBRATE_POLLING_STATUS:
441         if (mData.txrxBuf.bytes[0] & PROX_INT_BIT) {
442             /* Done */
443             mData.txrxBuf.bytes[0] = AMS_TMD2772_REG_PDATAL;
444             i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, mData.txrxBuf.bytes, 1,
445                           mData.txrxBuf.bytes, 2, &i2cCallback,
446                           (void *)SENSOR_STATE_CALIBRATE_AWAITING_SAMPLE);
447         } else {
448             /* Poll again; go back to previous state */
449             handle_calibration_event(SENSOR_STATE_CALIBRATE_ENABLING);
450         }
451         break;
452 
453     case SENSOR_STATE_CALIBRATE_AWAITING_SAMPLE:
454         mData.calibrationSampleCount++;
455         mData.calibrationSampleTotal += mData.txrxBuf.calibration.prox;
456 
457         mData.txrxBuf.bytes[0] = AMS_TMD2772_REG_ENABLE;
458         mData.txrxBuf.bytes[1] = 0x00;
459         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mData.txrxBuf.bytes, 2,
460                     &i2cCallback, (void *)SENSOR_STATE_CALIBRATE_DISABLING);
461         break;
462 
463     case SENSOR_STATE_CALIBRATE_DISABLING:
464         if (mData.calibrationSampleCount >= 20) {
465             /* Done, calculate calibration */
466             uint16_t average = mData.calibrationSampleTotal / mData.calibrationSampleCount;
467             uint16_t crosstalk = (average > 0x7f) ? 0x7f : average;
468 
469             mData.txrxBuf.bytes[0] = AMS_TMD2772_REG_POFFSET;
470             mData.txrxBuf.bytes[1] = crosstalk;
471             i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mData.txrxBuf.bytes, 2,
472                         &i2cCallback, (void *)SENSOR_STATE_IDLE);
473         } else {
474             /* Get another sample; go back to earlier state */
475             handle_calibration_event(SENSOR_STATE_CALIBRATE_START);
476         }
477         break;
478 
479     default:
480         break;
481     }
482 }
483 
handle_i2c_event(int state)484 static void handle_i2c_event(int state)
485 {
486     union EmbeddedDataPoint sample;
487     bool sendData;
488 
489     switch (state) {
490     case SENSOR_STATE_VERIFY_ID:
491         /* Check the sensor ID */
492         if (mData.txrxBuf.bytes[0] != AMS_TMD2772_ID) {
493             osLog(LOG_INFO, DRIVER_NAME "not detected\n");
494             sensorUnregister(mData.alsHandle);
495             sensorUnregister(mData.proxHandle);
496             break;
497         }
498 
499         /* Start address */
500         mData.txrxBuf.bytes[0] = AMS_TMD2772_REG_ENABLE;
501         /* ENABLE */
502         mData.txrxBuf.bytes[1] = 0x00;
503         /* ATIME */
504         mData.txrxBuf.bytes[2] = AMS_TMD2772_ATIME_SETTING;
505         /* PTIME */
506         mData.txrxBuf.bytes[3] = AMS_TMD2772_PTIME_SETTING;
507         /* WTIME */
508         mData.txrxBuf.bytes[4] = 0xFF;
509         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mData.txrxBuf.bytes, 5,
510                     &i2cCallback, (void *)SENSOR_STATE_INIT);
511         break;
512 
513     case SENSOR_STATE_INIT:
514         /* Start address */
515         mData.txrxBuf.bytes[0] = AMS_TMD2772_REG_PERS;
516         /* PERS */
517         mData.txrxBuf.bytes[1] = 0x00;
518         /* CONFIG */
519         mData.txrxBuf.bytes[2] = 0x00;
520         /* PPULSE */
521         mData.txrxBuf.bytes[3] = AMS_TMD2772_PPULSE_SETTING;
522         /* CONTROL */
523         mData.txrxBuf.bytes[4] = 0x20;
524         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mData.txrxBuf.bytes, 5,
525                     &i2cCallback, (void *)SENSOR_STATE_IDLE);
526         break;
527 
528     case SENSOR_STATE_IDLE:
529         sensorRegisterInitComplete(mData.alsHandle);
530         sensorRegisterInitComplete(mData.proxHandle);
531         break;
532 
533     case SENSOR_STATE_ENABLING_ALS:
534         sensorSignalInternalEvt(mData.alsHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, true, 0);
535         break;
536 
537     case SENSOR_STATE_ENABLING_PROX:
538         sensorSignalInternalEvt(mData.proxHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, true, 0);
539         break;
540 
541     case SENSOR_STATE_DISABLING_ALS:
542         sensorSignalInternalEvt(mData.alsHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, false, 0);
543         break;
544 
545     case SENSOR_STATE_DISABLING_PROX:
546         sensorSignalInternalEvt(mData.proxHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, false, 0);
547         break;
548 
549     case SENSOR_STATE_SAMPLING:
550         /* TEST: log collected data
551         osLog(LOG_INFO, DRIVER_NAME "sample ready: status=%02x prox=%u als0=%u als1=%u\n",
552               mData.txrxBuf.sample.status, mData.txrxBuf.sample.prox,
553               mData.txrxBuf.sample.als[0], mData.txrxBuf.sample.als[1]);
554         */
555 
556         if (mData.alsOn && mData.alsReading &&
557             (mData.txrxBuf.sample.status & ALS_VALID_BIT)) {
558             /* Create event */
559             sample.fdata = getLuxFromAlsData(mData.txrxBuf.sample.als[0],
560                                              mData.txrxBuf.sample.als[1]);
561             if (mData.lastAlsSample.idata != sample.idata) {
562                 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), sample.vptr, NULL);
563                 mData.lastAlsSample.fdata = sample.fdata;
564             }
565         }
566 
567         if (mData.proxOn && mData.proxReading &&
568             (mData.txrxBuf.sample.status & PROX_VALID_BIT)) {
569             /* Create event */
570             sendData = true;
571             if (mData.proxState == PROX_STATE_INIT) {
572                 if (mData.txrxBuf.sample.prox > AMS_TMD2772_THRESHOLD_ASSERT_NEAR) {
573                     sample.fdata = AMS_TMD2772_REPORT_NEAR_VALUE;
574                     mData.proxState = PROX_STATE_NEAR;
575                 } else {
576                     sample.fdata = AMS_TMD2772_REPORT_FAR_VALUE;
577                     mData.proxState = PROX_STATE_FAR;
578                 }
579             } else {
580                 if (mData.proxState == PROX_STATE_NEAR &&
581                     mData.txrxBuf.sample.prox < AMS_TMD2772_THRESHOLD_DEASSERT_NEAR) {
582                     sample.fdata = AMS_TMD2772_REPORT_FAR_VALUE;
583                     mData.proxState = PROX_STATE_FAR;
584                 } else if (mData.proxState == PROX_STATE_FAR &&
585                     mData.txrxBuf.sample.prox > AMS_TMD2772_THRESHOLD_ASSERT_NEAR) {
586                     sample.fdata = AMS_TMD2772_REPORT_NEAR_VALUE;
587                     mData.proxState = PROX_STATE_NEAR;
588                 } else {
589                     sendData = false;
590                 }
591             }
592 
593             if (sendData)
594                 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL);
595         }
596 
597         mData.alsReading = false;
598         mData.proxReading = false;
599         break;
600 
601     default:
602         handle_calibration_event(state);
603         break;
604     }
605 }
606 
607 /*
608  * Main driver entry points
609  */
610 
init_app(uint32_t myTid)611 static bool init_app(uint32_t myTid)
612 {
613     /* Set up driver private data */
614     mData.tid = myTid;
615     mData.alsOn = false;
616     mData.alsReading = false;
617     mData.proxOn = false;
618     mData.proxReading = false;
619     mData.lastAlsSample.idata = AMS_TMD2772_ALS_INVALID;
620     mData.proxState = PROX_STATE_INIT;
621 
622     /* Register sensors */
623     mData.alsHandle = sensorRegister(&sensorInfoAls, &sensorOpsAls, NULL, false);
624     mData.proxHandle = sensorRegister(&sensorInfoProx, &sensorOpsProx, NULL, false);
625 
626     osEventSubscribe(myTid, EVT_APP_START);
627 
628     return true;
629 }
630 
end_app(void)631 static void end_app(void)
632 {
633     sensorUnregister(mData.alsHandle);
634     sensorUnregister(mData.proxHandle);
635 
636     i2cMasterRelease(I2C_BUS_ID);
637 }
638 
handle_event(uint32_t evtType,const void * evtData)639 static void handle_event(uint32_t evtType, const void* evtData)
640 {
641     switch (evtType) {
642     case EVT_APP_START:
643         osEventUnsubscribe(mData.tid, EVT_APP_START);
644         i2cMasterRequest(I2C_BUS_ID, I2C_SPEED);
645 
646         /* TODO: reset chip first */
647 
648         mData.txrxBuf.bytes[0] = AMS_TMD2772_REG_ID;
649         i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, mData.txrxBuf.bytes, 1,
650                         mData.txrxBuf.bytes, 1, &i2cCallback,
651                         (void *)SENSOR_STATE_VERIFY_ID);
652         break;
653 
654     case EVT_SENSOR_I2C:
655         handle_i2c_event((int)evtData);
656         break;
657 
658     case EVT_SENSOR_ALS_TIMER:
659     case EVT_SENSOR_PROX_TIMER:
660         /* Start sampling for a value */
661         if (!mData.alsReading && !mData.proxReading) {
662             mData.txrxBuf.bytes[0] = AMS_TMD2772_REG_STATUS;
663             i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, mData.txrxBuf.bytes, 1,
664                                 mData.txrxBuf.bytes, 7, &i2cCallback,
665                                 (void *)SENSOR_STATE_SAMPLING);
666         }
667 
668         if (evtType == EVT_SENSOR_ALS_TIMER)
669             mData.alsReading = true;
670         else
671             mData.proxReading = true;
672         break;
673     }
674 }
675 
676 INTERNAL_APP_INIT(APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 9), TMD2772_APP_VERSION, init_app, end_app, handle_event);
677