Add support for multiple I2C buses
This commit is contained in:
@ -1,12 +1,12 @@
|
|||||||
#include <common/debug.h>
|
#include <common/debug.h>
|
||||||
#include <common/i2c.h>
|
#include <ec/i2c.h>
|
||||||
|
|
||||||
int smbus_read(uint8_t address, uint8_t command, uint16_t * data) {
|
int smbus_read(uint8_t address, uint8_t command, uint16_t * data) {
|
||||||
return i2c_get(address, command, (uint8_t *)data, 2);
|
return i2c_get(&I2C_0, address, command, (uint8_t *)data, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int smbus_write(uint8_t address, uint8_t command, uint16_t data) {
|
int smbus_write(uint8_t address, uint8_t command, uint16_t data) {
|
||||||
return i2c_set(address, command, (uint8_t *)&data, 2);
|
return i2c_set(&I2C_0, address, command, (uint8_t *)&data, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChargeOption0 flags
|
// ChargeOption0 flags
|
||||||
|
@ -23,6 +23,8 @@ extern struct Gpio __code DD_ON;
|
|||||||
extern struct Gpio __code EC_EN;
|
extern struct Gpio __code EC_EN;
|
||||||
extern struct Gpio __code EC_RSMRST_N;
|
extern struct Gpio __code EC_RSMRST_N;
|
||||||
extern struct Gpio __code LED_ACIN;
|
extern struct Gpio __code LED_ACIN;
|
||||||
|
extern struct Gpio __code LED_BAT_CHG;
|
||||||
|
extern struct Gpio __code LED_BAT_FULL;
|
||||||
extern struct Gpio __code LED_PWR;
|
extern struct Gpio __code LED_PWR;
|
||||||
extern struct Gpio __code LID_SW_N;
|
extern struct Gpio __code LID_SW_N;
|
||||||
extern struct Gpio __code PCH_DPWROK_EC;
|
extern struct Gpio __code PCH_DPWROK_EC;
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#define KM_LAY 2
|
#define KM_LAY 2
|
||||||
|
|
||||||
// Keymap
|
// Keymap
|
||||||
extern uint16_t __code KEYMAP[KM_LAY][KM_OUT][KM_IN];
|
extern uint16_t __code KEYMAP[KM_OUT][KM_IN][KM_LAY];
|
||||||
|
|
||||||
// Get a keycode from the keymap
|
// Get a keycode from the keymap
|
||||||
uint16_t keymap(int output, int input, int layer);
|
uint16_t keymap(int output, int input, int layer);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef I2C_DEBUGGER
|
#ifdef I2C_DEBUGGER
|
||||||
#include <common/i2c.h>
|
#include <ec/i2c.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int putchar(int c) {
|
int putchar(int c) {
|
||||||
@ -14,7 +14,7 @@ int putchar(int c) {
|
|||||||
SBUF = byte;
|
SBUF = byte;
|
||||||
#endif
|
#endif
|
||||||
#ifdef I2C_DEBUGGER
|
#ifdef I2C_DEBUGGER
|
||||||
i2c_send(I2C_DEBUGGER, &byte, 1);
|
i2c_send(&I2C_0, I2C_DEBUGGER, &byte, 1);
|
||||||
#endif
|
#endif
|
||||||
return (int)byte;
|
return (int)byte;
|
||||||
}
|
}
|
||||||
|
@ -17,5 +17,5 @@ void smbus_init(void) {
|
|||||||
SMB45P3USH = 0x01;
|
SMB45P3USH = 0x01;
|
||||||
|
|
||||||
// Set up for i2c usage
|
// Set up for i2c usage
|
||||||
i2c_reset(true);
|
i2c_reset(&I2C_0, true);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef I2C_DEBUGGER
|
#ifdef I2C_DEBUGGER
|
||||||
#include <common/i2c.h>
|
#include <ec/i2c.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int putchar(int c) {
|
int putchar(int c) {
|
||||||
@ -14,7 +14,7 @@ int putchar(int c) {
|
|||||||
SBUF = byte;
|
SBUF = byte;
|
||||||
#endif
|
#endif
|
||||||
#ifdef I2C_DEBUGGER
|
#ifdef I2C_DEBUGGER
|
||||||
i2c_send(I2C_DEBUGGER, &byte, 1);
|
i2c_send(&I2C_0, I2C_DEBUGGER, &byte, 1);
|
||||||
#endif
|
#endif
|
||||||
return (int)byte;
|
return (int)byte;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#include <common/debug.h>
|
#include <common/debug.h>
|
||||||
#include <common/i2c.h>
|
#include <ec/i2c.h>
|
||||||
|
|
||||||
int smbus_read(uint8_t address, uint8_t command, uint16_t * data) {
|
int smbus_read(uint8_t address, uint8_t command, uint16_t * data) {
|
||||||
return i2c_get(address, command, (uint8_t *)data, 2);
|
return i2c_get(&I2C_4, address, command, (uint8_t *)data, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int smbus_write(uint8_t address, uint8_t command, uint16_t data) {
|
int smbus_write(uint8_t address, uint8_t command, uint16_t data) {
|
||||||
return i2c_set(address, command, (uint8_t *)&data, 2);
|
return i2c_set(&I2C_4, address, command, (uint8_t *)&data, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChargeOption0 flags
|
// ChargeOption0 flags
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef I2C_DEBUGGER
|
#ifdef I2C_DEBUGGER
|
||||||
#include <common/i2c.h>
|
#include <ec/i2c.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int putchar(int c) {
|
int putchar(int c) {
|
||||||
@ -14,7 +14,7 @@ int putchar(int c) {
|
|||||||
SBUF = byte;
|
SBUF = byte;
|
||||||
#endif
|
#endif
|
||||||
#ifdef I2C_DEBUGGER
|
#ifdef I2C_DEBUGGER
|
||||||
i2c_send(I2C_DEBUGGER, &byte, 1);
|
i2c_send(&I2C_4, I2C_DEBUGGER, &byte, 1);
|
||||||
#endif
|
#endif
|
||||||
return (int)byte;
|
return (int)byte;
|
||||||
}
|
}
|
||||||
|
@ -17,5 +17,5 @@ void smbus_init(void) {
|
|||||||
SMB45P3USH = 0x01;
|
SMB45P3USH = 0x01;
|
||||||
|
|
||||||
// Set up for i2c usage
|
// Set up for i2c usage
|
||||||
i2c_reset(true);
|
i2c_reset(&I2C_4, true);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef I2C_DEBUGGER
|
#ifdef I2C_DEBUGGER
|
||||||
#include <common/i2c.h>
|
#include <ec/i2c.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int putchar(int c) {
|
int putchar(int c) {
|
||||||
@ -14,7 +14,7 @@ int putchar(int c) {
|
|||||||
SBUF = byte;
|
SBUF = byte;
|
||||||
#endif
|
#endif
|
||||||
#ifdef I2C_DEBUGGER
|
#ifdef I2C_DEBUGGER
|
||||||
i2c_send(I2C_DEBUGGER, &byte, 1);
|
i2c_send(&I2C_4, I2C_DEBUGGER, &byte, 1);
|
||||||
#endif
|
#endif
|
||||||
return (int)byte;
|
return (int)byte;
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,53 @@
|
|||||||
#include <common/i2c.h>
|
#include <common/i2c.h>
|
||||||
|
|
||||||
int i2c_recv(uint8_t addr, uint8_t* data, int length) {
|
int i2c_recv(struct I2C * i2c, uint8_t addr, uint8_t* data, int length) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
res = i2c_start(addr, true);
|
res = i2c_start(i2c, addr, true);
|
||||||
if (res < 0) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
res = i2c_read(data, length);
|
res = i2c_read(i2c, data, length);
|
||||||
if (res < 0) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
i2c_stop();
|
i2c_stop(i2c);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_send(uint8_t addr, uint8_t* data, int length) {
|
int i2c_send(struct I2C * i2c, uint8_t addr, uint8_t* data, int length) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
res = i2c_start(addr, false);
|
res = i2c_start(i2c, addr, false);
|
||||||
if (res < 0) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
res = i2c_write(data, length);
|
res = i2c_write(i2c, data, length);
|
||||||
if (res < 0) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
i2c_stop();
|
i2c_stop(i2c);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_get(uint8_t addr, uint8_t reg, uint8_t* data, int length) {
|
int i2c_get(struct I2C * i2c, uint8_t addr, uint8_t reg, uint8_t* data, int length) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
res = i2c_start(addr, false);
|
res = i2c_start(i2c, addr, false);
|
||||||
if (res < 0) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
res = i2c_write(®, 1);
|
res = i2c_write(i2c, ®, 1);
|
||||||
if (res < 0) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
return i2c_recv(addr, data, length);
|
return i2c_recv(i2c, addr, data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_set(uint8_t addr, uint8_t reg, uint8_t* data, int length) {
|
int i2c_set(struct I2C * i2c, uint8_t addr, uint8_t reg, uint8_t* data, int length) {
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
res = i2c_start(addr, false);
|
res = i2c_start(i2c, addr, false);
|
||||||
if (res < 0) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
res = i2c_write(®, 1);
|
res = i2c_write(i2c, ®, 1);
|
||||||
if (res < 0) return res;
|
if (res < 0) return res;
|
||||||
|
|
||||||
return i2c_send(addr, data, length);
|
return i2c_send(i2c, addr, data, length);
|
||||||
}
|
}
|
||||||
|
@ -4,32 +4,35 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// I2C bus, should be defined elsewhere
|
||||||
|
struct I2C;
|
||||||
|
|
||||||
// Start i2c transaction
|
// Start i2c transaction
|
||||||
// Must be defined by arch, board, or ec
|
// Must be defined by arch, board, or ec
|
||||||
int i2c_start(uint8_t addr, bool read);
|
int i2c_start(struct I2C * i2c, uint8_t addr, bool read);
|
||||||
|
|
||||||
// Stop i2c transaction
|
// Stop i2c transaction
|
||||||
// Must be defined by arch, board, or ec
|
// Must be defined by arch, board, or ec
|
||||||
void i2c_stop(void);
|
void i2c_stop(struct I2C * i2c);
|
||||||
|
|
||||||
// Send a byte on i2c bus
|
// Send a byte on i2c bus
|
||||||
// Must be defined by arch, board, or ec
|
// Must be defined by arch, board, or ec
|
||||||
int i2c_write(uint8_t * data, int length);
|
int i2c_write(struct I2C * i2c, uint8_t * data, int length);
|
||||||
|
|
||||||
// Read bytes from bus
|
// Read bytes from bus
|
||||||
// Must be defined by arch, board, or ec
|
// Must be defined by arch, board, or ec
|
||||||
int i2c_read(uint8_t * data, int length);
|
int i2c_read(struct I2C * i2c, uint8_t * data, int length);
|
||||||
|
|
||||||
// Read multiple bytes from address in one transaction
|
// Read multiple bytes from address in one transaction
|
||||||
int i2c_recv(uint8_t addr, uint8_t* data, int length);
|
int i2c_recv(struct I2C * i2c, uint8_t addr, uint8_t* data, int length);
|
||||||
|
|
||||||
// Write multiple bytes to address in one transaction
|
// Write multiple bytes to address in one transaction
|
||||||
int i2c_send(uint8_t addr, uint8_t* data, int length);
|
int i2c_send(struct I2C * i2c, uint8_t addr, uint8_t* data, int length);
|
||||||
|
|
||||||
// Read multiple bytes from a register in one transaction
|
// Read multiple bytes from a register in one transaction
|
||||||
int i2c_get(uint8_t addr, uint8_t reg, uint8_t* data, int length);
|
int i2c_get(struct I2C * i2c, uint8_t addr, uint8_t reg, uint8_t* data, int length);
|
||||||
|
|
||||||
// Write multiple bytes to a register in one transaction
|
// Write multiple bytes to a register in one transaction
|
||||||
int i2c_set(uint8_t addr, uint8_t reg, uint8_t* data, int length);
|
int i2c_set(struct I2C * i2c, uint8_t addr, uint8_t reg, uint8_t* data, int length);
|
||||||
|
|
||||||
#endif // _COMMON_I2C_H
|
#endif // _COMMON_I2C_H
|
||||||
|
@ -6,101 +6,111 @@
|
|||||||
//TODO: find best value
|
//TODO: find best value
|
||||||
#define I2C_TIMEOUT 10000
|
#define I2C_TIMEOUT 10000
|
||||||
|
|
||||||
#define HOSTA HOSTAE
|
struct I2C {
|
||||||
#define HOCTL HOCTLE
|
volatile uint8_t * hosta;
|
||||||
#define HOCTL2 HOCTL2E
|
volatile uint8_t * hoctl;
|
||||||
#define HOBDB HOBDBE
|
volatile uint8_t * hoctl2;
|
||||||
#define TRASLA TRASLAE
|
volatile uint8_t * hobdb;
|
||||||
|
volatile uint8_t * trasla;
|
||||||
|
};
|
||||||
|
|
||||||
void i2c_reset(bool kill) {
|
struct I2C __code I2C_4 = {
|
||||||
if (HOSTA & HOSTA_BUSY) {
|
.hosta = HOSTAE,
|
||||||
|
.hoctl = HOCTLE,
|
||||||
|
.hoctl2 = HOCTL2E,
|
||||||
|
.hobdb = HOBDBE,
|
||||||
|
.trasla = TRASLAE,
|
||||||
|
};
|
||||||
|
|
||||||
|
void i2c_reset(struct I2C * i2c, bool kill) {
|
||||||
|
if (*(i2c->hosta) & HOSTA_BUSY) {
|
||||||
// Set kill bit
|
// Set kill bit
|
||||||
if (kill) HOCTL |= (1 << 1);
|
if (kill) *(i2c->hoctl) |= (1 << 1);
|
||||||
// Wait for host to finish
|
// Wait for host to finish
|
||||||
while (HOSTA & HOSTA_BUSY) {}
|
while (*(i2c->hosta) & HOSTA_BUSY) {}
|
||||||
}
|
}
|
||||||
// Clear status register
|
// Clear status register
|
||||||
HOSTA = HOSTA;
|
*(i2c->hosta) = *(i2c->hosta);
|
||||||
// Clear current command
|
// Clear current command
|
||||||
HOCTL = 0;
|
*(i2c->hoctl) = 0;
|
||||||
// Disable host interface
|
// Disable host interface
|
||||||
HOCTL2 = 0;
|
*(i2c->hoctl2) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_start(uint8_t addr, bool read) {
|
int i2c_start(struct I2C * i2c, uint8_t addr, bool read) {
|
||||||
// If we are already in a transaction
|
// If we are already in a transaction
|
||||||
if (HOSTA & HOSTA_BYTE_DONE) {
|
if (*(i2c->hosta) & HOSTA_BYTE_DONE) {
|
||||||
// If we are switching direction
|
// If we are switching direction
|
||||||
if ((TRASLA & 1) != read) {
|
if ((*(i2c->trasla) & 1) != read) {
|
||||||
// If we are switching to read mode
|
// If we are switching to read mode
|
||||||
if (read) {
|
if (read) {
|
||||||
// Enable direction switch
|
// Enable direction switch
|
||||||
HOCTL2 |= (1 << 3) | (1 << 2);
|
*(i2c->hoctl2) |= (1 << 3) | (1 << 2);
|
||||||
} else {
|
} else {
|
||||||
// Unsupported!
|
// Unsupported!
|
||||||
i2c_reset(true);
|
i2c_reset(i2c, true);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i2c_reset(true);
|
i2c_reset(i2c, true);
|
||||||
|
|
||||||
// Enable host controller with i2c compatibility
|
// Enable host controller with i2c compatibility
|
||||||
HOCTL2 = (1 << 1) | 1;
|
*(i2c->hoctl2) = (1 << 1) | 1;
|
||||||
|
|
||||||
// Set address
|
// Set address
|
||||||
TRASLA = (addr << 1) | read;
|
*(i2c->trasla) = (addr << 1) | read;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_stop(void) {
|
void i2c_stop(struct I2C * i2c) {
|
||||||
// Disable i2c compatibility
|
// Disable i2c compatibility
|
||||||
HOCTL2 &= ~(1 << 1);
|
*(i2c->hoctl2) &= ~(1 << 1);
|
||||||
// Clear status
|
// Clear status
|
||||||
HOSTA = HOSTA;
|
*(i2c->hosta) = *(i2c->hosta);
|
||||||
|
|
||||||
i2c_reset(false);
|
i2c_reset(i2c, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i2c_transaction(uint8_t * data, int length, bool read) {
|
static int i2c_transaction(struct I2C * i2c, uint8_t * data, int length, bool read) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < length; i++) {
|
for (i = 0; i < length; i++) {
|
||||||
if (read) {
|
if (read) {
|
||||||
// If last byte
|
// If last byte
|
||||||
if ((i + 1) == length) {
|
if ((i + 1) == length) {
|
||||||
// Set last byte bit
|
// Set last byte bit
|
||||||
HOCTL |= (1 << 5);
|
*(i2c->hoctl) |= (1 << 5);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Write byte
|
// Write byte
|
||||||
HOBDB = data[i];
|
*(i2c->hobdb) = data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are already in a transaction
|
// If we are already in a transaction
|
||||||
if (HOSTA & HOSTA_BYTE_DONE) {
|
if (*(i2c->hosta) & HOSTA_BYTE_DONE) {
|
||||||
// Clear status to process next byte
|
// Clear status to process next byte
|
||||||
HOSTA = HOSTA;
|
*(i2c->hosta) = *(i2c->hosta);
|
||||||
} else {
|
} else {
|
||||||
// Start new transaction
|
// Start new transaction
|
||||||
HOCTL = (1 << 6) | (0b111 << 2);
|
*(i2c->hoctl) = (1 << 6) | (0b111 << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are waiting on direction switch
|
// If we are waiting on direction switch
|
||||||
if (HOCTL2 & (1 << 2)) {
|
if (*(i2c->hoctl2) & (1 << 2)) {
|
||||||
// Complete direction switch
|
// Complete direction switch
|
||||||
HOCTL2 &= ~(1 << 2);
|
*(i2c->hoctl2) &= ~(1 << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for byte done, timeout, or error
|
// Wait for byte done, timeout, or error
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
uint32_t timeout = I2C_TIMEOUT;
|
uint32_t timeout = I2C_TIMEOUT;
|
||||||
for(timeout = I2C_TIMEOUT; timeout > 0; timeout--) {
|
for(timeout = I2C_TIMEOUT; timeout > 0; timeout--) {
|
||||||
status = HOSTA;
|
status = *(i2c->hosta);
|
||||||
// If error occured, kill transaction and return error
|
// If error occured, kill transaction and return error
|
||||||
if (status & HOSTA_ERR) {
|
if (status & HOSTA_ERR) {
|
||||||
i2c_reset(true);
|
i2c_reset(i2c, true);
|
||||||
return -(int)(status);
|
return -(int)(status);
|
||||||
} else
|
} else
|
||||||
// If byte done, break
|
// If byte done, break
|
||||||
@ -110,23 +120,23 @@ static int i2c_transaction(uint8_t * data, int length, bool read) {
|
|||||||
}
|
}
|
||||||
// If timeout occured, kill transaction and return error
|
// If timeout occured, kill transaction and return error
|
||||||
if (timeout == 0) {
|
if (timeout == 0) {
|
||||||
i2c_reset(true);
|
i2c_reset(i2c, true);
|
||||||
return -(0x1000 | (int)status);
|
return -(0x1000 | (int)status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read) {
|
if (read) {
|
||||||
// Read byte
|
// Read byte
|
||||||
data[i] = HOBDB;
|
data[i] = *(i2c->hobdb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_read(uint8_t * data, int length) {
|
int i2c_read(struct I2C * i2c, uint8_t * data, int length) {
|
||||||
return i2c_transaction(data, length, true);
|
return i2c_transaction(i2c, data, length, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_write(uint8_t * data, int length) {
|
int i2c_write(struct I2C * i2c, uint8_t * data, int length) {
|
||||||
return i2c_transaction(data, length, false);
|
return i2c_transaction(i2c, data, length, false);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <common/i2c.h>
|
#include <common/i2c.h>
|
||||||
|
|
||||||
void i2c_reset(bool kill);
|
extern struct I2C __code I2C_4;
|
||||||
|
|
||||||
|
void i2c_reset(struct I2C * i2c, bool kill);
|
||||||
|
|
||||||
#endif // _EC_I2C_H
|
#endif // _EC_I2C_H
|
||||||
|
@ -6,101 +6,111 @@
|
|||||||
//TODO: find best value
|
//TODO: find best value
|
||||||
#define I2C_TIMEOUT 10000
|
#define I2C_TIMEOUT 10000
|
||||||
|
|
||||||
#define HOSTA HOSTAA
|
struct I2C {
|
||||||
#define HOCTL HOCTLA
|
volatile uint8_t * hosta;
|
||||||
#define HOCTL2 HOCTL2A
|
volatile uint8_t * hoctl;
|
||||||
#define HOBDB HOBDBA
|
volatile uint8_t * hoctl2;
|
||||||
#define TRASLA TRASLAA
|
volatile uint8_t * hobdb;
|
||||||
|
volatile uint8_t * trasla;
|
||||||
|
};
|
||||||
|
|
||||||
void i2c_reset(bool kill) {
|
struct I2C __code I2C_0 = {
|
||||||
if (HOSTA & HOSTA_BUSY) {
|
.hosta = HOSTAA,
|
||||||
|
.hoctl = HOCTLA,
|
||||||
|
.hoctl2 = HOCTL2A,
|
||||||
|
.hobdb = HOBDBA,
|
||||||
|
.trasla = TRASLAA,
|
||||||
|
};
|
||||||
|
|
||||||
|
void i2c_reset(struct I2C * i2c, bool kill) {
|
||||||
|
if (*(i2c->hosta) & HOSTA_BUSY) {
|
||||||
// Set kill bit
|
// Set kill bit
|
||||||
if (kill) HOCTL |= (1 << 1);
|
if (kill) *(i2c->hoctl) |= (1 << 1);
|
||||||
// Wait for host to finish
|
// Wait for host to finish
|
||||||
while (HOSTA & HOSTA_BUSY) {}
|
while (*(i2c->hosta) & HOSTA_BUSY) {}
|
||||||
}
|
}
|
||||||
// Clear status register
|
// Clear status register
|
||||||
HOSTA = HOSTA;
|
*(i2c->hosta) = *(i2c->hosta);
|
||||||
// Clear current command
|
// Clear current command
|
||||||
HOCTL = 0;
|
*(i2c->hoctl) = 0;
|
||||||
// Disable host interface
|
// Disable host interface
|
||||||
HOCTL2 = 0;
|
*(i2c->hoctl2) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_start(uint8_t addr, bool read) {
|
int i2c_start(struct I2C * i2c, uint8_t addr, bool read) {
|
||||||
// If we are already in a transaction
|
// If we are already in a transaction
|
||||||
if (HOSTA & HOSTA_BYTE_DONE) {
|
if (*(i2c->hosta) & HOSTA_BYTE_DONE) {
|
||||||
// If we are switching direction
|
// If we are switching direction
|
||||||
if ((TRASLA & 1) != read) {
|
if ((*(i2c->trasla) & 1) != read) {
|
||||||
// If we are switching to read mode
|
// If we are switching to read mode
|
||||||
if (read) {
|
if (read) {
|
||||||
// Enable direction switch
|
// Enable direction switch
|
||||||
HOCTL2 |= (1 << 3) | (1 << 2);
|
*(i2c->hoctl2) |= (1 << 3) | (1 << 2);
|
||||||
} else {
|
} else {
|
||||||
// Unsupported!
|
// Unsupported!
|
||||||
i2c_reset(true);
|
i2c_reset(i2c, true);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i2c_reset(true);
|
i2c_reset(i2c, true);
|
||||||
|
|
||||||
// Enable host controller with i2c compatibility
|
// Enable host controller with i2c compatibility
|
||||||
HOCTL2 = (1 << 1) | 1;
|
*(i2c->hoctl2) = (1 << 1) | 1;
|
||||||
|
|
||||||
// Set address
|
// Set address
|
||||||
TRASLA = (addr << 1) | read;
|
*(i2c->trasla) = (addr << 1) | read;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_stop(void) {
|
void i2c_stop(struct I2C * i2c) {
|
||||||
// Disable i2c compatibility
|
// Disable i2c compatibility
|
||||||
HOCTL2 &= ~(1 << 1);
|
*(i2c->hoctl2) &= ~(1 << 1);
|
||||||
// Clear status
|
// Clear status
|
||||||
HOSTA = HOSTA;
|
*(i2c->hosta) = *(i2c->hosta);
|
||||||
|
|
||||||
i2c_reset(false);
|
i2c_reset(i2c, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i2c_transaction(uint8_t * data, int length, bool read) {
|
static int i2c_transaction(struct I2C * i2c, uint8_t * data, int length, bool read) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < length; i++) {
|
for (i = 0; i < length; i++) {
|
||||||
if (read) {
|
if (read) {
|
||||||
// If last byte
|
// If last byte
|
||||||
if ((i + 1) == length) {
|
if ((i + 1) == length) {
|
||||||
// Set last byte bit
|
// Set last byte bit
|
||||||
HOCTL |= (1 << 5);
|
*(i2c->hoctl) |= (1 << 5);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Write byte
|
// Write byte
|
||||||
HOBDB = data[i];
|
*(i2c->hobdb) = data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are already in a transaction
|
// If we are already in a transaction
|
||||||
if (HOSTA & HOSTA_BYTE_DONE) {
|
if (*(i2c->hosta) & HOSTA_BYTE_DONE) {
|
||||||
// Clear status to process next byte
|
// Clear status to process next byte
|
||||||
HOSTA = HOSTA;
|
*(i2c->hosta) = *(i2c->hosta);
|
||||||
} else {
|
} else {
|
||||||
// Start new transaction
|
// Start new transaction
|
||||||
HOCTL = (1 << 6) | (0b111 << 2);
|
*(i2c->hoctl) = (1 << 6) | (0b111 << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are waiting on direction switch
|
// If we are waiting on direction switch
|
||||||
if (HOCTL2 & (1 << 2)) {
|
if (*(i2c->hoctl2) & (1 << 2)) {
|
||||||
// Complete direction switch
|
// Complete direction switch
|
||||||
HOCTL2 &= ~(1 << 2);
|
*(i2c->hoctl2) &= ~(1 << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for byte done, timeout, or error
|
// Wait for byte done, timeout, or error
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
uint32_t timeout = I2C_TIMEOUT;
|
uint32_t timeout = I2C_TIMEOUT;
|
||||||
for(timeout = I2C_TIMEOUT; timeout > 0; timeout--) {
|
for(timeout = I2C_TIMEOUT; timeout > 0; timeout--) {
|
||||||
status = HOSTA;
|
status = *(i2c->hosta);
|
||||||
// If error occured, kill transaction and return error
|
// If error occured, kill transaction and return error
|
||||||
if (status & HOSTA_ERR) {
|
if (status & HOSTA_ERR) {
|
||||||
i2c_reset(true);
|
i2c_reset(i2c, true);
|
||||||
return -(int)(status);
|
return -(int)(status);
|
||||||
} else
|
} else
|
||||||
// If byte done, break
|
// If byte done, break
|
||||||
@ -110,23 +120,23 @@ static int i2c_transaction(uint8_t * data, int length, bool read) {
|
|||||||
}
|
}
|
||||||
// If timeout occured, kill transaction and return error
|
// If timeout occured, kill transaction and return error
|
||||||
if (timeout == 0) {
|
if (timeout == 0) {
|
||||||
i2c_reset(true);
|
i2c_reset(i2c, true);
|
||||||
return -(0x1000 | (int)status);
|
return -(0x1000 | (int)status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read) {
|
if (read) {
|
||||||
// Read byte
|
// Read byte
|
||||||
data[i] = HOBDB;
|
data[i] = *(i2c->hobdb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_read(uint8_t * data, int length) {
|
int i2c_read(struct I2C * i2c, uint8_t * data, int length) {
|
||||||
return i2c_transaction(data, length, true);
|
return i2c_transaction(i2c, data, length, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_write(uint8_t * data, int length) {
|
int i2c_write(struct I2C * i2c, uint8_t * data, int length) {
|
||||||
return i2c_transaction(data, length, false);
|
return i2c_transaction(i2c, data, length, false);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <common/i2c.h>
|
#include <common/i2c.h>
|
||||||
|
|
||||||
void i2c_reset(bool kill);
|
extern struct I2C __code I2C_0;
|
||||||
|
|
||||||
|
void i2c_reset(struct I2C * i2c, bool kill);
|
||||||
|
|
||||||
#endif // _EC_I2C_H
|
#endif // _EC_I2C_H
|
||||||
|
Reference in New Issue
Block a user