blob: dce518d5e50edd2961cb53ec08ac55a67cbc2ab8 [file] [log] [blame]
Alexandre Belloni697e5a42017-07-06 11:42:02 +02001/*
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>
Alexandre Bellonibba3d2d2018-12-31 00:49:36 +010015#include <linux/slab.h>
Alexandre Belloni697e5a42017-07-06 11:42:02 +020016#include <linux/sysfs.h>
17
Alexandre Belloni697e5a42017-07-06 11:42:02 +020018/*
19 * Deprecated ABI compatibility, this should be removed at some point
20 */
21
22static const char nvram_warning[] = "Deprecated ABI, please use nvmem";
23
24static ssize_t
25rtc_nvram_read(struct file *filp, struct kobject *kobj,
26 struct bin_attribute *attr,
27 char *buf, loff_t off, size_t count)
28{
Alexandre Belloni697e5a42017-07-06 11:42:02 +020029 dev_warn_once(kobj_to_dev(kobj), nvram_warning);
30
Alexandre Belloni41c9e132018-11-10 21:29:03 +010031 return nvmem_device_read(attr->private, off, count, buf);
Alexandre Belloni697e5a42017-07-06 11:42:02 +020032}
33
34static ssize_t
35rtc_nvram_write(struct file *filp, struct kobject *kobj,
36 struct bin_attribute *attr,
37 char *buf, loff_t off, size_t count)
38{
Alexandre Belloni697e5a42017-07-06 11:42:02 +020039 dev_warn_once(kobj_to_dev(kobj), nvram_warning);
40
Alexandre Belloni41c9e132018-11-10 21:29:03 +010041 return nvmem_device_write(attr->private, off, count, buf);
Alexandre Belloni697e5a42017-07-06 11:42:02 +020042}
43
Alexandre Belloni41c9e132018-11-10 21:29:03 +010044static int rtc_nvram_register(struct rtc_device *rtc,
45 struct nvmem_device *nvmem, size_t size)
Alexandre Belloni697e5a42017-07-06 11:42:02 +020046{
47 int err;
48
Alexandre Bellonibba3d2d2018-12-31 00:49:36 +010049 rtc->nvram = kzalloc(sizeof(struct bin_attribute), GFP_KERNEL);
Alexandre Belloni697e5a42017-07-06 11:42:02 +020050 if (!rtc->nvram)
51 return -ENOMEM;
52
53 rtc->nvram->attr.name = "nvram";
54 rtc->nvram->attr.mode = 0644;
Alexandre Belloni41c9e132018-11-10 21:29:03 +010055 rtc->nvram->private = nvmem;
Alexandre Belloni697e5a42017-07-06 11:42:02 +020056
57 sysfs_bin_attr_init(rtc->nvram);
58
59 rtc->nvram->read = rtc_nvram_read;
60 rtc->nvram->write = rtc_nvram_write;
Alexandre Belloni4cce9d32018-02-12 23:47:16 +010061 rtc->nvram->size = size;
Alexandre Belloni697e5a42017-07-06 11:42:02 +020062
63 err = sysfs_create_bin_file(&rtc->dev.parent->kobj,
64 rtc->nvram);
65 if (err) {
Alexandre Bellonibba3d2d2018-12-31 00:49:36 +010066 kfree(rtc->nvram);
Alexandre Belloni697e5a42017-07-06 11:42:02 +020067 rtc->nvram = NULL;
68 }
69
70 return err;
71}
72
73static void rtc_nvram_unregister(struct rtc_device *rtc)
74{
75 sysfs_remove_bin_file(&rtc->dev.parent->kobj, rtc->nvram);
Alexandre Bellonibba3d2d2018-12-31 00:49:36 +010076 kfree(rtc->nvram);
77 rtc->nvram = NULL;
Alexandre Belloni697e5a42017-07-06 11:42:02 +020078}
79
80/*
81 * New ABI, uses nvmem
82 */
Alexandre Belloni2cc82122018-02-12 23:47:17 +010083int rtc_nvmem_register(struct rtc_device *rtc,
84 struct nvmem_config *nvmem_config)
Alexandre Belloni697e5a42017-07-06 11:42:02 +020085{
Alexandre Belloni41c9e132018-11-10 21:29:03 +010086 struct nvmem_device *nvmem;
Alexandre Belloniab3ea362018-02-12 23:47:18 +010087
Alexandre Belloni4cce9d32018-02-12 23:47:16 +010088 if (!nvmem_config)
Alexandre Belloni2cc82122018-02-12 23:47:17 +010089 return -ENODEV;
Alexandre Belloni697e5a42017-07-06 11:42:02 +020090
Alexandre Belloniac757792018-02-28 21:58:02 +010091 nvmem_config->dev = rtc->dev.parent;
Alexandre Belloni4cce9d32018-02-12 23:47:16 +010092 nvmem_config->owner = rtc->owner;
Alexandre Belloni41c9e132018-11-10 21:29:03 +010093 nvmem = devm_nvmem_register(rtc->dev.parent, nvmem_config);
94 if (IS_ERR(nvmem))
95 return PTR_ERR(nvmem);
Alexandre Belloni697e5a42017-07-06 11:42:02 +020096
97 /* Register the old ABI */
98 if (rtc->nvram_old_abi)
Alexandre Belloni41c9e132018-11-10 21:29:03 +010099 rtc_nvram_register(rtc, nvmem, nvmem_config->size);
Alexandre Belloni2cc82122018-02-12 23:47:17 +0100100
101 return 0;
Alexandre Belloni697e5a42017-07-06 11:42:02 +0200102}
Alexandre Bellonifd5cd212018-02-12 23:47:19 +0100103EXPORT_SYMBOL_GPL(rtc_nvmem_register);
Alexandre Belloni697e5a42017-07-06 11:42:02 +0200104
105void rtc_nvmem_unregister(struct rtc_device *rtc)
106{
Alexandre Belloni697e5a42017-07-06 11:42:02 +0200107 /* unregister the old ABI */
108 if (rtc->nvram)
109 rtc_nvram_unregister(rtc);
Alexandre Belloni697e5a42017-07-06 11:42:02 +0200110}