6344d0ed03213ae66b7fbc9f9004c3770e889382
[oweals/openwrt.git] /
1 From b6c217ab9be6895384cf0b284ace84ad79e5c53b Mon Sep 17 00:00:00 2001
2 From: Andrew Lunn <andrew@lunn.ch>
3 Date: Fri, 26 Feb 2016 20:59:19 +0100
4 Subject: nvmem: Add backwards compatibility support for older EEPROM drivers.
5
6 Older drivers made an 'eeprom' file available in the /sys device
7 directory. Have the NVMEM core provide this to retain backwards
8 compatibility.
9
10 Signed-off-by: Andrew Lunn <andrew@lunn.ch>
11 Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
12 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
13 ---
14  drivers/nvmem/core.c           | 84 ++++++++++++++++++++++++++++++++++++++----
15  include/linux/nvmem-provider.h |  4 +-
16  2 files changed, 79 insertions(+), 9 deletions(-)
17
18 --- a/drivers/nvmem/core.c
19 +++ b/drivers/nvmem/core.c
20 @@ -38,8 +38,13 @@ struct nvmem_device {
21         int                     users;
22         size_t                  size;
23         bool                    read_only;
24 +       int                     flags;
25 +       struct bin_attribute    eeprom;
26 +       struct device           *base_dev;
27  };
28  
29 +#define FLAG_COMPAT            BIT(0)
30 +
31  struct nvmem_cell {
32         const char              *name;
33         int                     offset;
34 @@ -56,16 +61,26 @@ static DEFINE_IDA(nvmem_ida);
35  static LIST_HEAD(nvmem_cells);
36  static DEFINE_MUTEX(nvmem_cells_mutex);
37  
38 +#ifdef CONFIG_DEBUG_LOCK_ALLOC
39 +static struct lock_class_key eeprom_lock_key;
40 +#endif
41 +
42  #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
43  
44  static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
45                                     struct bin_attribute *attr,
46                                     char *buf, loff_t pos, size_t count)
47  {
48 -       struct device *dev = container_of(kobj, struct device, kobj);
49 -       struct nvmem_device *nvmem = to_nvmem_device(dev);
50 +       struct device *dev;
51 +       struct nvmem_device *nvmem;
52         int rc;
53  
54 +       if (attr->private)
55 +               dev = attr->private;
56 +       else
57 +               dev = container_of(kobj, struct device, kobj);
58 +       nvmem = to_nvmem_device(dev);
59 +
60         /* Stop the user from reading */
61         if (pos >= nvmem->size)
62                 return 0;
63 @@ -90,10 +105,16 @@ static ssize_t bin_attr_nvmem_write(stru
64                                      struct bin_attribute *attr,
65                                      char *buf, loff_t pos, size_t count)
66  {
67 -       struct device *dev = container_of(kobj, struct device, kobj);
68 -       struct nvmem_device *nvmem = to_nvmem_device(dev);
69 +       struct device *dev;
70 +       struct nvmem_device *nvmem;
71         int rc;
72  
73 +       if (attr->private)
74 +               dev = attr->private;
75 +       else
76 +               dev = container_of(kobj, struct device, kobj);
77 +       nvmem = to_nvmem_device(dev);
78 +
79         /* Stop the user from writing */
80         if (pos >= nvmem->size)
81                 return 0;
82 @@ -349,6 +370,43 @@ err:
83         return rval;
84  }
85  
86 +/*
87 + * nvmem_setup_compat() - Create an additional binary entry in
88 + * drivers sys directory, to be backwards compatible with the older
89 + * drivers/misc/eeprom drivers.
90 + */
91 +static int nvmem_setup_compat(struct nvmem_device *nvmem,
92 +                             const struct nvmem_config *config)
93 +{
94 +       int rval;
95 +
96 +       if (!config->base_dev)
97 +               return -EINVAL;
98 +
99 +       if (nvmem->read_only)
100 +               nvmem->eeprom = bin_attr_ro_root_nvmem;
101 +       else
102 +               nvmem->eeprom = bin_attr_rw_root_nvmem;
103 +       nvmem->eeprom.attr.name = "eeprom";
104 +       nvmem->eeprom.size = nvmem->size;
105 +#ifdef CONFIG_DEBUG_LOCK_ALLOC
106 +       nvmem->eeprom.attr.key = &eeprom_lock_key;
107 +#endif
108 +       nvmem->eeprom.private = &nvmem->dev;
109 +       nvmem->base_dev = config->base_dev;
110 +
111 +       rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
112 +       if (rval) {
113 +               dev_err(&nvmem->dev,
114 +                       "Failed to create eeprom binary file %d\n", rval);
115 +               return rval;
116 +       }
117 +
118 +       nvmem->flags |= FLAG_COMPAT;
119 +
120 +       return 0;
121 +}
122 +
123  /**
124   * nvmem_register() - Register a nvmem device for given nvmem_config.
125   * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
126 @@ -416,16 +474,23 @@ struct nvmem_device *nvmem_register(cons
127         dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
128  
129         rval = device_add(&nvmem->dev);
130 -       if (rval) {
131 -               ida_simple_remove(&nvmem_ida, nvmem->id);
132 -               kfree(nvmem);
133 -               return ERR_PTR(rval);
134 +       if (rval)
135 +               goto out;
136 +
137 +       if (config->compat) {
138 +               rval = nvmem_setup_compat(nvmem, config);
139 +               if (rval)
140 +                       goto out;
141         }
142  
143         if (config->cells)
144                 nvmem_add_cells(nvmem, config);
145  
146         return nvmem;
147 +out:
148 +       ida_simple_remove(&nvmem_ida, nvmem->id);
149 +       kfree(nvmem);
150 +       return ERR_PTR(rval);
151  }
152  EXPORT_SYMBOL_GPL(nvmem_register);
153  
154 @@ -445,6 +510,9 @@ int nvmem_unregister(struct nvmem_device
155         }
156         mutex_unlock(&nvmem_mutex);
157  
158 +       if (nvmem->flags & FLAG_COMPAT)
159 +               device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
160 +
161         nvmem_device_remove_all_cells(nvmem);
162         device_del(&nvmem->dev);
163  
164 --- a/include/linux/nvmem-provider.h
165 +++ b/include/linux/nvmem-provider.h
166 @@ -24,6 +24,9 @@ struct nvmem_config {
167         int                     ncells;
168         bool                    read_only;
169         bool                    root_only;
170 +       /* To be only used by old driver/misc/eeprom drivers */
171 +       bool                    compat;
172 +       struct device           *base_dev;
173  };
174  
175  #if IS_ENABLED(CONFIG_NVMEM)
176 @@ -44,5 +47,4 @@ static inline int nvmem_unregister(struc
177  }
178  
179  #endif /* CONFIG_NVMEM */
180 -
181  #endif  /* ifndef _LINUX_NVMEM_PROVIDER_H */