1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) 2014 Linaro Ltd. |
4 | * Copyright (c) 2014 HiSilicon Limited. |
5 | * |
6 | * Now only support 7 bit address. |
7 | */ |
8 | |
9 | #include <linux/clk.h> |
10 | #include <linux/delay.h> |
11 | #include <linux/i2c.h> |
12 | #include <linux/io.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/pm_runtime.h> |
18 | |
19 | /* Register Map */ |
20 | #define HIX5I2C_CTRL 0x00 |
21 | #define HIX5I2C_COM 0x04 |
22 | #define HIX5I2C_ICR 0x08 |
23 | #define HIX5I2C_SR 0x0c |
24 | #define HIX5I2C_SCL_H 0x10 |
25 | #define HIX5I2C_SCL_L 0x14 |
26 | #define HIX5I2C_TXR 0x18 |
27 | #define HIX5I2C_RXR 0x1c |
28 | |
29 | /* I2C_CTRL_REG */ |
30 | #define I2C_ENABLE BIT(8) |
31 | #define I2C_UNMASK_TOTAL BIT(7) |
32 | #define I2C_UNMASK_START BIT(6) |
33 | #define I2C_UNMASK_END BIT(5) |
34 | #define I2C_UNMASK_SEND BIT(4) |
35 | #define I2C_UNMASK_RECEIVE BIT(3) |
36 | #define I2C_UNMASK_ACK BIT(2) |
37 | #define I2C_UNMASK_ARBITRATE BIT(1) |
38 | #define I2C_UNMASK_OVER BIT(0) |
39 | #define I2C_UNMASK_ALL (I2C_UNMASK_ACK | I2C_UNMASK_OVER) |
40 | |
41 | /* I2C_COM_REG */ |
42 | #define I2C_NO_ACK BIT(4) |
43 | #define I2C_START BIT(3) |
44 | #define I2C_READ BIT(2) |
45 | #define I2C_WRITE BIT(1) |
46 | #define I2C_STOP BIT(0) |
47 | |
48 | /* I2C_ICR_REG */ |
49 | #define I2C_CLEAR_START BIT(6) |
50 | #define I2C_CLEAR_END BIT(5) |
51 | #define I2C_CLEAR_SEND BIT(4) |
52 | #define I2C_CLEAR_RECEIVE BIT(3) |
53 | #define I2C_CLEAR_ACK BIT(2) |
54 | #define I2C_CLEAR_ARBITRATE BIT(1) |
55 | #define I2C_CLEAR_OVER BIT(0) |
56 | #define I2C_CLEAR_ALL (I2C_CLEAR_START | I2C_CLEAR_END | \ |
57 | I2C_CLEAR_SEND | I2C_CLEAR_RECEIVE | \ |
58 | I2C_CLEAR_ACK | I2C_CLEAR_ARBITRATE | \ |
59 | I2C_CLEAR_OVER) |
60 | |
61 | /* I2C_SR_REG */ |
62 | #define I2C_BUSY BIT(7) |
63 | #define I2C_START_INTR BIT(6) |
64 | #define I2C_END_INTR BIT(5) |
65 | #define I2C_SEND_INTR BIT(4) |
66 | #define I2C_RECEIVE_INTR BIT(3) |
67 | #define I2C_ACK_INTR BIT(2) |
68 | #define I2C_ARBITRATE_INTR BIT(1) |
69 | #define I2C_OVER_INTR BIT(0) |
70 | |
71 | enum hix5hd2_i2c_state { |
72 | HIX5I2C_STAT_RW_ERR = -1, |
73 | HIX5I2C_STAT_INIT, |
74 | HIX5I2C_STAT_RW, |
75 | HIX5I2C_STAT_SND_STOP, |
76 | HIX5I2C_STAT_RW_SUCCESS, |
77 | }; |
78 | |
79 | struct hix5hd2_i2c_priv { |
80 | struct i2c_adapter adap; |
81 | struct i2c_msg *msg; |
82 | struct completion msg_complete; |
83 | unsigned int msg_idx; |
84 | unsigned int msg_len; |
85 | int stop; |
86 | void __iomem *regs; |
87 | struct clk *clk; |
88 | struct device *dev; |
89 | spinlock_t lock; /* IRQ synchronization */ |
90 | int err; |
91 | unsigned int freq; |
92 | enum hix5hd2_i2c_state state; |
93 | }; |
94 | |
95 | static u32 hix5hd2_i2c_clr_pend_irq(struct hix5hd2_i2c_priv *priv) |
96 | { |
97 | u32 val = readl_relaxed(priv->regs + HIX5I2C_SR); |
98 | |
99 | writel_relaxed(val, priv->regs + HIX5I2C_ICR); |
100 | |
101 | return val; |
102 | } |
103 | |
104 | static void hix5hd2_i2c_clr_all_irq(struct hix5hd2_i2c_priv *priv) |
105 | { |
106 | writel_relaxed(I2C_CLEAR_ALL, priv->regs + HIX5I2C_ICR); |
107 | } |
108 | |
109 | static void hix5hd2_i2c_disable_irq(struct hix5hd2_i2c_priv *priv) |
110 | { |
111 | writel_relaxed(0, priv->regs + HIX5I2C_CTRL); |
112 | } |
113 | |
114 | static void hix5hd2_i2c_enable_irq(struct hix5hd2_i2c_priv *priv) |
115 | { |
116 | writel_relaxed(I2C_ENABLE | I2C_UNMASK_TOTAL | I2C_UNMASK_ALL, |
117 | priv->regs + HIX5I2C_CTRL); |
118 | } |
119 | |
120 | static void hix5hd2_i2c_drv_setrate(struct hix5hd2_i2c_priv *priv) |
121 | { |
122 | u32 rate, val; |
123 | u32 scl, sysclock; |
124 | |
125 | /* close all i2c interrupt */ |
126 | val = readl_relaxed(priv->regs + HIX5I2C_CTRL); |
127 | writel_relaxed(val & (~I2C_UNMASK_TOTAL), priv->regs + HIX5I2C_CTRL); |
128 | |
129 | rate = priv->freq; |
130 | sysclock = clk_get_rate(clk: priv->clk); |
131 | scl = (sysclock / (rate * 2)) / 2 - 1; |
132 | writel_relaxed(scl, priv->regs + HIX5I2C_SCL_H); |
133 | writel_relaxed(scl, priv->regs + HIX5I2C_SCL_L); |
134 | |
135 | /* restore original interrupt*/ |
136 | writel_relaxed(val, priv->regs + HIX5I2C_CTRL); |
137 | |
138 | dev_dbg(priv->dev, "%s: sysclock=%d, rate=%d, scl=%d\n" , |
139 | __func__, sysclock, rate, scl); |
140 | } |
141 | |
142 | static void hix5hd2_i2c_init(struct hix5hd2_i2c_priv *priv) |
143 | { |
144 | hix5hd2_i2c_disable_irq(priv); |
145 | hix5hd2_i2c_drv_setrate(priv); |
146 | hix5hd2_i2c_clr_all_irq(priv); |
147 | hix5hd2_i2c_enable_irq(priv); |
148 | } |
149 | |
150 | static void hix5hd2_i2c_reset(struct hix5hd2_i2c_priv *priv) |
151 | { |
152 | clk_disable_unprepare(clk: priv->clk); |
153 | msleep(msecs: 20); |
154 | clk_prepare_enable(clk: priv->clk); |
155 | hix5hd2_i2c_init(priv); |
156 | } |
157 | |
158 | static int hix5hd2_i2c_wait_bus_idle(struct hix5hd2_i2c_priv *priv) |
159 | { |
160 | unsigned long stop_time; |
161 | u32 int_status; |
162 | |
163 | /* wait for 100 milli seconds for the bus to be idle */ |
164 | stop_time = jiffies + msecs_to_jiffies(m: 100); |
165 | do { |
166 | int_status = hix5hd2_i2c_clr_pend_irq(priv); |
167 | if (!(int_status & I2C_BUSY)) |
168 | return 0; |
169 | |
170 | usleep_range(min: 50, max: 200); |
171 | } while (time_before(jiffies, stop_time)); |
172 | |
173 | return -EBUSY; |
174 | } |
175 | |
176 | static void hix5hd2_rw_over(struct hix5hd2_i2c_priv *priv) |
177 | { |
178 | if (priv->state == HIX5I2C_STAT_SND_STOP) |
179 | dev_dbg(priv->dev, "%s: rw and send stop over\n" , __func__); |
180 | else |
181 | dev_dbg(priv->dev, "%s: have not data to send\n" , __func__); |
182 | |
183 | priv->state = HIX5I2C_STAT_RW_SUCCESS; |
184 | priv->err = 0; |
185 | } |
186 | |
187 | static void hix5hd2_rw_handle_stop(struct hix5hd2_i2c_priv *priv) |
188 | { |
189 | if (priv->stop) { |
190 | priv->state = HIX5I2C_STAT_SND_STOP; |
191 | writel_relaxed(I2C_STOP, priv->regs + HIX5I2C_COM); |
192 | } else { |
193 | hix5hd2_rw_over(priv); |
194 | } |
195 | } |
196 | |
197 | static void hix5hd2_read_handle(struct hix5hd2_i2c_priv *priv) |
198 | { |
199 | if (priv->msg_len == 1) { |
200 | /* the last byte don't need send ACK */ |
201 | writel_relaxed(I2C_READ | I2C_NO_ACK, priv->regs + HIX5I2C_COM); |
202 | } else if (priv->msg_len > 1) { |
203 | /* if i2c master receive data will send ACK */ |
204 | writel_relaxed(I2C_READ, priv->regs + HIX5I2C_COM); |
205 | } else { |
206 | hix5hd2_rw_handle_stop(priv); |
207 | } |
208 | } |
209 | |
210 | static void hix5hd2_write_handle(struct hix5hd2_i2c_priv *priv) |
211 | { |
212 | u8 data; |
213 | |
214 | if (priv->msg_len > 0) { |
215 | data = priv->msg->buf[priv->msg_idx++]; |
216 | writel_relaxed(data, priv->regs + HIX5I2C_TXR); |
217 | writel_relaxed(I2C_WRITE, priv->regs + HIX5I2C_COM); |
218 | } else { |
219 | hix5hd2_rw_handle_stop(priv); |
220 | } |
221 | } |
222 | |
223 | static int hix5hd2_rw_preprocess(struct hix5hd2_i2c_priv *priv) |
224 | { |
225 | u8 data; |
226 | |
227 | if (priv->state == HIX5I2C_STAT_INIT) { |
228 | priv->state = HIX5I2C_STAT_RW; |
229 | } else if (priv->state == HIX5I2C_STAT_RW) { |
230 | if (priv->msg->flags & I2C_M_RD) { |
231 | data = readl_relaxed(priv->regs + HIX5I2C_RXR); |
232 | priv->msg->buf[priv->msg_idx++] = data; |
233 | } |
234 | priv->msg_len--; |
235 | } else { |
236 | dev_dbg(priv->dev, "%s: error: priv->state = %d, msg_len = %d\n" , |
237 | __func__, priv->state, priv->msg_len); |
238 | return -EAGAIN; |
239 | } |
240 | return 0; |
241 | } |
242 | |
243 | static irqreturn_t hix5hd2_i2c_irq(int irqno, void *dev_id) |
244 | { |
245 | struct hix5hd2_i2c_priv *priv = dev_id; |
246 | u32 int_status; |
247 | int ret; |
248 | |
249 | spin_lock(lock: &priv->lock); |
250 | |
251 | int_status = hix5hd2_i2c_clr_pend_irq(priv); |
252 | |
253 | /* handle error */ |
254 | if (int_status & I2C_ARBITRATE_INTR) { |
255 | /* bus error */ |
256 | dev_dbg(priv->dev, "ARB bus loss\n" ); |
257 | priv->err = -EAGAIN; |
258 | priv->state = HIX5I2C_STAT_RW_ERR; |
259 | goto stop; |
260 | } else if (int_status & I2C_ACK_INTR) { |
261 | /* ack error */ |
262 | dev_dbg(priv->dev, "No ACK from device\n" ); |
263 | priv->err = -ENXIO; |
264 | priv->state = HIX5I2C_STAT_RW_ERR; |
265 | goto stop; |
266 | } |
267 | |
268 | if (int_status & I2C_OVER_INTR) { |
269 | if (priv->msg_len > 0) { |
270 | ret = hix5hd2_rw_preprocess(priv); |
271 | if (ret) { |
272 | priv->err = ret; |
273 | priv->state = HIX5I2C_STAT_RW_ERR; |
274 | goto stop; |
275 | } |
276 | if (priv->msg->flags & I2C_M_RD) |
277 | hix5hd2_read_handle(priv); |
278 | else |
279 | hix5hd2_write_handle(priv); |
280 | } else { |
281 | hix5hd2_rw_over(priv); |
282 | } |
283 | } |
284 | |
285 | stop: |
286 | if ((priv->state == HIX5I2C_STAT_RW_SUCCESS && |
287 | priv->msg->len == priv->msg_idx) || |
288 | (priv->state == HIX5I2C_STAT_RW_ERR)) { |
289 | hix5hd2_i2c_disable_irq(priv); |
290 | hix5hd2_i2c_clr_pend_irq(priv); |
291 | complete(&priv->msg_complete); |
292 | } |
293 | |
294 | spin_unlock(lock: &priv->lock); |
295 | |
296 | return IRQ_HANDLED; |
297 | } |
298 | |
299 | static void hix5hd2_i2c_message_start(struct hix5hd2_i2c_priv *priv, int stop) |
300 | { |
301 | unsigned long flags; |
302 | |
303 | spin_lock_irqsave(&priv->lock, flags); |
304 | hix5hd2_i2c_clr_all_irq(priv); |
305 | hix5hd2_i2c_enable_irq(priv); |
306 | |
307 | writel_relaxed(i2c_8bit_addr_from_msg(priv->msg), |
308 | priv->regs + HIX5I2C_TXR); |
309 | |
310 | writel_relaxed(I2C_WRITE | I2C_START, priv->regs + HIX5I2C_COM); |
311 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
312 | } |
313 | |
314 | static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv, |
315 | struct i2c_msg *msgs, int stop) |
316 | { |
317 | unsigned long timeout; |
318 | int ret; |
319 | |
320 | priv->msg = msgs; |
321 | priv->msg_idx = 0; |
322 | priv->msg_len = priv->msg->len; |
323 | priv->stop = stop; |
324 | priv->err = 0; |
325 | priv->state = HIX5I2C_STAT_INIT; |
326 | |
327 | reinit_completion(x: &priv->msg_complete); |
328 | hix5hd2_i2c_message_start(priv, stop); |
329 | |
330 | timeout = wait_for_completion_timeout(x: &priv->msg_complete, |
331 | timeout: priv->adap.timeout); |
332 | if (timeout == 0) { |
333 | priv->state = HIX5I2C_STAT_RW_ERR; |
334 | priv->err = -ETIMEDOUT; |
335 | dev_warn(priv->dev, "%s timeout=%d\n" , |
336 | msgs->flags & I2C_M_RD ? "rx" : "tx" , |
337 | priv->adap.timeout); |
338 | } |
339 | ret = priv->state; |
340 | |
341 | /* |
342 | * If this is the last message to be transfered (stop == 1) |
343 | * Then check if the bus can be brought back to idle. |
344 | */ |
345 | if (priv->state == HIX5I2C_STAT_RW_SUCCESS && stop) |
346 | ret = hix5hd2_i2c_wait_bus_idle(priv); |
347 | |
348 | if (ret < 0) |
349 | hix5hd2_i2c_reset(priv); |
350 | |
351 | return priv->err; |
352 | } |
353 | |
354 | static int hix5hd2_i2c_xfer(struct i2c_adapter *adap, |
355 | struct i2c_msg *msgs, int num) |
356 | { |
357 | struct hix5hd2_i2c_priv *priv = i2c_get_adapdata(adap); |
358 | int i, ret, stop; |
359 | |
360 | pm_runtime_get_sync(dev: priv->dev); |
361 | |
362 | for (i = 0; i < num; i++, msgs++) { |
363 | if ((i == num - 1) || (msgs->flags & I2C_M_STOP)) |
364 | stop = 1; |
365 | else |
366 | stop = 0; |
367 | |
368 | ret = hix5hd2_i2c_xfer_msg(priv, msgs, stop); |
369 | if (ret < 0) |
370 | goto out; |
371 | } |
372 | |
373 | ret = num; |
374 | |
375 | out: |
376 | pm_runtime_mark_last_busy(dev: priv->dev); |
377 | pm_runtime_put_autosuspend(dev: priv->dev); |
378 | return ret; |
379 | } |
380 | |
381 | static u32 hix5hd2_i2c_func(struct i2c_adapter *adap) |
382 | { |
383 | return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); |
384 | } |
385 | |
386 | static const struct i2c_algorithm hix5hd2_i2c_algorithm = { |
387 | .master_xfer = hix5hd2_i2c_xfer, |
388 | .functionality = hix5hd2_i2c_func, |
389 | }; |
390 | |
391 | static int hix5hd2_i2c_probe(struct platform_device *pdev) |
392 | { |
393 | struct device_node *np = pdev->dev.of_node; |
394 | struct hix5hd2_i2c_priv *priv; |
395 | unsigned int freq; |
396 | int irq, ret; |
397 | |
398 | priv = devm_kzalloc(dev: &pdev->dev, size: sizeof(*priv), GFP_KERNEL); |
399 | if (!priv) |
400 | return -ENOMEM; |
401 | |
402 | if (of_property_read_u32(np, propname: "clock-frequency" , out_value: &freq)) { |
403 | /* use 100k as default value */ |
404 | priv->freq = I2C_MAX_STANDARD_MODE_FREQ; |
405 | } else { |
406 | if (freq > I2C_MAX_FAST_MODE_FREQ) { |
407 | priv->freq = I2C_MAX_FAST_MODE_FREQ; |
408 | dev_warn(priv->dev, "use max freq %d instead\n" , |
409 | I2C_MAX_FAST_MODE_FREQ); |
410 | } else { |
411 | priv->freq = freq; |
412 | } |
413 | } |
414 | |
415 | priv->regs = devm_platform_ioremap_resource(pdev, index: 0); |
416 | if (IS_ERR(ptr: priv->regs)) |
417 | return PTR_ERR(ptr: priv->regs); |
418 | |
419 | irq = platform_get_irq(pdev, 0); |
420 | if (irq < 0) |
421 | return irq; |
422 | |
423 | priv->clk = devm_clk_get_enabled(dev: &pdev->dev, NULL); |
424 | if (IS_ERR(ptr: priv->clk)) { |
425 | dev_err(&pdev->dev, "cannot enable clock\n" ); |
426 | return PTR_ERR(ptr: priv->clk); |
427 | } |
428 | |
429 | strscpy(p: priv->adap.name, q: "hix5hd2-i2c" , size: sizeof(priv->adap.name)); |
430 | priv->dev = &pdev->dev; |
431 | priv->adap.owner = THIS_MODULE; |
432 | priv->adap.algo = &hix5hd2_i2c_algorithm; |
433 | priv->adap.retries = 3; |
434 | priv->adap.dev.of_node = np; |
435 | priv->adap.algo_data = priv; |
436 | priv->adap.dev.parent = &pdev->dev; |
437 | i2c_set_adapdata(adap: &priv->adap, data: priv); |
438 | platform_set_drvdata(pdev, data: priv); |
439 | spin_lock_init(&priv->lock); |
440 | init_completion(x: &priv->msg_complete); |
441 | |
442 | hix5hd2_i2c_init(priv); |
443 | |
444 | ret = devm_request_irq(dev: &pdev->dev, irq, handler: hix5hd2_i2c_irq, |
445 | IRQF_NO_SUSPEND, devname: dev_name(dev: &pdev->dev), dev_id: priv); |
446 | if (ret != 0) { |
447 | dev_err(&pdev->dev, "cannot request HS-I2C IRQ %d\n" , irq); |
448 | return ret; |
449 | } |
450 | |
451 | pm_runtime_set_autosuspend_delay(dev: priv->dev, MSEC_PER_SEC); |
452 | pm_runtime_use_autosuspend(dev: priv->dev); |
453 | pm_runtime_set_active(dev: priv->dev); |
454 | pm_runtime_enable(dev: priv->dev); |
455 | |
456 | ret = i2c_add_adapter(adap: &priv->adap); |
457 | if (ret < 0) |
458 | goto err_runtime; |
459 | |
460 | return ret; |
461 | |
462 | err_runtime: |
463 | pm_runtime_disable(dev: priv->dev); |
464 | pm_runtime_set_suspended(dev: priv->dev); |
465 | |
466 | return ret; |
467 | } |
468 | |
469 | static void hix5hd2_i2c_remove(struct platform_device *pdev) |
470 | { |
471 | struct hix5hd2_i2c_priv *priv = platform_get_drvdata(pdev); |
472 | |
473 | i2c_del_adapter(adap: &priv->adap); |
474 | pm_runtime_disable(dev: priv->dev); |
475 | pm_runtime_set_suspended(dev: priv->dev); |
476 | } |
477 | |
478 | static int hix5hd2_i2c_runtime_suspend(struct device *dev) |
479 | { |
480 | struct hix5hd2_i2c_priv *priv = dev_get_drvdata(dev); |
481 | |
482 | clk_disable_unprepare(clk: priv->clk); |
483 | |
484 | return 0; |
485 | } |
486 | |
487 | static int hix5hd2_i2c_runtime_resume(struct device *dev) |
488 | { |
489 | struct hix5hd2_i2c_priv *priv = dev_get_drvdata(dev); |
490 | |
491 | clk_prepare_enable(clk: priv->clk); |
492 | hix5hd2_i2c_init(priv); |
493 | |
494 | return 0; |
495 | } |
496 | |
497 | static const struct dev_pm_ops hix5hd2_i2c_pm_ops = { |
498 | RUNTIME_PM_OPS(hix5hd2_i2c_runtime_suspend, |
499 | hix5hd2_i2c_runtime_resume, |
500 | NULL) |
501 | }; |
502 | |
503 | static const struct of_device_id hix5hd2_i2c_match[] = { |
504 | { .compatible = "hisilicon,hix5hd2-i2c" }, |
505 | {}, |
506 | }; |
507 | MODULE_DEVICE_TABLE(of, hix5hd2_i2c_match); |
508 | |
509 | static struct platform_driver hix5hd2_i2c_driver = { |
510 | .probe = hix5hd2_i2c_probe, |
511 | .remove_new = hix5hd2_i2c_remove, |
512 | .driver = { |
513 | .name = "hix5hd2-i2c" , |
514 | .pm = pm_ptr(&hix5hd2_i2c_pm_ops), |
515 | .of_match_table = hix5hd2_i2c_match, |
516 | }, |
517 | }; |
518 | |
519 | module_platform_driver(hix5hd2_i2c_driver); |
520 | |
521 | MODULE_DESCRIPTION("Hix5hd2 I2C Bus driver" ); |
522 | MODULE_AUTHOR("Wei Yan <sledge.yanwei@huawei.com>" ); |
523 | MODULE_LICENSE("GPL" ); |
524 | MODULE_ALIAS("platform:hix5hd2-i2c" ); |
525 | |