13cff842bSKuo-Jung Su /* 23cff842bSKuo-Jung Su * Faraday I2C Controller 33cff842bSKuo-Jung Su * 43cff842bSKuo-Jung Su * (C) Copyright 2010 Faraday Technology 53cff842bSKuo-Jung Su * Dante Su <dantesu@faraday-tech.com> 63cff842bSKuo-Jung Su * 78dde4ca9STom Rini * SPDX-License-Identifier: GPL-2.0+ 83cff842bSKuo-Jung Su */ 93cff842bSKuo-Jung Su 103cff842bSKuo-Jung Su #include <common.h> 113cff842bSKuo-Jung Su #include <asm/io.h> 123cff842bSKuo-Jung Su #include <i2c.h> 133cff842bSKuo-Jung Su 143cff842bSKuo-Jung Su #include "fti2c010.h" 153cff842bSKuo-Jung Su 163cff842bSKuo-Jung Su #ifndef CONFIG_SYS_I2C_SPEED 17e6d3ab89SKuo-Jung Su #define CONFIG_SYS_I2C_SPEED 5000 183cff842bSKuo-Jung Su #endif 193cff842bSKuo-Jung Su 2049f4c762SKuo-Jung Su #ifndef CONFIG_SYS_I2C_SLAVE 2149f4c762SKuo-Jung Su #define CONFIG_SYS_I2C_SLAVE 0 2249f4c762SKuo-Jung Su #endif 2349f4c762SKuo-Jung Su 24e6d3ab89SKuo-Jung Su #ifndef CONFIG_FTI2C010_CLOCK 25e6d3ab89SKuo-Jung Su #define CONFIG_FTI2C010_CLOCK clk_get_rate("I2C") 263cff842bSKuo-Jung Su #endif 273cff842bSKuo-Jung Su 28e6d3ab89SKuo-Jung Su #ifndef CONFIG_FTI2C010_TIMEOUT 29e6d3ab89SKuo-Jung Su #define CONFIG_FTI2C010_TIMEOUT 10 /* ms */ 30e6d3ab89SKuo-Jung Su #endif 313cff842bSKuo-Jung Su 32e6d3ab89SKuo-Jung Su /* 7-bit dev address + 1-bit read/write */ 33e6d3ab89SKuo-Jung Su #define I2C_RD(dev) ((((dev) << 1) & 0xfe) | 1) 34e6d3ab89SKuo-Jung Su #define I2C_WR(dev) (((dev) << 1) & 0xfe) 353cff842bSKuo-Jung Su 363cff842bSKuo-Jung Su struct fti2c010_chip { 37e6d3ab89SKuo-Jung Su struct fti2c010_regs *regs; 383cff842bSKuo-Jung Su }; 393cff842bSKuo-Jung Su 403cff842bSKuo-Jung Su static struct fti2c010_chip chip_list[] = { 413cff842bSKuo-Jung Su { 42e6d3ab89SKuo-Jung Su .regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE, 433cff842bSKuo-Jung Su }, 443cff842bSKuo-Jung Su #ifdef CONFIG_FTI2C010_BASE1 453cff842bSKuo-Jung Su { 46e6d3ab89SKuo-Jung Su .regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE1, 473cff842bSKuo-Jung Su }, 483cff842bSKuo-Jung Su #endif 493cff842bSKuo-Jung Su #ifdef CONFIG_FTI2C010_BASE2 503cff842bSKuo-Jung Su { 51e6d3ab89SKuo-Jung Su .regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE2, 523cff842bSKuo-Jung Su }, 533cff842bSKuo-Jung Su #endif 543cff842bSKuo-Jung Su #ifdef CONFIG_FTI2C010_BASE3 553cff842bSKuo-Jung Su { 56e6d3ab89SKuo-Jung Su .regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE3, 573cff842bSKuo-Jung Su }, 583cff842bSKuo-Jung Su #endif 593cff842bSKuo-Jung Su }; 603cff842bSKuo-Jung Su 6149f4c762SKuo-Jung Su static int fti2c010_reset(struct fti2c010_chip *chip) 6249f4c762SKuo-Jung Su { 6349f4c762SKuo-Jung Su ulong ts; 6449f4c762SKuo-Jung Su int ret = -1; 6549f4c762SKuo-Jung Su struct fti2c010_regs *regs = chip->regs; 663cff842bSKuo-Jung Su 6749f4c762SKuo-Jung Su writel(CR_I2CRST, ®s->cr); 6849f4c762SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CONFIG_FTI2C010_TIMEOUT; ) { 6949f4c762SKuo-Jung Su if (!(readl(®s->cr) & CR_I2CRST)) { 7049f4c762SKuo-Jung Su ret = 0; 7149f4c762SKuo-Jung Su break; 7249f4c762SKuo-Jung Su } 7349f4c762SKuo-Jung Su } 7449f4c762SKuo-Jung Su 7549f4c762SKuo-Jung Su if (ret) 7649f4c762SKuo-Jung Su printf("fti2c010: reset timeout\n"); 7749f4c762SKuo-Jung Su 7849f4c762SKuo-Jung Su return ret; 7949f4c762SKuo-Jung Su } 8049f4c762SKuo-Jung Su 8149f4c762SKuo-Jung Su static int fti2c010_wait(struct fti2c010_chip *chip, uint32_t mask) 823cff842bSKuo-Jung Su { 833cff842bSKuo-Jung Su int ret = -1; 843cff842bSKuo-Jung Su uint32_t stat, ts; 8549f4c762SKuo-Jung Su struct fti2c010_regs *regs = chip->regs; 863cff842bSKuo-Jung Su 87e6d3ab89SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CONFIG_FTI2C010_TIMEOUT; ) { 883cff842bSKuo-Jung Su stat = readl(®s->sr); 893cff842bSKuo-Jung Su if ((stat & mask) == mask) { 903cff842bSKuo-Jung Su ret = 0; 913cff842bSKuo-Jung Su break; 923cff842bSKuo-Jung Su } 933cff842bSKuo-Jung Su } 943cff842bSKuo-Jung Su 953cff842bSKuo-Jung Su return ret; 963cff842bSKuo-Jung Su } 973cff842bSKuo-Jung Su 9849f4c762SKuo-Jung Su static unsigned int set_i2c_bus_speed(struct fti2c010_chip *chip, 9949f4c762SKuo-Jung Su unsigned int speed) 10049f4c762SKuo-Jung Su { 10149f4c762SKuo-Jung Su struct fti2c010_regs *regs = chip->regs; 10249f4c762SKuo-Jung Su unsigned int clk = CONFIG_FTI2C010_CLOCK; 10349f4c762SKuo-Jung Su unsigned int gsr = 0; 10449f4c762SKuo-Jung Su unsigned int tsr = 32; 10549f4c762SKuo-Jung Su unsigned int div, rate; 10649f4c762SKuo-Jung Su 10749f4c762SKuo-Jung Su for (div = 0; div < 0x3ffff; ++div) { 10849f4c762SKuo-Jung Su /* SCLout = PCLK/(2*(COUNT + 2) + GSR) */ 10949f4c762SKuo-Jung Su rate = clk / (2 * (div + 2) + gsr); 11049f4c762SKuo-Jung Su if (rate <= speed) 11149f4c762SKuo-Jung Su break; 11249f4c762SKuo-Jung Su } 11349f4c762SKuo-Jung Su 11449f4c762SKuo-Jung Su writel(TGSR_GSR(gsr) | TGSR_TSR(tsr), ®s->tgsr); 11549f4c762SKuo-Jung Su writel(CDR_DIV(div), ®s->cdr); 11649f4c762SKuo-Jung Su 11749f4c762SKuo-Jung Su return rate; 11849f4c762SKuo-Jung Su } 1193cff842bSKuo-Jung Su 1203cff842bSKuo-Jung Su /* 1213cff842bSKuo-Jung Su * Initialization, must be called once on start up, may be called 1223cff842bSKuo-Jung Su * repeatedly to change the speed and slave addresses. 1233cff842bSKuo-Jung Su */ 12449f4c762SKuo-Jung Su static void fti2c010_init(struct i2c_adapter *adap, int speed, int slaveaddr) 1253cff842bSKuo-Jung Su { 12649f4c762SKuo-Jung Su struct fti2c010_chip *chip = chip_list + adap->hwadapnr; 1273cff842bSKuo-Jung Su 12849f4c762SKuo-Jung Su if (adap->init_done) 1293cff842bSKuo-Jung Su return; 1303cff842bSKuo-Jung Su 13149f4c762SKuo-Jung Su #ifdef CONFIG_SYS_I2C_INIT_BOARD 13249f4c762SKuo-Jung Su /* Call board specific i2c bus reset routine before accessing the 13349f4c762SKuo-Jung Su * environment, which might be in a chip on that bus. For details 13449f4c762SKuo-Jung Su * about this problem see doc/I2C_Edge_Conditions. 1353cff842bSKuo-Jung Su */ 13649f4c762SKuo-Jung Su i2c_init_board(); 13749f4c762SKuo-Jung Su #endif 13849f4c762SKuo-Jung Su 13949f4c762SKuo-Jung Su /* master init */ 14049f4c762SKuo-Jung Su 14149f4c762SKuo-Jung Su fti2c010_reset(chip); 14249f4c762SKuo-Jung Su 14349f4c762SKuo-Jung Su set_i2c_bus_speed(chip, speed); 14449f4c762SKuo-Jung Su 14549f4c762SKuo-Jung Su /* slave init, don't care */ 14649f4c762SKuo-Jung Su 14749f4c762SKuo-Jung Su #ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT 14849f4c762SKuo-Jung Su /* Call board specific i2c bus reset routine AFTER the bus has been 14949f4c762SKuo-Jung Su * initialized. Use either this callpoint or i2c_init_board; 15049f4c762SKuo-Jung Su * which is called before fti2c010_init operations. 15149f4c762SKuo-Jung Su * For details about this problem see doc/I2C_Edge_Conditions. 15249f4c762SKuo-Jung Su */ 15349f4c762SKuo-Jung Su i2c_board_late_init(); 15449f4c762SKuo-Jung Su #endif 1553cff842bSKuo-Jung Su } 1563cff842bSKuo-Jung Su 1573cff842bSKuo-Jung Su /* 1583cff842bSKuo-Jung Su * Probe the given I2C chip address. Returns 0 if a chip responded, 1593cff842bSKuo-Jung Su * not 0 on failure. 1603cff842bSKuo-Jung Su */ 16149f4c762SKuo-Jung Su static int fti2c010_probe(struct i2c_adapter *adap, u8 dev) 1623cff842bSKuo-Jung Su { 16349f4c762SKuo-Jung Su struct fti2c010_chip *chip = chip_list + adap->hwadapnr; 16449f4c762SKuo-Jung Su struct fti2c010_regs *regs = chip->regs; 1653cff842bSKuo-Jung Su int ret; 1663cff842bSKuo-Jung Su 1673cff842bSKuo-Jung Su /* 1. Select slave device (7bits Address + 1bit R/W) */ 16849f4c762SKuo-Jung Su writel(I2C_WR(dev), ®s->dr); 1693cff842bSKuo-Jung Su writel(CR_ENABLE | CR_TBEN | CR_START, ®s->cr); 17049f4c762SKuo-Jung Su ret = fti2c010_wait(chip, SR_DT); 1713cff842bSKuo-Jung Su if (ret) 1723cff842bSKuo-Jung Su return ret; 1733cff842bSKuo-Jung Su 1743cff842bSKuo-Jung Su /* 2. Select device register */ 1753cff842bSKuo-Jung Su writel(0, ®s->dr); 1763cff842bSKuo-Jung Su writel(CR_ENABLE | CR_TBEN, ®s->cr); 17749f4c762SKuo-Jung Su ret = fti2c010_wait(chip, SR_DT); 1783cff842bSKuo-Jung Su 1793cff842bSKuo-Jung Su return ret; 1803cff842bSKuo-Jung Su } 1813cff842bSKuo-Jung Su 182c727618dSKuo-Jung Su static void to_i2c_addr(u8 *buf, uint32_t addr, int alen) 183c727618dSKuo-Jung Su { 184c727618dSKuo-Jung Su int i, shift; 185c727618dSKuo-Jung Su 186c727618dSKuo-Jung Su if (!buf || alen <= 0) 187c727618dSKuo-Jung Su return; 188c727618dSKuo-Jung Su 189c727618dSKuo-Jung Su /* MSB first */ 190c727618dSKuo-Jung Su i = 0; 191c727618dSKuo-Jung Su shift = (alen - 1) * 8; 192c727618dSKuo-Jung Su while (alen-- > 0) { 193c727618dSKuo-Jung Su buf[i] = (u8)(addr >> shift); 194c727618dSKuo-Jung Su shift -= 8; 195c727618dSKuo-Jung Su } 196c727618dSKuo-Jung Su } 197c727618dSKuo-Jung Su 19849f4c762SKuo-Jung Su static int fti2c010_read(struct i2c_adapter *adap, 19949f4c762SKuo-Jung Su u8 dev, uint addr, int alen, uchar *buf, int len) 2003cff842bSKuo-Jung Su { 20149f4c762SKuo-Jung Su struct fti2c010_chip *chip = chip_list + adap->hwadapnr; 20249f4c762SKuo-Jung Su struct fti2c010_regs *regs = chip->regs; 2033cff842bSKuo-Jung Su int ret, pos; 204*dccacbe0SKuo-Jung Su uchar paddr[4] = { 0 }; 2053cff842bSKuo-Jung Su 206c727618dSKuo-Jung Su to_i2c_addr(paddr, addr, alen); 2073cff842bSKuo-Jung Su 2083cff842bSKuo-Jung Su /* 2093cff842bSKuo-Jung Su * Phase A. Set register address 2103cff842bSKuo-Jung Su */ 2113cff842bSKuo-Jung Su 2123cff842bSKuo-Jung Su /* A.1 Select slave device (7bits Address + 1bit R/W) */ 21349f4c762SKuo-Jung Su writel(I2C_WR(dev), ®s->dr); 2143cff842bSKuo-Jung Su writel(CR_ENABLE | CR_TBEN | CR_START, ®s->cr); 21549f4c762SKuo-Jung Su ret = fti2c010_wait(chip, SR_DT); 2163cff842bSKuo-Jung Su if (ret) 2173cff842bSKuo-Jung Su return ret; 2183cff842bSKuo-Jung Su 2193cff842bSKuo-Jung Su /* A.2 Select device register */ 2203cff842bSKuo-Jung Su for (pos = 0; pos < alen; ++pos) { 2213cff842bSKuo-Jung Su uint32_t ctrl = CR_ENABLE | CR_TBEN; 2223cff842bSKuo-Jung Su 2233cff842bSKuo-Jung Su writel(paddr[pos], ®s->dr); 2243cff842bSKuo-Jung Su writel(ctrl, ®s->cr); 22549f4c762SKuo-Jung Su ret = fti2c010_wait(chip, SR_DT); 2263cff842bSKuo-Jung Su if (ret) 2273cff842bSKuo-Jung Su return ret; 2283cff842bSKuo-Jung Su } 2293cff842bSKuo-Jung Su 2303cff842bSKuo-Jung Su /* 2313cff842bSKuo-Jung Su * Phase B. Get register data 2323cff842bSKuo-Jung Su */ 2333cff842bSKuo-Jung Su 2343cff842bSKuo-Jung Su /* B.1 Select slave device (7bits Address + 1bit R/W) */ 23549f4c762SKuo-Jung Su writel(I2C_RD(dev), ®s->dr); 2363cff842bSKuo-Jung Su writel(CR_ENABLE | CR_TBEN | CR_START, ®s->cr); 23749f4c762SKuo-Jung Su ret = fti2c010_wait(chip, SR_DT); 2383cff842bSKuo-Jung Su if (ret) 2393cff842bSKuo-Jung Su return ret; 2403cff842bSKuo-Jung Su 2413cff842bSKuo-Jung Su /* B.2 Get register data */ 2423cff842bSKuo-Jung Su for (pos = 0; pos < len; ++pos) { 2433cff842bSKuo-Jung Su uint32_t ctrl = CR_ENABLE | CR_TBEN; 2443cff842bSKuo-Jung Su uint32_t stat = SR_DR; 2453cff842bSKuo-Jung Su 2463cff842bSKuo-Jung Su if (pos == len - 1) { 2473cff842bSKuo-Jung Su ctrl |= CR_NAK | CR_STOP; 2483cff842bSKuo-Jung Su stat |= SR_ACK; 2493cff842bSKuo-Jung Su } 2503cff842bSKuo-Jung Su writel(ctrl, ®s->cr); 25149f4c762SKuo-Jung Su ret = fti2c010_wait(chip, stat); 2523cff842bSKuo-Jung Su if (ret) 2533cff842bSKuo-Jung Su break; 2543cff842bSKuo-Jung Su buf[pos] = (uchar)(readl(®s->dr) & 0xFF); 2553cff842bSKuo-Jung Su } 2563cff842bSKuo-Jung Su 2573cff842bSKuo-Jung Su return ret; 2583cff842bSKuo-Jung Su } 2593cff842bSKuo-Jung Su 26049f4c762SKuo-Jung Su static int fti2c010_write(struct i2c_adapter *adap, 26149f4c762SKuo-Jung Su u8 dev, uint addr, int alen, u8 *buf, int len) 2623cff842bSKuo-Jung Su { 26349f4c762SKuo-Jung Su struct fti2c010_chip *chip = chip_list + adap->hwadapnr; 26449f4c762SKuo-Jung Su struct fti2c010_regs *regs = chip->regs; 2653cff842bSKuo-Jung Su int ret, pos; 266*dccacbe0SKuo-Jung Su uchar paddr[4] = { 0 }; 2673cff842bSKuo-Jung Su 268c727618dSKuo-Jung Su to_i2c_addr(paddr, addr, alen); 2693cff842bSKuo-Jung Su 2703cff842bSKuo-Jung Su /* 2713cff842bSKuo-Jung Su * Phase A. Set register address 2723cff842bSKuo-Jung Su * 2733cff842bSKuo-Jung Su * A.1 Select slave device (7bits Address + 1bit R/W) 2743cff842bSKuo-Jung Su */ 27549f4c762SKuo-Jung Su writel(I2C_WR(dev), ®s->dr); 2763cff842bSKuo-Jung Su writel(CR_ENABLE | CR_TBEN | CR_START, ®s->cr); 27749f4c762SKuo-Jung Su ret = fti2c010_wait(chip, SR_DT); 2783cff842bSKuo-Jung Su if (ret) 2793cff842bSKuo-Jung Su return ret; 2803cff842bSKuo-Jung Su 2813cff842bSKuo-Jung Su /* A.2 Select device register */ 2823cff842bSKuo-Jung Su for (pos = 0; pos < alen; ++pos) { 2833cff842bSKuo-Jung Su uint32_t ctrl = CR_ENABLE | CR_TBEN; 2843cff842bSKuo-Jung Su 2853cff842bSKuo-Jung Su writel(paddr[pos], ®s->dr); 2863cff842bSKuo-Jung Su writel(ctrl, ®s->cr); 28749f4c762SKuo-Jung Su ret = fti2c010_wait(chip, SR_DT); 2883cff842bSKuo-Jung Su if (ret) 2893cff842bSKuo-Jung Su return ret; 2903cff842bSKuo-Jung Su } 2913cff842bSKuo-Jung Su 2923cff842bSKuo-Jung Su /* 2933cff842bSKuo-Jung Su * Phase B. Set register data 2943cff842bSKuo-Jung Su */ 2953cff842bSKuo-Jung Su for (pos = 0; pos < len; ++pos) { 2963cff842bSKuo-Jung Su uint32_t ctrl = CR_ENABLE | CR_TBEN; 2973cff842bSKuo-Jung Su 2983cff842bSKuo-Jung Su if (pos == len - 1) 2993cff842bSKuo-Jung Su ctrl |= CR_STOP; 3003cff842bSKuo-Jung Su writel(buf[pos], ®s->dr); 3013cff842bSKuo-Jung Su writel(ctrl, ®s->cr); 30249f4c762SKuo-Jung Su ret = fti2c010_wait(chip, SR_DT); 3033cff842bSKuo-Jung Su if (ret) 3043cff842bSKuo-Jung Su break; 3053cff842bSKuo-Jung Su } 3063cff842bSKuo-Jung Su 3073cff842bSKuo-Jung Su return ret; 3083cff842bSKuo-Jung Su } 3093cff842bSKuo-Jung Su 31049f4c762SKuo-Jung Su static unsigned int fti2c010_set_bus_speed(struct i2c_adapter *adap, 31149f4c762SKuo-Jung Su unsigned int speed) 3123cff842bSKuo-Jung Su { 31349f4c762SKuo-Jung Su struct fti2c010_chip *chip = chip_list + adap->hwadapnr; 31449f4c762SKuo-Jung Su int ret; 31549f4c762SKuo-Jung Su 31649f4c762SKuo-Jung Su fti2c010_reset(chip); 31749f4c762SKuo-Jung Su ret = set_i2c_bus_speed(chip, speed); 31849f4c762SKuo-Jung Su 31949f4c762SKuo-Jung Su return ret; 3203cff842bSKuo-Jung Su } 3213cff842bSKuo-Jung Su 3223cff842bSKuo-Jung Su /* 32349f4c762SKuo-Jung Su * Register i2c adapters 3243cff842bSKuo-Jung Su */ 32549f4c762SKuo-Jung Su U_BOOT_I2C_ADAP_COMPLETE(i2c_0, fti2c010_init, fti2c010_probe, fti2c010_read, 32649f4c762SKuo-Jung Su fti2c010_write, fti2c010_set_bus_speed, 32749f4c762SKuo-Jung Su CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 32849f4c762SKuo-Jung Su 0) 32949f4c762SKuo-Jung Su #ifdef CONFIG_FTI2C010_BASE1 33049f4c762SKuo-Jung Su U_BOOT_I2C_ADAP_COMPLETE(i2c_1, fti2c010_init, fti2c010_probe, fti2c010_read, 33149f4c762SKuo-Jung Su fti2c010_write, fti2c010_set_bus_speed, 33249f4c762SKuo-Jung Su CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 33349f4c762SKuo-Jung Su 1) 33449f4c762SKuo-Jung Su #endif 33549f4c762SKuo-Jung Su #ifdef CONFIG_FTI2C010_BASE2 33649f4c762SKuo-Jung Su U_BOOT_I2C_ADAP_COMPLETE(i2c_2, fti2c010_init, fti2c010_probe, fti2c010_read, 33749f4c762SKuo-Jung Su fti2c010_write, fti2c010_set_bus_speed, 33849f4c762SKuo-Jung Su CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 33949f4c762SKuo-Jung Su 2) 34049f4c762SKuo-Jung Su #endif 34149f4c762SKuo-Jung Su #ifdef CONFIG_FTI2C010_BASE3 34249f4c762SKuo-Jung Su U_BOOT_I2C_ADAP_COMPLETE(i2c_3, fti2c010_init, fti2c010_probe, fti2c010_read, 34349f4c762SKuo-Jung Su fti2c010_write, fti2c010_set_bus_speed, 34449f4c762SKuo-Jung Su CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 34549f4c762SKuo-Jung Su 3) 34649f4c762SKuo-Jung Su #endif 347