1/*
2 * Copyright (c) 2022 Chipsea Technologies (Shenzhen) Corp., Ltd.
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 "ppg_cs1262_spi.h"
10#include "spi_if.h"
11
12#define HDF_LOG_TAG khdf_sensor_ppg_driver
13
14#define CS1262_HEAD_BUF_SINGLEREG_LEN 4
15#define CS1262_HEAD_BUF_FULL_LEN 6
16#define OFFSET_BITS_8 8
17#define OFFSET_BITS_2 2
18
19static struct SensorBusCfg *g_busCfg = NULL;
20
21static inline uint16_t ReverseEndianInt16(uint16_t data)
22{
23    return (((data & 0x00FF) << OFFSET_BITS_8) |
24            ((data & 0xFF00) >> OFFSET_BITS_8));
25}
26
27static inline uint16_t Cs1262RegAddrConvert(uint16_t reg)
28{
29    /* CS1262 takes the register address from bit[2] to bit[15], bit[1~0] fixed as 00,
30     * so reg needs to be shifted left by 2 bits to convert it to the address format required by CS1262
31     */
32    return (reg << OFFSET_BITS_2) & 0x0FFC;
33}
34
35static inline uint8_t Cs1262GetHighByteInt16(uint16_t data)
36{
37    return (data & 0xFF00) >> OFFSET_BITS_8;
38}
39
40static inline uint8_t Cs1262GetLowByteInt16(uint16_t data)
41{
42    return data & 0x00FF;
43}
44
45void Cs1262ReleaseSpi(struct SensorBusCfg *busCfg)
46{
47    SpiClose(busCfg->spiCfg.handle);
48    busCfg->spiCfg.handle = NULL;
49    g_busCfg = NULL;
50}
51
52int32_t Cs1262InitSpi(struct SensorBusCfg *busCfg)
53{
54    int32_t ret;
55    CHECK_NULL_PTR_RETURN_VALUE(busCfg, HDF_ERR_INVALID_PARAM);
56    struct SpiDevInfo spiDevinfo = {
57        .busNum = busCfg->spiCfg.busNum,
58        .csNum = busCfg->spiCfg.csNum,
59    };
60
61    HDF_LOGI("%s: SpiOpen busNum = %d, csNum = %d", __func__, spiDevinfo.busNum, spiDevinfo.csNum);
62
63    busCfg->spiCfg.handle = SpiOpen(&spiDevinfo);
64    if (busCfg->spiCfg.handle == NULL) {
65        HDF_LOGE("%s: SpiOpen failed", __func__);
66        return HDF_FAILURE;
67    }
68
69    HDF_LOGD("%s: SpiSetCfg: maxSpeedHz:%d, mode=%d, transferMode=%d, bitsPerWord=%d",
70        __func__, busCfg->spiCfg.spi.maxSpeedHz, busCfg->spiCfg.spi.mode,
71        busCfg->spiCfg.spi.transferMode, busCfg->spiCfg.spi.bitsPerWord);
72
73    ret = SpiSetCfg(busCfg->spiCfg.handle, &busCfg->spiCfg.spi);
74    if (ret != HDF_SUCCESS) {
75        HDF_LOGE("%s: SpiSetCfg failed", __func__);
76        SpiClose(busCfg->spiCfg.handle);
77        return ret;
78    }
79
80    g_busCfg = busCfg;
81    return HDF_SUCCESS;
82}
83
84int32_t Cs1262ReadFifoReg(Cs1262FifoVal *fifoBuf, uint16_t fifoLen)
85{
86    CHECK_NULL_PTR_RETURN_VALUE(fifoBuf, HDF_ERR_INVALID_PARAM);
87    CHECK_NULL_PTR_RETURN_VALUE(g_busCfg, HDF_ERR_NOT_SUPPORT);
88
89    uint8_t headBuf[CS1262_HEAD_BUF_FULL_LEN] = {
90        CS1262_SPI_NOCHECK_CONTINUOUSREAD,
91        0,
92        Cs1262GetHighByteInt16(Cs1262RegAddrConvert(CS1262_FIFO_DATA_REG)),
93        Cs1262GetLowByteInt16(Cs1262RegAddrConvert(CS1262_FIFO_DATA_REG)),
94        Cs1262GetHighByteInt16(fifoLen - 1),
95        Cs1262GetLowByteInt16(fifoLen - 1),
96    };
97
98    struct SpiMsg msg[] = {
99        {
100            .wbuf = headBuf,
101            .rbuf = NULL,
102            .len = CS1262_HEAD_BUF_FULL_LEN,
103            .keepCs = 0,  // cs low
104            .delayUs = 0,
105            .speed = g_busCfg->spiCfg.spi.maxSpeedHz,
106        },
107        {
108            .wbuf = NULL,
109            .rbuf = (uint8_t *)fifoBuf,
110            .len = fifoLen * sizeof(Cs1262FifoVal),
111            .keepCs = 1,  // cs high
112            .delayUs = 0,
113            .speed = g_busCfg->spiCfg.spi.maxSpeedHz
114        }
115    };
116
117    if (SpiTransfer(g_busCfg->spiCfg.handle, msg, HDF_ARRAY_SIZE(msg)) != HDF_SUCCESS) {
118        HDF_LOGE("%s: Read Fifo data use spi failed", __func__);
119        return HDF_FAILURE;
120    }
121
122    return HDF_SUCCESS;
123}
124
125int32_t Cs1262ReadRegs(uint16_t regAddr, uint16_t *dataBuf, uint16_t dataLen)
126{
127    CHECK_NULL_PTR_RETURN_VALUE(dataBuf, HDF_ERR_INVALID_PARAM);
128    CHECK_NULL_PTR_RETURN_VALUE(g_busCfg, HDF_ERR_NOT_SUPPORT);
129
130    uint8_t headBuf[CS1262_HEAD_BUF_FULL_LEN] = {
131        CS1262_SPI_NOCHECK_SINGLEREAD,
132        0,
133        Cs1262GetHighByteInt16(Cs1262RegAddrConvert(regAddr)),
134        Cs1262GetLowByteInt16(Cs1262RegAddrConvert(regAddr))
135    };
136    uint8_t bufLen = CS1262_HEAD_BUF_SINGLEREG_LEN;
137
138    if (dataLen > 1) {
139        headBuf[0] = CS1262_SPI_NOCHECK_CONTINUOUSREAD;
140        headBuf[bufLen++] = Cs1262GetHighByteInt16(dataLen - 1);
141        headBuf[bufLen++] = Cs1262GetLowByteInt16(dataLen - 1);
142    }
143
144    struct SpiMsg msg[] = {
145        {
146            .wbuf = headBuf,
147            .rbuf = NULL,
148            .len = bufLen,
149            .keepCs = 0,
150            .delayUs = 0,
151            .speed = g_busCfg->spiCfg.spi.maxSpeedHz
152        },
153        {
154            .wbuf = NULL,
155            .rbuf = (uint8_t *)dataBuf,
156            .len = dataLen * 2,  // 2 bytes reg
157            .keepCs = 1,  // 1 means enable
158            .delayUs = 0,
159            .speed = g_busCfg->spiCfg.spi.maxSpeedHz
160        }
161    };
162
163    if (SpiTransfer(g_busCfg->spiCfg.handle, msg, HDF_ARRAY_SIZE(msg)) != HDF_SUCCESS) {
164        HDF_LOGE("%s: Read data use spi failed", __func__);
165        return HDF_FAILURE;
166    }
167
168    for (uint16_t index = 0; index < dataLen; index++) {
169        *(dataBuf + index) = ReverseEndianInt16(*(dataBuf + index));
170    }
171
172    return HDF_SUCCESS;
173}
174
175int32_t Cs1262WriteRegs(uint16_t regAddr, uint16_t *dataBuf, uint16_t dataLen)
176{
177    CHECK_NULL_PTR_RETURN_VALUE(dataBuf, HDF_ERR_INVALID_PARAM);
178    CHECK_NULL_PTR_RETURN_VALUE(g_busCfg, HDF_ERR_NOT_SUPPORT);
179
180    uint8_t headBuf[CS1262_HEAD_BUF_FULL_LEN] = {
181        CS1262_SPI_NOCHECK_SINGLEWRITE,
182        0,
183        Cs1262GetHighByteInt16(Cs1262RegAddrConvert(regAddr)),
184        Cs1262GetLowByteInt16(Cs1262RegAddrConvert(regAddr))
185    };
186    uint8_t bufLen = CS1262_HEAD_BUF_SINGLEREG_LEN;
187
188    if (dataLen > 1) {
189        headBuf[0] = CS1262_SPI_NOCHECK_CONTINUOUSWRITE;
190        headBuf[bufLen++] = Cs1262GetHighByteInt16(dataLen - 1);
191        headBuf[bufLen++] = Cs1262GetLowByteInt16(dataLen - 1);
192    }
193
194    for (uint16_t index = 0; index < dataLen; index++) {
195        *(dataBuf + index) = ReverseEndianInt16(*(dataBuf + index));
196    }
197
198    struct SpiMsg msg[] = {
199        {
200            .wbuf = headBuf,
201            .rbuf = NULL,
202            .len = bufLen,
203            .keepCs = 0,
204            .delayUs = 0,
205            .speed = g_busCfg->spiCfg.spi.maxSpeedHz
206        },
207        {
208            .wbuf = (uint8_t *)dataBuf,
209            .rbuf = NULL,
210            .len = dataLen * 2,  // 1 data has 2 bytes
211            .keepCs = 1,  // 1 means enable
212            .delayUs = 0,
213            .speed = g_busCfg->spiCfg.spi.maxSpeedHz
214        }
215    };
216
217    if (SpiTransfer(g_busCfg->spiCfg.handle, msg, HDF_ARRAY_SIZE(msg)) != HDF_SUCCESS) {
218        HDF_LOGE("%s: Write data use spi failed", __func__);
219        return HDF_FAILURE;
220    }
221
222    return HDF_SUCCESS;
223}
224
225inline int32_t Cs1262WriteReg(uint16_t regAddr, uint16_t data)
226{
227    return Cs1262WriteRegs(regAddr, &data, 1);
228}
229
230int32_t Cs1262WriteData(uint8_t *data, uint16_t dataLen)
231{
232    CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
233    CHECK_NULL_PTR_RETURN_VALUE(g_busCfg, HDF_ERR_NOT_SUPPORT);
234    struct SpiMsg msg = {
235        .wbuf = data,
236        .rbuf = NULL,
237        .len = dataLen,
238        .keepCs = 1,  // 1 means enable
239        .delayUs = 0,
240        .speed = g_busCfg->spiCfg.spi.maxSpeedHz
241    };
242    return SpiTransfer(g_busCfg->spiCfg.handle, &msg, 1);
243}
244
245int32_t Cs1262WriteRegbit(uint16_t regAddr, uint16_t setbit, Cs1262BitStatus bitval)
246{
247    uint16_t regData = 0;
248
249    if (Cs1262ReadRegs(regAddr, &regData, 1) != HDF_SUCCESS) {
250        HDF_LOGE("%s: failed", __func__);
251        return HDF_FAILURE;
252    }
253
254    if (bitval == CS1262_REG_BIT_SET) {
255        regData |= (uint16_t)(1 << setbit);
256    } else {
257        regData &=  (uint16_t)(~(1 << setbit));
258    }
259
260    return Cs1262WriteRegs(regAddr, &regData, 1);
261}
262
263int32_t Cs1262WriteGroup(Cs1262RegGroup *regGroup, uint16_t groupLen)
264{
265    int32_t ret;
266
267    CHECK_NULL_PTR_RETURN_VALUE(regGroup, HDF_ERR_INVALID_PARAM);
268
269    for (uint16_t index = 0; index < groupLen; index++) {
270        if (regGroup[index].regLen == 1) {
271            ret = Cs1262WriteReg(regGroup[index].regAddr, regGroup[index].regVal);
272        } else {
273            ret = Cs1262WriteRegs(regGroup[index].regAddr, regGroup[index].regValGroup, regGroup[index].regLen);
274        }
275
276        if (ret != HDF_SUCCESS) {
277            HDF_LOGE("%s: failed, index = %u", __func__, index);
278            return HDF_FAILURE;
279        }
280    }
281
282    return HDF_SUCCESS;
283}
284