All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lubomir Popov <lpopov@mm-sol.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 2/2] OMAP4/5: I2C: New I2C driver files added
Date: Fri, 29 Mar 2013 18:36:40 +0200	[thread overview]
Message-ID: <5155C318.1070203@mm-sol.com> (raw)

New I2C driver that fixes read-related issues with some types
of I2C chips. The i2c_read function now performs bulk read of
the requested number of bytes in a single transaction and
completes much faster. Whether to use Stop-Start or Repeated
Start between the address and data phases is configurable
(e.g. in the board config header).

Signed-off-by: Lubomir Popov <lpopov@mm-sol.com>

---

The main feature of this new driver is that now i2c_read operates
correctly with chips that have addressable registers wider than 8 bits
(such as TI temperature sensors), or that have multiple non-addressable
registers that have to be retrieved in a bulk transaction (such as TI
clock distributors). The old driver (omap24xx_i2c.c) performs separate
read transactions for every byte requested and returns invalid data in
these cases (except possibly the first byte; this invalid data is in
fact presented by the chips, so the driver does not know that it is
invalid).

The new driver performs a standard bulk read transaction (with S-P by
default, or with Sr if configured so) and works correctly with all types
of I2C devices.

The i2c_write and i2c_probe functions have also been modified.

I have tested the driver on OMAP4430, 4460, 4470 and 5430 and found no
issues so far. Nevertheless, folks, any additional testing is strongly
encouraged; the driver should also work on OMAP3 and derivatives, but I
didn't have this opportunity, so any feedback is welcome.

 drivers/i2c/omap4x5x_i2c.c |  562 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/i2c/omap4x5x_i2c.h |  176 ++++++++++++++
 2 files changed, 738 insertions(+)
 create mode 100644 drivers/i2c/omap4x5x_i2c.c
 create mode 100644 drivers/i2c/omap4x5x_i2c.h

