uboot/arch/powerpc/cpu/mpc824x/drivers/i2c/i2c.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2003
   3 * Gleb Natapov <gnatapov@mrv.com>
   4 * Some bits are taken from linux driver writen by adrian@humboldt.co.uk
   5 *
   6 * Hardware I2C driver for MPC107 PCI bridge.
   7 *
   8 * See file CREDITS for list of people who contributed to this
   9 * project.
  10 *
  11 * This program is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU General Public License as
  13 * published by the Free Software Foundation; either version 2 of
  14 * the License, or (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  24 * MA 02111-1307 USA
  25 */
  26
  27#include <common.h>
  28
  29#undef I2CDBG
  30
  31#ifdef CONFIG_HARD_I2C
  32#include <i2c.h>
  33
  34#define TIMEOUT (CONFIG_SYS_HZ/4)
  35
  36#define I2C_Addr ((unsigned *)(CONFIG_SYS_EUMB_ADDR + 0x3000))
  37
  38#define I2CADR &I2C_Addr[0]
  39#define I2CFDR  &I2C_Addr[1]
  40#define I2CCCR  &I2C_Addr[2]
  41#define I2CCSR  &I2C_Addr[3]
  42#define I2CCDR  &I2C_Addr[4]
  43
  44#define MPC107_CCR_MEN  0x80
  45#define MPC107_CCR_MIEN 0x40
  46#define MPC107_CCR_MSTA 0x20
  47#define MPC107_CCR_MTX  0x10
  48#define MPC107_CCR_TXAK 0x08
  49#define MPC107_CCR_RSTA 0x04
  50
  51#define MPC107_CSR_MCF  0x80
  52#define MPC107_CSR_MAAS 0x40
  53#define MPC107_CSR_MBB  0x20
  54#define MPC107_CSR_MAL  0x10
  55#define MPC107_CSR_SRW  0x04
  56#define MPC107_CSR_MIF  0x02
  57#define MPC107_CSR_RXAK 0x01
  58
  59#define I2C_READ  1
  60#define I2C_WRITE 0
  61
  62/* taken from linux include/asm-ppc/io.h */
  63inline unsigned in_le32 (volatile unsigned *addr)
  64{
  65        unsigned ret;
  66
  67        __asm__ __volatile__ ("lwbrx %0,0,%1;\n"
  68                              "twi 0,%0,0;\n"
  69                              "isync":"=r" (ret): "r" (addr), "m" (*addr));
  70        return ret;
  71}
  72
  73inline void out_le32 (volatile unsigned *addr, int val)
  74{
  75        __asm__ __volatile__ ("stwbrx %1,0,%2; eieio":"=m" (*addr):"r" (val),
  76                              "r" (addr));
  77}
  78
  79#define writel(val, addr) out_le32(addr, val)
  80#define readl(addr) in_le32(addr)
  81
  82void i2c_init (int speed, int slaveadd)
  83{
  84        /* stop I2C controller */
  85        writel (0x0, I2CCCR);
  86        /* set clock */
  87        writel (0x1020, I2CFDR);
  88        /* write slave address */
  89        writel (slaveadd, I2CADR);
  90        /* clear status register */
  91        writel (0x0, I2CCSR);
  92        /* start I2C controller */
  93        writel (MPC107_CCR_MEN, I2CCCR);
  94
  95        return;
  96}
  97
  98static __inline__ int i2c_wait4bus (void)
  99{
 100        ulong timeval = get_timer (0);
 101
 102        while (readl (I2CCSR) & MPC107_CSR_MBB)
 103                if (get_timer (timeval) > TIMEOUT)
 104                        return -1;
 105
 106        return 0;
 107}
 108
 109static __inline__ int i2c_wait (int write)
 110{
 111        u32 csr;
 112        ulong timeval = get_timer (0);
 113
 114        do {
 115                csr = readl (I2CCSR);
 116
 117                if (!(csr & MPC107_CSR_MIF))
 118                        continue;
 119
 120                writel (0x0, I2CCSR);
 121
 122                if (csr & MPC107_CSR_MAL) {
 123#ifdef I2CDBG
 124                        printf ("i2c_wait: MAL\n");
 125#endif
 126                        return -1;
 127                }
 128
 129                if (!(csr & MPC107_CSR_MCF)) {
 130#ifdef I2CDBG
 131                        printf ("i2c_wait: unfinished\n");
 132#endif
 133                        return -1;
 134                }
 135
 136                if (write == I2C_WRITE && (csr & MPC107_CSR_RXAK)) {
 137#ifdef I2CDBG
 138                        printf ("i2c_wait: No RXACK\n");
 139#endif
 140                        return -1;
 141                }
 142
 143                return 0;
 144        } while (get_timer (timeval) < TIMEOUT);
 145
 146#ifdef I2CDBG
 147        printf ("i2c_wait: timed out\n");
 148#endif
 149        return -1;
 150}
 151
 152static __inline__ int i2c_write_addr (u8 dev, u8 dir, int rsta)
 153{
 154        writel (MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_MTX |
 155                (rsta ? MPC107_CCR_RSTA : 0), I2CCCR);
 156
 157        writel ((dev << 1) | dir, I2CCDR);
 158
 159        if (i2c_wait (I2C_WRITE) < 0)
 160                return 0;
 161
 162        return 1;
 163}
 164
 165static __inline__ int __i2c_write (u8 * data, int length)
 166{
 167        int i;
 168
 169        writel (MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_MTX, I2CCCR);
 170
 171        for (i = 0; i < length; i++) {
 172                writel (data[i], I2CCDR);
 173
 174                if (i2c_wait (I2C_WRITE) < 0)
 175                        break;
 176        }
 177
 178        return i;
 179}
 180
 181static __inline__ int __i2c_read (u8 * data, int length)
 182{
 183        int i;
 184
 185        writel (MPC107_CCR_MEN | MPC107_CCR_MSTA |
 186                ((length == 1) ? MPC107_CCR_TXAK : 0), I2CCCR);
 187
 188        /* dummy read */
 189        readl (I2CCDR);
 190
 191        for (i = 0; i < length; i++) {
 192                if (i2c_wait (I2C_READ) < 0)
 193                        break;
 194
 195                /* Generate ack on last next to last byte */
 196                if (i == length - 2)
 197                        writel (MPC107_CCR_MEN | MPC107_CCR_MSTA |
 198                                MPC107_CCR_TXAK, I2CCCR);
 199
 200                /* Generate stop on last byte */
 201                if (i == length - 1)
 202                        writel (MPC107_CCR_MEN | MPC107_CCR_TXAK, I2CCCR);
 203
 204                data[i] = readl (I2CCDR);
 205        }
 206
 207        return i;
 208}
 209
 210int i2c_read (u8 dev, uint addr, int alen, u8 * data, int length)
 211{
 212        int i = 0;
 213        u8 *a = (u8 *) & addr;
 214
 215        if (i2c_wait4bus () < 0)
 216                goto exit;
 217
 218        if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
 219                goto exit;
 220
 221        if (__i2c_write (&a[4 - alen], alen) != alen)
 222                goto exit;
 223
 224        if (i2c_write_addr (dev, I2C_READ, 1) == 0)
 225                goto exit;
 226
 227        i = __i2c_read (data, length);
 228
 229exit:
 230        writel (MPC107_CCR_MEN, I2CCCR);
 231
 232        return !(i == length);
 233}
 234
 235int i2c_write (u8 dev, uint addr, int alen, u8 * data, int length)
 236{
 237        int i = 0;
 238        u8 *a = (u8 *) & addr;
 239
 240        if (i2c_wait4bus () < 0)
 241                goto exit;
 242
 243        if (i2c_write_addr (dev, I2C_WRITE, 0) == 0)
 244                goto exit;
 245
 246        if (__i2c_write (&a[4 - alen], alen) != alen)
 247                goto exit;
 248
 249        i = __i2c_write (data, length);
 250
 251exit:
 252        writel (MPC107_CCR_MEN, I2CCCR);
 253
 254        return !(i == length);
 255}
 256
 257int i2c_probe (uchar chip)
 258{
 259        int tmp;
 260
 261        /*
 262         * Try to read the first location of the chip.  The underlying
 263         * driver doesn't appear to support sending just the chip address
 264         * and looking for an <ACK> back.
 265         */
 266        udelay (10000);
 267        return i2c_read (chip, 0, 1, (uchar *) &tmp, 1);
 268}
 269
 270#endif /* CONFIG_HARD_I2C */
 271