1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2024-2025 Troy Mitchell <troymitchell988@gmail.com>
4 */
5
6 #include <linux/clk.h>
7 #include <linux/i2c.h>
8 #include <linux/iopoll.h>
9 #include <linux/module.h>
10 #include <linux/of_address.h>
11 #include <linux/platform_device.h>
12
13/* spacemit i2c registers */
14#define SPACEMIT_ICR 0x0 /* Control register */
15#define SPACEMIT_ISR 0x4 /* Status register */
16#define SPACEMIT_IDBR 0xc /* Data buffer register */
17#define SPACEMIT_IBMR 0x1c /* Bus monitor register */
18
19/* SPACEMIT_ICR register fields */
20#define SPACEMIT_CR_START BIT(0) /* start bit */
21#define SPACEMIT_CR_STOP BIT(1) /* stop bit */
22#define SPACEMIT_CR_ACKNAK BIT(2) /* send ACK(0) or NAK(1) */
23#define SPACEMIT_CR_TB BIT(3) /* transfer byte bit */
24/* Bits 4-7 are reserved */
25#define SPACEMIT_CR_MODE_FAST BIT(8) /* bus mode (master operation) */
26/* Bit 9 is reserved */
27#define SPACEMIT_CR_UR BIT(10) /* unit reset */
28/* Bits 11-12 are reserved */
29#define SPACEMIT_CR_SCLE BIT(13) /* master clock enable */
30#define SPACEMIT_CR_IUE BIT(14) /* unit enable */
31/* Bits 15-17 are reserved */
32#define SPACEMIT_CR_ALDIE BIT(18) /* enable arbitration interrupt */
33#define SPACEMIT_CR_DTEIE BIT(19) /* enable TX interrupts */
34#define SPACEMIT_CR_DRFIE BIT(20) /* enable RX interrupts */
35#define SPACEMIT_CR_GCD BIT(21) /* general call disable */
36#define SPACEMIT_CR_BEIE BIT(22) /* enable bus error ints */
37/* Bits 23-24 are reserved */
38#define SPACEMIT_CR_MSDIE BIT(25) /* master STOP detected int enable */
39#define SPACEMIT_CR_MSDE BIT(26) /* master STOP detected enable */
40#define SPACEMIT_CR_TXDONEIE BIT(27) /* transaction done int enable */
41#define SPACEMIT_CR_TXEIE BIT(28) /* transmit FIFO empty int enable */
42#define SPACEMIT_CR_RXHFIE BIT(29) /* receive FIFO half-full int enable */
43#define SPACEMIT_CR_RXFIE BIT(30) /* receive FIFO full int enable */
44#define SPACEMIT_CR_RXOVIE BIT(31) /* receive FIFO overrun int enable */
45
46#define SPACEMIT_I2C_INT_CTRL_MASK (SPACEMIT_CR_ALDIE | SPACEMIT_CR_DTEIE | \
47 SPACEMIT_CR_DRFIE | SPACEMIT_CR_BEIE | \
48 SPACEMIT_CR_TXDONEIE | SPACEMIT_CR_TXEIE | \
49 SPACEMIT_CR_RXHFIE | SPACEMIT_CR_RXFIE | \
50 SPACEMIT_CR_RXOVIE | SPACEMIT_CR_MSDIE)
51
52/* SPACEMIT_ISR register fields */
53/* Bits 0-13 are reserved */
54#define SPACEMIT_SR_ACKNAK BIT(14) /* ACK/NACK status */
55#define SPACEMIT_SR_UB BIT(15) /* unit busy */
56#define SPACEMIT_SR_IBB BIT(16) /* i2c bus busy */
57#define SPACEMIT_SR_EBB BIT(17) /* early bus busy */
58#define SPACEMIT_SR_ALD BIT(18) /* arbitration loss detected */
59#define SPACEMIT_SR_ITE BIT(19) /* TX buffer empty */
60#define SPACEMIT_SR_IRF BIT(20) /* RX buffer full */
61#define SPACEMIT_SR_GCAD BIT(21) /* general call address detected */
62#define SPACEMIT_SR_BED BIT(22) /* bus error no ACK/NAK */
63#define SPACEMIT_SR_SAD BIT(23) /* slave address detected */
64#define SPACEMIT_SR_SSD BIT(24) /* slave stop detected */
65/* Bit 25 is reserved */
66#define SPACEMIT_SR_MSD BIT(26) /* master stop detected */
67#define SPACEMIT_SR_TXDONE BIT(27) /* transaction done */
68#define SPACEMIT_SR_TXE BIT(28) /* TX FIFO empty */
69#define SPACEMIT_SR_RXHF BIT(29) /* RX FIFO half-full */
70#define SPACEMIT_SR_RXF BIT(30) /* RX FIFO full */
71#define SPACEMIT_SR_RXOV BIT(31) /* RX FIFO overrun */
72
73#define SPACEMIT_I2C_INT_STATUS_MASK (SPACEMIT_SR_RXOV | SPACEMIT_SR_RXF | SPACEMIT_SR_RXHF | \
74 SPACEMIT_SR_TXE | SPACEMIT_SR_TXDONE | SPACEMIT_SR_MSD | \
75 SPACEMIT_SR_SSD | SPACEMIT_SR_SAD | SPACEMIT_SR_BED | \
76 SPACEMIT_SR_GCAD | SPACEMIT_SR_IRF | SPACEMIT_SR_ITE | \
77 SPACEMIT_SR_ALD)
78
79/* SPACEMIT_IBMR register fields */
80#define SPACEMIT_BMR_SDA BIT(0) /* SDA line level */
81#define SPACEMIT_BMR_SCL BIT(1) /* SCL line level */
82
83/* i2c bus recover timeout: us */
84#define SPACEMIT_I2C_BUS_BUSY_TIMEOUT 100000
85
86#define SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ 100000 /* Hz */
87#define SPACEMIT_I2C_MAX_FAST_MODE_FREQ 400000 /* Hz */
88
89#define SPACEMIT_SR_ERR (SPACEMIT_SR_BED | SPACEMIT_SR_RXOV | SPACEMIT_SR_ALD)
90
91enum spacemit_i2c_state {
92 SPACEMIT_STATE_IDLE,
93 SPACEMIT_STATE_START,
94 SPACEMIT_STATE_READ,
95 SPACEMIT_STATE_WRITE,
96};
97
98/* i2c-spacemit driver's main struct */
99struct spacemit_i2c_dev {
100 struct device *dev;
101 struct i2c_adapter adapt;
102
103 /* hardware resources */
104 void __iomem *base;
105 int irq;
106 u32 clock_freq;
107
108 struct i2c_msg *msgs;
109 u32 msg_num;
110
111 /* index of the current message being processed */
112 u32 msg_idx;
113 u8 *msg_buf;
114 /* the number of unprocessed bytes remaining in the current message */
115 u32 unprocessed;
116
117 enum spacemit_i2c_state state;
118 bool read;
119 struct completion complete;
120 u32 status;
121};
122
123static void spacemit_i2c_enable(struct spacemit_i2c_dev *i2c)
124{
125 u32 val;
126
127 val = readl(addr: i2c->base + SPACEMIT_ICR);
128 val |= SPACEMIT_CR_IUE;
129 writel(val, addr: i2c->base + SPACEMIT_ICR);
130}
131
132static void spacemit_i2c_disable(struct spacemit_i2c_dev *i2c)
133{
134 u32 val;
135
136 val = readl(addr: i2c->base + SPACEMIT_ICR);
137 val &= ~SPACEMIT_CR_IUE;
138 writel(val, addr: i2c->base + SPACEMIT_ICR);
139}
140
141static void spacemit_i2c_reset(struct spacemit_i2c_dev *i2c)
142{
143 writel(SPACEMIT_CR_UR, addr: i2c->base + SPACEMIT_ICR);
144 udelay(usec: 5);
145 writel(val: 0, addr: i2c->base + SPACEMIT_ICR);
146}
147
148static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c)
149{
150 dev_dbg(i2c->dev, "i2c error status: 0x%08x\n", i2c->status);
151
152 if (i2c->status & (SPACEMIT_SR_BED | SPACEMIT_SR_ALD)) {
153 spacemit_i2c_reset(i2c);
154 return -EAGAIN;
155 }
156
157 return i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO;
158}
159
160static void spacemit_i2c_conditionally_reset_bus(struct spacemit_i2c_dev *i2c)
161{
162 u32 status;
163
164 /* if bus is locked, reset unit. 0: locked */
165 status = readl(addr: i2c->base + SPACEMIT_IBMR);
166 if ((status & SPACEMIT_BMR_SDA) && (status & SPACEMIT_BMR_SCL))
167 return;
168
169 spacemit_i2c_reset(i2c);
170 usleep_range(min: 10, max: 20);
171
172 /* check scl status again */
173 status = readl(addr: i2c->base + SPACEMIT_IBMR);
174 if (!(status & SPACEMIT_BMR_SCL))
175 dev_warn_ratelimited(i2c->dev, "unit reset failed\n");
176}
177
178static int spacemit_i2c_wait_bus_idle(struct spacemit_i2c_dev *i2c)
179{
180 int ret;
181 u32 val;
182
183 val = readl(addr: i2c->base + SPACEMIT_ISR);
184 if (!(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)))
185 return 0;
186
187 ret = readl_poll_timeout(i2c->base + SPACEMIT_ISR,
188 val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),
189 1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT);
190 if (ret)
191 spacemit_i2c_reset(i2c);
192
193 return ret;
194}
195
196static void spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c)
197{
198 /* in case bus is not released after transfer completes */
199 if (readl(addr: i2c->base + SPACEMIT_ISR) & SPACEMIT_SR_EBB) {
200 spacemit_i2c_conditionally_reset_bus(i2c);
201 usleep_range(min: 90, max: 150);
202 }
203}
204
205static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
206{
207 u32 val;
208
209 /*
210 * Unmask interrupt bits for all xfer mode:
211 * bus error, arbitration loss detected.
212 * For transaction complete signal, we use master stop
213 * interrupt, so we don't need to unmask SPACEMIT_CR_TXDONEIE.
214 */
215 val = SPACEMIT_CR_BEIE | SPACEMIT_CR_ALDIE;
216
217 /*
218 * Unmask interrupt bits for interrupt xfer mode:
219 * When IDBR receives a byte, an interrupt is triggered.
220 *
221 * For the tx empty interrupt, it will be enabled in the
222 * i2c_start function.
223 * Otherwise, it will cause an erroneous empty interrupt before i2c_start.
224 */
225 val |= SPACEMIT_CR_DRFIE;
226
227 if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)
228 val |= SPACEMIT_CR_MODE_FAST;
229
230 /* disable response to general call */
231 val |= SPACEMIT_CR_GCD;
232
233 /* enable SCL clock output */
234 val |= SPACEMIT_CR_SCLE;
235
236 /* enable master stop detected */
237 val |= SPACEMIT_CR_MSDE | SPACEMIT_CR_MSDIE;
238
239 writel(val, addr: i2c->base + SPACEMIT_ICR);
240}
241
242static inline void
243spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask)
244{
245 writel(val: mask & SPACEMIT_I2C_INT_STATUS_MASK, addr: i2c->base + SPACEMIT_ISR);
246}
247
248static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
249{
250 u32 target_addr_rw, val;
251 struct i2c_msg *cur_msg = i2c->msgs + i2c->msg_idx;
252
253 i2c->read = !!(cur_msg->flags & I2C_M_RD);
254
255 i2c->state = SPACEMIT_STATE_START;
256
257 target_addr_rw = (cur_msg->addr & 0x7f) << 1;
258 if (cur_msg->flags & I2C_M_RD)
259 target_addr_rw |= 1;
260
261 writel(val: target_addr_rw, addr: i2c->base + SPACEMIT_IDBR);
262
263 /* send start pulse */
264 val = readl(addr: i2c->base + SPACEMIT_ICR);
265 val &= ~SPACEMIT_CR_STOP;
266 val |= SPACEMIT_CR_START | SPACEMIT_CR_TB | SPACEMIT_CR_DTEIE;
267 writel(val, addr: i2c->base + SPACEMIT_ICR);
268}
269
270static void spacemit_i2c_stop(struct spacemit_i2c_dev *i2c)
271{
272 u32 val;
273
274 val = readl(addr: i2c->base + SPACEMIT_ICR);
275 val |= SPACEMIT_CR_STOP | SPACEMIT_CR_ALDIE | SPACEMIT_CR_TB;
276
277 if (i2c->read)
278 val |= SPACEMIT_CR_ACKNAK;
279
280 writel(val, addr: i2c->base + SPACEMIT_ICR);
281}
282
283static int spacemit_i2c_xfer_msg(struct spacemit_i2c_dev *i2c)
284{
285 unsigned long time_left;
286 struct i2c_msg *msg;
287
288 for (i2c->msg_idx = 0; i2c->msg_idx < i2c->msg_num; i2c->msg_idx++) {
289 msg = &i2c->msgs[i2c->msg_idx];
290 i2c->msg_buf = msg->buf;
291 i2c->unprocessed = msg->len;
292 i2c->status = 0;
293
294 reinit_completion(x: &i2c->complete);
295
296 spacemit_i2c_start(i2c);
297
298 time_left = wait_for_completion_timeout(x: &i2c->complete,
299 timeout: i2c->adapt.timeout);
300 if (!time_left) {
301 dev_err(i2c->dev, "msg completion timeout\n");
302 spacemit_i2c_conditionally_reset_bus(i2c);
303 spacemit_i2c_reset(i2c);
304 return -ETIMEDOUT;
305 }
306
307 if (i2c->status & SPACEMIT_SR_ERR)
308 return spacemit_i2c_handle_err(i2c);
309 }
310
311 return 0;
312}
313
314static bool spacemit_i2c_is_last_msg(struct spacemit_i2c_dev *i2c)
315{
316 if (i2c->msg_idx != i2c->msg_num - 1)
317 return false;
318
319 if (i2c->read)
320 return i2c->unprocessed == 1;
321
322 return !i2c->unprocessed;
323}
324
325static void spacemit_i2c_handle_write(struct spacemit_i2c_dev *i2c)
326{
327 /* if transfer completes, SPACEMIT_ISR will handle it */
328 if (i2c->status & SPACEMIT_SR_MSD)
329 return;
330
331 if (i2c->unprocessed) {
332 writel(val: *i2c->msg_buf++, addr: i2c->base + SPACEMIT_IDBR);
333 i2c->unprocessed--;
334 return;
335 }
336
337 /* SPACEMIT_STATE_IDLE avoids trigger next byte */
338 i2c->state = SPACEMIT_STATE_IDLE;
339 complete(&i2c->complete);
340}
341
342static void spacemit_i2c_handle_read(struct spacemit_i2c_dev *i2c)
343{
344 if (i2c->unprocessed) {
345 *i2c->msg_buf++ = readl(addr: i2c->base + SPACEMIT_IDBR);
346 i2c->unprocessed--;
347 }
348
349 /* if transfer completes, SPACEMIT_ISR will handle it */
350 if (i2c->status & (SPACEMIT_SR_MSD | SPACEMIT_SR_ACKNAK))
351 return;
352
353 /* it has to append stop bit in icr that read last byte */
354 if (i2c->unprocessed)
355 return;
356
357 /* SPACEMIT_STATE_IDLE avoids trigger next byte */
358 i2c->state = SPACEMIT_STATE_IDLE;
359 complete(&i2c->complete);
360}
361
362static void spacemit_i2c_handle_start(struct spacemit_i2c_dev *i2c)
363{
364 i2c->state = i2c->read ? SPACEMIT_STATE_READ : SPACEMIT_STATE_WRITE;
365 if (i2c->state == SPACEMIT_STATE_WRITE)
366 spacemit_i2c_handle_write(i2c);
367}
368
369static void spacemit_i2c_err_check(struct spacemit_i2c_dev *i2c)
370{
371 u32 val;
372
373 /*
374 * Send transaction complete signal:
375 * error happens, detect master stop
376 */
377 if (!(i2c->status & (SPACEMIT_SR_ERR | SPACEMIT_SR_MSD)))
378 return;
379
380 /*
381 * Here the transaction is already done, we don't need any
382 * other interrupt signals from now, in case any interrupt
383 * happens before spacemit_i2c_xfer to disable irq and i2c unit,
384 * we mask all the interrupt signals and clear the interrupt
385 * status.
386 */
387 val = readl(addr: i2c->base + SPACEMIT_ICR);
388 val &= ~SPACEMIT_I2C_INT_CTRL_MASK;
389 writel(val, addr: i2c->base + SPACEMIT_ICR);
390
391 spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK);
392
393 i2c->state = SPACEMIT_STATE_IDLE;
394 complete(&i2c->complete);
395}
396
397static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
398{
399 struct spacemit_i2c_dev *i2c = devid;
400 u32 status, val;
401
402 status = readl(addr: i2c->base + SPACEMIT_ISR);
403 if (!status)
404 return IRQ_HANDLED;
405
406 i2c->status = status;
407
408 spacemit_i2c_clear_int_status(i2c, mask: status);
409
410 if (i2c->status & SPACEMIT_SR_ERR)
411 goto err_out;
412
413 val = readl(addr: i2c->base + SPACEMIT_ICR);
414 val &= ~(SPACEMIT_CR_TB | SPACEMIT_CR_ACKNAK | SPACEMIT_CR_STOP | SPACEMIT_CR_START);
415 writel(val, addr: i2c->base + SPACEMIT_ICR);
416
417 switch (i2c->state) {
418 case SPACEMIT_STATE_START:
419 spacemit_i2c_handle_start(i2c);
420 break;
421 case SPACEMIT_STATE_READ:
422 spacemit_i2c_handle_read(i2c);
423 break;
424 case SPACEMIT_STATE_WRITE:
425 spacemit_i2c_handle_write(i2c);
426 break;
427 default:
428 break;
429 }
430
431 if (i2c->state != SPACEMIT_STATE_IDLE) {
432 if (spacemit_i2c_is_last_msg(i2c)) {
433 /* trigger next byte with stop */
434 spacemit_i2c_stop(i2c);
435 } else {
436 /* trigger next byte */
437 val |= SPACEMIT_CR_ALDIE | SPACEMIT_CR_TB;
438 writel(val, addr: i2c->base + SPACEMIT_ICR);
439 }
440 }
441
442err_out:
443 spacemit_i2c_err_check(i2c);
444 return IRQ_HANDLED;
445}
446
447static void spacemit_i2c_calc_timeout(struct spacemit_i2c_dev *i2c)
448{
449 unsigned long timeout;
450 int idx = 0, cnt = 0;
451
452 for (; idx < i2c->msg_num; idx++)
453 cnt += (i2c->msgs + idx)->len + 1;
454
455 /*
456 * Multiply by 9 because each byte in I2C transmission requires
457 * 9 clock cycles: 8 bits of data plus 1 ACK/NACK bit.
458 */
459 timeout = cnt * 9 * USEC_PER_SEC / i2c->clock_freq;
460
461 i2c->adapt.timeout = usecs_to_jiffies(u: timeout + USEC_PER_SEC / 10) / i2c->msg_num;
462}
463
464static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num)
465{
466 struct spacemit_i2c_dev *i2c = i2c_get_adapdata(adap: adapt);
467 int ret;
468
469 i2c->msgs = msgs;
470 i2c->msg_num = num;
471
472 spacemit_i2c_calc_timeout(i2c);
473
474 spacemit_i2c_init(i2c);
475
476 spacemit_i2c_enable(i2c);
477
478 ret = spacemit_i2c_wait_bus_idle(i2c);
479 if (!ret)
480 spacemit_i2c_xfer_msg(i2c);
481 else if (ret < 0)
482 dev_dbg(i2c->dev, "i2c transfer error: %d\n", ret);
483 else
484 spacemit_i2c_check_bus_release(i2c);
485
486 spacemit_i2c_disable(i2c);
487
488 if (ret == -ETIMEDOUT || ret == -EAGAIN)
489 dev_err(i2c->dev, "i2c transfer failed, ret %d err 0x%lx\n",
490 ret, i2c->status & SPACEMIT_SR_ERR);
491
492 return ret < 0 ? ret : num;
493}
494
495static u32 spacemit_i2c_func(struct i2c_adapter *adap)
496{
497 return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
498}
499
500static const struct i2c_algorithm spacemit_i2c_algo = {
501 .xfer = spacemit_i2c_xfer,
502 .functionality = spacemit_i2c_func,
503};
504
505static int spacemit_i2c_probe(struct platform_device *pdev)
506{
507 struct clk *clk;
508 struct device *dev = &pdev->dev;
509 struct device_node *of_node = pdev->dev.of_node;
510 struct spacemit_i2c_dev *i2c;
511 int ret;
512
513 i2c = devm_kzalloc(dev, size: sizeof(*i2c), GFP_KERNEL);
514 if (!i2c)
515 return -ENOMEM;
516
517 ret = of_property_read_u32(np: of_node, propname: "clock-frequency", out_value: &i2c->clock_freq);
518 if (ret && ret != -EINVAL)
519 dev_warn(dev, "failed to read clock-frequency property: %d\n", ret);
520
521 /* For now, this driver doesn't support high-speed. */
522 if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) {
523 dev_warn(dev, "unsupported clock frequency %u; using %u\n",
524 i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ);
525 i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ;
526 } else if (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) {
527 dev_warn(dev, "unsupported clock frequency %u; using %u\n",
528 i2c->clock_freq, SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ);
529 i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ;
530 }
531
532 i2c->dev = &pdev->dev;
533
534 i2c->base = devm_platform_ioremap_resource(pdev, index: 0);
535 if (IS_ERR(ptr: i2c->base))
536 return dev_err_probe(dev, err: PTR_ERR(ptr: i2c->base), fmt: "failed to do ioremap");
537
538 i2c->irq = platform_get_irq(pdev, 0);
539 if (i2c->irq < 0)
540 return dev_err_probe(dev, err: i2c->irq, fmt: "failed to get irq resource");
541
542 ret = devm_request_irq(dev: i2c->dev, irq: i2c->irq, handler: spacemit_i2c_irq_handler,
543 IRQF_NO_SUSPEND | IRQF_ONESHOT, devname: dev_name(dev: i2c->dev), dev_id: i2c);
544 if (ret)
545 return dev_err_probe(dev, err: ret, fmt: "failed to request irq");
546
547 clk = devm_clk_get_enabled(dev, id: "func");
548 if (IS_ERR(ptr: clk))
549 return dev_err_probe(dev, err: PTR_ERR(ptr: clk), fmt: "failed to enable func clock");
550
551 clk = devm_clk_get_enabled(dev, id: "bus");
552 if (IS_ERR(ptr: clk))
553 return dev_err_probe(dev, err: PTR_ERR(ptr: clk), fmt: "failed to enable bus clock");
554
555 spacemit_i2c_reset(i2c);
556
557 i2c_set_adapdata(adap: &i2c->adapt, data: i2c);
558 i2c->adapt.owner = THIS_MODULE;
559 i2c->adapt.algo = &spacemit_i2c_algo;
560 i2c->adapt.dev.parent = i2c->dev;
561 i2c->adapt.nr = pdev->id;
562
563 i2c->adapt.dev.of_node = of_node;
564
565 strscpy(i2c->adapt.name, "spacemit-i2c-adapter", sizeof(i2c->adapt.name));
566
567 init_completion(x: &i2c->complete);
568
569 platform_set_drvdata(pdev, data: i2c);
570
571 ret = i2c_add_numbered_adapter(adap: &i2c->adapt);
572 if (ret)
573 return dev_err_probe(dev: &pdev->dev, err: ret, fmt: "failed to add i2c adapter");
574
575 return 0;
576}
577
578static void spacemit_i2c_remove(struct platform_device *pdev)
579{
580 struct spacemit_i2c_dev *i2c = platform_get_drvdata(pdev);
581
582 i2c_del_adapter(adap: &i2c->adapt);
583}
584
585static const struct of_device_id spacemit_i2c_of_match[] = {
586 { .compatible = "spacemit,k1-i2c", },
587 { /* sentinel */ }
588};
589MODULE_DEVICE_TABLE(of, spacemit_i2c_of_match);
590
591static struct platform_driver spacemit_i2c_driver = {
592 .probe = spacemit_i2c_probe,
593 .remove = spacemit_i2c_remove,
594 .driver = {
595 .name = "i2c-k1",
596 .of_match_table = spacemit_i2c_of_match,
597 },
598};
599module_platform_driver(spacemit_i2c_driver);
600
601MODULE_LICENSE("GPL");
602MODULE_DESCRIPTION("I2C bus driver for SpacemiT K1 SoC");
603

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of linux/drivers/i2c/busses/i2c-k1.c