linux/drivers/rtc/rtc-pcf2127.c
<<
>>
Prefs
   1/*
   2 * An I2C driver for the NXP PCF2127 RTC
   3 * Copyright 2013 Til-Technologies
   4 *
   5 * Author: Renaud Cerrato <r.cerrato@til-technologies.fr>
   6 *
   7 * based on the other drivers in this same directory.
   8 *
   9 * http://www.nxp.com/documents/data_sheet/PCF2127AT.pdf
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License version 2 as
  13 * published by the Free Software Foundation.
  14 */
  15
  16#include <linux/i2c.h>
  17#include <linux/bcd.h>
  18#include <linux/rtc.h>
  19#include <linux/slab.h>
  20#include <linux/module.h>
  21#include <linux/of.h>
  22
  23#define DRV_VERSION "0.0.1"
  24
  25#define PCF2127_REG_CTRL1       (0x00)  /* Control Register 1 */
  26#define PCF2127_REG_CTRL2       (0x01)  /* Control Register 2 */
  27#define PCF2127_REG_CTRL3       (0x02)  /* Control Register 3 */
  28#define PCF2127_REG_SC          (0x03)  /* datetime */
  29#define PCF2127_REG_MN          (0x04)
  30#define PCF2127_REG_HR          (0x05)
  31#define PCF2127_REG_DM          (0x06)
  32#define PCF2127_REG_DW          (0x07)
  33#define PCF2127_REG_MO          (0x08)
  34#define PCF2127_REG_YR          (0x09)
  35
  36static struct i2c_driver pcf2127_driver;
  37
  38struct pcf2127 {
  39        struct rtc_device *rtc;
  40        int voltage_low; /* indicates if a low_voltage was detected */
  41};
  42
  43/*
  44 * In the routines that deal directly with the pcf2127 hardware, we use
  45 * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
  46 */
  47static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
  48{
  49        struct pcf2127 *pcf2127 = i2c_get_clientdata(client);
  50        unsigned char buf[10] = { PCF2127_REG_CTRL1 };
  51
  52        /* read registers */
  53        if (i2c_master_send(client, buf, 1) != 1 ||
  54                i2c_master_recv(client, buf, sizeof(buf)) != sizeof(buf)) {
  55                dev_err(&client->dev, "%s: read error\n", __func__);
  56                return -EIO;
  57        }
  58
  59        if (buf[PCF2127_REG_CTRL3] & 0x04) {
  60                pcf2127->voltage_low = 1;
  61                dev_info(&client->dev,
  62                        "low voltage detected, date/time is not reliable.\n");
  63        }
  64
  65        dev_dbg(&client->dev,
  66                "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, "
  67                "sec=%02x, min=%02x, hr=%02x, "
  68                "mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
  69                __func__,
  70                buf[0], buf[1], buf[2],
  71                buf[3], buf[4], buf[5],
  72                buf[6], buf[7], buf[8], buf[9]);
  73
  74
  75        tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F);
  76        tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F);
  77        tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F); /* rtc hr 0-23 */
  78        tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F);
  79        tm->tm_wday = buf[PCF2127_REG_DW] & 0x07;
  80        tm->tm_mon = bcd2bin(buf[PCF2127_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
  81        tm->tm_year = bcd2bin(buf[PCF2127_REG_YR]);
  82        if (tm->tm_year < 70)
  83                tm->tm_year += 100;     /* assume we are in 1970...2069 */
  84
  85        dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
  86                "mday=%d, mon=%d, year=%d, wday=%d\n",
  87                __func__,
  88                tm->tm_sec, tm->tm_min, tm->tm_hour,
  89                tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
  90
  91        /* the clock can give out invalid datetime, but we cannot return
  92         * -EINVAL otherwise hwclock will refuse to set the time on bootup.
  93         */
  94        if (rtc_valid_tm(tm) < 0)
  95                dev_err(&client->dev, "retrieved date/time is not valid.\n");
  96
  97        return 0;
  98}
  99
 100static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 101{
 102        unsigned char buf[8];
 103        int i = 0, err;
 104
 105        dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
 106                "mday=%d, mon=%d, year=%d, wday=%d\n",
 107                __func__,
 108                tm->tm_sec, tm->tm_min, tm->tm_hour,
 109                tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
 110
 111        /* start register address */
 112        buf[i++] = PCF2127_REG_SC;
 113
 114        /* hours, minutes and seconds */
 115        buf[i++] = bin2bcd(tm->tm_sec);
 116        buf[i++] = bin2bcd(tm->tm_min);
 117        buf[i++] = bin2bcd(tm->tm_hour);
 118        buf[i++] = bin2bcd(tm->tm_mday);
 119        buf[i++] = tm->tm_wday & 0x07;
 120
 121        /* month, 1 - 12 */
 122        buf[i++] = bin2bcd(tm->tm_mon + 1);
 123
 124        /* year */
 125        buf[i++] = bin2bcd(tm->tm_year % 100);
 126
 127        /* write register's data */
 128        err = i2c_master_send(client, buf, i);
 129        if (err != i) {
 130                dev_err(&client->dev,
 131                        "%s: err=%d", __func__, err);
 132                return -EIO;
 133        }
 134
 135        return 0;
 136}
 137
 138#ifdef CONFIG_RTC_INTF_DEV
 139static int pcf2127_rtc_ioctl(struct device *dev,
 140                                unsigned int cmd, unsigned long arg)
 141{
 142        struct pcf2127 *pcf2127 = i2c_get_clientdata(to_i2c_client(dev));
 143
 144        switch (cmd) {
 145        case RTC_VL_READ:
 146                if (pcf2127->voltage_low)
 147                        dev_info(dev, "low voltage detected, date/time is not reliable.\n");
 148
 149                if (copy_to_user((void __user *)arg, &pcf2127->voltage_low,
 150                                        sizeof(int)))
 151                        return -EFAULT;
 152                return 0;
 153        default:
 154                return -ENOIOCTLCMD;
 155        }
 156}
 157#else
 158#define pcf2127_rtc_ioctl NULL
 159#endif
 160
 161static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
 162{
 163        return pcf2127_get_datetime(to_i2c_client(dev), tm);
 164}
 165
 166static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm)
 167{
 168        return pcf2127_set_datetime(to_i2c_client(dev), tm);
 169}
 170
 171static const struct rtc_class_ops pcf2127_rtc_ops = {
 172        .ioctl          = pcf2127_rtc_ioctl,
 173        .read_time      = pcf2127_rtc_read_time,
 174        .set_time       = pcf2127_rtc_set_time,
 175};
 176
 177static int pcf2127_probe(struct i2c_client *client,
 178                                const struct i2c_device_id *id)
 179{
 180        struct pcf2127 *pcf2127;
 181
 182        dev_dbg(&client->dev, "%s\n", __func__);
 183
 184        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 185                return -ENODEV;
 186
 187        pcf2127 = devm_kzalloc(&client->dev, sizeof(struct pcf2127),
 188                                GFP_KERNEL);
 189        if (!pcf2127)
 190                return -ENOMEM;
 191
 192        dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
 193
 194        i2c_set_clientdata(client, pcf2127);
 195
 196        pcf2127->rtc = devm_rtc_device_register(&client->dev,
 197                                pcf2127_driver.driver.name,
 198                                &pcf2127_rtc_ops, THIS_MODULE);
 199
 200        if (IS_ERR(pcf2127->rtc))
 201                return PTR_ERR(pcf2127->rtc);
 202
 203        return 0;
 204}
 205
 206static int pcf2127_remove(struct i2c_client *client)
 207{
 208        return 0;
 209}
 210
 211static const struct i2c_device_id pcf2127_id[] = {
 212        { "pcf2127", 0 },
 213        { }
 214};
 215MODULE_DEVICE_TABLE(i2c, pcf2127_id);
 216
 217#ifdef CONFIG_OF
 218static const struct of_device_id pcf2127_of_match[] = {
 219        { .compatible = "nxp,pcf2127" },
 220        {}
 221};
 222MODULE_DEVICE_TABLE(of, pcf2127_of_match);
 223#endif
 224
 225static struct i2c_driver pcf2127_driver = {
 226        .driver         = {
 227                .name   = "rtc-pcf2127",
 228                .owner  = THIS_MODULE,
 229                .of_match_table = of_match_ptr(pcf2127_of_match),
 230        },
 231        .probe          = pcf2127_probe,
 232        .remove         = pcf2127_remove,
 233        .id_table       = pcf2127_id,
 234};
 235
 236module_i2c_driver(pcf2127_driver);
 237
 238MODULE_AUTHOR("Renaud Cerrato <r.cerrato@til-technologies.fr>");
 239MODULE_DESCRIPTION("NXP PCF2127 RTC driver");
 240MODULE_LICENSE("GPL");
 241MODULE_VERSION(DRV_VERSION);
 242
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.