Blame view

drivers/rtc/class.c 12.2 KB
cdf7545ae   Alexandre Belloni   rtc: convert core...
1
  // SPDX-License-Identifier: GPL-2.0
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
2
3
4
5
6
7
8
  /*
   * RTC subsystem, base class
   *
   * Copyright (C) 2005 Tower Technologies
   * Author: Alessandro Zummo <a.zummo@towertech.it>
   *
   * class skeleton from drivers/hwmon/hwmon.c
cdf7545ae   Alexandre Belloni   rtc: convert core...
9
   */
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
10

c100a5e02   Jingoo Han   rtc: use dev_warn...
11
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
12
  #include <linux/module.h>
9d2b7e532   Stephen Warren   rtc: honor device...
13
  #include <linux/of.h>
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
14
15
16
  #include <linux/rtc.h>
  #include <linux/kdev_t.h>
  #include <linux/idr.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
6610e0893   John Stultz   RTC: Rework RTC c...
18
  #include <linux/workqueue.h>
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
19

5726fb201   David Brownell   rtc: remove /sys/...
20
  #include "rtc-core.h"
6d03d06db   Jonathan Cameron   drivers/rtc/class...
21
  static DEFINE_IDA(rtc_ida);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
22
  struct class *rtc_class;
cd9662094   David Brownell   rtc: remove rest ...
23
  static void rtc_device_release(struct device *dev)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
24
  {
cd9662094   David Brownell   rtc: remove rest ...
25
  	struct rtc_device *rtc = to_rtc_device(dev);
606cc43c7   Alexandre Belloni   rtc: core: correc...
26

6d03d06db   Jonathan Cameron   drivers/rtc/class...
27
  	ida_simple_remove(&rtc_ida, rtc->id);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
28
29
  	kfree(rtc);
  }
4c24e29e6   David Fries   rtc_sysfs_show_hc...
30
31
32
  #ifdef CONFIG_RTC_HCTOSYS_DEVICE
  /* Result of the last RTC to system clock attempt. */
  int rtc_hctosys_ret = -ENODEV;
0fb885c7b   Greg Kroah-Hartman   ANDROID: fix up r...
33
34
35
36
37
38
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
70
71
72
73
74
75
76
77
78
  
  /* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
   * whether it stores the most close value or the value with partial
   * seconds truncated. However, it is important that we use it to store
   * the truncated value. This is because otherwise it is necessary,
   * in an rtc sync function, to read both xtime.tv_sec and
   * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
   * of >32bits is not possible. So storing the most close value would
   * slow down the sync API. So here we have the truncated value and
   * the best guess is to add 0.5s.
   */
  
  static void rtc_hctosys(struct rtc_device *rtc)
  {
  	int err;
  	struct rtc_time tm;
  	struct timespec64 tv64 = {
  		.tv_nsec = NSEC_PER_SEC >> 1,
  	};
  
  	err = rtc_read_time(rtc, &tm);
  	if (err) {
  		dev_err(rtc->dev.parent,
  			"hctosys: unable to read the hardware clock
  ");
  		goto err_read;
  	}
  
  	tv64.tv_sec = rtc_tm_to_time64(&tm);
  
  #if BITS_PER_LONG == 32
  	if (tv64.tv_sec > INT_MAX) {
  		err = -ERANGE;
  		goto err_read;
  	}
  #endif
  
  	err = do_settimeofday64(&tv64);
  
  	dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)
  ",
  		 &tm, (long long)tv64.tv_sec);
  
  err_read:
  	rtc_hctosys_ret = err;
  }
4c24e29e6   David Fries   rtc_sysfs_show_hc...
79
  #endif
7ca1d488f   David Brownell   rtc: suspend()/re...
80

92e7f04a7   Shuah Khan   drivers/rtc/class...
81
  #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
7ca1d488f   David Brownell   rtc: suspend()/re...
82
83
84
85
  /*
   * On suspend(), measure the delta between one RTC and the
   * system's wall clock; restore it on resume().
   */
d4bda8f84   John Stultz   rtc: Update suspe...
86
  static struct timespec64 old_rtc, old_system, old_delta;
