diff options
author | lionel.debieve@st.com <lionel.debieve@st.com> | 2018-06-26 08:52:46 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2018-07-08 12:26:22 -0400 |
commit | 73463ade0a57d2c7f23e1dfad25d32f18c79db95 (patch) | |
tree | 1c955926033563fe1489d51f60f6ed1c35d89757 | |
parent | 8b4d566de6a5ecb332a7fe8d79731d4d6fc06d6b (diff) |
crypto: stm32/crc - Add power management support
Adding pm and pm_runtime support to STM32 CRC.
Signed-off-by: Lionel Debieve <lionel.debieve@st.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | drivers/crypto/stm32/stm32_crc32.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/drivers/crypto/stm32/stm32_crc32.c b/drivers/crypto/stm32/stm32_crc32.c index 8f09b8430893..04ba5e1399e5 100644 --- a/drivers/crypto/stm32/stm32_crc32.c +++ b/drivers/crypto/stm32/stm32_crc32.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/clk.h> | 8 | #include <linux/clk.h> |
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/platform_device.h> | 10 | #include <linux/platform_device.h> |
11 | #include <linux/pm_runtime.h> | ||
11 | 12 | ||
12 | #include <crypto/internal/hash.h> | 13 | #include <crypto/internal/hash.h> |
13 | 14 | ||
@@ -32,6 +33,8 @@ | |||
32 | #define POLY_CRC32 0xEDB88320 | 33 | #define POLY_CRC32 0xEDB88320 |
33 | #define POLY_CRC32C 0x82F63B78 | 34 | #define POLY_CRC32C 0x82F63B78 |
34 | 35 | ||
36 | #define CRC_AUTOSUSPEND_DELAY 50 | ||
37 | |||
35 | struct stm32_crc { | 38 | struct stm32_crc { |
36 | struct list_head list; | 39 | struct list_head list; |
37 | struct device *dev; | 40 | struct device *dev; |
@@ -106,6 +109,8 @@ static int stm32_crc_init(struct shash_desc *desc) | |||
106 | } | 109 | } |
107 | spin_unlock_bh(&crc_list.lock); | 110 | spin_unlock_bh(&crc_list.lock); |
108 | 111 | ||
112 | pm_runtime_get_sync(ctx->crc->dev); | ||
113 | |||
109 | /* Reset, set key, poly and configure in bit reverse mode */ | 114 | /* Reset, set key, poly and configure in bit reverse mode */ |
110 | writel_relaxed(bitrev32(mctx->key), ctx->crc->regs + CRC_INIT); | 115 | writel_relaxed(bitrev32(mctx->key), ctx->crc->regs + CRC_INIT); |
111 | writel_relaxed(bitrev32(mctx->poly), ctx->crc->regs + CRC_POL); | 116 | writel_relaxed(bitrev32(mctx->poly), ctx->crc->regs + CRC_POL); |
@@ -115,6 +120,9 @@ static int stm32_crc_init(struct shash_desc *desc) | |||
115 | ctx->partial = readl_relaxed(ctx->crc->regs + CRC_DR); | 120 | ctx->partial = readl_relaxed(ctx->crc->regs + CRC_DR); |
116 | ctx->crc->nb_pending_bytes = 0; | 121 | ctx->crc->nb_pending_bytes = 0; |
117 | 122 | ||
123 | pm_runtime_mark_last_busy(ctx->crc->dev); | ||
124 | pm_runtime_put_autosuspend(ctx->crc->dev); | ||
125 | |||
118 | return 0; | 126 | return 0; |
119 | } | 127 | } |
120 | 128 | ||
@@ -126,6 +134,8 @@ static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, | |||
126 | u32 *d32; | 134 | u32 *d32; |
127 | unsigned int i; | 135 | unsigned int i; |
128 | 136 | ||
137 | pm_runtime_get_sync(crc->dev); | ||
138 | |||
129 | if (unlikely(crc->nb_pending_bytes)) { | 139 | if (unlikely(crc->nb_pending_bytes)) { |
130 | while (crc->nb_pending_bytes != sizeof(u32) && length) { | 140 | while (crc->nb_pending_bytes != sizeof(u32) && length) { |
131 | /* Fill in pending data */ | 141 | /* Fill in pending data */ |
@@ -149,6 +159,9 @@ static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, | |||
149 | /* Store partial result */ | 159 | /* Store partial result */ |
150 | ctx->partial = readl_relaxed(crc->regs + CRC_DR); | 160 | ctx->partial = readl_relaxed(crc->regs + CRC_DR); |
151 | 161 | ||
162 | pm_runtime_mark_last_busy(crc->dev); | ||
163 | pm_runtime_put_autosuspend(crc->dev); | ||
164 | |||
152 | /* Check for pending data (non 32 bits) */ | 165 | /* Check for pending data (non 32 bits) */ |
153 | length &= 3; | 166 | length &= 3; |
154 | if (likely(!length)) | 167 | if (likely(!length)) |
@@ -272,6 +285,13 @@ static int stm32_crc_probe(struct platform_device *pdev) | |||
272 | return ret; | 285 | return ret; |
273 | } | 286 | } |
274 | 287 | ||
288 | pm_runtime_set_autosuspend_delay(dev, CRC_AUTOSUSPEND_DELAY); | ||
289 | pm_runtime_use_autosuspend(dev); | ||
290 | |||
291 | pm_runtime_get_noresume(dev); | ||
292 | pm_runtime_set_active(dev); | ||
293 | pm_runtime_enable(dev); | ||
294 | |||
275 | platform_set_drvdata(pdev, crc); | 295 | platform_set_drvdata(pdev, crc); |
276 | 296 | ||
277 | spin_lock(&crc_list.lock); | 297 | spin_lock(&crc_list.lock); |
@@ -287,12 +307,18 @@ static int stm32_crc_probe(struct platform_device *pdev) | |||
287 | 307 | ||
288 | dev_info(dev, "Initialized\n"); | 308 | dev_info(dev, "Initialized\n"); |
289 | 309 | ||
310 | pm_runtime_put_sync(dev); | ||
311 | |||
290 | return 0; | 312 | return 0; |
291 | } | 313 | } |
292 | 314 | ||
293 | static int stm32_crc_remove(struct platform_device *pdev) | 315 | static int stm32_crc_remove(struct platform_device *pdev) |
294 | { | 316 | { |
295 | struct stm32_crc *crc = platform_get_drvdata(pdev); | 317 | struct stm32_crc *crc = platform_get_drvdata(pdev); |
318 | int ret = pm_runtime_get_sync(crc->dev); | ||
319 | |||
320 | if (ret < 0) | ||
321 | return ret; | ||
296 | 322 | ||
297 | spin_lock(&crc_list.lock); | 323 | spin_lock(&crc_list.lock); |
298 | list_del(&crc->list); | 324 | list_del(&crc->list); |
@@ -300,11 +326,46 @@ static int stm32_crc_remove(struct platform_device *pdev) | |||
300 | 326 | ||
301 | crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); | 327 | crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); |
302 | 328 | ||
329 | pm_runtime_disable(crc->dev); | ||
330 | pm_runtime_put_noidle(crc->dev); | ||
331 | |||
303 | clk_disable_unprepare(crc->clk); | 332 | clk_disable_unprepare(crc->clk); |
304 | 333 | ||
305 | return 0; | 334 | return 0; |
306 | } | 335 | } |
307 | 336 | ||
337 | #ifdef CONFIG_PM | ||
338 | static int stm32_crc_runtime_suspend(struct device *dev) | ||
339 | { | ||
340 | struct stm32_crc *crc = dev_get_drvdata(dev); | ||
341 | |||
342 | clk_disable_unprepare(crc->clk); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static int stm32_crc_runtime_resume(struct device *dev) | ||
348 | { | ||
349 | struct stm32_crc *crc = dev_get_drvdata(dev); | ||
350 | int ret; | ||
351 | |||
352 | ret = clk_prepare_enable(crc->clk); | ||
353 | if (ret) { | ||
354 | dev_err(crc->dev, "Failed to prepare_enable clock\n"); | ||
355 | return ret; | ||
356 | } | ||
357 | |||
358 | return 0; | ||
359 | } | ||
360 | #endif | ||
361 | |||
362 | static const struct dev_pm_ops stm32_crc_pm_ops = { | ||
363 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
364 | pm_runtime_force_resume) | ||
365 | SET_RUNTIME_PM_OPS(stm32_crc_runtime_suspend, | ||
366 | stm32_crc_runtime_resume, NULL) | ||
367 | }; | ||
368 | |||
308 | static const struct of_device_id stm32_dt_ids[] = { | 369 | static const struct of_device_id stm32_dt_ids[] = { |
309 | { .compatible = "st,stm32f7-crc", }, | 370 | { .compatible = "st,stm32f7-crc", }, |
310 | {}, | 371 | {}, |
@@ -316,6 +377,7 @@ static struct platform_driver stm32_crc_driver = { | |||
316 | .remove = stm32_crc_remove, | 377 | .remove = stm32_crc_remove, |
317 | .driver = { | 378 | .driver = { |
318 | .name = DRIVER_NAME, | 379 | .name = DRIVER_NAME, |
380 | .pm = &stm32_crc_pm_ops, | ||
319 | .of_match_table = stm32_dt_ids, | 381 | .of_match_table = stm32_dt_ids, |
320 | }, | 382 | }, |
321 | }; | 383 | }; |