mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-27 21:24:11 -04:00
git subrepo clone --branch=develop https://github.com/m4xw/emuMMC emummc
subrepo: subdir: "emummc" merged: "e72e8f1c" upstream: origin: "https://github.com/m4xw/emuMMC" branch: "develop" commit: "e72e8f1c" git-subrepo: version: "0.4.0" origin: "https://github.com/ingydotnet/git-subrepo" commit: "5d6aba9"
This commit is contained in:
parent
87a1aa17a7
commit
b7a370b156
90 changed files with 21714 additions and 0 deletions
148
emummc/source/soc/i2c.c
Normal file
148
emummc/source/soc/i2c.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2018 naehrwert
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 <string.h>
|
||||
|
||||
#include "i2c.h"
|
||||
#include "../utils/util.h"
|
||||
#include "t210.h"
|
||||
|
||||
static u32 i2c_addrs[] = {
|
||||
0x7000C000, 0x7000C400, 0x7000C500,
|
||||
0x7000C700, 0x7000D000, 0x7000D100
|
||||
};
|
||||
|
||||
static void _i2c_wait(vu32 *base)
|
||||
{
|
||||
base[I2C_CONFIG_LOAD] = 0x25;
|
||||
for (u32 i = 0; i < 20; i++)
|
||||
{
|
||||
usleep(1);
|
||||
if (!(base[I2C_CONFIG_LOAD] & 1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int _i2c_send_pkt(u32 idx, u32 x, u8 *buf, u32 size)
|
||||
{
|
||||
if (size > 4)
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
memcpy(&tmp, buf, size);
|
||||
|
||||
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[0], 0x2000);
|
||||
base = base + (i2c_addrs[idx] - i2c_addrs[0]);
|
||||
base[I2C_CMD_ADDR0] = x << 1; //Set x (send mode).
|
||||
base[I2C_CMD_DATA1] = tmp; //Set value.
|
||||
base[I2C_CNFG] = (2 * size - 2) | 0x2800; //Set size and send mode.
|
||||
_i2c_wait(base); //Kick transaction.
|
||||
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||
while (base[I2C_STATUS] & 0x100)
|
||||
;
|
||||
|
||||
if (base[I2C_STATUS] << 28)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
|
||||
{
|
||||
if (size > 8)
|
||||
return 0;
|
||||
|
||||
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[0], 0x2000);
|
||||
base = base + (i2c_addrs[idx] - i2c_addrs[0]);
|
||||
|
||||
base[I2C_CMD_ADDR0] = (x << 1) | 1; // Set x (recv mode).
|
||||
base[I2C_CNFG] = (size - 1) << 1 | 0x2840; // Set size and recv mode.
|
||||
_i2c_wait(base); // Kick transaction.
|
||||
|
||||
base[I2C_CNFG] = (base[I2C_CNFG] & 0xFFFFFDFF) | 0x200;
|
||||
while (base[I2C_STATUS] & 0x100)
|
||||
;
|
||||
|
||||
if (base[I2C_STATUS] << 28)
|
||||
return 0;
|
||||
|
||||
u32 tmp = base[I2C_CMD_DATA1]; // Get LS value.
|
||||
if (size > 4)
|
||||
{
|
||||
memcpy(buf, &tmp, 4);
|
||||
tmp = base[I2C_CMD_DATA2]; // Get MS value.
|
||||
memcpy(buf + 4, &tmp, size - 4);
|
||||
}
|
||||
else
|
||||
memcpy(buf, &tmp, size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void i2c_init(u32 idx)
|
||||
{
|
||||
vu32 *base = (vu32 *)QueryIoMapping(i2c_addrs[0], 0x2000);
|
||||
base = base + (i2c_addrs[idx] - i2c_addrs[0]);
|
||||
|
||||
base[I2C_CLK_DIVISOR_REGISTER] = 0x50001;
|
||||
base[I2C_BUS_CLEAR_CONFIG] = 0x90003;
|
||||
_i2c_wait(base);
|
||||
|
||||
for (u32 i = 0; i < 10; i++)
|
||||
{
|
||||
usleep(20000);
|
||||
if (base[INTERRUPT_STATUS_REGISTER] & 0x800)
|
||||
break;
|
||||
}
|
||||
|
||||
(vu32)base[I2C_BUS_CLEAR_STATUS];
|
||||
base[INTERRUPT_STATUS_REGISTER] = base[INTERRUPT_STATUS_REGISTER];
|
||||
}
|
||||
|
||||
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size)
|
||||
{
|
||||
u8 tmp[4];
|
||||
|
||||
if (size > 3)
|
||||
return 0;
|
||||
|
||||
tmp[0] = y;
|
||||
memcpy(tmp + 1, buf, size);
|
||||
|
||||
return _i2c_send_pkt(idx, x, tmp, size + 1);
|
||||
}
|
||||
|
||||
int i2c_recv_buf_small(u8 *buf, u32 size, u32 idx, u32 x, u32 y)
|
||||
{
|
||||
int res = _i2c_send_pkt(idx, x, (u8 *)&y, 1);
|
||||
if (res)
|
||||
res = _i2c_recv_pkt(idx, buf, size, x);
|
||||
return res;
|
||||
}
|
||||
|
||||
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b)
|
||||
{
|
||||
return i2c_send_buf_small(idx, x, y, &b, 1);
|
||||
}
|
||||
|
||||
u8 i2c_recv_byte(u32 idx, u32 x, u32 y)
|
||||
{
|
||||
u8 tmp = 0;
|
||||
i2c_recv_buf_small(&tmp, 1, idx, x, y);
|
||||
return tmp;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue