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