From 8d64827172ae680d34d0611a1e865b546e6a5f08 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 23 Sep 2009 04:59:24 -0300 Subject: V4L/DVB (13040): V4L2: Add a v4l2-subdev (soc-camera) driver for OmniVision OV9640 sensor Signed-off-by: Marek Vasut Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 6 + drivers/media/video/Makefile | 1 + drivers/media/video/ov9640.c | 801 +++++++++++++++++++++++++++++++++++++++++++ drivers/media/video/ov9640.h | 209 +++++++++++ 4 files changed, 1017 insertions(+) create mode 100644 drivers/media/video/ov9640.c create mode 100644 drivers/media/video/ov9640.h (limited to 'drivers/media') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index e6186b338a1..c318676f2d2 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -865,6 +865,12 @@ config SOC_CAMERA_OV772X help This is a ov772x camera driver +config SOC_CAMERA_OV9640 + tristate "ov9640 camera support" + depends on SOC_CAMERA && I2C + help + This is a ov9640 camera driver + config MX1_VIDEO bool diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index e541932a789..e706ceecef8 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o +obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o # And now the v4l2 drivers: diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c new file mode 100644 index 00000000000..c81ae219288 --- /dev/null +++ b/drivers/media/video/ov9640.c @@ -0,0 +1,801 @@ +/* + * OmniVision OV96xx Camera Driver + * + * Copyright (C) 2009 Marek Vasut + * + * Based on ov772x camera driver: + * + * Copyright (C) 2008 Renesas Solutions Corp. + * Kuninori Morimoto + * + * Based on ov7670 and soc_camera_platform driver, + * + * Copyright 2006-7 Jonathan Corbet + * Copyright (C) 2008 Magnus Damm + * Copyright (C) 2008, Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ov9640.h" + +/* default register setup */ +static const struct ov9640_reg ov9640_regs_dflt[] = { + { OV9640_COM5, OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP }, + { OV9640_COM6, OV9640_COM6_OPT_BLC | OV9640_COM6_ADBLC_BIAS | + OV9640_COM6_FMT_RST | OV9640_COM6_ADBLC_OPTEN }, + { OV9640_PSHFT, OV9640_PSHFT_VAL(0x01) }, + { OV9640_ACOM, OV9640_ACOM_2X_ANALOG | OV9640_ACOM_RSVD }, + { OV9640_TSLB, OV9640_TSLB_YUYV_UYVY }, + { OV9640_COM16, OV9640_COM16_RB_AVG }, + + /* Gamma curve P */ + { 0x6c, 0x40 }, { 0x6d, 0x30 }, { 0x6e, 0x4b }, { 0x6f, 0x60 }, + { 0x70, 0x70 }, { 0x71, 0x70 }, { 0x72, 0x70 }, { 0x73, 0x70 }, + { 0x74, 0x60 }, { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 }, + { 0x78, 0x3a }, { 0x79, 0x2e }, { 0x7a, 0x28 }, { 0x7b, 0x22 }, + + /* Gamma curve T */ + { 0x7c, 0x04 }, { 0x7d, 0x07 }, { 0x7e, 0x10 }, { 0x7f, 0x28 }, + { 0x80, 0x36 }, { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 }, + { 0x84, 0x6c }, { 0x85, 0x78 }, { 0x86, 0x8c }, { 0x87, 0x9e }, + { 0x88, 0xbb }, { 0x89, 0xd2 }, { 0x8a, 0xe6 }, +}; + +/* Configurations + * NOTE: for YUV, alter the following registers: + * COM12 |= OV9640_COM12_YUV_AVG + * + * for RGB, alter the following registers: + * COM7 |= OV9640_COM7_RGB + * COM13 |= OV9640_COM13_RGB_AVG + * COM15 |= proper RGB color encoding mode + */ +static const struct ov9640_reg ov9640_regs_qqcif[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) }, + { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP }, + { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, + { OV9640_COM7, OV9640_COM7_QCIF }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_qqvga[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) }, + { OV9640_COM1, OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP }, + { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, + { OV9640_COM7, OV9640_COM7_QVGA }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_qcif[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) }, + { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, + { OV9640_COM7, OV9640_COM7_QCIF }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_qvga[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) }, + { OV9640_COM4, OV9640_COM4_QQ_VP | OV9640_COM4_RSVD }, + { OV9640_COM7, OV9640_COM7_QVGA }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_cif[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) }, + { OV9640_COM3, OV9640_COM3_VP }, + { OV9640_COM7, OV9640_COM7_CIF }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_vga[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) }, + { OV9640_COM3, OV9640_COM3_VP }, + { OV9640_COM7, OV9640_COM7_VGA }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_sxga[] = { + { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) }, + { OV9640_COM3, OV9640_COM3_VP }, + { OV9640_COM7, 0 }, + { OV9640_COM12, OV9640_COM12_RSVD }, + { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN }, + { OV9640_COM15, OV9640_COM15_OR_10F0 }, +}; + +static const struct ov9640_reg ov9640_regs_yuv[] = { + { OV9640_MTX1, 0x58 }, + { OV9640_MTX2, 0x48 }, + { OV9640_MTX3, 0x10 }, + { OV9640_MTX4, 0x28 }, + { OV9640_MTX5, 0x48 }, + { OV9640_MTX6, 0x70 }, + { OV9640_MTX7, 0x40 }, + { OV9640_MTX8, 0x40 }, + { OV9640_MTX9, 0x40 }, + { OV9640_MTXS, 0x0f }, +}; + +static const struct ov9640_reg ov9640_regs_rgb[] = { + { OV9640_MTX1, 0x71 }, + { OV9640_MTX2, 0x3e }, + { OV9640_MTX3, 0x0c }, + { OV9640_MTX4, 0x33 }, + { OV9640_MTX5, 0x72 }, + { OV9640_MTX6, 0x00 }, + { OV9640_MTX7, 0x2b }, + { OV9640_MTX8, 0x66 }, + { OV9640_MTX9, 0xd2 }, + { OV9640_MTXS, 0x65 }, +}; + +/* + * TODO: this sensor also supports RGB555 and RGB565 formats, but support for + * them has not yet been sufficiently tested and so it is not included with + * this version of the driver. To test and debug these formats add two entries + * to the below array, see ov722x.c for an example. + */ +static const struct soc_camera_data_format ov9640_fmt_lists[] = { + { + .name = "UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + .colorspace = V4L2_COLORSPACE_JPEG, + }, +}; + +static const struct v4l2_queryctrl ov9640_controls[] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Vertically", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Horizontally", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, +}; + +/* read a register */ +static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int ret; + u8 data = reg; + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &data, + }; + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) + goto err; + + msg.flags = I2C_M_RD; + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) + goto err; + + *val = data; + return 0; + +err: + dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg); + return ret; +} + +/* write a register */ +static int ov9640_reg_write(struct i2c_client *client, u8 reg, u8 val) +{ + int ret; + u8 _val; + unsigned char data[2] = { reg, val }; + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = data, + }; + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) { + dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg); + return ret; + } + + /* we have to read the register back ... no idea why, maybe HW bug */ + ret = ov9640_reg_read(client, reg, &_val); + if (ret) + dev_err(&client->dev, + "Failed reading back register 0x%02x!\n", reg); + + return 0; +} + + +/* Read a register, alter its bits, write it back */ +static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset) +{ + u8 val; + int ret; + + ret = ov9640_reg_read(client, reg, &val); + if (ret) { + dev_err(&client->dev, + "[Read]-Modify-Write of register %02x failed!\n", reg); + return val; + } + + val |= set; + val &= ~unset; + + ret = ov9640_reg_write(client, reg, val); + if (ret) + dev_err(&client->dev, + "Read-Modify-[Write] of register %02x failed!\n", reg); + + return ret; +} + +/* Soft reset the camera. This has nothing to do with the RESET pin! */ +static int ov9640_reset(struct i2c_client *client) +{ + int ret; + + ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET); + if (ret) + dev_err(&client->dev, + "An error occured while entering soft reset!\n"); + + return ret; +} + +/* Start/Stop streaming from the device */ +static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) +{ + return 0; +} + +/* Alter bus settings on camera side */ +static int ov9640_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + return 0; +} + +/* Request bus settings on camera side */ +static unsigned long ov9640_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + + /* + * REVISIT: the camera probably can do 10 bit transfers, but I don't + * have those pins connected on my hardware. + */ + 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); +} + +/* Get status of additional camera capabilities */ +static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct ov9640_priv *priv = container_of(i2c_get_clientdata(client), + struct ov9640_priv, subdev); + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + ctrl->value = priv->flag_vflip; + break; + case V4L2_CID_HFLIP: + ctrl->value = priv->flag_hflip; + break; + } + return 0; +} + +/* Set status of additional camera capabilities */ +static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct i2c_client *client = sd->priv; + struct ov9640_priv *priv = container_of(i2c_get_clientdata(client), + struct ov9640_priv, subdev); + + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + priv->flag_vflip = ctrl->value; + if (ctrl->value) + ret = ov9640_reg_rmw(client, OV9640_MVFP, + OV9640_MVFP_V, 0); + else + ret = ov9640_reg_rmw(client, OV9640_MVFP, + 0, OV9640_MVFP_V); + break; + case V4L2_CID_HFLIP: + priv->flag_hflip = ctrl->value; + if (ctrl->value) + ret = ov9640_reg_rmw(client, OV9640_MVFP, + OV9640_MVFP_H, 0); + else + ret = ov9640_reg_rmw(client, OV9640_MVFP, + 0, OV9640_MVFP_H); + break; + } + + return ret; +} + +/* Get chip identification */ +static int ov9640_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = sd->priv; + struct ov9640_priv *priv = container_of(i2c_get_clientdata(client), + struct ov9640_priv, subdev); + + id->ident = priv->model; + id->revision = priv->revision; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ov9640_get_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = sd->priv; + int ret; + u8 val; + + if (reg->reg & ~0xff) + return -EINVAL; + + reg->size = 1; + + ret = ov9640_reg_read(client, reg->reg, &val); + if (ret) + return ret; + + reg->val = (__u64)val; + + return 0; +} + +static int ov9640_set_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = sd->priv; + + if (reg->reg & ~0xff || reg->val & ~0xff) + return -EINVAL; + + return ov9640_reg_write(client, reg->reg, reg->val); +} +#endif + +/* select nearest higher resolution for capture */ +static void ov9640_res_roundup(u32 *width, u32 *height) +{ + int i; + enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA }; + int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 }; + int res_y[] = { 72, 120, 144, 240, 288, 480, 960 }; + + for (i = 0; i < ARRAY_SIZE(res_x); i++) { + if (res_x[i] >= *width && res_y[i] >= *height) { + *width = res_x[i]; + *height = res_y[i]; + return; + } + } + + *width = res_x[SXGA]; + *height = res_y[SXGA]; +} + +/* Prepare necessary register changes depending on color encoding */ +static void ov9640_alter_regs(u32 pixfmt, struct ov9640_reg_alt *alt) +{ + switch (pixfmt) { + case V4L2_PIX_FMT_UYVY: + alt->com12 = OV9640_COM12_YUV_AVG; + alt->com13 = OV9640_COM13_Y_DELAY_EN | + OV9640_COM13_YUV_DLY(0x01); + break; + case V4L2_PIX_FMT_RGB555: + alt->com7 = OV9640_COM7_RGB; + alt->com13 = OV9640_COM13_RGB_AVG; + alt->com15 = OV9640_COM15_RGB_555; + break; + case V4L2_PIX_FMT_RGB565: + alt->com7 = OV9640_COM7_RGB; + alt->com13 = OV9640_COM13_RGB_AVG; + alt->com15 = OV9640_COM15_RGB_565; + break; + }; +} + +/* Setup registers according to resolution and color encoding */ +static int ov9640_write_regs(struct i2c_client *client, + u32 width, u32 pixfmt, struct ov9640_reg_alt *alts) +{ + const struct ov9640_reg *ov9640_regs, *matrix_regs; + int ov9640_regs_len, matrix_regs_len; + int i, ret; + u8 val; + + /* select register configuration for given resolution */ + switch (width) { + case W_QQCIF: + ov9640_regs = ov9640_regs_qqcif; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqcif); + break; + case W_QQVGA: + ov9640_regs = ov9640_regs_qqvga; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqvga); + break; + case W_QCIF: + ov9640_regs = ov9640_regs_qcif; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qcif); + break; + case W_QVGA: + ov9640_regs = ov9640_regs_qvga; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qvga); + break; + case W_CIF: + ov9640_regs = ov9640_regs_cif; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_cif); + break; + case W_VGA: + ov9640_regs = ov9640_regs_vga; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_vga); + break; + case W_SXGA: + ov9640_regs = ov9640_regs_sxga; + ov9640_regs_len = ARRAY_SIZE(ov9640_regs_sxga); + break; + default: + dev_err(&client->dev, "Failed to select resolution!\n"); + return -EINVAL; + } + + /* select color matrix configuration for given color encoding */ + if (pixfmt == V4L2_PIX_FMT_UYVY) { + matrix_regs = ov9640_regs_yuv; + matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv); + } else { + matrix_regs = ov9640_regs_rgb; + matrix_regs_len = ARRAY_SIZE(ov9640_regs_rgb); + } + + /* write register settings into the module */ + for (i = 0; i < ov9640_regs_len; i++) { + val = ov9640_regs[i].val; + + switch (ov9640_regs[i].reg) { + case OV9640_COM7: + val |= alts->com7; + break; + case OV9640_COM12: + val |= alts->com12; + break; + case OV9640_COM13: + val |= alts->com13; + break; + case OV9640_COM15: + val |= alts->com15; + break; + } + + ret = ov9640_reg_write(client, ov9640_regs[i].reg, val); + if (ret) + return ret; + } + + /* write color matrix configuration into the module */ + for (i = 0; i < matrix_regs_len; i++) { + ret = ov9640_reg_write(client, matrix_regs[i].reg, + matrix_regs[i].val); + if (ret) + return ret; + } + + return 0; +} + +/* program default register values */ +static int ov9640_prog_dflt(struct i2c_client *client) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) { + ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg, + ov9640_regs_dflt[i].val); + if (ret) + return ret; + } + + /* wait for the changes to actually happen, 140ms are not enough yet */ + mdelay(150); + + return 0; +} + +/* set the format we will capture in */ +static int ov9640_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct i2c_client *client = sd->priv; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct ov9640_reg_alt alts = {0}; + int ret; + + ov9640_res_roundup(&pix->width, &pix->height); + ov9640_alter_regs(pix->pixelformat, &alts); + + ov9640_reset(client); + + ret = ov9640_prog_dflt(client); + if (ret) + return ret; + + return ov9640_write_regs(client, pix->width, pix->pixelformat, &alts); +} + +static int ov9640_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + + ov9640_res_roundup(&pix->width, &pix->height); + pix->field = V4L2_FIELD_NONE; + + return 0; +} + +static int ov9640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + a->c.left = 0; + a->c.top = 0; + a->c.width = W_SXGA; + a->c.height = H_SXGA; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + a->bounds.left = 0; + a->bounds.top = 0; + a->bounds.width = W_SXGA; + a->bounds.height = H_SXGA; + a->defrect = a->bounds; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + + + +static int ov9640_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + struct ov9640_priv *priv = i2c_get_clientdata(client); + u8 pid, ver, midh, midl; + const char *devname; + int ret = 0; + + /* + * We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. + */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) { + dev_err(&client->dev, "Parent missing or invalid!\n"); + ret = -ENODEV; + goto err; + } + + icd->formats = ov9640_fmt_lists; + icd->num_formats = ARRAY_SIZE(ov9640_fmt_lists); + + /* + * check and show product ID and manufacturer ID + */ + + ret = ov9640_reg_read(client, OV9640_PID, &pid); + if (ret) + goto err; + + ret = ov9640_reg_read(client, OV9640_VER, &ver); + if (ret) + goto err; + + ret = ov9640_reg_read(client, OV9640_MIDH, &midh); + if (ret) + goto err; + + ret = ov9640_reg_read(client, OV9640_MIDL, &midl); + if (ret) + goto err; + + switch (VERSION(pid, ver)) { + case OV9640_V2: + devname = "ov9640"; + priv->model = V4L2_IDENT_OV9640; + priv->revision = 2; + case OV9640_V3: + devname = "ov9640"; + priv->model = V4L2_IDENT_OV9640; + priv->revision = 3; + break; + default: + dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); + ret = -ENODEV; + goto err; + } + + dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", + devname, pid, ver, midh, midl); + +err: + return ret; +} + +static struct soc_camera_ops ov9640_ops = { + .set_bus_param = ov9640_set_bus_param, + .query_bus_param = ov9640_query_bus_param, + .controls = ov9640_controls, + .num_controls = ARRAY_SIZE(ov9640_controls), +}; + +static struct v4l2_subdev_core_ops ov9640_core_ops = { + .g_ctrl = ov9640_g_ctrl, + .s_ctrl = ov9640_s_ctrl, + .g_chip_ident = ov9640_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov9640_get_register, + .s_register = ov9640_set_register, +#endif + +}; + +static struct v4l2_subdev_video_ops ov9640_video_ops = { + .s_stream = ov9640_s_stream, + .s_fmt = ov9640_s_fmt, + .try_fmt = ov9640_try_fmt, + .cropcap = ov9640_cropcap, + .g_crop = ov9640_g_crop, + +}; + +static struct v4l2_subdev_ops ov9640_subdev_ops = { + .core = &ov9640_core_ops, + .video = &ov9640_video_ops, +}; + +/* + * i2c_driver function + */ +static int ov9640_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct ov9640_priv *priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl; + int ret; + + if (!icd) { + dev_err(&client->dev, "Missing soc-camera data!\n"); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "Missing platform_data for driver\n"); + return -EINVAL; + } + + priv = kzalloc(sizeof(struct ov9640_priv), GFP_KERNEL); + if (!priv) { + dev_err(&client->dev, + "Failed to allocate memory for private data!\n"); + return -ENOMEM; + } + + v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); + + icd->ops = &ov9640_ops; + + ret = ov9640_video_probe(icd, client); + + if (ret) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(priv); + } + + return ret; +} + +static int ov9640_remove(struct i2c_client *client) +{ + struct ov9640_priv *priv = i2c_get_clientdata(client); + + i2c_set_clientdata(client, NULL); + kfree(priv); + return 0; +} + +static const struct i2c_device_id ov9640_id[] = { + { "ov9640", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ov9640_id); + +static struct i2c_driver ov9640_i2c_driver = { + .driver = { + .name = "ov9640", + }, + .probe = ov9640_probe, + .remove = ov9640_remove, + .id_table = ov9640_id, +}; + +static int __init ov9640_module_init(void) +{ + return i2c_add_driver(&ov9640_i2c_driver); +} + +static void __exit ov9640_module_exit(void) +{ + i2c_del_driver(&ov9640_i2c_driver); +} + +module_init(ov9640_module_init); +module_exit(ov9640_module_exit); + +MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx"); +MODULE_AUTHOR("Marek Vasut "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/ov9640.h b/drivers/media/video/ov9640.h new file mode 100644 index 00000000000..f8a51b70792 --- /dev/null +++ b/drivers/media/video/ov9640.h @@ -0,0 +1,209 @@ +/* + * OmniVision OV96xx Camera Header File + * + * Copyright (C) 2009 Marek Vasut + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DRIVERS_MEDIA_VIDEO_OV9640_H__ +#define __DRIVERS_MEDIA_VIDEO_OV9640_H__ + +/* Register definitions */ +#define OV9640_GAIN 0x00 +#define OV9640_BLUE 0x01 +#define OV9640_RED 0x02 +#define OV9640_VFER 0x03 +#define OV9640_COM1 0x04 +#define OV9640_BAVE 0x05 +#define OV9640_GEAVE 0x06 +#define OV9640_RSID 0x07 +#define OV9640_RAVE 0x08 +#define OV9640_COM2 0x09 +#define OV9640_PID 0x0a +#define OV9640_VER 0x0b +#define OV9640_COM3 0x0c +#define OV9640_COM4 0x0d +#define OV9640_COM5 0x0e +#define OV9640_COM6 0x0f +#define OV9640_AECH 0x10 +#define OV9640_CLKRC 0x11 +#define OV9640_COM7 0x12 +#define OV9640_COM8 0x13 +#define OV9640_COM9 0x14 +#define OV9640_COM10 0x15 +/* 0x16 - RESERVED */ +#define OV9640_HSTART 0x17 +#define OV9640_HSTOP 0x18 +#define OV9640_VSTART 0x19 +#define OV9640_VSTOP 0x1a +#define OV9640_PSHFT 0x1b +#define OV9640_MIDH 0x1c +#define OV9640_MIDL 0x1d +#define OV9640_MVFP 0x1e +#define OV9640_LAEC 0x1f +#define OV9640_BOS 0x20 +#define OV9640_GBOS 0x21 +#define OV9640_GROS 0x22 +#define OV9640_ROS 0x23 +#define OV9640_AEW 0x24 +#define OV9640_AEB 0x25 +#define OV9640_VPT 0x26 +#define OV9640_BBIAS 0x27 +#define OV9640_GBBIAS 0x28 +/* 0x29 - RESERVED */ +#define OV9640_EXHCH 0x2a +#define OV9640_EXHCL 0x2b +#define OV9640_RBIAS 0x2c +#define OV9640_ADVFL 0x2d +#define OV9640_ADVFH 0x2e +#define OV9640_YAVE 0x2f +#define OV9640_HSYST 0x30 +#define OV9640_HSYEN 0x31 +#define OV9640_HREF 0x32 +#define OV9640_CHLF 0x33 +#define OV9640_ARBLM 0x34 +/* 0x35..0x36 - RESERVED */ +#define OV9640_ADC 0x37 +#define OV9640_ACOM 0x38 +#define OV9640_OFON 0x39 +#define OV9640_TSLB 0x3a +#define OV9640_COM11 0x3b +#define OV9640_COM12 0x3c +#define OV9640_COM13 0x3d +#define OV9640_COM14 0x3e +#define OV9640_EDGE 0x3f +#define OV9640_COM15 0x40 +#define OV9640_COM16 0x41 +#define OV9640_COM17 0x42 +/* 0x43..0x4e - RESERVED */ +#define OV9640_MTX1 0x4f +#define OV9640_MTX2 0x50 +#define OV9640_MTX3 0x51 +#define OV9640_MTX4 0x52 +#define OV9640_MTX5 0x53 +#define OV9640_MTX6 0x54 +#define OV9640_MTX7 0x55 +#define OV9640_MTX8 0x56 +#define OV9640_MTX9 0x57 +#define OV9640_MTXS 0x58 +/* 0x59..0x61 - RESERVED */ +#define OV9640_LCC1 0x62 +#define OV9640_LCC2 0x63 +#define OV9640_LCC3 0x64 +#define OV9640_LCC4 0x65 +#define OV9640_LCC5 0x66 +#define OV9640_MANU 0x67 +#define OV9640_MANV 0x68 +#define OV9640_HV 0x69 +#define OV9640_MBD 0x6a +#define OV9640_DBLV 0x6b +#define OV9640_GSP 0x6c /* ... till 0x7b */ +#define OV9640_GST 0x7c /* ... till 0x8a */ + +#define OV9640_CLKRC_DPLL_EN 0x80 +#define OV9640_CLKRC_DIRECT 0x40 +#define OV9640_CLKRC_DIV(x) ((x) & 0x3f) + +#define OV9640_PSHFT_VAL(x) ((x) & 0xff) + +#define OV9640_ACOM_2X_ANALOG 0x80 +#define OV9640_ACOM_RSVD 0x12 + +#define OV9640_MVFP_V 0x10 +#define OV9640_MVFP_H 0x20 + +#define OV9640_COM1_HREF_NOSKIP 0x00 +#define OV9640_COM1_HREF_2SKIP 0x04 +#define OV9640_COM1_HREF_3SKIP 0x08 +#define OV9640_COM1_QQFMT 0x20 + +#define OV9640_COM2_SSM 0x10 + +#define OV9640_COM3_VP 0x04 + +#define OV9640_COM4_QQ_VP 0x80 +#define OV9640_COM4_RSVD 0x40 + +#define OV9640_COM5_SYSCLK 0x80 +#define OV9640_COM5_LONGEXP 0x01 + +#define OV9640_COM6_OPT_BLC 0x40 +#define OV9640_COM6_ADBLC_BIAS 0x08 +#define OV9640_COM6_FMT_RST 0x82 +#define OV9640_COM6_ADBLC_OPTEN 0x01 + +#define OV9640_COM7_RAW_RGB 0x01 +#define OV9640_COM7_RGB 0x04 +#define OV9640_COM7_QCIF 0x08 +#define OV9640_COM7_QVGA 0x10 +#define OV9640_COM7_CIF 0x20 +#define OV9640_COM7_VGA 0x40 +#define OV9640_COM7_SCCB_RESET 0x80 + +#define OV9640_TSLB_YVYU_YUYV 0x04 +#define OV9640_TSLB_YUYV_UYVY 0x08 + +#define OV9640_COM12_YUV_AVG 0x04 +#define OV9640_COM12_RSVD 0x40 + +#define OV9640_COM13_GAMMA_NONE 0x00 +#define OV9640_COM13_GAMMA_Y 0x40 +#define OV9640_COM13_GAMMA_RAW 0x80 +#define OV9640_COM13_RGB_AVG 0x20 +#define OV9640_COM13_MATRIX_EN 0x10 +#define OV9640_COM13_Y_DELAY_EN 0x08 +#define OV9640_COM13_YUV_DLY(x) ((x) & 0x07) + +#define OV9640_COM15_OR_00FF 0x00 +#define OV9640_COM15_OR_01FE 0x40 +#define OV9640_COM15_OR_10F0 0xc0 +#define OV9640_COM15_RGB_NORM 0x00 +#define OV9640_COM15_RGB_565 0x10 +#define OV9640_COM15_RGB_555 0x30 + +#define OV9640_COM16_RB_AVG 0x01 + +/* IDs */ +#define OV9640_V2 0x9648 +#define OV9640_V3 0x9649 +#define VERSION(pid, ver) (((pid) << 8) | ((ver) & 0xFF)) + +/* supported resolutions */ +enum { + W_QQCIF = 88, + W_QQVGA = 160, + W_QCIF = 176, + W_QVGA = 320, + W_CIF = 352, + W_VGA = 640, + W_SXGA = 1280 +}; +#define H_SXGA 960 + +/* Misc. structures */ +struct ov9640_reg_alt { + u8 com7; + u8 com12; + u8 com13; + u8 com15; +}; + +struct ov9640_reg { + u8 reg; + u8 val; +}; + +struct ov9640_priv { + struct v4l2_subdev subdev; + + int model; + int revision; + + bool flag_vflip; + bool flag_hflip; +}; + +#endif /* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */ -- cgit v1.2.3-18-g5258 From aa15c0a347be6d5d16c557ed5b6b72345be48bdd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 26 Sep 2009 13:29:35 -0300 Subject: V4L/DVB (13042): Add NEC protocol to firmware v1.2 handler Currently, dvb_usb_dib0700_ir_proto is supported only with firmwares older than 1.2. Adds support for it also with the newer firmware. This is needed in order to support PixelView SBTVD IR. Cc: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 61 +++++++++++++++++------------ 1 file changed, 37 insertions(+), 24 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 6bd8951ea02..81569deaa19 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -558,8 +558,7 @@ static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event, struct dib0700_rc_response { u8 report_id; u8 data_state; - u8 system_msb; - u8 system_lsb; + u16 system; u8 data; u8 not_data; }; @@ -589,37 +588,51 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, return 0; } - if (actlen != sizeof(buf)) { - /* We didn't get back the 6 byte message we expected */ - err("Unexpected RC response size [%d]", actlen); - return -1; - } + printk("IR raw %2X %2X %2X %2X %2X %2X (len %d)\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], actlen); - poll_reply.report_id = buf[0]; - poll_reply.data_state = buf[1]; - poll_reply.system_msb = buf[2]; - poll_reply.system_lsb = buf[3]; - poll_reply.data = buf[4]; - poll_reply.not_data = buf[5]; + switch (dvb_usb_dib0700_ir_proto) { + case 0: + poll_reply.report_id = 0; + poll_reply.data_state = 1; + poll_reply.system = buf[2]; + poll_reply.data = buf[4]; + poll_reply.not_data = buf[5]; - /* - info("rid=%02x ds=%02x sm=%02x sl=%02x d=%02x nd=%02x\n", - poll_reply.report_id, poll_reply.data_state, - poll_reply.system_msb, poll_reply.system_lsb, - poll_reply.data, poll_reply.not_data); - */ + /* NEC protocol sends repeat code as 0 0 0 FF */ + if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00) + && (poll_reply.not_data == 0xff)) { + poll_reply.data_state = 2; + break; + } + break; + default: + if (actlen != sizeof(buf)) { + /* We didn't get back the 6 byte message we expected */ + err("Unexpected RC response size [%d]", actlen); + return -1; + } + + poll_reply.report_id = buf[0]; + poll_reply.data_state = buf[1]; + poll_reply.system = (buf[2] << 8) | buf[3]; + poll_reply.data = buf[4]; + poll_reply.not_data = buf[5]; + + break; + } if ((poll_reply.data + poll_reply.not_data) != 0xff) { /* Key failed integrity check */ - err("key failed integrity check: %02x %02x %02x %02x", - poll_reply.system_msb, poll_reply.system_lsb, + err("key failed integrity check: %04x %02x %02x", + poll_reply.system, poll_reply.data, poll_reply.not_data); return -1; } + /* Find the key in the map */ for (i = 0; i < d->props.rc_key_map_size; i++) { - if (rc5_custom(&keymap[i]) == poll_reply.system_lsb && + if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) && rc5_data(&keymap[i]) == poll_reply.data) { *event = keymap[i].event; found = 1; @@ -628,8 +641,8 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, } if (found == 0) { - err("Unknown remote controller key: %02x %02x %02x %02x", - poll_reply.system_msb, poll_reply.system_lsb, + err("Unknown remote controller key: %04x %02x %02x", + poll_reply.system, poll_reply.data, poll_reply.not_data); d->last_event = 0; return 0; -- cgit v1.2.3-18-g5258 From 4c5128b30dc079d625bd109a94d5937d14f93ece Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 26 Sep 2009 13:31:31 -0300 Subject: V4L/DVB (13043): Add support for Pixelview SBTVD IR This IR uses NEC protocol. In order to use, dvb_usb_dib0700_ir_proto=0 should be used. Cc: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 81569deaa19..599e03bbb43 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -887,6 +887,37 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0x1d37, KEY_RECORD }, { 0x1d3b, KEY_GOTO }, { 0x1d3d, KEY_POWER }, + + /* Key codes for the Pixelview SBTVD remote (proto NEC) */ + { 0x8613, KEY_MUTE }, + { 0x8612, KEY_POWER }, + { 0x8601, KEY_1 }, + { 0x8602, KEY_2 }, + { 0x8603, KEY_3 }, + { 0x8604, KEY_4 }, + { 0x8605, KEY_5 }, + { 0x8606, KEY_6 }, + { 0x8607, KEY_7 }, + { 0x8608, KEY_8 }, + { 0x8609, KEY_9 }, + { 0x8600, KEY_0 }, + { 0x860d, KEY_CHANNELUP }, + { 0x8619, KEY_CHANNELDOWN }, + { 0x8610, KEY_VOLUMEUP }, + { 0x860c, KEY_VOLUMEDOWN }, + + { 0x860a, KEY_CAMERA }, + { 0x860b, KEY_ZOOM }, + { 0x861b, KEY_BACKSPACE }, + { 0x8615, KEY_ENTER }, + + { 0x861d, KEY_UP }, + { 0x861e, KEY_DOWN }, + { 0x860e, KEY_LEFT }, + { 0x860f, KEY_RIGHT }, + + { 0x8618, KEY_RECORD }, + { 0x861a, KEY_STOP }, }; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ -- cgit v1.2.3-18-g5258 From 61b1e58f0e1b9dd0e6ab7199f19b93948af4baa1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 26 Sep 2009 13:45:03 -0300 Subject: V4L/DVB (13044): dib0700: Be less verbose when an IR key is pressed Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 599e03bbb43..bf8e83187cb 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -588,7 +588,6 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, return 0; } - printk("IR raw %2X %2X %2X %2X %2X %2X (len %d)\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], actlen); switch (dvb_usb_dib0700_ir_proto) { case 0: -- cgit v1.2.3-18-g5258 From 8171c2059cc4b0507faf3a0e0fdf28cc83d8ac62 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sat, 19 Sep 2009 08:37:40 -0300 Subject: V4L/DVB (13045): Fix debug messaging for stv0900 demod. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0900_core.c | 58 +++++++++++++++--------------- drivers/media/dvb/frontends/stv0900_priv.h | 2 +- drivers/media/dvb/frontends/stv0900_sw.c | 31 ++++++++-------- 3 files changed, 46 insertions(+), 45 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c index 3bde3324a03..768a1611e8c 100644 --- a/drivers/media/dvb/frontends/stv0900_core.c +++ b/drivers/media/dvb/frontends/stv0900_core.c @@ -34,7 +34,7 @@ #include "stv0900_priv.h" #include "stv0900_init.h" -static int stvdebug = 1; +int stvdebug = 1; module_param_named(debug, stvdebug, int, 0644); /* internal params node */ @@ -146,7 +146,7 @@ void stv0900_write_reg(struct stv0900_internal *i_params, u16 reg_addr, ret = i2c_transfer(i_params->i2c_adap, &i2cmsg, 1); if (ret != 1) - dprintk(KERN_ERR "%s: i2c error %d\n", __func__, ret); + dprintk("%s: i2c error %d\n", __func__, ret); } u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg) @@ -170,7 +170,7 @@ u8 stv0900_read_reg(struct stv0900_internal *i_params, u16 reg) ret = i2c_transfer(i_params->i2c_adap, msg, 2); if (ret != 2) - dprintk(KERN_ERR "%s: i2c error %d, reg[0x%02x]\n", + dprintk("%s: i2c error %d, reg[0x%02x]\n", __func__, ret, reg); return buf; @@ -281,7 +281,7 @@ u32 stv0900_get_mclk_freq(struct stv0900_internal *i_params, u32 ext_clk) mclk = (div + 1) * ext_clk / ad_div; - dprintk(KERN_INFO "%s: Calculated Mclk = %d\n", __func__, mclk); + dprintk("%s: Calculated Mclk = %d\n", __func__, mclk); return mclk; } @@ -291,7 +291,7 @@ enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *i_params, u32 mc enum fe_stv0900_error error = STV0900_NO_ERROR; u32 m_div, clk_sel; - dprintk(KERN_INFO "%s: Mclk set to %d, Quartz = %d\n", __func__, mclk, + dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk, i_params->quartz); if (i_params == NULL) @@ -381,7 +381,7 @@ static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params, enum fe_stv0900_clock_type path2_ts) { - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); if (i_params->chip_id >= 0x20) { switch (path1_ts) { @@ -423,7 +423,7 @@ static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params, case STV0900_DVBCI_CLOCK: stv0900_write_reg(i_params, R0900_TSGENERAL, 0x0A); - dprintk(KERN_INFO "%s: 0x0a\n", __func__); + dprintk("%s: 0x0a\n", __func__); break; } break; @@ -469,7 +469,7 @@ static void stv0900_set_ts_parallel_serial(struct stv0900_internal *i_params, case STV0900_DVBCI_CLOCK: stv0900_write_reg(i_params, R0900_TSGENERAL1X, 0x12); - dprintk(KERN_INFO "%s: 0x12\n", __func__); + dprintk("%s: 0x12\n", __func__); break; } @@ -584,7 +584,7 @@ static s32 stv0900_get_rf_level(struct stv0900_internal *i_params, i, rf_lvl = 0; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); if ((lookup != NULL) && lookup->size) { switch (demod) { @@ -622,7 +622,7 @@ static s32 stv0900_get_rf_level(struct stv0900_internal *i_params, } - dprintk(KERN_INFO "%s: RFLevel = %d\n", __func__, rf_lvl); + dprintk("%s: RFLevel = %d\n", __func__, rf_lvl); return rf_lvl; } @@ -654,7 +654,7 @@ static s32 stv0900_carr_get_quality(struct dvb_frontend *fe, noise_field1, noise_field0; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); dmd_reg(lock_flag_field, F0900_P1_LOCK_DEFINITIF, F0900_P2_LOCK_DEFINITIF); @@ -876,7 +876,7 @@ void stv0900_stop_all_s2_modcod(struct stv0900_internal *i_params, s32 regflist, i; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); dmd_reg(regflist, R0900_P1_MODCODLST0, R0900_P2_MODCODLST0); @@ -893,7 +893,7 @@ void stv0900_activate_s2_modcode(struct stv0900_internal *i_params, reg_index, field_index; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); if (i_params->chip_id <= 0x11) { msleep(5); @@ -979,7 +979,7 @@ void stv0900_activate_s2_modcode_single(struct stv0900_internal *i_params, { u32 reg_index; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); switch (demod) { case STV0900_DEMOD_1: @@ -1012,7 +1012,7 @@ static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe) static int stb0900_set_property(struct dvb_frontend *fe, struct dtv_property *tvp) { - dprintk(KERN_INFO "%s(..)\n", __func__); + dprintk("%s(..)\n", __func__); return 0; } @@ -1020,7 +1020,7 @@ static int stb0900_set_property(struct dvb_frontend *fe, static int stb0900_get_property(struct dvb_frontend *fe, struct dtv_property *tvp) { - dprintk(KERN_INFO "%s(..)\n", __func__); + dprintk("%s(..)\n", __func__); return 0; } @@ -1191,7 +1191,7 @@ u8 stv0900_get_optim_carr_loop(s32 srate, enum fe_stv0900_modcode modcode, s32 i; const struct stv0900_car_loop_optim *car_loop_s2; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); if (chip_id <= 0x12) car_loop_s2 = FE_STV0900_S2CarLoop; @@ -1294,7 +1294,7 @@ u8 stv0900_get_optim_short_carr_loop(s32 srate, enum fe_stv0900_modulation modul u8 aclc_value = 0x0b; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); switch (modulation) { case STV0900_QPSK: @@ -1351,7 +1351,7 @@ static enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *i_ { enum fe_stv0900_error error = STV0900_NO_ERROR; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); switch (LDPC_Mode) { case STV0900_DUAL: @@ -1398,12 +1398,12 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe, struct stv0900_inode *temp_int = find_inode(state->i2c_adap, state->config->demod_address); - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); if (temp_int != NULL) { state->internal = temp_int->internal; (state->internal->dmds_used)++; - dprintk(KERN_INFO "%s: Find Internal Structure!\n", __func__); + dprintk("%s: Find Internal Structure!\n", __func__); return STV0900_NO_ERROR; } else { state->internal = kmalloc(sizeof(struct stv0900_internal), GFP_KERNEL); @@ -1413,7 +1413,7 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe, state->internal->i2c_addr = state->config->demod_address; state->internal->clkmode = state->config->clkmode; state->internal->errs = STV0900_NO_ERROR; - dprintk(KERN_INFO "%s: Create New Internal Structure!\n", __func__); + dprintk("%s: Create New Internal Structure!\n", __func__); } if (state->internal != NULL) { @@ -1551,7 +1551,7 @@ static enum dvbfe_search stv0900_search(struct dvb_frontend *fe, enum fe_stv0900_error error = STV0900_NO_ERROR; - dprintk(KERN_INFO "%s: ", __func__); + dprintk("%s: ", __func__); p_result.locked = FALSE; p_search.path = state->demod; @@ -1652,10 +1652,10 @@ static enum dvbfe_search stv0900_search(struct dvb_frontend *fe, error = STV0900_BAD_PARAMETER; if ((p_result.locked == TRUE) && (error == STV0900_NO_ERROR)) { - dprintk(KERN_INFO "Search Success\n"); + dprintk("Search Success\n"); return DVBFE_ALGO_SEARCH_SUCCESS; } else { - dprintk(KERN_INFO "Search Fail\n"); + dprintk("Search Fail\n"); return DVBFE_ALGO_SEARCH_FAILED; } @@ -1723,7 +1723,7 @@ static int stv0900_diseqc_init(struct dvb_frontend *fe) static int stv0900_init(struct dvb_frontend *fe) { - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); stv0900_stop_ts(fe, 1); stv0900_diseqc_init(fe); @@ -1865,7 +1865,7 @@ static int stv0900_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) enum fe_stv0900_demod_num demod = state->demod; s32 mode_field, reset_field; - dprintk(KERN_INFO "%s: %s\n", __func__, ((tone == 0) ? "Off" : "On")); + dprintk("%s: %s\n", __func__, ((tone == 0) ? "Off" : "On")); dmd_reg(mode_field, F0900_P1_DISTX_MODE, F0900_P2_DISTX_MODE); dmd_reg(reset_field, F0900_P1_DISEQC_RESET, F0900_P2_DISEQC_RESET); @@ -1889,11 +1889,11 @@ static void stv0900_release(struct dvb_frontend *fe) { struct stv0900_state *state = fe->demodulator_priv; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); if ((--(state->internal->dmds_used)) <= 0) { - dprintk(KERN_INFO "%s: Actually removing\n", __func__); + dprintk("%s: Actually removing\n", __func__); remove_inode(state->internal); kfree(state->internal); diff --git a/drivers/media/dvb/frontends/stv0900_priv.h b/drivers/media/dvb/frontends/stv0900_priv.h index 5ed7a145c7d..5f4414f8da2 100644 --- a/drivers/media/dvb/frontends/stv0900_priv.h +++ b/drivers/media/dvb/frontends/stv0900_priv.h @@ -60,7 +60,7 @@ } \ } while (0) -static int stvdebug; +extern int stvdebug; #define dprintk(args...) \ do { \ diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c index 962fde1437c..8c83c8b306a 100644 --- a/drivers/media/dvb/frontends/stv0900_sw.c +++ b/drivers/media/dvb/frontends/stv0900_sw.c @@ -527,7 +527,7 @@ static void stv0900_set_symbol_rate(struct stv0900_internal *i_params, s32 sfr_init_reg; u32 symb; - dprintk(KERN_INFO "%s: Mclk %d, SR %d, Dmd %d\n", __func__, mclk, + dprintk("%s: Mclk %d, SR %d, Dmd %d\n", __func__, mclk, srate, demod); dmd_reg(sfr_init_reg, R0900_P1_SFRINIT1, R0900_P2_SFRINIT1); @@ -952,7 +952,7 @@ static void stv0900_set_viterbi_tracq(struct stv0900_internal *i_params, s32 vth_reg; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); dmd_reg(vth_reg, R0900_P1_VTH12, R0900_P2_VTH12); @@ -973,7 +973,7 @@ static void stv0900_set_viterbi_standard(struct stv0900_internal *i_params, s32 fecmReg, prvitReg; - dprintk(KERN_INFO "%s: ViterbiStandard = ", __func__); + dprintk("%s: ViterbiStandard = ", __func__); switch (demod) { case STV0900_DEMOD_1: @@ -1055,7 +1055,7 @@ static void stv0900_track_optimization(struct dvb_frontend *fe) enum fe_stv0900_rolloff rolloff; enum fe_stv0900_modcode foundModcod; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); srate = stv0900_get_symbol_rate(i_params, i_params->mclk, demod); srate += stv0900_get_timing_offst(i_params, srate, demod); @@ -1370,7 +1370,7 @@ static int stv0900_get_fec_lock(struct stv0900_internal *i_params, enum fe_stv09 enum fe_stv0900_search_state dmd_state; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); dmd_reg(header_field, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE); dmd_reg(pktdelin_field, F0900_P1_PKTDELIN_LOCK, F0900_P2_PKTDELIN_LOCK); @@ -1414,7 +1414,7 @@ static int stv0900_wait_for_lock(struct stv0900_internal *i_params, s32 timer = 0, lock = 0, str_merg_rst_fld, str_merg_lock_fld; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); dmd_reg(str_merg_rst_fld, F0900_P1_RST_HWARE, F0900_P2_RST_HWARE); dmd_reg(str_merg_lock_fld, F0900_P1_TSFIFO_LINEOK, F0900_P2_TSFIFO_LINEOK); @@ -1427,7 +1427,8 @@ static int stv0900_wait_for_lock(struct stv0900_internal *i_params, if (lock) { lock = 0; - dprintk(KERN_INFO "%s: Timer = %d, time_out = %d\n", __func__, timer, fec_timeout); + dprintk("%s: Timer = %d, time_out = %d\n", __func__, timer, + fec_timeout); while ((timer < fec_timeout) && (lock == 0)) { lock = stv0900_get_bits(i_params, str_merg_lock_fld); @@ -1437,9 +1438,9 @@ static int stv0900_wait_for_lock(struct stv0900_internal *i_params, } if (lock) - dprintk(KERN_INFO "%s: DEMOD LOCK OK\n", __func__); + dprintk("%s: DEMOD LOCK OK\n", __func__); else - dprintk(KERN_INFO "%s: DEMOD LOCK FAIL\n", __func__); + dprintk("%s: DEMOD LOCK FAIL\n", __func__); if (lock) return TRUE; @@ -1456,7 +1457,7 @@ enum fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe, s32 state_field, dss_dvb_field; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); dmd_reg(state_field, F0900_P1_HEADER_MODE, F0900_P2_HEADER_MODE); dmd_reg(dss_dvb_field, F0900_P1_DSS_DVB, F0900_P2_DSS_DVB); @@ -1820,7 +1821,7 @@ static u16 stv0900_blind_check_agc2_min_level(struct stv0900_internal *i_params, s32 i, j, nb_steps, direction; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); switch (demod) { case STV0900_DEMOD_1: @@ -2274,7 +2275,7 @@ static int stv0900_blind_search_algo(struct dvb_frontend *fe) u16 agc2_integr; u8 dstatus2; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); if (i_params->chip_id < 0x20) { k_ref_tmg_max = 233; @@ -2397,7 +2398,7 @@ static void stv0900_set_viterbi_acq(struct stv0900_internal *i_params, { s32 vth_reg; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); dmd_reg(vth_reg, R0900_P1_VTH12, R0900_P2_VTH12); @@ -2415,7 +2416,7 @@ static void stv0900_set_search_standard(struct stv0900_internal *i_params, int sstndrd; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); sstndrd = i_params->dmd1_srch_standard; if (demod == 1) @@ -2578,7 +2579,7 @@ enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe) enum fe_stv0900_search_algo algo; int no_signal = FALSE; - dprintk(KERN_INFO "%s\n", __func__); + dprintk("%s\n", __func__); switch (demod) { case STV0900_DEMOD_1: -- cgit v1.2.3-18-g5258 From f8731f4ddedb78693ae05e40aac5c4817f740518 Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Fri, 18 Sep 2009 04:08:43 -0300 Subject: V4L/DVB (13049): dib8000: SNR in 10th of dB dib7000p/dib8000: added pid filtering dib8000: the SNR is in 10th of dB (not in dB) dib7000p and dib8000: added the pid filtering. This feature is enabled by module option (dvb-usb module). Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 71 +++++++++++++++++++++++++++++ drivers/media/dvb/frontends/dib7000p.c | 18 ++++++++ drivers/media/dvb/frontends/dib7000p.h | 13 ++++++ drivers/media/dvb/frontends/dib8000.c | 21 ++++++++- drivers/media/dvb/frontends/dib8000.h | 14 ++++++ 5 files changed, 136 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index bf8e83187cb..cda60291c06 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1252,6 +1252,16 @@ static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) return 0; } +static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) +{ + return dib7000p_pid_filter(adapter->fe, index, pid, onoff); +} + +static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) +{ + return dib7000p_pid_filter_ctrl(adapter->fe, onoff); +} + static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { 60000, 15000, // internal, sampling 1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass @@ -1543,6 +1553,15 @@ static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) return 0; } +static int stk807x_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) +{ + return dib8000_pid_filter(adapter->fe, index, pid, onoff); +} + +static int stk807x_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) +{ + return dib8000_pid_filter_ctrl(adapter->fe, onoff); +} /* STK807x */ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) @@ -1938,6 +1957,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, .frontend_attach = stk7700p_frontend_attach, .tuner_attach = stk7700p_tuner_attach, @@ -2019,11 +2042,19 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, .frontend_attach = stk7700d_frontend_attach, .tuner_attach = stk7700d_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x02), }, { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, .frontend_attach = stk7700d_frontend_attach, .tuner_attach = stk7700d_tuner_attach, @@ -2066,6 +2097,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, .frontend_attach = stk7700P2_frontend_attach, .tuner_attach = stk7700d_tuner_attach, @@ -2098,6 +2133,14 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, .frontend_attach = stk7070p_frontend_attach, .tuner_attach = dib7070p_tuner_attach, @@ -2200,6 +2243,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, .frontend_attach = stk7070pd_frontend_attach0, .tuner_attach = dib7070p_tuner_attach, @@ -2207,6 +2254,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { .size_of_priv = sizeof(struct dib0700_adapter_state), }, { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, .frontend_attach = stk7070pd_frontend_attach1, .tuner_attach = dib7070p_tuner_attach, @@ -2253,6 +2304,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, .frontend_attach = stk7700ph_frontend_attach, .tuner_attach = stk7700ph_tuner_attach, @@ -2365,6 +2420,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, .frontend_attach = stk7070p_frontend_attach, .tuner_attach = dib7770p_tuner_attach, @@ -2396,6 +2455,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk807x_pid_filter, + .pid_filter_ctrl = stk807x_pid_filter_ctrl, .frontend_attach = stk807x_frontend_attach, .tuner_attach = dib807x_tuner_attach, @@ -2427,6 +2490,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 2, .adapter = { { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk807x_pid_filter, + .pid_filter_ctrl = stk807x_pid_filter_ctrl, .frontend_attach = stk807xpvr_frontend_attach0, .tuner_attach = dib807x_tuner_attach, @@ -2436,6 +2503,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { sizeof(struct dib0700_adapter_state), }, { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk807x_pid_filter, + .pid_filter_ctrl = stk807x_pid_filter_ctrl, .frontend_attach = stk807xpvr_frontend_attach1, .tuner_attach = dib807x_tuner_attach, diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 0781f94e05d..60e1aaaec5b 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -1302,6 +1302,24 @@ struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum di } EXPORT_SYMBOL(dib7000p_get_i2c_master); +int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 val = dib7000p_read_word(state, 235) & 0xffef; + val |= (onoff & 0x1) << 4; + dprintk("PID filter enabled %d", onoff); + return dib7000p_write_word(state, 235, val); +} +EXPORT_SYMBOL(dib7000p_pid_filter_ctrl); + +int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + struct dib7000p_state *state = fe->demodulator_priv; + dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff); + return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0); +} +EXPORT_SYMBOL(dib7000p_pid_filter); + int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]) { struct dib7000p_state st = { .i2c_adap = i2c }; diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 02a4c82f0c7..3a769df3c86 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -51,6 +51,8 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); +extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); +extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); #else static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, @@ -95,6 +97,17 @@ static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap) printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } +static inline int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, uint8_t onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} #endif #endif diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index 852c790d09d..44c2dc9b4f1 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -2121,7 +2121,7 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) else result -= intlog10(2) * 10 * noise_exp - 100; - *snr = result / (1 << 24); + *snr = result / ((1 << 24) / 10); return 0; } @@ -2195,6 +2195,25 @@ struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000 EXPORT_SYMBOL(dib8000_get_i2c_master); +int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +{ + struct dib8000_state *st = fe->demodulator_priv; + u16 val = dib8000_read_word(st, 299) & 0xffef; + val |= (onoff & 0x1) << 4; + + dprintk("pid filter enabled %d", onoff); + return dib8000_write_word(st, 299, val); +} +EXPORT_SYMBOL(dib8000_pid_filter_ctrl); + +int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + struct dib8000_state *st = fe->demodulator_priv; + dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); + return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0); +} +EXPORT_SYMBOL(dib8000_pid_filter); + static const struct dvb_frontend_ops dib8000_ops = { .info = { .name = "DiBcom 8000 ISDB-T", diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h index a86de340dd5..8c89482b738 100644 --- a/drivers/media/dvb/frontends/dib8000.h +++ b/drivers/media/dvb/frontends/dib8000.h @@ -44,6 +44,8 @@ extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value); +extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff); +extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); #else static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) { @@ -74,6 +76,18 @@ int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } + +int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} #endif #endif -- cgit v1.2.3-18-g5258 From eac1fe1050f223d28ebe5bb73b438d82ffd5b675 Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Wed, 23 Sep 2009 13:41:27 -0300 Subject: V4L/DVB (13051): DiB7000P: improve rebostness of HAS_LOCK indicator Update the dib7000p: The status is HAS_LOCK only if the demod is able to decode the TPS. Sometimes, there is a TPS data lock, even if the demod is not able to decode it (ex: no RF signal). For the STK7770P: correct value for the charge pump Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 1 + drivers/media/dvb/frontends/dib7000p.c | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index cda60291c06..3b7e07749c3 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1176,6 +1176,7 @@ static struct dib0070_config dib7770p_dib0070_config = { .clock_khz = 12000, .clock_pad_drive = 0, .flip_chip = 1, + .charge_pump = 2, }; static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 60e1aaaec5b..750ae61a20f 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -108,7 +108,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) outreg = 0; fifo_threshold = 1792; - smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1); + smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1); dprintk( "setting output mode for demod %p to %d", &state->demod, mode); @@ -162,18 +162,19 @@ static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) if (state->div_force_off) { dprintk( "diversity combination deactivated - forced by COFDM parameters"); onoff = 0; - } + dib7000p_write_word(state, 207, 0); + } else + dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); + state->div_state = (u8)onoff; if (onoff) { dib7000p_write_word(state, 204, 6); dib7000p_write_word(state, 205, 16); /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ - dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); } else { dib7000p_write_word(state, 204, 1); dib7000p_write_word(state, 205, 0); - dib7000p_write_word(state, 207, 0); } return 0; @@ -1188,7 +1189,7 @@ static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat) *stat |= FE_HAS_VITERBI; if (lock & 0x0010) *stat |= FE_HAS_SYNC; - if (lock & 0x0008) + if ((lock & 0x0038) == 0x38) *stat |= FE_HAS_LOCK; return 0; @@ -1332,8 +1333,10 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau /* designated i2c address */ new_addr = (0x40 + k) << 1; st.i2c_addr = new_addr; + dib7000p_write_word(&st, 1287, 0x0003); /* sram lead in, rdy */ if (dib7000p_identify(&st) != 0) { st.i2c_addr = default_addr; + dib7000p_write_word(&st, 1287, 0x0003); /* sram lead in, rdy */ if (dib7000p_identify(&st) != 0) { dprintk("DiB7000P #%d: not identified\n", k); return -EIO; @@ -1390,6 +1393,8 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops)); + dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */ + if (dib7000p_identify(st) != 0) goto error; -- cgit v1.2.3-18-g5258 From 8a378e8543f044b3e54ddbbb03c349bf054fcedf Mon Sep 17 00:00:00 2001 From: S?rgio Fortier