Skip to content

Commit

Permalink
Merge commit 'gcl/gcl-next'
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjamin Herrenschmidt committed Jul 28, 2008
2 parents 837b41b + 284b018 commit d65d830
Show file tree
Hide file tree
Showing 9 changed files with 317 additions and 105 deletions.
6 changes: 6 additions & 0 deletions drivers/of/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions drivers/of/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
88 changes: 88 additions & 0 deletions drivers/of/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

64 changes: 3 additions & 61 deletions drivers/of/of_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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
Expand All @@ -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);
Expand Down
93 changes: 93 additions & 0 deletions drivers/of/of_spi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* 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

0 comments on commit d65d830

Please sign in to comment.