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