Merge commit 'gcl/gcl-next'

This commit is contained in:
Benjamin Herrenschmidt 2008-07-28 16:30:40 +10:00
commit d65d830ca0
9 changed files with 317 additions and 105 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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)
{
@ -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
@ -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);

93
drivers/of/of_spi.c Normal file
View File

@ -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);

View File

@ -178,6 +178,96 @@ struct boardinfo {
static LIST_HEAD(board_list);
static DEFINE_MUTEX(board_lock);
/**
* spi_alloc_device - Allocate a new SPI device
* @master: Controller to which device is connected
* Context: can sleep
*
* Allows a driver to allocate and initialize a spi_device without
* registering it immediately. This allows a driver to directly
* fill the spi_device with device parameters before calling
* spi_add_device() on it.
*
* Caller is responsible to call spi_add_device() on the returned
* spi_device structure to add it to the SPI master. If the caller
* needs to discard the spi_device without adding it, then it should
* call spi_dev_put() on it.
*
* Returns a pointer to the new device, or NULL.
*/
struct spi_device *spi_alloc_device(struct spi_master *master)
{
struct spi_device *spi;
struct device *dev = master->dev.parent;
if (!spi_master_get(master))
return NULL;
spi = kzalloc(sizeof *spi, GFP_KERNEL);
if (!spi) {
dev_err(dev, "cannot alloc spi_device\n");
spi_master_put(master);
return NULL;
}
spi->master = master;
spi->dev.parent = dev;
spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release;
device_initialize(&spi->dev);
return spi;
}
EXPORT_SYMBOL_GPL(spi_alloc_device);
/**
* spi_add_device - Add spi_device allocated with spi_alloc_device
* @spi: spi_device to register
*
* Companion function to spi_alloc_device. Devices allocated with
* spi_alloc_device can be added onto the spi bus with this function.
*
* Returns 0 on success; non-zero on failure
*/
int spi_add_device(struct spi_device *spi)
{
struct device *dev = spi->master->dev.parent;
int status;
/* Chipselects are numbered 0..max; validate. */
if (spi->chip_select >= spi->master->num_chipselect) {
dev_err(dev, "cs%d >= max %d\n",
spi->chip_select,
spi->master->num_chipselect);
return -EINVAL;
}
/* Set the bus ID string */
snprintf(spi->dev.bus_id, sizeof spi->dev.bus_id,
"%s.%u", spi->master->dev.bus_id,
spi->chip_select);
/* drivers may modify this initial i/o setup */
status = spi->master->setup(spi);
if (status < 0) {
dev_err(dev, "can't %s %s, status %d\n",
"setup", spi->dev.bus_id, status);
return status;
}
/* driver core catches callers that misbehave by defining
* devices that already exist.
*/
status = device_add(&spi->dev);
if (status < 0) {
dev_err(dev, "can't %s %s, status %d\n",
"add", spi->dev.bus_id, status);
return status;
}
dev_dbg(dev, "registered child %s\n", spi->dev.bus_id);
return 0;
}
EXPORT_SYMBOL_GPL(spi_add_device);
/**
* spi_new_device - instantiate one new SPI device
@ -197,7 +287,6 @@ struct spi_device *spi_new_device(struct spi_master *master,
struct spi_board_info *chip)
{
struct spi_device *proxy;
struct device *dev = master->dev.parent;
int status;
/* NOTE: caller did any chip->bus_num checks necessary.
@ -207,66 +296,28 @@ struct spi_device *spi_new_device(struct spi_master *master,
* suggests syslogged diagnostics are best here (ugh).
*/
/* Chipselects are numbered 0..max; validate. */
if (chip->chip_select >= master->num_chipselect) {
dev_err(dev, "cs%d > max %d\n",
chip->chip_select,
master->num_chipselect);
return NULL;
}
if (!spi_master_get(master))
proxy = spi_alloc_device(master);
if (!proxy)
return NULL;
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
if (!proxy) {
dev_err(dev, "can't alloc dev for cs%d\n",
chip->chip_select);
goto fail;
}
proxy->master = master;
proxy->chip_select = chip->chip_select;
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->irq = chip->irq;
strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
"%s.%u", master->dev.bus_id,
chip->chip_select);
proxy->dev.parent = dev;
proxy->dev.bus = &spi_bus_type;
proxy->dev.platform_data = (void *) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
proxy->dev.release = spidev_release;
/* drivers may modify this initial i/o setup */
status = master->setup(proxy);
status = spi_add_device(proxy);
if (status < 0) {
dev_err(dev, "can't %s %s, status %d\n",
"setup", proxy->dev.bus_id, status);
goto fail;
spi_dev_put(proxy);
return NULL;
}
/* driver core catches callers that misbehave by defining
* devices that already exist.
*/
status = device_register(&proxy->dev);
if (status < 0) {
dev_err(dev, "can't %s %s, status %d\n",
"add", proxy->dev.bus_id, status);
goto fail;
}
dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id);
return proxy;
fail:
spi_master_put(master);
kfree(proxy);
return NULL;
}
EXPORT_SYMBOL_GPL(spi_new_device);

View File

@ -70,5 +70,6 @@ extern int of_n_addr_cells(struct device_node *np);
extern int of_n_size_cells(struct device_node *np);
extern const struct of_device_id *of_match_node(
const struct of_device_id *matches, const struct device_node *node);
extern int of_modalias_node(struct device_node *node, char *modalias, int len);
#endif /* _LINUX_OF_H */

18
include/linux/of_spi.h Normal file
View File

@ -0,0 +1,18 @@
/*
* OpenFirmware SPI support routines
* Copyright (C) 2008 Secret Lab Technologies Ltd.
*
* Support routines for deriving SPI device attachments from the device
* tree.
*/
#ifndef __LINUX_OF_SPI_H
#define __LINUX_OF_SPI_H
#include <linux/of.h>
#include <linux/spi/spi.h>
extern void of_register_spi_devices(struct spi_master *master,
struct device_node *np);
#endif /* __LINUX_OF_SPI */

View File

@ -778,7 +778,19 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
* use spi_new_device() to describe each device. You can also call
* spi_unregister_device() to start making that device vanish, but
* normally that would be handled by spi_unregister_master().
*
* You can also use spi_alloc_device() and spi_add_device() to use a two
* stage registration sequence for each spi_device. This gives the caller
* some more control over the spi_device structure before it is registered,
* but requires that caller to initialize fields that would otherwise
* be defined using the board info.
*/
extern struct spi_device *
spi_alloc_device(struct spi_master *master);
extern int
spi_add_device(struct spi_device *spi);
extern struct spi_device *
spi_new_device(struct spi_master *, struct spi_board_info *);