Move i2c support to common
This commit is contained in:
parent
894e448dfc
commit
890d8e9968
@ -2,15 +2,12 @@
|
||||
#include <avr/io.h>
|
||||
#include <util/twi.h>
|
||||
|
||||
#include <arch/i2c.h>
|
||||
#include <board/cpu.h>
|
||||
#include <common/i2c.h>
|
||||
|
||||
#define TIMEOUT (F_CPU/1000)
|
||||
|
||||
#define I2C_READ 0x01
|
||||
#define I2C_WRITE 0x00
|
||||
|
||||
uint8_t i2c_start(uint8_t addr, uint8_t rw) {
|
||||
uint8_t i2c_start(uint8_t addr, bool read) {
|
||||
uint32_t count;
|
||||
|
||||
// reset TWI control register
|
||||
@ -32,7 +29,7 @@ uint8_t i2c_start(uint8_t addr, uint8_t rw) {
|
||||
}
|
||||
|
||||
// load slave addr into data register
|
||||
TWDR = ((addr << 1) | rw);
|
||||
TWDR = ((addr << 1) | read);
|
||||
// start transmission of addr
|
||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||
// wait for end of transmission
|
||||
@ -53,7 +50,7 @@ uint8_t i2c_start(uint8_t addr, uint8_t rw) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void i2c_stop() {
|
||||
void i2c_stop(void) {
|
||||
// transmit STOP condition
|
||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
||||
}
|
||||
@ -81,83 +78,16 @@ uint8_t i2c_write(uint8_t data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t i2c_read_ack() {
|
||||
// start TWI module and acknowledge data after reception
|
||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
|
||||
uint8_t i2c_read(bool ack) {
|
||||
if (ack) {
|
||||
// start TWI module and acknowledge data after reception
|
||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
|
||||
} else {
|
||||
// start receiving without acknowledging reception
|
||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||
}
|
||||
// wait for end of transmission
|
||||
while( !(TWCR & (1<<TWINT)) );
|
||||
// return received data from TWDR
|
||||
return TWDR;
|
||||
}
|
||||
|
||||
uint8_t i2c_read_nack() {
|
||||
// start receiving without acknowledging reception
|
||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||
// wait for end of transmission
|
||||
while( !(TWCR & (1<<TWINT)) );
|
||||
// return received data from TWDR
|
||||
return TWDR;
|
||||
}
|
||||
|
||||
uint8_t i2c_recv(uint8_t addr, uint8_t* data, uint16_t length) {
|
||||
if (i2c_start(addr, I2C_READ)) return 1;
|
||||
|
||||
uint16_t i;
|
||||
for (i = 0; i < (length-1); i++)
|
||||
{
|
||||
data[i] = i2c_read_ack();
|
||||
}
|
||||
data[(length-1)] = i2c_read_nack();
|
||||
|
||||
i2c_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t i2c_send(uint8_t addr, uint8_t* data, uint16_t length) {
|
||||
if (i2c_start(addr, I2C_WRITE)) return 1;
|
||||
|
||||
uint16_t i;
|
||||
for (i = 0; i < length; i++) {
|
||||
if (i2c_write(data[i])) return 1;
|
||||
}
|
||||
|
||||
i2c_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t i2c_get(uint8_t addr, uint8_t reg, uint8_t* data, uint16_t length) {
|
||||
if (i2c_start(addr, I2C_WRITE)) return 1;
|
||||
|
||||
if (i2c_write(reg)) return 1;
|
||||
|
||||
if (i2c_start(addr, I2C_READ)) return 1;
|
||||
|
||||
uint16_t i;
|
||||
for (i = 0; i < (length-1); i++)
|
||||
{
|
||||
data[i] = i2c_read_ack();
|
||||
}
|
||||
data[(length-1)] = i2c_read_nack();
|
||||
|
||||
i2c_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t i2c_set(uint8_t addr, uint8_t reg, uint8_t* data, uint16_t length) {
|
||||
if (i2c_start(addr, I2C_WRITE)) return 1;
|
||||
|
||||
if(i2c_write(reg)) return 1;
|
||||
|
||||
uint16_t i;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
if (i2c_write(data[i])) return 1;
|
||||
}
|
||||
|
||||
i2c_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
#ifndef _ARCH_I2C_H
|
||||
#define _ARCH_I2C_H
|
||||
|
||||
uint8_t i2c_recv(uint8_t addr, uint8_t* data, uint16_t length);
|
||||
uint8_t i2c_send(uint8_t addr, uint8_t* data, uint16_t length);
|
||||
|
||||
uint8_t i2c_get(uint8_t addr, uint8_t reg, uint8_t* data, uint16_t length);
|
||||
uint8_t i2c_set(uint8_t addr, uint8_t reg, uint8_t* data, uint16_t length);
|
||||
|
||||
#endif // _ARCH_I2C_H
|
@ -1,8 +1,6 @@
|
||||
#ifndef _BOARD_I2C_H
|
||||
#define _BOARD_I2C_H
|
||||
|
||||
#include <arch/i2c.h>
|
||||
|
||||
void i2c_init(unsigned long baud);
|
||||
|
||||
#endif // _BOARD_I2C_H
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <board/smbus.h>
|
||||
#include <ec/i2c.h>
|
||||
|
||||
void smbus_init(void) {
|
||||
// 9.2 MHz * 4.7 us = 43.24
|
||||
@ -17,4 +18,7 @@ void smbus_init(void) {
|
||||
|
||||
// Clock set to 50 Hz
|
||||
SCLKTSA = 1;
|
||||
|
||||
// Set up for i2c usage
|
||||
i2c_reset(true);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <ec/i2c.h>
|
||||
#include <common/i2c.h>
|
||||
|
||||
int putchar(int c) {
|
||||
unsigned char byte = (unsigned char)c;
|
||||
i2c_write(0x76, &byte, 1);
|
||||
i2c_send(0x76, &byte, 1);
|
||||
return (int)byte;
|
||||
}
|
||||
|
53
src/common/i2c.c
Normal file
53
src/common/i2c.c
Normal file
@ -0,0 +1,53 @@
|
||||
#include <common/i2c.h>
|
||||
|
||||
int i2c_recv(uint8_t addr, uint8_t* data, int length) {
|
||||
int res = 0;
|
||||
|
||||
res = i2c_start(addr, true);
|
||||
if (res < 0) return res;
|
||||
|
||||
res = i2c_read(data, length);
|
||||
if (res < 0) return res;
|
||||
|
||||
i2c_stop();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int i2c_send(uint8_t addr, uint8_t* data, int length) {
|
||||
int res = 0;
|
||||
|
||||
res = i2c_start(addr, false);
|
||||
if (res < 0) return res;
|
||||
|
||||
res = i2c_write(data, length);
|
||||
if (res < 0) return res;
|
||||
|
||||
i2c_stop();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int i2c_get(uint8_t addr, uint8_t reg, uint8_t* data, int length) {
|
||||
int res = 0;
|
||||
|
||||
res = i2c_start(addr, false);
|
||||
if (res < 0) return res;
|
||||
|
||||
res = i2c_write(®, 1);
|
||||
if (res < 0) return res;
|
||||
|
||||
return i2c_recv(addr, data, length);
|
||||
}
|
||||
|
||||
int i2c_set(uint8_t addr, uint8_t reg, uint8_t* data, int length) {
|
||||
int res = 0;
|
||||
|
||||
res = i2c_start(addr, false);
|
||||
if (res < 0) return res;
|
||||
|
||||
res = i2c_write(®, 1);
|
||||
if (res < 0) return res;
|
||||
|
||||
return i2c_send(addr, data, length);
|
||||
}
|
35
src/common/include/common/i2c.h
Normal file
35
src/common/include/common/i2c.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef _COMMON_I2C_H
|
||||
#define _COMMON_I2C_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Start i2c transaction
|
||||
// Must be defined by arch, board, or ec
|
||||
int i2c_start(uint8_t addr, bool read);
|
||||
|
||||
// Stop i2c transaction
|
||||
// Must be defined by arch, board, or ec
|
||||
void i2c_stop(void);
|
||||
|
||||
// Send a byte on i2c bus
|
||||
// Must be defined by arch, board, or ec
|
||||
int i2c_write(uint8_t * data, int length);
|
||||
|
||||
// Read bytes from bus
|
||||
// Must be defined by arch, board, or ec
|
||||
int i2c_read(uint8_t * data, int length);
|
||||
|
||||
// Read multiple bytes from address in one transaction
|
||||
int i2c_recv(uint8_t addr, uint8_t* data, int length);
|
||||
|
||||
// Write multiple bytes to address in one transaction
|
||||
int i2c_send(uint8_t addr, uint8_t* data, int length);
|
||||
|
||||
// Read multiple bytes from a register in one transaction
|
||||
int i2c_get(uint8_t addr, uint8_t reg, uint8_t* data, int length);
|
||||
|
||||
// Write multiple bytes to a register in one transaction
|
||||
int i2c_set(uint8_t addr, uint8_t reg, uint8_t* data, int length);
|
||||
|
||||
#endif // _COMMON_I2C_H
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user