0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/err.h>
0010 #include <linux/init.h>
0011 #include <linux/export.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/pm.h>
0014 #include <linux/reboot.h>
0015 #include <linux/signal.h>
0016 #include <linux/power_supply.h>
0017 #include <linux/mfd/abx500.h>
0018 #include <linux/mfd/abx500/ab8500.h>
0019 #include <linux/mfd/abx500/ab8500-sysctrl.h>
0020
0021
0022 #define AB8500_ALARM_MIN_LOW 0x08
0023 #define AB8500_ALARM_MIN_MID 0x09
0024 #define RTC_CTRL 0x0B
0025 #define RTC_ALARM_ENABLE 0x4
0026
0027 static struct device *sysctrl_dev;
0028
0029 static void ab8500_power_off(void)
0030 {
0031 sigset_t old;
0032 sigset_t all;
0033 static const char * const pss[] = {"ab8500_ac", "pm2301", "ab8500_usb"};
0034 int i;
0035 bool charger_present = false;
0036 union power_supply_propval val;
0037 struct power_supply *psy;
0038 int ret;
0039
0040 if (sysctrl_dev == NULL) {
0041 pr_err("%s: sysctrl not initialized\n", __func__);
0042 return;
0043 }
0044
0045
0046
0047
0048
0049
0050 for (i = 0; i < ARRAY_SIZE(pss); i++) {
0051 psy = power_supply_get_by_name(pss[i]);
0052 if (!psy)
0053 continue;
0054
0055 ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE,
0056 &val);
0057 power_supply_put(psy);
0058
0059 if (!ret && val.intval) {
0060 charger_present = true;
0061 break;
0062 }
0063 }
0064
0065 if (!charger_present)
0066 goto shutdown;
0067
0068
0069 psy = power_supply_get_by_name("ab8500_btemp");
0070 if (psy) {
0071 ret = power_supply_get_property(psy,
0072 POWER_SUPPLY_PROP_TECHNOLOGY, &val);
0073 if (!ret && val.intval != POWER_SUPPLY_TECHNOLOGY_UNKNOWN) {
0074 pr_info("Charger '%s' is connected with known battery",
0075 pss[i]);
0076 pr_info(" - Rebooting.\n");
0077 machine_restart("charging");
0078 }
0079 power_supply_put(psy);
0080 }
0081
0082 shutdown:
0083 sigfillset(&all);
0084
0085 if (!sigprocmask(SIG_BLOCK, &all, &old)) {
0086 (void)ab8500_sysctrl_set(AB8500_STW4500CTRL1,
0087 AB8500_STW4500CTRL1_SWOFF |
0088 AB8500_STW4500CTRL1_SWRESET4500N);
0089 (void)sigprocmask(SIG_SETMASK, &old, NULL);
0090 }
0091 }
0092
0093 static inline bool valid_bank(u8 bank)
0094 {
0095 return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
0096 (bank == AB8500_SYS_CTRL2_BLOCK));
0097 }
0098
0099 int ab8500_sysctrl_read(u16 reg, u8 *value)
0100 {
0101 u8 bank;
0102
0103 if (sysctrl_dev == NULL)
0104 return -EPROBE_DEFER;
0105
0106 bank = (reg >> 8);
0107 if (!valid_bank(bank))
0108 return -EINVAL;
0109
0110 return abx500_get_register_interruptible(sysctrl_dev, bank,
0111 (u8)(reg & 0xFF), value);
0112 }
0113 EXPORT_SYMBOL(ab8500_sysctrl_read);
0114
0115 int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
0116 {
0117 u8 bank;
0118
0119 if (sysctrl_dev == NULL)
0120 return -EPROBE_DEFER;
0121
0122 bank = (reg >> 8);
0123 if (!valid_bank(bank)) {
0124 pr_err("invalid bank\n");
0125 return -EINVAL;
0126 }
0127
0128 return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
0129 (u8)(reg & 0xFF), mask, value);
0130 }
0131 EXPORT_SYMBOL(ab8500_sysctrl_write);
0132
0133 static int ab8500_sysctrl_probe(struct platform_device *pdev)
0134 {
0135 sysctrl_dev = &pdev->dev;
0136
0137 if (!pm_power_off)
0138 pm_power_off = ab8500_power_off;
0139
0140 return 0;
0141 }
0142
0143 static int ab8500_sysctrl_remove(struct platform_device *pdev)
0144 {
0145 sysctrl_dev = NULL;
0146
0147 if (pm_power_off == ab8500_power_off)
0148 pm_power_off = NULL;
0149
0150 return 0;
0151 }
0152
0153 static const struct of_device_id ab8500_sysctrl_match[] = {
0154 { .compatible = "stericsson,ab8500-sysctrl", },
0155 {}
0156 };
0157
0158 static struct platform_driver ab8500_sysctrl_driver = {
0159 .driver = {
0160 .name = "ab8500-sysctrl",
0161 .of_match_table = ab8500_sysctrl_match,
0162 },
0163 .probe = ab8500_sysctrl_probe,
0164 .remove = ab8500_sysctrl_remove,
0165 };
0166
0167 static int __init ab8500_sysctrl_init(void)
0168 {
0169 return platform_driver_register(&ab8500_sysctrl_driver);
0170 }
0171 arch_initcall(ab8500_sysctrl_init);