diff options
-rw-r--r-- | drivers/nvmem/Kconfig | 10 | ||||
-rw-r--r-- | drivers/nvmem/Makefile | 2 | ||||
-rw-r--r-- | drivers/nvmem/lpc18xx_otp.c | 124 |
3 files changed, 136 insertions, 0 deletions
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index ba140eaee5c8..605524c93e45 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig | |||
@@ -35,6 +35,16 @@ config NVMEM_LPC18XX_EEPROM | |||
35 | To compile this driver as a module, choose M here: the module | 35 | To compile this driver as a module, choose M here: the module |
36 | will be called nvmem_lpc18xx_eeprom. | 36 | will be called nvmem_lpc18xx_eeprom. |
37 | 37 | ||
38 | config NVMEM_LPC18XX_OTP | ||
39 | tristate "NXP LPC18XX OTP Memory Support" | ||
40 | depends on ARCH_LPC18XX || COMPILE_TEST | ||
41 | depends on HAS_IOMEM | ||
42 | help | ||
43 | Say Y here to include support for NXP LPC18xx OTP memory found on | ||
44 | all LPC18xx and LPC43xx devices. | ||
45 | To compile this driver as a module, choose M here: the module | ||
46 | will be called nvmem_lpc18xx_otp. | ||
47 | |||
38 | config NVMEM_MXS_OCOTP | 48 | config NVMEM_MXS_OCOTP |
39 | tristate "Freescale MXS On-Chip OTP Memory Support" | 49 | tristate "Freescale MXS On-Chip OTP Memory Support" |
40 | depends on ARCH_MXS || COMPILE_TEST | 50 | depends on ARCH_MXS || COMPILE_TEST |
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 8f942a0cdaec..b2d31950ce58 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile | |||
@@ -10,6 +10,8 @@ obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o | |||
10 | nvmem-imx-ocotp-y := imx-ocotp.o | 10 | nvmem-imx-ocotp-y := imx-ocotp.o |
11 | obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o | 11 | obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o |
12 | nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o | 12 | nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o |
13 | obj-$(CONFIG_NVMEM_LPC18XX_OTP) += nvmem_lpc18xx_otp.o | ||
14 | nvmem_lpc18xx_otp-y := lpc18xx_otp.o | ||
13 | obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o | 15 | obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o |
14 | nvmem-mxs-ocotp-y := mxs-ocotp.o | 16 | nvmem-mxs-ocotp-y := mxs-ocotp.o |
15 | obj-$(CONFIG_MTK_EFUSE) += nvmem_mtk-efuse.o | 17 | obj-$(CONFIG_MTK_EFUSE) += nvmem_mtk-efuse.o |
diff --git a/drivers/nvmem/lpc18xx_otp.c b/drivers/nvmem/lpc18xx_otp.c new file mode 100644 index 000000000000..be8d07403ffc --- /dev/null +++ b/drivers/nvmem/lpc18xx_otp.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * NXP LPC18xx/43xx OTP memory NVMEM driver | ||
3 | * | ||
4 | * Copyright (c) 2016 Joachim Eastwood <manabian@gmail.com> | ||
5 | * | ||
6 | * Based on the imx ocotp driver, | ||
7 | * Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de> | ||
8 | * | ||
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. | ||
12 | * | ||
13 | * TODO: add support for writing OTP register via API in boot ROM. | ||
14 | */ | ||
15 | |||
16 | #include <linux/io.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/nvmem-provider.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_device.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | /* | ||
25 | * LPC18xx OTP memory contains 4 banks with 4 32-bit words. Bank 0 starts | ||
26 | * at offset 0 from the base. | ||
27 | * | ||
28 | * Bank 0 contains the part ID for Flashless devices and is reseverd for | ||
29 | * devices with Flash. | ||
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. | ||
32 | */ | ||
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) | ||
39 | |||
40 | struct lpc18xx_otp { | ||
41 | void __iomem *base; | ||
42 | }; | ||
43 | |||
44 | static int lpc18xx_otp_read(void *context, unsigned int offset, | ||
45 | void *val, size_t bytes) | ||
46 | { | ||
47 | struct lpc18xx_otp *otp = context; | ||
48 | unsigned int count = bytes >> 2; | ||
49 | u32 index = offset >> 2; | ||
50 | u32 *buf = val; | ||
51 | int i; | ||
52 | |||
53 | if (count > (LPC18XX_OTP_SIZE - index)) | ||
54 | count = LPC18XX_OTP_SIZE - index; | ||
55 | |||
56 | for (i = index; i < (index + count); i++) | ||
57 | *buf++ = readl(otp->base + i * LPC18XX_OTP_WORD_SIZE); | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static struct nvmem_config lpc18xx_otp_nvmem_config = { | ||
63 | .name = "lpc18xx-otp", | ||
64 | .read_only = true, | ||
65 | .word_size = LPC18XX_OTP_WORD_SIZE, | ||
66 | .stride = LPC18XX_OTP_WORD_SIZE, | ||
67 | .owner = THIS_MODULE, | ||
68 | .reg_read = lpc18xx_otp_read, | ||
69 | }; | ||
70 | |||
71 | static int lpc18xx_otp_probe(struct platform_device *pdev) | ||
72 | { | ||
73 | struct nvmem_device *nvmem; | ||
74 | struct lpc18xx_otp *otp; | ||
75 | struct resource *res; | ||
76 | |||
77 | otp = devm_kzalloc(&pdev->dev, sizeof(*otp), GFP_KERNEL); | ||
78 | if (!otp) | ||
79 | return -ENOMEM; | ||
80 | |||
81 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
82 | otp->base = devm_ioremap_resource(&pdev->dev, res); | ||
83 | if (IS_ERR(otp->base)) | ||
84 | return PTR_ERR(otp->base); | ||
85 | |||
86 | lpc18xx_otp_nvmem_config.size = LPC18XX_OTP_SIZE; | ||
87 | lpc18xx_otp_nvmem_config.dev = &pdev->dev; | ||
88 | lpc18xx_otp_nvmem_config.priv = otp; | ||
89 | |||
90 | nvmem = nvmem_register(&lpc18xx_otp_nvmem_config); | ||
91 | if (IS_ERR(nvmem)) | ||
92 | return PTR_ERR(nvmem); | ||
93 | |||
94 | platform_set_drvdata(pdev, nvmem); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static int lpc18xx_otp_remove(struct platform_device *pdev) | ||
100 | { | ||
101 | struct nvmem_device *nvmem = platform_get_drvdata(pdev); | ||
102 | |||
103 | return nvmem_unregister(nvmem); | ||
104 | } | ||
105 | |||
106 | static const struct of_device_id lpc18xx_otp_dt_ids[] = { | ||
107 | { .compatible = "nxp,lpc1850-otp" }, | ||
108 | { }, | ||
109 | }; | ||
110 | MODULE_DEVICE_TABLE(of, lpc18xx_otp_dt_ids); | ||
111 | |||
112 | static struct platform_driver lpc18xx_otp_driver = { | ||
113 | .probe = lpc18xx_otp_probe, | ||
114 | .remove = lpc18xx_otp_remove, | ||
115 | .driver = { | ||
116 | .name = "lpc18xx_otp", | ||
117 | .of_match_table = lpc18xx_otp_dt_ids, | ||
118 | }, | ||
119 | }; | ||
120 | module_platform_driver(lpc18xx_otp_driver); | ||
121 | |||
122 | MODULE_AUTHOR("Joachim Eastwoood <manabian@gmail.com>"); | ||
123 | MODULE_DESCRIPTION("NXP LPC18xx OTP NVMEM driver"); | ||
124 | MODULE_LICENSE("GPL v2"); | ||