All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/3] dm: i2c: enable driver model for software i2c
@ 2015-03-10 10:30 Przemyslaw Marczak
  2015-03-10 10:30 ` [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver Przemyslaw Marczak
                   ` (4 more replies)
  0 siblings, 5 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-10 10:30 UTC (permalink / raw)
  To: u-boot

This patchset enables driver model support for software i2c bus driver.
It was tested on Trats2 and Odroid U3 devices.

It can be tested on any other device by just modifying the dts file,
first by disabling the hardware i2c bus and then, as it is described
in the Kconfig help entry, setup soft-i2c node.

The drivers, which are using the old api are not converted with this patchset.
I hope that maintainers will do this if required.

Probably the software i2c is used for PMIC devices not only for Trats2,
or Universal C210, so I suggest to wait with moving the drivers until
the pmic is done - this will prevent adding temporary code.

Przemyslaw Marczak (3):
  dm: i2c soft: enable driver model for software i2c driver
  Kconfig: i2c: remove wrong help message related to dm i2c
  Kconfig: i2c: add entry for driver-model software i2c

 drivers/i2c/Kconfig    |  54 +++++--
 drivers/i2c/Makefile   |   1 +
 drivers/i2c/soft_i2c.c | 410 +++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 444 insertions(+), 21 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver
  2015-03-10 10:30 [U-Boot] [PATCH 0/3] dm: i2c: enable driver model for software i2c Przemyslaw Marczak
@ 2015-03-10 10:30 ` Przemyslaw Marczak
  2015-03-23  8:44   ` Lukasz Majewski
  2015-03-23 23:38   ` Simon Glass
  2015-03-10 10:30 ` [U-Boot] [PATCH 2/3] Kconfig: i2c: remove wrong help message related to dm i2c Przemyslaw Marczak
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-10 10:30 UTC (permalink / raw)
  To: u-boot

This change adds driver model support to software emulated
i2c bus driver. To bind the driver, proper device-tree node
must be defined, with the following attributes:
- alias: to keep proper bus order
- compatible: 'soft-i2c'
- clock-frequency [Hz]
- clock-pin, data-pin: gpio phandles

/* Define the alias number to keep bus numbering order */
aliases {
	[...]
	i2c5 = "/i2c at 13500000";
	i2c6 = "/soft-i2c at 1";
	[...]
};

/* Define the basic bus attributes */
soft-i2c at 1 {
	#address-cells = <1>;
	#size-cells = <0>;
	compatible = "soft-i2c";
	clock-frequency = <50000>;

	/* Define the proper GPIO pins */
	clock-pin = <&gpa0 0 GPIO_ACTIVE_HIGH>;
	data-pin = <&gpa0 1 GPIO_ACTIVE_HIGH>;

	/* Optionally, define some driver node (bus child) */
	somedev at 0x44 {
		compatible = "somedev";
		reg = <0x44>;
		[...]
	};
};

The device can be accessed by the i2c command:
 i2c dev 8                   (bus number set by alias)
 i2c probe <0x44>            (address is optionally)
 i2c md 0x44 0x0             (dump dev registers at address 0x0)
 Valid chip addresses: 0x44  (success!)
 ...

The previous driver functionality stays unchanged. Driving the bus lines
is done by dm gpio calls in the preprocessor macros. Each, can be redefined
by the user as previous.

Tested on Trats2 and Odroid U3.

Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Simon Glass <sjg@chromium.org>
Cc: Heiko Schocher <hs@denx.de>
---
 drivers/i2c/Makefile   |   1 +
 drivers/i2c/soft_i2c.c | 410 +++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 400 insertions(+), 11 deletions(-)

diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 774bc94..7039b6d 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -6,6 +6,7 @@
 #
 obj-$(CONFIG_DM_I2C) += i2c-uclass.o
 obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
+obj-$(CONFIG_DM_I2C_SOFT) += soft_i2c.o
 
 obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
 obj-$(CONFIG_I2C_MV) += mv_i2c.o
diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
index db9b402..7afae0b 100644
--- a/drivers/i2c/soft_i2c.c
+++ b/drivers/i2c/soft_i2c.c
@@ -1,4 +1,7 @@
 /*
+ * (C) Copyright 2015, Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
  * (C) Copyright 2009
  * Heiko Schocher, DENX Software Engineering, hs at denx.de.
  * Changes for multibus/multiadapter I2C support.
@@ -14,6 +17,11 @@
  */
 
 #include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <div64.h>
+#include <asm/gpio.h>
 #ifdef	CONFIG_MPC8260			/* only valid for MPC8260 */
 #include <ioports.h>
 #include <asm/io.h>
@@ -32,11 +40,9 @@
 #if defined(CONFIG_MPC852T) || defined(CONFIG_MPC866)
 #include <asm/io.h>
 #endif
-#include <i2c.h>
 
+#if defined(CONFIG_SYS_I2C)
 #if defined(CONFIG_SOFT_I2C_GPIO_SCL)
-# include <asm/gpio.h>
-
 # ifndef I2C_GPIO_SYNC
 #  define I2C_GPIO_SYNC
 # endif
@@ -85,6 +91,7 @@
 # endif
 
 #endif
+#endif
 
 /* #define	DEBUG_I2C	*/
 
@@ -109,6 +116,65 @@ DECLARE_GLOBAL_DATA_PTR;
 #define CONFIG_SYS_I2C_SOFT_SLAVE CONFIG_SYS_I2C_SLAVE
 #endif
 
+/* DM SOFT I2C */
+#ifdef CONFIG_DM_I2C_SOFT
+# ifndef I2C_GPIO_SYNC
+#  define I2C_GPIO_SYNC(gpio)
+# endif
+
+# ifndef I2C_INIT
+#  define I2C_INIT(scl, sda)  \
+	do { } while (0)
+# endif
+
+# ifndef I2C_ACTIVE
+#  define I2C_ACTIVE(sda) \
+	do { } while (0)
+# endif
+
+# ifndef I2C_TRISTATE
+#  define I2C_TRISTATE(sda) \
+	do { } while (0)
+# endif
+
+# ifndef I2C_READ
+#  define I2C_READ(sda) dm_gpio_get_value(sda);
+# endif
+
+# ifndef I2C_SDA
+#  define I2C_SDA(sda, bit) \
+	do { \
+		if (bit) { \
+			sda->flags &= ~GPIOD_IS_OUT; \
+			sda->flags |= GPIOD_IS_IN; \
+			dm_gpio_set_dir(sda); \
+		} else { \
+			sda->flags &= ~GPIOD_IS_IN; \
+			sda->flags |= GPIOD_IS_OUT; \
+			dm_gpio_set_dir(sda); \
+			dm_gpio_set_value(sda, 0); \
+		} \
+		I2C_GPIO_SYNC(sda); \
+	} while (0)
+# endif
+
+# ifndef I2C_SCL
+#  define I2C_SCL(scl, bit) \
+	do { \
+		scl->flags &= ~GPIOD_IS_IN; \
+		scl->flags |= GPIOD_IS_OUT; \
+		dm_gpio_set_dir(scl); \
+		dm_gpio_set_value(scl, bit); \
+		I2C_GPIO_SYNC(scl); \
+	} while (0)
+# endif
+
+# ifndef I2C_DELAY
+#  define I2C_DELAY(us) udelay(us)	/* 1/4 I2C clock duration */
+# endif
+
+#endif /* CONFIG_DM_I2C_SOFT */
+
 /*-----------------------------------------------------------------------
  * Definitions
  */
@@ -117,7 +183,6 @@ DECLARE_GLOBAL_DATA_PTR;
 #define I2C_ACK		0		/* PD_SDA level to ack a byte */
 #define I2C_NOACK	1		/* PD_SDA level to noack a byte */
 
-
 #ifdef DEBUG_I2C
 #define PRINTD(fmt,args...)	do {	\
 		printf (fmt ,##args);	\
@@ -129,21 +194,30 @@ DECLARE_GLOBAL_DATA_PTR;
 /*-----------------------------------------------------------------------
  * Local functions
  */
+#ifdef CONFIG_SYS_I2C
 #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
-static void  send_reset	(void);
+static void send_reset(void);
+#endif
+static void send_start(void);
+static void send_stop(void);
+static void send_ack(int);
+static int write_byte(uchar byte);
+static uchar read_byte(int);
+#else
+static void send_reset(struct gpio_desc *, struct gpio_desc *, int);
+static void send_start(struct gpio_desc *, struct gpio_desc *, int);
+static void send_stop(struct gpio_desc *, struct gpio_desc *, int);
+static void send_ack(struct gpio_desc *, struct gpio_desc *, int, int);
+static int write_byte(struct gpio_desc *, struct gpio_desc *, int, uchar);
+static uchar read_byte(struct gpio_desc *, struct gpio_desc *, int, int);
 #endif
-static void  send_start	(void);
-static void  send_stop	(void);
-static void  send_ack	(int);
-static int   write_byte	(uchar byte);
-static uchar read_byte	(int);
-
 #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
 /*-----------------------------------------------------------------------
  * Send a reset sequence consisting of 9 clocks with the data signal high
  * to clock any confused device back into an idle state.  Also send a
  * <stop> at the end of the sequence for belts & suspenders.
  */
+#ifdef CONFIG_SYS_I2C_SOFT
 static void send_reset(void)
 {
 	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
@@ -166,11 +240,36 @@ static void send_reset(void)
 	send_stop();
 	I2C_TRISTATE;
 }
+#else
+static void send_reset(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
+{
+	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
+	int j;
+
+	I2C_SCL(scl, 1);
+	I2C_SDA(sda, 1);
+#ifdef	I2C_INIT
+	I2C_INIT(scl, sda);
+#endif
+	I2C_TRISTATE(sda);
+	for (j = 0; j < 9; j++) {
+		I2C_SCL(scl, 0);
+		I2C_DELAY(delay);
+		I2C_DELAY(delay);
+		I2C_SCL(scl, 1);
+		I2C_DELAY(delay);
+		I2C_DELAY(delay);
+	}
+	send_stop(scl, sda, delay);
+	I2C_TRISTATE(sda);
+}
+#endif /* CONFIG_SYS_I2C_SOFT */
 #endif
 
 /*-----------------------------------------------------------------------
  * START: High -> Low on SDA while SCL is High
  */
+#ifdef CONFIG_SYS_I2C_SOFT
 static void send_start(void)
 {
 	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
@@ -184,10 +283,25 @@ static void send_start(void)
 	I2C_SDA(0);
 	I2C_DELAY;
 }
+#else
+static void send_start(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
+{
+	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
 
+	I2C_DELAY(delay);
+	I2C_SDA(sda, 1);
+	I2C_ACTIVE(sda);
+	I2C_DELAY(delay);
+	I2C_SCL(scl, 1);
+	I2C_DELAY(delay);
+	I2C_SDA(sda, 0);
+	I2C_DELAY(delay);
+}
+#endif /* CONFIG_SYS_I2C_SOFT */
 /*-----------------------------------------------------------------------
  * STOP: Low -> High on SDA while SCL is High
  */
+#ifdef CONFIG_SYS_I2C_SOFT
 static void send_stop(void)
 {
 	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
@@ -203,10 +317,28 @@ static void send_stop(void)
 	I2C_DELAY;
 	I2C_TRISTATE;
 }
+#else
+static void send_stop(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
+{
+	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
+
+	I2C_SCL(scl, 0);
+	I2C_DELAY(delay);
+	I2C_SDA(sda, 0);
+	I2C_ACTIVE(sda);
+	I2C_DELAY(delay);
+	I2C_SCL(scl, 1);
+	I2C_DELAY(delay);
+	I2C_SDA(sda, 1);
+	I2C_DELAY(delay);
+	I2C_TRISTATE(sda);
+}
+#endif /* CONFIG_SYS_I2C_SOFT */
 
 /*-----------------------------------------------------------------------
  * ack should be I2C_ACK or I2C_NOACK
  */
+#ifdef CONFIG_SYS_I2C_SOFT
 static void send_ack(int ack)
 {
 	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
@@ -222,10 +354,29 @@ static void send_ack(int ack)
 	I2C_SCL(0);
 	I2C_DELAY;
 }
+#else
+static void send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
+		     int delay, int ack)
+{
+	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
+
+	I2C_SCL(scl, 0);
+	I2C_DELAY(delay);
+	I2C_ACTIVE(sda);
+	I2C_SDA(sda, ack);
+	I2C_DELAY(delay);
+	I2C_SCL(scl, 1);
+	I2C_DELAY(delay);
+	I2C_DELAY(delay);
+	I2C_SCL(scl, 0);
+	I2C_DELAY(delay);
+}
+#endif
 
 /*-----------------------------------------------------------------------
  * Send 8 bits and look for an acknowledgement.
  */
+#ifdef CONFIG_SYS_I2C_SOFT
 static int write_byte(uchar data)
 {
 	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
@@ -263,11 +414,52 @@ static int write_byte(uchar data)
 
 	return(nack);	/* not a nack is an ack */
 }
+#else
+static int write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
+		      int delay, uchar data)
+{
+	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
+	int j;
+	int nack;
+
+	I2C_ACTIVE(sda);
+	for (j = 0; j < 8; j++) {
+		I2C_SCL(scl, 0);
+		I2C_DELAY(delay);
+		I2C_SDA(sda, data & 0x80);
+		I2C_DELAY(delay);
+		I2C_SCL(scl, 1);
+		I2C_DELAY(delay);
+		I2C_DELAY(delay);
+
+		data <<= 1;
+	}
+
+	/*
+	 * Look for an <ACK>(negative logic) and return it.
+	 */
+	I2C_SCL(scl, 0);
+	I2C_DELAY(delay);
+	I2C_SDA(sda, 1);
+	I2C_TRISTATE(sda);
+	I2C_DELAY(delay);
+	I2C_SCL(scl, 1);
+	I2C_DELAY(delay);
+	I2C_DELAY(delay);
+	nack = I2C_READ(sda);
+	I2C_SCL(scl, 0);
+	I2C_DELAY(delay);
+	I2C_ACTIVE(sda);
+
+	return nack;	/* not a nack is an ack */
+}
+#endif
 
 /*-----------------------------------------------------------------------
  * if ack == I2C_ACK, ACK the byte so can continue reading, else
  * send I2C_NOACK to end the read.
  */
+#ifdef CONFIG_SYS_I2C_SOFT
 static uchar read_byte(int ack)
 {
 	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
@@ -293,10 +485,38 @@ static uchar read_byte(int ack)
 
 	return(data);
 }
+#else
+static uchar read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
+		       int delay, int ack)
+{
+	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
+	int  data;
+	int  j;
+
+	/*
+	 * Read 8 bits, MSB first.
+	 */
+	I2C_TRISTATE(sda);
+	I2C_SDA(sda, 1);
+	data = 0;
+	for (j = 0; j < 8; j++) {
+		I2C_SCL(scl, 0);
+		I2C_DELAY(delay);
+		I2C_SCL(scl, 1);
+		I2C_DELAY(delay);
+		data <<= 1;
+		data |= I2C_READ(sda);
+		I2C_DELAY(delay);
+	}
+	send_ack(scl, sda, delay, ack);
 
+	return data;
+}
+#endif /* CONFIG_SYS_I2C_SOFT */
 /*-----------------------------------------------------------------------
  * Initialization
  */
+#ifdef CONFIG_SYS_I2C_SOFT
 static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
 {
 #if defined(CONFIG_SYS_I2C_INIT_BOARD)
@@ -314,12 +534,14 @@ static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
 	send_reset ();
 #endif
 }
+#endif
 
 /*-----------------------------------------------------------------------
  * Probe to see if a chip is present.  Also good for checking for the
  * completion of EEPROM writes since the chip stops responding until
  * the write completes (typically 10mSec).
  */
+#ifdef CONFIG_SYS_I2C_SOFT
 static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
 {
 	int rc;
@@ -334,10 +556,12 @@ static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
 
 	return (rc ? 1 : 0);
 }
+#endif
 
 /*-----------------------------------------------------------------------
  * Read bytes
  */
+#ifdef CONFIG_SYS_I2C_SOFT
 static int  soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
 			int alen, uchar *buffer, int len)
 {
@@ -409,10 +633,12 @@ static int  soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
 	send_stop();
 	return(0);
 }
+#endif
 
 /*-----------------------------------------------------------------------
  * Write bytes
  */
+#ifdef CONFIG_SYS_I2C_SOFT
 static int  soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
 			int alen, uchar *buffer, int len)
 {
@@ -444,10 +670,12 @@ static int  soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
 	send_stop();
 	return(failures);
 }
+#endif
 
 /*
  * Register soft i2c adapters
  */
