2019-03-14 01:02:48 +03:00
// SPDX-License-Identifier: GPL-2.0
2017-07-06 12:42:02 +03:00
/*
* RTC subsystem , nvmem interface
*
* Copyright ( C ) 2017 Alexandre Belloni
*/
# include <linux/err.h>
# include <linux/types.h>
# include <linux/nvmem-consumer.h>
# include <linux/rtc.h>
2018-12-31 02:49:36 +03:00
# include <linux/slab.h>
2017-07-06 12:42:02 +03:00
# include <linux/sysfs.h>
/*
* Deprecated ABI compatibility , this should be removed at some point
*/
static const char nvram_warning [ ] = " Deprecated ABI, please use nvmem " ;
static ssize_t
rtc_nvram_read ( struct file * filp , struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off , size_t count )
{
dev_warn_once ( kobj_to_dev ( kobj ) , nvram_warning ) ;
2018-11-10 23:29:03 +03:00
return nvmem_device_read ( attr - > private , off , count , buf ) ;
2017-07-06 12:42:02 +03:00
}
static ssize_t
rtc_nvram_write ( struct file * filp , struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off , size_t count )
{
dev_warn_once ( kobj_to_dev ( kobj ) , nvram_warning ) ;
2018-11-10 23:29:03 +03:00
return nvmem_device_write ( attr - > private , off , count , buf ) ;
2017-07-06 12:42:02 +03:00
}
2018-11-10 23:29:03 +03:00
static int rtc_nvram_register ( struct rtc_device * rtc ,
struct nvmem_device * nvmem , size_t size )
2017-07-06 12:42:02 +03:00
{
int err ;
2019-03-20 14:59:09 +03:00
rtc - > nvram = kzalloc ( sizeof ( * rtc - > nvram ) , GFP_KERNEL ) ;
2017-07-06 12:42:02 +03:00
if ( ! rtc - > nvram )
return - ENOMEM ;
rtc - > nvram - > attr . name = " nvram " ;
rtc - > nvram - > attr . mode = 0644 ;
2018-11-10 23:29:03 +03:00
rtc - > nvram - > private = nvmem ;
2017-07-06 12:42:02 +03:00
sysfs_bin_attr_init ( rtc - > nvram ) ;
rtc - > nvram - > read = rtc_nvram_read ;
rtc - > nvram - > write = rtc_nvram_write ;
2018-02-13 01:47:16 +03:00
rtc - > nvram - > size = size ;
2017-07-06 12:42:02 +03:00
err = sysfs_create_bin_file ( & rtc - > dev . parent - > kobj ,
rtc - > nvram ) ;
if ( err ) {
2018-12-31 02:49:36 +03:00
kfree ( rtc - > nvram ) ;
2017-07-06 12:42:02 +03:00
rtc - > nvram = NULL ;
}
return err ;
}
static void rtc_nvram_unregister ( struct rtc_device * rtc )
{
sysfs_remove_bin_file ( & rtc - > dev . parent - > kobj , rtc - > nvram ) ;
2018-12-31 02:49:36 +03:00
kfree ( rtc - > nvram ) ;
rtc - > nvram = NULL ;
2017-07-06 12:42:02 +03:00
}
/*
* New ABI , uses nvmem
*/
2018-02-13 01:47:17 +03:00
int rtc_nvmem_register ( struct rtc_device * rtc ,
struct nvmem_config * nvmem_config )
2017-07-06 12:42:02 +03:00
{
2018-11-10 23:29:03 +03:00
struct nvmem_device * nvmem ;
2018-02-13 01:47:18 +03:00
2018-02-13 01:47:16 +03:00
if ( ! nvmem_config )
2018-02-13 01:47:17 +03:00
return - ENODEV ;
2017-07-06 12:42:02 +03:00
2018-02-28 23:58:02 +03:00
nvmem_config - > dev = rtc - > dev . parent ;
2018-02-13 01:47:16 +03:00
nvmem_config - > owner = rtc - > owner ;
2018-11-10 23:29:03 +03:00
nvmem = devm_nvmem_register ( rtc - > dev . parent , nvmem_config ) ;
if ( IS_ERR ( nvmem ) )
return PTR_ERR ( nvmem ) ;
2017-07-06 12:42:02 +03:00
/* Register the old ABI */
if ( rtc - > nvram_old_abi )
2018-11-10 23:29:03 +03:00
rtc_nvram_register ( rtc , nvmem , nvmem_config - > size ) ;
2018-02-13 01:47:17 +03:00
return 0 ;
2017-07-06 12:42:02 +03:00
}
2018-02-13 01:47:19 +03:00
EXPORT_SYMBOL_GPL ( rtc_nvmem_register ) ;
2017-07-06 12:42:02 +03:00
void rtc_nvmem_unregister ( struct rtc_device * rtc )
{
/* unregister the old ABI */
if ( rtc - > nvram )
rtc_nvram_unregister ( rtc ) ;
}