i2c: mvtwsi: Add compatibility to DM

This patch adds the necessary functions and Kconfig entry to make the
MVTWSI I2C driver compatible with the driver model.

A possible device tree entry might look like this:

i2c@11100 {
	compatible = "marvell,mv64xxx-i2c";
	reg = <0x11000 0x20>;
	clock-frequency = <100000>;
	u-boot,i2c-slave-addr = <0x0>;
};

Signed-off-by: Mario Six <mario.six@gdsys.cc>
Reviewed-by: Stefan Roese <sr@denx.de>
This commit is contained in:
mario.six@gdsys.cc 2016-07-21 11:57:10 +02:00 committed by Heiko Schocher
parent f8a10ed1fd
commit 14a6ff2c4f
2 changed files with 117 additions and 1 deletions

View File

@ -154,6 +154,13 @@ config SYS_I2C_UNIPHIER_F
Support for UniPhier FIFO-builtin I2C controller driver.
This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs.
config SYS_I2C_MVTWSI
bool "Marvell I2C driver"
depends on DM_I2C
help
Support for Marvell I2C controllers as used on the orion5x and
kirkwood SoC families.
source "drivers/i2c/muxes/Kconfig"
endmenu

View File

@ -12,12 +12,18 @@
#include <i2c.h>
#include <asm/errno.h>
#include <asm/io.h>
#ifdef CONFIG_DM_I2C
#include <dm.h>
#endif
DECLARE_GLOBAL_DATA_PTR;
/*
* Include a file that will provide CONFIG_I2C_MVTWSI_BASE*, and possibly other
* settings
*/
#ifndef CONFIG_DM_I2C
#if defined(CONFIG_ORION5X)
#include <asm/arch/orion5x.h>
#elif (defined(CONFIG_KIRKWOOD) || defined(CONFIG_ARCH_MVEBU))
@ -27,6 +33,7 @@
#else
#error Driver mvtwsi not supported by SoC or board
#endif
#endif /* CONFIG_DM_I2C */
/*
* TWSI register structure
@ -61,6 +68,19 @@ struct mvtwsi_registers {
#endif
#ifdef CONFIG_DM_I2C
struct mvtwsi_i2c_dev {
/* TWSI Register base for the device */
struct mvtwsi_registers *base;
/* Number of the device (determined from cell-index property) */
int index;
/* The I2C slave address for the device */
u8 slaveadd;
/* The configured I2C speed in Hz */
uint speed;
};
#endif /* CONFIG_DM_I2C */
/*
* enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control
* register
@ -134,6 +154,7 @@ enum mvtwsi_ack_flags {
MVTWSI_READ_ACK = 1,
};
#ifndef CONFIG_DM_I2C
/*
* MVTWSI controller base
*/
@ -172,6 +193,7 @@ static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
return NULL;
}
#endif
/*
* enum mvtwsi_error_class - types of I2C errors
@ -358,7 +380,7 @@ static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi,
}
static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed,
int slaveadd)
int slaveadd)
{
/* Reset controller */
twsi_reset(twsi);
@ -472,6 +494,7 @@ static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip,
return status != 0 ? status : stop_status;
}
#ifndef CONFIG_DM_I2C
static void twsi_i2c_init(struct i2c_adapter *adap, int speed,
int slaveadd)
{
@ -561,3 +584,89 @@ U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
#endif
#else /* CONFIG_DM_I2C */
static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
u32 chip_flags)
{
struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
return __twsi_i2c_probe_chip(dev->base, chip_addr);
}
static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed)
{
struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
return __twsi_i2c_set_bus_speed(dev->base, speed);
}
static int mvtwsi_i2c_ofdata_to_platdata(struct udevice *bus)
{
struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
dev->base = dev_get_addr_ptr(bus);
if (!dev->base)
return -ENOMEM;
dev->index = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
"cell-index", -1);
dev->slaveadd = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
"u-boot,i2c-slave-addr", 0x0);
dev->speed = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
"clock-frequency", 100000);
return 0;
}
static int mvtwsi_i2c_probe(struct udevice *bus)
{
struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
__twsi_i2c_init(dev->base, dev->speed, dev->slaveadd);
return 0;
}
static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
{
struct mvtwsi_i2c_dev *dev = dev_get_priv(bus);
struct i2c_msg *dmsg, *omsg, dummy;
memset(&dummy, 0, sizeof(struct i2c_msg));
/* We expect either two messages (one with an offset and one with the
* actual data) or one message (just data or offset/data combined) */
if (nmsgs > 2 || nmsgs == 0) {
debug("%s: Only one or two messages are supported.", __func__);
return -1;
}
omsg = nmsgs == 1 ? &dummy : msg;
dmsg = nmsgs == 1 ? msg : msg + 1;
if (dmsg->flags & I2C_M_RD)
return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf,
omsg->len, dmsg->buf, dmsg->len);
else
return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf,
omsg->len, dmsg->buf, dmsg->len);
}
static const struct dm_i2c_ops mvtwsi_i2c_ops = {
.xfer = mvtwsi_i2c_xfer,
.probe_chip = mvtwsi_i2c_probe_chip,
.set_bus_speed = mvtwsi_i2c_set_bus_speed,
};
static const struct udevice_id mvtwsi_i2c_ids[] = {
{ .compatible = "marvell,mv64xxx-i2c", },
{ /* sentinel */ }
};
U_BOOT_DRIVER(i2c_mvtwsi) = {
.name = "i2c_mvtwsi",
.id = UCLASS_I2C,
.of_match = mvtwsi_i2c_ids,
.probe = mvtwsi_i2c_probe,
.ofdata_to_platdata = mvtwsi_i2c_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct mvtwsi_i2c_dev),
.ops = &mvtwsi_i2c_ops,
};
#endif /* CONFIG_DM_I2C */