0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/delay.h>
0009 #include <linux/mfd/atc260x/core.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/power_supply.h>
0013 #include <linux/reboot.h>
0014 #include <linux/regmap.h>
0015
0016 struct atc260x_pwrc {
0017 struct device *dev;
0018 struct regmap *regmap;
0019 struct notifier_block restart_nb;
0020 int (*do_poweroff)(const struct atc260x_pwrc *pwrc, bool restart);
0021 };
0022
0023
0024 static struct atc260x_pwrc *atc260x_pwrc_data;
0025
0026 static int atc2603c_do_poweroff(const struct atc260x_pwrc *pwrc, bool restart)
0027 {
0028 int ret, deep_sleep = 0;
0029 uint reg_mask, reg_val;
0030
0031
0032 if (!restart && !power_supply_is_system_supplied()) {
0033 deep_sleep = 1;
0034 dev_info(pwrc->dev, "Enabling S4-Deep Sleep Mode");
0035 }
0036
0037
0038 reg_val = ATC2603C_PMU_SYS_CTL0_ONOFF_LONG_WK_EN |
0039 (restart ? ATC2603C_PMU_SYS_CTL0_RESET_WK_EN
0040 : ATC2603C_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN);
0041
0042 ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL0,
0043 ATC2603C_PMU_SYS_CTL0_WK_ALL, reg_val);
0044 if (ret)
0045 dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret);
0046
0047
0048 reg_mask = ATC2603C_PMU_SYS_CTL3_EN_S2 | ATC2603C_PMU_SYS_CTL3_EN_S3;
0049
0050 ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL3, reg_mask,
0051 deep_sleep ? 0 : ATC2603C_PMU_SYS_CTL3_EN_S3);
0052 if (ret) {
0053 dev_err(pwrc->dev, "failed to write SYS_CTL3: %d\n", ret);
0054 return ret;
0055 }
0056
0057
0058 reg_mask = restart ? ATC2603C_PMU_SYS_CTL0_RESTART_EN
0059 : ATC2603C_PMU_SYS_CTL1_EN_S1;
0060 reg_val = restart ? ATC2603C_PMU_SYS_CTL0_RESTART_EN : 0;
0061
0062 ret = regmap_update_bits(pwrc->regmap,
0063 restart ? ATC2603C_PMU_SYS_CTL0 : ATC2603C_PMU_SYS_CTL1,
0064 reg_mask, reg_val);
0065 if (ret) {
0066 dev_err(pwrc->dev, "failed to write SYS_CTL%d: %d\n",
0067 restart ? 0 : 1, ret);
0068 return ret;
0069 }
0070
0071
0072 mdelay(200);
0073
0074 return 0;
0075 }
0076
0077 static int atc2609a_do_poweroff(const struct atc260x_pwrc *pwrc, bool restart)
0078 {
0079 int ret, deep_sleep = 0;
0080 uint reg_mask, reg_val;
0081
0082
0083 if (!restart && !power_supply_is_system_supplied()) {
0084 deep_sleep = 1;
0085 dev_info(pwrc->dev, "Enabling S4-Deep Sleep Mode");
0086 }
0087
0088
0089 reg_val = ATC2609A_PMU_SYS_CTL0_ONOFF_LONG_WK_EN |
0090 (restart ? ATC2609A_PMU_SYS_CTL0_RESET_WK_EN
0091 : ATC2609A_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN);
0092
0093 ret = regmap_update_bits(pwrc->regmap, ATC2609A_PMU_SYS_CTL0,
0094 ATC2609A_PMU_SYS_CTL0_WK_ALL, reg_val);
0095 if (ret)
0096 dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret);
0097
0098
0099 reg_mask = ATC2609A_PMU_SYS_CTL3_EN_S2 | ATC2609A_PMU_SYS_CTL3_EN_S3;
0100
0101 ret = regmap_update_bits(pwrc->regmap, ATC2609A_PMU_SYS_CTL3, reg_mask,
0102 deep_sleep ? 0 : ATC2609A_PMU_SYS_CTL3_EN_S3);
0103 if (ret) {
0104 dev_err(pwrc->dev, "failed to write SYS_CTL3: %d\n", ret);
0105 return ret;
0106 }
0107
0108
0109 reg_mask = restart ? ATC2609A_PMU_SYS_CTL0_RESTART_EN
0110 : ATC2609A_PMU_SYS_CTL1_EN_S1;
0111 reg_val = restart ? ATC2609A_PMU_SYS_CTL0_RESTART_EN : 0;
0112
0113 ret = regmap_update_bits(pwrc->regmap,
0114 restart ? ATC2609A_PMU_SYS_CTL0 : ATC2609A_PMU_SYS_CTL1,
0115 reg_mask, reg_val);
0116 if (ret) {
0117 dev_err(pwrc->dev, "failed to write SYS_CTL%d: %d\n",
0118 restart ? 0 : 1, ret);
0119 return ret;
0120 }
0121
0122
0123 mdelay(200);
0124
0125 return 0;
0126 }
0127
0128 static int atc2603c_init(const struct atc260x_pwrc *pwrc)
0129 {
0130 int ret;
0131
0132
0133
0134
0135
0136 ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL3,
0137 ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN,
0138 ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN);
0139 if (ret)
0140 dev_warn(pwrc->dev, "failed to write SYS_CTL3: %d\n", ret);
0141
0142
0143 ret = regmap_update_bits(pwrc->regmap, ATC2603C_PMU_SYS_CTL0,
0144 ATC2603C_PMU_SYS_CTL0_WK_ALL,
0145 ATC2603C_PMU_SYS_CTL0_HDSW_WK_EN |
0146 ATC2603C_PMU_SYS_CTL0_ONOFF_LONG_WK_EN);
0147 if (ret)
0148 dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret);
0149
0150 return ret;
0151 }
0152
0153 static int atc2609a_init(const struct atc260x_pwrc *pwrc)
0154 {
0155 int ret;
0156
0157
0158 ret = regmap_update_bits(pwrc->regmap, ATC2609A_PMU_SYS_CTL0,
0159 ATC2609A_PMU_SYS_CTL0_WK_ALL,
0160 ATC2609A_PMU_SYS_CTL0_HDSW_WK_EN |
0161 ATC2609A_PMU_SYS_CTL0_ONOFF_LONG_WK_EN);
0162 if (ret)
0163 dev_warn(pwrc->dev, "failed to write SYS_CTL0: %d\n", ret);
0164
0165 return ret;
0166 }
0167
0168 static void atc260x_pwrc_pm_handler(void)
0169 {
0170 atc260x_pwrc_data->do_poweroff(atc260x_pwrc_data, false);
0171
0172 WARN_ONCE(1, "Unable to power off system\n");
0173 }
0174
0175 static int atc260x_pwrc_restart_handler(struct notifier_block *nb,
0176 unsigned long mode, void *cmd)
0177 {
0178 struct atc260x_pwrc *pwrc = container_of(nb, struct atc260x_pwrc,
0179 restart_nb);
0180 pwrc->do_poweroff(pwrc, true);
0181
0182 return NOTIFY_DONE;
0183 }
0184
0185 static int atc260x_pwrc_probe(struct platform_device *pdev)
0186 {
0187 struct atc260x *atc260x = dev_get_drvdata(pdev->dev.parent);
0188 struct atc260x_pwrc *priv;
0189 int ret;
0190
0191 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0192 if (!priv)
0193 return -ENOMEM;
0194
0195 priv->dev = &pdev->dev;
0196 priv->regmap = atc260x->regmap;
0197 priv->restart_nb.notifier_call = atc260x_pwrc_restart_handler;
0198 priv->restart_nb.priority = 192;
0199
0200 switch (atc260x->ic_type) {
0201 case ATC2603C:
0202 priv->do_poweroff = atc2603c_do_poweroff;
0203 ret = atc2603c_init(priv);
0204 break;
0205 case ATC2609A:
0206 priv->do_poweroff = atc2609a_do_poweroff;
0207 ret = atc2609a_init(priv);
0208 break;
0209 default:
0210 dev_err(priv->dev,
0211 "Poweroff not supported for ATC260x PMIC type: %u\n",
0212 atc260x->ic_type);
0213 return -EINVAL;
0214 }
0215
0216 if (ret)
0217 return ret;
0218
0219 platform_set_drvdata(pdev, priv);
0220
0221 if (!pm_power_off) {
0222 atc260x_pwrc_data = priv;
0223 pm_power_off = atc260x_pwrc_pm_handler;
0224 } else {
0225 dev_warn(priv->dev, "Poweroff callback already assigned\n");
0226 }
0227
0228 ret = register_restart_handler(&priv->restart_nb);
0229 if (ret)
0230 dev_err(priv->dev, "failed to register restart handler: %d\n",
0231 ret);
0232
0233 return ret;
0234 }
0235
0236 static int atc260x_pwrc_remove(struct platform_device *pdev)
0237 {
0238 struct atc260x_pwrc *priv = platform_get_drvdata(pdev);
0239
0240 if (atc260x_pwrc_data == priv) {
0241 pm_power_off = NULL;
0242 atc260x_pwrc_data = NULL;
0243 }
0244
0245 unregister_restart_handler(&priv->restart_nb);
0246
0247 return 0;
0248 }
0249
0250 static struct platform_driver atc260x_pwrc_driver = {
0251 .probe = atc260x_pwrc_probe,
0252 .remove = atc260x_pwrc_remove,
0253 .driver = {
0254 .name = "atc260x-pwrc",
0255 },
0256 };
0257
0258 module_platform_driver(atc260x_pwrc_driver);
0259
0260 MODULE_DESCRIPTION("Poweroff & reset driver for ATC260x PMICs");
0261 MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
0262 MODULE_LICENSE("GPL");