Commit | Line | Data |
---|---|---|
697e5a47 AB |
1 | /* |
2 | * RTC subsystem, nvmem interface | |
3 | * | |
4 | * Copyright (C) 2017 Alexandre Belloni | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | */ | |
10 | ||
11 | #include <linux/err.h> | |
12 | #include <linux/types.h> | |
13 | #include <linux/nvmem-consumer.h> | |
14 | #include <linux/rtc.h> | |
15 | #include <linux/sysfs.h> | |
16 | ||
17 | #include "rtc-core.h" | |
18 | ||
19 | /* | |
20 | * Deprecated ABI compatibility, this should be removed at some point | |
21 | */ | |
22 | ||
23 | static const char nvram_warning[] = "Deprecated ABI, please use nvmem"; | |
24 | ||
25 | static ssize_t | |
26 | rtc_nvram_read(struct file *filp, struct kobject *kobj, | |
27 | struct bin_attribute *attr, | |
28 | char *buf, loff_t off, size_t count) | |
29 | { | |
30 | struct rtc_device *rtc = attr->private; | |
31 | ||
32 | dev_warn_once(kobj_to_dev(kobj), nvram_warning); | |
33 | ||
34 | return nvmem_device_read(rtc->nvmem, off, count, buf); | |
35 | } | |
36 | ||
37 | static ssize_t | |
38 | rtc_nvram_write(struct file *filp, struct kobject *kobj, | |
39 | struct bin_attribute *attr, | |
40 | char *buf, loff_t off, size_t count) | |
41 | { | |
42 | struct rtc_device *rtc = attr->private; | |
43 | ||
44 | dev_warn_once(kobj_to_dev(kobj), nvram_warning); | |
45 | ||
46 | return nvmem_device_write(rtc->nvmem, off, count, buf); | |
47 | } | |
48 | ||
49 | static int rtc_nvram_register(struct rtc_device *rtc) | |
50 | { | |
51 | int err; | |
52 | ||
53 | rtc->nvram = devm_kzalloc(rtc->dev.parent, | |
54 | sizeof(struct bin_attribute), | |
55 | GFP_KERNEL); | |
56 | if (!rtc->nvram) | |
57 | return -ENOMEM; | |
58 | ||
59 | rtc->nvram->attr.name = "nvram"; | |
60 | rtc->nvram->attr.mode = 0644; | |
61 | rtc->nvram->private = rtc; | |
62 | ||
63 | sysfs_bin_attr_init(rtc->nvram); | |
64 | ||
65 | rtc->nvram->read = rtc_nvram_read; | |
66 | rtc->nvram->write = rtc_nvram_write; | |
67 | rtc->nvram->size = rtc->nvmem_config->size; | |
68 | ||
69 | err = sysfs_create_bin_file(&rtc->dev.parent->kobj, | |
70 | rtc->nvram); | |
71 | if (err) { | |
72 | devm_kfree(rtc->dev.parent, rtc->nvram); | |
73 | rtc->nvram = NULL; | |
74 | } | |
75 | ||
76 | return err; | |
77 | } | |
78 | ||
79 | static void rtc_nvram_unregister(struct rtc_device *rtc) | |
80 | { | |
81 | sysfs_remove_bin_file(&rtc->dev.parent->kobj, rtc->nvram); | |
82 | } | |
83 | ||
84 | /* | |
85 | * New ABI, uses nvmem | |
86 | */ | |
87 | void rtc_nvmem_register(struct rtc_device *rtc) | |
88 | { | |
89 | if (!rtc->nvmem_config) | |
90 | return; | |
91 | ||
92 | rtc->nvmem_config->dev = &rtc->dev; | |
93 | rtc->nvmem_config->owner = rtc->owner; | |
94 | rtc->nvmem = nvmem_register(rtc->nvmem_config); | |
95 | if (IS_ERR_OR_NULL(rtc->nvmem)) | |
96 | return; | |
97 | ||
98 | /* Register the old ABI */ | |
99 | if (rtc->nvram_old_abi) | |
100 | rtc_nvram_register(rtc); | |
101 | } | |
102 | ||
103 | void rtc_nvmem_unregister(struct rtc_device *rtc) | |
104 | { | |
105 | if (IS_ERR_OR_NULL(rtc->nvmem)) | |
106 | return; | |
107 | ||
108 | /* unregister the old ABI */ | |
109 | if (rtc->nvram) | |
110 | rtc_nvram_unregister(rtc); | |
111 | ||
112 | nvmem_unregister(rtc->nvmem); | |
113 | } |