Blame view

drivers/rtc/rtc-ds1302.c 6.17 KB
739d340db   Paul Mundt   rtc: ds1302 rtc s...
1
2
3
  /*
   * Dallas DS1302 RTC Support
   *
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
4
5
   *  Copyright (C) 2002 David McCullough
   *  Copyright (C) 2003 - 2007 Paul Mundt
739d340db   Paul Mundt   rtc: ds1302 rtc s...
6
7
   *
   * This file is subject to the terms and conditions of the GNU General Public
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
8
   * License version 2. See the file "COPYING" in the main directory of
739d340db   Paul Mundt   rtc: ds1302 rtc s...
9
10
   * this archive for more details.
   */
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
11

739d340db   Paul Mundt   rtc: ds1302 rtc s...
12
13
14
15
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/platform_device.h>
739d340db   Paul Mundt   rtc: ds1302 rtc s...
16
  #include <linux/rtc.h>
739d340db   Paul Mundt   rtc: ds1302 rtc s...
17
18
  #include <linux/io.h>
  #include <linux/bcd.h>
739d340db   Paul Mundt   rtc: ds1302 rtc s...
19
20
  
  #define DRV_NAME	"rtc-ds1302"
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
21
  #define DRV_VERSION	"0.1.1"
739d340db   Paul Mundt   rtc: ds1302 rtc s...
22
23
24
25
26
27
28
29
30
31
32
33
34
  
  #define	RTC_CMD_READ	0x81		/* Read command */
  #define	RTC_CMD_WRITE	0x80		/* Write command */
  
  #define RTC_ADDR_RAM0	0x20		/* Address of RAM0 */
  #define RTC_ADDR_TCR	0x08		/* Address of trickle charge register */
  #define	RTC_ADDR_YEAR	0x06		/* Address of year register */
  #define	RTC_ADDR_DAY	0x05		/* Address of day of week register */
  #define	RTC_ADDR_MON	0x04		/* Address of month register */
  #define	RTC_ADDR_DATE	0x03		/* Address of day of month register */
  #define	RTC_ADDR_HOUR	0x02		/* Address of hour register */
  #define	RTC_ADDR_MIN	0x01		/* Address of minute register */
  #define	RTC_ADDR_SEC	0x00		/* Address of second register */
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
35
36
  #ifdef CONFIG_SH_SECUREEDGE5410
  #include <asm/rtc.h>
f6eec8d66   Paul Mundt   sh: mach-snapgear...
37
  #include <mach/secureedge5410.h>
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
38

739d340db   Paul Mundt   rtc: ds1302 rtc s...
39
40
41
  #define	RTC_RESET	0x1000
  #define	RTC_IODATA	0x0800
  #define	RTC_SCLK	0x0400
739d340db   Paul Mundt   rtc: ds1302 rtc s...
42
43
  #define set_dp(x)	SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
  #define get_dp()	SECUREEDGE_READ_IOPORT()
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  #define ds1302_set_tx()
  #define ds1302_set_rx()
  
  static inline int ds1302_hw_init(void)
  {
  	return 0;
  }
  
  static inline void ds1302_reset(void)
  {
  	set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
  }
  
  static inline void ds1302_clock(void)
  {
  	set_dp(get_dp() | RTC_SCLK);	/* clock high */
  	set_dp(get_dp() & ~RTC_SCLK);	/* clock low */
  }
  
  static inline void ds1302_start(void)
  {
  	set_dp(get_dp() | RTC_RESET);
  }
  
  static inline void ds1302_stop(void)
  {
  	set_dp(get_dp() & ~RTC_RESET);
  }
  
  static inline void ds1302_txbit(int bit)
  {
  	set_dp((get_dp() & ~RTC_IODATA) | (bit ? RTC_IODATA : 0));
  }
  
  static inline int ds1302_rxbit(void)
  {
  	return !!(get_dp() & RTC_IODATA);
  }
739d340db   Paul Mundt   rtc: ds1302 rtc s...
82
83
84
  #else
  #error "Add support for your platform"
  #endif
