Blame view

drivers/rtc/rtc-m48t59.c 13.8 KB
2e774c7ca   Mark Zhan   rtc: add support ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   * ST M48T59 RTC driver
   *
   * Copyright (c) 2007 Wind River Systems, Inc.
   *
   * Author: Mark Zhan <rongkai.zhan@windriver.com>
   *
   * 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.
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/io.h>
  #include <linux/device.h>
  #include <linux/platform_device.h>
  #include <linux/rtc.h>
  #include <linux/rtc/m48t59.h>
  #include <linux/bcd.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
22
  #include <linux/slab.h>
2e774c7ca   Mark Zhan   rtc: add support ...
23
24
25
26
  
  #ifndef NO_IRQ
  #define NO_IRQ	(-1)
  #endif
94fe7424a   Krzysztof Helt   rtc-m48t59: add s...
27
28
29
  #define M48T59_READ(reg) (pdata->read_byte(dev, pdata->offset + reg))
  #define M48T59_WRITE(val, reg) \
  	(pdata->write_byte(dev, pdata->offset + reg, val))
2e774c7ca   Mark Zhan   rtc: add support ...
30
31
32
33
34
35
36
37
  
  #define M48T59_SET_BITS(mask, reg)	\
  	M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg))
  #define M48T59_CLEAR_BITS(mask, reg)	\
  	M48T59_WRITE((M48T59_READ(reg) & ~(mask)), (reg))
  
  struct m48t59_private {
  	void __iomem *ioaddr;
0439208a8   Mark Zhan   rtc-m48t59 driver...
38
  	int irq;
2e774c7ca   Mark Zhan   rtc: add support ...
39
40
41
42
43
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
  	struct rtc_device *rtc;
  	spinlock_t lock; /* serialize the NVRAM and RTC access */
  };
  
  /*
   * This is the generic access method when the chip is memory-mapped
   */
  static void
  m48t59_mem_writeb(struct device *dev, u32 ofs, u8 val)
  {
  	struct platform_device *pdev = to_platform_device(dev);
  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
  
  	writeb(val, m48t59->ioaddr+ofs);
  }
  
  static u8
  m48t59_mem_readb(struct device *dev, u32 ofs)
  {
  	struct platform_device *pdev = to_platform_device(dev);
  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
  
  	return readb(m48t59->ioaddr+ofs);
  }
  
  /*
   * NOTE: M48T59 only uses BCD mode
   */
  static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
  {
  	struct platform_device *pdev = to_platform_device(dev);
8136032ba   Jingoo Han   drivers/rtc/rtc-m...
70
  	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
2e774c7ca   Mark Zhan   rtc: add support ...
71
72
73
74
75
76
77
  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
  	unsigned long flags;
  	u8 val;
  
  	spin_lock_irqsave(&m48t59->lock, flags);
  	/* Issue the READ command */
  	M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
78
  	tm->tm_year	= bcd2bin(M48T59_READ(M48T59_YEAR));
2e774c7ca   Mark Zhan   rtc: add support ...
79
  	/* tm_mon is 0-11 */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
80
81
  	tm->tm_mon	= bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;
  	tm->tm_mday	= bcd2bin(M48T59_READ(M48T59_MDAY));
2e774c7ca   Mark Zhan   rtc: add support ...
82
83
  
  	val = M48T59_READ(M48T59_WDAY);
833be4e1f   Robert Reif   rtc-m48t59: Only ...
84
85
  	if ((pdata->type == M48T59RTC_TYPE_M48T59) &&
  	    (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
2e774c7ca   Mark Zhan   rtc: add support ...
86
87
88
89
  		dev_dbg(dev, "Century bit is enabled
  ");
  		tm->tm_year += 100;	/* one century */
  	}
12a9ee3cc   Krzysztof Helt   rtc-m48t59: shift...
90
91
92
93
  #ifdef CONFIG_SPARC
  	/* Sun SPARC machines count years since 1968 */
  	tm->tm_year += 68;
  #endif
2e774c7ca   Mark Zhan   rtc: add support ...
94

fe20ba70a   Adrian Bunk   drivers/rtc/: use...
95
96
97
98
  	tm->tm_wday	= bcd2bin(val & 0x07);
  	tm->tm_hour	= bcd2bin(M48T59_READ(M48T59_HOUR) & 0x3F);
  	tm->tm_min	= bcd2bin(M48T59_READ(M48T59_MIN) & 0x7F);
  	tm->tm_sec	= bcd2bin(M48T59_READ(M48T59_SEC) & 0x7F);
2e774c7ca   Mark Zhan   rtc: add support ...
99
100
101
102
103
104
105
106
107
  
  	/* Clear the READ bit */
  	M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL);
  	spin_unlock_irqrestore(&m48t59->lock, flags);
  
  	dev_dbg(dev, "RTC read time %04d-%02d-%02d %02d/%02d/%02d
  ",
  		tm->tm_year + 1900, tm->tm_mon, tm->tm_mday,
  		tm->tm_hour, tm->tm_min, tm->tm_sec);
caf1e1068   Wan ZongShun   rtc/m48t59: use r...
108
  	return rtc_valid_tm(tm);
2e774c7ca   Mark Zhan   rtc: add support ...
109
110
111
112
113
  }
  
  static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
  {
  	struct platform_device *pdev = to_platform_device(dev);
8136032ba   Jingoo Han   drivers/rtc/rtc-m...
114
  	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
2e774c7ca   Mark Zhan   rtc: add support ...
115
116
117
  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
  	unsigned long flags;
  	u8 val = 0;
12a9ee3cc   Krzysztof Helt   rtc-m48t59: shift...
118
119
120
121
122
123
  	int year = tm->tm_year;
  
  #ifdef CONFIG_SPARC
  	/* Sun SPARC machines count years since 1968 */
  	year -= 68;
  #endif
2e774c7ca   Mark Zhan   rtc: add support ...
124
125
126
  
  	dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d
  ",
12a9ee3cc   Krzysztof Helt   rtc-m48t59: shift...
127
  		year + 1900, tm->tm_mon, tm->tm_mday,
2e774c7ca   Mark Zhan   rtc: add support ...
128
  		tm->tm_hour, tm->tm_min, tm->tm_sec);
12a9ee3cc   Krzysztof Helt   rtc-m48t59: shift...
129
130
  	if (year < 0)
  		return -EINVAL;
2e774c7ca   Mark Zhan   rtc: add support ...
131
132
133
  	spin_lock_irqsave(&m48t59->lock, flags);
  	/* Issue the WRITE command */
  	M48T59_SET_BITS(M48T59_CNTL_WRITE, M48T59_CNTL);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
134
135
136
137
  	M48T59_WRITE((bin2bcd(tm->tm_sec) & 0x7F), M48T59_SEC);
  	M48T59_WRITE((bin2bcd(tm->tm_min) & 0x7F), M48T59_MIN);
  	M48T59_WRITE((bin2bcd(tm->tm_hour) & 0x3F), M48T59_HOUR);
  	M48T59_WRITE((bin2bcd(tm->tm_mday) & 0x3F), M48T59_MDAY);
2e774c7ca   Mark Zhan   rtc: add support ...
138
  	/* tm_mon is 0-11 */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
139
  	M48T59_WRITE((bin2bcd(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
12a9ee3cc   Krzysztof Helt   rtc-m48t59: shift...
140
  	M48T59_WRITE(bin2bcd(year % 100), M48T59_YEAR);
2e774c7ca   Mark Zhan   rtc: add support ...
141

12a9ee3cc   Krzysztof Helt   rtc-m48t59: shift...
142
  	if (pdata->type == M48T59RTC_TYPE_M48T59 && (year / 100))
2e774c7ca   Mark Zhan   rtc: add support ...
143
  		val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
144
  	val |= (bin2bcd(tm->tm_wday) & 0x07);
2e774c7ca   Mark Zhan   rtc: add support ...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  	M48T59_WRITE(val, M48T59_WDAY);
  
  	/* Clear the WRITE bit */
  	M48T59_CLEAR_BITS(M48T59_CNTL_WRITE, M48T59_CNTL);
  	spin_unlock_irqrestore(&m48t59->lock, flags);
  	return 0;
  }
  
  /*
   * Read alarm time and date in RTC
   */
  static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	struct platform_device *pdev = to_platform_device(dev);
8136032ba   Jingoo Han   drivers/rtc/rtc-m...
159
  	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
2e774c7ca   Mark Zhan   rtc: add support ...
160
161
162
163
164
165
166
167
168
169
170
171
  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
  	struct rtc_time *tm = &alrm->time;
  	unsigned long flags;
  	u8 val;
  
  	/* If no irq, we don't support ALARM */
  	if (m48t59->irq == NO_IRQ)
  		return -EIO;
  
  	spin_lock_irqsave(&m48t59->lock, flags);
  	/* Issue the READ command */
  	M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
172
  	tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR));
12a9ee3cc   Krzysztof Helt   rtc-m48t59: shift...
173
174
175
176
  #ifdef CONFIG_SPARC
  	/* Sun SPARC machines count years since 1968 */
  	tm->tm_year += 68;
  #endif
2e774c7ca   Mark Zhan   rtc: add support ...
177
  	/* tm_mon is 0-11 */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
178
  	tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1;
2e774c7ca   Mark Zhan   rtc: add support ...
179
180
181
182
  
  	val = M48T59_READ(M48T59_WDAY);
  	if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB))
  		tm->tm_year += 100;	/* one century */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
