/* * This file is part of Luma3DS * Copyright (C) 2016-2017 Aurora Wright, TuxSH * * 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 . * * Additional Terms 7.b and 7.c of GPLv3 apply to this file: * * Requiring preservation of specified reasonable legal notices or * author attributions in that material or in the Appropriate Legal * Notices displayed by works containing it. * * Prohibiting misrepresentation of the origin of that material, * or requiring that modified versions of such material be marked in * reasonable ways as different from the original version. */ /* * Thanks to whoever contributed in the development of this file */ #include "utils.h" #include "i2c.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}, }; static inline u8 i2cGetDeviceBusId(u8 device_id) { return dev_data[device_id].bus_id; } static inline u8 i2cGetDeviceRegAddr(u8 device_id) { return dev_data[device_id].reg_addr; } //----------------------------------------------------------------------------- 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), }; static inline vu8 *i2cGetDataReg(u8 bus_id) { return reg_data_addrs[bus_id]; } //----------------------------------------------------------------------------- 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), }; static inline vu8 *i2cGetCntReg(u8 bus_id) { return reg_cnt_addrs[bus_id]; } //----------------------------------------------------------------------------- static inline void i2cWaitBusy(u8 bus_id) { while (*i2cGetCntReg(bus_id) & 0x80); } static inline bool i2cGetResult(u8 bus_id) { i2cWaitBusy(bus_id); return (*i2cGetCntReg(bus_id) >> 4) & 1; } static void i2cStop(u8 bus_id, u8 arg0) { *i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0; i2cWaitBusy(bus_id); *i2cGetCntReg(bus_id) = 0xC5; } //----------------------------------------------------------------------------- static bool i2cSelectDevice(u8 bus_id, u8 dev_reg) { i2cWaitBusy(bus_id); *i2cGetDataReg(bus_id) = dev_reg; *i2cGetCntReg(bus_id) = 0xC2; return i2cGetResult(bus_id); } static 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), dev_addr = i2cGetDeviceRegAddr(dev_id), ret = 0xFF; for(u32 i = 0; i < 8 && ret == 0xFF; 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); ret = *i2cGetDataReg(bus_id); } } *i2cGetCntReg(bus_id) = 0xC5; i2cWaitBusy(bus_id); } wait(3ULL); return ret; } bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data) { u8 bus_id = i2cGetDeviceBusId(dev_id), dev_addr = i2cGetDeviceRegAddr(dev_id); bool ret = false; for(u32 i = 0; i < 8 && !ret; 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)) ret = true; } *i2cGetCntReg(bus_id) = 0xC5; i2cWaitBusy(bus_id); } wait(3ULL); return ret; }