greybus: es2: add support for CDSI1 allocation

Use the new CPort-allocation callbacks to allow for rudimentary resource
management of the CDSI CPorts.

How to manage offloaded resources in a generic fashion is yet to be
determined, but this minimal implementation will allow core to manage
the camera data connection so that the current camera-driver hacks can
be removed. This is specifically required to be able to implement proper
connection closing and for power management.

Note that the CDSI CPorts can not (currently) be reset through the
USB vendor request.

Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Johan Hovold 2016-05-11 10:18:04 +02:00 committed by Greg Kroah-Hartman
parent e7b848c288
commit 045d356114
2 changed files with 60 additions and 0 deletions

View File

@ -16,6 +16,7 @@
#define GB_CONNECTION_FLAG_CSD BIT(0)
#define GB_CONNECTION_FLAG_NO_FLOWCTRL BIT(1)
#define GB_CONNECTION_FLAG_OFFLOADED BIT(2)
#define GB_CONNECTION_FLAG_CDSI1 BIT(3)
enum gb_connection_state {
GB_CONNECTION_STATE_INVALID = 0,

View File

@ -99,6 +99,8 @@ struct es2_ap_dev {
bool cport_out_urb_cancelled[NUM_CPORT_OUT_URB];
spinlock_t cport_out_urb_lock;
bool cdsi1_in_use;
int *cport_to_ep;
struct task_struct *apb_log_task;
@ -508,6 +510,8 @@ static int cport_reset(struct gb_host_device *hd, u16 cport_id)
switch (cport_id) {
case GB_SVC_CPORT_ID:
case ES2_CPORT_CDSI0:
case ES2_CPORT_CDSI1:
return 0;
}
@ -525,6 +529,59 @@ static int cport_reset(struct gb_host_device *hd, u16 cport_id)
return 0;
}
static int es2_cport_allocate(struct gb_host_device *hd, int cport_id,
unsigned long flags)
{
struct es2_ap_dev *es2 = hd_to_es2(hd);
struct ida *id_map = &hd->cport_id_map;
int ida_start, ida_end;
switch (cport_id) {
case ES2_CPORT_CDSI0:
case ES2_CPORT_CDSI1:
dev_err(&hd->dev, "cport %d not available\n", cport_id);
return -EBUSY;
}
if (flags & GB_CONNECTION_FLAG_OFFLOADED &&
flags & GB_CONNECTION_FLAG_CDSI1) {
if (es2->cdsi1_in_use) {
dev_err(&hd->dev, "CDSI1 already in use\n");
return -EBUSY;
}
es2->cdsi1_in_use = true;
return ES2_CPORT_CDSI1;
}
if (cport_id < 0) {
ida_start = 0;
ida_end = hd->num_cports;
} else if (cport_id < hd->num_cports) {
ida_start = cport_id;
ida_end = cport_id + 1;
} else {
dev_err(&hd->dev, "cport %d not available\n", cport_id);
return -EINVAL;
}
return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
}
static void es2_cport_release(struct gb_host_device *hd, u16 cport_id)
{
struct es2_ap_dev *es2 = hd_to_es2(hd);
switch (cport_id) {
case ES2_CPORT_CDSI1:
es2->cdsi1_in_use = false;
return;
}
ida_simple_remove(&hd->cport_id_map, cport_id);
}
static int cport_enable(struct gb_host_device *hd, u16 cport_id)
{
int retval;
@ -621,6 +678,8 @@ static struct gb_hd_driver es2_driver = {
.hd_priv_size = sizeof(struct es2_ap_dev),
.message_send = message_send,
.message_cancel = message_cancel,
.cport_allocate = es2_cport_allocate,
.cport_release = es2_cport_release,
.cport_enable = cport_enable,
.latency_tag_enable = latency_tag_enable,
.latency_tag_disable = latency_tag_disable,