/* * (C) Copyright 2014 Leo C. * * SPDX-License-Identifier: GPL-2.0+ */ /* * I2C (TWI) master interface. */ #include "common.h" #include #include #include "config.h" #include "timer.h" #include "debug.h" #include "i2c.h" #define DEBUG_I2C 0 #define debug_i2c(fmt, args...) \ debug_cond(DEBUG_I2C, fmt, ##args) /* General TWI Master status codes */ #define TWI_START 0x08 /* START has been transmitted */ #define TWI_REP_START 0x10 /* Repeated START has been transmitted */ #define TWI_ARB_LOST 0x38 /* Arbitration lost */ /* TWI Master Transmitter status codes */ #define TWI_MTX_ADR_ACK 0x18 /* SLA+W has been transmitted and ACK received */ #define TWI_MTX_ADR_NACK 0x20 /* SLA+W has been transmitted and NACK received */ #define TWI_MTX_DATA_ACK 0x28 /* Data byte has been transmitted and ACK received */ #define TWI_MTX_DATA_NACK 0x30 /* Data byte has been transmitted and NACK received */ /* TWI Master Receiver status codes */ #define TWI_MRX_ADR_ACK 0x40 /* SLA+R has been transmitted and ACK received */ #define TWI_MRX_ADR_NACK 0x48 /* SLA+R has been transmitted and NACK received */ #define TWI_MRX_DATA_ACK 0x50 /* Data byte has been received and ACK transmitted */ #define TWI_MRX_DATA_NACK 0x58 /* Data byte has been received and NACK transmitted */ /* TWI Miscellaneous status codes */ #define TWI_NO_STATE 0xF8 /* No relevant state information available */ #define TWI_BUS_ERROR 0x00 /* Bus error due to an illegal START or STOP condition */ /* * TWINT: TWI Interrupt Flag * TWEA: TWI Enable Acknowledge Bit * TWSTA: TWI START Condition Bit * TWSTO: TWI STOP Condition Bit * TWEN: TWI Enable Bit * TWIE: TWI Interrupt Enable * * (1< 255) { tmp_twbr >>= 4; twps += 1; } debug_cond((twps > 3), "*** TWCLK too low: %lu Hz\n", speed); twbr = (uint8_t) tmp_twbr; PRR0 &= ~_BV(PRTWI); _init(); } int_fast8_t i2c_waitready(void) { uint32_t timer = get_timer(0); uint8_t timeout = 0; do { if (get_timer(timer) >= 30) { timeout = TIMEOUT; _init(); } } while ((TWCR & ((1<>= 8; } for (n = len + i; i < n; i++) xmit.buf[i] = *buffer++; xmit.len = i; #if DEBUG_I2C dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_send"); _delay_ms(30); #endif /* Enable TWI, TWI int and initiate start condition */ TWCR = (1< 2) || (1 + alen + len > CONFIG_SYS_I2C_BUFSIZE)) { debug("** i2c_write: buffer overflow, alen: %u, len: %u\n", alen, len); return -1; } i2c_send(chip, addr, alen, buffer, len); rc = i2c_waitready(); return (rc & XMIT_DONE) != 0; } int i2c_read(uint8_t chip, unsigned int addr, uint_fast8_t alen, uint8_t *buffer, uint_fast8_t len) { int rc; if ((alen > 2) || (1 + len > CONFIG_SYS_I2C_BUFSIZE)) { debug("** i2c_read: parameter error: alen: %u, len: %u\n", alen, len); return -1; } if (alen != 0) { i2c_send(chip, addr, alen, NULL, 0); } rc = i2c_recv(chip, buffer, len); return !((rc & (XMIT_DONE|DATA_ACK)) == (XMIT_DONE|DATA_ACK)); }