1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Poweroff & reset driver for Actions Semi ATC260x PMICs 4 * 5 * Copyright (c) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com> 6 */ 7 8 #include <linux/delay.h> 9 #include <linux/mfd/atc260x/core.h> 10 #include <linux/module.h> 11 #include <linux/platform_device.h> 12 #include <linux/power_supply.h> 13 #include <linux/reboot.h> 14 #include <linux/regmap.h> 15 16 struct atc260x_pwrc { 17 struct device *dev; 18 struct regmap *regmap; 19 int (*do_poweroff)(const struct atc260x_pwrc *pwrc, bool restart); 20 }; 21 22 static int atc2603c_do_poweroff(const struct atc260x_pwrc *pwrc, bool restart) 23 { 24 int ret, deep_sleep = 0; 25 uint reg_mask, reg_val; 26 27 /* S4-Deep Sleep Mode is NOT available for WALL/USB power */ 28 if (!restart && !power_supply_is_system_supplied()) { 29 deep_sleep = 1; 30 dev_info(pwrc->dev, "Enabling S4-Deep Sleep Mode"); 31 } 32 33 /* Update wakeup sources */ 34 reg_val = ATC2603C_PMU_SYS_CTL0_ONOFF_LONG_WK_EN | 35 (restart ? ATC2603C_PMU_SYS_CTL0_RESET_WK_EN 36 : ATC2603C_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN); 37 38 ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL0, 39 ATC2603C_PMU_SYS_CTL0_WK_ALL, reg_val); 40 if (ret) 41 dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret); 42 43 /* Update power mode */ 44 reg_mask = ATC2603C_PMU_SYS_CTL3_EN_S2 | ATC2603C_PMU_SYS_CTL3_EN_S3; 45 46 ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL3, reg_mask, 47 deep_sleep ? 0 : ATC2603C_PMU_SYS_CTL3_EN_S3); 48 if (ret) { 49 dev_err(pwrc->dev, "failed to write SYS_CTL3: %d\n", ret); 50 return ret; 51 } 52 53 /* Trigger poweroff / restart sequence */ 54 reg_mask = restart ? ATC2603C_PMU_SYS_CTL0_RESTART_EN 55 : ATC2603C_PMU_SYS_CTL1_EN_S1; 56 reg_val = restart ? ATC2603C_PMU_SYS_CTL0_RESTART_EN : 0; 57 58 ret = regmap_update_bits(pwrc->regmap, 59 restart ? ATC2603C_PMU_SYS_CTL0 : ATC2603C_PMU_SYS_CTL1, 60 reg_mask, reg_val); 61 if (ret) { 62 dev_err(pwrc->dev, "failed to write SYS_CTL%d: %d\n", 63 restart ? 0 : 1, ret); 64 return ret; 65 } 66 67 /* Wait for trigger completion */ 68 mdelay(200); 69 70 return 0; 71 } 72 73 static int atc2609a_do_poweroff(const struct atc260x_pwrc *pwrc, bool restart) 74 { 75 int ret, deep_sleep = 0; 76 uint reg_mask, reg_val; 77 78 /* S4-Deep Sleep Mode is NOT available for WALL/USB power */ 79 if (!restart && !power_supply_is_system_supplied()) { 80 deep_sleep = 1; 81 dev_info(pwrc->dev, "Enabling S4-Deep Sleep Mode"); 82 } 83 84 /* Update wakeup sources */ 85 reg_val = ATC2609A_PMU_SYS_CTL0_ONOFF_LONG_WK_EN | 86 (restart ? ATC2609A_PMU_SYS_CTL0_RESET_WK_EN 87 : ATC2609A_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN); 88 89 ret = regmap_update_bits(pwrc->regmap, ATC2609A_PMU_SYS_CTL0, 90 ATC2609A_PMU_SYS_CTL0_WK_ALL, reg_val); 91 if (ret) 92 dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret); 93 94 /* Update power mode */ 95 reg_mask = ATC2609A_PMU_SYS_CTL3_EN_S2 | ATC2609A_PMU_SYS_CTL3_EN_S3; 96 97 ret = regmap_update_bits(pwrc->regmap, ATC2609A_PMU_SYS_CTL3, reg_mask, 98 deep_sleep ? 0 : ATC2609A_PMU_SYS_CTL3_EN_S3); 99 if (ret) { 100 dev_err(pwrc->dev, "failed to write SYS_CTL3: %d\n", ret); 101 return ret; 102 } 103 104 /* Trigger poweroff / restart sequence */ 105 reg_mask = restart ? ATC2609A_PMU_SYS_CTL0_RESTART_EN 106 : ATC2609A_PMU_SYS_CTL1_EN_S1; 107 reg_val = restart ? ATC2609A_PMU_SYS_CTL0_RESTART_EN : 0; 108 109 ret = regmap_update_bits(pwrc->regmap, 110 restart ? ATC2609A_PMU_SYS_CTL0 : ATC2609A_PMU_SYS_CTL1, 111 reg_mask, reg_val); 112 if (ret) { 113 dev_err(pwrc->dev, "failed to write SYS_CTL%d: %d\n", 114 restart ? 0 : 1, ret); 115 return ret; 116 } 117 118 /* Wait for trigger completion */ 119 mdelay(200); 120 121 return 0; 122 } 123 124 static int atc2603c_init(const struct atc260x_pwrc *pwrc) 125 { 126 int ret; 127 128 /* 129 * Delay transition from S2/S3 to S1 in order to avoid 130 * DDR init failure in Bootloader. 131 */ 132 ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL3, 133 ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN, 134 ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN); 135 if (ret) 136 dev_warn(pwrc->dev, "failed to write SYS_CTL3: %d\n", ret); 137 138 /* Set wakeup sources */ 139 ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL0, 140 ATC2603C_PMU_SYS_CTL0_WK_ALL, 141 ATC2603C_PMU_SYS_CTL0_HDSW_WK_EN | 142 ATC2603C_PMU_SYS_CTL0_ONOFF_LONG_WK_EN); 143 if (ret) 144 dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret); 145 146 return ret; 147 } 148 149 static int atc2609a_init(const struct atc260x_pwrc *pwrc) 150 { 151 int ret; 152 153 /* Set wakeup sources */ 154 ret = regmap_update_bits(pwrc->regmap, ATC2609A_PMU_SYS_CTL0, 155 ATC2609A_PMU_SYS_CTL0_WK_ALL, 156 ATC2609A_PMU_SYS_CTL0_HDSW_WK_EN | 157 ATC2609A_PMU_SYS_CTL0_ONOFF_LONG_WK_EN); 158 if (ret) 159 dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret); 160 161 return ret; 162 } 163 164 static int atc260x_pwrc_pm_handler(struct sys_off_data *data) 165 { 166 struct atc260x_pwrc *pwrc = data->cb_data; 167 168 pwrc->do_poweroff(pwrc, false); 169 170 WARN_ONCE(1, "Unable to power off system\n"); 171 172 return NOTIFY_DONE; 173 } 174 175 static int atc260x_pwrc_restart_handler(struct sys_off_data *data) 176 { 177 struct atc260x_pwrc *pwrc = data->cb_data; 178 pwrc->do_poweroff(pwrc, true); 179 180 return NOTIFY_DONE; 181 } 182 183 static int atc260x_pwrc_probe(struct platform_device *pdev) 184 { 185 struct atc260x *atc260x = dev_get_drvdata(pdev->dev.parent); 186 struct atc260x_pwrc *priv; 187 int ret; 188 189 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 190 if (!priv) 191 return -ENOMEM; 192 193 priv->dev = &pdev->dev; 194 priv->regmap = atc260x->regmap; 195 196 switch (atc260x->ic_type) { 197 case ATC2603C: 198 priv->do_poweroff = atc2603c_do_poweroff; 199 ret = atc2603c_init(priv); 200 break; 201 case ATC2609A: 202 priv->do_poweroff = atc2609a_do_poweroff; 203 ret = atc2609a_init(priv); 204 break; 205 default: 206 dev_err(priv->dev, 207 "Poweroff not supported for ATC260x PMIC type: %u\n", 208 atc260x->ic_type); 209 return -EINVAL; 210 } 211 212 if (ret) 213 return ret; 214 215 ret = devm_register_sys_off_handler(priv->dev, 216 SYS_OFF_MODE_POWER_OFF, 217 SYS_OFF_PRIO_DEFAULT, 218 atc260x_pwrc_pm_handler, 219 priv); 220 if (ret) 221 dev_err(priv->dev, "failed to register power-off handler: %d\n", 222 ret); 223 224 ret = devm_register_sys_off_handler(priv->dev, 225 SYS_OFF_MODE_RESTART, 226 SYS_OFF_PRIO_HIGH, 227 atc260x_pwrc_restart_handler, 228 priv); 229 if (ret) 230 dev_err(priv->dev, "failed to register restart handler: %d\n", 231 ret); 232 233 return ret; 234 } 235 236 static struct platform_driver atc260x_pwrc_driver = { 237 .probe = atc260x_pwrc_probe, 238 .driver = { 239 .name = "atc260x-pwrc", 240 }, 241 }; 242 243 module_platform_driver(atc260x_pwrc_driver); 244 245 MODULE_DESCRIPTION("Poweroff & reset driver for ATC260x PMICs"); 246 MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>"); 247 MODULE_LICENSE("GPL"); 248