uboot/drivers/i2c/fti2c010.c
<<
>>
Prefs
   1/*
   2 * Faraday I2C Controller
   3 *
   4 * (C) Copyright 2010 Faraday Technology
   5 * Dante Su <dantesu@faraday-tech.com>
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0+
   8 */
   9
  10#include <common.h>
  11#include <asm/io.h>
  12#include <i2c.h>
  13
  14#include "fti2c010.h"
  15
  16#ifndef CONFIG_SYS_I2C_SPEED
  17#define CONFIG_SYS_I2C_SPEED    5000
  18#endif
  19
  20#ifndef CONFIG_SYS_I2C_SLAVE
  21#define CONFIG_SYS_I2C_SLAVE    0
  22#endif
  23
  24#ifndef CONFIG_FTI2C010_CLOCK
  25#define CONFIG_FTI2C010_CLOCK   clk_get_rate("I2C")
  26#endif
  27
  28#ifndef CONFIG_FTI2C010_TIMEOUT
  29#define CONFIG_FTI2C010_TIMEOUT 10 /* ms */
  30#endif
  31
  32/* 7-bit dev address + 1-bit read/write */
  33#define I2C_RD(dev)             ((((dev) << 1) & 0xfe) | 1)
  34#define I2C_WR(dev)             (((dev) << 1) & 0xfe)
  35
  36struct fti2c010_chip {
  37        struct fti2c010_regs *regs;
  38};
  39
  40static struct fti2c010_chip chip_list[] = {
  41        {
  42                .regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE,
  43        },
  44#ifdef CONFIG_FTI2C010_BASE1
  45        {
  46                .regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE1,
  47        },
  48#endif
  49#ifdef CONFIG_FTI2C010_BASE2
  50        {
  51                .regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE2,
  52        },
  53#endif
  54#ifdef CONFIG_FTI2C010_BASE3
  55        {
  56                .regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE3,
  57        },
  58#endif
  59};
  60
  61static int fti2c010_reset(struct fti2c010_chip *chip)
  62{
  63        ulong ts;
  64        int ret = -1;
  65        struct fti2c010_regs *regs = chip->regs;
  66
  67        writel(CR_I2CRST, &regs->cr);
  68        for (ts = get_timer(0); get_timer(ts) < CONFIG_FTI2C010_TIMEOUT; ) {
  69                if (!(readl(&regs->cr) & CR_I2CRST)) {
  70                        ret = 0;
  71                        break;
  72                }
  73        }
  74
  75        if (ret)
  76                printf("fti2c010: reset timeout\n");
  77
  78        return ret;
  79}
  80
  81static int fti2c010_wait(struct fti2c010_chip *chip, uint32_t mask)
  82{
  83        int ret = -1;
  84        uint32_t stat, ts;
  85        struct fti2c010_regs *regs = chip->regs;
  86
  87        for (ts = get_timer(0); get_timer(ts) < CONFIG_FTI2C010_TIMEOUT; ) {
  88                stat = readl(&regs->sr);
  89                if ((stat & mask) == mask) {
  90                        ret = 0;
  91                        break;
  92                }
  93        }
  94
  95        return ret;
  96}
  97
  98static unsigned int set_i2c_bus_speed(struct fti2c010_chip *chip,
  99        unsigned int speed)
 100{
 101        struct fti2c010_regs *regs = chip->regs;
 102        unsigned int clk = CONFIG_FTI2C010_CLOCK;
 103        unsigned int gsr = 0;
 104        unsigned int tsr = 32;
 105        unsigned int div, rate;
 106
 107        for (div = 0; div < 0x3ffff; ++div) {
 108                /* SCLout = PCLK/(2*(COUNT + 2) + GSR) */
 109                rate = clk / (2 * (div + 2) + gsr);
 110                if (rate <= speed)
 111                        break;
 112        }
 113
 114        writel(TGSR_GSR(gsr) | TGSR_TSR(tsr), &regs->tgsr);
 115        writel(CDR_DIV(div), &regs->cdr);
 116
 117        return rate;
 118}
 119
 120/*
 121 * Initialization, must be called once on start up, may be called
 122 * repeatedly to change the speed and slave addresses.
 123 */
 124static void fti2c010_init(struct i2c_adapter *adap, int speed, int slaveaddr)
 125{
 126        struct fti2c010_chip *chip = chip_list + adap->hwadapnr;
 127
 128        if (adap->init_done)
 129                return;
 130
 131#ifdef CONFIG_SYS_I2C_INIT_BOARD
 132        /* Call board specific i2c bus reset routine before accessing the
 133         * environment, which might be in a chip on that bus. For details
 134         * about this problem see doc/I2C_Edge_Conditions.
 135        */
 136        i2c_init_board();
 137#endif
 138
 139        /* master init */
 140
 141        fti2c010_reset(chip);
 142
 143        set_i2c_bus_speed(chip, speed);
 144
 145        /* slave init, don't care */
 146
 147#ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT
 148        /* Call board specific i2c bus reset routine AFTER the bus has been
 149         * initialized. Use either this callpoint or i2c_init_board;
 150         * which is called before fti2c010_init operations.
 151         * For details about this problem see doc/I2C_Edge_Conditions.
 152        */
 153        i2c_board_late_init();
 154#endif
 155}
 156
 157/*
 158 * Probe the given I2C chip address.  Returns 0 if a chip responded,
 159 * not 0 on failure.
 160 */
 161static int fti2c010_probe(struct i2c_adapter *adap, u8 dev)
 162{
 163        struct fti2c010_chip *chip = chip_list + adap->hwadapnr;
 164        struct fti2c010_regs *regs = chip->regs;
 165        int ret;
 166
 167        /* 1. Select slave device (7bits Address + 1bit R/W) */
 168        writel(I2C_WR(dev), &regs->dr);
 169        writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
 170        ret = fti2c010_wait(chip, SR_DT);
 171        if (ret)
 172                return ret;
 173
 174        /* 2. Select device register */
 175        writel(0, &regs->dr);
 176        writel(CR_ENABLE | CR_TBEN, &regs->cr);
 177        ret = fti2c010_wait(chip, SR_DT);
 178
 179        return ret;
 180}
 181
 182static void to_i2c_addr(u8 *buf, uint32_t addr, int alen)
 183{
 184        int i, shift;
 185
 186        if (!buf || alen <= 0)
 187                return;
 188
 189        /* MSB first */
 190        i = 0;
 191        shift = (alen - 1) * 8;
 192        while (alen-- > 0) {
 193                buf[i] = (u8)(addr >> shift);
 194                shift -= 8;
 195        }
 196}
 197
 198static int fti2c010_read(struct i2c_adapter *adap,
 199                        u8 dev, uint addr, int alen, uchar *buf, int len)
 200{
 201        struct fti2c010_chip *chip = chip_list + adap->hwadapnr;
 202        struct fti2c010_regs *regs = chip->regs;
 203        int ret, pos;
 204        uchar paddr[4] = { 0 };
 205
 206        to_i2c_addr(paddr, addr, alen);
 207
 208        /*
 209         * Phase A. Set register address
 210         */
 211
 212        /* A.1 Select slave device (7bits Address + 1bit R/W) */
 213        writel(I2C_WR(dev), &regs->dr);
 214        writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
 215        ret = fti2c010_wait(chip, SR_DT);
 216        if (ret)
 217                return ret;
 218
 219        /* A.2 Select device register */
 220        for (pos = 0; pos < alen; ++pos) {
 221                uint32_t ctrl = CR_ENABLE | CR_TBEN;
 222
 223                writel(paddr[pos], &regs->dr);
 224                writel(ctrl, &regs->cr);
 225                ret = fti2c010_wait(chip, SR_DT);
 226                if (ret)
 227                        return ret;
 228        }
 229
 230        /*
 231         * Phase B. Get register data
 232         */
 233
 234        /* B.1 Select slave device (7bits Address + 1bit R/W) */
 235        writel(I2C_RD(dev), &regs->dr);
 236        writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
 237        ret = fti2c010_wait(chip, SR_DT);
 238        if (ret)
 239                return ret;
 240
 241        /* B.2 Get register data */
 242        for (pos = 0; pos < len; ++pos) {
 243                uint32_t ctrl = CR_ENABLE | CR_TBEN;
 244                uint32_t stat = SR_DR;
 245
 246                if (pos == len - 1) {
 247                        ctrl |= CR_NAK | CR_STOP;
 248                        stat |= SR_ACK;
 249                }
 250                writel(ctrl, &regs->cr);
 251                ret = fti2c010_wait(chip, stat);
 252                if (ret)
 253                        break;
 254                buf[pos] = (uchar)(readl(&regs->dr) & 0xFF);
 255        }
 256
 257        return ret;
 258}
 259
 260static int fti2c010_write(struct i2c_adapter *adap,
 261                        u8 dev, uint addr, int alen, u8 *buf, int len)
 262{
 263        struct fti2c010_chip *chip = chip_list + adap->hwadapnr;
 264        struct fti2c010_regs *regs = chip->regs;
 265        int ret, pos;
 266        uchar paddr[4] = { 0 };
 267
 268        to_i2c_addr(paddr, addr, alen);
 269
 270        /*
 271         * Phase A. Set register address
 272         *
 273         * A.1 Select slave device (7bits Address + 1bit R/W)
 274         */
 275        writel(I2C_WR(dev), &regs->dr);
 276        writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
 277        ret = fti2c010_wait(chip, SR_DT);
 278        if (ret)
 279                return ret;
 280
 281        /* A.2 Select device register */
 282        for (pos = 0; pos < alen; ++pos) {
 283                uint32_t ctrl = CR_ENABLE | CR_TBEN;
 284
 285                writel(paddr[pos], &regs->dr);
 286                writel(ctrl, &regs->cr);
 287                ret = fti2c010_wait(chip, SR_DT);
 288                if (ret)
 289                        return ret;
 290        }
 291
 292        /*
 293         * Phase B. Set register data
 294         */
 295        for (pos = 0; pos < len; ++pos) {
 296                uint32_t ctrl = CR_ENABLE | CR_TBEN;
 297
 298                if (pos == len - 1)
 299                        ctrl |= CR_STOP;
 300                writel(buf[pos], &regs->dr);
 301                writel(ctrl, &regs->cr);
 302                ret = fti2c010_wait(chip, SR_DT);
 303                if (ret)
 304                        break;
 305        }
 306
 307        return ret;
 308}
 309
 310static unsigned int fti2c010_set_bus_speed(struct i2c_adapter *adap,
 311                        unsigned int speed)
 312{
 313        struct fti2c010_chip *chip = chip_list + adap->hwadapnr;
 314        int ret;
 315
 316        fti2c010_reset(chip);
 317        ret = set_i2c_bus_speed(chip, speed);
 318
 319        return ret;
 320}
 321
 322/*
 323 * Register i2c adapters
 324 */
 325U_BOOT_I2C_ADAP_COMPLETE(i2c_0, fti2c010_init, fti2c010_probe, fti2c010_read,
 326                        fti2c010_write, fti2c010_set_bus_speed,
 327                        CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
 328                        0)
 329#ifdef CONFIG_FTI2C010_BASE1
 330U_BOOT_I2C_ADAP_COMPLETE(i2c_1, fti2c010_init, fti2c010_probe, fti2c010_read,
 331                        fti2c010_write, fti2c010_set_bus_speed,
 332                        CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
 333                        1)
 334#endif
 335#ifdef CONFIG_FTI2C010_BASE2
 336U_BOOT_I2C_ADAP_COMPLETE(i2c_2, fti2c010_init, fti2c010_probe, fti2c010_read,
 337                        fti2c010_write, fti2c010_set_bus_speed,
 338                        CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
 339                        2)
 340#endif
 341#ifdef CONFIG_FTI2C010_BASE3
 342U_BOOT_I2C_ADAP_COMPLETE(i2c_3, fti2c010_init, fti2c010_probe, fti2c010_read,
 343                        fti2c010_write, fti2c010_set_bus_speed,
 344                        CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
 345                        3)
 346#endif
 347