This repository has been archived on 2022-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
Luma3DS-3GX/source/i2c.c

177 lines
4.6 KiB
C
Raw Permalink Normal View History

2016-07-05 16:05:53 +02:00
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
2016-07-05 16:05:53 +02:00
*
* 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/>.
*
* 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.
2016-07-05 16:05:53 +02:00
*/
2016-09-08 23:07:03 +02:00
/*
* Thanks to whoever contributed in the development of this file
2016-09-08 23:07:03 +02:00
*/
2017-06-04 18:32:09 +02:00
#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;
}
//-----------------------------------------------------------------------------
2016-04-26 20:06:31 +02:00
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),
};
2016-04-26 20:06:31 +02:00
static inline vu8 *i2cGetDataReg(u8 bus_id)
{
return reg_data_addrs[bus_id];
}
//-----------------------------------------------------------------------------
2016-04-26 20:06:31 +02:00
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),
};
2016-04-26 20:06:31 +02:00
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);
}
2016-09-08 23:07:03 +02:00
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;
}
//-----------------------------------------------------------------------------
2016-09-08 23:07:03 +02:00
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);
}
2016-09-08 23:07:03 +02:00
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),
2017-06-04 18:32:09 +02:00
dev_addr = i2cGetDeviceRegAddr(dev_id),
ret = 0xFF;
2017-06-04 18:32:09 +02:00
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);
2017-06-04 18:32:09 +02:00
ret = *i2cGetDataReg(bus_id);
}
}
*i2cGetCntReg(bus_id) = 0xC5;
i2cWaitBusy(bus_id);
}
2017-06-04 18:32:09 +02:00
wait(3ULL);
return ret;
}
2016-09-08 23:07:03 +02:00
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
{
2016-09-14 22:31:25 +02:00
u8 bus_id = i2cGetDeviceBusId(dev_id),
dev_addr = i2cGetDeviceRegAddr(dev_id);
2017-06-04 18:32:09 +02:00
bool ret = false;
for(u32 i = 0; i < 8 && !ret; i++)
{
2016-04-26 20:06:31 +02:00
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);
2017-06-04 18:32:09 +02:00
if(i2cGetResult(bus_id)) ret = true;
}
*i2cGetCntReg(bus_id) = 0xC5;
i2cWaitBusy(bus_id);
}
2017-06-04 18:32:09 +02:00
wait(3ULL);
return ret;
}