diff options
Diffstat (limited to 'drivers/media/video/adv7180.c')
-rw-r--r-- | drivers/media/video/adv7180.c | 172 |
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"); - |