+#ifdef CONFIG_SYS_I2C_SOFT
 U_BOOT_I2C_ADAP_COMPLETE(soft0, soft_i2c_init, soft_i2c_probe,
 			 soft_i2c_read, soft_i2c_write, NULL,
 			 CONFIG_SYS_I2C_SOFT_SPEED, CONFIG_SYS_I2C_SOFT_SLAVE,
@@ -473,3 +701,163 @@ U_BOOT_I2C_ADAP_COMPLETE(soft3, soft_i2c_init, soft_i2c_probe,
 			 CONFIG_SYS_I2C_SOFT_SLAVE_4,
 			 3)
 #endif
+#endif /* CONFIG_SYS_I2C_SOFT */
+
+#ifdef CONFIG_DM_I2C_SOFT
+struct soft_i2c_bus {
+	unsigned int speed;
+	unsigned long delay;
+	struct gpio_desc scl;
+	struct gpio_desc sda;
+};
+
+static int i2c_write_data(struct soft_i2c_bus *i2c_bus, uchar chip,
+			  uchar *buffer, int len, bool end_with_repeated_start)
+{
+	struct gpio_desc *scl = &i2c_bus->scl;
+	struct gpio_desc *sda = &i2c_bus->sda;
+	unsigned int delay = i2c_bus->delay;
+	int failures = 0;
+
+	PRINTD("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
+
+	send_start(scl, sda, delay);
+	if (write_byte(scl, sda, delay, chip << 1)) {
+		send_stop(scl, sda, delay);
+		PRINTD("i2c_write, no chip responded %02X\n", chip);
+		return -ENODEV;
+	}
+
+	while (len-- > 0) {
+		if (write_byte(scl, sda, delay, *buffer++))
+			failures++;
+	}
+
+	send_stop(scl, sda, delay);
+
+	return failures;
+}
+
+static int i2c_read_data(struct soft_i2c_bus *i2c_bus, uchar chip,
+			 uchar *buffer, int len)
+{
+	struct gpio_desc *scl = &i2c_bus->scl;
+	struct gpio_desc *sda = &i2c_bus->sda;
+	unsigned int delay = i2c_bus->delay;
+
+	PRINTD("%s: chip %x buffer: %x len %d\n", __func__, chip, buffer, len);
+
+	send_start(scl, sda, delay);
+	write_byte(scl, sda, delay, (chip << 1) | 1);	/* read cycle */
+
+	while (len-- > 0)
+		*buffer++ = read_byte(scl, sda, delay, len == 0);
+
+	send_stop(scl, sda, delay);
+
+	return 0;
+}
+
+static int soft_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+	struct soft_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 soft_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
+{
+	struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
+	struct gpio_desc *scl = &i2c_bus->scl;
+	struct gpio_desc *sda = &i2c_bus->sda;
+	unsigned int delay = i2c_bus->delay;
+	int ret;
+
+	send_start(scl, sda, delay);
+	ret = write_byte(scl, sda, delay, (chip << 1) | 0);
+	send_stop(scl, sda, delay);
+
+	PRINTD("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
+	       __func__, dev->seq, dev->name, chip, chip_flags, ret);
+
+	return ret;
+}
+
+static int soft_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+	struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
+	struct gpio_desc *scl = &i2c_bus->scl;
+	struct gpio_desc *sda = &i2c_bus->sda;
+
+	i2c_bus->speed = speed;
+	i2c_bus->delay = lldiv(1000000, speed << 2);
+
+	send_reset(scl, sda, i2c_bus->delay);
+
+	PRINTD("%s: bus: %d (%s) speed: %u Hz (1/4 of period: %lu us)\n",
+	       __func__, dev->seq, dev->name, speed, i2c_bus->delay);
+
+	return 0;
+}
+
+static int soft_i2c_ofdata_to_platdata(struct udevice *dev)
+{
+	struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
+	const void *blob = gd->fdt_blob;
+	char *pin_name;
+	int ret;
+
+	pin_name = "clock-pin";
+	ret = gpio_request_by_name_nodev(blob, dev->of_offset, pin_name,
+					 0, &i2c_bus->scl, GPIOD_IS_OUT);
+	if (ret)
+		goto error;
+
+	pin_name = "data-pin";
+	ret = gpio_request_by_name_nodev(blob, dev->of_offset, pin_name,
+					 0, &i2c_bus->sda, GPIOD_IS_OUT);
+	if (ret)
+		goto error;
+
+	PRINTD("%s: bus: %d (%s) fdt node ok\n", __func__, dev->seq, dev->name);
+
+	return 0;
+error:
+	error("Can't get %s for soft i2c dev: %s", pin_name, dev->name);
+	return ret;
+}
+
+static const struct dm_i2c_ops soft_i2c_ops = {
+	.xfer		= soft_i2c_xfer,
+	.probe_chip	= soft_i2c_probe,
+	.set_bus_speed	= soft_i2c_set_bus_speed,
+};
+
+static const struct udevice_id soft_i2c_ids[] = {
+	{ .compatible = "soft-i2c" },
+	{ }
+};
+
+U_BOOT_DRIVER(soft_i2c) = {
+	.name	= "soft-i2c",
+	.id	= UCLASS_I2C,
+	.of_match = soft_i2c_ids,
+	.ofdata_to_platdata = soft_i2c_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct soft_i2c_bus),
+	.ops	= &soft_i2c_ops,
+};
+#endif /* CONFIG_DM_I2C_SOFT */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 2/3] Kconfig: i2c: remove wrong help message related to dm i2c
  2015-03-10 10:30 [U-Boot] [PATCH 0/3] dm: i2c: enable driver model for software i2c Przemyslaw Marczak
  2015-03-10 10:30 ` [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver Przemyslaw Marczak
@ 2015-03-10 10:30 ` Przemyslaw Marczak
  2015-03-23  8:45   ` Lukasz Majewski
  2015-03-23 23:39   ` Simon Glass
  2015-03-10 10:30 ` [U-Boot] [PATCH 3/3] Kconfig: i2c: add entry for driver-model software i2c Przemyslaw Marczak
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-10 10:30 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Simon Glass <sjg@chromium.org>
Cc: Heiko Schocher <hs@denx.de>
---
 drivers/i2c/Kconfig | 11 +----------
 1 file changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 692810d..0a52ed9 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -2,16 +2,7 @@ config DM_I2C
 	bool "Enable Driver Model for I2C drivers"
 	depends on DM
 	help
-	  Enable driver model for I2C. This SPI flash interface
-	  (spi_flash_probe(), spi_flash_write(), etc.) is then
-	  implemented by the SPI flash uclass. There is one standard
-	  SPI flash driver which knows how to probe most chips
-	  supported by U-Boot. The uclass interface is defined in
-	  include/spi_flash.h, but is currently fully compatible
-	  with the old interface to avoid confusion and duplication
-	  during the transition parent. SPI and SPI flash must be
-	  enabled together (it is not possible to use driver model
-	  for one and not the other).
+	  Enable driver model for I2C.
 
 config DM_I2C_COMPAT
 	bool "Enable I2C compatibility layer"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 3/3] Kconfig: i2c: add entry for driver-model software i2c
  2015-03-10 10:30 [U-Boot] [PATCH 0/3] dm: i2c: enable driver model for software i2c Przemyslaw Marczak
  2015-03-10 10:30 ` [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver Przemyslaw Marczak
  2015-03-10 10:30 ` [U-Boot] [PATCH 2/3] Kconfig: i2c: remove wrong help message related to dm i2c Przemyslaw Marczak
@ 2015-03-10 10:30 ` Przemyslaw Marczak
  2015-03-23  8:46   ` Lukasz Majewski
                     ` (2 more replies)
  2015-03-27 17:33 ` [U-Boot] [PATCH V2 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
  2015-03-31 16:57 ` [U-Boot] [PATCH V3 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
  4 siblings, 3 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-10 10:30 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Simon Glass <sjg@chromium.org>
Cc: Heiko Schocher <hs@denx.de>
---
 drivers/i2c/Kconfig | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 0a52ed9..dd7eb3c 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -13,6 +13,49 @@ config DM_I2C_COMPAT
 	  to convert all code for a board in a single commit. It should not
 	  be enabled for any board in an official release.
 
+config DM_I2C_SOFT
+	bool "Enable Driver Model for Software I2C Driver"
+	depends on DM_I2C
+	help
+	  Enable the i2c bus driver emulation by using GPIO.
+	  The bus configuration is given by the device-tree, like below.
+
+	  /* First, define the alias number to have continuous bus numbering */
+	  aliases {
+	    [...]
+	    i2c5 = "/i2c at 13500000";
+	    i2c6 = "/soft-i2c at 1";
+	    [...]
+	  }
+
+	  /* And next define the basic bus attributes */
+	  soft-i2c at 1 {
+	    #address-cells = <1>;
+	    #size-cells = <0>;
+	    compatible = "soft-i2c";
+	    clock-frequency = <50000>;
+	    /* Define the proper GPIO pins */
+	    clock-pin = <&gpa0 0 GPIO_ACTIVE_HIGH>;
+	    data-pin = <&gpa0 1 GPIO_ACTIVE_HIGH>;
+
+	    /* Optionally, define some driver node (bus child) */
+	    somedev at 0x44 {
+	        compatible = "somedev";
+	        reg = <0x44>;
+	        [...]
+	    };
+	  }
+
+	  The device can be accessed by the i2c command:
+	  # i2c dev 8                   (bus number set by alias)
+	  # i2c probe <0x44>            (address is optionally)
+	  # i2c md 0x44 0x0             (dump dev registers at address 0x0)
+	  # Valid chip addresses: 0x44  (success!)
+	  ...
+
+	  Driving the bus lines is done by dm gpio calls in the preprocessor
+	  macros. Each, can be redefined by the user.
+
 config SYS_I2C_UNIPHIER
 	bool "UniPhier I2C driver"
 	depends on ARCH_UNIPHIER && DM_I2C
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver
  2015-03-10 10:30 ` [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver Przemyslaw Marczak
@ 2015-03-23  8:44   ` Lukasz Majewski
  2015-03-23 23:38   ` Simon Glass
  1 sibling, 0 replies; 36+ messages in thread
From: Lukasz Majewski @ 2015-03-23  8:44 UTC (permalink / raw)
  To: u-boot

Hi Przemyslaw,

> This change adds driver model support to software emulated
> i2c bus driver. To bind the driver, proper device-tree node
> must be defined, with the following attributes:
> - alias: to keep proper bus order
> - compatible: 'soft-i2c'
> - clock-frequency [Hz]
> - clock-pin, data-pin: gpio phandles
> 
> /* Define the alias number to keep bus numbering order */
> aliases {
> 	[...]
> 	i2c5 = "/i2c at 13500000";
> 	i2c6 = "/soft-i2c at 1";
> 	[...]
> };
> 
> /* Define the basic bus attributes */
> soft-i2c at 1 {
> 	#address-cells = <1>;
> 	#size-cells = <0>;
> 	compatible = "soft-i2c";
> 	clock-frequency = <50000>;
> 
> 	/* Define the proper GPIO pins */
> 	clock-pin = <&gpa0 0 GPIO_ACTIVE_HIGH>;
> 	data-pin = <&gpa0 1 GPIO_ACTIVE_HIGH>;
> 
> 	/* Optionally, define some driver node (bus child) */
> 	somedev at 0x44 {
> 		compatible = "somedev";
> 		reg = <0x44>;
> 		[...]
> 	};
> };
> 
> The device can be accessed by the i2c command:
>  i2c dev 8                   (bus number set by alias)
>  i2c probe <0x44>            (address is optionally)
>  i2c md 0x44 0x0             (dump dev registers at address 0x0)
>  Valid chip addresses: 0x44  (success!)
>  ...
> 
> The previous driver functionality stays unchanged. Driving the bus
> lines is done by dm gpio calls in the preprocessor macros. Each, can
> be redefined by the user as previous.
> 
> Tested on Trats2 and Odroid U3.
> 
> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
> Cc: Mike Frysinger <vapier@gentoo.org>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Heiko Schocher <hs@denx.de>
> ---
>  drivers/i2c/Makefile   |   1 +
>  drivers/i2c/soft_i2c.c | 410
> +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed,
> 400 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
> index 774bc94..7039b6d 100644
> --- a/drivers/i2c/Makefile
> +++ b/drivers/i2c/Makefile
> @@ -6,6 +6,7 @@
>  #
>  obj-$(CONFIG_DM_I2C) += i2c-uclass.o
>  obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
> +obj-$(CONFIG_DM_I2C_SOFT) += soft_i2c.o
>  
>  obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
>  obj-$(CONFIG_I2C_MV) += mv_i2c.o
> diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
> index db9b402..7afae0b 100644
> --- a/drivers/i2c/soft_i2c.c
> +++ b/drivers/i2c/soft_i2c.c
> @@ -1,4 +1,7 @@
>  /*
> + * (C) Copyright 2015, Samsung Electronics
> + * Przemyslaw Marczak <p.marczak@samsung.com>
> + *
>   * (C) Copyright 2009
>   * Heiko Schocher, DENX Software Engineering, hs at denx.de.
>   * Changes for multibus/multiadapter I2C support.
> @@ -14,6 +17,11 @@
>   */
>  
>  #include <common.h>
> +#include <errno.h>
> +#include <dm.h>
> +#include <i2c.h>
> +#include <div64.h>
> +#include <asm/gpio.h>
>  #ifdef	CONFIG_MPC8260			/* only valid
> for MPC8260 */ #include <ioports.h>
>  #include <asm/io.h>
> @@ -32,11 +40,9 @@
>  #if defined(CONFIG_MPC852T) || defined(CONFIG_MPC866)
>  #include <asm/io.h>
>  #endif
> -#include <i2c.h>
>  
> +#if defined(CONFIG_SYS_I2C)
>  #if defined(CONFIG_SOFT_I2C_GPIO_SCL)
> -# include <asm/gpio.h>
> -
>  # ifndef I2C_GPIO_SYNC
>  #  define I2C_GPIO_SYNC
>  # endif
> @@ -85,6 +91,7 @@
>  # endif
>  
>  #endif
> +#endif
>  
>  /* #define	DEBUG_I2C	*/
>  
> @@ -109,6 +116,65 @@ DECLARE_GLOBAL_DATA_PTR;
>  #define CONFIG_SYS_I2C_SOFT_SLAVE CONFIG_SYS_I2C_SLAVE
>  #endif
>  
> +/* DM SOFT I2C */
> +#ifdef CONFIG_DM_I2C_SOFT
> +# ifndef I2C_GPIO_SYNC
> +#  define I2C_GPIO_SYNC(gpio)
> +# endif
> +
> +# ifndef I2C_INIT
> +#  define I2C_INIT(scl, sda)  \
> +	do { } while (0)
> +# endif
> +
> +# ifndef I2C_ACTIVE
> +#  define I2C_ACTIVE(sda) \
> +	do { } while (0)
> +# endif
> +
> +# ifndef I2C_TRISTATE
> +#  define I2C_TRISTATE(sda) \
> +	do { } while (0)
> +# endif
> +
> +# ifndef I2C_READ
> +#  define I2C_READ(sda) dm_gpio_get_value(sda);
> +# endif
> +
> +# ifndef I2C_SDA
> +#  define I2C_SDA(sda, bit) \
> +	do { \
> +		if (bit) { \
> +			sda->flags &= ~GPIOD_IS_OUT; \
> +			sda->flags |= GPIOD_IS_IN; \
> +			dm_gpio_set_dir(sda); \
> +		} else { \
> +			sda->flags &= ~GPIOD_IS_IN; \
> +			sda->flags |= GPIOD_IS_OUT; \
> +			dm_gpio_set_dir(sda); \
> +			dm_gpio_set_value(sda, 0); \
> +		} \
> +		I2C_GPIO_SYNC(sda); \
> +	} while (0)
> +# endif
> +
> +# ifndef I2C_SCL
> +#  define I2C_SCL(scl, bit) \
> +	do { \
> +		scl->flags &= ~GPIOD_IS_IN; \
> +		scl->flags |= GPIOD_IS_OUT; \
> +		dm_gpio_set_dir(scl); \
> +		dm_gpio_set_value(scl, bit); \
> +		I2C_GPIO_SYNC(scl); \
> +	} while (0)
> +# endif
> +
> +# ifndef I2C_DELAY
> +#  define I2C_DELAY(us) udelay(us)	/* 1/4 I2C clock duration
> */ +# endif
> +
> +#endif /* CONFIG_DM_I2C_SOFT */
> +
>  /*-----------------------------------------------------------------------
>   * Definitions
>   */
> @@ -117,7 +183,6 @@ DECLARE_GLOBAL_DATA_PTR;
>  #define I2C_ACK		0		/* PD_SDA level to
> ack a byte */ #define I2C_NOACK	1		/* PD_SDA
> level to noack a byte */ 
> -
>  #ifdef DEBUG_I2C
>  #define PRINTD(fmt,args...)	do {	\
>  		printf (fmt ,##args);	\
> @@ -129,21 +194,30 @@ DECLARE_GLOBAL_DATA_PTR;
>  /*-----------------------------------------------------------------------
>   * Local functions
>   */
> +#ifdef CONFIG_SYS_I2C
>  #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
> -static void  send_reset	(void);
> +static void send_reset(void);
> +#endif
> +static void send_start(void);
> +static void send_stop(void);
> +static void send_ack(int);
> +static int write_byte(uchar byte);
> +static uchar read_byte(int);
> +#else
> +static void send_reset(struct gpio_desc *, struct gpio_desc *, int);
> +static void send_start(struct gpio_desc *, struct gpio_desc *, int);
> +static void send_stop(struct gpio_desc *, struct gpio_desc *, int);
> +static void send_ack(struct gpio_desc *, struct gpio_desc *, int,
> int); +static int write_byte(struct gpio_desc *, struct gpio_desc *,
> int, uchar); +static uchar read_byte(struct gpio_desc *, struct
> gpio_desc *, int, int); #endif
> -static void  send_start	(void);
> -static void  send_stop	(void);
> -static void  send_ack	(int);
> -static int   write_byte	(uchar byte);
> -static uchar read_byte	(int);
> -
>  #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
>  /*-----------------------------------------------------------------------
>   * Send a reset sequence consisting of 9 clocks with the data signal
> high
>   * to clock any confused device back into an idle state.  Also send a
>   * <stop> at the end of the sequence for belts & suspenders.
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static void send_reset(void)
>  {
>  	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
> @@ -166,11 +240,36 @@ static void send_reset(void)
>  	send_stop();
>  	I2C_TRISTATE;
>  }
> +#else
> +static void send_reset(struct gpio_desc *scl, struct gpio_desc *sda,
> int delay) +{
> +	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
> +	int j;
> +
> +	I2C_SCL(scl, 1);
> +	I2C_SDA(sda, 1);
> +#ifdef	I2C_INIT
> +	I2C_INIT(scl, sda);
> +#endif
> +	I2C_TRISTATE(sda);
> +	for (j = 0; j < 9; j++) {
> +		I2C_SCL(scl, 0);
> +		I2C_DELAY(delay);
> +		I2C_DELAY(delay);
> +		I2C_SCL(scl, 1);
> +		I2C_DELAY(delay);
> +		I2C_DELAY(delay);
> +	}
> +	send_stop(scl, sda, delay);
> +	I2C_TRISTATE(sda);
> +}
> +#endif /* CONFIG_SYS_I2C_SOFT */
>  #endif
>  
>  /*-----------------------------------------------------------------------
>   * START: High -> Low on SDA while SCL is High
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static void send_start(void)
>  {
>  	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
> @@ -184,10 +283,25 @@ static void send_start(void)
>  	I2C_SDA(0);
>  	I2C_DELAY;
>  }
> +#else
> +static void send_start(struct gpio_desc *scl, struct gpio_desc *sda,
> int delay) +{
> +	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
>  
> +	I2C_DELAY(delay);
> +	I2C_SDA(sda, 1);
> +	I2C_ACTIVE(sda);
> +	I2C_DELAY(delay);
> +	I2C_SCL(scl, 1);
> +	I2C_DELAY(delay);
> +	I2C_SDA(sda, 0);
> +	I2C_DELAY(delay);
> +}
> +#endif /* CONFIG_SYS_I2C_SOFT */
>  /*-----------------------------------------------------------------------
>   * STOP: Low -> High on SDA while SCL is High
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static void send_stop(void)
>  {
>  	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
> @@ -203,10 +317,28 @@ static void send_stop(void)
>  	I2C_DELAY;
>  	I2C_TRISTATE;
>  }
> +#else
> +static void send_stop(struct gpio_desc *scl, struct gpio_desc *sda,
> int delay) +{
> +	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
> +
> +	I2C_SCL(scl, 0);
> +	I2C_DELAY(delay);
> +	I2C_SDA(sda, 0);
> +	I2C_ACTIVE(sda);
> +	I2C_DELAY(delay);
> +	I2C_SCL(scl, 1);
> +	I2C_DELAY(delay);
> +	I2C_SDA(sda, 1);
> +	I2C_DELAY(delay);
> +	I2C_TRISTATE(sda);
> +}
> +#endif /* CONFIG_SYS_I2C_SOFT */
>  
>  /*-----------------------------------------------------------------------
>   * ack should be I2C_ACK or I2C_NOACK
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static void send_ack(int ack)
>  {
>  	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
> @@ -222,10 +354,29 @@ static void send_ack(int ack)
>  	I2C_SCL(0);
>  	I2C_DELAY;
>  }
> +#else
> +static void send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
> +		     int delay, int ack)
> +{
> +	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
> +
> +	I2C_SCL(scl, 0);
> +	I2C_DELAY(delay);
> +	I2C_ACTIVE(sda);
> +	I2C_SDA(sda, ack);
> +	I2C_DELAY(delay);
> +	I2C_SCL(scl, 1);
> +	I2C_DELAY(delay);
> +	I2C_DELAY(delay);
> +	I2C_SCL(scl, 0);
> +	I2C_DELAY(delay);
> +}
> +#endif
>  
>  /*-----------------------------------------------------------------------
>   * Send 8 bits and look for an acknowledgement.
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static int write_byte(uchar data)
>  {
>  	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
> @@ -263,11 +414,52 @@ static int write_byte(uchar data)
>  
>  	return(nack);	/* not a nack is an ack */
>  }
> +#else
> +static int write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
> +		      int delay, uchar data)
> +{
> +	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
> +	int j;
> +	int nack;
> +
> +	I2C_ACTIVE(sda);
> +	for (j = 0; j < 8; j++) {
> +		I2C_SCL(scl, 0);
> +		I2C_DELAY(delay);
> +		I2C_SDA(sda, data & 0x80);
> +		I2C_DELAY(delay);
> +		I2C_SCL(scl, 1);
> +		I2C_DELAY(delay);
> +		I2C_DELAY(delay);
> +
> +		data <<= 1;
> +	}
> +
> +	/*
> +	 * Look for an <ACK>(negative logic) and return it.
> +	 */
> +	I2C_SCL(scl, 0);
> +	I2C_DELAY(delay);
> +	I2C_SDA(sda, 1);
> +	I2C_TRISTATE(sda);
> +	I2C_DELAY(delay);
> +	I2C_SCL(scl, 1);
> +	I2C_DELAY(delay);
> +	I2C_DELAY(delay);
> +	nack = I2C_READ(sda);
> +	I2C_SCL(scl, 0);
> +	I2C_DELAY(delay);
> +	I2C_ACTIVE(sda);
> +
> +	return nack;	/* not a nack is an ack */
> +}
> +#endif
>  
>  /*-----------------------------------------------------------------------
>   * if ack == I2C_ACK, ACK the byte so can continue reading, else
>   * send I2C_NOACK to end the read.
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static uchar read_byte(int ack)
>  {
>  	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
> @@ -293,10 +485,38 @@ static uchar read_byte(int ack)
>  
>  	return(data);
>  }
> +#else
> +static uchar read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
> +		       int delay, int ack)
> +{
> +	I2C_SOFT_DECLARATIONS	/* intentional without ';' */
> +	int  data;
> +	int  j;
> +
> +	/*
> +	 * Read 8 bits, MSB first.
> +	 */
> +	I2C_TRISTATE(sda);
> +	I2C_SDA(sda, 1);
> +	data = 0;
> +	for (j = 0; j < 8; j++) {
> +		I2C_SCL(scl, 0);
> +		I2C_DELAY(delay);
> +		I2C_SCL(scl, 1);
> +		I2C_DELAY(delay);
> +		data <<= 1;
> +		data |= I2C_READ(sda);
> +		I2C_DELAY(delay);
> +	}
> +	send_ack(scl, sda, delay, ack);
>  
> +	return data;
> +}
> +#endif /* CONFIG_SYS_I2C_SOFT */
>  /*-----------------------------------------------------------------------
>   * Initialization
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static void soft_i2c_init(struct i2c_adapter *adap, int speed, int
> slaveaddr) {
>  #if defined(CONFIG_SYS_I2C_INIT_BOARD)
> @@ -314,12 +534,14 @@ static void soft_i2c_init(struct i2c_adapter
> *adap, int speed, int slaveaddr) send_reset ();
>  #endif
>  }
> +#endif
>  
>  /*-----------------------------------------------------------------------
>   * Probe to see if a chip is present.  Also good for checking for the
>   * completion of EEPROM writes since the chip stops responding until
>   * the write completes (typically 10mSec).
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
>  {
>  	int rc;
> @@ -334,10 +556,12 @@ static int soft_i2c_probe(struct i2c_adapter
> *adap, uint8_t addr) 
>  	return (rc ? 1 : 0);
>  }
> +#endif
>  
>  /*-----------------------------------------------------------------------
>   * Read bytes
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static int  soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint
> addr, int alen, uchar *buffer, int len)
>  {
> @@ -409,10 +633,12 @@ static int  soft_i2c_read(struct i2c_adapter
> *adap, uchar chip, uint addr, send_stop();
>  	return(0);
>  }
> +#endif
>  
>  /*-----------------------------------------------------------------------
>   * Write bytes
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static int  soft_i2c_write(struct i2c_adapter *adap, uchar chip,
> uint addr, int alen, uchar *buffer, int len)
>  {
> @@ -444,10 +670,12 @@ static int  soft_i2c_write(struct i2c_adapter
> *adap, uchar chip, uint addr, send_stop();
>  	return(failures);
>  }
> +#endif
>  
>  /*
>   * Register soft i2c adapters
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  U_BOOT_I2C_ADAP_COMPLETE(soft0, soft_i2c_init, soft_i2c_probe,
>  			 soft_i2c_read, soft_i2c_write, NULL,
>  			 CONFIG_SYS_I2C_SOFT_SPEED,
> CONFIG_SYS_I2C_SOFT_SLAVE, @@ -473,3 +701,163 @@
> U_BOOT_I2C_ADAP_COMPLETE(soft3, soft_i2c_init, soft_i2c_probe,
> CONFIG_SYS_I2C_SOFT_SLAVE_4, 3)
>  #endif
> +#endif /* CONFIG_SYS_I2C_SOFT */
> +
> +#ifdef CONFIG_DM_I2C_SOFT
> +struct soft_i2c_bus {
> +	unsigned int speed;
> +	unsigned long delay;
> +	struct gpio_desc scl;
> +	struct gpio_desc sda;
> +};
> +
> +static int i2c_write_data(struct soft_i2c_bus *i2c_bus, uchar chip,
> +			  uchar *buffer, int len, bool
> end_with_repeated_start) +{
> +	struct gpio_desc *scl = &i2c_bus->scl;
> +	struct gpio_desc *sda = &i2c_bus->sda;
> +	unsigned int delay = i2c_bus->delay;
> +	int failures = 0;
> +
> +	PRINTD("%s: chip %x buffer %p len %d\n", __func__, chip,
> buffer, len); +
> +	send_start(scl, sda, delay);
> +	if (write_byte(scl, sda, delay, chip << 1)) {
> +		send_stop(scl, sda, delay);
> +		PRINTD("i2c_write, no chip responded %02X\n", chip);
> +		return -ENODEV;
> +	}
> +
> +	while (len-- > 0) {
> +		if (write_byte(scl, sda, delay, *buffer++))
> +			failures++;
> +	}
> +
> +	send_stop(scl, sda, delay);
> +
> +	return failures;
> +}
> +
> +static int i2c_read_data(struct soft_i2c_bus *i2c_bus, uchar chip,
> +			 uchar *buffer, int len)
> +{
> +	struct gpio_desc *scl = &i2c_bus->scl;
> +	struct gpio_desc *sda = &i2c_bus->sda;
> +	unsigned int delay = i2c_bus->delay;
> +
> +	PRINTD("%s: chip %x buffer: %x len %d\n", __func__, chip,
> buffer, len); +
> +	send_start(scl, sda, delay);
> +	write_byte(scl, sda, delay, (chip << 1) | 1);	/* read
> cycle */ +
> +	while (len-- > 0)
> +		*buffer++ = read_byte(scl, sda, delay, len == 0);
> +
> +	send_stop(scl, sda, delay);
> +
> +	return 0;
> +}
> +
> +static int soft_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
> int nmsgs) +{
> +	struct soft_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 soft_i2c_probe(struct udevice *dev, uint chip, uint
> chip_flags) +{
> +	struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
> +	struct gpio_desc *scl = &i2c_bus->scl;
> +	struct gpio_desc *sda = &i2c_bus->sda;
> +	unsigned int delay = i2c_bus->delay;
> +	int ret;
> +
> +	send_start(scl, sda, delay);
> +	ret = write_byte(scl, sda, delay, (chip << 1) | 0);
> +	send_stop(scl, sda, delay);
> +
> +	PRINTD("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
> +	       __func__, dev->seq, dev->name, chip, chip_flags, ret);
> +
> +	return ret;
> +}
> +
> +static int soft_i2c_set_bus_speed(struct udevice *dev, unsigned int
> speed) +{
> +	struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
> +	struct gpio_desc *scl = &i2c_bus->scl;
> +	struct gpio_desc *sda = &i2c_bus->sda;
> +
> +	i2c_bus->speed = speed;
> +	i2c_bus->delay = lldiv(1000000, speed << 2);
> +
> +	send_reset(scl, sda, i2c_bus->delay);
> +
> +	PRINTD("%s: bus: %d (%s) speed: %u Hz (1/4 of period: %lu
> us)\n",
> +	       __func__, dev->seq, dev->name, speed, i2c_bus->delay);
> +
> +	return 0;
> +}
> +
> +static int soft_i2c_ofdata_to_platdata(struct udevice *dev)
> +{
> +	struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
> +	const void *blob = gd->fdt_blob;
> +	char *pin_name;
> +	int ret;
> +
> +	pin_name = "clock-pin";
> +	ret = gpio_request_by_name_nodev(blob, dev->of_offset,
> pin_name,
> +					 0, &i2c_bus->scl,
> GPIOD_IS_OUT);
> +	if (ret)
> +		goto error;
> +
> +	pin_name = "data-pin";
> +	ret = gpio_request_by_name_nodev(blob, dev->of_offset,
> pin_name,
> +					 0, &i2c_bus->sda,
> GPIOD_IS_OUT);
> +	if (ret)
> +		goto error;
> +
> +	PRINTD("%s: bus: %d (%s) fdt node ok\n", __func__, dev->seq,
> dev->name); +
> +	return 0;
> +error:
> +	error("Can't get %s for soft i2c dev: %s", pin_name,
> dev->name);
> +	return ret;
> +}
> +
> +static const struct dm_i2c_ops soft_i2c_ops = {
> +	.xfer		= soft_i2c_xfer,
> +	.probe_chip	= soft_i2c_probe,
> +	.set_bus_speed	= soft_i2c_set_bus_speed,
> +};
> +
> +static const struct udevice_id soft_i2c_ids[] = {
> +	{ .compatible = "soft-i2c" },
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(soft_i2c) = {
> +	.name	= "soft-i2c",
> +	.id	= UCLASS_I2C,
> +	.of_match = soft_i2c_ids,
> +	.ofdata_to_platdata = soft_i2c_ofdata_to_platdata,
> +	.priv_auto_alloc_size = sizeof(struct soft_i2c_bus),
> +	.ops	= &soft_i2c_ops,
> +};
> +#endif /* CONFIG_DM_I2C_SOFT */

Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 2/3] Kconfig: i2c: remove wrong help message related to dm i2c
  2015-03-10 10:30 ` [U-Boot] [PATCH 2/3] Kconfig: i2c: remove wrong help message related to dm i2c Przemyslaw Marczak
@ 2015-03-23  8:45   ` Lukasz Majewski
  2015-03-23 23:39   ` Simon Glass
  1 sibling, 0 replies; 36+ messages in thread
From: Lukasz Majewski @ 2015-03-23  8:45 UTC (permalink / raw)
  To: u-boot

Hi Przemyslaw,

> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
> Cc: Mike Frysinger <vapier@gentoo.org>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Heiko Schocher <hs@denx.de>
> ---
>  drivers/i2c/Kconfig | 11 +----------
>  1 file changed, 1 insertion(+), 10 deletions(-)
> 
> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
> index 692810d..0a52ed9 100644
> --- a/drivers/i2c/Kconfig
> +++ b/drivers/i2c/Kconfig
> @@ -2,16 +2,7 @@ config DM_I2C
>  	bool "Enable Driver Model for I2C drivers"
>  	depends on DM
>  	help
> -	  Enable driver model for I2C. This SPI flash interface
> -	  (spi_flash_probe(), spi_flash_write(), etc.) is then
> -	  implemented by the SPI flash uclass. There is one standard
> -	  SPI flash driver which knows how to probe most chips
> -	  supported by U-Boot. The uclass interface is defined in
> -	  include/spi_flash.h, but is currently fully compatible
> -	  with the old interface to avoid confusion and duplication
> -	  during the transition parent. SPI and SPI flash must be
> -	  enabled together (it is not possible to use driver model
> -	  for one and not the other).
> +	  Enable driver model for I2C.
>  
>  config DM_I2C_COMPAT
>  	bool "Enable I2C compatibility layer"

Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 3/3] Kconfig: i2c: add entry for driver-model software i2c
  2015-03-10 10:30 ` [U-Boot] [PATCH 3/3] Kconfig: i2c: add entry for driver-model software i2c Przemyslaw Marczak
@ 2015-03-23  8:46   ` Lukasz Majewski
  2015-03-23 23:40   ` Simon Glass
  2015-03-25  3:35   ` Masahiro Yamada
  2 siblings, 0 replies; 36+ messages in thread
From: Lukasz Majewski @ 2015-03-23  8:46 UTC (permalink / raw)
  To: u-boot

Hi Przemyslaw,

> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
> Cc: Mike Frysinger <vapier@gentoo.org>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Heiko Schocher <hs@denx.de>
> ---
>  drivers/i2c/Kconfig | 43 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 43 insertions(+)
> 
> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
> index 0a52ed9..dd7eb3c 100644
> --- a/drivers/i2c/Kconfig
> +++ b/drivers/i2c/Kconfig
> @@ -13,6 +13,49 @@ config DM_I2C_COMPAT
>  	  to convert all code for a board in a single commit. It
> should not be enabled for any board in an official release.
>  
> +config DM_I2C_SOFT
> +	bool "Enable Driver Model for Software I2C Driver"
> +	depends on DM_I2C
> +	help
> +	  Enable the i2c bus driver emulation by using GPIO.
> +	  The bus configuration is given by the device-tree, like
> below. +
> +	  /* First, define the alias number to have continuous bus
> numbering */
> +	  aliases {
> +	    [...]
> +	    i2c5 = "/i2c at 13500000";
> +	    i2c6 = "/soft-i2c at 1";
> +	    [...]
> +	  }
> +
> +	  /* And next define the basic bus attributes */
> +	  soft-i2c at 1 {
> +	    #address-cells = <1>;
> +	    #size-cells = <0>;
> +	    compatible = "soft-i2c";
> +	    clock-frequency = <50000>;
> +	    /* Define the proper GPIO pins */
> +	    clock-pin = <&gpa0 0 GPIO_ACTIVE_HIGH>;
> +	    data-pin = <&gpa0 1 GPIO_ACTIVE_HIGH>;
> +
> +	    /* Optionally, define some driver node (bus child) */
> +	    somedev at 0x44 {
> +	        compatible = "somedev";
> +	        reg = <0x44>;
> +	        [...]
> +	    };
> +	  }
> +
> +	  The device can be accessed by the i2c command:
> +	  # i2c dev 8                   (bus number set by alias)
> +	  # i2c probe <0x44>            (address is optionally)
> +	  # i2c md 0x44 0x0             (dump dev registers at
> address 0x0)
> +	  # Valid chip addresses: 0x44  (success!)
> +	  ...
> +
> +	  Driving the bus lines is done by dm gpio calls in the
> preprocessor
> +	  macros. Each, can be redefined by the user.
> +
>  config SYS_I2C_UNIPHIER
>  	bool "UniPhier I2C driver"
>  	depends on ARCH_UNIPHIER && DM_I2C

Reviewed-by: Lukasz Majewski <l.majewski@samsung.com>

-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver
  2015-03-10 10:30 ` [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver Przemyslaw Marczak
  2015-03-23  8:44   ` Lukasz Majewski
