Blame view

drivers/rtc/rtc-m48t86.c 5.48 KB
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  /*
   * ST M48T86 / Dallas DS12887 RTC driver
   * Copyright (c) 2006 Tower Technologies
   *
   * Author: Alessandro Zummo <a.zummo@towertech.it>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   * This drivers only supports the clock running in BCD and 24H mode.
   * If it will be ever adapted to binary and 12H mode, care must be taken
   * to not introduce bugs.
   */
  
  #include <linux/module.h>
  #include <linux/rtc.h>
  #include <linux/platform_device.h>
  #include <linux/m48t86.h>
  #include <linux/bcd.h>
  
  #define M48T86_REG_SEC		0x00
  #define M48T86_REG_SECALRM	0x01
  #define M48T86_REG_MIN		0x02
  #define M48T86_REG_MINALRM	0x03
f90a65060   Alessandro Zummo   [PATCH] RTC subsy...
26
  #define M48T86_REG_HOUR		0x04
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  #define M48T86_REG_HOURALRM	0x05
  #define M48T86_REG_DOW		0x06 /* 1 = sunday */
  #define M48T86_REG_DOM		0x07
  #define M48T86_REG_MONTH	0x08 /* 1 - 12 */
  #define M48T86_REG_YEAR		0x09 /* 0 - 99 */
  #define M48T86_REG_A		0x0A
  #define M48T86_REG_B		0x0B
  #define M48T86_REG_C		0x0C
  #define M48T86_REG_D		0x0D
  
  #define M48T86_REG_B_H24	(1 << 1)
  #define M48T86_REG_B_DM		(1 << 2)
  #define M48T86_REG_B_SET	(1 << 7)
  #define M48T86_REG_D_VRT	(1 << 7)
  
  #define DRV_VERSION "0.1"
  
  
  static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm)
  {
  	unsigned char reg;
  	struct platform_device *pdev = to_platform_device(dev);
  	struct m48t86_ops *ops = pdev->dev.platform_data;
2d7b20c18   Andrew Morton   [PATCH] m48t86: i...
50
  	reg = ops->readbyte(M48T86_REG_B);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
51
52
53
  
  	if (reg & M48T86_REG_B_DM) {
  		/* data (binary) mode */
2d7b20c18   Andrew Morton   [PATCH] m48t86: i...
54
55
56
57
  		tm->tm_sec	= ops->readbyte(M48T86_REG_SEC);
  		tm->tm_min	= ops->readbyte(M48T86_REG_MIN);
  		tm->tm_hour	= ops->readbyte(M48T86_REG_HOUR) & 0x3F;
  		tm->tm_mday	= ops->readbyte(M48T86_REG_DOM);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
58
  		/* tm_mon is 0-11 */
2d7b20c18   Andrew Morton   [PATCH] m48t86: i...
59
60
61
  		tm->tm_mon	= ops->readbyte(M48T86_REG_MONTH) - 1;
  		tm->tm_year	= ops->readbyte(M48T86_REG_YEAR) + 100;
  		tm->tm_wday	= ops->readbyte(M48T86_REG_DOW);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
62
63
  	} else {
  		/* bcd mode */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
64
65
66
67
  		tm->tm_sec	= bcd2bin(ops->readbyte(M48T86_REG_SEC));
  		tm->tm_min	= bcd2bin(ops->readbyte(M48T86_REG_MIN));
  		tm->tm_hour	= bcd2bin(ops->readbyte(M48T86_REG_HOUR) & 0x3F);
  		tm->tm_mday	= bcd2bin(ops->readbyte(M48T86_REG_DOM));
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
68
  		/* tm_mon is 0-11 */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
69
70
71
  		tm->tm_mon	= bcd2bin(ops->readbyte(M48T86_REG_MONTH)) - 1;
  		tm->tm_year	= bcd2bin(ops->readbyte(M48T86_REG_YEAR)) + 100;
  		tm->tm_wday	= bcd2bin(ops->readbyte(M48T86_REG_DOW));
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
72
73
74
75
  	}
  
  	/* correct the hour if the clock is in 12h mode */
  	if (!(reg & M48T86_REG_B_H24))
2d7b20c18   Andrew Morton   [PATCH] m48t86: i...
76
  		if (ops->readbyte(M48T86_REG_HOUR) & 0x80)
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
77
  			tm->tm_hour += 12;
52142ed41   Wan ZongShun   rtc/m48t86: use r...
78
  	return rtc_valid_tm(tm);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
79
80
81
82
83
84
85
  }
  
  static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm)
  {
  	unsigned char reg;
  	struct platform_device *pdev = to_platform_device(dev);
  	struct m48t86_ops *ops = pdev->dev.platform_data;
2d7b20c18   Andrew Morton   [PATCH] m48t86: i...
86
  	reg = ops->readbyte(M48T86_REG_B);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
87
88
89
  
  	/* update flag and 24h mode */
  	reg |= M48T86_REG_B_SET | M48T86_REG_B_H24;
2d7b20c18   Andrew Morton   [PATCH] m48t86: i...
90
  	ops->writebyte(reg, M48T86_REG_B);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
91
92
93
  
  	if (reg & M48T86_REG_B_DM) {
  		/* data (binary) mode */
2d7b20c18   Andrew Morton   [PATCH] m48t86: i...
94
95
96
97
98
99
100
  		ops->writebyte(tm->tm_sec, M48T86_REG_SEC);
  		ops->writebyte(tm->tm_min, M48T86_REG_MIN);
  		ops->writebyte(tm->tm_hour, M48T86_REG_HOUR);
  		ops->writebyte(tm->tm_mday, M48T86_REG_DOM);
  		ops->writebyte(tm->tm_mon + 1, M48T86_REG_MONTH);
  		ops->writebyte(tm->tm_year % 100, M48T86_REG_YEAR);
  		ops->writebyte(tm->tm_wday, M48T86_REG_DOW);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
101
102
  	} else {
  		/* bcd mode */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
103
104
105
106
107
108
109
  		ops->writebyte(bin2bcd(tm->tm_sec), M48T86_REG_SEC);
  		ops->writebyte(bin2bcd(tm->tm_min), M48T86_REG_MIN);
  		ops->writebyte(bin2bcd(tm->tm_hour), M48T86_REG_HOUR);
  		ops->writebyte(bin2bcd(tm->tm_mday), M48T86_REG_DOM);
  		ops->writebyte(bin2bcd(tm->tm_mon + 1), M48T86_REG_MONTH);
  		ops->writebyte(bin2bcd(tm->tm_year % 100), M48T86_REG_YEAR);
  		ops->writebyte(bin2bcd(tm->tm_wday), M48T86_REG_DOW);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
110
111
112
113
  	}
  
  	/* update ended */
  	reg &= ~M48T86_REG_B_SET;
2d7b20c18   Andrew Morton   [PATCH] m48t86: i...
114
  	ops->writebyte(reg, M48T86_REG_B);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
115
116
117
118
119
120
121
122
123
  
  	return 0;
  }
  
  static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq)
  {
  	unsigned char reg;
  	struct platform_device *pdev = to_platform_device(dev);
  	struct m48t86_ops *ops = pdev->dev.platform_data;
2d7b20c18   Andrew Morton   [PATCH] m48t86: i...
124
  	reg = ops->readbyte(M48T86_REG_B);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
125

1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
126
127
128
  	seq_printf(seq, "mode\t\t: %s
  ",
  		 (reg & M48T86_REG_B_DM) ? "binary" : "bcd");
2d7b20c18   Andrew Morton   [PATCH] m48t86: i...
129
  	reg = ops->readbyte(M48T86_REG_D);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
130
131
132
133
134
135
136
  
  	seq_printf(seq, "battery\t\t: %s
  ",
  		 (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted");
  
  	return 0;
  }
ff8371ac9   David Brownell   [PATCH] constify ...
137
  static const struct rtc_class_ops m48t86_rtc_ops = {
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
138
139
140
141
142
143
144
145
146
147
148
  	.read_time	= m48t86_rtc_read_time,
  	.set_time	= m48t86_rtc_set_time,
  	.proc		= m48t86_rtc_proc,
  };
  
  static int __devinit m48t86_rtc_probe(struct platform_device *dev)
  {
  	unsigned char reg;
  	struct m48t86_ops *ops = dev->dev.platform_data;
  	struct rtc_device *rtc = rtc_device_register("m48t86",
  				&dev->dev, &m48t86_rtc_ops, THIS_MODULE);
d1d65b771   Alessandro Zummo   [PATCH] RTC subsy...
149
  	if (IS_ERR(rtc))
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
150
  		return PTR_ERR(rtc);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
151
152
153
154
  
  	platform_set_drvdata(dev, rtc);
  
  	/* read battery status */
2d7b20c18   Andrew Morton   [PATCH] m48t86: i...
155
  	reg = ops->readbyte(M48T86_REG_D);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  	dev_info(&dev->dev, "battery %s
  ",
  		(reg & M48T86_REG_D_VRT) ? "ok" : "exhausted");
  
  	return 0;
  }
  
  static int __devexit m48t86_rtc_remove(struct platform_device *dev)
  {
  	struct rtc_device *rtc = platform_get_drvdata(dev);
  
   	if (rtc)
  		rtc_device_unregister(rtc);
  
  	platform_set_drvdata(dev, NULL);
  
  	return 0;
  }
  
  static struct platform_driver m48t86_rtc_platform_driver = {
  	.driver		= {
  		.name	= "rtc-m48t86",
  		.owner	= THIS_MODULE,
  	},
  	.probe		= m48t86_rtc_probe,
  	.remove		= __devexit_p(m48t86_rtc_remove),
  };
0c4eae665   Axel Lin   rtc: convert driv...
183
  module_platform_driver(m48t86_rtc_platform_driver);
1d98af872   Alessandro Zummo   [PATCH] RTC subsy...
184
185
186
187
188
  
  MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
  MODULE_DESCRIPTION("M48T86 RTC driver");
  MODULE_LICENSE("GPL");
  MODULE_VERSION(DRV_VERSION);
ad28a07bc   Kay Sievers   rtc: fix platform...
189
  MODULE_ALIAS("platform:rtc-m48t86");