@@ -64,8 +64,17 @@ struct i2c_sam0_dev_data {
64
64
struct device * dma ;
65
65
#endif
66
66
67
+ #ifdef CONFIG_I2C_SLAVE
68
+ bool master_active ;
69
+ struct i2c_slave_config * slave_cfg ;
70
+ bool slave_attached ;
71
+ #endif /* CONFIG_I2C_SLAVE */
67
72
};
68
73
74
+ #ifdef CONFIG_I2C_SLAVE
75
+ static void i2c_sam0_slave_event (struct device * dev );
76
+ #endif /* CONFIG_I2C_SLAVE */
77
+
69
78
#define DEV_NAME (dev ) ((dev)->name)
70
79
#define DEV_CFG (dev ) \
71
80
((const struct i2c_sam0_dev_config *const)(dev)->config_info)
@@ -162,6 +171,13 @@ static void i2c_sam0_isr(void *arg)
162
171
const struct i2c_sam0_dev_config * const cfg = DEV_CFG (dev );
163
172
SercomI2cm * i2c = cfg -> regs ;
164
173
174
+ #ifdef CONFIG_I2C_SLAVE
175
+ if (data -> slave_attached && !data -> master_active ) {
176
+ i2c_sam0_slave_event (dev );
177
+ return ;
178
+ }
179
+ #endif /* CONFIG_I2C_SLAVE */
180
+
165
181
int key = irq_lock ();
166
182
167
183
/* Get present interrupts */
@@ -449,6 +465,13 @@ static int i2c_sam0_transfer(struct device *dev, struct i2c_msg *msgs,
449
465
return 0 ;
450
466
}
451
467
468
+ #ifdef CONFIG_I2C_SLAVE
469
+ if (data -> slave_attached ) {
470
+ LOG_ERR ("Driver is registered as slave" );
471
+ return - EBUSY ;
472
+ }
473
+ #endif /* CONFIG_I2C_SLAVE */
474
+
452
475
i = 0 ;
453
476
wait_synchronization (i2c );
454
477
while (i2c -> STATUS .bit .BUSSTATE != 1 ) {
@@ -460,11 +483,15 @@ static int i2c_sam0_transfer(struct device *dev, struct i2c_msg *msgs,
460
483
i ++ ;
461
484
}
462
485
463
- if (k_sem_take (& data -> transfer_sync , 1000 ) == - EAGAIN ) {
486
+ if (k_sem_take (& data -> transfer_sync , K_MSEC ( 1000 ) ) == - EAGAIN ) {
464
487
LOG_WRN ("Failed to acquire sam0 i2c device lock" );
465
488
return - EAGAIN ;
466
489
}
467
490
491
+ #ifdef CONFIG_I2C_SLAVE
492
+ data -> master_active = true;
493
+ #endif /* CONFIG_I2C_SLAVE */
494
+
468
495
for (; num_msgs > 0 ;) {
469
496
if (!msgs -> len ) {
470
497
if ((msgs -> flags & I2C_MSG_RW_MASK ) == I2C_MSG_READ ) {
@@ -587,6 +614,10 @@ static int i2c_sam0_transfer(struct device *dev, struct i2c_msg *msgs,
587
614
msgs ++ ;
588
615
}
589
616
617
+ #ifdef CONFIG_I2C_SLAVE
618
+ data -> master_active = false;
619
+ #endif /* CONFIG_I2C_SLAVE */
620
+
590
621
k_sem_give (& data -> transfer_sync );
591
622
return ret ;
592
623
}
@@ -727,16 +758,39 @@ static int i2c_sam0_set_apply_bitrate(struct device *dev, uint32_t config)
727
758
728
759
static int i2c_sam0_configure (struct device * dev , uint32_t config )
729
760
{
730
- struct i2c_sam0_dev_data * data = DEV_DATA (dev );
731
761
const struct i2c_sam0_dev_config * const cfg = DEV_CFG (dev );
732
762
SercomI2cm * i2c = cfg -> regs ;
733
763
int retval ;
734
764
735
765
if (!(config & I2C_MODE_MASTER )) {
736
- return - EINVAL ;
766
+ /* configure for slave mode */
767
+ i2c -> CTRLA .bit .ENABLE = 0 ;
768
+ wait_synchronization (i2c );
769
+
770
+ /* Disable all I2C interrupts */
771
+ i2c -> INTENCLR .reg = SERCOM_I2CS_INTENCLR_MASK ;
772
+
773
+ /* I2C mode, enable timeouts */
774
+ i2c -> CTRLA .reg = SERCOM_I2CS_CTRLA_MODE_I2C_SLAVE
775
+ #ifdef SERCOM_I2CS_CTRLA_LOWTOUTEN
776
+ | SERCOM_I2CS_CTRLA_LOWTOUTEN
777
+ #endif
778
+ | SERCOM_I2CS_CTRLA_RUNSTDBY ;
779
+ wait_synchronization (i2c );
780
+
781
+ /*
782
+ * Enable smart mode (auto ACK data received)
783
+ * and auto ack an address match
784
+ */
785
+ i2c -> CTRLB .reg = SERCOM_I2CS_CTRLB_SMEN ;
786
+ wait_synchronization (i2c );
787
+
788
+ i2c -> CTRLA .bit .ENABLE = 1 ;
789
+ wait_synchronization (i2c );
737
790
}
738
791
739
792
if (config & I2C_MODE_MASTER ) {
793
+ /* configure for master mode */
740
794
i2c -> CTRLA .bit .ENABLE = 0 ;
741
795
wait_synchronization (i2c );
742
796
@@ -847,12 +901,211 @@ static int i2c_sam0_initialize(struct device *dev)
847
901
i2c -> STATUS .bit .BUSSTATE = 1 ;
848
902
wait_synchronization (i2c );
849
903
904
+ #ifdef CONFIG_I2C_SLAVE
905
+ data -> master_active = false;
906
+ data -> slave_attached = false;
907
+ #endif /* CONFIG_I2C_SLAVE */
908
+
850
909
return 0 ;
851
910
}
852
911
912
+ #ifdef CONFIG_I2C_SLAVE
913
+ static void i2c_sam0_slave_event (struct device * dev )
914
+ {
915
+ const struct i2c_sam0_dev_config * cfg = DEV_CFG (dev );
916
+ struct i2c_sam0_dev_data * data = DEV_DATA (dev );
917
+ SercomI2cs * i2c = (SercomI2cs * )cfg -> regs ;
918
+ const struct i2c_slave_callbacks * slave_cb =
919
+ data -> slave_cfg -> callbacks ;
920
+
921
+ /* Get present interrupts */
922
+ u32_t status = i2c -> INTFLAG .reg ;
923
+
924
+ if (status & SERCOM_I2CS_INTFLAG_ERROR ) {
925
+ /* error */
926
+ if (i2c -> STATUS .bit .LOWTOUT ) {
927
+ LOG_ERR ("slave SCL low timeout" );
928
+ }
929
+
930
+ if (i2c -> STATUS .bit .SEXTTOUT ) {
931
+ LOG_ERR ("slave SCL low extend timeout" );
932
+ }
933
+
934
+ if (i2c -> STATUS .bit .COLL || i2c -> STATUS .bit .BUSERR ) {
935
+ /* Bus error */
936
+ i2c -> STATUS .bit .COLL = 1 ;
937
+ i2c -> STATUS .bit .BUSERR = 1 ;
938
+ LOG_ERR ("slave bus error" );
939
+ }
940
+ i2c -> INTFLAG .reg = SERCOM_I2CS_INTFLAG_ERROR ;
941
+ i2c -> INTENCLR .reg = SERCOM_I2CS_INTENCLR_ERROR ;
942
+ i2c -> INTENCLR .reg = SERCOM_I2CS_INTENCLR_DRDY ;
943
+ i2c -> INTENCLR .reg = SERCOM_I2CS_INTENCLR_PREC ;
944
+ slave_cb -> stop (data -> slave_cfg );
945
+ return ;
946
+ }
947
+
948
+ if (status & SERCOM_I2CS_INTFLAG_PREC ) {
949
+ /* stop */
950
+ i2c -> INTFLAG .reg = SERCOM_I2CS_INTFLAG_PREC ;
951
+ i2c -> INTENCLR .reg = SERCOM_I2CS_INTENCLR_ERROR ;
952
+ i2c -> INTENCLR .reg = SERCOM_I2CS_INTENCLR_DRDY ;
953
+ i2c -> INTENCLR .reg = SERCOM_I2CS_INTENCLR_PREC ;
954
+ slave_cb -> stop (data -> slave_cfg );
955
+ }
956
+
957
+ if (status & SERCOM_I2CS_INTFLAG_AMATCH ) {
958
+ /* address match */
959
+ i2c -> INTFLAG .reg = SERCOM_I2CS_INTFLAG_AMATCH ;
960
+
961
+ if (!i2c -> STATUS .bit .DIR ) {
962
+ /* Master requested write */
963
+ slave_cb -> write_requested (data -> slave_cfg );
964
+ } else {
965
+ /* Master requested read */
966
+ u8_t val ;
967
+
968
+ slave_cb -> read_requested (data -> slave_cfg , & val );
969
+ while (!(i2c -> INTFLAG .reg & SERCOM_I2CS_INTFLAG_DRDY )) {
970
+ /* wait for data ready */
971
+ }
972
+ i2c -> data .reg = val ;
973
+ }
974
+
975
+ i2c -> INTENSET .reg = SERCOM_I2CS_INTENSET_ERROR ;
976
+ i2c -> INTENSET .reg = SERCOM_I2CS_INTENSET_DRDY ;
977
+ i2c -> INTENSET .reg = SERCOM_I2CS_INTENSET_PREC ;
978
+ i2c -> CTRLB .bit .ACKACT = 0 ;
979
+ }
980
+
981
+ if (status & SERCOM_I2CS_INTFLAG_DRDY ) {
982
+ /* data ready */
983
+ if (!i2c -> STATUS .bit .DIR ) {
984
+ /* Master requested write */
985
+ u8_t val = i2c -> data .reg ;
986
+
987
+ if (slave_cb -> write_received (data -> slave_cfg , val )) {
988
+ /*
989
+ * If write_received() returns !=0, then
990
+ * handle exception and send NACK to master
991
+ */
992
+ }
993
+ } else {
994
+ /* Master requested read */
995
+ u8_t val ;
996
+
997
+ if (!i2c -> STATUS .bit .RXNACK ) {
998
+ slave_cb -> read_processed (data -> slave_cfg , & val );
999
+ i2c -> data .reg = val ;
1000
+ } else {
1001
+ /*
1002
+ * Master terminated the bus transaction.
1003
+ * Clear DRDY flag
1004
+ */
1005
+ i2c -> INTFLAG .reg = SERCOM_I2CS_INTFLAG_DRDY ;
1006
+ }
1007
+ }
1008
+ return ;
1009
+ }
1010
+
1011
+ }
1012
+
1013
+ /* Attach and start I2C as slave */
1014
+ int i2c_sam0_slave_register (struct device * dev ,
1015
+ struct i2c_slave_config * config )
1016
+ {
1017
+ const struct i2c_sam0_dev_config * cfg = DEV_CFG (dev );
1018
+ struct i2c_sam0_dev_data * data = DEV_DATA (dev );
1019
+ SercomI2cs * i2c = (SercomI2cs * )cfg -> regs ;
1020
+ u32_t bitrate_cfg ;
1021
+ int ret ;
1022
+
1023
+ if (!config ) {
1024
+ return - EINVAL ;
1025
+ }
1026
+
1027
+ if (data -> slave_attached ) {
1028
+ return - EBUSY ;
1029
+ }
1030
+
1031
+ if (data -> master_active ) {
1032
+ return - EBUSY ;
1033
+ }
1034
+
1035
+ bitrate_cfg = i2c_map_dt_bitrate (cfg -> bitrate ) & ~I2C_MODE_MASTER ;
1036
+
1037
+ ret = i2c_sam0_configure (dev , bitrate_cfg );
1038
+ if (ret < 0 ) {
1039
+ LOG_ERR ("i2c: failure initializing" );
1040
+ return ret ;
1041
+ }
1042
+
1043
+ i2c -> CTRLA .bit .ENABLE = 0 ;
1044
+ wait_synchronization ((SercomI2cm * )i2c );
1045
+ i2c -> ADDR .reg = (config -> address << 1 );
1046
+ i2c -> CTRLA .bit .ENABLE = 1 ;
1047
+ wait_synchronization ((SercomI2cm * )i2c );
1048
+ data -> slave_cfg = config ;
1049
+ data -> slave_attached = true;
1050
+
1051
+ /* Enable Address Match interrupt */
1052
+ i2c -> INTENSET .reg = SERCOM_I2CS_INTENSET_AMATCH ;
1053
+
1054
+ LOG_DBG ("i2c: slave registered" );
1055
+
1056
+ return 0 ;
1057
+ }
1058
+
1059
+ int i2c_sam0_slave_unregister (struct device * dev ,
1060
+ struct i2c_slave_config * config )
1061
+ {
1062
+ const struct i2c_sam0_dev_config * cfg = DEV_CFG (dev );
1063
+ struct i2c_sam0_dev_data * data = DEV_DATA (dev );
1064
+ SercomI2cs * i2c = (SercomI2cs * )cfg -> regs ;
1065
+ int ret ;
1066
+
1067
+ if (!data -> slave_attached ) {
1068
+ return - EINVAL ;
1069
+ }
1070
+
1071
+ if (data -> master_active ) {
1072
+ return - EBUSY ;
1073
+ }
1074
+
1075
+ i2c -> CTRLA .bit .ENABLE = 0 ;
1076
+ wait_synchronization ((SercomI2cm * )i2c );
1077
+
1078
+ /* Disable all I2C interrupts */
1079
+ i2c -> INTENCLR .reg = SERCOM_I2CM_INTENCLR_MASK ;
1080
+
1081
+ /* Clear all pending I2C interrupts */
1082
+ i2c -> INTFLAG .reg = i2c -> INTFLAG .reg ;
1083
+
1084
+ data -> slave_attached = false;
1085
+
1086
+ u32_t bitrate_cfg = i2c_map_dt_bitrate (cfg -> bitrate ) | I2C_MODE_MASTER ;
1087
+
1088
+ ret = i2c_sam0_configure (dev , bitrate_cfg );
1089
+ if (ret < 0 ) {
1090
+ LOG_ERR ("i2c: failure initializing" );
1091
+ return ret ;
1092
+ }
1093
+
1094
+ LOG_DBG ("i2c: slave unregistered" );
1095
+
1096
+ return 0 ;
1097
+ }
1098
+
1099
+ #endif /* CONFIG_I2C_SLAVE */
1100
+
1101
+
853
1102
static const struct i2c_driver_api i2c_sam0_driver_api = {
854
1103
.configure = i2c_sam0_configure ,
855
1104
.transfer = i2c_sam0_transfer ,
1105
+ #ifdef CONFIG_I2C_SLAVE
1106
+ .slave_register = i2c_sam0_slave_register ,
1107
+ .slave_unregister = i2c_sam0_slave_unregister ,
1108
+ #endif /* CONFIG_I2C_SLAVE */
856
1109
};
857
1110
858
1111
#ifdef CONFIG_I2C_SAM0_DMA_DRIVEN
0 commit comments