Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 75368bf6 authored by Anton Vorontsov's avatar Anton Vorontsov Committed by Linus Torvalds
Browse files

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: default avatarAnton 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b5f3294f
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -59,9 +59,32 @@ 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;
}

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)
{
	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;
}
+10 −0
Original line number Diff line number Diff line
@@ -399,6 +399,16 @@ struct i2c_device_id {
			__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 */
enum dmi_field {
	DMI_NONE,
+8 −2
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#define __LINUX_SPI_H

#include <linux/device.h>
#include <linux/mod_devicetable.h>

/*
 * 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,7 @@ struct spi_message;

/**
 * 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
 *	that the device is actually present, and may need to configure
 *	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.
 */
struct spi_driver {
	const struct spi_device_id *id_table;
	int			(*probe)(struct spi_device *spi);
	int			(*remove)(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,
	 * irq is copied too
	 */
	char		modalias[32];
	char		modalias[SPI_NAME_SIZE];
	const void	*platform_data;
	void		*controller_data;
	int		irq;
@@ -802,4 +805,7 @@ spi_unregister_device(struct spi_device *spi)
		device_unregister(&spi->dev);
}

extern const struct spi_device_id *
spi_get_device_id(const struct spi_device *sdev);

#endif /* __LINUX_SPI_H */
+13 −0
Original line number Diff line number Diff line
@@ -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",