@ 2015-03-23 23:38   ` Simon Glass
  2015-03-24  6:01     ` Heiko Schocher
  2015-03-26 13:18     ` Przemyslaw Marczak
  1 sibling, 2 replies; 36+ messages in thread
From: Simon Glass @ 2015-03-23 23:38 UTC (permalink / raw)
  To: u-boot

Hi Przemyslaw,

On 10 March 2015 at 04:30, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
> This change adds driver model support to software emulated
> i2c bus driver. To bind the driver, proper device-tree node
> must be defined, with the following attributes:
> - alias: to keep proper bus order
> - compatible: 'soft-i2c'
> - clock-frequency [Hz]
> - clock-pin, data-pin: gpio phandles
>
> /* Define the alias number to keep bus numbering order */
> aliases {
>         [...]
>         i2c5 = "/i2c at 13500000";
>         i2c6 = "/soft-i2c at 1";
>         [...]
> };
>
> /* Define the basic bus attributes */
> soft-i2c at 1 {
>         #address-cells = <1>;
>         #size-cells = <0>;
>         compatible = "soft-i2c";
>         clock-frequency = <50000>;
>
>         /* Define the proper GPIO pins */
>         clock-pin = <&gpa0 0 GPIO_ACTIVE_HIGH>;
>         data-pin = <&gpa0 1 GPIO_ACTIVE_HIGH>;
>
>         /* Optionally, define some driver node (bus child) */
>         somedev at 0x44 {
>                 compatible = "somedev";
>                 reg = <0x44>;
>                 [...]
>         };
> };
>
> The device can be accessed by the i2c command:
>  i2c dev 8                   (bus number set by alias)
>  i2c probe <0x44>            (address is optionally)
>  i2c md 0x44 0x0             (dump dev registers at address 0x0)
>  Valid chip addresses: 0x44  (success!)
>  ...
>
> The previous driver functionality stays unchanged. Driving the bus lines
> is done by dm gpio calls in the preprocessor macros. Each, can be redefined
> by the user as previous.
>
> Tested on Trats2 and Odroid U3.

Is the intention to retire the old (non-driver-model) code? What boards use it?

>
> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
> Cc: Mike Frysinger <vapier@gentoo.org>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Heiko Schocher <hs@denx.de>
> ---
>  drivers/i2c/Makefile   |   1 +
>  drivers/i2c/soft_i2c.c | 410 +++++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 400 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
> index 774bc94..7039b6d 100644
> --- a/drivers/i2c/Makefile
> +++ b/drivers/i2c/Makefile
> @@ -6,6 +6,7 @@
>  #
>  obj-$(CONFIG_DM_I2C) += i2c-uclass.o
>  obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
> +obj-$(CONFIG_DM_I2C_SOFT) += soft_i2c.o
>
>  obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
>  obj-$(CONFIG_I2C_MV) += mv_i2c.o
> diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
> index db9b402..7afae0b 100644
> --- a/drivers/i2c/soft_i2c.c
> +++ b/drivers/i2c/soft_i2c.c
> @@ -1,4 +1,7 @@
>  /*
> + * (C) Copyright 2015, Samsung Electronics
> + * Przemyslaw Marczak <p.marczak@samsung.com>
> + *
>   * (C) Copyright 2009
>   * Heiko Schocher, DENX Software Engineering, hs at denx.de.
>   * Changes for multibus/multiadapter I2C support.
> @@ -14,6 +17,11 @@
>   */
>
>  #include <common.h>
> +#include <errno.h>
> +#include <dm.h>
> +#include <i2c.h>
> +#include <div64.h>
> +#include <asm/gpio.h>
>  #ifdef CONFIG_MPC8260                  /* only valid for MPC8260 */
>  #include <ioports.h>
>  #include <asm/io.h>
> @@ -32,11 +40,9 @@
>  #if defined(CONFIG_MPC852T) || defined(CONFIG_MPC866)
>  #include <asm/io.h>
>  #endif
> -#include <i2c.h>
>
> +#if defined(CONFIG_SYS_I2C)
>  #if defined(CONFIG_SOFT_I2C_GPIO_SCL)
> -# include <asm/gpio.h>
> -
>  # ifndef I2C_GPIO_SYNC
>  #  define I2C_GPIO_SYNC
>  # endif
> @@ -85,6 +91,7 @@
>  # endif
>
>  #endif
> +#endif
>
>  /* #define     DEBUG_I2C       */
>
> @@ -109,6 +116,65 @@ DECLARE_GLOBAL_DATA_PTR;
>  #define CONFIG_SYS_I2C_SOFT_SLAVE CONFIG_SYS_I2C_SLAVE
>  #endif
>
> +/* DM SOFT I2C */
> +#ifdef CONFIG_DM_I2C_SOFT
> +# ifndef I2C_GPIO_SYNC
> +#  define I2C_GPIO_SYNC(gpio)
> +# endif
> +
> +# ifndef I2C_INIT
> +#  define I2C_INIT(scl, sda)  \
> +       do { } while (0)
> +# endif
> +
> +# ifndef I2C_ACTIVE
> +#  define I2C_ACTIVE(sda) \
> +       do { } while (0)
> +# endif
> +
> +# ifndef I2C_TRISTATE
> +#  define I2C_TRISTATE(sda) \
> +       do { } while (0)
> +# endif
> +
> +# ifndef I2C_READ
> +#  define I2C_READ(sda) dm_gpio_get_value(sda);
> +# endif
> +
> +# ifndef I2C_SDA
> +#  define I2C_SDA(sda, bit) \
> +       do { \
> +               if (bit) { \
> +                       sda->flags &= ~GPIOD_IS_OUT; \
> +                       sda->flags |= GPIOD_IS_IN; \
> +                       dm_gpio_set_dir(sda); \
> +               } else { \
> +                       sda->flags &= ~GPIOD_IS_IN; \
> +                       sda->flags |= GPIOD_IS_OUT; \
> +                       dm_gpio_set_dir(sda); \
> +                       dm_gpio_set_value(sda, 0); \
> +               } \
> +               I2C_GPIO_SYNC(sda); \
> +       } while (0)
> +# endif
> +
> +# ifndef I2C_SCL
> +#  define I2C_SCL(scl, bit) \
> +       do { \
> +               scl->flags &= ~GPIOD_IS_IN; \
> +               scl->flags |= GPIOD_IS_OUT; \
> +               dm_gpio_set_dir(scl); \
> +               dm_gpio_set_value(scl, bit); \
> +               I2C_GPIO_SYNC(scl); \
> +       } while (0)
> +# endif
> +
> +# ifndef I2C_DELAY
> +#  define I2C_DELAY(us) udelay(us)     /* 1/4 I2C clock duration */
> +# endif
> +
> +#endif /* CONFIG_DM_I2C_SOFT */
> +
>  /*-----------------------------------------------------------------------
>   * Definitions
>   */
> @@ -117,7 +183,6 @@ DECLARE_GLOBAL_DATA_PTR;
>  #define I2C_ACK                0               /* PD_SDA level to ack a byte */
>  #define I2C_NOACK      1               /* PD_SDA level to noack a byte */
>
> -
>  #ifdef DEBUG_I2C
>  #define PRINTD(fmt,args...)    do {    \
>                 printf (fmt ,##args);   \
> @@ -129,21 +194,30 @@ DECLARE_GLOBAL_DATA_PTR;
>  /*-----------------------------------------------------------------------
>   * Local functions
>   */
> +#ifdef CONFIG_SYS_I2C
>  #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
> -static void  send_reset        (void);
> +static void send_reset(void);
> +#endif
> +static void send_start(void);
> +static void send_stop(void);
> +static void send_ack(int);
> +static int write_byte(uchar byte);
> +static uchar read_byte(int);
> +#else
> +static void send_reset(struct gpio_desc *, struct gpio_desc *, int);
> +static void send_start(struct gpio_desc *, struct gpio_desc *, int);
> +static void send_stop(struct gpio_desc *, struct gpio_desc *, int);
> +static void send_ack(struct gpio_desc *, struct gpio_desc *, int, int);
> +static int write_byte(struct gpio_desc *, struct gpio_desc *, int, uchar);
> +static uchar read_byte(struct gpio_desc *, struct gpio_desc *, int, int);
>  #endif
> -static void  send_start        (void);
> -static void  send_stop (void);
> -static void  send_ack  (int);
> -static int   write_byte        (uchar byte);
> -static uchar read_byte (int);
> -
>  #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
>  /*-----------------------------------------------------------------------
>   * Send a reset sequence consisting of 9 clocks with the data signal high
>   * to clock any confused device back into an idle state.  Also send a
>   * <stop> at the end of the sequence for belts & suspenders.
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static void send_reset(void)
>  {
>         I2C_SOFT_DECLARATIONS   /* intentional without ';' */
> @@ -166,11 +240,36 @@ static void send_reset(void)
>         send_stop();
>         I2C_TRISTATE;
>  }
> +#else
> +static void send_reset(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
> +{
> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
> +       int j;
> +
> +       I2C_SCL(scl, 1);
> +       I2C_SDA(sda, 1);
> +#ifdef I2C_INIT
> +       I2C_INIT(scl, sda);
> +#endif
> +       I2C_TRISTATE(sda);
> +       for (j = 0; j < 9; j++) {
> +               I2C_SCL(scl, 0);
> +               I2C_DELAY(delay);
> +               I2C_DELAY(delay);
> +               I2C_SCL(scl, 1);
> +               I2C_DELAY(delay);
> +               I2C_DELAY(delay);
> +       }
> +       send_stop(scl, sda, delay);
> +       I2C_TRISTATE(sda);

For the new code I would much prefer that these become functions
rather than macros. What is the benefit of using a macro?

> +}
> +#endif /* CONFIG_SYS_I2C_SOFT */
>  #endif
>
>  /*-----------------------------------------------------------------------
>   * START: High -> Low on SDA while SCL is High
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static void send_start(void)
>  {
>         I2C_SOFT_DECLARATIONS   /* intentional without ';' */
> @@ -184,10 +283,25 @@ static void send_start(void)
>         I2C_SDA(0);
>         I2C_DELAY;
>  }
> +#else
> +static void send_start(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
> +{
> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>
> +       I2C_DELAY(delay);
> +       I2C_SDA(sda, 1);
> +       I2C_ACTIVE(sda);
> +       I2C_DELAY(delay);
> +       I2C_SCL(scl, 1);
> +       I2C_DELAY(delay);
> +       I2C_SDA(sda, 0);
> +       I2C_DELAY(delay);
> +}
> +#endif /* CONFIG_SYS_I2C_SOFT */
>  /*-----------------------------------------------------------------------
>   * STOP: Low -> High on SDA while SCL is High
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static void send_stop(void)
>  {
>         I2C_SOFT_DECLARATIONS   /* intentional without ';' */
> @@ -203,10 +317,28 @@ static void send_stop(void)
>         I2C_DELAY;
>         I2C_TRISTATE;
>  }
> +#else
> +static void send_stop(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
> +{
> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
> +
> +       I2C_SCL(scl, 0);
> +       I2C_DELAY(delay);
> +       I2C_SDA(sda, 0);
> +       I2C_ACTIVE(sda);
> +       I2C_DELAY(delay);
> +       I2C_SCL(scl, 1);
> +       I2C_DELAY(delay);
> +       I2C_SDA(sda, 1);
> +       I2C_DELAY(delay);
> +       I2C_TRISTATE(sda);
> +}
> +#endif /* CONFIG_SYS_I2C_SOFT */
>
>  /*-----------------------------------------------------------------------
>   * ack should be I2C_ACK or I2C_NOACK
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static void send_ack(int ack)
>  {
>         I2C_SOFT_DECLARATIONS   /* intentional without ';' */
> @@ -222,10 +354,29 @@ static void send_ack(int ack)
>         I2C_SCL(0);
>         I2C_DELAY;
>  }
> +#else
> +static void send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
> +                    int delay, int ack)
> +{
> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
> +
> +       I2C_SCL(scl, 0);
> +       I2C_DELAY(delay);
> +       I2C_ACTIVE(sda);
> +       I2C_SDA(sda, ack);
> +       I2C_DELAY(delay);
> +       I2C_SCL(scl, 1);
> +       I2C_DELAY(delay);
> +       I2C_DELAY(delay);
> +       I2C_SCL(scl, 0);
> +       I2C_DELAY(delay);
> +}
> +#endif
>
>  /*-----------------------------------------------------------------------
>   * Send 8 bits and look for an acknowledgement.
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static int write_byte(uchar data)
>  {
>         I2C_SOFT_DECLARATIONS   /* intentional without ';' */
> @@ -263,11 +414,52 @@ static int write_byte(uchar data)
>
>         return(nack);   /* not a nack is an ack */
>  }
> +#else
> +static int write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
> +                     int delay, uchar data)
> +{
> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
> +       int j;
> +       int nack;
> +
> +       I2C_ACTIVE(sda);
> +       for (j = 0; j < 8; j++) {
> +               I2C_SCL(scl, 0);
> +               I2C_DELAY(delay);
> +               I2C_SDA(sda, data & 0x80);
> +               I2C_DELAY(delay);
> +               I2C_SCL(scl, 1);
> +               I2C_DELAY(delay);
> +               I2C_DELAY(delay);
> +
> +               data <<= 1;
> +       }
> +
> +       /*
> +        * Look for an <ACK>(negative logic) and return it.
> +        */
> +       I2C_SCL(scl, 0);
> +       I2C_DELAY(delay);
> +       I2C_SDA(sda, 1);
> +       I2C_TRISTATE(sda);
> +       I2C_DELAY(delay);
> +       I2C_SCL(scl, 1);
> +       I2C_DELAY(delay);
> +       I2C_DELAY(delay);
> +       nack = I2C_READ(sda);
> +       I2C_SCL(scl, 0);
> +       I2C_DELAY(delay);
> +       I2C_ACTIVE(sda);
> +
> +       return nack;    /* not a nack is an ack */
> +}
> +#endif
>
>  /*-----------------------------------------------------------------------
>   * if ack == I2C_ACK, ACK the byte so can continue reading, else
>   * send I2C_NOACK to end the read.
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static uchar read_byte(int ack)
>  {
>         I2C_SOFT_DECLARATIONS   /* intentional without ';' */
> @@ -293,10 +485,38 @@ static uchar read_byte(int ack)
>
>         return(data);
>  }
> +#else
> +static uchar read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
> +                      int delay, int ack)
> +{
> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
> +       int  data;
> +       int  j;
> +
> +       /*
> +        * Read 8 bits, MSB first.
> +        */
> +       I2C_TRISTATE(sda);
> +       I2C_SDA(sda, 1);
> +       data = 0;
> +       for (j = 0; j < 8; j++) {
> +               I2C_SCL(scl, 0);
> +               I2C_DELAY(delay);
> +               I2C_SCL(scl, 1);
> +               I2C_DELAY(delay);
> +               data <<= 1;
> +               data |= I2C_READ(sda);
> +               I2C_DELAY(delay);
> +       }
> +       send_ack(scl, sda, delay, ack);
>
> +       return data;
> +}
> +#endif /* CONFIG_SYS_I2C_SOFT */
>  /*-----------------------------------------------------------------------
>   * Initialization
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
>  {
>  #if defined(CONFIG_SYS_I2C_INIT_BOARD)
> @@ -314,12 +534,14 @@ static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
>         send_reset ();
>  #endif
>  }
> +#endif
>
>  /*-----------------------------------------------------------------------
>   * Probe to see if a chip is present.  Also good for checking for the
>   * completion of EEPROM writes since the chip stops responding until
>   * the write completes (typically 10mSec).
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
>  {
>         int rc;
> @@ -334,10 +556,12 @@ static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
>
>         return (rc ? 1 : 0);
>  }
> +#endif
>
>  /*-----------------------------------------------------------------------
>   * Read bytes
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static int  soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
>                         int alen, uchar *buffer, int len)
>  {
> @@ -409,10 +633,12 @@ static int  soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
>         send_stop();
>         return(0);
>  }
> +#endif
>
>  /*-----------------------------------------------------------------------
>   * Write bytes
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  static int  soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
>                         int alen, uchar *buffer, int len)
>  {
> @@ -444,10 +670,12 @@ static int  soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
>         send_stop();
>         return(failures);
>  }
> +#endif
>
>  /*
>   * Register soft i2c adapters
>   */
> +#ifdef CONFIG_SYS_I2C_SOFT
>  U_BOOT_I2C_ADAP_COMPLETE(soft0, soft_i2c_init, soft_i2c_probe,
>                          soft_i2c_read, soft_i2c_write, NULL,
>                          CONFIG_SYS_I2C_SOFT_SPEED, CONFIG_SYS_I2C_SOFT_SLAVE,
> @@ -473,3 +701,163 @@ U_BOOT_I2C_ADAP_COMPLETE(soft3, soft_i2c_init, soft_i2c_probe,
>                          CONFIG_SYS_I2C_SOFT_SLAVE_4,
>                          3)
>  #endif
> +#endif /* CONFIG_SYS_I2C_SOFT */
> +
> +#ifdef CONFIG_DM_I2C_SOFT
> +struct soft_i2c_bus {
> +       unsigned int speed;
> +       unsigned long delay;
> +       struct gpio_desc scl;
> +       struct gpio_desc sda;
> +};
> +
> +static int i2c_write_data(struct soft_i2c_bus *i2c_bus, uchar chip,
> +                         uchar *buffer, int len, bool end_with_repeated_start)
> +{
> +       struct gpio_desc *scl = &i2c_bus->scl;
> +       struct gpio_desc *sda = &i2c_bus->sda;
> +       unsigned int delay = i2c_bus->delay;
> +       int failures = 0;
> +
> +       PRINTD("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
> +
> +       send_start(scl, sda, delay);
> +       if (write_byte(scl, sda, delay, chip << 1)) {
> +               send_stop(scl, sda, delay);
> +               PRINTD("i2c_write, no chip responded %02X\n", chip);
> +               return -ENODEV;

-EIO I think

> +       }
> +
> +       while (len-- > 0) {
> +               if (write_byte(scl, sda, delay, *buffer++))
> +                       failures++;
> +       }
> +
> +       send_stop(scl, sda, delay);
> +
> +       return failures;
> +}
> +
> +static int i2c_read_data(struct soft_i2c_bus *i2c_bus, uchar chip,
> +                        uchar *buffer, int len)
> +{
> +       struct gpio_desc *scl = &i2c_bus->scl;
> +       struct gpio_desc *sda = &i2c_bus->sda;
> +       unsigned int delay = i2c_bus->delay;
> +
> +       PRINTD("%s: chip %x buffer: %x len %d\n", __func__, chip, buffer, len);
> +
> +       send_start(scl, sda, delay);
> +       write_byte(scl, sda, delay, (chip << 1) | 1);   /* read cycle */
> +
> +       while (len-- > 0)
> +               *buffer++ = read_byte(scl, sda, delay, len == 0);
> +
> +       send_stop(scl, sda, delay);
> +
> +       return 0;
> +}
> +
> +static int soft_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
> +{
> +       struct soft_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 soft_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
> +{
> +       struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
> +       struct gpio_desc *scl = &i2c_bus->scl;
> +       struct gpio_desc *sda = &i2c_bus->sda;
> +       unsigned int delay = i2c_bus->delay;
> +       int ret;
> +
> +       send_start(scl, sda, delay);
> +       ret = write_byte(scl, sda, delay, (chip << 1) | 0);
> +       send_stop(scl, sda, delay);
> +
> +       PRINTD("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
> +              __func__, dev->seq, dev->name, chip, chip_flags, ret);
> +
> +       return ret;
> +}
> +
> +static int soft_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
> +{
> +       struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
> +       struct gpio_desc *scl = &i2c_bus->scl;
> +       struct gpio_desc *sda = &i2c_bus->sda;
> +
> +       i2c_bus->speed = speed;
> +       i2c_bus->delay = lldiv(1000000, speed << 2);
> +
> +       (scl, sda, i2c_bus->delay);
> +
> +       PRINTD("%s: bus: %d (%s) speed: %u Hz (1/4 of period: %lu us)\n",
> +              __func__, dev->seq, dev->name, speed, i2c_bus->delay);
> +
> +       return 0;
> +}
> +
> +static int soft_i2c_ofdata_to_platdata(struct udevice *dev)
> +{
> +       struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
> +       const void *blob = gd->fdt_blob;
> +       char *pin_name;
> +       int ret;
> +
> +       pin_name = "clock-pin";

nit: You don't need this variable

> +       ret = gpio_request_by_name_nodev(blob, dev->of_offset, pin_name,
> +                                        0, &i2c_bus->scl, GPIOD_IS_OUT);

You should not use the nodev version when you have a device. Also below.

> +       if (ret)
> +               goto error;
> +
> +       pin_name = "data-pin";

nit: or here

> +       ret = gpio_request_by_name_nodev(blob, dev->of_offset, pin_name,
> +                                        0, &i2c_bus->sda, GPIOD_IS_OUT);
> +       if (ret)
> +               goto error;
> +
> +       PRINTD("%s: bus: %d (%s) fdt node ok\n", __func__, dev->seq, dev->name);
> +
> +       return 0;
> +error:
> +       error("Can't get %s for soft i2c dev: %s", pin_name, dev->name);
> +       return ret;
> +}
> +
> +static const struct dm_i2c_ops soft_i2c_ops = {
> +       .xfer           = soft_i2c_xfer,
> +       .probe_chip     = soft_i2c_probe,
> +       .set_bus_speed  = soft_i2c_set_bus_speed,
> +};
> +
> +static const struct udevice_id soft_i2c_ids[] = {
> +       { .compatible = "soft-i2c" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(soft_i2c) = {
> +       .name   = "soft-i2c",
> +       .id     = UCLASS_I2C,
> +       .of_match = soft_i2c_ids,
> +       .ofdata_to_platdata = soft_i2c_ofdata_to_platdata,
> +       .priv_auto_alloc_size = sizeof(struct soft_i2c_bus),
> +       .ops    = &soft_i2c_ops,
> +};
> +#endif /* CONFIG_DM_I2C_SOFT */
> --
> 1.9.1
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 2/3] Kconfig: i2c: remove wrong help message related to dm i2c
  2015-03-10 10:30 ` [U-Boot] [PATCH 2/3] Kconfig: i2c: remove wrong help message related to dm i2c Przemyslaw Marczak
  2015-03-23  8:45   ` Lukasz Majewski
@ 2015-03-23 23:39   ` Simon Glass
  2015-03-26 13:18     ` Przemyslaw Marczak
  1 sibling, 1 reply; 36+ messages in thread
From: Simon Glass @ 2015-03-23 23:39 UTC (permalink / raw)
  To: u-boot

Hi,

On 10 March 2015 at 04:30, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
> Cc: Mike Frysinger <vapier@gentoo.org>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Heiko Schocher <hs@denx.de>
> ---
>  drivers/i2c/Kconfig | 11 +----------
>  1 file changed, 1 insertion(+), 10 deletions(-)
>
> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
> index 692810d..0a52ed9 100644
> --- a/drivers/i2c/Kconfig
> +++ b/drivers/i2c/Kconfig
> @@ -2,16 +2,7 @@ config DM_I2C
>         bool "Enable Driver Model for I2C drivers"
>         depends on DM
>         help
> -         Enable driver model for I2C. This SPI flash interface
> -         (spi_flash_probe(), spi_flash_write(), etc.) is then
> -         implemented by the SPI flash uclass. There is one standard
> -         SPI flash driver which knows how to probe most chips
> -         supported by U-Boot. The uclass interface is defined in
> -         include/spi_flash.h, but is currently fully compatible
> -         with the old interface to avoid confusion and duplication
> -         during the transition parent. SPI and SPI flash must be
> -         enabled together (it is not possible to use driver model
> -         for one and not the other).
> +         Enable driver model for I2C.

That's too short IMO :-)

Can you add a few more details along the lines of what is described
for SPI, and also mention the COMPAT option?

Thanks for fixing this.

>
>  config DM_I2C_COMPAT
>         bool "Enable I2C compatibility layer"
> --
> 1.9.1
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 3/3] Kconfig: i2c: add entry for driver-model software i2c
  2015-03-10 10:30 ` [U-Boot] [PATCH 3/3] Kconfig: i2c: add entry for driver-model software i2c Przemyslaw Marczak
  2015-03-23  8:46   ` Lukasz Majewski
@ 2015-03-23 23:40   ` Simon Glass
  2015-03-25  3:35   ` Masahiro Yamada
  2 siblings, 0 replies; 36+ messages in thread
From: Simon Glass @ 2015-03-23 23:40 UTC (permalink / raw)
  To: u-boot

On 10 March 2015 at 04:30, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
> Cc: Mike Frysinger <vapier@gentoo.org>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Heiko Schocher <hs@denx.de>
> ---
>  drivers/i2c/Kconfig | 43 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 43 insertions(+)
>

This is very nice.

Acked-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver
  2015-03-23 23:38   ` Simon Glass
@ 2015-03-24  6:01     ` Heiko Schocher
  2015-03-26 13:18       ` Przemyslaw Marczak
  2015-03-26 13:18     ` Przemyslaw Marczak
  1 sibling, 1 reply; 36+ messages in thread
From: Heiko Schocher @ 2015-03-24  6:01 UTC (permalink / raw)
  To: u-boot

Hello Simon, Przemyslaw,

Am 24.03.2015 00:38, schrieb Simon Glass:
> Hi Przemyslaw,
>
> On 10 March 2015 at 04:30, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
>> This change adds driver model support to software emulated
>> i2c bus driver. To bind the driver, proper device-tree node
>> must be defined, with the following attributes:
>> - alias: to keep proper bus order
>> - compatible: 'soft-i2c'
>> - clock-frequency [Hz]
>> - clock-pin, data-pin: gpio phandles
>>
>> /* Define the alias number to keep bus numbering order */
>> aliases {
>>          [...]
>>          i2c5 = "/i2c at 13500000";
>>          i2c6 = "/soft-i2c at 1";
>>          [...]
>> };
>>
>> /* Define the basic bus attributes */
>> soft-i2c at 1 {
>>          #address-cells = <1>;
>>          #size-cells = <0>;
>>          compatible = "soft-i2c";
>>          clock-frequency = <50000>;
>>
>>          /* Define the proper GPIO pins */
>>          clock-pin = <&gpa0 0 GPIO_ACTIVE_HIGH>;
>>          data-pin = <&gpa0 1 GPIO_ACTIVE_HIGH>;
>>
>>          /* Optionally, define some driver node (bus child) */
>>          somedev at 0x44 {
>>                  compatible = "somedev";
>>                  reg = <0x44>;
>>                  [...]
>>          };
>> };
>>
>> The device can be accessed by the i2c command:
>>   i2c dev 8                   (bus number set by alias)
>>   i2c probe <0x44>            (address is optionally)
>>   i2c md 0x44 0x0             (dump dev registers at address 0x0)
>>   Valid chip addresses: 0x44  (success!)
>>   ...
>>
>> The previous driver functionality stays unchanged. Driving the bus lines
>> is done by dm gpio calls in the preprocessor macros. Each, can be redefined
>> by the user as previous.
>>
>> Tested on Trats2 and Odroid U3.
>
> Is the intention to retire the old (non-driver-model) code? What boards use it?

I think not ... Hmm ... maybe you move the new code into
a new file?

>> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
>> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
>> Cc: Mike Frysinger <vapier@gentoo.org>
>> Cc: Simon Glass <sjg@chromium.org>
>> Cc: Heiko Schocher <hs@denx.de>

Hups... seems I missed this patches ...

>> ---
>>   drivers/i2c/Makefile   |   1 +
>>   drivers/i2c/soft_i2c.c | 410 +++++++++++++++++++++++++++++++++++++++++++++++--
>>   2 files changed, 400 insertions(+), 11 deletions(-)

Thanks for this work!

>> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
>> index 774bc94..7039b6d 100644
>> --- a/drivers/i2c/Makefile
>> +++ b/drivers/i2c/Makefile
>> @@ -6,6 +6,7 @@
>>   #
>>   obj-$(CONFIG_DM_I2C) += i2c-uclass.o
>>   obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
>> +obj-$(CONFIG_DM_I2C_SOFT) += soft_i2c.o
>>
>>   obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
>>   obj-$(CONFIG_I2C_MV) += mv_i2c.o
>> diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
>> index db9b402..7afae0b 100644
>> --- a/drivers/i2c/soft_i2c.c
>> +++ b/drivers/i2c/soft_i2c.c
>> @@ -1,4 +1,7 @@
>>   /*
>> + * (C) Copyright 2015, Samsung Electronics
>> + * Przemyslaw Marczak <p.marczak@samsung.com>
>> + *
>>    * (C) Copyright 2009
>>    * Heiko Schocher, DENX Software Engineering, hs at denx.de.
>>    * Changes for multibus/multiadapter I2C support.
>> @@ -14,6 +17,11 @@
>>    */
>>
>>   #include <common.h>
>> +#include <errno.h>
>> +#include <dm.h>
>> +#include <i2c.h>
>> +#include <div64.h>
>> +#include <asm/gpio.h>
>>   #ifdef CONFIG_MPC8260                  /* only valid for MPC8260 */
>>   #include <ioports.h>
>>   #include <asm/io.h>
>> @@ -32,11 +40,9 @@
>>   #if defined(CONFIG_MPC852T) || defined(CONFIG_MPC866)
>>   #include <asm/io.h>
>>   #endif
>> -#include <i2c.h>
>>
>> +#if defined(CONFIG_SYS_I2C)
>>   #if defined(CONFIG_SOFT_I2C_GPIO_SCL)
>> -# include <asm/gpio.h>
>> -
>>   # ifndef I2C_GPIO_SYNC
>>   #  define I2C_GPIO_SYNC
>>   # endif
>> @@ -85,6 +91,7 @@
>>   # endif
>>
>>   #endif
>> +#endif
>>
>>   /* #define     DEBUG_I2C       */
>>
>> @@ -109,6 +116,65 @@ DECLARE_GLOBAL_DATA_PTR;
>>   #define CONFIG_SYS_I2C_SOFT_SLAVE CONFIG_SYS_I2C_SLAVE
>>   #endif
>>
>> +/* DM SOFT I2C */
>> +#ifdef CONFIG_DM_I2C_SOFT
>> +# ifndef I2C_GPIO_SYNC
>> +#  define I2C_GPIO_SYNC(gpio)
>> +# endif
>> +
>> +# ifndef I2C_INIT
>> +#  define I2C_INIT(scl, sda)  \
>> +       do { } while (0)
>> +# endif
>> +
>> +# ifndef I2C_ACTIVE
>> +#  define I2C_ACTIVE(sda) \
>> +       do { } while (0)
>> +# endif
>> +
>> +# ifndef I2C_TRISTATE
>> +#  define I2C_TRISTATE(sda) \
>> +       do { } while (0)
>> +# endif
>> +
>> +# ifndef I2C_READ
>> +#  define I2C_READ(sda) dm_gpio_get_value(sda);
>> +# endif
>> +
>> +# ifndef I2C_SDA
>> +#  define I2C_SDA(sda, bit) \
>> +       do { \
>> +               if (bit) { \
>> +                       sda->flags &= ~GPIOD_IS_OUT; \
>> +                       sda->flags |= GPIOD_IS_IN; \
>> +                       dm_gpio_set_dir(sda); \
>> +               } else { \
>> +                       sda->flags &= ~GPIOD_IS_IN; \
>> +                       sda->flags |= GPIOD_IS_OUT; \
>> +                       dm_gpio_set_dir(sda); \
>> +                       dm_gpio_set_value(sda, 0); \
>> +               } \
>> +               I2C_GPIO_SYNC(sda); \
>> +       } while (0)
>> +# endif
>> +
>> +# ifndef I2C_SCL
>> +#  define I2C_SCL(scl, bit) \
>> +       do { \
>> +               scl->flags &= ~GPIOD_IS_IN; \
>> +               scl->flags |= GPIOD_IS_OUT; \
>> +               dm_gpio_set_dir(scl); \
>> +               dm_gpio_set_value(scl, bit); \
>> +               I2C_GPIO_SYNC(scl); \
>> +       } while (0)
>> +# endif
>> +
>> +# ifndef I2C_DELAY
>> +#  define I2C_DELAY(us) udelay(us)     /* 1/4 I2C clock duration */
>> +# endif
>> +
>> +#endif /* CONFIG_DM_I2C_SOFT */
>> +
>>   /*-----------------------------------------------------------------------
>>    * Definitions
>>    */
>> @@ -117,7 +183,6 @@ DECLARE_GLOBAL_DATA_PTR;
>>   #define I2C_ACK                0               /* PD_SDA level to ack a byte */
>>   #define I2C_NOACK      1               /* PD_SDA level to noack a byte */
>>
>> -
>>   #ifdef DEBUG_I2C
>>   #define PRINTD(fmt,args...)    do {    \
>>                  printf (fmt ,##args);   \
>> @@ -129,21 +194,30 @@ DECLARE_GLOBAL_DATA_PTR;
>>   /*-----------------------------------------------------------------------
>>    * Local functions
>>    */
>> +#ifdef CONFIG_SYS_I2C
>>   #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
>> -static void  send_reset        (void);
>> +static void send_reset(void);
>> +#endif
>> +static void send_start(void);
>> +static void send_stop(void);
>> +static void send_ack(int);
>> +static int write_byte(uchar byte);
>> +static uchar read_byte(int);
>> +#else
>> +static void send_reset(struct gpio_desc *, struct gpio_desc *, int);
>> +static void send_start(struct gpio_desc *, struct gpio_desc *, int);
>> +static void send_stop(struct gpio_desc *, struct gpio_desc *, int);
>> +static void send_ack(struct gpio_desc *, struct gpio_desc *, int, int);
>> +static int write_byte(struct gpio_desc *, struct gpio_desc *, int, uchar);
>> +static uchar read_byte(struct gpio_desc *, struct gpio_desc *, int, int);
>>   #endif
>> -static void  send_start        (void);
>> -static void  send_stop (void);
>> -static void  send_ack  (int);
>> -static int   write_byte        (uchar byte);
>> -static uchar read_byte (int);
>> -
>>   #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
>>   /*-----------------------------------------------------------------------
>>    * Send a reset sequence consisting of 9 clocks with the data signal high
>>    * to clock any confused device back into an idle state.  Also send a
>>    * <stop> at the end of the sequence for belts & suspenders.
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static void send_reset(void)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -166,11 +240,36 @@ static void send_reset(void)
>>          send_stop();
>>          I2C_TRISTATE;
>>   }
>> +#else
>> +static void send_reset(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> +       int j;
>> +
>> +       I2C_SCL(scl, 1);
>> +       I2C_SDA(sda, 1);
>> +#ifdef I2C_INIT
>> +       I2C_INIT(scl, sda);
>> +#endif
>> +       I2C_TRISTATE(sda);
>> +       for (j = 0; j < 9; j++) {
>> +               I2C_SCL(scl, 0);
>> +               I2C_DELAY(delay);
>> +               I2C_DELAY(delay);
>> +               I2C_SCL(scl, 1);
>> +               I2C_DELAY(delay);
>> +               I2C_DELAY(delay);
>> +       }
>> +       send_stop(scl, sda, delay);
>> +       I2C_TRISTATE(sda);
>
> For the new code I would much prefer that these become functions
> rather than macros. What is the benefit of using a macro?

I do not know the real reason, but I think it comes from powerpc
times, where we had not yet such powerful SoCs and it saved some
instructions ... I tend to say, lets move the dm part into a new
file ... and let it us do like linux ...

@Simon: Do you pick up this patches through DM tree, or should
I pick them up?

bye,
Heiko
>> +}
>> +#endif /* CONFIG_SYS_I2C_SOFT */
>>   #endif
>>
>>   /*-----------------------------------------------------------------------
>>    * START: High -> Low on SDA while SCL is High
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static void send_start(void)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -184,10 +283,25 @@ static void send_start(void)
>>          I2C_SDA(0);
>>          I2C_DELAY;
>>   }
>> +#else
>> +static void send_start(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>>
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 1);
>> +       I2C_ACTIVE(sda);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 0);
>> +       I2C_DELAY(delay);
>> +}
>> +#endif /* CONFIG_SYS_I2C_SOFT */
>>   /*-----------------------------------------------------------------------
>>    * STOP: Low -> High on SDA while SCL is High
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static void send_stop(void)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -203,10 +317,28 @@ static void send_stop(void)
>>          I2C_DELAY;
>>          I2C_TRISTATE;
>>   }
>> +#else
>> +static void send_stop(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> +
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 0);
>> +       I2C_ACTIVE(sda);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_TRISTATE(sda);
>> +}
>> +#endif /* CONFIG_SYS_I2C_SOFT */
>>
>>   /*-----------------------------------------------------------------------
>>    * ack should be I2C_ACK or I2C_NOACK
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static void send_ack(int ack)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -222,10 +354,29 @@ static void send_ack(int ack)
>>          I2C_SCL(0);
>>          I2C_DELAY;
>>   }
>> +#else
>> +static void send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
>> +                    int delay, int ack)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> +
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_ACTIVE(sda);
>> +       I2C_SDA(sda, ack);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +}
>> +#endif
>>
>>   /*-----------------------------------------------------------------------
>>    * Send 8 bits and look for an acknowledgement.
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static int write_byte(uchar data)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -263,11 +414,52 @@ static int write_byte(uchar data)
>>
>>          return(nack);   /* not a nack is an ack */
>>   }
>> +#else
>> +static int write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
>> +                     int delay, uchar data)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> +       int j;
>> +       int nack;
>> +
>> +       I2C_ACTIVE(sda);
>> +       for (j = 0; j < 8; j++) {
>> +               I2C_SCL(scl, 0);
>> +               I2C_DELAY(delay);
>> +               I2C_SDA(sda, data & 0x80);
>> +               I2C_DELAY(delay);
>> +               I2C_SCL(scl, 1);
>> +               I2C_DELAY(delay);
>> +               I2C_DELAY(delay);
>> +
>> +               data <<= 1;
>> +       }
>> +
>> +       /*
>> +        * Look for an <ACK>(negative logic) and return it.
>> +        */
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 1);
>> +       I2C_TRISTATE(sda);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_DELAY(delay);
>> +       nack = I2C_READ(sda);
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_ACTIVE(sda);
>> +
>> +       return nack;    /* not a nack is an ack */
>> +}
>> +#endif
>>
>>   /*-----------------------------------------------------------------------
>>    * if ack == I2C_ACK, ACK the byte so can continue reading, else
>>    * send I2C_NOACK to end the read.
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static uchar read_byte(int ack)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -293,10 +485,38 @@ static uchar read_byte(int ack)
>>
>>          return(data);
>>   }
>> +#else
>> +static uchar read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
>> +                      int delay, int ack)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> +       int  data;
>> +       int  j;
>> +
>> +       /*
>> +        * Read 8 bits, MSB first.
>> +        */
>> +       I2C_TRISTATE(sda);
>> +       I2C_SDA(sda, 1);
>> +       data = 0;
>> +       for (j = 0; j < 8; j++) {
>> +               I2C_SCL(scl, 0);
>> +               I2C_DELAY(delay);
>> +               I2C_SCL(scl, 1);
>> +               I2C_DELAY(delay);
>> +               data <<= 1;
>> +               data |= I2C_READ(sda);
>> +               I2C_DELAY(delay);
>> +       }
>> +       send_ack(scl, sda, delay, ack);
>>
>> +       return data;
>> +}
>> +#endif /* CONFIG_SYS_I2C_SOFT */
>>   /*-----------------------------------------------------------------------
>>    * Initialization
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
>>   {
>>   #if defined(CONFIG_SYS_I2C_INIT_BOARD)
>> @@ -314,12 +534,14 @@ static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
>>          send_reset ();
>>   #endif
>>   }
>> +#endif
>>
>>   /*-----------------------------------------------------------------------
>>    * Probe to see if a chip is present.  Also good for checking for the
>>    * completion of EEPROM writes since the chip stops responding until
>>    * the write completes (typically 10mSec).
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
>>   {
>>          int rc;
>> @@ -334,10 +556,12 @@ static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
>>
>>          return (rc ? 1 : 0);
>>   }
>> +#endif
>>
>>   /*-----------------------------------------------------------------------
>>    * Read bytes
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static int  soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
>>                          int alen, uchar *buffer, int len)
>>   {
>> @@ -409,10 +633,12 @@ static int  soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
>>          send_stop();
>>          return(0);
>>   }
>> +#endif
>>
>>   /*-----------------------------------------------------------------------
>>    * Write bytes
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static int  soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
>>                          int alen, uchar *buffer, int len)
>>   {
>> @@ -444,10 +670,12 @@ static int  soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
>>          send_stop();
>>          return(failures);
>>   }
>> +#endif
>>
>>   /*
>>    * Register soft i2c adapters
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   U_BOOT_I2C_ADAP_COMPLETE(soft0, soft_i2c_init, soft_i2c_probe,
>>                           soft_i2c_read, soft_i2c_write, NULL,
>>                           CONFIG_SYS_I2C_SOFT_SPEED, CONFIG_SYS_I2C_SOFT_SLAVE,
>> @@ -473,3 +701,163 @@ U_BOOT_I2C_ADAP_COMPLETE(soft3, soft_i2c_init, soft_i2c_probe,
>>                           CONFIG_SYS_I2C_SOFT_SLAVE_4,
>>                           3)
>>   #endif
>> +#endif /* CONFIG_SYS_I2C_SOFT */
>> +
>> +#ifdef CONFIG_DM_I2C_SOFT
>> +struct soft_i2c_bus {
>> +       unsigned int speed;
>> +       unsigned long delay;
>> +       struct gpio_desc scl;
>> +       struct gpio_desc sda;
>> +};
>> +
>> +static int i2c_write_data(struct soft_i2c_bus *i2c_bus, uchar chip,
>> +                         uchar *buffer, int len, bool end_with_repeated_start)
>> +{
>> +       struct gpio_desc *scl = &i2c_bus->scl;
>> +       struct gpio_desc *sda = &i2c_bus->sda;
>> +       unsigned int delay = i2c_bus->delay;
>> +       int failures = 0;
>> +
>> +       PRINTD("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
>> +
>> +       send_start(scl, sda, delay);
>> +       if (write_byte(scl, sda, delay, chip << 1)) {
>> +               send_stop(scl, sda, delay);
>> +               PRINTD("i2c_write, no chip responded %02X\n", chip);
>> +               return -ENODEV;
>
> -EIO I think
>
>> +       }
>> +
>> +       while (len-- > 0) {
>> +               if (write_byte(scl, sda, delay, *buffer++))
>> +                       failures++;
>> +       }
>> +
>> +       send_stop(scl, sda, delay);
>> +
>> +       return failures;
>> +}
>> +
>> +static int i2c_read_data(struct soft_i2c_bus *i2c_bus, uchar chip,
>> +                        uchar *buffer, int len)
>> +{
>> +       struct gpio_desc *scl = &i2c_bus->scl;
>> +       struct gpio_desc *sda = &i2c_bus->sda;
>> +       unsigned int delay = i2c_bus->delay;
>> +
>> +       PRINTD("%s: chip %x buffer: %x len %d\n", __func__, chip, buffer, len);
>> +
>> +       send_start(scl, sda, delay);
>> +       write_byte(scl, sda, delay, (chip << 1) | 1);   /* read cycle */
>> +
>> +       while (len-- > 0)
>> +               *buffer++ = read_byte(scl, sda, delay, len == 0);
>> +
>> +       send_stop(scl, sda, delay);
>> +
>> +       return 0;
>> +}
>> +
>> +static int soft_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
>> +{
>> +       struct soft_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 soft_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
>> +{
>> +       struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
>> +       struct gpio_desc *scl = &i2c_bus->scl;
>> +       struct gpio_desc *sda = &i2c_bus->sda;
>> +       unsigned int delay = i2c_bus->delay;
>> +       int ret;
>> +
>> +       send_start(scl, sda, delay);
>> +       ret = write_byte(scl, sda, delay, (chip << 1) | 0);
>> +       send_stop(scl, sda, delay);
>> +
>> +       PRINTD("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
>> +              __func__, dev->seq, dev->name, chip, chip_flags, ret);
>> +
>> +       return ret;
>> +}
>> +
>> +static int soft_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
>> +{
>> +       struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
>> +       struct gpio_desc *scl = &i2c_bus->scl;
>> +       struct gpio_desc *sda = &i2c_bus->sda;
>> +
>> +       i2c_bus->speed = speed;
>> +       i2c_bus->delay = lldiv(1000000, speed << 2);
>> +
>> +       (scl, sda, i2c_bus->delay);
>> +
>> +       PRINTD("%s: bus: %d (%s) speed: %u Hz (1/4 of period: %lu us)\n",
>> +              __func__, dev->seq, dev->name, speed, i2c_bus->delay);
>> +
>> +       return 0;
>> +}
>> +
>> +static int soft_i2c_ofdata_to_platdata(struct udevice *dev)
>> +{
>> +       struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
>> +       const void *blob = gd->fdt_blob;
>> +       char *pin_name;
>> +       int ret;
>> +
>> +       pin_name = "clock-pin";
>
> nit: You don't need this variable
>
>> +       ret = gpio_request_by_name_nodev(blob, dev->of_offset, pin_name,
>> +                                        0, &i2c_bus->scl, GPIOD_IS_OUT);
>
> You should not use the nodev version when you have a device. Also below.
>
>> +       if (ret)
>> +               goto error;
>> +
>> +       pin_name = "data-pin";
>
> nit: or here
>
>> +       ret = gpio_request_by_name_nodev(blob, dev->of_offset, pin_name,
>> +                                        0, &i2c_bus->sda, GPIOD_IS_OUT);
>> +       if (ret)
>> +               goto error;
>> +
>> +       PRINTD("%s: bus: %d (%s) fdt node ok\n", __func__, dev->seq, dev->name);
>> +
>> +       return 0;
>> +error:
>> +       error("Can't get %s for soft i2c dev: %s", pin_name, dev->name);
>> +       return ret;
>> +}
>> +
>> +static const struct dm_i2c_ops soft_i2c_ops = {
>> +       .xfer           = soft_i2c_xfer,
>> +       .probe_chip     = soft_i2c_probe,
>> +       .set_bus_speed  = soft_i2c_set_bus_speed,
>> +};
>> +
>> +static const struct udevice_id soft_i2c_ids[] = {
>> +       { .compatible = "soft-i2c" },
>> +       { }
>> +};
>> +
>> +U_BOOT_DRIVER(soft_i2c) = {
>> +       .name   = "soft-i2c",
>> +       .id     = UCLASS_I2C,
>> +       .of_match = soft_i2c_ids,
>> +       .ofdata_to_platdata = soft_i2c_ofdata_to_platdata,
>> +       .priv_auto_alloc_size = sizeof(struct soft_i2c_bus),
>> +       .ops    = &soft_i2c_ops,
>> +};
>> +#endif /* CONFIG_DM_I2C_SOFT */
>> --
>> 1.9.1
>>
>
> Regards,
> Simon
>

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 3/3] Kconfig: i2c: add entry for driver-model software i2c
  2015-03-10 10:30 ` [U-Boot] [PATCH 3/3] Kconfig: i2c: add entry for driver-model software i2c Przemyslaw Marczak
  2015-03-23  8:46   ` Lukasz Majewski
  2015-03-23 23:40   ` Simon Glass
