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