]> git.proxmox.com Git - mirror_edk2.git/blame - Omap35xxPkg/SmbusDxe/Smbus.c
Omap35xxPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / Omap35xxPkg / SmbusDxe / Smbus.c
CommitLineData
1e57a462 1/** @file\r
2\r
3 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
3402aac7 4\r
538311f7 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
1e57a462 6\r
7**/\r
8\r
9#include <Uefi.h>\r
10#include <Omap3530/Omap3530.h>\r
11\r
12#include <Library/DebugLib.h>\r
13#include <Library/IoLib.h>\r
14#include <Library/UefiBootServicesTableLib.h>\r
15\r
16#include <Protocol/SmbusHc.h>\r
17\r
18#define MAX_RETRY 1000\r
19\r
20//\r
21// Internal Functions\r
22//\r
23STATIC\r
24EFI_STATUS\r
25WaitForBusBusy (\r
26 VOID\r
27 )\r
28{\r
29 UINTN Retry = 0;\r
30\r
31 while (++Retry < MAX_RETRY && (MmioRead16(I2C_STAT) & BB) == 0x1);\r
32\r
33 if (Retry == MAX_RETRY) {\r
34 return EFI_TIMEOUT;\r
35 }\r
36\r
37 return EFI_SUCCESS;\r
38}\r
39\r
40STATIC\r
41EFI_STATUS\r
42PollForStatus(\r
43 UINT16 StatusBit\r
44 )\r
45{\r
46 UINTN Retry = 0;\r
47\r
48 while(Retry < MAX_RETRY) {\r
49 if (MmioRead16(I2C_STAT) & StatusBit) {\r
50 //Clear particular status bit from Status register.\r
51 MmioOr16(I2C_STAT, StatusBit);\r
52 break;\r
53 }\r
54 Retry++;\r
55 }\r
56\r
57 if (Retry == MAX_RETRY) {\r
58 return EFI_TIMEOUT;\r
59 }\r
60\r
61 return EFI_SUCCESS;\r
62}\r
63\r
64STATIC\r
65EFI_STATUS\r
66ConfigureI2c (\r
67 VOID\r
68 )\r
69{\r
70 //Program prescaler to obtain 12-MHz clock\r
71 MmioWrite16(I2C_PSC, 0x0000);\r
72\r
3402aac7
RC
73 //Program SCLL and SCLH\r
74 //NOTE: Following values are the register dump after U-Boot code executed.\r
1e57a462 75 //We need to figure out how its calculated based on the I2C functional clock and I2C_PSC.\r
76 MmioWrite16(I2C_SCLL, 0x0035);\r
77 MmioWrite16(I2C_SCLH, 0x0035);\r
78\r
79 //Take the I2C controller out of reset.\r
80 MmioOr16(I2C_CON, I2C_EN);\r
81\r
82 //Initialize the I2C controller.\r
83\r
84 //Set I2C controller in Master mode.\r
85 MmioOr16(I2C_CON, MST);\r
86\r
87 //Enable interrupts for receive/transmit mode.\r
88 MmioOr16(I2C_IE, (XRDY_IE | RRDY_IE | ARDY_IE | NACK_IE));\r
89\r
90 return EFI_SUCCESS;\r
91}\r
92\r
93STATIC\r
94EFI_STATUS\r
95I2CReadOneByte (\r
96 UINT8 *Data\r
97 )\r
98{\r
99 EFI_STATUS Status;\r
100\r
101 //I2C bus status checking\r
102 Status = WaitForBusBusy();\r
103 if (EFI_ERROR(Status)) {\r
104 return Status;\r
105 }\r
106\r
107 //Poll till Receive ready bit is set.\r
108 Status = PollForStatus(RRDY);\r
109 if (EFI_ERROR(Status)) {\r
110 return Status;\r
111 }\r
112\r
113 *Data = MmioRead8(I2C_DATA);\r
114\r
115 return EFI_SUCCESS;\r
116}\r
117\r
118STATIC\r
119EFI_STATUS\r
120I2CWriteOneByte (\r
3402aac7 121 UINT8 Data\r
1e57a462 122 )\r
123{\r
124 EFI_STATUS Status;\r
125\r
126 //I2C bus status checking\r
127 Status = WaitForBusBusy();\r
128 if (EFI_ERROR(Status)) {\r
129 return Status;\r
130 }\r
131\r
132 //Data transfer\r
133 //Poll till Transmit ready bit is set\r
134 Status = PollForStatus(XRDY);\r
135 if (EFI_ERROR(Status)) {\r
136 return Status;\r
137 }\r
138\r
139 MmioWrite8(I2C_DATA, Data);\r
140\r
141 //Wait and check if the NACK is not set.\r
142 gBS->Stall(1000);\r
143 if (MmioRead16(I2C_STAT) & NACK) {\r
144 return EFI_DEVICE_ERROR;\r
145 }\r
146\r
147 return EFI_SUCCESS;\r
148}\r
149\r
150STATIC\r
151EFI_STATUS\r
152SmbusBlockRead (\r
153 OUT UINT8 *Buffer,\r
154 IN UINTN Length\r
155 )\r
156{\r
157 UINTN Index = 0;\r
158 EFI_STATUS Status = EFI_SUCCESS;\r
159\r
160 //Transfer configuration for receiving data.\r
161 MmioWrite16(I2C_CNT, Length);\r
162 //Need stop bit before sending data.\r
163 MmioWrite16(I2C_CON, (I2C_EN | MST | STP | STT));\r
164\r
165 while (Index < Length) {\r
166 //Read a byte\r
167 Status = I2CReadOneByte(&Buffer[Index++]);\r
168 if (EFI_ERROR(Status)) {\r
169 return Status;\r
170 }\r
171 }\r
172\r
173 //Transfer completion\r
174 Status = PollForStatus(ARDY);\r
175 if (EFI_ERROR(Status)) {\r
176 return Status;\r
177 }\r
178\r
179 return Status;\r
180}\r
181\r
182STATIC\r
183EFI_STATUS\r
184SmbusBlockWrite (\r
185 IN UINT8 *Buffer,\r
186 IN UINTN Length\r
187 )\r
188{\r
189 UINTN Index = 0;\r
190 EFI_STATUS Status = EFI_SUCCESS;\r
191\r
192 //Transfer configuration for transmitting data\r
193 MmioWrite16(I2C_CNT, Length);\r
194 MmioWrite16(I2C_CON, (I2C_EN | TRX | MST | STT | STP));\r
195\r
196 while (Index < Length) {\r
197 //Send a byte\r
198 Status = I2CWriteOneByte(Buffer[Index++]);\r
199 if (EFI_ERROR(Status)) {\r
200 return Status;\r
201 }\r
202 }\r
203\r
204 //Transfer completion\r
205 Status = PollForStatus(ARDY);\r
206 if (EFI_ERROR(Status)) {\r
207 return Status;\r
208 }\r
209\r
210 return Status;\r
211}\r
212\r
213//\r
214// Public Functions.\r
215//\r
216EFI_STATUS\r
217EFIAPI\r
218SmbusExecute (\r
219 IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
220 IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,\r
221 IN CONST EFI_SMBUS_DEVICE_COMMAND Command,\r
222 IN CONST EFI_SMBUS_OPERATION Operation,\r
223 IN CONST BOOLEAN PecCheck,\r
224 IN OUT UINTN *Length,\r
225 IN OUT VOID *Buffer\r
226 )\r
227{\r
228 UINT8 *ByteBuffer = Buffer;\r
229 EFI_STATUS Status = EFI_SUCCESS;\r
230 UINT8 SlaveAddr = (UINT8)(SlaveAddress.SmbusDeviceAddress);\r
231\r
232 if (PecCheck) {\r
233 return EFI_UNSUPPORTED;\r
234 }\r
235\r
236 if ((Operation != EfiSmbusWriteBlock) && (Operation != EfiSmbusReadBlock)) {\r
237 return EFI_UNSUPPORTED;\r
238 }\r
239\r
240 //Set the Slave address.\r
241 MmioWrite16(I2C_SA, SlaveAddr);\r
242\r
243 if (Operation == EfiSmbusReadBlock) {\r
244 Status = SmbusBlockRead(ByteBuffer, *Length);\r
245 } else if (Operation == EfiSmbusWriteBlock) {\r
246 Status = SmbusBlockWrite(ByteBuffer, *Length);\r
247 }\r
248\r
249 return Status;\r
250}\r
251\r
252EFI_STATUS\r
253EFIAPI\r
254SmbusArpDevice (\r
255 IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
256 IN BOOLEAN ArpAll,\r
257 IN EFI_SMBUS_UDID *SmbusUdid OPTIONAL,\r
258 IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress OPTIONAL\r
259 )\r
260{\r
261 return EFI_UNSUPPORTED;\r
262}\r
263\r
264\r
265EFI_STATUS\r
266EFIAPI\r
267SmbusGetArpMap (\r
268 IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
269 IN OUT UINTN *Length,\r
270 IN OUT EFI_SMBUS_DEVICE_MAP **SmbusDeviceMap\r
271 )\r
272{\r
273 return EFI_UNSUPPORTED;\r
274}\r
275\r
276\r
277EFI_STATUS\r
278EFIAPI\r
279SmbusNotify (\r
280 IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
281 IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,\r
282 IN CONST UINTN Data,\r
283 IN CONST EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction\r
284 )\r
285{\r
286 return EFI_UNSUPPORTED;\r
287}\r
288\r
289EFI_SMBUS_HC_PROTOCOL SmbusProtocol =\r
290{\r
291 SmbusExecute,\r
292 SmbusArpDevice,\r
293 SmbusGetArpMap,\r
294 SmbusNotify\r
295};\r
296\r
297EFI_STATUS\r
298InitializeSmbus (\r
299 IN EFI_HANDLE ImageHandle,\r
300 IN EFI_SYSTEM_TABLE *SystemTable\r
301 )\r
302{\r
303 EFI_HANDLE Handle = NULL;\r
304 EFI_STATUS Status;\r
305\r
306 //Configure I2C controller.\r
307 Status = ConfigureI2c();\r
308 if (EFI_ERROR(Status)) {\r
309 DEBUG ((EFI_D_ERROR, "InitializeI2c fails.\n"));\r
310 return Status;\r
311 }\r
312\r
313 // Install the SMBUS interface\r
314 Status = gBS->InstallMultipleProtocolInterfaces(&Handle, &gEfiSmbusHcProtocolGuid, &SmbusProtocol, NULL);\r
315 ASSERT_EFI_ERROR(Status);\r
3402aac7 316\r
1e57a462 317 return Status;\r
318}\r
319\r