183
184
185
186
  	tm->tm_mday = bcd2bin(M48T59_READ(M48T59_ALARM_DATE));
  	tm->tm_hour = bcd2bin(M48T59_READ(M48T59_ALARM_HOUR));
  	tm->tm_min = bcd2bin(M48T59_READ(M48T59_ALARM_MIN));
  	tm->tm_sec = bcd2bin(M48T59_READ(M48T59_ALARM_SEC));
2e774c7ca   Mark Zhan   rtc: add support ...
187
188
189
190
191
192
193
194
195
  
  	/* Clear the READ bit */
  	M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL);
  	spin_unlock_irqrestore(&m48t59->lock, flags);
  
  	dev_dbg(dev, "RTC read alarm time %04d-%02d-%02d %02d/%02d/%02d
  ",
  		tm->tm_year + 1900, tm->tm_mon, tm->tm_mday,
  		tm->tm_hour, tm->tm_min, tm->tm_sec);
caf1e1068   Wan ZongShun   rtc/m48t59: use r...
196
  	return rtc_valid_tm(tm);
2e774c7ca   Mark Zhan   rtc: add support ...
197
198
199
200
201
202
203
204
  }
  
  /*
   * Set alarm time and date in RTC
   */
  static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	struct platform_device *pdev = to_platform_device(dev);
