blob: 937410fa2c2cd684e6b26732f0ea8ea070a5dbd8 [file] [log] [blame]
Peng Fand684adb2017-02-24 09:54:18 +08001/*
2 * Copyright 2016 Freescale Semiconductors, Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <common.h>
8#include <errno.h>
9#include <asm/io.h>
10#include <asm/arch/clock.h>
11#include <asm/arch/imx-regs.h>
12#include <asm/arch/imx_lpi2c.h>
13#include <asm/arch/sys_proto.h>
14#include <dm.h>
15#include <fdtdec.h>
16#include <i2c.h>
17
Peng Fand684adb2017-02-24 09:54:18 +080018#define LPI2C_FIFO_SIZE 4
19#define LPI2C_TIMEOUT_MS 100
20
21/* Weak linked function for overridden by some SoC power function */
22int __weak init_i2c_power(unsigned i2c_num)
23{
24 return 0;
25}
26
Simon Glassba1dea42017-05-17 17:18:05 -060027static int imx_lpci2c_check_busy_bus(const struct imx_lpi2c_reg *regs)
Peng Fand684adb2017-02-24 09:54:18 +080028{
Peng Fand684adb2017-02-24 09:54:18 +080029 lpi2c_status_t result = LPI2C_SUCESS;
30 u32 status;
31
32 status = readl(&regs->msr);
33
34 if ((status & LPI2C_MSR_BBF_MASK) && !(status & LPI2C_MSR_MBF_MASK))
35 result = LPI2C_BUSY;
36
37 return result;
38}
39
Simon Glassba1dea42017-05-17 17:18:05 -060040static int imx_lpci2c_check_clear_error(struct imx_lpi2c_reg *regs)
Peng Fand684adb2017-02-24 09:54:18 +080041{
Peng Fand684adb2017-02-24 09:54:18 +080042 lpi2c_status_t result = LPI2C_SUCESS;
43 u32 val, status;
44
45 status = readl(&regs->msr);
46 /* errors to check for */
47 status &= LPI2C_MSR_NDF_MASK | LPI2C_MSR_ALF_MASK |
48 LPI2C_MSR_FEF_MASK | LPI2C_MSR_PLTF_MASK;
49
50 if (status) {
51 if (status & LPI2C_MSR_PLTF_MASK)
52 result = LPI2C_PIN_LOW_TIMEOUT_ERR;
53 else if (status & LPI2C_MSR_ALF_MASK)
54 result = LPI2C_ARB_LOST_ERR;
55 else if (status & LPI2C_MSR_NDF_MASK)
56 result = LPI2C_NAK_ERR;
57 else if (status & LPI2C_MSR_FEF_MASK)
58 result = LPI2C_FIFO_ERR;
59
60 /* clear status flags */
61 writel(0x7f00, &regs->msr);
62 /* reset fifos */
63 val = readl(&regs->mcr);
64 val |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
65 writel(val, &regs->mcr);
66 }
67
68 return result;
69}
70
Simon Glassba1dea42017-05-17 17:18:05 -060071static int bus_i2c_wait_for_tx_ready(struct imx_lpi2c_reg *regs)
Peng Fand684adb2017-02-24 09:54:18 +080072{
Peng Fand684adb2017-02-24 09:54:18 +080073 lpi2c_status_t result = LPI2C_SUCESS;
74 u32 txcount = 0;
75 ulong start_time = get_timer(0);
76
77 do {
78 txcount = LPI2C_MFSR_TXCOUNT(readl(&regs->mfsr));
79 txcount = LPI2C_FIFO_SIZE - txcount;
Simon Glassba1dea42017-05-17 17:18:05 -060080 result = imx_lpci2c_check_clear_error(regs);
Peng Fand684adb2017-02-24 09:54:18 +080081 if (result) {
82 debug("i2c: wait for tx ready: result 0x%x\n", result);
83 return result;
84 }
85 if (get_timer(start_time) > LPI2C_TIMEOUT_MS) {
86 debug("i2c: wait for tx ready: timeout\n");
87 return -1;
88 }
89 } while (!txcount);
90
91 return result;
92}
93
Simon Glassba1dea42017-05-17 17:18:05 -060094static int bus_i2c_send(struct imx_lpi2c_reg *regs, u8 *txbuf, int len)
Peng Fand684adb2017-02-24 09:54:18 +080095{
Peng Fand684adb2017-02-24 09:54:18 +080096 lpi2c_status_t result = LPI2C_SUCESS;
97
98 /* empty tx */
99 if (!len)
100 return result;
101
102 while (len--) {
Simon Glassba1dea42017-05-17 17:18:05 -0600103 result = bus_i2c_wait_for_tx_ready(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800104 if (result) {
105 debug("i2c: send wait fot tx ready: %d\n", result);
106 return result;
107 }
108 writel(*txbuf++, &regs->mtdr);
109 }
110
111 return result;
112}
113
Simon Glassba1dea42017-05-17 17:18:05 -0600114static int bus_i2c_receive(struct imx_lpi2c_reg *regs, u8 *rxbuf, int len)
Peng Fand684adb2017-02-24 09:54:18 +0800115{
Peng Fand684adb2017-02-24 09:54:18 +0800116 lpi2c_status_t result = LPI2C_SUCESS;
117 u32 val;
118 ulong start_time = get_timer(0);
119
120 /* empty read */
121 if (!len)
122 return result;
123
Simon Glassba1dea42017-05-17 17:18:05 -0600124 result = bus_i2c_wait_for_tx_ready(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800125 if (result) {
126 debug("i2c: receive wait fot tx ready: %d\n", result);
127 return result;
128 }
129
130 /* clear all status flags */
131 writel(0x7f00, &regs->msr);
132 /* send receive command */
133 val = LPI2C_MTDR_CMD(0x1) | LPI2C_MTDR_DATA(len - 1);
134 writel(val, &regs->mtdr);
135
136 while (len--) {
137 do {
Simon Glassba1dea42017-05-17 17:18:05 -0600138 result = imx_lpci2c_check_clear_error(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800139 if (result) {
Simon Glassba1dea42017-05-17 17:18:05 -0600140 debug("i2c: receive check clear error: %d\n",
141 result);
Peng Fand684adb2017-02-24 09:54:18 +0800142 return result;
143 }
144 if (get_timer(start_time) > LPI2C_TIMEOUT_MS) {
145 debug("i2c: receive mrdr: timeout\n");
146 return -1;
147 }
148 val = readl(&regs->mrdr);
149 } while (val & LPI2C_MRDR_RXEMPTY_MASK);
150 *rxbuf++ = LPI2C_MRDR_DATA(val);
151 }
152
153 return result;
154}
155
Simon Glassba1dea42017-05-17 17:18:05 -0600156static int bus_i2c_start(struct imx_lpi2c_reg *regs, u8 addr, u8 dir)
Peng Fand684adb2017-02-24 09:54:18 +0800157{
Heinrich Schuchardt1a5d4852018-03-18 11:14:56 +0100158 lpi2c_status_t result;
Peng Fand684adb2017-02-24 09:54:18 +0800159 u32 val;
160
Simon Glassba1dea42017-05-17 17:18:05 -0600161 result = imx_lpci2c_check_busy_bus(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800162 if (result) {
163 debug("i2c: start check busy bus: 0x%x\n", result);
164 return result;
165 }
166 /* clear all status flags */
167 writel(0x7f00, &regs->msr);
168 /* turn off auto-stop condition */
169 val = readl(&regs->mcfgr1) & ~LPI2C_MCFGR1_AUTOSTOP_MASK;
170 writel(val, &regs->mcfgr1);
171 /* wait tx fifo ready */
Simon Glassba1dea42017-05-17 17:18:05 -0600172 result = bus_i2c_wait_for_tx_ready(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800173 if (result) {
174 debug("i2c: start wait for tx ready: 0x%x\n", result);
175 return result;
176 }
177 /* issue start command */
178 val = LPI2C_MTDR_CMD(0x4) | (addr << 0x1) | dir;
179 writel(val, &regs->mtdr);
180
181 return result;
182}
Simon Glassba1dea42017-05-17 17:18:05 -0600183
184static int bus_i2c_stop(struct imx_lpi2c_reg *regs)
Peng Fand684adb2017-02-24 09:54:18 +0800185{
Heinrich Schuchardt1a5d4852018-03-18 11:14:56 +0100186 lpi2c_status_t result;
Peng Fand684adb2017-02-24 09:54:18 +0800187 u32 status;
188
Simon Glassba1dea42017-05-17 17:18:05 -0600189 result = bus_i2c_wait_for_tx_ready(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800190 if (result) {
191 debug("i2c: stop wait for tx ready: 0x%x\n", result);
192 return result;
193 }
194
195 /* send stop command */
196 writel(LPI2C_MTDR_CMD(0x2), &regs->mtdr);
197
198 while (result == LPI2C_SUCESS) {
199 status = readl(&regs->msr);
Simon Glassba1dea42017-05-17 17:18:05 -0600200 result = imx_lpci2c_check_clear_error(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800201 /* stop detect flag */
202 if (status & LPI2C_MSR_SDF_MASK) {
203 /* clear stop flag */
204 status &= LPI2C_MSR_SDF_MASK;
205 writel(status, &regs->msr);
206 break;
207 }
208 }
209
210 return result;
211}
212
Simon Glassba1dea42017-05-17 17:18:05 -0600213static int bus_i2c_read(struct imx_lpi2c_reg *regs, u32 chip, u8 *buf, int len)
Peng Fand684adb2017-02-24 09:54:18 +0800214{
Heinrich Schuchardt1a5d4852018-03-18 11:14:56 +0100215 lpi2c_status_t result;
Peng Fand684adb2017-02-24 09:54:18 +0800216
Simon Glassba1dea42017-05-17 17:18:05 -0600217 result = bus_i2c_start(regs, chip, 1);
Peng Fand684adb2017-02-24 09:54:18 +0800218 if (result)
219 return result;
Simon Glassba1dea42017-05-17 17:18:05 -0600220 result = bus_i2c_receive(regs, buf, len);
Peng Fand684adb2017-02-24 09:54:18 +0800221 if (result)
222 return result;
Simon Glassba1dea42017-05-17 17:18:05 -0600223 result = bus_i2c_stop(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800224 if (result)
225 return result;
226
227 return result;
228}
229
Simon Glassba1dea42017-05-17 17:18:05 -0600230static int bus_i2c_write(struct imx_lpi2c_reg *regs, u32 chip, u8 *buf, int len)
Peng Fand684adb2017-02-24 09:54:18 +0800231{
Heinrich Schuchardt1a5d4852018-03-18 11:14:56 +0100232 lpi2c_status_t result;
Peng Fand684adb2017-02-24 09:54:18 +0800233
Simon Glassba1dea42017-05-17 17:18:05 -0600234 result = bus_i2c_start(regs, chip, 0);
Peng Fand684adb2017-02-24 09:54:18 +0800235 if (result)
236 return result;
Simon Glassba1dea42017-05-17 17:18:05 -0600237 result = bus_i2c_send(regs, buf, len);
Peng Fand684adb2017-02-24 09:54:18 +0800238 if (result)
239 return result;
Simon Glassba1dea42017-05-17 17:18:05 -0600240 result = bus_i2c_stop(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800241 if (result)
242 return result;
243
244 return result;
245}
246
247
248static int bus_i2c_set_bus_speed(struct udevice *bus, int speed)
249{
Simon Glassba1dea42017-05-17 17:18:05 -0600250 struct imx_lpi2c_reg *regs;
Peng Fand684adb2017-02-24 09:54:18 +0800251 u32 val;
252 u32 preescale = 0, best_pre = 0, clkhi = 0;
253 u32 best_clkhi = 0, abs_error = 0, rate;
254 u32 error = 0xffffffff;
255 u32 clock_rate;
256 bool mode;
257 int i;
258
Simon Glassba1dea42017-05-17 17:18:05 -0600259 regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
Peng Fan32306dd2018-01-02 15:41:52 +0800260 clock_rate = imx_get_i2cclk(bus->seq);
Peng Fand684adb2017-02-24 09:54:18 +0800261 if (!clock_rate)
262 return -EPERM;
263
264 mode = (readl(&regs->mcr) & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT;
265 /* disable master mode */
266 val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
267 writel(val | LPI2C_MCR_MEN(0), &regs->mcr);
268
269 for (preescale = 1; (preescale <= 128) &&
270 (error != 0); preescale = 2 * preescale) {
271 for (clkhi = 1; clkhi < 32; clkhi++) {
272 if (clkhi == 1)
273 rate = (clock_rate / preescale) / (1 + 3 + 2 + 2 / preescale);
274 else
275 rate = (clock_rate / preescale / (3 * clkhi + 2 + 2 / preescale));
276
277 abs_error = speed > rate ? speed - rate : rate - speed;
278
279 if (abs_error < error) {
280 best_pre = preescale;
281 best_clkhi = clkhi;
282 error = abs_error;
283 if (abs_error == 0)
284 break;
285 }
286 }
287 }
288
289 /* Standard, fast, fast mode plus and ultra-fast transfers. */
290 val = LPI2C_MCCR0_CLKHI(best_clkhi);
291 if (best_clkhi < 2)
292 val |= LPI2C_MCCR0_CLKLO(3) | LPI2C_MCCR0_SETHOLD(2) | LPI2C_MCCR0_DATAVD(1);
293 else
294 val |= LPI2C_MCCR0_CLKLO(2 * best_clkhi) | LPI2C_MCCR0_SETHOLD(best_clkhi) |
295 LPI2C_MCCR0_DATAVD(best_clkhi / 2);
296 writel(val, &regs->mccr0);
297
298 for (i = 0; i < 8; i++) {
299 if (best_pre == (1 << i)) {
300 best_pre = i;
301 break;
302 }
303 }
304
305 val = readl(&regs->mcfgr1) & ~LPI2C_MCFGR1_PRESCALE_MASK;
306 writel(val | LPI2C_MCFGR1_PRESCALE(best_pre), &regs->mcfgr1);
307
308 if (mode) {
309 val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
310 writel(val | LPI2C_MCR_MEN(1), &regs->mcr);
311 }
312
313 return 0;
314}
315
316static int bus_i2c_init(struct udevice *bus, int speed)
317{
Simon Glassba1dea42017-05-17 17:18:05 -0600318 struct imx_lpi2c_reg *regs;
Peng Fand684adb2017-02-24 09:54:18 +0800319 u32 val;
320 int ret;
321
Simon Glassba1dea42017-05-17 17:18:05 -0600322 regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
Peng Fand684adb2017-02-24 09:54:18 +0800323 /* reset peripheral */
324 writel(LPI2C_MCR_RST_MASK, &regs->mcr);
325 writel(0x0, &regs->mcr);
326 /* Disable Dozen mode */
327 writel(LPI2C_MCR_DBGEN(0) | LPI2C_MCR_DOZEN(1), &regs->mcr);
328 /* host request disable, active high, external pin */
329 val = readl(&regs->mcfgr0);
330 val &= (~(LPI2C_MCFGR0_HREN_MASK | LPI2C_MCFGR0_HRPOL_MASK |
331 LPI2C_MCFGR0_HRSEL_MASK));
332 val |= LPI2C_MCFGR0_HRPOL(0x1);
333 writel(val, &regs->mcfgr0);
334 /* pincfg and ignore ack */
335 val = readl(&regs->mcfgr1);
336 val &= ~(LPI2C_MCFGR1_PINCFG_MASK | LPI2C_MCFGR1_IGNACK_MASK);
337 val |= LPI2C_MCFGR1_PINCFG(0x0); /* 2 pin open drain */
338 val |= LPI2C_MCFGR1_IGNACK(0x0); /* ignore nack */
339 writel(val, &regs->mcfgr1);
340
341 ret = bus_i2c_set_bus_speed(bus, speed);
342
343 /* enable lpi2c in master mode */
344 val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
345 writel(val | LPI2C_MCR_MEN(1), &regs->mcr);
346
347 debug("i2c : controller bus %d, speed %d:\n", bus->seq, speed);
348
349 return ret;
350}
351
352static int imx_lpi2c_probe_chip(struct udevice *bus, u32 chip,
353 u32 chip_flags)
354{
Simon Glassba1dea42017-05-17 17:18:05 -0600355 struct imx_lpi2c_reg *regs;
Heinrich Schuchardt1a5d4852018-03-18 11:14:56 +0100356 lpi2c_status_t result;
Peng Fand684adb2017-02-24 09:54:18 +0800357
Simon Glassba1dea42017-05-17 17:18:05 -0600358 regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
359 result = bus_i2c_start(regs, chip, 0);
Peng Fand684adb2017-02-24 09:54:18 +0800360 if (result) {
Simon Glassba1dea42017-05-17 17:18:05 -0600361 bus_i2c_stop(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800362 bus_i2c_init(bus, 100000);
363 return result;
364 }
365
Simon Glassba1dea42017-05-17 17:18:05 -0600366 result = bus_i2c_stop(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800367 if (result) {
368 bus_i2c_init(bus, 100000);
369 return -result;
370 }
371
372 return result;
373}
374
375static int imx_lpi2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
376{
Simon Glassba1dea42017-05-17 17:18:05 -0600377 struct imx_lpi2c_reg *regs;
Peng Fand684adb2017-02-24 09:54:18 +0800378 int ret = 0;
379
Simon Glassba1dea42017-05-17 17:18:05 -0600380 regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
Peng Fand684adb2017-02-24 09:54:18 +0800381 for (; nmsgs > 0; nmsgs--, msg++) {
382 debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
383 if (msg->flags & I2C_M_RD)
Simon Glassba1dea42017-05-17 17:18:05 -0600384 ret = bus_i2c_read(regs, msg->addr, msg->buf, msg->len);
Peng Fand684adb2017-02-24 09:54:18 +0800385 else {
Simon Glassba1dea42017-05-17 17:18:05 -0600386 ret = bus_i2c_write(regs, msg->addr, msg->buf,
Peng Fand684adb2017-02-24 09:54:18 +0800387 msg->len);
388 if (ret)
389 break;
390 }
391 }
392
393 if (ret)
394 debug("i2c_write: error sending\n");
395
396 return ret;
397}
398
399static int imx_lpi2c_set_bus_speed(struct udevice *bus, unsigned int speed)
400{
401 return bus_i2c_set_bus_speed(bus, speed);
402}
403
404static int imx_lpi2c_probe(struct udevice *bus)
405{
406 struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
407 fdt_addr_t addr;
408 int ret;
409
410 i2c_bus->driver_data = dev_get_driver_data(bus);
411
Simon Glassba1dea42017-05-17 17:18:05 -0600412 addr = devfdt_get_addr(bus);
Peng Fand684adb2017-02-24 09:54:18 +0800413 if (addr == FDT_ADDR_T_NONE)
Simon Glassf44b4bf2017-09-17 16:54:53 -0600414 return -EINVAL;
Peng Fand684adb2017-02-24 09:54:18 +0800415
416 i2c_bus->base = addr;
417 i2c_bus->index = bus->seq;
418 i2c_bus->bus = bus;
419
420 /* power up i2c resource */
Peng Fan32306dd2018-01-02 15:41:52 +0800421 ret = init_i2c_power(bus->seq);
Peng Fand684adb2017-02-24 09:54:18 +0800422 if (ret) {
423 debug("init_i2c_power err = %d\n", ret);
424 return ret;
425 }
426
Peng Fan32306dd2018-01-02 15:41:52 +0800427 /* To i.MX7ULP, only i2c4-7 can be handled by A7 core */
428 ret = enable_i2c_clk(1, bus->seq);
Peng Fand684adb2017-02-24 09:54:18 +0800429 if (ret < 0)
430 return ret;
431
432 ret = bus_i2c_init(bus, 100000);
433 if (ret < 0)
434 return ret;
435
436 debug("i2c : controller bus %d at %lu , speed %d: ",
437 bus->seq, i2c_bus->base,
438 i2c_bus->speed);
439
440 return 0;
441}
442
443static const struct dm_i2c_ops imx_lpi2c_ops = {
444 .xfer = imx_lpi2c_xfer,
445 .probe_chip = imx_lpi2c_probe_chip,
446 .set_bus_speed = imx_lpi2c_set_bus_speed,
447};
448
449static const struct udevice_id imx_lpi2c_ids[] = {
450 { .compatible = "fsl,imx7ulp-lpi2c", },
451 {}
452};
453
454U_BOOT_DRIVER(imx_lpi2c) = {
455 .name = "imx_lpi2c",
456 .id = UCLASS_I2C,
457 .of_match = imx_lpi2c_ids,
458 .probe = imx_lpi2c_probe,
459 .priv_auto_alloc_size = sizeof(struct imx_lpi2c_bus),
460 .ops = &imx_lpi2c_ops,
461};