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