From patchwork Thu Apr 21 06:19:41 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Roese X-Patchwork-Id: 612988 X-Patchwork-Delegate: hs@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 3qr7sz50jvz9t3m for ; Thu, 21 Apr 2016 16:20:55 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id D15E6A76F0; Thu, 21 Apr 2016 08:20:32 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id TNMqBLidHBfL; Thu, 21 Apr 2016 08:20:32 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 28B99A770B; Thu, 21 Apr 2016 08:20:19 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 90115A7676 for ; Thu, 21 Apr 2016 08:20:05 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 4NidHJJQTbHQ for ; Thu, 21 Apr 2016 08:20:05 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from sohosted5.com (ns2.sohosted5.com [195.8.208.35]) by theia.denx.de (Postfix) with ESMTPS id B6310A767D for ; Thu, 21 Apr 2016 08:20:00 +0200 (CEST) Received: from stefan-work.fritz.box ([185.22.143.102]) by sohosted5.com with MailEnable ESMTP; Thu, 21 Apr 2016 08:19:44 +0200 From: Stefan Roese To: u-boot@lists.denx.de Date: Thu, 21 Apr 2016 08:19:41 +0200 Message-Id: <1461219582-16788-5-git-send-email-sr@denx.de> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1461219582-16788-1-git-send-email-sr@denx.de> References: <1461219582-16788-1-git-send-email-sr@denx.de> X-ME-Bayesian: 0.000000 Cc: Marek Vasut Subject: [U-Boot] [PATCH 5/6 v4] i2c: designware_i2c: Add DM support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" This patch adds DM support to the designware I2C driver. It currently supports DM and the legacy I2C support. The legacy support should be removed, once all platforms using it have DM enabled. Signed-off-by: Stefan Roese Reviewed-by: Simon Glass Reviewed-by: Bin Meng Cc: Marek Vasut Cc: Heiko Schocher --- v4: - Rebased on latest mainline drivers/i2c/designware_i2c.c | 149 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 123 insertions(+), 26 deletions(-) diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index 2adc36e..d653eff 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -6,10 +6,15 @@ */ #include +#include #include #include #include "designware_i2c.h" +struct dw_i2c { + struct i2c_regs *regs; +}; + static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable) { u32 ena = enable ? IC_ENABLE_0B : 0; @@ -294,6 +299,36 @@ static int __dw_i2c_write(struct i2c_regs *i2c_base, u8 dev, uint addr, return i2c_xfer_finish(i2c_base); } +/* + * __dw_i2c_init - Init function + * @speed: required i2c speed + * @slaveaddr: slave address for the device + * + * Initialization function. + */ +static void __dw_i2c_init(struct i2c_regs *i2c_base, int speed, int slaveaddr) +{ + /* Disable i2c */ + dw_i2c_enable(i2c_base, false); + + writel((IC_CON_SD | IC_CON_SPD_FS | IC_CON_MM), &i2c_base->ic_con); + writel(IC_RX_TL, &i2c_base->ic_rx_tl); + writel(IC_TX_TL, &i2c_base->ic_tx_tl); + writel(IC_STOP_DET, &i2c_base->ic_intr_mask); +#ifndef CONFIG_DM_I2C + __dw_i2c_set_bus_speed(i2c_base, speed); + writel(slaveaddr, &i2c_base->ic_sar); +#endif + + /* Enable i2c */ + dw_i2c_enable(i2c_base, true); +} + +#ifndef CONFIG_DM_I2C +/* + * The legacy I2C functions. These need to get removed once + * all users of this driver are converted to DM. + */ static struct i2c_regs *i2c_get_base(struct i2c_adapter *adap) { switch (adap->hwadapnr) { @@ -325,30 +360,9 @@ static unsigned int dw_i2c_set_bus_speed(struct i2c_adapter *adap, return __dw_i2c_set_bus_speed(i2c_get_base(adap), speed); } -/* - * i2c_init - Init function - * @speed: required i2c speed - * @slaveaddr: slave address for the device - * - * Initialization function. - */ -static void dw_i2c_init(struct i2c_adapter *adap, int speed, - int slaveaddr) +static void dw_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) { - struct i2c_regs *i2c_base = i2c_get_base(adap); - - /* Disable i2c */ - dw_i2c_enable(i2c_base, false); - - writel((IC_CON_SD | IC_CON_SPD_FS | IC_CON_MM), &i2c_base->ic_con); - writel(IC_RX_TL, &i2c_base->ic_rx_tl); - writel(IC_TX_TL, &i2c_base->ic_tx_tl); - dw_i2c_set_bus_speed(adap, speed); - writel(IC_STOP_DET, &i2c_base->ic_intr_mask); - writel(slaveaddr, &i2c_base->ic_sar); - - /* Enable i2c */ - dw_i2c_enable(i2c_base, true); + __dw_i2c_init(i2c_get_base(adap), speed, slaveaddr); } static int dw_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr, @@ -363,9 +377,7 @@ static int dw_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr, return __dw_i2c_write(i2c_get_base(adap), dev, addr, alen, buffer, len); } -/* - * i2c_probe - Probe the i2c chip - */ +/* dw_i2c_probe - Probe the i2c chip */ static int dw_i2c_probe(struct i2c_adapter *adap, u8 dev) { struct i2c_regs *i2c_base = i2c_get_base(adap); @@ -403,3 +415,88 @@ U_BOOT_I2C_ADAP_COMPLETE(dw_3, dw_i2c_init, dw_i2c_probe, dw_i2c_read, dw_i2c_write, dw_i2c_set_bus_speed, CONFIG_SYS_I2C_SPEED3, CONFIG_SYS_I2C_SLAVE3, 3) #endif + +#else /* CONFIG_DM_I2C */ +/* The DM I2C functions */ + +static int designware_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, + int nmsgs) +{ + struct dw_i2c *i2c = dev_get_priv(bus); + int ret; + + debug("i2c_xfer: %d messages\n", nmsgs); + for (; nmsgs > 0; nmsgs--, msg++) { + debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len); + if (msg->flags & I2C_M_RD) { + ret = __dw_i2c_read(i2c->regs, msg->addr, 0, 0, + msg->buf, msg->len); + } else { + ret = __dw_i2c_write(i2c->regs, msg->addr, 0, 0, + msg->buf, msg->len); + } + if (ret) { + debug("i2c_write: error sending\n"); + return -EREMOTEIO; + } + } + + return 0; +} + +static int designware_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) +{ + struct dw_i2c *i2c = dev_get_priv(bus); + + return __dw_i2c_set_bus_speed(i2c->regs, speed); +} + +static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr, + uint chip_flags) +{ + struct dw_i2c *i2c = dev_get_priv(bus); + struct i2c_regs *i2c_base = i2c->regs; + u32 tmp; + int ret; + + /* Try to read the first location of the chip */ + ret = __dw_i2c_read(i2c_base, chip_addr, 0, 1, (uchar *)&tmp, 1); + if (ret) + __dw_i2c_init(i2c_base, 0, 0); + + return ret; +} + +static int designware_i2c_probe(struct udevice *bus) +{ + struct dw_i2c *priv = dev_get_priv(bus); + + /* Save base address from device-tree */ + priv->regs = (struct i2c_regs *)dev_get_addr(bus); + + __dw_i2c_init(priv->regs, 0, 0); + + return 0; +} + +static const struct dm_i2c_ops designware_i2c_ops = { + .xfer = designware_i2c_xfer, + .probe_chip = designware_i2c_probe_chip, + .set_bus_speed = designware_i2c_set_bus_speed, +}; + +static const struct udevice_id designware_i2c_ids[] = { + { .compatible = "snps,designware-i2c" }, + { } +}; + +U_BOOT_DRIVER(i2c_designware) = { + .name = "i2c_designware", + .id = UCLASS_I2C, + .of_match = designware_i2c_ids, + .probe = designware_i2c_probe, + .priv_auto_alloc_size = sizeof(struct dw_i2c), + .ops = &designware_i2c_ops, +}; + +#endif /* CONFIG_DM_I2C */