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#define DRV_VERSION "0.1"
  24
  25/* ISL register offsets */
  26#define ISL12022_REG_SC         0x00
  27#define ISL12022_REG_MN         0x01
  28#define ISL12022_REG_HR         0x02
  29#define ISL12022_REG_DT         0x03
  30#define ISL12022_REG_MO         0x04
  31#define ISL12022_REG_YR         0x05
  32#define ISL12022_REG_DW         0x06
  33
  34#define ISL12022_REG_SR         0x07
  35#define ISL12022_REG_INT        0x08
  36
  37/* ISL register bits */
  38#define ISL12022_HR_MIL         (1 << 7)        /* military or 24 hour time */
  39
  40#define ISL12022_SR_LBAT85      (1 << 2)
  41#define ISL12022_SR_LBAT75      (1 << 1)
  42
  43#define ISL12022_INT_WRTC       (1 << 6)
  44
  45
  46static struct i2c_driver isl12022_driver;
  47
  48struct isl12022 {
  49        struct rtc_device *rtc;
  50
  51        bool write_enabled;     /* true if write enable is set */
  52};
  53
  54
  55static int isl12022_read_regs(struct i2c_client *client, uint8_t reg,
  56                              uint8_t *data, size_t n)
  57{
  58        struct i2c_msg msgs[] = {
  59                {
  60                        .addr   = client->addr,
  61                        .flags  = 0,
  62                        .len    = 1,
  63                        .buf    = data
  64                },              /* setup read ptr */
  65                {
  66                        .addr   = client->addr,
  67                        .flags  = I2C_M_RD,
  68                        .len    = n,
  69                        .buf    = data
  70                }
  71        };
  72
  73        int ret;
  74
  75        data[0] = reg;
  76        ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
  77        if (ret != ARRAY_SIZE(msgs)) {
  78                dev_err(&client->dev, "%s: read error, ret=%d\n",
  79                        __func__, ret);
  80                return -EIO;
  81        }
  82
  83        return 0;
  84}
  85
  86
  87static int isl12022_write_reg(struct i2c_client *client,
  88                              uint8_t reg, uint8_t val)
  89{
  90        uint8_t data[2] = { reg, val };
  91        int err;
  92
  93        err = i2c_master_send(client, data, sizeof(data));
  94        if (err != sizeof(data)) {
  95                dev_err(&client->dev,
  96                        "%s: err=%d addr=%02x, data=%02x\n",
  97                        __func__, err, data[0], data[1]);
  98                return -EIO;
  99        }
 100
 101        return 0;
 102}
 103
 104
 105/*
 106 * In the routines that deal directly with the isl12022 hardware, we use
 107 * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
 108 */
 109static int isl12022_get_datetime(struct i2c_client *client, struct rtc_time *tm)
 110{
 111        uint8_t buf[ISL12022_REG_INT + 1];
 112        int ret;
 113
 114        ret = isl12022_read_regs(client, ISL12022_REG_SC, buf, sizeof(buf));
 115        if (ret)
 116                return ret;
 117
 118        if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) {
 119                dev_warn(&client->dev,
 120                         "voltage dropped below %u%%, "
 121                         "date and time is not reliable.\n",
 122                         buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75);
 123        }
 124
 125        dev_dbg(&client->dev,
 126                "%s: raw data is sec=%02x, min=%02x, hr=%02x, "
 127                "mday=%02x, mon=%02x, year=%02x, wday=%02x, "
 128                "sr=%02x, int=%02x",
 129                __func__,
 130                buf[ISL12022_REG_SC],
 131                buf[ISL12022_REG_MN],
 132                buf[ISL12022_REG_HR],
 133                buf[ISL12022_REG_DT],
 134                buf[ISL12022_REG_MO],
 135                buf[ISL12022_REG_YR],
 136                buf[ISL12022_REG_DW],
 137                buf[ISL12022_REG_SR],
 138                buf[ISL12022_REG_INT]);
 139
 140        tm->tm_sec = bcd2bin(buf[ISL12022_REG_SC] & 0x7F);
 141        tm->tm_min = bcd2bin(buf[ISL12022_REG_MN] & 0x7F);
 142        tm->tm_hour = bcd2bin(buf[ISL12022_REG_HR] & 0x3F);
 143        tm->tm_mday = bcd2bin(buf[ISL12022_REG_DT] & 0x3F);
 144        tm->tm_wday = buf[ISL12022_REG_DW] & 0x07;
 145        tm->tm_mon = bcd2bin(buf[ISL12022_REG_MO] & 0x1F) - 1;
 146        tm->tm_year = bcd2bin(buf[ISL12022_REG_YR]) + 100;
 147
 148        dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
 149                "mday=%d, mon=%d, year=%d, wday=%d\n",
 150                __func__,
 151                tm->tm_sec, tm->tm_min, tm->tm_hour,
 152                tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
 153
 154        return rtc_valid_tm(tm);
 155}
 156
 157static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 158{
 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 = 1;
 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 int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
 234{
 235        return isl12022_get_datetime(to_i2c_client(dev), tm);
 236}
 237
 238static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
 239{
 240        return isl12022_set_datetime(to_i2c_client(dev), tm);
 241}
 242
 243static const struct rtc_class_ops isl12022_rtc_ops = {
 244        .read_time      = isl12022_rtc_read_time,
 245        .set_time       = isl12022_rtc_set_time,
 246};
 247
 248static int isl12022_probe(struct i2c_client *client,
 249                          const struct i2c_device_id *id)
 250{
 251        struct isl12022 *isl12022;
 252
 253        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 254                return -ENODEV;
 255
 256        isl12022 = devm_kzalloc(&client->dev, sizeof(struct isl12022),
 257                                GFP_KERNEL);
 258        if (!isl12022)
 259                return -ENOMEM;
 260
 261        dev_dbg(&client->dev, "chip found, driver version " DRV_VERSION "\n");
 262
 263        i2c_set_clientdata(client, isl12022);
 264
 265        isl12022->rtc = devm_rtc_device_register(&client->dev,
 266                                        isl12022_driver.driver.name,
 267                                        &isl12022_rtc_ops, THIS_MODULE);
 268        return PTR_ERR_OR_ZERO(isl12022->rtc);
 269}
 270
 271#ifdef CONFIG_OF
 272static const struct of_device_id isl12022_dt_match[] = {
 273        { .compatible = "isl,isl12022" }, /* for backward compat., don't use */
 274        { .compatible = "isil,isl12022" },
 275        { },
 276};
 277MODULE_DEVICE_TABLE(of, isl12022_dt_match);
 278#endif
 279
 280static const struct i2c_device_id isl12022_id[] = {
 281        { "isl12022", 0 },
 282        { }
 283};
 284MODULE_DEVICE_TABLE(i2c, isl12022_id);
 285
 286static struct i2c_driver isl12022_driver = {
 287        .driver         = {
 288                .name   = "rtc-isl12022",
 289#ifdef CONFIG_OF
 290                .of_match_table = of_match_ptr(isl12022_dt_match),
 291#endif
 292        },
 293        .probe          = isl12022_probe,
 294        .id_table       = isl12022_id,
 295};
 296
 297module_i2c_driver(isl12022_driver);
 298
 299MODULE_AUTHOR("roman.fietze@telemotive.de");
 300MODULE_DESCRIPTION("ISL 12022 RTC driver");
 301MODULE_LICENSE("GPL");
 302MODULE_VERSION(DRV_VERSION);
 303