2019-04-16 12:59:24 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2019 , Linaro Limited
*/
# include "nvmem.h"
static const char * const nvmem_type_str [ ] = {
[ NVMEM_TYPE_UNKNOWN ] = " Unknown " ,
[ NVMEM_TYPE_EEPROM ] = " EEPROM " ,
[ NVMEM_TYPE_OTP ] = " OTP " ,
[ NVMEM_TYPE_BATTERY_BACKED ] = " Battery backed " ,
} ;
# ifdef CONFIG_DEBUG_LOCK_ALLOC
static struct lock_class_key eeprom_lock_key ;
# endif
static ssize_t type_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct nvmem_device * nvmem = to_nvmem_device ( dev ) ;
return sprintf ( buf , " %s \n " , nvmem_type_str [ nvmem - > type ] ) ;
}
static DEVICE_ATTR_RO ( type ) ;
static struct attribute * nvmem_attrs [ ] = {
& dev_attr_type . attr ,
NULL ,
} ;
static ssize_t bin_attr_nvmem_read ( struct file * filp , struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t pos , size_t count )
{
struct device * dev ;
struct nvmem_device * nvmem ;
int rc ;
if ( attr - > private )
dev = attr - > private ;
else
dev = container_of ( kobj , struct device , kobj ) ;
nvmem = to_nvmem_device ( dev ) ;
/* Stop the user from reading */
if ( pos > = nvmem - > size )
return 0 ;
if ( count < nvmem - > word_size )
return - EINVAL ;
if ( pos + count > nvmem - > size )
count = nvmem - > size - pos ;
count = round_down ( count , nvmem - > word_size ) ;
rc = nvmem - > reg_read ( nvmem - > priv , pos , buf , count ) ;
if ( rc )
return rc ;
return count ;
}
static ssize_t bin_attr_nvmem_write ( struct file * filp , struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t pos , size_t count )
{
struct device * dev ;
struct nvmem_device * nvmem ;
int rc ;
if ( attr - > private )
dev = attr - > private ;
else
dev = container_of ( kobj , struct device , kobj ) ;
nvmem = to_nvmem_device ( dev ) ;
/* Stop the user from writing */
if ( pos > = nvmem - > size )
return - EFBIG ;
if ( count < nvmem - > word_size )
return - EINVAL ;
if ( pos + count > nvmem - > size )
count = nvmem - > size - pos ;
count = round_down ( count , nvmem - > word_size ) ;
rc = nvmem - > reg_write ( nvmem - > priv , pos , buf , count ) ;
if ( rc )
return rc ;
return count ;
}
/* default read/write permissions */
static struct bin_attribute bin_attr_rw_nvmem = {
. attr = {
. name = " nvmem " ,
. mode = 0644 ,
} ,
. read = bin_attr_nvmem_read ,
. write = bin_attr_nvmem_write ,
} ;
static struct bin_attribute * nvmem_bin_rw_attributes [ ] = {
& bin_attr_rw_nvmem ,
NULL ,
} ;
static const struct attribute_group nvmem_bin_rw_group = {
. bin_attrs = nvmem_bin_rw_attributes ,
. attrs = nvmem_attrs ,
} ;
static const struct attribute_group * nvmem_rw_dev_groups [ ] = {
& nvmem_bin_rw_group ,
NULL ,
} ;
/* read only permission */
static struct bin_attribute bin_attr_ro_nvmem = {
. attr = {
. name = " nvmem " ,
. mode = 0444 ,
} ,
. read = bin_attr_nvmem_read ,
} ;
static struct bin_attribute * nvmem_bin_ro_attributes [ ] = {
& bin_attr_ro_nvmem ,
NULL ,
} ;
static const struct attribute_group nvmem_bin_ro_group = {
. bin_attrs = nvmem_bin_ro_attributes ,
. attrs = nvmem_attrs ,
} ;
static const struct attribute_group * nvmem_ro_dev_groups [ ] = {
& nvmem_bin_ro_group ,
NULL ,
} ;
/* default read/write permissions, root only */
static struct bin_attribute bin_attr_rw_root_nvmem = {
. attr = {
. name = " nvmem " ,
. mode = 0600 ,
} ,
. read = bin_attr_nvmem_read ,
. write = bin_attr_nvmem_write ,
} ;
static struct bin_attribute * nvmem_bin_rw_root_attributes [ ] = {
& bin_attr_rw_root_nvmem ,
NULL ,
} ;
static const struct attribute_group nvmem_bin_rw_root_group = {
. bin_attrs = nvmem_bin_rw_root_attributes ,
. attrs = nvmem_attrs ,
} ;
static const struct attribute_group * nvmem_rw_root_dev_groups [ ] = {
& nvmem_bin_rw_root_group ,
NULL ,
} ;
/* read only permission, root only */
static struct bin_attribute bin_attr_ro_root_nvmem = {
. attr = {
. name = " nvmem " ,
. mode = 0400 ,
} ,
. read = bin_attr_nvmem_read ,
} ;
static struct bin_attribute * nvmem_bin_ro_root_attributes [ ] = {
& bin_attr_ro_root_nvmem ,
NULL ,
} ;
static const struct attribute_group nvmem_bin_ro_root_group = {
. bin_attrs = nvmem_bin_ro_root_attributes ,
. attrs = nvmem_attrs ,
} ;
static const struct attribute_group * nvmem_ro_root_dev_groups [ ] = {
& nvmem_bin_ro_root_group ,
NULL ,
} ;
const struct attribute_group * * nvmem_sysfs_get_groups (
struct nvmem_device * nvmem ,
const struct nvmem_config * config )
{
if ( config - > root_only )
return nvmem - > read_only ?
nvmem_ro_root_dev_groups :
nvmem_rw_root_dev_groups ;
return nvmem - > read_only ? nvmem_ro_dev_groups : nvmem_rw_dev_groups ;
}
/*
* nvmem_setup_compat ( ) - Create an additional binary entry in
* drivers sys directory , to be backwards compatible with the older
* drivers / misc / eeprom drivers .
*/
int nvmem_sysfs_setup_compat ( struct nvmem_device * nvmem ,
const struct nvmem_config * config )
{
int rval ;
if ( ! config - > compat )
return 0 ;
if ( ! config - > base_dev )
return - EINVAL ;
2019-07-28 19:42:55 +03:00
if ( nvmem - > read_only ) {
if ( config - > root_only )
nvmem - > eeprom = bin_attr_ro_root_nvmem ;
else
nvmem - > eeprom = bin_attr_ro_nvmem ;
} else {
if ( config - > root_only )
nvmem - > eeprom = bin_attr_rw_root_nvmem ;
else
nvmem - > eeprom = bin_attr_rw_nvmem ;
}
2019-04-16 12:59:24 +03:00
nvmem - > eeprom . attr . name = " eeprom " ;
nvmem - > eeprom . size = nvmem - > size ;
# ifdef CONFIG_DEBUG_LOCK_ALLOC
nvmem - > eeprom . attr . key = & eeprom_lock_key ;
# endif
nvmem - > eeprom . private = & nvmem - > dev ;
nvmem - > base_dev = config - > base_dev ;
rval = device_create_bin_file ( nvmem - > base_dev , & nvmem - > eeprom ) ;
if ( rval ) {
dev_err ( & nvmem - > dev ,
" Failed to create eeprom binary file %d \n " , rval ) ;
return rval ;
}
nvmem - > flags | = FLAG_COMPAT ;
return 0 ;
}
void nvmem_sysfs_remove_compat ( struct nvmem_device * nvmem ,
const struct nvmem_config * config )
{
if ( config - > compat )
device_remove_bin_file ( nvmem - > base_dev , & nvmem - > eeprom ) ;
}