root/drivers/rtc/rtc-sd3078.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sd3078_enable_reg_write
  2. sd3078_disable_reg_write
  3. sd3078_rtc_read_time
  4. sd3078_rtc_set_time
  5. sd3078_probe

   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 
  39 struct 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  */
  52 static 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  */
  72 static 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 
  83 static 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 
 122 static 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 
 155 static const struct rtc_class_ops sd3078_rtc_ops = {
 156         .read_time      = sd3078_rtc_read_time,
 157         .set_time       = sd3078_rtc_set_time,
 158 };
 159 
 160 static const struct regmap_config regmap_config = {
 161         .reg_bits = 8,
 162         .val_bits = 8,
 163         .max_register = 0x11,
 164 };
 165 
 166 static 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 
 204 static const struct i2c_device_id sd3078_id[] = {
 205         {"sd3078", 0},
 206         { }
 207 };
 208 MODULE_DEVICE_TABLE(i2c, sd3078_id);
 209 
 210 static const struct of_device_id rtc_dt_match[] = {
 211         { .compatible = "whwave,sd3078" },
 212         {},
 213 };
 214 MODULE_DEVICE_TABLE(of, rtc_dt_match);
 215 
 216 static 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 
 225 module_i2c_driver(sd3078_driver);
 226 
 227 MODULE_AUTHOR("Dianlong Li <long17.cool@163.com>");
 228 MODULE_DESCRIPTION("SD3078 RTC driver");
 229 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */