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, ®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 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