diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 12:45:35 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 12:45:35 -0800 | 
| commit | bad73c5aa069f1f14cc07ce7bbae8d463635560c (patch) | |
| tree | db905bb3400e6fe70be95cd20158bed79b2b2c6c /drivers/spi | |
| parent | b58ed041a360ed051fab17e4d9b0f451c6fedba7 (diff) | |
| parent | f316fc56555a5c3bcf6350f3d5ac26dd2c55f4cb (diff) | |
| download | olio-linux-3.10-bad73c5aa069f1f14cc07ce7bbae8d463635560c.tar.xz olio-linux-3.10-bad73c5aa069f1f14cc07ce7bbae8d463635560c.zip  | |
Merge tag 'pm+acpi-for-3.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI and power management updates from Rafael Wysocki:
 - Introduction of device PM QoS flags.
 - ACPI device power management update allowing subsystems other than
   PCI to use it more easily.
 - ACPI device enumeration rework allowing additional kinds of devices
   to be enumerated via ACPI.  From Mika Westerberg, Adrian Hunter,
   Mathias Nyman, Andy Shevchenko, and Rafael J. Wysocki.
 - ACPICA update to version 20121018 from Bob Moore and Lv Zheng.
 - ACPI memory hotplug update from Wen Congyang and Yasuaki Ishimatsu.
 - Introduction of acpi_handle_<level>() messaging macros and ACPI-based
   CPU hot-remove support from Toshi Kani.
 - ACPI EC updates from Feng Tang.
 - cpufreq updates from Viresh Kumar, Fabio Baltieri and others.
 - cpuidle changes to quickly notice governor prediction failure from
   Youquan Song.
 - Support for using multiple cpuidle drivers at the same time and
   cpuidle cleanups from Daniel Lezcano.
 - devfreq updates from Nishanth Menon and others.
 - cpupower update from Thomas Renninger.
 - Fixes and small cleanups all over the place.
* tag 'pm+acpi-for-3.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (196 commits)
  mmc: sdhci-acpi: enable runtime-pm for device HID INT33C6
  ACPI: add Haswell LPSS devices to acpi_platform_device_ids list
  ACPI: add documentation about ACPI 5 enumeration
  pnpacpi: fix incorrect TEST_ALPHA() test
  ACPI / PM: Fix header of acpi_dev_pm_detach() in acpi.h
  ACPI / video: ignore BIOS initial backlight value for HP Folio 13-2000
  ACPI : do not use Lid and Sleep button for S5 wakeup
  ACPI / PNP: Do not crash due to stale pointer use during system resume
  ACPI / video: Add "Asus UL30VT" to ACPI video detect blacklist
  ACPI: do acpisleep dmi check when CONFIG_ACPI_SLEEP is set
  spi / ACPI: add ACPI enumeration support
  gpio / ACPI: add ACPI support
  PM / devfreq: remove compiler error with module governors (2)
  cpupower: IvyBridge (0x3a and 0x3e models) support
  cpupower: Provide -c param for cpupower monitor to schedule process on all cores
  cpupower tools: Fix warning and a bug with the cpu package count
  cpupower tools: Fix malloc of cpu_info structure
  cpupower tools: Fix issues with sysfs_topology_read_file
  cpupower tools: Fix minor warnings
  cpupower tools: Update .gitignore for files created in the debug directories
  ...
Diffstat (limited to 'drivers/spi')
| -rw-r--r-- | drivers/spi/spi.c | 103 | 
1 files changed, 102 insertions, 1 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index d3e64080c40..718cc1f4923 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -35,6 +35,8 @@  #include <linux/sched.h>  #include <linux/delay.h>  #include <linux/kthread.h> +#include <linux/ioport.h> +#include <linux/acpi.h>  static void spidev_release(struct device *dev)  { @@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)  	if (of_driver_match_device(dev, drv))  		return 1; +	/* Then try ACPI */ +	if (acpi_driver_match_device(dev, drv)) +		return 1; +  	if (sdrv->id_table)  		return !!spi_match_id(sdrv->id_table, spi); @@ -888,6 +894,100 @@ static void of_register_spi_devices(struct spi_master *master)  static void of_register_spi_devices(struct spi_master *master) { }  #endif +#ifdef CONFIG_ACPI +static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) +{ +	struct spi_device *spi = data; + +	if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { +		struct acpi_resource_spi_serialbus *sb; + +		sb = &ares->data.spi_serial_bus; +		if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) { +			spi->chip_select = sb->device_selection; +			spi->max_speed_hz = sb->connection_speed; + +			if (sb->clock_phase == ACPI_SPI_SECOND_PHASE) +				spi->mode |= SPI_CPHA; +			if (sb->clock_polarity == ACPI_SPI_START_HIGH) +				spi->mode |= SPI_CPOL; +			if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH) +				spi->mode |= SPI_CS_HIGH; +		} +	} else if (spi->irq < 0) { +		struct resource r; + +		if (acpi_dev_resource_interrupt(ares, 0, &r)) +			spi->irq = r.start; +	} + +	/* Always tell the ACPI core to skip this resource */ +	return 1; +} + +static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, +				       void *data, void **return_value) +{ +	struct spi_master *master = data; +	struct list_head resource_list; +	struct acpi_device *adev; +	struct spi_device *spi; +	int ret; + +	if (acpi_bus_get_device(handle, &adev)) +		return AE_OK; +	if (acpi_bus_get_status(adev) || !adev->status.present) +		return AE_OK; + +	spi = spi_alloc_device(master); +	if (!spi) { +		dev_err(&master->dev, "failed to allocate SPI device for %s\n", +			dev_name(&adev->dev)); +		return AE_NO_MEMORY; +	} + +	ACPI_HANDLE_SET(&spi->dev, handle); +	spi->irq = -1; + +	INIT_LIST_HEAD(&resource_list); +	ret = acpi_dev_get_resources(adev, &resource_list, +				     acpi_spi_add_resource, spi); +	acpi_dev_free_resource_list(&resource_list); + +	if (ret < 0 || !spi->max_speed_hz) { +		spi_dev_put(spi); +		return AE_OK; +	} + +	strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias)); +	if (spi_add_device(spi)) { +		dev_err(&master->dev, "failed to add SPI device %s from ACPI\n", +			dev_name(&adev->dev)); +		spi_dev_put(spi); +	} + +	return AE_OK; +} + +static void acpi_register_spi_devices(struct spi_master *master) +{ +	acpi_status status; +	acpi_handle handle; + +	handle = ACPI_HANDLE(&master->dev); +	if (!handle) +		return; + +	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, +				     acpi_spi_add_device, NULL, +				     master, NULL); +	if (ACPI_FAILURE(status)) +		dev_warn(&master->dev, "failed to enumerate SPI slaves\n"); +} +#else +static inline void acpi_register_spi_devices(struct spi_master *master) {} +#endif /* CONFIG_ACPI */ +  static void spi_master_release(struct device *dev)  {  	struct spi_master *master; @@ -1023,8 +1123,9 @@ int spi_register_master(struct spi_master *master)  		spi_match_master_to_boardinfo(master, &bi->board_info);  	mutex_unlock(&board_lock); -	/* Register devices from the device tree */ +	/* Register devices from the device tree and ACPI */  	of_register_spi_devices(master); +	acpi_register_spi_devices(master);  done:  	return status;  }  |