Blame view

drivers/rtc/rtc-ds1302.c 6.01 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
  
  #define	RTC_CMD_READ	0x81		/* Read command */
  #define	RTC_CMD_WRITE	0x80		/* Write command */
dfc657b13   Sergey Yanovich   drivers/rtc/rtc-d...
25
26
  #define	RTC_CMD_WRITE_ENABLE	0x00		/* Write enable */
  #define	RTC_CMD_WRITE_DISABLE	0x80		/* Write disable */
739d340db   Paul Mundt   rtc: ds1302 rtc s...
27
28
  #define RTC_ADDR_RAM0	0x20		/* Address of RAM0 */
  #define RTC_ADDR_TCR	0x08		/* Address of trickle charge register */
dfc657b13   Sergey Yanovich   drivers/rtc/rtc-d...
29
  #define	RTC_ADDR_CTRL	0x07		/* Address of control register */
739d340db   Paul Mundt   rtc: ds1302 rtc s...
30
31
32
33
34
35
36
  #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...
37
38
  #ifdef CONFIG_SH_SECUREEDGE5410
  #include <asm/rtc.h>
f6eec8d66   Paul Mundt   sh: mach-snapgear...
39
  #include <mach/secureedge5410.h>
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
40

739d340db   Paul Mundt   rtc: ds1302 rtc s...
41
42
43
  #define	RTC_RESET	0x1000
  #define	RTC_IODATA	0x0800
  #define	RTC_SCLK	0x0400
739d340db   Paul Mundt   rtc: ds1302 rtc s...
44
45
  #define set_dp(x)	SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
  #define get_dp()	SECUREEDGE_READ_IOPORT()
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
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
82
83
  #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...
84
85
86
  #else
  #error "Add support for your platform"
  #endif
739d340db   Paul Mundt   rtc: ds1302 rtc s...
87
88
89
  static void ds1302_sendbits(unsigned int val)
  {
  	int i;
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
90
  	ds1302_set_tx();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
91
  	for (i = 8; (i); i--, val >>= 1) {
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
92
93
  		ds1302_txbit(val & 0x1);
  		ds1302_clock();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
94
95
96
97
98
99
100
  	}
  }
  
  static unsigned int ds1302_recvbits(void)
  {
  	unsigned int val;
  	int i;
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
101
  	ds1302_set_rx();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
102
  	for (i = 0, val = 0; (i < 8); i++) {
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
103
104
  		val |= (ds1302_rxbit() << i);
  		ds1302_clock();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
105
106
107
108
109
110
111
112
  	}
  
  	return val;
  }
  
  static unsigned int ds1302_readbyte(unsigned int addr)
  {
  	unsigned int val;
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
113
  	ds1302_reset();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
114

72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
115
  	ds1302_start();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
116
117
  	ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
  	val = ds1302_recvbits();
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
118
  	ds1302_stop();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
119
120
121
122
123
124
  
  	return val;
  }
  
  static void ds1302_writebyte(unsigned int addr, unsigned int val)
  {
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
125
126
127
  	ds1302_reset();
  
  	ds1302_start();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
128
129
  	ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
  	ds1302_sendbits(val);
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
130
  	ds1302_stop();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
131
132
133
134
  }
  
  static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
  {
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
135
136
137
138
139
140
141
  	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...
142
143
144
  
  	if (tm->tm_year < 70)
  		tm->tm_year += 100;
739d340db   Paul Mundt   rtc: ds1302 rtc s...
145
146
147
  	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...
148
  		__func__,
739d340db   Paul Mundt   rtc: ds1302 rtc s...
149
150
  		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...
151
  	return rtc_valid_tm(tm);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
152
153
154
155
  }
  
  static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
  {
dfc657b13   Sergey Yanovich   drivers/rtc/rtc-d...
156
  	ds1302_writebyte(RTC_ADDR_CTRL, RTC_CMD_WRITE_ENABLE);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
157
158
  	/* Stop RTC */
  	ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
159
160
161
162
163
164
165
  	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...
166
167
168
  
  	/* Start RTC */
  	ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80);
dfc657b13   Sergey Yanovich   drivers/rtc/rtc-d...
169
  	ds1302_writebyte(RTC_ADDR_CTRL, RTC_CMD_WRITE_DISABLE);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
170
171
172
173
174
175
176
177
178
179
  	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...
180
181
182
183
  		int tcs_val;
  
  		if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int)))
  			return -EFAULT;
739d340db   Paul Mundt   rtc: ds1302 rtc s...
184
  		ds1302_writebyte(RTC_ADDR_TCR, (0xa0 | tcs_val * 0xf));
739d340db   Paul Mundt   rtc: ds1302 rtc s...
185
186
187
188
189
190
191
192
193
194
195
196
197
  		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...
198
  static int __init ds1302_rtc_probe(struct platform_device *pdev)
739d340db   Paul Mundt   rtc: ds1302 rtc s...
199
  {
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
200
  	struct rtc_device *rtc;
739d340db   Paul Mundt   rtc: ds1302 rtc s...
201

72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
202
203
204
205
  	if (ds1302_hw_init()) {
  		dev_err(&pdev->dev, "Failed to init communication channel");
  		return -EINVAL;
  	}
739d340db   Paul Mundt   rtc: ds1302 rtc s...
206
  	/* Reset */
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
207
  	ds1302_reset();
739d340db   Paul Mundt   rtc: ds1302 rtc s...
208
209
210
  
  	/* 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...
211
212
  	if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) {
  		dev_err(&pdev->dev, "Failed to probe");
739d340db   Paul Mundt   rtc: ds1302 rtc s...
213
  		return -ENODEV;
72cc8e51c   Marc Zyngier   rtc-ds1302: add s...
214
  	}
739d340db   Paul Mundt   rtc: ds1302 rtc s...
215

0ea9a0e78   Jingoo Han   rtc: rtc-ds1302: ...
216
  	rtc = devm_rtc_device_register(&pdev->dev, "ds1302",
739d340db   Paul Mundt   rtc: ds1302 rtc s...
217
  					   &ds1302_rtc_ops, THIS_MODULE);
2bfc3305f   Alessandro Zummo   rtc: rtc-ds1302 f...
218
219
  	if (IS_ERR(rtc))
  		return PTR_ERR(rtc);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
220
221
222
223
  
  	platform_set_drvdata(pdev, rtc);
  
  	return 0;
739d340db   Paul Mundt   rtc: ds1302 rtc s...
224
  }
739d340db   Paul Mundt   rtc: ds1302 rtc s...
225
226
227
228
229
  static struct platform_driver ds1302_platform_driver = {
  	.driver		= {
  		.name	= DRV_NAME,
  		.owner	= THIS_MODULE,
  	},
739d340db   Paul Mundt   rtc: ds1302 rtc s...
230
  };
625f5225b   Jingoo Han   rtc: rtc-ds1302: ...
231
  module_platform_driver_probe(ds1302_platform_driver, ds1302_rtc_probe);
739d340db   Paul Mundt   rtc: ds1302 rtc s...
232
233
234
235
236
  
  MODULE_DESCRIPTION("Dallas DS1302 RTC driver");
  MODULE_VERSION(DRV_VERSION);
  MODULE_AUTHOR("Paul Mundt, David McCullough");
  MODULE_LICENSE("GPL v2");