@ 2015-03-25  3:35   ` Masahiro Yamada
  2015-03-26 13:17     ` Przemyslaw Marczak
  2 siblings, 1 reply; 36+ messages in thread
From: Masahiro Yamada @ 2015-03-25  3:35 UTC (permalink / raw)
  To: u-boot

Hi.



2015-03-10 19:30 GMT+09:00 Przemyslaw Marczak <p.marczak@samsung.com>:
> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>

I am no longer working for Panasonic.
The old email address will get unavailable at the end of March.

Going forward, please use my new address, yamada.masahiro at socionext.com



>
> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
> index 0a52ed9..dd7eb3c 100644
> --- a/drivers/i2c/Kconfig
> +++ b/drivers/i2c/Kconfig
> @@ -13,6 +13,49 @@ config DM_I2C_COMPAT
>           to convert all code for a board in a single commit. It should not
>           be enabled for any board in an official release.
>
> +config DM_I2C_SOFT
> +       bool "Enable Driver Model for Software I2C Driver"
> +       depends on DM_I2C
> +       help
> +         Enable the i2c bus driver emulation by using GPIO.

Very nice!

> +         The bus configuration is given by the device-tree, like below.
> +
> +         /* First, define the alias number to have continuous bus numbering */
> +         aliases {
> +           [...]
> +           i2c5 = "/i2c at 13500000";
> +           i2c6 = "/soft-i2c at 1";
> +           [...]
> +         }

This description is not specific to this CONFIG option.

The relation between the aliases node and the sequence number
is well-documented in doc/driver-model/README.txt.

Should we repeat it here?


> +         /* And next define the basic bus attributes */
> +         soft-i2c at 1 {
> +           #address-cells = <1>;
> +           #size-cells = <0>;
> +           compatible = "soft-i2c";
> +           clock-frequency = <50000>;
> +           /* Define the proper GPIO pins */
> +           clock-pin = <&gpa0 0 GPIO_ACTIVE_HIGH>;
> +           data-pin = <&gpa0 1 GPIO_ACTIVE_HIGH>;
> +
> +           /* Optionally, define some driver node (bus child) */
> +           somedev at 0x44 {
> +               compatible = "somedev";
> +               reg = <0x44>;
> +               [...]
> +           };
> +         }

This is binding information, right?

Stuff like that is usually documented in a separate text file.

In Linux, Documentation/devicetree/bindings/i2c/
In U-boot, doc/device-tree-bindings/i2c/



> +         The device can be accessed by the i2c command:
> +         # i2c dev 8                   (bus number set by alias)
> +         # i2c probe <0x44>            (address is optionally)
> +         # i2c md 0x44 0x0             (dump dev registers at address 0x0)
> +         # Valid chip addresses: 0x44  (success!)
> +         ...


This is the usage of "i2c" command.
It is not specific to this option, either.




> +         Driving the bus lines is done by dm gpio calls in the preprocessor
> +         macros. Each, can be redefined by the user.
> +
>  config SYS_I2C_UNIPHIER
>         bool "UniPhier I2C driver"
>         depends on ARCH_UNIPHIER && DM_I2C
> --
> 1.9.1
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot



-- 
Best Regards
Masahiro Yamada

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 3/3] Kconfig: i2c: add entry for driver-model software i2c
  2015-03-25  3:35   ` Masahiro Yamada
@ 2015-03-26 13:17     ` Przemyslaw Marczak
  0 siblings, 0 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-26 13:17 UTC (permalink / raw)
  To: u-boot

Hello Masahiro,

On 03/25/2015 04:35 AM, Masahiro Yamada wrote:
> Hi.
>
>
>
> 2015-03-10 19:30 GMT+09:00 Przemyslaw Marczak <p.marczak@samsung.com>:
>> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
>> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
>
> I am no longer working for Panasonic.
> The old email address will get unavailable at the end of March.
>
> Going forward, please use my new address, yamada.masahiro at socionext.com
>
>
>

Ok, will update this.

>>
>> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
>> index 0a52ed9..dd7eb3c 100644
>> --- a/drivers/i2c/Kconfig
>> +++ b/drivers/i2c/Kconfig
>> @@ -13,6 +13,49 @@ config DM_I2C_COMPAT
>>            to convert all code for a board in a single commit. It should not
>>            be enabled for any board in an official release.
>>
>> +config DM_I2C_SOFT
>> +       bool "Enable Driver Model for Software I2C Driver"
>> +       depends on DM_I2C
>> +       help
>> +         Enable the i2c bus driver emulation by using GPIO.
>
> Very nice!
>
>> +         The bus configuration is given by the device-tree, like below.
>> +
>> +         /* First, define the alias number to have continuous bus numbering */
>> +         aliases {
>> +           [...]
>> +           i2c5 = "/i2c at 13500000";
>> +           i2c6 = "/soft-i2c at 1";
>> +           [...]
>> +         }
>
> This description is not specific to this CONFIG option.
>
> The relation between the aliases node and the sequence number
> is well-documented in doc/driver-model/README.txt.
>
> Should we repeat it here?
>
>

Yes, you are right. I wanted to put here all informations, required to 
make it working with devices, since I think it could facilitate the 
development for the others.
Will remove this.

>> +         /* And next define the basic bus attributes */
>> +         soft-i2c at 1 {
>> +           #address-cells = <1>;
>> +           #size-cells = <0>;
>> +           compatible = "soft-i2c";
>> +           clock-frequency = <50000>;
>> +           /* Define the proper GPIO pins */
>> +           clock-pin = <&gpa0 0 GPIO_ACTIVE_HIGH>;
>> +           data-pin = <&gpa0 1 GPIO_ACTIVE_HIGH>;
>> +
>> +           /* Optionally, define some driver node (bus child) */
>> +           somedev at 0x44 {
>> +               compatible = "somedev";
>> +               reg = <0x44>;
>> +               [...]
>> +           };
>> +         }
>
> This is binding information, right?
>
> Stuff like that is usually documented in a separate text file.
>
> In Linux, Documentation/devicetree/bindings/i2c/
> In U-boot, doc/device-tree-bindings/i2c/
>

Right, will move into proper path.

>
>
>> +         The device can be accessed by the i2c command:
>> +         # i2c dev 8                   (bus number set by alias)
>> +         # i2c probe <0x44>            (address is optionally)
>> +         # i2c md 0x44 0x0             (dump dev registers at address 0x0)
>> +         # Valid chip addresses: 0x44  (success!)
>> +         ...
>
>
> This is the usage of "i2c" command.
> It is not specific to this option, either.
 >

Ok.

>
>
>
>> +         Driving the bus lines is done by dm gpio calls in the preprocessor
>> +         macros. Each, can be redefined by the user.
>> +
>>   config SYS_I2C_UNIPHIER
>>          bool "UniPhier I2C driver"
>>          depends on ARCH_UNIPHIER && DM_I2C
>> --
>> 1.9.1
>>
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot at lists.denx.de
>> http://lists.denx.de/mailman/listinfo/u-boot
>
>
>

Thanks for review!

Best regards,
-- 
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver
  2015-03-23 23:38   ` Simon Glass
  2015-03-24  6:01     ` Heiko Schocher
@ 2015-03-26 13:18     ` Przemyslaw Marczak
  1 sibling, 0 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-26 13:18 UTC (permalink / raw)
  To: u-boot

Hello Simon,

On 03/24/2015 12:38 AM, Simon Glass wrote:
> Hi Przemyslaw,
>
> On 10 March 2015 at 04:30, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
>> This change adds driver model support to software emulated
>> i2c bus driver. To bind the driver, proper device-tree node
>> must be defined, with the following attributes:
>> - alias: to keep proper bus order
>> - compatible: 'soft-i2c'
>> - clock-frequency [Hz]
>> - clock-pin, data-pin: gpio phandles
>>
>> /* Define the alias number to keep bus numbering order */
>> aliases {
>>          [...]
>>          i2c5 = "/i2c at 13500000";
>>          i2c6 = "/soft-i2c at 1";
>>          [...]
>> };
>>
>> /* Define the basic bus attributes */
>> soft-i2c at 1 {
>>          #address-cells = <1>;
>>          #size-cells = <0>;
>>          compatible = "soft-i2c";
>>          clock-frequency = <50000>;
>>
>>          /* Define the proper GPIO pins */
>>          clock-pin = <&gpa0 0 GPIO_ACTIVE_HIGH>;
>>          data-pin = <&gpa0 1 GPIO_ACTIVE_HIGH>;
>>
>>          /* Optionally, define some driver node (bus child) */
>>          somedev at 0x44 {
>>                  compatible = "somedev";
>>                  reg = <0x44>;
>>                  [...]
>>          };
>> };
>>
>> The device can be accessed by the i2c command:
>>   i2c dev 8                   (bus number set by alias)
>>   i2c probe <0x44>            (address is optionally)
>>   i2c md 0x44 0x0             (dump dev registers at address 0x0)
>>   Valid chip addresses: 0x44  (success!)
>>   ...
>>
>> The previous driver functionality stays unchanged. Driving the bus lines
>> is done by dm gpio calls in the preprocessor macros. Each, can be redefined
>> by the user as previous.
>>
>> Tested on Trats2 and Odroid U3.
>
> Is the intention to retire the old (non-driver-model) code? What boards use it?
>

Yes, it is in the intention. There is about 20 boards, with defined 
soft-i2c macros in their configs.

>>
>> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
>> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
>> Cc: Mike Frysinger <vapier@gentoo.org>
>> Cc: Simon Glass <sjg@chromium.org>
>> Cc: Heiko Schocher <hs@denx.de>
>> ---
>>   drivers/i2c/Makefile   |   1 +
>>   drivers/i2c/soft_i2c.c | 410 +++++++++++++++++++++++++++++++++++++++++++++++--
>>   2 files changed, 400 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
>> index 774bc94..7039b6d 100644
>> --- a/drivers/i2c/Makefile
>> +++ b/drivers/i2c/Makefile
>> @@ -6,6 +6,7 @@
>>   #
>>   obj-$(CONFIG_DM_I2C) += i2c-uclass.o
>>   obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
>> +obj-$(CONFIG_DM_I2C_SOFT) += soft_i2c.o
>>
>>   obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
>>   obj-$(CONFIG_I2C_MV) += mv_i2c.o
>> diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
>> index db9b402..7afae0b 100644
>> --- a/drivers/i2c/soft_i2c.c
>> +++ b/drivers/i2c/soft_i2c.c
>> @@ -1,4 +1,7 @@
>>   /*
>> + * (C) Copyright 2015, Samsung Electronics
>> + * Przemyslaw Marczak <p.marczak@samsung.com>
>> + *
>>    * (C) Copyright 2009
>>    * Heiko Schocher, DENX Software Engineering, hs at denx.de.
>>    * Changes for multibus/multiadapter I2C support.
>> @@ -14,6 +17,11 @@
>>    */
>>
>>   #include <common.h>
>> +#include <errno.h>
>> +#include <dm.h>
>> +#include <i2c.h>
>> +#include <div64.h>
>> +#include <asm/gpio.h>
>>   #ifdef CONFIG_MPC8260                  /* only valid for MPC8260 */
>>   #include <ioports.h>
>>   #include <asm/io.h>
>> @@ -32,11 +40,9 @@
>>   #if defined(CONFIG_MPC852T) || defined(CONFIG_MPC866)
>>   #include <asm/io.h>
>>   #endif
>> -#include <i2c.h>
>>
>> +#if defined(CONFIG_SYS_I2C)
>>   #if defined(CONFIG_SOFT_I2C_GPIO_SCL)
>> -# include <asm/gpio.h>
>> -
>>   # ifndef I2C_GPIO_SYNC
>>   #  define I2C_GPIO_SYNC
>>   # endif
>> @@ -85,6 +91,7 @@
>>   # endif
>>
>>   #endif
>> +#endif
>>
>>   /* #define     DEBUG_I2C       */
>>
>> @@ -109,6 +116,65 @@ DECLARE_GLOBAL_DATA_PTR;
>>   #define CONFIG_SYS_I2C_SOFT_SLAVE CONFIG_SYS_I2C_SLAVE
>>   #endif
>>
>> +/* DM SOFT I2C */
>> +#ifdef CONFIG_DM_I2C_SOFT
>> +# ifndef I2C_GPIO_SYNC
>> +#  define I2C_GPIO_SYNC(gpio)
>> +# endif
>> +
>> +# ifndef I2C_INIT
>> +#  define I2C_INIT(scl, sda)  \
>> +       do { } while (0)
>> +# endif
>> +
>> +# ifndef I2C_ACTIVE
>> +#  define I2C_ACTIVE(sda) \
>> +       do { } while (0)
>> +# endif
>> +
>> +# ifndef I2C_TRISTATE
>> +#  define I2C_TRISTATE(sda) \
>> +       do { } while (0)
>> +# endif
>> +
>> +# ifndef I2C_READ
>> +#  define I2C_READ(sda) dm_gpio_get_value(sda);
>> +# endif
>> +
>> +# ifndef I2C_SDA
>> +#  define I2C_SDA(sda, bit) \
>> +       do { \
>> +               if (bit) { \
>> +                       sda->flags &= ~GPIOD_IS_OUT; \
>> +                       sda->flags |= GPIOD_IS_IN; \
>> +                       dm_gpio_set_dir(sda); \
>> +               } else { \
>> +                       sda->flags &= ~GPIOD_IS_IN; \
>> +                       sda->flags |= GPIOD_IS_OUT; \
>> +                       dm_gpio_set_dir(sda); \
>> +                       dm_gpio_set_value(sda, 0); \
>> +               } \
>> +               I2C_GPIO_SYNC(sda); \
>> +       } while (0)
>> +# endif
>> +
>> +# ifndef I2C_SCL
>> +#  define I2C_SCL(scl, bit) \
>> +       do { \
>> +               scl->flags &= ~GPIOD_IS_IN; \
>> +               scl->flags |= GPIOD_IS_OUT; \
>> +               dm_gpio_set_dir(scl); \
>> +               dm_gpio_set_value(scl, bit); \
>> +               I2C_GPIO_SYNC(scl); \
>> +       } while (0)
>> +# endif
>> +
>> +# ifndef I2C_DELAY
>> +#  define I2C_DELAY(us) udelay(us)     /* 1/4 I2C clock duration */
>> +# endif
>> +
>> +#endif /* CONFIG_DM_I2C_SOFT */
>> +
>>   /*-----------------------------------------------------------------------
>>    * Definitions
>>    */
>> @@ -117,7 +183,6 @@ DECLARE_GLOBAL_DATA_PTR;
>>   #define I2C_ACK                0               /* PD_SDA level to ack a byte */
>>   #define I2C_NOACK      1               /* PD_SDA level to noack a byte */
>>
>> -
>>   #ifdef DEBUG_I2C
>>   #define PRINTD(fmt,args...)    do {    \
>>                  printf (fmt ,##args);   \
>> @@ -129,21 +194,30 @@ DECLARE_GLOBAL_DATA_PTR;
>>   /*-----------------------------------------------------------------------
>>    * Local functions
>>    */
>> +#ifdef CONFIG_SYS_I2C
>>   #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
>> -static void  send_reset        (void);
>> +static void send_reset(void);
>> +#endif
>> +static void send_start(void);
>> +static void send_stop(void);
>> +static void send_ack(int);
>> +static int write_byte(uchar byte);
>> +static uchar read_byte(int);
>> +#else
>> +static void send_reset(struct gpio_desc *, struct gpio_desc *, int);
>> +static void send_start(struct gpio_desc *, struct gpio_desc *, int);
>> +static void send_stop(struct gpio_desc *, struct gpio_desc *, int);
>> +static void send_ack(struct gpio_desc *, struct gpio_desc *, int, int);
>> +static int write_byte(struct gpio_desc *, struct gpio_desc *, int, uchar);
>> +static uchar read_byte(struct gpio_desc *, struct gpio_desc *, int, int);
>>   #endif
>> -static void  send_start        (void);
>> -static void  send_stop (void);
>> -static void  send_ack  (int);
>> -static int   write_byte        (uchar byte);
>> -static uchar read_byte (int);
>> -
>>   #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
>>   /*-----------------------------------------------------------------------
>>    * Send a reset sequence consisting of 9 clocks with the data signal high
>>    * to clock any confused device back into an idle state.  Also send a
>>    * <stop> at the end of the sequence for belts & suspenders.
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static void send_reset(void)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -166,11 +240,36 @@ static void send_reset(void)
>>          send_stop();
>>          I2C_TRISTATE;
>>   }
>> +#else
>> +static void send_reset(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> +       int j;
>> +
>> +       I2C_SCL(scl, 1);
>> +       I2C_SDA(sda, 1);
>> +#ifdef I2C_INIT
>> +       I2C_INIT(scl, sda);
>> +#endif
>> +       I2C_TRISTATE(sda);
>> +       for (j = 0; j < 9; j++) {
>> +               I2C_SCL(scl, 0);
>> +               I2C_DELAY(delay);
>> +               I2C_DELAY(delay);
>> +               I2C_SCL(scl, 1);
>> +               I2C_DELAY(delay);
>> +               I2C_DELAY(delay);
>> +       }
>> +       send_stop(scl, sda, delay);
>> +       I2C_TRISTATE(sda);
>
> For the new code I would much prefer that these become functions
> rather than macros. What is the benefit of using a macro?
>

Right, there are probably no benefits of keeping old code style.

>> +}
>> +#endif /* CONFIG_SYS_I2C_SOFT */
>>   #endif
>>
>>   /*-----------------------------------------------------------------------
>>    * START: High -> Low on SDA while SCL is High
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static void send_start(void)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -184,10 +283,25 @@ static void send_start(void)
>>          I2C_SDA(0);
>>          I2C_DELAY;
>>   }
>> +#else
>> +static void send_start(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>>
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 1);
>> +       I2C_ACTIVE(sda);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 0);
>> +       I2C_DELAY(delay);
>> +}
>> +#endif /* CONFIG_SYS_I2C_SOFT */
>>   /*-----------------------------------------------------------------------
>>    * STOP: Low -> High on SDA while SCL is High
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static void send_stop(void)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -203,10 +317,28 @@ static void send_stop(void)
>>          I2C_DELAY;
>>          I2C_TRISTATE;
>>   }
>> +#else
>> +static void send_stop(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> +
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 0);
>> +       I2C_ACTIVE(sda);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_TRISTATE(sda);
>> +}
>> +#endif /* CONFIG_SYS_I2C_SOFT */
>>
>>   /*-----------------------------------------------------------------------
>>    * ack should be I2C_ACK or I2C_NOACK
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static void send_ack(int ack)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -222,10 +354,29 @@ static void send_ack(int ack)
>>          I2C_SCL(0);
>>          I2C_DELAY;
>>   }
>> +#else
>> +static void send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
>> +                    int delay, int ack)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> +
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_ACTIVE(sda);
>> +       I2C_SDA(sda, ack);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +}
>> +#endif
>>
>>   /*-----------------------------------------------------------------------
>>    * Send 8 bits and look for an acknowledgement.
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static int write_byte(uchar data)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -263,11 +414,52 @@ static int write_byte(uchar data)
>>
>>          return(nack);   /* not a nack is an ack */
>>   }
>> +#else
>> +static int write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
>> +                     int delay, uchar data)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> +       int j;
>> +       int nack;
>> +
>> +       I2C_ACTIVE(sda);
>> +       for (j = 0; j < 8; j++) {
>> +               I2C_SCL(scl, 0);
>> +               I2C_DELAY(delay);
>> +               I2C_SDA(sda, data & 0x80);
>> +               I2C_DELAY(delay);
>> +               I2C_SCL(scl, 1);
>> +               I2C_DELAY(delay);
>> +               I2C_DELAY(delay);
>> +
>> +               data <<= 1;
>> +       }
>> +
>> +       /*
>> +        * Look for an <ACK>(negative logic) and return it.
>> +        */
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 1);
>> +       I2C_TRISTATE(sda);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_DELAY(delay);
>> +       nack = I2C_READ(sda);
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_ACTIVE(sda);
>> +
>> +       return nack;    /* not a nack is an ack */
>> +}
>> +#endif
>>
>>   /*-----------------------------------------------------------------------
>>    * if ack == I2C_ACK, ACK the byte so can continue reading, else
>>    * send I2C_NOACK to end the read.
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static uchar read_byte(int ack)
>>   {
>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> @@ -293,10 +485,38 @@ static uchar read_byte(int ack)
>>
>>          return(data);
>>   }
>> +#else
>> +static uchar read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
>> +                      int delay, int ack)
>> +{
>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>> +       int  data;
>> +       int  j;
>> +
>> +       /*
>> +        * Read 8 bits, MSB first.
>> +        */
>> +       I2C_TRISTATE(sda);
>> +       I2C_SDA(sda, 1);
>> +       data = 0;
>> +       for (j = 0; j < 8; j++) {
>> +               I2C_SCL(scl, 0);
>> +               I2C_DELAY(delay);
>> +               I2C_SCL(scl, 1);
>> +               I2C_DELAY(delay);
>> +               data <<= 1;
>> +               data |= I2C_READ(sda);
>> +               I2C_DELAY(delay);
>> +       }
>> +       send_ack(scl, sda, delay, ack);
>>
>> +       return data;
>> +}
>> +#endif /* CONFIG_SYS_I2C_SOFT */
>>   /*-----------------------------------------------------------------------
>>    * Initialization
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
>>   {
>>   #if defined(CONFIG_SYS_I2C_INIT_BOARD)
>> @@ -314,12 +534,14 @@ static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
>>          send_reset ();
>>   #endif
>>   }
>> +#endif
>>
>>   /*-----------------------------------------------------------------------
>>    * Probe to see if a chip is present.  Also good for checking for the
>>    * completion of EEPROM writes since the chip stops responding until
>>    * the write completes (typically 10mSec).
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
>>   {
>>          int rc;
>> @@ -334,10 +556,12 @@ static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
>>
>>          return (rc ? 1 : 0);
>>   }
>> +#endif
>>
>>   /*-----------------------------------------------------------------------
>>    * Read bytes
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static int  soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
>>                          int alen, uchar *buffer, int len)
>>   {
>> @@ -409,10 +633,12 @@ static int  soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
>>          send_stop();
>>          return(0);
>>   }
>> +#endif
>>
>>   /*-----------------------------------------------------------------------
>>    * Write bytes
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   static int  soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
>>                          int alen, uchar *buffer, int len)
>>   {
>> @@ -444,10 +670,12 @@ static int  soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
>>          send_stop();
>>          return(failures);
>>   }
>> +#endif
>>
>>   /*
>>    * Register soft i2c adapters
>>    */
>> +#ifdef CONFIG_SYS_I2C_SOFT
>>   U_BOOT_I2C_ADAP_COMPLETE(soft0, soft_i2c_init, soft_i2c_probe,
>>                           soft_i2c_read, soft_i2c_write, NULL,
>>                           CONFIG_SYS_I2C_SOFT_SPEED, CONFIG_SYS_I2C_SOFT_SLAVE,
>> @@ -473,3 +701,163 @@ U_BOOT_I2C_ADAP_COMPLETE(soft3, soft_i2c_init, soft_i2c_probe,
>>                           CONFIG_SYS_I2C_SOFT_SLAVE_4,
>>                           3)
>>   #endif
>> +#endif /* CONFIG_SYS_I2C_SOFT */
>> +
>> +#ifdef CONFIG_DM_I2C_SOFT
>> +struct soft_i2c_bus {
>> +       unsigned int speed;
>> +       unsigned long delay;
>> +       struct gpio_desc scl;
>> +       struct gpio_desc sda;
>> +};
>> +
>> +static int i2c_write_data(struct soft_i2c_bus *i2c_bus, uchar chip,
>> +                         uchar *buffer, int len, bool end_with_repeated_start)
>> +{
>> +       struct gpio_desc *scl = &i2c_bus->scl;
>> +       struct gpio_desc *sda = &i2c_bus->sda;
>> +       unsigned int delay = i2c_bus->delay;
>> +       int failures = 0;
>> +
>> +       PRINTD("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
>> +
>> +       send_start(scl, sda, delay);
>> +       if (write_byte(scl, sda, delay, chip << 1)) {
>> +               send_stop(scl, sda, delay);
>> +               PRINTD("i2c_write, no chip responded %02X\n", chip);
>> +               return -ENODEV;
>
> -EIO I think
>

Ok, will fix.

>> +       }
>> +
>> +       while (len-- > 0) {
>> +               if (write_byte(scl, sda, delay, *buffer++))
>> +                       failures++;
>> +       }
>> +
>> +       send_stop(scl, sda, delay);
>> +
>> +       return failures;
>> +}
>> +
>> +static int i2c_read_data(struct soft_i2c_bus *i2c_bus, uchar chip,
>> +                        uchar *buffer, int len)
>> +{
>> +       struct gpio_desc *scl = &i2c_bus->scl;
>> +       struct gpio_desc *sda = &i2c_bus->sda;
>> +       unsigned int delay = i2c_bus->delay;
>> +
>> +       PRINTD("%s: chip %x buffer: %x len %d\n", __func__, chip, buffer, len);
>> +
>> +       send_start(scl, sda, delay);
>> +       write_byte(scl, sda, delay, (chip << 1) | 1);   /* read cycle */
>> +
>> +       while (len-- > 0)
>> +               *buffer++ = read_byte(scl, sda, delay, len == 0);
>> +
>> +       send_stop(scl, sda, delay);
>> +
>> +       return 0;
>> +}
>> +
>> +static int soft_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
>> +{
>> +       struct soft_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 soft_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
>> +{
>> +       struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
>> +       struct gpio_desc *scl = &i2c_bus->scl;
>> +       struct gpio_desc *sda = &i2c_bus->sda;
>> +       unsigned int delay = i2c_bus->delay;
>> +       int ret;
>> +
>> +       send_start(scl, sda, delay);
>> +       ret = write_byte(scl, sda, delay, (chip << 1) | 0);
>> +       send_stop(scl, sda, delay);
>> +
>> +       PRINTD("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
>> +              __func__, dev->seq, dev->name, chip, chip_flags, ret);
>> +
>> +       return ret;
>> +}
>> +
>> +static int soft_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
>> +{
>> +       struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
>> +       struct gpio_desc *scl = &i2c_bus->scl;
>> +       struct gpio_desc *sda = &i2c_bus->sda;
>> +
>> +       i2c_bus->speed = speed;
>> +       i2c_bus->delay = lldiv(1000000, speed << 2);
>> +
>> +       (scl, sda, i2c_bus->delay);
>> +
>> +       PRINTD("%s: bus: %d (%s) speed: %u Hz (1/4 of period: %lu us)\n",
>> +              __func__, dev->seq, dev->name, speed, i2c_bus->delay);
>> +
>> +       return 0;
>> +}
>> +
>> +static int soft_i2c_ofdata_to_platdata(struct udevice *dev)
>> +{
>> +       struct soft_i2c_bus *i2c_bus = dev_get_priv(dev);
>> +       const void *blob = gd->fdt_blob;
>> +       char *pin_name;
>> +       int ret;
>> +
>> +       pin_name = "clock-pin";
>
> nit: You don't need this variable
>
It is used when printing the error, at the end of this function.

>> +       ret = gpio_request_by_name_nodev(blob, dev->of_offset, pin_name,
>> +                                        0, &i2c_bus->scl, GPIOD_IS_OUT);
>
> You should not use the nodev version when you have a device. Also below.
>
Ah, right. I made this mistake also in last pmic patches. Will fix for both.

>> +       if (ret)
>> +               goto error;
>> +
>> +       pin_name = "data-pin";
>
> nit: or here
>
>> +       ret = gpio_request_by_name_nodev(blob, dev->of_offset, pin_name,
>> +                                        0, &i2c_bus->sda, GPIOD_IS_OUT);
>> +       if (ret)
>> +               goto error;
>> +
>> +       PRINTD("%s: bus: %d (%s) fdt node ok\n", __func__, dev->seq, dev->name);
>> +
>> +       return 0;
>> +error:
>> +       error("Can't get %s for soft i2c dev: %s", pin_name, dev->name);
>> +       return ret;
>> +}
>> +
>> +static const struct dm_i2c_ops soft_i2c_ops = {
>> +       .xfer           = soft_i2c_xfer,
>> +       .probe_chip     = soft_i2c_probe,
>> +       .set_bus_speed  = soft_i2c_set_bus_speed,
>> +};
>> +
>> +static const struct udevice_id soft_i2c_ids[] = {
>> +       { .compatible = "soft-i2c" },
>> +       { }
>> +};
>> +
>> +U_BOOT_DRIVER(soft_i2c) = {
>> +       .name   = "soft-i2c",
>> +       .id     = UCLASS_I2C,
>> +       .of_match = soft_i2c_ids,
>> +       .ofdata_to_platdata = soft_i2c_ofdata_to_platdata,
>> +       .priv_auto_alloc_size = sizeof(struct soft_i2c_bus),
>> +       .ops    = &soft_i2c_ops,
>> +};
>> +#endif /* CONFIG_DM_I2C_SOFT */
>> --
>> 1.9.1
>>
>
> Regards,
> Simon
>

Best regards,
-- 
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver
  2015-03-24  6:01     ` Heiko Schocher
