1 /*
2 * Copyright 2019 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 /*
9 * fsl_tfa9xxx_IMX.c
10 *
11 * IMX platform specific integration of tfa2_core code.
12 */
13
14 #include "fsl_tfa9xxx.h"
15 #include "stdarg.h"
16 #include "fsl_codec_i2c.h"
17 /*******************************************************************************
18 * Definitions
19 ******************************************************************************/
20
21 /*! @brief Message buffer used to communicate with TFA DSP. */
22 static uint8_t s_TFA_DSP_Message_Buffer[TFADSP_COMMAND_BUFFER_MAX_SIZE];
23
24 /* i2c_client used by the driver */
25 static struct i2c_client s_myclient[4] = {{0x34U, NULL, 0U}, {0x35U, NULL, 1U}, {0x36U, NULL, 2U}, {0x37U, NULL, 3U}};
26
27 typedef status_t (*tfa9xxx_codec_i2c_callback_t)(
28 void *handle, uint8_t deviceAddress, uint32_t subAddress, uint8_t subaddressSize, uint8_t *buff, uint8_t buffSize);
29 /*******************************************************************************
30 * Prototypes
31 ******************************************************************************/
32 void SysTick_DelayTicks(uint32_t n);
33
34 /*******************************************************************************
35 * Code
36 ******************************************************************************/
37
tfa2_i2c_trace(const char * str,unsigned addr,const char * buf,size_t buf_len)38 void tfa2_i2c_trace(const char *str, unsigned addr, const char *buf, size_t buf_len)
39 {
40 const char *p = buf;
41
42 TFA9XXX_Printf("%s [%d]: 0x%02x ", str, buf_len, addr);
43
44 if (buf && buf_len)
45 {
46 do
47 {
48 /* Print buffer item. For all items, aside last, terminate it with space */
49 TFA9XXX_Printf("0x%02x%c", (unsigned char)*p, ((buf_len - 1) ? ' ' : '\n'));
50 p++;
51 buf_len--;
52 } while (buf_len);
53 }
54 else
55 {
56 TFA9XXX_Printf("\n");
57 }
58 }
59
TFA9XXX_I2C_Transfer(tfa9xxx_codec_i2c_callback_t codec_i2c_callback,void * handle,uint8_t deviceAddress,uint32_t subAddress,uint8_t subaddressSize,uint8_t * buff,int buffSize)60 static status_t TFA9XXX_I2C_Transfer(tfa9xxx_codec_i2c_callback_t codec_i2c_callback,
61 void *handle,
62 uint8_t deviceAddress,
63 uint32_t subAddress,
64 uint8_t subaddressSize,
65 uint8_t *buff,
66 int buffSize)
67 {
68 status_t retval = kStatus_Success;
69 assert(buffSize >= 0);
70
71 uint8_t *transferAddress = buff;
72 uint32_t remainSize = buffSize;
73 uint8_t transferSize;
74 while (remainSize > 0)
75 {
76 transferSize = (remainSize > BOARD_I2C_TRANSFER_SIZE_MAX) ? BOARD_I2C_TRANSFER_SIZE_MAX : remainSize;
77 retval = codec_i2c_callback(handle, deviceAddress, subAddress, subaddressSize, transferAddress, transferSize);
78 if (retval != kStatus_Success)
79 {
80 return retval;
81 }
82 transferAddress += transferSize;
83 remainSize = buffSize - (transferAddress - buff);
84 }
85
86 return retval;
87 }
88
89 /* platform i2c */
90 /*!
91 * @brief Low level I2C write read function for TFA driver, should be implemented using platform specific I2C APIs
92 *
93 * @param client I2C client. For IMX codec implementation, client->hal will point to the tfa9xxx_handle_t->i2cHandle.
94 * @param wrlen Length of the data to write
95 * @param wrdata Buffer of write data
96 * @param rdlen Length of the data to read
97 * @param rddata Buffer of read data
98 * @return int Returns kStatus_Success if success, or negative value of error code in enum _lpi2c_status
99 */
tfa2_i2c_write_read_raw(struct i2c_client * client,int wrlen,uint8_t * wrdata,int rdlen,uint8_t * rddata)100 int tfa2_i2c_write_read_raw(struct i2c_client *client, int wrlen, uint8_t *wrdata, int rdlen, uint8_t *rddata)
101 {
102 uint16_t retval = kStatus_Success;
103
104 if (rdlen == 0 || rddata == NULL)
105 {
106 retval = TFA9XXX_I2C_Transfer(CODEC_I2C_Send, client->hal, client->addr, *wrdata, 1U, wrdata + 1U, wrlen - 1U);
107 }
108 else
109 {
110 retval = TFA9XXX_I2C_Transfer(CODEC_I2C_Send, client->hal, client->addr, 0, 0, wrdata, wrlen);
111 if (retval != kStatus_Success)
112 {
113 return -retval;
114 }
115 retval = TFA9XXX_I2C_Transfer(CODEC_I2C_Receive, client->hal, client->addr, 0, 0, rddata, rdlen);
116 if (retval != kStatus_Success)
117 {
118 return -retval;
119 }
120 }
121
122 return retval;
123 }
124
125 /*!
126 * @brief Low level I2C write function, wrapper for the tfa2_i2c_write_read_raw
127 *
128 * @param client I2C client
129 * @param len Length of the data to write
130 * @param data Pointer to the write data buffer
131 * @return int Returns kStatus_Success if success, or negative value of error code in enum _lpi2c_status
132 */
tfa2_i2c_write_raw(struct i2c_client * client,int len,const uint8_t * data)133 int tfa2_i2c_write_raw(struct i2c_client *client, int len, const uint8_t *data)
134 {
135 return tfa2_i2c_write_read_raw(client, len, (uint8_t *)data, 0, NULL);
136 }
137
138 /*****************************************************************************/
139 /*!
140 * @brief Get the pointer of the I2C client structure for given slave address.
141 *
142 * Depending on how ADS1 and ADS2 pins on TFA are connected physically, TFA supports 4 options of slave address: 0x34,
143 * 0x35, 0x36 or 0x37. The provided slave address will also be double checked with the container file.
144 *
145 * @param cnt Pointer of the container array.
146 * @param slaveAddress Device slave address.
147 * @return void* Returns the pointer of the I2C client structure, NULL if slaveAddress is not valid.
148 */
TFA9XXX_GetI2CClient(nxpTfaContainer_t * cnt,uint8_t slaveAddress)149 void *TFA9XXX_GetI2CClient(nxpTfaContainer_t *cnt, uint8_t slaveAddress)
150 {
151 if (slaveAddress < 0x34U || slaveAddress > 0x37U)
152 return NULL;
153
154 return &s_myclient[slaveAddress - 0x34U];
155 }
156
157 /*!
158 * @brief Wait function for the TFA
159 *
160 * User needs to implement below in the upper layer:
161 *
162 * //global volatile counter used for sleep/wait
163 * volatile uint32_t g_systickCounter;
164 *
165 * void SysTick_Handler(void)
166 * {
167 * if (g_systickCounter != 0U)
168 * {
169 * g_systickCounter--;
170 * }
171 * }
172 *
173 * void SysTick_DelayTicks(uint32_t n)
174 * {
175 * g_systickCounter = n;
176 * while(g_systickCounter != 0U)
177 * {
178 * }
179 * }
180 *
181 * void main(void)
182 * {
183 * ...
184 * //System Tick Configuration, generate 1ms interrupt
185 * SysTick_Config(SystemCoreClock / 1000U);
186 * ...
187 * //then initialize TFA
188 * }
189 *
190 * @param val Time to wait in terms of milliseconds
191 */
TFA9XXX_WaitMS(uint32_t val)192 void TFA9XXX_WaitMS(uint32_t val)
193 {
194 SysTick_DelayTicks(val);
195 }
196
197 /*!
198 * @brief Convert the return check value from TFA driver to predefined error code.
199 *
200 * If passing in fsl_common.h/enum _generic_status, it will be returned directly without any conversion.
201 *
202 * @param rc Return check value from TFA driver.
203 * @return status_t Returns error code from enum _tfa_error or enum _lpi2c_status.
204 */
TFA9XXX_ConvertErrorCode(int32_t rc)205 status_t TFA9XXX_ConvertErrorCode(int32_t rc)
206 {
207 switch (rc)
208 {
209 case kStatus_Success:
210 case kStatus_Fail:
211 case kStatus_ReadOnly:
212 case kStatus_OutOfRange:
213 case kStatus_InvalidArgument:
214 case kStatus_Timeout:
215 return rc; /* if input is already the predefined error code, return rc directly */
216 case -EINVAL:
217 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "EINVAL", "Invalid argument");
218 return kStatus_InvalidArgument;
219 case -EPERM:
220 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "EPERM", "Operation not permitted");
221 return kStatus_Fail;
222 case -ENODEV:
223 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "ENODEV", "No such device");
224 return kStatus_InvalidArgument;
225 case -ENOMEM:
226 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "ENOMEM", "Out of memory");
227 return kStatus_Fail;
228 case -ENXIO:
229 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "ENXIO", "No such device or address");
230 return kStatus_InvalidArgument;
231 case -ETIME:
232 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "ETIME", "Timer expired");
233 return kStatus_Timeout;
234 case -EIO:
235 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "EIO", "I/O error");
236 return kStatus_Fail;
237 case -ERANGE:
238 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "ERANGE",
239 "Math result not representable");
240 return kStatus_OutOfRange;
241 case -ETIMEDOUT:
242 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "ETIMEDOUT", "Connection timed out");
243 return kStatus_Timeout;
244 case -ENOENT:
245 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "ENOENT",
246 "No such file or directory");
247 return kStatus_InvalidArgument;
248 case -EFAULT:
249 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "EFAULT", "Bad address");
250 return kStatus_InvalidArgument;
251 case -E2BIG:
252 TFA9XXX_Printf("%s: error code: %s, description: %s\n", __FUNCTION__, "E2BIG", "Argument list too long");
253 return kStatus_InvalidArgument;
254 default:
255 TFA9XXX_Printf("Error code unknown: %d\n", rc);
256 return kStatus_Fail;
257 }
258 }
259
TFA9XXX_GetDSPMessageBuffer(void)260 uint8_t *TFA9XXX_GetDSPMessageBuffer(void)
261 {
262 memset(s_TFA_DSP_Message_Buffer, 0, TFADSP_COMMAND_BUFFER_MAX_SIZE);
263 return s_TFA_DSP_Message_Buffer;
264 }
265
TFA9XXX_NOP(const char * format,...)266 void TFA9XXX_NOP(const char *format, ...)
267 {
268 }
269