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