Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

greybus: spilib: make spilib independent of gbphy

spilib is used by multiple users currently (spi.c and fw-core.c) but
commit aa52b62a0556 broke that hierarchy and introduced gbphy dependent
code in spilib.

This may have unreliable consequences as we are doing following
operation unconditionally now:

gbphy_dev = to_gbphy_dev(spi->parent);
gbphy_runtime_get_sync(gbphy_dev);

which may not go well when the parent is of type &bundle->dev
(fw-core.c).

This patch introduces spilib_ops and lets the users of the core register
them. This shall have no functional change for the spi.c usecase and
shall fix the unreliable results for the fw-core.c usecase.

Tested by writing to mtd0 dev and verifying (with print messages) that
the below routines are getting called for a gpbridge-test module.

Fixes: aa52b62a0556 ("spi: Add runtime_pm support")
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>

authored by

Viresh Kumar and committed by
Greg Kroah-Hartman
92bcadde adac4b95

+46 -15
+1 -1
drivers/staging/greybus/fw-core.c
··· 38 38 if (ret) 39 39 return ret; 40 40 41 - ret = gb_spilib_master_init(connection, &connection->bundle->dev); 41 + ret = gb_spilib_master_init(connection, &connection->bundle->dev, NULL); 42 42 if (ret) { 43 43 gb_connection_disable(connection); 44 44 return ret;
+22 -1
drivers/staging/greybus/spi.c
··· 13 13 #include "gbphy.h" 14 14 #include "spilib.h" 15 15 16 + #ifndef SPI_CORE_SUPPORT_PM 17 + static int gbphy_spi_prepare_transfer_hardware(struct device *dev) 18 + { 19 + return gbphy_runtime_get_sync(to_gbphy_dev(dev)); 20 + } 21 + 22 + static void gbphy_spi_unprepare_transfer_hardware(struct device *dev) 23 + { 24 + gbphy_runtime_put_autosuspend(to_gbphy_dev(dev)); 25 + } 26 + 27 + static struct spilib_ops __spilib_ops = { 28 + .prepare_transfer_hardware = gbphy_spi_prepare_transfer_hardware, 29 + .unprepare_transfer_hardware = gbphy_spi_unprepare_transfer_hardware, 30 + }; 31 + 32 + static struct spilib_ops *spilib_ops = &__spilib_ops; 33 + #else 34 + static struct spilib_ops *spilib_ops = NULL; 35 + #endif 36 + 16 37 static int gb_spi_probe(struct gbphy_device *gbphy_dev, 17 38 const struct gbphy_device_id *id) 18 39 { ··· 50 29 if (ret) 51 30 goto exit_connection_destroy; 52 31 53 - ret = gb_spilib_master_init(connection, &gbphy_dev->dev); 32 + ret = gb_spilib_master_init(connection, &gbphy_dev->dev, spilib_ops); 54 33 if (ret) 55 34 goto exit_connection_disable; 56 35
+16 -12
drivers/staging/greybus/spilib.c
··· 15 15 16 16 #include "greybus.h" 17 17 #include "spilib.h" 18 - #include "gbphy.h" 19 18 20 19 struct gb_spilib { 21 20 struct gb_connection *connection; 22 21 struct device *parent; 23 22 struct spi_transfer *first_xfer; 24 23 struct spi_transfer *last_xfer; 24 + struct spilib_ops *ops; 25 25 u32 rx_xfer_offset; 26 26 u32 tx_xfer_offset; 27 27 u32 last_xfer_size; ··· 373 373 return ret; 374 374 } 375 375 376 - #ifndef SPI_CORE_SUPPORT_PM 377 376 static int gb_spi_prepare_transfer_hardware(struct spi_master *master) 378 377 { 379 378 struct gb_spilib *spi = spi_master_get_devdata(master); 380 - struct gbphy_device *gbphy_dev = to_gbphy_dev(spi->parent); 381 379 382 - return gbphy_runtime_get_sync(gbphy_dev); 380 + return spi->ops->prepare_transfer_hardware(spi->parent); 383 381 } 384 382 385 383 static int gb_spi_unprepare_transfer_hardware(struct spi_master *master) 386 384 { 387 385 struct gb_spilib *spi = spi_master_get_devdata(master); 388 - struct gbphy_device *gbphy_dev = to_gbphy_dev(spi->parent); 389 386 390 - gbphy_runtime_put_autosuspend(gbphy_dev); 387 + spi->ops->unprepare_transfer_hardware(spi->parent); 391 388 392 389 return 0; 393 390 } 394 - #endif 395 391 396 392 static int gb_spi_setup(struct spi_device *spi) 397 393 { ··· 479 483 return 0; 480 484 } 481 485 482 - int gb_spilib_master_init(struct gb_connection *connection, struct device *dev) 486 + int gb_spilib_master_init(struct gb_connection *connection, struct device *dev, 487 + struct spilib_ops *ops) 483 488 { 484 489 struct gb_spilib *spi; 485 490 struct spi_master *master; ··· 498 501 spi->connection = connection; 499 502 gb_connection_set_data(connection, master); 500 503 spi->parent = dev; 504 + spi->ops = ops; 501 505 502 506 /* get master configuration */ 503 507 ret = gb_spi_get_master_config(spi); ··· 516 518 master->setup = gb_spi_setup; 517 519 master->transfer_one_message = gb_spi_transfer_one_message; 518 520 519 - #ifndef SPI_CORE_SUPPORT_PM 520 - master->prepare_transfer_hardware = gb_spi_prepare_transfer_hardware; 521 - master->unprepare_transfer_hardware = 521 + if (ops && ops->prepare_transfer_hardware) { 522 + master->prepare_transfer_hardware = 523 + gb_spi_prepare_transfer_hardware; 524 + } 525 + 526 + if (ops && ops->unprepare_transfer_hardware) { 527 + master->unprepare_transfer_hardware = 522 528 gb_spi_unprepare_transfer_hardware; 523 - #else 529 + } 530 + 531 + #ifdef SPI_CORE_SUPPORT_PM 524 532 master->auto_runtime_pm = true; 525 533 #endif 526 534
+7 -1
drivers/staging/greybus/spilib.h
··· 10 10 #ifndef __SPILIB_H 11 11 #define __SPILIB_H 12 12 13 + struct device; 13 14 struct gb_connection; 14 15 15 - int gb_spilib_master_init(struct gb_connection *connection, struct device *dev); 16 + struct spilib_ops { 17 + int (*prepare_transfer_hardware)(struct device *dev); 18 + void (*unprepare_transfer_hardware)(struct device *dev); 19 + }; 20 + 21 + int gb_spilib_master_init(struct gb_connection *connection, struct device *dev, struct spilib_ops *ops); 16 22 void gb_spilib_master_exit(struct gb_connection *connection); 17 23 18 24 #endif /* __SPILIB_H */