8136032ba   Jingoo Han   drivers/rtc/rtc-m...
205
  	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
2e774c7ca   Mark Zhan   rtc: add support ...
206
207
208
209
  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
  	struct rtc_time *tm = &alrm->time;
  	u8 mday, hour, min, sec;
  	unsigned long flags;
12a9ee3cc   Krzysztof Helt   rtc-m48t59: shift...
210
211
212
213
214
215
  	int year = tm->tm_year;
  
  #ifdef CONFIG_SPARC
  	/* Sun SPARC machines count years since 1968 */
  	year -= 68;
  #endif
2e774c7ca   Mark Zhan   rtc: add support ...
216
217
218
219
  
  	/* If no irq, we don't support ALARM */
  	if (m48t59->irq == NO_IRQ)
  		return -EIO;
12a9ee3cc   Krzysztof Helt   rtc-m48t59: shift...
220
221
  	if (year < 0)
  		return -EINVAL;
2e774c7ca   Mark Zhan   rtc: add support ...
222
223
224
225
  	/*
  	 * 0xff means "always match"
  	 */
  	mday = tm->tm_mday;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
226
  	mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff;
2e774c7ca   Mark Zhan   rtc: add support ...
227
228
229
230
  	if (mday == 0xff)
  		mday = M48T59_READ(M48T59_MDAY);
  
  	hour = tm->tm_hour;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
231
  	hour = (hour < 24) ? bin2bcd(hour) : 0x00;
2e774c7ca   Mark Zhan   rtc: add support ...
232
233
  
  	min = tm->tm_min;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
234
  	min = (min < 60) ? bin2bcd(min) : 0x00;
