2 * Freescale MXS On-Chip OTP driver
4 * Copyright (C) 2015 Stefan Wahren <stefan.wahren@i2se.com>
6 * Based on the driver from Huang Shijie and Christoph G. Baumann
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
19 #include <linux/clk.h>
20 #include <linux/delay.h>
21 #include <linux/device.h>
22 #include <linux/err.h>
24 #include <linux/module.h>
25 #include <linux/nvmem-provider.h>
26 #include <linux/of_device.h>
27 #include <linux/platform_device.h>
28 #include <linux/regmap.h>
29 #include <linux/slab.h>
30 #include <linux/stmp_device.h>
32 /* OCOTP registers and bits */
34 #define BM_OCOTP_CTRL_RD_BANK_OPEN BIT(12)
35 #define BM_OCOTP_CTRL_ERROR BIT(9)
36 #define BM_OCOTP_CTRL_BUSY BIT(8)
38 #define OCOTP_TIMEOUT 10000
39 #define OCOTP_DATA_OFFSET 0x20
44 struct nvmem_device
*nvmem
;
47 static int mxs_ocotp_wait(struct mxs_ocotp
*otp
)
49 int timeout
= OCOTP_TIMEOUT
;
50 unsigned int status
= 0;
53 status
= readl(otp
->base
);
55 if (!(status
& (BM_OCOTP_CTRL_BUSY
| BM_OCOTP_CTRL_ERROR
)))
61 if (status
& BM_OCOTP_CTRL_BUSY
)
63 else if (status
& BM_OCOTP_CTRL_ERROR
)
69 static int mxs_ocotp_read(void *context
, const void *reg
, size_t reg_size
,
70 void *val
, size_t val_size
)
72 struct mxs_ocotp
*otp
= context
;
73 unsigned int offset
= *(u32
*)reg
;
77 ret
= clk_enable(otp
->clk
);
81 writel(BM_OCOTP_CTRL_ERROR
, otp
->base
+ STMP_OFFSET_REG_CLR
);
83 ret
= mxs_ocotp_wait(otp
);
87 /* open OCOTP banks for read */
88 writel(BM_OCOTP_CTRL_RD_BANK_OPEN
, otp
->base
+ STMP_OFFSET_REG_SET
);
90 /* approximately wait 33 hclk cycles */
93 ret
= mxs_ocotp_wait(otp
);
98 if ((offset
< OCOTP_DATA_OFFSET
) || (offset
% 16)) {
99 /* fill up non-data register */
102 *buf
= readl(otp
->base
+ offset
);
111 /* close banks for power saving */
112 writel(BM_OCOTP_CTRL_RD_BANK_OPEN
, otp
->base
+ STMP_OFFSET_REG_CLR
);
115 clk_disable(otp
->clk
);
120 static int mxs_ocotp_write(void *context
, const void *data
, size_t count
)
122 /* We don't want to support writing */
126 static bool mxs_ocotp_writeable_reg(struct device
*dev
, unsigned int reg
)
131 static struct nvmem_config ocotp_config
= {
133 .owner
= THIS_MODULE
,
136 static const struct regmap_range imx23_ranges
[] = {
137 regmap_reg_range(OCOTP_DATA_OFFSET
, 0x210),
140 static const struct regmap_access_table imx23_access
= {
141 .yes_ranges
= imx23_ranges
,
142 .n_yes_ranges
= ARRAY_SIZE(imx23_ranges
),
145 static const struct regmap_range imx28_ranges
[] = {
146 regmap_reg_range(OCOTP_DATA_OFFSET
, 0x290),
149 static const struct regmap_access_table imx28_access
= {
150 .yes_ranges
= imx28_ranges
,
151 .n_yes_ranges
= ARRAY_SIZE(imx28_ranges
),
154 static struct regmap_bus mxs_ocotp_bus
= {
155 .read
= mxs_ocotp_read
,
156 .write
= mxs_ocotp_write
, /* make regmap_init() happy */
157 .reg_format_endian_default
= REGMAP_ENDIAN_NATIVE
,
158 .val_format_endian_default
= REGMAP_ENDIAN_NATIVE
,
161 static struct regmap_config mxs_ocotp_config
= {
165 .writeable_reg
= mxs_ocotp_writeable_reg
,
168 static const struct of_device_id mxs_ocotp_match
[] = {
169 { .compatible
= "fsl,imx23-ocotp", .data
= &imx23_access
},
170 { .compatible
= "fsl,imx28-ocotp", .data
= &imx28_access
},
173 MODULE_DEVICE_TABLE(of
, mxs_ocotp_match
);
175 static int mxs_ocotp_probe(struct platform_device
*pdev
)
177 struct device
*dev
= &pdev
->dev
;
178 struct mxs_ocotp
*otp
;
179 struct resource
*res
;
180 const struct of_device_id
*match
;
181 struct regmap
*regmap
;
182 const struct regmap_access_table
*access
;
185 match
= of_match_device(dev
->driver
->of_match_table
, dev
);
186 if (!match
|| !match
->data
)
189 otp
= devm_kzalloc(dev
, sizeof(*otp
), GFP_KERNEL
);
193 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
194 otp
->base
= devm_ioremap_resource(dev
, res
);
195 if (IS_ERR(otp
->base
))
196 return PTR_ERR(otp
->base
);
198 otp
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
199 if (IS_ERR(otp
->clk
))
200 return PTR_ERR(otp
->clk
);
202 ret
= clk_prepare(otp
->clk
);
204 dev_err(dev
, "failed to prepare clk: %d\n", ret
);
208 access
= match
->data
;
209 mxs_ocotp_config
.rd_table
= access
;
210 mxs_ocotp_config
.max_register
= access
->yes_ranges
[0].range_max
;
212 regmap
= devm_regmap_init(dev
, &mxs_ocotp_bus
, otp
, &mxs_ocotp_config
);
213 if (IS_ERR(regmap
)) {
214 dev_err(dev
, "regmap init failed\n");
215 ret
= PTR_ERR(regmap
);
219 ocotp_config
.dev
= dev
;
220 otp
->nvmem
= nvmem_register(&ocotp_config
);
221 if (IS_ERR(otp
->nvmem
)) {
222 ret
= PTR_ERR(otp
->nvmem
);
226 platform_set_drvdata(pdev
, otp
);
231 clk_unprepare(otp
->clk
);
236 static int mxs_ocotp_remove(struct platform_device
*pdev
)
238 struct mxs_ocotp
*otp
= platform_get_drvdata(pdev
);
240 clk_unprepare(otp
->clk
);
242 return nvmem_unregister(otp
->nvmem
);
245 static struct platform_driver mxs_ocotp_driver
= {
246 .probe
= mxs_ocotp_probe
,
247 .remove
= mxs_ocotp_remove
,
250 .of_match_table
= mxs_ocotp_match
,
254 module_platform_driver(mxs_ocotp_driver
);
255 MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
256 MODULE_DESCRIPTION("driver for OCOTP in i.MX23/i.MX28");
257 MODULE_LICENSE("GPL v2");