Newer
Older
uwuboot / source / arm11 / i2c.c
@profi200 profi200 on 5 Feb 2017 7 KB Moved reg defines back from io.h.
#include "mem_map.h"
#include "types.h"
#include "util.h"


#define I2C_REGS_BUS0_BASE  (IO_MEM_ARM9_ARM11 + 0x61000)
#define I2C_REGS_BUS1_BASE  (IO_MEM_ARM9_ARM11 + 0x44000)
#define REG_I2C_BUS0_DATA   *((vu8* )(I2C_REGS_BUS0_BASE + 0x00))
#define REG_I2C_BUS1_DATA   *((vu8* )(I2C_REGS_BUS1_BASE + 0x00))
#define REG_I2C_BUS0_CNT    *((vu8* )(I2C_REGS_BUS0_BASE + 0x01))
#define REG_I2C_BUS1_CNT    *((vu8* )(I2C_REGS_BUS1_BASE + 0x01))


struct i2c_dev_table_entry {
	u32 bus_id;
	u8 devaddr;
};


static const struct i2c_dev_table_entry i2c_dev_table[] =
{
	{0,	0x4A},
	{0,	0x7A},
	{0,	0x78},
	{1,	0x4A},
	{1,	0x78},
	{1,	0x2C},
	{1,	0x2E},
	{1,	0x40},
	{1,	0x44}
};

// i2c mcu defines
bool i2cmcu_reg0_upper_read;
u8 i2cmcu_reg0_upper_data;
bool i2cmcu_readreg0x0_bus0_read_flag;
u8 i2cmcu_readreg0x0_bus0_first;
u8 i2cmcu_readreg0x0_bus0_second;



void i2c_wait(u32 bus_id);
void i2c_put_byte(u32 bus_id, u8 data_byte);
void i2c_start(u32 bus_id);
void i2c_set_rw(u32 bus_id, u32 read_enable);
bool i2c_test_ack(u32 bus_id);
u8 i2c_receive_byte(u32 bus_id);
void i2c_stop(u32 bus_id, u32 read_enable);
void i2c_stop_err(u32 dev_id);
bool i2c_start_put_devaddr(u32 dev_id);
bool i2c_put_devaddr_set_read(u32 dev_id);
bool i2c_put_regaddr_set_write(u32 dev_id, u32 regaddr);
u8 i2c_get_byte(u32 dev_id);
u8 i2c_get_byte_stop(u32 dev_id);
u32 i2c_readregdata(u32 dev_id, u32 regaddr, u8 *out, u32 size);
u32 i2cmcu_readregdata(u32 regaddr, u8 *outbuf, u32 size);


void i2c_wait(u32 bus_id)
{
	u8 result;
	do {
		if(bus_id == 0)
			result = REG_I2C_BUS0_CNT;
		else
			result = REG_I2C_BUS1_CNT;
	} while((result>>7) & 1);
}

void i2c_put_byte(u32 bus_id, u8 data_byte)
{
	if(bus_id == 0)
		REG_I2C_BUS0_DATA = data_byte;
	else
		REG_I2C_BUS1_DATA = data_byte;
}

void i2c_start(u32 bus_id)
{
	wait(0x100);
	if(bus_id == 0)
		REG_I2C_BUS0_CNT = 0xC2;
	else
		REG_I2C_BUS1_CNT = 0xC2;
}

void i2c_set_rw(u32 bus_id, u32 read_enable)
{
	u8 cnt = 0xC0;
	cnt |= read_enable << 5;
	cnt |= read_enable << 4;
	if(bus_id == 0)
		REG_I2C_BUS0_CNT = cnt;
	else
		REG_I2C_BUS1_CNT = cnt;
}

bool i2c_test_ack(u32 bus_id)
{
	i2c_wait(bus_id);
	wait(0x80);
	u8 result;
	if(bus_id == 0)
		result = REG_I2C_BUS0_CNT;
	else
		result = REG_I2C_BUS1_CNT;
	return ((result << 0x1B) >> 0x1F);	// 	return Ack Flag
}

