blob: 45d65c0b3a85d07ed592b9cb0380e01fe1e2b27a [file] [log] [blame]
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -08001/*
2 * An rtc/i2c driver for the Dallas DS1672
Alessandro Zummo39035862006-04-10 22:54:41 -07003 * Copyright 2005-06 Tower Technologies
4 *
5 * Author: Alessandro Zummo <a.zummo@towertech.it>
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -08006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080012#include <linux/i2c.h>
13#include <linux/rtc.h>
Paul Gortmaker21138522011-05-27 09:57:25 -040014#include <linux/module.h>
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080015
Alessandro Zummo1716b0f2008-10-15 22:03:10 -070016#define DRV_VERSION "0.4"
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080017
18/* Registers */
19
20#define DS1672_REG_CNT_BASE 0
21#define DS1672_REG_CONTROL 4
22#define DS1672_REG_TRICKLE 5
23
Alessandro Zummo39035862006-04-10 22:54:41 -070024#define DS1672_REG_CONTROL_EOSC 0x80
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080025
Alessandro Zummo1716b0f2008-10-15 22:03:10 -070026static struct i2c_driver ds1672_driver;
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080027
28/*
29 * In the routines that deal directly with the ds1672 hardware, we use
30 * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
31 * Epoch is initialized as 2000. Time is set to UTC.
32 */
33static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
34{
35 unsigned long time;
36 unsigned char addr = DS1672_REG_CNT_BASE;
37 unsigned char buf[4];
38
39 struct i2c_msg msgs[] = {
Shubhrajyoti D2bfc37d2012-10-04 17:14:17 -070040 {/* setup read ptr */
41 .addr = client->addr,
42 .len = 1,
43 .buf = &addr
44 },
45 {/* read date */
46 .addr = client->addr,
47 .flags = I2C_M_RD,
48 .len = 4,
49 .buf = buf
50 },
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080051 };
52
53 /* read date registers */
54 if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
Harvey Harrison2a4e2b8782008-04-28 02:12:00 -070055 dev_err(&client->dev, "%s: read error\n", __func__);
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080056 return -EIO;
57 }
58
59 dev_dbg(&client->dev,
Jeff Garzik11966ad2006-10-04 04:41:53 -040060 "%s: raw read data - counters=%02x,%02x,%02x,%02x\n",
Harvey Harrison2a4e2b8782008-04-28 02:12:00 -070061 __func__, buf[0], buf[1], buf[2], buf[3]);
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080062
63 time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
64
65 rtc_time_to_tm(time, tm);
66
67 dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
68 "mday=%d, mon=%d, year=%d, wday=%d\n",
Harvey Harrison2a4e2b8782008-04-28 02:12:00 -070069 __func__, tm->tm_sec, tm->tm_min, tm->tm_hour,
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080070 tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
71
72 return 0;
73}
74
75static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs)
76{
77 int xfer;
Kumar Gala8a95b252006-04-10 22:54:39 -070078 unsigned char buf[6];
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080079
80 buf[0] = DS1672_REG_CNT_BASE;
81 buf[1] = secs & 0x000000FF;
82 buf[2] = (secs & 0x0000FF00) >> 8;
83 buf[3] = (secs & 0x00FF0000) >> 16;
84 buf[4] = (secs & 0xFF000000) >> 24;
Alessandro Zummo1716b0f2008-10-15 22:03:10 -070085 buf[5] = 0; /* set control reg to enable counting */
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080086
Kumar Gala8a95b252006-04-10 22:54:39 -070087 xfer = i2c_master_send(client, buf, 6);
88 if (xfer != 6) {
Harvey Harrison2a4e2b8782008-04-28 02:12:00 -070089 dev_err(&client->dev, "%s: send: %d\n", __func__, xfer);
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080090 return -EIO;
91 }
92
93 return 0;
94}
95
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -080096static int ds1672_rtc_read_time(struct device *dev, struct rtc_time *tm)
97{
98 return ds1672_get_datetime(to_i2c_client(dev), tm);
99}
100
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800101static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs)
102{
103 return ds1672_set_mmss(to_i2c_client(dev), secs);
104}
105
Kumar Gala8a95b252006-04-10 22:54:39 -0700106static int ds1672_get_control(struct i2c_client *client, u8 *status)
107{
108 unsigned char addr = DS1672_REG_CONTROL;
109
110 struct i2c_msg msgs[] = {
Shubhrajyoti D2bfc37d2012-10-04 17:14:17 -0700111 {/* setup read ptr */
112 .addr = client->addr,
113 .len = 1,
114 .buf = &addr
115 },
116 {/* read control */
117 .addr = client->addr,
118 .flags = I2C_M_RD,
119 .len = 1,
120 .buf = status
121 },
Kumar Gala8a95b252006-04-10 22:54:39 -0700122 };
123
124 /* read control register */
125 if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
Harvey Harrison2a4e2b8782008-04-28 02:12:00 -0700126 dev_err(&client->dev, "%s: read error\n", __func__);
Kumar Gala8a95b252006-04-10 22:54:39 -0700127 return -EIO;
128 }
129
130 return 0;
131}
132
133/* following are the sysfs callback functions */
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700134static ssize_t show_control(struct device *dev, struct device_attribute *attr,
135 char *buf)
Kumar Gala8a95b252006-04-10 22:54:39 -0700136{
137 struct i2c_client *client = to_i2c_client(dev);
Kumar Gala8a95b252006-04-10 22:54:39 -0700138 u8 control;
139 int err;
140
141 err = ds1672_get_control(client, &control);
142 if (err)
143 return err;
144
Alessandro Zummo39035862006-04-10 22:54:41 -0700145 return sprintf(buf, "%s\n", (control & DS1672_REG_CONTROL_EOSC)
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700146 ? "disabled" : "enabled");
Kumar Gala8a95b252006-04-10 22:54:39 -0700147}
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700148
Kumar Gala8a95b252006-04-10 22:54:39 -0700149static DEVICE_ATTR(control, S_IRUGO, show_control, NULL);
150
David Brownellff8371a2006-09-30 23:28:17 -0700151static const struct rtc_class_ops ds1672_rtc_ops = {
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700152 .read_time = ds1672_rtc_read_time,
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700153 .set_mmss = ds1672_rtc_set_mmss,
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800154};
155
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700156static int ds1672_remove(struct i2c_client *client)
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800157{
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800158 struct rtc_device *rtc = i2c_get_clientdata(client);
159
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700160 if (rtc)
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800161 rtc_device_unregister(rtc);
162
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800163 return 0;
164}
165
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700166static int ds1672_probe(struct i2c_client *client,
167 const struct i2c_device_id *id)
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800168{
169 int err = 0;
Kumar Gala8a95b252006-04-10 22:54:39 -0700170 u8 control;
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800171 struct rtc_device *rtc;
172
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700173 dev_dbg(&client->dev, "%s\n", __func__);
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800174
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700175 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
176 return -ENODEV;
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800177
178 dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
179
180 rtc = rtc_device_register(ds1672_driver.driver.name, &client->dev,
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700181 &ds1672_rtc_ops, THIS_MODULE);
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800182
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700183 if (IS_ERR(rtc))
184 return PTR_ERR(rtc);
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800185
186 i2c_set_clientdata(client, rtc);
187
Kumar Gala8a95b252006-04-10 22:54:39 -0700188 /* read control register */
189 err = ds1672_get_control(client, &control);
Alessandro Zummo39035862006-04-10 22:54:41 -0700190 if (err)
Jeff Garzik91046a82006-12-06 20:35:34 -0800191 goto exit_devreg;
Kumar Gala8a95b252006-04-10 22:54:39 -0700192
193 if (control & DS1672_REG_CONTROL_EOSC)
194 dev_warn(&client->dev, "Oscillator not enabled. "
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700195 "Set time to enable.\n");
Kumar Gala8a95b252006-04-10 22:54:39 -0700196
197 /* Register sysfs hooks */
Jeff Garzik91046a82006-12-06 20:35:34 -0800198 err = device_create_file(&client->dev, &dev_attr_control);
199 if (err)
200 goto exit_devreg;
Kumar Gala8a95b252006-04-10 22:54:39 -0700201
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800202 return 0;
203
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700204 exit_devreg:
Jeff Garzik91046a82006-12-06 20:35:34 -0800205 rtc_device_unregister(rtc);
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800206 return err;
207}
208
Alessandro Zummofe102c72008-12-09 13:14:11 -0800209static struct i2c_device_id ds1672_id[] = {
210 { "ds1672", 0 },
211 { }
212};
213
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700214static struct i2c_driver ds1672_driver = {
215 .driver = {
216 .name = "rtc-ds1672",
217 },
218 .probe = &ds1672_probe,
219 .remove = &ds1672_remove,
Alessandro Zummofe102c72008-12-09 13:14:11 -0800220 .id_table = ds1672_id,
Alessandro Zummo1716b0f2008-10-15 22:03:10 -0700221};
222
Axel Lin0abc9202012-03-23 15:02:31 -0700223module_i2c_driver(ds1672_driver);
Alessandro Zummoedf1aaa2006-03-27 01:16:43 -0800224
225MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
226MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
227MODULE_LICENSE("GPL");
228MODULE_VERSION(DRV_VERSION);