2 * Copyright (c) 2012 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 #include "dev/i2c/bus.hh"
42 #include "debug/Checkpoint.hh"
43 #include "dev/i2c/device.hh"
44 #include "mem/packet_access.hh"
46 // clang complains about std::set being overloaded with Packet::set if
47 // we open up the entire namespace std
53 * http://infocenter.arm.com/help/topic/com.arm.doc.dui0440b/Bbajihec.html
55 I2CBus::I2CBus(const I2CBusParams
*p
)
56 : BasicPioDevice(p
, 0x1000), scl(1), sda(1), state(IDLE
), currBit(7),
57 i2cAddr(0x00), message(0x00)
59 vector
<I2CDevice
*> devs
= p
->devices
;
61 for (auto d
: p
->devices
) {
62 devices
[d
->i2cAddr()] = d
;
67 * Reads will always be to SB_CONTROLS. The kernel wants to know the state
71 I2CBus::read(PacketPtr pkt
)
73 assert(pkt
->getAddr() == pioAddr
+ SB_CONTROLS
);
75 pkt
->set
<uint8_t>((sda
<< 1) | scl
);
76 pkt
->makeAtomicResponse();
81 * The default i2c bus driver used by the realview pbx board writes to
82 * this device one bit at a time. To facilitate making new i2c devices,
83 * i2cBus::write takes care of the low-level details of the i2c protocol.
84 * See the I2C Specification [1] for a detailed description of the
87 * [1] - http://www.nxp.com/documents/user_manual/UM10204.pdf
90 I2CBus::write(PacketPtr pkt
)
92 assert(pkt
->getAddr() == pioAddr
+ SB_CONTROLS
||
93 pkt
->getAddr() == pioAddr
+ SB_CONTROLC
);
97 // Check if the bus master is starting a new transmission.
99 state
= RECEIVING_ADDR
;
102 /* Most i2c devices expect something special (e.g., command,
103 * register address) in the first byte they receive so they
104 * must be notified somehow that this is a new transmission.
106 for (auto& d
: devices
) {
107 d
.second
->i2cStart();
112 // Check if the bus master is ending a transmission.
118 // Only change state when the clock is transitioning from low to high.
119 // This may not perfectly mimic physical i2c devices but the important
120 // part is to only do the following once per clock cycle.
121 if (isClockSet(pkt
)) {
125 message
|= sda
<< currBit
;
128 i2cAddr
= message
>> 1;
129 assert(devices
.find(i2cAddr
) != devices
.end());
130 if (message
& 0x01) {
131 state
= SENDING_DATA
;
132 message
= devices
[i2cAddr
]->read();
134 state
= RECEIVING_DATA
;
143 message
|= sda
<< currBit
;
146 devices
[i2cAddr
]->write(message
);
154 sda
= (message
>> currBit
) & 0x01;
157 if (!sda
) /* Check for ack from the bus master. */
158 message
= devices
[i2cAddr
]->read();
164 panic("Invalid state on posedge of clock in I2CBus::write.\n");
173 I2CBus::updateSignals(PacketPtr pkt
)
175 uint8_t msg
= pkt
->get
<uint8_t>();
176 Addr daddr
= pkt
->getAddr() - pioAddr
;
180 scl
= (msg
& 1) ? 1 : scl
;
181 sda
= (msg
& 2) ? 1 : sda
;
184 scl
= (msg
& 1) ? 0 : scl
;
185 sda
= (msg
& 2) ? 0 : sda
;
193 I2CBus::isClockSet(PacketPtr pkt
) const
195 uint8_t msg
= pkt
->get
<uint8_t>();
196 Addr daddr
= pkt
->getAddr() - pioAddr
;
197 return daddr
== SB_CONTROLS
&& (msg
& 1);
201 I2CBus::isStart(PacketPtr pkt
) const
203 uint8_t msg
= pkt
->get
<uint8_t>();
204 Addr daddr
= pkt
->getAddr() - pioAddr
;
205 return scl
&& (msg
& 2) && daddr
== SB_CONTROLC
;
209 I2CBus::isEnd(PacketPtr pkt
) const
211 uint8_t msg
= pkt
->get
<uint8_t>();
212 Addr daddr
= pkt
->getAddr() - pioAddr
;
213 return scl
&& (msg
& 2) && daddr
== SB_CONTROLS
;
216 I2CBus::serialize(CheckpointOut
&cp
) const
218 DPRINTF(Checkpoint
, "Serializing I2C bus.\n");
219 SERIALIZE_SCALAR(scl
);
220 SERIALIZE_SCALAR(sda
);
221 SERIALIZE_ENUM(state
);
222 SERIALIZE_SCALAR(currBit
);
223 SERIALIZE_SCALAR(i2cAddr
);
224 SERIALIZE_SCALAR(message
);
228 I2CBus::unserialize(CheckpointIn
&cp
)
230 DPRINTF(Checkpoint
, "Unserializing I2C bus.\n");
231 UNSERIALIZE_SCALAR(scl
);
232 UNSERIALIZE_SCALAR(sda
);
233 UNSERIALIZE_ENUM(state
);
234 UNSERIALIZE_SCALAR(currBit
);
235 UNSERIALIZE_SCALAR(i2cAddr
);
236 UNSERIALIZE_SCALAR(message
);
240 I2CBusParams::create()
242 return new I2CBus(this);