[U-Boot] [PATCH] i2c: adding driver for pxa27x, pxa3xx, pxa25x

Marek Vasut marex at denx.de
Wed Aug 12 21:34:14 CEST 2015


On Wednesday, August 12, 2015 at 08:43:52 PM, Andrew Ruder wrote:

Commit message is missing :'-(

> Cc: Marek Vasut <marex at denx.de>
> Cc: Heiko Schocher <hs at denx.de>
> Signed-off-by: Andrew Ruder <andrew.ruder at elecsyscorp.com>
> ---
> 
> This driver was written before the driver model stuff was really around (or
> at least based on a U-Boot version that only had very preliminary support)
> so there might be some older conventions in use here.  I have tested on a
> PXA270 board running upstream master with this driver, however - so to
> some extent this all still works fine.  Let me know if things need to
> change to be accepted, and I'll try to find some time to update!
> 
>  drivers/i2c/Makefile  |   1 +
>  drivers/i2c/pxa_i2c.c | 796
> ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 797
> insertions(+)
>  create mode 100644 drivers/i2c/pxa_i2c.c
> 
> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
> index 9b45248..cf2c8a8 100644
> --- a/drivers/i2c/Makefile
> +++ b/drivers/i2c/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_SYS_I2C_MXS) += mxs_i2c.o
>  obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
>  obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o
>  obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o
> +obj-$(CONFIG_SYS_I2C_PXA) += pxa_i2c.o
>  obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o
>  obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o
>  obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
> diff --git a/drivers/i2c/pxa_i2c.c b/drivers/i2c/pxa_i2c.c
> new file mode 100644
> index 0000000..859d6cf
> --- /dev/null
> +++ b/drivers/i2c/pxa_i2c.c
> @@ -0,0 +1,796 @@
> +/*
> + *  pxa_i2c.c
> + *
> + *  I2C adapter for the PXA I2C bus access.
> + *
> + *  Copyright (C) 2002 Intrinsyc Software Inc.
> + *  Copyright (C) 2004-2005 Deep Blue Solutions Ltd.
> + *  Copyright (C) 2014 Andrew Ruder
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License version 2 as
> + *  published by the Free Software Foundation.
> + *
> + *  This is a heavily modified version of the PXA I2C driver from the
> Linux + *  kernel 3.15.10.
> + */
> +
> +#include <common.h>
> +#include <compiler.h>
> +#include <i2c.h>
> +#include <asm/arch/pxa-regs.h>
> +
> +#include <asm/errno.h>
> +#include <asm/io.h>
> +
> +#define MAX_TRANSFER_MS 5000
> +#define WAIT_MASTER_MS 64
> +#define ABORT_LENGTH_MS 50
> +
> +/* Set up some defaults for various configurable pieces of this driver
> + * so that most of the time we don't need extra things defined

Multiline comment should be of the form:

/*
 * foo
 * bar
 */

> + */
> +#if !defined(CONFIG_SYS_PXA_STD_I2C_SPEED)
> +#define CONFIG_SYS_PXA_STD_I2C_SPEED 100000
> +#endif
> +
> +#if !defined(CONFIG_SYS_PXA_STD_I2C_SLAVE)
> +#define CONFIG_SYS_PXA_STD_I2C_SLAVE 1
> +#endif
> +
> +#if !defined(CONFIG_SYS_PXA_PWR_I2C_SPEED)
> +#define CONFIG_SYS_PXA_PWR_I2C_SPEED 40000
> +#endif
> +
> +#if !defined(CONFIG_SYS_PXA_PWR_I2C_SLAVE)
> +#define CONFIG_SYS_PXA_PWR_I2C_SLAVE 1
> +#endif

Please remove all this stuff, it's only going to hide bugs.

> +#if defined(CONFIG_CPU_MONAHANS) && defined(CONFIG_PXA_PWR_I2C)
> +#warning Monahans + PWRI2C is unlikely to work without additional testing
> +#endif
> +

