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