Skip to content

Commit 5a35614

Browse files
ciprianmcosteagregkh
authored andcommitted
nvmem: s32g-ocotp: Add driver for S32G OCOTP
Provide access to the On Chip One-Time Programmable Controller (OCOTP) pages on the NXP S32G platform. Signed-off-by: Ciprian Costea <ciprianmarian.costea@nxp.com> Co-developed-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com> Signed-off-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com> Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com> Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com> Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org> Signed-off-by: Srinivas Kandagatla <srini@kernel.org> Link: https://lore.kernel.org/r/20250912131415.303407-3-srini@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 9b58f88 commit 5a35614

3 files changed

Lines changed: 112 additions & 0 deletions

File tree

drivers/nvmem/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,16 @@ config NVMEM_NINTENDO_OTP
240240
This driver can also be built as a module. If so, the module
241241
will be called nvmem-nintendo-otp.
242242

243+
config NVMEM_S32G_OCOTP
244+
tristate "S32G SoC OCOTP support"
245+
depends on ARCH_S32
246+
help
247+
This is a driver for the 'OCOTP' peripheral available on S32G
248+
platforms.
249+
250+
If you say Y here, you will get support for the One Time
251+
Programmable memory pages.
252+
243253
config NVMEM_QCOM_QFPROM
244254
tristate "QCOM QFPROM Support"
245255
depends on ARCH_QCOM || COMPILE_TEST

drivers/nvmem/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o
7979
nvmem_sunplus_ocotp-y := sunplus-ocotp.o
8080
obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o
8181
nvmem_sunxi_sid-y := sunxi_sid.o
82+
obj-$(CONFIG_NVMEM_S32G_OCOTP) += nvmem-s32g-ocotp-nvmem.o
83+
nvmem-s32g-ocotp-nvmem-y := s32g-ocotp-nvmem.o
8284
obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o
8385
nvmem_u-boot-env-y := u-boot-env.o
8486
obj-$(CONFIG_NVMEM_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o

drivers/nvmem/s32g-ocotp-nvmem.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
/*
3+
* Copyright 2023-2025 NXP
4+
*/
5+
6+
#include <linux/device.h>
7+
#include <linux/io.h>
8+
#include <linux/module.h>
9+
#include <linux/nvmem-provider.h>
10+
#include <linux/of.h>
11+
#include <linux/of_device.h>
12+
#include <linux/platform_device.h>
13+
14+
struct s32g_ocotp_priv {
15+
struct device *dev;
16+
void __iomem *base;
17+
};
18+
19+
static int s32g_ocotp_read(void *context, unsigned int offset,
20+
void *val, size_t bytes)
21+
{
22+
struct s32g_ocotp_priv *s32g_data = context;
23+
u32 *dst = val;
24+
25+
while (bytes >= sizeof(u32)) {
26+
*dst++ = ioread32(s32g_data->base + offset);
27+
28+
bytes -= sizeof(u32);
29+
offset += sizeof(u32);
30+
}
31+
32+
return 0;
33+
}
34+
35+
static struct nvmem_keepout s32g_keepouts[] = {
36+
{ .start = 0, .end = 520 },
37+
{ .start = 540, .end = 564 },
38+
{ .start = 596, .end = 664 },
39+
{ .start = 668, .end = 676 },
40+
{ .start = 684, .end = 732 },
41+
{ .start = 744, .end = 864 },
42+
{ .start = 908, .end = 924 },
43+
{ .start = 928, .end = 936 },
44+
{ .start = 948, .end = 964 },
45+
{ .start = 968, .end = 976 },
46+
{ .start = 984, .end = 1012 },
47+
};
48+
49+
static struct nvmem_config s32g_ocotp_nvmem_config = {
50+
.name = "s32g-ocotp",
51+
.add_legacy_fixed_of_cells = true,
52+
.read_only = true,
53+
.word_size = 4,
54+
.reg_read = s32g_ocotp_read,
55+
.keepout = s32g_keepouts,
56+
.nkeepout = ARRAY_SIZE(s32g_keepouts),
57+
};
58+
59+
static const struct of_device_id ocotp_of_match[] = {
60+
{ .compatible = "nxp,s32g2-ocotp" },
61+
{ /* sentinel */ }
62+
};
63+
64+
static int s32g_ocotp_probe(struct platform_device *pdev)
65+
{
66+
struct s32g_ocotp_priv *s32g_data;
67+
struct device *dev = &pdev->dev;
68+
struct nvmem_device *nvmem;
69+
struct resource *res;
70+
71+
s32g_data = devm_kzalloc(dev, sizeof(*s32g_data), GFP_KERNEL);
72+
if (!s32g_data)
73+
return -ENOMEM;
74+
75+
s32g_data->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
76+
if (IS_ERR(s32g_data->base))
77+
return dev_err_probe(dev, PTR_ERR(s32g_data->base),
78+
"Cannot map OCOTP device.\n");
79+
80+
s32g_data->dev = dev;
81+
s32g_ocotp_nvmem_config.dev = dev;
82+
s32g_ocotp_nvmem_config.priv = s32g_data;
83+
s32g_ocotp_nvmem_config.size = resource_size(res);
84+
85+
nvmem = devm_nvmem_register(dev, &s32g_ocotp_nvmem_config);
86+
87+
return PTR_ERR_OR_ZERO(nvmem);
88+
}
89+
90+
static struct platform_driver s32g_ocotp_driver = {
91+
.probe = s32g_ocotp_probe,
92+
.driver = {
93+
.name = "s32g-ocotp",
94+
.of_match_table = ocotp_of_match,
95+
},
96+
};
97+
module_platform_driver(s32g_ocotp_driver);
98+
MODULE_AUTHOR("NXP");
99+
MODULE_DESCRIPTION("S32G OCOTP driver");
100+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)