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