From patchwork Fri Mar 29 16:36:40 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lubomir Popov X-Patchwork-Id: 232485 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 5F72B2C00B1 for ; Sat, 30 Mar 2013 06:04:45 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 6924B4A040; Fri, 29 Mar 2013 20:04:22 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Pp7PbXg9FcJZ; Fri, 29 Mar 2013 20:04:22 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 004B44A094; Fri, 29 Mar 2013 20:03:30 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E6E9C4A025 for ; Fri, 29 Mar 2013 17:37:55 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZCs0j+a-GmoJ for ; Fri, 29 Mar 2013 17:37:51 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from extserv.mm-sol.com (ns.mm-sol.com [213.240.235.226]) by theia.denx.de (Postfix) with ESMTPS id 3ED214A023 for ; Fri, 29 Mar 2013 17:37:48 +0100 (CET) Received: from intsrv.int.mm-sol.com (unknown [172.18.0.2]) by extserv.mm-sol.com (Postfix) with ESMTP id 4AB60BF23; Fri, 29 Mar 2013 18:37:46 +0200 (EET) Received: from localhost (localhost [127.0.0.1]) by intsrv.int.mm-sol.com (Postfix) with ESMTP id D96DFFC200F; Fri, 29 Mar 2013 18:37:45 +0200 (EET) X-Virus-Scanned: by amavisd-new-2.6.4 (20090625) Received: from intsrv.int.mm-sol.com ([127.0.0.1]) by localhost (mail.mm-sol.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id u56yu5JJ5tOt; Fri, 29 Mar 2013 18:37:36 +0200 (EET) Received: from [172.20.2.19] (unknown [172.20.2.19]) by intsrv.int.mm-sol.com (Postfix) with ESMTPS id B4CCDFC2007; Fri, 29 Mar 2013 18:37:36 +0200 (EET) Message-ID: <5155C318.1070203@mm-sol.com> Date: Fri, 29 Mar 2013 18:36:40 +0200 From: Lubomir Popov Organization: MM Solutions AD User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130308 Thunderbird/17.0.4 MIME-Version: 1.0 To: u-boot@lists.denx.de X-Mailman-Approved-At: Fri, 29 Mar 2013 20:03:20 +0100 Cc: Tom Rini Subject: [U-Boot] [PATCH 2/2] OMAP4/5: I2C: New I2C driver files added X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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 --- 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@ti.com, Texas Instruments + * + * Copyright (c) 2003 Wolfgang Denk, wd@denx.de + * Rewritten to fit into the current U-Boot framework + * + * Adapted for OMAP2420 I2C, r-woodruff2@ti.com + * + * Copyright (c) 2013 Lubomir Popov , 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 + +#include +#include + +#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, + * + * Copyright (c) 2013 Lubomir Popov , 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_ */