linux/drivers/rtc/rtc-sd3078.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Real Time Clock (RTC) Driver for sd3078
   4 * Copyright (C) 2018 Zoro Li
   5 */
   6
   7#include <linux/bcd.h>
   8#include <linux/i2c.h>
   9#include <linux/module.h>
  10#include <linux/regmap.h>
  11#include <linux/rtc.h>
  12#include <linux/slab.h>
  13
  14#define SD3078_REG_SC                   0x00
  15#define SD3078_REG_MN                   0x01
  16#define SD3078_REG_HR                   0x02
  17#define SD3078_REG_DW                   0x03
  18#define SD3078_REG_DM                   0x04
  19#define SD3078_REG_MO                   0x05
  20#define SD3078_REG_YR                   0x06
  21
  22#define SD3078_REG_CTRL1                0x0f
  23#define SD3078_REG_CTRL2                0x10
  24#define SD3078_REG_CTRL3                0x11
  25
  26#define KEY_WRITE1              0x80
  27#define KEY_WRITE2              0x04
  28#define KEY_WRITE3              0x80
  29
  30#define NUM_TIME_REGS   (SD3078_REG_YR - SD3078_REG_SC + 1)
  31
  32/*
  33 * The sd3078 has write protection
  34 * and we can choose whether or not to use it.
  35 * Write protection is turned off by default.
  36 */
  37#define WRITE_PROTECT_EN        0
  38
  39struct sd3078 {
  40        struct rtc_device       *rtc;
  41        struct regmap           *regmap;
  42};
  43
  44/*
  45 * In order to prevent arbitrary modification of the time register,
  46 * when modification of the register,
  47 * the "write" bit needs to be written in a certain order.
  48 * 1. set WRITE1 bit
  49 * 2. set WRITE2 bit
  50 * 3. set WRITE3 bit
  51 */
  52static void sd3078_enable_reg_write(struct sd3078 *sd3078)
  53{
  54        regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL2,
  55                           KEY_WRITE1, KEY_WRITE1);
  56        regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
  57                           KEY_WRITE2, KEY_WRITE2);
  58        regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
  59                           KEY_WRITE3, KEY_WRITE3);
  60}
  61
  62#if WRITE_PROTECT_EN
  63/*
  64 * In order to prevent arbitrary modification of the time register,
  65 * we should disable the write function.
  66 * when disable write,
  67 * the "write" bit needs to be clear in a certain order.
  68 * 1. clear WRITE2 bit
  69 * 2. clear WRITE3 bit
  70 * 3. clear WRITE1 bit
  71 */
  72static void sd3078_disable_reg_write(struct sd3078 *sd3078)
  73{
  74        regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
  75                           KEY_WRITE2, 0);
  76        regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
  77                           KEY_WRITE3, 0);
  78        regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL2,
  79                           KEY_WRITE1, 0);
  80}
  81#endif
  82
  83static int sd3078_rtc_read_time(struct device *dev, struct rtc_time *tm)
  84{
  85        unsigned char hour;
  86        unsigned char rtc_data[NUM_TIME_REGS] = {0};
  87        struct i2c_client *client = to_i2c_client(dev);
  88        struct sd3078 *sd3078 = i2c_get_clientdata(client);
  89        int ret;
  90
  91        ret = regmap_bulk_read(sd3078->regmap, SD3078_REG_SC, rtc_data,
  92                               NUM_TIME_REGS);
  93        if (ret < 0) {
  94                dev_err(dev, "reading from RTC failed with err:%d\n", ret);
  95                return ret;
  96        }
  97
  98        tm->tm_sec      = bcd2bin(rtc_data[SD3078_REG_SC] & 0x7F);
  99        tm->tm_min      = bcd2bin(rtc_data[SD3078_REG_MN] & 0x7F);
 100
 101        /*
 102         * The sd3078 supports 12/24 hour mode.
 103         * When getting time,
 104         * we need to convert the 12 hour mode to the 24 hour mode.
 105         */
 106        hour = rtc_data[SD3078_REG_HR];
 107        if (hour & 0x80) /* 24H MODE */
 108                tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x3F);
 109        else if (hour & 0x20) /* 12H MODE PM */
 110                tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x1F) + 12;
 111        else /* 12H MODE AM */
 112                tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x1F);
 113
 114        tm->tm_mday = bcd2bin(rtc_data[SD3078_REG_DM] & 0x3F);
 115        tm->tm_wday = rtc_data[SD3078_REG_DW] & 0x07;
 116        tm->tm_mon      = bcd2bin(rtc_data[SD3078_REG_MO] & 0x1F) - 1;
 117        tm->tm_year = bcd2bin(rtc_data[SD3078_REG_YR]) + 100;
 118
 119        return 0;
 120}
 121
 122static int sd3078_rtc_set_time(struct device *dev, struct rtc_time *tm)
 123{
 124        unsigned char rtc_data[NUM_TIME_REGS];
 125        struct i2c_client *client = to_i2c_client(dev);
 126        struct sd3078 *sd3078 = i2c_get_clientdata(client);
 127        int ret;
 128
 129        rtc_data[SD3078_REG_SC] = bin2bcd(tm->tm_sec);
 130        rtc_data[SD3078_REG_MN] = bin2bcd(tm->tm_min);
 131        rtc_data[SD3078_REG_HR] = bin2bcd(tm->tm_hour) | 0x80;
 132        rtc_data[SD3078_REG_DM] = bin2bcd(tm->tm_mday);
 133        rtc_data[SD3078_REG_DW] = tm->tm_wday & 0x07;
 134        rtc_data[SD3078_REG_MO] = bin2bcd(tm->tm_mon) + 1;
 135        rtc_data[SD3078_REG_YR] = bin2bcd(tm->tm_year - 100);
 136
 137#if WRITE_PROTECT_EN
 138        sd3078_enable_reg_write(sd3078);
 139#endif
 140
 141        ret = regmap_bulk_write(sd3078->regmap, SD3078_REG_SC, rtc_data,
 142                                NUM_TIME_REGS);
 143        if (ret < 0) {
 144                dev_err(dev, "writing to RTC failed with err:%d\n", ret);
 145                return ret;
 146        }
 147
 148#if WRITE_PROTECT_EN
 149        sd3078_disable_reg_write(sd3078);
 150#endif
 151
 152        return 0;
 153}
 154
 155static const struct rtc_class_ops sd3078_rtc_ops = {
 156        .read_time      = sd3078_rtc_read_time,
 157        .set_time       = sd3078_rtc_set_time,
 158};
 159
 160static const struct regmap_config regmap_config = {
 161        .reg_bits = 8,
 162        .val_bits = 8,
 163        .max_register = 0x11,
 164};
 165
 166static int sd3078_probe(struct i2c_client *client,
 167                        const struct i2c_device_id *id)
 168{
 169        int ret;
 170        struct sd3078 *sd3078;
 171
 172        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 173                return -ENODEV;
 174
 175        sd3078 = devm_kzalloc(&client->dev, sizeof(*sd3078), GFP_KERNEL);
 176        if (!sd3078)
 177                return -ENOMEM;
 178
 179        sd3078->regmap = devm_regmap_init_i2c(client, &regmap_config);
 180        if (IS_ERR(sd3078->regmap)) {
 181                dev_err(&client->dev, "regmap allocation failed\n");
 182                return PTR_ERR(sd3078->regmap);
 183        }
 184
 185        i2c_set_clientdata(client, sd3078);
 186
 187        sd3078->rtc = devm_rtc_allocate_device(&client->dev);
 188        if (IS_ERR(sd3078->rtc))
 189                return PTR_ERR(sd3078->rtc);
 190
 191        sd3078->rtc->ops = &sd3078_rtc_ops;
 192        sd3078->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
 193        sd3078->rtc->range_max = RTC_TIMESTAMP_END_2099;
 194
 195        ret = rtc_register_device(sd3078->rtc);
 196        if (ret)
 197                return ret;
 198
 199        sd3078_enable_reg_write(sd3078);
 200
 201        return 0;
 202}
 203
 204static const struct i2c_device_id sd3078_id[] = {
 205        {"sd3078", 0},
 206        { }
 207};
 208MODULE_DEVICE_TABLE(i2c, sd3078_id);
 209
 210static const struct of_device_id rtc_dt_match[] = {
 211        { .compatible = "whwave,sd3078" },
 212        {},
 213};
 214MODULE_DEVICE_TABLE(of, rtc_dt_match);
 215
 216static struct i2c_driver sd3078_driver = {
 217        .driver     = {
 218                .name   = "sd3078",
 219                .of_match_table = of_match_ptr(rtc_dt_match),
 220        },
 221        .probe      = sd3078_probe,
 222        .id_table   = sd3078_id,
 223};
 224
 225module_i2c_driver(sd3078_driver);
 226
 227MODULE_AUTHOR("Dianlong Li <long17.cool@163.com>");
 228MODULE_DESCRIPTION("SD3078 RTC driver");
 229MODULE_LICENSE("GPL v2");
 230