On 05/21/2015 09:43 AM, Srinivas Kandagatla wrote:Yep, not required.
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
new file mode 100644
index 0000000..6c2f0b1
--- /dev/null
+++ b/drivers/nvmem/core.c
@@ -0,0 +1,398 @@
+/*
+ * nvmem framework core.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxx>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@xxxxxxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/nvmem-provider.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
Is this include used?
Sure,+
+static int of_nvmem_match(struct device *dev, const void *nvmem_np)
+{
+ return dev->of_node == nvmem_np;
+}
+
+static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
const?
Yep, Will remove it.
+{
+ struct device *d;
+
+ if (!nvmem_np)
+ return NULL;
+
+ d = class_find_device(&nvmem_class, NULL, nvmem_np, of_nvmem_match);
+
+ return d ? to_nvmem_device(d) : NULL;
+}
+
+static struct nvmem_cell *nvmem_find_cell(const char *cell_id)
+{
+ struct nvmem_cell *p;
+
+ list_for_each_entry(p, &nvmem_cells, node) {
Unnecessary braces.
Yes.
+ if (p && !strcmp(p->name, cell_id))
+ return p;
+ }
+
+ return NULL;
+}
+
+static void nvmem_cell_drop(struct nvmem_cell *cell)
+{
+ mutex_lock(&nvmem_cells_mutex);
+ list_del(&cell->node);
+ mutex_unlock(&nvmem_cells_mutex);
+ kfree(cell);
+}
+
+static void nvmem_device_remove_all_cells(struct nvmem_device *nvmem)
+{
+ struct nvmem_cell *cell = NULL;
Unnecessary initialization
This is temporary array, I did this on intention, to make it easy to kfree cells which are found invalid at runtime.
+ struct list_head *p, *n;[..]
+
+ list_for_each_safe(p, n, &nvmem_cells) {
+ cell = list_entry(p, struct nvmem_cell, node);
+ if (cell->nvmem == nvmem)
+ nvmem_cell_drop(cell);
+ }
+
+static int nvmem_add_cells(struct nvmem_device *nvmem,
+ struct nvmem_config *cfg)
+{
+ struct nvmem_cell **cells;
+ struct nvmem_cell_info *info = cfg->cells;
+ int i, rval;
+
+ cells = kzalloc(sizeof(*cells) * cfg->ncells, GFP_KERNEL);
kcalloc
Yep.
+ if (!cells)
+ return -ENOMEM;
+
+ for (i = 0; i < cfg->ncells; i++) {
+ cells[i] = kzalloc(sizeof(struct nvmem_cell), GFP_KERNEL);
sizeof(**cells) ?
Yes, I will fix it.
+
+/**
+ * nvmem_register(): Register a nvmem device for given nvmem.
+ * Also creates an binary entry in /sys/class/nvmem/dev-name/nvmem
+ *
+ * @nvmem: nvmem device that needs to be created
You mean @config?
We can do that, but I wanted to make the sysfs and dev entries more readable than just nvmem0, nvmem1...+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ nvmem->dev.of_node = config->dev->of_node;
+ dev_set_name(&nvmem->dev, "%s%d",
+ config->name ? : "nvmem", config->id);
It may be better to always name it nvmem%d so that we don't allow the
possibility of conflicts.
Thanks for spotting, you are correct, I need to add read_only flag to nvmem_config too.
+
+ nvmem->read_only = of_property_read_bool(nvmem->dev.of_node,
+ "read-only");
What if we're not using DT? How would we specify read_only?
+
+ device_initialize(&nvmem->dev);
+
+ dev_dbg(&nvmem->dev, "Registering nvmem device %s\n",
+ dev_name(&nvmem->dev));
+
+ rval = device_add(&nvmem->dev);
+ if (rval) {
+ ida_simple_remove(&nvmem_ida, nvmem->id);
+ kfree(nvmem);
+ return ERR_PTR(rval);
+ }
+
+ /* update sysfs attributes */
+ if (nvmem->read_only)
+ sysfs_update_group(&nvmem->dev.kobj, &nvmem_bin_ro_group);
It would be nice if this could be done before the device was registered.
Perhaps have two device_types, one for read-only and one for read/write?
The consumer api is get/put style, so consumers who already have references to the provider, removing provider forcefully might lead to dangling pointer. Having said that I can give a try and see how it looks.
+
+ */
+int nvmem_unregister(struct nvmem_device *nvmem)
+{
+ mutex_lock(&nvmem_mutex);
+ if (nvmem->users) {
+ mutex_unlock(&nvmem_mutex);
+ return -EBUSY;
Hmm... that doesn't seem nice. Typically when something is unregistered
we have to pull the rug out from underneath the users and start
returning errors to them. The provider needs to be free to unregister
because it's been forcibly removed. So really this function should
return void.
yep, will do that.+ }
+ mutex_unlock(&nvmem_mutex);
+
+ nvmem_device_remove_all_cells(nvmem);
+ device_del(&nvmem->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nvmem_unregister);
+
+static int nvmem_init(void)
__init? And __exit on nvmem_exit?
Do you remember any conversation on the list about this? I could not find it on web.
+{
+ return class_register(&nvmem_class);
I thought class was on the way out? Aren't we supposed to use bus types
for new stuff?
--