linux/drivers/rtc/rtc-bq32k.c
<<
>>
Prefs
   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 * https://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
  40struct 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
  50static struct i2c_driver bq32k_driver;
  51
  52static 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
  75static 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
  89static 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
 117static 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
 137static const struct rtc_class_ops bq32k_rtc_ops = {
 138        .read_time      = bq32k_rtc_read_time,
 139        .set_time       = bq32k_rtc_set_time,
 140};
 141
 142static 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
 193static 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
 206static 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
 238static DEVICE_ATTR(trickle_charge_bypass, 0644,
 239                   bq32k_sysfs_show_tricklecharge_bypass,
 240                   bq32k_sysfs_store_tricklecharge_bypass);
 241
 242static int bq32k_sysfs_register(struct device *dev)
 243{
 244        return device_create_file(dev, &dev_attr_trickle_charge_bypass);
 245}
 246
 247static void bq32k_sysfs_unregister(struct device *dev)
 248{
 249        device_remove_file(dev, &dev_attr_trickle_charge_bypass);
 250}
 251
 252static 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
 301static int bq32k_remove(struct i2c_client *client)
 302{
 303        bq32k_sysfs_unregister(&client->dev);
 304
 305        return 0;
 306}
 307
 308static const struct i2c_device_id bq32k_id[] = {
 309        { "bq32000", 0 },
 310        { }
 311};
 312MODULE_DEVICE_TABLE(i2c, bq32k_id);
 313
 314static const __maybe_unused struct of_device_id bq32k_of_match[] = {
 315        { .compatible = "ti,bq32000" },
 316        { }
 317};
 318MODULE_DEVICE_TABLE(of, bq32k_of_match);
 319
 320static 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
 330module_i2c_driver(bq32k_driver);
 331
 332MODULE_AUTHOR("Semihalf, Piotr Ziecik <kosmo@semihalf.com>");
 333MODULE_DESCRIPTION("TI BQ32000 I2C RTC driver");
 334MODULE_LICENSE("GPL");
 335
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.