Move i2c support to common

This commit is contained in:
Jeremy Soller
2019-11-13 14:33:04 -07:00
parent 894e448dfc
commit 890d8e9968
9 changed files with 215 additions and 152 deletions

View File

@ -1,7 +1,10 @@
#include <stdbool.h>
#include <board/cpu.h>
#include <ec/i2c.h>
#include <common/i2c.h>
#include <ec/smbus.h>
//TODO: find best value
#define TIMEOUT (F_CPU/1000)
#define HOSTA_BYTE_DONE (1 << 7)
@ -14,66 +17,118 @@
#define HOSTA_BUSY (1 << 0)
#define HOSTA_ERR (HOSTA_TIMEOUT | HOSTA_NACK | HOSTA_FAIL | HOSTA_BUS_ERR | HOSTA_DEV_ERR)
static void i2c_kill(void) {
if (HOSTAA & HOSTA_BUSY) {
HOCTLA = (1 << 1);
// TODO: is timeout needed?
while (HOSTAA & HOSTA_BUSY) {}
}
void i2c_reset(bool kill) {
// Set kill bit
if (kill) HOCTLA |= (1 << 1);
// Wait for host to finish
while (HOSTAA & HOSTA_BUSY) {}
// Clear status register
HOSTAA = HOSTAA;
// Clear current command
HOCTLA = 0;
// Disable host interface
HOCTL2A = 0;
}
uint8_t i2c_transaction(uint8_t addr_rw, uint8_t *data, uint16_t length) {
// End any current transaction
i2c_kill();
int i2c_start(uint8_t addr, bool read) {
// If we are already in a transaction
if (HOSTAA & HOSTA_BYTE_DONE) {
// If we are switching direction
if ((TRASLAA & 1) != read) {
// If we are switching to read mode
if (read) {
// Enable direction switch
HOCTL2A |= (1 << 3) | (1 << 2);
// Enable host controller with i2c compatibility
HOCTL2A = (1 << 1) | 1;
// Set slave address
TRASLAA = addr_rw;
static uint8_t __pdata status;
static uint32_t __pdata timeout;
static uint16_t __pdata i;
for (i = 0; i < length; i++) {
if ((addr_rw & 1) && ((i + 1) == length)) {
// Set last byte
HOCTLA |= (1 << 5);
}
// Clear status
HOSTAA = HOSTAA;
if (!(addr_rw & 1)) {
// Set data byte
HOBDBA = data[i];
}
if (i == 0) {
// Start transaction
HOCTLA = (1 << 6) | (0b111 << 2);
}
for(timeout = TIMEOUT; timeout > 0; timeout++) {
status = HOSTAA;
HOSTAA = status;
if (status & HOSTA_ERR) {
timeout = 0;
break;
}
if (status & HOSTA_BYTE_DONE) {
break;
// Clear status to start switch process
HOSTAA = HOSTAA;
} else {
// Unsupported!
i2c_reset(true);
return -1;
}
}
if (timeout == 0) {
i2c_kill();
return 1;
}
if (addr_rw & 1) {
// Get data byte
data[i] = HOBDBA;
}
}
} else {
// Enable host controller with i2c compatibility
HOCTL2A = (1 << 1) | 1;
HOCTL2A = 0;
// Set address
TRASLAA = (addr << 1) | read;
}
return 0;
}
void i2c_stop(void) {
// Disable i2c compatibility
HOCTL2A &= ~(1 << 1);
// Clear status
HOSTAA = HOSTAA;
i2c_reset(false);
}
static int i2c_transaction(uint8_t * data, int length, bool read) {
int i;
for (i = 0; i < length; i++) {
if (read) {
// If last byte
if ((i + 1) == length) {
// Set last byte bit
HOCTLA |= (1 << 5);
}
} else {
// Write byte
HOBDBA = data[i];
}
// If we are already in a transaction
if (HOSTAA & HOSTA_BYTE_DONE) {
// Clear status to process next byte
HOSTAA = HOSTAA;
} else
// If we are waiting on direction switch
if (HOCTLA & (1 << 2)) {
// Complete direction switch
HOCTLA &= ~(1 << 2);
} else {
// Start new transaction
HOCTLA = (1 << 6) | (0b111 << 2);
}
// Wait for byte done, timeout, or error
// uint32_t timeout;
// for(timeout = TIMEOUT; timeout > 0; timeout--) {
for(;;) {
uint8_t status = HOSTAA;
if (status & HOSTA_BYTE_DONE) {
// If byte is finished, break
break;
} else if (status & HOSTA_ERR) {
// If error occured, kill transaction and return error
i2c_reset(true);
return -(int)(status & HOSTA_ERR);
}
}
// if (timeout == 0) {
// // If timeout occured, kill transaction and return error
// i2c_reset(true);
// return -1;
// }
if (read) {
// Read byte
data[i] = HOBDBA;
}
}
return i;
}
int i2c_read(uint8_t * data, int length) {
return i2c_transaction(data, length, true);
}
int i2c_write(uint8_t * data, int length) {
return i2c_transaction(data, length, false);
}

View File

@ -1,10 +1,8 @@
#ifndef _EC_I2C_H
#define _EC_I2C_H
#include <stdint.h>
#include <common/i2c.h>
uint8_t i2c_transaction(uint8_t addr_rw, uint8_t * data, uint16_t length);
#define i2c_read(addr, data, length) i2c_transaction(((uint8_t)addr << 1) | 1, data, length)
#define i2c_write(addr, data, length) i2c_transaction(((uint8_t)addr << 1), data, length)
void i2c_reset(bool kill);
#endif // _EC_I2C_H