73
73
#include <zephyr/kernel.h>
74
74
#include <zephyr/sys/atomic.h>
75
75
#include <soc.h>
76
+ #include "soc_miwu.h"
77
+ #include "soc_pins.h"
78
+ #include "soc_power.h"
76
79
77
80
#include <zephyr/logging/log.h>
78
81
#include <zephyr/irq.h>
@@ -117,6 +120,11 @@ enum npcx_i2c_flag {
117
120
NPCX_I2C_FLAG_COUNT ,
118
121
};
119
122
123
+ enum i2c_pm_policy_state_flag {
124
+ I2C_PM_POLICY_STATE_FLAG_TGT ,
125
+ I2C_PM_POLICY_STATE_FLAG_COUNT ,
126
+ };
127
+
120
128
/*
121
129
* Internal SMBus Interface driver states values, which reflect events
122
130
* which occurred on the bus
@@ -145,6 +153,11 @@ struct i2c_ctrl_config {
145
153
uintptr_t base ; /* i2c controller base address */
146
154
struct npcx_clk_cfg clk_cfg ; /* clock configuration */
147
155
uint8_t irq ; /* i2c controller irq */
156
+ #ifdef CONFIG_I2C_TARGET
157
+ /* i2c wake-up input source configuration */
158
+ const struct npcx_wui smb_wui ;
159
+ bool wakeup_source ;
160
+ #endif /* CONFIG_I2C_TARGET */
148
161
};
149
162
150
163
/* Driver data */
@@ -164,7 +177,13 @@ struct i2c_ctrl_data {
164
177
#ifdef CONFIG_I2C_TARGET
165
178
struct i2c_target_config * target_cfg ;
166
179
atomic_t flags ;
167
- #endif
180
+ /* i2c wake-up callback configuration */
181
+ struct miwu_callback smb_wk_cb ;
182
+ #endif /* CONFIG_I2C_TARGET */
183
+
184
+ #if defined(CONFIG_PM ) && defined(CONFIG_I2C_TARGET )
185
+ ATOMIC_DEFINE (pm_policy_state_flag , I2C_PM_POLICY_STATE_FLAG_COUNT );
186
+ #endif /* CONFIG_PM && CONFIG_I2C_TARGET */
168
187
};
169
188
170
189
/* Driver convenience defines */
@@ -184,6 +203,38 @@ static const struct npcx_i2c_timing_cfg npcx_20m_speed_confs[] = {
184
203
[NPCX_I2C_BUS_SPEED_1MHZ ] = {.HLDT = 7 , .k1 = 16 , .k2 = 10 },
185
204
};
186
205
206
+ #if defined(CONFIG_PM ) && defined(CONFIG_I2C_TARGET )
207
+ static void i2c_npcx_pm_policy_state_lock_get (const struct device * dev ,
208
+ enum i2c_pm_policy_state_flag flag )
209
+ {
210
+ const struct i2c_ctrl_config * const config = dev -> config ;
211
+ struct i2c_ctrl_data * const data = dev -> data ;
212
+
213
+ if (!config -> wakeup_source ) {
214
+ return ;
215
+ }
216
+
217
+ if (atomic_test_and_set_bit (data -> pm_policy_state_flag , flag ) == 0 ) {
218
+ pm_policy_state_lock_get (PM_STATE_SUSPEND_TO_IDLE , PM_ALL_SUBSTATES );
219
+ }
220
+ }
221
+
222
+ static void i2c_npcx_pm_policy_state_lock_put (const struct device * dev ,
223
+ enum i2c_pm_policy_state_flag flag )
224
+ {
225
+ const struct i2c_ctrl_config * const config = dev -> config ;
226
+ struct i2c_ctrl_data * const data = dev -> data ;
227
+
228
+ if (!config -> wakeup_source ) {
229
+ return ;
230
+ }
231
+
232
+ if (atomic_test_and_clear_bit (data -> pm_policy_state_flag , flag ) == 1 ) {
233
+ pm_policy_state_lock_put (PM_STATE_SUSPEND_TO_IDLE , PM_ALL_SUBSTATES );
234
+ }
235
+ }
236
+ #endif /* CONFIG_PM && CONFIG_I2C_TARGET */
237
+
187
238
/* I2C controller inline functions access shared registers */
188
239
static inline void i2c_ctrl_start (const struct device * dev )
189
240
{
@@ -779,6 +830,10 @@ static void i2c_ctrl_target_isr(const struct device *dev, uint8_t status)
779
830
/* End of transaction */
780
831
data -> oper_state = NPCX_I2C_IDLE ;
781
832
833
+ #ifdef CONFIG_PM
834
+ i2c_npcx_pm_policy_state_lock_put (dev , I2C_PM_POLICY_STATE_FLAG_TGT );
835
+ #endif /* CONFIG_PM */
836
+
782
837
LOG_DBG ("target: Bus error on port%02x!" , data -> port );
783
838
return ;
784
839
}
@@ -793,6 +848,10 @@ static void i2c_ctrl_target_isr(const struct device *dev, uint8_t status)
793
848
if (target_cb -> stop ) {
794
849
target_cb -> stop (data -> target_cfg );
795
850
}
851
+
852
+ #ifdef CONFIG_PM
853
+ i2c_npcx_pm_policy_state_lock_put (dev , I2C_PM_POLICY_STATE_FLAG_TGT );
854
+ #endif /* CONFIG_PM */
796
855
return ;
797
856
}
798
857
@@ -857,7 +916,7 @@ static void i2c_ctrl_target_isr(const struct device *dev, uint8_t status)
857
916
status , data -> port );
858
917
}
859
918
}
860
- #endif
919
+ #endif /* CONFIG_I2C_TARGET */
861
920
862
921
/* I2C controller isr function */
863
922
static void i2c_ctrl_isr (const struct device * dev )
@@ -874,7 +933,7 @@ static void i2c_ctrl_isr(const struct device *dev)
874
933
i2c_ctrl_target_isr (dev , status );
875
934
return ;
876
935
}
877
- #endif
936
+ #endif /* CONFIG_I2C_TARGET */
878
937
879
938
/* A 'Bus Error' has been identified */
880
939
if (IS_BIT_SET (status , NPCX_SMBST_BER )) {
@@ -1073,6 +1132,7 @@ int npcx_i2c_ctrl_target_register(const struct device *i2c_dev,
1073
1132
struct i2c_target_config * target_cfg , uint8_t port )
1074
1133
{
1075
1134
struct smb_reg * const inst = HAL_I2C_INSTANCE (i2c_dev );
1135
+ const struct i2c_ctrl_config * const config = i2c_dev -> config ;
1076
1136
struct i2c_ctrl_data * const data = i2c_dev -> data ;
1077
1137
int idx_ctrl = (port & 0xF0 ) >> 4 ;
1078
1138
int idx_port = (port & 0x0F );
@@ -1105,16 +1165,29 @@ int npcx_i2c_ctrl_target_register(const struct device *i2c_dev,
1105
1165
1106
1166
/* Reconfigure SMBCTL1 */
1107
1167
inst -> SMBCTL1 |= BIT (NPCX_SMBCTL1_NMINTE ) | BIT (NPCX_SMBCTL1_INTEN );
1168
+
1169
+ /* Enable irq of smb wake-up event */
1170
+ if (IS_ENABLED (CONFIG_PM ) && config -> wakeup_source ) {
1171
+
1172
+ /* Enable SMB wake up detection */
1173
+ npcx_i2c_target_start_wk_enable (idx_ctrl , true);
1174
+ /* Enable start detect in IDLE */
1175
+ inst -> SMBCTL3 |= BIT (NPCX_SMBCTL3_IDL_START );
1176
+ /* Enable SMB's MIWU interrupts */
1177
+ npcx_miwu_irq_enable (& config -> smb_wui );
1178
+ }
1108
1179
i2c_ctrl_irq_enable (i2c_dev , 1 );
1109
1180
1110
1181
return 0 ;
1111
1182
}
1112
1183
1113
1184
int npcx_i2c_ctrl_target_unregister (const struct device * i2c_dev ,
1114
- struct i2c_target_config * target_cfg )
1185
+ struct i2c_target_config * target_cfg , uint8_t port )
1115
1186
{
1116
1187
struct smb_reg * const inst = HAL_I2C_INSTANCE (i2c_dev );
1188
+ const struct i2c_ctrl_config * const config = i2c_dev -> config ;
1117
1189
struct i2c_ctrl_data * const data = i2c_dev -> data ;
1190
+ int idx_ctrl = (port & 0xF0 ) >> 4 ;
1118
1191
1119
1192
/* No I2c module has been configured to target mode */
1120
1193
if (!atomic_test_bit (& data -> flags , NPCX_I2C_FLAG_TARGET )) {
@@ -1139,14 +1212,46 @@ int npcx_i2c_ctrl_target_unregister(const struct device *i2c_dev,
1139
1212
1140
1213
/* Reconfigure SMBCTL1 */
1141
1214
inst -> SMBCTL1 |= BIT (NPCX_SMBCTL1_NMINTE ) | BIT (NPCX_SMBCTL1_INTEN );
1142
- i2c_ctrl_irq_enable (i2c_dev , 1 );
1143
1215
1216
+ /* Disable irq of smb wake-up event */
1217
+ if (IS_ENABLED (CONFIG_PM )) {
1218
+ /* Disable SMB wake up detection */
1219
+ npcx_i2c_target_start_wk_enable (idx_ctrl , false);
1220
+ /* Disable start detect in IDLE */
1221
+ inst -> SMBCTL3 &= ~BIT (NPCX_SMBCTL3_IDL_START );
1222
+ /* Disable SMB's MIWU interrupts */
1223
+ npcx_miwu_irq_disable (& config -> smb_wui );
1224
+
1225
+ }
1226
+ i2c_ctrl_irq_enable (i2c_dev , 1 );
1144
1227
/* Mark it as controller mode */
1145
1228
atomic_clear_bit (& data -> flags , NPCX_I2C_FLAG_TARGET );
1146
1229
1147
1230
return 0 ;
1148
1231
}
1149
- #endif
1232
+
1233
+ static void i2c_target_wk_isr (const struct device * dev , struct npcx_wui * wui )
1234
+ {
1235
+ struct smb_reg * const inst = HAL_I2C_INSTANCE (dev );
1236
+
1237
+ /* Clear wake up detection event status */
1238
+ npcx_i2c_target_clear_detection_event ();
1239
+
1240
+ /* Reconfigure SMBCTL1 */
1241
+ inst -> SMBCTL1 |= BIT (NPCX_SMBCTL1_NMINTE ) | BIT (NPCX_SMBCTL1_INTEN );
1242
+
1243
+ /*
1244
+ * Suspend-to-idle stops SMB module clocks (derived from APB2/APB3), which must remain
1245
+ * active during a transaction.
1246
+ *
1247
+ * This also prevent Sr set pm_policy_state_lock_get() twice.
1248
+ * Otherwise, it will cause I2C cannot switch to deep sleep state for the next time.
1249
+ */
1250
+ #ifdef CONFIG_PM
1251
+ i2c_npcx_pm_policy_state_lock_get (dev , I2C_PM_POLICY_STATE_FLAG_TGT );
1252
+ #endif /* CONFIG_PM */
1253
+ }
1254
+ #endif /* CONFIG_I2C_TARGET */
1150
1255
1151
1256
int npcx_i2c_ctrl_transfer (const struct device * i2c_dev , struct i2c_msg * msgs ,
1152
1257
uint8_t num_msgs , uint16_t addr , int port )
@@ -1160,7 +1265,7 @@ int npcx_i2c_ctrl_transfer(const struct device *i2c_dev, struct i2c_msg *msgs,
1160
1265
if (atomic_test_bit (& data -> flags , NPCX_I2C_FLAG_TARGET )) {
1161
1266
return - EBUSY ;
1162
1267
}
1163
- #endif
1268
+ #endif /* CONFIG_I2C_TARGET */
1164
1269
1165
1270
/*
1166
1271
* suspend-to-idle stops SMB module clocks (derived from APB2/APB3), which must remain
@@ -1285,6 +1390,21 @@ static int i2c_ctrl_init(const struct device *dev)
1285
1390
/* Initialize i2c module */
1286
1391
i2c_ctrl_init_module (dev );
1287
1392
1393
+ #ifdef CONFIG_I2C_TARGET
1394
+ if (IS_ENABLED (CONFIG_PM ) && config -> wakeup_source ) {
1395
+ /* Initialize a miwu device input and its callback function */
1396
+ npcx_miwu_init_dev_callback (& data -> smb_wk_cb , & config -> smb_wui ,
1397
+ i2c_target_wk_isr , dev );
1398
+ npcx_miwu_manage_callback (& data -> smb_wk_cb , true);
1399
+ /*
1400
+ * Configure Start condition wake-up configuration of SMB
1401
+ * controller.
1402
+ */
1403
+ npcx_miwu_interrupt_configure (& config -> smb_wui , NPCX_MIWU_MODE_EDGE ,
1404
+ NPCX_MIWU_TRIG_HIGH );
1405
+ }
1406
+ #endif /* CONFIG_I2C_TARGET */
1407
+
1288
1408
/* initialize mutex and semaphore for i2c/smb controller */
1289
1409
k_sem_init (& data -> lock_sem , 1 , 1 );
1290
1410
k_sem_init (& data -> sync_sem , 0 , K_SEM_MAX_LIMIT );
@@ -1316,24 +1436,28 @@ static int i2c_ctrl_init(const struct device *dev)
1316
1436
}
1317
1437
1318
1438
1319
- #define NPCX_I2C_CTRL_INIT (inst ) \
1320
- NPCX_I2C_CTRL_INIT_FUNC_DECL(inst); \
1321
- \
1322
- static const struct i2c_ctrl_config i2c_ctrl_cfg_##inst = { \
1323
- .base = DT_INST_REG_ADDR(inst), \
1324
- .irq = DT_INST_IRQN(inst), \
1325
- .clk_cfg = NPCX_DT_CLK_CFG_ITEM(inst), \
1326
- }; \
1327
- \
1328
- static struct i2c_ctrl_data i2c_ctrl_data_##inst; \
1329
- \
1330
- DEVICE_DT_INST_DEFINE(inst, \
1331
- NPCX_I2C_CTRL_INIT_FUNC(inst), \
1332
- NULL, \
1333
- &i2c_ctrl_data_##inst, &i2c_ctrl_cfg_##inst, \
1334
- PRE_KERNEL_1, CONFIG_I2C_INIT_PRIORITY, \
1335
- NULL); \
1336
- \
1439
+ #define NPCX_I2C_CTRL_INIT (inst ) \
1440
+ NPCX_I2C_CTRL_INIT_FUNC_DECL(inst); \
1441
+ \
1442
+ static const struct i2c_ctrl_config i2c_ctrl_cfg_##inst = { \
1443
+ .base = DT_INST_REG_ADDR(inst), \
1444
+ .irq = DT_INST_IRQN(inst), \
1445
+ .clk_cfg = NPCX_DT_CLK_CFG_ITEM(inst), \
1446
+ IF_ENABLED(CONFIG_I2C_TARGET, ( \
1447
+ .smb_wui = NPCX_DT_WUI_ITEM_BY_NAME(inst, smb_wui), \
1448
+ .wakeup_source = DT_INST_PROP_OR(inst, wakeup_source, 0) \
1449
+ )) \
1450
+ }; \
1451
+ \
1452
+ static struct i2c_ctrl_data i2c_ctrl_data_##inst; \
1453
+ \
1454
+ DEVICE_DT_INST_DEFINE(inst, \
1455
+ NPCX_I2C_CTRL_INIT_FUNC(inst), \
1456
+ NULL, \
1457
+ &i2c_ctrl_data_##inst, &i2c_ctrl_cfg_##inst, \
1458
+ PRE_KERNEL_1, CONFIG_I2C_INIT_PRIORITY, \
1459
+ NULL); \
1460
+ \
1337
1461
NPCX_I2C_CTRL_INIT_FUNC_IMPL(inst)
1338
1462
1339
1463
DT_INST_FOREACH_STATUS_OKAY (NPCX_I2C_CTRL_INIT )
0 commit comments