linux/drivers/rtc/rtc-pcf8523.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 Avionic Design GmbH
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8
   9#include <linux/bcd.h>
  10#include <linux/i2c.h>
  11#include <linux/module.h>
  12#include <linux/rtc.h>
  13#include <linux/of.h>
  14
  15#define DRIVER_NAME "rtc-pcf8523"
  16
  17#define REG_CONTROL1 0x00
  18#define REG_CONTROL1_CAP_SEL (1 << 7)
  19#define REG_CONTROL1_STOP    (1 << 5)
  20
  21#define REG_CONTROL3 0x02
  22#define REG_CONTROL3_PM_BLD (1 << 7) /* battery low detection disabled */
  23#define REG_CONTROL3_PM_VDD (1 << 6) /* switch-over disabled */
  24#define REG_CONTROL3_PM_DSM (1 << 5) /* direct switching mode */
  25#define REG_CONTROL3_PM_MASK 0xe0
  26#define REG_CONTROL3_BLF (1 << 2) /* battery low bit, read-only */
  27
  28#define REG_SECONDS  0x03
  29#define REG_SECONDS_OS (1 << 7)
  30
  31#define REG_MINUTES  0x04
  32#define REG_HOURS    0x05
  33#define REG_DAYS     0x06
  34#define REG_WEEKDAYS 0x07
  35#define REG_MONTHS   0x08
  36#define REG_YEARS    0x09
  37
  38struct pcf8523 {
  39        struct rtc_device *rtc;
  40};
  41
  42static int pcf8523_read(struct i2c_client *client, u8 reg, u8 *valuep)
  43{
  44        struct i2c_msg msgs[2];
  45        u8 value = 0;
  46        int err;
  47
  48        msgs[0].addr = client->addr;
  49        msgs[0].flags = 0;
  50        msgs[0].len = sizeof(reg);
  51        msgs[0].buf = &reg;
  52
  53        msgs[1].addr = client->addr;
  54        msgs[1].flags = I2C_M_RD;
  55        msgs[1].len = sizeof(value);
  56        msgs[1].buf = &value;
  57
  58        err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
  59        if (err < 0)
  60                return err;
  61
  62        *valuep = value;
  63
  64        return 0;
  65}
  66
  67static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value)
  68{
  69        u8 buffer[2] = { reg, value };
  70        struct i2c_msg msg;
  71        int err;
  72
  73        msg.addr = client->addr;
  74        msg.flags = 0;
  75        msg.len = sizeof(buffer);
  76        msg.buf = buffer;
  77
  78        err = i2c_transfer(client->adapter, &msg, 1);
  79        if (err < 0)
  80                return err;
  81
  82        return 0;
  83}
  84
  85static int pcf8523_select_capacitance(struct i2c_client *client, bool high)
  86{
  87        u8 value;
  88        int err;
  89
  90        err = pcf8523_read(client, REG_CONTROL1, &value);
  91        if (err < 0)
  92                return err;
  93
  94        if (!high)
  95                value &= ~REG_CONTROL1_CAP_SEL;
  96        else
  97                value |= REG_CONTROL1_CAP_SEL;
  98
  99        err = pcf8523_write(client, REG_CONTROL1, value);
 100        if (err < 0)
 101                return err;
 102
 103        return err;
 104}
 105
 106static int pcf8523_set_pm(struct i2c_client *client, u8 pm)
 107{
 108        u8 value;
 109        int err;
 110
 111        err = pcf8523_read(client, REG_CONTROL3, &value);
 112        if (err < 0)
 113                return err;
 114
 115        value = (value & ~REG_CONTROL3_PM_MASK) | pm;
 116
 117        err = pcf8523_write(client, REG_CONTROL3, value);
 118        if (err < 0)
 119                return err;
 120
 121        return 0;
 122}
 123
 124static int pcf8523_stop_rtc(struct i2c_client *client)
 125{
 126        u8 value;
 127        int err;
 128
 129        err = pcf8523_read(client, REG_CONTROL1, &value);
 130        if (err < 0)
 131                return err;
 132
 133        value |= REG_CONTROL1_STOP;
 134
 135        err = pcf8523_write(client, REG_CONTROL1, value);
 136        if (err < 0)
 137                return err;
 138
 139        return 0;
 140}
 141
 142static int pcf8523_start_rtc(struct i2c_client *client)
 143{
 144        u8 value;
 145        int err;
 146
 147        err = pcf8523_read(client, REG_CONTROL1, &value);
 148        if (err < 0)
 149                return err;
 150
 151        value &= ~REG_CONTROL1_STOP;
 152
 153        err = pcf8523_write(client, REG_CONTROL1, value);
 154        if (err < 0)
 155                return err;
 156
 157        return 0;
 158}
 159
 160static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
 161{
 162        struct i2c_client *client = to_i2c_client(dev);
 163        u8 start = REG_SECONDS, regs[7];
 164        struct i2c_msg msgs[2];
 165        int err;
 166
 167        msgs[0].addr = client->addr;
 168        msgs[0].flags = 0;
 169        msgs[0].len = 1;
 170        msgs[0].buf = &start;
 171
 172        msgs[1].addr = client->addr;
 173        msgs[1].flags = I2C_M_RD;
 174        msgs[1].len = sizeof(regs);
 175        msgs[1].buf = regs;
 176
 177        err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
 178        if (err < 0)
 179                return err;
 180
 181        if (regs[0] & REG_SECONDS_OS) {
 182                /*
 183                 * If the oscillator was stopped, try to clear the flag. Upon
 184                 * power-up the flag is always set, but if we cannot clear it
 185                 * the oscillator isn't running properly for some reason. The
 186                 * sensible thing therefore is to return an error, signalling
 187                 * that the clock cannot be assumed to be correct.
 188                 */
 189
 190                regs[0] &= ~REG_SECONDS_OS;
 191
 192                err = pcf8523_write(client, REG_SECONDS, regs[0]);
 193                if (err < 0)
 194                        return err;
 195
 196                err = pcf8523_read(client, REG_SECONDS, &regs[0]);
 197                if (err < 0)
 198                        return err;
 199
 200                if (regs[0] & REG_SECONDS_OS)
 201                        return -EAGAIN;
 202        }
 203
 204        tm->tm_sec = bcd2bin(regs[0] & 0x7f);
 205        tm->tm_min = bcd2bin(regs[1] & 0x7f);
 206        tm->tm_hour = bcd2bin(regs[2] & 0x3f);
 207        tm->tm_mday = bcd2bin(regs[3] & 0x3f);
 208        tm->tm_wday = regs[4] & 0x7;
 209        tm->tm_mon = bcd2bin(regs[5] & 0x1f);
 210        tm->tm_year = bcd2bin(regs[6]) + 100;
 211
 212        return rtc_valid_tm(tm);
 213}
 214
 215static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
 216{
 217        struct i2c_client *client = to_i2c_client(dev);
 218        struct i2c_msg msg;
 219        u8 regs[8];
 220        int err;
 221
 222        err = pcf8523_stop_rtc(client);
 223        if (err < 0)
 224                return err;
 225
 226        regs[0] = REG_SECONDS;
 227        regs[1] = bin2bcd(tm->tm_sec);
 228        regs[2] = bin2bcd(tm->tm_min);
 229        regs[3] = bin2bcd(tm->tm_hour);
 230        regs[4] = bin2bcd(tm->tm_mday);
 231        regs[5] = tm->tm_wday;
 232        regs[6] = bin2bcd(tm->tm_mon);
 233        regs[7] = bin2bcd(tm->tm_year - 100);
 234
 235        msg.addr = client->addr;
 236        msg.flags = 0;
 237        msg.len = sizeof(regs);
 238        msg.buf = regs;
 239
 240        err = i2c_transfer(client->adapter, &msg, 1);
 241        if (err < 0) {
 242                /*
 243                 * If the time cannot be set, restart the RTC anyway. Note
 244                 * that errors are ignored if the RTC cannot be started so
 245                 * that we have a chance to propagate the original error.
 246                 */
 247                pcf8523_start_rtc(client);
 248                return err;
 249        }
 250
 251        return pcf8523_start_rtc(client);
 252}
 253
 254#ifdef CONFIG_RTC_INTF_DEV
 255static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd,
 256                             unsigned long arg)
 257{
 258        struct i2c_client *client = to_i2c_client(dev);
 259        u8 value;
 260        int ret = 0, err;
 261
 262        switch (cmd) {
 263        case RTC_VL_READ:
 264                err = pcf8523_read(client, REG_CONTROL3, &value);
 265                if (err < 0)
 266                        return err;
 267
 268                if (value & REG_CONTROL3_BLF)
 269                        ret = 1;
 270
 271                if (copy_to_user((void __user *)arg, &ret, sizeof(int)))
 272                        return -EFAULT;
 273
 274                return 0;
 275        default:
 276                return -ENOIOCTLCMD;
 277        }
 278}
 279#else
 280#define pcf8523_rtc_ioctl NULL
 281#endif
 282
 283static const struct rtc_class_ops pcf8523_rtc_ops = {
 284        .read_time = pcf8523_rtc_read_time,
 285        .set_time = pcf8523_rtc_set_time,
 286        .ioctl = pcf8523_rtc_ioctl,
 287};
 288
 289static int pcf8523_probe(struct i2c_client *client,
 290                         const struct i2c_device_id *id)
 291{
 292        struct pcf8523 *pcf;
 293        int err;
 294
 295        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 296                return -ENODEV;
 297
 298        pcf = devm_kzalloc(&client->dev, sizeof(*pcf), GFP_KERNEL);
 299        if (!pcf)
 300                return -ENOMEM;
 301
 302        err = pcf8523_select_capacitance(client, true);
 303        if (err < 0)
 304                return err;
 305
 306        err = pcf8523_set_pm(client, 0);
 307        if (err < 0)
 308                return err;
 309
 310        pcf->rtc = rtc_device_register(DRIVER_NAME, &client->dev,
 311                                       &pcf8523_rtc_ops, THIS_MODULE);
 312        if (IS_ERR(pcf->rtc))
 313                return PTR_ERR(pcf->rtc);
 314
 315        i2c_set_clientdata(client, pcf);
 316
 317        return 0;
 318}
 319
 320static int pcf8523_remove(struct i2c_client *client)
 321{
 322        struct pcf8523 *pcf = i2c_get_clientdata(client);
 323
 324        rtc_device_unregister(pcf->rtc);
 325
 326        return 0;
 327}
 328
 329static const struct i2c_device_id pcf8523_id[] = {
 330        { "pcf8523", 0 },
 331        { }
 332};
 333MODULE_DEVICE_TABLE(i2c, pcf8523_id);
 334
 335#ifdef CONFIG_OF
 336static const struct of_device_id pcf8523_of_match[] = {
 337        { .compatible = "nxp,pcf8523" },
 338        { }
 339};
 340MODULE_DEVICE_TABLE(of, pcf8523_of_match);
 341#endif
 342
 343static struct i2c_driver pcf8523_driver = {
 344        .driver = {
 345                .name = DRIVER_NAME,
 346                .owner = THIS_MODULE,
 347                .of_match_table = of_match_ptr(pcf8523_of_match),
 348        },
 349        .probe = pcf8523_probe,
 350        .remove = pcf8523_remove,
 351        .id_table = pcf8523_id,
 352};
 353module_i2c_driver(pcf8523_driver);
 354
 355MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
 356MODULE_DESCRIPTION("NXP PCF8523 RTC driver");
 357MODULE_LICENSE("GPL v2");
 358
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.