2e774c7ca   Mark Zhan   rtc: add support ...
235
236
  
  	sec = tm->tm_sec;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
237
  	sec = (sec < 60) ? bin2bcd(sec) : 0x00;
2e774c7ca   Mark Zhan   rtc: add support ...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
  
  	spin_lock_irqsave(&m48t59->lock, flags);
  	/* Issue the WRITE command */
  	M48T59_SET_BITS(M48T59_CNTL_WRITE, M48T59_CNTL);
  
  	M48T59_WRITE(mday, M48T59_ALARM_DATE);
  	M48T59_WRITE(hour, M48T59_ALARM_HOUR);
  	M48T59_WRITE(min, M48T59_ALARM_MIN);
  	M48T59_WRITE(sec, M48T59_ALARM_SEC);
  
  	/* Clear the WRITE bit */
  	M48T59_CLEAR_BITS(M48T59_CNTL_WRITE, M48T59_CNTL);
  	spin_unlock_irqrestore(&m48t59->lock, flags);
  
  	dev_dbg(dev, "RTC set alarm time %04d-%02d-%02d %02d/%02d/%02d
  ",
12a9ee3cc   Krzysztof Helt   rtc-m48t59: shift...
254
  		year + 1900, tm->tm_mon, tm->tm_mday,
2e774c7ca   Mark Zhan   rtc: add support ...
255
256
257
258
259
260
261
  		tm->tm_hour, tm->tm_min, tm->tm_sec);
  	return 0;
  }
  
  /*
   * Handle commands from user-space
   */
16380c153   John Stultz   RTC: Convert rtc ...
262
  static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
2e774c7ca   Mark Zhan   rtc: add support ...
263
264
  {
  	struct platform_device *pdev = to_platform_device(dev);
8136032ba   Jingoo Han   drivers/rtc/rtc-m...
265
  	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
2e774c7ca   Mark Zhan   rtc: add support ...
266
267
  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
  	unsigned long flags;
2e774c7ca   Mark Zhan   rtc: add support ...
268
269
  
  	spin_lock_irqsave(&m48t59->lock, flags);
16380c153   John Stultz   RTC: Convert rtc ...
270
  	if (enabled)
2e774c7ca   Mark Zhan   rtc: add support ...
271
  		M48T59_WRITE(M48T59_INTR_AFE, M48T59_INTR);
16380c153   John Stultz   RTC: Convert rtc ...
272
273
  	else
  		M48T59_WRITE(0x00, M48T59_INTR);
2e774c7ca   Mark Zhan   rtc: add support ...
274
  	spin_unlock_irqrestore(&m48t59->lock, flags);
16380c153   John Stultz   RTC: Convert rtc ...
275
  	return 0;
2e774c7ca   Mark Zhan   rtc: add support ...
276
277
278
279
280
  }
  
  static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq)
  {
  	struct platform_device *pdev = to_platform_device(dev);
8136032ba   Jingoo Han   drivers/rtc/rtc-m...
281
  	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
2e774c7ca   Mark Zhan   rtc: add support ...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
  	unsigned long flags;
  	u8 val;
  
  	spin_lock_irqsave(&m48t59->lock, flags);
  	val = M48T59_READ(M48T59_FLAGS);
  	spin_unlock_irqrestore(&m48t59->lock, flags);
  
  	seq_printf(seq, "battery\t\t: %s
  ",
  		 (val & M48T59_FLAGS_BF) ? "low" : "normal");
  	return 0;
  }
  
  /*
   * IRQ handler for the RTC
   */
  static irqreturn_t m48t59_rtc_interrupt(int irq, void *dev_id)
  {
  	struct device *dev = (struct device *)dev_id;
  	struct platform_device *pdev = to_platform_device(dev);
8136032ba   Jingoo Han   drivers/rtc/rtc-m...
303
  	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
2e774c7ca   Mark Zhan   rtc: add support ...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
  	u8 event;
  
  	spin_lock(&m48t59->lock);
  	event = M48T59_READ(M48T59_FLAGS);
  	spin_unlock(&m48t59->lock);
  
  	if (event & M48T59_FLAGS_AF) {
  		rtc_update_irq(m48t59->rtc, 1, (RTC_AF | RTC_IRQF));
  		return IRQ_HANDLED;
  	}
  
  	return IRQ_NONE;
  }
  
  static const struct rtc_class_ops m48t59_rtc_ops = {
2e774c7ca   Mark Zhan   rtc: add support ...
320
321
322
323
324
  	.read_time	= m48t59_rtc_read_time,
  	.set_time	= m48t59_rtc_set_time,
  	.read_alarm	= m48t59_rtc_readalarm,
  	.set_alarm	= m48t59_rtc_setalarm,
  	.proc		= m48t59_rtc_proc,
16380c153   John Stultz   RTC: Convert rtc ...
325
  	.alarm_irq_enable = m48t59_rtc_alarm_irq_enable,
2e774c7ca   Mark Zhan   rtc: add support ...
326
  };
