-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathi2c-cadence.c
1496 lines (1285 loc) · 41.4 KB
/
i2c-cadence.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* I2C bus driver for the Cadence I2C controller.
*
* Copyright (C) 2009 - 2014 Xilinx, Inc.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
/* Register offsets for the I2C device. */
#define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */
#define CDNS_I2C_SR_OFFSET 0x04 /* Status Register, RO */
#define CDNS_I2C_ADDR_OFFSET 0x08 /* I2C Address Register, RW */
#define CDNS_I2C_DATA_OFFSET 0x0C /* I2C Data Register, RW */
#define CDNS_I2C_ISR_OFFSET 0x10 /* IRQ Status Register, RW */
#define CDNS_I2C_XFER_SIZE_OFFSET 0x14 /* Transfer Size Register, RW */
#define CDNS_I2C_TIME_OUT_OFFSET 0x1C /* Time Out Register, RW */
#define CDNS_I2C_IMR_OFFSET 0x20 /* IRQ Mask Register, RO */
#define CDNS_I2C_IER_OFFSET 0x24 /* IRQ Enable Register, WO */
#define CDNS_I2C_IDR_OFFSET 0x28 /* IRQ Disable Register, WO */
/* Control Register Bit mask definitions */
#define CDNS_I2C_CR_HOLD BIT(4) /* Hold Bus bit */
#define CDNS_I2C_CR_ACK_EN BIT(3)
#define CDNS_I2C_CR_NEA BIT(2)
#define CDNS_I2C_CR_MS BIT(1)
/* Read or Write Master transfer 0 = Transmitter, 1 = Receiver */
#define CDNS_I2C_CR_RW BIT(0)
/* 1 = Auto init FIFO to zeroes */
#define CDNS_I2C_CR_CLR_FIFO BIT(6)
#define CDNS_I2C_CR_DIVA_SHIFT 14
#define CDNS_I2C_CR_DIVA_MASK (3 << CDNS_I2C_CR_DIVA_SHIFT)
#define CDNS_I2C_CR_DIVB_SHIFT 8
#define CDNS_I2C_CR_DIVB_MASK (0x3f << CDNS_I2C_CR_DIVB_SHIFT)
#define CDNS_I2C_CR_MASTER_EN_MASK \
(CDNS_I2C_CR_NEA | CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_MS)
#define CDNS_I2C_CR_SLAVE_EN_MASK ~CDNS_I2C_CR_MASTER_EN_MASK
/* Status Register Bit mask definitions */
#define CDNS_I2C_SR_BA BIT(8)
#define CDNS_I2C_SR_TXDV BIT(6)
#define CDNS_I2C_SR_RXDV BIT(5)
#define CDNS_I2C_SR_RXRW BIT(3)
/*
* I2C Address Register Bit mask definitions
* Normal addressing mode uses [6:0] bits. Extended addressing mode uses [9:0]
* bits. A write access to this register always initiates a transfer if the I2C
* is in master mode.
*/
#define CDNS_I2C_ADDR_MASK 0x000003FF /* I2C Address Mask */
/*
* I2C Interrupt Registers Bit mask definitions
* All the four interrupt registers (Status/Mask/Enable/Disable) have the same
* bit definitions.
*/
#define CDNS_I2C_IXR_ARB_LOST BIT(9)
#define CDNS_I2C_IXR_RX_UNF BIT(7)
#define CDNS_I2C_IXR_TX_OVF BIT(6)
#define CDNS_I2C_IXR_RX_OVF BIT(5)
#define CDNS_I2C_IXR_SLV_RDY BIT(4)
#define CDNS_I2C_IXR_TO BIT(3)
#define CDNS_I2C_IXR_NACK BIT(2)
#define CDNS_I2C_IXR_DATA BIT(1)
#define CDNS_I2C_IXR_COMP BIT(0)
#define CDNS_I2C_IXR_ALL_INTR_MASK \
(CDNS_I2C_IXR_ARB_LOST | CDNS_I2C_IXR_RX_UNF | CDNS_I2C_IXR_TX_OVF | \
CDNS_I2C_IXR_RX_OVF | CDNS_I2C_IXR_SLV_RDY | CDNS_I2C_IXR_TO | \
CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_DATA | CDNS_I2C_IXR_COMP)
#define CDNS_I2C_IXR_ERR_INTR_MASK \
(CDNS_I2C_IXR_ARB_LOST | CDNS_I2C_IXR_RX_UNF | CDNS_I2C_IXR_TX_OVF | \
CDNS_I2C_IXR_RX_OVF | CDNS_I2C_IXR_NACK)
#define CDNS_I2C_ENABLED_INTR_MASK \
(CDNS_I2C_IXR_ARB_LOST | CDNS_I2C_IXR_RX_UNF | CDNS_I2C_IXR_TX_OVF | \
CDNS_I2C_IXR_RX_OVF | CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_DATA | \
CDNS_I2C_IXR_COMP)
#define CDNS_I2C_IXR_SLAVE_INTR_MASK \
(CDNS_I2C_IXR_RX_UNF | CDNS_I2C_IXR_TX_OVF | CDNS_I2C_IXR_RX_OVF | \
CDNS_I2C_IXR_TO | CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_DATA | \
CDNS_I2C_IXR_COMP)
#define CDNS_I2C_TIMEOUT msecs_to_jiffies(1000)
/* timeout for pm runtime autosuspend */
#define CNDS_I2C_PM_TIMEOUT 1000 /* ms */
#define CDNS_I2C_FIFO_DEPTH 16
/* FIFO depth at which the DATA interrupt occurs */
#define CDNS_I2C_DATA_INTR_DEPTH (CDNS_I2C_FIFO_DEPTH - 2)
#define CDNS_I2C_MAX_TRANSFER_SIZE 255
/* Transfer size in multiples of data interrupt depth */
#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
#define DRIVER_NAME "cdns-i2c"
#define CDNS_I2C_DIVA_MAX 4
#define CDNS_I2C_DIVB_MAX 64
#define CDNS_I2C_TIMEOUT_MAX 0xFF
#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0)
#define CDNS_I2C_POLL_US 100000
#define CDNS_I2C_TIMEOUT_US 500000
#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset)
#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
#if IS_ENABLED(CONFIG_I2C_SLAVE)
/**
* enum cdns_i2c_mode - I2C Controller current operating mode
*
* @CDNS_I2C_MODE_SLAVE: I2C controller operating in slave mode
* @CDNS_I2C_MODE_MASTER: I2C Controller operating in master mode
*/
enum cdns_i2c_mode {
CDNS_I2C_MODE_SLAVE,
CDNS_I2C_MODE_MASTER,
};
/**
* enum cdns_i2c_slave_state - Slave state when I2C is operating in slave mode
*
* @CDNS_I2C_SLAVE_STATE_IDLE: I2C slave idle
* @CDNS_I2C_SLAVE_STATE_SEND: I2C slave sending data to master
* @CDNS_I2C_SLAVE_STATE_RECV: I2C slave receiving data from master
*/
enum cdns_i2c_slave_state {
CDNS_I2C_SLAVE_STATE_IDLE,
CDNS_I2C_SLAVE_STATE_SEND,
CDNS_I2C_SLAVE_STATE_RECV,
};
#endif
/**
* struct cdns_i2c - I2C device private data structure
*
* @dev: Pointer to device structure
* @membase: Base address of the I2C device
* @adap: I2C adapter instance
* @p_msg: Message pointer
* @err_status: Error status in Interrupt Status Register
* @xfer_done: Transfer complete status
* @p_send_buf: Pointer to transmit buffer
* @p_recv_buf: Pointer to receive buffer
* @send_count: Number of bytes still expected to send
* @recv_count: Number of bytes still expected to receive
* @curr_recv_count: Number of bytes to be received in current transfer
* @irq: IRQ number
* @input_clk: Input clock to I2C controller
* @i2c_clk: Maximum I2C clock speed
* @bus_hold_flag: Flag used in repeated start for clearing HOLD bit
* @clk: Pointer to struct clk
* @clk_rate_change_nb: Notifier block for clock rate changes
* @quirks: flag for broken hold bit usage in r1p10
* @ctrl_reg: Cached value of the control register.
* @ctrl_reg_diva_divb: value of fields DIV_A and DIV_B from CR register
* @slave: Registered slave instance.
* @dev_mode: I2C operating role(master/slave).
* @slave_state: I2C Slave state(idle/read/write).
*/
struct cdns_i2c {
struct device *dev;
void __iomem *membase;
struct i2c_adapter adap;
struct i2c_msg *p_msg;
int err_status;
struct completion xfer_done;
unsigned char *p_send_buf;
unsigned char *p_recv_buf;
unsigned int send_count;
unsigned int recv_count;
unsigned int curr_recv_count;
int irq;
unsigned long input_clk;
unsigned int i2c_clk;
unsigned int bus_hold_flag;
struct clk *clk;
struct notifier_block clk_rate_change_nb;
u32 quirks;
u32 ctrl_reg;
struct i2c_bus_recovery_info rinfo;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
u16 ctrl_reg_diva_divb;
struct i2c_client *slave;
enum cdns_i2c_mode dev_mode;
enum cdns_i2c_slave_state slave_state;
#endif
};
struct cdns_platform_data {
u32 quirks;
};
#define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, clk_rate_change_nb)
/**
* cdns_i2c_clear_bus_hold - Clear bus hold bit
* @id: Pointer to driver data struct
*
* Helper to clear the controller's bus hold bit.
*/
static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
{
u32 reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
if (reg & CDNS_I2C_CR_HOLD)
cdns_i2c_writereg(reg & ~CDNS_I2C_CR_HOLD, CDNS_I2C_CR_OFFSET);
}
static inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround)
{
return (hold_wrkaround &&
(id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1));
}
#if IS_ENABLED(CONFIG_I2C_SLAVE)
static void cdns_i2c_set_mode(enum cdns_i2c_mode mode, struct cdns_i2c *id)
{
/* Disable all interrupts */
cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
/* Clear FIFO and transfer size */
cdns_i2c_writereg(CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET);
/* Update device mode and state */
id->dev_mode = mode;
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
switch (mode) {
case CDNS_I2C_MODE_MASTER:
/* Enable i2c master */
cdns_i2c_writereg(id->ctrl_reg_diva_divb |
CDNS_I2C_CR_MASTER_EN_MASK,
CDNS_I2C_CR_OFFSET);
/*
* This delay is needed to give the IP some time to switch to
* the master mode. With lower values(like 110 us) i2cdetect
* will not detect any slave and without this delay, the IP will
* trigger a timeout interrupt.
*/
usleep_range(115, 125);
break;
case CDNS_I2C_MODE_SLAVE:
/* Enable i2c slave */
cdns_i2c_writereg(id->ctrl_reg_diva_divb &
CDNS_I2C_CR_SLAVE_EN_MASK,
CDNS_I2C_CR_OFFSET);
/* Setting slave address */
cdns_i2c_writereg(id->slave->addr & CDNS_I2C_ADDR_MASK,
CDNS_I2C_ADDR_OFFSET);
/* Enable slave send/receive interrupts */
cdns_i2c_writereg(CDNS_I2C_IXR_SLAVE_INTR_MASK,
CDNS_I2C_IER_OFFSET);
break;
}
}
static void cdns_i2c_slave_rcv_data(struct cdns_i2c *id)
{
u8 bytes;
unsigned char data;
/* Prepare backend for data reception */
if (id->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) {
id->slave_state = CDNS_I2C_SLAVE_STATE_RECV;
i2c_slave_event(id->slave, I2C_SLAVE_WRITE_REQUESTED, NULL);
}
/* Fetch number of bytes to receive */
bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
/* Read data and send to backend */
while (bytes--) {
data = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
i2c_slave_event(id->slave, I2C_SLAVE_WRITE_RECEIVED, &data);
}
}
static void cdns_i2c_slave_send_data(struct cdns_i2c *id)
{
u8 data;
/* Prepare backend for data transmission */
if (id->slave_state == CDNS_I2C_SLAVE_STATE_IDLE) {
id->slave_state = CDNS_I2C_SLAVE_STATE_SEND;
i2c_slave_event(id->slave, I2C_SLAVE_READ_REQUESTED, &data);
} else {
i2c_slave_event(id->slave, I2C_SLAVE_READ_PROCESSED, &data);
}
/* Send data over bus */
cdns_i2c_writereg(data, CDNS_I2C_DATA_OFFSET);
}
/**
* cdns_i2c_slave_isr - Interrupt handler for the I2C device in slave role
* @ptr: Pointer to I2C device private data
*
* This function handles the data interrupt and transfer complete interrupt of
* the I2C device in slave role.
*
* Return: IRQ_HANDLED always
*/
static irqreturn_t cdns_i2c_slave_isr(void *ptr)
{
struct cdns_i2c *id = ptr;
unsigned int isr_status, i2c_status;
/* Fetch the interrupt status */
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
/* Ignore masked interrupts */
isr_status &= ~cdns_i2c_readreg(CDNS_I2C_IMR_OFFSET);
/* Fetch transfer mode (send/receive) */
i2c_status = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET);
/* Handle data send/receive */
if (i2c_status & CDNS_I2C_SR_RXRW) {
/* Send data to master */
if (isr_status & CDNS_I2C_IXR_DATA)
cdns_i2c_slave_send_data(id);
if (isr_status & CDNS_I2C_IXR_COMP) {
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL);
}
} else {
/* Receive data from master */
if (isr_status & CDNS_I2C_IXR_DATA)
cdns_i2c_slave_rcv_data(id);
if (isr_status & CDNS_I2C_IXR_COMP) {
cdns_i2c_slave_rcv_data(id);
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL);
}
}
/* Master indicated xfer stop or fifo underflow/overflow */
if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_RX_OVF |
CDNS_I2C_IXR_RX_UNF | CDNS_I2C_IXR_TX_OVF)) {
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
i2c_slave_event(id->slave, I2C_SLAVE_STOP, NULL);
cdns_i2c_writereg(CDNS_I2C_CR_CLR_FIFO, CDNS_I2C_CR_OFFSET);
}
return IRQ_HANDLED;
}
#endif
/*
* Check completion of I2C transaction either from interrupt or process context
*/
static int cdns_i2c_check_completion(struct cdns_i2c *id, irqreturn_t *status)
{
unsigned int isr_status, avail_bytes;
unsigned int bytes_to_send;
bool updatetx;
/* Signal completion only after everything is updated */
int done_flag = 0;
*status = IRQ_NONE;
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
id->err_status = 0;
/* Handling nack and arbitration lost interrupt */
if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
done_flag = 1;
*status = IRQ_HANDLED;
}
/*
* Check if transfer size register needs to be updated again for a
* large data receive operation.
*/
updatetx = id->recv_count > id->curr_recv_count;
/* When receiving, handle data interrupt and completion interrupt */
if (id->p_recv_buf && ((isr_status & CDNS_I2C_IXR_COMP) ||
(isr_status & CDNS_I2C_IXR_DATA))) {
/* Read data if receive data valid is set */
while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
CDNS_I2C_SR_RXDV) {
if (id->recv_count > 0) {
*(id->p_recv_buf)++ =
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
id->recv_count--;
id->curr_recv_count--;
/*
* Clear hold bit that was set for FIFO control
* if RX data left is less than or equal to
* FIFO DEPTH unless repeated start is selected
*/
if (id->recv_count <= CDNS_I2C_FIFO_DEPTH &&
!id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
} else {
dev_err(id->adap.dev.parent,
"xfer_size reg rollover. xfer aborted!\n");
id->err_status |= CDNS_I2C_IXR_TO;
break;
}
if (cdns_is_holdquirk(id, updatetx))
break;
}
/*
* The controller sends NACK to the slave when transfer size
* register reaches zero without considering the HOLD bit.
* This workaround is implemented for large data transfers to
* maintain transfer size non-zero while performing a large
* receive operation.
*/
if (cdns_is_holdquirk(id, updatetx)) {
/* wait while fifo is full */
while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
(id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
;
/*
* Check number of bytes to be received against maximum
* transfer size and update register accordingly.
*/
if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) >
CDNS_I2C_TRANSFER_SIZE) {
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
CDNS_I2C_XFER_SIZE_OFFSET);
id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
CDNS_I2C_FIFO_DEPTH;
} else {
cdns_i2c_writereg(id->recv_count -
CDNS_I2C_FIFO_DEPTH,
CDNS_I2C_XFER_SIZE_OFFSET);
id->curr_recv_count = id->recv_count;
}
}
/* Clear hold (if not repeated start) and signal completion */
if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) {
if (!id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
done_flag = 1;
}
*status = IRQ_HANDLED;
}
/* When sending, handle transfer complete interrupt */
if ((isr_status & CDNS_I2C_IXR_COMP) && !id->p_recv_buf) {
/*
* If there is more data to be sent, calculate the
* space available in FIFO and fill with that many bytes.
*/
if (id->send_count) {
avail_bytes =
CDNS_I2C_FIFO_DEPTH -
cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
if (id->send_count > avail_bytes)
bytes_to_send = avail_bytes;
else
bytes_to_send = id->send_count;
while (bytes_to_send--) {
cdns_i2c_writereg((*(id->p_send_buf)++),
CDNS_I2C_DATA_OFFSET);
id->send_count--;
}
} else {
/*
* Signal the completion of transaction and
* clear the hold bus bit if there are no
* further messages to be processed.
*/
done_flag = 1;
}
if (!id->send_count && !id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
*status = IRQ_HANDLED;
}
/* Update the status for errors */
id->err_status |= isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
if (id->err_status)
*status = IRQ_HANDLED;
return done_flag;
}
/**
* cdns_i2c_master_isr - Interrupt handler for the I2C device in master role
* @ptr: Pointer to I2C device private data
*
* This function handles the data interrupt, transfer complete interrupt and
* the error interrupts of the I2C device in master role.
*
* Return: IRQ_HANDLED always
*/
static irqreturn_t cdns_i2c_master_isr(void *ptr)
{
struct cdns_i2c *id = ptr;
irqreturn_t status;
int done_flag;
done_flag = cdns_i2c_check_completion(id, &status);
if (done_flag)
complete(&id->xfer_done);
return status;
}
/**
* cdns_i2c_isr - Interrupt handler for the I2C device
* @irq: irq number for the I2C device
* @ptr: void pointer to cdns_i2c structure
*
* This function passes the control to slave/master based on current role of
* i2c controller.
*
* Return: IRQ_HANDLED always
*/
static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
{
#if IS_ENABLED(CONFIG_I2C_SLAVE)
struct cdns_i2c *id = ptr;
if (id->dev_mode == CDNS_I2C_MODE_SLAVE)
return cdns_i2c_slave_isr(ptr);
#endif
return cdns_i2c_master_isr(ptr);
}
/**
* cdns_i2c_mrecv - Prepare and start a master receive operation
* @id: pointer to the i2c device structure
*/
static void cdns_i2c_mrecv(struct cdns_i2c *id, int atomic)
{
unsigned int ctrl_reg;
unsigned int isr_status;
unsigned long flags;
bool hold_clear = false;
bool irq_save = false;
u32 addr;
id->p_recv_buf = id->p_msg->buf;
id->recv_count = id->p_msg->len;
/* Put the controller in master receive mode and clear the FIFO */
ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO;
/*
* Receive up to I2C_SMBUS_BLOCK_MAX data bytes, plus one message length
* byte, plus one checksum byte if PEC is enabled. p_msg->len will be 2 if
* PEC is enabled, otherwise 1.
*/
if (id->p_msg->flags & I2C_M_RECV_LEN)
id->recv_count = I2C_SMBUS_BLOCK_MAX + id->p_msg->len;
id->curr_recv_count = id->recv_count;
/*
* Check for the message size against FIFO depth and set the
* 'hold bus' bit if it is greater than FIFO depth.
*/
if (id->recv_count > CDNS_I2C_FIFO_DEPTH)
ctrl_reg |= CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
/* Clear the interrupts in interrupt status register */
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
/*
* The no. of bytes to receive is checked against the limit of
* max transfer size. Set transfer size register with no of bytes
* receive if it is less than transfer size and transfer size if
* it is more. Enable the interrupts.
*/
if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
CDNS_I2C_XFER_SIZE_OFFSET);
id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
} else {
cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
}
/* Determine hold_clear based on number of bytes to receive and hold flag */
if (!id->bus_hold_flag &&
((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
(id->recv_count <= CDNS_I2C_FIFO_DEPTH)) {
if (cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & CDNS_I2C_CR_HOLD) {
hold_clear = true;
if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT)
irq_save = true;
}
}
addr = id->p_msg->addr;
addr &= CDNS_I2C_ADDR_MASK;
if (hold_clear) {
ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) &
~CDNS_I2C_CR_HOLD;
/*
* In case of Xilinx Zynq SOC, clear the HOLD bit before transfer size
* register reaches '0'. This is an IP bug which causes transfer size
* register overflow to 0xFF. To satisfy this timing requirement,
* disable the interrupts on current processor core between register
* writes to slave address register and control register.
*/
if (irq_save && !atomic)
local_irq_save(flags);
cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
/* Read it back to avoid bufferring and make sure write happens */
cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
if (irq_save && !atomic)
local_irq_restore(flags);
} else {
cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET);
}
cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
}
/**
* cdns_i2c_msend - Prepare and start a master send operation
* @id: pointer to the i2c device
*/
static void cdns_i2c_msend(struct cdns_i2c *id)
{
unsigned int avail_bytes;
unsigned int bytes_to_send;
unsigned int ctrl_reg;
unsigned int isr_status;
id->p_recv_buf = NULL;
id->p_send_buf = id->p_msg->buf;
id->send_count = id->p_msg->len;
/* Set the controller in Master transmit mode and clear the FIFO. */
ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
ctrl_reg &= ~CDNS_I2C_CR_RW;
ctrl_reg |= CDNS_I2C_CR_CLR_FIFO;
/*
* Check for the message size against FIFO depth and set the
* 'hold bus' bit if it is greater than FIFO depth.
*/
if (id->send_count > CDNS_I2C_FIFO_DEPTH)
ctrl_reg |= CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
/* Clear the interrupts in interrupt status register. */
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
/*
* Calculate the space available in FIFO. Check the message length
* against the space available, and fill the FIFO accordingly.
* Enable the interrupts.
*/
avail_bytes = CDNS_I2C_FIFO_DEPTH -
cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
if (id->send_count > avail_bytes)
bytes_to_send = avail_bytes;
else
bytes_to_send = id->send_count;
while (bytes_to_send--) {
cdns_i2c_writereg((*(id->p_send_buf)++), CDNS_I2C_DATA_OFFSET);
id->send_count--;
}
/*
* Clear the bus hold flag if there is no more data
* and if it is the last message.
*/
if (!id->bus_hold_flag && !id->send_count)
cdns_i2c_clear_bus_hold(id);
/* Set the slave address in address register - triggers operation. */
cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
CDNS_I2C_ADDR_OFFSET);
cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
}
/**
* cdns_i2c_master_reset - Reset the interface
* @adap: pointer to the i2c adapter driver instance
*
* This function cleanup the fifos, clear the hold bit and status
* and disable the interrupts.
*/
static void cdns_i2c_master_reset(struct i2c_adapter *adap)
{
struct cdns_i2c *id = adap->algo_data;
u32 regval;
/* Disable the interrupts */
cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
/* Clear the hold bit and fifos */
regval = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
regval &= ~CDNS_I2C_CR_HOLD;
regval |= CDNS_I2C_CR_CLR_FIFO;
cdns_i2c_writereg(regval, CDNS_I2C_CR_OFFSET);
/* Update the transfercount register to zero */
cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
/* Clear the interrupt status register */
regval = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
cdns_i2c_writereg(regval, CDNS_I2C_ISR_OFFSET);
/* Clear the status register */
regval = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET);
cdns_i2c_writereg(regval, CDNS_I2C_SR_OFFSET);
}
static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
struct i2c_adapter *adap, int atomic)
{
unsigned long time_left, msg_timeout;
u32 reg;
id->p_msg = msg;
id->err_status = 0;
reinit_completion(&id->xfer_done);
/* Check for the TEN Bit mode on each msg */
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
if (msg->flags & I2C_M_TEN) {
if (reg & CDNS_I2C_CR_NEA)
cdns_i2c_writereg(reg & ~CDNS_I2C_CR_NEA,
CDNS_I2C_CR_OFFSET);
} else {
if (!(reg & CDNS_I2C_CR_NEA))
cdns_i2c_writereg(reg | CDNS_I2C_CR_NEA,
CDNS_I2C_CR_OFFSET);
}
/* Check for the R/W flag on each msg */
if (msg->flags & I2C_M_RD)
cdns_i2c_mrecv(id, atomic);
else
cdns_i2c_msend(id);
/* Minimal time to execute this message */
msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) /
id->i2c_clk);
/* Plus some wiggle room */
msg_timeout += msecs_to_jiffies(500);
if (msg_timeout < adap->timeout)
msg_timeout = adap->timeout;
/* Wait for the signal of completion */
if (!atomic) {
/* Wait for completion signal from ISR */
time_left = wait_for_completion_timeout(&id->xfer_done,
msg_timeout);
if (time_left == 0) {
goto timeout;
}
} else {
/* Interrupts are disabled; we have to poll for completion */
/* Fixed timeout of 500ms */
msg_timeout = 500;
irqreturn_t dummy;
while (!cdns_i2c_check_completion(id, &dummy)) {
udelay(1000);
if (!msg_timeout--) {
goto timeout;
}
}
}
cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
/* If it is bus arbitration error, try again */
if (id->err_status & CDNS_I2C_IXR_ARB_LOST)
return -EAGAIN;
if (msg->flags & I2C_M_RECV_LEN)
msg->len +=
min_t(unsigned int, msg->buf[0], I2C_SMBUS_BLOCK_MAX);
return 0;
timeout:
cdns_i2c_master_reset(adap);
dev_err(id->adap.dev.parent, "timeout waiting on completion\n");
return -ETIMEDOUT;
}
/**
* cdns_i2c_master_xfer - The main i2c transfer function
* @adap: pointer to the i2c adapter driver instance
* @msgs: pointer to the i2c message structure
* @num: the number of messages to transfer
*
* Initiates the send/recv activity based on the transfer message received.
*
* Return: number of msgs processed on success, negative error otherwise
*/
static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
int ret, count;
u32 reg;
struct cdns_i2c *id = adap->algo_data;
bool hold_quirk;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
bool change_role = false;
#endif
ret = pm_runtime_resume_and_get(id->dev);
if (ret < 0)
return ret;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
/* Check i2c operating mode and switch if possible */
if (id->dev_mode == CDNS_I2C_MODE_SLAVE) {
if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE)
return -EAGAIN;
/* Set mode to master */
cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id);
/* Mark flag to change role once xfer is completed */
change_role = true;
}
#endif
/* Check if the bus is free */
ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET, reg,
!(reg & CDNS_I2C_SR_BA),
CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US);
if (ret) {
ret = -EAGAIN;
if (id->adap.bus_recovery_info)
i2c_recover_bus(adap);
goto out;
}
hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
/*
* Set the flag to one when multiple messages are to be
* processed with a repeated start.
*/
if (num > 1) {
/*
* This controller does not give completion interrupt after a
* master receive message if HOLD bit is set (repeated start),
* resulting in SW timeout. Hence, if a receive message is
* followed by any other message, an error is returned
* indicating that this sequence is not supported.
*/
for (count = 0; (count < num - 1 && hold_quirk); count++) {
if (msgs[count].flags & I2C_M_RD) {
dev_warn(
adap->dev.parent,
"Can't do repeated start after a receive message\n");
ret = -EOPNOTSUPP;
goto out;
}
}
id->bus_hold_flag = 1;
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
reg |= CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET);
} else {
id->bus_hold_flag = 0;
}
/* Process the msg one by one */
for (count = 0; count < num; count++, msgs++) {
if (count == (num - 1))
id->bus_hold_flag = 0;
ret = cdns_i2c_process_msg(id, msgs, adap, 0);
if (ret)
goto out;
/* Report the other error interrupts to application */
if (id->err_status) {
cdns_i2c_master_reset(adap);
if (id->err_status & CDNS_I2C_IXR_NACK) {
ret = -ENXIO;
goto out;
}
ret = -EIO;
goto out;
}
}
ret = num;
out:
#if IS_ENABLED(CONFIG_I2C_SLAVE)
/* Switch i2c mode to slave */
if (change_role)
cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id);
#endif
pm_runtime_mark_last_busy(id->dev);
pm_runtime_put_autosuspend(id->dev);
return ret;
}
static int cdns_i2c_master_xfer_atomic(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
int ret, count;
u32 reg;
struct cdns_i2c *id = adap->algo_data;
bool hold_quirk;
ret = pm_runtime_resume_and_get(id->dev);
if (ret < 0)
return ret;
/* Check if the bus is free */
ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET, reg,
!(reg & CDNS_I2C_SR_BA),
CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US);
if (ret) {
ret = -EAGAIN;
if (id->adap.bus_recovery_info)
i2c_recover_bus(adap);
goto out;
}
hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
/*
* Set the flag to one when multiple messages are to be
* processed with a repeated start.
*/
if (num > 1) {
/*
* This controller does not give completion interrupt after a
* master receive message if HOLD bit is set (repeated start),
* resulting in SW timeout. Hence, if a receive message is
* followed by any other message, an error is returned
* indicating that this sequence is not supported.
*/
for (count = 0; (count < num - 1 && hold_quirk); count++) {
if (msgs[count].flags & I2C_M_RD) {
dev_warn(
adap->dev.parent,
"Can't do repeated start after a receive message\n");
ret = -EOPNOTSUPP;
goto out;
}
}
id->bus_hold_flag = 1;
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
reg |= CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET);
} else {
id->bus_hold_flag = 0;
}
/* Process the msg one by one */
for (count = 0; count < num; count++, msgs++) {
if (count == (num - 1))
id->bus_hold_flag = 0;