summaryrefslogtreecommitdiff
path: root/drivers/media/video/adv7180.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/adv7180.c')
-rw-r--r--drivers/media/video/adv7180.c172
1 files changed, 157 insertions, 15 deletions
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c
index d2138d06bcad..14b48edb39b2 100644
--- a/drivers/media/video/adv7180.c
+++ b/drivers/media/video/adv7180.c
@@ -27,13 +27,20 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
#include <linux/mutex.h>
#define DRIVER_NAME "adv7180"
#define ADV7180_INPUT_CONTROL_REG 0x00
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN1 0x00
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN2 0x01
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN3 0x02
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN4 0x03
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN5 0x04
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN6 0x05
#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00
-#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
+#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_M_SECAM 0x10
#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM 0x20
#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM 0x30
#define ADV7180_INPUT_CONTROL_NTSC_J 0x40
@@ -71,7 +78,8 @@
#define ADV7180_STATUS1_AUTOD_SECAM_525 0x70
#define ADV7180_IDENT_REG 0x11
-#define ADV7180_ID_7180 0x18
+#define ADV7180_ID_7180 0x1C /* 64-lead and 40-lead models only */
+#define ADV7180_ID2_7180 0x1E /* 48-lead and 32-lead devices only */
#define ADV7180_ICONF1_ADI 0x40
#define ADV7180_ICONF1_ACTIVE_LOW 0x01
@@ -97,6 +105,7 @@ struct adv7180_state {
int irq;
v4l2_std_id curr_norm;
bool autodetect;
+ int active_input;
};
static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
@@ -224,14 +233,18 @@ static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
if (std == V4L2_STD_ALL) {
ret = i2c_smbus_write_byte_data(client,
ADV7180_INPUT_CONTROL_REG,
- ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
+ ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM |
+ (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input));
if (ret < 0)
goto out;
__adv7180_status(client, NULL, &state->curr_norm);
state->autodetect = true;
} else {
- ret = v4l2_std_to_adv7180(std);
+ ret = v4l2_std_to_adv7180(std) |
+ (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input);
if (ret < 0)
goto out;
@@ -249,19 +262,99 @@ out:
return ret;
}
+static int adv7180_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ return 0;
+}
+
+/* Request bus settings on camera side */
+static unsigned long adv7180_query_bus_param(struct soc_camera_device *icd)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static enum v4l2_mbus_pixelcode adv7180_codes[] = {
+ V4L2_MBUS_FMT_YUYV8_2X8,
+};
+
+static int adv7180_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ enum v4l2_colorspace cspace;
+ enum v4l2_mbus_pixelcode code = mf->code;
+// struct i2c_client *client = v4l2_get_subdevdata(sd);
+// u8 status1;
+
+// status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
+// printk(KERN_ERR "*********************************** status1 = 0x%02x\n", status1);
+
+ switch (code) {
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ cspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mf->code = code;
+ mf->colorspace = cspace;
+
+ return adv7180_s_std(sd, V4L2_STD_ALL);
+}
+
+static int adv7180_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ mf->field = V4L2_FIELD_INTERLACED_TB;
+ mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+
+ // PAL
+ mf->width = 720;
+ mf->height = 576;
+
+ return 0;
+}
+
+static int adv7180_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(adv7180_codes))
+ return -EINVAL;
+
+ *code = adv7180_codes[index];
+
+ return 0;
+}
+
+static struct soc_camera_ops adv7180_ops = {
+ .set_bus_param = adv7180_set_bus_param,
+ .query_bus_param = adv7180_query_bus_param,
+};
+
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
- .querystd = adv7180_querystd,
- .g_input_status = adv7180_g_input_status,
+ .s_mbus_fmt = adv7180_s_fmt,
+ .try_mbus_fmt = adv7180_try_fmt,
+ .enum_mbus_fmt = adv7180_enum_fmt,
+ .querystd = adv7180_querystd,
+ .g_input_status = adv7180_g_input_status,
};
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
- .g_chip_ident = adv7180_g_chip_ident,
- .s_std = adv7180_s_std,
+ .g_chip_ident = adv7180_g_chip_ident,
+ .s_std = adv7180_s_std,
};
-static const struct v4l2_subdev_ops adv7180_ops = {
- .core = &adv7180_core_ops,
- .video = &adv7180_video_ops,
+static const struct v4l2_subdev_ops adv7180_subdev_ops = {
+ .core = &adv7180_core_ops,
+ .video = &adv7180_video_ops,
};
static void adv7180_work(struct work_struct *work)
@@ -297,6 +390,36 @@ static irqreturn_t adv7180_irq(int irq, void *devid)
return IRQ_HANDLED;
}
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i) {
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct adv7180_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 val;
+
+ if (i < 6) {
+ state->active_input = i;
+ val = i2c_smbus_read_byte_data(client,
+ ADV7180_INPUT_CONTROL_REG);
+ val &= 0xf0;
+ val |= (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input);
+ return i2c_smbus_write_byte_data(client,
+ ADV7180_INPUT_CONTROL_REG, val);
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) {
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct adv7180_state *state = to_state(sd);
+
+ *i = state->active_input;
+
+ return 0;
+}
+
/*
* Generic i2c probe
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
@@ -306,8 +429,11 @@ static __devinit int adv7180_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct adv7180_state *state;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct v4l2_subdev *sd;
+ u8 ident;
int ret;
+ struct v4l2_ioctl_ops *ops;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -322,17 +448,25 @@ static __devinit int adv7180_probe(struct i2c_client *client,
goto err;
}
+ ident = i2c_smbus_read_byte_data(client, ADV7180_IDENT_REG);
+ WARN_ON((ident != ADV7180_ID_7180) && (ident != ADV7180_ID2_7180));
+ v4l_info(client, "ident reg is 0x%02x\n", ident);
+
state->irq = client->irq;
INIT_WORK(&state->work, adv7180_work);
mutex_init(&state->mutex);
state->autodetect = true;
+ state->active_input = 0; // input 1
sd = &state->sd;
- v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
+ v4l2_i2c_subdev_init(sd, client, &adv7180_subdev_ops);
+ icd->ops = &adv7180_ops;
/* Initialize adv7180 */
/* Enable autodetection */
ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
- ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
+ ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM |
+ (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input));
if (ret < 0)
goto err_unreg_subdev;
@@ -393,6 +527,15 @@ static __devinit int adv7180_probe(struct i2c_client *client,
goto err_unreg_subdev;
}
+ /*
+ * this is the only way to support more than one input as soc_camera
+ * assumes in its own vidioc_s(g)_input implementation that only one
+ * input is present we have to override that with our own handlers.
+ */
+ ops = (struct v4l2_ioctl_ops*)icd->vdev->ioctl_ops;
+ ops->vidioc_s_input = &vidioc_s_input;
+ ops->vidioc_g_input = &vidioc_g_input;
+
return 0;
err_unreg_subdev:
@@ -432,7 +575,7 @@ static const struct i2c_device_id adv7180_id[] = {
{},
};
-MODULE_DEVICE_TABLE(i2c, adv7180_id);
+//MODULE_DEVICE_TABLE(i2c, adv7180_id);
static struct i2c_driver adv7180_driver = {
.driver = {
@@ -460,4 +603,3 @@ module_exit(adv7180_exit);
MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
MODULE_AUTHOR("Mocean Laboratories");
MODULE_LICENSE("GPL v2");
-