739d340db   Paul Mundt   rtc: ds1302 rtc s...
85
86
87
  static void ds1302_sendbits(unsigned int val)
  {
  	int i;
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
88
  	ds1302_set_tx();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
89
  	for (i = 8; (i); i--, val >>= 1) {
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
90
91
  		ds1302_txbit(val & 0x1);
  		ds1302_clock();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
92
93
94
95
96
97
98
  	}
  }
  
  static unsigned int ds1302_recvbits(void)
  {
  	unsigned int val;
  	int i;
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
99
  	ds1302_set_rx();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
100
  	for (i = 0, val = 0; (i < 8); i++) {
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
101
102
  		val |= (ds1302_rxbit() << i);
  		ds1302_clock();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
103
104
105
106
107
108
109
110
  	}
  
  	return val;
  }
  
  static unsigned int ds1302_readbyte(unsigned int addr)
  {
  	unsigned int val;
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
111
  	ds1302_reset();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
112

72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
113
  	ds1302_start();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
114
115
  	ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
  	val = ds1302_recvbits();
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
116
  	ds1302_stop();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
117
118
119
120
121
122
  
  	return val;
  }
  
  static void ds1302_writebyte(unsigned int addr, unsigned int val)
  {
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
123
124
125
  	ds1302_reset();
  
  	ds1302_start();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
126
127
  	ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
  	ds1302_sendbits(val);
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
128
  	ds1302_stop();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
129
130
131
132
  }
  
  static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
  {
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
133
134
135
136
137
138
139
  	tm->tm_sec	= bcd2bin(ds1302_readbyte(RTC_ADDR_SEC));
  	tm->tm_min	= bcd2bin(ds1302_readbyte(RTC_ADDR_MIN));
  	tm->tm_hour	= bcd2bin(ds1302_readbyte(RTC_ADDR_HOUR));
  	tm->tm_wday	= bcd2bin(ds1302_readbyte(RTC_ADDR_DAY));
  	tm->tm_mday	= bcd2bin(ds1302_readbyte(RTC_ADDR_DATE));
  	tm->tm_mon	= bcd2bin(ds1302_readbyte(RTC_ADDR_MON)) - 1;
  	tm->tm_year	= bcd2bin(ds1302_readbyte(RTC_ADDR_YEAR));
739d340db   Paul Mundt   rtc: ds1302 rtc s...
140
141
142
  
  	if (tm->tm_year < 70)
  		tm->tm_year += 100;
739d340db   Paul Mundt   rtc: ds1302 rtc s...
143
144
145
  	dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
  		"mday=%d, mon=%d, year=%d, wday=%d
  ",
2a4e2b878   Harvey Harrison   rtc: replace rema...
146
  		__func__,
739d340db   Paul Mundt   rtc: ds1302 rtc s...
147
148
  		tm->tm_sec, tm->tm_min, tm->tm_hour,
  		tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
149
  	return rtc_valid_tm(tm);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
150
151
152
153
  }
  
  static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
  {
739d340db   Paul Mundt   rtc: ds1302 rtc s...
154
155
  	/* Stop RTC */
  	ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
156
157
158
159
160
161
162
  	ds1302_writebyte(RTC_ADDR_SEC, bin2bcd(tm->tm_sec));
  	ds1302_writebyte(RTC_ADDR_MIN, bin2bcd(tm->tm_min));
  	ds1302_writebyte(RTC_ADDR_HOUR, bin2bcd(tm->tm_hour));
  	ds1302_writebyte(RTC_ADDR_DAY, bin2bcd(tm->tm_wday));
  	ds1302_writebyte(RTC_ADDR_DATE, bin2bcd(tm->tm_mday));
  	ds1302_writebyte(RTC_ADDR_MON, bin2bcd(tm->tm_mon + 1));
  	ds1302_writebyte(RTC_ADDR_YEAR, bin2bcd(tm->tm_year % 100));
739d340db   Paul Mundt   rtc: ds1302 rtc s...
163
164
165
  
  	/* Start RTC */
  	ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
166
167
168
169
170
171
172
173
174
175
  	return 0;
  }
  
  static int ds1302_rtc_ioctl(struct device *dev, unsigned int cmd,
  			    unsigned long arg)
  {
  	switch (cmd) {
  #ifdef RTC_SET_CHARGE
  	case RTC_SET_CHARGE:
  	{
739d340db   Paul Mundt   rtc: ds1302 rtc s...
176
177
178
179
  		int tcs_val;
  
  		if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int)))
  			return -EFAULT;
