[linux-yocto] [PATCH 06/12] of: Add of_memory_accessor to map device tree node to memory accessor functions.
Chandrakala Chavva
cchavva.cavm at gmail.com
Thu Jan 29 07:32:05 PST 2015
From: Abhishek Paliwal <abhishek.paliwal at aricent.com>
From: Aaron Williams <aaron.williams at cavium.com>
Currently there is no easy way to map a device tree node to a memory
accessor function for devices like I2C EEPROMs. For example, the Vitesse
vsc848x 10G PHY driver needs to be able to use the I2C at24 serial EEPROM
memory accessor function in order to read the SFP+ eeprom.
This provides a way where the vsc848x module can parse its device tree and
easily gain the accessor functions for the eeprom through a phandle.
This may be useful for any module which provides memory accessor functions.
Signed-off-by: Aaron Williams <aaron.williams at cavium.com>
Signed-off-by: Leonid Rosenboim <lrosenboim at caviumnetworks.com>
Signed-off-by: Abhishek Paliwal <abhishek.paliwal at aricent.com>
---
drivers/of/Kconfig | 7 ++
drivers/of/Makefile | 1 +
drivers/of/of_memory_accessor.c | 192 ++++++++++++++++++++++++++++++++++++++++
include/linux/of_memory_accessor.h | 71 ++++++++++++++
4 files changed, 271 insertions(+)
create mode 100644 drivers/of/of_memory_accessor.c
create mode 100644 include/linux/of_memory_accessor.h
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index c6973f1..020cdbd 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -75,4 +75,11 @@ config OF_MTD
depends on MTD
def_bool y
+config OF_MEMORY_ACCESSOR
+ def_bool y
+ depends on OF_I2C || OF_SPI
+ help
+ OpenFirmware memory accessor support for accessing devices like
+ i2c and SPI eeproms.
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index efd0510..f05c31a 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
+obj-$(CONFIG_OF_MEMORY_ACCESSOR) += of_memory_accessor.o
diff --git a/drivers/of/of_memory_accessor.c b/drivers/of/of_memory_accessor.c
new file mode 100644
index 0000000..25146a2
--- /dev/null
+++ b/drivers/of/of_memory_accessor.c
@@ -0,0 +1,192 @@
+/*
+ * Memory accessor OF helpers
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012 Cavium Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_memory_accessor.h>
+#include <linux/list.h>
+#include <linux/memory.h>
+
+struct of_macc_entry {
+ struct list_head list;
+ struct device *dev;
+ struct memory_accessor *macc;
+ int ref;
+};
+
+static DEFINE_MUTEX(lock);
+static LIST_HEAD(macc_list);
+
+/**
+ * Adds a mapping of a device node to a memory accessor
+ *
+ * @param[in] dev - device
+ * @param[in] macc - memory accessor
+ *
+ * @returns 0 for success or -ENOMEM
+ */
+int of_memory_accessor_register(struct device *dev,
+ struct memory_accessor *macc)
+{
+ struct of_macc_entry *mentry;
+
+ mentry = kmalloc(sizeof(*mentry), GFP_KERNEL);
+ if (mentry == NULL)
+ return -ENOMEM;
+
+ mentry->dev = dev;
+ mentry->macc = macc;
+ mentry->ref = 0;
+
+ mutex_lock(&lock);
+
+ list_add(&(mentry->list), &macc_list);
+
+ mutex_unlock(&lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(of_memory_accessor_register);
+
+/**
+ * removes the mapping of a device node to a memory accessor
+ *
+ * @param[in] devnode - device node to remove
+ *
+ * @returns 0 for success or -ENODEV if device node not found, -EBUSY if still
+ * in use
+ */
+
+int of_memory_accessor_remove(struct device *dev)
+{
+ struct of_macc_entry *mentry;
+ struct list_head *pos, *q;
+ int ret = -ENODEV;
+
+ mutex_lock(&lock);
+
+ list_for_each_safe(pos, q, &macc_list) {
+ mentry = list_entry(pos, struct of_macc_entry, list);
+ if (mentry->dev == dev) {
+ if (mentry->ref > 0) {
+ ret = -EBUSY;
+ goto done;
+ }
+ list_del(pos);
+ kfree(mentry);
+ ret = 0;
+ goto done;
+ }
+ }
+
+ /* Not found */
+done:
+ mutex_unlock(&lock);
+ return ret;
+}
+EXPORT_SYMBOL(of_memory_accessor_remove);
+
+/**
+ * Returns the memory accessor for a device node and increments a reference
+ * count
+ *
+ * @param[in] devnode - device node to look up
+ *
+ * @returns memory accessor for device node or NULL if none found.
+ */
+struct memory_accessor *
+of_memory_accessor_get(const struct device_node *devnode)
+{
+ struct of_macc_entry *mentry;
+ struct list_head *pos;
+ struct memory_accessor *macc = NULL;
+
+ mutex_lock(&lock);
+
+ list_for_each(pos, &macc_list) {
+ mentry = list_entry(pos, struct of_macc_entry, list);
+ if (mentry->dev->of_node == devnode) {
+ macc = mentry->macc;
+ if (!mentry->ref) {
+ if (!try_module_get(mentry->dev->driver->owner)) {
+ macc = NULL;
+ pr_info("Warning: module for %s not found!",
+ mentry->dev->of_node->full_name);
+ }
+ }
+ mentry->ref++;
+ goto done;
+ }
+ }
+done:
+ mutex_unlock(&lock);
+ return macc;
+}
+EXPORT_SYMBOL(of_memory_accessor_get);
+
+/**
+ * Decrements the reference count for the memory accessor attached to the
+ * device node.
+ *
+ * @param[in] devnode - device node to look up
+ *
+ * @returns 0 for success or -ENODEV if the device node was not found.
+ */
+int of_memory_accessor_put(const struct device_node *devnode)
+{
+ struct of_macc_entry *mentry;
+ struct list_head *pos;
+ int ret = -ENODEV;
+
+ mutex_lock(&lock);
+ list_for_each(pos, &macc_list) {
+ mentry = list_entry(pos, struct of_macc_entry, list);
+ if (mentry->dev->of_node == devnode) {
+ if (mentry->ref > 0)
+ mentry->ref--;
+ if (!mentry->ref)
+ module_put(mentry->dev->driver->owner);
+
+ module_put(THIS_MODULE);
+ ret = 0;
+ goto done;
+ }
+ }
+done:
+ mutex_unlock(&lock);
+ return ret;
+}
+EXPORT_SYMBOL(of_memory_accessor_put);
+
+static void __exit of_memory_accessor_exit(void)
+{
+ struct of_macc_entry *mentry;
+ struct list_head *pos, *q;
+
+ list_for_each_safe(pos, q, &macc_list) {
+ mentry = list_entry(pos, struct of_macc_entry, list);
+ if (mentry->ref)
+ module_put(mentry->dev->driver->owner);
+ list_del(pos);
+ kfree(mentry);
+ }
+
+ /* Not found */
+ mutex_destroy(&lock);
+ list_del(&macc_list);
+}
+module_exit(of_memory_accessor_exit);
+
+MODULE_DESCRIPTION("Driver for mapping device nodes to memory accessors");
+MODULE_AUTHOR("Aaron Williams");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/of_memory_accessor.h b/include/linux/of_memory_accessor.h
new file mode 100644
index 0000000..939a0ae
--- /dev/null
+++ b/include/linux/of_memory_accessor.h
@@ -0,0 +1,71 @@
+#ifndef _LINUX_OF_MEMORY_ACCESSOR_H
+#define _LINUX_OF_MEMORY_ACCESSOR_H
+/*
+ * Memory accessor OF helpers
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012 Cavium Inc.
+ */
+
+#include <linux/of.h>
+#include <linux/memory.h>
+
+/**
+ * Adds a mapping of a device node to a memory accessor
+ *
+ * @param[in] dev - device
+ * @param[in] macc - memory accessor
+ *
+ * @returns 0 for success or -ENOMEM
+ */
+#ifdef CONFIG_OF_MEMORY_ACCESSOR
+int of_memory_accessor_register(struct device *dev,
+ struct memory_accessor *macc);
+#else
+static inline int of_memory_accessor_register(struct device *dev,
+ struct memory_accessor *macc)
+{
+ return 0;
+}
+#endif
+
+/**
+ * removes the mapping of a device node to a memory accessor
+ *
+ * @param[in] devnode - device node to remove
+ *
+ * @returns 0 for success or 1 if device node not found
+ */
+#ifdef CONFIG_OF_MEMORY_ACCESSOR
+int of_memory_accessor_remove(struct device *dev);
+#else
+static inline int of_memory_accessor_remove(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+/**
+ * Returns the memory accessor for a device node
+ *
+ * @param[in] devnode - device node to look up
+ *
+ * @returns memory accessor for device node or NULL if none found.
+ */
+struct memory_accessor *
+of_memory_accessor_get(const struct device_node *devnode);
+
+/**
+ * Decrements the reference count for the memory accessor attached to the
+ * device node.
+ *
+ * @param[in] devnode - device node to look up
+ *
+ * @returns 0 for success or -1 if the device node was not found.
+ */
+int of_memory_accessor_put(const struct device_node *devnode);
+
+#endif /* _LINUX_OF_MEMORY_ACCESSOR_H */
--
1.8.1.4
More information about the linux-yocto
mailing list