Commit dcd2086a authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

greybus: SDIO: convert to a gpbridge driver

This converts the SDIO driver to be a gpbridge driver, moving it away
from the "legacy" interface.

Testing Done: Tested on gbsim.
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
Signed-off-by: default avatarVaibhav 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: default avatarViresh Kumar <viresh.kumar@linaro.org>
Tested-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 315bea0e
...@@ -255,6 +255,7 @@ static const struct greybus_bundle_id gb_gpbridge_id_table[] = { ...@@ -255,6 +255,7 @@ static const struct greybus_bundle_id gb_gpbridge_id_table[] = {
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_GPIO) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_GPIO) },
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_I2C) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_I2C) },
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_PWM) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_PWM) },
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SDIO) },
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_UART) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_UART) },
{ }, { },
}; };
...@@ -295,8 +296,8 @@ static int __init gpbridge_init(void) ...@@ -295,8 +296,8 @@ static int __init gpbridge_init(void)
pr_err("error initializing uart driver\n"); pr_err("error initializing uart driver\n");
goto error_uart; goto error_uart;
} }
if (gb_sdio_protocol_init()) { if (gb_sdio_driver_init()) {
pr_err("error initializing sdio protocol\n"); pr_err("error initializing sdio driver\n");
goto error_sdio; goto error_sdio;
} }
if (gb_usb_protocol_init()) { if (gb_usb_protocol_init()) {
...@@ -319,7 +320,7 @@ static int __init gpbridge_init(void) ...@@ -319,7 +320,7 @@ static int __init gpbridge_init(void)
error_i2c: error_i2c:
gb_usb_protocol_exit(); gb_usb_protocol_exit();
error_usb: error_usb:
gb_sdio_protocol_exit(); gb_sdio_driver_exit();
error_sdio: error_sdio:
gb_uart_driver_exit(); gb_uart_driver_exit();
error_uart: error_uart:
...@@ -340,7 +341,7 @@ static void __exit gpbridge_exit(void) ...@@ -340,7 +341,7 @@ static void __exit gpbridge_exit(void)
gb_spi_protocol_exit(); gb_spi_protocol_exit();
gb_i2c_driver_exit(); gb_i2c_driver_exit();
gb_usb_protocol_exit(); gb_usb_protocol_exit();
gb_sdio_protocol_exit(); gb_sdio_driver_exit();
gb_uart_driver_exit(); gb_uart_driver_exit();
gb_pwm_driver_exit(); gb_pwm_driver_exit();
gb_gpio_driver_exit(); gb_gpio_driver_exit();
......
...@@ -75,8 +75,8 @@ extern void gb_pwm_driver_exit(void); ...@@ -75,8 +75,8 @@ extern void gb_pwm_driver_exit(void);
extern int gb_uart_driver_init(void); extern int gb_uart_driver_init(void);
extern void gb_uart_driver_exit(void); extern void gb_uart_driver_exit(void);
extern int gb_sdio_protocol_init(void); extern int gb_sdio_driver_init(void);
extern void gb_sdio_protocol_exit(void); extern void gb_sdio_driver_exit(void);
extern int gb_usb_protocol_init(void); extern int gb_usb_protocol_init(void);
extern void gb_usb_protocol_exit(void); extern void gb_usb_protocol_exit(void);
......
...@@ -237,7 +237,6 @@ static void legacy_disconnect(struct gb_bundle *bundle) ...@@ -237,7 +237,6 @@ static void legacy_disconnect(struct gb_bundle *bundle)
static const struct greybus_bundle_id legacy_id_table[] = { static const struct greybus_bundle_id legacy_id_table[] = {
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_USB) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_USB) },
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SDIO) },
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SPI) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SPI) },
{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_CAMERA) }, { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_CAMERA) },
{ } { }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
struct gb_sdio_host { struct gb_sdio_host {
struct gb_connection *connection; struct gb_connection *connection;
struct gpbridge_device *gpbdev;
struct mmc_host *mmc; struct mmc_host *mmc;
struct mmc_request *mrq; struct mmc_request *mrq;
struct mutex lock; /* lock for this host */ struct mutex lock; /* lock for this host */
...@@ -199,11 +200,12 @@ static int _gb_sdio_process_events(struct gb_sdio_host *host, u8 event) ...@@ -199,11 +200,12 @@ static int _gb_sdio_process_events(struct gb_sdio_host *host, u8 event)
return 0; return 0;
} }
static int gb_sdio_event_recv(u8 type, struct gb_operation *op) static int gb_sdio_request_handler(struct gb_operation *op)
{ {
struct gb_sdio_host *host = gb_connection_get_data(op->connection); struct gb_sdio_host *host = gb_connection_get_data(op->connection);
struct gb_message *request; struct gb_message *request;
struct gb_sdio_event_request *payload; struct gb_sdio_event_request *payload;
u8 type = op->type;
int ret = 0; int ret = 0;
u8 event; u8 event;
...@@ -706,27 +708,47 @@ static const struct mmc_host_ops gb_sdio_ops = { ...@@ -706,27 +708,47 @@ static const struct mmc_host_ops gb_sdio_ops = {
.get_cd = gb_mmc_get_cd, .get_cd = gb_mmc_get_cd,
}; };
static int gb_sdio_connection_init(struct gb_connection *connection) static int gb_sdio_probe(struct gpbridge_device *gpbdev,
const struct gpbridge_device_id *id)
{ {
struct gb_connection *connection;
struct mmc_host *mmc; struct mmc_host *mmc;
struct gb_sdio_host *host; struct gb_sdio_host *host;
size_t max_buffer; size_t max_buffer;
int ret = 0; int ret = 0;
mmc = mmc_alloc_host(sizeof(*host), &connection->bundle->dev); mmc = mmc_alloc_host(sizeof(*host), &gpbdev->dev);
if (!mmc) if (!mmc)
return -ENOMEM; return -ENOMEM;
connection = gb_connection_create(gpbdev->bundle,
le16_to_cpu(gpbdev->cport_desc->id),
gb_sdio_request_handler);
if (IS_ERR(connection)) {
ret = PTR_ERR(connection);
goto exit_mmc_free;
}
host = mmc_priv(mmc); host = mmc_priv(mmc);
host->mmc = mmc; host->mmc = mmc;
host->removed = true; host->removed = true;
host->connection = connection; host->connection = connection;
gb_connection_set_data(connection, host); gb_connection_set_data(connection, host);
host->gpbdev = gpbdev;
gb_gpbridge_set_data(gpbdev, host);
ret = gb_connection_enable_tx(connection);
if (ret)
goto exit_connection_destroy;
ret = gb_gpbridge_get_version(connection);
if (ret)
goto exit_connection_disable;
ret = gb_sdio_get_caps(host); ret = gb_sdio_get_caps(host);
if (ret < 0) if (ret < 0)
goto free_mmc; goto exit_connection_disable;
mmc->ops = &gb_sdio_ops; mmc->ops = &gb_sdio_ops;
...@@ -740,45 +762,50 @@ static int gb_sdio_connection_init(struct gb_connection *connection) ...@@ -740,45 +762,50 @@ static int gb_sdio_connection_init(struct gb_connection *connection)
host->xfer_buffer = kzalloc(max_buffer, GFP_KERNEL); host->xfer_buffer = kzalloc(max_buffer, GFP_KERNEL);
if (!host->xfer_buffer) { if (!host->xfer_buffer) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_mmc; goto exit_connection_disable;
} }
mutex_init(&host->lock); mutex_init(&host->lock);
spin_lock_init(&host->xfer); spin_lock_init(&host->xfer);
host->mrq_workqueue = alloc_workqueue("mmc-%s", 0, 1, host->mrq_workqueue = alloc_workqueue("mmc-%s", 0, 1,
dev_name(&connection->bundle->dev)); dev_name(&gpbdev->dev));
if (!host->mrq_workqueue) { if (!host->mrq_workqueue) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_buffer; goto exit_buf_free;
} }
INIT_WORK(&host->mrqwork, gb_sdio_mrq_work); INIT_WORK(&host->mrqwork, gb_sdio_mrq_work);
ret = gb_connection_enable(connection);
if (ret)
goto exit_wq_destroy;
ret = mmc_add_host(mmc); ret = mmc_add_host(mmc);
if (ret < 0) if (ret < 0)
goto free_work; goto exit_wq_destroy;
host->removed = false; host->removed = false;
ret = _gb_sdio_process_events(host, host->queued_events); ret = _gb_sdio_process_events(host, host->queued_events);
host->queued_events = 0; host->queued_events = 0;
return ret; return ret;
free_work: exit_wq_destroy:
destroy_workqueue(host->mrq_workqueue); destroy_workqueue(host->mrq_workqueue);
free_buffer: exit_buf_free:
kfree(host->xfer_buffer); kfree(host->xfer_buffer);
free_mmc: exit_connection_disable:
gb_connection_set_data(connection, NULL); gb_connection_disable(connection);
exit_connection_destroy:
gb_connection_destroy(connection);
exit_mmc_free:
mmc_free_host(mmc); mmc_free_host(mmc);
return ret; return ret;
} }
static void gb_sdio_connection_exit(struct gb_connection *connection) static void gb_sdio_remove(struct gpbridge_device *gpbdev)
{ {
struct gb_sdio_host *host = gb_gpbridge_get_data(gpbdev);
struct gb_connection *connection = host->connection;
struct mmc_host *mmc; struct mmc_host *mmc;
struct gb_sdio_host *host = gb_connection_get_data(connection);
if (!host)
return;
mutex_lock(&host->lock); mutex_lock(&host->lock);
host->removed = true; host->removed = true;
...@@ -788,19 +815,23 @@ static void gb_sdio_connection_exit(struct gb_connection *connection) ...@@ -788,19 +815,23 @@ static void gb_sdio_connection_exit(struct gb_connection *connection)
flush_workqueue(host->mrq_workqueue); flush_workqueue(host->mrq_workqueue);
destroy_workqueue(host->mrq_workqueue); destroy_workqueue(host->mrq_workqueue);
gb_connection_disable_rx(connection);
mmc_remove_host(mmc); mmc_remove_host(mmc);
gb_connection_disable(connection);
gb_connection_destroy(connection);
kfree(host->xfer_buffer); kfree(host->xfer_buffer);
mmc_free_host(mmc); mmc_free_host(mmc);
} }
static struct gb_protocol sdio_protocol = { static const struct gpbridge_device_id gb_sdio_id_table[] = {
.name = "sdio", { GPBRIDGE_PROTOCOL(GREYBUS_PROTOCOL_SDIO) },
.id = GREYBUS_PROTOCOL_SDIO, { },
.major = GB_SDIO_VERSION_MAJOR,
.minor = GB_SDIO_VERSION_MINOR,
.connection_init = gb_sdio_connection_init,
.connection_exit = gb_sdio_connection_exit,
.request_recv = gb_sdio_event_recv,
}; };
gb_builtin_protocol_driver(sdio_protocol); static struct gpbridge_driver sdio_driver = {
.name = "sdio",
.probe = gb_sdio_probe,
.remove = gb_sdio_remove,
.id_table = gb_sdio_id_table,
};
gb_gpbridge_builtin_driver(sdio_driver);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment