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

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;a=su...
Signed-off-by: Nishanth Menon x0nishan@ti.com
--- drivers/i2c/busses/Kconfig | 7 drivers/i2c/busses/i2c-omap.c | 692 ++++++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-omap/i2c.h | 158 +++++++++ 3 files changed, 857 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-17 17:01:06.000000000 -0500 @@ -0,0 +1,692 @@ +/** + * @file + * @brief OMAP I2C Adapter driver + * + * FileName: drivers/i2c/busses/i2c-omap.c + * + */ +/* + * (C) Copyright 2008 + * Texas Instruments, <www.ti.com> + * Nishanth Menon x0nishan@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@atomide.com + * Imre Deak imre.deak@nokia.com + * Juha Yrjola juha.yrjola@nokia.com + * Syed Khasim x0khasim@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); +#ifndef OMAP_HACK + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); +#else + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +#endif +} + +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 i2c_board_info const *info, unsigned int len) +{ + 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); + if (info) { + r = i2c_register_board_info(bus_id, info, len); + if (r) { + dev_err("unable to register board info %d", r); + return r; + } + } + 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, + i2cp->info, + i2cp->len); +} + +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-17 17:01:06.000000000 -0500 +++ u-boot-v2.git/drivers/i2c/busses/Kconfig 2008-06-17 17:01:06.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-17 17:01:06.000000000 -0500 @@ -0,0 +1,158 @@ +/** + * @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@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@atomide.com + * Imre Deak imre.deak@nokia.com + * Juha Yrjola juha.yrjola@nokia.com + * Syed Khasim x0khasim@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; + /** If you use i2c_board_info else NULL */ + struct i2c_board_info const *info; + /** num items of i2c_board_info else 0 */ + unsigned int len; +}; + +/** 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 */
participants (1)
-
Menon, Nishanth