root/drivers/rtc/rtc-bq32k.c

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

DEFINITIONS

This source file includes following definitions.
  1. bq32k_read
  2. bq32k_write
  3. bq32k_rtc_read_time
  4. bq32k_rtc_set_time
  5. trickle_charger_of_init
  6. bq32k_sysfs_show_tricklecharge_bypass
  7. bq32k_sysfs_store_tricklecharge_bypass
  8. bq32k_sysfs_register
  9. bq32k_sysfs_unregister
  10. bq32k_probe
  11. bq32k_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Driver for TI BQ32000 RTC.
   4  *
   5  * Copyright (C) 2009 Semihalf.
   6  * Copyright (C) 2014 Pavel Machek <pavel@denx.de>
   7  *
   8  * You can get hardware description at
   9  * http://www.ti.com/lit/ds/symlink/bq32000.pdf
  10  */
  11 
  12 #include <linux/module.h>
  13 #include <linux/i2c.h>
  14 #include <linux/rtc.h>
  15 #include <linux/init.h>
  16 #include <linux/errno.h>
  17 #include <linux/bcd.h>
  18 
  19 #define BQ32K_SECONDS           0x00    /* Seconds register address */
  20 #define BQ32K_SECONDS_MASK      0x7F    /* Mask over seconds value */
  21 #define BQ32K_STOP              0x80    /* Oscillator Stop flat */
  22 
  23 #define BQ32K_MINUTES           0x01    /* Minutes register address */
  24 #define BQ32K_MINUTES_MASK      0x7F    /* Mask over minutes value */
  25 #define BQ32K_OF                0x80    /* Oscillator Failure flag */
  26 
  27 #define BQ32K_HOURS_MASK        0x3F    /* Mask over hours value */
  28 #define BQ32K_CENT              0x40    /* Century flag */
  29 #define BQ32K_CENT_EN           0x80    /* Century flag enable bit */
  30 
  31 #define BQ32K_CALIBRATION       0x07    /* CAL_CFG1, calibration and control */
  32 #define BQ32K_TCH2              0x08    /* Trickle charge enable */
  33 #define BQ32K_CFG2              0x09    /* Trickle charger control */
  34 #define BQ32K_TCFE              BIT(6)  /* Trickle charge FET bypass */
  35 
  36 #define MAX_LEN                 10      /* Maximum number of consecutive
  37                                          * register for this particular RTC.
  38                                          */
  39 
  40 struct bq32k_regs {
  41         uint8_t         seconds;
  42         uint8_t         minutes;
  43         uint8_t         cent_hours;
  44         uint8_t         day;
  45         uint8_t         date;
  46         uint8_t         month;
  47         uint8_t         years;
  48 };
  49 
  50 static struct i2c_driver bq32k_driver;
  51 
  52 static int bq32k_read(struct device *dev, void *data, uint8_t off, uint8_t len)
  53 {
  54         struct i2c_client *client = to_i2c_client(dev);
  55         struct i2c_msg msgs[] = {
  56                 {
  57                         .addr = client->addr,
  58                         .flags = 0,
  59                         .len = 1,
  60                         .buf = &off,
  61                 }, {
  62                         .addr = client->addr,
  63                         .flags = I2C_M_RD,
  64                         .len = len,
  65                         .buf = data,
  66                 }
  67         };
  68 
  69         if (i2c_transfer(client->adapter, msgs, 2) == 2)
  70                 return 0;
  71 
  72         return -EIO;
  73 }
  74 
  75 static int bq32k_write(struct device *dev, void *data, uint8_t off, uint8_t len)
  76 {
  77         struct i2c_client *client = to_i2c_client(dev);
  78         uint8_t buffer[MAX_LEN + 1];
  79 
  80         buffer[0] = off;
  81         memcpy(&buffer[1], data, len);
  82 
  83         if (i2c_master_send(client, buffer, len + 1) == len + 1)
  84                 return 0;
  85 
  86         return -EIO;
  87 }
  88 
  89 static int bq32k_rtc_read_time(struct device *dev, struct rtc_time *tm)
  90 {
  91         struct bq32k_regs regs;
  92         int error;
  93 
  94         error = bq32k_read(dev, &regs, 0, sizeof(regs));
  95         if (error)
  96                 return error;
  97 
  98         /*
  99          * In case of oscillator failure, the register contents should be
 100          * considered invalid. The flag is cleared the next time the RTC is set.
 101          */
 102         if (regs.minutes & BQ32K_OF)
 103                 return -EINVAL;
 104 
 105         tm->tm_sec = bcd2bin(regs.seconds & BQ32K_SECONDS_MASK);
 106         tm->tm_min = bcd2bin(regs.minutes & BQ32K_MINUTES_MASK);
 107         tm->tm_hour = bcd2bin(regs.cent_hours & BQ32K_HOURS_MASK);
 108         tm->tm_mday = bcd2bin(regs.date);
 109         tm->tm_wday = bcd2bin(regs.day) - 1;
 110         tm->tm_mon = bcd2bin(regs.month) - 1;
 111         tm->tm_year = bcd2bin(regs.years) +
 112                                 ((regs.cent_hours & BQ32K_CENT) ? 100 : 0);
 113 
 114         return 0;
 115 }
 116 
 117 static int bq32k_rtc_set_time(struct device *dev, struct rtc_time *tm)
 118 {
 119         struct bq32k_regs regs;
 120 
 121         regs.seconds = bin2bcd(tm->tm_sec);
 122         regs.minutes = bin2bcd(tm->tm_min);
 123         regs.cent_hours = bin2bcd(tm->tm_hour) | BQ32K_CENT_EN;
 124         regs.day = bin2bcd(tm->tm_wday + 1);
 125         regs.date = bin2bcd(tm->tm_mday);
 126         regs.month = bin2bcd(tm->tm_mon + 1);
 127 
 128         if (tm->tm_year >= 100) {
 129                 regs.cent_hours |= BQ32K_CENT;
 130                 regs.years = bin2bcd(tm->tm_year - 100);
 131         } else
 132                 regs.years = bin2bcd(tm->tm_year);
 133 
 134         return bq32k_write(dev, &regs, 0, sizeof(regs));
 135 }
 136 
 137 static const struct rtc_class_ops bq32k_rtc_ops = {
 138         .read_time      = bq32k_rtc_read_time,
 139         .set_time       = bq32k_rtc_set_time,
 140 };
 141 
 142 static int trickle_charger_of_init(struct device *dev, struct device_node *node)
 143 {
 144         unsigned char reg;
 145         int error;
 146         u32 ohms = 0;
 147 
 148         if (of_property_read_u32(node, "trickle-resistor-ohms" , &ohms))
 149                 return 0;
 150 
 151         switch (ohms) {
 152         case 180+940:
 153                 /*
 154                  * TCHE[3:0] == 0x05, TCH2 == 1, TCFE == 0 (charging
 155                  * over diode and 940ohm resistor)
 156                  */
 157 
 158                 if (of_property_read_bool(node, "trickle-diode-disable")) {
 159                         dev_err(dev, "diode and resistor mismatch\n");
 160                         return -EINVAL;
 161                 }
 162                 reg = 0x05;
 163                 break;
 164 
 165         case 180+20000:
 166                 /* diode disabled */
 167 
 168                 if (!of_property_read_bool(node, "trickle-diode-disable")) {
 169                         dev_err(dev, "bq32k: diode and resistor mismatch\n");
 170                         return -EINVAL;
 171                 }
 172                 reg = 0x45;
 173                 break;
 174 
 175         default:
 176                 dev_err(dev, "invalid resistor value (%d)\n", ohms);
 177                 return -EINVAL;
 178         }
 179 
 180         error = bq32k_write(dev, &reg, BQ32K_CFG2, 1);
 181         if (error)
 182                 return error;
 183 
 184         reg = 0x20;
 185         error = bq32k_write(dev, &reg, BQ32K_TCH2, 1);
 186         if (error)
 187                 return error;
 188 
 189         dev_info(dev, "Enabled trickle RTC battery charge.\n");
 190         return 0;
 191 }
 192 
 193 static ssize_t bq32k_sysfs_show_tricklecharge_bypass(struct device *dev,
 194                                                struct device_attribute *attr,
 195                                                char *buf)
 196 {
 197         int reg, error;
 198 
 199         error = bq32k_read(dev, &reg, BQ32K_CFG2, 1);
 200         if (error)
 201                 return error;
 202 
 203         return sprintf(buf, "%d\n", (reg & BQ32K_TCFE) ? 1 : 0);
 204 }
 205 
 206 static ssize_t bq32k_sysfs_store_tricklecharge_bypass(struct device *dev,
 207                                                 struct device_attribute *attr,
 208                                                 const char *buf, size_t count)
 209 {
 210         int reg, enable, error;
 211 
 212         if (kstrtoint(buf, 0, &enable))
 213                 return -EINVAL;
 214 
 215         error = bq32k_read(dev, &reg, BQ32K_CFG2, 1);
 216         if (error)
 217                 return error;
 218 
 219         if (enable) {
 220                 reg |= BQ32K_TCFE;
 221                 error = bq32k_write(dev, &reg, BQ32K_CFG2, 1);
 222                 if (error)
 223                         return error;
 224 
 225                 dev_info(dev, "Enabled trickle charge FET bypass.\n");
 226         } else {
 227                 reg &= ~BQ32K_TCFE;
 228                 error = bq32k_write(dev, &reg, BQ32K_CFG2, 1);
 229                 if (error)
 230                         return error;
 231 
 232                 dev_info(dev, "Disabled trickle charge FET bypass.\n");
 233         }
 234 
 235         return count;
 236 }
 237 
 238 static DEVICE_ATTR(trickle_charge_bypass, 0644,
 239                    bq32k_sysfs_show_tricklecharge_bypass,
 240                    bq32k_sysfs_store_tricklecharge_bypass);
 241 
 242 static int bq32k_sysfs_register(struct device *dev)
 243 {
 244         return device_create_file(dev, &dev_attr_trickle_charge_bypass);
 245 }
 246 
 247 static void bq32k_sysfs_unregister(struct device *dev)
 248 {
 249         device_remove_file(dev, &dev_attr_trickle_charge_bypass);
 250 }
 251 
 252 static int bq32k_probe(struct i2c_client *client,
 253                                 const struct i2c_device_id *id)
 254 {
 255         struct device *dev = &client->dev;
 256         struct rtc_device *rtc;
 257         uint8_t reg;
 258         int error;
 259 
 260         if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 261                 return -ENODEV;
 262 
 263         /* Check Oscillator Stop flag */
 264         error = bq32k_read(dev, &reg, BQ32K_SECONDS, 1);
 265         if (!error && (reg & BQ32K_STOP)) {
 266                 dev_warn(dev, "Oscillator was halted. Restarting...\n");
 267                 reg &= ~BQ32K_STOP;
 268                 error = bq32k_write(dev, &reg, BQ32K_SECONDS, 1);
 269         }
 270         if (error)
 271                 return error;
 272 
 273         /* Check Oscillator Failure flag */
 274         error = bq32k_read(dev, &reg, BQ32K_MINUTES, 1);
 275         if (error)
 276                 return error;
 277         if (reg & BQ32K_OF)
 278                 dev_warn(dev, "Oscillator Failure. Check RTC battery.\n");
 279 
 280         if (client->dev.of_node)
 281                 trickle_charger_of_init(dev, client->dev.of_node);
 282 
 283         rtc = devm_rtc_device_register(&client->dev, bq32k_driver.driver.name,
 284                                                 &bq32k_rtc_ops, THIS_MODULE);
 285         if (IS_ERR(rtc))
 286                 return PTR_ERR(rtc);
 287 
 288         error = bq32k_sysfs_register(&client->dev);
 289         if (error) {
 290                 dev_err(&client->dev,
 291                         "Unable to create sysfs entries for rtc bq32000\n");
 292                 return error;
 293         }
 294 
 295 
 296         i2c_set_clientdata(client, rtc);
 297 
 298         return 0;
 299 }
 300 
 301 static int bq32k_remove(struct i2c_client *client)
 302 {
 303         bq32k_sysfs_unregister(&client->dev);
 304 
 305         return 0;
 306 }
 307 
 308 static const struct i2c_device_id bq32k_id[] = {
 309         { "bq32000", 0 },
 310         { }
 311 };
 312 MODULE_DEVICE_TABLE(i2c, bq32k_id);
 313 
 314 static const struct of_device_id bq32k_of_match[] = {
 315         { .compatible = "ti,bq32000" },
 316         { }
 317 };
 318 MODULE_DEVICE_TABLE(of, bq32k_of_match);
 319 
 320 static struct i2c_driver bq32k_driver = {
 321         .driver = {
 322                 .name   = "bq32k",
 323                 .of_match_table = of_match_ptr(bq32k_of_match),
 324         },
 325         .probe          = bq32k_probe,
 326         .remove         = bq32k_remove,
 327         .id_table       = bq32k_id,
 328 };
 329 
 330 module_i2c_driver(bq32k_driver);
 331 
 332 MODULE_AUTHOR("Semihalf, Piotr Ziecik <kosmo@semihalf.com>");
 333 MODULE_DESCRIPTION("TI BQ32000 I2C RTC driver");
 334 MODULE_LICENSE("GPL");

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