diff options
Diffstat (limited to 'src/cpu')
-rw-r--r-- | src/cpu/samsung/exynos5-common/exynos-fb.c | 2 | ||||
-rw-r--r-- | src/cpu/samsung/exynos5-common/i2c.c | 354 | ||||
-rw-r--r-- | src/cpu/samsung/exynos5-common/i2c.h | 8 |
3 files changed, 84 insertions, 280 deletions
diff --git a/src/cpu/samsung/exynos5-common/exynos-fb.c b/src/cpu/samsung/exynos5-common/exynos-fb.c index d3710a3a6d..30d0767923 100644 --- a/src/cpu/samsung/exynos5-common/exynos-fb.c +++ b/src/cpu/samsung/exynos5-common/exynos-fb.c @@ -33,7 +33,7 @@ #include <cpu/samsung/exynos5250/sysreg.h> #include <drivers/maxim/max77686/max77686.h> -#include "device/i2c-old.h" +#include "device/i2c.h" #include "cpu/samsung/exynos5-common/i2c.h" #include "cpu/samsung/exynos5250/dsim.h" #include "cpu/samsung/exynos5250/fimd.h" diff --git a/src/cpu/samsung/exynos5-common/i2c.c b/src/cpu/samsung/exynos5-common/i2c.c index c5315304b8..30fabe1659 100644 --- a/src/cpu/samsung/exynos5-common/i2c.c +++ b/src/cpu/samsung/exynos5-common/i2c.c @@ -26,19 +26,14 @@ * The different address mapping is handled by the s3c24xx.h files below. */ -#include <common.h> +#include <delay.h> #include <arch/io.h> -#include "clk.h" +#include <console/console.h> +#include <device/i2c.h> #include "cpu/samsung/exynos5-common/clk.h" -#include "cpu/samsung/exynos5250/cpu.h" -#include "gpio.h" -#include "cpu/samsung/exynos5250/gpio.h" +#include "cpu/samsung/exynos5-common/i2c.h" #include "cpu/samsung/exynos5250/pinmux.h" -//#include <fdtdec.h> -#include "device/i2c-old.h" -#include "i2c.h" - #define I2C_WRITE 0 #define I2C_READ 1 @@ -65,54 +60,49 @@ enum { I2C_STOP_TIMEOUT_US = 200, /* waiting for stop events */ }; -/* We should not rely on any particular ordering of these IDs */ -#if 0 -#ifndef CONFIG_OF_CONTROL -static enum periph_id periph_for_dev[EXYNOS_I2C_MAX_CONTROLLERS] = { - PERIPH_ID_I2C0, - PERIPH_ID_I2C1, - PERIPH_ID_I2C2, - PERIPH_ID_I2C3, - PERIPH_ID_I2C4, - PERIPH_ID_I2C5, - PERIPH_ID_I2C6, - PERIPH_ID_I2C7, +static struct s3c24x0_i2c_bus i2c_buses[] = { + /* FIXME: exynos5250-specific? */ + { + .bus_num = 0, + .regs = (struct s3c24x0_i2c *)0x12c60000, + .periph_id = PERIPH_ID_I2C0, + }, + { + .bus_num = 1, + .regs = (struct s3c24x0_i2c *)0x12c70000, + .periph_id = PERIPH_ID_I2C1, + }, + { + .bus_num = 2, + .regs = (struct s3c24x0_i2c *)0x12c80000, + .periph_id = PERIPH_ID_I2C2, + }, + { + .bus_num = 3, + .regs = (struct s3c24x0_i2c *)0x12c90000, + .periph_id = PERIPH_ID_I2C3, + }, + { + .bus_num = 4, + .regs = (struct s3c24x0_i2c *)0x12ca0000, + .periph_id = PERIPH_ID_I2C4, + }, + { + .bus_num = 5, + .regs = (struct s3c24x0_i2c *)0x12cb0000, + .periph_id = PERIPH_ID_I2C5, + }, + { + .bus_num = 6, + .regs = (struct s3c24x0_i2c *)0x12cc0000, + .periph_id = PERIPH_ID_I2C6, + }, + { + .bus_num = 7, + .regs = (struct s3c24x0_i2c *)0x12cd0000, + .periph_id = PERIPH_ID_I2C7, + }, }; -#endif -#endif - -static unsigned int g_current_bus __attribute__((section(".data"))); -static struct s3c24x0_i2c *g_early_i2c_config __attribute__((section(".data"))); - -static struct s3c24x0_i2c_bus i2c_bus[EXYNOS_I2C_MAX_CONTROLLERS] - __attribute__((section(".data"))); -static int i2c_busses __attribute__((section(".data"))); - -void i2c_set_early_reg(unsigned int base) -{ - g_early_i2c_config = (struct s3c24x0_i2c *)base; -} - -static struct s3c24x0_i2c_bus *get_bus(int bus_idx) -{ - /* If an early i2c config exists we just use that */ - if (g_early_i2c_config) { - /* FIXME: value not retained from i2c_set_early_reg()? (but then, how - * did if (!i2c) check pass earlier on? Corrupt value? */ - i2c_bus[0].regs = g_early_i2c_config; - return &i2c_bus[0]; - } - - if (bus_idx < i2c_busses) - return &i2c_bus[bus_idx]; - debug("Undefined bus: %d\n", bus_idx); - return NULL; -} - -static inline struct exynos5_gpio_part1 *exynos_get_base_gpio1(void) -{ - return (struct exynos5_gpio_part1 *)(EXYNOS5_GPIO_PART1_BASE); -} static int WaitForXfer(struct s3c24x0_i2c *i2c) { @@ -121,7 +111,7 @@ static int WaitForXfer(struct s3c24x0_i2c *i2c) i = I2C_XFER_TIMEOUT_MS * 20; while (!(readl(&i2c->iiccon) & I2CCON_IRPND)) { if (i == 0) { - debug("%s: i2c xfer timeout\n", __func__); + printk(BIOS_ERR, "%s: i2c xfer timeout\n", __func__); return I2C_NOK_TOUT; } udelay(50); @@ -142,15 +132,14 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c) x = readl(&i2c->iiccon); writel(x & ~I2CCON_IRPND, &i2c->iiccon); - /* FIXME(dhendrix): cannot use nested macro (compilation failure) */ -// writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); } -static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) +static void i2c_ch_init(struct s3c24x0_i2c_bus *bus, int speed, int slaveadd) { unsigned long freq, pres = 16, div; + unsigned long val; - freq = clock_get_periph_rate(PERIPH_ID_I2C0); + freq = clock_get_periph_rate(bus->periph_id); /* calculate prescaler and divisor values */ if ((freq / pres / (16 + 1)) > speed) /* set prescaler to 512 */ @@ -162,136 +151,25 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) div++; /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */ - writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon); + val = (div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0); + writel(val, &bus->regs->iiccon); - /* init to SLAVE REVEIVE and set slaveaddr */ - writel(0, &i2c->iicstat); - writel(slaveadd, &i2c->iicadd); + /* init to SLAVE RECEIVE mode and clear I2CADDn */ + writel(0, &bus->regs->iicstat); + writel(slaveadd, &bus->regs->iicadd); /* program Master Transmit (and implicit STOP) */ - writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); -} - -/* TODO: determine if this is necessary to init board using FDT-provided info */ -#if 0 -void board_i2c_init(const void *blob) -{ - /* - * Turn off the early i2c configuration and init the i2c properly, - * this is done here to enable the use of i2c configs from FDT. - */ - i2c_set_early_reg(0); - -#ifdef CONFIG_OF_CONTROL - int node_list[EXYNOS_I2C_MAX_CONTROLLERS]; - int i, count; - - count = fdtdec_find_aliases_for_id(blob, "i2c", - COMPAT_SAMSUNG_S3C2440_I2C, node_list, - EXYNOS_I2C_MAX_CONTROLLERS); - - for (i = 0; i < count; i++) { - struct s3c24x0_i2c_bus *bus; - int node = node_list[i]; - - if (node < 0) - continue; - bus = &i2c_bus[i2c_busses]; - bus->regs = (struct s3c24x0_i2c *) - fdtdec_get_addr(blob, node, "reg"); - bus->id = (enum periph_id) - fdtdec_get_int(blob, node, "samsung,periph-id", -1); - bus->node = node; - bus->bus_num = i2c_busses++; - } -#else - int i; - - for (i = 0; i < EXYNOS_I2C_MAX_CONTROLLERS; i++) { - unsigned intptr_t reg_addr = samsung_get_base_i2c() + - EXYNOS_I2C_SPACING * i; - - i2c_bus[i].regs = (struct s3c24x0_i2c_bus *)reg_addr; - i2c_bus[i].id = periph_for_dev[i]; - } - i2c_busses = EXYNOS_I2C_MAX_CONTROLLERS; -#endif + writel(I2C_MODE_MT | I2C_TXRX_ENA, &bus->regs->iicstat); } -#endif /* * MULTI BUS I2C support */ -static void i2c_bus_init(struct s3c24x0_i2c_bus *i2c, unsigned int bus) -{ - exynos_pinmux_config(i2c->id, 0); - i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); -} - -#ifdef CONFIG_I2C_MULTI_BUS -int i2c_set_bus_num(unsigned int bus) +static void i2c_bus_init(struct s3c24x0_i2c_bus *bus, int speed, int slaveadd) { - struct s3c24x0_i2c_bus *i2c; - - i2c = get_bus(bus); - if (!i2c) - return -1; - g_current_bus = bus; - i2c_bus_init(i2c, g_current_bus); - - return 0; + exynos_pinmux_config(bus->periph_id, 0); + i2c_ch_init(bus, speed, slaveadd); } -unsigned int i2c_get_bus_num(void) -{ - return g_current_bus; -} -#endif - -#ifdef CONFIG_OF_CONTROL -int i2c_get_bus_num_fdt(const void *blob, int node) -{ - enum fdt_compat_id compat; - fdt_addr_t reg; - int i; - - compat = fdtdec_lookup(blob, node); - if (compat != COMPAT_SAMSUNG_S3C2440_I2C) { - debug("%s: Not a supported I2C node\n", __func__); - return -1; - } - - reg = fdtdec_get_addr(blob, node, "reg"); - for (i = 0; i < i2c_busses; i++) - if (reg == (fdt_addr_t)(unsigned intptr_t)i2c_bus[i].regs) - return i; - - debug("%s: Can't find any matched I2C bus\n", __func__); - return -1; -} - -int i2c_reset_port_fdt(const void *blob, int node) -{ - struct s3c24x0_i2c_bus *i2c; - - int bus; - - bus = i2c_get_bus_num_fdt(blob, node); - if (bus < 0) { - printf("could not get bus for node %d\n", node); - return -1; - } - i2c = get_bus(bus); - if (!i2c) { - printf("get_bus() failed for node node %d\n", node); - return -1; - } - - i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); - - return 0; -} -#endif - /* * Verify the whether I2C ACK was received or not * @@ -321,21 +199,13 @@ static int i2c_send_verify(struct s3c24x0_i2c *i2c, unsigned char buf[], return result; } -void i2c_init(int speed, int slaveadd) +void i2c_init(unsigned bus_num, int speed, int slaveadd) { struct s3c24x0_i2c_bus *i2c; - struct exynos5_gpio_part1 *gpio; int i; - uint32_t x; - - /* By default i2c channel 0 is the current bus */ - g_current_bus = 0; - i2c = get_bus(g_current_bus); - if (!i2c) - return; - - i2c_bus_init(i2c, g_current_bus); + i2c = &i2c_buses[bus_num]; + i2c_bus_init(i2c, speed, slaveadd); /* wait for some time to give previous transfer a chance to finish */ i = I2C_INIT_TIMEOUT_MS * 20; @@ -344,13 +214,7 @@ void i2c_init(int speed, int slaveadd) i--; } - gpio = exynos_get_base_gpio1(); - /* FIXME(dhendrix): cannot use nested macro (compilation failure) */ -// writel((readl(&gpio->b3.con) & ~0x00FF) | 0x0022, &gpio->b3.con); - x = readl(&gpio->b3.con); - writel((x & ~0x00FF) | 0x0022, &gpio->b3.con); - - i2c_ch_init(i2c->regs, speed, slaveadd); + i2c_ch_init(i2c, speed, slaveadd); } /* @@ -397,7 +261,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, if (data == 0 || data_len == 0) { /* Don't support data transfer of no length or to address 0 */ - debug("i2c_transfer: bad call\n"); + printk(BIOS_ERR, "i2c_transfer: bad call\n"); return I2C_NOK; } @@ -409,12 +273,10 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, } if (readl(&i2c->iicstat) & I2CSTAT_BSY) { - debug("%s: bus busy\n", __func__); + printk(BIOS_ERR, "%s: bus busy\n", __func__); return I2C_NOK_TOUT; } - /* FIXME(dhendrix): cannot use nested macro (compilation failure) */ - //writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon); x = readl(&i2c->iiccon); writel(x | I2CCON_ACKGEN, &i2c->iiccon); @@ -465,12 +327,6 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, while ((i < data_len) && (result == I2C_OK)) { /* disable ACK for final READ */ if (i == data_len - 1) { - /* FIXME(dhendrix): nested macro */ -#if 0 - writel(readl(&i2c->iiccon) & - ~I2CCON_ACKGEN, - &i2c->iiccon); -#endif x = readl(&i2c->iiccon) & ~I2CCON_ACKGEN; writel(x, &i2c->iiccon); } @@ -488,7 +344,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, } default: - debug("i2c_transfer: bad call\n"); + printk(BIOS_ERR, "i2c_transfer: bad call\n"); result = stop_bit_result = I2C_NOK; break; } @@ -501,35 +357,15 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, return (result == I2C_OK) ? stop_bit_result : result; } -int i2c_probe(unsigned char chip) -{ - struct s3c24x0_i2c_bus *i2c; - unsigned char buf[1]; - int ret; - - i2c = get_bus(g_current_bus); - if (!i2c) - return -1; - buf[0] = 0; - - /* - * What is needed is to send the chip address and verify that the - * address was <ACK>ed (i.e. there was a chip at that address which - * drove the data line low). - */ - ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1, 0, 0, buf, 1); - - return ret != I2C_OK; -} - -int i2c_read(unsigned char chip, unsigned int addr, int alen, unsigned char *buffer, int len) +int i2c_read(unsigned bus, unsigned chip, unsigned addr, + unsigned alen, unsigned char *buf, unsigned len) { struct s3c24x0_i2c_bus *i2c; unsigned char xaddr[4]; int ret; if (alen > 4) { - debug("I2C read: addr len %d not supported\n", alen); + printk(BIOS_ERR, "I2C read: addr len %d not supported\n", alen); return 1; } @@ -540,42 +376,26 @@ int i2c_read(unsigned char chip, unsigned int addr, int alen, unsigned char *buf xaddr[3] = addr & 0xFF; } -#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW - /* - * EEPROM chips that implement "address overflow" are ones - * like Catalyst 24WC04/08/16 which has 9/10/11 bits of - * address and the extra bits end up in the "chip address" - * bit slots. This makes a 24WC08 (1Kbyte) chip look like - * four 256 byte chips. - * - * Note that we consider the length of the address field to - * still be one byte because the extra address bits are - * hidden in the chip address. - */ - if (alen > 0) - chip |= ((addr >> (alen * 8)) & - CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); -#endif - i2c = get_bus(g_current_bus); - if (!i2c) - return -1; + i2c = &i2c_buses[bus]; ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1, &xaddr[4 - alen], - alen, buffer, len); + alen, buf, len); if (ret) { - debug("I2c read: failed %d\n", ret); + printk(BIOS_ERR, "I2c read: failed %d\n", ret); return 1; } return 0; } -int i2c_write(unsigned char chip, unsigned int addr, int alen, unsigned char *buffer, int len) +int i2c_write(unsigned bus, unsigned chip, unsigned addr, + unsigned alen, unsigned char *buf, unsigned len) { struct s3c24x0_i2c_bus *i2c; unsigned char xaddr[4]; int ret; if (alen > 4) { - debug("I2C write: addr len %d not supported\n", alen); + printk(BIOS_ERR, "I2C write: addr len %d not supported\n", + alen); return 1; } @@ -585,28 +405,10 @@ int i2c_write(unsigned char chip, unsigned int addr, int alen, unsigned char *bu xaddr[2] = (addr >> 8) & 0xFF; xaddr[3] = addr & 0xFF; } -#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW - /* - * EEPROM chips that implement "address overflow" are ones - * like Catalyst 24WC04/08/16 which has 9/10/11 bits of - * address and the extra bits end up in the "chip address" - * bit slots. This makes a 24WC08 (1Kbyte) chip look like - * four 256 byte chips. - * - * Note that we consider the length of the address field to - * still be one byte because the extra address bits are - * hidden in the chip address. - */ - if (alen > 0) - chip |= ((addr >> (alen * 8)) & - CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); -#endif - i2c = get_bus(g_current_bus); - if (!i2c) - return -1; + i2c = &i2c_buses[bus]; ret = i2c_transfer(i2c->regs, I2C_WRITE, chip << 1, &xaddr[4 - alen], - alen, buffer, len); + alen, buf, len); return ret != 0; } diff --git a/src/cpu/samsung/exynos5-common/i2c.h b/src/cpu/samsung/exynos5-common/i2c.h index eb68af78f0..0bfee340e1 100644 --- a/src/cpu/samsung/exynos5-common/i2c.h +++ b/src/cpu/samsung/exynos5-common/i2c.h @@ -35,9 +35,11 @@ struct s3c24x0_i2c { }; struct s3c24x0_i2c_bus { - int node; /* device tree node */ - int bus_num; /* i2c bus number */ + int bus_num; struct s3c24x0_i2c *regs; - enum periph_id id; + enum periph_id periph_id; }; + +void i2c_init(unsigned bus, int speed, int slaveadd); + #endif /* _S3C24X0_I2C_H */ |