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