xref: /openbmc/linux/drivers/nvmem/sprd-efuse.c (revision 26e2fe4c)
1096030e7SFreeman Liu // SPDX-License-Identifier: GPL-2.0
2096030e7SFreeman Liu // Copyright (C) 2019 Spreadtrum Communications Inc.
3096030e7SFreeman Liu 
4096030e7SFreeman Liu #include <linux/clk.h>
5096030e7SFreeman Liu #include <linux/delay.h>
6096030e7SFreeman Liu #include <linux/hwspinlock.h>
7096030e7SFreeman Liu #include <linux/io.h>
8096030e7SFreeman Liu #include <linux/module.h>
9096030e7SFreeman Liu #include <linux/nvmem-provider.h>
109bf75da0SRob Herring #include <linux/of.h>
11096030e7SFreeman Liu #include <linux/platform_device.h>
12096030e7SFreeman Liu 
13096030e7SFreeman Liu #define SPRD_EFUSE_ENABLE		0x20
14096030e7SFreeman Liu #define SPRD_EFUSE_ERR_FLAG		0x24
15096030e7SFreeman Liu #define SPRD_EFUSE_ERR_CLR		0x28
16096030e7SFreeman Liu #define SPRD_EFUSE_MAGIC_NUM		0x2c
17096030e7SFreeman Liu #define SPRD_EFUSE_FW_CFG		0x50
18096030e7SFreeman Liu #define SPRD_EFUSE_PW_SWT		0x54
19096030e7SFreeman Liu #define SPRD_EFUSE_MEM(val)		(0x1000 + ((val) << 2))
20096030e7SFreeman Liu 
21096030e7SFreeman Liu #define SPRD_EFUSE_VDD_EN		BIT(0)
22096030e7SFreeman Liu #define SPRD_EFUSE_AUTO_CHECK_EN	BIT(1)
23096030e7SFreeman Liu #define SPRD_EFUSE_DOUBLE_EN		BIT(2)
24096030e7SFreeman Liu #define SPRD_EFUSE_MARGIN_RD_EN		BIT(3)
25096030e7SFreeman Liu #define SPRD_EFUSE_LOCK_WR_EN		BIT(4)
26096030e7SFreeman Liu 
27096030e7SFreeman Liu #define SPRD_EFUSE_ERR_CLR_MASK		GENMASK(13, 0)
28096030e7SFreeman Liu 
29096030e7SFreeman Liu #define SPRD_EFUSE_ENK1_ON		BIT(0)
30096030e7SFreeman Liu #define SPRD_EFUSE_ENK2_ON		BIT(1)
31096030e7SFreeman Liu #define SPRD_EFUSE_PROG_EN		BIT(2)
32096030e7SFreeman Liu 
33096030e7SFreeman Liu #define SPRD_EFUSE_MAGIC_NUMBER		0x8810
34096030e7SFreeman Liu 
35096030e7SFreeman Liu /* Block width (bytes) definitions */
36096030e7SFreeman Liu #define SPRD_EFUSE_BLOCK_WIDTH		4
37096030e7SFreeman Liu 
38096030e7SFreeman Liu /*
39096030e7SFreeman Liu  * The Spreadtrum AP efuse contains 2 parts: normal efuse and secure efuse,
40096030e7SFreeman Liu  * and we can only access the normal efuse in kernel. So define the normal
41096030e7SFreeman Liu  * block offset index and normal block numbers.
42096030e7SFreeman Liu  */
43096030e7SFreeman Liu #define SPRD_EFUSE_NORMAL_BLOCK_NUMS	24
44096030e7SFreeman Liu #define SPRD_EFUSE_NORMAL_BLOCK_OFFSET	72
45096030e7SFreeman Liu 
46096030e7SFreeman Liu /* Timeout (ms) for the trylock of hardware spinlocks */
47096030e7SFreeman Liu #define SPRD_EFUSE_HWLOCK_TIMEOUT	5000
48096030e7SFreeman Liu 
49096030e7SFreeman Liu /*
50096030e7SFreeman Liu  * Since different Spreadtrum SoC chip can have different normal block numbers
51096030e7SFreeman Liu  * and offset. And some SoC can support block double feature, which means
52096030e7SFreeman Liu  * when reading or writing data to efuse memory, the controller can save double
53096030e7SFreeman Liu  * data in case one data become incorrect after a long period.
54096030e7SFreeman Liu  *
55096030e7SFreeman Liu  * Thus we should save them in the device data structure.
56096030e7SFreeman Liu  */
57096030e7SFreeman Liu struct sprd_efuse_variant_data {
58096030e7SFreeman Liu 	u32 blk_nums;
59096030e7SFreeman Liu 	u32 blk_offset;
60096030e7SFreeman Liu 	bool blk_double;
61096030e7SFreeman Liu };
62096030e7SFreeman Liu 
63096030e7SFreeman Liu struct sprd_efuse {
64096030e7SFreeman Liu 	struct device *dev;
65096030e7SFreeman Liu 	struct clk *clk;
66096030e7SFreeman Liu 	struct hwspinlock *hwlock;
67096030e7SFreeman Liu 	struct mutex mutex;
68096030e7SFreeman Liu 	void __iomem *base;
69096030e7SFreeman Liu 	const struct sprd_efuse_variant_data *data;
70096030e7SFreeman Liu };
71096030e7SFreeman Liu 
72096030e7SFreeman Liu static const struct sprd_efuse_variant_data ums312_data = {
73096030e7SFreeman Liu 	.blk_nums = SPRD_EFUSE_NORMAL_BLOCK_NUMS,
74096030e7SFreeman Liu 	.blk_offset = SPRD_EFUSE_NORMAL_BLOCK_OFFSET,
75096030e7SFreeman Liu 	.blk_double = false,
76096030e7SFreeman Liu };
77096030e7SFreeman Liu 
78096030e7SFreeman Liu /*
79096030e7SFreeman Liu  * On Spreadtrum platform, we have multi-subsystems will access the unique
80096030e7SFreeman Liu  * efuse controller, so we need one hardware spinlock to synchronize between
81096030e7SFreeman Liu  * the multiple subsystems.
82096030e7SFreeman Liu  */
sprd_efuse_lock(struct sprd_efuse * efuse)83096030e7SFreeman Liu static int sprd_efuse_lock(struct sprd_efuse *efuse)
84096030e7SFreeman Liu {
85096030e7SFreeman Liu 	int ret;
86096030e7SFreeman Liu 
87096030e7SFreeman Liu 	mutex_lock(&efuse->mutex);
88096030e7SFreeman Liu 
89096030e7SFreeman Liu 	ret = hwspin_lock_timeout_raw(efuse->hwlock,
90096030e7SFreeman Liu 				      SPRD_EFUSE_HWLOCK_TIMEOUT);
91096030e7SFreeman Liu 	if (ret) {
92096030e7SFreeman Liu 		dev_err(efuse->dev, "timeout get the hwspinlock\n");
93096030e7SFreeman Liu 		mutex_unlock(&efuse->mutex);
94096030e7SFreeman Liu 		return ret;
95096030e7SFreeman Liu 	}
96096030e7SFreeman Liu 
97096030e7SFreeman Liu 	return 0;
98096030e7SFreeman Liu }
99096030e7SFreeman Liu 
sprd_efuse_unlock(struct sprd_efuse * efuse)100096030e7SFreeman Liu static void sprd_efuse_unlock(struct sprd_efuse *efuse)
101096030e7SFreeman Liu {
102096030e7SFreeman Liu 	hwspin_unlock_raw(efuse->hwlock);
103096030e7SFreeman Liu 	mutex_unlock(&efuse->mutex);
104096030e7SFreeman Liu }
105096030e7SFreeman Liu 
sprd_efuse_set_prog_power(struct sprd_efuse * efuse,bool en)106096030e7SFreeman Liu static void sprd_efuse_set_prog_power(struct sprd_efuse *efuse, bool en)
107096030e7SFreeman Liu {
108096030e7SFreeman Liu 	u32 val = readl(efuse->base + SPRD_EFUSE_PW_SWT);
109096030e7SFreeman Liu 
110096030e7SFreeman Liu 	if (en)
111096030e7SFreeman Liu 		val &= ~SPRD_EFUSE_ENK2_ON;
112096030e7SFreeman Liu 	else
113096030e7SFreeman Liu 		val &= ~SPRD_EFUSE_ENK1_ON;
114096030e7SFreeman Liu 
115096030e7SFreeman Liu 	writel(val, efuse->base + SPRD_EFUSE_PW_SWT);
116096030e7SFreeman Liu 
117096030e7SFreeman Liu 	/* Open or close efuse power need wait 1000us to make power stable. */
118096030e7SFreeman Liu 	usleep_range(1000, 1200);
119096030e7SFreeman Liu 
120096030e7SFreeman Liu 	if (en)
121096030e7SFreeman Liu 		val |= SPRD_EFUSE_ENK1_ON;
122096030e7SFreeman Liu 	else
123096030e7SFreeman Liu 		val |= SPRD_EFUSE_ENK2_ON;
124096030e7SFreeman Liu 
125096030e7SFreeman Liu 	writel(val, efuse->base + SPRD_EFUSE_PW_SWT);
126096030e7SFreeman Liu 
127096030e7SFreeman Liu 	/* Open or close efuse power need wait 1000us to make power stable. */
128096030e7SFreeman Liu 	usleep_range(1000, 1200);
129096030e7SFreeman Liu }
130096030e7SFreeman Liu 
sprd_efuse_set_read_power(struct sprd_efuse * efuse,bool en)131096030e7SFreeman Liu static void sprd_efuse_set_read_power(struct sprd_efuse *efuse, bool en)
132096030e7SFreeman Liu {
133096030e7SFreeman Liu 	u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE);
134096030e7SFreeman Liu 
135096030e7SFreeman Liu 	if (en)
136096030e7SFreeman Liu 		val |= SPRD_EFUSE_VDD_EN;
137096030e7SFreeman Liu 	else
138096030e7SFreeman Liu 		val &= ~SPRD_EFUSE_VDD_EN;
139096030e7SFreeman Liu 
140096030e7SFreeman Liu 	writel(val, efuse->base + SPRD_EFUSE_ENABLE);
141096030e7SFreeman Liu 
142096030e7SFreeman Liu 	/* Open or close efuse power need wait 1000us to make power stable. */
143096030e7SFreeman Liu 	usleep_range(1000, 1200);
144096030e7SFreeman Liu }
145096030e7SFreeman Liu 
sprd_efuse_set_prog_lock(struct sprd_efuse * efuse,bool en)146096030e7SFreeman Liu static void sprd_efuse_set_prog_lock(struct sprd_efuse *efuse, bool en)
147096030e7SFreeman Liu {
148096030e7SFreeman Liu 	u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE);
149096030e7SFreeman Liu 
150096030e7SFreeman Liu 	if (en)
151096030e7SFreeman Liu 		val |= SPRD_EFUSE_LOCK_WR_EN;
152096030e7SFreeman Liu 	else
153096030e7SFreeman Liu 		val &= ~SPRD_EFUSE_LOCK_WR_EN;
154096030e7SFreeman Liu 
155096030e7SFreeman Liu 	writel(val, efuse->base + SPRD_EFUSE_ENABLE);
156096030e7SFreeman Liu }
157096030e7SFreeman Liu 
sprd_efuse_set_auto_check(struct sprd_efuse * efuse,bool en)158096030e7SFreeman Liu static void sprd_efuse_set_auto_check(struct sprd_efuse *efuse, bool en)
159096030e7SFreeman Liu {
160096030e7SFreeman Liu 	u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE);
161096030e7SFreeman Liu 
162096030e7SFreeman Liu 	if (en)
163096030e7SFreeman Liu 		val |= SPRD_EFUSE_AUTO_CHECK_EN;
164096030e7SFreeman Liu 	else
165096030e7SFreeman Liu 		val &= ~SPRD_EFUSE_AUTO_CHECK_EN;
166096030e7SFreeman Liu 
167096030e7SFreeman Liu 	writel(val, efuse->base + SPRD_EFUSE_ENABLE);
168096030e7SFreeman Liu }
169096030e7SFreeman Liu 
sprd_efuse_set_data_double(struct sprd_efuse * efuse,bool en)170096030e7SFreeman Liu static void sprd_efuse_set_data_double(struct sprd_efuse *efuse, bool en)
171096030e7SFreeman Liu {
172096030e7SFreeman Liu 	u32 val = readl(efuse->base + SPRD_EFUSE_ENABLE);
173096030e7SFreeman Liu 
174096030e7SFreeman Liu 	if (en)
175096030e7SFreeman Liu 		val |= SPRD_EFUSE_DOUBLE_EN;
176096030e7SFreeman Liu 	else
177096030e7SFreeman Liu 		val &= ~SPRD_EFUSE_DOUBLE_EN;
178096030e7SFreeman Liu 
179096030e7SFreeman Liu 	writel(val, efuse->base + SPRD_EFUSE_ENABLE);
180096030e7SFreeman Liu }
181096030e7SFreeman Liu 
sprd_efuse_set_prog_en(struct sprd_efuse * efuse,bool en)182096030e7SFreeman Liu static void sprd_efuse_set_prog_en(struct sprd_efuse *efuse, bool en)
183096030e7SFreeman Liu {
184096030e7SFreeman Liu 	u32 val = readl(efuse->base + SPRD_EFUSE_PW_SWT);
185096030e7SFreeman Liu 
186096030e7SFreeman Liu 	if (en)
187096030e7SFreeman Liu 		val |= SPRD_EFUSE_PROG_EN;
188096030e7SFreeman Liu 	else
189096030e7SFreeman Liu 		val &= ~SPRD_EFUSE_PROG_EN;
190096030e7SFreeman Liu 
191096030e7SFreeman Liu 	writel(val, efuse->base + SPRD_EFUSE_PW_SWT);
192096030e7SFreeman Liu }
193096030e7SFreeman Liu 
sprd_efuse_raw_prog(struct sprd_efuse * efuse,u32 blk,bool doub,bool lock,u32 * data)194096030e7SFreeman Liu static int sprd_efuse_raw_prog(struct sprd_efuse *efuse, u32 blk, bool doub,
195096030e7SFreeman Liu 			       bool lock, u32 *data)
196096030e7SFreeman Liu {
197096030e7SFreeman Liu 	u32 status;
198096030e7SFreeman Liu 	int ret = 0;
199096030e7SFreeman Liu 
200096030e7SFreeman Liu 	/*
201096030e7SFreeman Liu 	 * We need set the correct magic number before writing the efuse to
202096030e7SFreeman Liu 	 * allow programming, and block other programming until we clear the
203096030e7SFreeman Liu 	 * magic number.
204096030e7SFreeman Liu 	 */
205096030e7SFreeman Liu 	writel(SPRD_EFUSE_MAGIC_NUMBER,
206096030e7SFreeman Liu 	       efuse->base + SPRD_EFUSE_MAGIC_NUM);
207096030e7SFreeman Liu 
208096030e7SFreeman Liu 	/*
209096030e7SFreeman Liu 	 * Power on the efuse, enable programme and enable double data
210096030e7SFreeman Liu 	 * if asked.
211096030e7SFreeman Liu 	 */
212096030e7SFreeman Liu 	sprd_efuse_set_prog_power(efuse, true);
213096030e7SFreeman Liu 	sprd_efuse_set_prog_en(efuse, true);
214096030e7SFreeman Liu 	sprd_efuse_set_data_double(efuse, doub);
215096030e7SFreeman Liu 
216096030e7SFreeman Liu 	/*
217096030e7SFreeman Liu 	 * Enable the auto-check function to validate if the programming is
218096030e7SFreeman Liu 	 * successful.
219096030e7SFreeman Liu 	 */
2205af25388SFreeman Liu 	if (lock)
221096030e7SFreeman Liu 		sprd_efuse_set_auto_check(efuse, true);
222096030e7SFreeman Liu 
223096030e7SFreeman Liu 	writel(*data, efuse->base + SPRD_EFUSE_MEM(blk));
224096030e7SFreeman Liu 
225096030e7SFreeman Liu 	/* Disable auto-check and data double after programming */
2265af25388SFreeman Liu 	if (lock)
227096030e7SFreeman Liu 		sprd_efuse_set_auto_check(efuse, false);
228096030e7SFreeman Liu 	sprd_efuse_set_data_double(efuse, false);
229096030e7SFreeman Liu 
230096030e7SFreeman Liu 	/*
231096030e7SFreeman Liu 	 * Check the efuse error status, if the programming is successful,
232096030e7SFreeman Liu 	 * we should lock this efuse block to avoid programming again.
233096030e7SFreeman Liu 	 */
234096030e7SFreeman Liu 	status = readl(efuse->base + SPRD_EFUSE_ERR_FLAG);
235096030e7SFreeman Liu 	if (status) {
236096030e7SFreeman Liu 		dev_err(efuse->dev,
23720be064eSChristophe JAILLET 			"write error status %u of block %d\n", status, blk);
238096030e7SFreeman Liu 
239096030e7SFreeman Liu 		writel(SPRD_EFUSE_ERR_CLR_MASK,
240096030e7SFreeman Liu 		       efuse->base + SPRD_EFUSE_ERR_CLR);
241096030e7SFreeman Liu 		ret = -EBUSY;
2425af25388SFreeman Liu 	} else if (lock) {
243096030e7SFreeman Liu 		sprd_efuse_set_prog_lock(efuse, lock);
244c66ebde4SFreeman Liu 		writel(0, efuse->base + SPRD_EFUSE_MEM(blk));
245096030e7SFreeman Liu 		sprd_efuse_set_prog_lock(efuse, false);
246096030e7SFreeman Liu 	}
247096030e7SFreeman Liu 
248096030e7SFreeman Liu 	sprd_efuse_set_prog_power(efuse, false);
249096030e7SFreeman Liu 	writel(0, efuse->base + SPRD_EFUSE_MAGIC_NUM);
250096030e7SFreeman Liu 
251096030e7SFreeman Liu 	return ret;
252096030e7SFreeman Liu }
253096030e7SFreeman Liu 
sprd_efuse_raw_read(struct sprd_efuse * efuse,int blk,u32 * val,bool doub)254096030e7SFreeman Liu static int sprd_efuse_raw_read(struct sprd_efuse *efuse, int blk, u32 *val,
255096030e7SFreeman Liu 			       bool doub)
256096030e7SFreeman Liu {
257096030e7SFreeman Liu 	u32 status;
258096030e7SFreeman Liu 
259096030e7SFreeman Liu 	/*
260096030e7SFreeman Liu 	 * Need power on the efuse before reading data from efuse, and will
261096030e7SFreeman Liu 	 * power off the efuse after reading process.
262096030e7SFreeman Liu 	 */
263096030e7SFreeman Liu 	sprd_efuse_set_read_power(efuse, true);
264096030e7SFreeman Liu 
265096030e7SFreeman Liu 	/* Enable double data if asked */
266096030e7SFreeman Liu 	sprd_efuse_set_data_double(efuse, doub);
267096030e7SFreeman Liu 
268096030e7SFreeman Liu 	/* Start to read data from efuse block */
269096030e7SFreeman Liu 	*val = readl(efuse->base + SPRD_EFUSE_MEM(blk));
270096030e7SFreeman Liu 
271096030e7SFreeman Liu 	/* Disable double data */
272096030e7SFreeman Liu 	sprd_efuse_set_data_double(efuse, false);
273096030e7SFreeman Liu 
274096030e7SFreeman Liu 	/* Power off the efuse */
275096030e7SFreeman Liu 	sprd_efuse_set_read_power(efuse, false);
276096030e7SFreeman Liu 
277096030e7SFreeman Liu 	/*
278096030e7SFreeman Liu 	 * Check the efuse error status and clear them if there are some
279096030e7SFreeman Liu 	 * errors occurred.
280096030e7SFreeman Liu 	 */
281096030e7SFreeman Liu 	status = readl(efuse->base + SPRD_EFUSE_ERR_FLAG);
282096030e7SFreeman Liu 	if (status) {
283096030e7SFreeman Liu 		dev_err(efuse->dev,
284096030e7SFreeman Liu 			"read error status %d of block %d\n", status, blk);
285096030e7SFreeman Liu 
286096030e7SFreeman Liu 		writel(SPRD_EFUSE_ERR_CLR_MASK,
287096030e7SFreeman Liu 		       efuse->base + SPRD_EFUSE_ERR_CLR);
288096030e7SFreeman Liu 		return -EBUSY;
289096030e7SFreeman Liu 	}
290096030e7SFreeman Liu 
291096030e7SFreeman Liu 	return 0;
292096030e7SFreeman Liu }
293096030e7SFreeman Liu 
sprd_efuse_read(void * context,u32 offset,void * val,size_t bytes)294096030e7SFreeman Liu static int sprd_efuse_read(void *context, u32 offset, void *val, size_t bytes)
295096030e7SFreeman Liu {
296096030e7SFreeman Liu 	struct sprd_efuse *efuse = context;
297096030e7SFreeman Liu 	bool blk_double = efuse->data->blk_double;
298096030e7SFreeman Liu 	u32 index = offset / SPRD_EFUSE_BLOCK_WIDTH + efuse->data->blk_offset;
299096030e7SFreeman Liu 	u32 blk_offset = (offset % SPRD_EFUSE_BLOCK_WIDTH) * BITS_PER_BYTE;
300096030e7SFreeman Liu 	u32 data;
301096030e7SFreeman Liu 	int ret;
302096030e7SFreeman Liu 
303096030e7SFreeman Liu 	ret = sprd_efuse_lock(efuse);
304096030e7SFreeman Liu 	if (ret)
305096030e7SFreeman Liu 		return ret;
306096030e7SFreeman Liu 
307096030e7SFreeman Liu 	ret = clk_prepare_enable(efuse->clk);
308096030e7SFreeman Liu 	if (ret)
309096030e7SFreeman Liu 		goto unlock;
310096030e7SFreeman Liu 
311096030e7SFreeman Liu 	ret = sprd_efuse_raw_read(efuse, index, &data, blk_double);
312096030e7SFreeman Liu 	if (!ret) {
313096030e7SFreeman Liu 		data >>= blk_offset;
314096030e7SFreeman Liu 		memcpy(val, &data, bytes);
315096030e7SFreeman Liu 	}
316096030e7SFreeman Liu 
317096030e7SFreeman Liu 	clk_disable_unprepare(efuse->clk);
318096030e7SFreeman Liu 
319096030e7SFreeman Liu unlock:
320096030e7SFreeman Liu 	sprd_efuse_unlock(efuse);
321096030e7SFreeman Liu 	return ret;
322096030e7SFreeman Liu }
323096030e7SFreeman Liu 
sprd_efuse_write(void * context,u32 offset,void * val,size_t bytes)324096030e7SFreeman Liu static int sprd_efuse_write(void *context, u32 offset, void *val, size_t bytes)
325096030e7SFreeman Liu {
326096030e7SFreeman Liu 	struct sprd_efuse *efuse = context;
3274bd5a15dSBaolin Wang 	bool blk_double = efuse->data->blk_double;
3285af25388SFreeman Liu 	bool lock;
329096030e7SFreeman Liu 	int ret;
330096030e7SFreeman Liu 
331096030e7SFreeman Liu 	ret = sprd_efuse_lock(efuse);
332096030e7SFreeman Liu 	if (ret)
333096030e7SFreeman Liu 		return ret;
334096030e7SFreeman Liu 
335096030e7SFreeman Liu 	ret = clk_prepare_enable(efuse->clk);
336096030e7SFreeman Liu 	if (ret)
337096030e7SFreeman Liu 		goto unlock;
338096030e7SFreeman Liu 
3395af25388SFreeman Liu 	/*
3405af25388SFreeman Liu 	 * If the writing bytes are equal with the block width, which means the
3415af25388SFreeman Liu 	 * whole block will be programmed. For this case, we should not allow
3425af25388SFreeman Liu 	 * this block to be programmed again by locking this block.
3435af25388SFreeman Liu 	 *
3445af25388SFreeman Liu 	 * If the block was programmed partially, we should allow this block to
3455af25388SFreeman Liu 	 * be programmed again.
3465af25388SFreeman Liu 	 */
3475af25388SFreeman Liu 	if (bytes < SPRD_EFUSE_BLOCK_WIDTH)
3485af25388SFreeman Liu 		lock = false;
3495af25388SFreeman Liu 	else
3505af25388SFreeman Liu 		lock = true;
3515af25388SFreeman Liu 
3524bd5a15dSBaolin Wang 	ret = sprd_efuse_raw_prog(efuse, offset, blk_double, lock, val);
353096030e7SFreeman Liu 
354096030e7SFreeman Liu 	clk_disable_unprepare(efuse->clk);
355096030e7SFreeman Liu 
356096030e7SFreeman Liu unlock:
357096030e7SFreeman Liu 	sprd_efuse_unlock(efuse);
358096030e7SFreeman Liu 	return ret;
359096030e7SFreeman Liu }
360096030e7SFreeman Liu 
sprd_efuse_probe(struct platform_device * pdev)361096030e7SFreeman Liu static int sprd_efuse_probe(struct platform_device *pdev)
362096030e7SFreeman Liu {
363096030e7SFreeman Liu 	struct device_node *np = pdev->dev.of_node;
364096030e7SFreeman Liu 	struct nvmem_device *nvmem;
365096030e7SFreeman Liu 	struct nvmem_config econfig = { };
366096030e7SFreeman Liu 	struct sprd_efuse *efuse;
367096030e7SFreeman Liu 	const struct sprd_efuse_variant_data *pdata;
368096030e7SFreeman Liu 	int ret;
369096030e7SFreeman Liu 
370096030e7SFreeman Liu 	pdata = of_device_get_match_data(&pdev->dev);
371096030e7SFreeman Liu 	if (!pdata) {
372096030e7SFreeman Liu 		dev_err(&pdev->dev, "No matching driver data found\n");
373096030e7SFreeman Liu 		return -EINVAL;
374096030e7SFreeman Liu 	}
375096030e7SFreeman Liu 
376096030e7SFreeman Liu 	efuse = devm_kzalloc(&pdev->dev, sizeof(*efuse), GFP_KERNEL);
377096030e7SFreeman Liu 	if (!efuse)
378096030e7SFreeman Liu 		return -ENOMEM;
379096030e7SFreeman Liu 
380096030e7SFreeman Liu 	efuse->base = devm_platform_ioremap_resource(pdev, 0);
381bcd14bb7STiezhu Yang 	if (IS_ERR(efuse->base))
382bcd14bb7STiezhu Yang 		return PTR_ERR(efuse->base);
383096030e7SFreeman Liu 
384096030e7SFreeman Liu 	ret = of_hwspin_lock_get_id(np, 0);
385096030e7SFreeman Liu 	if (ret < 0) {
386096030e7SFreeman Liu 		dev_err(&pdev->dev, "failed to get hwlock id\n");
387096030e7SFreeman Liu 		return ret;
388096030e7SFreeman Liu 	}
389096030e7SFreeman Liu 
390096030e7SFreeman Liu 	efuse->hwlock = devm_hwspin_lock_request_specific(&pdev->dev, ret);
391096030e7SFreeman Liu 	if (!efuse->hwlock) {
392096030e7SFreeman Liu 		dev_err(&pdev->dev, "failed to request hwlock\n");
393096030e7SFreeman Liu 		return -ENXIO;
394096030e7SFreeman Liu 	}
395096030e7SFreeman Liu 
396096030e7SFreeman Liu 	efuse->clk = devm_clk_get(&pdev->dev, "enable");
397096030e7SFreeman Liu 	if (IS_ERR(efuse->clk)) {
398096030e7SFreeman Liu 		dev_err(&pdev->dev, "failed to get enable clock\n");
399096030e7SFreeman Liu 		return PTR_ERR(efuse->clk);
400096030e7SFreeman Liu 	}
401096030e7SFreeman Liu 
402096030e7SFreeman Liu 	mutex_init(&efuse->mutex);
403096030e7SFreeman Liu 	efuse->dev = &pdev->dev;
404096030e7SFreeman Liu 	efuse->data = pdata;
405096030e7SFreeman Liu 
406096030e7SFreeman Liu 	econfig.stride = 1;
407096030e7SFreeman Liu 	econfig.word_size = 1;
408096030e7SFreeman Liu 	econfig.read_only = false;
409096030e7SFreeman Liu 	econfig.name = "sprd-efuse";
410096030e7SFreeman Liu 	econfig.size = efuse->data->blk_nums * SPRD_EFUSE_BLOCK_WIDTH;
41126e2fe4cSRafał Miłecki 	econfig.add_legacy_fixed_of_cells = true;
412096030e7SFreeman Liu 	econfig.reg_read = sprd_efuse_read;
413096030e7SFreeman Liu 	econfig.reg_write = sprd_efuse_write;
414096030e7SFreeman Liu 	econfig.priv = efuse;
415096030e7SFreeman Liu 	econfig.dev = &pdev->dev;
416096030e7SFreeman Liu 	nvmem = devm_nvmem_register(&pdev->dev, &econfig);
417096030e7SFreeman Liu 	if (IS_ERR(nvmem)) {
418096030e7SFreeman Liu 		dev_err(&pdev->dev, "failed to register nvmem\n");
419096030e7SFreeman Liu 		return PTR_ERR(nvmem);
420096030e7SFreeman Liu 	}
421096030e7SFreeman Liu 
422096030e7SFreeman Liu 	return 0;
423096030e7SFreeman Liu }
424096030e7SFreeman Liu 
425096030e7SFreeman Liu static const struct of_device_id sprd_efuse_of_match[] = {
426096030e7SFreeman Liu 	{ .compatible = "sprd,ums312-efuse", .data = &ums312_data },
427096030e7SFreeman Liu 	{ }
428096030e7SFreeman Liu };
429096030e7SFreeman Liu 
430096030e7SFreeman Liu static struct platform_driver sprd_efuse_driver = {
431096030e7SFreeman Liu 	.probe = sprd_efuse_probe,
432096030e7SFreeman Liu 	.driver = {
433096030e7SFreeman Liu 		.name = "sprd-efuse",
434096030e7SFreeman Liu 		.of_match_table = sprd_efuse_of_match,
435096030e7SFreeman Liu 	},
436096030e7SFreeman Liu };
437096030e7SFreeman Liu 
438096030e7SFreeman Liu module_platform_driver(sprd_efuse_driver);
439096030e7SFreeman Liu 
440096030e7SFreeman Liu MODULE_AUTHOR("Freeman Liu <freeman.liu@spreadtrum.com>");
441096030e7SFreeman Liu MODULE_DESCRIPTION("Spreadtrum AP efuse driver");
442096030e7SFreeman Liu MODULE_LICENSE("GPL v2");
443