Loading drivers/of/Kconfig +6 −0 Original line number Diff line number Diff line Loading @@ -13,3 +13,9 @@ config OF_I2C depends on PPC_OF && I2C help OpenFirmware I2C accessors config OF_SPI def_tristate SPI depends on OF && PPC_OF && SPI help OpenFirmware SPI accessors drivers/of/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -2,3 +2,4 @@ obj-y = base.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o obj-$(CONFIG_OF_SPI) += of_spi.o drivers/of/base.c +88 −0 Original line number Diff line number Diff line Loading @@ -385,3 +385,91 @@ struct device_node *of_find_matching_node(struct device_node *from, return np; } EXPORT_SYMBOL(of_find_matching_node); /** * of_modalias_table: Table of explicit compatible ==> modalias mappings * * This table allows particulare compatible property values to be mapped * to modalias strings. This is useful for busses which do not directly * understand the OF device tree but are populated based on data contained * within the device tree. SPI and I2C are the two current users of this * table. * * In most cases, devices do not need to be listed in this table because * the modalias value can be derived directly from the compatible table. * However, if for any reason a value cannot be derived, then this table * provides a method to override the implicit derivation. * * At the moment, a single table is used for all bus types because it is * assumed that the data size is small and that the compatible values * should already be distinct enough to differentiate between SPI, I2C * and other devices. */ struct of_modalias_table { char *of_device; char *modalias; }; static struct of_modalias_table of_modalias_table[] = { /* Empty for now; add entries as needed */ }; /** * of_modalias_node - Lookup appropriate modalias for a device node * @node: pointer to a device tree node * @modalias: Pointer to buffer that modalias value will be copied into * @len: Length of modalias value * * Based on the value of the compatible property, this routine will determine * an appropriate modalias value for a particular device tree node. Three * separate methods are used to derive a modalias value. * * First method is to lookup the compatible value in of_modalias_table. * Second is to look for a "linux,<modalias>" entry in the compatible list * and used that for modalias. Third is to strip off the manufacturer * prefix from the first compatible entry and use the remainder as modalias * * This routine returns 0 on success */ int of_modalias_node(struct device_node *node, char *modalias, int len) { int i, cplen; const char *compatible; const char *p; /* 1. search for exception list entry */ for (i = 0; i < ARRAY_SIZE(of_modalias_table); i++) { compatible = of_modalias_table[i].of_device; if (!of_device_is_compatible(node, compatible)) continue; strlcpy(modalias, of_modalias_table[i].modalias, len); return 0; } compatible = of_get_property(node, "compatible", &cplen); if (!compatible) return -ENODEV; /* 2. search for linux,<modalias> entry */ p = compatible; while (cplen > 0) { if (!strncmp(p, "linux,", 6)) { p += 6; strlcpy(modalias, p, len); return 0; } i = strlen(p) + 1; p += i; cplen -= i; } /* 3. take first compatible entry and strip manufacturer */ p = strchr(compatible, ','); if (!p) return -ENODEV; p++; strlcpy(modalias, p, len); return 0; } EXPORT_SYMBOL_GPL(of_modalias_node); drivers/of/of_i2c.c +3 −61 Original line number Diff line number Diff line Loading @@ -16,62 +16,6 @@ #include <linux/of_i2c.h> #include <linux/module.h> struct i2c_driver_device { char *of_device; char *i2c_type; }; static struct i2c_driver_device i2c_devices[] = { }; static int of_find_i2c_driver(struct device_node *node, struct i2c_board_info *info) { int i, cplen; const char *compatible; const char *p; /* 1. search for exception list entry */ for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) { if (!of_device_is_compatible(node, i2c_devices[i].of_device)) continue; if (strlcpy(info->type, i2c_devices[i].i2c_type, I2C_NAME_SIZE) >= I2C_NAME_SIZE) return -ENOMEM; return 0; } compatible = of_get_property(node, "compatible", &cplen); if (!compatible) return -ENODEV; /* 2. search for linux,<i2c-type> entry */ p = compatible; while (cplen > 0) { if (!strncmp(p, "linux,", 6)) { p += 6; if (strlcpy(info->type, p, I2C_NAME_SIZE) >= I2C_NAME_SIZE) return -ENOMEM; return 0; } i = strlen(p) + 1; p += i; cplen -= i; } /* 3. take fist compatible entry and strip manufacturer */ p = strchr(compatible, ','); if (!p) return -ENODEV; p++; if (strlcpy(info->type, p, I2C_NAME_SIZE) >= I2C_NAME_SIZE) return -ENOMEM; return 0; } void of_register_i2c_devices(struct i2c_adapter *adap, struct device_node *adap_node) { Loading @@ -83,6 +27,9 @@ void of_register_i2c_devices(struct i2c_adapter *adap, const u32 *addr; int len; if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) continue; addr = of_get_property(node, "reg", &len); if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) { printk(KERN_ERR Loading @@ -92,11 +39,6 @@ void of_register_i2c_devices(struct i2c_adapter *adap, info.irq = irq_of_parse_and_map(node, 0); if (of_find_i2c_driver(node, &info) < 0) { irq_dispose_mapping(info.irq); continue; } info.addr = *addr; request_module(info.type); Loading drivers/of/of_spi.c 0 → 100644 +93 −0 Original line number Diff line number Diff line /* * SPI OF support routines * Copyright (C) 2008 Secret Lab Technologies Ltd. * * Support routines for deriving SPI device attachments from the device * tree. */ #include <linux/of.h> #include <linux/device.h> #include <linux/spi/spi.h> #include <linux/of_spi.h> /** * of_register_spi_devices - Register child devices onto the SPI bus * @master: Pointer to spi_master device * @np: parent node of SPI device nodes * * Registers an spi_device for each child node of 'np' which has a 'reg' * property. */ void of_register_spi_devices(struct spi_master *master, struct device_node *np) { struct spi_device *spi; struct device_node *nc; const u32 *prop; int rc; int len; for_each_child_of_node(np, nc) { /* Alloc an spi_device */ spi = spi_alloc_device(master); if (!spi) { dev_err(&master->dev, "spi_device alloc error for %s\n", nc->full_name); spi_dev_put(spi); continue; } /* Select device driver */ if (of_modalias_node(nc, spi->modalias, sizeof(spi->modalias)) < 0) { dev_err(&master->dev, "cannot find modalias for %s\n", nc->full_name); spi_dev_put(spi); continue; } /* Device address */ prop = of_get_property(nc, "reg", &len); if (!prop || len < sizeof(*prop)) { dev_err(&master->dev, "%s has no 'reg' property\n", nc->full_name); spi_dev_put(spi); continue; } spi->chip_select = *prop; /* Mode (clock phase/polarity/etc.) */ if (of_find_property(nc, "spi-cpha", NULL)) spi->mode |= SPI_CPHA; if (of_find_property(nc, "spi-cpol", NULL)) spi->mode |= SPI_CPOL; /* Device speed */ prop = of_get_property(nc, "spi-max-frequency", &len); if (!prop || len < sizeof(*prop)) { dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n", nc->full_name); spi_dev_put(spi); continue; } spi->max_speed_hz = *prop; /* IRQ */ spi->irq = irq_of_parse_and_map(nc, 0); /* Store a pointer to the node in the device structure */ of_node_get(nc); spi->dev.archdata.of_node = nc; /* Register the new device */ request_module(spi->modalias); rc = spi_add_device(spi); if (rc) { dev_err(&master->dev, "spi_device register error %s\n", nc->full_name); spi_dev_put(spi); } } } EXPORT_SYMBOL(of_register_spi_devices); Loading
drivers/of/Kconfig +6 −0 Original line number Diff line number Diff line Loading @@ -13,3 +13,9 @@ config OF_I2C depends on PPC_OF && I2C help OpenFirmware I2C accessors config OF_SPI def_tristate SPI depends on OF && PPC_OF && SPI help OpenFirmware SPI accessors
drivers/of/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -2,3 +2,4 @@ obj-y = base.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o obj-$(CONFIG_OF_SPI) += of_spi.o
drivers/of/base.c +88 −0 Original line number Diff line number Diff line Loading @@ -385,3 +385,91 @@ struct device_node *of_find_matching_node(struct device_node *from, return np; } EXPORT_SYMBOL(of_find_matching_node); /** * of_modalias_table: Table of explicit compatible ==> modalias mappings * * This table allows particulare compatible property values to be mapped * to modalias strings. This is useful for busses which do not directly * understand the OF device tree but are populated based on data contained * within the device tree. SPI and I2C are the two current users of this * table. * * In most cases, devices do not need to be listed in this table because * the modalias value can be derived directly from the compatible table. * However, if for any reason a value cannot be derived, then this table * provides a method to override the implicit derivation. * * At the moment, a single table is used for all bus types because it is * assumed that the data size is small and that the compatible values * should already be distinct enough to differentiate between SPI, I2C * and other devices. */ struct of_modalias_table { char *of_device; char *modalias; }; static struct of_modalias_table of_modalias_table[] = { /* Empty for now; add entries as needed */ }; /** * of_modalias_node - Lookup appropriate modalias for a device node * @node: pointer to a device tree node * @modalias: Pointer to buffer that modalias value will be copied into * @len: Length of modalias value * * Based on the value of the compatible property, this routine will determine * an appropriate modalias value for a particular device tree node. Three * separate methods are used to derive a modalias value. * * First method is to lookup the compatible value in of_modalias_table. * Second is to look for a "linux,<modalias>" entry in the compatible list * and used that for modalias. Third is to strip off the manufacturer * prefix from the first compatible entry and use the remainder as modalias * * This routine returns 0 on success */ int of_modalias_node(struct device_node *node, char *modalias, int len) { int i, cplen; const char *compatible; const char *p; /* 1. search for exception list entry */ for (i = 0; i < ARRAY_SIZE(of_modalias_table); i++) { compatible = of_modalias_table[i].of_device; if (!of_device_is_compatible(node, compatible)) continue; strlcpy(modalias, of_modalias_table[i].modalias, len); return 0; } compatible = of_get_property(node, "compatible", &cplen); if (!compatible) return -ENODEV; /* 2. search for linux,<modalias> entry */ p = compatible; while (cplen > 0) { if (!strncmp(p, "linux,", 6)) { p += 6; strlcpy(modalias, p, len); return 0; } i = strlen(p) + 1; p += i; cplen -= i; } /* 3. take first compatible entry and strip manufacturer */ p = strchr(compatible, ','); if (!p) return -ENODEV; p++; strlcpy(modalias, p, len); return 0; } EXPORT_SYMBOL_GPL(of_modalias_node);
drivers/of/of_i2c.c +3 −61 Original line number Diff line number Diff line Loading @@ -16,62 +16,6 @@ #include <linux/of_i2c.h> #include <linux/module.h> struct i2c_driver_device { char *of_device; char *i2c_type; }; static struct i2c_driver_device i2c_devices[] = { }; static int of_find_i2c_driver(struct device_node *node, struct i2c_board_info *info) { int i, cplen; const char *compatible; const char *p; /* 1. search for exception list entry */ for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) { if (!of_device_is_compatible(node, i2c_devices[i].of_device)) continue; if (strlcpy(info->type, i2c_devices[i].i2c_type, I2C_NAME_SIZE) >= I2C_NAME_SIZE) return -ENOMEM; return 0; } compatible = of_get_property(node, "compatible", &cplen); if (!compatible) return -ENODEV; /* 2. search for linux,<i2c-type> entry */ p = compatible; while (cplen > 0) { if (!strncmp(p, "linux,", 6)) { p += 6; if (strlcpy(info->type, p, I2C_NAME_SIZE) >= I2C_NAME_SIZE) return -ENOMEM; return 0; } i = strlen(p) + 1; p += i; cplen -= i; } /* 3. take fist compatible entry and strip manufacturer */ p = strchr(compatible, ','); if (!p) return -ENODEV; p++; if (strlcpy(info->type, p, I2C_NAME_SIZE) >= I2C_NAME_SIZE) return -ENOMEM; return 0; } void of_register_i2c_devices(struct i2c_adapter *adap, struct device_node *adap_node) { Loading @@ -83,6 +27,9 @@ void of_register_i2c_devices(struct i2c_adapter *adap, const u32 *addr; int len; if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) continue; addr = of_get_property(node, "reg", &len); if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) { printk(KERN_ERR Loading @@ -92,11 +39,6 @@ void of_register_i2c_devices(struct i2c_adapter *adap, info.irq = irq_of_parse_and_map(node, 0); if (of_find_i2c_driver(node, &info) < 0) { irq_dispose_mapping(info.irq); continue; } info.addr = *addr; request_module(info.type); Loading
drivers/of/of_spi.c 0 → 100644 +93 −0 Original line number Diff line number Diff line /* * SPI OF support routines * Copyright (C) 2008 Secret Lab Technologies Ltd. * * Support routines for deriving SPI device attachments from the device * tree. */ #include <linux/of.h> #include <linux/device.h> #include <linux/spi/spi.h> #include <linux/of_spi.h> /** * of_register_spi_devices - Register child devices onto the SPI bus * @master: Pointer to spi_master device * @np: parent node of SPI device nodes * * Registers an spi_device for each child node of 'np' which has a 'reg' * property. */ void of_register_spi_devices(struct spi_master *master, struct device_node *np) { struct spi_device *spi; struct device_node *nc; const u32 *prop; int rc; int len; for_each_child_of_node(np, nc) { /* Alloc an spi_device */ spi = spi_alloc_device(master); if (!spi) { dev_err(&master->dev, "spi_device alloc error for %s\n", nc->full_name); spi_dev_put(spi); continue; } /* Select device driver */ if (of_modalias_node(nc, spi->modalias, sizeof(spi->modalias)) < 0) { dev_err(&master->dev, "cannot find modalias for %s\n", nc->full_name); spi_dev_put(spi); continue; } /* Device address */ prop = of_get_property(nc, "reg", &len); if (!prop || len < sizeof(*prop)) { dev_err(&master->dev, "%s has no 'reg' property\n", nc->full_name); spi_dev_put(spi); continue; } spi->chip_select = *prop; /* Mode (clock phase/polarity/etc.) */ if (of_find_property(nc, "spi-cpha", NULL)) spi->mode |= SPI_CPHA; if (of_find_property(nc, "spi-cpol", NULL)) spi->mode |= SPI_CPOL; /* Device speed */ prop = of_get_property(nc, "spi-max-frequency", &len); if (!prop || len < sizeof(*prop)) { dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n", nc->full_name); spi_dev_put(spi); continue; } spi->max_speed_hz = *prop; /* IRQ */ spi->irq = irq_of_parse_and_map(nc, 0); /* Store a pointer to the node in the device structure */ of_node_get(nc); spi->dev.archdata.of_node = nc; /* Register the new device */ request_module(spi->modalias); rc = spi_add_device(spi); if (rc) { dev_err(&master->dev, "spi_device register error %s\n", nc->full_name); spi_dev_put(spi); } } } EXPORT_SYMBOL(of_register_spi_devices);