root/drivers/rtc/rtc-opal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. opal_to_tm
  2. tm_to_opal
  3. opal_get_rtc_time
  4. opal_set_rtc_time
  5. opal_get_tpo_time
  6. opal_set_tpo_time
  7. opal_tpo_alarm_irq_enable
  8. opal_rtc_probe
  9. opal_rtc_init
  10. opal_rtc_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * IBM OPAL RTC driver
   4  * Copyright (C) 2014 IBM
   5  */
   6 
   7 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   8 
   9 #define DRVNAME         "rtc-opal"
  10 
  11 #include <linux/module.h>
  12 #include <linux/err.h>
  13 #include <linux/rtc.h>
  14 #include <linux/delay.h>
  15 #include <linux/bcd.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/of.h>
  18 #include <asm/opal.h>
  19 #include <asm/firmware.h>
  20 
  21 static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm)
  22 {
  23         tm->tm_year = ((bcd2bin(y_m_d >> 24) * 100) +
  24                        bcd2bin((y_m_d >> 16) & 0xff)) - 1900;
  25         tm->tm_mon  = bcd2bin((y_m_d >> 8) & 0xff) - 1;
  26         tm->tm_mday = bcd2bin(y_m_d & 0xff);
  27         tm->tm_hour = bcd2bin((h_m_s_ms >> 56) & 0xff);
  28         tm->tm_min  = bcd2bin((h_m_s_ms >> 48) & 0xff);
  29         tm->tm_sec  = bcd2bin((h_m_s_ms >> 40) & 0xff);
  30 
  31         tm->tm_wday = -1;
  32 }
  33 
  34 static void tm_to_opal(struct rtc_time *tm, u32 *y_m_d, u64 *h_m_s_ms)
  35 {
  36         *y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) / 100)) << 24;
  37         *y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) % 100)) << 16;
  38         *y_m_d |= ((u32)bin2bcd((tm->tm_mon + 1))) << 8;
  39         *y_m_d |= ((u32)bin2bcd(tm->tm_mday));
  40 
  41         *h_m_s_ms |= ((u64)bin2bcd(tm->tm_hour)) << 56;
  42         *h_m_s_ms |= ((u64)bin2bcd(tm->tm_min)) << 48;
  43         *h_m_s_ms |= ((u64)bin2bcd(tm->tm_sec)) << 40;
  44 }
  45 
  46 static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm)
  47 {
  48         s64 rc = OPAL_BUSY;
  49         int retries = 10;
  50         u32 y_m_d;
  51         u64 h_m_s_ms;
  52         __be32 __y_m_d;
  53         __be64 __h_m_s_ms;
  54 
  55         while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
  56                 rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms);
  57                 if (rc == OPAL_BUSY_EVENT) {
  58                         msleep(OPAL_BUSY_DELAY_MS);
  59                         opal_poll_events(NULL);
  60                 } else if (rc == OPAL_BUSY) {
  61                         msleep(OPAL_BUSY_DELAY_MS);
  62                 } else if (rc == OPAL_HARDWARE || rc == OPAL_INTERNAL_ERROR) {
  63                         if (retries--) {
  64                                 msleep(10); /* Wait 10ms before retry */
  65                                 rc = OPAL_BUSY; /* go around again */
  66                         }
  67                 }
  68         }
  69 
  70         if (rc != OPAL_SUCCESS)
  71                 return -EIO;
  72 
  73         y_m_d = be32_to_cpu(__y_m_d);
  74         h_m_s_ms = be64_to_cpu(__h_m_s_ms);
  75         opal_to_tm(y_m_d, h_m_s_ms, tm);
  76 
  77         return 0;
  78 }
  79 
  80 static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm)
  81 {
  82         s64 rc = OPAL_BUSY;
  83         int retries = 10;
  84         u32 y_m_d = 0;
  85         u64 h_m_s_ms = 0;
  86 
  87         tm_to_opal(tm, &y_m_d, &h_m_s_ms);
  88 
  89         while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
  90                 rc = opal_rtc_write(y_m_d, h_m_s_ms);
  91                 if (rc == OPAL_BUSY_EVENT) {
  92                         msleep(OPAL_BUSY_DELAY_MS);
  93                         opal_poll_events(NULL);
  94                 } else if (rc == OPAL_BUSY) {
  95                         msleep(OPAL_BUSY_DELAY_MS);
  96                 } else if (rc == OPAL_HARDWARE || rc == OPAL_INTERNAL_ERROR) {
  97                         if (retries--) {
  98                                 msleep(10); /* Wait 10ms before retry */
  99                                 rc = OPAL_BUSY; /* go around again */
 100                         }
 101                 }
 102         }
 103 
 104         return rc == OPAL_SUCCESS ? 0 : -EIO;
 105 }
 106 
 107 /*
 108  * TPO  Timed Power-On
 109  *
 110  * TPO get/set OPAL calls care about the hour and min and to make it consistent
 111  * with the rtc utility time conversion functions, we use the 'u64' to store
 112  * its value and perform bit shift by 32 before use..
 113  */
 114 static int opal_get_tpo_time(struct device *dev, struct rtc_wkalrm *alarm)
 115 {
 116         __be32 __y_m_d, __h_m;
 117         struct opal_msg msg;
 118         int rc, token;
 119         u64 h_m_s_ms;
 120         u32 y_m_d;
 121 
 122         token = opal_async_get_token_interruptible();
 123         if (token < 0) {
 124                 if (token != -ERESTARTSYS)
 125                         pr_err("Failed to get the async token\n");
 126 
 127                 return token;
 128         }
 129 
 130         rc = opal_tpo_read(token, &__y_m_d, &__h_m);
 131         if (rc != OPAL_ASYNC_COMPLETION) {
 132                 rc = -EIO;
 133                 goto exit;
 134         }
 135 
 136         rc = opal_async_wait_response(token, &msg);
 137         if (rc) {
 138                 rc = -EIO;
 139                 goto exit;
 140         }
 141 
 142         rc = opal_get_async_rc(msg);
 143         if (rc != OPAL_SUCCESS) {
 144                 rc = -EIO;
 145                 goto exit;
 146         }
 147 
 148         y_m_d = be32_to_cpu(__y_m_d);
 149         h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32);
 150 
 151         /* check if no alarm is set */
 152         if (y_m_d == 0 && h_m_s_ms == 0) {
 153                 pr_debug("No alarm is set\n");
 154                 rc = -ENOENT;
 155                 goto exit;
 156         } else {
 157                 pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms);
 158         }
 159 
 160         opal_to_tm(y_m_d, h_m_s_ms, &alarm->time);
 161 
 162 exit:
 163         opal_async_release_token(token);
 164         return rc;
 165 }
 166 
 167 /* Set Timed Power-On */
 168 static int opal_set_tpo_time(struct device *dev, struct rtc_wkalrm *alarm)
 169 {
 170         u64 h_m_s_ms = 0;
 171         struct opal_msg msg;
 172         u32 y_m_d = 0;
 173         int token, rc;
 174 
 175         /* if alarm is enabled */
 176         if (alarm->enabled) {
 177                 tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms);
 178                 pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms);
 179 
 180         } else {
 181                 pr_debug("Alarm getting disabled\n");
 182         }
 183 
 184         token = opal_async_get_token_interruptible();
 185         if (token < 0) {
 186                 if (token != -ERESTARTSYS)
 187                         pr_err("Failed to get the async token\n");
 188 
 189                 return token;
 190         }
 191 
 192         /* TPO, we care about hour and minute */
 193         rc = opal_tpo_write(token, y_m_d,
 194                             (u32)((h_m_s_ms >> 32) & 0xffff0000));
 195         if (rc != OPAL_ASYNC_COMPLETION) {
 196                 rc = -EIO;
 197                 goto exit;
 198         }
 199 
 200         rc = opal_async_wait_response(token, &msg);
 201         if (rc) {
 202                 rc = -EIO;
 203                 goto exit;
 204         }
 205 
 206         rc = opal_get_async_rc(msg);
 207         if (rc != OPAL_SUCCESS)
 208                 rc = -EIO;
 209 
 210 exit:
 211         opal_async_release_token(token);
 212         return rc;
 213 }
 214 
 215 static int opal_tpo_alarm_irq_enable(struct device *dev, unsigned int enabled)
 216 {
 217         struct rtc_wkalrm alarm = { .enabled = 0 };
 218 
 219         /*
 220          * TPO is automatically enabled when opal_set_tpo_time() is called with
 221          * non-zero rtc-time. We only handle disable case which needs to be
 222          * explicitly told to opal.
 223          */
 224         return enabled ? 0 : opal_set_tpo_time(dev, &alarm);
 225 }
 226 
 227 static struct rtc_class_ops opal_rtc_ops = {
 228         .read_time      = opal_get_rtc_time,
 229         .set_time       = opal_set_rtc_time,
 230 };
 231 
 232 static int opal_rtc_probe(struct platform_device *pdev)
 233 {
 234         struct rtc_device *rtc;
 235 
 236         if (pdev->dev.of_node &&
 237             (of_property_read_bool(pdev->dev.of_node, "wakeup-source") ||
 238              of_property_read_bool(pdev->dev.of_node, "has-tpo")/* legacy */)) {
 239                 device_set_wakeup_capable(&pdev->dev, true);
 240                 opal_rtc_ops.read_alarm = opal_get_tpo_time;
 241                 opal_rtc_ops.set_alarm = opal_set_tpo_time;
 242                 opal_rtc_ops.alarm_irq_enable = opal_tpo_alarm_irq_enable;
 243         }
 244 
 245         rtc = devm_rtc_device_register(&pdev->dev, DRVNAME, &opal_rtc_ops,
 246                                        THIS_MODULE);
 247         if (IS_ERR(rtc))
 248                 return PTR_ERR(rtc);
 249 
 250         rtc->uie_unsupported = 1;
 251 
 252         return 0;
 253 }
 254 
 255 static const struct of_device_id opal_rtc_match[] = {
 256         {
 257                 .compatible     = "ibm,opal-rtc",
 258         },
 259         { }
 260 };
 261 MODULE_DEVICE_TABLE(of, opal_rtc_match);
 262 
 263 static const struct platform_device_id opal_rtc_driver_ids[] = {
 264         {
 265                 .name           = "opal-rtc",
 266         },
 267         { }
 268 };
 269 MODULE_DEVICE_TABLE(platform, opal_rtc_driver_ids);
 270 
 271 static struct platform_driver opal_rtc_driver = {
 272         .probe          = opal_rtc_probe,
 273         .id_table       = opal_rtc_driver_ids,
 274         .driver         = {
 275                 .name           = DRVNAME,
 276                 .of_match_table = opal_rtc_match,
 277         },
 278 };
 279 
 280 static int __init opal_rtc_init(void)
 281 {
 282         if (!firmware_has_feature(FW_FEATURE_OPAL))
 283                 return -ENODEV;
 284 
 285         return platform_driver_register(&opal_rtc_driver);
 286 }
 287 
 288 static void __exit opal_rtc_exit(void)
 289 {
 290         platform_driver_unregister(&opal_rtc_driver);
 291 }
 292 
 293 MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
 294 MODULE_DESCRIPTION("IBM OPAL RTC driver");
 295 MODULE_LICENSE("GPL");
 296 
 297 module_init(opal_rtc_init);
 298 module_exit(opal_rtc_exit);

/* [<][>][^][v][top][bottom][index][help] */