linux/drivers/rtc/rtc-isl12022.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * An I2C driver for the Intersil ISL 12022
   4 *
   5 * Author: Roman Fietze <roman.fietze@telemotive.de>
   6 *
   7 * Based on the Philips PCF8563 RTC
   8 * by Alessandro Zummo <a.zummo@towertech.it>.
   9 */
  10
  11#include <linux/i2c.h>
  12#include <linux/bcd.h>
  13#include <linux/rtc.h>
  14#include <linux/slab.h>
  15#include <linux/module.h>
  16#include <linux/err.h>
  17#include <linux/of.h>
  18#include <linux/of_device.h>
  19
  20/* ISL register offsets */
  21#define ISL12022_REG_SC         0x00
  22#define ISL12022_REG_MN         0x01
  23#define ISL12022_REG_HR         0x02
  24#define ISL12022_REG_DT         0x03
  25#define ISL12022_REG_MO         0x04
  26#define ISL12022_REG_YR         0x05
  27#define ISL12022_REG_DW         0x06
  28
  29#define ISL12022_REG_SR         0x07
  30#define ISL12022_REG_INT        0x08
  31
  32/* ISL register bits */
  33#define ISL12022_HR_MIL         (1 << 7)        /* military or 24 hour time */
  34
  35#define ISL12022_SR_LBAT85      (1 << 2)
  36#define ISL12022_SR_LBAT75      (1 << 1)
  37
  38#define ISL12022_INT_WRTC       (1 << 6)
  39
  40
  41static struct i2c_driver isl12022_driver;
  42
  43struct isl12022 {
  44        struct rtc_device *rtc;
  45
  46        bool write_enabled;     /* true if write enable is set */
  47};
  48
  49
  50static int isl12022_read_regs(struct i2c_client *client, uint8_t reg,
  51                              uint8_t *data, size_t n)
  52{
  53        struct i2c_msg msgs[] = {
  54                {
  55                        .addr   = client->addr,
  56                        .flags  = 0,
  57                        .len    = 1,
  58                        .buf    = data
  59                },              /* setup read ptr */
  60                {
  61                        .addr   = client->addr,
  62                        .flags  = I2C_M_RD,
  63                        .len    = n,
  64                        .buf    = data
  65                }
  66        };
  67
  68        int ret;
  69
  70        data[0] = reg;
  71        ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
  72        if (ret != ARRAY_SIZE(msgs)) {
  73                dev_err(&client->dev, "%s: read error, ret=%d\n",
  74                        __func__, ret);
  75                return -EIO;
  76        }
  77
  78        return 0;
  79}
  80
  81
  82static int isl12022_write_reg(struct i2c_client *client,
  83                              uint8_t reg, uint8_t val)
  84{
  85        uint8_t data[2] = { reg, val };
  86        int err;
  87
  88        err = i2c_master_send(client, data, sizeof(data));
  89        if (err != sizeof(data)) {
  90                dev_err(&client->dev,
  91                        "%s: err=%d addr=%02x, data=%02x\n",
  92                        __func__, err, data[0], data[1]);
  93                return -EIO;
  94        }
  95
  96        return 0;
  97}
  98
  99
 100/*
 101 * In the routines that deal directly with the isl12022 hardware, we use
 102 * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
 103 */
 104static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
 105{
 106        struct i2c_client *client = to_i2c_client(dev);
 107        uint8_t buf[ISL12022_REG_INT + 1];
 108        int ret;
 109
 110        ret = isl12022_read_regs(client, ISL12022_REG_SC, buf, sizeof(buf));
 111        if (ret)
 112                return ret;
 113
 114        if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) {
 115                dev_warn(&client->dev,
 116                         "voltage dropped below %u%%, "
 117                         "date and time is not reliable.\n",
 118                         buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75);
 119        }
 120
 121        dev_dbg(&client->dev,
 122                "%s: raw data is sec=%02x, min=%02x, hr=%02x, "
 123                "mday=%02x, mon=%02x, year=%02x, wday=%02x, "
 124                "sr=%02x, int=%02x",
 125                __func__,
 126                buf[ISL12022_REG_SC],
 127                buf[ISL12022_REG_MN],
 128                buf[ISL12022_REG_HR],
 129                buf[ISL12022_REG_DT],
 130                buf[ISL12022_REG_MO],
 131                buf[ISL12022_REG_YR],
 132                buf[ISL12022_REG_DW],
 133                buf[ISL12022_REG_SR],
 134                buf[ISL12022_REG_INT]);
 135
 136        tm->tm_sec = bcd2bin(buf[ISL12022_REG_SC] & 0x7F);
 137        tm->tm_min = bcd2bin(buf[ISL12022_REG_MN] & 0x7F);
 138        tm->tm_hour = bcd2bin(buf[ISL12022_REG_HR] & 0x3F);
 139        tm->tm_mday = bcd2bin(buf[ISL12022_REG_DT] & 0x3F);
 140        tm->tm_wday = buf[ISL12022_REG_DW] & 0x07;
 141        tm->tm_mon = bcd2bin(buf[ISL12022_REG_MO] & 0x1F) - 1;
 142        tm->tm_year = bcd2bin(buf[ISL12022_REG_YR]) + 100;
 143
 144        dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
 145                "mday=%d, mon=%d, year=%d, wday=%d\n",
 146                __func__,
 147                tm->tm_sec, tm->tm_min, tm->tm_hour,
 148                tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
 149
 150        return 0;
 151}
 152
 153static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
 154{
 155        struct i2c_client *client = to_i2c_client(dev);
 156        struct isl12022 *isl12022 = i2c_get_clientdata(client);
 157        size_t i;
 158        int ret;
 159        uint8_t buf[ISL12022_REG_DW + 1];
 160
 161        dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
 162                "mday=%d, mon=%d, year=%d, wday=%d\n",
 163                __func__,
 164                tm->tm_sec, tm->tm_min, tm->tm_hour,
 165                tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
 166
 167        if (!isl12022->write_enabled) {
 168
 169                ret = isl12022_read_regs(client, ISL12022_REG_INT, buf, 1);
 170                if (ret)
 171                        return ret;
 172
 173                /* Check if WRTC (write rtc enable) is set factory default is
 174                 * 0 (not set) */
 175                if (!(buf[0] & ISL12022_INT_WRTC)) {
 176                        dev_info(&client->dev,
 177                                 "init write enable and 24 hour format\n");
 178
 179                        /* Set the write enable bit. */
 180                        ret = isl12022_write_reg(client,
 181                                                 ISL12022_REG_INT,
 182                                                 buf[0] | ISL12022_INT_WRTC);
 183                        if (ret)
 184                                return ret;
 185
 186                        /* Write to any RTC register to start RTC, we use the
 187                         * HR register, setting the MIL bit to use the 24 hour
 188                         * format. */
 189                        ret = isl12022_read_regs(client, ISL12022_REG_HR,
 190                                                 buf, 1);
 191                        if (ret)
 192                                return ret;
 193
 194                        ret = isl12022_write_reg(client,
 195                                                 ISL12022_REG_HR,
 196                                                 buf[0] | ISL12022_HR_MIL);
 197                        if (ret)
 198                                return ret;
 199                }
 200
 201                isl12022->write_enabled = true;
 202        }
 203
 204        /* hours, minutes and seconds */
 205        buf[ISL12022_REG_SC] = bin2bcd(tm->tm_sec);
 206        buf[ISL12022_REG_MN] = bin2bcd(tm->tm_min);
 207        buf[ISL12022_REG_HR] = bin2bcd(tm->tm_hour) | ISL12022_HR_MIL;
 208
 209        buf[ISL12022_REG_DT] = bin2bcd(tm->tm_mday);
 210
 211        /* month, 1 - 12 */
 212        buf[ISL12022_REG_MO] = bin2bcd(tm->tm_mon + 1);
 213
 214        /* year and century */
 215        buf[ISL12022_REG_YR] = bin2bcd(tm->tm_year % 100);
 216
 217        buf[ISL12022_REG_DW] = tm->tm_wday & 0x07;
 218
 219        /* write register's data */
 220        for (i = 0; i < ARRAY_SIZE(buf); i++) {
 221                ret = isl12022_write_reg(client, ISL12022_REG_SC + i,
 222                                         buf[ISL12022_REG_SC + i]);
 223                if (ret)
 224                        return -EIO;
 225        }
 226
 227        return 0;
 228}
 229
 230static const struct rtc_class_ops isl12022_rtc_ops = {
 231        .read_time      = isl12022_rtc_read_time,
 232        .set_time       = isl12022_rtc_set_time,
 233};
 234
 235static int isl12022_probe(struct i2c_client *client,
 236                          const struct i2c_device_id *id)
 237{
 238        struct isl12022 *isl12022;
 239
 240        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 241                return -ENODEV;
 242
 243        isl12022 = devm_kzalloc(&client->dev, sizeof(struct isl12022),
 244                                GFP_KERNEL);
 245        if (!isl12022)
 246                return -ENOMEM;
 247
 248        i2c_set_clientdata(client, isl12022);
 249
 250        isl12022->rtc = devm_rtc_device_register(&client->dev,
 251                                        isl12022_driver.driver.name,
 252                                        &isl12022_rtc_ops, THIS_MODULE);
 253        return PTR_ERR_OR_ZERO(isl12022->rtc);
 254}
 255
 256#ifdef CONFIG_OF
 257static const struct of_device_id isl12022_dt_match[] = {
 258        { .compatible = "isl,isl12022" }, /* for backward compat., don't use */
 259        { .compatible = "isil,isl12022" },
 260        { },
 261};
 262MODULE_DEVICE_TABLE(of, isl12022_dt_match);
 263#endif
 264
 265static const struct i2c_device_id isl12022_id[] = {
 266        { "isl12022", 0 },
 267        { }
 268};
 269MODULE_DEVICE_TABLE(i2c, isl12022_id);
 270
 271static struct i2c_driver isl12022_driver = {
 272        .driver         = {
 273                .name   = "rtc-isl12022",
 274#ifdef CONFIG_OF
 275                .of_match_table = of_match_ptr(isl12022_dt_match),
 276#endif
 277        },
 278        .probe          = isl12022_probe,
 279        .id_table       = isl12022_id,
 280};
 281
 282module_i2c_driver(isl12022_driver);
 283
 284MODULE_AUTHOR("roman.fietze@telemotive.de");
 285MODULE_DESCRIPTION("ISL 12022 RTC driver");
 286MODULE_LICENSE("GPL");
 287