xref: /openbmc/linux/drivers/nvmem/apple-efuses.c (revision e0d77d0f38aa60ca61b3ce6e60d64fad2aa0853d)
1b6b7ef93SSven Peter // SPDX-License-Identifier: GPL-2.0-only
2b6b7ef93SSven Peter /*
3b6b7ef93SSven Peter  * Apple SoC eFuse driver
4b6b7ef93SSven Peter  *
5b6b7ef93SSven Peter  * Copyright (C) The Asahi Linux Contributors
6b6b7ef93SSven Peter  */
7b6b7ef93SSven Peter 
8b6b7ef93SSven Peter #include <linux/io.h>
9b6b7ef93SSven Peter #include <linux/mod_devicetable.h>
10b6b7ef93SSven Peter #include <linux/module.h>
11b6b7ef93SSven Peter #include <linux/nvmem-provider.h>
12b6b7ef93SSven Peter #include <linux/platform_device.h>
13b6b7ef93SSven Peter 
14b6b7ef93SSven Peter struct apple_efuses_priv {
15b6b7ef93SSven Peter 	void __iomem *fuses;
16b6b7ef93SSven Peter };
17b6b7ef93SSven Peter 
apple_efuses_read(void * context,unsigned int offset,void * val,size_t bytes)18b6b7ef93SSven Peter static int apple_efuses_read(void *context, unsigned int offset, void *val,
19b6b7ef93SSven Peter 			     size_t bytes)
20b6b7ef93SSven Peter {
21b6b7ef93SSven Peter 	struct apple_efuses_priv *priv = context;
22b6b7ef93SSven Peter 	u32 *dst = val;
23b6b7ef93SSven Peter 
24b6b7ef93SSven Peter 	while (bytes >= sizeof(u32)) {
25b6b7ef93SSven Peter 		*dst++ = readl_relaxed(priv->fuses + offset);
26b6b7ef93SSven Peter 		bytes -= sizeof(u32);
27b6b7ef93SSven Peter 		offset += sizeof(u32);
28b6b7ef93SSven Peter 	}
29b6b7ef93SSven Peter 
30b6b7ef93SSven Peter 	return 0;
31b6b7ef93SSven Peter }
32b6b7ef93SSven Peter 
apple_efuses_probe(struct platform_device * pdev)33b6b7ef93SSven Peter static int apple_efuses_probe(struct platform_device *pdev)
34b6b7ef93SSven Peter {
35b6b7ef93SSven Peter 	struct apple_efuses_priv *priv;
36b6b7ef93SSven Peter 	struct resource *res;
37b6b7ef93SSven Peter 	struct nvmem_config config = {
38b6b7ef93SSven Peter 		.dev = &pdev->dev,
39*26e2fe4cSRafał Miłecki 		.add_legacy_fixed_of_cells = true,
40b6b7ef93SSven Peter 		.read_only = true,
41b6b7ef93SSven Peter 		.reg_read = apple_efuses_read,
42b6b7ef93SSven Peter 		.stride = sizeof(u32),
43b6b7ef93SSven Peter 		.word_size = sizeof(u32),
44b6b7ef93SSven Peter 		.name = "apple_efuses_nvmem",
45b6b7ef93SSven Peter 		.id = NVMEM_DEVID_AUTO,
46b6b7ef93SSven Peter 		.root_only = true,
47b6b7ef93SSven Peter 	};
48b6b7ef93SSven Peter 
49b6b7ef93SSven Peter 	priv = devm_kzalloc(config.dev, sizeof(*priv), GFP_KERNEL);
50b6b7ef93SSven Peter 	if (!priv)
51b6b7ef93SSven Peter 		return -ENOMEM;
52b6b7ef93SSven Peter 
53b6b7ef93SSven Peter 	priv->fuses = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
54b6b7ef93SSven Peter 	if (IS_ERR(priv->fuses))
55b6b7ef93SSven Peter 		return PTR_ERR(priv->fuses);
56b6b7ef93SSven Peter 
57b6b7ef93SSven Peter 	config.priv = priv;
58b6b7ef93SSven Peter 	config.size = resource_size(res);
59b6b7ef93SSven Peter 
60b6b7ef93SSven Peter 	return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config));
61b6b7ef93SSven Peter }
62b6b7ef93SSven Peter 
63b6b7ef93SSven Peter static const struct of_device_id apple_efuses_of_match[] = {
64b6b7ef93SSven Peter 	{ .compatible = "apple,efuses", },
65b6b7ef93SSven Peter 	{}
66b6b7ef93SSven Peter };
67b6b7ef93SSven Peter 
68b6b7ef93SSven Peter MODULE_DEVICE_TABLE(of, apple_efuses_of_match);
69b6b7ef93SSven Peter 
70b6b7ef93SSven Peter static struct platform_driver apple_efuses_driver = {
71b6b7ef93SSven Peter 	.driver = {
72b6b7ef93SSven Peter 		.name = "apple_efuses",
73b6b7ef93SSven Peter 		.of_match_table = apple_efuses_of_match,
74b6b7ef93SSven Peter 	},
75b6b7ef93SSven Peter 	.probe = apple_efuses_probe,
76b6b7ef93SSven Peter };
77b6b7ef93SSven Peter 
78b6b7ef93SSven Peter module_platform_driver(apple_efuses_driver);
79b6b7ef93SSven Peter 
80b6b7ef93SSven Peter MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>");
81b6b7ef93SSven Peter MODULE_LICENSE("GPL");
82