/*
* Greybus Camera protocol driver.
*
* Copyright 2015 Google Inc.
* Copyright 2015 Linaro Ltd.
*
* Released under the GPLv2 only.
*/
#include <linux/debugfs.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include "gb-camera.h"
#include "greybus.h"
#include "greybus_protocols.h"
enum gb_camera_debugs_buffer_id {
GB_CAMERA_DEBUGFS_BUFFER_CAPABILITIES,
GB_CAMERA_DEBUGFS_BUFFER_STREAMS,
GB_CAMERA_DEBUGFS_BUFFER_CAPTURE,
GB_CAMERA_DEBUGFS_BUFFER_FLUSH,
GB_CAMERA_DEBUGFS_BUFFER_MAX,
};
struct gb_camera_debugfs_buffer {
char data[PAGE_SIZE];
size_t length;
};
/**
* struct gb_camera - A Greybus Camera Device
* @connection: the greybus connection for camera control
* @data_connected: whether the data connection has been established
* @debugfs: debugfs entries for camera protocol operations testing
* @module: Greybus camera module registered to HOST processor.
*/
struct gb_camera {
struct gb_connection *connection;
struct gb_connection *data_connection;
struct {
struct dentry *root;
struct gb_camera_debugfs_buffer *buffers;
} debugfs;
struct gb_camera_module module;
};
struct gb_camera_stream_config {
unsigned int width;
unsigned int height;
unsigned int format;
unsigned int vc;
unsigned int dt[2];
unsigned int max_size;
};
struct gb_camera_fmt_map {
enum v4l2_mbus_pixelcode mbus_code;
unsigned int gb_format;
};
/* GB format to media code map */
static const struct gb_camera_fmt_map mbus_to_gbus_format[] = {
{
.mbus_code = V4L2_MBUS_FMT_UYVY8_1X16,
.gb_format = 0x01,
},
{
.mbus_code = V4L2_MBUS_FMT_NV12_1x8,
.gb_format = 0x12,
},
{
.mbus_code = V4L2_MBUS_FMT_NV21_1x8,
.gb_format = 0x13,
},
{
.mbus_code = V4L2_MBUS_FMT_YU12_1x8,
.gb_format = 0x16,
},
{
.mbus_code = V4L2_MBUS_FMT_YV12_1x8,
.gb_format = 0x17,
},
{
.mbus_code = V4L2_MBUS_FMT_JPEG_1X8,
.gb_format = 0x40,
},
{
.mbus_code = V4L2_MBUS_FMT_ARA_METADATA_1X8,
.gb_format = 0x41,
}
};
#define ES2_APB_CDSI0_CPORT 16
#define ES2_APB_CDSI1_CPORT 17
#define GB_CAMERA_MAX_SETTINGS_SIZE 8192
#define gcam_dbg(gcam, format...) \
dev_dbg(&gcam->connection->bundle->dev, format)
#define gcam_info(gcam, format...) \
dev_info(&gcam->connection->bundle->dev, format)
#define gcam_err(gcam, format...) \
dev_err(&gcam->connection->bundle->dev, format)
/* -----------------------------------------------------------------------------
* Camera Protocol Operations
*/
static int gb_camera_set_intf_power_mode(struct gb_camera *gcam, u8 intf_id,
bool hs)
{
struct gb_svc *svc = gcam->connection->hd->svc;
int ret;
if (hs)
ret = gb_svc_intf_set_power_mode(svc, intf_id,
GB_SVC_UNIPRO_HS_SERIES_A,
GB_SVC_UNIPRO_FAST_MODE, 2, 2,
GB_SVC_UNIPRO_FAST_MODE, 2, 2,
GB_SVC_PWRM_RXTERMINATION |
GB_SVC_PWRM_TXTERMINATION, 0);
else
ret = gb_svc_intf_set_power_mode(svc, intf_id,
GB_SVC_UNIPRO_HS_SERIES_A,
GB_SVC_UNIPRO_SLOW_AUTO_MODE,
2, 1,
GB_SVC_UNIPRO_SLOW_AUTO_MODE,
2, 1,
0, 0);
return ret;
}
static int gb_camera_set_power_mode(struct gb_camera *gcam, bool hs)
{
struct gb_interface *intf = gcam->connection->intf;
struct gb_svc *svc = gcam->connection->hd->svc;
int ret;
ret = gb_camera_set_intf_power_mode(gcam, intf->interface_id, hs);
if (ret < 0) {
gcam_err(gcam, "failed to set module interface to %s (%d)\n",
hs ? "HS" : "PWM", ret);
return ret;
}
ret = gb_camera_set_intf_power_mode(gcam, svc->ap_intf_id, hs);
if (ret < 0) {
gb_camera_set_intf_power_mode(gcam, intf->interface_id, !hs);
gcam_err(gcam, "failed to set AP interface to %s (%d)\n",
hs ? "HS" : "PWM", ret);
return ret;
}
return 0;
}
static int gb_camera_capabilities(struct gb_camera *gcam,
u8 *capabilities, size_t *size)
{
struct gb_operation *op;
int ret;
op = gb_operation_create_flags(gcam->connection,
GB_CAMERA_TYPE_CAPABILITIES, 0, *size,
GB_OPERATION_FLAG_SHORT_RESPONSE,
GFP_KERNEL);
if (!op)
return -ENOMEM;
ret = gb_operation_request_send_sync(op);
if (ret) {
gcam_err(gcam, "failed to retrieve capabilities: %