162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (C) 2019 Spreadtrum Communications Inc. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/clk.h> 562306a36Sopenharmony_ci#include <linux/delay.h> 662306a36Sopenharmony_ci#include <linux/hwspinlock.h> 762306a36Sopenharmony_ci#include <linux/io.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/nvmem-provider.h> 1062306a36Sopenharmony_ci#include <linux/of.h> 1162306a36Sopenharmony_ci#include <linux/platform_device.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define SPRD_EFUSE_ENABLE 0x20 1462306a36Sopenharmony_ci#define SPRD_EFUSE_ERR_FLAG 0x24 1562306a36Sopenharmony_ci#define SPRD_EFUSE_ERR_CLR 0x28 1662306a36Sopenharmony_ci#define SPRD_EFUSE_MAGIC_NUM 0x2c 1762306a36Sopenharmony_ci#define SPRD_EFUSE_FW_CFG 0x50 1862306a36Sopenharmony_ci#define SPRD_EFUSE_PW_SWT 0x54 1962306a36Sopenharmony_ci#define SPRD_EFUSE_MEM(val) (0x1000 + ((val) << 2)) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define SPRD_EFUSE_VDD_EN BIT(0) 2262306a36Sopenharmony_ci#define SPRD_EFUSE_AUTO_CHECK_EN BIT(1) 2362306a36Sopenharmony_ci#define SPRD_EFUSE_DOUBLE_EN BIT(2) 2462306a36Sopenharmony_ci#define SPRD_EFUSE_MARGIN_RD_EN BIT(3) 2562306a36Sopenharmony_ci#define SPRD_EFUSE_LOCK_WR_EN BIT(4) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define SPRD_EFUSE_ERR_CLR_MASK GENMASK(13, 0) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define SPRD_EFUSE_ENK1_ON BIT(0) 3062306a36Sopenharmony_ci#define SPRD_EFUSE_ENK2_ON BIT(1) 3162306a36Sopenharmony_ci#define SPRD_EFUSE_PROG_EN BIT(2) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define SPRD_EFUSE_MAGIC_NUMBER 0x8810 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* Block width (bytes) definitions */ 3662306a36Sopenharmony_ci#define SPRD_EFUSE_BLOCK_WIDTH 4 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * The Spreadtrum AP efuse contains 2 parts: normal efuse and secure efuse, 4062306a36Sopenharmony_ci * and we can only access the normal efuse in kernel. So define the normal 4162306a36Sopenharmony_ci * block offset index and normal block numbers. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci#define SPRD_EFUSE_NORMAL_BLOCK_NUMS 24 4462306a36Sopenharmony_ci#define SPRD_EFUSE_NORMAL_BLOCK_OFFSET 72 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* Timeout (ms) for the trylock of hardware spinlocks */ 4762306a36Sopenharmony_ci#define SPRD_EFUSE_HWLOCK_TIMEOUT 5000 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* 5062306a36Sopenharmony_ci * Since different Spreadtrum SoC chip can have different normal block numbers 5162306a36Sopenharmony_ci * and offset. And some SoC can support block double feature, which means 5262306a36Sopenharmony_ci * when reading or writing data to efuse memory, the controller can save double 5362306a36Sopenharmony_ci * data in case one data become incorrect after a long period. 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * Thus we should save them in the device data structure. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_cistruct sprd_efuse_variant_data { 5862306a36Sopenharmony_ci u32 blk_nums; 5962306a36Sopenharmony_ci u32 blk_offset; 6062306a36Sopenharmony_ci bool blk_double; 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct sprd_efuse { 6462306a36Sopenharmony_ci struct device *dev; 6562306a36Sopenharmony_ci struct clk *clk; 6662306a36Sopenharmony_ci struct hwspinlock *hwlock; 6762306a36Sopenharmony_ci struct mutex mutex; 6862306a36Sopenharmony_ci void __iomem *base; 6962306a36Sopenharmony_ci const struct sprd_efuse_variant_data *data; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic const struct sprd_efuse_variant_data ums312_data = { 7362306a36Sopenharmony_ci .blk_nums = SPRD_EFUSE_NORMAL_BLOCK_NUMS, 7462306a36Sopenharmony_ci .blk_offset = SPRD_EFUSE_NORMAL_BLOCK_OFFSET, 7562306a36Sopenharmony_ci .blk_double = false, 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* 7962306a36Sopenharmony_ci * On Spreadtrum platform, we have multi-subsystems will access the unique 8062306a36Sopenharmony_ci * efuse controller, so we need one hardware spinlock to synchronize between 8162306a36Sopenharmony_ci * the multiple subsystems. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_cistatic int sprd_efuse_lock(struct sprd_efuse *efuse) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci int ret; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci mutex_lock(&efuse->mutex); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ret = hwspin_lock_timeout_raw(efuse->hwlock, 9062306a36Sopenharmony_ci SPRD_EFUSE_HWLOCK_TIMEOUT); 9162306a36Sopenharmony_ci if (ret) { 9262306a36Sopenharmony_ci dev_err(efuse->dev, "timeout get the hwspinlock\n"); 9362306a36Sopenharmony_ci mutex_unlock(&efuse->mutex); 9462306a36Sopenharmony_ci return ret; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic void sprd_efuse_unlock(struct sprd_efuse *efuse) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci hwspin_unlock_raw(efuse->hwlock); 10362306a36Sopenharmony_ci mutex_unlock(&efuse->mutex); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void sprd_efuse_set_prog_power(struct sprd_efuse *efuse, bool en) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci u32 val = readl(efuse->base + SPRD_EFUSE_PW_SWT); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (en) 11162306a36Sopenharmony_ci val &= ~SPRD_EFUSE_ENK2_ON; 11262306a36Sopenharmony_ci else 11362306a36Sopenharmony_ci val &= ~SPRD_EFUSE_ENK1_ON; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci writel(val, efuse->base + SPRD_EFUSE_PW_SWT); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* Open or close efuse power need wait 1000us to make power stable. */ 11862306a36Sopenharmony_ci usleep_range(1000, 1200); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (en) 12162306a36Sopenharmony_ci val |= SPRD_EFUSE_ENK1_ON; 12262306a36Sopenharmony_ci else 12362306a36Sopenharmony_ci val |= SPRD_EFUSE_ENK2_ON; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci writel(val, efuse->base + SPRD_EFUSE_PW_SWT); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* Open or close efuse power need wait 1000us to make power stable. */ 12862306a36Sopenharmony_ci usleep_range(1000, 1200); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic void sprd_efuse_set_read_power(struct sprd_efuse *efuse, bool en) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (en) 13662306a36Sopenharmony_ci val |= SPRD_EFUSE_VDD_EN; 13762306a36Sopenharmony_ci else 13862306a36Sopenharmony_ci val &= ~SPRD_EFUSE_VDD_EN; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci writel(val, efuse->base + SPRD_EFUSE_ENABLE); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Open or close efuse power need wait 1000us to make power stable. */ 14362306a36Sopenharmony_ci usleep_range(1000, 1200); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic void sprd_efuse_set_prog_lock(struct sprd_efuse *efuse, bool en) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (en) 15162306a36Sopenharmony_ci val |= SPRD_EFUSE_LOCK_WR_EN; 15262306a36Sopenharmony_ci else 15362306a36Sopenharmony_ci val &= ~SPRD_EFUSE_LOCK_WR_EN; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci writel(val, efuse->base + SPRD_EFUSE_ENABLE); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void sprd_efuse_set_auto_check(struct sprd_efuse *efuse, bool en) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (en) 16362306a36Sopenharmony_ci val |= SPRD_EFUSE_AUTO_CHECK_EN; 16462306a36Sopenharmony_ci else 16562306a36Sopenharmony_ci val &= ~SPRD_EFUSE_AUTO_CHECK_EN; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci writel(val, efuse->base + SPRD_EFUSE_ENABLE); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic void sprd_efuse_set_data_double(struct sprd_efuse *efuse, bool en) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (en) 17562306a36Sopenharmony_ci val |= SPRD_EFUSE_DOUBLE_EN; 17662306a36Sopenharmony_ci else 17762306a36Sopenharmony_ci val &= ~SPRD_EFUSE_DOUBLE_EN; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci writel(val, efuse->base + SPRD_EFUSE_ENABLE); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic void sprd_efuse_set_prog_en(struct sprd_efuse *efuse, bool en) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci u32 val = readl(efuse->base + SPRD_EFUSE_PW_SWT); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (en) 18762306a36Sopenharmony_ci val |= SPRD_EFUSE_PROG_EN; 18862306a36Sopenharmony_ci else 18962306a36Sopenharmony_ci val &= ~SPRD_EFUSE_PROG_EN; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci writel(val, efuse->base + SPRD_EFUSE_PW_SWT); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int sprd_efuse_raw_prog(struct sprd_efuse *efuse, u32 blk, bool doub, 19562306a36Sopenharmony_ci bool lock, u32 *data) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci u32 status; 19862306a36Sopenharmony_ci int ret = 0; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* 20162306a36Sopenharmony_ci * We need set the correct magic number before writing the efuse to 20262306a36Sopenharmony_ci * allow programming, and block other programming until we clear the 20362306a36Sopenharmony_ci * magic number. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci writel(SPRD_EFUSE_MAGIC_NUMBER, 20662306a36Sopenharmony_ci efuse->base + SPRD_EFUSE_MAGIC_NUM); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* 20962306a36Sopenharmony_ci * Power on the efuse, enable programme and enable double data 21062306a36Sopenharmony_ci * if asked. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci sprd_efuse_set_prog_power(efuse, true); 21362306a36Sopenharmony_ci sprd_efuse_set_prog_en(efuse, true); 21462306a36Sopenharmony_ci sprd_efuse_set_data_double(efuse, doub); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* 21762306a36Sopenharmony_ci * Enable the auto-check function to validate if the programming is 21862306a36Sopenharmony_ci * successful. 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ci if (lock) 22162306a36Sopenharmony_ci sprd_efuse_set_auto_check(efuse, true); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci writel(*data, efuse->base + SPRD_EFUSE_MEM(blk)); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* Disable auto-check and data double after programming */ 22662306a36Sopenharmony_ci if (lock) 22762306a36Sopenharmony_ci sprd_efuse_set_auto_check(efuse, false); 22862306a36Sopenharmony_ci sprd_efuse_set_data_double(efuse, false); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* 23162306a36Sopenharmony_ci * Check the efuse error status, if the programming is successful, 23262306a36Sopenharmony_ci * we should lock this efuse block to avoid programming again. 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_ci status = readl(efuse->base + SPRD_EFUSE_ERR_FLAG); 23562306a36Sopenharmony_ci if (status) { 23662306a36Sopenharmony_ci dev_err(efuse->dev, 23762306a36Sopenharmony_ci "write error status %u of block %d\n", status, blk); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci writel(SPRD_EFUSE_ERR_CLR_MASK, 24062306a36Sopenharmony_ci efuse->base + SPRD_EFUSE_ERR_CLR); 24162306a36Sopenharmony_ci ret = -EBUSY; 24262306a36Sopenharmony_ci } else if (lock) { 24362306a36Sopenharmony_ci sprd_efuse_set_prog_lock(efuse, lock); 24462306a36Sopenharmony_ci writel(0, efuse->base + SPRD_EFUSE_MEM(blk)); 24562306a36Sopenharmony_ci sprd_efuse_set_prog_lock(efuse, false); 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci sprd_efuse_set_prog_power(efuse, false); 24962306a36Sopenharmony_ci writel(0, efuse->base + SPRD_EFUSE_MAGIC_NUM); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return ret; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int sprd_efuse_raw_read(struct sprd_efuse *efuse, int blk, u32 *val, 25562306a36Sopenharmony_ci bool doub) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci u32 status; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* 26062306a36Sopenharmony_ci * Need power on the efuse before reading data from efuse, and will 26162306a36Sopenharmony_ci * power off the efuse after reading process. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci sprd_efuse_set_read_power(efuse, true); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* Enable double data if asked */ 26662306a36Sopenharmony_ci sprd_efuse_set_data_double(efuse, doub); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* Start to read data from efuse block */ 26962306a36Sopenharmony_ci *val = readl(efuse->base + SPRD_EFUSE_MEM(blk)); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Disable double data */ 27262306a36Sopenharmony_ci sprd_efuse_set_data_double(efuse, false); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Power off the efuse */ 27562306a36Sopenharmony_ci sprd_efuse_set_read_power(efuse, false); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* 27862306a36Sopenharmony_ci * Check the efuse error status and clear them if there are some 27962306a36Sopenharmony_ci * errors occurred. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_ci status = readl(efuse->base + SPRD_EFUSE_ERR_FLAG); 28262306a36Sopenharmony_ci if (status) { 28362306a36Sopenharmony_ci dev_err(efuse->dev, 28462306a36Sopenharmony_ci "read error status %d of block %d\n", status, blk); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci writel(SPRD_EFUSE_ERR_CLR_MASK, 28762306a36Sopenharmony_ci efuse->base + SPRD_EFUSE_ERR_CLR); 28862306a36Sopenharmony_ci return -EBUSY; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic int sprd_efuse_read(void *context, u32 offset, void *val, size_t bytes) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct sprd_efuse *efuse = context; 29762306a36Sopenharmony_ci bool blk_double = efuse->data->blk_double; 29862306a36Sopenharmony_ci u32 index = offset / SPRD_EFUSE_BLOCK_WIDTH + efuse->data->blk_offset; 29962306a36Sopenharmony_ci u32 blk_offset = (offset % SPRD_EFUSE_BLOCK_WIDTH) * BITS_PER_BYTE; 30062306a36Sopenharmony_ci u32 data; 30162306a36Sopenharmony_ci int ret; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ret = sprd_efuse_lock(efuse); 30462306a36Sopenharmony_ci if (ret) 30562306a36Sopenharmony_ci return ret; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci ret = clk_prepare_enable(efuse->clk); 30862306a36Sopenharmony_ci if (ret) 30962306a36Sopenharmony_ci goto unlock; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci ret = sprd_efuse_raw_read(efuse, index, &data, blk_double); 31262306a36Sopenharmony_ci if (!ret) { 31362306a36Sopenharmony_ci data >>= blk_offset; 31462306a36Sopenharmony_ci memcpy(val, &data, bytes); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci clk_disable_unprepare(efuse->clk); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ciunlock: 32062306a36Sopenharmony_ci sprd_efuse_unlock(efuse); 32162306a36Sopenharmony_ci return ret; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int sprd_efuse_write(void *context, u32 offset, void *val, size_t bytes) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct sprd_efuse *efuse = context; 32762306a36Sopenharmony_ci bool blk_double = efuse->data->blk_double; 32862306a36Sopenharmony_ci bool lock; 32962306a36Sopenharmony_ci int ret; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci ret = sprd_efuse_lock(efuse); 33262306a36Sopenharmony_ci if (ret) 33362306a36Sopenharmony_ci return ret; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci ret = clk_prepare_enable(efuse->clk); 33662306a36Sopenharmony_ci if (ret) 33762306a36Sopenharmony_ci goto unlock; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* 34062306a36Sopenharmony_ci * If the writing bytes are equal with the block width, which means the 34162306a36Sopenharmony_ci * whole block will be programmed. For this case, we should not allow 34262306a36Sopenharmony_ci * this block to be programmed again by locking this block. 34362306a36Sopenharmony_ci * 34462306a36Sopenharmony_ci * If the block was programmed partially, we should allow this block to 34562306a36Sopenharmony_ci * be programmed again. 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci if (bytes < SPRD_EFUSE_BLOCK_WIDTH) 34862306a36Sopenharmony_ci lock = false; 34962306a36Sopenharmony_ci else 35062306a36Sopenharmony_ci lock = true; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci ret = sprd_efuse_raw_prog(efuse, offset, blk_double, lock, val); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci clk_disable_unprepare(efuse->clk); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ciunlock: 35762306a36Sopenharmony_ci sprd_efuse_unlock(efuse); 35862306a36Sopenharmony_ci return ret; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int sprd_efuse_probe(struct platform_device *pdev) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 36462306a36Sopenharmony_ci struct nvmem_device *nvmem; 36562306a36Sopenharmony_ci struct nvmem_config econfig = { }; 36662306a36Sopenharmony_ci struct sprd_efuse *efuse; 36762306a36Sopenharmony_ci const struct sprd_efuse_variant_data *pdata; 36862306a36Sopenharmony_ci int ret; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci pdata = of_device_get_match_data(&pdev->dev); 37162306a36Sopenharmony_ci if (!pdata) { 37262306a36Sopenharmony_ci dev_err(&pdev->dev, "No matching driver data found\n"); 37362306a36Sopenharmony_ci return -EINVAL; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci efuse = devm_kzalloc(&pdev->dev, sizeof(*efuse), GFP_KERNEL); 37762306a36Sopenharmony_ci if (!efuse) 37862306a36Sopenharmony_ci return -ENOMEM; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci efuse->base = devm_platform_ioremap_resource(pdev, 0); 38162306a36Sopenharmony_ci if (IS_ERR(efuse->base)) 38262306a36Sopenharmony_ci return PTR_ERR(efuse->base); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci ret = of_hwspin_lock_get_id(np, 0); 38562306a36Sopenharmony_ci if (ret < 0) { 38662306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get hwlock id\n"); 38762306a36Sopenharmony_ci return ret; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci efuse->hwlock = devm_hwspin_lock_request_specific(&pdev->dev, ret); 39162306a36Sopenharmony_ci if (!efuse->hwlock) { 39262306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to request hwlock\n"); 39362306a36Sopenharmony_ci return -ENXIO; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci efuse->clk = devm_clk_get(&pdev->dev, "enable"); 39762306a36Sopenharmony_ci if (IS_ERR(efuse->clk)) { 39862306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get enable clock\n"); 39962306a36Sopenharmony_ci return PTR_ERR(efuse->clk); 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci mutex_init(&efuse->mutex); 40362306a36Sopenharmony_ci efuse->dev = &pdev->dev; 40462306a36Sopenharmony_ci efuse->data = pdata; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci econfig.stride = 1; 40762306a36Sopenharmony_ci econfig.word_size = 1; 40862306a36Sopenharmony_ci econfig.read_only = false; 40962306a36Sopenharmony_ci econfig.name = "sprd-efuse"; 41062306a36Sopenharmony_ci econfig.size = efuse->data->blk_nums * SPRD_EFUSE_BLOCK_WIDTH; 41162306a36Sopenharmony_ci econfig.reg_read = sprd_efuse_read; 41262306a36Sopenharmony_ci econfig.reg_write = sprd_efuse_write; 41362306a36Sopenharmony_ci econfig.priv = efuse; 41462306a36Sopenharmony_ci econfig.dev = &pdev->dev; 41562306a36Sopenharmony_ci nvmem = devm_nvmem_register(&pdev->dev, &econfig); 41662306a36Sopenharmony_ci if (IS_ERR(nvmem)) { 41762306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register nvmem\n"); 41862306a36Sopenharmony_ci return PTR_ERR(nvmem); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic const struct of_device_id sprd_efuse_of_match[] = { 42562306a36Sopenharmony_ci { .compatible = "sprd,ums312-efuse", .data = &ums312_data }, 42662306a36Sopenharmony_ci { } 42762306a36Sopenharmony_ci}; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic struct platform_driver sprd_efuse_driver = { 43062306a36Sopenharmony_ci .probe = sprd_efuse_probe, 43162306a36Sopenharmony_ci .driver = { 43262306a36Sopenharmony_ci .name = "sprd-efuse", 43362306a36Sopenharmony_ci .of_match_table = sprd_efuse_of_match, 43462306a36Sopenharmony_ci }, 43562306a36Sopenharmony_ci}; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cimodule_platform_driver(sprd_efuse_driver); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ciMODULE_AUTHOR("Freeman Liu <freeman.liu@spreadtrum.com>"); 44062306a36Sopenharmony_ciMODULE_DESCRIPTION("Spreadtrum AP efuse driver"); 44162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 442