[U-Boot-Users] [Patch 8/9]U-boot-V2:I2C:Busses: OMAP I2C Adapter

Menon, Nishanth x0nishan at ti.com
Thu Jun 19 17:13:30 CEST 2008


Introduce the i2c adapter for OMAP i2c controller
This is mostly a port from 2.6.26 rc5 kernel at:
http://git.kernel.org/git/?p=linux/kernel/git/tmlind/linux-omap-2.6.git

Signed-off-by: Nishanth Menon <x0nishan at ti.com>

---
 drivers/i2c/busses/Kconfig      |    7
 drivers/i2c/busses/i2c-omap.c   |  678 ++++++++++++++++++++++++++++++++++++++++
 include/asm-arm/arch-omap/i2c.h |  154 +++++++++
 3 files changed, 839 insertions(+)

Index: u-boot-v2.git/drivers/i2c/busses/i2c-omap.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/drivers/i2c/busses/i2c-omap.c 2008-06-19 08:51:23.000000000 -0500
@@ -0,0 +1,678 @@
+/**
+ * @file
+ * @brief OMAP I2C Adapter driver
+ *
+ * FileName: drivers/i2c/busses/i2c-omap.c
+ *
+ */
+/*
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan at ti.com>
+ *
+ * based on Linux kernel omap i2c adapter driver
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2004 - 2007 Texas Instruments.
+ *
+ * Originally written by MontaVista Software, Inc.
+ * Additional contributions by:
+ *     Tony Lindgren <tony at atomide.com>
+ *     Imre Deak <imre.deak at nokia.com>
+ *     Juha Yrjola <juha.yrjola at nokia.com>
+ *     Syed Khasim <x0khasim at ti.com>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <config.h>
+#include <errno.h>
+#include <init.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <clock.h>
+#include <linux/i2c.h>
+#include <asm/io.h>
+#include <asm/arch/silicon.h>
+#include <asm/arch/i2c.h>
+
+/*---------------------- Debug Messages -------------------------------------*/
+#ifdef CONFIG_I2C_DEBUG_BUS
+#define DBG_MODULE_NAME "omap-i2c"
+#define dev_dbg(ARGS...) fprintf(stdout, ARGS);
+#define dev_warn(ARGS...) fprintf(stderr, ARGS);
+#define dbg_entry(FORMAT, ARGS...) fprintf(stdout,\
+               DBG_MODULE_NAME"%s:%d:Entry:"FORMAT"\n",\
+               __func__, __LINE__, ARGS)
+#define dbg_exit(FORMAT, ARGS...) fprintf(stdout,\
+               DBG_MODULE_NAME"%s:%d:Exit:"FORMAT"\n",\
+               __func__, __LINE__, ARGS)
+#else
+#define dev_dbg(ARGS...)
+#define dev_warn(ARGS...)
+#define dbg_entry(FORMAT, ARGS...)
+#define dbg_exit(FORMAT, ARGS...)
+#endif
+#define dev_err(ARGS...) fprintf(stderr, ARGS);
+
+/*---------------------- Defines --------------------------------------------*/
+/* Hack to enable zero length transfers and smbus quick until clean fix
+   is available */
+#define OMAP_HACK
+
+/*---------------------- Private Data Structures ----------------------------*/
+struct omap_i2c_dev {
+       unsigned long base;     /* virtual */
+       u32 speed;              /* Speed of bus in Khz */
+       u32 fclk;               /* Functional clock speed */
+       u16 cmd_err;
+       u8 *buf;
+       size_t buf_len;
+       struct i2c_adapter adapter;
+       u8 fifo_size;           /* use as flag and value
+                                * fifo_size==0 implies no fifo
+                                * if set, should be trsh+1
+                                */
+       unsigned rev1:1;
+       unsigned b_hw:1;        /* bad h/w fixes */
+};
+
+/*---------------------- Implementation -------------------------------------*/
+
+static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
+                                     int reg, u16 val)
+{
+       dbg_entry("i2c_dev=%x reg=%x val=%x", (u32) i2c_dev, reg, val);
+       __raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
+{
+       dbg_entry("i2c_dev=%x reg=%x", (u32) i2c_dev, reg);
+       return __raw_readw(i2c_dev->base + reg);
+}
+
+static int omap_i2c_init(struct omap_i2c_dev *dev)
+{
+       u16 psc = 0, scll = 0, sclh = 0;
+       u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
+       unsigned long fclk_rate = 12000000;
+       unsigned long internal_clk = 0;
+
+       dbg_entry("dev=%x", (u32) dev);
+       if (!dev->rev1) {
+               /* For some reason we need to set the EN bit before the
+                * reset done bit gets set. */
+               uint64_t timeout = OMAP_I2C_TIMEOUT;
+               uint64_t start;
+
+               start = get_time_ns();
+               omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
+               omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+               while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) &
+                        OMAP_I2C_SYSS_RDONE)) {
+                       if (is_timeout(start, timeout)) {
+                               dev_err("timeout waiting for bus ready\n");
+                               return -ETIMEDOUT;
+                       }
+               }
+       }
+       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+
+       if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+
+               /* HSI2C controller internal clk rate should be 19.2 Mhz */
+               if (dev->speed > 400)
+                       internal_clk = 19200;
+               else if (dev->speed > 100)
+                       internal_clk = 9600;
+               else
+                       internal_clk = 4000;
+               fclk_rate = dev->fclk / 1000;
+
+               /* Compute prescaler divisor */
+               psc = fclk_rate / internal_clk;
+               psc = psc - 1;
+
+               /* If configured for High Speed */
+               if (dev->speed > 400) {
+                       /* For first phase of HS mode */
+                       fsscll = internal_clk / (400 * 2) - 7;
+                       fssclh = internal_clk / (400 * 2) - 5;
+
+                       /* For second phase of HS mode */
+                       hsscll = fclk_rate / (dev->speed * 2) - 7;
+                       hssclh = fclk_rate / (dev->speed * 2) - 5;
+               } else {
+                       /* To handle F/S modes */
+                       fsscll = internal_clk / (dev->speed * 2) - 7;
+                       fssclh = internal_clk / (dev->speed * 2) - 5;
+               }
+               scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
+               sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
+               dev_dbg("base=%x,fclk=%d fclk_rate =%d, iclk=%d dev->speed=%d\n"
+                       "psc=%x fsscll=%x fssclh=%x hsscll=%x hssclh=%x\n"
+                       "scll=%x sclh=%x\n",
+                       dev->base, dev->fclk, fclk_rate, internal_clk,
+                       dev->speed, psc, fsscll, fssclh, hsscll, hssclh,
+                       scll, sclh);
+       } else {
+               /* Program desired operating rate */
+               fclk_rate /= (psc + 1) * 1000;
+               if (psc > 2)
+                       psc = 2;
+               scll = fclk_rate / (dev->speed * 2) - 7 + psc;
+               sclh = fclk_rate / (dev->speed * 2) - 7 + psc;
+       }
+
+       /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
+       omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
+
+       /* SCL low and high time values */
+       omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
+       omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
+
+       if (dev->fifo_size)
+               /* Note: setup required fifo size - 1 */
+               omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
+                               (dev->fifo_size - 1) << 8 |     /* RTRSH */
+                               OMAP_I2C_BUF_RXFIF_CLR |
+                               (dev->fifo_size - 1) |          /* XTRSH */
+                               OMAP_I2C_BUF_TXFIF_CLR);
+
+       /* DO NOT Enable interrupts -we work in polling mode */
+       omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
+
+       /* Take the I2C module out of reset: */
+       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+
+       return 0;
+}
+
+/*
+ * Waiting on Bus Busy
+ */
+static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
+{
+       uint64_t start, timeout;
+
+       dbg_entry("dev=%x", (u32) dev);
+
+       timeout = OMAP_I2C_TIMEOUT;
+       start = get_time_ns();
+
+       while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
+               if (is_timeout(start, timeout)) {
+                       dev_err("timeout waiting for bus ready\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static int omap_i2c_rev1_wait_event(struct omap_i2c_dev *dev, uint64_t timeout)
+{
+       u16 iv, w;
+       int stat = 0;
+       uint64_t start;
+
+       start = get_time_ns();
+       dbg_entry("dev=%x", (u32) dev);
+       /* we dont have anything better to do..
+        * So poll the status reg
+        */
+       while (!stat) {
+               if (is_timeout(start, timeout)) {
+                       dev_err("waitevent Timeout!");
+                       stat = -ETIMEDOUT;
+                       continue;
+               }
+               iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
+               switch (iv) {
+               case 0x01:      /* Arbitration lost */
+                       dev_err("Arbitration lost\n");
+                       dev->cmd_err = OMAP_I2C_STAT_AL;
+                       return 0;
+                       break;
+               case 0x02:      /* No acknowledgement */
+                       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+                                          OMAP_I2C_CON_STP);
+                       dev->cmd_err = OMAP_I2C_STAT_NACK;
+                       return 0;
+                       break;
+               case 0x03:      /* Register access ready */
+                       dev->cmd_err = 0;
+                       return 0;
+               case 0x04:      /* Receive data ready */
+                       if (dev->buf_len) {
+                               w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+                               *dev->buf++ = w;
+                               dev->buf_len--;
+                               if (dev->buf_len) {
+                                       *dev->buf++ = w >> 8;
+                                       dev->buf_len--;
+                               }
+                       } else {
+                               dev_err("RRDY IRQ while no data requested\n");
+                               stat = -2;
+                       }
+                       break;
+               case 0x05:      /* Transmit data ready */
+                       if (dev->buf_len) {
+                               w = *dev->buf++;
+                               dev->buf_len--;
+                               if (dev->buf_len) {
+                                       w |= *dev->buf++ << 8;
+                                       dev->buf_len--;
+                               }
+                               omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+                       } else {
+                               dev_err("XRDY IRQ while no data to send\n");
+                               stat = -1;
+                       }
+               case 0x00:      /* None */
+                       /* default.. continue to wait */
+                       break;
+               }
+       }
+
+       return stat;
+}
+
+static int omap_i2c_wait_event(struct omap_i2c_dev *dev, uint64_t timeout)
+{
+       u16 bits;
+       u16 stat, w;
+       int err;
+       uint64_t start;
+       dev_dbg("dev=%x timeout=%x", (u32) dev, timeout);
+
+       bits = OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ARDY |
+           OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+           OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR;
+
+       start = get_time_ns();
+       /* We will exit out of this loop eventually.
+        * Trusting the hardware?
+        */
+       while (1) {
+               stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)) & bits;
+
+               /* No Stat update? re-read */
+               if (!stat) {
+                       if (is_timeout(start, timeout)) {
+                               dev_err("waitevent Timeout!\n");
+                               return -ETIMEDOUT;
+                       }
+                       continue;
+               }
+
+               /* Ack other signals, but NOT RDY signals -> we need to do
+                * that after transfer of data
+                */
+               omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
+                               ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+                                 OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+
+               err = 0;
+               if (stat & OMAP_I2C_STAT_NACK) {
+                       dev_dbg("Nacked!\n", stat);
+                       err |= OMAP_I2C_STAT_NACK;
+               }
+               if (stat & OMAP_I2C_STAT_AL) {
+                       dev_err("Arbitration lost\n");
+                       err |= OMAP_I2C_STAT_AL;
+               }
+               if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
+                           OMAP_I2C_STAT_AL)) {
+                       dev->cmd_err = err;
+                       return 0;
+               }
+
+               if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
+                       u8 num_bytes = 1;
+                       if (dev->fifo_size) {
+                               num_bytes =
+                                   (stat & OMAP_I2C_STAT_RRDY) ? dev->
+                                   fifo_size : omap_i2c_read_reg(dev,
+                                                 OMAP_I2C_BUFSTAT_REG);
+                       }
+                       while (num_bytes) {
+                               num_bytes--;
+                               w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+                               if (dev->buf_len) {
+                                       *dev->buf++ = w;
+                                       dev->buf_len--;
+                                       /* Data reg from 2430 is 8 bit wide */
+                                       if (!cpu_is_omap2430() &&
+                                           !cpu_is_omap34xx()) {
+                                               if (dev->buf_len) {
+                                                       *dev->buf++ = w >> 8;
+                                                       dev->buf_len--;
+                                               }
+                                       }
+                               } else {
+                                       if (stat & OMAP_I2C_STAT_RRDY)
+                                               dev_err
+                                                   ("RRDY IRQ while no data "
+                                                    "requested\n");
+                                       if (stat & OMAP_I2C_STAT_RDR)
+                                               dev_err("RDR IRQ while no data "
+                                                       "requested\n");
+                                       return -2;
+                               }
+                       }
+                       omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
+                               (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
+               }
+               if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
+                       u8 num_bytes = 1;
+                       if (dev->fifo_size) {
+                               num_bytes =
+                                   (stat & OMAP_I2C_STAT_XRDY) ? dev->
+                                   fifo_size : omap_i2c_read_reg(dev,
+                                                 OMAP_I2C_BUFSTAT_REG);
+                       }
+                       while (num_bytes) {
+                               num_bytes--;
+                               w = 0;
+                               if (dev->buf_len) {
+                                       w = *dev->buf++;
+                                       dev->buf_len--;
+                                       /* Data reg from  2430 is 8 bit wide */
+                                       if (!cpu_is_omap2430() &&
+                                           !cpu_is_omap34xx()) {
+                                               if (dev->buf_len) {
+                                                       w |= *dev->buf++ << 8;
+                                                       dev->buf_len--;
+                                               }
+                                       }
+                               } else {
+                                       if (stat & OMAP_I2C_STAT_XRDY)
+                                               dev_err("XRDY IRQ while no "
+                                                       "data to send\n");
+                                       if (stat & OMAP_I2C_STAT_XDR)
+                                               dev_err("XDR IRQ while no "
+                                                       "data to send\n");
+                                       return -2;
+                               }
+                               omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+                       }
+                       omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
+                               (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+               }
+               if (stat & OMAP_I2C_STAT_ROVR) {
+                       dev_err("Receive overrun\n");
+                       dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+               }
+               if (stat & OMAP_I2C_STAT_XUDF) {
+                       dev_err("Transmit overflow\n");
+                       dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
+                            struct i2c_msg *msg, int stop)
+{
+       struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+#ifdef OMAP_HACK
+       u8 zero_byte = 0;
+#endif
+       int r;
+       u16 w;
+
+       dbg_entry("adap=%x msg=%s stop=%x", (u32) adap, (u32) msg, stop);
+       dev_dbg("addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+               msg->addr, msg->len, msg->flags, stop);
+
+#ifndef OMAP_HACK
+       if (msg->len == 0)
+               return -EINVAL;
+
+       omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+
+       /* REVISIT: Could the STB bit of I2C_CON be used with probing? */
+       dev->buf = msg->buf;
+       dev->buf_len = msg->len;
+
+#else
+
+       omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+       /* REVISIT: Remove this hack when we can get I2C chips from board-*.c
+        *          files
+        * Sigh, seems we can't do zero length transactions. Thus, we
+        * can't probe for devices w/o actually sending/receiving at least
+        * a single byte. So we'll set count to 1 for the zero length
+        * transaction case and hope we don't cause grief for some
+        * arbitrary device due to random byte write/read during
+        * probes.
+        */
+       if (msg->len == 0) {
+               dev->buf = &zero_byte;
+               dev->buf_len = 1;
+       } else {
+               dev->buf = msg->buf;
+               dev->buf_len = msg->len;
+       }
+#endif
+
+       omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
+
+       /* Clear the FIFO Buffers */
+       w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
+       w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
+       omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
+
+       dev->cmd_err = 0;
+
+       w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+
+       /* High speed configuration */
+       if (dev->speed > 400)
+               w |= OMAP_I2C_CON_OPMODE_HS;
+
+       if (msg->flags & I2C_M_TEN)
+               w |= OMAP_I2C_CON_XA;
+       if (!(msg->flags & I2C_M_RD))
+               w |= OMAP_I2C_CON_TRX;
+
+       if (!dev->b_hw && stop)
+               w |= OMAP_I2C_CON_STP;
+
+       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+
+       if (dev->b_hw && stop) {
+               /* H/w behavior: dont write stt and stp together.. */
+               while (omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
+                      OMAP_I2C_CON_STT) {
+                       /* Dont do anything - this will come in a
+                        * couple of loops at max */
+               }
+               w |= OMAP_I2C_CON_STP;
+               w &= ~OMAP_I2C_CON_STT;
+               omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+       }
+       /* We dont get data in one millisec.. some thing is definitely
+        * and badly wrong!! */
+       if ((cpu_is_omap15xx()) && dev->rev1)
+               r = omap_i2c_rev1_wait_event(dev, MSECOND);
+       else
+               r = omap_i2c_wait_event(dev, MSECOND);
+       dev->buf_len = 0;
+       if (r < 0) {
+               dev_err("controller error %d\n", r);
+               omap_i2c_init(dev);
+               return r;
+       }
+
+       if (!dev->cmd_err)
+               return 0;
+
+       /* We have an error */
+       if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
+                           OMAP_I2C_STAT_XUDF)) {
+               /* Reprogram the controller ->NOTE 2 as in flow chart of TRM */
+               omap_i2c_init(dev);
+               return -EIO;
+       }
+
+       if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
+               /* Reprogram the controller ->NOTE 2 as in flow chart of TRM */
+               omap_i2c_init(dev);
+               if (msg->flags & I2C_M_IGNORE_NAK)
+                       return 0;
+               return -EREMOTEIO;
+       }
+       return -EIO;
+}
+
+/*
+ * Prepare controller for a transaction and call omap_i2c_xfer_msg
+ * to do the work during transfer processing
+ */
+static int
+omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+       struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+       int i;
+       int r;
+
+       dbg_entry("adap=%x msgs=%x num=%x", (u32) adap, (u32) msgs, num);
+       r = omap_i2c_wait_for_bb(dev);
+       if (r < 0) {
+               dev_err("timedout waiting for bus to free\n");
+               goto out;
+       }
+
+       for (i = 0; i < num; i++) {
+               r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+               if (r != 0)
+                       break;
+       }
+
+       if (r == 0)
+               r = num;
+out:
+       return r;
+}
+
+static u32 omap_i2c_func(struct i2c_adapter *adap)
+{
+       dbg_entry("adap=%x", (u32) adap);
+       return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm omap_i2c_algo = {
+       .master_xfer = omap_i2c_xfer,
+       .functionality = omap_i2c_func,
+};
+
+static int omap_register_i2c_bus(int bus_id, unsigned long base,
+                         u32 clkrate, u32 func_clk)
+{
+       struct omap_i2c_dev *dev;
+       struct i2c_adapter *adap;
+       int r = 0;
+       dbg_entry("bus_id=%x base=%x clkrate=%x func_clk=%x info=%x len=%x",
+                 bus_id, base, clkrate, func_clk, (u32) info, len);
+       dev = calloc(sizeof(struct omap_i2c_dev), 1);
+       if (!dev) {
+               dev_err("malloc failed for omap_i2c_dev");
+               return -ENOMEM;
+       }
+
+       if (!clkrate)
+               clkrate = 100;
+
+       dev->speed = clkrate;
+       dev->fclk = func_clk;
+       dev->base = base;
+
+       if (cpu_is_omap15xx())
+               dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
+
+       if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+               /* Set up the fifo size - Get total size */
+               dev->fifo_size = 0x8 <<
+                   ((omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) &
+                    0x3);
+               /*
+                * Set up notification threshold as half the total available
+                * size. This is to ensure that we can handle the status on
+                * int call back latencies
+                */
+               dev->fifo_size = (dev->fifo_size / 2);
+               dev->b_hw = 1;  /* Enable hardware fixes */
+       }
+
+       /* reset ASAP, clearing any IRQs */
+       omap_i2c_init(dev);
+
+       r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+       dev_dbg("bus %d rev%d.%d at %d kHz\n",
+               bus_id, r >> 4, r & 0xf, dev->speed);
+
+       adap = &dev->adapter;
+       i2c_set_adapdata(adap, dev);
+       strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
+       adap->algo = &omap_i2c_algo;
+       adap->dev.parent = NULL;
+
+       /* i2c device drivers may be active on return from add_adapter() */
+       adap->nr = bus_id;
+       r = i2c_add_numbered_adapter(adap);
+       if (r) {
+               dev_err("failure adding adapter %d\n", r);
+               free(dev);
+       }
+       return r;
+}
+
+static int omap_i2c_probe(struct device_d *dev)
+{
+        struct i2c_omap_platform_data *i2cp =
+                (struct i2c_omap_platform_data *) (dev->platform_data);
+        if (i2cp == NULL) {
+                dev_err("I2c_OMAP: need platform data\n");
+                return -EINVAL;
+        }
+       return omap_register_i2c_bus(i2cp->bus_id,
+                                    dev->map_base,
+                                    i2cp->i2c_clock_speed,
+                                    i2cp->func_clk);
+}
+
+static struct driver_d omapi2c_drv = {
+       .name = OMAP_I2C_ADAPTER_NAME,
+       .probe = omap_i2c_probe,
+       .type = DEVICE_TYPE_I2C,
+};
+
+static int omap_i2cdrv_init(void)
+{
+       int ret;
+       ret = register_driver(&omapi2c_drv);
+       return ret;
+}
+device_initcall(omap_i2cdrv_init);
Index: u-boot-v2.git/drivers/i2c/busses/Kconfig
===================================================================
--- u-boot-v2.git.orig/drivers/i2c/busses/Kconfig       2008-06-19 08:42:46.000000000 -0500
+++ u-boot-v2.git/drivers/i2c/busses/Kconfig    2008-06-19 08:51:23.000000000 -0500
@@ -4,4 +4,11 @@

 menu "I2C Hardware Bus support"

