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_MT6323, 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 if (!res) 61 return -EINVAL; 62 63 pwrc->base = res->start; 64 pwrc->regmap = mt6397_chip->regmap; 65 pwrc->dev = &pdev->dev; 66 mt_pwrc = pwrc; 67 68 pm_power_off = &mt6323_do_pwroff; 69 70 return 0; 71 } 72 73 static void mt6323_pwrc_remove(struct platform_device *pdev) 74 { 75 if (pm_power_off == &mt6323_do_pwroff) 76 pm_power_off = NULL; 77 } 78 79 static const struct of_device_id mt6323_pwrc_dt_match[] = { 80 { .compatible = "mediatek,mt6323-pwrc" }, 81 {}, 82 }; 83 MODULE_DEVICE_TABLE(of, mt6323_pwrc_dt_match); 84 85 static struct platform_driver mt6323_pwrc_driver = { 86 .probe = mt6323_pwrc_probe, 87 .remove_new = mt6323_pwrc_remove, 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