2 * i.MX6 OCOTP fusebox driver
4 * Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de>
6 * Based on the barebox ocotp driver,
7 * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>,
8 * Orex Computed Radiography
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * http://www.opensource.org/licenses/gpl-license.html
15 * http://www.gnu.org/copyleft/gpl.html
18 #include <linux/device.h>
20 #include <linux/module.h>
21 #include <linux/nvmem-provider.h>
23 #include <linux/of_device.h>
24 #include <linux/platform_device.h>
25 #include <linux/regmap.h>
26 #include <linux/slab.h>
34 static int imx_ocotp_read(void *context
, const void *reg
, size_t reg_size
,
35 void *val
, size_t val_size
)
37 struct ocotp_priv
*priv
= context
;
38 unsigned int offset
= *(u32
*)reg
;
44 count
= val_size
>> 2;
46 if (count
> (priv
->nregs
- index
))
47 count
= priv
->nregs
- index
;
49 for (i
= index
; i
< (index
+ count
); i
++) {
50 *(u32
*)val
= readl(priv
->base
+ 0x400 + i
* 0x10);
54 return (i
- index
) * 4;
57 static int imx_ocotp_write(void *context
, const void *data
, size_t count
)
63 static struct regmap_bus imx_ocotp_bus
= {
64 .read
= imx_ocotp_read
,
65 .write
= imx_ocotp_write
,
66 .reg_format_endian_default
= REGMAP_ENDIAN_NATIVE
,
67 .val_format_endian_default
= REGMAP_ENDIAN_NATIVE
,
70 static bool imx_ocotp_writeable_reg(struct device
*dev
, unsigned int reg
)
75 static struct regmap_config imx_ocotp_regmap_config
= {
79 .writeable_reg
= imx_ocotp_writeable_reg
,
83 static struct nvmem_config imx_ocotp_nvmem_config
= {
89 static const struct of_device_id imx_ocotp_dt_ids
[] = {
90 { .compatible
= "fsl,imx6q-ocotp", (void *)128 },
91 { .compatible
= "fsl,imx6sl-ocotp", (void *)32 },
92 { .compatible
= "fsl,imx6sx-ocotp", (void *)128 },
95 MODULE_DEVICE_TABLE(of
, imx_ocotp_dt_ids
);
97 static int imx_ocotp_probe(struct platform_device
*pdev
)
99 const struct of_device_id
*of_id
;
100 struct device
*dev
= &pdev
->dev
;
101 struct resource
*res
;
102 struct regmap
*regmap
;
103 struct ocotp_priv
*priv
;
104 struct nvmem_device
*nvmem
;
106 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
110 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
111 priv
->base
= devm_ioremap_resource(dev
, res
);
112 if (IS_ERR(priv
->base
))
113 return PTR_ERR(priv
->base
);
115 of_id
= of_match_device(imx_ocotp_dt_ids
, dev
);
116 priv
->nregs
= (unsigned int)of_id
->data
;
117 imx_ocotp_regmap_config
.max_register
= 4 * priv
->nregs
- 4;
119 regmap
= devm_regmap_init(dev
, &imx_ocotp_bus
, priv
,
120 &imx_ocotp_regmap_config
);
121 if (IS_ERR(regmap
)) {
122 dev_err(dev
, "regmap init failed\n");
123 return PTR_ERR(regmap
);
125 imx_ocotp_nvmem_config
.dev
= dev
;
126 nvmem
= nvmem_register(&imx_ocotp_nvmem_config
);
128 return PTR_ERR(nvmem
);
130 platform_set_drvdata(pdev
, nvmem
);
135 static int imx_ocotp_remove(struct platform_device
*pdev
)
137 struct nvmem_device
*nvmem
= platform_get_drvdata(pdev
);
139 return nvmem_unregister(nvmem
);
142 static struct platform_driver imx_ocotp_driver
= {
143 .probe
= imx_ocotp_probe
,
144 .remove
= imx_ocotp_remove
,
147 .of_match_table
= imx_ocotp_dt_ids
,
150 module_platform_driver(imx_ocotp_driver
);
152 MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
153 MODULE_DESCRIPTION("i.MX6 OCOTP fuse box driver");
154 MODULE_LICENSE("GPL v2");