[...]

> +#define ISR_ITE		(1 << 6)	   /* tx buffer empty */
> +#define ISR_IRF		(1 << 7)	   /* rx buffer full */
> +#define ISR_GCAD	(1 << 8)	   /* general call address detected */
> +#define ISR_SAD		(1 << 9)	   /* slave address detected */
> +#define ISR_BED		(1 << 10)	   /* bus error no ACK/NAK */
> +
> +struct pxa_i2c_msg {
> +	u16 addr;
> +	u16 flags;
> +#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */

Be consistent about using 1 << n or 0x0n00 please. Just use the BIT(n) macro.

> +#define I2C_M_RD		0x0001	/* read data, from slave to master */
> +#define I2C_M_STOP		0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */
> +#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
> +#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
> +#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
> +#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING 
*/
> +#define I2C_M_RECV_LEN		0x0400	/* length will be first received 
byte */
> +#define I2C_M_FIRST		0x0800	/* First message in a chain */
> +	u16 len;
> +	u8 *buf;
> +};
> +
> +struct pxa_i2c_state {
> +	struct pxa_i2c_msg	*msg;
> +	unsigned int		msg_num;
> +	unsigned int		msg_ptr;
> +};
> +
> +#define STD_I2C_BASE 0x40301680
> +#if defined(CONFIG_CPU_PXA27X) || defined(CONFIG_CPU_PXA25X)
> +#define PWR_I2C_BASE	0x40f00180
> +#define IBMR_OFFSET	0x00
> +#define IDBR_OFFSET	0x08
> +#define ICR_OFFSET	0x10
> +#define ISR_OFFSET	0x18
> +#define ISAR_OFFSET	0x20
> +#elif defined(CONFIG_CPU_MONAHANS)
> +#define PWR_I2C_BASE	0x40f500c0
> +#define IBMR_OFFSET	0x00
> +#define IDBR_OFFSET	0x04
> +#define ICR_OFFSET	0x08
> +#define ISR_OFFSET	0x0c
> +#define ISAR_OFFSET	0x10
> +#endif
> +
> +static inline void __iomem *
> +pxa_i2c_base(const struct i2c_adapter *adap)
> +{
> +	return (adap->hwadapnr == 0) ? (void *)STD_I2C_BASE : (void
> *)PWR_I2C_BASE; +}
> +
> +static inline void __iomem *
> +pxa_i2c_ibmr(const struct i2c_adapter *adap)
> +{
> +	return (void *)((char *)pxa_i2c_base(adap) + IBMR_OFFSET);

No need for these hideous casts, just use pxa_i2c_base() + OFFSET in the code.

> +}

[...]

> +static void
> +i2c_pxa_abort(struct i2c_adapter *adap)
> +{
> +	unsigned long long end;
> +
> +	end = get_ticks() + (get_tbclk() / 1000) * ABORT_LENGTH_MS;
> +
> +	while ((get_ticks() < end) &&

Please use get_timer() to implement the delay loop.

time = get_timer(0);
while (true) {
	reg = readl();
	if (reg & bit)
		break;

	if (get_timer(time) > timeout)
		return -ETIMEDOUT;
}

Also, the lpc32xx patches recently implemented a wait_for_bit() function.
If you make this generic, that'd be really cool.

> +	       (readl(_IBMR(adap)) & 0x1) == 0) {
> +		unsigned long icr = readl(_ICR(adap));
> +
> +		icr &= ~ICR_START;
> +		icr |= ICR_ACKNAK | ICR_STOP | ICR_TB;
> +
> +		writel(icr, _ICR(adap));
> +
> +		show_state(adap);
> +
> +		mdelay(1);
> +	}
> +
> +	writel(readl(_ICR(adap)) & ~(ICR_MA | ICR_START | ICR_STOP),
> +	       _ICR(adap));

Please use clrsetbits_le32();

> +}
[...]


More information about the U-Boot mailing list