drivers: i2c: smartbond: Add support for PM
This commit should add all the functionality needed for the I2C driver to work when PM is enabled. Signed-off-by: Ioannis Karachalios <ioannis.karachalios.px@renesas.com>
This commit is contained in:
parent
054f453ea7
commit
c140053654
4 changed files with 134 additions and 7 deletions
|
@ -24,6 +24,15 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/omit-if-no-ref/ i2c_sleep: i2c_sleep {
|
||||||
|
group1 {
|
||||||
|
pinmux = <SMARTBOND_PINMUX(GPIO, 0, 31)>,
|
||||||
|
<SMARTBOND_PINMUX(GPIO, 0, 30)>;
|
||||||
|
bias-pull-up;
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
i2c2_default: i2c2_default {
|
i2c2_default: i2c2_default {
|
||||||
group1 {
|
group1 {
|
||||||
pinmux = <SMARTBOND_PINMUX(I2C2_SDA, 0, 28)>,
|
pinmux = <SMARTBOND_PINMUX(I2C2_SDA, 0, 28)>,
|
||||||
|
@ -32,6 +41,14 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/omit-if-no-ref/ i2c2_sleep: i2c2_sleep {
|
||||||
|
group1 {
|
||||||
|
pinmux = <SMARTBOND_PINMUX(GPIO, 0, 28)>,
|
||||||
|
<SMARTBOND_PINMUX(GPIO, 0, 29)>;
|
||||||
|
bias-pull-up;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
display_controller_default: display_controller_default {
|
display_controller_default: display_controller_default {
|
||||||
group1 {
|
group1 {
|
||||||
pinmux = <SMARTBOND_PINMUX(LCD, 1, 2)>,
|
pinmux = <SMARTBOND_PINMUX(LCD, 1, 2)>,
|
||||||
|
|
|
@ -153,13 +153,15 @@ zephyr_udc0: &usbd {
|
||||||
&i2c {
|
&i2c {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
pinctrl-0 = <&i2c_default>;
|
pinctrl-0 = <&i2c_default>;
|
||||||
pinctrl-names = "default";
|
pinctrl-1 = <&i2c_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
};
|
};
|
||||||
|
|
||||||
&i2c2 {
|
&i2c2 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
pinctrl-0 = <&i2c2_default>;
|
pinctrl-0 = <&i2c2_default>;
|
||||||
pinctrl-names = "default";
|
pinctrl-1 = <&i2c2_sleep>;
|
||||||
|
pinctrl-names = "default", "sleep";
|
||||||
};
|
};
|
||||||
|
|
||||||
&spi {
|
&spi {
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
group1 {
|
group1 {
|
||||||
pinmux = <SMARTBOND_PINMUX(GPIO, 0, 19)>,
|
pinmux = <SMARTBOND_PINMUX(GPIO, 0, 19)>,
|
||||||
<SMARTBOND_PINMUX(GPIO, 0, 18)>;
|
<SMARTBOND_PINMUX(GPIO, 0, 18)>;
|
||||||
bias-pull-down;
|
bias-pull-up;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
#include <zephyr/drivers/i2c.h>
|
#include <zephyr/drivers/i2c.h>
|
||||||
#include <zephyr/drivers/pinctrl.h>
|
#include <zephyr/drivers/pinctrl.h>
|
||||||
#include <DA1469xAB.h>
|
#include <DA1469xAB.h>
|
||||||
|
#include <da1469x_pd.h>
|
||||||
|
#include <zephyr/pm/device.h>
|
||||||
|
#include <zephyr/pm/policy.h>
|
||||||
|
#include <zephyr/pm/device_runtime.h>
|
||||||
|
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
LOG_MODULE_REGISTER(i2c_smartbond);
|
LOG_MODULE_REGISTER(i2c_smartbond);
|
||||||
|
@ -31,8 +35,36 @@ struct i2c_smartbond_data {
|
||||||
uint32_t transmit_cnt, receive_cnt;
|
uint32_t transmit_cnt, receive_cnt;
|
||||||
i2c_callback_t cb;
|
i2c_callback_t cb;
|
||||||
void *userdata;
|
void *userdata;
|
||||||
|
#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME)
|
||||||
|
ATOMIC_DEFINE(pm_policy_state_flag, 1);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline void i2c_smartbond_pm_policy_state_lock_get(struct i2c_smartbond_data *data)
|
||||||
|
{
|
||||||
|
#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME)
|
||||||
|
if (atomic_test_and_set_bit(data->pm_policy_state_flag, 0) == 0) {
|
||||||
|
/*
|
||||||
|
* Prevent the SoC from etering the normal sleep state as PDC does not support
|
||||||
|
* waking up the application core following I2C events.
|
||||||
|
*/
|
||||||
|
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void i2c_smartbond_pm_policy_state_lock_put(struct i2c_smartbond_data *data)
|
||||||
|
{
|
||||||
|
#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME)
|
||||||
|
if (atomic_test_and_clear_bit(data->pm_policy_state_flag, 0) == 1) {
|
||||||
|
/*
|
||||||
|
* Allow the SoC to enter the nornmal sleep state once I2C transactions are done.
|
||||||
|
*/
|
||||||
|
pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static int i2c_smartbond_configure(const struct device *dev, uint32_t dev_config)
|
static int i2c_smartbond_configure(const struct device *dev, uint32_t dev_config)
|
||||||
{
|
{
|
||||||
const struct i2c_smartbond_cfg *config = dev->config;
|
const struct i2c_smartbond_cfg *config = dev->config;
|
||||||
|
@ -149,6 +181,7 @@ static inline void i2c_smartbond_set_target_address(const struct i2c_smartbond_c
|
||||||
} else {
|
} else {
|
||||||
config->regs->I2C_CON_REG &= ~(I2C_I2C_CON_REG_I2C_10BITADDR_MASTER_Msk);
|
config->regs->I2C_CON_REG &= ~(I2C_I2C_CON_REG_I2C_10BITADDR_MASTER_Msk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Change the Target Address */
|
/* Change the Target Address */
|
||||||
config->regs->I2C_TAR_REG = ((config->regs->I2C_TAR_REG & ~I2C_I2C_TAR_REG_IC_TAR_Msk) |
|
config->regs->I2C_TAR_REG = ((config->regs->I2C_TAR_REG & ~I2C_I2C_TAR_REG_IC_TAR_Msk) |
|
||||||
(addr & I2C_I2C_TAR_REG_IC_TAR_Msk));
|
(addr & I2C_I2C_TAR_REG_IC_TAR_Msk));
|
||||||
|
@ -294,6 +327,8 @@ static int i2c_smartbond_transfer(const struct device *dev, struct i2c_msg *msgs
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i2c_smartbond_pm_policy_state_lock_get(data);
|
||||||
|
|
||||||
for (; data->num_msgs > 0; data->num_msgs--, data->msgs++) {
|
for (; data->num_msgs > 0; data->num_msgs--, data->msgs++) {
|
||||||
data->transmit_cnt = 0;
|
data->transmit_cnt = 0;
|
||||||
data->receive_cnt = 0;
|
data->receive_cnt = 0;
|
||||||
|
@ -323,6 +358,7 @@ static int i2c_smartbond_transfer(const struct device *dev, struct i2c_msg *msgs
|
||||||
}
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
|
i2c_smartbond_pm_policy_state_lock_put(data);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -377,6 +413,8 @@ static int i2c_smartbond_transfer_cb(const struct device *dev, struct i2c_msg *m
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i2c_smartbond_pm_policy_state_lock_get(data);
|
||||||
|
|
||||||
i2c_smartbond_enable_msg_interrupts(config, data);
|
i2c_smartbond_enable_msg_interrupts(config, data);
|
||||||
|
|
||||||
LOG_INF("async transfer started");
|
LOG_INF("async transfer started");
|
||||||
|
@ -441,6 +479,7 @@ static inline void i2c_smartbond_async_msg_done(const struct device *dev)
|
||||||
data->cb = NULL;
|
data->cb = NULL;
|
||||||
LOG_INF("async transfer finished");
|
LOG_INF("async transfer finished");
|
||||||
cb(dev, 0, data->userdata);
|
cb(dev, 0, data->userdata);
|
||||||
|
i2c_smartbond_pm_policy_state_lock_put(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,7 +532,7 @@ static const struct i2c_driver_api i2c_smartbond_driver_api = {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int i2c_smartbond_init(const struct device *dev)
|
static int i2c_smartbond_resume(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct i2c_smartbond_cfg *config = dev->config;
|
const struct i2c_smartbond_cfg *config = dev->config;
|
||||||
int err;
|
int err;
|
||||||
|
@ -515,7 +554,75 @@ static int i2c_smartbond_init(const struct device *dev)
|
||||||
I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->bitrate));
|
I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->bitrate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_PM_DEVICE) || defined(CONFIG_PM_DEVICE_RUNTIME)
|
||||||
|
static int i2c_smartbond_suspend(const struct device *dev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
const struct i2c_smartbond_cfg *config = dev->config;
|
||||||
|
|
||||||
|
/* Disable the I2C digital block */
|
||||||
|
config->regs->I2C_ENABLE_REG &= ~I2C_I2C_ENABLE_REG_I2C_EN_Msk;
|
||||||
|
/* Gate I2C clocking */
|
||||||
|
CRG_COM->RESET_CLK_COM_REG = config->periph_clock_config;
|
||||||
|
|
||||||
|
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_WRN("Fialid to configure the I2C pins to inactive state");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i2c_smartbond_pm_action(const struct device *dev,
|
||||||
|
enum pm_device_action action)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case PM_DEVICE_ACTION_RESUME:
|
||||||
|
/*
|
||||||
|
* Although the GPIO driver should already be initialized, make sure PD_COM
|
||||||
|
* is up and running before accessing the I2C block.
|
||||||
|
*/
|
||||||
|
da1469x_pd_acquire(MCU_PD_DOMAIN_COM);
|
||||||
|
ret = i2c_smartbond_resume(dev);
|
||||||
|
break;
|
||||||
|
case PM_DEVICE_ACTION_SUSPEND:
|
||||||
|
ret = i2c_smartbond_suspend(dev);
|
||||||
|
/*
|
||||||
|
* Once the I2C block is turned off its power domain can
|
||||||
|
* be released, as well.
|
||||||
|
*/
|
||||||
|
da1469x_pd_release(MCU_PD_DOMAIN_COM);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static int i2c_smartbond_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_DEVICE_RUNTIME
|
||||||
|
/* Make sure device state is marked as suspended */
|
||||||
|
pm_device_init_suspended(dev);
|
||||||
|
|
||||||
|
ret = pm_device_runtime_enable(dev);
|
||||||
|
#else
|
||||||
|
da1469x_pd_acquire(MCU_PD_DOMAIN_COM);
|
||||||
|
ret = i2c_smartbond_resume(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#define I2C_SMARTBOND_DEVICE(id) \
|
#define I2C_SMARTBOND_DEVICE(id) \
|
||||||
|
PM_DEVICE_DT_INST_DEFINE(id, i2c_smartbond_pm_action); \
|
||||||
PINCTRL_DT_INST_DEFINE(id); \
|
PINCTRL_DT_INST_DEFINE(id); \
|
||||||
static const struct i2c_smartbond_cfg i2c_smartbond_##id##_cfg = { \
|
static const struct i2c_smartbond_cfg i2c_smartbond_##id##_cfg = { \
|
||||||
.regs = (I2C_Type *)DT_INST_REG_ADDR(id), \
|
.regs = (I2C_Type *)DT_INST_REG_ADDR(id), \
|
||||||
|
@ -529,8 +636,9 @@ static int i2c_smartbond_init(const struct device *dev)
|
||||||
I2C_SMARTBOND_CONFIGURE(id); \
|
I2C_SMARTBOND_CONFIGURE(id); \
|
||||||
return ret; \
|
return ret; \
|
||||||
} \
|
} \
|
||||||
I2C_DEVICE_DT_INST_DEFINE(id, i2c_smartbond_##id##_init, NULL, &i2c_smartbond_##id##_data, \
|
I2C_DEVICE_DT_INST_DEFINE(id, i2c_smartbond_##id##_init, PM_DEVICE_DT_INST_GET(id), \
|
||||||
&i2c_smartbond_##id##_cfg, POST_KERNEL, \
|
&i2c_smartbond_##id##_data, \
|
||||||
CONFIG_I2C_INIT_PRIORITY, &i2c_smartbond_driver_api);
|
&i2c_smartbond_##id##_cfg, POST_KERNEL, \
|
||||||
|
CONFIG_I2C_INIT_PRIORITY, &i2c_smartbond_driver_api);
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(I2C_SMARTBOND_DEVICE)
|
DT_INST_FOREACH_STATUS_OKAY(I2C_SMARTBOND_DEVICE)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue