169468320SAlexandre Belloni // SPDX-License-Identifier: GPL-2.0
2edf1aaa3SAlessandro Zummo /*
3edf1aaa3SAlessandro Zummo * An rtc/i2c driver for the Dallas DS1672
43903586aSAlessandro Zummo * Copyright 2005-06 Tower Technologies
53903586aSAlessandro Zummo *
63903586aSAlessandro Zummo * Author: Alessandro Zummo <a.zummo@towertech.it>
7edf1aaa3SAlessandro Zummo */
8edf1aaa3SAlessandro Zummo
9edf1aaa3SAlessandro Zummo #include <linux/i2c.h>
10edf1aaa3SAlessandro Zummo #include <linux/rtc.h>
112113852bSPaul Gortmaker #include <linux/module.h>
12edf1aaa3SAlessandro Zummo
13edf1aaa3SAlessandro Zummo /* Registers */
14edf1aaa3SAlessandro Zummo
15edf1aaa3SAlessandro Zummo #define DS1672_REG_CNT_BASE 0
16edf1aaa3SAlessandro Zummo #define DS1672_REG_CONTROL 4
17edf1aaa3SAlessandro Zummo #define DS1672_REG_TRICKLE 5
18edf1aaa3SAlessandro Zummo
193903586aSAlessandro Zummo #define DS1672_REG_CONTROL_EOSC 0x80
20edf1aaa3SAlessandro Zummo
21edf1aaa3SAlessandro Zummo /*
22edf1aaa3SAlessandro Zummo * In the routines that deal directly with the ds1672 hardware, we use
23edf1aaa3SAlessandro Zummo * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
24d1fbe695SAlexandre Belloni * Time is set to UTC.
25edf1aaa3SAlessandro Zummo */
ds1672_read_time(struct device * dev,struct rtc_time * tm)267a5670c7SAlexandre Belloni static int ds1672_read_time(struct device *dev, struct rtc_time *tm)
27edf1aaa3SAlessandro Zummo {
287a5670c7SAlexandre Belloni struct i2c_client *client = to_i2c_client(dev);
29edf1aaa3SAlessandro Zummo unsigned long time;
3010e3efc1SAlexandre Belloni unsigned char addr = DS1672_REG_CONTROL;
31edf1aaa3SAlessandro Zummo unsigned char buf[4];
32edf1aaa3SAlessandro Zummo
33edf1aaa3SAlessandro Zummo struct i2c_msg msgs[] = {
342bfc37dfSShubhrajyoti D {/* setup read ptr */
352bfc37dfSShubhrajyoti D .addr = client->addr,
362bfc37dfSShubhrajyoti D .len = 1,
372bfc37dfSShubhrajyoti D .buf = &addr
382bfc37dfSShubhrajyoti D },
392bfc37dfSShubhrajyoti D {/* read date */
402bfc37dfSShubhrajyoti D .addr = client->addr,
412bfc37dfSShubhrajyoti D .flags = I2C_M_RD,
4210e3efc1SAlexandre Belloni .len = 1,
432bfc37dfSShubhrajyoti D .buf = buf
442bfc37dfSShubhrajyoti D },
45edf1aaa3SAlessandro Zummo };
46edf1aaa3SAlessandro Zummo
4710e3efc1SAlexandre Belloni /* read control register */
4810e3efc1SAlexandre Belloni if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
4910e3efc1SAlexandre Belloni dev_warn(&client->dev, "Unable to read the control register\n");
5010e3efc1SAlexandre Belloni return -EIO;
5110e3efc1SAlexandre Belloni }
5210e3efc1SAlexandre Belloni
5310e3efc1SAlexandre Belloni if (buf[0] & DS1672_REG_CONTROL_EOSC) {
5410e3efc1SAlexandre Belloni dev_warn(&client->dev, "Oscillator not enabled. Set time to enable.\n");
5510e3efc1SAlexandre Belloni return -EINVAL;
5610e3efc1SAlexandre Belloni }
5710e3efc1SAlexandre Belloni
5810e3efc1SAlexandre Belloni addr = DS1672_REG_CNT_BASE;
5910e3efc1SAlexandre Belloni msgs[1].len = 4;
6010e3efc1SAlexandre Belloni
61edf1aaa3SAlessandro Zummo /* read date registers */
62edf1aaa3SAlessandro Zummo if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
632a4e2b87SHarvey Harrison dev_err(&client->dev, "%s: read error\n", __func__);
64edf1aaa3SAlessandro Zummo return -EIO;
65edf1aaa3SAlessandro Zummo }
66edf1aaa3SAlessandro Zummo
67edf1aaa3SAlessandro Zummo dev_dbg(&client->dev,
6811966adcSJeff Garzik "%s: raw read data - counters=%02x,%02x,%02x,%02x\n",
692a4e2b87SHarvey Harrison __func__, buf[0], buf[1], buf[2], buf[3]);
70edf1aaa3SAlessandro Zummo
71f0c04c27SColin Ian King time = ((unsigned long)buf[3] << 24) | (buf[2] << 16) |
72f0c04c27SColin Ian King (buf[1] << 8) | buf[0];
73edf1aaa3SAlessandro Zummo
74520d6516SAlexandre Belloni rtc_time64_to_tm(time, tm);
75edf1aaa3SAlessandro Zummo
76e3a76913SAlexandre Belloni dev_dbg(&client->dev, "%s: tm is %ptR\n", __func__, tm);
77edf1aaa3SAlessandro Zummo
78edf1aaa3SAlessandro Zummo return 0;
79edf1aaa3SAlessandro Zummo }
80edf1aaa3SAlessandro Zummo
ds1672_set_time(struct device * dev,struct rtc_time * tm)81219219d9SAlexandre Belloni static int ds1672_set_time(struct device *dev, struct rtc_time *tm)
82edf1aaa3SAlessandro Zummo {
837a5670c7SAlexandre Belloni struct i2c_client *client = to_i2c_client(dev);
84edf1aaa3SAlessandro Zummo int xfer;
858a95b252SKumar Gala unsigned char buf[6];
86219219d9SAlexandre Belloni unsigned long secs = rtc_tm_to_time64(tm);
87edf1aaa3SAlessandro Zummo
88edf1aaa3SAlessandro Zummo buf[0] = DS1672_REG_CNT_BASE;
89edf1aaa3SAlessandro Zummo buf[1] = secs & 0x000000FF;
90edf1aaa3SAlessandro Zummo buf[2] = (secs & 0x0000FF00) >> 8;
91edf1aaa3SAlessandro Zummo buf[3] = (secs & 0x00FF0000) >> 16;
92edf1aaa3SAlessandro Zummo buf[4] = (secs & 0xFF000000) >> 24;
938a95b252SKumar Gala buf[5] = 0; /* set control reg to enable counting */
94edf1aaa3SAlessandro Zummo
958a95b252SKumar Gala xfer = i2c_master_send(client, buf, 6);
968a95b252SKumar Gala if (xfer != 6) {
972a4e2b87SHarvey Harrison dev_err(&client->dev, "%s: send: %d\n", __func__, xfer);
98edf1aaa3SAlessandro Zummo return -EIO;
99edf1aaa3SAlessandro Zummo }
100edf1aaa3SAlessandro Zummo
101edf1aaa3SAlessandro Zummo return 0;
102edf1aaa3SAlessandro Zummo }
103edf1aaa3SAlessandro Zummo
104ff8371acSDavid Brownell static const struct rtc_class_ops ds1672_rtc_ops = {
1057a5670c7SAlexandre Belloni .read_time = ds1672_read_time,
106219219d9SAlexandre Belloni .set_time = ds1672_set_time,
107edf1aaa3SAlessandro Zummo };
108edf1aaa3SAlessandro Zummo
ds1672_probe(struct i2c_client * client)1093f4a3322SStephen Kitt static int ds1672_probe(struct i2c_client *client)
110edf1aaa3SAlessandro Zummo {
111edf1aaa3SAlessandro Zummo int err = 0;
112edf1aaa3SAlessandro Zummo struct rtc_device *rtc;
113edf1aaa3SAlessandro Zummo
1141716b0feSAlessandro Zummo dev_dbg(&client->dev, "%s\n", __func__);
115edf1aaa3SAlessandro Zummo
1161716b0feSAlessandro Zummo if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
1171716b0feSAlessandro Zummo return -ENODEV;
118edf1aaa3SAlessandro Zummo
119d1fbe695SAlexandre Belloni rtc = devm_rtc_allocate_device(&client->dev);
120d1fbe695SAlexandre Belloni if (IS_ERR(rtc))
121d1fbe695SAlexandre Belloni return PTR_ERR(rtc);
122d1fbe695SAlexandre Belloni
123d1fbe695SAlexandre Belloni rtc->ops = &ds1672_rtc_ops;
124d1fbe695SAlexandre Belloni rtc->range_max = U32_MAX;
125d1fbe695SAlexandre Belloni
126fdcfd854SBartosz Golaszewski err = devm_rtc_register_device(rtc);
127d1fbe695SAlexandre Belloni if (err)
128d1fbe695SAlexandre Belloni return err;
129edf1aaa3SAlessandro Zummo
130edf1aaa3SAlessandro Zummo i2c_set_clientdata(client, rtc);
131edf1aaa3SAlessandro Zummo
132edf1aaa3SAlessandro Zummo return 0;
133edf1aaa3SAlessandro Zummo }
134edf1aaa3SAlessandro Zummo
13545a63518SArvind Yadav static const struct i2c_device_id ds1672_id[] = {
136fe102c71SAlessandro Zummo { "ds1672", 0 },
137fe102c71SAlessandro Zummo { }
138fe102c71SAlessandro Zummo };
1398ad0f5b6SAxel Lin MODULE_DEVICE_TABLE(i2c, ds1672_id);
140fe102c71SAlessandro Zummo
141fb38b5daSAlexandre Belloni static const __maybe_unused struct of_device_id ds1672_of_match[] = {
14223194ac0SJavier Martinez Canillas { .compatible = "dallas,ds1672" },
14323194ac0SJavier Martinez Canillas { }
14423194ac0SJavier Martinez Canillas };
14523194ac0SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, ds1672_of_match);
14623194ac0SJavier Martinez Canillas
1471716b0feSAlessandro Zummo static struct i2c_driver ds1672_driver = {
1481716b0feSAlessandro Zummo .driver = {
1491716b0feSAlessandro Zummo .name = "rtc-ds1672",
15023194ac0SJavier Martinez Canillas .of_match_table = of_match_ptr(ds1672_of_match),
1511716b0feSAlessandro Zummo },
152*31b0cecbSUwe Kleine-König .probe = ds1672_probe,
153fe102c71SAlessandro Zummo .id_table = ds1672_id,
1541716b0feSAlessandro Zummo };
1551716b0feSAlessandro Zummo
1560abc9201SAxel Lin module_i2c_driver(ds1672_driver);
157edf1aaa3SAlessandro Zummo
158edf1aaa3SAlessandro Zummo MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
159edf1aaa3SAlessandro Zummo MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
160edf1aaa3SAlessandro Zummo MODULE_LICENSE("GPL");
161