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 <eventnums.h>
22 #include <gpio.h>
23 #include <timer.h>
24 #include <sensors.h>
25 #include <heap.h>
26 #include <hostIntf.h>
27 #include <isr.h>
28 #include <i2c.h>
29 #include <nanohubPacket.h>
30 #include <sensors.h>
31 #include <seos.h>
32
33 #include <plat/exti.h>
34 #include <plat/gpio.h>
35 #include <plat/syscfg.h>
36 #include <variant/variant.h>
37
38 #ifndef PROX_INT_PIN
39 #error "PROX_INT_PIN is not defined; please define in variant.h"
40 #endif
41
42 #ifndef PROX_IRQ
43 #error "PROX_IRQ is not defined; please define in variant.h"
44 #endif
45
46 #ifndef PROX_I2C_BUS_ID
47 #define PROX_I2C_BUS_ID 0
48 #endif
49
50 #define RPR0521_APP_VERSION 3
51
52 #define I2C_BUS_ID PROX_I2C_BUS_ID
53 #define I2C_SPEED 400000
54 #define I2C_ADDR 0x38
55
56 #define ROHM_RPR0521_REG_ID 0x92
57 #define ROHM_RPR0521_REG_SYSTEM_CONTROL 0x40
58 #define ROHM_RPR0521_REG_MODE_CONTROL 0x41
59 #define ROHM_RPR0521_REG_ALS_PS_CONTROL 0x42
60 #define ROHM_RPR0521_REG_PS_CONTROL 0x43
61 #define ROHM_RPR0521_REG_PS_DATA_LSB 0x44
62 #define ROHM_RPR0521_REG_ALS_DATA0_LSB 0x46
63 #define ROHM_RPR0521_REG_INTERRUPT 0x4a
64 #define ROHM_RPR0521_REG_PS_TH_LSB 0x4b
65 #define ROHM_RPR0521_REG_PS_TH_MSB 0x4c
66 #define ROHM_RPR0521_REG_PS_TL_LSB 0x4d
67 #define ROHM_RPR0521_REG_PS_TL_MSB 0x4e
68 #define ROHM_RPR0521_REG_ALS_DATA0_TH_LSB 0x4f
69 #define ROHM_RPR0521_REG_ALS_DATA0_TL_LSB 0x51
70 #define ROHM_RPR0521_REG_PS_OFFSET_LSB 0x53
71 #define ROHM_RPR0521_REG_PS_OFFSET_MSB 0x54
72
73 #define ROHM_RPR0521_ID 0xe0
74
75 #define ROHM_RPR0521_DEFAULT_RATE SENSOR_HZ(5)
76
77 enum {
78 ALS_GAIN_X1 = 0,
79 ALS_GAIN_X2 = 1,
80 ALS_GAIN_X64 = 2,
81 ALS_GAIN_X128 = 3,
82 };
83 #define ROHM_RPR0521_GAIN_ALS0 ALS_GAIN_X1
84 #define ROHM_RPR0521_GAIN_ALS1 ALS_GAIN_X1
85
86 enum {
87 LED_CURRENT_25MA = 0,
88 LED_CURRENT_50MA = 1,
89 LED_CURRENT_100MA = 2,
90 LED_CURRENT_200MA = 3,
91 };
92 #define ROHM_RPR0521_LED_CURRENT LED_CURRENT_100MA
93
94 /* ROHM_RPR0521_REG_SYSTEM_CONTROL */
95 #define SW_RESET_BIT (1 << 7)
96 #define INT_RESET_BIT (1 << 6)
97
98 /* ROHM_RPR0521_REG_MODE_CONTROL */
99 #define ALS_EN_BIT (1 << 7)
100 #define PS_EN_BIT (1 << 6)
101
102 /* ROHM_RPR0521_REG_PS_CONTROL */
103 enum {
104 PS_GAIN_X1 = 0,
105 PS_GAIN_X2 = 1,
106 PS_GAIN_X4 = 2,
107 };
108 enum {
109 PS_PERSISTENCE_ACTIVE_AT_EACH_MEASUREMENT_END = 0,
110 PS_PERSISTENCE_STATUS_UPDATED_AT_EACH_MEASUREMENT_END = 1,
111 };
112 #define ROHM_RPR0521_GAIN_PS PS_GAIN_X1
113
114
115 /* ROHM_RPR0521_REG_INTERRUPT */
116 #define INTERRUPT_LATCH_BIT (1 << 2)
117 enum {
118 INTERRUPT_MODE_PS_TH_H_ONLY = 0,
119 INTERRUPT_MODE_PS_HYSTERESIS = 1,
120 INTERRUPT_MODE_PS_OUTSIDE_DETECT = 2
121 };
122 enum {
123 INTERRUPT_TRIGGER_INACTIVE = 0,
124 INTERRUPT_TRIGGER_PS = 1,
125 INTERRUPT_TRIGGER_ALS = 2,
126 INTERRUPT_TRIGGER_BOTH = 3
127 };
128
129
130 #define ROHM_RPR0521_REPORT_NEAR_VALUE 0.0f // centimeters
131 #define ROHM_RPR0521_REPORT_FAR_VALUE 5.0f // centimeters
132 #define ROHM_RPR0521_THRESHOLD_ASSERT_NEAR 12 // value in PS_DATA
133 #define ROHM_RPR0521_THRESHOLD_DEASSERT_NEAR 7 // value in PS_DATA
134
135 #define ROHM_RPR0521_ALS_INVALID UINT32_MAX
136
137 #define ROHM_RPR0521_ALS_TIMER_DELAY 200000000ULL
138
139 #define ROHM_RPR0521_MAX_PENDING_I2C_REQUESTS 4
140 #define ROHM_RPR0521_MAX_I2C_TRANSFER_SIZE 16
141
142 #define VERBOSE_PRINT(fmt, ...) do { \
143 osLog(LOG_VERBOSE, "[Rohm RPR-0521] " fmt, ##__VA_ARGS__); \
144 } while (0);
145
146 #define INFO_PRINT(fmt, ...) do { \
147 osLog(LOG_INFO, "[Rohm RPR-0521] " fmt, ##__VA_ARGS__); \
148 } while (0);
149
150 #define ERROR_PRINT(fmt, ...) do { \
151 osLog(LOG_ERROR, "[Rohm RPR-0521] " fmt, ##__VA_ARGS__); \
152 } while (0);
153
154 #define DEBUG_PRINT(fmt, ...) do { \
155 if (enable_debug) { \
156 osLog(LOG_INFO, "[Rohm RPR-0521] " fmt, ##__VA_ARGS__); \
157 } \
158 } while (0);
159
160 static const bool enable_debug = 0;
161
162 /* Private driver events */
163 enum SensorEvents
164 {
165 EVT_SENSOR_I2C = EVT_APP_START + 1,
166 EVT_SENSOR_ALS_TIMER,
167 EVT_SENSOR_PROX_INTERRUPT,
168 };
169
170 /* I2C state machine */
171 enum SensorState
172 {
173 SENSOR_STATE_RESET,
174 SENSOR_STATE_VERIFY_ID,
175 SENSOR_STATE_INIT_GAINS,
176 SENSOR_STATE_INIT_THRESHOLDS,
177 SENSOR_STATE_INIT_OFFSETS,
178 SENSOR_STATE_FINISH_INIT,
179 SENSOR_STATE_ENABLING_ALS,
180 SENSOR_STATE_ENABLING_PROX,
181 SENSOR_STATE_DISABLING_ALS,
182 SENSOR_STATE_DISABLING_PROX,
183 SENSOR_STATE_DISABLING_PROX_2,
184 SENSOR_STATE_DISABLING_PROX_3,
185 SENSOR_STATE_ALS_SAMPLING,
186 SENSOR_STATE_PROX_SAMPLING,
187 SENSOR_STATE_IDLE,
188 };
189
190 enum ProxState
191 {
192 PROX_STATE_INIT,
193 PROX_STATE_NEAR,
194 PROX_STATE_FAR,
195 };
196
197 enum MeasurementTime {
198 MEASUREMENT_TIME_ALS_STANDBY_PS_STANDBY = 0,
199 MEASUREMENT_TIME_ALS_STANDBY_PS_10 = 1,
200 MEASUREMENT_TIME_ALS_STANDBY_PS_40 = 2,
201 MEASUREMENT_TIME_ALS_STANDBY_PS_100 = 3,
202 MEASUREMENT_TIME_ALS_STANDBY_PS_400 = 4,
203 MEASUREMENT_TIME_ALS_100_PS_50 = 5,
204 MEASUREMENT_TIME_ALS_100_PS_100 = 6,
205 MEASUREMENT_TIME_ALS_100_PS_400 = 7,
206 MEASUREMENT_TIME_ALS_400_PS_50 = 8,
207 MEASUREMENT_TIME_ALS_400_PS_100 = 9,
208 MEASUREMENT_TIME_ALS_400_PS_STANDBY = 10,
209 MEASUREMENT_TIME_ALS_400_PS_400 = 11,
210 MEASUREMENT_TIME_ALS_50_PS_50 = 12,
211 };
212
213 struct I2cTransfer
214 {
215 size_t tx;
216 size_t rx;
217 int err;
218 uint8_t txrxBuf[ROHM_RPR0521_MAX_I2C_TRANSFER_SIZE];
219 uint8_t state;
220 bool inUse;
221 };
222
223 struct SensorData
224 {
225 struct Gpio *pin;
226 struct ChainedIsr isr;
227
228 uint32_t tid;
229
230 uint32_t alsHandle;
231 uint32_t proxHandle;
232 uint32_t alsTimerHandle;
233
234 union EmbeddedDataPoint lastAlsSample;
235
236 struct I2cTransfer transfers[ROHM_RPR0521_MAX_PENDING_I2C_REQUESTS];
237
238 uint8_t proxState; // enum ProxState
239
240 bool alsOn;
241 bool proxOn;
242 };
243
244 static struct SensorData mTask;
245
246 static const uint32_t supportedRates[] =
247 {
248 SENSOR_HZ(5),
249 SENSOR_RATE_ONCHANGE,
250 0,
251 };
252
253 /*
254 * Helper functions
255 */
proxIsr(struct ChainedIsr * localIsr)256 static bool proxIsr(struct ChainedIsr *localIsr)
257 {
258 struct SensorData *data = container_of(localIsr, struct SensorData, isr);
259 bool firstProxSample = (data->proxState == PROX_STATE_INIT);
260 uint8_t lastProxState = data->proxState;
261 bool pinState;
262 union EmbeddedDataPoint sample;
263
264 if (!extiIsPendingGpio(data->pin)) {
265 return false;
266 }
267
268 if (data->proxOn) {
269 pinState = gpioGet(data->pin);
270
271 if (firstProxSample && !pinState) {
272 osEnqueuePrivateEvt(EVT_SENSOR_PROX_INTERRUPT, NULL, NULL, mTask.tid);
273 } else if (!firstProxSample) {
274 sample.fdata = (pinState) ? ROHM_RPR0521_REPORT_FAR_VALUE : ROHM_RPR0521_REPORT_NEAR_VALUE;
275 data->proxState = (pinState) ? PROX_STATE_FAR : PROX_STATE_NEAR;
276 if (data->proxState != lastProxState)
277 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL);
278 }
279 }
280
281 extiClearPendingGpio(data->pin);
282 return true;
283 }
284
enableInterrupt(struct Gpio * pin,struct ChainedIsr * isr)285 static bool enableInterrupt(struct Gpio *pin, struct ChainedIsr *isr)
286 {
287 extiEnableIntGpio(pin, EXTI_TRIGGER_BOTH);
288 extiChainIsr(PROX_IRQ, isr);
289 return true;
290 }
291
disableInterrupt(struct Gpio * pin,struct ChainedIsr * isr)292 static bool disableInterrupt(struct Gpio *pin, struct ChainedIsr *isr)
293 {
294 extiUnchainIsr(PROX_IRQ, isr);
295 extiDisableIntGpio(pin);
296 return true;
297 }
298
i2cCallback(void * cookie,size_t tx,size_t rx,int err)299 static void i2cCallback(void *cookie, size_t tx, size_t rx, int err)
300 {
301 struct I2cTransfer *xfer = cookie;
302
303 xfer->tx = tx;
304 xfer->rx = rx;
305 xfer->err = err;
306
307 osEnqueuePrivateEvt(EVT_SENSOR_I2C, cookie, NULL, mTask.tid);
308 if (err != 0)
309 ERROR_PRINT("i2c error (tx: %d, rx: %d, err: %d)\n", tx, rx, err);
310 }
311
alsTimerCallback(uint32_t timerId,void * cookie)312 static void alsTimerCallback(uint32_t timerId, void *cookie)
313 {
314 osEnqueuePrivateEvt(EVT_SENSOR_ALS_TIMER, cookie, NULL, mTask.tid);
315 }
316
317 // Allocate a buffer and mark it as in use with the given state, or return NULL
318 // if no buffers available. Must *not* be called from interrupt context.
allocXfer(uint8_t state)319 static struct I2cTransfer *allocXfer(uint8_t state)
320 {
321 size_t i;
322
323 for (i = 0; i < ARRAY_SIZE(mTask.transfers); i++) {
324 if (!mTask.transfers[i].inUse) {
325 mTask.transfers[i].inUse = true;
326 mTask.transfers[i].state = state;
327 return &mTask.transfers[i];
328 }
329 }
330
331 osLog(LOG_ERROR, "[BMP280]: Ran out of i2c buffers!");
332 return NULL;
333 }
334
335 // Helper function to write a one byte register. Returns true if we got a
336 // successful return value from i2cMasterTx().
writeRegister(uint8_t reg,uint8_t value,uint8_t state)337 static bool writeRegister(uint8_t reg, uint8_t value, uint8_t state)
338 {
339 struct I2cTransfer *xfer = allocXfer(state);
340 int ret = -1;
341
342 if (xfer != NULL) {
343 xfer->txrxBuf[0] = reg;
344 xfer->txrxBuf[1] = value;
345 ret = i2cMasterTx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 2, i2cCallback, xfer);
346 }
347
348 return (ret == 0);
349 }
350
getLuxFromAlsData(uint16_t als0,uint16_t als1)351 static inline float getLuxFromAlsData(uint16_t als0, uint16_t als1)
352 {
353 static const float invGain[] = {1.0f, 0.5f, 1.0f / 64.0f, 1.0f / 128.0f};
354 float d0 = (float)als0 * invGain[ROHM_RPR0521_GAIN_ALS0];
355 float d1 = (float)als1 * invGain[ROHM_RPR0521_GAIN_ALS1];
356 float ratio = d1 / d0;
357 float c1;
358 float c2;
359
360 if (ratio < 1.221f) {
361 c1 = 6.323f;
362 c2 = -3.917f;
363 } else if (ratio < 1.432f) {
364 c1 = 5.350f;
365 c2 = -3.121f;
366 } else if (ratio < 1.710f) {
367 c1 = 2.449f;
368 c2 = -1.096f;
369 } else if (ratio < 3.393f) {
370 c1 = 1.155f;
371 c2 = -0.340f;
372 } else {
373 c1 = c2 = 0.0f;
374 }
375
376 return c1 * d0 + c2 * d1;
377 }
378
setMode(bool alsOn,bool proxOn,uint8_t state)379 static void setMode(bool alsOn, bool proxOn, uint8_t state)
380 {
381 uint8_t ctrl;
382
383 static const uint8_t measurementTime[] = {
384 MEASUREMENT_TIME_ALS_STANDBY_PS_STANDBY, /* als disabled, prox disabled */
385 MEASUREMENT_TIME_ALS_100_PS_100, /* als enabled, prox disabled */
386 MEASUREMENT_TIME_ALS_STANDBY_PS_100, /* als disabled, prox enabled */
387 MEASUREMENT_TIME_ALS_100_PS_100, /* als enabled, prox enabled */
388 };
389
390 ctrl = measurementTime[alsOn ? 1 : 0 + proxOn ? 2 : 0] | (alsOn ? ALS_EN_BIT : 0) | (proxOn ? PS_EN_BIT : 0);
391 writeRegister(ROHM_RPR0521_REG_MODE_CONTROL, ctrl, state);
392 }
393
sensorPowerAls(bool on,void * cookie)394 static bool sensorPowerAls(bool on, void *cookie)
395 {
396 VERBOSE_PRINT("sensorPowerAls: %d\n", on);
397
398 if (on && !mTask.alsTimerHandle) {
399 mTask.alsTimerHandle = timTimerSet(ROHM_RPR0521_ALS_TIMER_DELAY, 0, 50, alsTimerCallback, NULL, false);
400 } else if (!on && mTask.alsTimerHandle) {
401 timTimerCancel(mTask.alsTimerHandle);
402 mTask.alsTimerHandle = 0;
403 }
404
405 mTask.lastAlsSample.idata = ROHM_RPR0521_ALS_INVALID;
406 mTask.alsOn = on;
407
408 setMode(on, mTask.proxOn, (on ? SENSOR_STATE_ENABLING_ALS : SENSOR_STATE_DISABLING_ALS));
409 return true;
410 }
411
sensorFirmwareAls(void * cookie)412 static bool sensorFirmwareAls(void *cookie)
413 {
414 return sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
415 }
416
sensorRateAls(uint32_t rate,uint64_t latency,void * cookie)417 static bool sensorRateAls(uint32_t rate, uint64_t latency, void *cookie)
418 {
419 if (rate == SENSOR_RATE_ONCHANGE)
420 rate = ROHM_RPR0521_DEFAULT_RATE;
421
422 VERBOSE_PRINT("sensorRateAls: rate=%ld Hz latency=%lld ns\n", rate/1024, latency);
423
424 return sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
425 }
426
sensorFlushAls(void * cookie)427 static bool sensorFlushAls(void *cookie)
428 {
429 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), SENSOR_DATA_EVENT_FLUSH, NULL);
430 }
431
sendLastSampleAls(void * cookie,uint32_t tid)432 static bool sendLastSampleAls(void *cookie, uint32_t tid) {
433 bool result = true;
434
435 // If we don't end up doing anything here, the expectation is that we are powering up/haven't got the
436 // first sample yet, so the client will get a broadcast event soon
437 if (mTask.lastAlsSample.idata != ROHM_RPR0521_ALS_INVALID) {
438 result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_ALS), mTask.lastAlsSample.vptr, NULL, tid);
439 }
440 return result;
441 }
442
sensorPowerProx(bool on,void * cookie)443 static bool sensorPowerProx(bool on, void *cookie)
444 {
445 VERBOSE_PRINT("sensorPowerProx: %d\n", on);
446
447 if (on) {
448 extiClearPendingGpio(mTask.pin);
449 enableInterrupt(mTask.pin, &mTask.isr);
450 } else {
451 disableInterrupt(mTask.pin, &mTask.isr);
452 extiClearPendingGpio(mTask.pin);
453 }
454
455 mTask.proxState = PROX_STATE_INIT;
456 mTask.proxOn = on;
457
458 setMode(mTask.alsOn, on, (on ? SENSOR_STATE_ENABLING_PROX : SENSOR_STATE_DISABLING_PROX));
459 return true;
460 }
461
sensorFirmwareProx(void * cookie)462 static bool sensorFirmwareProx(void *cookie)
463 {
464 return sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
465 }
466
sensorRateProx(uint32_t rate,uint64_t latency,void * cookie)467 static bool sensorRateProx(uint32_t rate, uint64_t latency, void *cookie)
468 {
469 if (rate == SENSOR_RATE_ONCHANGE)
470 rate = ROHM_RPR0521_DEFAULT_RATE;
471
472 VERBOSE_PRINT("sensorRateProx: rate=%ld Hz latency=%lld ns\n", rate/1024, latency);
473
474 return sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
475 }
476
sensorFlushProx(void * cookie)477 static bool sensorFlushProx(void *cookie)
478 {
479 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), SENSOR_DATA_EVENT_FLUSH, NULL);
480 }
481
sensorCfgDataProx(void * data,void * cookie)482 static bool sensorCfgDataProx(void *data, void *cookie)
483 {
484 struct I2cTransfer *xfer;
485
486 int32_t offset = *(int32_t*)data;
487
488 INFO_PRINT("Received cfg data: %d\n", (int)offset);
489
490 xfer = allocXfer(SENSOR_STATE_IDLE);
491 if (xfer != NULL) {
492 xfer->txrxBuf[0] = ROHM_RPR0521_REG_PS_OFFSET_LSB;
493 xfer->txrxBuf[1] = offset & 0xFF;
494 xfer->txrxBuf[2] = (offset >> 8) & 0x3;
495 i2cMasterTx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 3, i2cCallback, xfer);
496
497 return true;
498 }
499
500 return false;
501 }
502
sendLastSampleProx(void * cookie,uint32_t tid)503 static bool sendLastSampleProx(void *cookie, uint32_t tid) {
504 union EmbeddedDataPoint sample;
505 bool result = true;
506
507 // See note in sendLastSampleAls
508 if (mTask.proxState != PROX_STATE_INIT) {
509 sample.fdata = (mTask.proxState == PROX_STATE_NEAR) ? ROHM_RPR0521_REPORT_NEAR_VALUE : ROHM_RPR0521_REPORT_FAR_VALUE;
510 result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL, tid);
511 }
512 return result;
513 }
514
515 static const struct SensorInfo sensorInfoAls =
516 {
517 .sensorName = "ALS",
518 .supportedRates = supportedRates,
519 .sensorType = SENS_TYPE_ALS,
520 .numAxis = NUM_AXIS_EMBEDDED,
521 .interrupt = NANOHUB_INT_NONWAKEUP,
522 .minSamples = 20
523 };
524
525 static const struct SensorOps sensorOpsAls =
526 {
527 .sensorPower = sensorPowerAls,
528 .sensorFirmwareUpload = sensorFirmwareAls,
529 .sensorSetRate = sensorRateAls,
530 .sensorFlush = sensorFlushAls,
531 .sensorTriggerOndemand = NULL,
532 .sensorCalibrate = NULL,
533 .sensorSendOneDirectEvt = sendLastSampleAls
534 };
535
536 static const struct SensorInfo sensorInfoProx =
537 {
538 .sensorName = "Proximity",
539 .supportedRates = supportedRates,
540 .sensorType = SENS_TYPE_PROX,
541 .numAxis = NUM_AXIS_EMBEDDED,
542 .interrupt = NANOHUB_INT_WAKEUP,
543 .minSamples = 300
544 };
545
546 static const struct SensorOps sensorOpsProx =
547 {
548 .sensorPower = sensorPowerProx,
549 .sensorFirmwareUpload = sensorFirmwareProx,
550 .sensorSetRate = sensorRateProx,
551 .sensorFlush = sensorFlushProx,
552 .sensorTriggerOndemand = NULL,
553 .sensorCalibrate = NULL,
554 .sensorCfgData = sensorCfgDataProx,
555 .sensorSendOneDirectEvt = sendLastSampleProx
556 };
557
558 /*
559 * Sensor i2c state machine
560 */
561
sensorAlsFree(void * ptr)562 static void __attribute__((unused)) sensorAlsFree(void *ptr)
563 {
564 }
565
sensorProxFree(void * ptr)566 static void __attribute__((unused)) sensorProxFree(void *ptr)
567 {
568 }
569
handle_i2c_event(struct I2cTransfer * xfer)570 static void handle_i2c_event(struct I2cTransfer *xfer)
571 {
572 union EmbeddedDataPoint sample;
573 uint16_t als0, als1, ps;
574 uint8_t lastProxState;
575 struct I2cTransfer *newXfer;
576 uint8_t regData;
577
578 switch (xfer->state) {
579 case SENSOR_STATE_RESET:
580 newXfer = allocXfer(SENSOR_STATE_VERIFY_ID);
581 if (newXfer != NULL) {
582 newXfer->txrxBuf[0] = ROHM_RPR0521_REG_ID;
583 i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, newXfer->txrxBuf, 1, newXfer->txrxBuf, 1, i2cCallback, newXfer);
584 }
585 break;
586
587 case SENSOR_STATE_VERIFY_ID:
588 /* Check the sensor ID */
589 if (xfer->err != 0 || xfer->txrxBuf[0] != ROHM_RPR0521_ID) {
590 INFO_PRINT("not detected\n");
591 sensorUnregister(mTask.alsHandle);
592 sensorUnregister(mTask.proxHandle);
593 break;
594 }
595
596 newXfer = allocXfer(SENSOR_STATE_INIT_GAINS);
597 if (newXfer != NULL) {
598 newXfer->txrxBuf[0] = ROHM_RPR0521_REG_ALS_PS_CONTROL;
599 newXfer->txrxBuf[1] = (ROHM_RPR0521_GAIN_ALS0 << 4) | (ROHM_RPR0521_GAIN_ALS1 << 2) | ROHM_RPR0521_LED_CURRENT;
600 newXfer->txrxBuf[2] = (ROHM_RPR0521_GAIN_PS << 4) | PS_PERSISTENCE_ACTIVE_AT_EACH_MEASUREMENT_END;
601 i2cMasterTx(I2C_BUS_ID, I2C_ADDR, newXfer->txrxBuf, 3, i2cCallback, newXfer);
602 }
603 break;
604
605 case SENSOR_STATE_INIT_GAINS:
606 /* Offset register */
607 newXfer = allocXfer(SENSOR_STATE_INIT_OFFSETS);
608 if (newXfer != NULL) {
609 newXfer->txrxBuf[0] = ROHM_RPR0521_REG_PS_OFFSET_LSB;
610 newXfer->txrxBuf[1] = 0;
611 newXfer->txrxBuf[2] = 0;
612 i2cMasterTx(I2C_BUS_ID, I2C_ADDR, newXfer->txrxBuf, 3, i2cCallback, newXfer);
613 }
614 break;
615
616 case SENSOR_STATE_INIT_OFFSETS:
617 /* PS Threshold register */
618 newXfer = allocXfer(SENSOR_STATE_INIT_THRESHOLDS);
619 if (newXfer != NULL) {
620 newXfer->txrxBuf[0] = ROHM_RPR0521_REG_PS_TH_LSB;
621 newXfer->txrxBuf[1] = (ROHM_RPR0521_THRESHOLD_ASSERT_NEAR & 0xFF);
622 newXfer->txrxBuf[2] = (ROHM_RPR0521_THRESHOLD_ASSERT_NEAR & 0xFF00) >> 8;
623 newXfer->txrxBuf[3] = (ROHM_RPR0521_THRESHOLD_DEASSERT_NEAR & 0xFF);
624 newXfer->txrxBuf[4] = (ROHM_RPR0521_THRESHOLD_DEASSERT_NEAR & 0xFF00) >> 8;
625 i2cMasterTx(I2C_BUS_ID, I2C_ADDR, newXfer->txrxBuf, 5, i2cCallback, newXfer);
626 }
627 break;
628
629 case SENSOR_STATE_INIT_THRESHOLDS:
630 /* Interrupt register */
631 regData = (INTERRUPT_MODE_PS_HYSTERESIS << 4) | INTERRUPT_LATCH_BIT | INTERRUPT_TRIGGER_PS;
632 writeRegister(ROHM_RPR0521_REG_INTERRUPT, regData, SENSOR_STATE_FINISH_INIT);
633 break;
634
635 case SENSOR_STATE_FINISH_INIT:
636 sensorRegisterInitComplete(mTask.alsHandle);
637 sensorRegisterInitComplete(mTask.proxHandle);
638 break;
639
640 case SENSOR_STATE_ENABLING_ALS:
641 sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, true, 0);
642 break;
643
644 case SENSOR_STATE_ENABLING_PROX:
645 sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, true, 0);
646 break;
647
648 case SENSOR_STATE_DISABLING_ALS:
649 sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, false, 0);
650 break;
651
652 case SENSOR_STATE_DISABLING_PROX:
653 // Clear persistence setting
654 regData = (ROHM_RPR0521_GAIN_PS << 4) | PS_PERSISTENCE_ACTIVE_AT_EACH_MEASUREMENT_END;
655 writeRegister(ROHM_RPR0521_REG_PS_CONTROL, regData, SENSOR_STATE_DISABLING_PROX_2);
656 break;
657
658 case SENSOR_STATE_DISABLING_PROX_2:
659 // Reset interrupt
660 writeRegister(ROHM_RPR0521_REG_SYSTEM_CONTROL, INT_RESET_BIT, SENSOR_STATE_DISABLING_PROX_3);
661 break;
662
663 case SENSOR_STATE_DISABLING_PROX_3:
664 sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, false, 0);
665 break;
666
667 case SENSOR_STATE_ALS_SAMPLING:
668 als0 = *(uint16_t*)(xfer->txrxBuf);
669 als1 = *(uint16_t*)(xfer->txrxBuf+2);
670
671 DEBUG_PRINT("als sample ready: als0=%u als1=%u\n", als0, als1);
672
673 if (mTask.alsOn) {
674 sample.fdata = getLuxFromAlsData(als0, als1);
675 if (mTask.lastAlsSample.idata != sample.idata) {
676 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), sample.vptr, NULL);
677 mTask.lastAlsSample.fdata = sample.fdata;
678 }
679 }
680
681 break;
682
683 case SENSOR_STATE_PROX_SAMPLING:
684 ps = *(uint16_t*)(xfer->txrxBuf);
685 lastProxState = mTask.proxState;
686
687 DEBUG_PRINT("prox sample ready: prox=%u\n", ps);
688
689 if (mTask.proxOn) {
690 if (ps > ROHM_RPR0521_THRESHOLD_ASSERT_NEAR) {
691 sample.fdata = ROHM_RPR0521_REPORT_NEAR_VALUE;
692 mTask.proxState = PROX_STATE_NEAR;
693 } else {
694 sample.fdata = ROHM_RPR0521_REPORT_FAR_VALUE;
695 mTask.proxState = PROX_STATE_FAR;
696 }
697
698 if (mTask.proxState != lastProxState)
699 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL);
700
701 // After the first prox sample, change the persistance setting to assert
702 // interrupt on-change, rather than after every sample
703 regData = (ROHM_RPR0521_GAIN_PS << 4) | PS_PERSISTENCE_STATUS_UPDATED_AT_EACH_MEASUREMENT_END;
704 writeRegister(ROHM_RPR0521_REG_PS_CONTROL, regData, SENSOR_STATE_IDLE);
705 }
706
707 break;
708
709 default:
710 break;
711 }
712
713 xfer->inUse = false;
714 }
715
716 /*
717 * Main driver entry points
718 */
719
init_app(uint32_t myTid)720 static bool init_app(uint32_t myTid)
721 {
722 /* Set up driver private data */
723 mTask.tid = myTid;
724 mTask.alsOn = false;
725 mTask.proxOn = false;
726 mTask.lastAlsSample.idata = ROHM_RPR0521_ALS_INVALID;
727 mTask.proxState = PROX_STATE_INIT;
728
729 mTask.pin = gpioRequest(PROX_INT_PIN);
730 gpioConfigInput(mTask.pin, GPIO_SPEED_LOW, GPIO_PULL_NONE);
731 syscfgSetExtiPort(mTask.pin);
732 mTask.isr.func = proxIsr;
733
734 /* Register sensors */
735 mTask.alsHandle = sensorRegister(&sensorInfoAls, &sensorOpsAls, NULL, false);
736 mTask.proxHandle = sensorRegister(&sensorInfoProx, &sensorOpsProx, NULL, false);
737
738 osEventSubscribe(myTid, EVT_APP_START);
739
740 return true;
741 }
742
end_app(void)743 static void end_app(void)
744 {
745 disableInterrupt(mTask.pin, &mTask.isr);
746 extiUnchainIsr(PROX_IRQ, &mTask.isr);
747 extiClearPendingGpio(mTask.pin);
748 gpioRelease(mTask.pin);
749
750 sensorUnregister(mTask.alsHandle);
751 sensorUnregister(mTask.proxHandle);
752
753 i2cMasterRelease(I2C_BUS_ID);
754 }
755
handle_event(uint32_t evtType,const void * evtData)756 static void handle_event(uint32_t evtType, const void* evtData)
757 {
758 struct I2cTransfer *xfer;
759
760 switch (evtType) {
761 case EVT_APP_START:
762 i2cMasterRequest(I2C_BUS_ID, I2C_SPEED);
763
764 /* Reset chip */
765 writeRegister(ROHM_RPR0521_REG_SYSTEM_CONTROL, SW_RESET_BIT, SENSOR_STATE_RESET);
766 break;
767
768 case EVT_SENSOR_I2C:
769 handle_i2c_event((struct I2cTransfer*)evtData);
770 break;
771
772 case EVT_SENSOR_ALS_TIMER:
773 xfer = allocXfer(SENSOR_STATE_ALS_SAMPLING);
774 if (xfer != NULL) {
775 xfer->txrxBuf[0] = ROHM_RPR0521_REG_ALS_DATA0_LSB;
776 i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 1, xfer->txrxBuf, 4, i2cCallback, xfer);
777 }
778 break;
779
780 case EVT_SENSOR_PROX_INTERRUPT:
781 // Over-read to read the INTERRUPT register to clear the interrupt
782 xfer = allocXfer(SENSOR_STATE_PROX_SAMPLING);
783 if (xfer != NULL) {
784 xfer->txrxBuf[0] = ROHM_RPR0521_REG_PS_DATA_LSB;
785 i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 1, xfer->txrxBuf, 7, i2cCallback, xfer);
786 }
787 break;
788
789 }
790 }
791
792 INTERNAL_APP_INIT(APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 10), RPR0521_APP_VERSION, init_app, end_app, handle_event);
793