blob: 5ce4c7d8146ef48b8af4cd22cb12e9838276c73b [file] [log] [blame]
Angel Pons1ddb8942020-04-04 18:51:26 +02001/* SPDX-License-Identifier: GPL-2.0-only */
David Hendricks45256b32012-12-27 14:06:05 -08002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Gabe Blackcdb61a62014-04-07 18:45:14 -07004#include <assert.h>
Stefan Reinauer08dc3572013-05-14 16:57:50 -07005#include <console/console.h>
David Hendricksb959fbb2013-04-05 16:11:12 -07006#include <delay.h>
Nico Huber0f2dd1e2017-08-01 14:02:40 +02007#include <device/i2c_simple.h>
Julius Werner1ed0c8c2014-10-20 13:16:29 -07008#include <soc/clk.h>
9#include <soc/i2c.h>
10#include <soc/periph.h>
Jes Klinke19baa9d2022-02-22 16:00:09 -080011#include <timer.h>
12
13#define I2C_TIMEOUT_US (1000 * USECS_PER_MSEC)
David Hendricks45256b32012-12-27 14:06:05 -080014
Stefan Reinauer6a001132017-07-13 02:20:27 +020015struct __packed i2c_regs
Gabe Blackcdb61a62014-04-07 18:45:14 -070016{
17 uint8_t con;
18 uint8_t _1[3];
19 uint8_t stat;
20 uint8_t _2[3];
21 uint8_t add;
22 uint8_t _3[3];
23 uint8_t ds;
24 uint8_t _4[3];
25 uint8_t lc;
26 uint8_t _5[3];
David Hendricks45256b32012-12-27 14:06:05 -080027};
28
Gabe Blackcdb61a62014-04-07 18:45:14 -070029struct s3c24x0_i2c_bus {
30 int bus_num;
31 struct i2c_regs *regs;
32 enum periph_id periph_id;
33};
34
35enum {
36 I2cConIntPending = 0x1 << 4,
37 I2cConIntEn = 0x1 << 5,
38 I2cConAckGen = 0x1 << 7
39};
40
41enum {
42 I2cStatAck = 0x1 << 0,
43 I2cStatAddrZero = 0x1 << 1,
44 I2cStatAddrSlave = 0x1 << 2,
45 I2cStatArb = 0x1 << 3,
46 I2cStatEnable = 0x1 << 4,
47 I2cStatStartStop = 0x1 << 5,
48 I2cStatBusy = 0x1 << 5,
49
50 I2cStatModeMask = 0x3 << 6,
51 I2cStatSlaveRecv = 0x0 << 6,
52 I2cStatSlaveXmit = 0x1 << 6,
53 I2cStatMasterRecv = 0x2 << 6,
54 I2cStatMasterXmit = 0x3 << 6
55};
56
57static struct s3c24x0_i2c_bus i2c_busses[] = {
David Hendricksb959fbb2013-04-05 16:11:12 -070058 {
59 .bus_num = 0,
Gabe Blackcdb61a62014-04-07 18:45:14 -070060 .regs = (void *)0x12c60000,
David Hendricksb959fbb2013-04-05 16:11:12 -070061 .periph_id = PERIPH_ID_I2C0,
62 },
63 {
64 .bus_num = 1,
Gabe Blackcdb61a62014-04-07 18:45:14 -070065 .regs = (void *)0x12c70000,
David Hendricksb959fbb2013-04-05 16:11:12 -070066 .periph_id = PERIPH_ID_I2C1,
67 },
68 {
69 .bus_num = 2,
Gabe Blackcdb61a62014-04-07 18:45:14 -070070 .regs = (void *)0x12c80000,
David Hendricksb959fbb2013-04-05 16:11:12 -070071 .periph_id = PERIPH_ID_I2C2,
72 },
73 {
74 .bus_num = 3,
Gabe Blackcdb61a62014-04-07 18:45:14 -070075 .regs = (void *)0x12c90000,
David Hendricksb959fbb2013-04-05 16:11:12 -070076 .periph_id = PERIPH_ID_I2C3,
77 },
78 {
79 .bus_num = 4,
Gabe Blackcdb61a62014-04-07 18:45:14 -070080 .regs = (void *)0x12ca0000,
David Hendricksb959fbb2013-04-05 16:11:12 -070081 .periph_id = PERIPH_ID_I2C4,
82 },
83 {
84 .bus_num = 5,
Gabe Blackcdb61a62014-04-07 18:45:14 -070085 .regs = (void *)0x12cb0000,
David Hendricksb959fbb2013-04-05 16:11:12 -070086 .periph_id = PERIPH_ID_I2C5,
87 },
88 {
89 .bus_num = 6,
Gabe Blackcdb61a62014-04-07 18:45:14 -070090 .regs = (void *)0x12cc0000,
David Hendricksb959fbb2013-04-05 16:11:12 -070091 .periph_id = PERIPH_ID_I2C6,
92 },
93 {
94 .bus_num = 7,
Gabe Blackcdb61a62014-04-07 18:45:14 -070095 .regs = (void *)0x12cd0000,
David Hendricksb959fbb2013-04-05 16:11:12 -070096 .periph_id = PERIPH_ID_I2C7,
97 },
David Hendricks45256b32012-12-27 14:06:05 -080098};
David Hendricks45256b32012-12-27 14:06:05 -080099
Gabe Blackcdb61a62014-04-07 18:45:14 -0700100static int i2c_int_pending(struct i2c_regs *regs)
101{
Julius Werner2f37bd62015-02-19 14:51:15 -0800102 return read8(&regs->con) & I2cConIntPending;
Gabe Blackcdb61a62014-04-07 18:45:14 -0700103}
104
105static void i2c_clear_int(struct i2c_regs *regs)
106{
Julius Werner2f37bd62015-02-19 14:51:15 -0800107 write8(&regs->con, read8(&regs->con) & ~I2cConIntPending);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700108}
109
110static void i2c_ack_enable(struct i2c_regs *regs)
111{
Julius Werner2f37bd62015-02-19 14:51:15 -0800112 write8(&regs->con, read8(&regs->con) | I2cConAckGen);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700113}
114
115static void i2c_ack_disable(struct i2c_regs *regs)
116{
Julius Werner2f37bd62015-02-19 14:51:15 -0800117 write8(&regs->con, read8(&regs->con) & ~I2cConAckGen);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700118}
119
120static int i2c_got_ack(struct i2c_regs *regs)
121{
Julius Werner2f37bd62015-02-19 14:51:15 -0800122 return !(read8(&regs->stat) & I2cStatAck);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700123}
124
Jes Klinke19baa9d2022-02-22 16:00:09 -0800125static int i2c_wait_for_idle(struct i2c_regs *regs, int timeout_us)
Gabe Blackcdb61a62014-04-07 18:45:14 -0700126{
Jes Klinke19baa9d2022-02-22 16:00:09 -0800127 int timeout = DIV_ROUND_UP(timeout_us, 10);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700128 while (timeout--) {
Julius Werner2f37bd62015-02-19 14:51:15 -0800129 if (!(read8(&regs->stat) & I2cStatBusy))
Gabe Blackcdb61a62014-04-07 18:45:14 -0700130 return 0;
131 udelay(10);
132 }
133 printk(BIOS_ERR, "I2C timeout waiting for idle.\n");
134 return 1;
135}
136
Jes Klinke19baa9d2022-02-22 16:00:09 -0800137static int i2c_wait_for_int(struct i2c_regs *regs, int timeout_us)
Gabe Blackcdb61a62014-04-07 18:45:14 -0700138{
Jes Klinke19baa9d2022-02-22 16:00:09 -0800139 int timeout = DIV_ROUND_UP(timeout_us, 10);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700140 while (timeout--) {
141 if (i2c_int_pending(regs))
142 return 0;
143 udelay(10);
144 }
145 printk(BIOS_ERR, "I2C timeout waiting for I2C interrupt.\n");
146 return 1;
147}
148
Gabe Blackcdb61a62014-04-07 18:45:14 -0700149static int i2c_send_stop(struct i2c_regs *regs)
150{
Julius Werner2f37bd62015-02-19 14:51:15 -0800151 uint8_t mode = read8(&regs->stat) & (I2cStatModeMask);
152 write8(&regs->stat, mode | I2cStatEnable);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700153 i2c_clear_int(regs);
Jes Klinke19baa9d2022-02-22 16:00:09 -0800154 return i2c_wait_for_idle(regs, I2C_TIMEOUT_US);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700155}
156
157static int i2c_send_start(struct i2c_regs *regs, int read, int chip)
158{
Julius Werner2f37bd62015-02-19 14:51:15 -0800159 write8(&regs->ds, chip << 1);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700160 uint8_t mode = read ? I2cStatMasterRecv : I2cStatMasterXmit;
Julius Werner2f37bd62015-02-19 14:51:15 -0800161 write8(&regs->stat, mode | I2cStatStartStop | I2cStatEnable);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700162 i2c_clear_int(regs);
163
Jes Klinke19baa9d2022-02-22 16:00:09 -0800164 if (i2c_wait_for_int(regs, I2C_TIMEOUT_US))
Gabe Blackcdb61a62014-04-07 18:45:14 -0700165 return 1;
166
167 if (!i2c_got_ack(regs)) {
168 // Nobody home, but they may just be asleep.
169 return 1;
David Hendricks45256b32012-12-27 14:06:05 -0800170 }
171
Gabe Blackcdb61a62014-04-07 18:45:14 -0700172 return 0;
David Hendricks45256b32012-12-27 14:06:05 -0800173}
174
Gabe Blackcdb61a62014-04-07 18:45:14 -0700175static int i2c_xmit_buf(struct i2c_regs *regs, uint8_t *data, int len)
David Hendricks45256b32012-12-27 14:06:05 -0800176{
Gabe Blackcdb61a62014-04-07 18:45:14 -0700177 ASSERT(len);
178
179 i2c_ack_enable(regs);
180
181 int i;
182 for (i = 0; i < len; i++) {
Julius Werner2f37bd62015-02-19 14:51:15 -0800183 write8(&regs->ds, data[i]);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700184
185 i2c_clear_int(regs);
Jes Klinke19baa9d2022-02-22 16:00:09 -0800186 if (i2c_wait_for_int(regs, CONFIG_I2C_TRANSFER_TIMEOUT_US))
Gabe Blackcdb61a62014-04-07 18:45:14 -0700187 return 1;
188
189 if (!i2c_got_ack(regs)) {
190 printk(BIOS_INFO, "I2c nacked.\n");
191 return 1;
192 }
193 }
194
195 return 0;
David Hendricks45256b32012-12-27 14:06:05 -0800196}
197
Gabe Blackcdb61a62014-04-07 18:45:14 -0700198static int i2c_recv_buf(struct i2c_regs *regs, uint8_t *data, int len)
David Hendricks45256b32012-12-27 14:06:05 -0800199{
Gabe Blackcdb61a62014-04-07 18:45:14 -0700200 ASSERT(len);
David Hendricks45256b32012-12-27 14:06:05 -0800201
Gabe Blackcdb61a62014-04-07 18:45:14 -0700202 i2c_ack_enable(regs);
203
204 int i;
205 for (i = 0; i < len; i++) {
206 if (i == len - 1)
207 i2c_ack_disable(regs);
208
209 i2c_clear_int(regs);
Jes Klinke19baa9d2022-02-22 16:00:09 -0800210 if (i2c_wait_for_int(regs, CONFIG_I2C_TRANSFER_TIMEOUT_US))
Gabe Blackcdb61a62014-04-07 18:45:14 -0700211 return 1;
212
Julius Werner2f37bd62015-02-19 14:51:15 -0800213 data[i] = read8(&regs->ds);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700214 }
215
216 return 0;
David Hendricks45256b32012-12-27 14:06:05 -0800217}
218
Martin Roth57e89092019-10-23 21:45:23 -0600219int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments,
Nico Huber029dfff2017-07-12 17:59:16 +0200220 int seg_count)
David Hendricks45256b32012-12-27 14:06:05 -0800221{
Gabe Blackcdb61a62014-04-07 18:45:14 -0700222 struct s3c24x0_i2c_bus *i2c = &i2c_busses[bus];
223 struct i2c_regs *regs = i2c->regs;
224 int res = 0;
225
Jes Klinke19baa9d2022-02-22 16:00:09 -0800226 if (!regs || i2c_wait_for_idle(regs, I2C_TIMEOUT_US))
Gabe Blackcdb61a62014-04-07 18:45:14 -0700227 return 1;
228
Julius Werner2f37bd62015-02-19 14:51:15 -0800229 write8(&regs->stat, I2cStatMasterXmit | I2cStatEnable);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700230
231 int i;
232 for (i = 0; i < seg_count; i++) {
Nico Huber029dfff2017-07-12 17:59:16 +0200233 struct i2c_msg *seg = &segments[i];
Gabe Blackcdb61a62014-04-07 18:45:14 -0700234
Nico Huber029dfff2017-07-12 17:59:16 +0200235 res = i2c_send_start(regs, seg->flags & I2C_M_RD, seg->slave);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700236 if (res)
237 break;
Nico Huber029dfff2017-07-12 17:59:16 +0200238 if (seg->flags & I2C_M_RD)
Gabe Blackcdb61a62014-04-07 18:45:14 -0700239 res = i2c_recv_buf(regs, seg->buf, seg->len);
240 else
241 res = i2c_xmit_buf(regs, seg->buf, seg->len);
242 if (res)
243 break;
244 }
245
246 return i2c_send_stop(regs) || res;
247}
248
Martin Roth57e89092019-10-23 21:45:23 -0600249void i2c_init(unsigned int bus, int speed, int slaveadd)
Gabe Blackcdb61a62014-04-07 18:45:14 -0700250{
251 struct s3c24x0_i2c_bus *i2c = &i2c_busses[bus];
252
Stefan Reinauer1cf46a72013-02-14 17:06:43 -0800253 unsigned long freq, pres = 16, div;
David Hendricksb959fbb2013-04-05 16:11:12 -0700254 unsigned long val;
David Hendricks45256b32012-12-27 14:06:05 -0800255
Gabe Blackcdb61a62014-04-07 18:45:14 -0700256 freq = clock_get_periph_rate(i2c->periph_id);
257 // Calculate prescaler and divisor values.
David Hendricks45256b32012-12-27 14:06:05 -0800258 if ((freq / pres / (16 + 1)) > speed)
259 /* set prescaler to 512 */
260 pres = 512;
261
262 div = 0;
263
264 while ((freq / pres / (div + 1)) > speed)
265 div++;
266
Gabe Blackcdb61a62014-04-07 18:45:14 -0700267 // Set prescaler, divisor according to freq, also set ACKGEN, IRQ.
268 val = (div & 0x0f) | 0xa0 | ((pres == 512) ? 0x40 : 0);
Julius Werner2f37bd62015-02-19 14:51:15 -0800269 write32(&i2c->regs->con, val);
David Hendricks45256b32012-12-27 14:06:05 -0800270
Gabe Blackcdb61a62014-04-07 18:45:14 -0700271 // Init to SLAVE RECEIVE mode and clear I2CADDn.
Julius Werner2f37bd62015-02-19 14:51:15 -0800272 write32(&i2c->regs->stat, 0);
273 write32(&i2c->regs->add, slaveadd);
Gabe Blackcdb61a62014-04-07 18:45:14 -0700274 // program Master Transmit (and implicit STOP).
Julius Werner2f37bd62015-02-19 14:51:15 -0800275 write32(&i2c->regs->stat, I2cStatMasterXmit | I2cStatEnable);
David Hendricks45256b32012-12-27 14:06:05 -0800276}