diff options
Diffstat (limited to 'drivers/mxc')
-rw-r--r-- | drivers/mxc/sim/imx_emvsim.c | 88 |
1 files changed, 57 insertions, 31 deletions
diff --git a/drivers/mxc/sim/imx_emvsim.c b/drivers/mxc/sim/imx_emvsim.c index 96822e894f43..4ccac7c62420 100644 --- a/drivers/mxc/sim/imx_emvsim.c +++ b/drivers/mxc/sim/imx_emvsim.c @@ -31,6 +31,7 @@ #include <linux/types.h> #include <linux/pinctrl/consumer.h> #include <linux/pm_domain.h> +#include <linux/pm_runtime.h> #define DRIVER_NAME "mxc_emvsim" @@ -1474,6 +1475,7 @@ copy_data: static int emvsim_open(struct inode *inode, struct file *file) { + int err; int errval = SIM_OK; struct emvsim_t *emvsim = dev_get_drvdata(emvsim_dev.parent); @@ -1485,12 +1487,11 @@ static int emvsim_open(struct inode *inode, struct file *file) return errval; } - if (!emvsim->open_cnt) { - clk_prepare_enable(emvsim->ipg); - clk_prepare_enable(emvsim->clk); - } - emvsim->open_cnt = 1; + err = pm_runtime_get_sync(emvsim_dev.parent); + if (err < 0) + return err; + init_completion(&emvsim->xfer_done); errval = emvsim_reset_module(emvsim); emvsim_data_reset(emvsim); @@ -1510,11 +1511,7 @@ static int emvsim_release(struct inode *inode, struct file *file) if (emvsim->present != SIM_PRESENT_REMOVED) emvsim_deactivate(emvsim); - if (emvsim->open_cnt) { - clk_disable_unprepare(emvsim->clk); - clk_disable_unprepare(emvsim->ipg); - } - + pm_runtime_put(emvsim_dev.parent); emvsim->open_cnt = 0; return 0; @@ -1593,7 +1590,6 @@ static int emvsim_probe(struct platform_device *pdev) return -EINVAL; emvsim->clk_rate = FCLK_FREQ; - emvsim->open_cnt = 0; emvsim->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!emvsim->res) { @@ -1642,7 +1638,22 @@ static int emvsim_probe(struct platform_device *pdev) if (ret) return ret; + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + ret = misc_register(&emvsim_dev); + + emvsim->open_cnt = 1; + clk_prepare_enable(emvsim->ipg); + clk_prepare_enable(emvsim->clk); + + /* Let pm_runtime_put() disable the clocks. + * If CONFIG_PM is not enabled, the clocks will stay powered. + */ + pm_runtime_put(&pdev->dev); + emvsim->open_cnt = 0; + dev_info(&pdev->dev, "emvsim register %s\n", ret ? "fail" : "success"); return ret; @@ -1650,62 +1661,77 @@ static int emvsim_probe(struct platform_device *pdev) static int emvsim_remove(struct platform_device *pdev) { - struct emvsim_t *emvsim = platform_get_drvdata(pdev); - - if (emvsim->open_cnt) { - clk_disable_unprepare(emvsim->clk); - clk_disable_unprepare(emvsim->ipg); - } + pm_runtime_disable(&pdev->dev); misc_deregister(&emvsim_dev); return 0; } -#ifdef CONFIG_PM -static int emvsim_suspend(struct platform_device *pdev, pm_message_t state) +static int __maybe_unused emvsim_suspend(struct device *dev) { - struct emvsim_t *emvsim = platform_get_drvdata(pdev); + int err; + + err = pm_runtime_force_suspend(dev); + if (err) + return err; + + pinctrl_pm_select_sleep_state(dev); + + return 0; +} + +static int __maybe_unused emvsim_runtime_suspend(struct device *dev) +{ + struct emvsim_t *emvsim = dev_get_drvdata(dev); if (emvsim->open_cnt) { clk_disable_unprepare(emvsim->clk); clk_disable_unprepare(emvsim->ipg); } - pinctrl_pm_select_sleep_state(&pdev->dev); + return 0; +} + +static int __maybe_unused emvsim_resume(struct device *dev) +{ + int err; + + err = pm_runtime_force_resume(dev); + if (err) + return err; + + pinctrl_pm_select_default_state(dev); return 0; } -static int emvsim_resume(struct platform_device *pdev) +static int __maybe_unused emvsim_runtime_resume(struct device *dev) { - struct emvsim_t *emvsim = platform_get_drvdata(pdev); + struct emvsim_t *emvsim = dev_get_drvdata(dev); if (emvsim->open_cnt) { clk_prepare_enable(emvsim->ipg); clk_prepare_enable(emvsim->clk); } - pinctrl_pm_select_default_state(&pdev->dev); - return 0; } -#else -#define emvsim_suspend NULL -#define emvsim_resume NULL -#endif +static const struct dev_pm_ops emvsim_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(emvsim_suspend, emvsim_resume) + SET_RUNTIME_PM_OPS(emvsim_runtime_suspend, emvsim_runtime_resume, NULL) +}; static struct platform_driver emvsim_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, + .pm = &emvsim_pm_ops, .of_match_table = emvsim_imx_dt_ids, }, .probe = emvsim_probe, .remove = emvsim_remove, - .suspend = emvsim_suspend, - .resume = emvsim_resume, }; static int __init emvsim_drv_init(void) |