161 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * An rtc/i2c driver for the Dallas DS16724 * Copyright 2005-06 Tower Technologies5 *6 * Author: Alessandro Zummo <a.zummo@towertech.it>7 */8 9#include <linux/i2c.h>10#include <linux/rtc.h>11#include <linux/module.h>12 13/* Registers */14 15#define DS1672_REG_CNT_BASE 016#define DS1672_REG_CONTROL 417#define DS1672_REG_TRICKLE 518 19#define DS1672_REG_CONTROL_EOSC 0x8020 21/*22 * In the routines that deal directly with the ds1672 hardware, we use23 * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch24 * Time is set to UTC.25 */26static int ds1672_read_time(struct device *dev, struct rtc_time *tm)27{28 struct i2c_client *client = to_i2c_client(dev);29 unsigned long time;30 unsigned char addr = DS1672_REG_CONTROL;31 unsigned char buf[4];32 33 struct i2c_msg msgs[] = {34 {/* setup read ptr */35 .addr = client->addr,36 .len = 1,37 .buf = &addr38 },39 {/* read date */40 .addr = client->addr,41 .flags = I2C_M_RD,42 .len = 1,43 .buf = buf44 },45 };46 47 /* read control register */48 if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {49 dev_warn(&client->dev, "Unable to read the control register\n");50 return -EIO;51 }52 53 if (buf[0] & DS1672_REG_CONTROL_EOSC) {54 dev_warn(&client->dev, "Oscillator not enabled. Set time to enable.\n");55 return -EINVAL;56 }57 58 addr = DS1672_REG_CNT_BASE;59 msgs[1].len = 4;60 61 /* read date registers */62 if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {63 dev_err(&client->dev, "%s: read error\n", __func__);64 return -EIO;65 }66 67 dev_dbg(&client->dev,68 "%s: raw read data - counters=%02x,%02x,%02x,%02x\n",69 __func__, buf[0], buf[1], buf[2], buf[3]);70 71 time = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |72 (buf[1] << 8) | buf[0];73 74 rtc_time64_to_tm(time, tm);75 76 dev_dbg(&client->dev, "%s: tm is %ptR\n", __func__, tm);77 78 return 0;79}80 81static int ds1672_set_time(struct device *dev, struct rtc_time *tm)82{83 struct i2c_client *client = to_i2c_client(dev);84 int xfer;85 unsigned char buf[6];86 unsigned long secs = rtc_tm_to_time64(tm);87 88 buf[0] = DS1672_REG_CNT_BASE;89 buf[1] = secs & 0x000000FF;90 buf[2] = (secs & 0x0000FF00) >> 8;91 buf[3] = (secs & 0x00FF0000) >> 16;92 buf[4] = (secs & 0xFF000000) >> 24;93 buf[5] = 0; /* set control reg to enable counting */94 95 xfer = i2c_master_send(client, buf, 6);96 if (xfer != 6) {97 dev_err(&client->dev, "%s: send: %d\n", __func__, xfer);98 return -EIO;99 }100 101 return 0;102}103 104static const struct rtc_class_ops ds1672_rtc_ops = {105 .read_time = ds1672_read_time,106 .set_time = ds1672_set_time,107};108 109static int ds1672_probe(struct i2c_client *client)110{111 int err = 0;112 struct rtc_device *rtc;113 114 dev_dbg(&client->dev, "%s\n", __func__);115 116 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))117 return -ENODEV;118 119 rtc = devm_rtc_allocate_device(&client->dev);120 if (IS_ERR(rtc))121 return PTR_ERR(rtc);122 123 rtc->ops = &ds1672_rtc_ops;124 rtc->range_max = U32_MAX;125 126 err = devm_rtc_register_device(rtc);127 if (err)128 return err;129 130 i2c_set_clientdata(client, rtc);131 132 return 0;133}134 135static const struct i2c_device_id ds1672_id[] = {136 { "ds1672" },137 { }138};139MODULE_DEVICE_TABLE(i2c, ds1672_id);140 141static const __maybe_unused struct of_device_id ds1672_of_match[] = {142 { .compatible = "dallas,ds1672" },143 { }144};145MODULE_DEVICE_TABLE(of, ds1672_of_match);146 147static struct i2c_driver ds1672_driver = {148 .driver = {149 .name = "rtc-ds1672",150 .of_match_table = of_match_ptr(ds1672_of_match),151 },152 .probe = ds1672_probe,153 .id_table = ds1672_id,154};155 156module_i2c_driver(ds1672_driver);157 158MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");159MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");160MODULE_LICENSE("GPL");161