--- /dev/null
+// See LICENSE for license details.
+package sifive.blocks.devices.i2c
+
+import Chisel._
+import config._
+import regmapper._
+import uncore.tilelink2._
+import rocketchip.PeripheryBusConfig
+import util.AsyncResetRegVec
+import sifive.blocks.devices.gpio.{GPIOPinCtrl}
+
+case class I2CConfig(address: BigInt)
+
+trait HasI2CParameters {
+ implicit val p: Parameters
+ val params: I2CConfig
+ val c = params
+}
+
+class I2CPin extends Bundle {
+ val in = Bool(INPUT)
+ val out = Bool(OUTPUT)
+ val oe = Bool(OUTPUT)
+}
+
+class I2CPort extends Bundle {
+ val scl = new I2CPin
+ val sda = new I2CPin
+}
+
+trait I2CBundle extends Bundle with HasI2CParameters {
+ val port = new I2CPort
+}
+
+trait I2CModule extends Module with HasI2CParameters with HasRegMap {
+ val io: I2CBundle
+
+ val prescaler_lo = Reg(UInt(8.W)) // low byte clock prescaler register
+ val prescaler_hi = Reg(UInt(8.W)) // high byte clock prescaler register
+ val control = Reg(UInt(8.W)) // control register
+ val data = Reg(UInt(8.W)) // write: transmit byte, read: receive byte
+ val cmd_status = Reg(UInt(8.W)) // write: command, read: status
+
+ // Note that these are out of order.
+ regmap(
+ I2CCtrlRegs.prescaler_lo -> Seq(RegField(8, prescaler_lo)),
+ I2CCtrlRegs.prescaler_hi -> Seq(RegField(8, prescaler_hi)),
+ I2CCtrlRegs.control -> Seq(RegField(8, control)),
+ I2CCtrlRegs.data -> Seq(RegField(8, data)),
+ I2CCtrlRegs.cmd_status -> Seq(RegField(8, cmd_status))
+ )
+}
+
+// Magic TL2 Incantation to create a TL2 Slave
+class TLI2C(c: I2CConfig)(implicit p: Parameters)
+ extends TLRegisterRouter(c.address, interrupts = 1, beatBytes = p(PeripheryBusConfig).beatBytes)(
+ new TLRegBundle(c, _) with I2CBundle)(
+ new TLRegModule(c, _, _) with I2CModule)
--- /dev/null
+// See LICENSE for license details.
+package sifive.blocks.devices.i2c
+
+// matching Open Cores I2C to re-use Linux driver
+// http://lxr.free-electrons.com/source/drivers/i2c/busses/i2c-ocores.c?v=4.6
+
+object I2CCtrlRegs {
+ val prescaler_lo = 0x00 // low byte clock prescaler register
+ val prescaler_hi = 0x01 // high byte clock prescaler register
+ val control = 0x02 // control register
+ val data = 0x03 // write: transmit byte, read: receive byte
+ val cmd_status = 0x04 // write: command, read: status
+}
--- /dev/null
+// See LICENSE for license details.
+package sifive.blocks.devices.i2c
+
+import Chisel._
+import diplomacy.LazyModule
+import rocketchip.{TopNetwork,TopNetworkModule}
+import uncore.tilelink2.TLFragmenter
+
+trait PeripheryI2C {
+ this: TopNetwork { val i2cConfigs: Seq[I2CConfig] } =>
+ val i2cDevices = i2cConfigs.zipWithIndex.map { case (c, i) =>
+ val i2c = LazyModule(new TLI2C(c))
+ i2c.suggestName(s"i2c$i")
+ i2c.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
+ intBus.intnode := i2c.intnode
+ i2c
+ }
+}
+
+trait PeripheryI2CBundle {
+ this: { val i2cConfigs: Seq[I2CConfig] } =>
+ val i2cs = Vec(i2cConfigs.size, new I2CPort)
+}
+
+trait PeripheryI2CModule {
+ this: TopNetworkModule {
+ val i2cConfigs: Seq[I2CConfig]
+ val outer: PeripheryI2C
+ val io: PeripheryI2CBundle
+ } =>
+ (io.i2cs zip outer.i2cDevices).foreach { case (io, device) =>
+ io <> device.module.io.port
+ }
+}
--- /dev/null
+// See LICENSE for license details.
+package sifive.blocks.devices.i2c
+
+import Chisel._
+import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl}
+import sifive.blocks.util.ShiftRegisterInit
+
+
+class I2CPinsIO extends Bundle {
+ val scl = new GPIOPin
+ val sda = new GPIOPin
+}
+
+class I2CGPIOPort(syncStages: Int = 0) extends Module {
+ val io = new Bundle{
+ val i2c = new I2CPort().flip()
+ val pins = new I2CPinsIO
+ }
+
+ GPIOOutputPinCtrl(io.pins.scl, io.i2c.scl.out, pue=true.B, ie = true.B)
+ io.pins.scl.o.oe := io.i2c.scl.oe
+ io.i2c.scl.in := ShiftRegisterInit(io.pins.scl.i.ival, syncStages, Bool(true))
+
+ GPIOOutputPinCtrl(io.pins.sda, io.i2c.sda.out, pue=true.B, ie = true.B)
+ io.pins.sda.o.oe := io.i2c.sda.oe
+ io.i2c.sda.in := ShiftRegisterInit(io.pins.sda.i.ival, syncStages, Bool(true))
+}