Commit a0a90718 authored by Mika Westerberg's avatar Mika Westerberg Committed by Mark Brown

spi: Let drivers translate ACPI DeviceSelection to suitable Linux chip select

In Windows it is up to the SPI host controller driver to handle the ACPI
DeviceSelection as it likes. The SPI core does not take any part in it.
This is different in Linux because we always expect to have chip select in
range of 0 .. master->num_chipselect - 1.

In order to support this in Linux we need a way to allow the driver to
translate between ACPI DeviceSelection field and Linux chip select number
so provide a new optional hook ->fw_translate_cs() that can be used by a
driver to handle translation and call this hook if set during SPI slave
ACPI enumeration.
Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: default avatarJarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 92e963f5
...@@ -1581,13 +1581,30 @@ static void of_register_spi_devices(struct spi_master *master) { } ...@@ -1581,13 +1581,30 @@ static void of_register_spi_devices(struct spi_master *master) { }
static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
{ {
struct spi_device *spi = data; struct spi_device *spi = data;
struct spi_master *master = spi->master;
if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
struct acpi_resource_spi_serialbus *sb; struct acpi_resource_spi_serialbus *sb;
sb = &ares->data.spi_serial_bus; sb = &ares->data.spi_serial_bus;
if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) { if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) {
spi->chip_select = sb->device_selection; /*
* ACPI DeviceSelection numbering is handled by the
* host controller driver in Windows and can vary
* from driver to driver. In Linux we always expect
* 0 .. max - 1 so we need to ask the driver to
* translate between the two schemes.
*/
if (master->fw_translate_cs) {
int cs = master->fw_translate_cs(master,
sb->device_selection);
if (cs < 0)
return cs;
spi->chip_select = cs;
} else {
spi->chip_select = sb->device_selection;
}
spi->max_speed_hz = sb->connection_speed; spi->max_speed_hz = sb->connection_speed;
if (sb->clock_phase == ACPI_SPI_SECOND_PHASE) if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
......
...@@ -369,6 +369,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) ...@@ -369,6 +369,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @dma_rx: DMA receive channel * @dma_rx: DMA receive channel
* @dummy_rx: dummy receive buffer for full-duplex devices * @dummy_rx: dummy receive buffer for full-duplex devices
* @dummy_tx: dummy transmit buffer for full-duplex devices * @dummy_tx: dummy transmit buffer for full-duplex devices
* @fw_translate_cs: If the boot firmware uses different numbering scheme
* what Linux expects, this optional hook can be used to translate
* between the two.
* *
* Each SPI master controller can communicate with one or more @spi_device * Each SPI master controller can communicate with one or more @spi_device
* children. These make a small bus, sharing MOSI, MISO and SCK signals * children. These make a small bus, sharing MOSI, MISO and SCK signals
...@@ -537,6 +540,8 @@ struct spi_master { ...@@ -537,6 +540,8 @@ struct spi_master {
/* dummy data for full duplex devices */ /* dummy data for full duplex devices */
void *dummy_rx; void *dummy_rx;
void *dummy_tx; void *dummy_tx;
int (*fw_translate_cs)(struct spi_master *master, unsigned cs);
}; };
static inline void *spi_master_get_devdata(struct spi_master *master) static inline void *spi_master_get_devdata(struct spi_master *master)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment