Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.3-rc6 263 lines 5.7 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2019, Linaro Limited 4 */ 5#include "nvmem.h" 6 7static const char * const nvmem_type_str[] = { 8 [NVMEM_TYPE_UNKNOWN] = "Unknown", 9 [NVMEM_TYPE_EEPROM] = "EEPROM", 10 [NVMEM_TYPE_OTP] = "OTP", 11 [NVMEM_TYPE_BATTERY_BACKED] = "Battery backed", 12}; 13 14#ifdef CONFIG_DEBUG_LOCK_ALLOC 15static struct lock_class_key eeprom_lock_key; 16#endif 17 18static ssize_t type_show(struct device *dev, 19 struct device_attribute *attr, char *buf) 20{ 21 struct nvmem_device *nvmem = to_nvmem_device(dev); 22 23 return sprintf(buf, "%s\n", nvmem_type_str[nvmem->type]); 24} 25 26static DEVICE_ATTR_RO(type); 27 28static struct attribute *nvmem_attrs[] = { 29 &dev_attr_type.attr, 30 NULL, 31}; 32 33static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, 34 struct bin_attribute *attr, 35 char *buf, loff_t pos, size_t count) 36{ 37 struct device *dev; 38 struct nvmem_device *nvmem; 39 int rc; 40 41 if (attr->private) 42 dev = attr->private; 43 else 44 dev = container_of(kobj, struct device, kobj); 45 nvmem = to_nvmem_device(dev); 46 47 /* Stop the user from reading */ 48 if (pos >= nvmem->size) 49 return 0; 50 51 if (count < nvmem->word_size) 52 return -EINVAL; 53 54 if (pos + count > nvmem->size) 55 count = nvmem->size - pos; 56 57 count = round_down(count, nvmem->word_size); 58 59 rc = nvmem->reg_read(nvmem->priv, pos, buf, count); 60 61 if (rc) 62 return rc; 63 64 return count; 65} 66 67static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, 68 struct bin_attribute *attr, 69 char *buf, loff_t pos, size_t count) 70{ 71 struct device *dev; 72 struct nvmem_device *nvmem; 73 int rc; 74 75 if (attr->private) 76 dev = attr->private; 77 else 78 dev = container_of(kobj, struct device, kobj); 79 nvmem = to_nvmem_device(dev); 80 81 /* Stop the user from writing */ 82 if (pos >= nvmem->size) 83 return -EFBIG; 84 85 if (count < nvmem->word_size) 86 return -EINVAL; 87 88 if (pos + count > nvmem->size) 89 count = nvmem->size - pos; 90 91 count = round_down(count, nvmem->word_size); 92 93 rc = nvmem->reg_write(nvmem->priv, pos, buf, count); 94 95 if (rc) 96 return rc; 97 98 return count; 99} 100 101/* default read/write permissions */ 102static struct bin_attribute bin_attr_rw_nvmem = { 103 .attr = { 104 .name = "nvmem", 105 .mode = 0644, 106 }, 107 .read = bin_attr_nvmem_read, 108 .write = bin_attr_nvmem_write, 109}; 110 111static struct bin_attribute *nvmem_bin_rw_attributes[] = { 112 &bin_attr_rw_nvmem, 113 NULL, 114}; 115 116static const struct attribute_group nvmem_bin_rw_group = { 117 .bin_attrs = nvmem_bin_rw_attributes, 118 .attrs = nvmem_attrs, 119}; 120 121static const struct attribute_group *nvmem_rw_dev_groups[] = { 122 &nvmem_bin_rw_group, 123 NULL, 124}; 125 126/* read only permission */ 127static struct bin_attribute bin_attr_ro_nvmem = { 128 .attr = { 129 .name = "nvmem", 130 .mode = 0444, 131 }, 132 .read = bin_attr_nvmem_read, 133}; 134 135static struct bin_attribute *nvmem_bin_ro_attributes[] = { 136 &bin_attr_ro_nvmem, 137 NULL, 138}; 139 140static const struct attribute_group nvmem_bin_ro_group = { 141 .bin_attrs = nvmem_bin_ro_attributes, 142 .attrs = nvmem_attrs, 143}; 144 145static const struct attribute_group *nvmem_ro_dev_groups[] = { 146 &nvmem_bin_ro_group, 147 NULL, 148}; 149 150/* default read/write permissions, root only */ 151static struct bin_attribute bin_attr_rw_root_nvmem = { 152 .attr = { 153 .name = "nvmem", 154 .mode = 0600, 155 }, 156 .read = bin_attr_nvmem_read, 157 .write = bin_attr_nvmem_write, 158}; 159 160static struct bin_attribute *nvmem_bin_rw_root_attributes[] = { 161 &bin_attr_rw_root_nvmem, 162 NULL, 163}; 164 165static const struct attribute_group nvmem_bin_rw_root_group = { 166 .bin_attrs = nvmem_bin_rw_root_attributes, 167 .attrs = nvmem_attrs, 168}; 169 170static const struct attribute_group *nvmem_rw_root_dev_groups[] = { 171 &nvmem_bin_rw_root_group, 172 NULL, 173}; 174 175/* read only permission, root only */ 176static struct bin_attribute bin_attr_ro_root_nvmem = { 177 .attr = { 178 .name = "nvmem", 179 .mode = 0400, 180 }, 181 .read = bin_attr_nvmem_read, 182}; 183 184static struct bin_attribute *nvmem_bin_ro_root_attributes[] = { 185 &bin_attr_ro_root_nvmem, 186 NULL, 187}; 188 189static const struct attribute_group nvmem_bin_ro_root_group = { 190 .bin_attrs = nvmem_bin_ro_root_attributes, 191 .attrs = nvmem_attrs, 192}; 193 194static const struct attribute_group *nvmem_ro_root_dev_groups[] = { 195 &nvmem_bin_ro_root_group, 196 NULL, 197}; 198 199const struct attribute_group **nvmem_sysfs_get_groups( 200 struct nvmem_device *nvmem, 201 const struct nvmem_config *config) 202{ 203 if (config->root_only) 204 return nvmem->read_only ? 205 nvmem_ro_root_dev_groups : 206 nvmem_rw_root_dev_groups; 207 208 return nvmem->read_only ? nvmem_ro_dev_groups : nvmem_rw_dev_groups; 209} 210 211/* 212 * nvmem_setup_compat() - Create an additional binary entry in 213 * drivers sys directory, to be backwards compatible with the older 214 * drivers/misc/eeprom drivers. 215 */ 216int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem, 217 const struct nvmem_config *config) 218{ 219 int rval; 220 221 if (!config->compat) 222 return 0; 223 224 if (!config->base_dev) 225 return -EINVAL; 226 227 if (nvmem->read_only) { 228 if (config->root_only) 229 nvmem->eeprom = bin_attr_ro_root_nvmem; 230 else 231 nvmem->eeprom = bin_attr_ro_nvmem; 232 } else { 233 if (config->root_only) 234 nvmem->eeprom = bin_attr_rw_root_nvmem; 235 else 236 nvmem->eeprom = bin_attr_rw_nvmem; 237 } 238 nvmem->eeprom.attr.name = "eeprom"; 239 nvmem->eeprom.size = nvmem->size; 240#ifdef CONFIG_DEBUG_LOCK_ALLOC 241 nvmem->eeprom.attr.key = &eeprom_lock_key; 242#endif 243 nvmem->eeprom.private = &nvmem->dev; 244 nvmem->base_dev = config->base_dev; 245 246 rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); 247 if (rval) { 248 dev_err(&nvmem->dev, 249 "Failed to create eeprom binary file %d\n", rval); 250 return rval; 251 } 252 253 nvmem->flags |= FLAG_COMPAT; 254 255 return 0; 256} 257 258void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem, 259 const struct nvmem_config *config) 260{ 261 if (config->compat) 262 device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); 263}