Home | History | Annotate | Download | only in ams_tmd2772
      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 
    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.
    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().
    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 
    264 static void alsTimerCallback(uint32_t timerId, void *cookie)
    265 {
    266     osEnqueuePrivateEvt(EVT_SENSOR_ALS_TIMER, cookie, NULL, mData.tid);
    267 }
    268 
    269 static void proxTimerCallback(uint32_t timerId, void *cookie)
    270 {
    271     osEnqueuePrivateEvt(EVT_SENSOR_PROX_TIMER, cookie, NULL, mData.tid);
    272 }
    273 
    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 
    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 
    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 
    338 static bool sensorFirmwareAls(void *cookie)
    339 {
    340     sensorSignalInternalEvt(mData.alsHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
    341     return true;
    342 }
    343 
    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 
    360 static bool sensorFlushAls(void *cookie)
    361 {
    362     return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), SENSOR_DATA_EVENT_FLUSH, NULL);
    363 }
    364 
    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 
    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 
    393 static bool sensorFirmwareProx(void *cookie)
    394 {
    395     sensorSignalInternalEvt(mData.proxHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
    396     return true;
    397 }
    398 
    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 
    415 static bool sensorFlushProx(void *cookie)
    416 {
    417     return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), SENSOR_DATA_EVENT_FLUSH, NULL);
    418 }
    419 
    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 
    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 
    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 
    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 
    695 static void end_app(void)
    696 {
    697     sensorUnregister(mData.alsHandle);
    698     sensorUnregister(mData.proxHandle);
    699 
    700     i2cMasterRelease(I2C_BUS_ID);
    701 }
    702 
    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