xref: /linux/drivers/nvmem/mtk-efuse.c (revision 80d443e8876602be2c130f79c4de81e12e2a700d)
1 /*
2  * Copyright (c) 2015 MediaTek Inc.
3  * Author: Andrew-CT Chen <andrew-ct.chen@mediatek.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14 
15 #include <linux/device.h>
16 #include <linux/module.h>
17 #include <linux/io.h>
18 #include <linux/nvmem-provider.h>
19 #include <linux/platform_device.h>
20 
21 static int mtk_reg_read(void *context,
22 			unsigned int reg, void *_val, size_t bytes)
23 {
24 	void __iomem *base = context;
25 	u32 *val = _val;
26 	int i = 0, words = bytes / 4;
27 
28 	while (words--)
29 		*val++ = readl(base + reg + (i++ * 4));
30 
31 	return 0;
32 }
33 
34 static int mtk_reg_write(void *context,
35 			 unsigned int reg, void *_val, size_t bytes)
36 {
37 	void __iomem *base = context;
38 	u32 *val = _val;
39 	int i = 0, words = bytes / 4;
40 
41 	while (words--)
42 		writel(*val++, base + reg + (i++ * 4));
43 
44 	return 0;
45 }
46 
47 static int mtk_efuse_probe(struct platform_device *pdev)
48 {
49 	struct device *dev = &pdev->dev;
50 	struct resource *res;
51 	struct nvmem_device *nvmem;
52 	struct nvmem_config *econfig;
53 	void __iomem *base;
54 
55 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
56 	base = devm_ioremap_resource(dev, res);
57 	if (IS_ERR(base))
58 		return PTR_ERR(base);
59 
60 	econfig = devm_kzalloc(dev, sizeof(*econfig), GFP_KERNEL);
61 	if (!econfig)
62 		return -ENOMEM;
63 
64 	econfig->stride = 4;
65 	econfig->word_size = 4;
66 	econfig->reg_read = mtk_reg_read;
67 	econfig->reg_write = mtk_reg_write;
68 	econfig->size = resource_size(res);
69 	econfig->priv = base;
70 	econfig->dev = dev;
71 	econfig->owner = THIS_MODULE;
72 	nvmem = nvmem_register(econfig);
73 	if (IS_ERR(nvmem))
74 		return PTR_ERR(nvmem);
75 
76 	platform_set_drvdata(pdev, nvmem);
77 
78 	return 0;
79 }
80 
81 static int mtk_efuse_remove(struct platform_device *pdev)
82 {
83 	struct nvmem_device *nvmem = platform_get_drvdata(pdev);
84 
85 	return nvmem_unregister(nvmem);
86 }
87 
88 static const struct of_device_id mtk_efuse_of_match[] = {
89 	{ .compatible = "mediatek,mt8173-efuse",},
90 	{ .compatible = "mediatek,efuse",},
91 	{/* sentinel */},
92 };
93 MODULE_DEVICE_TABLE(of, mtk_efuse_of_match);
94 
95 static struct platform_driver mtk_efuse_driver = {
96 	.probe = mtk_efuse_probe,
97 	.remove = mtk_efuse_remove,
98 	.driver = {
99 		.name = "mediatek,efuse",
100 		.of_match_table = mtk_efuse_of_match,
101 	},
102 };
103 
104 static int __init mtk_efuse_init(void)
105 {
106 	int ret;
107 
108 	ret = platform_driver_register(&mtk_efuse_driver);
109 	if (ret) {
110 		pr_err("Failed to register efuse driver\n");
111 		return ret;
112 	}
113 
114 	return 0;
115 }
116 
117 static void __exit mtk_efuse_exit(void)
118 {
119 	return platform_driver_unregister(&mtk_efuse_driver);
120 }
121 
122 subsys_initcall(mtk_efuse_init);
123 module_exit(mtk_efuse_exit);
124 
125 MODULE_AUTHOR("Andrew-CT Chen <andrew-ct.chen@mediatek.com>");
126 MODULE_DESCRIPTION("Mediatek EFUSE driver");
127 MODULE_LICENSE("GPL v2");
128