@ 2015-03-26 13:18       ` Przemyslaw Marczak
  0 siblings, 0 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-26 13:18 UTC (permalink / raw)
  To: u-boot

Hello,

On 03/24/2015 07:01 AM, Heiko Schocher wrote:
> Hello Simon, Przemyslaw,
>
> Am 24.03.2015 00:38, schrieb Simon Glass:
>> Hi Przemyslaw,
>>
>> On 10 March 2015 at 04:30, Przemyslaw Marczak <p.marczak@samsung.com>
>> wrote:
>>> This change adds driver model support to software emulated
>>> i2c bus driver. To bind the driver, proper device-tree node
>>> must be defined, with the following attributes:
>>> - alias: to keep proper bus order
>>> - compatible: 'soft-i2c'
>>> - clock-frequency [Hz]
>>> - clock-pin, data-pin: gpio phandles
>>>
>>> /* Define the alias number to keep bus numbering order */
>>> aliases {
>>>          [...]
>>>          i2c5 = "/i2c at 13500000";
>>>          i2c6 = "/soft-i2c at 1";
>>>          [...]
>>> };
>>>
>>> /* Define the basic bus attributes */
>>> soft-i2c at 1 {
>>>          #address-cells = <1>;
>>>          #size-cells = <0>;
>>>          compatible = "soft-i2c";
>>>          clock-frequency = <50000>;
>>>
>>>          /* Define the proper GPIO pins */
>>>          clock-pin = <&gpa0 0 GPIO_ACTIVE_HIGH>;
>>>          data-pin = <&gpa0 1 GPIO_ACTIVE_HIGH>;
>>>
>>>          /* Optionally, define some driver node (bus child) */
>>>          somedev at 0x44 {
>>>                  compatible = "somedev";
>>>                  reg = <0x44>;
>>>                  [...]
>>>          };
>>> };
>>>
>>> The device can be accessed by the i2c command:
>>>   i2c dev 8                   (bus number set by alias)
>>>   i2c probe <0x44>            (address is optionally)
>>>   i2c md 0x44 0x0             (dump dev registers at address 0x0)
>>>   Valid chip addresses: 0x44  (success!)
>>>   ...
>>>
>>> The previous driver functionality stays unchanged. Driving the bus lines
>>> is done by dm gpio calls in the preprocessor macros. Each, can be
>>> redefined
>>> by the user as previous.
>>>
>>> Tested on Trats2 and Odroid U3.
>>
>> Is the intention to retire the old (non-driver-model) code? What
>> boards use it?
>
> I think not ... Hmm ... maybe you move the new code into
> a new file?
>
Ok, I will do this for v2.

>>> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
>>> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
>>> Cc: Mike Frysinger <vapier@gentoo.org>
>>> Cc: Simon Glass <sjg@chromium.org>
>>> Cc: Heiko Schocher <hs@denx.de>
>
> Hups... seems I missed this patches ...
>
>>> ---
>>>   drivers/i2c/Makefile   |   1 +
>>>   drivers/i2c/soft_i2c.c | 410
>>> +++++++++++++++++++++++++++++++++++++++++++++++--
>>>   2 files changed, 400 insertions(+), 11 deletions(-)
>
> Thanks for this work!
>
>>> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
>>> index 774bc94..7039b6d 100644
>>> --- a/drivers/i2c/Makefile
>>> +++ b/drivers/i2c/Makefile
>>> @@ -6,6 +6,7 @@
>>>   #
>>>   obj-$(CONFIG_DM_I2C) += i2c-uclass.o
>>>   obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
>>> +obj-$(CONFIG_DM_I2C_SOFT) += soft_i2c.o
>>>
>>>   obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
>>>   obj-$(CONFIG_I2C_MV) += mv_i2c.o
>>> diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
>>> index db9b402..7afae0b 100644
>>> --- a/drivers/i2c/soft_i2c.c
>>> +++ b/drivers/i2c/soft_i2c.c
>>> @@ -1,4 +1,7 @@
>>>   /*
>>> + * (C) Copyright 2015, Samsung Electronics
>>> + * Przemyslaw Marczak <p.marczak@samsung.com>
>>> + *
>>>    * (C) Copyright 2009
>>>    * Heiko Schocher, DENX Software Engineering, hs at denx.de.
>>>    * Changes for multibus/multiadapter I2C support.
>>> @@ -14,6 +17,11 @@
>>>    */
>>>
>>>   #include <common.h>
>>> +#include <errno.h>
>>> +#include <dm.h>
>>> +#include <i2c.h>
>>> +#include <div64.h>
>>> +#include <asm/gpio.h>
>>>   #ifdef CONFIG_MPC8260                  /* only valid for MPC8260 */
>>>   #include <ioports.h>
>>>   #include <asm/io.h>
>>> @@ -32,11 +40,9 @@
>>>   #if defined(CONFIG_MPC852T) || defined(CONFIG_MPC866)
>>>   #include <asm/io.h>
>>>   #endif
>>> -#include <i2c.h>
>>>
>>> +#if defined(CONFIG_SYS_I2C)
>>>   #if defined(CONFIG_SOFT_I2C_GPIO_SCL)
>>> -# include <asm/gpio.h>
>>> -
>>>   # ifndef I2C_GPIO_SYNC
>>>   #  define I2C_GPIO_SYNC
>>>   # endif
>>> @@ -85,6 +91,7 @@
>>>   # endif
>>>
>>>   #endif
>>> +#endif
>>>
>>>   /* #define     DEBUG_I2C       */
>>>
>>> @@ -109,6 +116,65 @@ DECLARE_GLOBAL_DATA_PTR;
>>>   #define CONFIG_SYS_I2C_SOFT_SLAVE CONFIG_SYS_I2C_SLAVE
>>>   #endif
>>>
>>> +/* DM SOFT I2C */
>>> +#ifdef CONFIG_DM_I2C_SOFT
>>> +# ifndef I2C_GPIO_SYNC
>>> +#  define I2C_GPIO_SYNC(gpio)
>>> +# endif
>>> +
>>> +# ifndef I2C_INIT
>>> +#  define I2C_INIT(scl, sda)  \
>>> +       do { } while (0)
>>> +# endif
>>> +
>>> +# ifndef I2C_ACTIVE
>>> +#  define I2C_ACTIVE(sda) \
>>> +       do { } while (0)
>>> +# endif
>>> +
>>> +# ifndef I2C_TRISTATE
>>> +#  define I2C_TRISTATE(sda) \
>>> +       do { } while (0)
>>> +# endif
>>> +
>>> +# ifndef I2C_READ
>>> +#  define I2C_READ(sda) dm_gpio_get_value(sda);
>>> +# endif
>>> +
>>> +# ifndef I2C_SDA
>>> +#  define I2C_SDA(sda, bit) \
>>> +       do { \
>>> +               if (bit) { \
>>> +                       sda->flags &= ~GPIOD_IS_OUT; \
>>> +                       sda->flags |= GPIOD_IS_IN; \
>>> +                       dm_gpio_set_dir(sda); \
>>> +               } else { \
>>> +                       sda->flags &= ~GPIOD_IS_IN; \
>>> +                       sda->flags |= GPIOD_IS_OUT; \
>>> +                       dm_gpio_set_dir(sda); \
>>> +                       dm_gpio_set_value(sda, 0); \
>>> +               } \
>>> +               I2C_GPIO_SYNC(sda); \
>>> +       } while (0)
>>> +# endif
>>> +
>>> +# ifndef I2C_SCL
>>> +#  define I2C_SCL(scl, bit) \
>>> +       do { \
>>> +               scl->flags &= ~GPIOD_IS_IN; \
>>> +               scl->flags |= GPIOD_IS_OUT; \
>>> +               dm_gpio_set_dir(scl); \
>>> +               dm_gpio_set_value(scl, bit); \
>>> +               I2C_GPIO_SYNC(scl); \
>>> +       } while (0)
>>> +# endif
>>> +
>>> +# ifndef I2C_DELAY
>>> +#  define I2C_DELAY(us) udelay(us)     /* 1/4 I2C clock duration */
>>> +# endif
>>> +
>>> +#endif /* CONFIG_DM_I2C_SOFT */
>>> +
>>>
>>> /*-----------------------------------------------------------------------
>>>
>>>    * Definitions
>>>    */
>>> @@ -117,7 +183,6 @@ DECLARE_GLOBAL_DATA_PTR;
>>>   #define I2C_ACK                0               /* PD_SDA level to
>>> ack a byte */
>>>   #define I2C_NOACK      1               /* PD_SDA level to noack a
>>> byte */
>>>
>>> -
>>>   #ifdef DEBUG_I2C
>>>   #define PRINTD(fmt,args...)    do {    \
>>>                  printf (fmt ,##args);   \
>>> @@ -129,21 +194,30 @@ DECLARE_GLOBAL_DATA_PTR;
>>>
>>> /*-----------------------------------------------------------------------
>>>
>>>    * Local functions
>>>    */
>>> +#ifdef CONFIG_SYS_I2C
>>>   #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
>>> -static void  send_reset        (void);
>>> +static void send_reset(void);
>>> +#endif
>>> +static void send_start(void);
>>> +static void send_stop(void);
>>> +static void send_ack(int);
>>> +static int write_byte(uchar byte);
>>> +static uchar read_byte(int);
>>> +#else
>>> +static void send_reset(struct gpio_desc *, struct gpio_desc *, int);
>>> +static void send_start(struct gpio_desc *, struct gpio_desc *, int);
>>> +static void send_stop(struct gpio_desc *, struct gpio_desc *, int);
>>> +static void send_ack(struct gpio_desc *, struct gpio_desc *, int, int);
>>> +static int write_byte(struct gpio_desc *, struct gpio_desc *, int,
>>> uchar);
>>> +static uchar read_byte(struct gpio_desc *, struct gpio_desc *, int,
>>> int);
>>>   #endif
>>> -static void  send_start        (void);
>>> -static void  send_stop (void);
>>> -static void  send_ack  (int);
>>> -static int   write_byte        (uchar byte);
>>> -static uchar read_byte (int);
>>> -
>>>   #if !defined(CONFIG_SYS_I2C_INIT_BOARD)
>>>
>>> /*-----------------------------------------------------------------------
>>>
>>>    * Send a reset sequence consisting of 9 clocks with the data
>>> signal high
>>>    * to clock any confused device back into an idle state.  Also send a
>>>    * <stop> at the end of the sequence for belts & suspenders.
>>>    */
>>> +#ifdef CONFIG_SYS_I2C_SOFT
>>>   static void send_reset(void)
>>>   {
>>>          I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>>> @@ -166,11 +240,36 @@ static void send_reset(void)
>>>          send_stop();
>>>          I2C_TRISTATE;
>>>   }
>>> +#else
>>> +static void send_reset(struct gpio_desc *scl, struct gpio_desc *sda,
>>> int delay)
>>> +{
>>> +       I2C_SOFT_DECLARATIONS   /* intentional without ';' */
>>> +       int j;
>>> +
>>> +       I2C_SCL(scl, 1);
>>> +       I2C_SDA(sda, 1);
>>> +#ifdef I2C_INIT
>>> +       I2C_INIT(scl, sda);
>>> +#endif
>>> +       I2C_TRISTATE(sda);
>>> +       for (j = 0; j < 9; j++) {
>>> +               I2C_SCL(scl, 0);
>>> +               I2C_DELAY(delay);
>>> +               I2C_DELAY(delay);
>>> +               I2C_SCL(scl, 1);
>>> +               I2C_DELAY(delay);
>>> +               I2C_DELAY(delay);
>>> +       }
>>> +       send_stop(scl, sda, delay);
>>> +       I2C_TRISTATE(sda);
>>
>> For the new code I would much prefer that these become functions
>> rather than macros. What is the benefit of using a macro?
>
> I do not know the real reason, but I think it comes from powerpc
> times, where we had not yet such powerful SoCs and it saved some
> instructions ... I tend to say, lets move the dm part into a new
> file ... and let it us do like linux ...
>
> @Simon: Do you pick up this patches through DM tree, or should
> I pick them up?
>
> bye,
> Heiko

Yes, I will make the new file.


Best regards,
-- 
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH 2/3] Kconfig: i2c: remove wrong help message related to dm i2c
  2015-03-23 23:39   ` Simon Glass