3dcad5ff0   John Stultz   rtc: Avoid accumu...
87

92e7f04a7   Shuah Khan   drivers/rtc/class...
88
  static int rtc_suspend(struct device *dev)
7ca1d488f   David Brownell   rtc: suspend()/re...
89
90
91
  {
  	struct rtc_device	*rtc = to_rtc_device(dev);
  	struct rtc_time		tm;
d4bda8f84   John Stultz   rtc: Update suspe...
92
  	struct timespec64	delta, delta_delta;
e1d60093c   Hyogi Gim   driver/rtc/class....
93
  	int err;
9ecf37eb7   Feng Tang   rtc: Skip the sus...
94

0fa88cb4b   Xunlei Pang   time, drivers/rtc...
95
  	if (timekeeping_rtc_skipsuspend())
9ecf37eb7   Feng Tang   rtc: Skip the sus...
96
  		return 0;
d4afc76c0   Kay Sievers   rtc: struct devic...
97
  	if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
7ca1d488f   David Brownell   rtc: suspend()/re...
98
  		return 0;
3dcad5ff0   John Stultz   rtc: Avoid accumu...
99
  	/* snapshot the current RTC and system time at suspend*/
e1d60093c   Hyogi Gim   driver/rtc/class....
100
101
102
103
104
105
  	err = rtc_read_time(rtc, &tm);
  	if (err < 0) {
  		pr_debug("%s:  fail to read rtc time
  ", dev_name(&rtc->dev));
  		return 0;
  	}
5089ea15b   Arnd Bergmann   rtc: use ktime_ge...
106
  	ktime_get_real_ts64(&old_system);
d4bda8f84   John Stultz   rtc: Update suspe...
107
  	old_rtc.tv_sec = rtc_tm_to_time64(&tm);
3dcad5ff0   John Stultz   rtc: Avoid accumu...
108

3dcad5ff0   John Stultz   rtc: Avoid accumu...
109
110
111
112
113
114
  	/*
  	 * To avoid drift caused by repeated suspend/resumes,
  	 * which each can add ~1 second drift error,
  	 * try to compensate so the difference in system time
  	 * and rtc time stays close to constant.
  	 */
d4bda8f84   John Stultz   rtc: Update suspe...
115
116
  	delta = timespec64_sub(old_system, old_rtc);
  	delta_delta = timespec64_sub(delta, old_delta);
6a8943d9e   Arve Hjønnevåg   rtc: Fix some bug...
117
  	if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) {
3dcad5ff0   John Stultz   rtc: Avoid accumu...
118
119
  		/*
  		 * if delta_delta is too large, assume time correction
606cc43c7   Alexandre Belloni   rtc: core: correc...
120
  		 * has occurred and set old_delta to the current delta.
3dcad5ff0   John Stultz   rtc: Avoid accumu...
121
122
123
124
  		 */
  		old_delta = delta;
  	} else {
  		/* Otherwise try to adjust old_system to compensate */
d4bda8f84   John Stultz   rtc: Update suspe...
125
  		old_system = timespec64_sub(old_system, delta_delta);
3dcad5ff0   John Stultz   rtc: Avoid accumu...
126
  	}
7ca1d488f   David Brownell   rtc: suspend()/re...
127

7ca1d488f   David Brownell   rtc: suspend()/re...
128
129
130
131
132
133
134
  	return 0;
  }
  
  static int rtc_resume(struct device *dev)
  {
  	struct rtc_device	*rtc = to_rtc_device(dev);
  	struct rtc_time		tm;
d4bda8f84   John Stultz   rtc: Update suspe...
135
136
  	struct timespec64	new_system, new_rtc;
  	struct timespec64	sleep_time;
e1d60093c   Hyogi Gim   driver/rtc/class....
137
  	int err;
7ca1d488f   David Brownell   rtc: suspend()/re...
138

0fa88cb4b   Xunlei Pang   time, drivers/rtc...
139
  	if (timekeeping_rtc_skipresume())
9ecf37eb7   Feng Tang   rtc: Skip the sus...
140
  		return 0;
4c24e29e6   David Fries   rtc_sysfs_show_hc...
141
  	rtc_hctosys_ret = -ENODEV;
d4afc76c0   Kay Sievers   rtc: struct devic...
142
  	if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
7ca1d488f   David Brownell   rtc: suspend()/re...
143
  		return 0;
3dcad5ff0   John Stultz   rtc: Avoid accumu...
144
  	/* snapshot the current rtc and system time at resume */
5089ea15b   Arnd Bergmann   rtc: use ktime_ge...
145
  	ktime_get_real_ts64(&new_system);
e1d60093c   Hyogi Gim   driver/rtc/class....
146
147
148
149
150
151
  	err = rtc_read_time(rtc, &tm);
  	if (err < 0) {
  		pr_debug("%s:  fail to read rtc time
  ", dev_name(&rtc->dev));
  		return 0;
  	}
d4bda8f84   John Stultz   rtc: Update suspe...
152
  	new_rtc.tv_sec = rtc_tm_to_time64(&tm);
3dcad5ff0   John Stultz   rtc: Avoid accumu...
153
  	new_rtc.tv_nsec = 0;
6a8943d9e   Arve Hjønnevåg   rtc: Fix some bug...
154
155
156
  	if (new_rtc.tv_sec < old_rtc.tv_sec) {
  		pr_debug("%s:  time travel!
  ", dev_name(&rtc->dev));
7ca1d488f   David Brownell   rtc: suspend()/re...
157
158
  		return 0;
  	}
3dcad5ff0   John Stultz   rtc: Avoid accumu...
159
  	/* calculate the RTC time delta (sleep time)*/
d4bda8f84   John Stultz   rtc: Update suspe...
160
  	sleep_time = timespec64_sub(new_rtc, old_rtc);
3dcad5ff0   John Stultz   rtc: Avoid accumu...
161
162
163
164
165
166
167
168
  
  	/*
  	 * Since these RTC suspend/resume handlers are not called
  	 * at the very end of suspend or the start of resume,
  	 * some run-time may pass on either sides of the sleep time
  	 * so subtract kernel run-time between rtc_suspend to rtc_resume
  	 * to keep things accurate.
  	 */
d4bda8f84   John Stultz   rtc: Update suspe...
169
  	sleep_time = timespec64_sub(sleep_time,
606cc43c7   Alexandre Belloni   rtc: core: correc...
170
  				    timespec64_sub(new_system, old_system));
7ca1d488f   David Brownell   rtc: suspend()/re...
171

6a8943d9e   Arve Hjønnevåg   rtc: Fix some bug...
172
  	if (sleep_time.tv_sec >= 0)
d4bda8f84   John Stultz   rtc: Update suspe...
173
  		timekeeping_inject_sleeptime64(&sleep_time);
4c24e29e6   David Fries   rtc_sysfs_show_hc...
174
  	rtc_hctosys_ret = 0;
7ca1d488f   David Brownell   rtc: suspend()/re...
175
176
  	return 0;
  }
92e7f04a7   Shuah Khan   drivers/rtc/class...
177
178
  static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume);
  #define RTC_CLASS_DEV_PM_OPS	(&rtc_class_dev_pm_ops)
7ca1d488f   David Brownell   rtc: suspend()/re...
179
  #else
92e7f04a7   Shuah Khan   drivers/rtc/class...
180
  #define RTC_CLASS_DEV_PM_OPS	NULL
7ca1d488f   David Brownell   rtc: suspend()/re...
181
  #endif
3068a254d   Alexandre Belloni   rtc: introduce ne...
182
  /* Ensure the caller will set the id before releasing the device */
d1bec20fa   Alexandre Belloni   rtc: class separa...
183
184
185
186
187
188
189
190
191
  static struct rtc_device *rtc_allocate_device(void)
  {
  	struct rtc_device *rtc;
  
  	rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
  	if (!rtc)
  		return NULL;
  
  	device_initialize(&rtc->dev);
0f295b065   Jason Gunthorpe   rtc: Allow rtc dr...
192
193
  	/* Drivers can revise this default after allocating the device. */
  	rtc->set_offset_nsec =  NSEC_PER_SEC / 2;
d1bec20fa   Alexandre Belloni   rtc: class separa...
194
195
196
197
198
199
200
201
  	rtc->irq_freq = 1;
  	rtc->max_user_freq = 64;
  	rtc->dev.class = rtc_class;
  	rtc->dev.groups = rtc_get_dev_attribute_groups();
  	rtc->dev.release = rtc_device_release;
  
  	mutex_init(&rtc->ops_lock);
  	spin_lock_init(&rtc->irq_lock);
d1bec20fa   Alexandre Belloni   rtc: class separa...
202
203
204
205
206
207
  	init_waitqueue_head(&rtc->irq_queue);
  
  	/* Init timerqueue */
  	timerqueue_init_head(&rtc->timerqueue);
  	INIT_WORK(&rtc->irqwork, rtc_timer_do_work);
  	/* Init aie timer */
9a0320117   Alexandre Belloni   rtc: enforce rtc_...
208
  	rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, rtc);
d1bec20fa   Alexandre Belloni   rtc: class separa...
209
  	/* Init uie timer */
9a0320117   Alexandre Belloni   rtc: enforce rtc_...
210
  	rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, rtc);
