4c6fe00dc83a9480fe86f7710ccc524a926dc3cb
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.
38 #include "dev/i2c/bus.hh"
40 #include "base/trace.hh"
41 #include "debug/Checkpoint.hh"
42 #include "dev/i2c/device.hh"
43 #include "mem/packet_access.hh"
45 // clang complains about std::set being overloaded with Packet::set if
46 // we open up the entire namespace std
52 * http://infocenter.arm.com/help/topic/com.arm.doc.dui0440b/Bbajihec.html
54 I2CBus::I2CBus(const I2CBusParams
&p
)
55 : BasicPioDevice(p
, 0x1000), scl(1), sda(1), state(IDLE
), currBit(7),
56 i2cAddr(0x00), message(0x00)
58 vector
<I2CDevice
*> devs
= p
.devices
;
60 for (auto d
: p
.devices
) {
61 devices
[d
->i2cAddr()] = d
;
66 * Reads will always be to SB_CONTROLS. The kernel wants to know the state
70 I2CBus::read(PacketPtr pkt
)
72 assert(pkt
->getAddr() == pioAddr
+ SB_CONTROLS
);
74 pkt
->setRaw
<uint8_t>((sda
<< 1) | scl
);
75 pkt
->makeAtomicResponse();
80 * The default i2c bus driver used by the realview pbx board writes to
81 * this device one bit at a time. To facilitate making new i2c devices,
82 * i2cBus::write takes care of the low-level details of the i2c protocol.
83 * See the I2C Specification [1] for a detailed description of the
86 * [1] - http://www.nxp.com/documents/user_manual/UM10204.pdf
89 I2CBus::write(PacketPtr pkt
)
91 assert(pkt
->getAddr() == pioAddr
+ SB_CONTROLS
||
92 pkt
->getAddr() == pioAddr
+ SB_CONTROLC
);
96 // Check if the bus master is starting a new transmission.
98 state
= RECEIVING_ADDR
;
101 /* Most i2c devices expect something special (e.g., command,
102 * register address) in the first byte they receive so they
103 * must be notified somehow that this is a new transmission.
105 for (auto& d
: devices
) {
106 d
.second
->i2cStart();
111 // Check if the bus master is ending a transmission.
117 // Only change state when the clock is transitioning from low to high.
118 // This may not perfectly mimic physical i2c devices but the important
119 // part is to only do the following once per clock cycle.
120 if (isClockSet(pkt
)) {
124 message
|= sda
<< currBit
;
127 i2cAddr
= message
>> 1;
128 assert(devices
.find(i2cAddr
) != devices
.end());
129 if (message
& 0x01) {
130 state
= SENDING_DATA
;
131 message
= devices
[i2cAddr
]->read();
133 state
= RECEIVING_DATA
;
142 message
|= sda
<< currBit
;
145 devices
[i2cAddr
]->write(message
);
153 sda
= (message
>> currBit
) & 0x01;
156 if (!sda
) /* Check for ack from the bus master. */
157 message
= devices
[i2cAddr
]->read();
163 panic("Invalid state on posedge of clock in I2CBus::write.\n");
172 I2CBus::updateSignals(PacketPtr pkt
)
174 uint8_t msg
= pkt
->getRaw
<uint8_t>();
175 Addr daddr
= pkt
->getAddr() - pioAddr
;
179 scl
= (msg
& 1) ? 1 : scl
;
180 sda
= (msg
& 2) ? 1 : sda
;
183 scl
= (msg
& 1) ? 0 : scl
;
184 sda
= (msg
& 2) ? 0 : sda
;
192 I2CBus::isClockSet(PacketPtr pkt
) const
194 uint8_t msg
= pkt
->getRaw
<uint8_t>();
195 Addr daddr
= pkt
->getAddr() - pioAddr
;
196 return daddr
== SB_CONTROLS
&& (msg
& 1);
200 I2CBus::isStart(PacketPtr pkt
) const
202 uint8_t msg
= pkt
->getRaw
<uint8_t>();
203 Addr daddr
= pkt
->getAddr() - pioAddr
;
204 return scl
&& (msg
& 2) && daddr
== SB_CONTROLC
;
208 I2CBus::isEnd(PacketPtr pkt
) const
210 uint8_t msg
= pkt
->getRaw
<uint8_t>();
211 Addr daddr
= pkt
->getAddr() - pioAddr
;
212 return scl
&& (msg
& 2) && daddr
== SB_CONTROLS
;
215 I2CBus::serialize(CheckpointOut
&cp
) const
217 DPRINTF(Checkpoint
, "Serializing I2C bus.\n");
218 SERIALIZE_SCALAR(scl
);
219 SERIALIZE_SCALAR(sda
);
220 SERIALIZE_ENUM(state
);
221 SERIALIZE_SCALAR(currBit
);
222 SERIALIZE_SCALAR(i2cAddr
);
223 SERIALIZE_SCALAR(message
);
227 I2CBus::unserialize(CheckpointIn
&cp
)
229 DPRINTF(Checkpoint
, "Unserializing I2C bus.\n");
230 UNSERIALIZE_SCALAR(scl
);
231 UNSERIALIZE_SCALAR(sda
);
232 UNSERIALIZE_ENUM(state
);
233 UNSERIALIZE_SCALAR(currBit
);
234 UNSERIALIZE_SCALAR(i2cAddr
);
235 UNSERIALIZE_SCALAR(message
);
239 I2CBusParams::create() const
241 return new I2CBus(*this);