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 18 struct mt6323_pwrc { 19 struct device *dev; 20 struct regmap *regmap; 21 u32 base; 22 }; 23 24 static struct mt6323_pwrc *mt_pwrc; 25 26 static void mt6323_do_pwroff(void) 27 { 28 struct mt6323_pwrc *pwrc = mt_pwrc; 29 unsigned int val; 30 int ret; 31 32 regmap_write(pwrc->regmap, pwrc->base + RTC_BBPU, RTC_BBPU_KEY); 33 regmap_write(pwrc->regmap, pwrc->base + RTC_WRTGR, 1); 34 35 ret = regmap_read_poll_timeout(pwrc->regmap, 36 pwrc->base + RTC_BBPU, val, 37 !(val & RTC_BBPU_CBUSY), 38 MTK_RTC_POLL_DELAY_US, 39 MTK_RTC_POLL_TIMEOUT); 40 if (ret) 41 dev_err(pwrc->dev, "failed to write BBPU: %d\n", ret); 42 43 /* Wait some time until system down, otherwise, notice with a warn */ 44 mdelay(1000); 45 46 WARN_ONCE(1, "Unable to power off system\n"); 47 } 48 49 static int mt6323_pwrc_probe(struct platform_device *pdev) 50 { 51 struct mt6397_chip *mt6397_chip = dev_get_drvdata(pdev->dev.parent); 52 struct mt6323_pwrc *pwrc; 53 struct resource *res; 54 55 pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL); 56 if (!pwrc) 57 return -ENOMEM; 58 59 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 60 pwrc->base = res->start; 61 pwrc->regmap = mt6397_chip->regmap; 62 pwrc->dev = &pdev->dev; 63 mt_pwrc = pwrc; 64 65 pm_power_off = &mt6323_do_pwroff; 66 67 return 0; 68 } 69 70 static int mt6323_pwrc_remove(struct platform_device *pdev) 71 { 72 if (pm_power_off == &mt6323_do_pwroff) 73 pm_power_off = NULL; 74 75 return 0; 76 } 77 78 static const struct of_device_id mt6323_pwrc_dt_match[] = { 79 { .compatible = "mediatek,mt6323-pwrc" }, 80 {}, 81 }; 82 MODULE_DEVICE_TABLE(of, mt6323_pwrc_dt_match); 83 84 static struct platform_driver mt6323_pwrc_driver = { 85 .probe = mt6323_pwrc_probe, 86 .remove = mt6323_pwrc_remove, 87 .driver = { 88 .name = "mt6323-pwrc", 89 .of_match_table = mt6323_pwrc_dt_match, 90 }, 91 }; 92 93 module_platform_driver(mt6323_pwrc_driver); 94 95 MODULE_DESCRIPTION("Poweroff driver for MT6323 PMIC"); 96 MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); 97 MODULE_LICENSE("GPL v2"); 98