d1bec20fa   Alexandre Belloni   rtc: class separa...
211
212
213
214
215
216
217
  	/* Init pie timer */
  	hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
  	rtc->pie_timer.function = rtc_pie_update_irq;
  	rtc->pie_enabled = 0;
  
  	return rtc;
  }
7ca1d488f   David Brownell   rtc: suspend()/re...
218

b91336df8   Alexandre Belloni   rtc: class separa...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  static int rtc_device_get_id(struct device *dev)
  {
  	int of_id = -1, id = -1;
  
  	if (dev->of_node)
  		of_id = of_alias_get_id(dev->of_node, "rtc");
  	else if (dev->parent && dev->parent->of_node)
  		of_id = of_alias_get_id(dev->parent->of_node, "rtc");
  
  	if (of_id >= 0) {
  		id = ida_simple_get(&rtc_ida, of_id, of_id + 1, GFP_KERNEL);
  		if (id < 0)
  			dev_warn(dev, "/aliases ID %d not available
  ", of_id);
  	}
  
  	if (id < 0)
  		id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
  
  	return id;
  }
989515647   Baolin Wang   rtc: Add one offs...
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
  static void rtc_device_get_offset(struct rtc_device *rtc)
  {
  	time64_t range_secs;
  	u32 start_year;
  	int ret;
  
  	/*
  	 * If RTC driver did not implement the range of RTC hardware device,
  	 * then we can not expand the RTC range by adding or subtracting one
  	 * offset.
  	 */
  	if (rtc->range_min == rtc->range_max)
  		return;
  
  	ret = device_property_read_u32(rtc->dev.parent, "start-year",
  				       &start_year);
  	if (!ret) {
  		rtc->start_secs = mktime64(start_year, 1, 1, 0, 0, 0);
  		rtc->set_start_time = true;
  	}
  
  	/*
  	 * If user did not implement the start time for RTC driver, then no
  	 * need to expand the RTC range.
  	 */
  	if (!rtc->set_start_time)
  		return;
  
  	range_secs = rtc->range_max - rtc->range_min + 1;
  
  	/*
  	 * If the start_secs is larger than the maximum seconds (rtc->range_max)
  	 * supported by RTC hardware or the maximum seconds of new expanded
  	 * range (start_secs + rtc->range_max - rtc->range_min) is less than
  	 * rtc->range_min, which means the minimum seconds (rtc->range_min) of
  	 * RTC hardware will be mapped to start_secs by adding one offset, so
  	 * the offset seconds calculation formula should be:
  	 * rtc->offset_secs = rtc->start_secs - rtc->range_min;
  	 *
  	 * If the start_secs is larger than the minimum seconds (rtc->range_min)
  	 * supported by RTC hardware, then there is one region is overlapped
  	 * between the original RTC hardware range and the new expanded range,
  	 * and this overlapped region do not need to be mapped into the new
  	 * expanded range due to it is valid for RTC device. So the minimum
  	 * seconds of RTC hardware (rtc->range_min) should be mapped to
  	 * rtc->range_max + 1, then the offset seconds formula should be:
  	 * rtc->offset_secs = rtc->range_max - rtc->range_min + 1;
  	 *
  	 * If the start_secs is less than the minimum seconds (rtc->range_min),
  	 * which is similar to case 2. So the start_secs should be mapped to
  	 * start_secs + rtc->range_max - rtc->range_min + 1, then the
  	 * offset seconds formula should be:
  	 * rtc->offset_secs = -(rtc->range_max - rtc->range_min + 1);
  	 *
  	 * Otherwise the offset seconds should be 0.
  	 */
  	if (rtc->start_secs > rtc->range_max ||
  	    rtc->start_secs + range_secs - 1 < rtc->range_min)
  		rtc->offset_secs = rtc->start_secs - rtc->range_min;
  	else if (rtc->start_secs > rtc->range_min)
  		rtc->offset_secs = range_secs;
  	else if (rtc->start_secs < rtc->range_min)
  		rtc->offset_secs = -range_secs;
  	else
  		rtc->offset_secs = 0;
  }
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
306
  /**
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
307
308
309
310
   * rtc_device_unregister - removes the previously registered RTC class device
   *
   * @rtc: the RTC class device to destroy
   */
1e479c619   Alexandre Belloni   rtc: unexport non...
311
  static void rtc_device_unregister(struct rtc_device *rtc)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
312
  {
c3b399a4b   Dmitry Torokhov   rtc: class: remov...
313
314
315
316
317
  	mutex_lock(&rtc->ops_lock);
  	/*
  	 * Remove innards of this RTC, then disable it, before
  	 * letting any rtc_class_open() users access it again
  	 */
c3b399a4b   Dmitry Torokhov   rtc: class: remov...
318
  	rtc_proc_del_device(rtc);
d5ed9177f   Logan Gunthorpe   rtc: utilize new ...
319
  	cdev_device_del(&rtc->char_dev, &rtc->dev);
c3b399a4b   Dmitry Torokhov   rtc: class: remov...
320
321
322
  	rtc->ops = NULL;
  	mutex_unlock(&rtc->ops_lock);
  	put_device(&rtc->dev);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
323
  }
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
324

3068a254d   Alexandre Belloni   rtc: introduce ne...
325
326
327
  static void devm_rtc_release_device(struct device *dev, void *res)
  {
  	struct rtc_device *rtc = *(struct rtc_device **)res;
ac75779b7   Alexandre Belloni   rtc: nvmem: allow...
328
  	rtc_nvmem_unregister(rtc);
3068a254d   Alexandre Belloni   rtc: introduce ne...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  	if (rtc->registered)
  		rtc_device_unregister(rtc);
  	else
  		put_device(&rtc->dev);
  }
  
  struct rtc_device *devm_rtc_allocate_device(struct device *dev)
  {
  	struct rtc_device **ptr, *rtc;
  	int id, err;
  
  	id = rtc_device_get_id(dev);
  	if (id < 0)
  		return ERR_PTR(id);
  
  	ptr = devres_alloc(devm_rtc_release_device, sizeof(*ptr), GFP_KERNEL);
  	if (!ptr) {
  		err = -ENOMEM;
  		goto exit_ida;
  	}
  
  	rtc = rtc_allocate_device();
  	if (!rtc) {
  		err = -ENOMEM;
  		goto exit_devres;
  	}
  
  	*ptr = rtc;
  	devres_add(dev, ptr);
  
  	rtc->id = id;
  	rtc->dev.parent = dev;
  	dev_set_name(&rtc->dev, "rtc%d", id);
  
  	return rtc;
  
  exit_devres:
  	devres_free(ptr);
  exit_ida:
  	ida_simple_remove(&rtc_ida, id);
  	return ERR_PTR(err);
  }
  EXPORT_SYMBOL_GPL(devm_rtc_allocate_device);
  
  int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
  {
  	struct rtc_wkalrm alrm;
  	int err;
924068e50   Alexandre Belloni   rtc: class: add d...
377
378
379
  	if (!rtc->ops) {
  		dev_dbg(&rtc->dev, "no ops set
  ");
3068a254d   Alexandre Belloni   rtc: introduce ne...
380
  		return -EINVAL;
924068e50   Alexandre Belloni   rtc: class: add d...
381
  	}
3068a254d   Alexandre Belloni   rtc: introduce ne...
382
383
  
  	rtc->owner = owner;
989515647   Baolin Wang   rtc: Add one offs...
384
  	rtc_device_get_offset(rtc);
3068a254d   Alexandre Belloni   rtc: introduce ne...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
  
  	/* Check to see if there is an ALARM already set in hw */
  	err = __rtc_read_alarm(rtc, &alrm);
  	if (!err && !rtc_valid_tm(&alrm.time))
  		rtc_initialize_alarm(rtc, &alrm);
  
  	rtc_dev_prepare(rtc);
  
  	err = cdev_device_add(&rtc->char_dev, &rtc->dev);
  	if (err)
  		dev_warn(rtc->dev.parent, "failed to add char device %d:%d
  ",
  			 MAJOR(rtc->dev.devt), rtc->id);
  	else
  		dev_dbg(rtc->dev.parent, "char device (%d:%d)
  ",
  			MAJOR(rtc->dev.devt), rtc->id);
  
  	rtc_proc_add_device(rtc);
  
  	rtc->registered = true;
  	dev_info(rtc->dev.parent, "registered as %s
  ",
  		 dev_name(&rtc->dev));
14ad431cd   Steve Muckle   ANDROID: rtc: cla...
409
410
  #ifdef CONFIG_RTC_HCTOSYS_DEVICE
  	if (!strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE))
0fb885c7b   Greg Kroah-Hartman   ANDROID: fix up r...
411
  		rtc_hctosys(rtc);
14ad431cd   Steve Muckle   ANDROID: rtc: cla...
412
  #endif
3068a254d   Alexandre Belloni   rtc: introduce ne...
413
414
415
  	return 0;
  }
  EXPORT_SYMBOL_GPL(__rtc_register_device);
a26944149   Alexandre Belloni   rtc: class: reimp...
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
  /**
   * devm_rtc_device_register - resource managed rtc_device_register()
   * @dev: the device to register
   * @name: the name of the device (unused)
   * @ops: the rtc operations structure
   * @owner: the module owner
   *
   * @return a struct rtc on success, or an ERR_PTR on error
   *
   * Managed rtc_device_register(). The rtc_device returned from this function
   * are automatically freed on driver detach.
   * This function is deprecated, use devm_rtc_allocate_device and
   * rtc_register_device instead
   */
  struct rtc_device *devm_rtc_device_register(struct device *dev,
606cc43c7   Alexandre Belloni   rtc: core: correc...
431
432
433
  					    const char *name,
  					    const struct rtc_class_ops *ops,
  					    struct module *owner)
a26944149   Alexandre Belloni   rtc: class: reimp...
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  {
  	struct rtc_device *rtc;
  	int err;
  
  	rtc = devm_rtc_allocate_device(dev);
  	if (IS_ERR(rtc))
  		return rtc;
  
  	rtc->ops = ops;
  
  	err = __rtc_register_device(owner, rtc);
  	if (err)
  		return ERR_PTR(err);
  
  	return rtc;
  }
  EXPORT_SYMBOL_GPL(devm_rtc_device_register);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
451
452
453
454
  static int __init rtc_init(void)
  {
  	rtc_class = class_create(THIS_MODULE, "rtc");
  	if (IS_ERR(rtc_class)) {
c100a5e02   Jingoo Han   rtc: use dev_warn...
455
456
  		pr_err("couldn't create class
  ");
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
457
458
  		return PTR_ERR(rtc_class);
  	}
92e7f04a7   Shuah Khan   drivers/rtc/class...
459
  	rtc_class->pm = RTC_CLASS_DEV_PM_OPS;
5726fb201   David Brownell   rtc: remove /sys/...
460
  	rtc_dev_init();
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
461
462
  	return 0;
  }
818a8674b   David Brownell   [PATCH] RTC class...
463
  subsys_initcall(rtc_init);