diff options
author | Andrew Lunn <andrew@lunn.ch> | 2016-02-26 14:59:19 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-03-01 19:55:48 -0500 |
commit | b6c217ab9be6895384cf0b284ace84ad79e5c53b (patch) | |
tree | 5e41a05bde354301b9b8ebe9ed6d56e57c53f4eb /drivers/nvmem/core.c | |
parent | 811b0d6538b9f26f3eb0f90fe4e6118f2480ec6f (diff) |
nvmem: Add backwards compatibility support for older EEPROM drivers.
Older drivers made an 'eeprom' file available in the /sys device
directory. Have the NVMEM core provide this to retain backwards
compatibility.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/nvmem/core.c')
-rw-r--r-- | drivers/nvmem/core.c | 84 |
1 files changed, 76 insertions, 8 deletions
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index b03690bc8f09..0de3d878c439 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c | |||
@@ -38,8 +38,13 @@ struct nvmem_device { | |||
38 | int users; | 38 | int users; |
39 | size_t size; | 39 | size_t size; |
40 | bool read_only; | 40 | bool read_only; |
41 | int flags; | ||
42 | struct bin_attribute eeprom; | ||
43 | struct device *base_dev; | ||
41 | }; | 44 | }; |
42 | 45 | ||
46 | #define FLAG_COMPAT BIT(0) | ||
47 | |||
43 | struct nvmem_cell { | 48 | struct nvmem_cell { |
44 | const char *name; | 49 | const char *name; |
45 | int offset; | 50 | int offset; |
@@ -56,16 +61,26 @@ static DEFINE_IDA(nvmem_ida); | |||
56 | static LIST_HEAD(nvmem_cells); | 61 | static LIST_HEAD(nvmem_cells); |
57 | static DEFINE_MUTEX(nvmem_cells_mutex); | 62 | static DEFINE_MUTEX(nvmem_cells_mutex); |
58 | 63 | ||
64 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
65 | static struct lock_class_key eeprom_lock_key; | ||
66 | #endif | ||
67 | |||
59 | #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) | 68 | #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) |
60 | 69 | ||
61 | static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, | 70 | static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, |
62 | struct bin_attribute *attr, | 71 | struct bin_attribute *attr, |
63 | char *buf, loff_t pos, size_t count) | 72 | char *buf, loff_t pos, size_t count) |
64 | { | 73 | { |
65 | struct device *dev = container_of(kobj, struct device, kobj); | 74 | struct device *dev; |
66 | struct nvmem_device *nvmem = to_nvmem_device(dev); | 75 | struct nvmem_device *nvmem; |
67 | int rc; | 76 | int rc; |
68 | 77 | ||
78 | if (attr->private) | ||
79 | dev = attr->private; | ||
80 | else | ||
81 | dev = container_of(kobj, struct device, kobj); | ||
82 | nvmem = to_nvmem_device(dev); | ||
83 | |||
69 | /* Stop the user from reading */ | 84 | /* Stop the user from reading */ |
70 | if (pos >= nvmem->size) | 85 | if (pos >= nvmem->size) |
71 | return 0; | 86 | return 0; |
@@ -90,10 +105,16 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, | |||
90 | struct bin_attribute *attr, | 105 | struct bin_attribute *attr, |
91 | char *buf, loff_t pos, size_t count) | 106 | char *buf, loff_t pos, size_t count) |
92 | { | 107 | { |
93 | struct device *dev = container_of(kobj, struct device, kobj); | 108 | struct device *dev; |
94 | struct nvmem_device *nvmem = to_nvmem_device(dev); | 109 | struct nvmem_device *nvmem; |
95 | int rc; | 110 | int rc; |
96 | 111 | ||
112 | if (attr->private) | ||
113 | dev = attr->private; | ||
114 | else | ||
115 | dev = container_of(kobj, struct device, kobj); | ||
116 | nvmem = to_nvmem_device(dev); | ||
117 | |||
97 | /* Stop the user from writing */ | 118 | /* Stop the user from writing */ |
98 | if (pos >= nvmem->size) | 119 | if (pos >= nvmem->size) |
99 | return 0; | 120 | return 0; |
@@ -349,6 +370,43 @@ err: | |||
349 | return rval; | 370 | return rval; |
350 | } | 371 | } |
351 | 372 | ||
373 | /* | ||
374 | * nvmem_setup_compat() - Create an additional binary entry in | ||
375 | * drivers sys directory, to be backwards compatible with the older | ||
376 | * drivers/misc/eeprom drivers. | ||
377 | */ | ||
378 | static int nvmem_setup_compat(struct nvmem_device *nvmem, | ||
379 | const struct nvmem_config *config) | ||
380 | { | ||
381 | int rval; | ||
382 | |||
383 | if (!config->base_dev) | ||
384 | return -EINVAL; | ||
385 | |||
386 | if (nvmem->read_only) | ||
387 | nvmem->eeprom = bin_attr_ro_root_nvmem; | ||
388 | else | ||
389 | nvmem->eeprom = bin_attr_rw_root_nvmem; | ||
390 | nvmem->eeprom.attr.name = "eeprom"; | ||
391 | nvmem->eeprom.size = nvmem->size; | ||
392 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
393 | nvmem->eeprom.attr.key = &eeprom_lock_key; | ||
394 | #endif | ||
395 | nvmem->eeprom.private = &nvmem->dev; | ||
396 | nvmem->base_dev = config->base_dev; | ||
397 | |||
398 | rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom); | ||
399 | if (rval) { | ||
400 | dev_err(&nvmem->dev, | ||
401 | "Failed to create eeprom binary file %d\n", rval); | ||
402 | return rval; | ||
403 | } | ||
404 | |||
405 | nvmem->flags |= FLAG_COMPAT; | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
352 | /** | 410 | /** |
353 | * nvmem_register() - Register a nvmem device for given nvmem_config. | 411 | * nvmem_register() - Register a nvmem device for given nvmem_config. |
354 | * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem | 412 | * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem |
@@ -416,16 +474,23 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) | |||
416 | dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); | 474 | dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); |
417 | 475 | ||
418 | rval = device_add(&nvmem->dev); | 476 | rval = device_add(&nvmem->dev); |
419 | if (rval) { | 477 | if (rval) |
420 | ida_simple_remove(&nvmem_ida, nvmem->id); | 478 | goto out; |
421 | kfree(nvmem); | 479 | |
422 | return ERR_PTR(rval); | 480 | if (config->compat) { |
481 | rval = nvmem_setup_compat(nvmem, config); | ||
482 | if (rval) | ||
483 | goto out; | ||
423 | } | 484 | } |
424 | 485 | ||
425 | if (config->cells) | 486 | if (config->cells) |
426 | nvmem_add_cells(nvmem, config); | 487 | nvmem_add_cells(nvmem, config); |
427 | 488 | ||
428 | return nvmem; | 489 | return nvmem; |
490 | out: | ||
491 | ida_simple_remove(&nvmem_ida, nvmem->id); | ||
492 | kfree(nvmem); | ||
493 | return ERR_PTR(rval); | ||
429 | } | 494 | } |
430 | EXPORT_SYMBOL_GPL(nvmem_register); | 495 | EXPORT_SYMBOL_GPL(nvmem_register); |
431 | 496 | ||
@@ -445,6 +510,9 @@ int nvmem_unregister(struct nvmem_device *nvmem) | |||
445 | } | 510 | } |
446 | mutex_unlock(&nvmem_mutex); | 511 | mutex_unlock(&nvmem_mutex); |
447 | 512 | ||
513 | if (nvmem->flags & FLAG_COMPAT) | ||
514 | device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); | ||
515 | |||
448 | nvmem_device_remove_all_cells(nvmem); | 516 | nvmem_device_remove_all_cells(nvmem); |
449 | device_del(&nvmem->dev); | 517 | device_del(&nvmem->dev); |
450 | 518 | ||