94fe7424a   Krzysztof Helt   rtc-m48t59: add s...
327
328
329
330
  static const struct rtc_class_ops m48t02_rtc_ops = {
  	.read_time	= m48t59_rtc_read_time,
  	.set_time	= m48t59_rtc_set_time,
  };
2c3c8bea6   Chris Wright   sysfs: add struct...
331
  static ssize_t m48t59_nvram_read(struct file *filp, struct kobject *kobj,
2e774c7ca   Mark Zhan   rtc: add support ...
332
333
334
335
336
  				struct bin_attribute *bin_attr,
  				char *buf, loff_t pos, size_t size)
  {
  	struct device *dev = container_of(kobj, struct device, kobj);
  	struct platform_device *pdev = to_platform_device(dev);
8136032ba   Jingoo Han   drivers/rtc/rtc-m...
337
  	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
2e774c7ca   Mark Zhan   rtc: add support ...
338
339
340
  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
  	ssize_t cnt = 0;
  	unsigned long flags;
99be3e371   Vladimir Zapolskiy   rtc: m48t59: clea...
341
342
343
  	spin_lock_irqsave(&m48t59->lock, flags);
  
  	for (; cnt < size; cnt++)
2e774c7ca   Mark Zhan   rtc: add support ...
344
  		*buf++ = M48T59_READ(cnt);
99be3e371   Vladimir Zapolskiy   rtc: m48t59: clea...
345
346
  
  	spin_unlock_irqrestore(&m48t59->lock, flags);
2e774c7ca   Mark Zhan   rtc: add support ...
347
348
349
  
  	return cnt;
  }
2c3c8bea6   Chris Wright   sysfs: add struct...
350
  static ssize_t m48t59_nvram_write(struct file *filp, struct kobject *kobj,
2e774c7ca   Mark Zhan   rtc: add support ...
351
352
353
354
355
  				struct bin_attribute *bin_attr,
  				char *buf, loff_t pos, size_t size)
  {
  	struct device *dev = container_of(kobj, struct device, kobj);
  	struct platform_device *pdev = to_platform_device(dev);
8136032ba   Jingoo Han   drivers/rtc/rtc-m...
356
  	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
2e774c7ca   Mark Zhan   rtc: add support ...
357
358
359
  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
  	ssize_t cnt = 0;
  	unsigned long flags;
99be3e371   Vladimir Zapolskiy   rtc: m48t59: clea...
360
361
362
  	spin_lock_irqsave(&m48t59->lock, flags);
  
  	for (; cnt < size; cnt++)
2e774c7ca   Mark Zhan   rtc: add support ...
363
  		M48T59_WRITE(*buf++, cnt);
99be3e371   Vladimir Zapolskiy   rtc: m48t59: clea...
364
365
  
  	spin_unlock_irqrestore(&m48t59->lock, flags);
2e774c7ca   Mark Zhan   rtc: add support ...
366
367
368
369
370
371
372
  
  	return cnt;
  }
  
  static struct bin_attribute m48t59_nvram_attr = {
  	.attr = {
  		.name = "nvram",
a4b1d50e6   David Brownell   RTCs: handle NVRA...
373
  		.mode = S_IRUGO | S_IWUSR,
2e774c7ca   Mark Zhan   rtc: add support ...
374
375
376
377
  	},
  	.read = m48t59_nvram_read,
  	.write = m48t59_nvram_write,
  };
