1/*
2 * Copyright (c) 2021-2022 xu
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9#include "proximity_apds9960.h"
10#include <securec.h>
11#include "osal_mem.h"
12#include "osal_time.h"
13#include "sensor_config_controller.h"
14#include "sensor_device_manager.h"
15#include "sensor_proximity_driver.h"
16
17#define HDF_LOG_TAG    khdf_sensor_proximity_driver
18
19#define PROXIMITY_STATE_FAR    5
20#define PROXIMITY_STATE_NEAR   0
21
22static struct Apds9960DrvData *g_apds9960DrvData = NULL;
23
24/* IO config for int-pin and I2C-pin */
25#define SENSOR_I2C6_DATA_REG_ADDR 0x114f004c
26#define SENSOR_I2C6_CLK_REG_ADDR  0x114f0048
27#define SENSOR_I2C_REG_CFG        0x403
28
29static int32_t ReadApds9960RawData(struct SensorCfgData *data, struct ProximityData *rawData, uint64_t *timestamp)
30{
31    OsalTimespec time;
32
33    (void)memset_s(&time, sizeof(time), 0, sizeof(time));
34
35    CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
36
37    if (OsalGetTime(&time) != HDF_SUCCESS) {
38        HDF_LOGE("%s: Get time failed", __func__);
39        return HDF_FAILURE;
40    }
41    *timestamp = time.sec * SENSOR_SECOND_CONVERT_NANOSECOND + time.usec * SENSOR_CONVERT_UNIT; /* unit nanosecond */
42
43    int32_t ret = ReadSensor(&data->busCfg, APDS9960_PROXIMITY_DATA_ADDR, &rawData->stateFlag, sizeof(uint8_t));
44    CHECK_PARSER_RESULT_RETURN_VALUE(ret, "read data");
45
46    return ret;
47}
48
49static int32_t ReadApds9960Data(struct SensorCfgData *data)
50{
51    int32_t ret;
52    int32_t tmp;
53    struct ProximityData rawData = { 5 };
54    struct SensorReportEvent event;
55
56    (void)memset_s(&event, sizeof(event), 0, sizeof(event));
57
58    ret = ReadApds9960RawData(data, &rawData, &event.timestamp);
59    if (ret != HDF_SUCCESS) {
60        return HDF_FAILURE;
61    }
62
63    event.sensorId = SENSOR_TAG_PROXIMITY;
64    event.option = 0;
65    event.mode = SENSOR_WORK_MODE_ON_CHANGE;
66
67    if (rawData.stateFlag <= APDS9960_PROXIMITY_THRESHOLD) {
68        tmp = PROXIMITY_STATE_FAR;
69    } else {
70        tmp = PROXIMITY_STATE_NEAR;
71    }
72
73    event.dataLen = sizeof(tmp);
74    event.data = (uint8_t *)&tmp;
75    ret = ReportSensorEvent(&event);
76    if (ret != HDF_SUCCESS) {
77        HDF_LOGE("%s: APDS9960 report data failed", __func__);
78    }
79
80    return ret;
81}
82
83static int32_t InitApda9960(struct SensorCfgData *data)
84{
85    int32_t ret;
86
87    CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
88    ret = SetSensorRegCfgArray(&data->busCfg, data->regCfgGroup[SENSOR_INIT_GROUP]);
89    if (ret != HDF_SUCCESS) {
90        HDF_LOGE("%s: APDS9960 sensor init config failed", __func__);
91        return HDF_FAILURE;
92    }
93    return HDF_SUCCESS;
94}
95
96static int32_t InitProximityPreConfig(void)
97{
98    if (SetSensorPinMux(SENSOR_I2C6_DATA_REG_ADDR, SENSOR_ADDR_WIDTH_4_BYTE, SENSOR_I2C_REG_CFG) != HDF_SUCCESS) {
99        HDF_LOGE("%s: Data write mux pin failed", __func__);
100        return HDF_FAILURE;
101    }
102    if (SetSensorPinMux(SENSOR_I2C6_CLK_REG_ADDR, SENSOR_ADDR_WIDTH_4_BYTE, SENSOR_I2C_REG_CFG) != HDF_SUCCESS) {
103        HDF_LOGE("%s: Clk write mux pin failed", __func__);
104        return HDF_FAILURE;
105    }
106
107    return HDF_SUCCESS;
108}
109
110static int32_t DispatchApds9960(struct HdfDeviceIoClient *client,
111    int cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
112{
113    (void)client;
114    (void)cmd;
115    (void)data;
116    (void)reply;
117
118    return HDF_SUCCESS;
119}
120
121static int32_t Apds9960BindDriver(struct HdfDeviceObject *device)
122{
123    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
124
125    struct Apds9960DrvData *drvData = (struct Apds9960DrvData *)OsalMemCalloc(sizeof(*drvData));
126    if (drvData == NULL) {
127        HDF_LOGE("%s: Malloc Apds9960 drv data fail", __func__);
128        return HDF_ERR_MALLOC_FAIL;
129    }
130
131    drvData->ioService.Dispatch = DispatchApds9960;
132    drvData->device = device;
133    device->service = &drvData->ioService;
134    g_apds9960DrvData = drvData;
135
136    return HDF_SUCCESS;
137}
138
139static int32_t Apds996InitDriver(struct HdfDeviceObject *device)
140{
141    int32_t ret;
142    struct ProximityOpsCall ops;
143
144    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
145    struct Apds9960DrvData *drvData = (struct Apds9960DrvData *)device->service;
146    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
147
148    ret = InitProximityPreConfig();
149    if (ret != HDF_SUCCESS) {
150        HDF_LOGE("%s: Init  APDS9960 bus mux config", __func__);
151        return HDF_FAILURE;
152    }
153
154    drvData->sensorCfg = ProximityCreateCfgData(device->property);
155    if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) {
156        HDF_LOGD("%s: Creating proximitycfg failed because detection failed", __func__);
157        return HDF_ERR_NOT_SUPPORT;
158    }
159
160    ops.Init = NULL;
161    ops.ReadData = ReadApds9960Data;
162    ret = ProximityRegisterChipOps(&ops);
163    if (ret != HDF_SUCCESS) {
164        HDF_LOGE("%s: Register APDS9960 proximity failed", __func__);
165        return HDF_FAILURE;
166    }
167
168    ret = InitApda9960(drvData->sensorCfg);
169    if (ret != HDF_SUCCESS) {
170        HDF_LOGE("%s: Init APDS9960 proximity failed", __func__);
171        return HDF_FAILURE;
172    }
173
174    return HDF_SUCCESS;
175}
176
177
178static void Apds996ReleaseDriver(struct HdfDeviceObject *device)
179{
180    CHECK_NULL_PTR_RETURN(device);
181
182    struct Apds9960DrvData *drvData = (struct Apds9960DrvData *)device->service;
183    CHECK_NULL_PTR_RETURN(drvData);
184
185    if (drvData->sensorCfg != NULL) {
186        ProximityReleaseCfgData(drvData->sensorCfg);
187        drvData->sensorCfg = NULL;
188    }
189    OsalMemFree(drvData);
190}
191
192struct HdfDriverEntry g_proximityApds9960DevEntry = {
193    .moduleVersion = 1,
194    .moduleName = "HDF_SENSOR_PROXIMITY_APDS9960",
195    .Bind = Apds9960BindDriver,
196    .Init = Apds996InitDriver,
197    .Release = Apds996ReleaseDriver,
198};
199
200HDF_INIT(g_proximityApds9960DevEntry);