134374699SSimon Glass /* 234374699SSimon Glass * (C) Copyright 2015 Google, Inc 334374699SSimon Glass * 434374699SSimon Glass * (C) Copyright 2008-2014 Rockchip Electronics 534374699SSimon Glass * Peter, Software Engineering, <superpeter.cai@gmail.com>. 634374699SSimon Glass * 734374699SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 834374699SSimon Glass */ 934374699SSimon Glass 1034374699SSimon Glass #include <common.h> 1134374699SSimon Glass #include <clk.h> 1234374699SSimon Glass #include <dm.h> 1334374699SSimon Glass #include <errno.h> 1434374699SSimon Glass #include <i2c.h> 1534374699SSimon Glass #include <asm/io.h> 1634374699SSimon Glass #include <asm/arch/clock.h> 1734374699SSimon Glass #include <asm/arch/i2c.h> 1834374699SSimon Glass #include <asm/arch/periph.h> 1934374699SSimon Glass #include <dm/pinctrl.h> 2034374699SSimon Glass #include <linux/sizes.h> 2134374699SSimon Glass 2234374699SSimon Glass DECLARE_GLOBAL_DATA_PTR; 2334374699SSimon Glass 2434374699SSimon Glass /* i2c timerout */ 2534374699SSimon Glass #define I2C_TIMEOUT_MS 100 2634374699SSimon Glass #define I2C_RETRY_COUNT 3 2734374699SSimon Glass 2834374699SSimon Glass /* rk i2c fifo max transfer bytes */ 2934374699SSimon Glass #define RK_I2C_FIFO_SIZE 32 3034374699SSimon Glass 3134374699SSimon Glass struct rk_i2c { 32135aa950SStephen Warren struct clk clk; 3334374699SSimon Glass struct i2c_regs *regs; 3434374699SSimon Glass unsigned int speed; 35*3d5347f8SDavid Wu unsigned int cfg; 3634374699SSimon Glass }; 3734374699SSimon Glass 38*3d5347f8SDavid Wu struct i2c_spec_values { 39*3d5347f8SDavid Wu unsigned int min_low_ns; 40*3d5347f8SDavid Wu unsigned int min_high_ns; 41*3d5347f8SDavid Wu unsigned int max_rise_ns; 42*3d5347f8SDavid Wu unsigned int max_fall_ns; 43*3d5347f8SDavid Wu }; 44*3d5347f8SDavid Wu 45*3d5347f8SDavid Wu enum { 46*3d5347f8SDavid Wu RK_I2C_VERSION0 = 0, 47*3d5347f8SDavid Wu RK_I2C_VERSION1, 48*3d5347f8SDavid Wu RK_I2C_VERSION5 = 5, 49*3d5347f8SDavid Wu }; 50*3d5347f8SDavid Wu 51*3d5347f8SDavid Wu /********************* Private Variable Definition ***************************/ 52*3d5347f8SDavid Wu 53*3d5347f8SDavid Wu static const struct i2c_spec_values standard_mode_spec = { 54*3d5347f8SDavid Wu .min_low_ns = 4700, 55*3d5347f8SDavid Wu .min_high_ns = 4000, 56*3d5347f8SDavid Wu .max_rise_ns = 1000, 57*3d5347f8SDavid Wu .max_fall_ns = 300, 58*3d5347f8SDavid Wu }; 59*3d5347f8SDavid Wu 60*3d5347f8SDavid Wu static const struct i2c_spec_values fast_mode_spec = { 61*3d5347f8SDavid Wu .min_low_ns = 1300, 62*3d5347f8SDavid Wu .min_high_ns = 600, 63*3d5347f8SDavid Wu .max_rise_ns = 300, 64*3d5347f8SDavid Wu .max_fall_ns = 300, 65*3d5347f8SDavid Wu }; 66*3d5347f8SDavid Wu 67*3d5347f8SDavid Wu static const struct i2c_spec_values fast_modeplus_spec = { 68*3d5347f8SDavid Wu .min_low_ns = 500, 69*3d5347f8SDavid Wu .min_high_ns = 260, 70*3d5347f8SDavid Wu .max_rise_ns = 120, 71*3d5347f8SDavid Wu .max_fall_ns = 120, 72*3d5347f8SDavid Wu }; 73*3d5347f8SDavid Wu 74*3d5347f8SDavid Wu static const struct i2c_spec_values *rk_i2c_get_spec(unsigned int speed) 7534374699SSimon Glass { 76*3d5347f8SDavid Wu if (speed == 1000) 77*3d5347f8SDavid Wu return &fast_modeplus_spec; 78*3d5347f8SDavid Wu else if (speed == 400) 79*3d5347f8SDavid Wu return &fast_mode_spec; 8034374699SSimon Glass else 81*3d5347f8SDavid Wu return &standard_mode_spec; 8234374699SSimon Glass } 8334374699SSimon Glass 8434374699SSimon Glass static void rk_i2c_show_regs(struct i2c_regs *regs) 8534374699SSimon Glass { 8634374699SSimon Glass #ifdef DEBUG 8734374699SSimon Glass uint i; 8834374699SSimon Glass 8934374699SSimon Glass debug("i2c_con: 0x%08x\n", readl(®s->con)); 9034374699SSimon Glass debug("i2c_clkdiv: 0x%08x\n", readl(®s->clkdiv)); 9134374699SSimon Glass debug("i2c_mrxaddr: 0x%08x\n", readl(®s->mrxaddr)); 9234374699SSimon Glass debug("i2c_mrxraddR: 0x%08x\n", readl(®s->mrxraddr)); 9334374699SSimon Glass debug("i2c_mtxcnt: 0x%08x\n", readl(®s->mtxcnt)); 9434374699SSimon Glass debug("i2c_mrxcnt: 0x%08x\n", readl(®s->mrxcnt)); 9534374699SSimon Glass debug("i2c_ien: 0x%08x\n", readl(®s->ien)); 9634374699SSimon Glass debug("i2c_ipd: 0x%08x\n", readl(®s->ipd)); 9734374699SSimon Glass debug("i2c_fcnt: 0x%08x\n", readl(®s->fcnt)); 9834374699SSimon Glass for (i = 0; i < 8; i++) 9934374699SSimon Glass debug("i2c_txdata%d: 0x%08x\n", i, readl(®s->txdata[i])); 10034374699SSimon Glass for (i = 0; i < 8; i++) 10134374699SSimon Glass debug("i2c_rxdata%d: 0x%08x\n", i, readl(®s->rxdata[i])); 10234374699SSimon Glass #endif 10334374699SSimon Glass } 10434374699SSimon Glass 105*3d5347f8SDavid Wu static inline void rk_i2c_get_div(int div, int *divh, int *divl) 106*3d5347f8SDavid Wu { 107*3d5347f8SDavid Wu *divl = div / 2; 108*3d5347f8SDavid Wu if (div % 2 == 0) 109*3d5347f8SDavid Wu *divh = div / 2; 110*3d5347f8SDavid Wu else 111*3d5347f8SDavid Wu *divh = DIV_ROUND_UP(div, 2); 112*3d5347f8SDavid Wu } 113*3d5347f8SDavid Wu 114*3d5347f8SDavid Wu /* 115*3d5347f8SDavid Wu * SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1) 116*3d5347f8SDavid Wu * SCL = PCLK / SCLK Divisor 117*3d5347f8SDavid Wu * i2c_rate = PCLK 118*3d5347f8SDavid Wu */ 119*3d5347f8SDavid Wu static void rk_i2c_set_clk(struct rk_i2c *i2c, unsigned int scl_rate) 120*3d5347f8SDavid Wu { 121*3d5347f8SDavid Wu unsigned int i2c_rate; 122*3d5347f8SDavid Wu int div, divl, divh; 123*3d5347f8SDavid Wu 124*3d5347f8SDavid Wu /* First get i2c rate from pclk */ 125*3d5347f8SDavid Wu i2c_rate = clk_get_rate(&i2c->clk); 126*3d5347f8SDavid Wu 127*3d5347f8SDavid Wu div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2; 128*3d5347f8SDavid Wu divh = 0; 129*3d5347f8SDavid Wu divl = 0; 130*3d5347f8SDavid Wu if (div >= 0) 131*3d5347f8SDavid Wu rk_i2c_get_div(div, &divh, &divl); 132*3d5347f8SDavid Wu writel(I2C_CLKDIV_VAL(divl, divh), &i2c->regs->clkdiv); 133*3d5347f8SDavid Wu 134*3d5347f8SDavid Wu debug("rk_i2c_set_clk: i2c rate = %d, scl rate = %d\n", i2c_rate, 135*3d5347f8SDavid Wu scl_rate); 136*3d5347f8SDavid Wu debug("set i2c clk div = %d, divh = %d, divl = %d\n", div, divh, divl); 137*3d5347f8SDavid Wu debug("set clk(I2C_CLKDIV: 0x%08x)\n", readl(&i2c->regs->clkdiv)); 138*3d5347f8SDavid Wu } 139*3d5347f8SDavid Wu 140*3d5347f8SDavid Wu static int rk_i2c_adapter_clk(struct rk_i2c *i2c, unsigned int scl_rate) 141*3d5347f8SDavid Wu { 142*3d5347f8SDavid Wu const struct i2c_spec_values *spec; 143*3d5347f8SDavid Wu unsigned int min_total_div, min_low_div, min_high_div, min_hold_div; 144*3d5347f8SDavid Wu unsigned int low_div, high_div, extra_div, extra_low_div; 145*3d5347f8SDavid Wu unsigned int min_low_ns, min_high_ns; 146*3d5347f8SDavid Wu unsigned int start_setup = 0; 147*3d5347f8SDavid Wu unsigned int i2c_rate = clk_get_rate(&i2c->clk); 148*3d5347f8SDavid Wu unsigned int speed; 149*3d5347f8SDavid Wu 150*3d5347f8SDavid Wu debug("rk_i2c_set_clk: i2c rate = %d, scl rate = %d\n", i2c_rate, 151*3d5347f8SDavid Wu scl_rate); 152*3d5347f8SDavid Wu 153*3d5347f8SDavid Wu if (scl_rate <= 100000 && scl_rate >= 1000) { 154*3d5347f8SDavid Wu start_setup = 1; 155*3d5347f8SDavid Wu speed = 100; 156*3d5347f8SDavid Wu } else if (scl_rate <= 400000 && scl_rate >= 100000) { 157*3d5347f8SDavid Wu speed = 400; 158*3d5347f8SDavid Wu } else if (scl_rate <= 1000000 && scl_rate > 400000) { 159*3d5347f8SDavid Wu speed = 1000; 160*3d5347f8SDavid Wu } else { 161*3d5347f8SDavid Wu debug("invalid i2c speed : %d\n", scl_rate); 162*3d5347f8SDavid Wu return -EINVAL; 163*3d5347f8SDavid Wu } 164*3d5347f8SDavid Wu 165*3d5347f8SDavid Wu spec = rk_i2c_get_spec(speed); 166*3d5347f8SDavid Wu i2c_rate = DIV_ROUND_UP(i2c_rate, 1000); 167*3d5347f8SDavid Wu speed = DIV_ROUND_UP(scl_rate, 1000); 168*3d5347f8SDavid Wu 169*3d5347f8SDavid Wu min_total_div = DIV_ROUND_UP(i2c_rate, speed * 8); 170*3d5347f8SDavid Wu 171*3d5347f8SDavid Wu min_high_ns = spec->max_rise_ns + spec->min_high_ns; 172*3d5347f8SDavid Wu min_high_div = DIV_ROUND_UP(i2c_rate * min_high_ns, 8 * 1000000); 173*3d5347f8SDavid Wu 174*3d5347f8SDavid Wu min_low_ns = spec->max_fall_ns + spec->min_low_ns; 175*3d5347f8SDavid Wu min_low_div = DIV_ROUND_UP(i2c_rate * min_low_ns, 8 * 1000000); 176*3d5347f8SDavid Wu 177*3d5347f8SDavid Wu min_high_div = (min_high_div < 1) ? 2 : min_high_div; 178*3d5347f8SDavid Wu min_low_div = (min_low_div < 1) ? 2 : min_low_div; 179*3d5347f8SDavid Wu 180*3d5347f8SDavid Wu min_hold_div = min_high_div + min_low_div; 181*3d5347f8SDavid Wu 182*3d5347f8SDavid Wu if (min_hold_div >= min_total_div) { 183*3d5347f8SDavid Wu high_div = min_high_div; 184*3d5347f8SDavid Wu low_div = min_low_div; 185*3d5347f8SDavid Wu } else { 186*3d5347f8SDavid Wu extra_div = min_total_div - min_hold_div; 187*3d5347f8SDavid Wu extra_low_div = DIV_ROUND_UP(min_low_div * extra_div, 188*3d5347f8SDavid Wu min_hold_div); 189*3d5347f8SDavid Wu 190*3d5347f8SDavid Wu low_div = min_low_div + extra_low_div; 191*3d5347f8SDavid Wu high_div = min_high_div + (extra_div - extra_low_div); 192*3d5347f8SDavid Wu } 193*3d5347f8SDavid Wu 194*3d5347f8SDavid Wu high_div--; 195*3d5347f8SDavid Wu low_div--; 196*3d5347f8SDavid Wu 197*3d5347f8SDavid Wu if (high_div > 0xffff || low_div > 0xffff) 198*3d5347f8SDavid Wu return -EINVAL; 199*3d5347f8SDavid Wu 200*3d5347f8SDavid Wu /* 1 for data hold/setup time is enough */ 201*3d5347f8SDavid Wu i2c->cfg = I2C_CON_SDA_CFG(1) | I2C_CON_STA_CFG(start_setup); 202*3d5347f8SDavid Wu writel((high_div << I2C_CLK_DIV_HIGH_SHIFT) | low_div, 203*3d5347f8SDavid Wu &i2c->regs->clkdiv); 204*3d5347f8SDavid Wu 205*3d5347f8SDavid Wu debug("set clk(I2C_TIMING: 0x%08x)\n", i2c->cfg); 206*3d5347f8SDavid Wu debug("set clk(I2C_CLKDIV: 0x%08x)\n", readl(&i2c->regs->clkdiv)); 207*3d5347f8SDavid Wu 208*3d5347f8SDavid Wu return 0; 209*3d5347f8SDavid Wu } 210*3d5347f8SDavid Wu 21156082ed3SDavid Wu static int rk_i2c_send_start_bit(struct rk_i2c *i2c, u32 con) 21234374699SSimon Glass { 21334374699SSimon Glass struct i2c_regs *regs = i2c->regs; 21434374699SSimon Glass ulong start; 21534374699SSimon Glass 21634374699SSimon Glass debug("I2c Send Start bit.\n"); 21734374699SSimon Glass writel(I2C_IPD_ALL_CLEAN, ®s->ipd); 21834374699SSimon Glass 21934374699SSimon Glass writel(I2C_STARTIEN, ®s->ien); 220*3d5347f8SDavid Wu writel(I2C_CON_EN | I2C_CON_START | i2c->cfg | con, ®s->con); 22134374699SSimon Glass 22234374699SSimon Glass start = get_timer(0); 22334374699SSimon Glass while (1) { 22434374699SSimon Glass if (readl(®s->ipd) & I2C_STARTIPD) { 22534374699SSimon Glass writel(I2C_STARTIPD, ®s->ipd); 22634374699SSimon Glass break; 22734374699SSimon Glass } 22834374699SSimon Glass if (get_timer(start) > I2C_TIMEOUT_MS) { 22934374699SSimon Glass debug("I2C Send Start Bit Timeout\n"); 23034374699SSimon Glass rk_i2c_show_regs(regs); 23134374699SSimon Glass return -ETIMEDOUT; 23234374699SSimon Glass } 23334374699SSimon Glass udelay(1); 23434374699SSimon Glass } 23534374699SSimon Glass 23656082ed3SDavid Wu /* clean start bit */ 237*3d5347f8SDavid Wu writel(I2C_CON_EN | i2c->cfg | con, ®s->con); 23856082ed3SDavid Wu 23934374699SSimon Glass return 0; 24034374699SSimon Glass } 24134374699SSimon Glass 24234374699SSimon Glass static int rk_i2c_send_stop_bit(struct rk_i2c *i2c) 24334374699SSimon Glass { 24434374699SSimon Glass struct i2c_regs *regs = i2c->regs; 24534374699SSimon Glass ulong start; 24634374699SSimon Glass 24734374699SSimon Glass debug("I2c Send Stop bit.\n"); 24834374699SSimon Glass writel(I2C_IPD_ALL_CLEAN, ®s->ipd); 24934374699SSimon Glass 250*3d5347f8SDavid Wu writel(I2C_CON_EN | i2c->cfg | I2C_CON_STOP, ®s->con); 25134374699SSimon Glass writel(I2C_CON_STOP, ®s->ien); 25234374699SSimon Glass 25334374699SSimon Glass start = get_timer(0); 25434374699SSimon Glass while (1) { 25534374699SSimon Glass if (readl(®s->ipd) & I2C_STOPIPD) { 25634374699SSimon Glass writel(I2C_STOPIPD, ®s->ipd); 25734374699SSimon Glass break; 25834374699SSimon Glass } 25934374699SSimon Glass if (get_timer(start) > I2C_TIMEOUT_MS) { 26034374699SSimon Glass debug("I2C Send Start Bit Timeout\n"); 26134374699SSimon Glass rk_i2c_show_regs(regs); 26234374699SSimon Glass return -ETIMEDOUT; 26334374699SSimon Glass } 26434374699SSimon Glass udelay(1); 26534374699SSimon Glass } 26634374699SSimon Glass 26756082ed3SDavid Wu udelay(1); 26834374699SSimon Glass return 0; 26934374699SSimon Glass } 27034374699SSimon Glass 27134374699SSimon Glass static inline void rk_i2c_disable(struct rk_i2c *i2c) 27234374699SSimon Glass { 2737ef28ab6SDavid Wu writel(0, &i2c->regs->ien); 2747ef28ab6SDavid Wu writel(I2C_IPD_ALL_CLEAN, &i2c->regs->ipd); 27534374699SSimon Glass writel(0, &i2c->regs->con); 27634374699SSimon Glass } 27734374699SSimon Glass 27834374699SSimon Glass static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len, 27956082ed3SDavid Wu uchar *buf, uint b_len, bool snd) 28034374699SSimon Glass { 28134374699SSimon Glass struct i2c_regs *regs = i2c->regs; 28234374699SSimon Glass uchar *pbuf = buf; 28334374699SSimon Glass uint bytes_remain_len = b_len; 28434374699SSimon Glass uint bytes_xferred = 0; 28534374699SSimon Glass uint words_xferred = 0; 28634374699SSimon Glass ulong start; 28734374699SSimon Glass uint con = 0; 28834374699SSimon Glass uint rxdata; 28934374699SSimon Glass uint i, j; 29056082ed3SDavid Wu int err = 0; 2915deaa530SWadim Egorov bool snd_chunk = false; 29234374699SSimon Glass 29334374699SSimon Glass debug("rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n", 29434374699SSimon Glass chip, reg, r_len, b_len); 29534374699SSimon Glass 29656082ed3SDavid Wu /* If the second message for TRX read, resetting internal state. */ 29756082ed3SDavid Wu if (snd) 29856082ed3SDavid Wu writel(0, ®s->con); 29934374699SSimon Glass 30034374699SSimon Glass writel(I2C_MRXADDR_SET(1, chip << 1 | 1), ®s->mrxaddr); 30134374699SSimon Glass if (r_len == 0) { 30234374699SSimon Glass writel(0, ®s->mrxraddr); 30334374699SSimon Glass } else if (r_len < 4) { 30434374699SSimon Glass writel(I2C_MRXRADDR_SET(r_len, reg), ®s->mrxraddr); 30534374699SSimon Glass } else { 30634374699SSimon Glass debug("I2C Read: addr len %d not supported\n", r_len); 30734374699SSimon Glass return -EIO; 30834374699SSimon Glass } 30934374699SSimon Glass 31034374699SSimon Glass while (bytes_remain_len) { 31134374699SSimon Glass if (bytes_remain_len > RK_I2C_FIFO_SIZE) { 3125deaa530SWadim Egorov con = I2C_CON_EN; 31334374699SSimon Glass bytes_xferred = 32; 31434374699SSimon Glass } else { 3155deaa530SWadim Egorov /* 3165deaa530SWadim Egorov * The hw can read up to 32 bytes at a time. If we need 3175deaa530SWadim Egorov * more than one chunk, send an ACK after the last byte. 3185deaa530SWadim Egorov */ 3195deaa530SWadim Egorov con = I2C_CON_EN | I2C_CON_LASTACK; 32034374699SSimon Glass bytes_xferred = bytes_remain_len; 32134374699SSimon Glass } 32234374699SSimon Glass words_xferred = DIV_ROUND_UP(bytes_xferred, 4); 32334374699SSimon Glass 3245deaa530SWadim Egorov /* 32556082ed3SDavid Wu * make sure we are in plain RX mode if we read a second chunk; 32656082ed3SDavid Wu * and first rx read need to send start bit. 3275deaa530SWadim Egorov */ 32856082ed3SDavid Wu if (snd_chunk) { 3295deaa530SWadim Egorov con |= I2C_CON_MOD(I2C_MODE_RX); 330*3d5347f8SDavid Wu writel(con | i2c->cfg, ®s->con); 33156082ed3SDavid Wu } else { 33256082ed3SDavid Wu con |= I2C_CON_MOD(I2C_MODE_TRX); 33356082ed3SDavid Wu err = rk_i2c_send_start_bit(i2c, con); 33456082ed3SDavid Wu if (err) 33556082ed3SDavid Wu return err; 33656082ed3SDavid Wu } 33756082ed3SDavid Wu 33834374699SSimon Glass writel(I2C_MBRFIEN | I2C_NAKRCVIEN, ®s->ien); 33956082ed3SDavid Wu writel(bytes_xferred, ®s->mrxcnt); 34034374699SSimon Glass 34134374699SSimon Glass start = get_timer(0); 34234374699SSimon Glass while (1) { 34334374699SSimon Glass if (readl(®s->ipd) & I2C_NAKRCVIPD) { 34434374699SSimon Glass writel(I2C_NAKRCVIPD, ®s->ipd); 34534374699SSimon Glass err = -EREMOTEIO; 34634374699SSimon Glass } 34734374699SSimon Glass if (readl(®s->ipd) & I2C_MBRFIPD) { 34834374699SSimon Glass writel(I2C_MBRFIPD, ®s->ipd); 34934374699SSimon Glass break; 35034374699SSimon Glass } 35134374699SSimon Glass if (get_timer(start) > I2C_TIMEOUT_MS) { 35234374699SSimon Glass debug("I2C Read Data Timeout\n"); 35334374699SSimon Glass err = -ETIMEDOUT; 35434374699SSimon Glass rk_i2c_show_regs(regs); 35534374699SSimon Glass goto i2c_exit; 35634374699SSimon Glass } 35734374699SSimon Glass udelay(1); 35834374699SSimon Glass } 35934374699SSimon Glass 36034374699SSimon Glass for (i = 0; i < words_xferred; i++) { 36134374699SSimon Glass rxdata = readl(®s->rxdata[i]); 36234374699SSimon Glass debug("I2c Read RXDATA[%d] = 0x%x\n", i, rxdata); 36334374699SSimon Glass for (j = 0; j < 4; j++) { 36434374699SSimon Glass if ((i * 4 + j) == bytes_xferred) 36534374699SSimon Glass break; 36634374699SSimon Glass *pbuf++ = (rxdata >> (j * 8)) & 0xff; 36734374699SSimon Glass } 36834374699SSimon Glass } 36934374699SSimon Glass 37034374699SSimon Glass bytes_remain_len -= bytes_xferred; 3715deaa530SWadim Egorov snd_chunk = true; 37234374699SSimon Glass debug("I2C Read bytes_remain_len %d\n", bytes_remain_len); 37334374699SSimon Glass } 37434374699SSimon Glass 37534374699SSimon Glass i2c_exit: 37634374699SSimon Glass return err; 37734374699SSimon Glass } 37834374699SSimon Glass 37934374699SSimon Glass static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len, 38034374699SSimon Glass uchar *buf, uint b_len) 38134374699SSimon Glass { 38234374699SSimon Glass struct i2c_regs *regs = i2c->regs; 38356082ed3SDavid Wu int err = 0; 38434374699SSimon Glass uchar *pbuf = buf; 38534374699SSimon Glass uint bytes_remain_len = b_len + r_len + 1; 38634374699SSimon Glass uint bytes_xferred = 0; 38734374699SSimon Glass uint words_xferred = 0; 38856082ed3SDavid Wu bool next = false; 38934374699SSimon Glass ulong start; 39034374699SSimon Glass uint txdata; 39134374699SSimon Glass uint i, j; 39234374699SSimon Glass 39334374699SSimon Glass debug("rk_i2c_write: chip = %d, reg = %d, r_len = %d, b_len = %d\n", 39434374699SSimon Glass chip, reg, r_len, b_len); 39534374699SSimon Glass 39634374699SSimon Glass while (bytes_remain_len) { 39734374699SSimon Glass if (bytes_remain_len > RK_I2C_FIFO_SIZE) 39880333fd8SJohn Keeping bytes_xferred = RK_I2C_FIFO_SIZE; 39934374699SSimon Glass else 40034374699SSimon Glass bytes_xferred = bytes_remain_len; 40134374699SSimon Glass words_xferred = DIV_ROUND_UP(bytes_xferred, 4); 40234374699SSimon Glass 40334374699SSimon Glass for (i = 0; i < words_xferred; i++) { 40434374699SSimon Glass txdata = 0; 40534374699SSimon Glass for (j = 0; j < 4; j++) { 40634374699SSimon Glass if ((i * 4 + j) == bytes_xferred) 40734374699SSimon Glass break; 40834374699SSimon Glass 40921d4b7d4SJohn Keeping if (i == 0 && j == 0 && pbuf == buf) { 41034374699SSimon Glass txdata |= (chip << 1); 41121d4b7d4SJohn Keeping } else if (i == 0 && j <= r_len && pbuf == buf) { 41234374699SSimon Glass txdata |= (reg & 41334374699SSimon Glass (0xff << ((j - 1) * 8))) << 8; 41434374699SSimon Glass } else { 41534374699SSimon Glass txdata |= (*pbuf++)<<(j * 8); 41634374699SSimon Glass } 41734374699SSimon Glass } 418551288bdSJohn Keeping writel(txdata, ®s->txdata[i]); 419551288bdSJohn Keeping debug("I2c Write TXDATA[%d] = 0x%08x\n", i, txdata); 42034374699SSimon Glass } 42134374699SSimon Glass 42256082ed3SDavid Wu /* If the write is the first, need to send start bit */ 42356082ed3SDavid Wu if (!next) { 424*3d5347f8SDavid Wu err = rk_i2c_send_start_bit(i2c, I2C_CON_EN | 425*3d5347f8SDavid Wu I2C_CON_MOD(I2C_MODE_TX)); 42656082ed3SDavid Wu if (err) 42756082ed3SDavid Wu return err; 42856082ed3SDavid Wu next = true; 42956082ed3SDavid Wu } else { 430*3d5347f8SDavid Wu writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX) | i2c->cfg, 431*3d5347f8SDavid Wu ®s->con); 43256082ed3SDavid Wu } 43334374699SSimon Glass writel(I2C_MBTFIEN | I2C_NAKRCVIEN, ®s->ien); 43456082ed3SDavid Wu writel(bytes_xferred, ®s->mtxcnt); 43534374699SSimon Glass 43634374699SSimon Glass start = get_timer(0); 43734374699SSimon Glass while (1) { 43834374699SSimon Glass if (readl(®s->ipd) & I2C_NAKRCVIPD) { 43934374699SSimon Glass writel(I2C_NAKRCVIPD, ®s->ipd); 44034374699SSimon Glass err = -EREMOTEIO; 44134374699SSimon Glass } 44234374699SSimon Glass if (readl(®s->ipd) & I2C_MBTFIPD) { 44334374699SSimon Glass writel(I2C_MBTFIPD, ®s->ipd); 44434374699SSimon Glass break; 44534374699SSimon Glass } 44634374699SSimon Glass if (get_timer(start) > I2C_TIMEOUT_MS) { 44734374699SSimon Glass debug("I2C Write Data Timeout\n"); 44834374699SSimon Glass err = -ETIMEDOUT; 44934374699SSimon Glass rk_i2c_show_regs(regs); 45034374699SSimon Glass goto i2c_exit; 45134374699SSimon Glass } 45234374699SSimon Glass udelay(1); 45334374699SSimon Glass } 45434374699SSimon Glass 45534374699SSimon Glass bytes_remain_len -= bytes_xferred; 45634374699SSimon Glass debug("I2C Write bytes_remain_len %d\n", bytes_remain_len); 45734374699SSimon Glass } 45834374699SSimon Glass 45934374699SSimon Glass i2c_exit: 46034374699SSimon Glass return err; 46134374699SSimon Glass } 46234374699SSimon Glass 46334374699SSimon Glass static int rockchip_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, 46434374699SSimon Glass int nmsgs) 46534374699SSimon Glass { 46634374699SSimon Glass struct rk_i2c *i2c = dev_get_priv(bus); 46756082ed3SDavid Wu bool snd = false; /* second message for TRX read */ 46834374699SSimon Glass int ret; 46934374699SSimon Glass 47034374699SSimon Glass debug("i2c_xfer: %d messages\n", nmsgs); 47156082ed3SDavid Wu if (nmsgs > 2 || ((nmsgs == 2) && (msg->flags & I2C_M_RD))) { 47256082ed3SDavid Wu debug("Not support more messages now, split them\n"); 47356082ed3SDavid Wu return -EINVAL; 47456082ed3SDavid Wu } 47556082ed3SDavid Wu 47634374699SSimon Glass for (; nmsgs > 0; nmsgs--, msg++) { 47734374699SSimon Glass debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len); 47856082ed3SDavid Wu 47934374699SSimon Glass if (msg->flags & I2C_M_RD) { 48056082ed3SDavid Wu /* If snd is true, it is TRX mode. */ 48134374699SSimon Glass ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf, 48256082ed3SDavid Wu msg->len, snd); 48334374699SSimon Glass } else { 48456082ed3SDavid Wu snd = true; 48534374699SSimon Glass ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf, 48634374699SSimon Glass msg->len); 48734374699SSimon Glass } 48856082ed3SDavid Wu 48934374699SSimon Glass if (ret) { 49034374699SSimon Glass debug("i2c_write: error sending\n"); 49156082ed3SDavid Wu ret = -EREMOTEIO; 49256082ed3SDavid Wu goto exit; 49334374699SSimon Glass } 49434374699SSimon Glass } 49534374699SSimon Glass 49656082ed3SDavid Wu exit: 497133495afSVasily Khoruzhick rk_i2c_send_stop_bit(i2c); 498133495afSVasily Khoruzhick rk_i2c_disable(i2c); 499133495afSVasily Khoruzhick 50056082ed3SDavid Wu return ret; 50134374699SSimon Glass } 50234374699SSimon Glass 503*3d5347f8SDavid Wu static unsigned int rk3x_i2c_get_version(struct rk_i2c *i2c) 504*3d5347f8SDavid Wu { 505*3d5347f8SDavid Wu struct i2c_regs *regs = i2c->regs; 506*3d5347f8SDavid Wu uint version; 507*3d5347f8SDavid Wu 508*3d5347f8SDavid Wu version = readl(®s->con) & I2C_CON_VERSION; 509*3d5347f8SDavid Wu 510*3d5347f8SDavid Wu return version >>= I2C_CON_VERSION_SHIFT; 511*3d5347f8SDavid Wu } 512*3d5347f8SDavid Wu 51334374699SSimon Glass int rockchip_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) 51434374699SSimon Glass { 51534374699SSimon Glass struct rk_i2c *i2c = dev_get_priv(bus); 51634374699SSimon Glass 517*3d5347f8SDavid Wu if (rk3x_i2c_get_version(i2c) >= RK_I2C_VERSION1) 518*3d5347f8SDavid Wu rk_i2c_adapter_clk(i2c, speed); 519*3d5347f8SDavid Wu else 52034374699SSimon Glass rk_i2c_set_clk(i2c, speed); 52134374699SSimon Glass 52234374699SSimon Glass return 0; 52334374699SSimon Glass } 52434374699SSimon Glass 525930bc374SSimon Glass static int rockchip_i2c_ofdata_to_platdata(struct udevice *bus) 52634374699SSimon Glass { 527930bc374SSimon Glass struct rk_i2c *priv = dev_get_priv(bus); 52834374699SSimon Glass int ret; 52934374699SSimon Glass 530930bc374SSimon Glass ret = clk_get_by_index(bus, 0, &priv->clk); 531930bc374SSimon Glass if (ret < 0) { 532930bc374SSimon Glass debug("%s: Could not get clock for %s: %d\n", __func__, 533930bc374SSimon Glass bus->name, ret); 53434374699SSimon Glass return ret; 535930bc374SSimon Glass } 536930bc374SSimon Glass 537930bc374SSimon Glass return 0; 538930bc374SSimon Glass } 539930bc374SSimon Glass 540930bc374SSimon Glass static int rockchip_i2c_probe(struct udevice *bus) 541930bc374SSimon Glass { 542930bc374SSimon Glass struct rk_i2c *priv = dev_get_priv(bus); 543930bc374SSimon Glass 544e2186db8SPhilipp Tomsich priv->regs = dev_read_addr_ptr(bus); 545930bc374SSimon Glass 546930bc374SSimon Glass return 0; 54734374699SSimon Glass } 54834374699SSimon Glass 54934374699SSimon Glass static const struct dm_i2c_ops rockchip_i2c_ops = { 55034374699SSimon Glass .xfer = rockchip_i2c_xfer, 55134374699SSimon Glass .set_bus_speed = rockchip_i2c_set_bus_speed, 55234374699SSimon Glass }; 55334374699SSimon Glass 55434374699SSimon Glass static const struct udevice_id rockchip_i2c_ids[] = { 55502a7d833SHeiko Stübner { .compatible = "rockchip,rk3066-i2c" }, 55602a7d833SHeiko Stübner { .compatible = "rockchip,rk3188-i2c" }, 55734374699SSimon Glass { .compatible = "rockchip,rk3288-i2c" }, 5584d786a23SElaine Zhang { .compatible = "rockchip,rk3328-i2c" }, 559b644354aSeric.gao@rock-chips.com { .compatible = "rockchip,rk3399-i2c" }, 560f312c7e4SShunqing Chen { .compatible = "rockchip,rk3228-i2c" }, 5612fe2ebadSElaine Zhang { .compatible = "rockchip,rv1108-i2c" }, 56234374699SSimon Glass { } 56334374699SSimon Glass }; 56434374699SSimon Glass 56534374699SSimon Glass U_BOOT_DRIVER(i2c_rockchip) = { 56634374699SSimon Glass .name = "i2c_rockchip", 56734374699SSimon Glass .id = UCLASS_I2C, 56834374699SSimon Glass .of_match = rockchip_i2c_ids, 569930bc374SSimon Glass .ofdata_to_platdata = rockchip_i2c_ofdata_to_platdata, 57034374699SSimon Glass .probe = rockchip_i2c_probe, 57134374699SSimon Glass .priv_auto_alloc_size = sizeof(struct rk_i2c), 57234374699SSimon Glass .ops = &rockchip_i2c_ops, 57334374699SSimon Glass }; 574