2 * NXP LPC18xx/43xx OTP memory NVMEM driver
4 * Copyright (c) 2016 Joachim Eastwood <manabian@gmail.com>
6 * Based on the imx ocotp driver,
7 * Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
13 * TODO: add support for writing OTP register via API in boot ROM.
17 #include <linux/module.h>
18 #include <linux/nvmem-provider.h>
20 #include <linux/of_device.h>
21 #include <linux/platform_device.h>
22 #include <linux/slab.h>
25 * LPC18xx OTP memory contains 4 banks with 4 32-bit words. Bank 0 starts
26 * at offset 0 from the base.
28 * Bank 0 contains the part ID for Flashless devices and is reseverd for
30 * Bank 1/2 is generale purpose or AES key storage for secure devices.
31 * Bank 3 contains control data, USB ID and generale purpose words.
33 #define LPC18XX_OTP_NUM_BANKS 4
34 #define LPC18XX_OTP_WORDS_PER_BANK 4
35 #define LPC18XX_OTP_WORD_SIZE sizeof(u32)
36 #define LPC18XX_OTP_SIZE (LPC18XX_OTP_NUM_BANKS * \
37 LPC18XX_OTP_WORDS_PER_BANK * \
38 LPC18XX_OTP_WORD_SIZE)
44 static int lpc18xx_otp_read(void *context
, unsigned int offset
,
45 void *val
, size_t bytes
)
47 struct lpc18xx_otp
*otp
= context
;
48 unsigned int count
= bytes
>> 2;
49 u32 index
= offset
>> 2;
53 if (count
> (LPC18XX_OTP_SIZE
- index
))
54 count
= LPC18XX_OTP_SIZE
- index
;
56 for (i
= index
; i
< (index
+ count
); i
++)
57 *buf
++ = readl(otp
->base
+ i
* LPC18XX_OTP_WORD_SIZE
);
62 static struct nvmem_config lpc18xx_otp_nvmem_config
= {
63 .name
= "lpc18xx-otp",
65 .word_size
= LPC18XX_OTP_WORD_SIZE
,
66 .stride
= LPC18XX_OTP_WORD_SIZE
,
67 .reg_read
= lpc18xx_otp_read
,
70 static int lpc18xx_otp_probe(struct platform_device
*pdev
)
72 struct nvmem_device
*nvmem
;
73 struct lpc18xx_otp
*otp
;
76 otp
= devm_kzalloc(&pdev
->dev
, sizeof(*otp
), GFP_KERNEL
);
80 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
81 otp
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
82 if (IS_ERR(otp
->base
))
83 return PTR_ERR(otp
->base
);
85 lpc18xx_otp_nvmem_config
.size
= LPC18XX_OTP_SIZE
;
86 lpc18xx_otp_nvmem_config
.dev
= &pdev
->dev
;
87 lpc18xx_otp_nvmem_config
.priv
= otp
;
89 nvmem
= nvmem_register(&lpc18xx_otp_nvmem_config
);
91 return PTR_ERR(nvmem
);
93 platform_set_drvdata(pdev
, nvmem
);
98 static int lpc18xx_otp_remove(struct platform_device
*pdev
)
100 struct nvmem_device
*nvmem
= platform_get_drvdata(pdev
);
102 return nvmem_unregister(nvmem
);
105 static const struct of_device_id lpc18xx_otp_dt_ids
[] = {
106 { .compatible
= "nxp,lpc1850-otp" },
109 MODULE_DEVICE_TABLE(of
, lpc18xx_otp_dt_ids
);
111 static struct platform_driver lpc18xx_otp_driver
= {
112 .probe
= lpc18xx_otp_probe
,
113 .remove
= lpc18xx_otp_remove
,
115 .name
= "lpc18xx_otp",
116 .of_match_table
= lpc18xx_otp_dt_ids
,
119 module_platform_driver(lpc18xx_otp_driver
);
121 MODULE_AUTHOR("Joachim Eastwoood <manabian@gmail.com>");
122 MODULE_DESCRIPTION("NXP LPC18xx OTP NVMEM driver");
123 MODULE_LICENSE("GPL v2");