2 * Greybus Firmware Core Bundle Driver.
4 * Copyright 2016 Google Inc.
5 * Copyright 2016 Linaro Ltd.
7 * Released under the GPLv2 only.
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 #include <linux/firmware.h>
17 struct gb_connection *download_connection;
18 struct gb_connection *mgmt_connection;
19 struct gb_connection *spi_connection;
22 struct gb_connection *to_fw_mgmt_connection(struct device *dev)
24 struct gb_fw_core *fw_core = dev_get_drvdata(dev);
26 return fw_core->mgmt_connection;
29 static int gb_fw_spi_connection_init(struct gb_connection *connection)
36 ret = gb_connection_enable(connection);
40 ret = gb_spilib_master_init(connection, &connection->bundle->dev);
42 gb_connection_disable(connection);
49 static void gb_fw_spi_connection_exit(struct gb_connection *connection)
54 gb_spilib_master_exit(connection);
55 gb_connection_disable(connection);
58 static int gb_fw_core_probe(struct gb_bundle *bundle,
59 const struct greybus_bundle_id *id)
61 struct greybus_descriptor_cport *cport_desc;
62 struct gb_connection *connection;
63 struct gb_fw_core *fw_core;
68 fw_core = kzalloc(sizeof(*fw_core), GFP_KERNEL);
72 /* Parse CPorts and create connections */
73 for (i = 0; i < bundle->num_cports; i++) {
74 cport_desc = &bundle->cport_desc[i];
75 cport_id = le16_to_cpu(cport_desc->id);
76 protocol_id = cport_desc->protocol_id;
78 switch (protocol_id) {
79 case GREYBUS_PROTOCOL_FW_MANAGEMENT:
80 /* Disallow multiple Firmware Management CPorts */
81 if (fw_core->mgmt_connection) {
83 "multiple management CPorts found\n");
85 goto err_destroy_connections;
88 connection = gb_connection_create(bundle, cport_id,
89 gb_fw_mgmt_request_handler);
90 if (IS_ERR(connection)) {
91 ret = PTR_ERR(connection);
93 "failed to create management connection (%d)\n",
95 goto err_destroy_connections;
98 fw_core->mgmt_connection = connection;
100 case GREYBUS_PROTOCOL_FW_DOWNLOAD:
101 /* Disallow multiple Firmware Download CPorts */
102 if (fw_core->download_connection) {
103 dev_err(&bundle->dev,
104 "multiple download CPorts found\n");
106 goto err_destroy_connections;
109 connection = gb_connection_create(bundle, cport_id,
110 gb_fw_download_request_handler);
111 if (IS_ERR(connection)) {
112 dev_err(&bundle->dev, "failed to create download connection (%ld)\n",
113 PTR_ERR(connection));
115 fw_core->download_connection = connection;
119 case GREYBUS_PROTOCOL_SPI:
120 /* Disallow multiple SPI CPorts */
121 if (fw_core->spi_connection) {
122 dev_err(&bundle->dev,
123 "multiple SPI CPorts found\n");
125 goto err_destroy_connections;
128 connection = gb_connection_create(bundle, cport_id,
130 if (IS_ERR(connection)) {
131 dev_err(&bundle->dev, "failed to create SPI connection (%ld)\n",
132 PTR_ERR(connection));
134 fw_core->spi_connection = connection;
139 dev_err(&bundle->dev, "invalid protocol id (0x%02x)\n",
142 goto err_free_fw_core;
146 /* Firmware Management connection is mandatory */
147 if (!fw_core->mgmt_connection) {
148 dev_err(&bundle->dev, "missing management connection\n");
150 goto err_destroy_connections;
153 ret = gb_fw_download_connection_init(fw_core->download_connection);
155 /* We may still be able to work with the Interface */
156 dev_err(&bundle->dev, "failed to initialize firmware download connection, disable it (%d)\n",
158 gb_connection_destroy(fw_core->download_connection);
159 fw_core->download_connection = NULL;
162 ret = gb_fw_spi_connection_init(fw_core->spi_connection);
164 /* We may still be able to work with the Interface */
165 dev_err(&bundle->dev, "failed to initialize SPI connection, disable it (%d)\n",
167 gb_connection_destroy(fw_core->spi_connection);
168 fw_core->spi_connection = NULL;
171 ret = gb_fw_mgmt_connection_init(fw_core->mgmt_connection);
173 /* We may still be able to work with the Interface */
174 dev_err(&bundle->dev, "failed to initialize firmware management connection, disable it (%d)\n",
176 goto err_exit_connections;
179 greybus_set_drvdata(bundle, fw_core);
183 err_exit_connections:
184 gb_fw_spi_connection_exit(fw_core->spi_connection);
185 gb_fw_download_connection_exit(fw_core->download_connection);
186 err_destroy_connections:
187 gb_connection_destroy(fw_core->mgmt_connection);
188 gb_connection_destroy(fw_core->spi_connection);
189 gb_connection_destroy(fw_core->download_connection);
196 static void gb_fw_core_disconnect(struct gb_bundle *bundle)
198 struct gb_fw_core *fw_core = greybus_get_drvdata(bundle);
200 gb_fw_mgmt_connection_exit(fw_core->mgmt_connection);
201 gb_fw_spi_connection_exit(fw_core->spi_connection);
202 gb_fw_download_connection_exit(fw_core->download_connection);
204 gb_connection_destroy(fw_core->mgmt_connection);
205 gb_connection_destroy(fw_core->spi_connection);
206 gb_connection_destroy(fw_core->download_connection);
211 static const struct greybus_bundle_id gb_fw_core_id_table[] = {
212 { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_FW_MANAGEMENT) },
216 static struct greybus_driver gb_fw_core_driver = {
217 .name = "gb-firmware",
218 .probe = gb_fw_core_probe,
219 .disconnect = gb_fw_core_disconnect,
220 .id_table = gb_fw_core_id_table,
223 static int fw_core_init(void)
227 ret = fw_mgmt_init();
229 pr_err("Failed to initialize fw-mgmt core (%d)\n", ret);
233 ret = greybus_register(&gb_fw_core_driver);
241 module_init(fw_core_init);
243 static void __exit fw_core_exit(void)
245 greybus_deregister(&gb_fw_core_driver);
248 module_exit(fw_core_exit);
250 MODULE_ALIAS("greybus:firmware");
251 MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
252 MODULE_DESCRIPTION("Greybus Firmware Bundle Driver");
253 MODULE_LICENSE("GPL v2");