162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) STMicroelectronics SA 2017 462306a36Sopenharmony_ci * Author: Fabien Dessenne <fabien.dessenne@st.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/bitrev.h> 862306a36Sopenharmony_ci#include <linux/clk.h> 962306a36Sopenharmony_ci#include <linux/crc32.h> 1062306a36Sopenharmony_ci#include <linux/crc32poly.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <asm/unaligned.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define DRIVER_NAME "stm32-crc32" 2362306a36Sopenharmony_ci#define CHKSUM_DIGEST_SIZE 4 2462306a36Sopenharmony_ci#define CHKSUM_BLOCK_SIZE 1 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Registers */ 2762306a36Sopenharmony_ci#define CRC_DR 0x00000000 2862306a36Sopenharmony_ci#define CRC_CR 0x00000008 2962306a36Sopenharmony_ci#define CRC_INIT 0x00000010 3062306a36Sopenharmony_ci#define CRC_POL 0x00000014 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* Registers values */ 3362306a36Sopenharmony_ci#define CRC_CR_RESET BIT(0) 3462306a36Sopenharmony_ci#define CRC_CR_REV_IN_WORD (BIT(6) | BIT(5)) 3562306a36Sopenharmony_ci#define CRC_CR_REV_IN_BYTE BIT(5) 3662306a36Sopenharmony_ci#define CRC_CR_REV_OUT BIT(7) 3762306a36Sopenharmony_ci#define CRC32C_INIT_DEFAULT 0xFFFFFFFF 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define CRC_AUTOSUSPEND_DELAY 50 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic unsigned int burst_size; 4262306a36Sopenharmony_cimodule_param(burst_size, uint, 0644); 4362306a36Sopenharmony_ciMODULE_PARM_DESC(burst_size, "Select burst byte size (0 unlimited)"); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistruct stm32_crc { 4662306a36Sopenharmony_ci struct list_head list; 4762306a36Sopenharmony_ci struct device *dev; 4862306a36Sopenharmony_ci void __iomem *regs; 4962306a36Sopenharmony_ci struct clk *clk; 5062306a36Sopenharmony_ci spinlock_t lock; 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistruct stm32_crc_list { 5462306a36Sopenharmony_ci struct list_head dev_list; 5562306a36Sopenharmony_ci spinlock_t lock; /* protect dev_list */ 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic struct stm32_crc_list crc_list = { 5962306a36Sopenharmony_ci .dev_list = LIST_HEAD_INIT(crc_list.dev_list), 6062306a36Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(crc_list.lock), 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct stm32_crc_ctx { 6462306a36Sopenharmony_ci u32 key; 6562306a36Sopenharmony_ci u32 poly; 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistruct stm32_crc_desc_ctx { 6962306a36Sopenharmony_ci u32 partial; /* crc32c: partial in first 4 bytes of that struct */ 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int stm32_crc32_cra_init(struct crypto_tfm *tfm) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci mctx->key = 0; 7762306a36Sopenharmony_ci mctx->poly = CRC32_POLY_LE; 7862306a36Sopenharmony_ci return 0; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic int stm32_crc32c_cra_init(struct crypto_tfm *tfm) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci mctx->key = CRC32C_INIT_DEFAULT; 8662306a36Sopenharmony_ci mctx->poly = CRC32C_POLY_LE; 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int stm32_crc_setkey(struct crypto_shash *tfm, const u8 *key, 9162306a36Sopenharmony_ci unsigned int keylen) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct stm32_crc_ctx *mctx = crypto_shash_ctx(tfm); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (keylen != sizeof(u32)) 9662306a36Sopenharmony_ci return -EINVAL; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci mctx->key = get_unaligned_le32(key); 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic struct stm32_crc *stm32_crc_get_next_crc(void) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct stm32_crc *crc; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci spin_lock_bh(&crc_list.lock); 10762306a36Sopenharmony_ci crc = list_first_entry_or_null(&crc_list.dev_list, struct stm32_crc, list); 10862306a36Sopenharmony_ci if (crc) 10962306a36Sopenharmony_ci list_move_tail(&crc->list, &crc_list.dev_list); 11062306a36Sopenharmony_ci spin_unlock_bh(&crc_list.lock); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return crc; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int stm32_crc_init(struct shash_desc *desc) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); 11862306a36Sopenharmony_ci struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); 11962306a36Sopenharmony_ci struct stm32_crc *crc; 12062306a36Sopenharmony_ci unsigned long flags; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci crc = stm32_crc_get_next_crc(); 12362306a36Sopenharmony_ci if (!crc) 12462306a36Sopenharmony_ci return -ENODEV; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci pm_runtime_get_sync(crc->dev); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci spin_lock_irqsave(&crc->lock, flags); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Reset, set key, poly and configure in bit reverse mode */ 13162306a36Sopenharmony_ci writel_relaxed(bitrev32(mctx->key), crc->regs + CRC_INIT); 13262306a36Sopenharmony_ci writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL); 13362306a36Sopenharmony_ci writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, 13462306a36Sopenharmony_ci crc->regs + CRC_CR); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* Store partial result */ 13762306a36Sopenharmony_ci ctx->partial = readl_relaxed(crc->regs + CRC_DR); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci spin_unlock_irqrestore(&crc->lock, flags); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci pm_runtime_mark_last_busy(crc->dev); 14262306a36Sopenharmony_ci pm_runtime_put_autosuspend(crc->dev); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int burst_update(struct shash_desc *desc, const u8 *d8, 14862306a36Sopenharmony_ci size_t length) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); 15162306a36Sopenharmony_ci struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); 15262306a36Sopenharmony_ci struct stm32_crc *crc; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci crc = stm32_crc_get_next_crc(); 15562306a36Sopenharmony_ci if (!crc) 15662306a36Sopenharmony_ci return -ENODEV; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci pm_runtime_get_sync(crc->dev); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (!spin_trylock(&crc->lock)) { 16162306a36Sopenharmony_ci /* Hardware is busy, calculate crc32 by software */ 16262306a36Sopenharmony_ci if (mctx->poly == CRC32_POLY_LE) 16362306a36Sopenharmony_ci ctx->partial = crc32_le(ctx->partial, d8, length); 16462306a36Sopenharmony_ci else 16562306a36Sopenharmony_ci ctx->partial = __crc32c_le(ctx->partial, d8, length); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci goto pm_out; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* 17162306a36Sopenharmony_ci * Restore previously calculated CRC for this context as init value 17262306a36Sopenharmony_ci * Restore polynomial configuration 17362306a36Sopenharmony_ci * Configure in register for word input data, 17462306a36Sopenharmony_ci * Configure out register in reversed bit mode data. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ci writel_relaxed(bitrev32(ctx->partial), crc->regs + CRC_INIT); 17762306a36Sopenharmony_ci writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL); 17862306a36Sopenharmony_ci writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, 17962306a36Sopenharmony_ci crc->regs + CRC_CR); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (d8 != PTR_ALIGN(d8, sizeof(u32))) { 18262306a36Sopenharmony_ci /* Configure for byte data */ 18362306a36Sopenharmony_ci writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT, 18462306a36Sopenharmony_ci crc->regs + CRC_CR); 18562306a36Sopenharmony_ci while (d8 != PTR_ALIGN(d8, sizeof(u32)) && length) { 18662306a36Sopenharmony_ci writeb_relaxed(*d8++, crc->regs + CRC_DR); 18762306a36Sopenharmony_ci length--; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci /* Configure for word data */ 19062306a36Sopenharmony_ci writel_relaxed(CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, 19162306a36Sopenharmony_ci crc->regs + CRC_CR); 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci for (; length >= sizeof(u32); d8 += sizeof(u32), length -= sizeof(u32)) 19562306a36Sopenharmony_ci writel_relaxed(*((u32 *)d8), crc->regs + CRC_DR); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (length) { 19862306a36Sopenharmony_ci /* Configure for byte data */ 19962306a36Sopenharmony_ci writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT, 20062306a36Sopenharmony_ci crc->regs + CRC_CR); 20162306a36Sopenharmony_ci while (length--) 20262306a36Sopenharmony_ci writeb_relaxed(*d8++, crc->regs + CRC_DR); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Store partial result */ 20662306a36Sopenharmony_ci ctx->partial = readl_relaxed(crc->regs + CRC_DR); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci spin_unlock(&crc->lock); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cipm_out: 21162306a36Sopenharmony_ci pm_runtime_mark_last_busy(crc->dev); 21262306a36Sopenharmony_ci pm_runtime_put_autosuspend(crc->dev); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic int stm32_crc_update(struct shash_desc *desc, const u8 *d8, 21862306a36Sopenharmony_ci unsigned int length) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci const unsigned int burst_sz = burst_size; 22162306a36Sopenharmony_ci unsigned int rem_sz; 22262306a36Sopenharmony_ci const u8 *cur; 22362306a36Sopenharmony_ci size_t size; 22462306a36Sopenharmony_ci int ret; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (!burst_sz) 22762306a36Sopenharmony_ci return burst_update(desc, d8, length); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* Digest first bytes not 32bit aligned at first pass in the loop */ 23062306a36Sopenharmony_ci size = min_t(size_t, length, burst_sz + (size_t)d8 - 23162306a36Sopenharmony_ci ALIGN_DOWN((size_t)d8, sizeof(u32))); 23262306a36Sopenharmony_ci for (rem_sz = length, cur = d8; rem_sz; 23362306a36Sopenharmony_ci rem_sz -= size, cur += size, size = min(rem_sz, burst_sz)) { 23462306a36Sopenharmony_ci ret = burst_update(desc, cur, size); 23562306a36Sopenharmony_ci if (ret) 23662306a36Sopenharmony_ci return ret; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic int stm32_crc_final(struct shash_desc *desc, u8 *out) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); 24562306a36Sopenharmony_ci struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Send computed CRC */ 24862306a36Sopenharmony_ci put_unaligned_le32(mctx->poly == CRC32C_POLY_LE ? 24962306a36Sopenharmony_ci ~ctx->partial : ctx->partial, out); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int stm32_crc_finup(struct shash_desc *desc, const u8 *data, 25562306a36Sopenharmony_ci unsigned int length, u8 *out) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci return stm32_crc_update(desc, data, length) ?: 25862306a36Sopenharmony_ci stm32_crc_final(desc, out); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int stm32_crc_digest(struct shash_desc *desc, const u8 *data, 26262306a36Sopenharmony_ci unsigned int length, u8 *out) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci return stm32_crc_init(desc) ?: stm32_crc_finup(desc, data, length, out); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic unsigned int refcnt; 26862306a36Sopenharmony_cistatic DEFINE_MUTEX(refcnt_lock); 26962306a36Sopenharmony_cistatic struct shash_alg algs[] = { 27062306a36Sopenharmony_ci /* CRC-32 */ 27162306a36Sopenharmony_ci { 27262306a36Sopenharmony_ci .setkey = stm32_crc_setkey, 27362306a36Sopenharmony_ci .init = stm32_crc_init, 27462306a36Sopenharmony_ci .update = stm32_crc_update, 27562306a36Sopenharmony_ci .final = stm32_crc_final, 27662306a36Sopenharmony_ci .finup = stm32_crc_finup, 27762306a36Sopenharmony_ci .digest = stm32_crc_digest, 27862306a36Sopenharmony_ci .descsize = sizeof(struct stm32_crc_desc_ctx), 27962306a36Sopenharmony_ci .digestsize = CHKSUM_DIGEST_SIZE, 28062306a36Sopenharmony_ci .base = { 28162306a36Sopenharmony_ci .cra_name = "crc32", 28262306a36Sopenharmony_ci .cra_driver_name = "stm32-crc32-crc32", 28362306a36Sopenharmony_ci .cra_priority = 200, 28462306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, 28562306a36Sopenharmony_ci .cra_blocksize = CHKSUM_BLOCK_SIZE, 28662306a36Sopenharmony_ci .cra_alignmask = 3, 28762306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct stm32_crc_ctx), 28862306a36Sopenharmony_ci .cra_module = THIS_MODULE, 28962306a36Sopenharmony_ci .cra_init = stm32_crc32_cra_init, 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci }, 29262306a36Sopenharmony_ci /* CRC-32Castagnoli */ 29362306a36Sopenharmony_ci { 29462306a36Sopenharmony_ci .setkey = stm32_crc_setkey, 29562306a36Sopenharmony_ci .init = stm32_crc_init, 29662306a36Sopenharmony_ci .update = stm32_crc_update, 29762306a36Sopenharmony_ci .final = stm32_crc_final, 29862306a36Sopenharmony_ci .finup = stm32_crc_finup, 29962306a36Sopenharmony_ci .digest = stm32_crc_digest, 30062306a36Sopenharmony_ci .descsize = sizeof(struct stm32_crc_desc_ctx), 30162306a36Sopenharmony_ci .digestsize = CHKSUM_DIGEST_SIZE, 30262306a36Sopenharmony_ci .base = { 30362306a36Sopenharmony_ci .cra_name = "crc32c", 30462306a36Sopenharmony_ci .cra_driver_name = "stm32-crc32-crc32c", 30562306a36Sopenharmony_ci .cra_priority = 200, 30662306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, 30762306a36Sopenharmony_ci .cra_blocksize = CHKSUM_BLOCK_SIZE, 30862306a36Sopenharmony_ci .cra_alignmask = 3, 30962306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct stm32_crc_ctx), 31062306a36Sopenharmony_ci .cra_module = THIS_MODULE, 31162306a36Sopenharmony_ci .cra_init = stm32_crc32c_cra_init, 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci}; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic int stm32_crc_probe(struct platform_device *pdev) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci struct device *dev = &pdev->dev; 31962306a36Sopenharmony_ci struct stm32_crc *crc; 32062306a36Sopenharmony_ci int ret; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci crc = devm_kzalloc(dev, sizeof(*crc), GFP_KERNEL); 32362306a36Sopenharmony_ci if (!crc) 32462306a36Sopenharmony_ci return -ENOMEM; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci crc->dev = dev; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci crc->regs = devm_platform_ioremap_resource(pdev, 0); 32962306a36Sopenharmony_ci if (IS_ERR(crc->regs)) { 33062306a36Sopenharmony_ci dev_err(dev, "Cannot map CRC IO\n"); 33162306a36Sopenharmony_ci return PTR_ERR(crc->regs); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci crc->clk = devm_clk_get(dev, NULL); 33562306a36Sopenharmony_ci if (IS_ERR(crc->clk)) { 33662306a36Sopenharmony_ci dev_err(dev, "Could not get clock\n"); 33762306a36Sopenharmony_ci return PTR_ERR(crc->clk); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci ret = clk_prepare_enable(crc->clk); 34162306a36Sopenharmony_ci if (ret) { 34262306a36Sopenharmony_ci dev_err(crc->dev, "Failed to enable clock\n"); 34362306a36Sopenharmony_ci return ret; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, CRC_AUTOSUSPEND_DELAY); 34762306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci pm_runtime_get_noresume(dev); 35062306a36Sopenharmony_ci pm_runtime_set_active(dev); 35162306a36Sopenharmony_ci pm_runtime_irq_safe(dev); 35262306a36Sopenharmony_ci pm_runtime_enable(dev); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci spin_lock_init(&crc->lock); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci platform_set_drvdata(pdev, crc); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci spin_lock(&crc_list.lock); 35962306a36Sopenharmony_ci list_add(&crc->list, &crc_list.dev_list); 36062306a36Sopenharmony_ci spin_unlock(&crc_list.lock); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci mutex_lock(&refcnt_lock); 36362306a36Sopenharmony_ci if (!refcnt) { 36462306a36Sopenharmony_ci ret = crypto_register_shashes(algs, ARRAY_SIZE(algs)); 36562306a36Sopenharmony_ci if (ret) { 36662306a36Sopenharmony_ci mutex_unlock(&refcnt_lock); 36762306a36Sopenharmony_ci dev_err(dev, "Failed to register\n"); 36862306a36Sopenharmony_ci clk_disable_unprepare(crc->clk); 36962306a36Sopenharmony_ci return ret; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci refcnt++; 37362306a36Sopenharmony_ci mutex_unlock(&refcnt_lock); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci dev_info(dev, "Initialized\n"); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci pm_runtime_put_sync(dev); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int stm32_crc_remove(struct platform_device *pdev) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct stm32_crc *crc = platform_get_drvdata(pdev); 38562306a36Sopenharmony_ci int ret = pm_runtime_get_sync(crc->dev); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (ret < 0) { 38862306a36Sopenharmony_ci pm_runtime_put_noidle(crc->dev); 38962306a36Sopenharmony_ci return ret; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci spin_lock(&crc_list.lock); 39362306a36Sopenharmony_ci list_del(&crc->list); 39462306a36Sopenharmony_ci spin_unlock(&crc_list.lock); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci mutex_lock(&refcnt_lock); 39762306a36Sopenharmony_ci if (!--refcnt) 39862306a36Sopenharmony_ci crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); 39962306a36Sopenharmony_ci mutex_unlock(&refcnt_lock); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci pm_runtime_disable(crc->dev); 40262306a36Sopenharmony_ci pm_runtime_put_noidle(crc->dev); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci clk_disable_unprepare(crc->clk); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return 0; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic int __maybe_unused stm32_crc_suspend(struct device *dev) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct stm32_crc *crc = dev_get_drvdata(dev); 41262306a36Sopenharmony_ci int ret; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci ret = pm_runtime_force_suspend(dev); 41562306a36Sopenharmony_ci if (ret) 41662306a36Sopenharmony_ci return ret; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci clk_unprepare(crc->clk); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return 0; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic int __maybe_unused stm32_crc_resume(struct device *dev) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct stm32_crc *crc = dev_get_drvdata(dev); 42662306a36Sopenharmony_ci int ret; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci ret = clk_prepare(crc->clk); 42962306a36Sopenharmony_ci if (ret) { 43062306a36Sopenharmony_ci dev_err(crc->dev, "Failed to prepare clock\n"); 43162306a36Sopenharmony_ci return ret; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return pm_runtime_force_resume(dev); 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int __maybe_unused stm32_crc_runtime_suspend(struct device *dev) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct stm32_crc *crc = dev_get_drvdata(dev); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci clk_disable(crc->clk); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic int __maybe_unused stm32_crc_runtime_resume(struct device *dev) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct stm32_crc *crc = dev_get_drvdata(dev); 44962306a36Sopenharmony_ci int ret; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci ret = clk_enable(crc->clk); 45262306a36Sopenharmony_ci if (ret) { 45362306a36Sopenharmony_ci dev_err(crc->dev, "Failed to enable clock\n"); 45462306a36Sopenharmony_ci return ret; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci return 0; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic const struct dev_pm_ops stm32_crc_pm_ops = { 46162306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(stm32_crc_suspend, 46262306a36Sopenharmony_ci stm32_crc_resume) 46362306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(stm32_crc_runtime_suspend, 46462306a36Sopenharmony_ci stm32_crc_runtime_resume, NULL) 46562306a36Sopenharmony_ci}; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic const struct of_device_id stm32_dt_ids[] = { 46862306a36Sopenharmony_ci { .compatible = "st,stm32f7-crc", }, 46962306a36Sopenharmony_ci {}, 47062306a36Sopenharmony_ci}; 47162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_dt_ids); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic struct platform_driver stm32_crc_driver = { 47462306a36Sopenharmony_ci .probe = stm32_crc_probe, 47562306a36Sopenharmony_ci .remove = stm32_crc_remove, 47662306a36Sopenharmony_ci .driver = { 47762306a36Sopenharmony_ci .name = DRIVER_NAME, 47862306a36Sopenharmony_ci .pm = &stm32_crc_pm_ops, 47962306a36Sopenharmony_ci .of_match_table = stm32_dt_ids, 48062306a36Sopenharmony_ci }, 48162306a36Sopenharmony_ci}; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cimodule_platform_driver(stm32_crc_driver); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ciMODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>"); 48662306a36Sopenharmony_ciMODULE_DESCRIPTION("STMicrolectronics STM32 CRC32 hardware driver"); 48762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 488