From 93545fb83cbedadb57c389bef5bcd9409f5413c2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Jan 2020 16:25:30 -0700 Subject: [PATCH] Add support for multiple I2C buses --- src/board/system76/galp3-c/battery.c | 6 +- .../system76/galp3-c/include/board/gpio.h | 2 + .../system76/galp3-c/include/board/keymap.h | 2 +- src/board/system76/galp3-c/scratch/stdio.c | 4 +- src/board/system76/galp3-c/smbus.c | 2 +- src/board/system76/galp3-c/stdio.c | 4 +- src/board/system76/lemp9/battery.c | 6 +- src/board/system76/lemp9/scratch/stdio.c | 4 +- src/board/system76/lemp9/smbus.c | 2 +- src/board/system76/lemp9/stdio.c | 4 +- src/common/i2c.c | 32 +++---- src/common/include/common/i2c.h | 19 ++-- src/ec/it5570e/i2c.c | 90 ++++++++++--------- src/ec/it5570e/include/ec/i2c.h | 4 +- src/ec/it8587e/i2c.c | 90 ++++++++++--------- src/ec/it8587e/include/ec/i2c.h | 4 +- 16 files changed, 152 insertions(+), 123 deletions(-) diff --git a/src/board/system76/galp3-c/battery.c b/src/board/system76/galp3-c/battery.c index 8a98771..d107622 100644 --- a/src/board/system76/galp3-c/battery.c +++ b/src/board/system76/galp3-c/battery.c @@ -1,12 +1,12 @@ #include -#include +#include 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) { - return i2c_set(address, command, (uint8_t *)&data, 2); + return i2c_set(&I2C_0, address, command, (uint8_t *)&data, 2); } // ChargeOption0 flags diff --git a/src/board/system76/galp3-c/include/board/gpio.h b/src/board/system76/galp3-c/include/board/gpio.h index 17b749b..bb2bc9a 100644 --- a/src/board/system76/galp3-c/include/board/gpio.h +++ b/src/board/system76/galp3-c/include/board/gpio.h @@ -23,6 +23,8 @@ extern struct Gpio __code DD_ON; extern struct Gpio __code EC_EN; extern struct Gpio __code EC_RSMRST_N; 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 LID_SW_N; extern struct Gpio __code PCH_DPWROK_EC; diff --git a/src/board/system76/galp3-c/include/board/keymap.h b/src/board/system76/galp3-c/include/board/keymap.h index ddd0f53..43913ad 100644 --- a/src/board/system76/galp3-c/include/board/keymap.h +++ b/src/board/system76/galp3-c/include/board/keymap.h @@ -11,7 +11,7 @@ #define KM_LAY 2 // 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 uint16_t keymap(int output, int input, int layer); diff --git a/src/board/system76/galp3-c/scratch/stdio.c b/src/board/system76/galp3-c/scratch/stdio.c index 6537ec8..2a552ab 100644 --- a/src/board/system76/galp3-c/scratch/stdio.c +++ b/src/board/system76/galp3-c/scratch/stdio.c @@ -5,7 +5,7 @@ #endif #ifdef I2C_DEBUGGER - #include + #include #endif int putchar(int c) { @@ -14,7 +14,7 @@ int putchar(int c) { SBUF = byte; #endif #ifdef I2C_DEBUGGER - i2c_send(I2C_DEBUGGER, &byte, 1); + i2c_send(&I2C_0, I2C_DEBUGGER, &byte, 1); #endif return (int)byte; } diff --git a/src/board/system76/galp3-c/smbus.c b/src/board/system76/galp3-c/smbus.c index c3df1cd..c61c31d 100644 --- a/src/board/system76/galp3-c/smbus.c +++ b/src/board/system76/galp3-c/smbus.c @@ -17,5 +17,5 @@ void smbus_init(void) { SMB45P3USH = 0x01; // Set up for i2c usage - i2c_reset(true); + i2c_reset(&I2C_0, true); } diff --git a/src/board/system76/galp3-c/stdio.c b/src/board/system76/galp3-c/stdio.c index 6537ec8..2a552ab 100644 --- a/src/board/system76/galp3-c/stdio.c +++ b/src/board/system76/galp3-c/stdio.c @@ -5,7 +5,7 @@ #endif #ifdef I2C_DEBUGGER - #include + #include #endif int putchar(int c) { @@ -14,7 +14,7 @@ int putchar(int c) { SBUF = byte; #endif #ifdef I2C_DEBUGGER - i2c_send(I2C_DEBUGGER, &byte, 1); + i2c_send(&I2C_0, I2C_DEBUGGER, &byte, 1); #endif return (int)byte; } diff --git a/src/board/system76/lemp9/battery.c b/src/board/system76/lemp9/battery.c index d2cab3a..1eb87c9 100644 --- a/src/board/system76/lemp9/battery.c +++ b/src/board/system76/lemp9/battery.c @@ -1,12 +1,12 @@ #include -#include +#include 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) { - return i2c_set(address, command, (uint8_t *)&data, 2); + return i2c_set(&I2C_4, address, command, (uint8_t *)&data, 2); } // ChargeOption0 flags diff --git a/src/board/system76/lemp9/scratch/stdio.c b/src/board/system76/lemp9/scratch/stdio.c index 6537ec8..bd5e99e 100644 --- a/src/board/system76/lemp9/scratch/stdio.c +++ b/src/board/system76/lemp9/scratch/stdio.c @@ -5,7 +5,7 @@ #endif #ifdef I2C_DEBUGGER - #include + #include #endif int putchar(int c) { @@ -14,7 +14,7 @@ int putchar(int c) { SBUF = byte; #endif #ifdef I2C_DEBUGGER - i2c_send(I2C_DEBUGGER, &byte, 1); + i2c_send(&I2C_4, I2C_DEBUGGER, &byte, 1); #endif return (int)byte; } diff --git a/src/board/system76/lemp9/smbus.c b/src/board/system76/lemp9/smbus.c index c3df1cd..7808cbe 100644 --- a/src/board/system76/lemp9/smbus.c +++ b/src/board/system76/lemp9/smbus.c @@ -17,5 +17,5 @@ void smbus_init(void) { SMB45P3USH = 0x01; // Set up for i2c usage - i2c_reset(true); + i2c_reset(&I2C_4, true); } diff --git a/src/board/system76/lemp9/stdio.c b/src/board/system76/lemp9/stdio.c index 6537ec8..bd5e99e 100644 --- a/src/board/system76/lemp9/stdio.c +++ b/src/board/system76/lemp9/stdio.c @@ -5,7 +5,7 @@ #endif #ifdef I2C_DEBUGGER - #include + #include #endif int putchar(int c) { @@ -14,7 +14,7 @@ int putchar(int c) { SBUF = byte; #endif #ifdef I2C_DEBUGGER - i2c_send(I2C_DEBUGGER, &byte, 1); + i2c_send(&I2C_4, I2C_DEBUGGER, &byte, 1); #endif return (int)byte; } diff --git a/src/common/i2c.c b/src/common/i2c.c index b3c4d9f..d3ecf65 100644 --- a/src/common/i2c.c +++ b/src/common/i2c.c @@ -1,53 +1,53 @@ #include -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; - res = i2c_start(addr, true); + res = i2c_start(i2c, addr, true); if (res < 0) return res; - res = i2c_read(data, length); + res = i2c_read(i2c, data, length); if (res < 0) return res; - i2c_stop(); + i2c_stop(i2c); 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; - res = i2c_start(addr, false); + res = i2c_start(i2c, addr, false); if (res < 0) return res; - res = i2c_write(data, length); + res = i2c_write(i2c, data, length); if (res < 0) return res; - i2c_stop(); + i2c_stop(i2c); 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; - res = i2c_start(addr, false); + res = i2c_start(i2c, addr, false); if (res < 0) return res; - res = i2c_write(®, 1); + res = i2c_write(i2c, ®, 1); 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; - res = i2c_start(addr, false); + res = i2c_start(i2c, addr, false); if (res < 0) return res; - res = i2c_write(®, 1); + res = i2c_write(i2c, ®, 1); if (res < 0) return res; - return i2c_send(addr, data, length); + return i2c_send(i2c, addr, data, length); } diff --git a/src/common/include/common/i2c.h b/src/common/include/common/i2c.h index 8f79820..9e3b9b3 100644 --- a/src/common/include/common/i2c.h +++ b/src/common/include/common/i2c.h @@ -4,32 +4,35 @@ #include #include +// I2C bus, should be defined elsewhere +struct I2C; + // Start i2c transaction // 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 // Must be defined by arch, board, or ec -void i2c_stop(void); +void i2c_stop(struct I2C * i2c); // Send a byte on i2c bus // 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 // 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 -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 -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 -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 -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 diff --git a/src/ec/it5570e/i2c.c b/src/ec/it5570e/i2c.c index e1a6557..bc5c13f 100644 --- a/src/ec/it5570e/i2c.c +++ b/src/ec/it5570e/i2c.c @@ -6,101 +6,111 @@ //TODO: find best value #define I2C_TIMEOUT 10000 -#define HOSTA HOSTAE -#define HOCTL HOCTLE -#define HOCTL2 HOCTL2E -#define HOBDB HOBDBE -#define TRASLA TRASLAE +struct I2C { + volatile uint8_t * hosta; + volatile uint8_t * hoctl; + volatile uint8_t * hoctl2; + volatile uint8_t * hobdb; + volatile uint8_t * trasla; +}; -void i2c_reset(bool kill) { - if (HOSTA & HOSTA_BUSY) { +struct I2C __code I2C_4 = { + .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 - if (kill) HOCTL |= (1 << 1); + if (kill) *(i2c->hoctl) |= (1 << 1); // Wait for host to finish - while (HOSTA & HOSTA_BUSY) {} + while (*(i2c->hosta) & HOSTA_BUSY) {} } // Clear status register - HOSTA = HOSTA; + *(i2c->hosta) = *(i2c->hosta); // Clear current command - HOCTL = 0; + *(i2c->hoctl) = 0; // 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 (HOSTA & HOSTA_BYTE_DONE) { + if (*(i2c->hosta) & HOSTA_BYTE_DONE) { // If we are switching direction - if ((TRASLA & 1) != read) { + if ((*(i2c->trasla) & 1) != read) { // If we are switching to read mode if (read) { // Enable direction switch - HOCTL2 |= (1 << 3) | (1 << 2); + *(i2c->hoctl2) |= (1 << 3) | (1 << 2); } else { // Unsupported! - i2c_reset(true); + i2c_reset(i2c, true); return -1; } } } else { - i2c_reset(true); + i2c_reset(i2c, true); // Enable host controller with i2c compatibility - HOCTL2 = (1 << 1) | 1; + *(i2c->hoctl2) = (1 << 1) | 1; // Set address - TRASLA = (addr << 1) | read; + *(i2c->trasla) = (addr << 1) | read; } return 0; } -void i2c_stop(void) { +void i2c_stop(struct I2C * i2c) { // Disable i2c compatibility - HOCTL2 &= ~(1 << 1); + *(i2c->hoctl2) &= ~(1 << 1); // 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; for (i = 0; i < length; i++) { if (read) { // If last byte if ((i + 1) == length) { // Set last byte bit - HOCTL |= (1 << 5); + *(i2c->hoctl) |= (1 << 5); } } else { // Write byte - HOBDB = data[i]; + *(i2c->hobdb) = data[i]; } // If we are already in a transaction - if (HOSTA & HOSTA_BYTE_DONE) { + if (*(i2c->hosta) & HOSTA_BYTE_DONE) { // Clear status to process next byte - HOSTA = HOSTA; + *(i2c->hosta) = *(i2c->hosta); } else { // Start new transaction - HOCTL = (1 << 6) | (0b111 << 2); + *(i2c->hoctl) = (1 << 6) | (0b111 << 2); } // If we are waiting on direction switch - if (HOCTL2 & (1 << 2)) { + if (*(i2c->hoctl2) & (1 << 2)) { // Complete direction switch - HOCTL2 &= ~(1 << 2); + *(i2c->hoctl2) &= ~(1 << 2); } // Wait for byte done, timeout, or error uint8_t status; uint32_t timeout = I2C_TIMEOUT; for(timeout = I2C_TIMEOUT; timeout > 0; timeout--) { - status = HOSTA; + status = *(i2c->hosta); // If error occured, kill transaction and return error if (status & HOSTA_ERR) { - i2c_reset(true); + i2c_reset(i2c, true); return -(int)(status); } else // 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 == 0) { - i2c_reset(true); + i2c_reset(i2c, true); return -(0x1000 | (int)status); } if (read) { // Read byte - data[i] = HOBDB; + data[i] = *(i2c->hobdb); } } return i; } -int i2c_read(uint8_t * data, int length) { - return i2c_transaction(data, length, true); +int i2c_read(struct I2C * i2c, uint8_t * data, int length) { + return i2c_transaction(i2c, data, length, true); } -int i2c_write(uint8_t * data, int length) { - return i2c_transaction(data, length, false); +int i2c_write(struct I2C * i2c, uint8_t * data, int length) { + return i2c_transaction(i2c, data, length, false); } diff --git a/src/ec/it5570e/include/ec/i2c.h b/src/ec/it5570e/include/ec/i2c.h index 7b1af45..9b2de18 100644 --- a/src/ec/it5570e/include/ec/i2c.h +++ b/src/ec/it5570e/include/ec/i2c.h @@ -3,6 +3,8 @@ #include -void i2c_reset(bool kill); +extern struct I2C __code I2C_4; + +void i2c_reset(struct I2C * i2c, bool kill); #endif // _EC_I2C_H diff --git a/src/ec/it8587e/i2c.c b/src/ec/it8587e/i2c.c index cb03048..9b86eec 100644 --- a/src/ec/it8587e/i2c.c +++ b/src/ec/it8587e/i2c.c @@ -6,101 +6,111 @@ //TODO: find best value #define I2C_TIMEOUT 10000 -#define HOSTA HOSTAA -#define HOCTL HOCTLA -#define HOCTL2 HOCTL2A -#define HOBDB HOBDBA -#define TRASLA TRASLAA +struct I2C { + volatile uint8_t * hosta; + volatile uint8_t * hoctl; + volatile uint8_t * hoctl2; + volatile uint8_t * hobdb; + volatile uint8_t * trasla; +}; -void i2c_reset(bool kill) { - if (HOSTA & HOSTA_BUSY) { +struct I2C __code I2C_0 = { + .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 - if (kill) HOCTL |= (1 << 1); + if (kill) *(i2c->hoctl) |= (1 << 1); // Wait for host to finish - while (HOSTA & HOSTA_BUSY) {} + while (*(i2c->hosta) & HOSTA_BUSY) {} } // Clear status register - HOSTA = HOSTA; + *(i2c->hosta) = *(i2c->hosta); // Clear current command - HOCTL = 0; + *(i2c->hoctl) = 0; // 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 (HOSTA & HOSTA_BYTE_DONE) { + if (*(i2c->hosta) & HOSTA_BYTE_DONE) { // If we are switching direction - if ((TRASLA & 1) != read) { + if ((*(i2c->trasla) & 1) != read) { // If we are switching to read mode if (read) { // Enable direction switch - HOCTL2 |= (1 << 3) | (1 << 2); + *(i2c->hoctl2) |= (1 << 3) | (1 << 2); } else { // Unsupported! - i2c_reset(true); + i2c_reset(i2c, true); return -1; } } } else { - i2c_reset(true); + i2c_reset(i2c, true); // Enable host controller with i2c compatibility - HOCTL2 = (1 << 1) | 1; + *(i2c->hoctl2) = (1 << 1) | 1; // Set address - TRASLA = (addr << 1) | read; + *(i2c->trasla) = (addr << 1) | read; } return 0; } -void i2c_stop(void) { +void i2c_stop(struct I2C * i2c) { // Disable i2c compatibility - HOCTL2 &= ~(1 << 1); + *(i2c->hoctl2) &= ~(1 << 1); // 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; for (i = 0; i < length; i++) { if (read) { // If last byte if ((i + 1) == length) { // Set last byte bit - HOCTL |= (1 << 5); + *(i2c->hoctl) |= (1 << 5); } } else { // Write byte - HOBDB = data[i]; + *(i2c->hobdb) = data[i]; } // If we are already in a transaction - if (HOSTA & HOSTA_BYTE_DONE) { + if (*(i2c->hosta) & HOSTA_BYTE_DONE) { // Clear status to process next byte - HOSTA = HOSTA; + *(i2c->hosta) = *(i2c->hosta); } else { // Start new transaction - HOCTL = (1 << 6) | (0b111 << 2); + *(i2c->hoctl) = (1 << 6) | (0b111 << 2); } // If we are waiting on direction switch - if (HOCTL2 & (1 << 2)) { + if (*(i2c->hoctl2) & (1 << 2)) { // Complete direction switch - HOCTL2 &= ~(1 << 2); + *(i2c->hoctl2) &= ~(1 << 2); } // Wait for byte done, timeout, or error uint8_t status; uint32_t timeout = I2C_TIMEOUT; for(timeout = I2C_TIMEOUT; timeout > 0; timeout--) { - status = HOSTA; + status = *(i2c->hosta); // If error occured, kill transaction and return error if (status & HOSTA_ERR) { - i2c_reset(true); + i2c_reset(i2c, true); return -(int)(status); } else // 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 == 0) { - i2c_reset(true); + i2c_reset(i2c, true); return -(0x1000 | (int)status); } if (read) { // Read byte - data[i] = HOBDB; + data[i] = *(i2c->hobdb); } } return i; } -int i2c_read(uint8_t * data, int length) { - return i2c_transaction(data, length, true); +int i2c_read(struct I2C * i2c, uint8_t * data, int length) { + return i2c_transaction(i2c, data, length, true); } -int i2c_write(uint8_t * data, int length) { - return i2c_transaction(data, length, false); +int i2c_write(struct I2C * i2c, uint8_t * data, int length) { + return i2c_transaction(i2c, data, length, false); } diff --git a/src/ec/it8587e/include/ec/i2c.h b/src/ec/it8587e/include/ec/i2c.h index 7b1af45..9cd9e19 100644 --- a/src/ec/it8587e/include/ec/i2c.h +++ b/src/ec/it8587e/include/ec/i2c.h @@ -3,6 +3,8 @@ #include -void i2c_reset(bool kill); +extern struct I2C __code I2C_0; + +void i2c_reset(struct I2C * i2c, bool kill); #endif // _EC_I2C_H