+config I2C_OMAP
+       bool "OMAP I2C adapter"
+       depends on ARCH_OMAP
+       help
+         If you say yes to this option, support will be included for the
+         I2C interface on the Texas Instruments OMAP family of processors.
+         For details see http://www.ti.com/omap.
 endmenu
Index: u-boot-v2.git/include/asm-arm/arch-omap/i2c.h
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ u-boot-v2.git/include/asm-arm/arch-omap/i2c.h       2008-06-19 08:51:23.000000000 -0500
@@ -0,0 +1,154 @@
+/**
+ * @file
+ * @brief definitions for OMAP I2C Adapter driver
+ *
+ * FileName: include/asm-arm/arch-omap/i2c.h
+ *
+ */
+/*
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Nishanth Menon <x0nishan at ti.com>
+ *
+ * based on Linux kernel omap i2c adapter driver.
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2004 - 2007 Texas Instruments.
+ *
+ * Originally written by MontaVista Software, Inc.
+ * Additional contributions by:
+ *     Tony Lindgren <tony at atomide.com>
+ *     Imre Deak <imre.deak at nokia.com>
+ *     Juha Yrjola <juha.yrjola at nokia.com>
+ *     Syed Khasim <x0khasim at ti.com>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP_I2C_H
+#define __ASM_ARCH_OMAP_I2C_H
+
+/*********** Stuff Interesting to board files ***********/
+
+#define OMAP_I2C_FCLK_96MHZ (96 * 1000 * 1000)
+#define OMAP_I2C_FCLK_48MHZ (48 * 1000 * 1000)
+
+/* Some Common i2c speeds */
+#define OMAP_I2C_CLK_2P6M (2600)
+#define OMAP_I2C_CLK_400K (400)
+#define OMAP_I2C_CLK_100K (100)
+
+/** I2c platform data that is registered by board files */
+struct i2c_omap_platform_data {
+       /** Give the bus index here */
+       int bus_id;
+       /** required i2c clock speed in khz */
+       u32 i2c_clock_speed;
+       /** Func clk speed of i2c -based on clock arch */
+       u32 func_clk;
+};
+
+/** Use this when you define an adapter instance in board file */
+#define OMAP_I2C_ADAPTER_NAME "omap-i2c"
+
+/*********** Stuff Interesting to OMAP Adapter ***********/
+
+/* timeout waiting for the controller to respond */
+#define OMAP_I2C_TIMEOUT MSECOND
+
+/* I2C Register defines */
+#define OMAP_I2C_REV_REG               0x00
+#define OMAP_I2C_IE_REG                        0x04
+#define OMAP_I2C_STAT_REG              0x08
+#define OMAP_I2C_IV_REG                        0x0c
+#define OMAP_I2C_SYSS_REG              0x10
+#define OMAP_I2C_BUF_REG               0x14
+#define OMAP_I2C_CNT_REG               0x18
+#define OMAP_I2C_DATA_REG              0x1c
+#define OMAP_I2C_SYSC_REG              0x20
+#define OMAP_I2C_CON_REG               0x24
+#define OMAP_I2C_OA_REG                        0x28
+#define OMAP_I2C_SA_REG                        0x2c
+#define OMAP_I2C_PSC_REG               0x30
+#define OMAP_I2C_SCLL_REG              0x34
+#define OMAP_I2C_SCLH_REG              0x38
+#define OMAP_I2C_SYSTEST_REG           0x3c
+#define OMAP_I2C_BUFSTAT_REG           0x40
+
+/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XDR                (1 << 14)       /* TX Buffer drn int enable */
+#define OMAP_I2C_IE_RDR                (1 << 13)       /* RX Buffer drn int enable */
+#define OMAP_I2C_IE_XRDY       (1 << 4)        /* TX data ready int enable */
+#define OMAP_I2C_IE_RRDY       (1 << 3)        /* RX data ready int enable */
+#define OMAP_I2C_IE_ARDY       (1 << 2)        /* Access ready int enable */
+#define OMAP_I2C_IE_NACK       (1 << 1)        /* No ack interrupt enable */
+#define OMAP_I2C_IE_AL         (1 << 0)        /* Arbitration lost int ena */
+
+/* I2C Status Register (OMAP_I2C_STAT): */
+#define OMAP_I2C_STAT_XDR      (1 << 14)       /* TX Buffer draining */
+#define OMAP_I2C_STAT_RDR      (1 << 13)       /* RX Buffer draining */
+#define OMAP_I2C_STAT_BB       (1 << 12)       /* Bus busy */
+#define OMAP_I2C_STAT_ROVR     (1 << 11)       /* Receive overrun */
+#define OMAP_I2C_STAT_XUDF     (1 << 10)       /* Transmit underflow */
+#define OMAP_I2C_STAT_AAS      (1 << 9)        /* Address as slave */
+#define OMAP_I2C_STAT_AD0      (1 << 8)        /* Address zero */
+#define OMAP_I2C_STAT_XRDY     (1 << 4)        /* Transmit data ready */
+#define OMAP_I2C_STAT_RRDY     (1 << 3)        /* Receive data ready */
+#define OMAP_I2C_STAT_ARDY     (1 << 2)        /* Register access ready */
+#define OMAP_I2C_STAT_NACK     (1 << 1)        /* No ack interrupt enable */
+#define OMAP_I2C_STAT_AL       (1 << 0)        /* Arbitration lost int ena */
+
+/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
+#define OMAP_I2C_BUF_RDMA_EN   (1 << 15)       /* RX DMA channel enable */
+#define OMAP_I2C_BUF_RXFIF_CLR (1 << 14)       /* RX FIFO Clear */
+#define OMAP_I2C_BUF_XDMA_EN   (1 << 7)        /* TX DMA channel enable */
+#define OMAP_I2C_BUF_TXFIF_CLR (1 << 6)        /* TX FIFO Clear */
+
+/* I2C Configuration Register (OMAP_I2C_CON): */
+#define OMAP_I2C_CON_EN                (1 << 15)       /* I2C module enable */
+#define OMAP_I2C_CON_BE                (1 << 14)       /* Big endian mode */
+#define OMAP_I2C_CON_OPMODE_HS (1 << 12)       /* High Speed support */
+#define OMAP_I2C_CON_STB       (1 << 11)       /* Start byte mode (master) */
+#define OMAP_I2C_CON_MST       (1 << 10)       /* Master/slave mode */
+#define OMAP_I2C_CON_TRX       (1 << 9)        /* TX/RX mode (master only) */
+#define OMAP_I2C_CON_XA                (1 << 8)        /* Expand address */
+#define OMAP_I2C_CON_RM                (1 << 2)        /* Repeat mode (master only) */
+#define OMAP_I2C_CON_STP       (1 << 1)        /* Stop cond (master only) */
+#define OMAP_I2C_CON_STT       (1 << 0)        /* Start condition (master) */
+
+/* I2C SCL time value when Master */
+#define OMAP_I2C_SCLL_HSSCLL   8
+#define OMAP_I2C_SCLH_HSSCLH   8
+
+/* I2C System Test Register (OMAP_I2C_SYSTEST): */
+#ifdef DEBUG
+#define OMAP_I2C_SYSTEST_ST_EN         (1 << 15)       /* System test enable */
+#define OMAP_I2C_SYSTEST_FREE          (1 << 14)       /* Free running mode */
+#define OMAP_I2C_SYSTEST_TMODE_MASK    (3 << 12)       /* Test mode select */
+#define OMAP_I2C_SYSTEST_TMODE_SHIFT   (12)            /* Test mode select */
+#define OMAP_I2C_SYSTEST_SCL_I         (1 << 3)        /* SCL line sense in */
+#define OMAP_I2C_SYSTEST_SCL_O         (1 << 2)        /* SCL line drive out */
+#define OMAP_I2C_SYSTEST_SDA_I         (1 << 1)        /* SDA line sense in */
+#define OMAP_I2C_SYSTEST_SDA_O         (1 << 0)        /* SDA line drive out */
+#endif
+
+/* I2C System Status register (OMAP_I2C_SYSS): */
+#define OMAP_I2C_SYSS_RDONE            (1 << 0)        /* Reset Done */
+
+/* I2C System Configuration Register (OMAP_I2C_SYSC): */
+#define OMAP_I2C_SYSC_SRST             (1 << 1)        /* Soft Reset */
+
+#endif         /* __ASM_ARCH_OMAP_I2C_H */




More information about the U-Boot mailing list