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
19 static struct SensorBusCfg *g_busCfg = NULL;
20
ReverseEndianInt16(uint16_t data)21 static inline uint16_t ReverseEndianInt16(uint16_t data)
22 {
23 return (((data & 0x00FF) << OFFSET_BITS_8) |
24 ((data & 0xFF00) >> OFFSET_BITS_8));
25 }
26
Cs1262RegAddrConvert(uint16_t reg)27 static 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
Cs1262GetHighByteInt16(uint16_t data)35 static inline uint8_t Cs1262GetHighByteInt16(uint16_t data)
36 {
37 return (data & 0xFF00) >> OFFSET_BITS_8;
38 }
39
Cs1262GetLowByteInt16(uint16_t data)40 static inline uint8_t Cs1262GetLowByteInt16(uint16_t data)
41 {
42 return data & 0x00FF;
43 }
44
Cs1262ReleaseSpi(struct SensorBusCfg * busCfg)45 void Cs1262ReleaseSpi(struct SensorBusCfg *busCfg)
46 {
47 SpiClose(busCfg->spiCfg.handle);
48 busCfg->spiCfg.handle = NULL;
49 g_busCfg = NULL;
50 }
51
Cs1262InitSpi(struct SensorBusCfg * busCfg)52 int32_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
Cs1262ReadFifoReg(Cs1262FifoVal * fifoBuf,uint16_t fifoLen)84 int32_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
Cs1262ReadRegs(uint16_t regAddr,uint16_t * dataBuf,uint16_t dataLen)125 int32_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
Cs1262WriteRegs(uint16_t regAddr,uint16_t * dataBuf,uint16_t dataLen)175 int32_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
Cs1262WriteReg(uint16_t regAddr,uint16_t data)225 inline int32_t Cs1262WriteReg(uint16_t regAddr, uint16_t data)
226 {
227 return Cs1262WriteRegs(regAddr, &data, 1);
228 }
229
Cs1262WriteData(uint8_t * data,uint16_t dataLen)230 int32_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
Cs1262WriteRegbit(uint16_t regAddr,uint16_t setbit,Cs1262BitStatus bitval)245 int32_t Cs1262WriteRegbit(uint16_t regAddr, uint16_t setbit, Cs1262BitStatus bitval)
246 {
247 uint16_t regData = 0;
248
249 if (Cs1262ReadRegs(regAddr, ®Data, 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, ®Data, 1);
261 }
262
Cs1262WriteGroup(Cs1262RegGroup * regGroup,uint16_t groupLen)263 int32_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