Skip to content
Snippets Groups Projects
s3c24x0_i2c.c 37.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • #ifdef CONFIG_OF_CONTROL
    
    static void process_nodes(const void *blob, int node_list[], int count,
    			 int is_highspeed)
    
    	struct s3c24x0_i2c_bus *bus;
    
    
    	for (i = 0; i < count; i++) {
    		int node = node_list[i];
    
    		if (node <= 0)
    			continue;
    
    		bus = &i2c_bus[i];
    
    		bus->is_highspeed = is_highspeed;
    
    
    		if (is_highspeed) {
    			flags = PINMUX_FLAG_HS_MODE;
    
    			bus->hsregs = (struct exynos5_hsi2c *)
    					fdtdec_get_addr(blob, node, "reg");
    
    			bus->regs = (struct s3c24x0_i2c *)
    					fdtdec_get_addr(blob, node, "reg");
    
    		bus->id = pinmux_decode_periph_id(blob, node);
    
    		bus->clock_frequency = fdtdec_get_int(blob, node,
    
    						"clock-frequency",
    						CONFIG_SYS_I2C_S3C24X0_SPEED);
    
    		bus->node = node;
    
    		exynos_pinmux_config(PERIPH_ID_I2C0 + bus->id, flags);
    
    
    		/* Mark position as used */
    		node_list[i] = -1;
    
    void board_i2c_init(const void *blob)
    
    	int node_list[CONFIG_MAX_I2C_NUM];
    	int count;
    
    	/* First get the normal i2c ports */
    	count = fdtdec_find_aliases_for_id(blob, "i2c",
    		COMPAT_SAMSUNG_S3C2440_I2C, node_list,
    		CONFIG_MAX_I2C_NUM);
    	process_nodes(blob, node_list, count, 0);
    
    	/* Now look for high speed i2c ports */
    	count = fdtdec_find_aliases_for_id(blob, "i2c",
    		COMPAT_SAMSUNG_EXYNOS5_I2C, node_list,
    		CONFIG_MAX_I2C_NUM);
    	process_nodes(blob, node_list, count, 1);
    
    }
    
    int i2c_get_bus_num_fdt(int node)
    {
    	int i;
    
    
    	for (i = 0; i < ARRAY_SIZE(i2c_bus); i++) {
    
    		if (node == i2c_bus[i].node)
    			return i;
    	}
    
    	debug("%s: Can't find any matched I2C bus\n", __func__);
    
    }
    
    int i2c_reset_port_fdt(const void *blob, int node)
    {
    
    	struct s3c24x0_i2c_bus *i2c_bus;
    
    	int bus;
    
    	bus = i2c_get_bus_num_fdt(node);
    	if (bus < 0) {
    		debug("could not get bus for node %d\n", node);
    
    	i2c_bus = get_bus(bus);
    	if (!i2c_bus) {
    
    		debug("get_bus() failed for node %d\n", node);
    		return -EFAULT;
    
    	if (i2c_bus->is_highspeed) {
    		if (hsi2c_get_clk_details(i2c_bus))
    
    		hsi2c_ch_init(i2c_bus);
    	} else {
    		i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
    
    			    CONFIG_SYS_I2C_S3C24X0_SLAVE);
    
    #endif /* CONFIG_OF_CONTROL */
    
    #ifdef CONFIG_EXYNOS5
    static void exynos_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
    {
    	/* This will override the speed selected in the fdt for that port */
    	debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
    	if (i2c_set_bus_speed(speed))
    		error("i2c_init: failed to init bus for speed = %d", speed);
    }
    #endif /* CONFIG_EXYNOS5 */
    
    /*
     * Register s3c24x0 i2c adapters
     */
    
    #if defined(CONFIG_EXYNOS5420)
    U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
    U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
    U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
    U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
    U_BOOT_I2C_ADAP_COMPLETE(i2c04, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
    U_BOOT_I2C_ADAP_COMPLETE(i2c05, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
    U_BOOT_I2C_ADAP_COMPLETE(i2c06, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
    U_BOOT_I2C_ADAP_COMPLETE(i2c07, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
    U_BOOT_I2C_ADAP_COMPLETE(i2c08, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
    U_BOOT_I2C_ADAP_COMPLETE(i2c09, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
    U_BOOT_I2C_ADAP_COMPLETE(i2c10, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
    #elif defined(CONFIG_EXYNOS5250)
    U_BOOT_I2C_ADAP_COMPLETE(i2c00, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
    U_BOOT_I2C_ADAP_COMPLETE(i2c01, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
    U_BOOT_I2C_ADAP_COMPLETE(i2c02, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
    U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
    U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
    U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
    U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
    U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
    U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
    U_BOOT_I2C_ADAP_COMPLETE(i2c09, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
    U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
    #elif defined(CONFIG_EXYNOS4)
    U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
    U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
    U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
    U_BOOT_I2C_ADAP_COMPLETE(i2c03, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
    U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
    U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
    U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
    U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
    U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
    #else
    U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
    			s3c24x0_i2c_read, s3c24x0_i2c_write,
    			s3c24x0_i2c_set_bus_speed,
    			CONFIG_SYS_I2C_S3C24X0_SPEED,
    			CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
    #endif
    
    #endif /* CONFIG_SYS_I2C */
    
    #ifdef CONFIG_DM_I2C
    static int i2c_write_data(struct s3c24x0_i2c_bus *i2c_bus, uchar chip,
    			  uchar *buffer, int len, bool end_with_repeated_start)
    {
    	int ret;
    
    	if (i2c_bus->is_highspeed) {
    		ret = hsi2c_write(i2c_bus->hsregs, chip, 0, 0,
    				  buffer, len, true);
    		if (ret)
    			exynos5_i2c_reset(i2c_bus);
    	} else {
    		ret = i2c_transfer(i2c_bus->regs, I2C_WRITE,
    				   chip << 1, 0, 0, buffer, len);
    	}
    
    	return ret != I2C_OK;
    }
    
    static int i2c_read_data(struct s3c24x0_i2c_bus  *i2c_bus, uchar chip,
    			 uchar *buffer, int len)
    {
    	int ret;
    
    	if (i2c_bus->is_highspeed) {
    		ret = hsi2c_read(i2c_bus->hsregs, chip, 0, 0, buffer, len);
    		if (ret)
    			exynos5_i2c_reset(i2c_bus);
    	} else {
    		ret = i2c_transfer(i2c_bus->regs, I2C_READ,
    				   chip << 1, 0, 0, buffer, len);
    	}
    
    	return ret != I2C_OK;
    }
    
    static int s3c24x0_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
    			    int nmsgs)
    {
    	struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
    	int ret;
    
    	for (; nmsgs > 0; nmsgs--, msg++) {
    		bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
    
    		if (msg->flags & I2C_M_RD) {
    			ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
    					    msg->len);
    		} else {
    			ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
    					     msg->len, next_is_read);
    		}
    		if (ret)
    			return -EREMOTEIO;
    	}
    
    	return 0;
    }
    
    static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
    {
    	const void *blob = gd->fdt_blob;
    	struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
    	int node, flags;
    
    
    	i2c_bus->is_highspeed = dev_get_driver_data(dev);
    
    	node = dev->of_offset;
    
    	if (i2c_bus->is_highspeed) {
    		flags = PINMUX_FLAG_HS_MODE;
    		i2c_bus->hsregs = (struct exynos5_hsi2c *)
    				fdtdec_get_addr(blob, node, "reg");
    	} else {
    		flags = 0;
    		i2c_bus->regs = (struct s3c24x0_i2c *)
    				fdtdec_get_addr(blob, node, "reg");
    	}
    
    	i2c_bus->id = pinmux_decode_periph_id(blob, node);
    
    	i2c_bus->clock_frequency = fdtdec_get_int(blob, node,
    						"clock-frequency",
    						CONFIG_SYS_I2C_S3C24X0_SPEED);
    	i2c_bus->node = node;
    	i2c_bus->bus_num = dev->seq;
    
    	exynos_pinmux_config(i2c_bus->id, flags);
    
    	i2c_bus->active = true;
    
    	return 0;
    }
    
    static const struct dm_i2c_ops s3c_i2c_ops = {
    	.xfer		= s3c24x0_i2c_xfer,
    	.probe_chip	= s3c24x0_i2c_probe,
    	.set_bus_speed	= s3c24x0_i2c_set_bus_speed,
    };
    
    static const struct udevice_id s3c_i2c_ids[] = {
    	{ .compatible = "samsung,s3c2440-i2c", .data = EXYNOS_I2C_STD },
    	{ .compatible = "samsung,exynos5-hsi2c", .data = EXYNOS_I2C_HS },
    	{ }
    };
    
    U_BOOT_DRIVER(i2c_s3c) = {
    	.name	= "i2c_s3c",
    	.id	= UCLASS_I2C,
    	.of_match = s3c_i2c_ids,
    	.ofdata_to_platdata = s3c_i2c_ofdata_to_platdata,
    	.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
    	.priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
    	.ops	= &s3c_i2c_ops,
    };
    #endif /* CONFIG_DM_I2C */