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