github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/nxp/i2c/i2c.go (about) 1 // NXP I2C driver 2 // https://github.com/usbarmory/tamago 3 // 4 // Copyright (c) WithSecure Corporation 5 // https://foundry.withsecure.com 6 // 7 // Use of this source code is governed by the license 8 // that can be found in the LICENSE file. 9 10 // Package i2c implements a driver for NXP I2C controllers adopting the 11 // following reference specifications: 12 // - IMX6ULLRM - i.MX 6ULL Applications Processor Reference Manual - Rev 1 2017/11 13 // - IMX6FG - i.MX 6 Series Firmware Guide - Rev 0 2012/11 14 // 15 // This package is only meant to be used with `GOOS=tamago GOARCH=arm` as 16 // supported by the TamaGo framework for bare metal Go on ARM SoCs, see 17 // https://github.com/usbarmory/tamago. 18 package i2c 19 20 import ( 21 "errors" 22 "sync" 23 "time" 24 25 "github.com/usbarmory/tamago/internal/reg" 26 ) 27 28 // I2C registers 29 // (p1462, 31.7 I2C Memory Map/Register Definition, IMX6ULLRM) 30 const ( 31 // The default IFDR value corresponds to a frequency divider of 768, 32 // assuming 66 MHz for PERCLK_CLK_ROOT this results in a baud rate of 33 // 85 kbps (p1464, 31.7.2 I2C Frequency Divider Register (I2Cx_IFDR), 34 // IMX6ULLRM). 35 I2C_DEFAULT_IFDR = 0x16 36 37 I2Cx_IADR = 0x0000 38 I2Cx_IFDR = 0x0004 39 40 I2Cx_I2CR = 0x0008 41 I2CR_IEN = 7 42 I2CR_MSTA = 5 43 I2CR_MTX = 4 44 I2CR_TXAK = 3 45 I2CR_RSTA = 2 46 47 I2Cx_I2SR = 0x000c 48 I2SR_IBB = 5 49 I2SR_IIF = 1 50 I2SR_RXAK = 0 51 52 I2Cx_I2DR = 0x0010 53 ) 54 55 // Configuration constants 56 const ( 57 // Timeout is the default timeout for I2C operations. 58 Timeout = 100 * time.Millisecond 59 ) 60 61 // I2C represents an I2C port instance. 62 type I2C struct { 63 sync.Mutex 64 65 // Controller index 66 Index int 67 // Base register 68 Base uint32 69 // Clock gate register 70 CCGR uint32 71 // Clock gate 72 CG int 73 // Timeout for I2C operations 74 Timeout time.Duration 75 // Div sets the frequency divider to control the I2C clock rate 76 // (p1464, 31.7.2 I2C Frequency Divider Register (I2Cx_IFDR), IMX6ULLRM). 77 Div uint16 78 79 // control registers 80 iadr uint32 81 ifdr uint32 82 i2cr uint32 83 i2sr uint32 84 i2dr uint32 85 } 86 87 // Init initializes the I2C controller instance. At this time only master mode 88 // is supported by this driver. 89 func (hw *I2C) Init() { 90 hw.Lock() 91 defer hw.Unlock() 92 93 if hw.Base == 0 || hw.CCGR == 0 { 94 panic("invalid I2C controller instance") 95 } 96 97 if hw.Timeout == 0 { 98 hw.Timeout = Timeout 99 } 100 101 if hw.Div == 0 { 102 hw.Div = I2C_DEFAULT_IFDR 103 } 104 105 hw.iadr = hw.Base + I2Cx_IADR 106 hw.ifdr = hw.Base + I2Cx_IFDR 107 hw.i2cr = hw.Base + I2Cx_I2CR 108 hw.i2sr = hw.Base + I2Cx_I2SR 109 hw.i2dr = hw.Base + I2Cx_I2DR 110 111 // p1452, 31.5.1 Initialization sequence, IMX6ULLRM 112 113 // enable clock 114 reg.SetN(hw.CCGR, hw.CG, 0b11, 0b11) 115 116 // Set SCL frequency 117 reg.Write16(hw.ifdr, hw.Div) 118 119 reg.Set16(hw.i2cr, I2CR_IEN) 120 } 121 122 // Read reads a sequence of bytes from a target device 123 // (p167, 16.4.2 Programming the I2C controller for I2C Read, IMX6FG). 124 // 125 // The return data buffer always matches the requested size, otherwise an error 126 // is returned. 127 // 128 // The address length (`alen`) parameter should be set greater then 0 for 129 // ordinary I2C reads (`SLAVE W|ADDR|SLAVE R|DATA`), equal to 0 when not 130 // sending a register address (`SLAVE W|SLAVE R|DATA`) and less than 0 only to 131 // send a target read (`SLAVE R|DATA`). 132 func (hw *I2C) Read(target uint8, addr uint32, alen int, size int) (buf []byte, err error) { 133 hw.Lock() 134 defer hw.Unlock() 135 136 if err = hw.start(false); err != nil { 137 return 138 } 139 defer hw.stop() 140 141 if alen > 0 { 142 if err = hw.txAddress(target, addr, alen); err != nil { 143 return 144 } 145 146 if err = hw.start(true); err != nil { 147 return 148 } 149 } 150 151 // send target address with R/W bit set 152 a := byte((target << 1) | 1) 153 154 if err = hw.tx([]byte{a}); err != nil { 155 return 156 } 157 158 buf = make([]byte, size) 159 err = hw.rx(buf) 160 161 return 162 } 163 164 // Write writes a sequence of bytes to a target device 165 // (p170, 16.4.4 Programming the I2C controller for I2C Write, IMX6FG) 166 // 167 // Set greater then 0 for ordinary I2C write (`SLAVE W|ADDR|DATA`), 168 // set equal then 0 to not send register address (`SLAVE W|DATA`), 169 // alen less then 0 is invalid. 170 // 171 // The address length (`alen`) parameter should be set greater then 0 for 172 // ordinary I2C writes (`SLAVE W|ADDR|DATA`), equal to 0 when not sending a 173 // register address (`SLAVE W|DATA`), values less than 0 are not valid. 174 func (hw *I2C) Write(buf []byte, target uint8, addr uint32, alen int) (err error) { 175 if alen < 0 { 176 return errors.New("invalid address length") 177 } 178 179 hw.Lock() 180 defer hw.Unlock() 181 182 if err = hw.start(false); err != nil { 183 return 184 } 185 defer hw.stop() 186 187 if err = hw.txAddress(target, addr, alen); err != nil { 188 return 189 } 190 191 return hw.tx(buf) 192 } 193 194 func (hw *I2C) txAddress(target uint8, addr uint32, alen int) (err error) { 195 if target > 0x7f { 196 return errors.New("invalid target address") 197 } 198 199 if alen > 4 { 200 return errors.New("invalid register address length") 201 } 202 203 if alen >= 0 { 204 // send target address with R/W bit unset 205 a := byte(target << 1) 206 207 if err = hw.tx([]byte{a}); err != nil { 208 return 209 } 210 } 211 212 // send register address 213 for alen > 0 { 214 alen-- 215 a := byte(addr >> (alen * 8) & 0xff) 216 217 if err = hw.tx([]byte{a}); err != nil { 218 return 219 } 220 } 221 222 return 223 } 224 225 func (hw *I2C) rx(buf []byte) (err error) { 226 size := len(buf) 227 228 // set read from target bit 229 reg.Clear16(hw.i2cr, I2CR_MTX) 230 231 if size == 1 { 232 reg.Set16(hw.i2cr, I2CR_TXAK) 233 } else { 234 reg.Clear16(hw.i2cr, I2CR_TXAK) 235 } 236 237 reg.Clear16(hw.i2sr, I2SR_IIF) 238 // dummy read 239 reg.Read16(hw.i2dr) 240 241 for i := 0; i < size; i++ { 242 if !reg.WaitFor16(hw.Timeout, hw.i2sr, I2SR_IIF, 1, 1) { 243 return errors.New("timeout on byte reception") 244 } 245 246 if i == size-2 { 247 reg.Set16(hw.i2cr, I2CR_TXAK) 248 } else if i == size-1 { 249 hw.stop() 250 } 251 252 buf[i] = byte(reg.Read16(hw.i2dr) & 0xff) 253 reg.Clear16(hw.i2sr, I2SR_IIF) 254 } 255 256 return 257 } 258 259 func (hw *I2C) tx(buf []byte) (err error) { 260 for i := 0; i < len(buf); i++ { 261 reg.Clear16(hw.i2sr, I2SR_IIF) 262 reg.Write16(hw.i2dr, uint16(buf[i])) 263 264 if !reg.WaitFor16(hw.Timeout, hw.i2sr, I2SR_IIF, 1, 1) { 265 return errors.New("timeout on byte transmission") 266 } 267 268 if reg.Get16(hw.i2sr, I2SR_RXAK, 1) == 1 { 269 return errors.New("no acknowledgement received") 270 } 271 } 272 273 return 274 } 275 276 func (hw *I2C) start(repeat bool) (err error) { 277 var pos int 278 279 if repeat == false { 280 // wait for bus to be free 281 if !reg.WaitFor16(hw.Timeout, hw.i2sr, I2SR_IBB, 1, 0) { 282 return errors.New("timeout waiting bus to be free") 283 } 284 285 // enable master mode, generates START signal 286 pos = I2CR_MSTA 287 } else { 288 pos = I2CR_RSTA 289 } 290 291 reg.Set16(hw.i2cr, pos) 292 293 // wait for bus to be busy 294 if !reg.WaitFor16(hw.Timeout, hw.i2sr, I2SR_IBB, 1, 1) { 295 reg.Clear16(hw.i2cr, pos) 296 return errors.New("timeout waiting bus to be busy") 297 } 298 299 if repeat == false { 300 // set Master Transmit mode 301 reg.Set16(hw.i2cr, I2CR_MTX) 302 } 303 304 return 305 } 306 307 func (hw *I2C) stop() { 308 reg.Clear16(hw.i2cr, I2CR_MSTA) 309 reg.Clear16(hw.i2cr, I2CR_MTX) 310 }