5a167f454   Greg Kroah-Hartman   Drivers: rtc: rem...
378
  static int m48t59_rtc_probe(struct platform_device *pdev)
2e774c7ca   Mark Zhan   rtc: add support ...
379
  {
8136032ba   Jingoo Han   drivers/rtc/rtc-m...
380
  	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
2e774c7ca   Mark Zhan   rtc: add support ...
381
382
383
  	struct m48t59_private *m48t59 = NULL;
  	struct resource *res;
  	int ret = -ENOMEM;
94fe7424a   Krzysztof Helt   rtc-m48t59: add s...
384
385
  	char *name;
  	const struct rtc_class_ops *ops;
2e774c7ca   Mark Zhan   rtc: add support ...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  
  	/* This chip could be memory-mapped or I/O-mapped */
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!res) {
  		res = platform_get_resource(pdev, IORESOURCE_IO, 0);
  		if (!res)
  			return -EINVAL;
  	}
  
  	if (res->flags & IORESOURCE_IO) {
  		/* If we are I/O-mapped, the platform should provide
  		 * the operations accessing chip registers.
  		 */
  		if (!pdata || !pdata->write_byte || !pdata->read_byte)
  			return -EINVAL;
  	} else if (res->flags & IORESOURCE_MEM) {
  		/* we are memory-mapped */
  		if (!pdata) {
19b8d8875   Jingoo Han   rtc: rtc-m48t59: ...
404
405
  			pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata),
  						GFP_KERNEL);
2e774c7ca   Mark Zhan   rtc: add support ...
406
407
408
409
410
  			if (!pdata)
  				return -ENOMEM;
  			/* Ensure we only kmalloc platform data once */
  			pdev->dev.platform_data = pdata;
  		}
94fe7424a   Krzysztof Helt   rtc-m48t59: add s...
411
412
  		if (!pdata->type)
  			pdata->type = M48T59RTC_TYPE_M48T59;
2e774c7ca   Mark Zhan   rtc: add support ...
413
414
415
416
417
418
419
  
  		/* Try to use the generic memory read/write ops */
  		if (!pdata->write_byte)
  			pdata->write_byte = m48t59_mem_writeb;
  		if (!pdata->read_byte)
  			pdata->read_byte = m48t59_mem_readb;
  	}
19b8d8875   Jingoo Han   rtc: rtc-m48t59: ...
420
  	m48t59 = devm_kzalloc(&pdev->dev, sizeof(*m48t59), GFP_KERNEL);
2e774c7ca   Mark Zhan   rtc: add support ...
421
422
  	if (!m48t59)
  		return -ENOMEM;
64151ad5b   Krzysztof Helt   rtc-m48t59: allow...
423
424
425
426
  	m48t59->ioaddr = pdata->ioaddr;
  
  	if (!m48t59->ioaddr) {
  		/* ioaddr not mapped externally */
19b8d8875   Jingoo Han   rtc: rtc-m48t59: ...
427
428
  		m48t59->ioaddr = devm_ioremap(&pdev->dev, res->start,
  						resource_size(res));
64151ad5b   Krzysztof Helt   rtc-m48t59: allow...
429
  		if (!m48t59->ioaddr)
19b8d8875   Jingoo Han   rtc: rtc-m48t59: ...
430
  			return ret;
64151ad5b   Krzysztof Helt   rtc-m48t59: allow...
431
  	}
2e774c7ca   Mark Zhan   rtc: add support ...
432
433
434
435
436
  
  	/* Try to get irq number. We also can work in
  	 * the mode without IRQ.
  	 */
  	m48t59->irq = platform_get_irq(pdev, 0);
2fac6674d   Anton Vorontsov   rtc: bunch of dri...
437
  	if (m48t59->irq <= 0)
2e774c7ca   Mark Zhan   rtc: add support ...
438
439
440
  		m48t59->irq = NO_IRQ;
  
  	if (m48t59->irq != NO_IRQ) {
19b8d8875   Jingoo Han   rtc: rtc-m48t59: ...
441
442
443
  		ret = devm_request_irq(&pdev->dev, m48t59->irq,
  				m48t59_rtc_interrupt, IRQF_SHARED,
  				"rtc-m48t59", &pdev->dev);
2e774c7ca   Mark Zhan   rtc: add support ...
444
  		if (ret)
19b8d8875   Jingoo Han   rtc: rtc-m48t59: ...
445
  			return ret;
2e774c7ca   Mark Zhan   rtc: add support ...
446
  	}
