blob: 4636da9f3015ec8854c471fe3041fb8560f70041 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Peng Fand684adb2017-02-24 09:54:18 +08002/*
3 * Copyright 2016 Freescale Semiconductors, Inc.
Peng Fand684adb2017-02-24 09:54:18 +08004 */
5
Peng Fand684adb2017-02-24 09:54:18 +08006#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -06007#include <log.h>
Peng Fand684adb2017-02-24 09:54:18 +08008#include <asm/io.h>
9#include <asm/arch/clock.h>
10#include <asm/arch/imx-regs.h>
Ye Lid9103f82018-07-08 11:46:40 +080011#include <imx_lpi2c.h>
Peng Fand684adb2017-02-24 09:54:18 +080012#include <asm/arch/sys_proto.h>
13#include <dm.h>
14#include <fdtdec.h>
15#include <i2c.h>
Simon Glass9bc15642020-02-03 07:36:16 -070016#include <dm/device_compat.h>
Peng Fand684adb2017-02-24 09:54:18 +080017
Peng Fand684adb2017-02-24 09:54:18 +080018#define LPI2C_FIFO_SIZE 4
Gao Pan52d457b2018-07-08 11:46:41 +080019#define LPI2C_NACK_TOUT_MS 1
Peng Fand684adb2017-02-24 09:54:18 +080020#define LPI2C_TIMEOUT_MS 100
21
Fedor Rosse78d13a2024-08-07 16:08:01 +020022#define LPI2C_CHUNK_DATA 256U
23#define LPI2C_CHUNK_LEN_MIN 1U
24
Fedor Rossdbef5472024-08-07 16:08:00 +020025static int bus_i2c_init(struct udevice *bus);
Ye Li2c695462018-07-08 11:46:43 +080026
Peng Fand684adb2017-02-24 09:54:18 +080027/* Weak linked function for overridden by some SoC power function */
28int __weak init_i2c_power(unsigned i2c_num)
29{
30 return 0;
31}
32
Simon Glassba1dea42017-05-17 17:18:05 -060033static int imx_lpci2c_check_busy_bus(const struct imx_lpi2c_reg *regs)
Peng Fand684adb2017-02-24 09:54:18 +080034{
Peng Fand684adb2017-02-24 09:54:18 +080035 lpi2c_status_t result = LPI2C_SUCESS;
36 u32 status;
37
38 status = readl(&regs->msr);
39
40 if ((status & LPI2C_MSR_BBF_MASK) && !(status & LPI2C_MSR_MBF_MASK))
41 result = LPI2C_BUSY;
42
43 return result;
44}
45
Simon Glassba1dea42017-05-17 17:18:05 -060046static int imx_lpci2c_check_clear_error(struct imx_lpi2c_reg *regs)
Peng Fand684adb2017-02-24 09:54:18 +080047{
Peng Fand684adb2017-02-24 09:54:18 +080048 lpi2c_status_t result = LPI2C_SUCESS;
49 u32 val, status;
50
51 status = readl(&regs->msr);
52 /* errors to check for */
53 status &= LPI2C_MSR_NDF_MASK | LPI2C_MSR_ALF_MASK |
54 LPI2C_MSR_FEF_MASK | LPI2C_MSR_PLTF_MASK;
55
56 if (status) {
57 if (status & LPI2C_MSR_PLTF_MASK)
58 result = LPI2C_PIN_LOW_TIMEOUT_ERR;
59 else if (status & LPI2C_MSR_ALF_MASK)
60 result = LPI2C_ARB_LOST_ERR;
61 else if (status & LPI2C_MSR_NDF_MASK)
62 result = LPI2C_NAK_ERR;
63 else if (status & LPI2C_MSR_FEF_MASK)
64 result = LPI2C_FIFO_ERR;
65
66 /* clear status flags */
67 writel(0x7f00, &regs->msr);
68 /* reset fifos */
69 val = readl(&regs->mcr);
70 val |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
71 writel(val, &regs->mcr);
72 }
73
74 return result;
75}
76
Simon Glassba1dea42017-05-17 17:18:05 -060077static int bus_i2c_wait_for_tx_ready(struct imx_lpi2c_reg *regs)
Peng Fand684adb2017-02-24 09:54:18 +080078{
Peng Fand684adb2017-02-24 09:54:18 +080079 lpi2c_status_t result = LPI2C_SUCESS;
80 u32 txcount = 0;
81 ulong start_time = get_timer(0);
82
83 do {
84 txcount = LPI2C_MFSR_TXCOUNT(readl(&regs->mfsr));
85 txcount = LPI2C_FIFO_SIZE - txcount;
Simon Glassba1dea42017-05-17 17:18:05 -060086 result = imx_lpci2c_check_clear_error(regs);
Peng Fand684adb2017-02-24 09:54:18 +080087 if (result) {
88 debug("i2c: wait for tx ready: result 0x%x\n", result);
89 return result;
90 }
91 if (get_timer(start_time) > LPI2C_TIMEOUT_MS) {
92 debug("i2c: wait for tx ready: timeout\n");
93 return -1;
94 }
95 } while (!txcount);
96
97 return result;
98}
99
Ye Li2c695462018-07-08 11:46:43 +0800100static int bus_i2c_send(struct udevice *bus, u8 *txbuf, int len)
Peng Fand684adb2017-02-24 09:54:18 +0800101{
Ye Li890813f2020-06-09 20:29:50 -0700102 struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
103 struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
Peng Fand684adb2017-02-24 09:54:18 +0800104 lpi2c_status_t result = LPI2C_SUCESS;
105
106 /* empty tx */
107 if (!len)
108 return result;
109
110 while (len--) {
Simon Glassba1dea42017-05-17 17:18:05 -0600111 result = bus_i2c_wait_for_tx_ready(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800112 if (result) {
Anatolij Gustschin422f8a82018-10-18 16:36:01 +0200113 debug("i2c: send wait for tx ready: %d\n", result);
Peng Fand684adb2017-02-24 09:54:18 +0800114 return result;
115 }
116 writel(*txbuf++, &regs->mtdr);
117 }
118
119 return result;
120}
121
Ye Li2c695462018-07-08 11:46:43 +0800122static int bus_i2c_receive(struct udevice *bus, u8 *rxbuf, int len)
Peng Fand684adb2017-02-24 09:54:18 +0800123{
Fedor Rosse78d13a2024-08-07 16:08:01 +0200124 struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
Ye Li890813f2020-06-09 20:29:50 -0700125 struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
126 struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
Fedor Rosse78d13a2024-08-07 16:08:01 +0200127 unsigned int chunk_len, rx_remain, timeout;
Peng Fand684adb2017-02-24 09:54:18 +0800128 lpi2c_status_t result = LPI2C_SUCESS;
129 u32 val;
130 ulong start_time = get_timer(0);
131
132 /* empty read */
133 if (!len)
134 return result;
135
Fedor Rosse78d13a2024-08-07 16:08:01 +0200136 /*
137 * Extend the timeout for a bulk read if needed.
138 * The calculated timeout is the result of multiplying the
139 * transfer length with 8 bit + ACK + one clock of extra time,
140 * considering the I2C bus frequency.
141 */
142 timeout = max(len * 10 * 1000 / i2c->speed_hz, LPI2C_TIMEOUT_MS);
Peng Fand684adb2017-02-24 09:54:18 +0800143
Fedor Rosse78d13a2024-08-07 16:08:01 +0200144 rx_remain = len;
145 while (rx_remain > 0) {
146 chunk_len = clamp(rx_remain, LPI2C_CHUNK_LEN_MIN, LPI2C_CHUNK_DATA) - 1;
Peng Fand684adb2017-02-24 09:54:18 +0800147
Fedor Rosse78d13a2024-08-07 16:08:01 +0200148 result = bus_i2c_wait_for_tx_ready(regs);
149 if (result) {
150 debug("i2c: receive wait for tx ready: %d\n", result);
151 return result;
152 }
153
154 /* clear all status flags */
155 writel(0x7f00, &regs->msr);
156 /* send receive command */
157 writel(LPI2C_MTDR_CMD(0x1) | LPI2C_MTDR_DATA(chunk_len), &regs->mtdr);
158 rx_remain = rx_remain - (chunk_len & 0xff) - 1;
159
160 while (len--) {
161 do {
162 result = imx_lpci2c_check_clear_error(regs);
163 if (result) {
164 debug("i2c: receive check clear error: %d\n",
165 result);
166 return result;
167 }
168 if (get_timer(start_time) > timeout) {
169 debug("i2c: receive mrdr: timeout\n");
170 return -1;
171 }
172 val = readl(&regs->mrdr);
173 } while (val & LPI2C_MRDR_RXEMPTY_MASK);
174 *rxbuf++ = LPI2C_MRDR_DATA(val);
175
176 /* send next receive command before controller NACKs last byte */
177 if ((len - rx_remain) < 2 && rx_remain > 0)
178 break;
179 }
Peng Fand684adb2017-02-24 09:54:18 +0800180 }
181
182 return result;
183}
184
Ye Li2c695462018-07-08 11:46:43 +0800185static int bus_i2c_start(struct udevice *bus, u8 addr, u8 dir)
Peng Fand684adb2017-02-24 09:54:18 +0800186{
Heinrich Schuchardt1a5d4852018-03-18 11:14:56 +0100187 lpi2c_status_t result;
Ye Li890813f2020-06-09 20:29:50 -0700188 struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
189 struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
Peng Fand684adb2017-02-24 09:54:18 +0800190 u32 val;
191
Simon Glassba1dea42017-05-17 17:18:05 -0600192 result = imx_lpci2c_check_busy_bus(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800193 if (result) {
194 debug("i2c: start check busy bus: 0x%x\n", result);
Ye Li2c695462018-07-08 11:46:43 +0800195
196 /* Try to init the lpi2c then check the bus busy again */
Fedor Rossdbef5472024-08-07 16:08:00 +0200197 bus_i2c_init(bus);
Ye Li2c695462018-07-08 11:46:43 +0800198 result = imx_lpci2c_check_busy_bus(regs);
199 if (result) {
200 printf("i2c: Error check busy bus: 0x%x\n", result);
201 return result;
202 }
Peng Fand684adb2017-02-24 09:54:18 +0800203 }
204 /* clear all status flags */
205 writel(0x7f00, &regs->msr);
206 /* turn off auto-stop condition */
207 val = readl(&regs->mcfgr1) & ~LPI2C_MCFGR1_AUTOSTOP_MASK;
208 writel(val, &regs->mcfgr1);
209 /* wait tx fifo ready */
Simon Glassba1dea42017-05-17 17:18:05 -0600210 result = bus_i2c_wait_for_tx_ready(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800211 if (result) {
212 debug("i2c: start wait for tx ready: 0x%x\n", result);
213 return result;
214 }
215 /* issue start command */
216 val = LPI2C_MTDR_CMD(0x4) | (addr << 0x1) | dir;
217 writel(val, &regs->mtdr);
218
219 return result;
220}
Simon Glassba1dea42017-05-17 17:18:05 -0600221
Ye Li2c695462018-07-08 11:46:43 +0800222static int bus_i2c_stop(struct udevice *bus)
Peng Fand684adb2017-02-24 09:54:18 +0800223{
Heinrich Schuchardt1a5d4852018-03-18 11:14:56 +0100224 lpi2c_status_t result;
Ye Li890813f2020-06-09 20:29:50 -0700225 struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
226 struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
Peng Fand684adb2017-02-24 09:54:18 +0800227 u32 status;
Gao Pan52d457b2018-07-08 11:46:41 +0800228 ulong start_time;
Peng Fand684adb2017-02-24 09:54:18 +0800229
Simon Glassba1dea42017-05-17 17:18:05 -0600230 result = bus_i2c_wait_for_tx_ready(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800231 if (result) {
232 debug("i2c: stop wait for tx ready: 0x%x\n", result);
233 return result;
234 }
235
236 /* send stop command */
237 writel(LPI2C_MTDR_CMD(0x2), &regs->mtdr);
238
Gao Pan52d457b2018-07-08 11:46:41 +0800239 start_time = get_timer(0);
240 while (1) {
Peng Fand684adb2017-02-24 09:54:18 +0800241 status = readl(&regs->msr);
Simon Glassba1dea42017-05-17 17:18:05 -0600242 result = imx_lpci2c_check_clear_error(regs);
Peng Fand684adb2017-02-24 09:54:18 +0800243 /* stop detect flag */
244 if (status & LPI2C_MSR_SDF_MASK) {
245 /* clear stop flag */
246 status &= LPI2C_MSR_SDF_MASK;
247 writel(status, &regs->msr);
248 break;
249 }
Gao Pan52d457b2018-07-08 11:46:41 +0800250
251 if (get_timer(start_time) > LPI2C_NACK_TOUT_MS) {
252 debug("stop timeout\n");
253 return -ETIMEDOUT;
254 }
Peng Fand684adb2017-02-24 09:54:18 +0800255 }
256
257 return result;
258}
259
Ye Li2c695462018-07-08 11:46:43 +0800260static int bus_i2c_read(struct udevice *bus, u32 chip, u8 *buf, int len)
Peng Fand684adb2017-02-24 09:54:18 +0800261{
Heinrich Schuchardt1a5d4852018-03-18 11:14:56 +0100262 lpi2c_status_t result;
Peng Fand684adb2017-02-24 09:54:18 +0800263
Ye Li2c695462018-07-08 11:46:43 +0800264 result = bus_i2c_start(bus, chip, 1);
Peng Fand684adb2017-02-24 09:54:18 +0800265 if (result)
266 return result;
Ye Li2c695462018-07-08 11:46:43 +0800267 result = bus_i2c_receive(bus, buf, len);
Peng Fand684adb2017-02-24 09:54:18 +0800268 if (result)
269 return result;
Peng Fand684adb2017-02-24 09:54:18 +0800270
271 return result;
272}
273
Ye Li2c695462018-07-08 11:46:43 +0800274static int bus_i2c_write(struct udevice *bus, u32 chip, u8 *buf, int len)
Peng Fand684adb2017-02-24 09:54:18 +0800275{
Heinrich Schuchardt1a5d4852018-03-18 11:14:56 +0100276 lpi2c_status_t result;
Peng Fand684adb2017-02-24 09:54:18 +0800277
Ye Li2c695462018-07-08 11:46:43 +0800278 result = bus_i2c_start(bus, chip, 0);
Peng Fand684adb2017-02-24 09:54:18 +0800279 if (result)
280 return result;
Ye Li2c695462018-07-08 11:46:43 +0800281 result = bus_i2c_send(bus, buf, len);
Peng Fand684adb2017-02-24 09:54:18 +0800282 if (result)
283 return result;
Peng Fand684adb2017-02-24 09:54:18 +0800284
285 return result;
286}
287
Peng Fan5b269c42018-07-17 20:38:33 +0800288u32 __weak imx_get_i2cclk(u32 i2c_num)
289{
290 return 0;
291}
292
Peng Fand684adb2017-02-24 09:54:18 +0800293static int bus_i2c_set_bus_speed(struct udevice *bus, int speed)
294{
Peng Fan5b269c42018-07-17 20:38:33 +0800295 struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
Ye Li890813f2020-06-09 20:29:50 -0700296 struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
Peng Fand684adb2017-02-24 09:54:18 +0800297 u32 val;
298 u32 preescale = 0, best_pre = 0, clkhi = 0;
299 u32 best_clkhi = 0, abs_error = 0, rate;
300 u32 error = 0xffffffff;
301 u32 clock_rate;
302 bool mode;
303 int i;
304
Ye Li725a7ac2023-04-06 18:26:35 +0800305 if (CONFIG_IS_ENABLED(CLK)) {
Peng Fan5b269c42018-07-17 20:38:33 +0800306 clock_rate = clk_get_rate(&i2c_bus->per_clk);
307 if (clock_rate <= 0) {
308 dev_err(bus, "Failed to get i2c clk: %d\n", clock_rate);
309 return clock_rate;
310 }
311 } else {
Simon Glass75e534b2020-12-16 21:20:07 -0700312 clock_rate = imx_get_i2cclk(dev_seq(bus));
Peng Fan5b269c42018-07-17 20:38:33 +0800313 if (!clock_rate)
314 return -EPERM;
315 }
Peng Fand684adb2017-02-24 09:54:18 +0800316
317 mode = (readl(&regs->mcr) & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT;
318 /* disable master mode */
319 val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
320 writel(val | LPI2C_MCR_MEN(0), &regs->mcr);
321
322 for (preescale = 1; (preescale <= 128) &&
323 (error != 0); preescale = 2 * preescale) {
324 for (clkhi = 1; clkhi < 32; clkhi++) {
325 if (clkhi == 1)
326 rate = (clock_rate / preescale) / (1 + 3 + 2 + 2 / preescale);
327 else
328 rate = (clock_rate / preescale / (3 * clkhi + 2 + 2 / preescale));
329
330 abs_error = speed > rate ? speed - rate : rate - speed;
331
332 if (abs_error < error) {
333 best_pre = preescale;
334 best_clkhi = clkhi;
335 error = abs_error;
336 if (abs_error == 0)
337 break;
338 }
339 }
340 }
341
342 /* Standard, fast, fast mode plus and ultra-fast transfers. */
343 val = LPI2C_MCCR0_CLKHI(best_clkhi);
344 if (best_clkhi < 2)
345 val |= LPI2C_MCCR0_CLKLO(3) | LPI2C_MCCR0_SETHOLD(2) | LPI2C_MCCR0_DATAVD(1);
346 else
347 val |= LPI2C_MCCR0_CLKLO(2 * best_clkhi) | LPI2C_MCCR0_SETHOLD(best_clkhi) |
348 LPI2C_MCCR0_DATAVD(best_clkhi / 2);
349 writel(val, &regs->mccr0);
350
351 for (i = 0; i < 8; i++) {
352 if (best_pre == (1 << i)) {
353 best_pre = i;
354 break;
355 }
356 }
357
358 val = readl(&regs->mcfgr1) & ~LPI2C_MCFGR1_PRESCALE_MASK;
359 writel(val | LPI2C_MCFGR1_PRESCALE(best_pre), &regs->mcfgr1);
360
361 if (mode) {
362 val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
363 writel(val | LPI2C_MCR_MEN(1), &regs->mcr);
364 }
365
366 return 0;
367}
368
Fedor Rossdbef5472024-08-07 16:08:00 +0200369static int bus_i2c_init(struct udevice *bus)
Peng Fand684adb2017-02-24 09:54:18 +0800370{
Peng Fand684adb2017-02-24 09:54:18 +0800371 u32 val;
372 int ret;
373
Fedor Rossdbef5472024-08-07 16:08:00 +0200374 struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
375 int speed = i2c->speed_hz;
376
Ye Li890813f2020-06-09 20:29:50 -0700377 struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
378 struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
Peng Fand684adb2017-02-24 09:54:18 +0800379 /* reset peripheral */
380 writel(LPI2C_MCR_RST_MASK, &regs->mcr);
381 writel(0x0, &regs->mcr);
382 /* Disable Dozen mode */
383 writel(LPI2C_MCR_DBGEN(0) | LPI2C_MCR_DOZEN(1), &regs->mcr);
384 /* host request disable, active high, external pin */
385 val = readl(&regs->mcfgr0);
386 val &= (~(LPI2C_MCFGR0_HREN_MASK | LPI2C_MCFGR0_HRPOL_MASK |
387 LPI2C_MCFGR0_HRSEL_MASK));
388 val |= LPI2C_MCFGR0_HRPOL(0x1);
389 writel(val, &regs->mcfgr0);
390 /* pincfg and ignore ack */
391 val = readl(&regs->mcfgr1);
392 val &= ~(LPI2C_MCFGR1_PINCFG_MASK | LPI2C_MCFGR1_IGNACK_MASK);
393 val |= LPI2C_MCFGR1_PINCFG(0x0); /* 2 pin open drain */
394 val |= LPI2C_MCFGR1_IGNACK(0x0); /* ignore nack */
395 writel(val, &regs->mcfgr1);
396
397 ret = bus_i2c_set_bus_speed(bus, speed);
398
399 /* enable lpi2c in master mode */
400 val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
401 writel(val | LPI2C_MCR_MEN(1), &regs->mcr);
402
Simon Glass75e534b2020-12-16 21:20:07 -0700403 debug("i2c : controller bus %d, speed %d:\n", dev_seq(bus), speed);
Peng Fand684adb2017-02-24 09:54:18 +0800404
405 return ret;
406}
407
408static int imx_lpi2c_probe_chip(struct udevice *bus, u32 chip,
409 u32 chip_flags)
410{
Heinrich Schuchardt1a5d4852018-03-18 11:14:56 +0100411 lpi2c_status_t result;
Peng Fand684adb2017-02-24 09:54:18 +0800412
Ye Li2c695462018-07-08 11:46:43 +0800413 result = bus_i2c_start(bus, chip, 0);
Peng Fand684adb2017-02-24 09:54:18 +0800414 if (result) {
Ye Li2c695462018-07-08 11:46:43 +0800415 bus_i2c_stop(bus);
Fedor Rossdbef5472024-08-07 16:08:00 +0200416 bus_i2c_init(bus);
Peng Fand684adb2017-02-24 09:54:18 +0800417 return result;
418 }
419
Ye Li2c695462018-07-08 11:46:43 +0800420 result = bus_i2c_stop(bus);
Gao Pan52d457b2018-07-08 11:46:41 +0800421 if (result)
Fedor Rossdbef5472024-08-07 16:08:00 +0200422 bus_i2c_init(bus);
Peng Fand684adb2017-02-24 09:54:18 +0800423
424 return result;
425}
426
427static int imx_lpi2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
428{
Ye Lia917ed92018-07-08 11:46:42 +0800429 int ret = 0, ret_stop;
Peng Fand684adb2017-02-24 09:54:18 +0800430
431 for (; nmsgs > 0; nmsgs--, msg++) {
432 debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
433 if (msg->flags & I2C_M_RD)
Ye Li2c695462018-07-08 11:46:43 +0800434 ret = bus_i2c_read(bus, msg->addr, msg->buf, msg->len);
Peng Fand684adb2017-02-24 09:54:18 +0800435 else {
Ye Li2c695462018-07-08 11:46:43 +0800436 ret = bus_i2c_write(bus, msg->addr, msg->buf,
Peng Fand684adb2017-02-24 09:54:18 +0800437 msg->len);
438 if (ret)
439 break;
440 }
441 }
442
443 if (ret)
444 debug("i2c_write: error sending\n");
445
Ye Li2c695462018-07-08 11:46:43 +0800446 ret_stop = bus_i2c_stop(bus);
Ye Lia917ed92018-07-08 11:46:42 +0800447 if (ret_stop)
448 debug("i2c_xfer: stop bus error\n");
449
450 ret |= ret_stop;
451
Peng Fand684adb2017-02-24 09:54:18 +0800452 return ret;
453}
454
455static int imx_lpi2c_set_bus_speed(struct udevice *bus, unsigned int speed)
456{
457 return bus_i2c_set_bus_speed(bus, speed);
458}
459
Peng Fan5b269c42018-07-17 20:38:33 +0800460__weak int enable_i2c_clk(unsigned char enable, unsigned int i2c_num)
461{
462 return 0;
463}
464
Peng Fand684adb2017-02-24 09:54:18 +0800465static int imx_lpi2c_probe(struct udevice *bus)
466{
467 struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
468 fdt_addr_t addr;
469 int ret;
470
471 i2c_bus->driver_data = dev_get_driver_data(bus);
472
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900473 addr = dev_read_addr(bus);
Peng Fand684adb2017-02-24 09:54:18 +0800474 if (addr == FDT_ADDR_T_NONE)
Simon Glassf44b4bf2017-09-17 16:54:53 -0600475 return -EINVAL;
Peng Fand684adb2017-02-24 09:54:18 +0800476
477 i2c_bus->base = addr;
Simon Glass75e534b2020-12-16 21:20:07 -0700478 i2c_bus->index = dev_seq(bus);
Peng Fand684adb2017-02-24 09:54:18 +0800479 i2c_bus->bus = bus;
480
481 /* power up i2c resource */
Simon Glass75e534b2020-12-16 21:20:07 -0700482 ret = init_i2c_power(dev_seq(bus));
Peng Fand684adb2017-02-24 09:54:18 +0800483 if (ret) {
484 debug("init_i2c_power err = %d\n", ret);
485 return ret;
486 }
487
Ye Li725a7ac2023-04-06 18:26:35 +0800488 if (CONFIG_IS_ENABLED(CLK)) {
Peng Fan5b269c42018-07-17 20:38:33 +0800489 ret = clk_get_by_name(bus, "per", &i2c_bus->per_clk);
490 if (ret) {
491 dev_err(bus, "Failed to get per clk\n");
492 return ret;
493 }
494 ret = clk_enable(&i2c_bus->per_clk);
495 if (ret) {
496 dev_err(bus, "Failed to enable per clk\n");
497 return ret;
498 }
Peng Fanf0fb3862019-07-24 08:54:16 +0000499
500 ret = clk_get_by_name(bus, "ipg", &i2c_bus->ipg_clk);
501 if (ret) {
502 dev_err(bus, "Failed to get ipg clk\n");
503 return ret;
504 }
505 ret = clk_enable(&i2c_bus->ipg_clk);
506 if (ret) {
507 dev_err(bus, "Failed to enable ipg clk\n");
508 return ret;
509 }
Peng Fan5b269c42018-07-17 20:38:33 +0800510 } else {
511 /* To i.MX7ULP, only i2c4-7 can be handled by A7 core */
Simon Glass75e534b2020-12-16 21:20:07 -0700512 ret = enable_i2c_clk(1, dev_seq(bus));
Peng Fan5b269c42018-07-17 20:38:33 +0800513 if (ret < 0)
514 return ret;
515 }
Peng Fand684adb2017-02-24 09:54:18 +0800516
Fedor Rossdbef5472024-08-07 16:08:00 +0200517 ret = bus_i2c_init(bus);
Peng Fand684adb2017-02-24 09:54:18 +0800518 if (ret < 0)
519 return ret;
520
Anatolij Gustschin422f8a82018-10-18 16:36:01 +0200521 debug("i2c : controller bus %d at 0x%lx , speed %d: ",
Simon Glass75e534b2020-12-16 21:20:07 -0700522 dev_seq(bus), i2c_bus->base,
Peng Fand684adb2017-02-24 09:54:18 +0800523 i2c_bus->speed);
524
525 return 0;
526}
527
528static const struct dm_i2c_ops imx_lpi2c_ops = {
529 .xfer = imx_lpi2c_xfer,
530 .probe_chip = imx_lpi2c_probe_chip,
531 .set_bus_speed = imx_lpi2c_set_bus_speed,
532};
533
534static const struct udevice_id imx_lpi2c_ids[] = {
535 { .compatible = "fsl,imx7ulp-lpi2c", },
Ye Lid9103f82018-07-08 11:46:40 +0800536 { .compatible = "fsl,imx8qm-lpi2c", },
Peng Fand684adb2017-02-24 09:54:18 +0800537 {}
538};
539
540U_BOOT_DRIVER(imx_lpi2c) = {
541 .name = "imx_lpi2c",
542 .id = UCLASS_I2C,
543 .of_match = imx_lpi2c_ids,
544 .probe = imx_lpi2c_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700545 .priv_auto = sizeof(struct imx_lpi2c_bus),
Peng Fand684adb2017-02-24 09:54:18 +0800546 .ops = &imx_lpi2c_ops,
547};