Home | History | Annotate | Download | only in leds
      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 
     20 #include <eventnums.h>
     21 #include <heap.h>
     22 #include <hostIntf.h>
     23 #include <i2c.h>
     24 #include <leds_gpio.h>
     25 #include <nanohubPacket.h>
     26 #include <sensors.h>
     27 #include <seos.h>
     28 #include <timer.h>
     29 #include <util.h>
     30 #include <variant/variant.h>
     31 
     32 #define LP3943_LEDS_APP_ID              APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 21)
     33 #define LP3943_LEDS_APP_VERSION         1
     34 
     35 #ifdef LP3943_I2C_BUS_ID
     36 #define I2C_BUS_ID                      LP3943_I2C_BUS_ID
     37 #else
     38 #define I2C_BUS_ID                      0
     39 #endif
     40 
     41 #ifdef LP3943_I2C_SPEED
     42 #define I2C_SPEED                       LP3943_I2C_SPEED
     43 #else
     44 #define I2C_SPEED                       400000
     45 #endif
     46 
     47 #ifdef LP3943_I2C_ADDR
     48 #define I2C_ADDR                        LP3943_I2C_ADDR
     49 #else
     50 #define I2C_ADDR                        0x60
     51 #endif
     52 
     53 #define LP3943_REG_PSC0                 0x02
     54 #define LP3943_REG_PWM0                 0x03
     55 #define LP3943_REG_PSC1                 0x04
     56 #define LP3943_REG_PWM1                 0x05
     57 #define LP3943_REG_LS0                  0x06
     58 #define LP3943_REG_LS1                  0x07
     59 #define LP3943_REG_LS2                  0x08
     60 #define LP3943_REG_LS3                  0x09
     61 
     62 #define LP3943_MAX_PENDING_I2C_REQUESTS 4
     63 #define LP3943_MAX_I2C_TRANSFER_SIZE    2
     64 #define LP3943_MAX_LED_NUM              16
     65 #define LP3943_MAX_LED_SECTION          4
     66 
     67 #ifndef LP3943_DBG_ENABLE
     68 #define LP3943_DBG_ENABLE               0
     69 #endif
     70 #define LP3943_DBG_VALUE                0x55
     71 
     72 enum LP3943SensorEvents
     73 {
     74     EVT_SENSOR_I2C = EVT_APP_START + 1,
     75     EVT_SENSOR_LEDS_TIMER,
     76     EVT_TEST,
     77 };
     78 
     79 enum LP3943TaskState
     80 {
     81     STATE_RESET,
     82     STATE_CLEAN_LS1,
     83     STATE_CLEAN_LS2,
     84     STATE_FINISH_INIT,
     85     STATE_LED,
     86 };
     87 
     88 struct I2cTransfer
     89 {
     90     size_t tx;
     91     size_t rx;
     92     int err;
     93     uint8_t txrxBuf[LP3943_MAX_I2C_TRANSFER_SIZE];
     94     uint8_t state;
     95     bool inUse;
     96 };
     97 
     98 static struct LP3943Task
     99 {
    100     uint32_t id;
    101     uint32_t sHandle;
    102     uint32_t num;
    103     bool     ledsOn;
    104     bool     blink;
    105     uint32_t ledsTimerHandle;
    106     uint8_t  led[LP3943_MAX_LED_SECTION];
    107 
    108     struct I2cTransfer transfers[LP3943_MAX_PENDING_I2C_REQUESTS];
    109 } mTask;
    110 
    111 /* sensor callbacks from nanohub */
    112 static void i2cCallback(void *cookie, size_t tx, size_t rx, int err)
    113 {
    114     struct I2cTransfer *xfer = cookie;
    115 
    116     xfer->tx = tx;
    117     xfer->rx = rx;
    118     xfer->err = err;
    119 
    120     osEnqueuePrivateEvt(EVT_SENSOR_I2C, cookie, NULL, mTask.id);
    121     if (err != 0)
    122         osLog(LOG_INFO, "[LP3943] i2c error (tx: %d, rx: %d, err: %d)\n", tx, rx, err);
    123 }
    124 
    125 static void sensorLP3943TimerCallback(uint32_t timerId, void *data)
    126 {
    127     osEnqueuePrivateEvt(EVT_SENSOR_LEDS_TIMER, data, NULL, mTask.id);
    128 }
    129 
    130 static uint32_t ledsRates[] = {
    131     SENSOR_HZ(0.1),
    132     SENSOR_HZ(0.5),
    133     SENSOR_HZ(1.0f),
    134     SENSOR_HZ(2.0f),
    135     0
    136 };
    137 
    138 // should match "supported rates in length"
    139 static const uint64_t ledsRatesRateVals[] =
    140 {
    141     10 * 1000000000ULL,
    142     2 * 1000000000ULL,
    143     1 * 1000000000ULL,
    144     1000000000ULL / 2,
    145 };
    146 
    147 // Allocate a buffer and mark it as in use with the given state, or return NULL
    148 // if no buffers available. Must *not* be called from interrupt context.
    149 static struct I2cTransfer *allocXfer(uint8_t state)
    150 {
    151     size_t i;
    152 
    153     for (i = 0; i < ARRAY_SIZE(mTask.transfers); i++) {
    154         if (!mTask.transfers[i].inUse) {
    155             mTask.transfers[i].inUse = true;
    156             mTask.transfers[i].state = state;
    157             return &mTask.transfers[i];
    158         }
    159     }
    160 
    161     osLog(LOG_ERROR, "[LP3943]: Ran out of i2c buffers!");
    162     return NULL;
    163 }
    164 
    165 // Helper function to release I2cTranfer structure.
    166 static inline void releaseXfer(struct I2cTransfer *xfer)
    167 {
    168     xfer->inUse = false;
    169 }
    170 
    171 // Helper function to write a one byte register. Returns true if we got a
    172 // successful return value from i2cMasterTx().
    173 static bool writeRegister(uint8_t reg, uint8_t value, uint8_t state)
    174 {
    175     struct I2cTransfer *xfer = allocXfer(state);
    176     int ret = -1;
    177 
    178     if (xfer != NULL) {
    179         xfer->txrxBuf[0] = reg;
    180         xfer->txrxBuf[1] = value;
    181         ret = i2cMasterTx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 2, i2cCallback, xfer);
    182         if (ret)
    183             releaseXfer(xfer);
    184     }
    185 
    186     return (ret == 0);
    187 }
    188 
    189 /* Sensor Operations */
    190 static bool sensorLP3943Power(bool on, void *cookie)
    191 {
    192     if (mTask.ledsTimerHandle) {
    193         timTimerCancel(mTask.ledsTimerHandle);
    194         mTask.ledsTimerHandle = 0;
    195     }
    196     mTask.ledsOn = on;
    197     return sensorSignalInternalEvt(mTask.sHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, on, 0);
    198 }
    199 
    200 static bool sensorLP3943FwUpload(void *cookie)
    201 {
    202     return sensorSignalInternalEvt(mTask.sHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
    203 }
    204 
    205 static bool sensorLP3943SetRate(uint32_t rate, uint64_t latency, void *cookie)
    206 {
    207     if (mTask.ledsTimerHandle)
    208         timTimerCancel(mTask.ledsTimerHandle);
    209 
    210     mTask.ledsTimerHandle = timTimerSet(sensorTimerLookupCommon(ledsRates,
    211                 ledsRatesRateVals, rate), 0, 50, sensorLP3943TimerCallback, NULL, false);
    212 
    213     return sensorSignalInternalEvt(mTask.sHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
    214 }
    215 
    216 static bool sensorCfgDataLedsLP3943(void *cfg, void *cookie)
    217 {
    218     struct LedsCfg *lcfg = (struct LedsCfg *)cfg;
    219     uint8_t laddr = LP3943_REG_LS0;
    220     uint8_t lval;
    221     uint8_t index;
    222     uint8_t lnum;
    223 
    224     if (lcfg->led_num >= mTask.num) {
    225         osLog(LOG_INFO, "Wrong led number %"PRIu32"\n", lcfg->led_num);
    226         return false;
    227     }
    228     index = lcfg->led_num >> 2;
    229     lnum = (lcfg->led_num & 0x3) << 1;
    230     lval = mTask.led[index];
    231     laddr += index;
    232     if (lcfg->value) {
    233         lval |= (1 << lnum);
    234     } else {
    235         lval &= ~(1 << lnum);
    236     }
    237 
    238     writeRegister(laddr, lval, STATE_LED);
    239     mTask.led[index] = lval;
    240     osLog(LOG_INFO, "Set led[%"PRIu32"]=%"PRIu32"\n", lcfg->led_num, lcfg->value);
    241     return true;
    242 }
    243 
    244 static void sensorLedsOnOff(bool flag)
    245 {
    246     uint8_t laddr = LP3943_REG_LS0;
    247     uint8_t lval;
    248     uint8_t index;
    249 
    250     for (index=0; index < LP3943_MAX_LED_SECTION; index++) {
    251         lval = flag ? mTask.led[index] : 0;
    252         writeRegister(laddr + index, lval, STATE_LED);
    253     }
    254 }
    255 
    256 static const struct SensorInfo sensorInfoLedsLP3943 = {
    257     .sensorName = "Leds-LP3943",
    258     .sensorType = SENS_TYPE_LEDS_I2C,
    259     .supportedRates = ledsRates,
    260 };
    261 
    262 static const struct SensorOps sensorOpsLedsLP3943 = {
    263     .sensorPower   = sensorLP3943Power,
    264     .sensorFirmwareUpload = sensorLP3943FwUpload,
    265     .sensorSetRate  = sensorLP3943SetRate,
    266     .sensorCfgData = sensorCfgDataLedsLP3943,
    267 };
    268 
    269 static void handleI2cEvent(struct I2cTransfer *xfer)
    270 {
    271     switch (xfer->state) {
    272         case STATE_RESET:
    273             writeRegister(LP3943_REG_LS1, 0, STATE_CLEAN_LS1);
    274             break;
    275 
    276         case STATE_CLEAN_LS1:
    277             writeRegister(LP3943_REG_LS2, 0, STATE_FINISH_INIT);
    278             break;
    279 
    280         case STATE_CLEAN_LS2:
    281             writeRegister(LP3943_REG_LS3, 0, STATE_FINISH_INIT);
    282             break;
    283 
    284         case STATE_FINISH_INIT:
    285             if (xfer->err != 0) {
    286                 osLog(LOG_INFO, "[LP3943] not detected\n");
    287             } else {
    288                 osLog(LOG_INFO, "[LP3943] detected\n");
    289                 sensorRegisterInitComplete(mTask.sHandle);
    290                 if (LP3943_DBG_ENABLE) {
    291                     mTask.ledsOn = true;
    292                     mTask.led[0] = LP3943_DBG_VALUE;
    293                     osEnqueuePrivateEvt(EVT_TEST, NULL, NULL, mTask.id);
    294                 }
    295             }
    296             break;
    297 
    298         case STATE_LED:
    299             break;
    300 
    301         default:
    302             break;
    303     }
    304 
    305     releaseXfer(xfer);
    306 }
    307 
    308 static void handleEvent(uint32_t evtType, const void* evtData)
    309 {
    310     switch (evtType) {
    311     case EVT_APP_START:
    312         osEventUnsubscribe(mTask.id, EVT_APP_START);
    313         i2cMasterRequest(I2C_BUS_ID, I2C_SPEED);
    314 
    315         /* Reset Leds */
    316         writeRegister(LP3943_REG_LS0, 0, STATE_RESET);
    317         break;
    318 
    319     case EVT_SENSOR_I2C:
    320         handleI2cEvent((struct I2cTransfer *)evtData);
    321         break;
    322 
    323     case EVT_SENSOR_LEDS_TIMER:
    324         if (!mTask.ledsOn)
    325             break;
    326         mTask.blink = !mTask.blink;
    327         sensorLedsOnOff(mTask.blink);
    328         break;
    329 
    330     case EVT_TEST:
    331         sensorLP3943SetRate(SENSOR_HZ(1), 0, NULL);
    332         break;
    333 
    334     default:
    335         break;
    336     }
    337 }
    338 
    339 static bool startTask(uint32_t taskId)
    340 {
    341     mTask.id = taskId;
    342     mTask.num = LP3943_MAX_LED_NUM;
    343     memset(mTask.led, 0x00, LP3943_MAX_LED_SECTION);
    344     mTask.ledsOn = mTask.blink = false;
    345 
    346     /* Register sensors */
    347     mTask.sHandle = sensorRegister(&sensorInfoLedsLP3943, &sensorOpsLedsLP3943, NULL, false);
    348 
    349     osEventSubscribe(taskId, EVT_APP_START);
    350 
    351     return true;
    352 }
    353 
    354 static void endTask(void)
    355 {
    356     sensorUnregister(mTask.sHandle);
    357 }
    358 
    359 INTERNAL_APP_INIT(LP3943_LEDS_APP_ID, LP3943_LEDS_APP_VERSION, startTask, endTask, handleEvent);
    360