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
  21#define DRV_VERSION "0.1"
  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_get_datetime(struct i2c_client *client, struct rtc_time *tm)
 108{
 109        uint8_t buf[ISL12022_REG_INT + 1];
 110        int ret;
 111
 112        ret = isl12022_read_regs(client, ISL12022_REG_SC, buf, sizeof(buf));
 113        if (ret)
 114                return ret;
 115
 116        if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) {
 117                dev_warn(&client->dev,
 118                         "voltage dropped below %u%%, "
 119                         "date and time is not reliable.\n",
 120                         buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75);
 121        }
 122
 123        dev_dbg(&client->dev,
 124                "%s: raw data is sec=%02x, min=%02x, hr=%02x, "
 125                "mday=%02x, mon=%02x, year=%02x, wday=%02x, "
 126                "sr=%02x, int=%02x",
 127                __func__,
 128                buf[ISL12022_REG_SC],
 129                buf[ISL12022_REG_MN],
 130                buf[ISL12022_REG_HR],
 131                buf[ISL12022_REG_DT],
 132                buf[ISL12022_REG_MO],
 133                buf[ISL12022_REG_YR],
 134                buf[ISL12022_REG_DW],
 135                buf[ISL12022_REG_SR],
 136                buf[ISL12022_REG_INT]);
 137
 138        tm->tm_sec = bcd2bin(buf[ISL12022_REG_SC] & 0x7F);
 139        tm->tm_min = bcd2bin(buf[ISL12022_REG_MN] & 0x7F);
 140        tm->tm_hour = bcd2bin(buf[ISL12022_REG_HR] & 0x3F);
 141        tm->tm_mday = bcd2bin(buf[ISL12022_REG_DT] & 0x3F);
 142        tm->tm_wday = buf[ISL12022_REG_DW] & 0x07;
 143        tm->tm_mon = bcd2bin(buf[ISL12022_REG_MO] & 0x1F) - 1;
 144        tm->tm_year = bcd2bin(buf[ISL12022_REG_YR]) + 100;
 145
 146        dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
 147                "mday=%d, mon=%d, year=%d, wday=%d\n",
 148                __func__,
 149                tm->tm_sec, tm->tm_min, tm->tm_hour,
 150                tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
 151
 152        /* The clock can give out invalid datetime, but we cannot return
 153         * -EINVAL otherwise hwclock will refuse to set the time on bootup. */
 154        if (rtc_valid_tm(tm) < 0)
 155                dev_err(&client->dev, "retrieved date and time is invalid.\n");
 156
 157        return 0;
 158}
 159
 160static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 161{
 162        struct isl12022 *isl12022 = i2c_get_clientdata(client);
 163        size_t i;
 164        int ret;
 165        uint8_t buf[ISL12022_REG_DW + 1];
 166
 167        dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
 168                "mday=%d, mon=%d, year=%d, wday=%d\n",
 169                __func__,
 170                tm->tm_sec, tm->tm_min, tm->tm_hour,
 171                tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
 172
 173        if (!isl12022->write_enabled) {
 174
 175                ret = isl12022_read_regs(client, ISL12022_REG_INT, buf, 1);
 176                if (ret)
 177                        return ret;
 178
 179                /* Check if WRTC (write rtc enable) is set factory default is
 180                 * 0 (not set) */
 181                if (!(buf[0] & ISL12022_INT_WRTC)) {
 182                        dev_info(&client->dev,
 183                                 "init write enable and 24 hour format\n");
 184
 185                        /* Set the write enable bit. */
 186                        ret = isl12022_write_reg(client,
 187                                                 ISL12022_REG_INT,
 188                                                 buf[0] | ISL12022_INT_WRTC);
 189                        if (ret)
 190                                return ret;
 191
 192                        /* Write to any RTC register to start RTC, we use the
 193                         * HR register, setting the MIL bit to use the 24 hour
 194                         * format. */
 195                        ret = isl12022_read_regs(client, ISL12022_REG_HR,
 196                                                 buf, 1);
 197                        if (ret)
 198                                return ret;
 199
 200                        ret = isl12022_write_reg(client,
 201                                                 ISL12022_REG_HR,
 202                                                 buf[0] | ISL12022_HR_MIL);
 203                        if (ret)
 204                                return ret;
 205                }
 206
 207                isl12022->write_enabled = 1;
 208        }
 209
 210        /* hours, minutes and seconds */
 211        buf[ISL12022_REG_SC] = bin2bcd(tm->tm_sec);
 212        buf[ISL12022_REG_MN] = bin2bcd(tm->tm_min);
 213        buf[ISL12022_REG_HR] = bin2bcd(tm->tm_hour) | ISL12022_HR_MIL;
 214
 215        buf[ISL12022_REG_DT] = bin2bcd(tm->tm_mday);
 216
 217        /* month, 1 - 12 */
 218        buf[ISL12022_REG_MO] = bin2bcd(tm->tm_mon + 1);
 219
 220        /* year and century */
 221        buf[ISL12022_REG_YR] = bin2bcd(tm->tm_year % 100);
 222
 223        buf[ISL12022_REG_DW] = tm->tm_wday & 0x07;
 224
 225        /* write register's data */
 226        for (i = 0; i < ARRAY_SIZE(buf); i++) {
 227                ret = isl12022_write_reg(client, ISL12022_REG_SC + i,
 228                                         buf[ISL12022_REG_SC + i]);
 229                if (ret)
 230                        return -EIO;
 231        }
 232
 233        return 0;
 234}
 235
 236static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
 237{
 238        return isl12022_get_datetime(to_i2c_client(dev), tm);
 239}
 240
 241static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
 242{
 243        return isl12022_set_datetime(to_i2c_client(dev), tm);
 244}
 245
 246static const struct rtc_class_ops isl12022_rtc_ops = {
 247        .read_time      = isl12022_rtc_read_time,
 248        .set_time       = isl12022_rtc_set_time,
 249};
 250
 251static int isl12022_probe(struct i2c_client *client,
 252                          const struct i2c_device_id *id)
 253{
 254        struct isl12022 *isl12022;
 255
 256        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 257                return -ENODEV;
 258
 259        isl12022 = devm_kzalloc(&client->dev, sizeof(struct isl12022),
 260                                GFP_KERNEL);
 261        if (!isl12022)
 262                return -ENOMEM;
 263
 264        dev_dbg(&client->dev, "chip found, driver version " DRV_VERSION "\n");
 265
 266        i2c_set_clientdata(client, isl12022);
 267
 268        isl12022->rtc = devm_rtc_device_register(&client->dev,
 269                                        isl12022_driver.driver.name,
 270                                        &isl12022_rtc_ops, THIS_MODULE);
 271        return PTR_ERR_OR_ZERO(isl12022->rtc);
 272}
 273
 274static const struct i2c_device_id isl12022_id[] = {
 275        { "isl12022", 0 },
 276        { }
 277};
 278MODULE_DEVICE_TABLE(i2c, isl12022_id);
 279
 280static struct i2c_driver isl12022_driver = {
 281        .driver         = {
 282                .name   = "rtc-isl12022",
 283        },
 284        .probe          = isl12022_probe,
 285        .id_table       = isl12022_id,
 286};
 287
 288module_i2c_driver(isl12022_driver);
 289
 290MODULE_AUTHOR("roman.fietze@telemotive.de");
 291MODULE_DESCRIPTION("ISL 12022 RTC driver");
 292MODULE_LICENSE("GPL");
 293MODULE_VERSION(DRV_VERSION);
 294
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.