94fe7424a   Krzysztof Helt   rtc-m48t59: add s...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  	switch (pdata->type) {
  	case M48T59RTC_TYPE_M48T59:
  		name = "m48t59";
  		ops = &m48t59_rtc_ops;
  		pdata->offset = 0x1ff0;
  		break;
  	case M48T59RTC_TYPE_M48T02:
  		name = "m48t02";
  		ops = &m48t02_rtc_ops;
  		pdata->offset = 0x7f0;
  		break;
  	case M48T59RTC_TYPE_M48T08:
  		name = "m48t08";
  		ops = &m48t02_rtc_ops;
  		pdata->offset = 0x1ff0;
  		break;
  	default:
  		dev_err(&pdev->dev, "Unknown RTC type
  ");
19b8d8875   Jingoo Han   rtc: rtc-m48t59: ...
466
  		return -ENODEV;
94fe7424a   Krzysztof Helt   rtc-m48t59: add s...
467
  	}
2e774c7ca   Mark Zhan   rtc: add support ...
468

b74d2caa6   Alessandro Zummo   rtc: fix driver d...
469
470
  	spin_lock_init(&m48t59->lock);
  	platform_set_drvdata(pdev, m48t59);
19b8d8875   Jingoo Han   rtc: rtc-m48t59: ...
471
472
473
474
  	m48t59->rtc = devm_rtc_device_register(&pdev->dev, name, ops,
  						THIS_MODULE);
  	if (IS_ERR(m48t59->rtc))
  		return PTR_ERR(m48t59->rtc);
2e774c7ca   Mark Zhan   rtc: add support ...
475

94fe7424a   Krzysztof Helt   rtc-m48t59: add s...
476
  	m48t59_nvram_attr.size = pdata->offset;
2e774c7ca   Mark Zhan   rtc: add support ...
477
  	ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
19b8d8875   Jingoo Han   rtc: rtc-m48t59: ...
478
479
  	if (ret)
  		return ret;
2e774c7ca   Mark Zhan   rtc: add support ...
480

2e774c7ca   Mark Zhan   rtc: add support ...
481
  	return 0;
2e774c7ca   Mark Zhan   rtc: add support ...
482
  }
5a167f454   Greg Kroah-Hartman   Drivers: rtc: rem...
483
  static int m48t59_rtc_remove(struct platform_device *pdev)
2e774c7ca   Mark Zhan   rtc: add support ...
484
  {
2e774c7ca   Mark Zhan   rtc: add support ...
485
  	sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
2e774c7ca   Mark Zhan   rtc: add support ...
486
487
  	return 0;
  }
ad28a07bc   Kay Sievers   rtc: fix platform...
488
489
  /* work with hotplug and coldplug */
  MODULE_ALIAS("platform:rtc-m48t59");
127309265   Randy Dunlap   rtc: m48t59 fix s...
490
  static struct platform_driver m48t59_rtc_driver = {
2e774c7ca   Mark Zhan   rtc: add support ...
491
492
  	.driver		= {
  		.name	= "rtc-m48t59",
2e774c7ca   Mark Zhan   rtc: add support ...
493
494
  	},
  	.probe		= m48t59_rtc_probe,
5a167f454   Greg Kroah-Hartman   Drivers: rtc: rem...
495
  	.remove		= m48t59_rtc_remove,
2e774c7ca   Mark Zhan   rtc: add support ...
496
  };
0c4eae665   Axel Lin   rtc: convert driv...
497
  module_platform_driver(m48t59_rtc_driver);
2e774c7ca   Mark Zhan   rtc: add support ...
498
499
  
  MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>");
94fe7424a   Krzysztof Helt   rtc-m48t59: add s...
500
  MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver");
2e774c7ca   Mark Zhan   rtc: add support ...
501
  MODULE_LICENSE("GPL");