739d340db   Paul Mundt   rtc: ds1302 rtc s...
180
  		ds1302_writebyte(RTC_ADDR_TCR, (0xa0 | tcs_val * 0xf));
739d340db   Paul Mundt   rtc: ds1302 rtc s...
181
182
183
184
185
186
187
188
189
190
191
192
193
  		return 0;
  	}
  #endif
  	}
  
  	return -ENOIOCTLCMD;
  }
  
  static struct rtc_class_ops ds1302_rtc_ops = {
  	.read_time	= ds1302_rtc_read_time,
  	.set_time	= ds1302_rtc_set_time,
  	.ioctl		= ds1302_rtc_ioctl,
  };
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
194
  static int __init ds1302_rtc_probe(struct platform_device *pdev)
739d340db   Paul Mundt   rtc: ds1302 rtc s...
195
  {
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
196
  	struct rtc_device *rtc;
739d340db   Paul Mundt   rtc: ds1302 rtc s...
197

72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
198
199
200
201
  	if (ds1302_hw_init()) {
  		dev_err(&pdev->dev, "Failed to init communication channel");
  		return -EINVAL;
  	}
739d340db   Paul Mundt   rtc: ds1302 rtc s...
202
  	/* Reset */
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
203
  	ds1302_reset();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
204
205
206
  
  	/* Write a magic value to the DS1302 RAM, and see if it sticks. */
  	ds1302_writebyte(RTC_ADDR_RAM0, 0x42);
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
207
208
  	if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) {
  		dev_err(&pdev->dev, "Failed to probe");
739d340db   Paul Mundt   rtc: ds1302 rtc s...
209
  		return -ENODEV;
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
210
  	}
739d340db   Paul Mundt   rtc: ds1302 rtc s...
211

2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
212
  	rtc = rtc_device_register("ds1302", &pdev->dev,
739d340db   Paul Mundt   rtc: ds1302 rtc s...
213
  					   &ds1302_rtc_ops, THIS_MODULE);
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
214
215
  	if (IS_ERR(rtc))
  		return PTR_ERR(rtc);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
216
217
218
219
  
  	platform_set_drvdata(pdev, rtc);
  
  	return 0;
739d340db   Paul Mundt   rtc: ds1302 rtc s...
220
221
222
223
  }
  
  static int __devexit ds1302_rtc_remove(struct platform_device *pdev)
  {
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
224
  	struct rtc_device *rtc = platform_get_drvdata(pdev);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
225

2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
226
  	rtc_device_unregister(rtc);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
227
  	platform_set_drvdata(pdev, NULL);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
228
229
230
231
232
233
234
235
  	return 0;
  }
  
  static struct platform_driver ds1302_platform_driver = {
  	.driver		= {
  		.name	= DRV_NAME,
  		.owner	= THIS_MODULE,
  	},
b9e05c64a   Uwe Kleine-König   rtc: don't use __...
236
  	.remove		= __devexit_p(ds1302_rtc_remove),
739d340db   Paul Mundt   rtc: ds1302 rtc s...
237
238
239
240
  };
  
  static int __init ds1302_rtc_init(void)
  {
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
241
  	return platform_driver_probe(&ds1302_platform_driver, ds1302_rtc_probe);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  }
  
  static void __exit ds1302_rtc_exit(void)
  {
  	platform_driver_unregister(&ds1302_platform_driver);
  }
  
  module_init(ds1302_rtc_init);
  module_exit(ds1302_rtc_exit);
  
  MODULE_DESCRIPTION("Dallas DS1302 RTC driver");
  MODULE_VERSION(DRV_VERSION);
  MODULE_AUTHOR("Paul Mundt, David McCullough");
  MODULE_LICENSE("GPL v2");