+}
+#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);
+
+ (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->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