1 /*
2  * @brief LPC15xx I2C slave driver
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2014
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products.  This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights.  NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers.  This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #ifndef __I2CS_15XX_H_
33 #define __I2CS_15XX_H_
34 
35 #include "i2c_common_15xx.h"
36 
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40 
41 /** @defgroup I2CS_15XX CHIP: LPC15xx I2C slave-only driver
42  * @ingroup I2C_15XX
43  * This driver only works in slave mode.
44  * @{
45  */
46 
47 /** @brief I2C slave service start callback
48  * This callback is called from the I2C slave handler when an I2C slave address is
49  * received and needs servicing. It's used to indicate the start of a slave transfer
50  * that will happen on the slave bus.
51  */
52 typedef void (*SlaveXferStart)(uint8_t addr);
53 
54 /** @brief I2C slave send data callback
55  * This callback is called from the I2C slave handler when an I2C slave address needs
56  * data to send. Return 0 to NACK the master and terminate the transfer, or return
57  * a non-0 value with the value to send in *data.
58  */
59 typedef uint8_t (*SlaveXferSend)(uint8_t *data);
60 
61 /** @brief I2C slave receive data callback
62  * This callback is called from the I2C slave handler when an I2C slave address has
63  * receive data. Return 0 to NACK the master and terminate the transfer, or return
64  * a non-0 value to continue the transfer.
65  */
66 typedef uint8_t (*SlaveXferRecv)(uint8_t data);
67 
68 /** @brief I2C slave service done callback
69  * This callback is called from the I2C slave handler when an I2C slave address is
70  * received and needs servicing. It's used to indicate the start of a slave transfer
71  * that will happen on the slave bus.
72  */
73 typedef void (*SlaveXferDone)(void);
74 
75 /**
76  * Slave transfer are performed using 3 callbacks. These 3 callbacks handle most I2C
77  * slave transfer cases. When the slave is setup and a slave interrupt is receive
78  * and processed with the Chip_I2CS_XferHandler() function in the I2C interrupt handler,
79  * one of these 3 callbacks is called. The callbacks can be used for unsized transfers
80  * from the master.
81  *
82  * When an address is received, the SlaveXferAddr() callback is called with the
83  * received address. Only addresses enabled in the slave controller will be handled.
84  * The slave controller can support up to 4 slave addresses.
85  *
86  * If the master is going to perform a read operation, the SlaveXferSend() callback
87  * is called. Place the data byte to send in *data and return a non-0 value to the
88  * caller, or return 0 to NACK the master. (Note the master ACKS/NACKS to slave
89  * on reads, so this won't necessarily stop the slave transfer.)<br>
90  *
91  * If the master performs a write operation, the SlaveXferRecv() callback is called
92  * with the received data. Return a non-0 value to the caller, or return 0 to NACK
93  * the master.<br>
94  *
95  * Once the transfer completes, the SlaveXferDone() callback will be called.<br>
96  */
97 typedef struct {
98 	SlaveXferStart slaveStart;	/*!< Called when an matching I2C slave address is received */
99 	SlaveXferSend slaveSend;		/*!< Called when a byte is needed to send to master */
100 	SlaveXferRecv slaveRecv;		/*!< Called when a byte is received from master */
101 	SlaveXferDone slaveDone;		/*!< Called when a slave transfer is complete */
102 } I2CS_XFER_T;
103 
104 /**
105  * @brief	Enable I2C slave interface
106  * @param	pI2C	: Pointer to selected I2C peripheral
107  * @return	Nothing
108  * @note	Do not call this function until the slave interface is fully configured.
109  */
Chip_I2CS_Enable(LPC_I2C_T * pI2C)110 STATIC INLINE void Chip_I2CS_Enable(LPC_I2C_T *pI2C)
111 {
112 	pI2C->CFG = (pI2C->CFG & I2C_CFG_MASK) | I2C_CFG_SLVEN;
113 }
114 
115 /**
116  * @brief	Disable I2C slave interface
117  * @param	pI2C	: Pointer to selected I2C peripheral
118  * @return	Nothing
119  */
Chip_I2CS_Disable(LPC_I2C_T * pI2C)120 STATIC INLINE void Chip_I2CS_Disable(LPC_I2C_T *pI2C)
121 {
122 	pI2C->CFG = (pI2C->CFG & I2C_CFG_MASK) & ~I2C_CFG_SLVEN;
123 }
124 
125 /**
126  * @brief	Get I2C Status
127  * @param	pI2C	: Pointer to selected I2C peripheral
128  * @return	I2C Status register value
129  * @note	This function returns the value of the status register.
130  */
Chip_I2CS_GetStatus(LPC_I2C_T * pI2C)131 STATIC INLINE uint32_t Chip_I2CS_GetStatus(LPC_I2C_T *pI2C)
132 {
133 	return pI2C->STAT;
134 }
135 
136 /**
137  * @brief	Clear I2C status bits (slave)
138  * @param	pI2C	: Pointer to selected I2C peripheral
139  * @param clrStatus : Status bit to clear, must be I2C_STAT_SLVDESEL
140  * @return	Nothing
141  * @note	This function clears selected status flags.
142  */
Chip_I2CS_ClearStatus(LPC_I2C_T * pI2C,uint32_t clrStatus)143 STATIC INLINE void Chip_I2CS_ClearStatus(LPC_I2C_T *pI2C, uint32_t clrStatus)
144 {
145 	pI2C->STAT = clrStatus & I2C_STAT_SLVDESEL;
146 }
147 
148 /**
149  * @brief	Check if I2C slave is pending
150  * @param	pI2C	: Pointer to selected I2C peripheral
151  * @return	Returns TRUE if the slave is pending else returns FALSE
152  * @note
153  */
Chip_I2CS_IsSlavePending(LPC_I2C_T * pI2C)154 STATIC INLINE bool Chip_I2CS_IsSlavePending(LPC_I2C_T *pI2C)
155 {
156 	return (pI2C->STAT & I2C_STAT_SLVPENDING) != 0;
157 }
158 
159 /**
160  * @brief	Check if I2C slave is selected
161  * @param	pI2C	: Pointer to selected I2C peripheral
162  * @return	Returns TRUE if the slave is is selected, otherwise FALSE
163  * @note
164  */
Chip_I2CS_IsSlaveSelected(LPC_I2C_T * pI2C)165 STATIC INLINE bool Chip_I2CS_IsSlaveSelected(LPC_I2C_T *pI2C)
166 {
167 	return (pI2C->STAT & I2C_STAT_SLVSEL) != 0;
168 }
169 
170 /**
171  * @brief	Check if I2C slave is deselected
172  * @param	pI2C	: Pointer to selected I2C peripheral
173  * @return	Returns TRUE if the slave is is deselected, otherwise FALSE
174  * @note
175  */
Chip_I2CS_IsSlaveDeSelected(LPC_I2C_T * pI2C)176 STATIC INLINE bool Chip_I2CS_IsSlaveDeSelected(LPC_I2C_T *pI2C)
177 {
178 	return (pI2C->STAT & I2C_STAT_SLVDESEL) != 0;
179 }
180 
181 /**
182  * @brief	Get current state of the I2C slave
183  * @param	pI2C	: Pointer to selected I2C peripheral
184  * @return	slave State Code, a value of type I2C_STAT_SLVCODE_*
185  * @note	After the slave is pending this state code tells the reason
186  *        for slave pending.
187  */
Chip_I2CS_GetSlaveState(LPC_I2C_T * pI2C)188 STATIC INLINE uint32_t Chip_I2CS_GetSlaveState(LPC_I2C_T *pI2C)
189 {
190 	return (pI2C->STAT & I2C_STAT_SLVSTATE) >> 9;
191 }
192 
193 /**
194  * @brief	Returns the current slave address match index
195  * @param	pI2C	: Pointer to selected I2C peripheral
196  * @return	slave match index, 0 - 3
197  */
Chip_I2CS_GetSlaveMatchIndex(LPC_I2C_T * pI2C)198 STATIC INLINE uint32_t Chip_I2CS_GetSlaveMatchIndex(LPC_I2C_T *pI2C)
199 {
200 	return (pI2C->STAT & I2C_STAT_SLVIDX) >> 12;
201 }
202 
203 /**
204  * @brief	Slave Continue transfer operation (ACK)
205  * @param	pI2C	: Pointer to selected I2C peripheral
206  * @return	Nothing
207  * @note	This function sets the slave controller to continue transmission.
208  *				This should be called only when slave is pending. The function writes a
209  *				complete value to slave Control register, ORing is not advised.
210  */
Chip_I2CS_SlaveContinue(LPC_I2C_T * pI2C)211 STATIC INLINE void Chip_I2CS_SlaveContinue(LPC_I2C_T *pI2C)
212 {
213 	pI2C->SLVCTL = I2C_SLVCTL_SLVCONTINUE;
214 }
215 
216 /**
217  * @brief	Slave NACK operation
218  * @param	pI2C	: Pointer to selected I2C peripheral
219  * @return	Nothing
220  * @note	This function sets the slave controller to NAK the master.
221  */
Chip_I2CS_SlaveNACK(LPC_I2C_T * pI2C)222 STATIC INLINE void Chip_I2CS_SlaveNACK(LPC_I2C_T *pI2C)
223 {
224 	pI2C->SLVCTL = I2C_SLVCTL_SLVNACK;
225 }
226 
227 /**
228  * @brief	Transmit a single data byte through the I2C peripheral (slave)
229  * @param	pI2C	: Pointer to selected I2C peripheral
230  * @param	data	: Byte to transmit
231  * @return	Nothing
232  * @note	This function attempts to place a byte into the I2C slave
233  *			Data Register
234  *
235  */
Chip_I2CS_WriteByte(LPC_I2C_T * pI2C,uint8_t data)236 STATIC INLINE void Chip_I2CS_WriteByte(LPC_I2C_T *pI2C, uint8_t data)
237 {
238 	pI2C->SLVDAT = (uint32_t) data;
239 }
240 
241 /**
242  * @brief	Read a single byte data from the I2C peripheral (slave)
243  * @param	pI2C	: Pointer to selected I2C peripheral
244  * @return	A single byte of data read
245  * @note	This function reads a byte from the I2C receive hold register
246  *			regardless of I2C state.
247  */
Chip_I2CS_ReadByte(LPC_I2C_T * pI2C)248 STATIC INLINE uint8_t Chip_I2CS_ReadByte(LPC_I2C_T *pI2C)
249 {
250 	return (uint8_t) (pI2C->SLVDAT & I2C_SLVDAT_DATAMASK);
251 }
252 
253 /**
254  * @brief	Set a I2C slave address for slave operation
255  * @param	pI2C	: Pointer to selected I2C peripheral
256  * @param	slvNum	: Possible slave address number, between 0 - 3
257  * @param	slvAddr	: Slave Address for the index (7-bits, bit 7 = 0)
258  * @return	Nothing
259  * @note	Setting a slave address also enables the slave address. Do
260  * not 'pre-shift' the slave address.
261  */
Chip_I2CS_SetSlaveAddr(LPC_I2C_T * pI2C,uint8_t slvNum,uint8_t slvAddr)262 STATIC INLINE void Chip_I2CS_SetSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum, uint8_t slvAddr)
263 {
264 	pI2C->SLVADR[slvNum] = (uint32_t) (slvAddr << 1);
265 }
266 
267 /**
268  * @brief	Return a I2C programmed slave address
269  * @param	pI2C	: Pointer to selected I2C peripheral
270  * @param	slvNum	: Possible slave address number, between 0 - 3
271  * @return	Nothing
272  */
Chip_I2CS_GetSlaveAddr(LPC_I2C_T * pI2C,uint8_t slvNum)273 STATIC INLINE uint8_t Chip_I2CS_GetSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
274 {
275 	return (pI2C->SLVADR[slvNum] >> 1) & 0x7F;
276 }
277 
278 /**
279  * @brief	Enable a I2C address
280  * @param	pI2C	: Pointer to selected I2C peripheral
281  * @param	slvNum	: Possible slave address number, between 0 - 3
282  * @return	Nothing
283  */
Chip_I2CS_EnableSlaveAddr(LPC_I2C_T * pI2C,uint8_t slvNum)284 STATIC INLINE void Chip_I2CS_EnableSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
285 {
286 	pI2C->SLVADR[slvNum] = (pI2C->SLVADR[slvNum] & I2C_SLVADR_MASK) & ~I2C_SLVADR_SADISABLE;
287 }
288 
289 /**
290  * @brief	Disable a I2C address
291  * @param	pI2C	: Pointer to selected I2C peripheral
292  * @param	slvNum	: Possible slave address number, between 0 - 3
293  * @return	Nothing
294  */
Chip_I2CS_DisableSlaveAddr(LPC_I2C_T * pI2C,uint8_t slvNum)295 STATIC INLINE void Chip_I2CS_DisableSlaveAddr(LPC_I2C_T *pI2C, uint8_t slvNum)
296 {
297 	pI2C->SLVADR[slvNum] = (pI2C->SLVADR[slvNum] & I2C_SLVADR_MASK) | I2C_SLVADR_SADISABLE;
298 }
299 
300 /**
301  * @brief	Setup slave qialifier address
302  * @param	pI2C	: Pointer to selected I2C peripheral
303  * @param	extend	: true to extend I2C slave detect address 0 range, or false to match to corresponding bits
304  * @param	slvAddr	: Slave address qualifier, see SLVQUAL0 register in User Manual
305  * @return	Nothing
306  * @note	Do not 'pre-shift' the slave address.
307  */
Chip_I2CS_SetSlaveQual0(LPC_I2C_T * pI2C,bool extend,uint8_t slvNum)308 STATIC INLINE void Chip_I2CS_SetSlaveQual0(LPC_I2C_T *pI2C, bool extend, uint8_t slvNum)
309 {
310 	slvNum = slvNum << 1;
311 	if (extend) {
312 		slvNum |= I2C_SLVQUAL_QUALMODE0;
313 	}
314 
315 	pI2C->SLVQUAL0 = slvNum;
316 }
317 
318 /**
319  * @brief	Slave transfer state change handler
320  * @param	pI2C	: Pointer to selected I2C peripheral
321  * @param	xfers	: Pointer to a I2CS_MULTI_XFER_T structure see notes below
322  * @return	Returns non-zero value on completion of transfer
323  * @note	See @ref I2CS_XFER_T for more information on this function. When using
324  * this function, the I2C_INTENSET_SLVPENDING and I2C_INTENSET_SLVDESEL interrupts
325  * should be enabled and setup in the I2C interrupt handler to call this function
326  * when they fire.
327  */
328 uint32_t Chip_I2CS_XferHandler(LPC_I2C_T *pI2C, const I2CS_XFER_T *xfers);
329 
330 /**
331  * @}
332  */
333 
334  #ifdef __cplusplus
335 }
336 #endif
337 
338 #endif /* __I2CS_15XX_H_ */
339