1 // SPDX-License-Identifier: GPL-2.0-only
3 * i.MX9 OCOTP fusebox driver
8 #include <linux/device.h>
10 #include <linux/module.h>
11 #include <linux/nvmem-provider.h>
13 #include <linux/platform_device.h>
14 #include <linux/slab.h>
22 struct ocotp_map_entry
{
23 u32 start
; /* start word */
24 u32 num
; /* num words */
28 struct ocotp_devtype_data
{
34 nvmem_reg_read_t reg_read
;
35 struct ocotp_map_entry entry
[];
38 struct imx_ocotp_priv
{
41 struct nvmem_config config
;
43 const struct ocotp_devtype_data
*data
;
46 static enum fuse_type
imx_ocotp_fuse_type(void *context
, u32 index
)
48 struct imx_ocotp_priv
*priv
= context
;
49 const struct ocotp_devtype_data
*data
= priv
->data
;
53 for (i
= 0; i
< data
->num_entry
; i
++) {
54 start
= data
->entry
[i
].start
;
55 end
= data
->entry
[i
].start
+ data
->entry
[i
].num
;
57 if (index
>= start
&& index
< end
)
58 return data
->entry
[i
].type
;
64 static int imx_ocotp_reg_read(void *context
, unsigned int offset
, void *val
, size_t bytes
)
66 struct imx_ocotp_priv
*priv
= context
;
67 void __iomem
*reg
= priv
->base
+ priv
->data
->reg_off
;
68 u32 count
, index
, num_bytes
;
75 num_bytes
= round_up(bytes
, 4);
76 count
= num_bytes
>> 2;
78 if (count
> ((priv
->data
->size
>> 2) - index
))
79 count
= (priv
->data
->size
>> 2) - index
;
81 p
= kzalloc(num_bytes
, GFP_KERNEL
);
85 mutex_lock(&priv
->lock
);
89 for (i
= index
; i
< (index
+ count
); i
++) {
90 type
= imx_ocotp_fuse_type(context
, i
);
91 if (type
== FUSE_INVALID
|| type
== FUSE_ELE
) {
96 *buf
++ = readl_relaxed(reg
+ (i
<< 2));
99 memcpy(val
, (u8
*)p
, bytes
);
101 mutex_unlock(&priv
->lock
);
108 static int imx_ele_ocotp_probe(struct platform_device
*pdev
)
110 struct device
*dev
= &pdev
->dev
;
111 struct imx_ocotp_priv
*priv
;
112 struct nvmem_device
*nvmem
;
114 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
118 priv
->data
= of_device_get_match_data(dev
);
120 priv
->base
= devm_platform_ioremap_resource(pdev
, 0);
121 if (IS_ERR(priv
->base
))
122 return PTR_ERR(priv
->base
);
124 priv
->config
.dev
= dev
;
125 priv
->config
.name
= "ELE-OCOTP";
126 priv
->config
.id
= NVMEM_DEVID_AUTO
;
127 priv
->config
.owner
= THIS_MODULE
;
128 priv
->config
.size
= priv
->data
->size
;
129 priv
->config
.reg_read
= priv
->data
->reg_read
;
130 priv
->config
.word_size
= 4;
131 priv
->config
.stride
= 1;
132 priv
->config
.priv
= priv
;
133 priv
->config
.read_only
= true;
134 mutex_init(&priv
->lock
);
136 nvmem
= devm_nvmem_register(dev
, &priv
->config
);
138 return PTR_ERR(nvmem
);
143 static const struct ocotp_devtype_data imx93_ocotp_data
= {
145 .reg_read
= imx_ocotp_reg_read
,
151 { 128, 16, FUSE_ELE
},
152 { 182, 1, FUSE_ELE
},
153 { 188, 1, FUSE_ELE
},
154 { 312, 200, FUSE_FSB
}
158 static const struct of_device_id imx_ele_ocotp_dt_ids
[] = {
159 { .compatible
= "fsl,imx93-ocotp", .data
= &imx93_ocotp_data
, },
162 MODULE_DEVICE_TABLE(of
, imx_ele_ocotp_dt_ids
);
164 static struct platform_driver imx_ele_ocotp_driver
= {
166 .name
= "imx_ele_ocotp",
167 .of_match_table
= imx_ele_ocotp_dt_ids
,
169 .probe
= imx_ele_ocotp_probe
,
171 module_platform_driver(imx_ele_ocotp_driver
);
173 MODULE_DESCRIPTION("i.MX OCOTP/ELE driver");
174 MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
175 MODULE_LICENSE("GPL");