diff --git a/drivers/i2c/omap4x5x_i2c.c b/drivers/i2c/omap4x5x_i2c.c
new file mode 100644
index 0000000..44d7813
--- /dev/null
+++ b/drivers/i2c/omap4x5x_i2c.c
@@ -0,0 +1,562 @@
+/*
+ * Basic I2C functions
+ *
+ * Copyright (c) 2004 Texas Instruments
+ *
+ * This package is free software;  you can redistribute it and/or
+ * modify it under the terms of the license found in the file
+ * named COPYING that should have accompanied this file.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Author: Jian Zhang jzhang at ti.com, Texas Instruments
+ *
+ * Copyright (c) 2003 Wolfgang Denk, wd at denx.de
+ * Rewritten to fit into the current U-Boot framework
+ *
+ * Adapted for OMAP2420 I2C, r-woodruff2 at ti.com
+ *
+ * Copyright (c) 2013 Lubomir Popov <lpopov@mm-sol.com>, MM Solutions
+ * Based on omap24xx_i2c.c and modified for OMAP4/5:
+ *         - i2c_read now operates correctly, with bulk transfer;
+ *         - i2c_probe performs write access vs read;
+ *         - Driver tries to identify I2C pads not properly padconf'd;
+ *         - Should work with OMAP3/AM33xx as well, but is not tested.
+ */
+
+#include <common.h>
+
+#include <asm/arch/i2c.h>
+#include <asm/io.h>
+
+#include "omap4x5x_i2c.h"
+
+#undef	I2C_DBG
+
+#ifdef	I2C_DBG
+#define I2C_PRINTF(fmt, args...)	printf(fmt , ##args)
+#else
+#define I2C_PRINTF(fmt, args...)
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define I2C_TIMEOUT	1000
+
+static int wait_for_bus_free(void);
+static u16 wait_for_event(void);
+static void flush_fifo(void);
+
+/*
+ * For SPL boot some boards need i2c before SDRAM is initialised so force
+ * variables to live in SRAM
+ */
+static struct i2c __attribute__((section (".data"))) *i2c_base =
+					(struct i2c *)I2C_DEFAULT_BASE;
+static unsigned int __attribute__((section (".data"))) bus_initialized[I2C_BUS_MAX] =
+					{ [0 ... (I2C_BUS_MAX-1)] = 0 };
+static unsigned int __attribute__((section (".data"))) current_bus = 0;
+
+void i2c_init(int speed, int slaveadd)
+{
+	int psc, fsscll, fssclh;
+	int hsscll = 0, hssclh = 0;
+	u32 scll, sclh;
+	int timeout = I2C_TIMEOUT;
+
+	/* Only handle standard, fast and high speeds */
+	if ((speed != OMAP_I2C_STANDARD) &&
+	    (speed != OMAP_I2C_FAST_MODE) &&
+	    (speed != OMAP_I2C_HIGH_SPEED)) {
+		printf("Error : I2C unsupported speed %d\n", speed);
+		return;
+	}
+
+	psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK;
+	psc -= 1;
+	if (psc < I2C_PSC_MIN) {
+		printf("Error : I2C unsupported prescalar %d\n", psc);
+		return;
+	}
+
+	if (speed == OMAP_I2C_HIGH_SPEED) {
+		/* High speed */
+
+		/* For first phase of HS mode */
+		fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK /
+			(2 * OMAP_I2C_FAST_MODE);
+
+		fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM;
+		fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM;
+		if (((fsscll < 0) || (fssclh < 0)) ||
+		    ((fsscll > 255) || (fssclh > 255))) {
+			printf("Error : I2C initializing first phase clock\n");
+			return;
+		}
+
+		/* For second phase of HS mode */
+		hsscll = hssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
+
+		hsscll -= I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM;
+		hssclh -= I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM;
+		if (((fsscll < 0) || (fssclh < 0)) ||
+		    ((fsscll > 255) || (fssclh > 255))) {
+			printf("Error : I2C initializing second phase clock\n");
+			return;
+		}
+
+		scll = (unsigned int)hsscll << 8 | (unsigned int)fsscll;
+		sclh = (unsigned int)hssclh << 8 | (unsigned int)fssclh;
+
+	} else {
+		/* Standard and fast speed */
+		fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
+
+		fsscll -= I2C_FASTSPEED_SCLL_TRIM;
+		fssclh -= I2C_FASTSPEED_SCLH_TRIM;
+		if (((fsscll < 0) || (fssclh < 0)) ||
+		    ((fsscll > 255) || (fssclh > 255))) {
+			printf("Error : I2C initializing clock\n");
+			return;
+		}
+
+		scll = (unsigned int)fsscll;
+		sclh = (unsigned int)fssclh;
+	}
+
+	I2C_PRINTF("i2c_init: bus %x, base %p\n", current_bus, i2c_base);
+	
+	if (readw(&i2c_base->con) & I2C_CON_EN) {
+		writew(0, &i2c_base->con);
+		udelay(50000);
+	}
+
+	writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */
+	udelay(1000);
+
+	writew(I2C_CON_EN, &i2c_base->con);
+	while (!(readw(&i2c_base->syss) & I2C_SYSS_RDONE) && timeout--) {
+		if (timeout <= 0) {
+			printf("ERROR: Timeout in soft-reset\n");
+			return;
+		}
+		udelay(1000);
+	}
+
+	writew(0, &i2c_base->con);
+	writew(psc, &i2c_base->psc);
+	writew(scll, &i2c_base->scll);
+	writew(sclh, &i2c_base->sclh);
+
+	/* own address */
+	writew(slaveadd, &i2c_base->oa);
+	writew(I2C_CON_EN, &i2c_base->con);
+
+	/* have to enable intrrupts or OMAP i2c module doesn't work */
+	writew(I2C_IE_BF_IE | I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
+		I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie);
+	udelay(1000);
+
+	flush_fifo();
+	writew(0xFFFF, &i2c_base->stat);
+	writew(0, &i2c_base->cnt);
+
+	if (gd->flags & GD_FLG_RELOC) {
+		bus_initialized[current_bus] = 1;
+	}
+}
+
+static void flush_fifo(void)
+{	u16 stat;
+
+	/* note: if you try and read data when its not there or ready
+	 * you get a bus error
+	 */
+	while (1) {
+		stat = readw(&i2c_base->stat);
+		if (stat == I2C_STAT_RRDY) {
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
+			readb(&i2c_base->data);
+#else
+			readw(&i2c_base->data);
+#endif
+			writew(I2C_STAT_RRDY, &i2c_base->stat);
+			udelay(1000);
+		} else
+			break;
+	}
+}
+
+/* i2c_probe: Use write access
+ */
+int i2c_probe(uchar chip)
+{
+	u16 status;
+	int res = 1; /* default = fail */
+
+	if (chip == readw(&i2c_base->oa))
+		return res;
+
+	/* wait until bus is free */
+	if (wait_for_bus_free())
+		return res;
+
+	/* No data transfer, slave addr only */
+	writew(0, &i2c_base->cnt);
+	/* set slave address */
+	writew(chip, &i2c_base->sa);
+	/* stop bit needed here */
+	writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
+	       I2C_CON_STP, &i2c_base->con);
+
+	status = wait_for_event();
+	I2C_PRINTF("%02x: RAW=%04x ST=%04x\n", chip, status, readw(&i2c_base->stat));
+
+	if ((status & ~I2C_STAT_XRDY) == 0 || (status & I2C_STAT_AL))
+		goto pr_exit;			/* If pads are not configured for I2C */
+		
+	/* check for ACK (!NAK) */
+	if (!(status & I2C_STAT_NACK)) {
+		res = 0;			/* Device found */
+		/* abort transfer (force idle state) */
+		writew(I2C_CON_MST | I2C_CON_TRX, &i2c_base->con); 	/* Reset cntrlr */
+		udelay(1000);
+		writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX |
+			I2C_CON_STP, &i2c_base->con);			/* STP */
+	}
+pr_exit:	
+	flush_fifo();
+	writew(0xFFFF, &i2c_base->stat);
+	writew(0, &i2c_base->cnt);
+	return res;
+}
+
+/* i2c_read: Function now uses a single I2C read transaction with bulk transfer of
+ *           up to 64 bytes ('i2c md' command limits this to 16 bytes anyway). If
+ *           CONFIG_I2C_REPEATED_START is defined in the board config header, this
+ *           transaction shall be with Repeated Start (Sr) between the address and
+ *           data phases; otherwise Stop-Start (P-S) shall be used (some I2C chips do
+ *           require a Stop-Start).
+ *           The address (reg offset) may be 0, 1 or 2 bytes long.
+ *           Function now reads correctly from chips that return more than one byte
+ *           of data per addressed register (such as TI temperature sensors), or that
+ *           do not need a register address (such as some clock distributors).
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+	int i2c_error = 0;
+	u16 status, acnt;
+
+	if (alen < 0) {
+		printf("I2C read: addr len < 0\n");
+		return 1;	
+	}
+	if (len < 0) {
+		printf("I2C read: data len < 0\n");
+		return 1;	
+	}
+	if (buffer == NULL) {
+		printf("I2C read: NULL pointer passed\n");
+		return 1;	
+	}
+
+	if (alen > 2) {
+		printf("I2C read: addr len %d not supported\n", alen);
+		return 1;
+	}
+
+	if (len > 64) {
+		printf("I2C read: max data len 64 (0x40) allowed\n");
+		return 1;
+	}
+
+	acnt = alen;
+
+	/* Wait until bus is free */
+	if (wait_for_bus_free())
+		return 1;
+
+	/* Zero, one or two bytes reg address (offset) */
+	writew(acnt, &i2c_base->cnt);
+	/* Set slave address */
+	writew(chip, &i2c_base->sa);
+
+	if (acnt) {
+		/* Must write reg offset first */
+#ifdef CONFIG_I2C_REPEATED_START
+		/* No stop bit, use Repeated Start */
+		writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
+	      		I2C_CON_TRX, &i2c_base->con);
+#else
+		/* Stop - Start */
+		writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP |
+	      		I2C_CON_TRX, &i2c_base->con);
+#endif
+		/* Send register offset */
+		while (1) {
+			status = wait_for_event();
+			I2C_PRINTF("RD: WR offs: ST=%04X\n", status);
+			/* Try to identify bus that is not padconf'd for I2C */
+			if (status == I2C_STAT_XRDY) {
+				i2c_error = 2;
+				printf("i2c_read: pads on bus %d probably not configured (status=0x%x)\n",
+			      		current_bus, status);
+				goto rd_exit;
+			}
+			if (status == 0 || status & I2C_STAT_NACK) {
+				i2c_error = 1;
+				printf("i2c_read: error waiting for addr ACK (status=0x%x)\n",
+			      		status);
+				goto rd_exit;
+			}
+			if (acnt) {
+				if (status & I2C_STAT_XRDY) {
+					acnt--;
+					/* Do we have to use byte access? */
+					writeb((addr >> (8 * acnt)) & 0xff, &i2c_base->data);
+					writew(I2C_STAT_XRDY, &i2c_base->stat);
+				}
+			}
+			if (status & I2C_STAT_ARDY) {
+				writew(I2C_STAT_ARDY, &i2c_base->stat);
+				break;
+			}
+		}
+	}
+	/* Set slave address */
+	writew(chip, &i2c_base->sa);
+	/* Read len bytes from slave */
+	writew(len, &i2c_base->cnt);
+	/* Need stop bit here */
+	writew(I2C_CON_EN | I2C_CON_MST |
+		I2C_CON_STT | I2C_CON_STP,
+		&i2c_base->con);
+
+	/* Receive data */
+	while (1) {
+		status = wait_for_event();
+		I2C_PRINTF("RD: RD data: ST=%04X\n", status);
+		if (status == 0 || status & I2C_STAT_NACK) {
+			i2c_error = 1;
+			goto rd_exit;
+		}
+		if (status & I2C_STAT_RRDY) {
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
+			*buffer++ = readb(&i2c_base->data);
+#else
+			*buffer++ = readw(&i2c_base->data) & 0xff;
+#endif
+			writew(I2C_STAT_RRDY, &i2c_base->stat);
+		}
+		if (status & I2C_STAT_ARDY) {
+			writew(I2C_STAT_ARDY, &i2c_base->stat);
+			break;
+		}
+	}
+
+rd_exit:
+	flush_fifo();
+	writew(0xFFFF, &i2c_base->stat);
+	writew(0, &i2c_base->cnt);
+	return i2c_error;
+}
+
+/* i2c_write: Address (reg offset) may be 0, 1 or 2 bytes long.
+ *            Up to 64 total bytes (addr + data) may be transferred.
+ */
+int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+{
+	int i;
+	u16 status, acnt;
+	int i2c_error = 0;
+
+	if (alen < 0) {
+		printf("I2C write: addr len < 0\n");
+		return 1;	
+	}
+	if (len < 0) {
+		printf("I2C write: data len < 0\n");
+		return 1;	
+	}
+	if (buffer == NULL) {
+		printf("I2C write: NULL pointer passed\n");
+		return 1;	
+	}
+	if (alen > 2) {
+		printf("I2C write: addr len %d not supported\n", alen);
+		return 1;
+	}
+	if (alen + len > 64) {
+		printf("I2C write: max (alen + len) of 64 (0x40) allowed\n");
+		return 1;
+	}
+
+	acnt = alen;
+
+	/* Wait until bus is free */
+	if (wait_for_bus_free())
+		return 1;
+
+	/* Start address phase - will write regoffset + len bytes data */
+	writew(alen + len, &i2c_base->cnt);
+	/* Set slave address */
+	writew(chip, &i2c_base->sa);
+	/* Stop bit needed */
+	writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
+		I2C_CON_STP, &i2c_base->con);
+
+	while (acnt) {
+		/* Must write reg offset (one or two bytes) */
+		status = wait_for_event();
+		I2C_PRINTF("WR: WR offs: ST=%04X\n", status);
+		/* Try to identify bus that is not padconf'd for I2C */
+		if (status == I2C_STAT_XRDY) {
+			i2c_error = 2;
+			printf("i2c_write: pads on bus %d probably not configured (status=0x%x)\n",
+		      		current_bus, status);
+			goto wr_exit;
+		}
+		if (status == 0 || status & I2C_STAT_NACK) {
+			i2c_error = 1;
+			printf("i2c_write: error waiting for addr ACK (status=0x%x)\n",
+			      	status);
+			goto wr_exit;
+		}
+		if (status & I2C_STAT_XRDY) {
+			acnt--;
+			writeb((addr >> (8 * acnt)) & 0xff, &i2c_base->data);
+			writew(I2C_STAT_XRDY, &i2c_base->stat);
+		}
+		else {
+			i2c_error = 1;
+			printf("i2c_write: bus not ready for addr Tx (status=0x%x)\n",
+			      status);
+			goto wr_exit;
+		}
+	}
+	/* Address phase is over, now write data */
+	for (i = 0; i < len; i++) {
+		status = wait_for_event();
+		I2C_PRINTF("WR: WR data: ST=%04X\n", status);
+		if (status == 0 || status & I2C_STAT_NACK) {
+			i2c_error = 1;
+			printf("i2c_write: error waiting for data ACK (status=0x%x)\n",
+					status);
+			goto wr_exit;
+		}
+		if (status & I2C_STAT_XRDY) {
+			writeb(buffer[i], &i2c_base->data);
+			writew(I2C_STAT_XRDY, &i2c_base->stat);
+		}
+		else {
+			i2c_error = 1;
+			printf("i2c_write: bus not ready for data Tx (i=%d)\n", i);
+			goto wr_exit;
+		}
+	}
+
+wr_exit:
+	flush_fifo();
+	writew(0xFFFF, &i2c_base->stat);
+	writew(0, &i2c_base->cnt);
+	return i2c_error;
+}
+
+/* Wait for the bus to be free by checking the Bus Busy (BB)
+ * bit to become clear
+ */
+static int wait_for_bus_free(void)
+{
+	int timeout = I2C_TIMEOUT, res = 0;
+	u16 stat;
+
+	writew(0xFFFF, &i2c_base->stat);	/* clear current interrupts...*/
+	/* Read RAW status */
+	while ((stat = readw(&i2c_base->irqstatus_raw) & I2C_STAT_BB) && timeout--) {
+		writew(stat, &i2c_base->stat);
+		udelay(200);
+	}
+
+	if (timeout <= 0) {
+		printf("Timed out in wait_for_bus_free: I2C_STAT_RAW=%x\n",
+			readw(&i2c_base->irqstatus_raw));
+		res = 1;
+	}
+	writew(0xFFFF, &i2c_base->stat);	 /* clear delayed stuff */
+	return res;
+}
+
+/* Wait for the I2C controller to complete current action
+ * and update status
+ */
+static u16 wait_for_event(void)
+{
+	u16 status;
+	int timeout = I2C_TIMEOUT;
+
+	do {
+		udelay(200);
+		status = readw(&i2c_base->irqstatus_raw);
+	} while (!(status &
+		   (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
+		    I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
+		    I2C_STAT_AL)) && timeout--);
+
+	if (timeout <= 0) {
+		printf("Timed out in wait_for_event: I2C_STAT_RAW=%x\n",
+			readw(&i2c_base->irqstatus_raw));
+		writew(0xFFFF, &i2c_base->stat);
+		status = 0;
+	}
+	return status;
+}
+
+int i2c_set_bus_num(unsigned int bus)
+{
+	if (bus >= I2C_BUS_MAX) {
+		printf("Bad bus: %x\n", bus);
+		return -1;
+	}
+
+	switch (bus) {
+		default:
+			bus = 0;	/* Fall through */
+		case 0:
+			i2c_base = (struct i2c *)I2C_BASE1;
+			break; 
+		case 1:
+			i2c_base = (struct i2c *)I2C_BASE2;
+			break;
+#if (I2C_BUS_MAX > 2) 
+		case 2:
+			i2c_base = (struct i2c *)I2C_BASE3;
+			break; 
+#if (I2C_BUS_MAX > 3) 
+		case 3:
+			i2c_base = (struct i2c *)I2C_BASE4;
+			break;
+#if (I2C_BUS_MAX > 4)
+		case 4:
+			i2c_base = (struct i2c *)I2C_BASE5;
+			break;
+#endif
+#endif
+#endif
+	}
+	current_bus = bus;
+
+	if (!bus_initialized[current_bus])
+		i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+	return 0;
+}
+
+int i2c_get_bus_num(void)
+{
+	return (int) current_bus;
+}
+
diff --git a/drivers/i2c/omap4x5x_i2c.h b/drivers/i2c/omap4x5x_i2c.h
new file mode 100644
index 0000000..1277abe
--- /dev/null
+++ b/drivers/i2c/omap4x5x_i2c.h
@@ -0,0 +1,176 @@
+/*
+ * (C) Copyright 2004-2010
+ * Texas Instruments, <www.ti.com>
+ *
+ * Copyright (c) 2013 Lubomir Popov <lpopov@mm-sol.com>, MM Solutions
+ * Based on omap24xx_i2c.h and modified for OMAP4/5
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef _OMAP4x5x_I2C_H_
+#define _OMAP4x5x_I2C_H_
+
+/* I2C masks */
+
+/* I2C Interrupt Enable Register (I2C_IRQENABLE_SET): */
+
+#define I2C_IE_XDR_IE	(1 << 14)
+#define I2C_IE_RDR_IE	(1 << 13)
+#define I2C_IE_ROVR_IE	(1 << 11)
+#define I2C_IE_XUDF_IE	(1 << 10)
+#define I2C_IE_ASS_IE   (1 << 9)
+#define I2C_IE_BF_IE	(1 << 8) /* Bus Free interrupt enable */
+#define I2C_IE_AERR_IE  (1 << 7)
+#define I2C_IE_STC_IE   (1 << 6)
+#define I2C_IE_GC_IE	(1 << 5)
+#define I2C_IE_XRDY_IE	(1 << 4) /* Transmit data ready interrupt enable */
+#define I2C_IE_RRDY_IE	(1 << 3) /* Receive data ready interrupt enable */
+#define I2C_IE_ARDY_IE	(1 << 2) /* Register access ready interrupt enable */
+#define I2C_IE_NACK_IE	(1 << 1) /* No acknowledgment interrupt enable */
+#define I2C_IE_AL_IE	(1 << 0) /* Arbitration lost interrupt enable */
+
+/* I2C Status Registers (I2C_IRQSTATUS and I2C_IRQSTATUS_RAW): */
+
+#define I2C_STAT_XDR    (1 << 14) /* Transmit Draining */
+#define I2C_STAT_RDR	(1 << 13) /* Receive Draining */
+#define I2C_STAT_BB	(1 << 12) /* Bus busy */
+#define I2C_STAT_ROVR	(1 << 11) /* Receive overrun */
+#define I2C_STAT_XUDF	(1 << 10) /* Transmit underflow */
+#define I2C_STAT_AAS	(1 << 9)  /* Addressed as slave */
+#define I2C_STAT_BF     (1 << 8)  /* Bus Free */
+#define I2C_STAT_AERR   (1 << 7)  /* Access Error */
+#define I2C_STAT_STC    (1 << 6)  /* Start Condition */
+#define I2C_STAT_GC	(1 << 5)  /* General Call */
+#define I2C_STAT_XRDY	(1 << 4)  /* Transmit data ready */
+#define I2C_STAT_RRDY	(1 << 3)  /* Receive data ready */
+#define I2C_STAT_ARDY	(1 << 2)  /* Register access ready */
+#define I2C_STAT_NACK	(1 << 1)  /* No acknowledgment */
+#define I2C_STAT_AL	(1 << 0)  /* Arbitration lost */
+
+/* I2C Buffer Configuration Register (I2C_BUF): */
+
+#define I2C_BUF_RDMA_EN		(1 << 15) /* Receive DMA channel enable */
+#define I2C_BUF_XDMA_EN		(1 << 7)  /* Transmit DMA channel enable */
+
+/* I2C Configuration Register (I2C_CON): */
+
+#define I2C_CON_EN	(1 << 15)  /* I2C module enable */
+#define I2C_CON_BE	(1 << 14)  /* Big endian mode */
+#define I2C_CON_STB	(1 << 11)  /* Start byte mode (master mode only) */
+#define I2C_CON_MST	(1 << 10)  /* Master/slave mode */
+#define I2C_CON_TRX	(1 << 9)   /* Transmitter/receiver mode */
+				   /* (master mode only) */
+#define I2C_CON_XA	(1 << 8)   /* Expand address */
+#define I2C_CON_STP	(1 << 1)   /* Stop condition (master mode only) */
+#define I2C_CON_STT	(1 << 0)   /* Start condition (master mode only) */
+
+/* I2C System Test Register (I2C_SYSTEST): */
+
+#define I2C_SYSTEST_ST_EN	(1 << 15) /* System test enable */
+#define I2C_SYSTEST_FREE	(1 << 14) /* Free running mode, on brkpoint) */
+#define I2C_SYSTEST_TMODE_MASK	(3 << 12) /* Test mode select */
+#define I2C_SYSTEST_TMODE_SHIFT	(12)	  /* Test mode select */
+#define I2C_SYSTEST_SCL_I	(1 << 3)  /* SCL line sense input value */
+#define I2C_SYSTEST_SCL_O	(1 << 2)  /* SCL line drive output value */
+#define I2C_SYSTEST_SDA_I	(1 << 1)  /* SDA line sense input value */
+#define I2C_SYSTEST_SDA_O	(1 << 0)  /* SDA line drive output value */
+
+/* I2C System Status Register (I2C_SYSS): */
+
+#define I2C_SYSS_RDONE          (1 << 0)  /* Internel reset monitoring */
+
+#define I2C_SCLL_SCLL		0
+#define I2C_SCLL_SCLL_M		0xFF
+#define I2C_SCLL_HSSCLL		8
+#define I2C_SCLH_HSSCLL_M	0xFF
+#define I2C_SCLH_SCLH		0
+#define I2C_SCLH_SCLH_M		0xFF
+#define I2C_SCLH_HSSCLH		8
+#define I2C_SCLH_HSSCLH_M	0xFF
+
+#define OMAP_I2C_STANDARD	100000
+#define OMAP_I2C_FAST_MODE	400000
+#define OMAP_I2C_HIGH_SPEED	3400000
+
+#define SYSTEM_CLOCK_12		12000000
+#define SYSTEM_CLOCK_13		13000000
+#define SYSTEM_CLOCK_192	19200000
+#define SYSTEM_CLOCK_96		96000000
+
+/* Use the reference value of 96MHz if not explicitly set by the board */
+#ifndef I2C_IP_CLK
+#define I2C_IP_CLK		SYSTEM_CLOCK_96
+#endif
+
+/*
+ * The reference minimum clock for high speed is 19.2MHz.
+ * The linux 2.6.30 kernel uses this value.
+ * The reference minimum clock for fast mode is 9.6MHz
+ * The reference minimum clock for standard mode is 4MHz
+ * In TRM, the value of 12MHz is used.
+ */
+#ifndef I2C_INTERNAL_SAMPLING_CLK
+#define I2C_INTERNAL_SAMPLING_CLK	19200000
+#endif
+
+/*
+ * The equation for the low and high time is
+ * tlow = scll + scll_trim = (sampling clock * tlow_duty) / speed
+ * thigh = sclh + sclh_trim = (sampling clock * (1 - tlow_duty)) / speed
+ *
+ * If the duty cycle is 50%
+ *
+ * tlow = scll + scll_trim = sampling clock / (2 * speed)
+ * thigh = sclh + sclh_trim = sampling clock / (2 * speed)
+ *
+ * In TRM
+ * scll_trim = 7
+ * sclh_trim = 5
+ *
+ * The linux 2.6.30 kernel uses
+ * scll_trim = 6
+ * sclh_trim = 6
+ *
+ * These are the trim values for standard and fast speed
+ */
+#ifndef I2C_FASTSPEED_SCLL_TRIM
+#define I2C_FASTSPEED_SCLL_TRIM		6
+#endif
+#ifndef I2C_FASTSPEED_SCLH_TRIM
+#define I2C_FASTSPEED_SCLH_TRIM		6
+#endif
+
+/* These are the trim values for high speed */
+#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM
+#define I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM	I2C_FASTSPEED_SCLL_TRIM
+#endif
+#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM
+#define I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM	I2C_FASTSPEED_SCLH_TRIM
+#endif
+#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM
+#define I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM	I2C_FASTSPEED_SCLL_TRIM
+#endif
+#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM
+#define I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM	I2C_FASTSPEED_SCLH_TRIM
+#endif
+
+#define I2C_PSC_MAX		0x0f
+#define I2C_PSC_MIN		0x00
+
+#endif /* _OMAP4x5x_I2C_H_ */
-- 
1.7.9.5

             reply	other threads:[~2013-03-29 16:36 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-03-29 16:36 Lubomir Popov [this message]
2013-04-02 19:16 ` [U-Boot] [PATCH 2/2] OMAP4/5: I2C: New I2C driver files added Tom Rini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5155C318.1070203@mm-sol.com \
    --to=lpopov@mm-sol.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.