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  }