diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-imx-early.c')
-rw-r--r-- | drivers/i2c/busses/i2c-imx-early.c | 70 |
1 files changed, 50 insertions, 20 deletions
diff --git a/drivers/i2c/busses/i2c-imx-early.c b/drivers/i2c/busses/i2c-imx-early.c index 472e4be83a..1db48a85e5 100644 --- a/drivers/i2c/busses/i2c-imx-early.c +++ b/drivers/i2c/busses/i2c-imx-early.c @@ -1,28 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright 2013 GE Intelligent Platforms, Inc * Copyright 2006,2009 Freescale Semiconductor, Inc. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * * Early I2C support functions to read SPD data or board * information. * Based on U-Boot drivers/i2c/fsl_i2c.c */ #include <common.h> #include <i2c/i2c.h> -#include <i2c/i2c-early.h> +#include <pbl/i2c.h> #include "i2c-imx.h" struct fsl_i2c { + struct pbl_i2c i2c; void __iomem *regs; unsigned int i2cr_ien_opcode; unsigned int i2sr_clr_opcode; @@ -98,6 +90,26 @@ static int i2c_fsl_acked(struct fsl_i2c *fsl_i2c) return i2c_fsl_poll_status(fsl_i2c, 0, I2SR_RXAK); } +static void i2c_fsl_settle(struct fsl_i2c *fsl_i2c) +{ +#ifdef CPU_ARCH_ARMv8 + udelay(100); +#else + /* + * We lack udelay on the 32bit i.MX SoCs, so delay manually: On an + * i.MX6 with a 66Mhz I2C peripheral clock one cycle of this loop + * takes 1.30us. Let's be generous and round up to 100 cycles. Other + * i.MX SoCs do not have a higher peripheral clock, so we should be + * safe here as well. + */ + + volatile int i = 0; + + for (i = 0; i < 100; i++) + fsl_i2c_read_reg(fsl_i2c, FSL_I2C_I2SR); +#endif +} + static int i2c_fsl_start(struct fsl_i2c *fsl_i2c) { unsigned int temp = 0; @@ -112,7 +124,7 @@ static int i2c_fsl_start(struct fsl_i2c *fsl_i2c) fsl_i2c, FSL_I2C_I2CR); /* Wait controller to be stable */ - udelay(100); + i2c_fsl_settle(fsl_i2c); /* Start I2C transaction */ temp = fsl_i2c_read_reg(fsl_i2c, FSL_I2C_I2CR); @@ -126,7 +138,7 @@ static int i2c_fsl_start(struct fsl_i2c *fsl_i2c) temp |= I2CR_MTX | I2CR_TXAK; fsl_i2c_write_reg(temp, fsl_i2c, FSL_I2C_I2CR); - return ret; + return 0; } static void i2c_fsl_stop(struct fsl_i2c *fsl_i2c) @@ -179,7 +191,7 @@ static int i2c_fsl_write(struct fsl_i2c *fsl_i2c, struct i2c_msg *msg) /* write data */ for (i = 0; i < msg->len; i++) { ret = i2c_fsl_send(fsl_i2c, msg->buf[i]); - if (ret) + if (ret) return ret; } @@ -238,9 +250,9 @@ static int i2c_fsl_read(struct fsl_i2c *fsl_i2c, struct i2c_msg *msg) * If successful returns the number of messages transferred, otherwise a negative * error code is returned. */ -int i2c_fsl_xfer(void *ctx, struct i2c_msg *msgs, int num) +static int i2c_fsl_xfer(struct pbl_i2c *i2c, struct i2c_msg *msgs, int num) { - struct fsl_i2c *fsl_i2c = ctx; + struct fsl_i2c *fsl_i2c = container_of(i2c, struct fsl_i2c, i2c); unsigned int i, temp; int ret; @@ -297,7 +309,7 @@ static struct fsl_i2c fsl_i2c; * This function returns a context pointer suitable to transfer I2C messages * using i2c_fsl_xfer. */ -void *ls1046_i2c_init(void __iomem *regs) +struct pbl_i2c *ls1046_i2c_init(void __iomem *regs) { fsl_i2c.regs = regs; fsl_i2c.regshift = 0; @@ -306,10 +318,26 @@ void *ls1046_i2c_init(void __iomem *regs) /* Divider for ~100kHz when coming from the ROM */ fsl_i2c.ifdr = 0x3e; - return &fsl_i2c; + fsl_i2c.i2c.xfer = i2c_fsl_xfer; + + return &fsl_i2c.i2c; } -void *imx8m_i2c_early_init(void __iomem *regs) +struct pbl_i2c *imx6_i2c_early_init(void __iomem *regs) +{ + fsl_i2c.regs = regs; + fsl_i2c.regshift = 2; + fsl_i2c.i2cr_ien_opcode = I2CR_IEN_OPCODE_1; + fsl_i2c.i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C; + /* Divider for ~100kHz when coming from the ROM */ + fsl_i2c.ifdr = 0x36; + + fsl_i2c.i2c.xfer = i2c_fsl_xfer; + + return &fsl_i2c.i2c; +} + +struct pbl_i2c *imx8m_i2c_early_init(void __iomem *regs) { fsl_i2c.regs = regs; fsl_i2c.regshift = 2; @@ -318,5 +346,7 @@ void *imx8m_i2c_early_init(void __iomem *regs) /* Divider for ~100kHz when coming from the ROM */ fsl_i2c.ifdr = 0x0f; - return &fsl_i2c; + fsl_i2c.i2c.xfer = i2c_fsl_xfer; + + return &fsl_i2c.i2c; } |