u8 i2c_receive_byte(u32 bus_id)
{
	i2c_wait(bus_id);
	wait(0x100);
	if(bus_id == 0)
		return REG_I2C_BUS0_DATA;
	else
		return REG_I2C_BUS1_DATA;
}

void i2c_stop(u32 bus_id, u32 read_enable)
{
	u8 cnt = 0xC1;
	cnt |= read_enable << 5;
	if(bus_id == 0)
		REG_I2C_BUS0_CNT = cnt;
	else
		REG_I2C_BUS1_CNT = cnt;
}

void i2c_stop_err(u32 dev_id)
{
	u32 bus_id = i2c_dev_table[dev_id].bus_id;
	if(bus_id == 0)
		REG_I2C_BUS0_CNT = 0xC5;
	else
		REG_I2C_BUS1_CNT = 0xC5;
	i2c_wait(bus_id);
	wait(0x200);
}

bool i2c_start_put_devaddr(u32 dev_id)
{
	u32 bus_id = i2c_dev_table[dev_id].bus_id;
	u8 dev_addr = i2c_dev_table[dev_id].devaddr;
	i2c_wait(bus_id);
	i2c_put_byte(bus_id, dev_addr);
	i2c_start(bus_id);
	return i2c_test_ack(bus_id);
}

bool i2c_put_devaddr_set_read(u32 dev_id)
{
	u32 bus_id = i2c_dev_table[dev_id].bus_id;
	u8 dev_addr = i2c_dev_table[dev_id].devaddr;
	i2c_wait(bus_id);
	dev_addr |= 1; // i2c direction: read bit set
	i2c_put_byte(bus_id, dev_addr);
	i2c_start(bus_id);
	return i2c_test_ack(bus_id);
}

bool i2c_put_regaddr_set_write(u32 dev_id, u32 regaddr)
{
	u32 bus_id = i2c_dev_table[dev_id].bus_id;
	i2c_wait(bus_id);
	i2c_put_byte(bus_id, regaddr);
	i2c_set_rw(bus_id, 0);	// write
	return i2c_test_ack(bus_id);
}

u8 i2c_get_byte(u32 dev_id)
{
	u32 bus_id = i2c_dev_table[dev_id].bus_id;
	i2c_wait(bus_id);
	i2c_set_rw(bus_id, 1);	// read
	return i2c_receive_byte(bus_id);
}

u8 i2c_get_byte_stop(u32 dev_id)
{
	u32 bus_id = i2c_dev_table[dev_id].bus_id;
	i2c_wait(bus_id);
	i2c_stop(bus_id, 1);	// 1=read
	return i2c_receive_byte(bus_id);
}

bool i2c_put_data_stop(u32 dev_id, u8 data)
{
	u32 bus_id = i2c_dev_table[dev_id].bus_id;
	i2c_wait(bus_id);
	i2c_put_byte(bus_id, data);
	i2c_stop(bus_id, 0);	// 0=write
	return i2c_receive_byte(bus_id);
}

u32 i2c_readregdata(u32 dev_id, u32 regaddr, u8 *out, u32 size)
{
	int i;
	for(i=0; i<8; i++)	// try max. 8 times
	{
		if(!i2c_start_put_devaddr(dev_id) ||
			!i2c_put_regaddr_set_write(dev_id, regaddr) ||
			!i2c_put_devaddr_set_read(dev_id))
				i2c_stop_err(dev_id);
		else break;
	}
	if(i == 8)
		return 0;
	
	while(size != 1)
	{
		*out = i2c_get_byte(dev_id);
		out++;
		size--;
	}
	
	// receive the last byte
	*out = i2c_get_byte_stop(dev_id);
	
	return 1;
}

u32 i2c_writeregdata(u32 dev_id, u32 regaddr, u8 data)
{
	int i;
	for(i=0; i<8; i++)	// try max. 8 times
	{
		if(!i2c_start_put_devaddr(dev_id) ||
			!i2c_put_regaddr_set_write(dev_id, regaddr) ||
			!i2c_put_data_stop(dev_id, data))
			i2c_stop_err(dev_id);
		else break;
	}
	if(i == 8)
		return 0;
	return 1;
}

