From patchwork Wed Jul 29 17:04:57 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Vorontsov X-Patchwork-Id: 30359 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [18.85.46.34]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by bilbo.ozlabs.org (Postfix) with ESMTPS id 8B4F0B83F6 for ; Thu, 30 Jul 2009 03:08:16 +1000 (EST) Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1MWCaP-0008Lp-96; Wed, 29 Jul 2009 17:05:05 +0000 Received: from [213.79.90.228] (helo=buildserver.ru.mvista.com) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1MWCaI-0007W7-Da for linux-mtd@lists.infradead.org; Wed, 29 Jul 2009 17:05:03 +0000 Received: from localhost (unknown [10.150.0.9]) by buildserver.ru.mvista.com (Postfix) with ESMTP id C6BD28825; Wed, 29 Jul 2009 22:04:57 +0500 (SAMST) Date: Wed, 29 Jul 2009 21:04:57 +0400 From: Anton Vorontsov To: Andrew Morton Subject: [PATCH 1/7] spi: Add support for device table matching Message-ID: <20090729170457.GA4803@oksana.dev.rtsoft.ru> References: <20090729170345.GA26787@oksana.dev.rtsoft.ru> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20090729170345.GA26787@oksana.dev.rtsoft.ru> User-Agent: Mutt/1.5.20 (2009-06-14) X-Spam-Score: 0.1 (/) X-Spam-Report: SpamAssassin version 3.2.5 on bombadil.infradead.org summary: Content analysis details: (0.1 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.1 RDNS_NONE Delivered to trusted network by a host with no rDNS Cc: David Brownell , linux-kernel@vger.kernel.org, lm-sensors@lm-sensors.org, Grant Likely , linuxppc-dev@ozlabs.org, linux-mtd@lists.infradead.org, Jean Delvare , David Woodhouse X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org 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 --- drivers/spi/spi.c | 26 +++++++++++++++++++++++++- include/linux/mod_devicetable.h | 13 +++++++++++++ include/linux/spi/spi.h | 10 ++++++++-- scripts/mod/file2alias.c | 13 +++++++++++++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 70845cc..1431bf2 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -59,9 +59,24 @@ static struct device_attribute spi_dev_attrs[] = { * 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; +} + static int spi_match_device(struct device *dev, struct device_driver *drv) { 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; } @@ -121,6 +136,13 @@ struct bus_type spi_bus_type = { }; EXPORT_SYMBOL_GPL(spi_bus_type); +static int spi_drv_probe_id(struct device *dev) +{ + const struct spi_driver *sdrv = to_spi_driver(dev->driver); + struct spi_device *sdev = to_spi_device(dev); + + return sdrv->probe_id(sdev, spi_match_id(sdrv->id_table, sdev)); +} static int spi_drv_probe(struct device *dev) { @@ -151,7 +173,9 @@ static void spi_drv_shutdown(struct device *dev) int spi_register_driver(struct spi_driver *sdrv) { sdrv->driver.bus = &spi_bus_type; - if (sdrv->probe) + if (sdrv->probe_id) + sdrv->driver.probe = spi_drv_probe_id; + else if (sdrv->probe) sdrv->driver.probe = spi_drv_probe; if (sdrv->remove) sdrv->driver.remove = spi_drv_remove; diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 1bf5900..9660dca 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -399,6 +399,19 @@ struct i2c_device_id { __attribute__((aligned(sizeof(kernel_ulong_t)))); }; +/* spi */ + +#define SPI_NAME_SIZE 20 + +struct spi_device_id { + char name[SPI_NAME_SIZE]; +#ifdef __KERNEL__ + void *data; +#else + kernel_ulong_t data; +#endif +}; + /* dmi */ enum dmi_field { DMI_NONE, diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index c47c4b4..c8d92a1 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -20,6 +20,7 @@ #define __LINUX_SPI_H #include +#include /* * INTERFACES between SPI master-side drivers and SPI infrastructure. @@ -86,7 +87,7 @@ struct spi_device { int irq; void *controller_state; void *controller_data; - char modalias[32]; + char modalias[SPI_NAME_SIZE]; /* * likely need more hooks for more protocol options affecting how @@ -145,6 +146,8 @@ struct spi_message; /** * struct spi_driver - Host side "protocol" driver + * @id_table: List of SPI devices supported by this driver + * @probe_id: Binds this driver to the spi device via id_table matching. * @probe: Binds this driver to the spi device. Drivers can verify * that the device is actually present, and may need to configure * characteristics (such as bits_per_word) which weren't needed for @@ -170,6 +173,9 @@ struct spi_message; * MMC, RTC, filesystem character device nodes, and hardware monitoring. */ struct spi_driver { + const struct spi_device_id *id_table; + int (*probe_id)(struct spi_device *spi, + const struct spi_device_id *id); int (*probe)(struct spi_device *spi); int (*remove)(struct spi_device *spi); void (*shutdown)(struct spi_device *spi); @@ -732,7 +738,7 @@ struct spi_board_info { * controller_data goes to spi_device.controller_data, * irq is copied too */ - char modalias[32]; + char modalias[SPI_NAME_SIZE]; const void *platform_data; void *controller_data; int irq; diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 40e0045..9d446e3 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, 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 { const char *prefix; int field; @@ -853,6 +862,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, do_table(symval, sym->st_size, sizeof(struct i2c_device_id), "i2c", 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")) do_table(symval, sym->st_size, sizeof(struct dmi_system_id), "dmi",