1 /*
2  * @brief LPC15xx I2C master 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 #include "chip.h"
33 
34 /*****************************************************************************
35  * Private types/enumerations/variables
36  ****************************************************************************/
37 
38 /*****************************************************************************
39  * Public types/enumerations/variables
40  ****************************************************************************/
41 
42 /*****************************************************************************
43  * Private functions
44  ****************************************************************************/
45 
46 /*****************************************************************************
47  * Public functions
48  ****************************************************************************/
49 
50 /* Set up bus speed for LPC_I2C interface */
Chip_I2CM_SetBusSpeed(LPC_I2C_T * pI2C,uint32_t busSpeed)51 void Chip_I2CM_SetBusSpeed(LPC_I2C_T *pI2C, uint32_t busSpeed)
52 {
53 	uint32_t scl = Chip_Clock_GetMainClockRate() / (Chip_I2C_GetClockDiv(pI2C) * busSpeed);
54 	Chip_I2CM_SetDutyCycle(pI2C, (scl >> 1), (scl - (scl >> 1)));
55 }
56 
57 /* Master transfer state change handler handler */
Chip_I2CM_XferHandler(LPC_I2C_T * pI2C,I2CM_XFER_T * xfer)58 uint32_t Chip_I2CM_XferHandler(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
59 {
60 	uint32_t status = Chip_I2CM_GetStatus(pI2C);
61 	/* Master Lost Arbitration */
62 	if (status & I2C_STAT_MSTRARBLOSS) {
63 		/* Set transfer status as Arbitration Lost */
64 		xfer->status = I2CM_STATUS_ARBLOST;
65 		/* Clear Status Flags */
66 		Chip_I2CM_ClearStatus(pI2C, I2C_STAT_MSTRARBLOSS);
67 	}
68 	/* Master Start Stop Error */
69 	else if (status & I2C_STAT_MSTSTSTPERR) {
70 		/* Set transfer status as Bus Error */
71 		xfer->status = I2CM_STATUS_BUS_ERROR;
72 		/* Clear Status Flags */
73 		Chip_I2CM_ClearStatus(pI2C, I2C_STAT_MSTSTSTPERR);
74 	}
75 	/* Master is Pending */
76 	else if (status & I2C_STAT_MSTPENDING) {
77 		/* Branch based on Master State Code */
78 		switch (Chip_I2CM_GetMasterState(pI2C)) {
79 		/* Master idle */
80 		case I2C_STAT_MSTCODE_IDLE:
81 			/* Do Nothing */
82 			break;
83 
84 		/* Receive data is available */
85 		case I2C_STAT_MSTCODE_RXREADY:
86 			/* Read Data */
87 			*xfer->rxBuff++ = pI2C->MSTDAT;
88 			xfer->rxSz--;
89 			if (xfer->rxSz) {
90 				/* Set Continue if there is more data to read */
91 				Chip_I2CM_MasterContinue(pI2C);
92 			}
93 			else {
94 				/* Set transfer status as OK */
95 				xfer->status = I2CM_STATUS_OK;
96 				/* No data to read send Stop */
97 				Chip_I2CM_SendStop(pI2C);
98 			}
99 			break;
100 
101 		/* Master Transmit available */
102 		case I2C_STAT_MSTCODE_TXREADY:
103 			if (xfer->txSz) {
104 				/* If Tx data available transmit data and continue */
105 				pI2C->MSTDAT = *xfer->txBuff++;
106 				xfer->txSz--;
107 				Chip_I2CM_MasterContinue(pI2C);
108 			}
109 			else {
110 				/* If receive queued after transmit then initiate master receive transfer*/
111 				if (xfer->rxSz) {
112 					/* Write Address and RW bit to data register */
113 					Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1) | 0x1);
114 					/* Enter to Master Transmitter mode */
115 					Chip_I2CM_SendStart(pI2C);
116 				}
117 				else {
118 					/* If no receive queued then set transfer status as OK */
119 					xfer->status = I2CM_STATUS_OK;
120 					/* Send Stop */
121 					Chip_I2CM_SendStop(pI2C);
122 				}
123 			}
124 			break;
125 
126 		case I2C_STAT_MSTCODE_NACKADR:
127 			/* Set transfer status as NACK on address */
128 			xfer->status = I2CM_STATUS_NAK_ADR;
129 			Chip_I2CM_SendStop(pI2C);
130 			break;
131 
132 		case I2C_STAT_MSTCODE_NACKDAT:
133 			/* Set transfer status as NACK on data */
134 			xfer->status = I2CM_STATUS_NAK_DAT;
135 			Chip_I2CM_SendStop(pI2C);
136 			break;
137 
138 		default:
139 			/* Default case should not occur*/
140 			xfer->status = I2CM_STATUS_ERROR;
141 			break;
142 		}
143 	}
144 	else {
145 		/* Default case should not occur */
146 		xfer->status = I2CM_STATUS_ERROR;
147 	}
148 	return xfer->status != I2CM_STATUS_BUSY;
149 }
150 
151 /* Transmit and Receive data in master mode */
Chip_I2CM_Xfer(LPC_I2C_T * pI2C,I2CM_XFER_T * xfer)152 void Chip_I2CM_Xfer(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
153 {
154 	/* set the transfer status as busy */
155 	xfer->status = I2CM_STATUS_BUSY;
156 	/* Clear controller state. */
157 	Chip_I2CM_ClearStatus(pI2C, I2C_STAT_MSTRARBLOSS | I2C_STAT_MSTSTSTPERR);
158 	/* Write Address and RW bit to data register */
159 	Chip_I2CM_WriteByte(pI2C, (xfer->slaveAddr << 1) | (xfer->txSz == 0));
160 	/* Enter to Master Transmitter mode */
161 	Chip_I2CM_SendStart(pI2C);
162 }
163 
164 /* Transmit and Receive data in master mode */
Chip_I2CM_XferBlocking(LPC_I2C_T * pI2C,I2CM_XFER_T * xfer)165 uint32_t Chip_I2CM_XferBlocking(LPC_I2C_T *pI2C, I2CM_XFER_T *xfer)
166 {
167 	uint32_t ret = 0;
168 	/* start transfer */
169 	Chip_I2CM_Xfer(pI2C, xfer);
170 
171 	while (ret == 0) {
172 		/* wait for status change interrupt */
173 		while (!Chip_I2CM_IsMasterPending(pI2C)) {}
174 		/* call state change handler */
175 		ret = Chip_I2CM_XferHandler(pI2C, xfer);
176 	}
177 	return ret;
178 }
179