summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Lavnikevich <d.lavnikevich@sam-solutions.net>2013-05-03 21:25:49 +0300
committerJustin Waters <justin.waters@timesys.com>2013-11-07 12:19:30 -0500
commitfc35bae9a23509e181cb5f1ac437208f79be40b5 (patch)
tree4791888deb17c451e8bf5934c2ba060cf00e6e3d
parentc064b6895b4ad23d8d2c30aa8c18c95bed8c5df3 (diff)
Added base implementation of tw9910.
* soc_camera driver now tries to call enum_input, g_input and s_input handlers from host camera driver if such exists; * tw9910 v4l device type redefined from V4L2_INPUT_TYPE_TUNER to V4L2_INPUT_TYPE_CAMERA; * added basic implementation of g_input and s_input for managing current videoinput handlers to tw9910 driver; Note: currently deinterlacing is disabled by default in the mxc_ipu driver so tw9910 returns interlaced image. Deinterlacing mode can be hardcoded on in the csi_enc_setup(struct mxc_camera_dev *cam) from drivers/media/video/mxc_ipu_csi_enc.c. Signed-off-by: Uladzimir Bely <u.bely@sam-solutions.net> Signed-off-by: Christian Hemp <c.hemp@phytec.de>
-rw-r--r--arch/arm/mach-mx6/board-mx6q_phyflex.c13
-rw-r--r--drivers/media/video/mxc_camera.c2
-rw-r--r--drivers/media/video/soc_camera.c24
-rw-r--r--drivers/media/video/tw9910.c58
-rw-r--r--include/media/soc_camera.h2
5 files changed, 86 insertions, 13 deletions
diff --git a/arch/arm/mach-mx6/board-mx6q_phyflex.c b/arch/arm/mach-mx6/board-mx6q_phyflex.c
index 4c3e434547e9..fc41f71b727c 100644
--- a/arch/arm/mach-mx6/board-mx6q_phyflex.c
+++ b/arch/arm/mach-mx6/board-mx6q_phyflex.c
@@ -57,6 +57,7 @@
#include <linux/spi/max7301.h>
#include <linux/can/platform/mcp251x.h>
#include <sound/tlv320aic3x.h>
+#include <media/tw9910.h>
#include <linux/i2c-gpio.h>
#include <linux/w1-gpio.h>
@@ -1037,11 +1038,18 @@ static struct i2c_board_info phyflex_cameras[] = {
[4] = {
I2C_BOARD_INFO("mt9v022", 0x48), /* CTRL1 = 1 */
},
+ [5] = {
+ I2C_BOARD_INFO("tw9910", 0x45), /* CTRL1 = 1 */
+ },
};
#define SOC_CAM_LINK(bus, bi, i2c_adapter) \
.bus_id = bus, .board_info = bi, .i2c_adapter_id = i2c_adapter
+struct tw9910_video_info tw9910_info = {
+ .buswidth = SOCAM_DATAWIDTH_8,
+ .mpout = TW9910_MPO_RTCO,
+};
static struct soc_camera_link phyflex_iclinks[] = {
{
@@ -1049,6 +1057,9 @@ static struct soc_camera_link phyflex_iclinks[] = {
}, {
SOC_CAM_LINK(0, &phyflex_cameras[2], 2)
}, {
+ SOC_CAM_LINK(1, &phyflex_cameras[5], 2),
+ .priv = &tw9910_info,
+ }, {
SOC_CAM_LINK(1, &phyflex_cameras[1], 2)
}, {
SOC_CAM_LINK(1, &phyflex_cameras[3], 2)
@@ -1071,6 +1082,8 @@ static struct platform_device mxc_ipu_cameras[] = {
SOC_CAM_PDRV(3, phyflex_iclinks),
}, {
SOC_CAM_PDRV(4, phyflex_iclinks),
+ }, {
+ SOC_CAM_PDRV(5, phyflex_iclinks),
},
};
diff --git a/drivers/media/video/mxc_camera.c b/drivers/media/video/mxc_camera.c
index ff8e3a9a468c..3b323f2a743c 100644
--- a/drivers/media/video/mxc_camera.c
+++ b/drivers/media/video/mxc_camera.c
@@ -660,6 +660,8 @@ static int mxc_camera_try_fmt(struct soc_camera_device *icd,
break;
case V4L2_FIELD_NONE:
break;
+ case V4L2_FIELD_INTERLACED_BT:
+ break;
default:
dev_err(icd->dev.parent, "Field type %d unsupported.\n",
mf.field);
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 4e4d4122d9a6..3d10c126357a 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -202,11 +202,10 @@ static int soc_camera_enum_input(struct file *file, void *priv,
struct soc_camera_device *icd = file->private_data;
int ret = 0;
- if (inp->index != 0)
- return -EINVAL;
-
if (icd->ops->enum_input)
ret = icd->ops->enum_input(icd, inp);
+ else if (inp->index != 0)
+ return -EINVAL;
else {
/* default is camera */
inp->type = V4L2_INPUT_TYPE_CAMERA;
@@ -219,17 +218,28 @@ static int soc_camera_enum_input(struct file *file, void *priv,
static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
{
- *i = 0;
+ struct soc_camera_device *icd = file->private_data;
+ int ret = 0;
- return 0;
+ if (icd->ops->g_input)
+ ret = icd->ops->g_input(icd, i);
+ else
+ *i = 0;
+
+ return ret;
}
static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
{
- if (i > 0)
+ struct soc_camera_device *icd = file->private_data;
+ int ret = 0;
+
+ if (icd->ops->s_input)
+ ret = icd->ops->s_input(icd, i);
+ else if (i > 0)
return -EINVAL;
- return 0;
+ return ret;
}
static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index 0347bbe36459..9108de02881b 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -555,9 +555,27 @@ static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
static int tw9910_enum_input(struct soc_camera_device *icd,
struct v4l2_input *inp)
{
- inp->type = V4L2_INPUT_TYPE_TUNER;
- inp->std = V4L2_STD_UNKNOWN;
- strcpy(inp->name, "Video");
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+
+ switch (inp->index) {
+ case 0:
+ strcpy(inp->name, "Video Input 1");
+ break;
+ case 1:
+ strcpy(inp->name, "Video Input 2");
+ break;
+ case 2:
+ strcpy(inp->name, "Video Input 3");
+ break;
+ case 3:
+ strcpy(inp->name, "Video Input 4");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = V4L2_STD_625_50 | V4L2_STD_525_60;
return 0;
}
@@ -817,11 +835,15 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd,
struct soc_camera_device *icd = client->dev.platform_data;
const struct tw9910_scale_ctrl *scale;
- if (V4L2_FIELD_ANY == mf->field) {
+ switch (mf->field) {
+ case V4L2_FIELD_ANY:
+ case V4L2_FIELD_INTERLACED:
mf->field = V4L2_FIELD_INTERLACED_BT;
- } else if (V4L2_FIELD_INTERLACED_BT != mf->field) {
+ break;
+ case V4L2_FIELD_INTERLACED_BT:
+ break;
+ default:
dev_err(&client->dev, "Field type %d invalid.\n", mf->field);
- return -EINVAL;
}
mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
@@ -888,10 +910,34 @@ static int tw9910_video_probe(struct soc_camera_device *icd,
return 0;
}
+static int tw9910_g_input(struct soc_camera_device *icd, unsigned int *i)
+{
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+
+ *i = (i2c_smbus_read_byte_data(client, INFORM) & 0x0C) >> 2;
+
+ if (*i < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int tw9910_s_input(struct soc_camera_device *icd, unsigned int i)
+{
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+
+ if (tw9910_mask_set(client, INFORM, 0X0C, i << 2))
+ return -EINVAL;
+
+ return 0;
+}
+
static struct soc_camera_ops tw9910_ops = {
.set_bus_param = tw9910_set_bus_param,
.query_bus_param = tw9910_query_bus_param,
.enum_input = tw9910_enum_input,
+ .g_input = tw9910_g_input,
+ .s_input = tw9910_s_input,
};
static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 68520c6611eb..cdc8022d2169 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -212,6 +212,8 @@ struct soc_camera_ops {
unsigned long (*query_bus_param)(struct soc_camera_device *);
int (*set_bus_param)(struct soc_camera_device *, unsigned long);
int (*enum_input)(struct soc_camera_device *, struct v4l2_input *);
+ int (*g_input)(struct soc_camera_device *, unsigned int *);
+ int (*s_input)(struct soc_camera_device *, unsigned int);
const struct v4l2_queryctrl *controls;
int num_controls;
};