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