blob: 2d006feb2d960d97fd94a44329898b77c1b4fccd [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2019 MediaTek Inc.
4 * Author Freddy Hsin <freddy.hsin@mediatek.com>
5 */
6
7#include <linux/init.h>
8#include <linux/module.h>
9#include <linux/kernel.h>
10#include <linux/of.h>
11#include <linux/platform_device.h>
12#include <linux/reboot.h>
13#include <linux/regmap.h>
14#include <linux/of_address.h>
15#include <linux/reboot-mode.h>
16
17static const struct regmap_config mtk_regmap_config = {
18 .reg_bits = 32,
19 .val_bits = 32,
20 .reg_stride = 4,
21};
22
23struct mtk_reboot_mode {
24 struct regmap *map;
25 struct reboot_mode_driver reboot;
26 u32 offset;
27 u32 mask;
28};
29
30static int mtk_reboot_mode_write(struct reboot_mode_driver *reboot,
31 unsigned int magic)
32{
33 struct mtk_reboot_mode *mtk_rbm;
34 int ret;
35
36 mtk_rbm = container_of(reboot, struct mtk_reboot_mode, reboot);
37
38 ret = regmap_update_bits(mtk_rbm->map, mtk_rbm->offset,
39 mtk_rbm->mask, magic);
40 if (ret < 0)
41 dev_info(reboot->dev, "update reboot mode bits failed\n");
42
43 return ret;
44}
45
46static int mtk_regmap_lookup_by_phandle(struct device *dev,
47 struct mtk_reboot_mode *mtk_rbm)
48{
49 struct device_node *toprgu_np;
50 struct device_node *np = dev->of_node;
51 void __iomem *base;
52
53 toprgu_np = of_parse_phandle(np, "regmap", 0);
54 if (!toprgu_np)
55 return -EINVAL;
56
57 if (!of_device_is_compatible(toprgu_np, "mediatek,toprgu"))
58 return -EINVAL;
59
60 base = of_iomap(toprgu_np, 0);
61 if (IS_ERR(base))
62 return PTR_ERR(base);
63
64 mtk_rbm->map = devm_regmap_init_mmio(dev, base,
65 &mtk_regmap_config);
66 return PTR_ERR_OR_ZERO(mtk_rbm->map);
67}
68
69static int mtk_reboot_mode_probe(struct platform_device *pdev)
70{
71 int ret;
72 struct mtk_reboot_mode *mtk_rbm;
73
74 mtk_rbm = devm_kzalloc(&pdev->dev, sizeof(*mtk_rbm), GFP_KERNEL);
75 if (!mtk_rbm)
76 return -ENOMEM;
77
78 mtk_rbm->reboot.dev = &pdev->dev;
79 mtk_rbm->reboot.write = mtk_reboot_mode_write;
80 mtk_rbm->mask = 0xf;
81
82 ret = mtk_regmap_lookup_by_phandle(&pdev->dev, mtk_rbm);
83 if (ret) {
84 dev_info(&pdev->dev, "Couldn't create the toprgu regmap\n");
85 return -EINVAL;
86 }
87
88 if (of_property_read_u32(pdev->dev.of_node, "offset",
89 &mtk_rbm->offset))
90 return -EINVAL;
91
92 of_property_read_u32(pdev->dev.of_node, "mask", &mtk_rbm->mask);
93
94 ret = devm_reboot_mode_register(&pdev->dev, &mtk_rbm->reboot);
95 if (ret)
96 dev_info(&pdev->dev, "can't register reboot mode\n");
97
98 return ret;
99}
100
101static const struct of_device_id mtk_reboot_mode_of_match[] = {
102 { .compatible = "toprgu-reboot-mode" },
103 {}
104};
105MODULE_DEVICE_TABLE(of, mtk_reboot_mode_of_match);
106
107static struct platform_driver mtk_reboot_mode_driver = {
108 .probe = mtk_reboot_mode_probe,
109 .driver = {
110 .name = "toprgu-reboot-mode",
111 .of_match_table = mtk_reboot_mode_of_match,
112 },
113};
114module_platform_driver(mtk_reboot_mode_driver);
115
116MODULE_AUTHOR("Freddy Hsin <freddy.hsin@mediatek.com>");
117MODULE_DESCRIPTION("Mediatek reboot mode driver");
118MODULE_LICENSE("GPL v2");