From ba3e67001b42626dec862410310d30db586074d5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 5 May 2016 14:32:35 +0530 Subject: [PATCH] greybus: SPI: convert to a gpbridge driver This converts the SPI driver to be a gpbridge driver, moving it away from the "legacy" interface. Testing Done: Tested on gbsim. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Vaibhav Hiremath [vaibhav.hiremath@linaro.org: 1.Changed code to retain init/exit fns of drivers. 2.Exit path fix. 3. Fixed review comments] Reviewed-by: Viresh Kumar Tested-by: Viresh Kumar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/gpbridge.c | 7 ++-- drivers/staging/greybus/gpbridge.h | 4 +- drivers/staging/greybus/legacy.c | 1 - drivers/staging/greybus/spi.c | 79 +++++++++++++++++++++++++++----------- 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/drivers/staging/greybus/gpbridge.c b/drivers/staging/greybus/gpbridge.c index d228e276f788..1dc6c8f85778 100644 --- a/drivers/staging/greybus/gpbridge.c +++ b/drivers/staging/greybus/gpbridge.c @@ -256,6 +256,7 @@ static const struct greybus_bundle_id gb_gpbridge_id_table[] = { { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_I2C) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_PWM) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SDIO) }, + { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SPI) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_UART) }, { }, }; @@ -308,8 +309,8 @@ static int __init gpbridge_init(void) pr_err("error initializing i2c driver\n"); goto error_i2c; } - if (gb_spi_protocol_init()) { - pr_err("error initializing spi protocol\n"); + if (gb_spi_driver_init()) { + pr_err("error initializing spi driver\n"); goto error_spi; } @@ -338,7 +339,7 @@ module_init(gpbridge_init); static void __exit gpbridge_exit(void) { - gb_spi_protocol_exit(); + gb_spi_driver_exit(); gb_i2c_driver_exit(); gb_usb_protocol_exit(); gb_sdio_driver_exit(); diff --git a/drivers/staging/greybus/gpbridge.h b/drivers/staging/greybus/gpbridge.h index 3f1d19eb35f3..ab3900363ec8 100644 --- a/drivers/staging/greybus/gpbridge.h +++ b/drivers/staging/greybus/gpbridge.h @@ -84,8 +84,8 @@ extern void gb_usb_protocol_exit(void); extern int gb_i2c_driver_init(void); extern void gb_i2c_driver_exit(void); -extern int gb_spi_protocol_init(void); -extern void gb_spi_protocol_exit(void); +extern int gb_spi_driver_init(void); +extern void gb_spi_driver_exit(void); #endif /* __GPBRIDGE_H */ diff --git a/drivers/staging/greybus/legacy.c b/drivers/staging/greybus/legacy.c index d94282d2dbe5..95d1eda98f72 100644 --- a/drivers/staging/greybus/legacy.c +++ b/drivers/staging/greybus/legacy.c @@ -237,7 +237,6 @@ static void legacy_disconnect(struct gb_bundle *bundle) static const struct greybus_bundle_id legacy_id_table[] = { { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_USB) }, - { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SPI) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_CAMERA) }, { } }; diff --git a/drivers/staging/greybus/spi.c b/drivers/staging/greybus/spi.c index ce706ed218e2..dc811b142432 100644 --- a/drivers/staging/greybus/spi.c +++ b/drivers/staging/greybus/spi.c @@ -18,6 +18,7 @@ struct gb_spi { struct gb_connection *connection; + struct gpbridge_device *gpbdev; struct spi_transfer *first_xfer; struct spi_transfer *last_xfer; u32 rx_xfer_offset; @@ -174,7 +175,7 @@ gb_spi_operation_create(struct gb_spi *spi, struct gb_connection *connection, spi->last_xfer = xfer; if (!xfer->tx_buf && !xfer->rx_buf) { - dev_err(&connection->bundle->dev, + dev_err(&spi->gpbdev->dev, "bufferless transfer, length %u\n", xfer->len); msg->state = GB_SPI_STATE_MSG_ERROR; return NULL; @@ -342,7 +343,7 @@ static int gb_spi_transfer_one_message(struct spi_master *master, if (response) gb_spi_decode_response(spi, msg, response); } else { - dev_err(&connection->bundle->dev, + dev_err(&spi->gpbdev->dev, "transfer operation failed: %d\n", ret); msg->state = GB_SPI_STATE_MSG_ERROR; } @@ -450,28 +451,48 @@ static int gb_spi_setup_device(struct gb_spi *spi, u8 cs) return 0; } -static int gb_spi_connection_init(struct gb_connection *connection) +static int gb_spi_probe(struct gpbridge_device *gpbdev, + const struct gpbridge_device_id *id) { + struct gb_connection *connection; struct gb_spi *spi; struct spi_master *master; int ret; u8 i; /* Allocate master with space for data */ - master = spi_alloc_master(&connection->bundle->dev, sizeof(*spi)); + master = spi_alloc_master(&gpbdev->dev, sizeof(*spi)); if (!master) { - dev_err(&connection->bundle->dev, "cannot alloc SPI master\n"); + dev_err(&gpbdev->dev, "cannot alloc SPI master\n"); return -ENOMEM; } + connection = gb_connection_create(gpbdev->bundle, + le16_to_cpu(gpbdev->cport_desc->id), + NULL); + if (IS_ERR(connection)) { + ret = PTR_ERR(connection); + goto exit_spi_put; + } + spi = spi_master_get_devdata(master); spi->connection = connection; gb_connection_set_data(connection, master); + spi->gpbdev = gpbdev; + gb_gpbridge_set_data(gpbdev, master); + + ret = gb_connection_enable(connection); + if (ret) + goto exit_connection_destroy; + + ret = gb_gpbridge_get_version(connection); + if (ret) + goto exit_connection_disable; /* get master configuration */ ret = gb_spi_get_master_config(spi); if (ret) - goto out_put_master; + goto exit_connection_disable; master->bus_num = -1; /* Allow spi-core to allocate it dynamically */ master->num_chipselect = spi->num_chipselect; @@ -486,42 +507,54 @@ static int gb_spi_connection_init(struct gb_connection *connection) ret = spi_register_master(master); if (ret < 0) - goto out_put_master; + goto exit_connection_disable; /* now, fetch the devices configuration */ for (i = 0; i < spi->num_chipselect; i++) { ret = gb_spi_setup_device(spi, i); if (ret < 0) { - dev_err(&connection->bundle->dev, - "failed to allocated spi device: %d\n", ret); - spi_unregister_master(master); - break; + dev_err(&gpbdev->dev, + "failed to allocate spi device %d: %d\n", + i, ret); + goto exit_spi_unregister; } } return ret; -out_put_master: +exit_spi_unregister: + spi_unregister_master(master); +exit_connection_disable: + gb_connection_disable(connection); +exit_connection_destroy: + gb_connection_destroy(connection); +exit_spi_put: spi_master_put(master); return ret; } -static void gb_spi_connection_exit(struct gb_connection *connection) +static void gb_spi_remove(struct gpbridge_device *gpbdev) { - struct spi_master *master = gb_connection_get_data(connection); + struct spi_master *master = gb_gpbridge_get_data(gpbdev); + struct gb_spi *spi = spi_master_get_devdata(master); + struct gb_connection *connection = spi->connection; spi_unregister_master(master); + gb_connection_disable(connection); + gb_connection_destroy(connection); + spi_master_put(master); } -static struct gb_protocol spi_protocol = { - .name = "spi", - .id = GREYBUS_PROTOCOL_SPI, - .major = GB_SPI_VERSION_MAJOR, - .minor = GB_SPI_VERSION_MINOR, - .connection_init = gb_spi_connection_init, - .connection_exit = gb_spi_connection_exit, - .request_recv = NULL, +static const struct gpbridge_device_id gb_spi_id_table[] = { + { GPBRIDGE_PROTOCOL(GREYBUS_PROTOCOL_SPI) }, + { }, }; -gb_builtin_protocol_driver(spi_protocol); +static struct gpbridge_driver spi_driver = { + .name = "spi", + .probe = gb_spi_probe, + .remove = gb_spi_remove, + .id_table = gb_spi_id_table, +}; +gb_gpbridge_builtin_driver(spi_driver); -- 2.11.0