Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-2.6-block.git] / drivers / rtc / nvmem.c
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 /*
18  * Deprecated ABI compatibility, this should be removed at some point
19  */
20
21 static const char nvram_warning[] = "Deprecated ABI, please use nvmem";
22
23 static ssize_t
24 rtc_nvram_read(struct file *filp, struct kobject *kobj,
25                struct bin_attribute *attr,
26                char *buf, loff_t off, size_t count)
27 {
28         struct rtc_device *rtc = attr->private;
29
30         dev_warn_once(kobj_to_dev(kobj), nvram_warning);
31
32         return nvmem_device_read(rtc->nvmem, off, count, buf);
33 }
34
35 static ssize_t
36 rtc_nvram_write(struct file *filp, struct kobject *kobj,
37                 struct bin_attribute *attr,
38                 char *buf, loff_t off, size_t count)
39 {
40         struct rtc_device *rtc = attr->private;
41
42         dev_warn_once(kobj_to_dev(kobj), nvram_warning);
43
44         return nvmem_device_write(rtc->nvmem, off, count, buf);
45 }
46
47 static int rtc_nvram_register(struct rtc_device *rtc, size_t size)
48 {
49         int err;
50
51         rtc->nvram = devm_kzalloc(rtc->dev.parent,
52                                 sizeof(struct bin_attribute),
53                                 GFP_KERNEL);
54         if (!rtc->nvram)
55                 return -ENOMEM;
56
57         rtc->nvram->attr.name = "nvram";
58         rtc->nvram->attr.mode = 0644;
59         rtc->nvram->private = rtc;
60
61         sysfs_bin_attr_init(rtc->nvram);
62
63         rtc->nvram->read = rtc_nvram_read;
64         rtc->nvram->write = rtc_nvram_write;
65         rtc->nvram->size = size;
66
67         err = sysfs_create_bin_file(&rtc->dev.parent->kobj,
68                                     rtc->nvram);
69         if (err) {
70                 devm_kfree(rtc->dev.parent, rtc->nvram);
71                 rtc->nvram = NULL;
72         }
73
74         return err;
75 }
76
77 static void rtc_nvram_unregister(struct rtc_device *rtc)
78 {
79         sysfs_remove_bin_file(&rtc->dev.parent->kobj, rtc->nvram);
80 }
81
82 /*
83  * New ABI, uses nvmem
84  */
85 int rtc_nvmem_register(struct rtc_device *rtc,
86                        struct nvmem_config *nvmem_config)
87 {
88         if (!IS_ERR_OR_NULL(rtc->nvmem))
89                 return -EBUSY;
90
91         if (!nvmem_config)
92                 return -ENODEV;
93
94         nvmem_config->dev = rtc->dev.parent;
95         nvmem_config->owner = rtc->owner;
96         rtc->nvmem = nvmem_register(nvmem_config);
97         if (IS_ERR(rtc->nvmem))
98                 return PTR_ERR(rtc->nvmem);
99
100         /* Register the old ABI */
101         if (rtc->nvram_old_abi)
102                 rtc_nvram_register(rtc, nvmem_config->size);
103
104         return 0;
105 }
106 EXPORT_SYMBOL_GPL(rtc_nvmem_register);
107
108 void rtc_nvmem_unregister(struct rtc_device *rtc)
109 {
110         if (IS_ERR_OR_NULL(rtc->nvmem))
111                 return;
112
113         /* unregister the old ABI */
114         if (rtc->nvram)
115                 rtc_nvram_unregister(rtc);
116
117         nvmem_unregister(rtc->nvmem);
118 }