spi: enable spi_board_info to be registered after spi_master
Currently spi_register_board_info() has to be called before its related spi_master be registered, otherwise these board info will be just ignored. This patch will remove this order limit, it adds a global spi master list like the existing global board info listr. Whenever a board info or a spi_master is registered, the spi master list or board info list will be scanned, and a new spi device will be created if there is a master-board info match. Signed-off-by: Feng Tang <feng.tang@intel.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
parent
d4429f608a
commit
2b9603a0d7
@ -29,11 +29,6 @@
|
|||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/of_spi.h>
|
#include <linux/of_spi.h>
|
||||||
|
|
||||||
|
|
||||||
/* SPI bustype and spi_master class are registered after board init code
|
|
||||||
* provides the SPI device tables, ensuring that both are present by the
|
|
||||||
* time controller driver registration causes spi_devices to "enumerate".
|
|
||||||
*/
|
|
||||||
static void spidev_release(struct device *dev)
|
static void spidev_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct spi_device *spi = to_spi_device(dev);
|
struct spi_device *spi = to_spi_device(dev);
|
||||||
@ -202,11 +197,16 @@ EXPORT_SYMBOL_GPL(spi_register_driver);
|
|||||||
|
|
||||||
struct boardinfo {
|
struct boardinfo {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
unsigned n_board_info;
|
struct spi_board_info board_info;
|
||||||
struct spi_board_info board_info[0];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static LIST_HEAD(board_list);
|
static LIST_HEAD(board_list);
|
||||||
|
static LIST_HEAD(spi_master_list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to protect add/del opertion for board_info list and
|
||||||
|
* spi_master list, and their matching process
|
||||||
|
*/
|
||||||
static DEFINE_MUTEX(board_lock);
|
static DEFINE_MUTEX(board_lock);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -371,6 +371,20 @@ struct spi_device *spi_new_device(struct spi_master *master,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_new_device);
|
EXPORT_SYMBOL_GPL(spi_new_device);
|
||||||
|
|
||||||
|
static void spi_match_master_to_boardinfo(struct spi_master *master,
|
||||||
|
struct spi_board_info *bi)
|
||||||
|
{
|
||||||
|
struct spi_device *dev;
|
||||||
|
|
||||||
|
if (master->bus_num != bi->bus_num)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dev = spi_new_device(master, bi);
|
||||||
|
if (!dev)
|
||||||
|
dev_err(master->dev.parent, "can't create new device for %s\n",
|
||||||
|
bi->modalias);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spi_register_board_info - register SPI devices for a given board
|
* spi_register_board_info - register SPI devices for a given board
|
||||||
* @info: array of chip descriptors
|
* @info: array of chip descriptors
|
||||||
@ -393,43 +407,25 @@ EXPORT_SYMBOL_GPL(spi_new_device);
|
|||||||
int __init
|
int __init
|
||||||
spi_register_board_info(struct spi_board_info const *info, unsigned n)
|
spi_register_board_info(struct spi_board_info const *info, unsigned n)
|
||||||
{
|
{
|
||||||
struct boardinfo *bi;
|
struct boardinfo *bi;
|
||||||
|
int i;
|
||||||
|
|
||||||
bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
|
bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
|
||||||
if (!bi)
|
if (!bi)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
bi->n_board_info = n;
|
|
||||||
memcpy(bi->board_info, info, n * sizeof *info);
|
|
||||||
|
|
||||||
mutex_lock(&board_lock);
|
for (i = 0; i < n; i++, bi++, info++) {
|
||||||
list_add_tail(&bi->list, &board_list);
|
struct spi_master *master;
|
||||||
mutex_unlock(&board_lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME someone should add support for a __setup("spi", ...) that
|
memcpy(&bi->board_info, info, sizeof(*info));
|
||||||
* creates board info from kernel command lines
|
mutex_lock(&board_lock);
|
||||||
*/
|
list_add_tail(&bi->list, &board_list);
|
||||||
|
list_for_each_entry(master, &spi_master_list, list)
|
||||||
static void scan_boardinfo(struct spi_master *master)
|
spi_match_master_to_boardinfo(master, &bi->board_info);
|
||||||
{
|
mutex_unlock(&board_lock);
|
||||||
struct boardinfo *bi;
|
|
||||||
|
|
||||||
mutex_lock(&board_lock);
|
|
||||||
list_for_each_entry(bi, &board_list, list) {
|
|
||||||
struct spi_board_info *chip = bi->board_info;
|
|
||||||
unsigned n;
|
|
||||||
|
|
||||||
for (n = bi->n_board_info; n > 0; n--, chip++) {
|
|
||||||
if (chip->bus_num != master->bus_num)
|
|
||||||
continue;
|
|
||||||
/* NOTE: this relies on spi_new_device to
|
|
||||||
* issue diagnostics when given bogus inputs
|
|
||||||
*/
|
|
||||||
(void) spi_new_device(master, chip);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mutex_unlock(&board_lock);
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@ -512,6 +508,7 @@ int spi_register_master(struct spi_master *master)
|
|||||||
{
|
{
|
||||||
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
|
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
|
||||||
struct device *dev = master->dev.parent;
|
struct device *dev = master->dev.parent;
|
||||||
|
struct boardinfo *bi;
|
||||||
int status = -ENODEV;
|
int status = -ENODEV;
|
||||||
int dynamic = 0;
|
int dynamic = 0;
|
||||||
|
|
||||||
@ -547,8 +544,12 @@ int spi_register_master(struct spi_master *master)
|
|||||||
dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
|
dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
|
||||||
dynamic ? " (dynamic)" : "");
|
dynamic ? " (dynamic)" : "");
|
||||||
|
|
||||||
/* populate children from any spi device tables */
|
mutex_lock(&board_lock);
|
||||||
scan_boardinfo(master);
|
list_add_tail(&master->list, &spi_master_list);
|
||||||
|
list_for_each_entry(bi, &board_list, list)
|
||||||
|
spi_match_master_to_boardinfo(master, &bi->board_info);
|
||||||
|
mutex_unlock(&board_lock);
|
||||||
|
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
||||||
/* Register devices from the device tree */
|
/* Register devices from the device tree */
|
||||||
@ -579,7 +580,12 @@ void spi_unregister_master(struct spi_master *master)
|
|||||||
{
|
{
|
||||||
int dummy;
|
int dummy;
|
||||||
|
|
||||||
dummy = device_for_each_child(&master->dev, NULL, __unregister);
|
mutex_lock(&board_lock);
|
||||||
|
list_del(&master->list);
|
||||||
|
mutex_unlock(&board_lock);
|
||||||
|
|
||||||
|
dummy = device_for_each_child(master->dev.parent, &master->dev,
|
||||||
|
__unregister);
|
||||||
device_unregister(&master->dev);
|
device_unregister(&master->dev);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_unregister_master);
|
EXPORT_SYMBOL_GPL(spi_unregister_master);
|
||||||
|
@ -204,6 +204,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
|||||||
/**
|
/**
|
||||||
* struct spi_master - interface to SPI master controller
|
* struct spi_master - interface to SPI master controller
|
||||||
* @dev: device interface to this driver
|
* @dev: device interface to this driver
|
||||||
|
* @list: link with the global spi_master list
|
||||||
* @bus_num: board-specific (and often SOC-specific) identifier for a
|
* @bus_num: board-specific (and often SOC-specific) identifier for a
|
||||||
* given SPI controller.
|
* given SPI controller.
|
||||||
* @num_chipselect: chipselects are used to distinguish individual
|
* @num_chipselect: chipselects are used to distinguish individual
|
||||||
@ -238,6 +239,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
|||||||
struct spi_master {
|
struct spi_master {
|
||||||
struct device dev;
|
struct device dev;
|
||||||
|
|
||||||
|
struct list_head list;
|
||||||
|
|
||||||
/* other than negative (== assign one dynamically), bus_num is fully
|
/* other than negative (== assign one dynamically), bus_num is fully
|
||||||
* board-specific. usually that simplifies to being SOC-specific.
|
* board-specific. usually that simplifies to being SOC-specific.
|
||||||
* example: one SOC has three SPI controllers, numbered 0..2,
|
* example: one SOC has three SPI controllers, numbered 0..2,
|
||||||
|
Loading…
Reference in New Issue
Block a user