diff --git a/include/arm11/hardware/i2c.h b/include/arm11/hardware/i2c.h index dd7472a..ca34cf6 100644 --- a/include/arm11/hardware/i2c.h +++ b/include/arm11/hardware/i2c.h @@ -30,8 +30,6 @@ #define I2C_IRQ_ENABLE (1u<<6) #define I2C_ENABLE (1u<<7) -#define I2C_GET_ACK(reg) ((bool)((reg)>>4 & 1u)) - typedef enum { diff --git a/include/arm11/hardware/interrupt.h b/include/arm11/hardware/interrupt.h index 4569ba3..594771e 100644 --- a/include/arm11/hardware/interrupt.h +++ b/include/arm11/hardware/interrupt.h @@ -85,7 +85,10 @@ IRQ_PXI_UNK = 81, // Unknown what this is for IRQ_PXI_NOT_FULL = 82, IRQ_PXI_NOT_EMPTY = 83, + IRQ_I2C1 = 84, + IRQ_I2C2 = 85, IRQ_PDN = 88, + IRQ_I2C3 = 92, IRQ_SHELL_OPENED = 96, IRQ_SHELL_CLOSED = 98, IRQ_TOUCHSCREEN = 99, // Triggers on hitting the touchscreen. diff --git a/source/arm11/hardware/hid.c b/source/arm11/hardware/hid.c index 0422fb5..c192793 100644 --- a/source/arm11/hardware/hid.c +++ b/source/arm11/hardware/hid.c @@ -29,7 +29,8 @@ static u32 kHeld = 0, kDown = 0, kUp = 0; -static vu32 homeShellState = 0, powerWifiState = 0; +static u32 homeShellState = 0, powerWifiState = 0; +static volatile bool mcuIrq = false; @@ -44,11 +45,19 @@ //I2C_writeRegBuf(I2C_DEV_MCU, 0x18, (const u8*)&mcuInterruptMask, 4); IRQ_registerHandler(IRQ_MCU_HID, 14, 0, true, hidIrqHandler); - GPIO_setBit(19, 9); // This enables the MCU HID IRQ + GPIO_setBit(19, 9); // This enables the MCU IRQ. } static void hidIrqHandler(UNUSED u32 intSource) { + mcuIrq = true; +} + +static void updateMcuIrqState(void) +{ + if(!mcuIrq) return; + mcuIrq = false; + const u32 state = (u32)i2cmcu_readreg_hid_irq(); u32 tmp = powerWifiState; @@ -90,6 +99,8 @@ void hidScanInput(void) { + updateMcuIrqState(); + u32 kOld = kHeld; kHeld = homeShellState | REG_HID_PAD;; kDown = (~kOld) & kHeld; diff --git a/source/arm11/hardware/i2c.c b/source/arm11/hardware/i2c.c index 156a647..a40a275 100644 --- a/source/arm11/hardware/i2c.c +++ b/source/arm11/hardware/i2c.c @@ -23,18 +23,16 @@ #define I2C1_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x61000) - #define I2C2_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x44000) - #define I2C3_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x48000) typedef struct { - vu8 REG_I2C_DATA; - vu8 REG_I2C_CNT; - vu16 REG_I2C_CNTEX; - vu16 REG_I2C_SCL; + vu8 I2C_DATA; + vu8 I2C_CNT; + vu16 I2C_CNTEX; + vu16 I2C_SCL; } I2cRegs; static const struct @@ -65,11 +63,6 @@ -static void i2cWaitBusy(I2cRegs *const regs) -{ - while(regs->REG_I2C_CNT & I2C_ENABLE); -} - static I2cRegs* i2cGetBusRegsBase(u8 busId) { I2cRegs *base; @@ -91,147 +84,145 @@ return base; } +static void i2cWaitBusy(I2cRegs *const regs) +{ + while(regs->I2C_CNT & I2C_ENABLE); +} + +static void i2cWaitBusyIrq(I2cRegs *const regs) +{ + while(regs->I2C_CNT & I2C_ENABLE) __wfi(); +} + void I2C_init(void) { - static bool initialized; + static bool initialized = false; /* run-once */ - if(initialized) - return; + if(initialized) return; + initialized = true; + + IRQ_registerHandler(IRQ_I2C1, 14, 0, true, NULL); + IRQ_registerHandler(IRQ_I2C2, 14, 0, true, NULL); + IRQ_registerHandler(IRQ_I2C3, 14, 0, true, NULL); I2cRegs *regs = i2cGetBusRegsBase(0); // Bus 1 i2cWaitBusy(regs); - regs->REG_I2C_CNTEX = 2; // ? - regs->REG_I2C_SCL = 1280; // ? + regs->I2C_CNTEX = 2; // TODO: Find out what this does. If bit 1 is not set I2C hangs. + regs->I2C_SCL = 1280; // TODO: How to calculate the frequency. regs = i2cGetBusRegsBase(1); // Bus 2 i2cWaitBusy(regs); - regs->REG_I2C_CNTEX = 2; // ? - regs->REG_I2C_SCL = 1280; // ? + regs->I2C_CNTEX = 2; + regs->I2C_SCL = 1280; regs = i2cGetBusRegsBase(2); // Bus 3 i2cWaitBusy(regs); - regs->REG_I2C_CNTEX = 2; // ? - regs->REG_I2C_SCL = 1280; // ? - - initialized = true; + regs->I2C_CNTEX = 2; + regs->I2C_SCL = 1280; } -static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, I2cRegs *const regs) +static bool i2cStartTransfer(u8 devAddr, u8 regAddr, bool read, I2cRegs *const regs) { - const u8 devAddr = i2cDevTable[devId].devAddr; - - - u32 i = 0; - for(; i < 8; i++) + u32 tries = 8; + do { - i2cWaitBusy(regs); + i2cWaitBusyIrq(regs); // Select device and start. - regs->REG_I2C_DATA = devAddr; - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; - i2cWaitBusy(regs); - if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. + regs->I2C_DATA = devAddr; + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_START; + i2cWaitBusyIrq(regs); + if(!(regs->I2C_CNT & I2C_ACK)) // If ack flag is 0 it failed. { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; continue; } - // Select register and change direction to write. - regs->REG_I2C_DATA = regAddr; - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; - i2cWaitBusy(regs); - if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. + // Select register. + regs->I2C_DATA = regAddr; + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; + i2cWaitBusyIrq(regs); + if(!(regs->I2C_CNT & I2C_ACK)) { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; continue; } // Select device in read mode for read transfer. if(read) { - regs->REG_I2C_DATA = devAddr | 1u; // Set bit 0 for read. - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; - i2cWaitBusy(regs); - if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. + regs->I2C_DATA = devAddr | 1u; // Set bit 0 for read. + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_START; + i2cWaitBusyIrq(regs); + if(!(regs->I2C_CNT & I2C_ACK)) { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; continue; } } break; - } + } while(--tries > 0); - if(i < 8) return true; - else return false; + return tries > 0; } bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size) { - const u32 oldState = enterCriticalSection(); // TODO: Don't block interrupts. const u8 busId = i2cDevTable[devId].busId; + const u8 devAddr = i2cDevTable[devId].devAddr; I2cRegs *const regs = i2cGetBusRegsBase(busId); - if(!i2cStartTransfer(devId, regAddr, true, regs)) - { - leaveCriticalSection(oldState); - return false; - } + if(!i2cStartTransfer(devAddr, regAddr, true, regs)) return false; while(--size) { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK; - i2cWaitBusy(regs); - *out++ = regs->REG_I2C_DATA; + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK; + i2cWaitBusyIrq(regs); + *out++ = regs->I2C_DATA; } - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP; - i2cWaitBusy(regs); - *out = regs->REG_I2C_DATA; // Last byte + // Last byte transfer. + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP; + i2cWaitBusyIrq(regs); + *out = regs->I2C_DATA; - leaveCriticalSection(oldState); return true; } bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size) { - const u32 oldState = enterCriticalSection(); // TODO: Don't block interrupts. const u8 busId = i2cDevTable[devId].busId; + const u8 devAddr = i2cDevTable[devId].devAddr; I2cRegs *const regs = i2cGetBusRegsBase(busId); - if(!i2cStartTransfer(devId, regAddr, false, regs)) - { - leaveCriticalSection(oldState); - return false; - } + if(!i2cStartTransfer(devAddr, regAddr, false, regs)) return false; while(--size) { - regs->REG_I2C_DATA = *in++; - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; - i2cWaitBusy(regs); - if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. + regs->I2C_DATA = *in++; + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; + i2cWaitBusyIrq(regs); + if(!(regs->I2C_CNT & I2C_ACK)) { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - leaveCriticalSection(oldState); + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; return false; } } - regs->REG_I2C_DATA = *in; - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP; - i2cWaitBusy(regs); - if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. + // Last byte transfer. + regs->I2C_DATA = *in; + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP; + i2cWaitBusyIrq(regs); + if(!(regs->I2C_CNT & I2C_ACK)) { - regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - leaveCriticalSection(oldState); + regs->I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; return false; } - leaveCriticalSection(oldState); return true; } diff --git a/source/arm11/power.c b/source/arm11/power.c index 0422e74..dd37cfc 100644 --- a/source/arm11/power.c +++ b/source/arm11/power.c @@ -21,11 +21,8 @@ #include "ipc_handler.h" #include "arm11/hardware/mcu.h" #include "arm11/hardware/timer.h" -#include "arm11/hardware/interrupt.h" #include "hardware/cache.h" -#include "hardware/gfx.h" #include "hardware/pxi.h" -#include "system.h" #include "arm.h" @@ -38,9 +35,7 @@ // give the screens a bit of time to turn off TIMER_sleepMs(400); - __systemDeinit(); flushDCache(); - __cpsid(aif); } noreturn void power_off(void) @@ -49,6 +44,7 @@ MCU_triggerPowerOff(); + __cpsid(aif); while(1) __wfi(); } @@ -58,5 +54,6 @@ MCU_triggerReboot(); + __cpsid(aif); while(1) __wfi(); } diff --git a/source/arm11/system.c b/source/arm11/system.c index e73f016..c933dce 100644 --- a/source/arm11/system.c +++ b/source/arm11/system.c @@ -65,5 +65,6 @@ void WEAK __systemDeinit(void) { + __cpsid(aif); IRQ_init(); }