VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.c@ 98103

Last change on this file since 98103 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.9 KB
Line 
1/* $Id: VBoxVgaI2c.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBoxVgaI2c.c
4 */
5
6/*
7 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37/*
38 This code is based on:
39
40 I2C Bus implementation upon CirrusLogic.
41
42 Copyright (c) 2008 - 2009, Intel Corporation
43 All rights reserved. This program and the accompanying materials
44 are licensed and made available under the terms and conditions of the BSD License
45 which accompanies this distribution. The full text of the license may be found at
46 http://opensource.org/licenses/bsd-license.php
47
48 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
49 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
50
51*/
52
53#include "VBoxVga.h"
54#include "VBoxVgaI2c.h"
55
56#define SEQ_ADDRESS_REGISTER 0x3c4
57#define SEQ_DATA_REGISTER 0x3c5
58
59#define I2C_CONTROL 0x08
60#define I2CDAT_IN 7
61#define I2CCLK_IN 2
62#define I2CDAT_OUT 1
63#define I2CCLK_OUT 0
64
65#define I2C_BUS_SPEED 100 //100kbps
66
67/**
68 PCI I/O byte write function.
69
70 @param PciIo The pointer to PCI_IO_PROTOCOL.
71 @param Address The bit map of I2C Data or I2C Clock pins.
72 @param Data The date to write.
73
74**/
75VOID
76I2cOutb (
77 EFI_PCI_IO_PROTOCOL *PciIo,
78 UINTN Address,
79 UINT8 Data
80 )
81{
82 PciIo->Io.Write (
83 PciIo,
84 EfiPciIoWidthUint8,
85 EFI_PCI_IO_PASS_THROUGH_BAR,
86 Address,
87 1,
88 &Data
89 );
90}
91/**
92 PCI I/O byte read function.
93
94 @param PciIo The pointer to PCI_IO_PROTOCOL.
95 @param Address The bit map of I2C Data or I2C Clock pins.
96
97 return byte value read from PCI I/O space.
98
99**/
100UINT8
101I2cInb (
102 EFI_PCI_IO_PROTOCOL *PciIo,
103 UINTN Address
104 )
105{
106 UINT8 Data;
107
108 PciIo->Io.Read (
109 PciIo,
110 EfiPciIoWidthUint8,
111 EFI_PCI_IO_PASS_THROUGH_BAR,
112 Address,
113 1,
114 &Data
115 );
116 return Data;
117}
118
119/**
120 Read status of I2C Data and I2C Clock Pins.
121
122 @param PciIo The pointer to PCI_IO_PROTOCOL.
123 @param Blt The bit map of I2C Data or I2C Clock pins.
124
125 @retval 0 Low on I2C Data or I2C Clock Pin.
126 @retval 1 High on I2C Data or I2C Clock Pin.
127
128**/
129UINT8
130I2cPinRead (
131 EFI_PCI_IO_PROTOCOL *PciIo,
132 UINT8 Bit
133 )
134{
135 I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);
136 return (UINT8) ((I2cInb (PciIo, SEQ_DATA_REGISTER) >> Bit ) & 0xfe);
137}
138
139
140/**
141 Set/Clear I2C Data and I2C Clock Pins.
142
143 @param PciIo The pointer to PCI_IO_PROTOCOL.
144 @param Blt The bit map to controller I2C Data or I2C Clock pins.
145 @param Value 1 or 0 stands for Set or Clear I2C Data and I2C Clock Pins.
146
147**/
148VOID
149I2cPinWrite (
150 EFI_PCI_IO_PROTOCOL *PciIo,
151 UINT8 Bit,
152 UINT8 Value
153 )
154{
155 UINT8 Byte;
156 I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);
157 Byte = (UINT8) (I2cInb (PciIo, SEQ_DATA_REGISTER) & (UINT8) ~(1 << Bit)) ;
158 Byte = (UINT8) (Byte | ((Value & 0x01) << Bit));
159 I2cOutb (PciIo, SEQ_DATA_REGISTER, (UINT8) (Byte | 0x40));
160 return;
161}
162
163/**
164 Read/write delay according to I2C Bus Speed.
165
166**/
167VOID
168I2cDelay (
169 VOID
170 )
171{
172 MicroSecondDelay (1000 / I2C_BUS_SPEED);
173}
174
175/**
176 Write a 8-bit data onto I2C Data Pin.
177
178 @param PciIo The pointer to PCI_IO_PROTOCOL.
179 @param Data The byte data to write.
180
181**/
182VOID
183I2cSendByte (
184 EFI_PCI_IO_PROTOCOL *PciIo,
185 UINT8 Data
186 )
187{
188 UINTN Index;
189 //
190 // Send byte data onto I2C Bus
191 //
192 for (Index = 0; Index < 8; Index --) {
193 I2cPinWrite (PciIo, I2CDAT_OUT, (UINT8) (Data >> (7 - Index)));
194 I2cPinWrite (PciIo, I2CCLK_OUT, 1);
195 I2cDelay ();
196 I2cPinWrite (PciIo, I2CCLK_OUT, 0);
197 }
198}
199
200/**
201 Read a 8-bit data from I2C Data Pin.
202
203 @param PciIo The pointer to PCI_IO_PROTOCOL.
204
205 Return the byte data read from I2C Data Pin.
206**/
207UINT8
208I2cReceiveByte (
209 EFI_PCI_IO_PROTOCOL *PciIo
210 )
211{
212 UINT8 Data;
213 UINTN Index;
214
215 Data = 0;
216 //
217 // Read byte data from I2C Bus
218 //
219 for (Index = 0; Index < 8; Index --) {
220 I2cPinWrite (PciIo, I2CCLK_OUT, 1);
221 I2cDelay ();
222 Data = (UINT8) (Data << 1);
223 Data = (UINT8) (Data | I2cPinRead (PciIo, I2CDAT_IN));
224 I2cPinWrite (PciIo, I2CCLK_OUT, 0);
225 }
226
227 return Data;
228}
229
230/**
231 Receive an ACK signal from I2C Bus.
232
233 @param PciIo The pointer to PCI_IO_PROTOCOL.
234
235**/
236BOOLEAN
237I2cWaitAck (
238 EFI_PCI_IO_PROTOCOL *PciIo
239 )
240{
241 //
242 // Wait for ACK signal
243 //
244 I2cPinWrite (PciIo, I2CDAT_OUT, 1);
245 I2cPinWrite (PciIo, I2CCLK_OUT, 1);
246 I2cDelay ();
247 if (I2cPinRead (PciIo, I2CDAT_IN) == 0) {
248 I2cPinWrite (PciIo, I2CDAT_OUT, 1);
249 return TRUE;
250 } else {
251 return FALSE;
252 }
253}
254
255/**
256 Send an ACK signal onto I2C Bus.
257
258 @param PciIo The pointer to PCI_IO_PROTOCOL.
259
260**/
261VOID
262I2cSendAck (
263 EFI_PCI_IO_PROTOCOL *PciIo
264 )
265{
266 I2cPinWrite (PciIo, I2CCLK_OUT, 1);
267 I2cPinWrite (PciIo, I2CDAT_OUT, 1);
268 I2cPinWrite (PciIo, I2CDAT_OUT, 0);
269 I2cPinWrite (PciIo, I2CCLK_OUT, 0);
270}
271
272/**
273 Start a I2C transfer on I2C Bus.
274
275 @param PciIo The pointer to PCI_IO_PROTOCOL.
276
277**/
278VOID
279I2cStart (
280 EFI_PCI_IO_PROTOCOL *PciIo
281 )
282{
283 //
284 // Init CLK and DAT pins
285 //
286 I2cPinWrite (PciIo, I2CCLK_OUT, 1);
287 I2cPinWrite (PciIo, I2CDAT_OUT, 1);
288 //
289 // Start a I2C transfer, set SDA low from high, when SCL is high
290 //
291 I2cPinWrite (PciIo, I2CDAT_OUT, 0);
292 I2cPinWrite (PciIo, I2CCLK_OUT, 0);
293}
294
295/**
296 Stop a I2C transfer on I2C Bus.
297
298 @param PciIo The pointer to PCI_IO_PROTOCOL.
299
300**/
301VOID
302I2cStop (
303 EFI_PCI_IO_PROTOCOL *PciIo
304 )
305{
306 //
307 // Stop a I2C transfer, set SDA high from low, when SCL is high
308 //
309 I2cPinWrite (PciIo, I2CDAT_OUT, 0);
310 I2cPinWrite (PciIo, I2CCLK_OUT, 1);
311 I2cPinWrite (PciIo, I2CDAT_OUT, 1);
312}
313
314/**
315 Read one byte data on I2C Bus.
316
317 Read one byte data from the slave device connected to I2C Bus.
318 If Data is NULL, then ASSERT().
319
320 @param PciIo The pointer to PCI_IO_PROTOCOL.
321 @param DeviceAddress Slave device's address.
322 @param RegisterAddress The register address on slave device.
323 @param Data The pointer to returned data if EFI_SUCCESS returned.
324
325 @retval EFI_DEVICE_ERROR
326 @retval EFI_SUCCESS
327
328**/
329EFI_STATUS
330EFIAPI
331I2cReadByte (
332 EFI_PCI_IO_PROTOCOL *PciIo,
333 UINT8 DeviceAddress,
334 UINT8 RegisterAddress,
335 UINT8 *Data
336 )
337{
338 ASSERT (Data != NULL);
339
340 //
341 // Start I2C transfer
342 //
343 I2cStart (PciIo);
344
345 //
346 // Send slave address with enabling write flag
347 //
348 I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));
349
350 //
351 // Wait for ACK signal
352 //
353 if (I2cWaitAck (PciIo) == FALSE) {
354 return EFI_DEVICE_ERROR;
355 }
356
357 //
358 // Send register address
359 //
360 I2cSendByte (PciIo, RegisterAddress);
361
362 //
363 // Wait for ACK signal
364 //
365 if (I2cWaitAck (PciIo) == FALSE) {
366 return EFI_DEVICE_ERROR;
367 }
368
369 //
370 // Send slave address with enabling read flag
371 //
372 I2cSendByte (PciIo, (UINT8) (DeviceAddress | 0x01));
373
374 //
375 // Wait for ACK signal
376 //
377 if (I2cWaitAck (PciIo) == FALSE) {
378 return EFI_DEVICE_ERROR;
379 }
380
381 //
382 // Read byte data from I2C Bus
383 //
384 *Data = I2cReceiveByte (PciIo);
385
386 //
387 // Send ACK signal onto I2C Bus
388 //
389 I2cSendAck (PciIo);
390
391 //
392 // Stop a I2C transfer
393 //
394 I2cStop (PciIo);
395
396 return EFI_SUCCESS;
397}
398
399/**
400 Write one byte data onto I2C Bus.
401
402 Write one byte data to the slave device connected to I2C Bus.
403 If Data is NULL, then ASSERT().
404
405 @param PciIo The pointer to PCI_IO_PROTOCOL.
406 @param DeviceAddress Slave device's address.
407 @param RegisterAddress The register address on slave device.
408 @param Data The pointer to write data.
409
410 @retval EFI_DEVICE_ERROR
411 @retval EFI_SUCCESS
412
413**/
414EFI_STATUS
415EFIAPI
416I2cWriteByte (
417 EFI_PCI_IO_PROTOCOL *PciIo,
418 UINT8 DeviceAddress,
419 UINT8 RegisterAddress,
420 UINT8 *Data
421 )
422{
423 ASSERT (Data != NULL);
424
425 I2cStart (PciIo);
426 //
427 // Send slave address with enabling write flag
428 //
429 I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));
430
431 //
432 // Wait for ACK signal
433 //
434 if (I2cWaitAck (PciIo) == FALSE) {
435 return EFI_DEVICE_ERROR;
436 }
437
438 //
439 // Send register address
440 //
441 I2cSendByte (PciIo, RegisterAddress);
442
443 //
444 // Wait for ACK signal
445 //
446 if (I2cWaitAck (PciIo) == FALSE) {
447 return EFI_DEVICE_ERROR;
448 }
449
450 //
451 // Send byte data onto I2C Bus
452 //
453 I2cSendByte (PciIo, *Data);
454
455 //
456 // Wait for ACK signal
457 //
458 if (I2cWaitAck (PciIo) == FALSE) {
459 return EFI_DEVICE_ERROR;
460 }
461
462 //
463 // Stop a I2C transfer
464 //
465 I2cStop (PciIo);
466
467 return EFI_SUCCESS;
468}
469
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette