diff --git a/drivers/staging/greybus/kernel_ver.h b/drivers/staging/greybus/kernel_ver.h index 84beb2f6334c..24d5bcd2e0ff 100644 --- a/drivers/staging/greybus/kernel_ver.h +++ b/drivers/staging/greybus/kernel_ver.h @@ -313,6 +313,11 @@ static inline bool led_sysfs_is_disabled(struct led_classdev *led_cdev) #define SPI_NOR_MODALIAS "m25p80" #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) +/* Starting from this version, the spi core handles runtime pm automatically */ +#define SPI_CORE_SUPPORT_PM +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) /** * reinit_completion - reinitialize a completion structure diff --git a/drivers/staging/greybus/spi.c b/drivers/staging/greybus/spi.c index a82337931c0d..2e6e328bae9e 100644 --- a/drivers/staging/greybus/spi.c +++ b/drivers/staging/greybus/spi.c @@ -35,6 +35,7 @@ static int gb_spi_probe(struct gbphy_device *gbphy_dev, gb_gbphy_set_data(gbphy_dev, connection); + gbphy_runtime_put_autosuspend(gbphy_dev); return 0; exit_connection_disable: @@ -48,6 +49,11 @@ exit_connection_destroy: static void gb_spi_remove(struct gbphy_device *gbphy_dev) { struct gb_connection *connection = gb_gbphy_get_data(gbphy_dev); + int ret; + + ret = gbphy_runtime_get_sync(gbphy_dev); + if (ret) + gbphy_runtime_get_noresume(gbphy_dev); gb_spilib_master_exit(connection); gb_connection_disable(connection); diff --git a/drivers/staging/greybus/spilib.c b/drivers/staging/greybus/spilib.c index 527909b26d79..e4c82e0a322b 100644 --- a/drivers/staging/greybus/spilib.c +++ b/drivers/staging/greybus/spilib.c @@ -15,6 +15,7 @@ #include "greybus.h" #include "spilib.h" +#include "gbphy.h" struct gb_spilib { struct gb_connection *connection; @@ -372,6 +373,26 @@ out: return ret; } +#ifndef SPI_CORE_SUPPORT_PM +static int gb_spi_prepare_transfer_hardware(struct spi_master *master) +{ + struct gb_spilib *spi = spi_master_get_devdata(master); + struct gbphy_device *gbphy_dev = to_gbphy_dev(spi->parent); + + return gbphy_runtime_get_sync(gbphy_dev); +} + +static int gb_spi_unprepare_transfer_hardware(struct spi_master *master) +{ + struct gb_spilib *spi = spi_master_get_devdata(master); + struct gbphy_device *gbphy_dev = to_gbphy_dev(spi->parent); + + gbphy_runtime_put_autosuspend(gbphy_dev); + + return 0; +} +#endif + static int gb_spi_setup(struct spi_device *spi) { /* Nothing to do for now */ @@ -497,6 +518,14 @@ int gb_spilib_master_init(struct gb_connection *connection, struct device *dev) master->setup = gb_spi_setup; master->transfer_one_message = gb_spi_transfer_one_message; +#ifndef SPI_CORE_SUPPORT_PM + master->prepare_transfer_hardware = gb_spi_prepare_transfer_hardware; + master->unprepare_transfer_hardware = + gb_spi_unprepare_transfer_hardware; +#else + master->auto_runtime_pm = true; +#endif + ret = spi_register_master(master); if (ret < 0) goto exit_spi_put;