xref: /openbmc/linux/drivers/greybus/control.c (revision 976e3645923bdd2fe7893aae33fd7a21098bfb28)
1*8465def4SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2*8465def4SGreg Kroah-Hartman /*
3*8465def4SGreg Kroah-Hartman  * Greybus CPort control protocol.
4*8465def4SGreg Kroah-Hartman  *
5*8465def4SGreg Kroah-Hartman  * Copyright 2015 Google Inc.
6*8465def4SGreg Kroah-Hartman  * Copyright 2015 Linaro Ltd.
7*8465def4SGreg Kroah-Hartman  */
8*8465def4SGreg Kroah-Hartman 
9*8465def4SGreg Kroah-Hartman #include <linux/kernel.h>
10*8465def4SGreg Kroah-Hartman #include <linux/module.h>
11*8465def4SGreg Kroah-Hartman #include <linux/slab.h>
12*8465def4SGreg Kroah-Hartman #include <linux/greybus.h>
13*8465def4SGreg Kroah-Hartman 
14*8465def4SGreg Kroah-Hartman /* Highest control-protocol version supported */
15*8465def4SGreg Kroah-Hartman #define GB_CONTROL_VERSION_MAJOR	0
16*8465def4SGreg Kroah-Hartman #define GB_CONTROL_VERSION_MINOR	1
17*8465def4SGreg Kroah-Hartman 
gb_control_get_version(struct gb_control * control)18*8465def4SGreg Kroah-Hartman static int gb_control_get_version(struct gb_control *control)
19*8465def4SGreg Kroah-Hartman {
20*8465def4SGreg Kroah-Hartman 	struct gb_interface *intf = control->connection->intf;
21*8465def4SGreg Kroah-Hartman 	struct gb_control_version_request request;
22*8465def4SGreg Kroah-Hartman 	struct gb_control_version_response response;
23*8465def4SGreg Kroah-Hartman 	int ret;
24*8465def4SGreg Kroah-Hartman 
25*8465def4SGreg Kroah-Hartman 	request.major = GB_CONTROL_VERSION_MAJOR;
26*8465def4SGreg Kroah-Hartman 	request.minor = GB_CONTROL_VERSION_MINOR;
27*8465def4SGreg Kroah-Hartman 
28*8465def4SGreg Kroah-Hartman 	ret = gb_operation_sync(control->connection,
29*8465def4SGreg Kroah-Hartman 				GB_CONTROL_TYPE_VERSION,
30*8465def4SGreg Kroah-Hartman 				&request, sizeof(request), &response,
31*8465def4SGreg Kroah-Hartman 				sizeof(response));
32*8465def4SGreg Kroah-Hartman 	if (ret) {
33*8465def4SGreg Kroah-Hartman 		dev_err(&intf->dev,
34*8465def4SGreg Kroah-Hartman 			"failed to get control-protocol version: %d\n",
35*8465def4SGreg Kroah-Hartman 			ret);
36*8465def4SGreg Kroah-Hartman 		return ret;
37*8465def4SGreg Kroah-Hartman 	}
38*8465def4SGreg Kroah-Hartman 
39*8465def4SGreg Kroah-Hartman 	if (response.major > request.major) {
40*8465def4SGreg Kroah-Hartman 		dev_err(&intf->dev,
41*8465def4SGreg Kroah-Hartman 			"unsupported major control-protocol version (%u > %u)\n",
42*8465def4SGreg Kroah-Hartman 			response.major, request.major);
43*8465def4SGreg Kroah-Hartman 		return -ENOTSUPP;
44*8465def4SGreg Kroah-Hartman 	}
45*8465def4SGreg Kroah-Hartman 
46*8465def4SGreg Kroah-Hartman 	control->protocol_major = response.major;
47*8465def4SGreg Kroah-Hartman 	control->protocol_minor = response.minor;
48*8465def4SGreg Kroah-Hartman 
49*8465def4SGreg Kroah-Hartman 	dev_dbg(&intf->dev, "%s - %u.%u\n", __func__, response.major,
50*8465def4SGreg Kroah-Hartman 		response.minor);
51*8465def4SGreg Kroah-Hartman 
52*8465def4SGreg Kroah-Hartman 	return 0;
53*8465def4SGreg Kroah-Hartman }
54*8465def4SGreg Kroah-Hartman 
gb_control_get_bundle_version(struct gb_control * control,struct gb_bundle * bundle)55*8465def4SGreg Kroah-Hartman static int gb_control_get_bundle_version(struct gb_control *control,
56*8465def4SGreg Kroah-Hartman 					 struct gb_bundle *bundle)
57*8465def4SGreg Kroah-Hartman {
58*8465def4SGreg Kroah-Hartman 	struct gb_interface *intf = control->connection->intf;
59*8465def4SGreg Kroah-Hartman 	struct gb_control_bundle_version_request request;
60*8465def4SGreg Kroah-Hartman 	struct gb_control_bundle_version_response response;
61*8465def4SGreg Kroah-Hartman 	int ret;
62*8465def4SGreg Kroah-Hartman 
63*8465def4SGreg Kroah-Hartman 	request.bundle_id = bundle->id;
64*8465def4SGreg Kroah-Hartman 
65*8465def4SGreg Kroah-Hartman 	ret = gb_operation_sync(control->connection,
66*8465def4SGreg Kroah-Hartman 				GB_CONTROL_TYPE_BUNDLE_VERSION,
67*8465def4SGreg Kroah-Hartman 				&request, sizeof(request),
68*8465def4SGreg Kroah-Hartman 				&response, sizeof(response));
69*8465def4SGreg Kroah-Hartman 	if (ret) {
70*8465def4SGreg Kroah-Hartman 		dev_err(&intf->dev,
71*8465def4SGreg Kroah-Hartman 			"failed to get bundle %u class version: %d\n",
72*8465def4SGreg Kroah-Hartman 			bundle->id, ret);
73*8465def4SGreg Kroah-Hartman 		return ret;
74*8465def4SGreg Kroah-Hartman 	}
75*8465def4SGreg Kroah-Hartman 
76*8465def4SGreg Kroah-Hartman 	bundle->class_major = response.major;
77*8465def4SGreg Kroah-Hartman 	bundle->class_minor = response.minor;
78*8465def4SGreg Kroah-Hartman 
79*8465def4SGreg Kroah-Hartman 	dev_dbg(&intf->dev, "%s - %u: %u.%u\n", __func__, bundle->id,
80*8465def4SGreg Kroah-Hartman 		response.major, response.minor);
81*8465def4SGreg Kroah-Hartman 
82*8465def4SGreg Kroah-Hartman 	return 0;
83*8465def4SGreg Kroah-Hartman }
84*8465def4SGreg Kroah-Hartman 
gb_control_get_bundle_versions(struct gb_control * control)85*8465def4SGreg Kroah-Hartman int gb_control_get_bundle_versions(struct gb_control *control)
86*8465def4SGreg Kroah-Hartman {
87*8465def4SGreg Kroah-Hartman 	struct gb_interface *intf = control->connection->intf;
88*8465def4SGreg Kroah-Hartman 	struct gb_bundle *bundle;
89*8465def4SGreg Kroah-Hartman 	int ret;
90*8465def4SGreg Kroah-Hartman 
91*8465def4SGreg Kroah-Hartman 	if (!control->has_bundle_version)
92*8465def4SGreg Kroah-Hartman 		return 0;
93*8465def4SGreg Kroah-Hartman 
94*8465def4SGreg Kroah-Hartman 	list_for_each_entry(bundle, &intf->bundles, links) {
95*8465def4SGreg Kroah-Hartman 		ret = gb_control_get_bundle_version(control, bundle);
96*8465def4SGreg Kroah-Hartman 		if (ret)
97*8465def4SGreg Kroah-Hartman 			return ret;
98*8465def4SGreg Kroah-Hartman 	}
99*8465def4SGreg Kroah-Hartman 
100*8465def4SGreg Kroah-Hartman 	return 0;
101*8465def4SGreg Kroah-Hartman }
102*8465def4SGreg Kroah-Hartman 
103*8465def4SGreg Kroah-Hartman /* Get Manifest's size from the interface */
gb_control_get_manifest_size_operation(struct gb_interface * intf)104*8465def4SGreg Kroah-Hartman int gb_control_get_manifest_size_operation(struct gb_interface *intf)
105*8465def4SGreg Kroah-Hartman {
106*8465def4SGreg Kroah-Hartman 	struct gb_control_get_manifest_size_response response;
107*8465def4SGreg Kroah-Hartman 	struct gb_connection *connection = intf->control->connection;
108*8465def4SGreg Kroah-Hartman 	int ret;
109*8465def4SGreg Kroah-Hartman 
110*8465def4SGreg Kroah-Hartman 	ret = gb_operation_sync(connection, GB_CONTROL_TYPE_GET_MANIFEST_SIZE,
111*8465def4SGreg Kroah-Hartman 				NULL, 0, &response, sizeof(response));
112*8465def4SGreg Kroah-Hartman 	if (ret) {
113*8465def4SGreg Kroah-Hartman 		dev_err(&connection->intf->dev,
114*8465def4SGreg Kroah-Hartman 			"failed to get manifest size: %d\n", ret);
115*8465def4SGreg Kroah-Hartman 		return ret;
116*8465def4SGreg Kroah-Hartman 	}
117*8465def4SGreg Kroah-Hartman 
118*8465def4SGreg Kroah-Hartman 	return le16_to_cpu(response.size);
119*8465def4SGreg Kroah-Hartman }
120*8465def4SGreg Kroah-Hartman 
121*8465def4SGreg Kroah-Hartman /* Reads Manifest from the interface */
gb_control_get_manifest_operation(struct gb_interface * intf,void * manifest,size_t size)122*8465def4SGreg Kroah-Hartman int gb_control_get_manifest_operation(struct gb_interface *intf, void *manifest,
123*8465def4SGreg Kroah-Hartman 				      size_t size)
124*8465def4SGreg Kroah-Hartman {
125*8465def4SGreg Kroah-Hartman 	struct gb_connection *connection = intf->control->connection;
126*8465def4SGreg Kroah-Hartman 
127*8465def4SGreg Kroah-Hartman 	return gb_operation_sync(connection, GB_CONTROL_TYPE_GET_MANIFEST,
128*8465def4SGreg Kroah-Hartman 				NULL, 0, manifest, size);
129*8465def4SGreg Kroah-Hartman }
130*8465def4SGreg Kroah-Hartman 
gb_control_connected_operation(struct gb_control * control,u16 cport_id)131*8465def4SGreg Kroah-Hartman int gb_control_connected_operation(struct gb_control *control, u16 cport_id)
132*8465def4SGreg Kroah-Hartman {
133*8465def4SGreg Kroah-Hartman 	struct gb_control_connected_request request;
134*8465def4SGreg Kroah-Hartman 
135*8465def4SGreg Kroah-Hartman 	request.cport_id = cpu_to_le16(cport_id);
136*8465def4SGreg Kroah-Hartman 	return gb_operation_sync(control->connection, GB_CONTROL_TYPE_CONNECTED,
137*8465def4SGreg Kroah-Hartman 				 &request, sizeof(request), NULL, 0);
138*8465def4SGreg Kroah-Hartman }
139*8465def4SGreg Kroah-Hartman 
gb_control_disconnected_operation(struct gb_control * control,u16 cport_id)140*8465def4SGreg Kroah-Hartman int gb_control_disconnected_operation(struct gb_control *control, u16 cport_id)
141*8465def4SGreg Kroah-Hartman {
142*8465def4SGreg Kroah-Hartman 	struct gb_control_disconnected_request request;
143*8465def4SGreg Kroah-Hartman 
144*8465def4SGreg Kroah-Hartman 	request.cport_id = cpu_to_le16(cport_id);
145*8465def4SGreg Kroah-Hartman 	return gb_operation_sync(control->connection,
146*8465def4SGreg Kroah-Hartman 				 GB_CONTROL_TYPE_DISCONNECTED, &request,
147*8465def4SGreg Kroah-Hartman 				 sizeof(request), NULL, 0);
148*8465def4SGreg Kroah-Hartman }
149*8465def4SGreg Kroah-Hartman 
gb_control_disconnecting_operation(struct gb_control * control,u16 cport_id)150*8465def4SGreg Kroah-Hartman int gb_control_disconnecting_operation(struct gb_control *control,
151*8465def4SGreg Kroah-Hartman 				       u16 cport_id)
152*8465def4SGreg Kroah-Hartman {
153*8465def4SGreg Kroah-Hartman 	struct gb_control_disconnecting_request *request;
154*8465def4SGreg Kroah-Hartman 	struct gb_operation *operation;
155*8465def4SGreg Kroah-Hartman 	int ret;
156*8465def4SGreg Kroah-Hartman 
157*8465def4SGreg Kroah-Hartman 	operation = gb_operation_create_core(control->connection,
158*8465def4SGreg Kroah-Hartman 					     GB_CONTROL_TYPE_DISCONNECTING,
159*8465def4SGreg Kroah-Hartman 					     sizeof(*request), 0, 0,
160*8465def4SGreg Kroah-Hartman 					     GFP_KERNEL);
161*8465def4SGreg Kroah-Hartman 	if (!operation)
162*8465def4SGreg Kroah-Hartman 		return -ENOMEM;
163*8465def4SGreg Kroah-Hartman 
164*8465def4SGreg Kroah-Hartman 	request = operation->request->payload;
165*8465def4SGreg Kroah-Hartman 	request->cport_id = cpu_to_le16(cport_id);
166*8465def4SGreg Kroah-Hartman 
167*8465def4SGreg Kroah-Hartman 	ret = gb_operation_request_send_sync(operation);
168*8465def4SGreg Kroah-Hartman 	if (ret) {
169*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "failed to send disconnecting: %d\n",
170*8465def4SGreg Kroah-Hartman 			ret);
171*8465def4SGreg Kroah-Hartman 	}
172*8465def4SGreg Kroah-Hartman 
173*8465def4SGreg Kroah-Hartman 	gb_operation_put(operation);
174*8465def4SGreg Kroah-Hartman 
175*8465def4SGreg Kroah-Hartman 	return ret;
176*8465def4SGreg Kroah-Hartman }
177*8465def4SGreg Kroah-Hartman 
gb_control_mode_switch_operation(struct gb_control * control)178*8465def4SGreg Kroah-Hartman int gb_control_mode_switch_operation(struct gb_control *control)
179*8465def4SGreg Kroah-Hartman {
180*8465def4SGreg Kroah-Hartman 	struct gb_operation *operation;
181*8465def4SGreg Kroah-Hartman 	int ret;
182*8465def4SGreg Kroah-Hartman 
183*8465def4SGreg Kroah-Hartman 	operation = gb_operation_create_core(control->connection,
184*8465def4SGreg Kroah-Hartman 					     GB_CONTROL_TYPE_MODE_SWITCH,
185*8465def4SGreg Kroah-Hartman 					     0, 0,
186*8465def4SGreg Kroah-Hartman 					     GB_OPERATION_FLAG_UNIDIRECTIONAL,
187*8465def4SGreg Kroah-Hartman 					     GFP_KERNEL);
188*8465def4SGreg Kroah-Hartman 	if (!operation)
189*8465def4SGreg Kroah-Hartman 		return -ENOMEM;
190*8465def4SGreg Kroah-Hartman 
191*8465def4SGreg Kroah-Hartman 	ret = gb_operation_request_send_sync(operation);
192*8465def4SGreg Kroah-Hartman 	if (ret)
193*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "failed to send mode switch: %d\n", ret);
194*8465def4SGreg Kroah-Hartman 
195*8465def4SGreg Kroah-Hartman 	gb_operation_put(operation);
196*8465def4SGreg Kroah-Hartman 
197*8465def4SGreg Kroah-Hartman 	return ret;
198*8465def4SGreg Kroah-Hartman }
199*8465def4SGreg Kroah-Hartman 
gb_control_bundle_pm_status_map(u8 status)200*8465def4SGreg Kroah-Hartman static int gb_control_bundle_pm_status_map(u8 status)
201*8465def4SGreg Kroah-Hartman {
202*8465def4SGreg Kroah-Hartman 	switch (status) {
203*8465def4SGreg Kroah-Hartman 	case GB_CONTROL_BUNDLE_PM_INVAL:
204*8465def4SGreg Kroah-Hartman 		return -EINVAL;
205*8465def4SGreg Kroah-Hartman 	case GB_CONTROL_BUNDLE_PM_BUSY:
206*8465def4SGreg Kroah-Hartman 		return -EBUSY;
207*8465def4SGreg Kroah-Hartman 	case GB_CONTROL_BUNDLE_PM_NA:
208*8465def4SGreg Kroah-Hartman 		return -ENOMSG;
209*8465def4SGreg Kroah-Hartman 	case GB_CONTROL_BUNDLE_PM_FAIL:
210*8465def4SGreg Kroah-Hartman 	default:
211*8465def4SGreg Kroah-Hartman 		return -EREMOTEIO;
212*8465def4SGreg Kroah-Hartman 	}
213*8465def4SGreg Kroah-Hartman }
214*8465def4SGreg Kroah-Hartman 
gb_control_bundle_suspend(struct gb_control * control,u8 bundle_id)215*8465def4SGreg Kroah-Hartman int gb_control_bundle_suspend(struct gb_control *control, u8 bundle_id)
216*8465def4SGreg Kroah-Hartman {
217*8465def4SGreg Kroah-Hartman 	struct gb_control_bundle_pm_request request;
218*8465def4SGreg Kroah-Hartman 	struct gb_control_bundle_pm_response response;
219*8465def4SGreg Kroah-Hartman 	int ret;
220*8465def4SGreg Kroah-Hartman 
221*8465def4SGreg Kroah-Hartman 	request.bundle_id = bundle_id;
222*8465def4SGreg Kroah-Hartman 	ret = gb_operation_sync(control->connection,
223*8465def4SGreg Kroah-Hartman 				GB_CONTROL_TYPE_BUNDLE_SUSPEND, &request,
224*8465def4SGreg Kroah-Hartman 				sizeof(request), &response, sizeof(response));
225*8465def4SGreg Kroah-Hartman 	if (ret) {
226*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "failed to send bundle %u suspend: %d\n",
227*8465def4SGreg Kroah-Hartman 			bundle_id, ret);
228*8465def4SGreg Kroah-Hartman 		return ret;
229*8465def4SGreg Kroah-Hartman 	}
230*8465def4SGreg Kroah-Hartman 
231*8465def4SGreg Kroah-Hartman 	if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
232*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "failed to suspend bundle %u: %d\n",
233*8465def4SGreg Kroah-Hartman 			bundle_id, response.status);
234*8465def4SGreg Kroah-Hartman 		return gb_control_bundle_pm_status_map(response.status);
235*8465def4SGreg Kroah-Hartman 	}
236*8465def4SGreg Kroah-Hartman 
237*8465def4SGreg Kroah-Hartman 	return 0;
238*8465def4SGreg Kroah-Hartman }
239*8465def4SGreg Kroah-Hartman 
gb_control_bundle_resume(struct gb_control * control,u8 bundle_id)240*8465def4SGreg Kroah-Hartman int gb_control_bundle_resume(struct gb_control *control, u8 bundle_id)
241*8465def4SGreg Kroah-Hartman {
242*8465def4SGreg Kroah-Hartman 	struct gb_control_bundle_pm_request request;
243*8465def4SGreg Kroah-Hartman 	struct gb_control_bundle_pm_response response;
244*8465def4SGreg Kroah-Hartman 	int ret;
245*8465def4SGreg Kroah-Hartman 
246*8465def4SGreg Kroah-Hartman 	request.bundle_id = bundle_id;
247*8465def4SGreg Kroah-Hartman 	ret = gb_operation_sync(control->connection,
248*8465def4SGreg Kroah-Hartman 				GB_CONTROL_TYPE_BUNDLE_RESUME, &request,
249*8465def4SGreg Kroah-Hartman 				sizeof(request), &response, sizeof(response));
250*8465def4SGreg Kroah-Hartman 	if (ret) {
251*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "failed to send bundle %u resume: %d\n",
252*8465def4SGreg Kroah-Hartman 			bundle_id, ret);
253*8465def4SGreg Kroah-Hartman 		return ret;
254*8465def4SGreg Kroah-Hartman 	}
255*8465def4SGreg Kroah-Hartman 
256*8465def4SGreg Kroah-Hartman 	if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
257*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "failed to resume bundle %u: %d\n",
258*8465def4SGreg Kroah-Hartman 			bundle_id, response.status);
259*8465def4SGreg Kroah-Hartman 		return gb_control_bundle_pm_status_map(response.status);
260*8465def4SGreg Kroah-Hartman 	}
261*8465def4SGreg Kroah-Hartman 
262*8465def4SGreg Kroah-Hartman 	return 0;
263*8465def4SGreg Kroah-Hartman }
264*8465def4SGreg Kroah-Hartman 
gb_control_bundle_deactivate(struct gb_control * control,u8 bundle_id)265*8465def4SGreg Kroah-Hartman int gb_control_bundle_deactivate(struct gb_control *control, u8 bundle_id)
266*8465def4SGreg Kroah-Hartman {
267*8465def4SGreg Kroah-Hartman 	struct gb_control_bundle_pm_request request;
268*8465def4SGreg Kroah-Hartman 	struct gb_control_bundle_pm_response response;
269*8465def4SGreg Kroah-Hartman 	int ret;
270*8465def4SGreg Kroah-Hartman 
271*8465def4SGreg Kroah-Hartman 	request.bundle_id = bundle_id;
272*8465def4SGreg Kroah-Hartman 	ret = gb_operation_sync(control->connection,
273*8465def4SGreg Kroah-Hartman 				GB_CONTROL_TYPE_BUNDLE_DEACTIVATE, &request,
274*8465def4SGreg Kroah-Hartman 				sizeof(request), &response, sizeof(response));
275*8465def4SGreg Kroah-Hartman 	if (ret) {
276*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev,
277*8465def4SGreg Kroah-Hartman 			"failed to send bundle %u deactivate: %d\n", bundle_id,
278*8465def4SGreg Kroah-Hartman 			ret);
279*8465def4SGreg Kroah-Hartman 		return ret;
280*8465def4SGreg Kroah-Hartman 	}
281*8465def4SGreg Kroah-Hartman 
282*8465def4SGreg Kroah-Hartman 	if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
283*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "failed to deactivate bundle %u: %d\n",
284*8465def4SGreg Kroah-Hartman 			bundle_id, response.status);
285*8465def4SGreg Kroah-Hartman 		return gb_control_bundle_pm_status_map(response.status);
286*8465def4SGreg Kroah-Hartman 	}
287*8465def4SGreg Kroah-Hartman 
288*8465def4SGreg Kroah-Hartman 	return 0;
289*8465def4SGreg Kroah-Hartman }
290*8465def4SGreg Kroah-Hartman 
gb_control_bundle_activate(struct gb_control * control,u8 bundle_id)291*8465def4SGreg Kroah-Hartman int gb_control_bundle_activate(struct gb_control *control, u8 bundle_id)
292*8465def4SGreg Kroah-Hartman {
293*8465def4SGreg Kroah-Hartman 	struct gb_control_bundle_pm_request request;
294*8465def4SGreg Kroah-Hartman 	struct gb_control_bundle_pm_response response;
295*8465def4SGreg Kroah-Hartman 	int ret;
296*8465def4SGreg Kroah-Hartman 
297*8465def4SGreg Kroah-Hartman 	if (!control->has_bundle_activate)
298*8465def4SGreg Kroah-Hartman 		return 0;
299*8465def4SGreg Kroah-Hartman 
300*8465def4SGreg Kroah-Hartman 	request.bundle_id = bundle_id;
301*8465def4SGreg Kroah-Hartman 	ret = gb_operation_sync(control->connection,
302*8465def4SGreg Kroah-Hartman 				GB_CONTROL_TYPE_BUNDLE_ACTIVATE, &request,
303*8465def4SGreg Kroah-Hartman 				sizeof(request), &response, sizeof(response));
304*8465def4SGreg Kroah-Hartman 	if (ret) {
305*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev,
306*8465def4SGreg Kroah-Hartman 			"failed to send bundle %u activate: %d\n", bundle_id,
307*8465def4SGreg Kroah-Hartman 			ret);
308*8465def4SGreg Kroah-Hartman 		return ret;
309*8465def4SGreg Kroah-Hartman 	}
310*8465def4SGreg Kroah-Hartman 
311*8465def4SGreg Kroah-Hartman 	if (response.status != GB_CONTROL_BUNDLE_PM_OK) {
312*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "failed to activate bundle %u: %d\n",
313*8465def4SGreg Kroah-Hartman 			bundle_id, response.status);
314*8465def4SGreg Kroah-Hartman 		return gb_control_bundle_pm_status_map(response.status);
315*8465def4SGreg Kroah-Hartman 	}
316*8465def4SGreg Kroah-Hartman 
317*8465def4SGreg Kroah-Hartman 	return 0;
318*8465def4SGreg Kroah-Hartman }
319*8465def4SGreg Kroah-Hartman 
gb_control_interface_pm_status_map(u8 status)320*8465def4SGreg Kroah-Hartman static int gb_control_interface_pm_status_map(u8 status)
321*8465def4SGreg Kroah-Hartman {
322*8465def4SGreg Kroah-Hartman 	switch (status) {
323*8465def4SGreg Kroah-Hartman 	case GB_CONTROL_INTF_PM_BUSY:
324*8465def4SGreg Kroah-Hartman 		return -EBUSY;
325*8465def4SGreg Kroah-Hartman 	case GB_CONTROL_INTF_PM_NA:
326*8465def4SGreg Kroah-Hartman 		return -ENOMSG;
327*8465def4SGreg Kroah-Hartman 	default:
328*8465def4SGreg Kroah-Hartman 		return -EREMOTEIO;
329*8465def4SGreg Kroah-Hartman 	}
330*8465def4SGreg Kroah-Hartman }
331*8465def4SGreg Kroah-Hartman 
gb_control_interface_suspend_prepare(struct gb_control * control)332*8465def4SGreg Kroah-Hartman int gb_control_interface_suspend_prepare(struct gb_control *control)
333*8465def4SGreg Kroah-Hartman {
334*8465def4SGreg Kroah-Hartman 	struct gb_control_intf_pm_response response;
335*8465def4SGreg Kroah-Hartman 	int ret;
336*8465def4SGreg Kroah-Hartman 
337*8465def4SGreg Kroah-Hartman 	ret = gb_operation_sync(control->connection,
338*8465def4SGreg Kroah-Hartman 				GB_CONTROL_TYPE_INTF_SUSPEND_PREPARE, NULL, 0,
339*8465def4SGreg Kroah-Hartman 				&response, sizeof(response));
340*8465def4SGreg Kroah-Hartman 	if (ret) {
341*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev,
342*8465def4SGreg Kroah-Hartman 			"failed to send interface suspend prepare: %d\n", ret);
343*8465def4SGreg Kroah-Hartman 		return ret;
344*8465def4SGreg Kroah-Hartman 	}
345*8465def4SGreg Kroah-Hartman 
346*8465def4SGreg Kroah-Hartman 	if (response.status != GB_CONTROL_INTF_PM_OK) {
347*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "interface error while preparing suspend: %d\n",
348*8465def4SGreg Kroah-Hartman 			response.status);
349*8465def4SGreg Kroah-Hartman 		return gb_control_interface_pm_status_map(response.status);
350*8465def4SGreg Kroah-Hartman 	}
351*8465def4SGreg Kroah-Hartman 
352*8465def4SGreg Kroah-Hartman 	return 0;
353*8465def4SGreg Kroah-Hartman }
354*8465def4SGreg Kroah-Hartman 
gb_control_interface_deactivate_prepare(struct gb_control * control)355*8465def4SGreg Kroah-Hartman int gb_control_interface_deactivate_prepare(struct gb_control *control)
356*8465def4SGreg Kroah-Hartman {
357*8465def4SGreg Kroah-Hartman 	struct gb_control_intf_pm_response response;
358*8465def4SGreg Kroah-Hartman 	int ret;
359*8465def4SGreg Kroah-Hartman 
360*8465def4SGreg Kroah-Hartman 	ret = gb_operation_sync(control->connection,
361*8465def4SGreg Kroah-Hartman 				GB_CONTROL_TYPE_INTF_DEACTIVATE_PREPARE, NULL,
362*8465def4SGreg Kroah-Hartman 				0, &response, sizeof(response));
363*8465def4SGreg Kroah-Hartman 	if (ret) {
364*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "failed to send interface deactivate prepare: %d\n",
365*8465def4SGreg Kroah-Hartman 			ret);
366*8465def4SGreg Kroah-Hartman 		return ret;
367*8465def4SGreg Kroah-Hartman 	}
368*8465def4SGreg Kroah-Hartman 
369*8465def4SGreg Kroah-Hartman 	if (response.status != GB_CONTROL_INTF_PM_OK) {
370*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "interface error while preparing deactivate: %d\n",
371*8465def4SGreg Kroah-Hartman 			response.status);
372*8465def4SGreg Kroah-Hartman 		return gb_control_interface_pm_status_map(response.status);
373*8465def4SGreg Kroah-Hartman 	}
374*8465def4SGreg Kroah-Hartman 
375*8465def4SGreg Kroah-Hartman 	return 0;
376*8465def4SGreg Kroah-Hartman }
377*8465def4SGreg Kroah-Hartman 
gb_control_interface_hibernate_abort(struct gb_control * control)378*8465def4SGreg Kroah-Hartman int gb_control_interface_hibernate_abort(struct gb_control *control)
379*8465def4SGreg Kroah-Hartman {
380*8465def4SGreg Kroah-Hartman 	struct gb_control_intf_pm_response response;
381*8465def4SGreg Kroah-Hartman 	int ret;
382*8465def4SGreg Kroah-Hartman 
383*8465def4SGreg Kroah-Hartman 	ret = gb_operation_sync(control->connection,
384*8465def4SGreg Kroah-Hartman 				GB_CONTROL_TYPE_INTF_HIBERNATE_ABORT, NULL, 0,
385*8465def4SGreg Kroah-Hartman 				&response, sizeof(response));
386*8465def4SGreg Kroah-Hartman 	if (ret) {
387*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev,
388*8465def4SGreg Kroah-Hartman 			"failed to send interface aborting hibernate: %d\n",
389*8465def4SGreg Kroah-Hartman 			ret);
390*8465def4SGreg Kroah-Hartman 		return ret;
391*8465def4SGreg Kroah-Hartman 	}
392*8465def4SGreg Kroah-Hartman 
393*8465def4SGreg Kroah-Hartman 	if (response.status != GB_CONTROL_INTF_PM_OK) {
394*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev, "interface error while aborting hibernate: %d\n",
395*8465def4SGreg Kroah-Hartman 			response.status);
396*8465def4SGreg Kroah-Hartman 		return gb_control_interface_pm_status_map(response.status);
397*8465def4SGreg Kroah-Hartman 	}
398*8465def4SGreg Kroah-Hartman 
399*8465def4SGreg Kroah-Hartman 	return 0;
400*8465def4SGreg Kroah-Hartman }
401*8465def4SGreg Kroah-Hartman 
vendor_string_show(struct device * dev,struct device_attribute * attr,char * buf)402*8465def4SGreg Kroah-Hartman static ssize_t vendor_string_show(struct device *dev,
403*8465def4SGreg Kroah-Hartman 				  struct device_attribute *attr, char *buf)
404*8465def4SGreg Kroah-Hartman {
405*8465def4SGreg Kroah-Hartman 	struct gb_control *control = to_gb_control(dev);
406*8465def4SGreg Kroah-Hartman 
407*8465def4SGreg Kroah-Hartman 	return scnprintf(buf, PAGE_SIZE, "%s\n", control->vendor_string);
408*8465def4SGreg Kroah-Hartman }
409*8465def4SGreg Kroah-Hartman static DEVICE_ATTR_RO(vendor_string);
410*8465def4SGreg Kroah-Hartman 
product_string_show(struct device * dev,struct device_attribute * attr,char * buf)411*8465def4SGreg Kroah-Hartman static ssize_t product_string_show(struct device *dev,
412*8465def4SGreg Kroah-Hartman 				   struct device_attribute *attr, char *buf)
413*8465def4SGreg Kroah-Hartman {
414*8465def4SGreg Kroah-Hartman 	struct gb_control *control = to_gb_control(dev);
415*8465def4SGreg Kroah-Hartman 
416*8465def4SGreg Kroah-Hartman 	return scnprintf(buf, PAGE_SIZE, "%s\n", control->product_string);
417*8465def4SGreg Kroah-Hartman }
418*8465def4SGreg Kroah-Hartman static DEVICE_ATTR_RO(product_string);
419*8465def4SGreg Kroah-Hartman 
420*8465def4SGreg Kroah-Hartman static struct attribute *control_attrs[] = {
421*8465def4SGreg Kroah-Hartman 	&dev_attr_vendor_string.attr,
422*8465def4SGreg Kroah-Hartman 	&dev_attr_product_string.attr,
423*8465def4SGreg Kroah-Hartman 	NULL,
424*8465def4SGreg Kroah-Hartman };
425*8465def4SGreg Kroah-Hartman ATTRIBUTE_GROUPS(control);
426*8465def4SGreg Kroah-Hartman 
gb_control_release(struct device * dev)427*8465def4SGreg Kroah-Hartman static void gb_control_release(struct device *dev)
428*8465def4SGreg Kroah-Hartman {
429*8465def4SGreg Kroah-Hartman 	struct gb_control *control = to_gb_control(dev);
430*8465def4SGreg Kroah-Hartman 
431*8465def4SGreg Kroah-Hartman 	gb_connection_destroy(control->connection);
432*8465def4SGreg Kroah-Hartman 
433*8465def4SGreg Kroah-Hartman 	kfree(control->vendor_string);
434*8465def4SGreg Kroah-Hartman 	kfree(control->product_string);
435*8465def4SGreg Kroah-Hartman 
436*8465def4SGreg Kroah-Hartman 	kfree(control);
437*8465def4SGreg Kroah-Hartman }
438*8465def4SGreg Kroah-Hartman 
439*8465def4SGreg Kroah-Hartman struct device_type greybus_control_type = {
440*8465def4SGreg Kroah-Hartman 	.name =		"greybus_control",
441*8465def4SGreg Kroah-Hartman 	.release =	gb_control_release,
442*8465def4SGreg Kroah-Hartman };
443*8465def4SGreg Kroah-Hartman 
gb_control_create(struct gb_interface * intf)444*8465def4SGreg Kroah-Hartman struct gb_control *gb_control_create(struct gb_interface *intf)
445*8465def4SGreg Kroah-Hartman {
446*8465def4SGreg Kroah-Hartman 	struct gb_connection *connection;
447*8465def4SGreg Kroah-Hartman 	struct gb_control *control;
448*8465def4SGreg Kroah-Hartman 
449*8465def4SGreg Kroah-Hartman 	control = kzalloc(sizeof(*control), GFP_KERNEL);
450*8465def4SGreg Kroah-Hartman 	if (!control)
451*8465def4SGreg Kroah-Hartman 		return ERR_PTR(-ENOMEM);
452*8465def4SGreg Kroah-Hartman 
453*8465def4SGreg Kroah-Hartman 	control->intf = intf;
454*8465def4SGreg Kroah-Hartman 
455*8465def4SGreg Kroah-Hartman 	connection = gb_connection_create_control(intf);
456*8465def4SGreg Kroah-Hartman 	if (IS_ERR(connection)) {
457*8465def4SGreg Kroah-Hartman 		dev_err(&intf->dev,
458*8465def4SGreg Kroah-Hartman 			"failed to create control connection: %ld\n",
459*8465def4SGreg Kroah-Hartman 			PTR_ERR(connection));
460*8465def4SGreg Kroah-Hartman 		kfree(control);
461*8465def4SGreg Kroah-Hartman 		return ERR_CAST(connection);
462*8465def4SGreg Kroah-Hartman 	}
463*8465def4SGreg Kroah-Hartman 
464*8465def4SGreg Kroah-Hartman 	control->connection = connection;
465*8465def4SGreg Kroah-Hartman 
466*8465def4SGreg Kroah-Hartman 	control->dev.parent = &intf->dev;
467*8465def4SGreg Kroah-Hartman 	control->dev.bus = &greybus_bus_type;
468*8465def4SGreg Kroah-Hartman 	control->dev.type = &greybus_control_type;
469*8465def4SGreg Kroah-Hartman 	control->dev.groups = control_groups;
470*8465def4SGreg Kroah-Hartman 	control->dev.dma_mask = intf->dev.dma_mask;
471*8465def4SGreg Kroah-Hartman 	device_initialize(&control->dev);
472*8465def4SGreg Kroah-Hartman 	dev_set_name(&control->dev, "%s.ctrl", dev_name(&intf->dev));
473*8465def4SGreg Kroah-Hartman 
474*8465def4SGreg Kroah-Hartman 	gb_connection_set_data(control->connection, control);
475*8465def4SGreg Kroah-Hartman 
476*8465def4SGreg Kroah-Hartman 	return control;
477*8465def4SGreg Kroah-Hartman }
478*8465def4SGreg Kroah-Hartman 
gb_control_enable(struct gb_control * control)479*8465def4SGreg Kroah-Hartman int gb_control_enable(struct gb_control *control)
480*8465def4SGreg Kroah-Hartman {
481*8465def4SGreg Kroah-Hartman 	int ret;
482*8465def4SGreg Kroah-Hartman 
483*8465def4SGreg Kroah-Hartman 	dev_dbg(&control->connection->intf->dev, "%s\n", __func__);
484*8465def4SGreg Kroah-Hartman 
485*8465def4SGreg Kroah-Hartman 	ret = gb_connection_enable_tx(control->connection);
486*8465def4SGreg Kroah-Hartman 	if (ret) {
487*8465def4SGreg Kroah-Hartman 		dev_err(&control->connection->intf->dev,
488*8465def4SGreg Kroah-Hartman 			"failed to enable control connection: %d\n",
489*8465def4SGreg Kroah-Hartman 			ret);
490*8465def4SGreg Kroah-Hartman 		return ret;
491*8465def4SGreg Kroah-Hartman 	}
492*8465def4SGreg Kroah-Hartman 
493*8465def4SGreg Kroah-Hartman 	ret = gb_control_get_version(control);
494*8465def4SGreg Kroah-Hartman 	if (ret)
495*8465def4SGreg Kroah-Hartman 		goto err_disable_connection;
496*8465def4SGreg Kroah-Hartman 
497*8465def4SGreg Kroah-Hartman 	if (control->protocol_major > 0 || control->protocol_minor > 1)
498*8465def4SGreg Kroah-Hartman 		control->has_bundle_version = true;
499*8465def4SGreg Kroah-Hartman 
500*8465def4SGreg Kroah-Hartman 	/* FIXME: use protocol version instead */
501*8465def4SGreg Kroah-Hartman 	if (!(control->intf->quirks & GB_INTERFACE_QUIRK_NO_BUNDLE_ACTIVATE))
502*8465def4SGreg Kroah-Hartman 		control->has_bundle_activate = true;
503*8465def4SGreg Kroah-Hartman 
504*8465def4SGreg Kroah-Hartman 	return 0;
505*8465def4SGreg Kroah-Hartman 
506*8465def4SGreg Kroah-Hartman err_disable_connection:
507*8465def4SGreg Kroah-Hartman 	gb_connection_disable(control->connection);
508*8465def4SGreg Kroah-Hartman 
509*8465def4SGreg Kroah-Hartman 	return ret;
510*8465def4SGreg Kroah-Hartman }
511*8465def4SGreg Kroah-Hartman 
gb_control_disable(struct gb_control * control)512*8465def4SGreg Kroah-Hartman void gb_control_disable(struct gb_control *control)
513*8465def4SGreg Kroah-Hartman {
514*8465def4SGreg Kroah-Hartman 	dev_dbg(&control->connection->intf->dev, "%s\n", __func__);
515*8465def4SGreg Kroah-Hartman 
516*8465def4SGreg Kroah-Hartman 	if (control->intf->disconnected)
517*8465def4SGreg Kroah-Hartman 		gb_connection_disable_forced(control->connection);
518*8465def4SGreg Kroah-Hartman 	else
519*8465def4SGreg Kroah-Hartman 		gb_connection_disable(control->connection);
520*8465def4SGreg Kroah-Hartman }
521*8465def4SGreg Kroah-Hartman 
gb_control_suspend(struct gb_control * control)522*8465def4SGreg Kroah-Hartman int gb_control_suspend(struct gb_control *control)
523*8465def4SGreg Kroah-Hartman {
524*8465def4SGreg Kroah-Hartman 	gb_connection_disable(control->connection);
525*8465def4SGreg Kroah-Hartman 
526*8465def4SGreg Kroah-Hartman 	return 0;
527*8465def4SGreg Kroah-Hartman }
528*8465def4SGreg Kroah-Hartman 
gb_control_resume(struct gb_control * control)529*8465def4SGreg Kroah-Hartman int gb_control_resume(struct gb_control *control)
530*8465def4SGreg Kroah-Hartman {
531*8465def4SGreg Kroah-Hartman 	int ret;
532*8465def4SGreg Kroah-Hartman 
533*8465def4SGreg Kroah-Hartman 	ret = gb_connection_enable_tx(control->connection);
534*8465def4SGreg Kroah-Hartman 	if (ret) {
535*8465def4SGreg Kroah-Hartman 		dev_err(&control->connection->intf->dev,
536*8465def4SGreg Kroah-Hartman 			"failed to enable control connection: %d\n", ret);
537*8465def4SGreg Kroah-Hartman 		return ret;
538*8465def4SGreg Kroah-Hartman 	}
539*8465def4SGreg Kroah-Hartman 
540*8465def4SGreg Kroah-Hartman 	return 0;
541*8465def4SGreg Kroah-Hartman }
542*8465def4SGreg Kroah-Hartman 
gb_control_add(struct gb_control * control)543*8465def4SGreg Kroah-Hartman int gb_control_add(struct gb_control *control)
544*8465def4SGreg Kroah-Hartman {
545*8465def4SGreg Kroah-Hartman 	int ret;
546*8465def4SGreg Kroah-Hartman 
547*8465def4SGreg Kroah-Hartman 	ret = device_add(&control->dev);
548*8465def4SGreg Kroah-Hartman 	if (ret) {
549*8465def4SGreg Kroah-Hartman 		dev_err(&control->dev,
550*8465def4SGreg Kroah-Hartman 			"failed to register control device: %d\n",
551*8465def4SGreg Kroah-Hartman 			ret);
552*8465def4SGreg Kroah-Hartman 		return ret;
553*8465def4SGreg Kroah-Hartman 	}
554*8465def4SGreg Kroah-Hartman 
555*8465def4SGreg Kroah-Hartman 	return 0;
556*8465def4SGreg Kroah-Hartman }
557*8465def4SGreg Kroah-Hartman 
gb_control_del(struct gb_control * control)558*8465def4SGreg Kroah-Hartman void gb_control_del(struct gb_control *control)
559*8465def4SGreg Kroah-Hartman {
560*8465def4SGreg Kroah-Hartman 	if (device_is_registered(&control->dev))
561*8465def4SGreg Kroah-Hartman 		device_del(&control->dev);
562*8465def4SGreg Kroah-Hartman }
563*8465def4SGreg Kroah-Hartman 
gb_control_get(struct gb_control * control)564*8465def4SGreg Kroah-Hartman struct gb_control *gb_control_get(struct gb_control *control)
565*8465def4SGreg Kroah-Hartman {
566*8465def4SGreg Kroah-Hartman 	get_device(&control->dev);
567*8465def4SGreg Kroah-Hartman 
568*8465def4SGreg Kroah-Hartman 	return control;
569*8465def4SGreg Kroah-Hartman }
570*8465def4SGreg Kroah-Hartman 
gb_control_put(struct gb_control * control)571*8465def4SGreg Kroah-Hartman void gb_control_put(struct gb_control *control)
572*8465def4SGreg Kroah-Hartman {
573*8465def4SGreg Kroah-Hartman 	put_device(&control->dev);
574*8465def4SGreg Kroah-Hartman }
575*8465def4SGreg Kroah-Hartman 
gb_control_mode_switch_prepare(struct gb_control * control)576*8465def4SGreg Kroah-Hartman void gb_control_mode_switch_prepare(struct gb_control *control)
577*8465def4SGreg Kroah-Hartman {
578*8465def4SGreg Kroah-Hartman 	gb_connection_mode_switch_prepare(control->connection);
579*8465def4SGreg Kroah-Hartman }
580*8465def4SGreg Kroah-Hartman 
gb_control_mode_switch_complete(struct gb_control * control)581*8465def4SGreg Kroah-Hartman void gb_control_mode_switch_complete(struct gb_control *control)
582*8465def4SGreg Kroah-Hartman {
583*8465def4SGreg Kroah-Hartman 	gb_connection_mode_switch_complete(control->connection);
584*8465def4SGreg Kroah-Hartman }
585