turris-omnia-mcu-sys-off-wakeup.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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. #include <linux/crc32.h>
  14. #include <linux/delay.h>
  15. #include <linux/device.h>
  16. #include <linux/err.h>
  17. #include <linux/i2c.h>
  18. #include <linux/kstrtox.h>
  19. #include <linux/reboot.h>
  20. #include <linux/rtc.h>
  21. #include <linux/sysfs.h>
  22. #include <linux/types.h>
  23. #include <linux/turris-omnia-mcu-interface.h>
  24. #include "turris-omnia-mcu.h"
  25. static int omnia_get_uptime_wakeup(const struct i2c_client *client, u32 *uptime,
  26. u32 *wakeup)
  27. {
  28. __le32 reply[2];
  29. int err;
  30. err = omnia_cmd_read(client, OMNIA_CMD_GET_UPTIME_AND_WAKEUP, reply,
  31. sizeof(reply));
  32. if (err)
  33. return err;
  34. if (uptime)
  35. *uptime = le32_to_cpu(reply[0]);
  36. if (wakeup)
  37. *wakeup = le32_to_cpu(reply[1]);
  38. return 0;
  39. }
  40. static int omnia_read_time(struct device *dev, struct rtc_time *tm)
  41. {
  42. u32 uptime;
  43. int err;
  44. err = omnia_get_uptime_wakeup(to_i2c_client(dev), &uptime, NULL);
  45. if (err)
  46. return err;
  47. rtc_time64_to_tm(uptime, tm);
  48. return 0;
  49. }
  50. static int omnia_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  51. {
  52. struct i2c_client *client = to_i2c_client(dev);
  53. struct omnia_mcu *mcu = i2c_get_clientdata(client);
  54. u32 wakeup;
  55. int err;
  56. err = omnia_get_uptime_wakeup(client, NULL, &wakeup);
  57. if (err)
  58. return err;
  59. alrm->enabled = !!wakeup;
  60. rtc_time64_to_tm(wakeup ?: mcu->rtc_alarm, &alrm->time);
  61. return 0;
  62. }
  63. static int omnia_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  64. {
  65. struct i2c_client *client = to_i2c_client(dev);
  66. struct omnia_mcu *mcu = i2c_get_clientdata(client);
  67. mcu->rtc_alarm = rtc_tm_to_time64(&alrm->time);
  68. if (alrm->enabled)
  69. return omnia_cmd_write_u32(client, OMNIA_CMD_SET_WAKEUP,
  70. mcu->rtc_alarm);
  71. return 0;
  72. }
  73. static int omnia_alarm_irq_enable(struct device *dev, unsigned int enabled)
  74. {
  75. struct i2c_client *client = to_i2c_client(dev);
  76. struct omnia_mcu *mcu = i2c_get_clientdata(client);
  77. return omnia_cmd_write_u32(client, OMNIA_CMD_SET_WAKEUP,
  78. enabled ? mcu->rtc_alarm : 0);
  79. }
  80. static const struct rtc_class_ops omnia_rtc_ops = {
  81. .read_time = omnia_read_time,
  82. .read_alarm = omnia_read_alarm,
  83. .set_alarm = omnia_set_alarm,
  84. .alarm_irq_enable = omnia_alarm_irq_enable,
  85. };
  86. static int omnia_power_off(struct sys_off_data *data)
  87. {
  88. struct omnia_mcu *mcu = data->cb_data;
  89. __be32 tmp;
  90. u8 cmd[9];
  91. u16 arg;
  92. int err;
  93. if (mcu->front_button_poweron)
  94. arg = OMNIA_CMD_POWER_OFF_POWERON_BUTTON;
  95. else
  96. arg = 0;
  97. cmd[0] = OMNIA_CMD_POWER_OFF;
  98. put_unaligned_le16(OMNIA_CMD_POWER_OFF_MAGIC, &cmd[1]);
  99. put_unaligned_le16(arg, &cmd[3]);
  100. /*
  101. * Although all values from and to MCU are passed in little-endian, the
  102. * MCU's CRC unit uses big-endian CRC32 polynomial (0x04c11db7), so we
  103. * need to use crc32_be() here.
  104. */
  105. tmp = cpu_to_be32(get_unaligned_le32(&cmd[1]));
  106. put_unaligned_le32(crc32_be(~0, (void *)&tmp, sizeof(tmp)), &cmd[5]);
  107. err = omnia_cmd_write(mcu->client, cmd, sizeof(cmd));
  108. if (err)
  109. dev_err(&mcu->client->dev,
  110. "Unable to send the poweroff command: %d\n", err);
  111. return NOTIFY_DONE;
  112. }
  113. static int omnia_restart(struct sys_off_data *data)
  114. {
  115. struct omnia_mcu *mcu = data->cb_data;
  116. u8 cmd[3];
  117. int err;
  118. cmd[0] = OMNIA_CMD_GENERAL_CONTROL;
  119. if (reboot_mode == REBOOT_HARD)
  120. cmd[1] = cmd[2] = OMNIA_CTL_HARD_RST;
  121. else
  122. cmd[1] = cmd[2] = OMNIA_CTL_LIGHT_RST;
  123. err = omnia_cmd_write(mcu->client, cmd, sizeof(cmd));
  124. if (err)
  125. dev_err(&mcu->client->dev,
  126. "Unable to send the restart command: %d\n", err);
  127. /*
  128. * MCU needs a little bit to process the I2C command, otherwise it will
  129. * do a light reset based on SOC SYSRES_OUT pin.
  130. */
  131. mdelay(1);
  132. return NOTIFY_DONE;
  133. }
  134. static ssize_t front_button_poweron_show(struct device *dev,
  135. struct device_attribute *a, char *buf)
  136. {
  137. struct omnia_mcu *mcu = dev_get_drvdata(dev);
  138. return sysfs_emit(buf, "%d\n", mcu->front_button_poweron);
  139. }
  140. static ssize_t front_button_poweron_store(struct device *dev,
  141. struct device_attribute *a,
  142. const char *buf, size_t count)
  143. {
  144. struct omnia_mcu *mcu = dev_get_drvdata(dev);
  145. bool val;
  146. int err;
  147. err = kstrtobool(buf, &val);
  148. if (err)
  149. return err;
  150. mcu->front_button_poweron = val;
  151. return count;
  152. }
  153. static DEVICE_ATTR_RW(front_button_poweron);
  154. static struct attribute *omnia_mcu_poweroff_attrs[] = {
  155. &dev_attr_front_button_poweron.attr,
  156. NULL
  157. };
  158. static umode_t poweroff_attrs_visible(struct kobject *kobj, struct attribute *a,
  159. int n)
  160. {
  161. struct device *dev = kobj_to_dev(kobj);
  162. struct omnia_mcu *mcu = dev_get_drvdata(dev);
  163. if (mcu->features & OMNIA_FEAT_POWEROFF_WAKEUP)
  164. return a->mode;
  165. return 0;
  166. }
  167. const struct attribute_group omnia_mcu_poweroff_group = {
  168. .attrs = omnia_mcu_poweroff_attrs,
  169. .is_visible = poweroff_attrs_visible,
  170. };
  171. int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu)
  172. {
  173. struct device *dev = &mcu->client->dev;
  174. int err;
  175. /* MCU restart is always available */
  176. err = devm_register_sys_off_handler(dev, SYS_OFF_MODE_RESTART,
  177. SYS_OFF_PRIO_FIRMWARE,
  178. omnia_restart, mcu);
  179. if (err)
  180. return dev_err_probe(dev, err,
  181. "Cannot register system restart handler\n");
  182. /*
  183. * Poweroff and wakeup are available only if POWEROFF_WAKEUP feature is
  184. * present.
  185. */
  186. if (!(mcu->features & OMNIA_FEAT_POWEROFF_WAKEUP))
  187. return 0;
  188. err = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF,
  189. SYS_OFF_PRIO_FIRMWARE,
  190. omnia_power_off, mcu);
  191. if (err)
  192. return dev_err_probe(dev, err,
  193. "Cannot register system power off handler\n");
  194. mcu->rtcdev = devm_rtc_allocate_device(dev);
  195. if (IS_ERR(mcu->rtcdev))
  196. return dev_err_probe(dev, PTR_ERR(mcu->rtcdev),
  197. "Cannot allocate RTC device\n");
  198. mcu->rtcdev->ops = &omnia_rtc_ops;
  199. mcu->rtcdev->range_max = U32_MAX;
  200. set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, mcu->rtcdev->features);
  201. err = devm_rtc_register_device(mcu->rtcdev);
  202. if (err)
  203. return dev_err_probe(dev, err, "Cannot register RTC device\n");
  204. mcu->front_button_poweron = true;
  205. return 0;
  206. }