@ 2015-03-26 13:18     ` Przemyslaw Marczak
  0 siblings, 0 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-26 13:18 UTC (permalink / raw)
  To: u-boot

Hello Simon,

On 03/24/2015 12:39 AM, Simon Glass wrote:
> Hi,
>
> On 10 March 2015 at 04:30, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
>> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
>> Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
>> Cc: Mike Frysinger <vapier@gentoo.org>
>> Cc: Simon Glass <sjg@chromium.org>
>> Cc: Heiko Schocher <hs@denx.de>
>> ---
>>   drivers/i2c/Kconfig | 11 +----------
>>   1 file changed, 1 insertion(+), 10 deletions(-)
>>
>> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
>> index 692810d..0a52ed9 100644
>> --- a/drivers/i2c/Kconfig
>> +++ b/drivers/i2c/Kconfig
>> @@ -2,16 +2,7 @@ config DM_I2C
>>          bool "Enable Driver Model for I2C drivers"
>>          depends on DM
>>          help
>> -         Enable driver model for I2C. This SPI flash interface
>> -         (spi_flash_probe(), spi_flash_write(), etc.) is then
>> -         implemented by the SPI flash uclass. There is one standard
>> -         SPI flash driver which knows how to probe most chips
>> -         supported by U-Boot. The uclass interface is defined in
>> -         include/spi_flash.h, but is currently fully compatible
>> -         with the old interface to avoid confusion and duplication
>> -         during the transition parent. SPI and SPI flash must be
>> -         enabled together (it is not possible to use driver model
>> -         for one and not the other).
>> +         Enable driver model for I2C.
>
> That's too short IMO :-)
>
> Can you add a few more details along the lines of what is described
> for SPI, and also mention the COMPAT option?
>
> Thanks for fixing this.
>

Ok, will add more details :)

>>
>>   config DM_I2C_COMPAT
>>          bool "Enable I2C compatibility layer"
>> --
>> 1.9.1
>>
>
> Regards,
> Simon
>

Best regards,
-- 
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V2 0/3] dm: i2c: enable driver model for i2c gpio
  2015-03-10 10:30 [U-Boot] [PATCH 0/3] dm: i2c: enable driver model for software i2c Przemyslaw Marczak
                   ` (2 preceding siblings ...)
  2015-03-10 10:30 ` [U-Boot] [PATCH 3/3] Kconfig: i2c: add entry for driver-model software i2c Przemyslaw Marczak
@ 2015-03-27 17:33 ` Przemyslaw Marczak
  2015-03-27 17:33   ` [U-Boot] [PATCH V2 1/3] dm: gpio: request list: return the count if requests max_count reached Przemyslaw Marczak
                     ` (2 more replies)
  2015-03-31 16:57 ` [U-Boot] [PATCH V3 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
  4 siblings, 3 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-27 17:33 UTC (permalink / raw)
  To: u-boot

This patchset enables driver model support for software i2c bus driver.
It was tested on Trats2 and Odroid U3 devices.

It can be tested on any other device by just modifying the dts file,
first by disabling the hardware i2c bus and then, as it is described
in the doc binding file, add i2c-gpio node.

The drivers, which are using the old api are not converted with this patchset.
I hope that maintainers will do this if required.

Probably the software i2c is used for PMIC devices not only for Trats2,
or Universal C210, so I suggest to wait with moving the drivers until
the pmic is done - this will prevent adding temporary code.

Przemyslaw Marczak (3):
  dm: gpio: request list: return the count if requests max_count reached
  Kconfig: i2c: fix help message related to dm i2c
  dm: i2c: add i2c-gpio driver

 doc/device-tree-bindings/i2c/i2c-gpio.txt |  37 ++++
 drivers/gpio/gpio-uclass.c                |   6 +-
 drivers/i2c/Kconfig                       |  26 ++-
 drivers/i2c/Makefile                      |   1 +
 drivers/i2c/i2c-gpio.c                    | 353 ++++++++++++++++++++++++++++++
 5 files changed, 408 insertions(+), 15 deletions(-)
 create mode 100644 doc/device-tree-bindings/i2c/i2c-gpio.txt
 create mode 100644 drivers/i2c/i2c-gpio.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V2 1/3] dm: gpio: request list: return the count if requests max_count reached
  2015-03-27 17:33 ` [U-Boot] [PATCH V2 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
@ 2015-03-27 17:33   ` Przemyslaw Marczak
  2015-03-28 15:04     ` Simon Glass
  2015-03-27 17:33   ` [U-Boot] [PATCH V2 2/3] Kconfig: i2c: fix help message related to dm i2c Przemyslaw Marczak
  2015-03-27 17:33   ` [U-Boot] [PATCH V2 3/3] dm: i2c: add i2c-gpio driver Przemyslaw Marczak
  2 siblings, 1 reply; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-27 17:33 UTC (permalink / raw)
  To: u-boot

The function gpio_request_list_by_name_nodev() returned -ENOSPC error,
when the loop count was greater than requested count. This was wrong,
because function should return the requested gpio count, when meets
the call request without errors. Now, the loop ends on requested
max_count.

Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
Cc: Simon Glass <sjg@chromium.org>
---
 drivers/gpio/gpio-uclass.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index a69bbd2..4b63025 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -590,11 +590,7 @@ int gpio_request_list_by_name_nodev(const void *blob, int node,
 	int count;
 	int ret;
 
-	for (count = 0; ; count++) {
-		if (count >= max_count) {
-			ret = -ENOSPC;
-			goto err;
-		}
+	for (count = 0; count < max_count; count++) {
 		ret = _gpio_request_by_name_nodev(blob, node, list_name, count,
 						  &desc[count], flags, true);
 		if (ret == -ENOENT)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V2 2/3] Kconfig: i2c: fix help message related to dm i2c
  2015-03-27 17:33 ` [U-Boot] [PATCH V2 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
  2015-03-27 17:33   ` [U-Boot] [PATCH V2 1/3] dm: gpio: request list: return the count if requests max_count reached Przemyslaw Marczak
@ 2015-03-27 17:33   ` Przemyslaw Marczak
  2015-03-28 15:08     ` Simon Glass
  2015-03-27 17:33   ` [U-Boot] [PATCH V2 3/3] dm: i2c: add i2c-gpio driver Przemyslaw Marczak
  2 siblings, 1 reply; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-27 17:33 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Simon Glass <sjg@chromium.org>
Cc: Heiko Schocher <hs@denx.de>

Changes V2:
- add i2c uclass description
---
 drivers/i2c/Kconfig | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 692810d..979522f 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -2,16 +2,13 @@ config DM_I2C
 	bool "Enable Driver Model for I2C drivers"
 	depends on DM
 	help
-	  Enable driver model for I2C. This SPI flash interface
-	  (spi_flash_probe(), spi_flash_write(), etc.) is then
-	  implemented by the SPI flash uclass. There is one standard
-	  SPI flash driver which knows how to probe most chips
-	  supported by U-Boot. The uclass interface is defined in
-	  include/spi_flash.h, but is currently fully compatible
-	  with the old interface to avoid confusion and duplication
-	  during the transition parent. SPI and SPI flash must be
-	  enabled together (it is not possible to use driver model
-	  for one and not the other).
+	  Enable driver model for I2C. The I2C uclass interface: probe, read,
+	  write or speed, is implemented with the bus drivers uclass operations,
+	  which provides methods for bus setting and data transfer. Each chip
+	  device (bus child) info is kept as parent platdata. The interface is
+	  defined in include/i2c.h. When i2c bus driver supports the i2c uclass,
+	  but the device drivers not, then DM_I2C_COMPAT config can be used as
+	  compatibility layer.
 
 config DM_I2C_COMPAT
 	bool "Enable I2C compatibility layer"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V2 3/3] dm: i2c: add i2c-gpio driver
  2015-03-27 17:33 ` [U-Boot] [PATCH V2 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
  2015-03-27 17:33   ` [U-Boot] [PATCH V2 1/3] dm: gpio: request list: return the count if requests max_count reached Przemyslaw Marczak
  2015-03-27 17:33   ` [U-Boot] [PATCH V2 2/3] Kconfig: i2c: fix help message related to dm i2c Przemyslaw Marczak
@ 2015-03-27 17:33   ` Przemyslaw Marczak
  2015-03-28 15:08     ` Simon Glass
  2 siblings, 1 reply; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-27 17:33 UTC (permalink / raw)
  To: u-boot

This commit adds driver model support to software emulated i2c bus driver.
The device-tree node is compatible with the kernel i2c-gpio driver. It means,
that boards device-tree "i2c-gpio" node, should be the same as in the kernel.
For operating, it requires proper compatible and gpio pins dts description.
Added:
- Config: CONFIG_DM_I2C_GPIO
- File: drivers/i2c/i2c-gpio.c
- File: doc/device-tree-bindings/i2c/i2c-gpio.txt

Driver base code is taken from: drivers/i2c/soft-i2c.c, changes:
- update comments style,
- move preprocesor macros into functions,
- add device-tree support,
- add driver model i2c support.
- add Kconfig entry

Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
CC: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Lukasz Majewski <l.majewski@samsung.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Simon Glass <sjg@chromium.org>
Cc: Heiko Schocher <hs@denx.de>

Changes V2:
- new file for software i2c driver: i2c-gpio.c
- update driver naming: use of "i2c-gpio"
- add full compatibility with the kernels device-tree "i2c-gpio" node
- fix Kconfig entry
---
 doc/device-tree-bindings/i2c/i2c-gpio.txt |  37 ++++
 drivers/i2c/Kconfig                       |   9 +
 drivers/i2c/Makefile                      |   1 +
 drivers/i2c/i2c-gpio.c                    | 353 ++++++++++++++++++++++++++++++
 4 files changed, 400 insertions(+)
 create mode 100644 doc/device-tree-bindings/i2c/i2c-gpio.txt
 create mode 100644 drivers/i2c/i2c-gpio.c

diff --git a/doc/device-tree-bindings/i2c/i2c-gpio.txt b/doc/device-tree-bindings/i2c/i2c-gpio.txt
new file mode 100644
index 0000000..3978381
--- /dev/null
+++ b/doc/device-tree-bindings/i2c/i2c-gpio.txt
@@ -0,0 +1,37 @@
+I2C gpio device binding
+=======================
+
+Driver:
+- drivers/i2c/i2c-gpio.c
+
+Software i2c device-tree node properties:
+Required:
+* #address-cells = <1>;
+* #size-cells = <0>;
+* compatible = "i2c-gpio";
+* gpios = <sda ...>, <scl ...>;
+
+Optional:
+* i2c-gpio,delay-us = <5>;
+   The resulting transfer speed can be adjusted by setting the delay[us]
+   between gpio-toggle operations. Speed [Hz] = 1us / 4 * udelay,
+   It not defined, then default is 5us (~50KHz).
+
+Example:
+
+i2c-gpio at 1 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	compatible = "i2c-gpio";
+	gpios = <&gpd1 0 GPIO_ACTIVE_HIGH>, /* SDA */
+		<&gpd1 1 GPIO_ACTIVE_HIGH>; /* CLK */
+
+	i2c-gpio,delay-us = <5>;
+
+	some_device at 5 {
+		compatible = "some_device";
+		reg = <0x5>;
+		...
+	};
+};
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 979522f..22e4a7c 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -19,6 +19,15 @@ config DM_I2C_COMPAT
 	  to convert all code for a board in a single commit. It should not
 	  be enabled for any board in an official release.
 
+config DM_I2C_GPIO
+	bool "Enable Driver Model for software emulated I2C bus driver"
+	depends on DM_I2C && DM_GPIO
+	help
+	  Enable the i2c bus driver emulation by using the GPIO.
+	  The bus gpio configuration is given by the device-tree.
+	  Kernel style device-tree node for i2c-gpio is supported.
+	  Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
+
 config SYS_I2C_UNIPHIER
 	bool "UniPhier I2C driver"
 	depends on ARCH_UNIPHIER && DM_I2C
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 774bc94..d9e9f3a 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -6,6 +6,7 @@
 #
 obj-$(CONFIG_DM_I2C) += i2c-uclass.o
 obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
+obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o
 
 obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
 obj-$(CONFIG_I2C_MV) += mv_i2c.o
diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
new file mode 100644
index 0000000..8e9ed6b
--- /dev/null
+++ b/drivers/i2c/i2c-gpio.c
@@ -0,0 +1,353 @@
+/*
+ * (C) Copyright 2015, Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ * Add driver-model support as a separated driver file
+ *
+ * (C) Copyright 2009
+ * Heiko Schocher, DENX Software Engineering, hs at denx.de.
+ * Changes for multibus/multiadapter I2C support.
+ *
+ * (C) Copyright 2001, 2002
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * This has been changed substantially by Gerald Van Baren, Custom IDEAS,
+ * vanbaren at cideas.com.  It was heavily influenced by LiMon, written by
+ * Neil Russell.
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <div64.h>
+#include <asm/gpio.h>
+
+#define DEFAULT_UDELAY	5
+#define RETRIES		0
+#define I2C_ACK		0
+#define I2C_NOACK	1
+
+#ifdef DEBUG_I2C
+#define PRINTD(fmt, args...)	do {	\
+		printf (fmt, ##args);	\
+	} while (0)
+#else
+#define PRINTD(fmt, args...)
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+	PIN_SDA = 0,
+	PIN_SCL,
+};
+
+struct i2c_gpio_bus {
+	unsigned int speed;
+	unsigned long udelay;
+	struct gpio_desc gpios[2]; /* sda, scl */
+};
+
+/* Local functions */
+static void send_reset(struct gpio_desc *, struct gpio_desc *, int);
+static void send_start(struct gpio_desc *, struct gpio_desc *, int);
+static void send_stop(struct gpio_desc *, struct gpio_desc *, int);
+static void send_ack(struct gpio_desc *, struct gpio_desc *, int, int);
+static int write_byte(struct gpio_desc *, struct gpio_desc *, int, uchar);
+static uchar read_byte(struct gpio_desc *, struct gpio_desc *, int, int);
+
+static int I2C_READ(struct gpio_desc *sda)
+{
+	return dm_gpio_get_value(sda);
+}
+
+static void I2C_SDA(struct gpio_desc *sda, int bit)
+{
+	if (bit) {
+		dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);
+	} else {
+		dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
+		dm_gpio_set_value(sda, 0);
+	}
+}
+
+static void I2C_SCL(struct gpio_desc *scl, int bit)
+{
+	dm_gpio_set_dir_flags(scl, GPIOD_IS_OUT);
+	dm_gpio_set_value(scl, bit);
+}
+
+static void I2C_DELAY(unsigned long us)
+{
+	udelay(us);	/* 1/4 I2C clock duration */
+}
+
+/**
+ * Send a reset sequence consisting of 9 clocks with the data signal high
+ * to clock any confused device back into an idle state.  Also send a
+ * <stop> at the end of the sequence for belts & suspenders.
+ */
+static void send_reset(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
+{
+	int j;
+
+	I2C_SCL(scl, 1);
+	I2C_SDA(sda, 1);
+
+	for (j = 0; j < 9; j++) {
+		I2C_SCL(scl, 0);
+		I2C_DELAY(delay);
+		I2C_DELAY(delay);
+		I2C_SCL(scl, 1);
+		I2C_DELAY(delay);
+		I2C_DELAY(delay);
+	}
+	send_stop(scl, sda, delay);
+}
+
+/* START: High -> Low on SDA while SCL is High */
+static void send_start(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
+{
+	I2C_DELAY(delay);
+	I2C_SDA(sda, 1);
+	I2C_DELAY(delay);
+	I2C_SCL(scl, 1);
+	I2C_DELAY(delay);
+	I2C_SDA(sda, 0);
+	I2C_DELAY(delay);
+}
+
+/* STOP: Low -> High on SDA while SCL is High */
+static void send_stop(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
+{
+	I2C_SCL(scl, 0);
+	I2C_DELAY(delay);
+	I2C_SDA(sda, 0);
+	I2C_DELAY(delay);
+	I2C_SCL(scl, 1);
+	I2C_DELAY(delay);
+	I2C_SDA(sda, 1);
+	I2C_DELAY(delay);
+}
+
+/* ack should be I2C_ACK or I2C_NOACK */
+static void send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
+		     int delay, int ack)
+{
+	I2C_SCL(scl, 0);
+	I2C_DELAY(delay);
+	I2C_SDA(sda, ack);
+	I2C_DELAY(delay);
+	I2C_SCL(scl, 1);
+	I2C_DELAY(delay);
+	I2C_DELAY(delay);
+	I2C_SCL(scl, 0);
+	I2C_DELAY(delay);
+}
+
+/* Send 8 bits and look for an acknowledgement */
+static int write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
+		      int delay, uchar data)
+{
+	int j;
+	int nack;
+
+	for (j = 0; j < 8; j++) {
+		I2C_SCL(scl, 0);
+		I2C_DELAY(delay);
+		I2C_SDA(sda, data & 0x80);
+		I2C_DELAY(delay);
+		I2C_SCL(scl, 1);
+		I2C_DELAY(delay);
+		I2C_DELAY(delay);
+
+		data <<= 1;
+	}
+
+	/* Look for an <ACK>(negative logic) and return it */
+	I2C_SCL(scl, 0);
+	I2C_DELAY(delay);
+	I2C_SDA(sda, 1);
+	I2C_DELAY(delay);
+	I2C_SCL(scl, 1);
+	I2C_DELAY(delay);
+	I2C_DELAY(delay);
+	nack = I2C_READ(sda);
+	I2C_SCL(scl, 0);
+	I2C_DELAY(delay);
+
+	return nack;	/* not a nack is an ack */
+}
+
+/**
+ * if ack == I2C_ACK, ACK the byte so can continue reading, else
+ * send I2C_NOACK to end the read.
+ */
+static uchar read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
+		       int delay, int ack)
+{
+	int  data;
+	int  j;
+
+	/* Read 8 bits, MSB first */
+	I2C_SDA(sda, 1);
+	data = 0;
+	for (j = 0; j < 8; j++) {
+		I2C_SCL(scl, 0);
+		I2C_DELAY(delay);
+		I2C_SCL(scl, 1);
+		I2C_DELAY(delay);
+		data <<= 1;
+		data |= I2C_READ(sda);
+		I2C_DELAY(delay);
+	}
+	send_ack(scl, sda, delay, ack);
+
+	return data;
+}
+
+static int i2c_write_data(struct i2c_gpio_bus *bus, uchar chip,
+			  uchar *buffer, int len, bool end_with_repeated_start)
+{
+	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+	unsigned int delay = bus->udelay;
+	int failures = 0;
+
+	PRINTD("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
+
+	send_start(scl, sda, delay);
+	if (write_byte(scl, sda, delay, chip << 1)) {
+		send_stop(scl, sda, delay);
+		PRINTD("i2c_write, no chip responded %02X\n", chip);
+		return -EIO;
+	}
+
+	while (len-- > 0) {
+		if (write_byte(scl, sda, delay, *buffer++))
+			failures++;
+	}
+
+	send_stop(scl, sda, delay);
+
+	return failures;
+}
+
+static int i2c_read_data(struct i2c_gpio_bus *bus, uchar chip,
+			 uchar *buffer, int len)
+{
+	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+	unsigned int delay = bus->udelay;
+
+	PRINTD("%s: chip %x buffer: %x len %d\n", __func__, chip, buffer, len);
+
+	send_start(scl, sda, delay);
+	write_byte(scl, sda, delay, (chip << 1) | 1);	/* read cycle */
+
+	while (len-- > 0)
+		*buffer++ = read_byte(scl, sda, delay, len == 0);
+
+	send_stop(scl, sda, delay);
+
+	return 0;
+}
+
+static int i2c_gpio_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+	struct i2c_gpio_bus *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(bus, msg->addr, msg->buf, msg->len);
+		else
+			ret = i2c_write_data(bus, msg->addr, msg->buf, msg->len,
+					     next_is_read);
+
+		if (ret)
+			return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags)
+{
+	struct i2c_gpio_bus *bus = dev_get_priv(dev);
+	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+	unsigned int delay = bus->udelay;
+	int ret;
+
+	send_start(scl, sda, delay);
+	ret = write_byte(scl, sda, delay, (chip << 1) | 0);
+	send_stop(scl, sda, delay);
+
+	PRINTD("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
+	       __func__, dev->seq, dev->name, chip, chip_flags, ret);
+
+	return ret;
+}
+
+static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed)
+{
+	struct i2c_gpio_bus *bus = dev_get_priv(dev);
+	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+
+	bus->speed = speed;
+	bus->udelay = lldiv(1000000, speed << 2);
+
+	send_reset(scl, sda, bus->udelay);
+
+	PRINTD("%s: bus: %d (%s) speed: %u Hz (1/4 of period: %lu us)\n",
+	       __func__, dev->seq, dev->name, speed, bus->udelay);
+
+	return 0;
+}
+
+static int i2c_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+	struct i2c_gpio_bus *bus = dev_get_priv(dev);
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
+	int ret;
+
+	ret = gpio_request_list_by_name(dev, "gpios", bus->gpios,
+					ARRAY_SIZE(bus->gpios), 0);
+	if (ret < 0)
+		goto error;
+
+	bus->udelay = fdtdec_get_int(blob, node, "i2c-gpio,delay-us",
+				     DEFAULT_UDELAY);
+
+	PRINTD("%s: bus: %d (%s) fdt node ok\n", __func__, dev->seq, dev->name);
+
+	return 0;
+error:
+	error("Can't get %s gpios! Error: %d", dev->name, ret);
+	return ret;
+}
+
+static const struct dm_i2c_ops i2c_gpio_ops = {
+	.xfer		= i2c_gpio_xfer,
+	.probe_chip	= i2c_gpio_probe,
+	.set_bus_speed	= i2c_gpio_set_bus_speed,
+};
+
+static const struct udevice_id i2c_gpio_ids[] = {
+	{ .compatible = "i2c-gpio" },
+	{ }
+};
+
+U_BOOT_DRIVER(i2c_gpio) = {
+	.name	= "i2c-gpio",
+	.id	= UCLASS_I2C,
+	.of_match = i2c_gpio_ids,
+	.ofdata_to_platdata = i2c_gpio_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct i2c_gpio_bus),
+	.ops	= &i2c_gpio_ops,
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V2 1/3] dm: gpio: request list: return the count if requests max_count reached
  2015-03-27 17:33   ` [U-Boot] [PATCH V2 1/3] dm: gpio: request list: return the count if requests max_count reached Przemyslaw Marczak
@ 2015-03-28 15:04     ` Simon Glass
  0 siblings, 0 replies; 36+ messages in thread
From: Simon Glass @ 2015-03-28 15:04 UTC (permalink / raw)
  To: u-boot

On 27 March 2015 at 11:33, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
>
> The function gpio_request_list_by_name_nodev() returned -ENOSPC error,
> when the loop count was greater than requested count. This was wrong,
> because function should return the requested gpio count, when meets
> the call request without errors. Now, the loop ends on requested
> max_count.
>
> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> Cc: Simon Glass <sjg@chromium.org>
> ---
>  drivers/gpio/gpio-uclass.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)

Acked-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V2 2/3] Kconfig: i2c: fix help message related to dm i2c
  2015-03-27 17:33   ` [U-Boot] [PATCH V2 2/3] Kconfig: i2c: fix help message related to dm i2c Przemyslaw Marczak
@ 2015-03-28 15:08     ` Simon Glass
  2015-03-31 15:57       ` Przemyslaw Marczak
  0 siblings, 1 reply; 36+ messages in thread
From: Simon Glass @ 2015-03-28 15:08 UTC (permalink / raw)
  To: u-boot

Hi Przemyslaw,

On 27 March 2015 at 11:33, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
> Cc: Mike Frysinger <vapier@gentoo.org>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Heiko Schocher <hs@denx.de>
>
> Changes V2:
> - add i2c uclass description
> ---
>  drivers/i2c/Kconfig | 17 +++++++----------
>  1 file changed, 7 insertions(+), 10 deletions(-)

Acked-by: Simon Glass <sjg@chromium.org>

(see nit below)

>
> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
> index 692810d..979522f 100644
> --- a/drivers/i2c/Kconfig
> +++ b/drivers/i2c/Kconfig
> @@ -2,16 +2,13 @@ config DM_I2C
>         bool "Enable Driver Model for I2C drivers"
>         depends on DM
>         help
> -         Enable driver model for I2C. This SPI flash interface
> -         (spi_flash_probe(), spi_flash_write(), etc.) is then
> -         implemented by the SPI flash uclass. There is one standard
> -         SPI flash driver which knows how to probe most chips
> -         supported by U-Boot. The uclass interface is defined in
> -         include/spi_flash.h, but is currently fully compatible
> -         with the old interface to avoid confusion and duplication
> -         during the transition parent. SPI and SPI flash must be
> -         enabled together (it is not possible to use driver model
> -         for one and not the other).
> +         Enable driver model for I2C. The I2C uclass interface: probe, read,
> +         write or speed, is implemented with the bus drivers uclass operations,
> +         which provides methods for bus setting and data transfer. Each chip

Can we tweak this a bit?

         write and speed, is implemented with the bus drivers' operations,
         which provide methods for bus setting and data transfer. Each chip


> +         device (bus child) info is kept as parent platdata. The interface is
> +         defined in include/i2c.h. When i2c bus driver supports the i2c uclass,
> +         but the device drivers not, then DM_I2C_COMPAT config can be used as
> +         compatibility layer.
>
>  config DM_I2C_COMPAT
>         bool "Enable I2C compatibility layer"
> --
> 1.9.1
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V2 3/3] dm: i2c: add i2c-gpio driver
  2015-03-27 17:33   ` [U-Boot] [PATCH V2 3/3] dm: i2c: add i2c-gpio driver Przemyslaw Marczak
@ 2015-03-28 15:08     ` Simon Glass
  2015-03-31 15:58       ` Przemyslaw Marczak
  0 siblings, 1 reply; 36+ messages in thread
From: Simon Glass @ 2015-03-28 15:08 UTC (permalink / raw)
  To: u-boot

Hi Przemyslaw,

On 27 March 2015 at 11:33, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
> This commit adds driver model support to software emulated i2c bus driver.
> The device-tree node is compatible with the kernel i2c-gpio driver. It means,
> that boards device-tree "i2c-gpio" node, should be the same as in the kernel.
> For operating, it requires proper compatible and gpio pins dts description.
> Added:
> - Config: CONFIG_DM_I2C_GPIO
> - File: drivers/i2c/i2c-gpio.c
> - File: doc/device-tree-bindings/i2c/i2c-gpio.txt
>
> Driver base code is taken from: drivers/i2c/soft-i2c.c, changes:
> - update comments style,
> - move preprocesor macros into functions,
> - add device-tree support,
> - add driver model i2c support.
> - add Kconfig entry
>
> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> CC: Masahiro Yamada <yamada.masahiro@socionext.com>
> Cc: Lukasz Majewski <l.majewski@samsung.com>
> Cc: Mike Frysinger <vapier@gentoo.org>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Heiko Schocher <hs@denx.de>
>
> Changes V2:
> - new file for software i2c driver: i2c-gpio.c
> - update driver naming: use of "i2c-gpio"
> - add full compatibility with the kernels device-tree "i2c-gpio" node
> - fix Kconfig entry

Sorry I still have a few more comments.

> ---
>  doc/device-tree-bindings/i2c/i2c-gpio.txt |  37 ++++
>  drivers/i2c/Kconfig                       |   9 +
>  drivers/i2c/Makefile                      |   1 +
>  drivers/i2c/i2c-gpio.c                    | 353 ++++++++++++++++++++++++++++++
>  4 files changed, 400 insertions(+)
>  create mode 100644 doc/device-tree-bindings/i2c/i2c-gpio.txt
>  create mode 100644 drivers/i2c/i2c-gpio.c
>
> diff --git a/doc/device-tree-bindings/i2c/i2c-gpio.txt b/doc/device-tree-bindings/i2c/i2c-gpio.txt
> new file mode 100644
> index 0000000..3978381
> --- /dev/null
> +++ b/doc/device-tree-bindings/i2c/i2c-gpio.txt
> @@ -0,0 +1,37 @@
> +I2C gpio device binding
> +=======================
> +
> +Driver:
> +- drivers/i2c/i2c-gpio.c
> +
> +Software i2c device-tree node properties:
> +Required:
> +* #address-cells = <1>;
> +* #size-cells = <0>;
> +* compatible = "i2c-gpio";
> +* gpios = <sda ...>, <scl ...>;
> +
> +Optional:
> +* i2c-gpio,delay-us = <5>;
> +   The resulting transfer speed can be adjusted by setting the delay[us]
> +   between gpio-toggle operations. Speed [Hz] = 1us / 4 * udelay,
> +   It not defined, then default is 5us (~50KHz).
> +
> +Example:
> +
> +i2c-gpio at 1 {
> +       #address-cells = <1>;
> +       #size-cells = <0>;
> +
> +       compatible = "i2c-gpio";
> +       gpios = <&gpd1 0 GPIO_ACTIVE_HIGH>, /* SDA */
> +               <&gpd1 1 GPIO_ACTIVE_HIGH>; /* CLK */
> +
> +       i2c-gpio,delay-us = <5>;
> +
> +       some_device at 5 {
> +               compatible = "some_device";
> +               reg = <0x5>;
> +               ...
> +       };
> +};
> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
> index 979522f..22e4a7c 100644
> --- a/drivers/i2c/Kconfig
> +++ b/drivers/i2c/Kconfig
> @@ -19,6 +19,15 @@ config DM_I2C_COMPAT
>           to convert all code for a board in a single commit. It should not
>           be enabled for any board in an official release.
>
> +config DM_I2C_GPIO
> +       bool "Enable Driver Model for software emulated I2C bus driver"
> +       depends on DM_I2C && DM_GPIO
> +       help
> +         Enable the i2c bus driver emulation by using the GPIO.

by using GPIOs.

> +         The bus gpio configuration is given by the device-tree.

GPIO

device tree
(no hypen)

> +         Kernel style device-tree node for i2c-gpio is supported.

Kernel-style device tree bindings are supported

> +         Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
> +
>  config SYS_I2C_UNIPHIER
>         bool "UniPhier I2C driver"
>         depends on ARCH_UNIPHIER && DM_I2C
> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
> index 774bc94..d9e9f3a 100644
> --- a/drivers/i2c/Makefile
> +++ b/drivers/i2c/Makefile
> @@ -6,6 +6,7 @@
>  #
>  obj-$(CONFIG_DM_I2C) += i2c-uclass.o
>  obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
> +obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o
>
>  obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
>  obj-$(CONFIG_I2C_MV) += mv_i2c.o
> diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
> new file mode 100644
> index 0000000..8e9ed6b
> --- /dev/null
> +++ b/drivers/i2c/i2c-gpio.c
> @@ -0,0 +1,353 @@
> +/*
> + * (C) Copyright 2015, Samsung Electronics
> + * Przemyslaw Marczak <p.marczak@samsung.com>
> + * Add driver-model support as a separated driver file
> + *
> + * (C) Copyright 2009
> + * Heiko Schocher, DENX Software Engineering, hs at denx.de.
> + * Changes for multibus/multiadapter I2C support.
> + *
> + * (C) Copyright 2001, 2002
> + * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + *
> + * This has been changed substantially by Gerald Van Baren, Custom IDEAS,
> + * vanbaren at cideas.com.  It was heavily influenced by LiMon, written by
> + * Neil Russell.
> + */
> +#include <common.h>
> +#include <errno.h>
> +#include <dm.h>
> +#include <i2c.h>
> +#include <div64.h>
> +#include <asm/gpio.h>
> +
> +#define DEFAULT_UDELAY 5
> +#define RETRIES                0
> +#define I2C_ACK                0
> +#define I2C_NOACK      1
> +
> +#ifdef DEBUG_I2C
> +#define PRINTD(fmt, args...)   do {    \
> +               printf (fmt, ##args);   \
> +       } while (0)
> +#else
> +#define PRINTD(fmt, args...)
> +#endif

I don't see any point in this - how about just using debug() instead?

> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +enum {
> +       PIN_SDA = 0,
> +       PIN_SCL,

PIN_COUNT

> +};
> +

Document these members - speed is in HzHz, udelay is the delay for what?

> +struct i2c_gpio_bus {
> +       unsigned int speed;
> +       unsigned long udelay;
> +       struct gpio_desc gpios[2]; /* sda, scl */

gpios[PIN_COUNT]

> +};
> +
> +/* Local functions */
> +static void send_reset(struct gpio_desc *, struct gpio_desc *, int);
> +static void send_start(struct gpio_desc *, struct gpio_desc *, int);
> +static void send_stop(struct gpio_desc *, struct gpio_desc *, int);
> +static void send_ack(struct gpio_desc *, struct gpio_desc *, int, int);
> +static int write_byte(struct gpio_desc *, struct gpio_desc *, int, uchar);
> +static uchar read_byte(struct gpio_desc *, struct gpio_desc *, int, int);

If you move send_reset() down a bit can you drop these declarations?

> +
> +static int I2C_READ(struct gpio_desc *sda)

Lower case - how about gpio_i2c_read()? Same for others.

> +{
> +       return dm_gpio_get_value(sda);
> +}
> +
> +static void I2C_SDA(struct gpio_desc *sda, int bit)
> +{
> +       if (bit) {
> +               dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);

I assume the polarity is never set, so this should be OK.

> +       } else {
> +               dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
> +               dm_gpio_set_value(sda, 0);
> +       }
> +}
> +
> +static void I2C_SCL(struct gpio_desc *scl, int bit)
> +{
> +       dm_gpio_set_dir_flags(scl, GPIOD_IS_OUT);
> +       dm_gpio_set_value(scl, bit);
> +}
> +
> +static void I2C_DELAY(unsigned long us)
> +{
> +       udelay(us);     /* 1/4 I2C clock duration */
> +}
> +
> +/**
> + * Send a reset sequence consisting of 9 clocks with the data signal high
> + * to clock any confused device back into an idle state.  Also send a
> + * <stop> at the end of the sequence for belts & suspenders.
> + */
> +static void send_reset(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
> +{
> +       int j;
> +
> +       I2C_SCL(scl, 1);
> +       I2C_SDA(sda, 1);
> +
> +       for (j = 0; j < 9; j++) {
> +               I2C_SCL(scl, 0);
> +               I2C_DELAY(delay);
> +               I2C_DELAY(delay);
> +               I2C_SCL(scl, 1);
> +               I2C_DELAY(delay);
> +               I2C_DELAY(delay);

I wonder why we don't do one call with delay * 2?

> +       }
> +       send_stop(scl, sda, delay);
> +}
> +
> +/* START: High -> Low on SDA while SCL is High */
> +static void send_start(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
> +{
> +       I2C_DELAY(delay);
> +       I2C_SDA(sda, 1);
> +       I2C_DELAY(delay);
> +       I2C_SCL(scl, 1);
> +       I2C_DELAY(delay);
> +       I2C_SDA(sda, 0);
> +       I2C_DELAY(delay);
> +}
> +
> +/* STOP: Low -> High on SDA while SCL is High */
> +static void send_stop(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
> +{
> +       I2C_SCL(scl, 0);
> +       I2C_DELAY(delay);
> +       I2C_SDA(sda, 0);
> +       I2C_DELAY(delay);
> +       I2C_SCL(scl, 1);
> +       I2C_DELAY(delay);
> +       I2C_SDA(sda, 1);
> +       I2C_DELAY(delay);
> +}
> +
> +/* ack should be I2C_ACK or I2C_NOACK */
> +static void send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
> +                    int delay, int ack)
> +{
> +       I2C_SCL(scl, 0);
> +       I2C_DELAY(delay);
> +       I2C_SDA(sda, ack);
> +       I2C_DELAY(delay);
> +       I2C_SCL(scl, 1);
> +       I2C_DELAY(delay);
> +       I2C_DELAY(delay);
> +       I2C_SCL(scl, 0);
> +       I2C_DELAY(delay);
> +}
> +
> +/* Send 8 bits and look for an acknowledgement */
> +static int write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
> +                     int delay, uchar data)
> +{
> +       int j;
> +       int nack;
> +
> +       for (j = 0; j < 8; j++) {
> +               I2C_SCL(scl, 0);
> +               I2C_DELAY(delay);
> +               I2C_SDA(sda, data & 0x80);
> +               I2C_DELAY(delay);
> +               I2C_SCL(scl, 1);
> +               I2C_DELAY(delay);
> +               I2C_DELAY(delay);

This sequence of 7 calls appears a lot in this code. Could it go in a
function and be called from various places?

> +
> +               data <<= 1;
> +       }
> +
> +       /* Look for an <ACK>(negative logic) and return it */
> +       I2C_SCL(scl, 0);
> +       I2C_DELAY(delay);
> +       I2C_SDA(sda, 1);
> +       I2C_DELAY(delay);
> +       I2C_SCL(scl, 1);
> +       I2C_DELAY(delay);
> +       I2C_DELAY(delay);
> +       nack = I2C_READ(sda);
> +       I2C_SCL(scl, 0);
> +       I2C_DELAY(delay);
> +
> +       return nack;    /* not a nack is an ack */
> +}
> +
> +/**
> + * if ack == I2C_ACK, ACK the byte so can continue reading, else
> + * send I2C_NOACK to end the read.
> + */
> +static uchar read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
> +                      int delay, int ack)
> +{
> +       int  data;
> +       int  j;
> +
> +       /* Read 8 bits, MSB first */
> +       I2C_SDA(sda, 1);
> +       data = 0;
> +       for (j = 0; j < 8; j++) {
> +               I2C_SCL(scl, 0);
> +               I2C_DELAY(delay);
> +               I2C_SCL(scl, 1);
> +               I2C_DELAY(delay);
> +               data <<= 1;
> +               data |= I2C_READ(sda);
> +               I2C_DELAY(delay);
> +       }
> +       send_ack(scl, sda, delay, ack);
> +
> +       return data;
> +}
> +
> +static int i2c_write_data(struct i2c_gpio_bus *bus, uchar chip,
> +                         uchar *buffer, int len, bool end_with_repeated_start)
> +{
> +       struct gpio_desc *scl = &bus->gpios[PIN_SCL];
> +       struct gpio_desc *sda = &bus->gpios[PIN_SDA];
> +       unsigned int delay = bus->udelay;
> +       int failures = 0;
> +
> +       PRINTD("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
> +
> +       send_start(scl, sda, delay);
> +       if (write_byte(scl, sda, delay, chip << 1)) {
> +               send_stop(scl, sda, delay);
> +               PRINTD("i2c_write, no chip responded %02X\n", chip);
> +               return -EIO;
> +       }
> +
> +       while (len-- > 0) {
> +               if (write_byte(scl, sda, delay, *buffer++))
> +                       failures++;
> +       }
> +
> +       send_stop(scl, sda, delay);
> +
> +       return failures;
> +}
> +
> +static int i2c_read_data(struct i2c_gpio_bus *bus, uchar chip,
> +                        uchar *buffer, int len)
> +{
> +       struct gpio_desc *scl = &bus->gpios[PIN_SCL];
> +       struct gpio_desc *sda = &bus->gpios[PIN_SDA];
> +       unsigned int delay = bus->udelay;
> +
> +       PRINTD("%s: chip %x buffer: %x len %d\n", __func__, chip, buffer, len);
> +
> +       send_start(scl, sda, delay);
> +       write_byte(scl, sda, delay, (chip << 1) | 1);   /* read cycle */
> +
> +       while (len-- > 0)
> +               *buffer++ = read_byte(scl, sda, delay, len == 0);
> +
> +       send_stop(scl, sda, delay);
> +
> +       return 0;
> +}
> +
> +static int i2c_gpio_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
> +{
> +       struct i2c_gpio_bus *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(bus, msg->addr, msg->buf, msg->len);
> +               else
> +                       ret = i2c_write_data(bus, msg->addr, msg->buf, msg->len,
> +                                            next_is_read);
> +
> +               if (ret)
> +                       return -EREMOTEIO;
> +       }
> +
> +       return 0;
> +}
> +
> +static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags)
> +{
> +       struct i2c_gpio_bus *bus = dev_get_priv(dev);
> +       struct gpio_desc *scl = &bus->gpios[PIN_SCL];
> +       struct gpio_desc *sda = &bus->gpios[PIN_SDA];
> +       unsigned int delay = bus->udelay;
> +       int ret;
> +
> +       send_start(scl, sda, delay);
> +       ret = write_byte(scl, sda, delay, (chip << 1) | 0);
> +       send_stop(scl, sda, delay);
> +
> +       PRINTD("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
> +              __func__, dev->seq, dev->name, chip, chip_flags, ret);
> +
> +       return ret;
> +}
> +
> +static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed)
> +{
> +       struct i2c_gpio_bus *bus = dev_get_priv(dev);
> +       struct gpio_desc *scl = &bus->gpios[PIN_SCL];
> +       struct gpio_desc *sda = &bus->gpios[PIN_SDA];
> +
> +       bus->speed = speed;
> +       bus->udelay = lldiv(1000000, speed << 2);

Why lldiv() if the value can never be >100,000? Can we just use normal division?

> +
> +       send_reset(scl, sda, bus->udelay);
> +
> +       PRINTD("%s: bus: %d (%s) speed: %u Hz (1/4 of period: %lu us)\n",
> +              __func__, dev->seq, dev->name, speed, bus->udelay);
> +
> +       return 0;
> +}
> +
> +static int i2c_gpio_ofdata_to_platdata(struct udevice *dev)
> +{
> +       struct i2c_gpio_bus *bus = dev_get_priv(dev);
> +       const void *blob = gd->fdt_blob;
> +       int node = dev->of_offset;
> +       int ret;
> +
> +       ret = gpio_request_list_by_name(dev, "gpios", bus->gpios,
> +                                       ARRAY_SIZE(bus->gpios), 0);
> +       if (ret < 0)
> +               goto error;
> +
> +       bus->udelay = fdtdec_get_int(blob, node, "i2c-gpio,delay-us",
> +                                    DEFAULT_UDELAY);
> +
> +       PRINTD("%s: bus: %d (%s) fdt node ok\n", __func__, dev->seq, dev->name);
> +
> +       return 0;
> +error:
> +       error("Can't get %s gpios! Error: %d", dev->name, ret);
> +       return ret;
> +}
> +
> +static const struct dm_i2c_ops i2c_gpio_ops = {
> +       .xfer           = i2c_gpio_xfer,
> +       .probe_chip     = i2c_gpio_probe,
> +       .set_bus_speed  = i2c_gpio_set_bus_speed,
> +};
> +
> +static const struct udevice_id i2c_gpio_ids[] = {
> +       { .compatible = "i2c-gpio" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(i2c_gpio) = {
> +       .name   = "i2c-gpio",
> +       .id     = UCLASS_I2C,
> +       .of_match = i2c_gpio_ids,
> +       .ofdata_to_platdata = i2c_gpio_ofdata_to_platdata,
> +       .priv_auto_alloc_size = sizeof(struct i2c_gpio_bus),
> +       .ops    = &i2c_gpio_ops,
> +};
> --
> 1.9.1
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V2 2/3] Kconfig: i2c: fix help message related to dm i2c
  2015-03-28 15:08     ` Simon Glass
@ 2015-03-31 15:57       ` Przemyslaw Marczak
  0 siblings, 0 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-31 15:57 UTC (permalink / raw)
  To: u-boot

Hello Simon,

On 03/28/2015 04:08 PM, Simon Glass wrote:
> Hi Przemyslaw,
>
> On 27 March 2015 at 11:33, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
>> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
>> Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
>> Cc: Mike Frysinger <vapier@gentoo.org>
>> Cc: Simon Glass <sjg@chromium.org>
>> Cc: Heiko Schocher <hs@denx.de>
>>
>> Changes V2:
>> - add i2c uclass description
>> ---
>>   drivers/i2c/Kconfig | 17 +++++++----------
>>   1 file changed, 7 insertions(+), 10 deletions(-)
>
> Acked-by: Simon Glass <sjg@chromium.org>
>
> (see nit below)
>
>>
>> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
>> index 692810d..979522f 100644
>> --- a/drivers/i2c/Kconfig
>> +++ b/drivers/i2c/Kconfig
>> @@ -2,16 +2,13 @@ config DM_I2C
>>          bool "Enable Driver Model for I2C drivers"
>>          depends on DM
>>          help
>> -         Enable driver model for I2C. This SPI flash interface
>> -         (spi_flash_probe(), spi_flash_write(), etc.) is then
>> -         implemented by the SPI flash uclass. There is one standard
>> -         SPI flash driver which knows how to probe most chips
>> -         supported by U-Boot. The uclass interface is defined in
>> -         include/spi_flash.h, but is currently fully compatible
>> -         with the old interface to avoid confusion and duplication
>> -         during the transition parent. SPI and SPI flash must be
>> -         enabled together (it is not possible to use driver model
>> -         for one and not the other).
>> +         Enable driver model for I2C. The I2C uclass interface: probe, read,
>> +         write or speed, is implemented with the bus drivers uclass operations,
>> +         which provides methods for bus setting and data transfer. Each chip
>
> Can we tweak this a bit?
>
>           write and speed, is implemented with the bus drivers' operations,
>           which provide methods for bus setting and data transfer. Each chip
>
>

Ok, will corrent this.

>> +         device (bus child) info is kept as parent platdata. The interface is
>> +         defined in include/i2c.h. When i2c bus driver supports the i2c uclass,
>> +         but the device drivers not, then DM_I2C_COMPAT config can be used as
>> +         compatibility layer.
>>
>>   config DM_I2C_COMPAT
>>          bool "Enable I2C compatibility layer"
>> --
>> 1.9.1
>>
>
> Regards,
> Simon
>

Best regards,
-- 
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V2 3/3] dm: i2c: add i2c-gpio driver
  2015-03-28 15:08     ` Simon Glass
@ 2015-03-31 15:58       ` Przemyslaw Marczak
  0 siblings, 0 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-31 15:58 UTC (permalink / raw)
  To: u-boot

