2 * Greybus legacy-protocol driver
4 * Copyright 2015 Google Inc.
5 * Copyright 2015 Linaro Ltd.
7 * Released under the GPLv2 only.
15 struct legacy_connection {
16 struct gb_connection *connection;
18 struct gb_protocol *protocol;
23 struct legacy_connection *connections;
27 static int legacy_connection_get_version(struct gb_connection *connection)
31 ret = gb_protocol_get_version(connection);
33 dev_err(&connection->hd->dev,
34 "%s: failed to get protocol version: %d\n",
35 connection->name, ret);
42 static int legacy_request_handler(struct gb_operation *operation)
44 struct gb_protocol *protocol = operation->connection->protocol;
46 return protocol->request_recv(operation->type, operation);
49 static int legacy_connection_init(struct legacy_connection *lc)
51 struct gb_connection *connection = lc->connection;
54 dev_dbg(&connection->bundle->dev, "%s - %s\n", __func__,
57 ret = gb_connection_enable(connection);
61 ret = legacy_connection_get_version(connection);
65 ret = connection->protocol->connection_init(connection);
69 lc->initialized = true;
74 gb_connection_disable(connection);
79 static void legacy_connection_exit(struct legacy_connection *lc)
81 struct gb_connection *connection = lc->connection;
86 gb_connection_disable(connection);
88 connection->protocol->connection_exit(connection);
90 lc->initialized = false;
93 static int legacy_connection_create(struct legacy_connection *lc,
94 struct gb_bundle *bundle,
95 struct greybus_descriptor_cport *desc)
97 struct gb_connection *connection;
98 struct gb_protocol *protocol;
99 gb_request_handler_t handler;
104 * The legacy protocols have always been looked up using a hard-coded
105 * version of 0.1, despite (or perhaps rather, due to) the fact that
106 * module version negotiation could not take place until after the
107 * protocol was bound.
112 protocol = gb_protocol_get(desc->protocol_id, major, minor);
114 dev_err(&bundle->dev,
115 "protocol 0x%02x version %u.%u not found\n",
116 desc->protocol_id, major, minor);
117 return -EPROTONOSUPPORT;
120 if (protocol->request_recv)
121 handler = legacy_request_handler;
125 connection = gb_connection_create(bundle, le16_to_cpu(desc->id),
127 if (IS_ERR(connection)) {
128 ret = PTR_ERR(connection);
129 goto err_protocol_put;
133 * NOTE: We need to keep a pointer to the protocol in the actual
134 * connection structure for now.
136 connection->protocol = protocol;
138 lc->connection = connection;
139 lc->protocol = protocol;
144 gb_protocol_put(protocol);
149 static void legacy_connection_destroy(struct legacy_connection *lc)
154 lc->connection->protocol = NULL;
156 gb_connection_destroy(lc->connection);
158 gb_protocol_put(lc->protocol);
161 static int legacy_probe(struct gb_bundle *bundle,
162 const struct greybus_bundle_id *id)
164 struct greybus_descriptor_cport *cport_desc;
165 struct legacy_data *data;
166 struct legacy_connection *lc;
170 dev_dbg(&bundle->dev,
171 "%s - bundle class = 0x%02x, num_cports = %zu\n",
172 __func__, bundle->class, bundle->num_cports);
174 data = kzalloc(sizeof(*data), GFP_KERNEL);
178 data->num_cports = bundle->num_cports;
179 data->connections = kcalloc(data->num_cports,
180 sizeof(*data->connections),
182 if (!data->connections) {
187 for (i = 0; i < data->num_cports; ++i) {
188 cport_desc = &bundle->cport_desc[i];
189 lc = &data->connections[i];
191 ret = legacy_connection_create(lc, bundle, cport_desc);
193 goto err_connections_destroy;
196 greybus_set_drvdata(bundle, data);
198 for (i = 0; i < data->num_cports; ++i) {
199 lc = &data->connections[i];
201 ret = legacy_connection_init(lc);
203 goto err_connections_disable;
208 err_connections_disable:
209 for (--i; i >= 0; --i)
210 legacy_connection_exit(&data->connections[i]);
211 err_connections_destroy:
212 for (i = 0; i < data->num_cports; ++i)
213 legacy_connection_destroy(&data->connections[i]);
214 kfree(data->connections);
221 static void legacy_disconnect(struct gb_bundle *bundle)
223 struct legacy_data *data = greybus_get_drvdata(bundle);
226 dev_dbg(&bundle->dev, "%s - bundle class = 0x%02x\n", __func__,
229 for (i = 0; i < data->num_cports; ++i) {
230 legacy_connection_exit(&data->connections[i]);
231 legacy_connection_destroy(&data->connections[i]);
234 kfree(data->connections);
238 static const struct greybus_bundle_id legacy_id_table[] = {
239 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_GPIO) },
240 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_I2C) },
241 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_UART) },
242 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_USB) },
243 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SDIO) },
244 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_POWER_SUPPLY) },
245 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_PWM) },
246 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SPI) },
247 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_DISPLAY) },
248 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_CAMERA) },
249 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SENSOR) },
250 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LIGHTS) },
251 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LOOPBACK) },
252 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO_MGMT) },
253 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO_DATA) },
254 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_SVC) },
255 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_FIRMWARE) },
256 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_RAW) },
259 MODULE_DEVICE_TABLE(greybus, legacy_id_table);
261 static struct greybus_driver legacy_driver = {
263 .probe = legacy_probe,
264 .disconnect = legacy_disconnect,
265 .id_table = legacy_id_table,
268 int gb_legacy_init(void)
270 return greybus_register(&legacy_driver);
273 void gb_legacy_exit(void)
275 greybus_deregister(&legacy_driver);