1d28c74c1SJosef Friedl // SPDX-License-Identifier: GPL-2.0
2d28c74c1SJosef Friedl /*
3d28c74c1SJosef Friedl * Power off through MediaTek PMIC
4d28c74c1SJosef Friedl *
5d28c74c1SJosef Friedl * Copyright (C) 2018 MediaTek Inc.
6d28c74c1SJosef Friedl *
7d28c74c1SJosef Friedl * Author: Sean Wang <sean.wang@mediatek.com>
8d28c74c1SJosef Friedl *
9d28c74c1SJosef Friedl */
10d28c74c1SJosef Friedl
11d28c74c1SJosef Friedl #include <linux/err.h>
12d28c74c1SJosef Friedl #include <linux/module.h>
13d28c74c1SJosef Friedl #include <linux/of.h>
14d28c74c1SJosef Friedl #include <linux/platform_device.h>
15d28c74c1SJosef Friedl #include <linux/mfd/mt6397/core.h>
16d28c74c1SJosef Friedl #include <linux/mfd/mt6397/rtc.h>
17d28c74c1SJosef Friedl
18d28c74c1SJosef Friedl struct mt6323_pwrc {
19d28c74c1SJosef Friedl struct device *dev;
20d28c74c1SJosef Friedl struct regmap *regmap;
21d28c74c1SJosef Friedl u32 base;
22d28c74c1SJosef Friedl };
23d28c74c1SJosef Friedl
24d28c74c1SJosef Friedl static struct mt6323_pwrc *mt_pwrc;
25d28c74c1SJosef Friedl
mt6323_do_pwroff(void)26d28c74c1SJosef Friedl static void mt6323_do_pwroff(void)
27d28c74c1SJosef Friedl {
28d28c74c1SJosef Friedl struct mt6323_pwrc *pwrc = mt_pwrc;
29d28c74c1SJosef Friedl unsigned int val;
30d28c74c1SJosef Friedl int ret;
31d28c74c1SJosef Friedl
32d28c74c1SJosef Friedl regmap_write(pwrc->regmap, pwrc->base + RTC_BBPU, RTC_BBPU_KEY);
3329ee4009SRan Bi regmap_write(pwrc->regmap, pwrc->base + RTC_WRTGR_MT6323, 1);
34d28c74c1SJosef Friedl
35d28c74c1SJosef Friedl ret = regmap_read_poll_timeout(pwrc->regmap,
36d28c74c1SJosef Friedl pwrc->base + RTC_BBPU, val,
37d28c74c1SJosef Friedl !(val & RTC_BBPU_CBUSY),
38d28c74c1SJosef Friedl MTK_RTC_POLL_DELAY_US,
39d28c74c1SJosef Friedl MTK_RTC_POLL_TIMEOUT);
40d28c74c1SJosef Friedl if (ret)
41d28c74c1SJosef Friedl dev_err(pwrc->dev, "failed to write BBPU: %d\n", ret);
42d28c74c1SJosef Friedl
43d28c74c1SJosef Friedl /* Wait some time until system down, otherwise, notice with a warn */
44d28c74c1SJosef Friedl mdelay(1000);
45d28c74c1SJosef Friedl
46d28c74c1SJosef Friedl WARN_ONCE(1, "Unable to power off system\n");
47d28c74c1SJosef Friedl }
48d28c74c1SJosef Friedl
mt6323_pwrc_probe(struct platform_device * pdev)49d28c74c1SJosef Friedl static int mt6323_pwrc_probe(struct platform_device *pdev)
50d28c74c1SJosef Friedl {
51d28c74c1SJosef Friedl struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent);
52d28c74c1SJosef Friedl struct mt6323_pwrc *pwrc;
53d28c74c1SJosef Friedl struct resource *res;
54d28c74c1SJosef Friedl
55d28c74c1SJosef Friedl pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);
56d28c74c1SJosef Friedl if (!pwrc)
57d28c74c1SJosef Friedl return -ENOMEM;
58d28c74c1SJosef Friedl
59d28c74c1SJosef Friedl res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
60*1c1348bfSJiasheng Jiang if (!res)
61*1c1348bfSJiasheng Jiang return -EINVAL;
62*1c1348bfSJiasheng Jiang
63d28c74c1SJosef Friedl pwrc->base = res->start;
64d28c74c1SJosef Friedl pwrc->regmap = mt6397_chip->regmap;
65d28c74c1SJosef Friedl pwrc->dev = &pdev->dev;
66d28c74c1SJosef Friedl mt_pwrc = pwrc;
67d28c74c1SJosef Friedl
68d28c74c1SJosef Friedl pm_power_off = &mt6323_do_pwroff;
69d28c74c1SJosef Friedl
70d28c74c1SJosef Friedl return 0;
71d28c74c1SJosef Friedl }
72d28c74c1SJosef Friedl
mt6323_pwrc_remove(struct platform_device * pdev)73d28c74c1SJosef Friedl static int mt6323_pwrc_remove(struct platform_device *pdev)
74d28c74c1SJosef Friedl {
75d28c74c1SJosef Friedl if (pm_power_off == &mt6323_do_pwroff)
76d28c74c1SJosef Friedl pm_power_off = NULL;
77d28c74c1SJosef Friedl
78d28c74c1SJosef Friedl return 0;
79d28c74c1SJosef Friedl }
80d28c74c1SJosef Friedl
81d28c74c1SJosef Friedl static const struct of_device_id mt6323_pwrc_dt_match[] = {
82d28c74c1SJosef Friedl { .compatible = "mediatek,mt6323-pwrc" },
83d28c74c1SJosef Friedl {},
84d28c74c1SJosef Friedl };
85d28c74c1SJosef Friedl MODULE_DEVICE_TABLE(of, mt6323_pwrc_dt_match);
86d28c74c1SJosef Friedl
87d28c74c1SJosef Friedl static struct platform_driver mt6323_pwrc_driver = {
88d28c74c1SJosef Friedl .probe = mt6323_pwrc_probe,
89d28c74c1SJosef Friedl .remove = mt6323_pwrc_remove,
90d28c74c1SJosef Friedl .driver = {
91d28c74c1SJosef Friedl .name = "mt6323-pwrc",
92d28c74c1SJosef Friedl .of_match_table = mt6323_pwrc_dt_match,
93d28c74c1SJosef Friedl },
94d28c74c1SJosef Friedl };
95d28c74c1SJosef Friedl
96d28c74c1SJosef Friedl module_platform_driver(mt6323_pwrc_driver);
97d28c74c1SJosef Friedl
98d28c74c1SJosef Friedl MODULE_DESCRIPTION("Poweroff driver for MT6323 PMIC");
99d28c74c1SJosef Friedl MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
100