diff options
author | Anton Vorontsov <avorontsov@ru.mvista.com> | 2009-09-22 19:46:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 10:39:43 -0400 |
commit | 75368bf6c2876d8f33abfe77aa3864869a3893eb (patch) | |
tree | 97a543508a8aeb45646d059f8cdd561ae0a76ef2 | |
parent | b5f3294f0be5496aec01e5aa709a5fab8bb2f225 (diff) |
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>
-rw-r--r-- | drivers/spi/spi.c | 23 | ||||
-rw-r--r-- | include/linux/mod_devicetable.h | 10 | ||||
-rw-r--r-- | include/linux/spi/spi.h | 10 | ||||
-rw-r--r-- | scripts/mod/file2alias.c | 13 |
4 files changed, 54 insertions, 2 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 70845ccd85c3..8518a6eb63f3 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -59,9 +59,32 @@ static struct device_attribute spi_dev_attrs[] = { | |||
59 | * and the sysfs version makes coldplug work too. | 59 | * and the sysfs version makes coldplug work too. |
60 | */ | 60 | */ |
61 | 61 | ||
62 | static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, | ||
63 | const struct spi_device *sdev) | ||
64 | { | ||
65 | while (id->name[0]) { | ||
66 | if (!strcmp(sdev->modalias, id->name)) | ||
67 | return id; | ||
68 | id++; | ||
69 | } | ||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | const struct spi_device_id *spi_get_device_id(const struct spi_device *sdev) | ||
74 | { | ||
75 | const struct spi_driver *sdrv = to_spi_driver(sdev->dev.driver); | ||
76 | |||
77 | return spi_match_id(sdrv->id_table, sdev); | ||
78 | } | ||
79 | EXPORT_SYMBOL_GPL(spi_get_device_id); | ||
80 | |||
62 | static int spi_match_device(struct device *dev, struct device_driver *drv) | 81 | static int spi_match_device(struct device *dev, struct device_driver *drv) |
63 | { | 82 | { |
64 | const struct spi_device *spi = to_spi_device(dev); | 83 | const struct spi_device *spi = to_spi_device(dev); |
84 | const struct spi_driver *sdrv = to_spi_driver(drv); | ||
85 | |||
86 | if (sdrv->id_table) | ||
87 | return !!spi_match_id(sdrv->id_table, spi); | ||
65 | 88 | ||
66 | return strcmp(spi->modalias, drv->name) == 0; | 89 | return strcmp(spi->modalias, drv->name) == 0; |
67 | } | 90 | } |
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 1bf5900ffe43..b34f1ef2f1fe 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h | |||
@@ -399,6 +399,16 @@ struct i2c_device_id { | |||
399 | __attribute__((aligned(sizeof(kernel_ulong_t)))); | 399 | __attribute__((aligned(sizeof(kernel_ulong_t)))); |
400 | }; | 400 | }; |
401 | 401 | ||
402 | /* spi */ | ||
403 | |||
404 | #define SPI_NAME_SIZE 32 | ||
405 | |||
406 | struct spi_device_id { | ||
407 | char name[SPI_NAME_SIZE]; | ||
408 | kernel_ulong_t driver_data /* Data private to the driver */ | ||
409 | __attribute__((aligned(sizeof(kernel_ulong_t)))); | ||
410 | }; | ||
411 | |||
402 | /* dmi */ | 412 | /* dmi */ |
403 | enum dmi_field { | 413 | enum dmi_field { |
404 | DMI_NONE, | 414 | DMI_NONE, |
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index eb25cedb995b..e2051f39f6a8 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #define __LINUX_SPI_H | 20 | #define __LINUX_SPI_H |
21 | 21 | ||
22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
23 | #include <linux/mod_devicetable.h> | ||
23 | 24 | ||
24 | /* | 25 | /* |
25 | * INTERFACES between SPI master-side drivers and SPI infrastructure. | 26 | * INTERFACES between SPI master-side drivers and SPI infrastructure. |
@@ -86,7 +87,7 @@ struct spi_device { | |||
86 | int irq; | 87 | int irq; |
87 | void *controller_state; | 88 | void *controller_state; |
88 | void *controller_data; | 89 | void *controller_data; |
89 | char modalias[32]; | 90 | char modalias[SPI_NAME_SIZE]; |
90 | 91 | ||
91 | /* | 92 | /* |
92 | * likely need more hooks for more protocol options affecting how | 93 | * likely need more hooks for more protocol options affecting how |
@@ -145,6 +146,7 @@ struct spi_message; | |||
145 | 146 | ||
146 | /** | 147 | /** |
147 | * struct spi_driver - Host side "protocol" driver | 148 | * struct spi_driver - Host side "protocol" driver |
149 | * @id_table: List of SPI devices supported by this driver | ||
148 | * @probe: Binds this driver to the spi device. Drivers can verify | 150 | * @probe: Binds this driver to the spi device. Drivers can verify |
149 | * that the device is actually present, and may need to configure | 151 | * that the device is actually present, and may need to configure |
150 | * characteristics (such as bits_per_word) which weren't needed for | 152 | * characteristics (such as bits_per_word) which weren't needed for |
@@ -170,6 +172,7 @@ struct spi_message; | |||
170 | * MMC, RTC, filesystem character device nodes, and hardware monitoring. | 172 | * MMC, RTC, filesystem character device nodes, and hardware monitoring. |
171 | */ | 173 | */ |
172 | struct spi_driver { | 174 | struct spi_driver { |
175 | const struct spi_device_id *id_table; | ||
173 | int (*probe)(struct spi_device *spi); | 176 | int (*probe)(struct spi_device *spi); |
174 | int (*remove)(struct spi_device *spi); | 177 | int (*remove)(struct spi_device *spi); |
175 | void (*shutdown)(struct spi_device *spi); | 178 | void (*shutdown)(struct spi_device *spi); |
@@ -734,7 +737,7 @@ struct spi_board_info { | |||
734 | * controller_data goes to spi_device.controller_data, | 737 | * controller_data goes to spi_device.controller_data, |
735 | * irq is copied too | 738 | * irq is copied too |
736 | */ | 739 | */ |
737 | char modalias[32]; | 740 | char modalias[SPI_NAME_SIZE]; |
738 | const void *platform_data; | 741 | const void *platform_data; |
739 | void *controller_data; | 742 | void *controller_data; |
740 | int irq; | 743 | int irq; |
@@ -802,4 +805,7 @@ spi_unregister_device(struct spi_device *spi) | |||
802 | device_unregister(&spi->dev); | 805 | device_unregister(&spi->dev); |
803 | } | 806 | } |
804 | 807 | ||
808 | extern const struct spi_device_id * | ||
809 | spi_get_device_id(const struct spi_device *sdev); | ||
810 | |||
805 | #endif /* __LINUX_SPI_H */ | 811 | #endif /* __LINUX_SPI_H */ |
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 40e0045876ee..9d446e34519c 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c | |||
@@ -657,6 +657,15 @@ static int do_i2c_entry(const char *filename, struct i2c_device_id *id, | |||
657 | return 1; | 657 | return 1; |
658 | } | 658 | } |
659 | 659 | ||
660 | /* Looks like: S */ | ||
661 | static int do_spi_entry(const char *filename, struct spi_device_id *id, | ||
662 | char *alias) | ||
663 | { | ||
664 | sprintf(alias, "%s", id->name); | ||
665 | |||
666 | return 1; | ||
667 | } | ||
668 | |||
660 | static const struct dmifield { | 669 | static const struct dmifield { |
661 | const char *prefix; | 670 | const char *prefix; |
662 | int field; | 671 | int field; |
@@ -853,6 +862,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, | |||
853 | do_table(symval, sym->st_size, | 862 | do_table(symval, sym->st_size, |
854 | sizeof(struct i2c_device_id), "i2c", | 863 | sizeof(struct i2c_device_id), "i2c", |
855 | do_i2c_entry, mod); | 864 | do_i2c_entry, mod); |
865 | else if (sym_is(symname, "__mod_spi_device_table")) | ||
866 | do_table(symval, sym->st_size, | ||
867 | sizeof(struct spi_device_id), "spi", | ||
868 | do_spi_entry, mod); | ||
856 | else if (sym_is(symname, "__mod_dmi_device_table")) | 869 | else if (sym_is(symname, "__mod_dmi_device_table")) |
857 | do_table(symval, sym->st_size, | 870 | do_table(symval, sym->st_size, |
858 | sizeof(struct dmi_system_id), "dmi", | 871 | sizeof(struct dmi_system_id), "dmi", |