Skip to content

Commit d7bf8c0

Browse files
bogdanovscfriedt
authored andcommitted
drivers: i2c: cc23x0: Add power management
Add PM support to cc23x0 I2C. Signed-off-by: Stoyan Bogdanov <[email protected]>
1 parent afd2962 commit d7bf8c0

File tree

1 file changed

+67
-9
lines changed

1 file changed

+67
-9
lines changed

drivers/i2c/i2c_cc23x0.c

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,30 @@ struct i2c_cc23x0_data {
3030
struct k_sem lock;
3131
struct k_sem complete;
3232
volatile uint32_t error;
33+
uint32_t cfg;
3334
};
3435

3536
struct i2c_cc23x0_config {
3637
uint32_t base;
3738
const struct pinctrl_dev_config *pcfg;
3839
};
3940

41+
static inline void i2c_cc23x0_pm_policy_state_lock_get(void)
42+
{
43+
#ifdef CONFIG_PM_DEVICE
44+
pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
45+
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
46+
#endif
47+
}
48+
49+
static inline void i2c_cc23x0_pm_policy_state_lock_put(void)
50+
{
51+
#ifdef CONFIG_PM_DEVICE
52+
pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
53+
pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
54+
#endif
55+
}
56+
4057
static int i2c_cc23x0_transmit(const struct device *dev, const uint8_t *buf, uint32_t len,
4158
uint16_t addr)
4259
{
@@ -53,7 +70,7 @@ static int i2c_cc23x0_transmit(const struct device *dev, const uint8_t *buf, uin
5370

5471
/* Single transmission */
5572
if (len == 1) {
56-
I2CControllerPutData(base, *buf);
73+
I2CControllerPutData(base, buf[0]);
5774
I2CControllerCommand(base, I2C_CONTROLLER_CMD_SINGLE_SEND);
5875
k_sem_take(&data->complete, K_FOREVER);
5976
return data->error == I2C_MASTER_ERR_NONE ? 0 : -EIO;
@@ -103,18 +120,19 @@ static int i2c_cc23x0_receive(const struct device *dev, uint8_t *buf, uint32_t l
103120
if (len == 0) {
104121
return -EIO;
105122
}
106-
I2CControllerSetTargetAddr(base, addr, true);
107123

124+
I2CControllerSetTargetAddr(base, addr, true);
108125
/* Single receive */
109126
if (len == 1) {
127+
buf[0] = I2CControllerGetData(base);
110128
I2CControllerCommand(base, I2C_CONTROLLER_CMD_SINGLE_RECEIVE);
129+
111130
k_sem_take(&data->complete, K_FOREVER);
112131

113132
if (data->error != I2C_MASTER_ERR_NONE) {
114133
return -EIO;
115134
}
116-
117-
*buf = I2CControllerGetData(base);
135+
buf[0] = I2CControllerGetData(base);
118136
return 0;
119137
}
120138

@@ -127,7 +145,6 @@ static int i2c_cc23x0_receive(const struct device *dev, uint8_t *buf, uint32_t l
127145
}
128146

129147
buf[0] = I2CControllerGetData(base);
130-
131148
for (int i = 1; i < len - 1; i++) {
132149
I2CControllerCommand(base, I2C_CONTROLLER_CMD_BURST_RECEIVE_CONT);
133150
k_sem_take(&data->complete, K_FOREVER);
@@ -159,6 +176,7 @@ static int i2c_cc23x0_transfer(const struct device *dev, struct i2c_msg *msgs, u
159176
uint16_t addr)
160177
{
161178
struct i2c_cc23x0_data *data = dev->data;
179+
const struct i2c_cc23x0_config *config = dev->config;
162180
int ret = 0;
163181

164182
if (num_msgs == 0) {
@@ -167,6 +185,8 @@ static int i2c_cc23x0_transfer(const struct device *dev, struct i2c_msg *msgs, u
167185

168186
k_sem_take(&data->lock, K_FOREVER);
169187

188+
i2c_cc23x0_pm_policy_state_lock_get();
189+
170190
for (int i = 0; i < num_msgs; i++) {
171191
/* Not supported by hardware */
172192
if (msgs[i].flags & I2C_MSG_ADDR_10_BITS) {
@@ -184,6 +204,13 @@ static int i2c_cc23x0_transfer(const struct device *dev, struct i2c_msg *msgs, u
184204
break;
185205
}
186206
}
207+
208+
while (I2CControllerBusy(config->base)) {
209+
;
210+
}
211+
212+
i2c_cc23x0_pm_policy_state_lock_put();
213+
187214
k_sem_give(&data->lock);
188215

189216
return ret;
@@ -227,6 +254,33 @@ static int i2c_cc23x0_configure(const struct device *dev, uint32_t dev_config)
227254
return 0;
228255
}
229256

257+
#ifdef CONFIG_PM_DEVICE
258+
259+
static int i2c_cc23x0_pm_action(const struct device *dev, enum pm_device_action action)
260+
{
261+
const struct i2c_cc23x0_config *config = dev->config;
262+
struct i2c_cc23x0_data *data = dev->data;
263+
264+
switch (action) {
265+
case PM_DEVICE_ACTION_SUSPEND:
266+
I2CControllerDisable(config->base);
267+
I2CControllerDisableInt(config->base);
268+
CLKCTLDisable(CLKCTL_BASE, CLKCTL_I2C0);
269+
break;
270+
case PM_DEVICE_ACTION_RESUME:
271+
CLKCTLEnable(CLKCTL_BASE, CLKCTL_I2C0);
272+
i2c_cc23x0_configure(dev, data->cfg | I2C_MODE_CONTROLLER);
273+
I2CControllerEnableInt(config->base);
274+
break;
275+
default:
276+
return -ENOTSUP;
277+
}
278+
279+
return 0;
280+
}
281+
282+
#endif /* CONFIG_PM_DEVICE */
283+
230284
static void i2c_cc23x0_isr(const struct device *dev)
231285
{
232286
const struct i2c_cc23x0_config *config = dev->config;
@@ -237,8 +291,12 @@ static void i2c_cc23x0_isr(const struct device *dev)
237291
I2CControllerClearInt(base);
238292

239293
data->error = I2CControllerError(base);
240-
241-
k_sem_give(&data->complete);
294+
if (data->error) {
295+
LOG_ERR("Error [%x]", data->error);
296+
}
297+
if (!I2CControllerBusy(config->base)) {
298+
k_sem_give(&data->complete);
299+
}
242300
}
243301
}
244302

@@ -290,8 +348,8 @@ static const struct i2c_driver_api i2c_cc23x0_driver_api = {.configure = i2c_cc2
290348
.complete = Z_SEM_INITIALIZER(i2c_cc23x0_##id##_data.complete, 0, 1), \
291349
.error = I2C_MASTER_ERR_NONE}; \
292350
\
293-
I2C_DEVICE_DT_INST_DEFINE(id, i2c_cc23x0_init##id, NULL, &i2c_cc23x0_##id##_data, \
294-
&i2c_cc23x0_##id##_config, POST_KERNEL, \
351+
I2C_DEVICE_DT_INST_DEFINE(id, i2c_cc23x0_init##id, PM_DEVICE_DT_INST_GET(id), \
352+
&i2c_cc23x0_##id##_data, &i2c_cc23x0_##id##_config, POST_KERNEL, \
295353
CONFIG_I2C_INIT_PRIORITY, &i2c_cc23x0_driver_api);
296354

297355
DT_INST_FOREACH_STATUS_OKAY(CC23X0_I2C);

0 commit comments

Comments
 (0)