1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * CZ.NIC's Turris Omnia MCU system off and RTC wakeup driver 4 * 5 * This is not a true RTC driver (in the sense that it does not provide a 6 * real-time clock), rather the MCU implements a wakeup from powered off state 7 * at a specified time relative to MCU boot, and we expose this feature via RTC 8 * alarm, so that it can be used via the rtcwake command, which is the standard 9 * Linux command for this. 10 * 11 * 2024 by Marek Behún <kabel@kernel.org> 12 */ 13 14 #include <linux/crc32.h> 15 #include <linux/delay.h> 16 #include <linux/device.h> 17 #include <linux/err.h> 18 #include <linux/i2c.h> 19 #include <linux/kstrtox.h> 20 #include <linux/reboot.h> 21 #include <linux/rtc.h> 22 #include <linux/sysfs.h> 23 #include <linux/types.h> 24 25 #include <linux/turris-omnia-mcu-interface.h> 26 #include "turris-omnia-mcu.h" 27 28 static int omnia_get_uptime_wakeup(const struct i2c_client *client, u32 *uptime, 29 u32 *wakeup) 30 { 31 __le32 reply[2]; 32 int err; 33 34 err = omnia_cmd_read(client, OMNIA_CMD_GET_UPTIME_AND_WAKEUP, reply, 35 sizeof(reply)); 36 if (err) 37 return err; 38 39 if (uptime) 40 *uptime = le32_to_cpu(reply[0]); 41 42 if (wakeup) 43 *wakeup = le32_to_cpu(reply[1]); 44 45 return 0; 46 } 47 48 static int omnia_read_time(struct device *dev, struct rtc_time *tm) 49 { 50 u32 uptime; 51 int err; 52 53 err = omnia_get_uptime_wakeup(to_i2c_client(dev), &uptime, NULL); 54 if (err) 55 return err; 56 57 rtc_time64_to_tm(uptime, tm); 58 59 return 0; 60 } 61 62 static int omnia_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 63 { 64 struct i2c_client *client = to_i2c_client(dev); 65 struct omnia_mcu *mcu = i2c_get_clientdata(client); 66 u32 wakeup; 67 int err; 68 69 err = omnia_get_uptime_wakeup(client, NULL, &wakeup); 70 if (err) 71 return err; 72 73 alrm->enabled = !!wakeup; 74 rtc_time64_to_tm(wakeup ?: mcu->rtc_alarm, &alrm->time); 75 76 return 0; 77 } 78 79 static int omnia_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 80 { 81 struct i2c_client *client = to_i2c_client(dev); 82 struct omnia_mcu *mcu = i2c_get_clientdata(client); 83 84 mcu->rtc_alarm = rtc_tm_to_time64(&alrm->time); 85 86 if (alrm->enabled) 87 return omnia_cmd_write_u32(client, OMNIA_CMD_SET_WAKEUP, 88 mcu->rtc_alarm); 89 90 return 0; 91 } 92 93 static int omnia_alarm_irq_enable(struct device *dev, unsigned int enabled) 94 { 95 struct i2c_client *client = to_i2c_client(dev); 96 struct omnia_mcu *mcu = i2c_get_clientdata(client); 97 98 return omnia_cmd_write_u32(client, OMNIA_CMD_SET_WAKEUP, 99 enabled ? mcu->rtc_alarm : 0); 100 } 101 102 static const struct rtc_class_ops omnia_rtc_ops = { 103 .read_time = omnia_read_time, 104 .read_alarm = omnia_read_alarm, 105 .set_alarm = omnia_set_alarm, 106 .alarm_irq_enable = omnia_alarm_irq_enable, 107 }; 108 109 static int omnia_power_off(struct sys_off_data *data) 110 { 111 struct omnia_mcu *mcu = data->cb_data; 112 __be32 tmp; 113 u8 cmd[9]; 114 u16 arg; 115 int err; 116 117 if (mcu->front_button_poweron) 118 arg = OMNIA_CMD_POWER_OFF_POWERON_BUTTON; 119 else 120 arg = 0; 121 122 cmd[0] = OMNIA_CMD_POWER_OFF; 123 put_unaligned_le16(OMNIA_CMD_POWER_OFF_MAGIC, &cmd[1]); 124 put_unaligned_le16(arg, &cmd[3]); 125 126 /* 127 * Although all values from and to MCU are passed in little-endian, the 128 * MCU's CRC unit uses big-endian CRC32 polynomial (0x04c11db7), so we 129 * need to use crc32_be() here. 130 */ 131 tmp = cpu_to_be32(get_unaligned_le32(&cmd[1])); 132 put_unaligned_le32(crc32_be(~0, (void *)&tmp, sizeof(tmp)), &cmd[5]); 133 134 err = omnia_cmd_write(mcu->client, cmd, sizeof(cmd)); 135 if (err) 136 dev_err(&mcu->client->dev, 137 "Unable to send the poweroff command: %d\n", err); 138 139 return NOTIFY_DONE; 140 } 141 142 static int omnia_restart(struct sys_off_data *data) 143 { 144 struct omnia_mcu *mcu = data->cb_data; 145 u8 cmd[3]; 146 int err; 147 148 cmd[0] = OMNIA_CMD_GENERAL_CONTROL; 149 150 if (reboot_mode == REBOOT_HARD) 151 cmd[1] = cmd[2] = OMNIA_CTL_HARD_RST; 152 else 153 cmd[1] = cmd[2] = OMNIA_CTL_LIGHT_RST; 154 155 err = omnia_cmd_write(mcu->client, cmd, sizeof(cmd)); 156 if (err) 157 dev_err(&mcu->client->dev, 158 "Unable to send the restart command: %d\n", err); 159 160 /* 161 * MCU needs a little bit to process the I2C command, otherwise it will 162 * do a light reset based on SOC SYSRES_OUT pin. 163 */ 164 mdelay(1); 165 166 return NOTIFY_DONE; 167 } 168 169 static ssize_t front_button_poweron_show(struct device *dev, 170 struct device_attribute *a, char *buf) 171 { 172 struct omnia_mcu *mcu = dev_get_drvdata(dev); 173 174 return sysfs_emit(buf, "%d\n", mcu->front_button_poweron); 175 } 176 177 static ssize_t front_button_poweron_store(struct device *dev, 178 struct device_attribute *a, 179 const char *buf, size_t count) 180 { 181 struct omnia_mcu *mcu = dev_get_drvdata(dev); 182 bool val; 183 int err; 184 185 err = kstrtobool(buf, &val); 186 if (err) 187 return err; 188 189 mcu->front_button_poweron = val; 190 191 return count; 192 } 193 static DEVICE_ATTR_RW(front_button_poweron); 194 195 static struct attribute *omnia_mcu_poweroff_attrs[] = { 196 &dev_attr_front_button_poweron.attr, 197 NULL 198 }; 199 200 static umode_t poweroff_attrs_visible(struct kobject *kobj, struct attribute *a, 201 int n) 202 { 203 struct device *dev = kobj_to_dev(kobj); 204 struct omnia_mcu *mcu = dev_get_drvdata(dev); 205 206 if (mcu->features & OMNIA_FEAT_POWEROFF_WAKEUP) 207 return a->mode; 208 209 return 0; 210 } 211 212 const struct attribute_group omnia_mcu_poweroff_group = { 213 .attrs = omnia_mcu_poweroff_attrs, 214 .is_visible = poweroff_attrs_visible, 215 }; 216 217 int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu) 218 { 219 struct device *dev = &mcu->client->dev; 220 int err; 221 222 /* MCU restart is always available */ 223 err = devm_register_sys_off_handler(dev, SYS_OFF_MODE_RESTART, 224 SYS_OFF_PRIO_FIRMWARE, 225 omnia_restart, mcu); 226 if (err) 227 return dev_err_probe(dev, err, 228 "Cannot register system restart handler\n"); 229 230 /* 231 * Poweroff and wakeup are available only if POWEROFF_WAKEUP feature is 232 * present. 233 */ 234 if (!(mcu->features & OMNIA_FEAT_POWEROFF_WAKEUP)) 235 return 0; 236 237 err = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF, 238 SYS_OFF_PRIO_FIRMWARE, 239 omnia_power_off, mcu); 240 if (err) 241 return dev_err_probe(dev, err, 242 "Cannot register system power off handler\n"); 243 244 mcu->rtcdev = devm_rtc_allocate_device(dev); 245 if (IS_ERR(mcu->rtcdev)) 246 return dev_err_probe(dev, PTR_ERR(mcu->rtcdev), 247 "Cannot allocate RTC device\n"); 248 249 mcu->rtcdev->ops = &omnia_rtc_ops; 250 mcu->rtcdev->range_max = U32_MAX; 251 set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, mcu->rtcdev->features); 252 253 err = devm_rtc_register_device(mcu->rtcdev); 254 if (err) 255 return dev_err_probe(dev, err, "Cannot register RTC device\n"); 256 257 mcu->front_button_poweron = true; 258 259 return 0; 260 } 261