mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Updated I2C routines
Thank @profi200
This commit is contained in:
parent
dc85dccd06
commit
e434c5aac8
@ -18,11 +18,13 @@ u32 InputWait() {
|
||||
u32 sd_state = SD_STATE;
|
||||
if (sd_state != sd_state_old)
|
||||
return sd_state ? SD_INSERT : SD_EJECT;
|
||||
u32 special_key = i2cReadRegister(I2C_DEV_MCU, 0x10);
|
||||
if (special_key == 0x01)
|
||||
return pad_state | BUTTON_POWER;
|
||||
else if (special_key == 0x04)
|
||||
return pad_state | BUTTON_HOME;
|
||||
u8 special_key;
|
||||
if (I2C_readRegBuf(I2C_DEV_MCU, 0x10, &special_key, 1)) {
|
||||
if (special_key == 0x01)
|
||||
return pad_state | BUTTON_POWER;
|
||||
else if (special_key == 0x04)
|
||||
return pad_state | BUTTON_HOME;
|
||||
}
|
||||
pad_state_old = pad_state;
|
||||
delay = 0;
|
||||
continue;
|
||||
|
@ -1,156 +1,195 @@
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2017 derrek, profi200
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "i2c.h"
|
||||
#include "timer.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static const struct { u8 bus_id, reg_addr; } dev_data[] = {
|
||||
{0, 0x4A}, {0, 0x7A}, {0, 0x78},
|
||||
{1, 0x4A}, {1, 0x78}, {1, 0x2C},
|
||||
{1, 0x2E}, {1, 0x40}, {1, 0x44},
|
||||
{2, 0xD6}, {2, 0xD0}, {2, 0xD2},
|
||||
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
|
||||
#define I2C1_REGS_BASE (0x10161000)
|
||||
#define REG_I2C1_DATA *((vu8* )(I2C1_REGS_BASE + 0x00))
|
||||
#define REG_I2C1_CNT *((vu8* )(I2C1_REGS_BASE + 0x01))
|
||||
#define REG_I2C1_CNTEX *((vu16*)(I2C1_REGS_BASE + 0x02))
|
||||
#define REG_I2C1_SCL *((vu16*)(I2C1_REGS_BASE + 0x04))
|
||||
|
||||
#define I2C2_REGS_BASE (0x10144000)
|
||||
#define REG_I2C2_DATA *((vu8* )(I2C2_REGS_BASE + 0x00))
|
||||
#define REG_I2C2_CNT *((vu8* )(I2C2_REGS_BASE + 0x01))
|
||||
#define REG_I2C2_CNTEX *((vu16*)(I2C2_REGS_BASE + 0x02))
|
||||
#define REG_I2C2_SCL *((vu16*)(I2C2_REGS_BASE + 0x04))
|
||||
|
||||
#define I2C3_REGS_BASE (0x10148000)
|
||||
#define REG_I2C3_DATA *((vu8* )(I2C3_REGS_BASE + 0x00))
|
||||
#define REG_I2C3_CNT *((vu8* )(I2C3_REGS_BASE + 0x01))
|
||||
#define REG_I2C3_CNTEX *((vu16*)(I2C3_REGS_BASE + 0x02))
|
||||
#define REG_I2C3_SCL *((vu16*)(I2C3_REGS_BASE + 0x04))
|
||||
|
||||
|
||||
static const struct
|
||||
{
|
||||
u8 busId;
|
||||
u8 devAddr;
|
||||
} i2cDevTable[] =
|
||||
{
|
||||
{0, 0x4A},
|
||||
{0, 0x7A},
|
||||
{0, 0x78},
|
||||
{1, 0x4A},
|
||||
{1, 0x78},
|
||||
{1, 0x2C},
|
||||
{1, 0x2E},
|
||||
{1, 0x40},
|
||||
{1, 0x44},
|
||||
{2, 0xA6}, // TODO: Find out if 0xA6 or 0xD6 is correct
|
||||
{2, 0xD0},
|
||||
{2, 0xD2},
|
||||
{2, 0xA4},
|
||||
{2, 0x9A},
|
||||
{2, 0xA0},
|
||||
{1, 0xEE},
|
||||
{0, 0x40},
|
||||
{2, 0x54}
|
||||
};
|
||||
|
||||
inline u8 i2cGetDeviceBusId(u8 device_id) {
|
||||
return dev_data[device_id].bus_id;
|
||||
|
||||
|
||||
static void i2cWaitBusy(vu8 *cntReg)
|
||||
{
|
||||
while(*cntReg & I2C_ENABLE);
|
||||
}
|
||||
|
||||
inline u8 i2cGetDeviceRegAddr(u8 device_id) {
|
||||
return dev_data[device_id].reg_addr;
|
||||
static vu8* i2cGetBusRegsBase(u8 busId)
|
||||
{
|
||||
vu8 *base;
|
||||
if(!busId) base = (vu8*)I2C1_REGS_BASE;
|
||||
else if(busId == 1) base = (vu8*)I2C2_REGS_BASE;
|
||||
else base = (vu8*)I2C3_REGS_BASE;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, vu8 *regsBase)
|
||||
{
|
||||
const u8 devAddr = i2cDevTable[devId].devAddr;
|
||||
vu8 *const i2cData = regsBase;
|
||||
vu8 *const i2cCnt = regsBase + 1;
|
||||
|
||||
static vu8* reg_data_addrs[] = {
|
||||
(vu8*)(I2C1_REG_OFF + I2C_REG_DATA),
|
||||
(vu8*)(I2C2_REG_OFF + I2C_REG_DATA),
|
||||
(vu8*)(I2C3_REG_OFF + I2C_REG_DATA),
|
||||
};
|
||||
|
||||
inline vu8* i2cGetDataReg(u8 bus_id) {
|
||||
return reg_data_addrs[bus_id];
|
||||
u32 i = 0;
|
||||
for(; i < 8; i++)
|
||||
{
|
||||
i2cWaitBusy(i2cCnt);
|
||||
|
||||
// Select device and start.
|
||||
*i2cData = devAddr;
|
||||
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START;
|
||||
i2cWaitBusy(i2cCnt);
|
||||
if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
|
||||
{
|
||||
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select register and change direction to write.
|
||||
*i2cData = regAddr;
|
||||
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE;
|
||||
i2cWaitBusy(i2cCnt);
|
||||
if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
|
||||
{
|
||||
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select device in read mode for read transfer.
|
||||
if(read)
|
||||
{
|
||||
*i2cData = devAddr | 1u; // Set bit 0 for read.
|
||||
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START;
|
||||
i2cWaitBusy(i2cCnt);
|
||||
if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
|
||||
{
|
||||
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(i < 8) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void I2C_init(void)
|
||||
{
|
||||
i2cWaitBusy(i2cGetBusRegsBase(0));
|
||||
REG_I2C1_CNTEX = 2; // ?
|
||||
REG_I2C1_SCL = 1280; // ?
|
||||
|
||||
static vu8* reg_cnt_addrs[] = {
|
||||
(vu8*)(I2C1_REG_OFF + I2C_REG_CNT),
|
||||
(vu8*)(I2C2_REG_OFF + I2C_REG_CNT),
|
||||
(vu8*)(I2C3_REG_OFF + I2C_REG_CNT),
|
||||
};
|
||||
i2cWaitBusy(i2cGetBusRegsBase(1));
|
||||
REG_I2C2_CNTEX = 2; // ?
|
||||
REG_I2C2_SCL = 1280; // ?
|
||||
|
||||
inline vu8* i2cGetCntReg(u8 bus_id) {
|
||||
return reg_cnt_addrs[bus_id];
|
||||
i2cWaitBusy(i2cGetBusRegsBase(2));
|
||||
REG_I2C3_CNTEX = 2; // ?
|
||||
REG_I2C3_SCL = 1280; // ?
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size)
|
||||
{
|
||||
const u8 busId = i2cDevTable[devId].busId;
|
||||
vu8 *const i2cData = i2cGetBusRegsBase(busId);
|
||||
vu8 *const i2cCnt = i2cData + 1;
|
||||
|
||||
inline void i2cWaitBusy(u8 bus_id) {
|
||||
while (*i2cGetCntReg(bus_id) & 0x80);
|
||||
|
||||
if(!i2cStartTransfer(devId, regAddr, true, i2cData)) return false;
|
||||
|
||||
while(--size)
|
||||
{
|
||||
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK;
|
||||
i2cWaitBusy(i2cCnt);
|
||||
*out++ = *i2cData;
|
||||
}
|
||||
|
||||
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP;
|
||||
i2cWaitBusy(i2cCnt);
|
||||
*out = *i2cData; // Last byte
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool i2cGetResult(u8 bus_id) {
|
||||
i2cWaitBusy(bus_id);
|
||||
return (*i2cGetCntReg(bus_id) >> 4) & 1;
|
||||
}
|
||||
|
||||
void i2cStop(u8 bus_id, u8 arg0) {
|
||||
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetCntReg(bus_id) = 0xC5;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool i2cSelectDevice(u8 bus_id, u8 dev_reg) {
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetDataReg(bus_id) = dev_reg;
|
||||
*i2cGetCntReg(bus_id) = 0xC2;
|
||||
return i2cGetResult(bus_id);
|
||||
}
|
||||
|
||||
bool i2cSelectRegister(u8 bus_id, u8 reg) {
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetDataReg(bus_id) = reg;
|
||||
*i2cGetCntReg(bus_id) = 0xC0;
|
||||
return i2cGetResult(bus_id);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
u8 i2cReadRegister(u8 dev_id, u8 reg) {
|
||||
u8 bus_id = i2cGetDeviceBusId(dev_id);
|
||||
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
|
||||
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) {
|
||||
if (i2cSelectDevice(bus_id, dev_addr | 1)) {
|
||||
i2cWaitBusy(bus_id);
|
||||
i2cStop(bus_id, 1);
|
||||
i2cWaitBusy(bus_id);
|
||||
return *i2cGetDataReg(bus_id);
|
||||
}
|
||||
}
|
||||
*i2cGetCntReg(bus_id) = 0xC5;
|
||||
i2cWaitBusy(bus_id);
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size) {
|
||||
u8 bus_id = i2cGetDeviceBusId(dev_id);
|
||||
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
|
||||
|
||||
size_t j = 0;
|
||||
while (!i2cSelectDevice(bus_id, dev_addr)
|
||||
|| !i2cSelectRegister(bus_id, reg)
|
||||
|| !i2cSelectDevice(bus_id, dev_addr | 1))
|
||||
{
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetCntReg(bus_id) = 0xC5;
|
||||
i2cWaitBusy(bus_id);
|
||||
if (++j >= 8)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buf_size != 1) {
|
||||
for (size_t i = 0; i < buf_size - 1; i++) {
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetCntReg(bus_id) = 0xF0;
|
||||
i2cWaitBusy(bus_id);
|
||||
buffer[i] = *i2cGetDataReg(bus_id);
|
||||
}
|
||||
}
|
||||
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetCntReg(bus_id) = 0xE1;
|
||||
i2cWaitBusy(bus_id);
|
||||
buffer[buf_size - 1] = *i2cGetDataReg(bus_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data) {
|
||||
u8 bus_id = i2cGetDeviceBusId(dev_id);
|
||||
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
|
||||
|
||||
wait_msec(3ULL);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) {
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetDataReg(bus_id) = data;
|
||||
*i2cGetCntReg(bus_id) = 0xC1;
|
||||
i2cStop(bus_id, 0);
|
||||
if (i2cGetResult(bus_id)) {
|
||||
wait_msec(3ULL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
*i2cGetCntReg(bus_id) = 0xC5;
|
||||
i2cWaitBusy(bus_id);
|
||||
}
|
||||
|
||||
wait_msec(3ULL);
|
||||
return false;
|
||||
bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data)
|
||||
{
|
||||
const u8 busId = i2cDevTable[devId].busId;
|
||||
vu8 *const i2cData = i2cGetBusRegsBase(busId);
|
||||
vu8 *const i2cCnt = i2cData + 1;
|
||||
|
||||
|
||||
if(!i2cStartTransfer(devId, regAddr, false, i2cData)) return false;
|
||||
|
||||
*i2cData = data;
|
||||
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP;
|
||||
i2cWaitBusy(i2cCnt);
|
||||
|
||||
if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed.
|
||||
{
|
||||
*i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,35 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* This file is part of fastboot 3DS
|
||||
* Copyright (C) 2017 derrek, profi200
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "common.h"
|
||||
|
||||
#define I2C1_REG_OFF 0x10161000
|
||||
#define I2C2_REG_OFF 0x10144000
|
||||
#define I2C3_REG_OFF 0x10148000
|
||||
|
||||
#define I2C_REG_DATA 0
|
||||
#define I2C_REG_CNT 1
|
||||
#define I2C_REG_CNTEX 2
|
||||
#define I2C_REG_SCL 4
|
||||
#define I2C_STOP (1u)
|
||||
#define I2C_START (1u<<1)
|
||||
#define I2C_ERROR (1u<<2)
|
||||
#define I2C_ACK (1u<<4)
|
||||
#define I2C_DIRE_WRITE (0u)
|
||||
#define I2C_DIRE_READ (1u<<5)
|
||||
#define I2C_IRQ_ENABLE (1u<<6)
|
||||
#define I2C_ENABLE (1u<<7)
|
||||
|
||||
#define I2C_DEV_MCU 3
|
||||
#define I2C_DEV_GYRO 10
|
||||
#define I2C_DEV_IR 13
|
||||
#define I2C_GET_ACK(reg) ((bool)((reg)>>4 & 1u))
|
||||
|
||||
u8 i2cGetDeviceBusId(u8 device_id);
|
||||
u8 i2cGetDeviceRegAddr(u8 device_id);
|
||||
|
||||
vu8* i2cGetDataReg(u8 bus_id);
|
||||
vu8* i2cGetCntReg(u8 bus_id);
|
||||
typedef enum
|
||||
{
|
||||
I2C_DEV_POWER = 0, // Unconfirmed
|
||||
I2C_DEV_CAMERA = 1, // Unconfirmed
|
||||
I2C_DEV_CAMERA2 = 2, // Unconfirmed
|
||||
I2C_DEV_MCU = 3,
|
||||
I2C_DEV_GYRO = 10,
|
||||
I2C_DEV_DEBUG_PAD = 12,
|
||||
I2C_DEV_IR = 13,
|
||||
I2C_DEV_EEPROM = 14, // Unconfirmed
|
||||
I2C_DEV_NFC = 15,
|
||||
I2C_DEV_QTM = 16,
|
||||
I2C_DEV_N3DS_HID = 17
|
||||
} I2cDevice;
|
||||
|
||||
void i2cWaitBusy(u8 bus_id);
|
||||
bool i2cGetResult(u8 bus_id);
|
||||
u8 i2cGetData(u8 bus_id);
|
||||
void i2cStop(u8 bus_id, u8 arg0);
|
||||
|
||||
bool i2cSelectDevice(u8 bus_id, u8 dev_reg);
|
||||
bool i2cSelectRegister(u8 bus_id, u8 reg);
|
||||
|
||||
u8 i2cReadRegister(u8 dev_id, u8 reg);
|
||||
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);
|
||||
|
||||
bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size);
|
||||
void I2C_init(void);
|
||||
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size);
|
||||
bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data);
|
||||
|
@ -6,14 +6,14 @@
|
||||
void Reboot() {
|
||||
ClearScreenF(true, true, COLOR_STD_BG);
|
||||
flushEntireDCache();
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
|
||||
while(true);
|
||||
if (I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 2))
|
||||
while(true);
|
||||
}
|
||||
|
||||
void PowerOff()
|
||||
{
|
||||
ClearScreenF(true, true, COLOR_STD_BG);
|
||||
flushEntireDCache();
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
|
||||
while (true);
|
||||
if (I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 0))
|
||||
while (true);
|
||||
}
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "chainload.h"
|
||||
#include "qlzcomp.h"
|
||||
#include "timer.h"
|
||||
#include "power.h"
|
||||
#include "i2c.h"
|
||||
#include QLZ_SPLASH_H
|
||||
|
||||
#define N_PANES 2
|
||||
@ -1599,6 +1601,9 @@ u32 GodMode() {
|
||||
clipboard->n_entries = 0;
|
||||
memset(panedata, 0x00, 0x10000);
|
||||
|
||||
// I2C init
|
||||
// I2C_init();
|
||||
|
||||
// check for embedded essential backup
|
||||
if (IS_SIGHAX && !PathExist("S:/essential.exefs") && CheckGenuineNandNcsd() &&
|
||||
ShowPrompt(true, "Essential files backup not found.\nCreate one now?")) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user