blob: a0498a52c7fd9329c83e4cb17a5e8f6cd496a51a [file] [log] [blame]
Angel Ponsbbc99cf2020-04-04 18:51:23 +02001/* SPDX-License-Identifier: GPL-2.0-only */
huang lin441a5782014-07-30 20:34:40 -07002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
huang lin441a5782014-07-30 20:34:40 -07004#include <assert.h>
Julius Werner7a453eb2014-10-20 13:14:55 -07005#include <console/console.h>
6#include <delay.h>
Nico Huber0f2dd1e2017-08-01 14:02:40 +02007#include <device/i2c_simple.h>
Julius Werner7a453eb2014-10-20 13:14:55 -07008#include <soc/addressmap.h>
9#include <soc/grf.h>
10#include <soc/soc.h>
11#include <soc/i2c.h>
12#include <soc/clock.h>
Elyes HAOUASc379d462020-07-27 08:16:24 +020013#include <stddef.h>
14#include <stdint.h>
huang linbbcffd92014-09-27 12:02:27 +080015
huang lin441a5782014-07-30 20:34:40 -070016#define RETRY_COUNT 3
17/* 100000us = 100ms */
18#define I2C_TIMEOUT_US 100000
Daisuke Nojiri51de5a82014-09-18 12:35:09 -070019#define I2C_BUS_MAX 6
huang lin441a5782014-07-30 20:34:40 -070020#define I2C_NOACK 2
21#define I2C_TIMEOUT 3
22
23#define i2c_info(x...) do {if (0) printk(BIOS_DEBUG, x); } while (0)
24
huang lind4c175b2016-03-02 18:46:24 +080025struct rk_i2c_regs {
huang lin441a5782014-07-30 20:34:40 -070026 u32 i2c_con;
27 u32 i2c_clkdiv;
28 u32 i2c_mrxaddr;
29 u32 i2c_mrxraddr;
30 u32 i2c_mtxcnt;
31 u32 i2c_mrxcnt;
32 u32 i2c_ien;
33 u32 i2c_ipd;
34 u32 i2c_fcnt;
35 u32 reserved0[(0x100 - 0x24) / 4];
36 u32 txdata[8];
37 u32 reserved1[(0x200 - 0x120) / 4];
38 u32 rxdata[8];
39};
40
huang lind4c175b2016-03-02 18:46:24 +080041static const uintptr_t i2c_bus[] = IC_BASES;
huang lin441a5782014-07-30 20:34:40 -070042
43/* Con register bits. */
44#define I2C_ACT2NAK (1<<6)
45#define I2C_NAK (1<<5)
46#define I2C_STOP (1<<4)
47#define I2C_START (1<<3)
48#define I2C_MODE_TX (0<<1)
49#define I2C_MODE_TRX (1<<1)
50#define I2C_MODE_RX (2<<1)
51#define I2C_EN (1<<0)
52
53#define I2C_8BIT (1<<24)
54#define I2C_16BIT (3<<24)
55#define I2C_24BIT (7<<24)
56
57/* Mtxcnt register bits. */
58#define I2C_CNT(cnt) ((cnt) & 0x3F)
59
60#define I2C_NAKRCVI (1<<6)
61#define I2C_STOPI (1<<5)
62#define I2C_STARTI (1<<4)
63#define I2C_MBRFI (1<<3)
64#define I2C_MBTFI (1<<2)
65#define I2C_BRFI (1<<1)
66#define I2C_BTFI (1<<0)
67#define I2C_CLEANI 0x7F
68
huang lind4c175b2016-03-02 18:46:24 +080069static int i2c_send_start(struct rk_i2c_regs *reg_addr)
huang lin441a5782014-07-30 20:34:40 -070070{
71 int res = 0;
72 int timeout = I2C_TIMEOUT_US;
73
74 i2c_info("I2c Start::Send Start bit\n");
Julius Werner2f37bd62015-02-19 14:51:15 -080075 write32(&reg_addr->i2c_ipd, I2C_CLEANI);
76 write32(&reg_addr->i2c_con, I2C_EN | I2C_START);
huang lin441a5782014-07-30 20:34:40 -070077 while (timeout--) {
Julius Werner2f37bd62015-02-19 14:51:15 -080078 if (read32(&reg_addr->i2c_ipd) & I2C_STARTI)
huang lin441a5782014-07-30 20:34:40 -070079 break;
80 udelay(1);
81 }
82
83 if (timeout <= 0) {
84 printk(BIOS_ERR, "I2C Start::Send Start Bit Timeout\n");
85 res = I2C_TIMEOUT;
86 }
87
88 return res;
89}
90
huang lind4c175b2016-03-02 18:46:24 +080091static int i2c_send_stop(struct rk_i2c_regs *reg_addr)
huang lin441a5782014-07-30 20:34:40 -070092{
93 int res = 0;
94 int timeout = I2C_TIMEOUT_US;
95
96 i2c_info("I2c Stop::Send Stop bit\n");
Julius Werner2f37bd62015-02-19 14:51:15 -080097 write32(&reg_addr->i2c_ipd, I2C_CLEANI);
98 write32(&reg_addr->i2c_con, I2C_EN | I2C_STOP);
huang lin441a5782014-07-30 20:34:40 -070099 while (timeout--) {
Julius Werner2f37bd62015-02-19 14:51:15 -0800100 if (read32(&reg_addr->i2c_ipd) & I2C_STOPI)
huang lin441a5782014-07-30 20:34:40 -0700101 break;
102 udelay(1);
103 }
Julius Werner2f37bd62015-02-19 14:51:15 -0800104 write32(&reg_addr->i2c_con, 0);
huang lin441a5782014-07-30 20:34:40 -0700105 if (timeout <= 0) {
106 printk(BIOS_ERR, "I2C Stop::Send Stop Bit Timeout\n");
107 res = I2C_TIMEOUT;
108 }
109
110 return res;
111}
112
Nico Huber029dfff2017-07-12 17:59:16 +0200113static int i2c_read(struct rk_i2c_regs *reg_addr, struct i2c_msg segment)
huang lin441a5782014-07-30 20:34:40 -0700114{
115 int res = 0;
116 uint8_t *data = segment.buf;
huang lin441a5782014-07-30 20:34:40 -0700117 unsigned int bytes_remaining = segment.len;
huang lin441a5782014-07-30 20:34:40 -0700118 unsigned int con = 0;
huang lin441a5782014-07-30 20:34:40 -0700119
Nico Huber029dfff2017-07-12 17:59:16 +0200120 write32(&reg_addr->i2c_mrxaddr, I2C_8BIT | segment.slave << 1 | 1);
Julius Werner2f37bd62015-02-19 14:51:15 -0800121 write32(&reg_addr->i2c_mrxraddr, 0);
Daisuke Nojiri51de5a82014-09-18 12:35:09 -0700122 con = I2C_MODE_TRX | I2C_EN | I2C_ACT2NAK;
huang lin441a5782014-07-30 20:34:40 -0700123 while (bytes_remaining) {
Jes Klinke19baa9d2022-02-22 16:00:09 -0800124 int timeout = CONFIG_I2C_TRANSFER_TIMEOUT_US;
Julius Wernerc788ae32019-08-09 16:57:20 -0700125 size_t size = MIN(bytes_remaining, 32);
126 bytes_remaining -= size;
huang lin441a5782014-07-30 20:34:40 -0700127 if (!bytes_remaining)
128 con |= I2C_EN | I2C_NAK;
huang lin441a5782014-07-30 20:34:40 -0700129
Julius Wernerc788ae32019-08-09 16:57:20 -0700130 i2c_info("I2C Read::%zu bytes\n", size);
Julius Werner2f37bd62015-02-19 14:51:15 -0800131 write32(&reg_addr->i2c_ipd, I2C_CLEANI);
132 write32(&reg_addr->i2c_con, con);
Julius Wernerc788ae32019-08-09 16:57:20 -0700133 write32(&reg_addr->i2c_mrxcnt, size);
huang lin441a5782014-07-30 20:34:40 -0700134
huang lin441a5782014-07-30 20:34:40 -0700135 while (timeout--) {
Julius Werner2f37bd62015-02-19 14:51:15 -0800136 if (read32(&reg_addr->i2c_ipd) & I2C_NAKRCVI) {
137 write32(&reg_addr->i2c_mrxcnt, 0);
138 write32(&reg_addr->i2c_con, 0);
huang lin441a5782014-07-30 20:34:40 -0700139 return I2C_NOACK;
140 }
Julius Werner2f37bd62015-02-19 14:51:15 -0800141 if (read32(&reg_addr->i2c_ipd) & I2C_MBRFI)
huang lin441a5782014-07-30 20:34:40 -0700142 break;
143 udelay(1);
144 }
145 if (timeout <= 0) {
146 printk(BIOS_ERR, "I2C Read::Recv Data Timeout\n");
Julius Werner2f37bd62015-02-19 14:51:15 -0800147 write32(&reg_addr->i2c_mrxcnt, 0);
148 write32(&reg_addr->i2c_con, 0);
Daisuke Nojiri51de5a82014-09-18 12:35:09 -0700149 return I2C_TIMEOUT;
huang lin441a5782014-07-30 20:34:40 -0700150 }
151
Julius Wernerc788ae32019-08-09 16:57:20 -0700152 buffer_from_fifo32(data, size, &reg_addr->rxdata, 4, 4);
153 data += size;
Daisuke Nojiri51de5a82014-09-18 12:35:09 -0700154 con = I2C_MODE_RX | I2C_EN | I2C_ACT2NAK;
huang lin441a5782014-07-30 20:34:40 -0700155 }
156 return res;
157}
158
Nico Huber029dfff2017-07-12 17:59:16 +0200159static int i2c_write(struct rk_i2c_regs *reg_addr, struct i2c_msg segment)
huang lin441a5782014-07-30 20:34:40 -0700160{
161 int res = 0;
162 uint8_t *data = segment.buf;
huang lin441a5782014-07-30 20:34:40 -0700163 int bytes_remaining = segment.len + 1;
huang lin441a5782014-07-30 20:34:40 -0700164
Julius Wernerc788ae32019-08-09 16:57:20 -0700165 /* Prepend one byte for the slave address to the transfer. */
166 u32 prefix = segment.slave << 1;
167 int prefsz = 1;
168
huang lin441a5782014-07-30 20:34:40 -0700169 while (bytes_remaining) {
Jes Klinke19baa9d2022-02-22 16:00:09 -0800170 int timeout = CONFIG_I2C_TRANSFER_TIMEOUT_US;
Julius Wernerc788ae32019-08-09 16:57:20 -0700171 size_t size = MIN(bytes_remaining, 32);
172 buffer_to_fifo32_prefix(data, prefix, prefsz, size,
173 &reg_addr->txdata, 4, 4);
174 data += size - prefsz;
huang lin441a5782014-07-30 20:34:40 -0700175
Julius Wernerc788ae32019-08-09 16:57:20 -0700176 i2c_info("I2C Write::%zu bytes\n", size);
Julius Werner2f37bd62015-02-19 14:51:15 -0800177 write32(&reg_addr->i2c_ipd, I2C_CLEANI);
178 write32(&reg_addr->i2c_con,
179 I2C_EN | I2C_MODE_TX | I2C_ACT2NAK);
Julius Wernerc788ae32019-08-09 16:57:20 -0700180 write32(&reg_addr->i2c_mtxcnt, size);
huang lin441a5782014-07-30 20:34:40 -0700181
huang lin441a5782014-07-30 20:34:40 -0700182 while (timeout--) {
Julius Werner2f37bd62015-02-19 14:51:15 -0800183 if (read32(&reg_addr->i2c_ipd) & I2C_NAKRCVI) {
184 write32(&reg_addr->i2c_mtxcnt, 0);
185 write32(&reg_addr->i2c_con, 0);
huang lin441a5782014-07-30 20:34:40 -0700186 return I2C_NOACK;
187 }
Julius Werner2f37bd62015-02-19 14:51:15 -0800188 if (read32(&reg_addr->i2c_ipd) & I2C_MBTFI)
huang lin441a5782014-07-30 20:34:40 -0700189 break;
190 udelay(1);
191 }
192
193 if (timeout <= 0) {
194 printk(BIOS_ERR, "I2C Write::Send Data Timeout\n");
Julius Werner2f37bd62015-02-19 14:51:15 -0800195 write32(&reg_addr->i2c_mtxcnt, 0);
196 write32(&reg_addr->i2c_con, 0);
Daisuke Nojiri51de5a82014-09-18 12:35:09 -0700197 return I2C_TIMEOUT;
huang lin441a5782014-07-30 20:34:40 -0700198 }
199
Julius Wernerc788ae32019-08-09 16:57:20 -0700200 bytes_remaining -= size;
201 prefsz = 0;
202 prefix = 0;
huang lin441a5782014-07-30 20:34:40 -0700203 }
204 return res;
205}
206
Nico Huber029dfff2017-07-12 17:59:16 +0200207static int i2c_do_xfer(void *reg_addr, struct i2c_msg segment)
huang lin441a5782014-07-30 20:34:40 -0700208{
209 int res = 0;
210
211 if (i2c_send_start(reg_addr))
212 return I2C_TIMEOUT;
Nico Huber029dfff2017-07-12 17:59:16 +0200213 if (segment.flags & I2C_M_RD)
huang lin441a5782014-07-30 20:34:40 -0700214 res = i2c_read(reg_addr, segment);
215 else
216 res = i2c_write(reg_addr, segment);
217 return i2c_send_stop(reg_addr) || res;
218}
219
Martin Roth57e89092019-10-23 21:45:23 -0600220int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments,
Nico Huber029dfff2017-07-12 17:59:16 +0200221 int seg_count)
huang lin441a5782014-07-30 20:34:40 -0700222{
223 int i;
224 int res = 0;
huang lind4c175b2016-03-02 18:46:24 +0800225 struct rk_i2c_regs *regs = (struct rk_i2c_regs *)(i2c_bus[bus]);
Nico Huber029dfff2017-07-12 17:59:16 +0200226 struct i2c_msg *seg = segments;
huang lin441a5782014-07-30 20:34:40 -0700227
228 for (i = 0; i < seg_count; i++, seg++) {
229 res = i2c_do_xfer(regs, *seg);
230 if (res)
231 break;
232 }
233 return res;
234}
huang linbbcffd92014-09-27 12:02:27 +0800235
236void i2c_init(unsigned int bus, unsigned int hz)
237{
238 unsigned int clk_div;
239 unsigned int divl;
240 unsigned int divh;
huang lind4c175b2016-03-02 18:46:24 +0800241 unsigned int i2c_src_clk;
Julius Werner8e42bd1c2016-11-01 15:24:54 -0700242 unsigned int i2c_clk;
huang lind4c175b2016-03-02 18:46:24 +0800243 struct rk_i2c_regs *regs = (struct rk_i2c_regs *)(i2c_bus[bus]);
huang linbbcffd92014-09-27 12:02:27 +0800244
huang lind4c175b2016-03-02 18:46:24 +0800245 i2c_src_clk = rkclk_i2c_clock_for_bus(bus);
huang linbbcffd92014-09-27 12:02:27 +0800246
Julius Werner8e42bd1c2016-11-01 15:24:54 -0700247 /* SCL Divisor = 8*(CLKDIVL + 1 + CLKDIVH + 1)
248 SCL = PCLK / SCLK Divisor */
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100249 clk_div = DIV_ROUND_UP(i2c_src_clk, hz * 8);
huang lin8affee52014-10-10 23:26:21 -0700250 divh = clk_div * 3 / 7 - 1;
251 divl = clk_div - divh - 2;
Julius Werner8e42bd1c2016-11-01 15:24:54 -0700252 i2c_clk = i2c_src_clk / (8 * (divl + 1 + divh + 1));
253 printk(BIOS_DEBUG, "I2C bus %u: %uHz (divh = %u, divl = %u)\n",
254 bus, i2c_clk, divh, divl);
Julius Werner7e1f68c2016-12-16 16:03:57 -0800255 assert((divh < 65536) && (divl < 65536) && hz - i2c_clk < 15*KHz);
Julius Werner2f37bd62015-02-19 14:51:15 -0800256 write32(&regs->i2c_clkdiv, (divh << 16) | (divl << 0));
huang linbbcffd92014-09-27 12:02:27 +0800257}