xref: /linux/drivers/nvmem/mtk-efuse.c (revision 2f4c53349961c8ca480193e47da4d44fdb8335a8)
1*1802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24c7e4fe3SAndrew-CT Chen /*
34c7e4fe3SAndrew-CT Chen  * Copyright (c) 2015 MediaTek Inc.
44c7e4fe3SAndrew-CT Chen  * Author: Andrew-CT Chen <andrew-ct.chen@mediatek.com>
54c7e4fe3SAndrew-CT Chen  */
64c7e4fe3SAndrew-CT Chen 
74c7e4fe3SAndrew-CT Chen #include <linux/device.h>
84c7e4fe3SAndrew-CT Chen #include <linux/module.h>
9ac316725SRandy Dunlap #include <linux/mod_devicetable.h>
10ba360fd0SSrinivas Kandagatla #include <linux/io.h>
114c7e4fe3SAndrew-CT Chen #include <linux/nvmem-provider.h>
124c7e4fe3SAndrew-CT Chen #include <linux/platform_device.h>
134c7e4fe3SAndrew-CT Chen 
14a48f1fffSMasahiro Yamada struct mtk_efuse_priv {
15a48f1fffSMasahiro Yamada 	void __iomem *base;
16a48f1fffSMasahiro Yamada };
17a48f1fffSMasahiro Yamada 
18ba360fd0SSrinivas Kandagatla static int mtk_reg_read(void *context,
19ba360fd0SSrinivas Kandagatla 			unsigned int reg, void *_val, size_t bytes)
20ba360fd0SSrinivas Kandagatla {
21a48f1fffSMasahiro Yamada 	struct mtk_efuse_priv *priv = context;
22ba360fd0SSrinivas Kandagatla 	u32 *val = _val;
23ba360fd0SSrinivas Kandagatla 	int i = 0, words = bytes / 4;
24ba360fd0SSrinivas Kandagatla 
25ba360fd0SSrinivas Kandagatla 	while (words--)
26a48f1fffSMasahiro Yamada 		*val++ = readl(priv->base + reg + (i++ * 4));
27ba360fd0SSrinivas Kandagatla 
28ba360fd0SSrinivas Kandagatla 	return 0;
29ba360fd0SSrinivas Kandagatla }
30ba360fd0SSrinivas Kandagatla 
31ba360fd0SSrinivas Kandagatla static int mtk_reg_write(void *context,
32ba360fd0SSrinivas Kandagatla 			 unsigned int reg, void *_val, size_t bytes)
33ba360fd0SSrinivas Kandagatla {
34a48f1fffSMasahiro Yamada 	struct mtk_efuse_priv *priv = context;
35ba360fd0SSrinivas Kandagatla 	u32 *val = _val;
36ba360fd0SSrinivas Kandagatla 	int i = 0, words = bytes / 4;
37ba360fd0SSrinivas Kandagatla 
38ba360fd0SSrinivas Kandagatla 	while (words--)
39a48f1fffSMasahiro Yamada 		writel(*val++, priv->base + reg + (i++ * 4));
40ba360fd0SSrinivas Kandagatla 
41ba360fd0SSrinivas Kandagatla 	return 0;
42ba360fd0SSrinivas Kandagatla }
434c7e4fe3SAndrew-CT Chen 
444c7e4fe3SAndrew-CT Chen static int mtk_efuse_probe(struct platform_device *pdev)
454c7e4fe3SAndrew-CT Chen {
464c7e4fe3SAndrew-CT Chen 	struct device *dev = &pdev->dev;
474c7e4fe3SAndrew-CT Chen 	struct resource *res;
484c7e4fe3SAndrew-CT Chen 	struct nvmem_device *nvmem;
494dd5f60eSMasahiro Yamada 	struct nvmem_config econfig = {};
50a48f1fffSMasahiro Yamada 	struct mtk_efuse_priv *priv;
51a48f1fffSMasahiro Yamada 
52a48f1fffSMasahiro Yamada 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
53a48f1fffSMasahiro Yamada 	if (!priv)
54a48f1fffSMasahiro Yamada 		return -ENOMEM;
554c7e4fe3SAndrew-CT Chen 
564c7e4fe3SAndrew-CT Chen 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
57a48f1fffSMasahiro Yamada 	priv->base = devm_ioremap_resource(dev, res);
58a48f1fffSMasahiro Yamada 	if (IS_ERR(priv->base))
59a48f1fffSMasahiro Yamada 		return PTR_ERR(priv->base);
604c7e4fe3SAndrew-CT Chen 
614dd5f60eSMasahiro Yamada 	econfig.stride = 4;
624dd5f60eSMasahiro Yamada 	econfig.word_size = 4;
634dd5f60eSMasahiro Yamada 	econfig.reg_read = mtk_reg_read;
644dd5f60eSMasahiro Yamada 	econfig.reg_write = mtk_reg_write;
654dd5f60eSMasahiro Yamada 	econfig.size = resource_size(res);
66a48f1fffSMasahiro Yamada 	econfig.priv = priv;
674dd5f60eSMasahiro Yamada 	econfig.dev = dev;
687e68a645SAndrey Smirnov 	nvmem = devm_nvmem_register(dev, &econfig);
694c7e4fe3SAndrew-CT Chen 
707e68a645SAndrey Smirnov 	return PTR_ERR_OR_ZERO(nvmem);
714c7e4fe3SAndrew-CT Chen }
724c7e4fe3SAndrew-CT Chen 
734c7e4fe3SAndrew-CT Chen static const struct of_device_id mtk_efuse_of_match[] = {
744c7e4fe3SAndrew-CT Chen 	{ .compatible = "mediatek,mt8173-efuse",},
754c7e4fe3SAndrew-CT Chen 	{ .compatible = "mediatek,efuse",},
764c7e4fe3SAndrew-CT Chen 	{/* sentinel */},
774c7e4fe3SAndrew-CT Chen };
784c7e4fe3SAndrew-CT Chen MODULE_DEVICE_TABLE(of, mtk_efuse_of_match);
794c7e4fe3SAndrew-CT Chen 
804c7e4fe3SAndrew-CT Chen static struct platform_driver mtk_efuse_driver = {
814c7e4fe3SAndrew-CT Chen 	.probe = mtk_efuse_probe,
824c7e4fe3SAndrew-CT Chen 	.driver = {
834c7e4fe3SAndrew-CT Chen 		.name = "mediatek,efuse",
844c7e4fe3SAndrew-CT Chen 		.of_match_table = mtk_efuse_of_match,
854c7e4fe3SAndrew-CT Chen 	},
864c7e4fe3SAndrew-CT Chen };
87564e7f87SAndrew-CT Chen 
88564e7f87SAndrew-CT Chen static int __init mtk_efuse_init(void)
89564e7f87SAndrew-CT Chen {
90564e7f87SAndrew-CT Chen 	int ret;
91564e7f87SAndrew-CT Chen 
92564e7f87SAndrew-CT Chen 	ret = platform_driver_register(&mtk_efuse_driver);
93564e7f87SAndrew-CT Chen 	if (ret) {
94564e7f87SAndrew-CT Chen 		pr_err("Failed to register efuse driver\n");
95564e7f87SAndrew-CT Chen 		return ret;
96564e7f87SAndrew-CT Chen 	}
97564e7f87SAndrew-CT Chen 
98564e7f87SAndrew-CT Chen 	return 0;
99564e7f87SAndrew-CT Chen }
100564e7f87SAndrew-CT Chen 
101564e7f87SAndrew-CT Chen static void __exit mtk_efuse_exit(void)
102564e7f87SAndrew-CT Chen {
103564e7f87SAndrew-CT Chen 	return platform_driver_unregister(&mtk_efuse_driver);
104564e7f87SAndrew-CT Chen }
105564e7f87SAndrew-CT Chen 
106564e7f87SAndrew-CT Chen subsys_initcall(mtk_efuse_init);
107564e7f87SAndrew-CT Chen module_exit(mtk_efuse_exit);
108564e7f87SAndrew-CT Chen 
1094c7e4fe3SAndrew-CT Chen MODULE_AUTHOR("Andrew-CT Chen <andrew-ct.chen@mediatek.com>");
1104c7e4fe3SAndrew-CT Chen MODULE_DESCRIPTION("Mediatek EFUSE driver");
1114c7e4fe3SAndrew-CT Chen MODULE_LICENSE("GPL v2");
112