forked from Minki/linux
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 <gregkh@google.com> Signed-off-by: Vaibhav Hiremath <vaibhav.hiremath@linaro.org> [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 <viresh.kumar@linaro.org> Tested-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
parent
dcd2086aa8
commit
ba3e67001b
@ -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();
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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) },
|
||||
{ }
|
||||
};
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user