1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 /**
10 * @file fxlc95000_drv.c
11 * @brief The fxlc95000_drv.c file implements the FXLC95000 sensor driver interface.
12 */
13
14 //-----------------------------------------------------------------------
15 // ISSDK Includes
16 //-----------------------------------------------------------------------
17 #include "gpio_driver.h"
18 #include "fxlc95000_drv.h"
19 #include "systick_utils.h"
20
21 //-----------------------------------------------------------------------
22 // Global Variables
23 //-----------------------------------------------------------------------
24 uint8_t fxlc95000_spiRead_CmdBuffer[FXLC95000_SPI_MAX_MSG_SIZE] = {0};
25 uint8_t fxlc95000_spiRead_DataBuffer[FXLC95000_SPI_MAX_MSG_SIZE] = {0};
26 uint8_t fxlc95000_spiWrite_CmdDataBuffer[FXLC95000_SPI_MAX_MSG_SIZE] = {0};
27
28 //-----------------------------------------------------------------------
29 // Functions
30 //-----------------------------------------------------------------------
FXLC95000_SPI_ReadPreprocess(void * pCmdOut,uint32_t offset,uint32_t size)31 void FXLC95000_SPI_ReadPreprocess(void *pCmdOut, uint32_t offset, uint32_t size)
32 {
33 spiCmdParams_t *pSlaveCmd = pCmdOut;
34
35 uint8_t *pWBuff = fxlc95000_spiRead_CmdBuffer;
36 uint8_t *pRBuff = fxlc95000_spiRead_DataBuffer;
37
38 /* Formatting for Read command of FXLC95000 SENSOR. */
39 *(pWBuff) =
40 (offset & 0x7F) << 1; /* offset is the internal register address of the sensor at which write is performed. */
41
42 /* Create the slave read command. */
43 pSlaveCmd->size = size + FXLC95000_SPI_CMD_LEN;
44 pSlaveCmd->pWriteBuffer = pWBuff;
45 pSlaveCmd->pReadBuffer = pRBuff;
46 }
47
FXLC95000_SPI_WritePreprocess(void * pCmdOut,uint32_t offset,uint32_t size,void * pWritebuffer)48 void FXLC95000_SPI_WritePreprocess(void *pCmdOut, uint32_t offset, uint32_t size, void *pWritebuffer)
49 {
50 spiCmdParams_t *pSlaveCmd = pCmdOut;
51
52 uint8_t *pWBuff = fxlc95000_spiWrite_CmdDataBuffer;
53 uint8_t *pRBuff = fxlc95000_spiWrite_CmdDataBuffer + size + FXLC95000_SPI_CMD_LEN;
54
55 /* Formatting for Write command of FXLC95000 SENSOR. */
56 *(pWBuff) =
57 (offset | 0x40) << 1; /* offset is the internal register address of the sensor at which write is performed. */
58
59 /* Copy the slave write command */
60 memcpy(pWBuff + FXLC95000_SPI_CMD_LEN, pWritebuffer, size);
61
62 /* Create the slave command. */
63 pSlaveCmd->size = size + FXLC95000_SPI_CMD_LEN;
64 pSlaveCmd->pWriteBuffer = pWBuff;
65 pSlaveCmd->pReadBuffer = pRBuff;
66 }
67
FXLC95000_SPI_Initialize(fxlc95000_spi_sensorhandle_t * pSensorHandle,ARM_DRIVER_SPI * pBus,uint8_t index,void * pSpiSelect,void * pSlaveSelect,void * pReset,uint16_t buildId)68 int32_t FXLC95000_SPI_Initialize(fxlc95000_spi_sensorhandle_t *pSensorHandle,
69 ARM_DRIVER_SPI *pBus,
70 uint8_t index,
71 void *pSpiSelect,
72 void *pSlaveSelect,
73 void *pReset,
74 uint16_t buildId)
75 {
76 int32_t status;
77 uint16_t readNumber[2];
78 GENERIC_DRIVER_GPIO *pGPIODriver = &Driver_GPIO_KSDK;
79
80 /*! Check the input parameters. */
81 if (pSensorHandle == NULL || pBus == NULL || pSpiSelect == NULL || pSlaveSelect == NULL || pReset == NULL)
82 {
83 return SENSOR_ERROR_INVALID_PARAM;
84 }
85
86 /*! Initialize the sensor handle. */
87 pSensorHandle->pCommDrv = pBus;
88 pSensorHandle->slaveParams.pReadPreprocessFN = FXLC95000_SPI_ReadPreprocess;
89 pSensorHandle->slaveParams.pWritePreprocessFN = FXLC95000_SPI_WritePreprocess;
90 pSensorHandle->slaveParams.pTargetSlavePinID = pSlaveSelect;
91 pSensorHandle->slaveParams.spiCmdLen = FXLC95000_SPI_CMD_LEN;
92 pSensorHandle->slaveParams.ssActiveValue = FXLC95000_SS_ACTIVE_VALUE;
93
94 pSensorHandle->deviceInfo.deviceInstance = index;
95 pSensorHandle->deviceInfo.functionParam = NULL;
96 pSensorHandle->deviceInfo.idleFunction = NULL;
97
98 /* Initialize the Slave Select and reset Pins. */
99 pGPIODriver->pin_init(pSlaveSelect, GPIO_DIRECTION_OUT, NULL, NULL, NULL);
100 pGPIODriver->pin_init(pSpiSelect, GPIO_DIRECTION_OUT, NULL, NULL, NULL);
101 pGPIODriver->pin_init(pReset, GPIO_DIRECTION_OUT, NULL, NULL, NULL);
102
103 /* Pull down SPI Select, Pull up SS and Reset */
104 pGPIODriver->set_pin(pSlaveSelect);
105 pGPIODriver->clr_pin(pSpiSelect);
106 pGPIODriver->set_pin(pReset);
107 BOARD_DELAY_ms(30); /* Wait for Part to Complete Reset */
108
109 pGPIODriver->clr_pin(pReset);
110 BOARD_DELAY_ms(50); /* Wait for Part to Initialize in SPI Mode */
111
112 pGPIODriver->set_pin(pSpiSelect);
113 BOARD_DELAY_ms(10); /* Wait for ROM Initialization before communication */
114
115 /* Verify if the SPI connection by writing command to Boot to flash and fetch Device Info.
116 * A matching Build Number confirms Sensor Identity and Firmware. */
117 Register_SPI_BlockWrite(pSensorHandle->pCommDrv, &pSensorHandle->deviceInfo, &pSensorHandle->slaveParams, 0,
118 BootToFlash, sizeof(BootToFlash));
119 BOARD_DELAY_ms(10); /* Allow time for the device to boot to Flash. */
120 Register_SPI_BlockWrite(pSensorHandle->pCommDrv, &pSensorHandle->deviceInfo, &pSensorHandle->slaveParams, 0,
121 GetDeviceInfoCmd, sizeof(GetDeviceInfoCmd));
122 BOARD_DELAY_ms(1);
123
124 status = Register_SPI_Read(pSensorHandle->pCommDrv, &pSensorHandle->deviceInfo, &pSensorHandle->slaveParams,
125 FXLC95000_BUILD_ID_OFFSET, FXLC95000_BUILD_ID_SIZE + FXLC95000_PART_NUMBER_SIZE,
126 (uint8_t *)&readNumber);
127 readNumber[0] = (readNumber[0] >> 8) | (readNumber[0] << 8);
128 readNumber[1] = (readNumber[1] >> 8) | (readNumber[1] << 8);
129 if (ARM_DRIVER_OK != status || readNumber[0] != buildId || readNumber[1] != FXLC95000_PART_NUMBER)
130 {
131 pSensorHandle->isInitialized = false;
132 return SENSOR_ERROR_INIT;
133 }
134
135 pSensorHandle->isInitialized = true;
136 return SENSOR_ERROR_NONE;
137 }
138
FXLC95000_SPI_SetIdleTask(fxlc95000_spi_sensorhandle_t * pSensorHandle,registeridlefunction_t idleTask,void * userParam)139 void FXLC95000_SPI_SetIdleTask(fxlc95000_spi_sensorhandle_t *pSensorHandle,
140 registeridlefunction_t idleTask,
141 void *userParam)
142 {
143 pSensorHandle->deviceInfo.functionParam = userParam;
144 pSensorHandle->deviceInfo.idleFunction = idleTask;
145 }
146
FXLC95000_SPI_CommandResponse(fxlc95000_spi_sensorhandle_t * pSensorHandle,const registercommandlist_t * pCommandList,const registerreadlist_t * pResponseList,uint8_t * pBuffer)147 int32_t FXLC95000_SPI_CommandResponse(fxlc95000_spi_sensorhandle_t *pSensorHandle,
148 const registercommandlist_t *pCommandList,
149 const registerreadlist_t *pResponseList,
150 uint8_t *pBuffer)
151 {
152 int32_t status;
153
154 /*! Validate for the correct handle and command list.*/
155 if (pSensorHandle == NULL || (pCommandList == NULL && pResponseList == NULL))
156 {
157 return SENSOR_ERROR_INVALID_PARAM;
158 }
159
160 /*! Check whether sensor handle is initialized before reading sensor data.*/
161 if (pSensorHandle->isInitialized != true)
162 {
163 return SENSOR_ERROR_INIT;
164 }
165
166 if (pCommandList != NULL)
167 { /* Write command to fetch configuration. */
168 status = Sensor_SPI_BlockWrite(pSensorHandle->pCommDrv, &pSensorHandle->deviceInfo, &pSensorHandle->slaveParams,
169 pCommandList, FXLC95000_COCO_ERROR_MASK);
170 if (ARM_DRIVER_OK != status)
171 {
172 return SENSOR_ERROR_WRITE;
173 }
174 }
175
176 /*! Parse through the read list and read the data one by one. */
177 if (pResponseList != NULL)
178 {
179 status = Sensor_SPI_Read(pSensorHandle->pCommDrv, &pSensorHandle->deviceInfo, &pSensorHandle->slaveParams,
180 pResponseList, pBuffer);
181 if (ARM_DRIVER_OK != status)
182 {
183 return SENSOR_ERROR_READ;
184 }
185 }
186
187 return SENSOR_ERROR_NONE;
188 }
189
FXLC95000_I2C_CheckRomMode(ARM_DRIVER_I2C * pBus,uint8_t index,uint16_t sAddress)190 int32_t FXLC95000_I2C_CheckRomMode(ARM_DRIVER_I2C *pBus, uint8_t index, uint16_t sAddress)
191 {
192 int32_t status;
193 uint16_t readNumber[2];
194 registerDeviceInfo_t deviceInfo = {.deviceInstance = index, .idleFunction = NULL};
195
196 Register_I2C_BlockWrite(pBus, &deviceInfo, sAddress, 0, GetDeviceInfoCmd, sizeof(GetDeviceInfoCmd));
197 BOARD_DELAY_ms(1);
198
199 status = Register_I2C_Read(pBus, &deviceInfo, sAddress, FXLC95000_BUILD_ID_OFFSET,
200 FXLC95000_BUILD_ID_SIZE + FXLC95000_PART_NUMBER_SIZE, (uint8_t *)&readNumber);
201 readNumber[0] = (readNumber[0] >> 8) | (readNumber[0] << 8);
202 readNumber[1] = (readNumber[1] >> 8) | (readNumber[1] << 8);
203 if (ARM_DRIVER_OK != status || readNumber[0] != FXLC95000_RESERVED_ID || readNumber[1] != FXLC95000_PART_NUMBER)
204 {
205 return -1;
206 }
207
208 return 0;
209 }
210
FXLC95000_I2C_FlashCommands(ARM_DRIVER_I2C * pBus,uint8_t index,uint16_t sAddress,const registercommandlist_t * pCommandList)211 int32_t FXLC95000_I2C_FlashCommands(ARM_DRIVER_I2C *pBus,
212 uint8_t index,
213 uint16_t sAddress,
214 const registercommandlist_t *pCommandList)
215 {
216 int32_t status;
217 registerDeviceInfo_t deviceInfo = {.deviceInstance = index, .idleFunction = NULL};
218
219 /*! Validate for the correct handle and register write list.*/
220 if (pBus == NULL || pCommandList == NULL)
221 {
222 return SENSOR_ERROR_INVALID_PARAM;
223 }
224
225 /* Write command to fetch configuration. */
226 status = Sensor_I2C_BlockWrite(pBus, &deviceInfo, sAddress, pCommandList, FXLC95000_COCO_ERROR_MASK);
227 if (ARM_DRIVER_OK != status)
228 {
229 return SENSOR_ERROR_WRITE;
230 }
231
232 return SENSOR_ERROR_NONE;
233 }
234
FXLC95000_I2C_FlashPayload(ARM_DRIVER_I2C * pBus,uint8_t index,uint16_t sAddress,uint8_t * pFlashBytes,uint8_t numBytes)235 int32_t FXLC95000_I2C_FlashPayload(
236 ARM_DRIVER_I2C *pBus, uint8_t index, uint16_t sAddress, uint8_t *pFlashBytes, uint8_t numBytes)
237 {
238 int32_t status;
239
240 /* First 4 bytes is address (which fits into 2 byte separate address field and Bank code)
241 * and then remaining bytes is WData. */
242 /* Make sure that the Flash payload received has the minimum information bytes
243 * required to construct a CI_READ_WRITE ROM Command. */
244 if (numBytes >= FXLC95000_FLASH_PAYLOAD_ADDR_LEN + FXLC95000_ROM_CI_WRITE_MIN_LEN)
245 {
246 uint8_t bytesToPageBoundary = 256 - *(pFlashBytes + 3);
247 uint8_t bytesAfterPageBoundary = numBytes - bytesToPageBoundary - FXLC95000_FLASH_PAYLOAD_ADDR_LEN;
248 /* Prepare CI_READ_WRITE ROM Command. */
249 /* Check if the write command being attempted spans across a page boundary (256 bytes). */
250 if (bytesToPageBoundary > 0 && bytesToPageBoundary < numBytes - FXLC95000_FLASH_PAYLOAD_ADDR_LEN)
251 { /* Break it into 2 write commands if write spans across 2 pages. Ref. Section 16.5 of FXLC95000CLHWRM. */
252 uint8_t writeFlashCommand[FXLC95000_ROM_CI_READ_WRITE_MAX_LEN] = {0x0A, 0x00, 0x12, 0x34, 0x56, 0x78};
253 uint8_t writeFlashCommand_2[FXLC95000_ROM_CI_READ_WRITE_MAX_LEN] = {0x0A, 0x00, 0x12, 0x34, 0x56, 0x78};
254
255 writeFlashCommand[1] =
256 (*(pFlashBytes + 1) == 0) ? 0x1F & (bytesToPageBoundary) : 0xC0 | (bytesToPageBoundary);
257 for (int i = 0; i < bytesToPageBoundary + FXLC95000_ROM_CI_READ_WRITE_ADDR_LEN;
258 i++) // 2 LSB Bytes of Address + Data.
259 {
260 writeFlashCommand[FXLC95000_ROM_CI_READ_WRITE_HDR_LEN + i] =
261 pFlashBytes[FXLC95000_ROM_CI_READ_WRITE_ADDR_LEN + i];
262 }
263
264 writeFlashCommand_2[1] =
265 (*(pFlashBytes + 1) == 0) ? 0x1F & (bytesAfterPageBoundary) : 0xC0 | (bytesAfterPageBoundary);
266 uint8_t address[] = {*(pFlashBytes + FXLC95000_ROM_CI_READ_WRITE_ADDR_LEN + 1),
267 *(pFlashBytes + FXLC95000_ROM_CI_READ_WRITE_ADDR_LEN)};
268 *((uint16_t *)address) += bytesToPageBoundary;
269 writeFlashCommand_2[FXLC95000_ROM_CI_READ_WRITE_HDR_LEN] = address[1];
270 writeFlashCommand_2[FXLC95000_ROM_CI_READ_WRITE_HDR_LEN + 1] = address[0];
271 for (int i = 0; i < bytesAfterPageBoundary; i++)
272 {
273 writeFlashCommand_2[FXLC95000_ROM_CI_READ_WRITE_HDR_LEN + FXLC95000_ROM_CI_READ_WRITE_ADDR_LEN + i] =
274 pFlashBytes[FXLC95000_FLASH_PAYLOAD_ADDR_LEN + bytesToPageBoundary + i];
275 }
276
277 if (bytesToPageBoundary > FXLC95000_ROM_CI_WRITE_MAX_LEN ||
278 bytesAfterPageBoundary > FXLC95000_ROM_CI_WRITE_MAX_LEN)
279 {
280 return SENSOR_ERROR_INVALID_PARAM;
281 }
282 else
283 { /* Create Command List to Write. */
284 const registercommandlist_t cWriteFlashSequence[] = {
285 {writeFlashCommand, 0,
286 FXLC95000_ROM_CI_READ_WRITE_HDR_LEN + FXLC95000_ROM_CI_READ_WRITE_ADDR_LEN + bytesToPageBoundary},
287 {writeFlashCommand_2, 0, FXLC95000_ROM_CI_READ_WRITE_HDR_LEN +
288 FXLC95000_ROM_CI_READ_WRITE_ADDR_LEN + bytesAfterPageBoundary},
289 __END_WRITE_CMD__};
290 /* Write Flash Bytes as Commands to Sensor. */
291 status = FXLC95000_I2C_FlashCommands(pBus, index, sAddress, cWriteFlashSequence);
292 if (ARM_DRIVER_OK != status)
293 {
294 return SENSOR_ERROR_WRITE;
295 }
296 }
297 }
298 else /* If write is enclosed within 1-page, a single CI_READ_WRITE will do the job. */
299 {
300 uint8_t writeFlashCommand[FXLC95000_ROM_CI_READ_WRITE_MAX_LEN] = {0x0A, 0x00, 0x12, 0x34, 0x56, 0x78};
301 writeFlashCommand[1] = /* Ref. Section 16.5 of FXLC95000CLHWRM. */
302 (*(pFlashBytes + 1) == 0) ? 0x1F & (numBytes - FXLC95000_FLASH_PAYLOAD_ADDR_LEN) :
303 0xC0 | (numBytes - FXLC95000_FLASH_PAYLOAD_ADDR_LEN);
304
305 for (int i = FXLC95000_ROM_CI_READ_WRITE_ADDR_LEN; i < numBytes; i++) // Skip 2 MSBs of Address.
306 {
307 writeFlashCommand[FXLC95000_ROM_CI_READ_WRITE_HDR_LEN + i - FXLC95000_ROM_CI_READ_WRITE_ADDR_LEN] =
308 pFlashBytes[i];
309 }
310 if (FXLC95000_ROM_CI_READ_WRITE_HDR_LEN + numBytes >
311 FXLC95000_ROM_CI_WRITE_MAX_LEN + FXLC95000_ROM_CI_READ_WRITE_ADDR_LEN)
312 {
313 return SENSOR_ERROR_INVALID_PARAM;
314 }
315 else
316 { /* Create Command List to Write. */
317 const registercommandlist_t cWriteFlashSequence[] = {
318 {writeFlashCommand, 0,
319 FXLC95000_ROM_CI_READ_WRITE_HDR_LEN + numBytes - FXLC95000_ROM_CI_READ_WRITE_ADDR_LEN},
320 __END_WRITE_CMD__};
321 /* Write Flash Bytes as Commands to Sensor. */
322 status = FXLC95000_I2C_FlashCommands(pBus, index, sAddress, cWriteFlashSequence);
323 if (ARM_DRIVER_OK != status)
324 {
325 return SENSOR_ERROR_WRITE;
326 }
327 }
328 }
329 }
330 else
331 {
332 return SENSOR_ERROR_INVALID_PARAM;
333 }
334
335 return SENSOR_ERROR_NONE;
336 }
337
FXLC95000_I2C_Initialize(fxlc95000_i2c_sensorhandle_t * pSensorHandle,ARM_DRIVER_I2C * pBus,uint8_t index,uint16_t sAddress,uint16_t buildId)338 int32_t FXLC95000_I2C_Initialize(fxlc95000_i2c_sensorhandle_t *pSensorHandle,
339 ARM_DRIVER_I2C *pBus,
340 uint8_t index,
341 uint16_t sAddress,
342 uint16_t buildId)
343 {
344 int32_t status;
345 uint16_t readNumber[2];
346
347 /*! Check the input parameters. */
348 if ((pSensorHandle == NULL) || (pBus == NULL))
349 {
350 return SENSOR_ERROR_INVALID_PARAM;
351 }
352
353 pSensorHandle->deviceInfo.deviceInstance = index;
354 pSensorHandle->deviceInfo.functionParam = NULL;
355 pSensorHandle->deviceInfo.idleFunction = NULL;
356
357 /* Verify if the I2C connection by writing command to Boot to flash and fetch Device Info.
358 * A matching Build Number confirms Sensor Identity and Firmware. */
359 Register_I2C_BlockWrite(pBus, &pSensorHandle->deviceInfo, sAddress, 0, BootToFlash, sizeof(BootToFlash));
360 BOARD_DELAY_ms(10); /* Allow time for the device to boot to Flash. */
361 Register_I2C_BlockWrite(pBus, &pSensorHandle->deviceInfo, sAddress, 0, GetDeviceInfoCmd, sizeof(GetDeviceInfoCmd));
362 BOARD_DELAY_ms(1);
363
364 status = Register_I2C_Read(pBus, &pSensorHandle->deviceInfo, sAddress, FXLC95000_BUILD_ID_OFFSET,
365 FXLC95000_BUILD_ID_SIZE + FXLC95000_PART_NUMBER_SIZE, (uint8_t *)&readNumber);
366 readNumber[0] = (readNumber[0] >> 8) | (readNumber[0] << 8);
367 readNumber[1] = (readNumber[1] >> 8) | (readNumber[1] << 8);
368 if (ARM_DRIVER_OK != status || readNumber[0] != buildId || readNumber[1] != FXLC95000_PART_NUMBER)
369 {
370 pSensorHandle->isInitialized = false;
371 return SENSOR_ERROR_INIT;
372 }
373
374 pSensorHandle->pCommDrv = pBus;
375 pSensorHandle->slaveAddress = sAddress;
376 pSensorHandle->isInitialized = true;
377
378 return SENSOR_ERROR_NONE;
379 }
380
FXLC95000_I2C_SetIdleTask(fxlc95000_i2c_sensorhandle_t * pSensorHandle,registeridlefunction_t idleTask,void * userParam)381 void FXLC95000_I2C_SetIdleTask(fxlc95000_i2c_sensorhandle_t *pSensorHandle,
382 registeridlefunction_t idleTask,
383 void *userParam)
384 {
385 pSensorHandle->deviceInfo.functionParam = userParam;
386 pSensorHandle->deviceInfo.idleFunction = idleTask;
387 }
388
FXLC95000_I2C_CommandResponse(fxlc95000_i2c_sensorhandle_t * pSensorHandle,const registercommandlist_t * pCommandList,const registerreadlist_t * pResponseList,uint8_t * pBuffer)389 int32_t FXLC95000_I2C_CommandResponse(fxlc95000_i2c_sensorhandle_t *pSensorHandle,
390 const registercommandlist_t *pCommandList,
391 const registerreadlist_t *pResponseList,
392 uint8_t *pBuffer)
393 {
394 int32_t status;
395
396 /*! Validate for the correct handle and register read list.*/
397 if (pSensorHandle == NULL || (pCommandList == NULL && pResponseList == NULL))
398 {
399 return SENSOR_ERROR_INVALID_PARAM;
400 }
401
402 /*! Check whether sensor handle is initialized before reading sensor data.*/
403 if (pSensorHandle->isInitialized != true)
404 {
405 return SENSOR_ERROR_INIT;
406 }
407
408 if (pCommandList != NULL)
409 { /* Write command to fetch configuration. */
410 status = Sensor_I2C_BlockWrite(pSensorHandle->pCommDrv, &pSensorHandle->deviceInfo, pSensorHandle->slaveAddress,
411 pCommandList, FXLC95000_COCO_ERROR_MASK);
412 if (ARM_DRIVER_OK != status)
413 {
414 return SENSOR_ERROR_WRITE;
415 }
416 }
417
418 if (pResponseList != NULL)
419 { /* Parse through the read list and read the data one by one */
420 status = Sensor_I2C_Read(pSensorHandle->pCommDrv, &pSensorHandle->deviceInfo, pSensorHandle->slaveAddress,
421 pResponseList, pBuffer);
422 if (ARM_DRIVER_OK != status)
423 {
424 return SENSOR_ERROR_READ;
425 }
426 }
427
428 return SENSOR_ERROR_NONE;
429 }
430