u32 i2cmcu_readregdata(u32 regaddr, u8 *outbuf, u32 size)
{
	return i2c_readregdata(3, regaddr, outbuf, size);
}

u32 i2cmcu_readreg0x0_upper(u8 *result)
{
	/*if(i2cmcu_reg0_upper_read)
	{
		result = i2cmcu_reg0_upper_data;
		return 1;
	}
	else*/
	{
		u8 data;
		u32 retval = i2cmcu_readregdata(0, &data, 1);
		if(retval != 0)
		{
			data >>= 4;
			i2cmcu_reg0_upper_data = data;
			*result = data;
		}
		return retval;
	}
}

u32 i2cmcu_readreg0x0_2bytes(u8 *byte1, u8 *byte2)
{
	u8 data[2];
	if(!i2cmcu_readregdata(0, data, 2))
		return 0;
	*byte1 = data[0] & 0xF;
	*byte2 = data[1];
	return 1;
}

u32 i2cmcu_readreg0x0_bus0()
{
	if(!i2cmcu_readreg0x0_bus0_read_flag)
	{
		i2cmcu_readreg0x0_bus0_read_flag = true;
		i2cmcu_readreg0x0_2bytes(&i2cmcu_readreg0x0_bus0_first, &i2cmcu_readreg0x0_bus0_second);
		if(i2cmcu_readreg0x0_bus0_first << 0x1C) return 1;
		if(i2cmcu_readreg0x0_bus0_second >= 9) return 1;
		i2cmcu_readreg0x0_bus0_second = 0;
		return 0;
	}
	return i2cmcu_readreg0x0_bus0_second ? 1 : 0;
}

u8 i2cmcu_readreg_hid()
{
	u8 data;
	if(!i2cmcu_readregdata(0x10, &data, 1))
		return 0;
	return data;
}

// aka i2cmcu_write_reg0x20_0x22
void i2cmcu_lcd_poweron()
{
	if(i2cmcu_readreg0x0_bus0())
		i2c_writeregdata(3, 0x22, 2);	// bit1 = lcd power enable for both screens
	else
		i2c_writeregdata(3, 0x20, 0x80);
}

// aka i2cmcu_write_reg0x20_0x22_2
void i2cmcu_lcd_backlight_poweron()
{
	if(i2cmcu_readreg0x0_bus0())
		i2c_writeregdata(3, 0x22, 0x28);	// bit3 = lower screen, bit5 = upper
	else
		i2c_writeregdata(3, 0x20, 0x20);
}

void i2cmcu_lcd_poweroff()
{
	i2c_writeregdata(3, 0x22, 1);	// bit0 = lcd power disable for both screens (also disabled backlight)
}

void i2cmcu_lcd_backlight_poweroff()
{
	i2c_writeregdata(3, 0x22, 0x14);	// bit2 = backlight disable lower, bit4 = upper
}

u32 i2c_write_regdata_dev5_dev6(bool dev5, bool dev6, u32 regaddr, u8 data)
{
	u32 result = 1;
	if(dev5)
		result &= i2c_writeregdata(5, regaddr, data);
	if(dev6)
		result &= i2c_writeregdata(6, regaddr, data);
	return result;
}

u8 i2c_write_echo_read(u32 dev_id, u32 regaddr, u8 data)
{
	int i;
	for(i=0; i<8; i++)	// try max. 8 times
	{
		if(!i2c_start_put_devaddr(dev_id) ||
			!i2c_put_regaddr_set_write(dev_id, regaddr) ||
			!i2c_put_data_stop(dev_id, data) ||
			!i2c_put_devaddr_set_read(dev_id) ||
			(i2c_get_byte(dev_id) != data))
			i2c_stop_err(dev_id);
		else break;
	}
	if(i == 8)
		return 0xFF;
	return i2c_get_byte_stop(dev_id);;
}