1
0
Fork 0
mirror of https://github.com/CTCaer/hekate.git synced 2024-11-29 21:12:06 +00:00
hekate/bootloader/soc/i2c.c

137 lines
2.7 KiB
C
Raw Normal View History

2018-03-27 00:04:16 +01:00
/*
2018-08-05 12:40:32 +01:00
* 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/>.
*/
2018-03-27 00:04:16 +01:00
#include <string.h>
2018-03-07 01:11:46 +00:00
#include "i2c.h"
2018-08-13 09:58:24 +01:00
#include "../utils/util.h"
2018-03-07 01:11:46 +00:00
2018-08-05 12:40:32 +01:00
static u32 i2c_addrs[] = {
0x7000C000, 0x7000C400, 0x7000C500,
0x7000C700, 0x7000D000, 0x7000D100
};
2018-03-07 01:11:46 +00:00
static void _i2c_wait(vu32 *base)
{
base[0x23] = 0x25;
for (u32 i = 0; i < 20; i++)
{
usleep(1);
2018-03-07 01:11:46 +00:00
if (!(base[0x23] & 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);
2018-03-07 01:11:46 +00:00
vu32 *base = (vu32 *)i2c_addrs[idx];
base[1] = x << 1; //Set x (send mode).
2018-08-05 12:40:32 +01:00
base[3] = tmp; //Set value.
2018-03-07 01:11:46 +00:00
base[0] = (2 * size - 2) | 0x2800; //Set size and send mode.
2018-08-05 12:40:32 +01:00
_i2c_wait(base); //Kick transaction.
2018-03-07 01:11:46 +00:00
2018-06-08 10:42:24 +01:00
base[0] = (base[0] & 0xFFFFFDFF) | 0x200;
2018-03-07 01:11:46 +00:00
while (base[7] & 0x100)
;
if (base[7] << 28)
return 0;
return 1;
}
static int _i2c_recv_pkt(u32 idx, u8 *buf, u32 size, u32 x)
{
if (size > 4)
return 0;
vu32 *base = (vu32 *)i2c_addrs[idx];
2018-08-05 12:40:32 +01:00
base[1] = (x << 1) | 1; // Set x (recv mode).
base[0] = (2 * size - 2) | 0x2840; // Set size and recv mode.
_i2c_wait(base); // Kick transaction.
2018-03-07 01:11:46 +00:00
2018-06-08 10:42:24 +01:00
base[0] = (base[0] & 0xFFFFFDFF) | 0x200;
2018-03-07 01:11:46 +00:00
while (base[7] & 0x100)
;
if (base[7] << 28)
return 0;
2018-08-05 12:40:32 +01:00
u32 tmp = base[3]; // Get value.
memcpy(buf, &tmp, size);
2018-03-07 01:11:46 +00:00
return 1;
}
void i2c_init(u32 idx)
{
vu32 *base = (vu32 *)i2c_addrs[idx];
base[0x1B] = 0x50001;
base[0x21] = 0x90003;
_i2c_wait(base);
for (u32 i = 0; i < 10; i++)
{
usleep(20000);
2018-03-07 01:11:46 +00:00
if (base[0x1A] & 0x800)
break;
}
2018-06-08 10:42:24 +01:00
(vu32)base[0x22];
2018-03-07 01:11:46 +00:00
base[0x1A] = base[0x1A];
}
2018-06-08 10:42:24 +01:00
int i2c_send_buf_small(u32 idx, u32 x, u32 y, u8 *buf, u32 size)
2018-03-07 01:11:46 +00:00
{
u8 tmp[4];
2018-08-05 12:40:32 +01:00
if (size > 3)
2018-03-07 01:11:46 +00:00
return 0;
tmp[0] = y;
memcpy(tmp + 1, buf, size);
2018-03-07 01:11:46 +00:00
2018-06-08 10:42:24 +01:00
return _i2c_send_pkt(idx, x, tmp, size + 1);
2018-03-07 01:11:46 +00:00
}
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;
}
2018-06-08 10:42:24 +01:00
int i2c_send_byte(u32 idx, u32 x, u32 y, u8 b)
2018-03-07 01:11:46 +00:00
{
2018-06-08 10:42:24 +01:00
return i2c_send_buf_small(idx, x, y, &b, 1);
2018-03-07 01:11:46 +00:00
}
u8 i2c_recv_byte(u32 idx, u32 x, u32 y)
{
u8 tmp;
i2c_recv_buf_small(&tmp, 1, idx, x, y);
return tmp;
}