Hello Simon,

On 03/28/2015 04:08 PM, Simon Glass wrote:
> Hi Przemyslaw,
>
> On 27 March 2015 at 11:33, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
>> This commit adds driver model support to software emulated i2c bus driver.
>> The device-tree node is compatible with the kernel i2c-gpio driver. It means,
>> that boards device-tree "i2c-gpio" node, should be the same as in the kernel.
>> For operating, it requires proper compatible and gpio pins dts description.
>> Added:
>> - Config: CONFIG_DM_I2C_GPIO
>> - File: drivers/i2c/i2c-gpio.c
>> - File: doc/device-tree-bindings/i2c/i2c-gpio.txt
>>
>> Driver base code is taken from: drivers/i2c/soft-i2c.c, changes:
>> - update comments style,
>> - move preprocesor macros into functions,
>> - add device-tree support,
>> - add driver model i2c support.
>> - add Kconfig entry
>>
>> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
>> CC: Masahiro Yamada <yamada.masahiro@socionext.com>
>> Cc: Lukasz Majewski <l.majewski@samsung.com>
>> Cc: Mike Frysinger <vapier@gentoo.org>
>> Cc: Simon Glass <sjg@chromium.org>
>> Cc: Heiko Schocher <hs@denx.de>
>>
>> Changes V2:
>> - new file for software i2c driver: i2c-gpio.c
>> - update driver naming: use of "i2c-gpio"
>> - add full compatibility with the kernels device-tree "i2c-gpio" node
>> - fix Kconfig entry
>
> Sorry I still have a few more comments.
>

OK, this is the purpose of this list:)

>> ---
>>   doc/device-tree-bindings/i2c/i2c-gpio.txt |  37 ++++
>>   drivers/i2c/Kconfig                       |   9 +
>>   drivers/i2c/Makefile                      |   1 +
>>   drivers/i2c/i2c-gpio.c                    | 353 ++++++++++++++++++++++++++++++
>>   4 files changed, 400 insertions(+)
>>   create mode 100644 doc/device-tree-bindings/i2c/i2c-gpio.txt
>>   create mode 100644 drivers/i2c/i2c-gpio.c
>>
>> diff --git a/doc/device-tree-bindings/i2c/i2c-gpio.txt b/doc/device-tree-bindings/i2c/i2c-gpio.txt
>> new file mode 100644
>> index 0000000..3978381
>> --- /dev/null
>> +++ b/doc/device-tree-bindings/i2c/i2c-gpio.txt
>> @@ -0,0 +1,37 @@
>> +I2C gpio device binding
>> +=======================
>> +
>> +Driver:
>> +- drivers/i2c/i2c-gpio.c
>> +
>> +Software i2c device-tree node properties:
>> +Required:
>> +* #address-cells = <1>;
>> +* #size-cells = <0>;
>> +* compatible = "i2c-gpio";
>> +* gpios = <sda ...>, <scl ...>;
>> +
>> +Optional:
>> +* i2c-gpio,delay-us = <5>;
>> +   The resulting transfer speed can be adjusted by setting the delay[us]
>> +   between gpio-toggle operations. Speed [Hz] = 1us / 4 * udelay,
>> +   It not defined, then default is 5us (~50KHz).
>> +
>> +Example:
>> +
>> +i2c-gpio at 1 {
>> +       #address-cells = <1>;
>> +       #size-cells = <0>;
>> +
>> +       compatible = "i2c-gpio";
>> +       gpios = <&gpd1 0 GPIO_ACTIVE_HIGH>, /* SDA */
>> +               <&gpd1 1 GPIO_ACTIVE_HIGH>; /* CLK */
>> +
>> +       i2c-gpio,delay-us = <5>;
>> +
>> +       some_device at 5 {
>> +               compatible = "some_device";
>> +               reg = <0x5>;
>> +               ...
>> +       };
>> +};
>> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
>> index 979522f..22e4a7c 100644
>> --- a/drivers/i2c/Kconfig
>> +++ b/drivers/i2c/Kconfig
>> @@ -19,6 +19,15 @@ config DM_I2C_COMPAT
>>            to convert all code for a board in a single commit. It should not
>>            be enabled for any board in an official release.
>>
>> +config DM_I2C_GPIO
>> +       bool "Enable Driver Model for software emulated I2C bus driver"
>> +       depends on DM_I2C && DM_GPIO
>> +       help
>> +         Enable the i2c bus driver emulation by using the GPIO.
>
> by using GPIOs.
>
>> +         The bus gpio configuration is given by the device-tree.
>
> GPIO
>
> device tree
> (no hypen)
>
>> +         Kernel style device-tree node for i2c-gpio is supported.
>
> Kernel-style device tree bindings are supported
>

Thanks, will fix the all above.

>> +         Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
>> +
>>   config SYS_I2C_UNIPHIER
>>          bool "UniPhier I2C driver"
>>          depends on ARCH_UNIPHIER && DM_I2C
>> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
>> index 774bc94..d9e9f3a 100644
>> --- a/drivers/i2c/Makefile
>> +++ b/drivers/i2c/Makefile
>> @@ -6,6 +6,7 @@
>>   #
>>   obj-$(CONFIG_DM_I2C) += i2c-uclass.o
>>   obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
>> +obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o
>>
>>   obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
>>   obj-$(CONFIG_I2C_MV) += mv_i2c.o
>> diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
>> new file mode 100644
>> index 0000000..8e9ed6b
>> --- /dev/null
>> +++ b/drivers/i2c/i2c-gpio.c
>> @@ -0,0 +1,353 @@
>> +/*
>> + * (C) Copyright 2015, Samsung Electronics
>> + * Przemyslaw Marczak <p.marczak@samsung.com>
>> + * Add driver-model support as a separated driver file
>> + *
>> + * (C) Copyright 2009
>> + * Heiko Schocher, DENX Software Engineering, hs at denx.de.
>> + * Changes for multibus/multiadapter I2C support.
>> + *
>> + * (C) Copyright 2001, 2002
>> + * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
>> + *
>> + * SPDX-License-Identifier:    GPL-2.0+
>> + *
>> + * This has been changed substantially by Gerald Van Baren, Custom IDEAS,
>> + * vanbaren at cideas.com.  It was heavily influenced by LiMon, written by
>> + * Neil Russell.
>> + */
>> +#include <common.h>
>> +#include <errno.h>
>> +#include <dm.h>
>> +#include <i2c.h>
>> +#include <div64.h>
>> +#include <asm/gpio.h>
>> +
>> +#define DEFAULT_UDELAY 5
>> +#define RETRIES                0
>> +#define I2C_ACK                0
>> +#define I2C_NOACK      1
>> +
>> +#ifdef DEBUG_I2C
>> +#define PRINTD(fmt, args...)   do {    \
>> +               printf (fmt, ##args);   \
>> +       } while (0)
>> +#else
>> +#define PRINTD(fmt, args...)
>> +#endif
>
> I don't see any point in this - how about just using debug() instead?
>

Right, will change to debug().

>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +enum {
>> +       PIN_SDA = 0,
>> +       PIN_SCL,
>
> PIN_COUNT
>

Ok

>> +};
>> +
>
> Document these members - speed is in HzHz, udelay is the delay for what?
>

The delay was described in the binding file, I will also add the 
description beside the structure. And I will remove the speed, since 
uclass keeps an info about this.

>> +struct i2c_gpio_bus {
>> +       unsigned int speed;
>> +       unsigned long udelay;
>> +       struct gpio_desc gpios[2]; /* sda, scl */
>
> gpios[PIN_COUNT]
>

Ok.

>> +};
>> +
>> +/* Local functions */
>> +static void send_reset(struct gpio_desc *, struct gpio_desc *, int);
>> +static void send_start(struct gpio_desc *, struct gpio_desc *, int);
>> +static void send_stop(struct gpio_desc *, struct gpio_desc *, int);
>> +static void send_ack(struct gpio_desc *, struct gpio_desc *, int, int);
>> +static int write_byte(struct gpio_desc *, struct gpio_desc *, int, uchar);
>> +static uchar read_byte(struct gpio_desc *, struct gpio_desc *, int, int);
>
> If you move send_reset() down a bit can you drop these declarations?
>
>> +
>> +static int I2C_READ(struct gpio_desc *sda)
>
> Lower case - how about gpio_i2c_read()? Same for others.
>

Ok, will clean this functions.

>> +{
>> +       return dm_gpio_get_value(sda);
>> +}
>> +
>> +static void I2C_SDA(struct gpio_desc *sda, int bit)
>> +{
>> +       if (bit) {
>> +               dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);
>
> I assume the polarity is never set, so this should be OK.
>

Yes, this works fine.

>> +       } else {
>> +               dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
>> +               dm_gpio_set_value(sda, 0);
>> +       }
>> +}
>> +
>> +static void I2C_SCL(struct gpio_desc *scl, int bit)
>> +{
>> +       dm_gpio_set_dir_flags(scl, GPIOD_IS_OUT);
>> +       dm_gpio_set_value(scl, bit);
>> +}
>> +
>> +static void I2C_DELAY(unsigned long us)
>> +{
>> +       udelay(us);     /* 1/4 I2C clock duration */
>> +}
>> +
>> +/**
>> + * Send a reset sequence consisting of 9 clocks with the data signal high
>> + * to clock any confused device back into an idle state.  Also send a
>> + * <stop> at the end of the sequence for belts & suspenders.
>> + */
>> +static void send_reset(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
>> +{
>> +       int j;
>> +
>> +       I2C_SCL(scl, 1);
>> +       I2C_SDA(sda, 1);
>> +
>> +       for (j = 0; j < 9; j++) {
>> +               I2C_SCL(scl, 0);
>> +               I2C_DELAY(delay);
>> +               I2C_DELAY(delay);
>> +               I2C_SCL(scl, 1);
>> +               I2C_DELAY(delay);
>> +               I2C_DELAY(delay);
>
> I wonder why we don't do one call with delay * 2?
>

Right.

>> +       }
>> +       send_stop(scl, sda, delay);
>> +}
>> +
>> +/* START: High -> Low on SDA while SCL is High */
>> +static void send_start(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
>> +{
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 0);
>> +       I2C_DELAY(delay);
>> +}
>> +
>> +/* STOP: Low -> High on SDA while SCL is High */
>> +static void send_stop(struct gpio_desc *scl, struct gpio_desc *sda, int delay)
>> +{
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 1);
>> +       I2C_DELAY(delay);
>> +}
>> +
>> +/* ack should be I2C_ACK or I2C_NOACK */
>> +static void send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
>> +                    int delay, int ack)
>> +{
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, ack);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +}
>> +
>> +/* Send 8 bits and look for an acknowledgement */
>> +static int write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
>> +                     int delay, uchar data)
>> +{
>> +       int j;
>> +       int nack;
>> +
>> +       for (j = 0; j < 8; j++) {
>> +               I2C_SCL(scl, 0);
>> +               I2C_DELAY(delay);
>> +               I2C_SDA(sda, data & 0x80);
>> +               I2C_DELAY(delay);
>> +               I2C_SCL(scl, 1);
>> +               I2C_DELAY(delay);
>> +               I2C_DELAY(delay);
>
> This sequence of 7 calls appears a lot in this code. Could it go in a
> function and be called from various places?
>

Ok, I will clean this.

>> +
>> +               data <<= 1;
>> +       }
>> +
>> +       /* Look for an <ACK>(negative logic) and return it */
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +       I2C_SDA(sda, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_SCL(scl, 1);
>> +       I2C_DELAY(delay);
>> +       I2C_DELAY(delay);
>> +       nack = I2C_READ(sda);
>> +       I2C_SCL(scl, 0);
>> +       I2C_DELAY(delay);
>> +
>> +       return nack;    /* not a nack is an ack */
>> +}
>> +
>> +/**
>> + * if ack == I2C_ACK, ACK the byte so can continue reading, else
>> + * send I2C_NOACK to end the read.
>> + */
>> +static uchar read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
>> +                      int delay, int ack)
>> +{
>> +       int  data;
>> +       int  j;
>> +
>> +       /* Read 8 bits, MSB first */
>> +       I2C_SDA(sda, 1);
>> +       data = 0;
>> +       for (j = 0; j < 8; j++) {
>> +               I2C_SCL(scl, 0);
>> +               I2C_DELAY(delay);
>> +               I2C_SCL(scl, 1);
>> +               I2C_DELAY(delay);
>> +               data <<= 1;
>> +               data |= I2C_READ(sda);
>> +               I2C_DELAY(delay);
>> +       }
>> +       send_ack(scl, sda, delay, ack);
>> +
>> +       return data;
>> +}
>> +
>> +static int i2c_write_data(struct i2c_gpio_bus *bus, uchar chip,
>> +                         uchar *buffer, int len, bool end_with_repeated_start)
>> +{
>> +       struct gpio_desc *scl = &bus->gpios[PIN_SCL];
>> +       struct gpio_desc *sda = &bus->gpios[PIN_SDA];
>> +       unsigned int delay = bus->udelay;
>> +       int failures = 0;
>> +
>> +       PRINTD("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
>> +
>> +       send_start(scl, sda, delay);
>> +       if (write_byte(scl, sda, delay, chip << 1)) {
>> +               send_stop(scl, sda, delay);
>> +               PRINTD("i2c_write, no chip responded %02X\n", chip);
>> +               return -EIO;
>> +       }
>> +
>> +       while (len-- > 0) {
>> +               if (write_byte(scl, sda, delay, *buffer++))
>> +                       failures++;
>> +       }
>> +
>> +       send_stop(scl, sda, delay);
>> +
>> +       return failures;
>> +}
>> +
>> +static int i2c_read_data(struct i2c_gpio_bus *bus, uchar chip,
>> +                        uchar *buffer, int len)
>> +{
>> +       struct gpio_desc *scl = &bus->gpios[PIN_SCL];
>> +       struct gpio_desc *sda = &bus->gpios[PIN_SDA];
>> +       unsigned int delay = bus->udelay;
>> +
>> +       PRINTD("%s: chip %x buffer: %x len %d\n", __func__, chip, buffer, len);
>> +
>> +       send_start(scl, sda, delay);
>> +       write_byte(scl, sda, delay, (chip << 1) | 1);   /* read cycle */
>> +
>> +       while (len-- > 0)
>> +               *buffer++ = read_byte(scl, sda, delay, len == 0);
>> +
>> +       send_stop(scl, sda, delay);
>> +
>> +       return 0;
>> +}
>> +
>> +static int i2c_gpio_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
>> +{
>> +       struct i2c_gpio_bus *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(bus, msg->addr, msg->buf, msg->len);
>> +               else
>> +                       ret = i2c_write_data(bus, msg->addr, msg->buf, msg->len,
>> +                                            next_is_read);
>> +
>> +               if (ret)
>> +                       return -EREMOTEIO;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags)
>> +{
>> +       struct i2c_gpio_bus *bus = dev_get_priv(dev);
>> +       struct gpio_desc *scl = &bus->gpios[PIN_SCL];
>> +       struct gpio_desc *sda = &bus->gpios[PIN_SDA];
>> +       unsigned int delay = bus->udelay;
>> +       int ret;
>> +
>> +       send_start(scl, sda, delay);
>> +       ret = write_byte(scl, sda, delay, (chip << 1) | 0);
>> +       send_stop(scl, sda, delay);
>> +
>> +       PRINTD("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
>> +              __func__, dev->seq, dev->name, chip, chip_flags, ret);
>> +
>> +       return ret;
>> +}
>> +
>> +static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed)
>> +{
>> +       struct i2c_gpio_bus *bus = dev_get_priv(dev);
>> +       struct gpio_desc *scl = &bus->gpios[PIN_SCL];
>> +       struct gpio_desc *sda = &bus->gpios[PIN_SDA];
>> +
>> +       bus->speed = speed;
>> +       bus->udelay = lldiv(1000000, speed << 2);
>
> Why lldiv() if the value can never be >100,000? Can we just use normal division?
>

ok, will change this. And I will remove the speed, since it's the same 
value as uclass provides in struct dm_i2c_bus.

>> +
>> +       send_reset(scl, sda, bus->udelay);
>> +
>> +       PRINTD("%s: bus: %d (%s) speed: %u Hz (1/4 of period: %lu us)\n",
>> +              __func__, dev->seq, dev->name, speed, bus->udelay);
>> +
>> +       return 0;
>> +}
>> +
>> +static int i2c_gpio_ofdata_to_platdata(struct udevice *dev)
>> +{
>> +       struct i2c_gpio_bus *bus = dev_get_priv(dev);
>> +       const void *blob = gd->fdt_blob;
>> +       int node = dev->of_offset;
>> +       int ret;
>> +
>> +       ret = gpio_request_list_by_name(dev, "gpios", bus->gpios,
>> +                                       ARRAY_SIZE(bus->gpios), 0);
>> +       if (ret < 0)
>> +               goto error;
>> +
>> +       bus->udelay = fdtdec_get_int(blob, node, "i2c-gpio,delay-us",
>> +                                    DEFAULT_UDELAY);
>> +
>> +       PRINTD("%s: bus: %d (%s) fdt node ok\n", __func__, dev->seq, dev->name);
>> +
>> +       return 0;
>> +error:
>> +       error("Can't get %s gpios! Error: %d", dev->name, ret);
>> +       return ret;
>> +}
>> +
>> +static const struct dm_i2c_ops i2c_gpio_ops = {
>> +       .xfer           = i2c_gpio_xfer,
>> +       .probe_chip     = i2c_gpio_probe,
>> +       .set_bus_speed  = i2c_gpio_set_bus_speed,
>> +};
>> +
>> +static const struct udevice_id i2c_gpio_ids[] = {
>> +       { .compatible = "i2c-gpio" },
>> +       { }
>> +};
>> +
>> +U_BOOT_DRIVER(i2c_gpio) = {
>> +       .name   = "i2c-gpio",
>> +       .id     = UCLASS_I2C,
>> +       .of_match = i2c_gpio_ids,
>> +       .ofdata_to_platdata = i2c_gpio_ofdata_to_platdata,
>> +       .priv_auto_alloc_size = sizeof(struct i2c_gpio_bus),
>> +       .ops    = &i2c_gpio_ops,
>> +};
>> --
>> 1.9.1
>>
>
> Regards,
> Simon
>

Thank you for the review.

