Commit 8c8463cce44d849e37744749b32d38e1dfb12e50

Authored by Sascha Hauer
Committed by Peter Pearse
1 parent c98b47ad24

add an i2c driver for mx31

This patch adds an i2c driver for Freescale i.MX processors

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Guennadi Liakhovetski <lg@denx.de>

Showing 2 changed files with 208 additions and 0 deletions Side-by-side Diff

drivers/i2c/Makefile
... ... @@ -29,6 +29,7 @@
29 29 COBJS-y += omap1510_i2c.o
30 30 COBJS-y += omap24xx_i2c.o
31 31 COBJS-y += tsi108_i2c.o
  32 +COBJS-y += mxc_i2c.o
32 33  
33 34 COBJS := $(COBJS-y)
34 35 SRCS := $(COBJS:.o=.c)
drivers/i2c/mxc_i2c.c
  1 +/*
  2 + * i2c driver for Freescale mx31
  3 + *
  4 + * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
  5 + *
  6 + * See file CREDITS for list of people who contributed to this
  7 + * project.
  8 + *
  9 + * This program is free software; you can redistribute it and/or
  10 + * modify it under the terms of the GNU General Public License as
  11 + * published by the Free Software Foundation; either version 2 of
  12 + * the License, or (at your option) any later version.
  13 + *
  14 + * This program is distributed in the hope that it will be useful,
  15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + * GNU General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program; if not, write to the Free Software
  21 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  22 + * MA 02111-1307 USA
  23 + */
  24 +
  25 +#include <common.h>
  26 +
  27 +#if defined(CONFIG_HARD_I2C) && defined(CONFIG_I2C_MXC)
  28 +
  29 +#include <asm/arch/mx31.h>
  30 +#include <asm/arch/mx31-regs.h>
  31 +
  32 +#define IADR 0x00
  33 +#define IFDR 0x04
  34 +#define I2CR 0x08
  35 +#define I2SR 0x0c
  36 +#define I2DR 0x10
  37 +
  38 +#define I2CR_IEN (1 << 7)
  39 +#define I2CR_IIEN (1 << 6)
  40 +#define I2CR_MSTA (1 << 5)
  41 +#define I2CR_MTX (1 << 4)
  42 +#define I2CR_TX_NO_AK (1 << 3)
  43 +#define I2CR_RSTA (1 << 2)
  44 +
  45 +#define I2SR_ICF (1 << 7)
  46 +#define I2SR_IBB (1 << 5)
  47 +#define I2SR_IIF (1 << 1)
  48 +#define I2SR_RX_NO_AK (1 << 0)
  49 +
  50 +#ifdef CFG_I2C_MX31_PORT1
  51 +#define I2C_BASE 0x43f80000
  52 +#elif defined(CFG_I2C_MX31_PORT2)
  53 +#define I2C_BASE 0x43f98000
  54 +#elif defined(CFG_I2C_MX31_PORT3)
  55 +#define I2C_BASE 0x43f84000
  56 +#else
  57 +#error "define CFG_I2C_MX31_PORTx to use the mx31 I2C driver"
  58 +#endif
  59 +
  60 +#ifdef DEBUG
  61 +#define DPRINTF(args...) printf(args)
  62 +#else
  63 +#define DPRINTF(args...)
  64 +#endif
  65 +
  66 +static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144,
  67 + 160, 192, 240, 288, 320, 384, 480, 576, 640, 768, 960,
  68 + 1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840};
  69 +
  70 +void i2c_init(int speed, int unused)
  71 +{
  72 + int freq = mx31_get_ipg_clk();
  73 + int i;
  74 +
  75 + for (i = 0; i < 0x1f; i++)
  76 + if (freq / div[i] <= speed)
  77 + break;
  78 +
  79 + DPRINTF("%s: speed: %d\n", __FUNCTION__, speed);
  80 +
  81 + __REG16(I2C_BASE + I2CR) = 0; /* Reset module */
  82 + __REG16(I2C_BASE + IFDR) = i;
  83 + __REG16(I2C_BASE + I2CR) = I2CR_IEN;
  84 + __REG16(I2C_BASE + I2SR) = 0;
  85 +}
  86 +
  87 +static int wait_busy(void)
  88 +{
  89 + int timeout = 10000;
  90 +
  91 + while (!(__REG16(I2C_BASE + I2SR) & I2SR_IIF) && --timeout)
  92 + udelay(1);
  93 + __REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */
  94 +
  95 + return timeout;
  96 +}
  97 +
  98 +static int tx_byte(u8 byte)
  99 +{
  100 + __REG16(I2C_BASE + I2DR) = byte;
  101 +
  102 + if (!wait_busy() || __REG16(I2C_BASE + I2SR) & I2SR_RX_NO_AK)
  103 + return -1;
  104 + return 0;
  105 +}
  106 +
  107 +static int rx_byte(void)
  108 +{
  109 + if (!wait_busy())
  110 + return -1;
  111 +
  112 + return __REG16(I2C_BASE + I2DR);
  113 +}
  114 +
  115 +int i2c_probe(uchar chip)
  116 +{
  117 + int ret;
  118 +
  119 + __REG16(I2C_BASE + I2CR) = 0; /* Reset module */
  120 + __REG16(I2C_BASE + I2CR) = I2CR_IEN;
  121 +
  122 + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX;
  123 + ret = tx_byte(chip << 1);
  124 + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MTX;
  125 +
  126 + return ret;
  127 +}
  128 +
  129 +static int i2c_addr(uchar chip, uint addr, int alen)
  130 +{
  131 + __REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */
  132 + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | I2CR_MTX;
  133 +
  134 + if (tx_byte(chip << 1))
  135 + return -1;
  136 +
  137 + while (alen--)
  138 + if (tx_byte((addr >> (alen * 8)) & 0xff))
  139 + return -1;
  140 + return 0;
  141 +}
  142 +
  143 +int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
  144 +{
  145 + int timeout = 10000;
  146 + int ret;
  147 +
  148 + DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: +%d\n", \
  149 + __FUNCTION__, chip, addr, alen, len);
  150 +
  151 + if (i2c_addr(chip, addr, alen)) {
  152 + printf("i2c_addr failed\n");
  153 + return -1;
  154 + }
  155 +
  156 + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | \
  157 + I2CR_MTX | I2CR_RSTA;
  158 +
  159 + if (tx_byte(chip << 1 | 1))
  160 + return -1;
  161 +
  162 + __REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MSTA | ((len == 1) \
  163 + ? I2CR_TX_NO_AK : 0);
  164 +
  165 + ret = __REG16(I2C_BASE + I2DR);
  166 +
  167 + while (len--) {
  168 + if ((ret = rx_byte()) < 0)
  169 + return -1;
  170 + *buf++ = ret;
  171 + if (len <= 1)
  172 + __REG16(I2C_BASE + I2CR) = I2CR_IEN | \
  173 + I2CR_MSTA | I2CR_TX_NO_AK;
  174 + }
  175 +
  176 + wait_busy();
  177 +
  178 + __REG16(I2C_BASE + I2CR) = I2CR_IEN;
  179 +
  180 + while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
  181 + udelay(1);
  182 +
  183 + return 0;
  184 +}
  185 +
  186 +int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
  187 +{
  188 + int timeout = 10000;
  189 + DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n", \
  190 + __FUNCTION__, chip, addr, alen, len);
  191 +
  192 + if (i2c_addr(chip, addr, alen))
  193 + return -1;
  194 +
  195 + while (len--)
  196 + if (tx_byte(*buf++))
  197 + return -1;
  198 +
  199 + __REG16(I2C_BASE + I2CR) = I2CR_IEN;
  200 +
  201 + while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout)
  202 + udelay(1);
  203 +
  204 + return 0;
  205 +}
  206 +
  207 +#endif /* CONFIG_HARD_I2C */