mirror of
https://github.com/adulau/aha.git
synced 2024-12-29 12:16:20 +00:00
spi: add support for device table matching
With this patch spi drivers can use standard spi_driver.id_table and MODULE_DEVICE_TABLE() mechanisms to bind against the devices. Just like we do with I2C drivers. This is useful when a single driver supports several variants of devices but it is not possible to detect them in run-time (like non-JEDEC chips probing in drivers/mtd/devices/m25p80.c), and when platform_data usage is overkill. This patch also makes life a lot easier on OpenFirmware platforms, since with OF we extensively use proper device IDs in modaliases. Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com> Cc: David Brownell <dbrownell@users.sourceforge.net> Cc: David Woodhouse <dwmw2@infradead.org> Cc: Grant Likely <grant.likely@secretlab.ca> Cc: Jean Delvare <khali@linux-fr.org> Cc: Ben Dooks <ben-linux@fluff.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
b5f3294f0b
commit
75368bf6c2
4 changed files with 54 additions and 2 deletions
|
@ -59,9 +59,32 @@ static struct device_attribute spi_dev_attrs[] = {
|
||||||
* and the sysfs version makes coldplug work too.
|
* and the sysfs version makes coldplug work too.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,
|
||||||
|
const struct spi_device *sdev)
|
||||||
|
{
|
||||||
|
while (id->name[0]) {
|
||||||
|
if (!strcmp(sdev->modalias, id->name))
|
||||||
|
return id;
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct spi_device_id *spi_get_device_id(const struct spi_device *sdev)
|
||||||
|
{
|
||||||
|
const struct spi_driver *sdrv = to_spi_driver(sdev->dev.driver);
|
||||||
|
|
||||||
|
return spi_match_id(sdrv->id_table, sdev);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(spi_get_device_id);
|
||||||
|
|
||||||
static int spi_match_device(struct device *dev, struct device_driver *drv)
|
static int spi_match_device(struct device *dev, struct device_driver *drv)
|
||||||
{
|
{
|
||||||
const struct spi_device *spi = to_spi_device(dev);
|
const struct spi_device *spi = to_spi_device(dev);
|
||||||
|
const struct spi_driver *sdrv = to_spi_driver(drv);
|
||||||
|
|
||||||
|
if (sdrv->id_table)
|
||||||
|
return !!spi_match_id(sdrv->id_table, spi);
|
||||||
|
|
||||||
return strcmp(spi->modalias, drv->name) == 0;
|
return strcmp(spi->modalias, drv->name) == 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -399,6 +399,16 @@ struct i2c_device_id {
|
||||||
__attribute__((aligned(sizeof(kernel_ulong_t))));
|
__attribute__((aligned(sizeof(kernel_ulong_t))));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* spi */
|
||||||
|
|
||||||
|
#define SPI_NAME_SIZE 32
|
||||||
|
|
||||||
|
struct spi_device_id {
|
||||||
|
char name[SPI_NAME_SIZE];
|
||||||
|
kernel_ulong_t driver_data /* Data private to the driver */
|
||||||
|
__attribute__((aligned(sizeof(kernel_ulong_t))));
|
||||||
|
};
|
||||||
|
|
||||||
/* dmi */
|
/* dmi */
|
||||||
enum dmi_field {
|
enum dmi_field {
|
||||||
DMI_NONE,
|
DMI_NONE,
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define __LINUX_SPI_H
|
#define __LINUX_SPI_H
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/mod_devicetable.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* INTERFACES between SPI master-side drivers and SPI infrastructure.
|
* INTERFACES between SPI master-side drivers and SPI infrastructure.
|
||||||
|
@ -86,7 +87,7 @@ struct spi_device {
|
||||||
int irq;
|
int irq;
|
||||||
void *controller_state;
|
void *controller_state;
|
||||||
void *controller_data;
|
void *controller_data;
|
||||||
char modalias[32];
|
char modalias[SPI_NAME_SIZE];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* likely need more hooks for more protocol options affecting how
|
* likely need more hooks for more protocol options affecting how
|
||||||
|
@ -145,6 +146,7 @@ struct spi_message;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct spi_driver - Host side "protocol" driver
|
* struct spi_driver - Host side "protocol" driver
|
||||||
|
* @id_table: List of SPI devices supported by this driver
|
||||||
* @probe: Binds this driver to the spi device. Drivers can verify
|
* @probe: Binds this driver to the spi device. Drivers can verify
|
||||||
* that the device is actually present, and may need to configure
|
* that the device is actually present, and may need to configure
|
||||||
* characteristics (such as bits_per_word) which weren't needed for
|
* characteristics (such as bits_per_word) which weren't needed for
|
||||||
|
@ -170,6 +172,7 @@ struct spi_message;
|
||||||
* MMC, RTC, filesystem character device nodes, and hardware monitoring.
|
* MMC, RTC, filesystem character device nodes, and hardware monitoring.
|
||||||
*/
|
*/
|
||||||
struct spi_driver {
|
struct spi_driver {
|
||||||
|
const struct spi_device_id *id_table;
|
||||||
int (*probe)(struct spi_device *spi);
|
int (*probe)(struct spi_device *spi);
|
||||||
int (*remove)(struct spi_device *spi);
|
int (*remove)(struct spi_device *spi);
|
||||||
void (*shutdown)(struct spi_device *spi);
|
void (*shutdown)(struct spi_device *spi);
|
||||||
|
@ -734,7 +737,7 @@ struct spi_board_info {
|
||||||
* controller_data goes to spi_device.controller_data,
|
* controller_data goes to spi_device.controller_data,
|
||||||
* irq is copied too
|
* irq is copied too
|
||||||
*/
|
*/
|
||||||
char modalias[32];
|
char modalias[SPI_NAME_SIZE];
|
||||||
const void *platform_data;
|
const void *platform_data;
|
||||||
void *controller_data;
|
void *controller_data;
|
||||||
int irq;
|
int irq;
|
||||||
|
@ -802,4 +805,7 @@ spi_unregister_device(struct spi_device *spi)
|
||||||
device_unregister(&spi->dev);
|
device_unregister(&spi->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern const struct spi_device_id *
|
||||||
|
spi_get_device_id(const struct spi_device *sdev);
|
||||||
|
|
||||||
#endif /* __LINUX_SPI_H */
|
#endif /* __LINUX_SPI_H */
|
||||||
|
|
|
@ -657,6 +657,15 @@ static int do_i2c_entry(const char *filename, struct i2c_device_id *id,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Looks like: S */
|
||||||
|
static int do_spi_entry(const char *filename, struct spi_device_id *id,
|
||||||
|
char *alias)
|
||||||
|
{
|
||||||
|
sprintf(alias, "%s", id->name);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct dmifield {
|
static const struct dmifield {
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
int field;
|
int field;
|
||||||
|
@ -853,6 +862,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
|
||||||
do_table(symval, sym->st_size,
|
do_table(symval, sym->st_size,
|
||||||
sizeof(struct i2c_device_id), "i2c",
|
sizeof(struct i2c_device_id), "i2c",
|
||||||
do_i2c_entry, mod);
|
do_i2c_entry, mod);
|
||||||
|
else if (sym_is(symname, "__mod_spi_device_table"))
|
||||||
|
do_table(symval, sym->st_size,
|
||||||
|
sizeof(struct spi_device_id), "spi",
|
||||||
|
do_spi_entry, mod);
|
||||||
else if (sym_is(symname, "__mod_dmi_device_table"))
|
else if (sym_is(symname, "__mod_dmi_device_table"))
|
||||||
do_table(symval, sym->st_size,
|
do_table(symval, sym->st_size,
|
||||||
sizeof(struct dmi_system_id), "dmi",
|
sizeof(struct dmi_system_id), "dmi",
|
||||||
|
|
Loading…
Reference in a new issue