Best regards,
-- 
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V3 0/3] dm: i2c: enable driver model for i2c gpio
  2015-03-10 10:30 [U-Boot] [PATCH 0/3] dm: i2c: enable driver model for software i2c Przemyslaw Marczak
                   ` (3 preceding siblings ...)
  2015-03-27 17:33 ` [U-Boot] [PATCH V2 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
@ 2015-03-31 16:57 ` Przemyslaw Marczak
  2015-03-31 16:57   ` [U-Boot] [PATCH V3 1/3] dm: gpio: request list: return the count if requests max_count reached Przemyslaw Marczak
                     ` (2 more replies)
  4 siblings, 3 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-31 16:57 UTC (permalink / raw)
  To: u-boot

This patchset enables driver model support for software i2c bus driver.
It was tested on Trats2 and Odroid U3 devices.

It can be tested on any other device by just modifying the dts file,
first by disabling the hardware i2c bus and then, as it is described
in the doc binding file, add i2c-gpio node.

The drivers, which are using the old api are not converted with this patchset.
I hope that maintainers will do this if required.

Probably the software i2c is used for PMIC devices not only for Trats2,
or Universal C210, so I suggest to wait with moving the drivers until
the pmic is done - this will prevent adding temporary code.

Przemyslaw Marczak (3):
  dm: gpio: request list: return the count if requests max_count reached
  Kconfig: i2c: fix help message related to dm i2c
  dm: i2c: add i2c-gpio driver

 doc/device-tree-bindings/i2c/i2c-gpio.txt |  37 ++++
 drivers/gpio/gpio-uclass.c                |   6 +-
 drivers/i2c/Kconfig                       |  26 ++-
 drivers/i2c/Makefile                      |   1 +
 drivers/i2c/i2c-gpio.c                    | 345 ++++++++++++++++++++++++++++++
 5 files changed, 400 insertions(+), 15 deletions(-)
 create mode 100644 doc/device-tree-bindings/i2c/i2c-gpio.txt
 create mode 100644 drivers/i2c/i2c-gpio.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V3 1/3] dm: gpio: request list: return the count if requests max_count reached
  2015-03-31 16:57 ` [U-Boot] [PATCH V3 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
@ 2015-03-31 16:57   ` Przemyslaw Marczak
  2015-04-01  3:17     ` Simon Glass
  2015-03-31 16:57   ` [U-Boot] [PATCH V3 2/3] Kconfig: i2c: fix help message related to dm i2c Przemyslaw Marczak
  2015-03-31 16:57   ` [U-Boot] [PATCH V3 3/3] dm: i2c: add i2c-gpio driver Przemyslaw Marczak
  2 siblings, 1 reply; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-31 16:57 UTC (permalink / raw)
  To: u-boot

The function gpio_request_list_by_name_nodev() returned -ENOSPC error,
when the loop count was greater than requested count. This was wrong,
because function should return the requested gpio count, when meets
the call request without errors. Now, the loop ends on requested
max_count.

Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
Cc: Simon Glass <sjg@chromium.org>

Changes V3:
- new commit
---
 drivers/gpio/gpio-uclass.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index a69bbd2..4b63025 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -590,11 +590,7 @@ int gpio_request_list_by_name_nodev(const void *blob, int node,
 	int count;
 	int ret;
 
-	for (count = 0; ; count++) {
-		if (count >= max_count) {
-			ret = -ENOSPC;
-			goto err;
-		}
+	for (count = 0; count < max_count; count++) {
 		ret = _gpio_request_by_name_nodev(blob, node, list_name, count,
 						  &desc[count], flags, true);
 		if (ret == -ENOENT)
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V3 2/3] Kconfig: i2c: fix help message related to dm i2c
  2015-03-31 16:57 ` [U-Boot] [PATCH V3 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
  2015-03-31 16:57   ` [U-Boot] [PATCH V3 1/3] dm: gpio: request list: return the count if requests max_count reached Przemyslaw Marczak
@ 2015-03-31 16:57   ` Przemyslaw Marczak
  2015-04-01  3:17     ` Simon Glass
  2015-03-31 16:57   ` [U-Boot] [PATCH V3 3/3] dm: i2c: add i2c-gpio driver Przemyslaw Marczak
  2 siblings, 1 reply; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-31 16:57 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Simon Glass <sjg@chromium.org>
Cc: Heiko Schocher <hs@denx.de>

Changes V2:
- add i2c uclass description

Changes v3:
- Kconfig: i2c-uclass: fix help message
---
 drivers/i2c/Kconfig | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 692810d..c83a984 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -2,16 +2,13 @@ config DM_I2C
 	bool "Enable Driver Model for I2C drivers"
 	depends on DM
 	help
-	  Enable driver model for I2C. This SPI flash interface
-	  (spi_flash_probe(), spi_flash_write(), etc.) is then
-	  implemented by the SPI flash uclass. There is one standard
-	  SPI flash driver which knows how to probe most chips
-	  supported by U-Boot. The uclass interface is defined in
-	  include/spi_flash.h, but is currently fully compatible
-	  with the old interface to avoid confusion and duplication
-	  during the transition parent. SPI and SPI flash must be
-	  enabled together (it is not possible to use driver model
-	  for one and not the other).
+	  Enable driver model for I2C. The I2C uclass interface: probe, read,
+	  write and speed, is implemented with the bus drivers operations,
+	  which provide methods for bus setting and data transfer. Each chip
+	  device (bus child) info is kept as parent platdata. The interface
+	  is defined in include/i2c.h. When i2c bus driver supports the i2c
+	  uclass, but the device drivers not, then DM_I2C_COMPAT config can
+	  be used as compatibility layer.
 
 config DM_I2C_COMPAT
 	bool "Enable I2C compatibility layer"
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V3 3/3] dm: i2c: add i2c-gpio driver
  2015-03-31 16:57 ` [U-Boot] [PATCH V3 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
  2015-03-31 16:57   ` [U-Boot] [PATCH V3 1/3] dm: gpio: request list: return the count if requests max_count reached Przemyslaw Marczak
  2015-03-31 16:57   ` [U-Boot] [PATCH V3 2/3] Kconfig: i2c: fix help message related to dm i2c Przemyslaw Marczak
@ 2015-03-31 16:57   ` Przemyslaw Marczak
  2015-04-01  3:18     ` Simon Glass
  2 siblings, 1 reply; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-03-31 16:57 UTC (permalink / raw)
  To: u-boot

This commit adds driver model support to software emulated i2c bus driver.
This driver supports kernel-style device tree bindings. Fdt properties in use:
- compatible - "i2c-gpio"
- gpios      - data and clock GPIO pin phandles
- delay-us   - micro seconds delay between GPIOs toggle operations,
               which is 1/4 of I2C speed clock period.

Added:
- Config: CONFIG_DM_I2C_GPIO
- File: drivers/i2c/i2c-gpio.c
- File: doc/device-tree-bindings/i2c/i2c-gpio.txt

Driver base code is taken from: drivers/i2c/soft-i2c.c, changes:
- use "i2c-gpio" naming
- update comments style
- move preprocesor macros into functions
- add device tree support
- add driver model i2c support
- code cleanup,
- add Kconfig entry

Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
CC: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Lukasz Majewski <l.majewski@samsung.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Simon Glass <sjg@chromium.org>
Cc: Heiko Schocher <hs@denx.de>

Changes V2:
- new file for software i2c driver: i2c-gpio.c
- update driver naming: use of "i2c-gpio"
- add full compatibility with the kernels device-tree "i2c-gpio" node
- fix Kconfig entry

Changes V3:
- fix Kconfig entry
- update file header
- remove field "speed" from struct i2c_gpio_bus
- move macros to functions
- move duplicated routines into functions
- update naming with prefix "i2c_gpio_"
---
 doc/device-tree-bindings/i2c/i2c-gpio.txt |  37 ++++
 drivers/i2c/Kconfig                       |   9 +
 drivers/i2c/Makefile                      |   1 +
 drivers/i2c/i2c-gpio.c                    | 345 ++++++++++++++++++++++++++++++
 4 files changed, 392 insertions(+)
 create mode 100644 doc/device-tree-bindings/i2c/i2c-gpio.txt
 create mode 100644 drivers/i2c/i2c-gpio.c

diff --git a/doc/device-tree-bindings/i2c/i2c-gpio.txt b/doc/device-tree-bindings/i2c/i2c-gpio.txt
new file mode 100644
index 0000000..ba56ed5
--- /dev/null
+++ b/doc/device-tree-bindings/i2c/i2c-gpio.txt
@@ -0,0 +1,37 @@
+I2C gpio device binding
+=======================
+
+Driver:
+- drivers/i2c/i2c-gpio.c
+
+Software i2c device-tree node properties:
+Required:
+* #address-cells = <1>;
+* #size-cells = <0>;
+* compatible = "i2c-gpio";
+* gpios = <sda ...>, <scl ...>;
+
+Optional:
+* i2c-gpio,delay-us = <5>;
+   The resulting transfer speed can be adjusted by setting the delay[us]
+   between gpio-toggle operations. Speed [Hz] = 1000000 / 4 * udelay[us],
+   It not defined, then default is 5us (~50KHz).
+
+Example:
+
+i2c-gpio at 1 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	compatible = "i2c-gpio";
+	gpios = <&gpd1 0 GPIO_ACTIVE_HIGH>, /* SDA */
+		<&gpd1 1 GPIO_ACTIVE_HIGH>; /* CLK */
+
+	i2c-gpio,delay-us = <5>;
+
+	some_device at 5 {
+		compatible = "some_device";
+		reg = <0x5>;
+		...
+	};
+};
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index c83a984..739badc 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -19,6 +19,15 @@ config DM_I2C_COMPAT
 	  to convert all code for a board in a single commit. It should not
 	  be enabled for any board in an official release.
 
+config DM_I2C_GPIO
+	bool "Enable Driver Model for software emulated I2C bus driver"
+	depends on DM_I2C && DM_GPIO
+	help
+	  Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO
+	  configuration is given by the device tree. Kernel-style device tree
+	  bindings are supported.
+	  Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
+
 config SYS_I2C_UNIPHIER
 	bool "UniPhier I2C driver"
 	depends on ARCH_UNIPHIER && DM_I2C
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 774bc94..d9e9f3a 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -6,6 +6,7 @@
 #
 obj-$(CONFIG_DM_I2C) += i2c-uclass.o
 obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
+obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o
 
 obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
 obj-$(CONFIG_I2C_MV) += mv_i2c.o
diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
new file mode 100644
index 0000000..f17839b
--- /dev/null
+++ b/drivers/i2c/i2c-gpio.c
@@ -0,0 +1,345 @@
+/*
+ * (C) Copyright 2015, Samsung Electronics
+ * Przemyslaw Marczak <p.marczak@samsung.com>
+ *
+ * This file is based on: drivers/i2c/soft-i2c.c,
+ * with added driver-model support and code cleanup.
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <asm/gpio.h>
+
+#define DEFAULT_UDELAY	5
+#define RETRIES		0
+#define I2C_ACK		0
+#define I2C_NOACK	1
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+	PIN_SDA = 0,
+	PIN_SCL,
+	PIN_COUNT,
+};
+
+struct i2c_gpio_bus {
+	/**
+	  * udelay - delay [us] between GPIO toggle operations,
+	  * which is 1/4 of I2C speed clock period.
+	 */
+	int udelay;
+	 /* sda, scl */
+	struct gpio_desc gpios[PIN_COUNT];
+};
+
+static int i2c_gpio_sda_get(struct gpio_desc *sda)
+{
+	return dm_gpio_get_value(sda);
+}
+
+static void i2c_gpio_sda_set(struct gpio_desc *sda, int bit)
+{
+	if (bit) {
+		dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);
+	} else {
+		dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
+		dm_gpio_set_value(sda, 0);
+	}
+}
+
+static void i2c_gpio_scl_set(struct gpio_desc *scl, int bit)
+{
+	dm_gpio_set_dir_flags(scl, GPIOD_IS_OUT);
+	dm_gpio_set_value(scl, bit);
+}
+
+static void i2c_gpio_write_bit(struct gpio_desc *scl, struct gpio_desc *sda,
+			       int delay, uchar bit)
+{
+	i2c_gpio_scl_set(scl, 0);
+	udelay(delay);
+	i2c_gpio_sda_set(sda, bit);
+	udelay(delay);
+	i2c_gpio_scl_set(scl, 1);
+	udelay(2 * delay);
+}
+
+static int i2c_gpio_read_bit(struct gpio_desc *scl, struct gpio_desc *sda,
+			     int delay)
+{
+	int value;
+
+	i2c_gpio_scl_set(scl, 1);
+	udelay(delay);
+	value = i2c_gpio_sda_get(sda);
+	udelay(delay);
+	i2c_gpio_scl_set(scl, 0);
+	udelay(2 * delay);
+
+	return value;
+}
+
+/* START: High -> Low on SDA while SCL is High */
+static void i2c_gpio_send_start(struct gpio_desc *scl, struct gpio_desc *sda,
+				int delay)
+{
+	udelay(delay);
+	i2c_gpio_sda_set(sda, 1);
+	udelay(delay);
+	i2c_gpio_scl_set(scl, 1);
+	udelay(delay);
+	i2c_gpio_sda_set(sda, 0);
+	udelay(delay);
+}
+
+/* STOP: Low -> High on SDA while SCL is High */
+static void i2c_gpio_send_stop(struct gpio_desc *scl, struct gpio_desc *sda,
+			       int delay)
+{
+	i2c_gpio_scl_set(scl, 0);
+	udelay(delay);
+	i2c_gpio_sda_set(sda, 0);
+	udelay(delay);
+	i2c_gpio_scl_set(scl, 1);
+	udelay(delay);
+	i2c_gpio_sda_set(sda, 1);
+	udelay(delay);
+}
+
+/* ack should be I2C_ACK or I2C_NOACK */
+static void i2c_gpio_send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
+			      int delay, int ack)
+{
+	i2c_gpio_write_bit(scl, sda, delay, ack);
+	i2c_gpio_scl_set(scl, 0);
+	udelay(delay);
+}
+
+/**
+ * Send a reset sequence consisting of 9 clocks with the data signal high
+ * to clock any confused device back into an idle state.  Also send a
+ * <stop> at the end of the sequence for belts & suspenders.
+ */
+static void i2c_gpio_send_reset(struct gpio_desc *scl, struct gpio_desc *sda,
+				int delay)
+{
+	int j;
+
+	for (j = 0; j < 9; j++)
+		i2c_gpio_write_bit(scl, sda, delay, 1);
+
+	i2c_gpio_send_stop(scl, sda, delay);
+}
+
+/* Set sda high with low clock, before reading slave data */
+static void i2c_gpio_sda_high(struct gpio_desc *scl, struct gpio_desc *sda,
+			      int delay)
+{
+	i2c_gpio_scl_set(scl, 0);
+	udelay(delay);
+	i2c_gpio_sda_set(sda, 1);
+	udelay(delay);
+}
+
+/* Send 8 bits and look for an acknowledgement */
+static int i2c_gpio_write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
+			       int delay, uchar data)
+{
+	int j;
+	int nack;
+
+	for (j = 0; j < 8; j++) {
+		i2c_gpio_write_bit(scl, sda, delay, data & 0x80);
+		data <<= 1;
+	}
+
+	udelay(delay);
+
+	/* Look for an <ACK>(negative logic) and return it */
+	i2c_gpio_sda_high(scl, sda, delay);
+	nack = i2c_gpio_read_bit(scl, sda, delay);
+
+	return nack;	/* not a nack is an ack */
+}
+
+/**
+ * if ack == I2C_ACK, ACK the byte so can continue reading, else
+ * send I2C_NOACK to end the read.
+ */
+static uchar i2c_gpio_read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
+				int delay, int ack)
+{
+	int  data;
+	int  j;
+
+	i2c_gpio_sda_high(scl, sda, delay);
+	data = 0;
+	for (j = 0; j < 8; j++) {
+		data <<= 1;
+		data |= i2c_gpio_read_bit(scl, sda, delay);
+	}
+	i2c_gpio_send_ack(scl, sda, delay, ack);
+
+	return data;
+}
+
+/* send start and the slave chip address */
+int i2c_send_slave_addr(struct gpio_desc *scl, struct gpio_desc *sda, int delay,
+			uchar chip)
+{
+	i2c_gpio_send_start(scl, sda, delay);
+
+	if (i2c_gpio_write_byte(scl, sda, delay, chip)) {
+		i2c_gpio_send_stop(scl, sda, delay);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int i2c_gpio_write_data(struct i2c_gpio_bus *bus, uchar chip,
+			       uchar *buffer, int len,
+			       bool end_with_repeated_start)
+{
+	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+	unsigned int delay = bus->udelay;
+	int failures = 0;
+
+	debug("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
+
+	if (i2c_send_slave_addr(scl, sda, delay, chip << 1)) {
+		debug("i2c_write, no chip responded %02X\n", chip);
+		return -EIO;
+	}
+
+	while (len-- > 0) {
+		if (i2c_gpio_write_byte(scl, sda, delay, *buffer++))
+			failures++;
+	}
+
+	if (!end_with_repeated_start) {
+		i2c_gpio_send_stop(scl, sda, delay);
+		return failures;
+	}
+
+	if (i2c_send_slave_addr(scl, sda, delay, (chip << 1) | 0x1)) {
+		debug("i2c_write, no chip responded %02X\n", chip);
+		return -EIO;
+	}
+
+	return failures;
+}
+
+static int i2c_gpio_read_data(struct i2c_gpio_bus *bus, uchar chip,
+			      uchar *buffer, int len)
+{
+	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+	unsigned int delay = bus->udelay;
+
+	debug("%s: chip %x buffer: %p len %d\n", __func__, chip, buffer, len);
+
+	while (len-- > 0)
+		*buffer++ = i2c_gpio_read_byte(scl, sda, delay, len == 0);
+
+	i2c_gpio_send_stop(scl, sda, delay);
+
+	return 0;
+}
+
+static int i2c_gpio_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
+{
+	struct i2c_gpio_bus *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_gpio_read_data(bus, msg->addr, msg->buf,
+						 msg->len);
+		else
+			ret = i2c_gpio_write_data(bus, msg->addr, msg->buf,
+						  msg->len, next_is_read);
+
+		if (ret)
+			return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags)
+{
+	struct i2c_gpio_bus *bus = dev_get_priv(dev);
+	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+	unsigned int delay = bus->udelay;
+	int ret;
+
+	i2c_gpio_send_start(scl, sda, delay);
+	ret = i2c_gpio_write_byte(scl, sda, delay, (chip << 1) | 0);
+	i2c_gpio_send_stop(scl, sda, delay);
+
+	debug("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
+	      __func__, dev->seq, dev->name, chip, chip_flags, ret);
+
+	return ret;
+}
+
+static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed_hz)
+{
+	struct i2c_gpio_bus *bus = dev_get_priv(dev);
+	struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+	struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+
+	bus->udelay = 1000000 / (speed_hz << 2);
+
+	i2c_gpio_send_reset(scl, sda, bus->udelay);
+
+	return 0;
+}
+
+static int i2c_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+	struct i2c_gpio_bus *bus = dev_get_priv(dev);
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
+	int ret;
+
+	ret = gpio_request_list_by_name(dev, "gpios", bus->gpios,
+					ARRAY_SIZE(bus->gpios), 0);
+	if (ret < 0)
+		goto error;
+
+	bus->udelay = fdtdec_get_int(blob, node, "i2c-gpio,delay-us",
+				     DEFAULT_UDELAY);
+
+	return 0;
+error:
+	error("Can't get %s gpios! Error: %d", dev->name, ret);
+	return ret;
+}
+
+static const struct dm_i2c_ops i2c_gpio_ops = {
+	.xfer		= i2c_gpio_xfer,
+	.probe_chip	= i2c_gpio_probe,
+	.set_bus_speed	= i2c_gpio_set_bus_speed,
+};
+
+static const struct udevice_id i2c_gpio_ids[] = {
+	{ .compatible = "i2c-gpio" },
+	{ }
+};
+
+U_BOOT_DRIVER(i2c_gpio) = {
+	.name	= "i2c-gpio",
+	.id	= UCLASS_I2C,
+	.of_match = i2c_gpio_ids,
+	.ofdata_to_platdata = i2c_gpio_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct i2c_gpio_bus),
+	.ops	= &i2c_gpio_ops,
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V3 1/3] dm: gpio: request list: return the count if requests max_count reached
  2015-03-31 16:57   ` [U-Boot] [PATCH V3 1/3] dm: gpio: request list: return the count if requests max_count reached Przemyslaw Marczak
@ 2015-04-01  3:17     ` Simon Glass
  2015-04-01  3:19       ` Simon Glass
  2015-04-01  6:44       ` Przemyslaw Marczak
  0 siblings, 2 replies; 36+ messages in thread
From: Simon Glass @ 2015-04-01  3:17 UTC (permalink / raw)
  To: u-boot

On 31 March 2015 at 10:57, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
> The function gpio_request_list_by_name_nodev() returned -ENOSPC error,
> when the loop count was greater than requested count. This was wrong,
> because function should return the requested gpio count, when meets
> the call request without errors. Now, the loop ends on requested
> max_count.
>
> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> Cc: Simon Glass <sjg@chromium.org>
>
> Changes V3:
> - new commit

There's something odd about the change logs here - they are coming in
as part of the commit message. Are you using patman?

Acked-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V3 2/3] Kconfig: i2c: fix help message related to dm i2c
  2015-03-31 16:57   ` [U-Boot] [PATCH V3 2/3] Kconfig: i2c: fix help message related to dm i2c Przemyslaw Marczak
@ 2015-04-01  3:17     ` Simon Glass
  2015-04-01  3:19       ` Simon Glass
  0 siblings, 1 reply; 36+ messages in thread
From: Simon Glass @ 2015-04-01  3:17 UTC (permalink / raw)
  To: u-boot

On 31 March 2015 at 10:57, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
> Cc: Mike Frysinger <vapier@gentoo.org>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Heiko Schocher <hs@denx.de>
>
> Changes V2:
> - add i2c uclass description
>
> Changes v3:
> - Kconfig: i2c-uclass: fix help message
> ---
>  drivers/i2c/Kconfig | 17 +++++++----------
>  1 file changed, 7 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
> index 692810d..c83a984 100644
> --- a/drivers/i2c/Kconfig
> +++ b/drivers/i2c/Kconfig
> @@ -2,16 +2,13 @@ config DM_I2C
>         bool "Enable Driver Model for I2C drivers"
>         depends on DM
>         help
> -         Enable driver model for I2C. This SPI flash interface
> -         (spi_flash_probe(), spi_flash_write(), etc.) is then
> -         implemented by the SPI flash uclass. There is one standard
> -         SPI flash driver which knows how to probe most chips
> -         supported by U-Boot. The uclass interface is defined in
> -         include/spi_flash.h, but is currently fully compatible
> -         with the old interface to avoid confusion and duplication
> -         during the transition parent. SPI and SPI flash must be
> -         enabled together (it is not possible to use driver model
> -         for one and not the other).
> +         Enable driver model for I2C. The I2C uclass interface: probe, read,
> +         write and speed, is implemented with the bus drivers operations,
> +         which provide methods for bus setting and data transfer. Each chip
> +         device (bus child) info is kept as parent platdata. The interface
> +         is defined in include/i2c.h. When i2c bus driver supports the i2c
> +         uclass, but the device drivers not, then DM_I2C_COMPAT config can
> +         be used as compatibility layer.
>
>  config DM_I2C_COMPAT
>         bool "Enable I2C compatibility layer"
> --
> 1.9.1
>

Acked-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V3 3/3] dm: i2c: add i2c-gpio driver
  2015-03-31 16:57   ` [U-Boot] [PATCH V3 3/3] dm: i2c: add i2c-gpio driver Przemyslaw Marczak
@ 2015-04-01  3:18     ` Simon Glass
  2015-04-01  3:19       ` Simon Glass
  0 siblings, 1 reply; 36+ messages in thread
From: Simon Glass @ 2015-04-01  3:18 UTC (permalink / raw)
  To: u-boot

On 31 March 2015 at 10:57, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
> This commit adds driver model support to software emulated i2c bus driver.
> This driver supports kernel-style device tree bindings. Fdt properties in use:
> - compatible - "i2c-gpio"
> - gpios      - data and clock GPIO pin phandles
> - delay-us   - micro seconds delay between GPIOs toggle operations,
>                which is 1/4 of I2C speed clock period.
>
> Added:
> - Config: CONFIG_DM_I2C_GPIO
> - File: drivers/i2c/i2c-gpio.c
> - File: doc/device-tree-bindings/i2c/i2c-gpio.txt
>
> Driver base code is taken from: drivers/i2c/soft-i2c.c, changes:
> - use "i2c-gpio" naming
> - update comments style
> - move preprocesor macros into functions
> - add device tree support
> - add driver model i2c support
> - code cleanup,
> - add Kconfig entry
>
> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
> CC: Masahiro Yamada <yamada.masahiro@socionext.com>
> Cc: Lukasz Majewski <l.majewski@samsung.com>
> Cc: Mike Frysinger <vapier@gentoo.org>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Heiko Schocher <hs@denx.de>
>
> Changes V2:
> - new file for software i2c driver: i2c-gpio.c
> - update driver naming: use of "i2c-gpio"
> - add full compatibility with the kernels device-tree "i2c-gpio" node
> - fix Kconfig entry
>
> Changes V3:
> - fix Kconfig entry
> - update file header
> - remove field "speed" from struct i2c_gpio_bus
> - move macros to functions
> - move duplicated routines into functions
> - update naming with prefix "i2c_gpio_"
> ---
>  doc/device-tree-bindings/i2c/i2c-gpio.txt |  37 ++++
>  drivers/i2c/Kconfig                       |   9 +
>  drivers/i2c/Makefile                      |   1 +
>  drivers/i2c/i2c-gpio.c                    | 345 ++++++++++++++++++++++++++++++
>  4 files changed, 392 insertions(+)
>  create mode 100644 doc/device-tree-bindings/i2c/i2c-gpio.txt
>  create mode 100644 drivers/i2c/i2c-gpio.c

Acked-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V3 1/3] dm: gpio: request list: return the count if requests max_count reached
  2015-04-01  3:17     ` Simon Glass
@ 2015-04-01  3:19       ` Simon Glass
  2015-04-01  6:44       ` Przemyslaw Marczak
  1 sibling, 0 replies; 36+ messages in thread
From: Simon Glass @ 2015-04-01  3:19 UTC (permalink / raw)
  To: u-boot

On 31 March 2015 at 21:17, Simon Glass <sjg@chromium.org> wrote:
> On 31 March 2015 at 10:57, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
>> The function gpio_request_list_by_name_nodev() returned -ENOSPC error,
>> when the loop count was greater than requested count. This was wrong,
>> because function should return the requested gpio count, when meets
>> the call request without errors. Now, the loop ends on requested
>> max_count.
>>
>> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
>> Cc: Simon Glass <sjg@chromium.org>
>>
>> Changes V3:
>> - new commit
>
> There's something odd about the change logs here - they are coming in
> as part of the commit message. Are you using patman?
>
> Acked-by: Simon Glass <sjg@chromium.org>

Applied to u-boot-dm/next, thanks!

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V3 2/3] Kconfig: i2c: fix help message related to dm i2c
  2015-04-01  3:17     ` Simon Glass
@ 2015-04-01  3:19       ` Simon Glass
  0 siblings, 0 replies; 36+ messages in thread
From: Simon Glass @ 2015-04-01  3:19 UTC (permalink / raw)
  To: u-boot

On 31 March 2015 at 21:17, Simon Glass <sjg@chromium.org> wrote:
> On 31 March 2015 at 10:57, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
>> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
>> Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
>> Cc: Mike Frysinger <vapier@gentoo.org>
>> Cc: Simon Glass <sjg@chromium.org>
>> Cc: Heiko Schocher <hs@denx.de>
>>
>> Changes V2:
>> - add i2c uclass description
>>
>> Changes v3:
>> - Kconfig: i2c-uclass: fix help message
>> ---
>>  drivers/i2c/Kconfig | 17 +++++++----------
>>  1 file changed, 7 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
>> index 692810d..c83a984 100644
>> --- a/drivers/i2c/Kconfig
>> +++ b/drivers/i2c/Kconfig
>> @@ -2,16 +2,13 @@ config DM_I2C
>>         bool "Enable Driver Model for I2C drivers"
>>         depends on DM
>>         help
>> -         Enable driver model for I2C. This SPI flash interface
>> -         (spi_flash_probe(), spi_flash_write(), etc.) is then
>> -         implemented by the SPI flash uclass. There is one standard
>> -         SPI flash driver which knows how to probe most chips
>> -         supported by U-Boot. The uclass interface is defined in
>> -         include/spi_flash.h, but is currently fully compatible
>> -         with the old interface to avoid confusion and duplication
>> -         during the transition parent. SPI and SPI flash must be
>> -         enabled together (it is not possible to use driver model
>> -         for one and not the other).
>> +         Enable driver model for I2C. The I2C uclass interface: probe, read,
>> +         write and speed, is implemented with the bus drivers operations,
>> +         which provide methods for bus setting and data transfer. Each chip
>> +         device (bus child) info is kept as parent platdata. The interface
>> +         is defined in include/i2c.h. When i2c bus driver supports the i2c
>> +         uclass, but the device drivers not, then DM_I2C_COMPAT config can
>> +         be used as compatibility layer.
>>
>>  config DM_I2C_COMPAT
>>         bool "Enable I2C compatibility layer"
>> --
>> 1.9.1
>>
>
> Acked-by: Simon Glass <sjg@chromium.org>

Applied to u-boot-dm/next, thanks!

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V3 3/3] dm: i2c: add i2c-gpio driver
  2015-04-01  3:18     ` Simon Glass
@ 2015-04-01  3:19       ` Simon Glass
  0 siblings, 0 replies; 36+ messages in thread
From: Simon Glass @ 2015-04-01  3:19 UTC (permalink / raw)
  To: u-boot

On 31 March 2015 at 21:18, Simon Glass <sjg@chromium.org> wrote:
> On 31 March 2015 at 10:57, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
>> This commit adds driver model support to software emulated i2c bus driver.
>> This driver supports kernel-style device tree bindings. Fdt properties in use:
>> - compatible - "i2c-gpio"
>> - gpios      - data and clock GPIO pin phandles
>> - delay-us   - micro seconds delay between GPIOs toggle operations,
>>                which is 1/4 of I2C speed clock period.
>>
>> Added:
>> - Config: CONFIG_DM_I2C_GPIO
>> - File: drivers/i2c/i2c-gpio.c
>> - File: doc/device-tree-bindings/i2c/i2c-gpio.txt
>>
>> Driver base code is taken from: drivers/i2c/soft-i2c.c, changes:
>> - use "i2c-gpio" naming
>> - update comments style
>> - move preprocesor macros into functions
>> - add device tree support
>> - add driver model i2c support
>> - code cleanup,
>> - add Kconfig entry
>>
>> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
>> CC: Masahiro Yamada <yamada.masahiro@socionext.com>
>> Cc: Lukasz Majewski <l.majewski@samsung.com>
>> Cc: Mike Frysinger <vapier@gentoo.org>
>> Cc: Simon Glass <sjg@chromium.org>
>> Cc: Heiko Schocher <hs@denx.de>
>>
>> Changes V2:
>> - new file for software i2c driver: i2c-gpio.c
>> - update driver naming: use of "i2c-gpio"
>> - add full compatibility with the kernels device-tree "i2c-gpio" node
>> - fix Kconfig entry
>>
>> Changes V3:
>> - fix Kconfig entry
>> - update file header
>> - remove field "speed" from struct i2c_gpio_bus
>> - move macros to functions
>> - move duplicated routines into functions
>> - update naming with prefix "i2c_gpio_"
>> ---
>>  doc/device-tree-bindings/i2c/i2c-gpio.txt |  37 ++++
>>  drivers/i2c/Kconfig                       |   9 +
>>  drivers/i2c/Makefile                      |   1 +
>>  drivers/i2c/i2c-gpio.c                    | 345 ++++++++++++++++++++++++++++++
>>  4 files changed, 392 insertions(+)
>>  create mode 100644 doc/device-tree-bindings/i2c/i2c-gpio.txt
>>  create mode 100644 drivers/i2c/i2c-gpio.c
>
> Acked-by: Simon Glass <sjg@chromium.org>

Applied to u-boot-dm/next, thanks!

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [U-Boot] [PATCH V3 1/3] dm: gpio: request list: return the count if requests max_count reached
  2015-04-01  3:17     ` Simon Glass
  2015-04-01  3:19       ` Simon Glass
@ 2015-04-01  6:44       ` Przemyslaw Marczak
  1 sibling, 0 replies; 36+ messages in thread
From: Przemyslaw Marczak @ 2015-04-01  6:44 UTC (permalink / raw)
  To: u-boot

Hello Simon,

On 04/01/2015 05:17 AM, Simon Glass wrote:
> On 31 March 2015 at 10:57, Przemyslaw Marczak <p.marczak@samsung.com> wrote:
>> The function gpio_request_list_by_name_nodev() returned -ENOSPC error,
>> when the loop count was greater than requested count. This was wrong,
>> because function should return the requested gpio count, when meets
>> the call request without errors. Now, the loop ends on requested
>> max_count.
>>
>> Signed-off-by: Przemyslaw Marczak <p.marczak@samsung.com>
>> Cc: Simon Glass <sjg@chromium.org>
>>
>> Changes V3:
>> - new commit
>
> There's something odd about the change logs here - they are coming in
> as part of the commit message. Are you using patman?
>
> Acked-by: Simon Glass <sjg@chromium.org>
>

Sorry for this, it's by mistake, I don't use patman for generating 
patches. I add change log manually.

Thanks for applying this series :)

Best regards,
-- 
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2015-04-01  6:44 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-10 10:30 [U-Boot] [PATCH 0/3] dm: i2c: enable driver model for software i2c Przemyslaw Marczak
2015-03-10 10:30 ` [U-Boot] [PATCH 1/3] dm: i2c soft: enable driver model for software i2c driver Przemyslaw Marczak
2015-03-23  8:44   ` Lukasz Majewski
2015-03-23 23:38   ` Simon Glass
2015-03-24  6:01     ` Heiko Schocher
2015-03-26 13:18       ` Przemyslaw Marczak
2015-03-26 13:18     ` Przemyslaw Marczak
2015-03-10 10:30 ` [U-Boot] [PATCH 2/3] Kconfig: i2c: remove wrong help message related to dm i2c Przemyslaw Marczak
2015-03-23  8:45   ` Lukasz Majewski
2015-03-23 23:39   ` Simon Glass
2015-03-26 13:18     ` Przemyslaw Marczak
2015-03-10 10:30 ` [U-Boot] [PATCH 3/3] Kconfig: i2c: add entry for driver-model software i2c Przemyslaw Marczak
2015-03-23  8:46   ` Lukasz Majewski
2015-03-23 23:40   ` Simon Glass
2015-03-25  3:35   ` Masahiro Yamada
2015-03-26 13:17     ` Przemyslaw Marczak
2015-03-27 17:33 ` [U-Boot] [PATCH V2 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
2015-03-27 17:33   ` [U-Boot] [PATCH V2 1/3] dm: gpio: request list: return the count if requests max_count reached Przemyslaw Marczak
2015-03-28 15:04     ` Simon Glass
2015-03-27 17:33   ` [U-Boot] [PATCH V2 2/3] Kconfig: i2c: fix help message related to dm i2c Przemyslaw Marczak
2015-03-28 15:08     ` Simon Glass
2015-03-31 15:57       ` Przemyslaw Marczak
2015-03-27 17:33   ` [U-Boot] [PATCH V2 3/3] dm: i2c: add i2c-gpio driver Przemyslaw Marczak
2015-03-28 15:08     ` Simon Glass
2015-03-31 15:58       ` Przemyslaw Marczak
2015-03-31 16:57 ` [U-Boot] [PATCH V3 0/3] dm: i2c: enable driver model for i2c gpio Przemyslaw Marczak
2015-03-31 16:57   ` [U-Boot] [PATCH V3 1/3] dm: gpio: request list: return the count if requests max_count reached Przemyslaw Marczak
2015-04-01  3:17     ` Simon Glass
2015-04-01  3:19       ` Simon Glass
2015-04-01  6:44       ` Przemyslaw Marczak
2015-03-31 16:57   ` [U-Boot] [PATCH V3 2/3] Kconfig: i2c: fix help message related to dm i2c Przemyslaw Marczak
2015-04-01  3:17     ` Simon Glass
2015-04-01  3:19       ` Simon Glass
2015-03-31 16:57   ` [U-Boot] [PATCH V3 3/3] dm: i2c: add i2c-gpio driver Przemyslaw Marczak
2015-04-01  3:18     ` Simon Glass
2015-04-01  3:19       ` Simon Glass

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.