diff options
| -rw-r--r-- | drivers/media/video/gspca/sonixb.c | 100 |
1 files changed, 93 insertions, 7 deletions
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index a512772664a3..51435e3dbb10 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c | |||
| @@ -44,6 +44,7 @@ struct sd { | |||
| 44 | unsigned char brightness; | 44 | unsigned char brightness; |
| 45 | unsigned char autogain; | 45 | unsigned char autogain; |
| 46 | unsigned char autogain_ignore_frames; | 46 | unsigned char autogain_ignore_frames; |
| 47 | unsigned char freq; /* light freq filter setting */ | ||
| 47 | 48 | ||
| 48 | unsigned char fr_h_sz; /* size of frame header */ | 49 | unsigned char fr_h_sz; /* size of frame header */ |
| 49 | char sensor; /* Type of image sensor chip */ | 50 | char sensor; /* Type of image sensor chip */ |
| @@ -85,6 +86,8 @@ static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); | |||
| 85 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); | 86 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); |
| 86 | static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); | 87 | static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); |
| 87 | static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); | 88 | static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); |
| 89 | static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); | ||
| 90 | static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); | ||
| 88 | 91 | ||
| 89 | static struct ctrl sd_ctrls[] = { | 92 | static struct ctrl sd_ctrls[] = { |
| 90 | { | 93 | { |
| @@ -147,6 +150,20 @@ static struct ctrl sd_ctrls[] = { | |||
| 147 | .set = sd_setautogain, | 150 | .set = sd_setautogain, |
| 148 | .get = sd_getautogain, | 151 | .get = sd_getautogain, |
| 149 | }, | 152 | }, |
| 153 | { | ||
| 154 | { | ||
| 155 | .id = V4L2_CID_POWER_LINE_FREQUENCY, | ||
| 156 | .type = V4L2_CTRL_TYPE_MENU, | ||
| 157 | .name = "Light frequency filter", | ||
| 158 | .minimum = 0, | ||
| 159 | .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ | ||
| 160 | .step = 1, | ||
| 161 | #define FREQ_DEF 1 | ||
| 162 | .default_value = FREQ_DEF, | ||
| 163 | }, | ||
| 164 | .set = sd_setfreq, | ||
| 165 | .get = sd_getfreq, | ||
| 166 | }, | ||
| 150 | }; | 167 | }; |
| 151 | 168 | ||
| 152 | static struct v4l2_pix_format vga_mode[] = { | 169 | static struct v4l2_pix_format vga_mode[] = { |
| @@ -225,11 +242,6 @@ static const __u8 ov6650_sensor_init[][8] = | |||
| 225 | /* Some more unknown stuff */ | 242 | /* Some more unknown stuff */ |
| 226 | {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10}, | 243 | {0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10}, |
| 227 | {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */ | 244 | {0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */ |
| 228 | {0xa0, 0x60, 0x10, 0x57, 0x99, 0x04, 0x94, 0x16}, | ||
| 229 | /* Framerate adjust register for artificial light 50 hz flicker | ||
| 230 | compensation, identical to ov6630 0x2b register, see 6630 datasheet. | ||
| 231 | 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */ | ||
| 232 | {0xa0, 0x60, 0x2b, 0x4f, 0x99, 0x04, 0x94, 0x15}, | ||
| 233 | }; | 245 | }; |
| 234 | 246 | ||
| 235 | static const __u8 initOv7630[] = { | 247 | static const __u8 initOv7630[] = { |
| @@ -657,8 +669,12 @@ static void setexposure(struct gspca_dev *gspca_dev) | |||
| 657 | */ | 669 | */ |
| 658 | __u8 i2c[] = {0xb0, 0x60, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10}; | 670 | __u8 i2c[] = {0xb0, 0x60, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10}; |
| 659 | int reg10, reg11; | 671 | int reg10, reg11; |
| 660 | /* No clear idea why, but setting reg10 above this value | 672 | /* ov6645 datasheet says reg10_max is 9a, but that uses |
| 661 | results in no change */ | 673 | tline * 2 * reg10 as formula for calculating texpo, the |
| 674 | ov6650 probably uses the same formula as the 7730 which uses | ||
| 675 | tline * 4 * reg10, which explains why the reg10max we've | ||
| 676 | found experimentally for the ov6650 is exactly half that of | ||
| 677 | the ov6645. */ | ||
| 662 | const int reg10_max = 0x4d; | 678 | const int reg10_max = 0x4d; |
| 663 | 679 | ||
| 664 | reg11 = (60 * sd->exposure + 999) / 1000; | 680 | reg11 = (60 * sd->exposure + 999) / 1000; |
| @@ -713,6 +729,34 @@ static void setexposure(struct gspca_dev *gspca_dev) | |||
| 713 | } | 729 | } |
| 714 | } | 730 | } |
| 715 | 731 | ||
| 732 | static void setfreq(struct gspca_dev *gspca_dev) | ||
| 733 | { | ||
| 734 | struct sd *sd = (struct sd *) gspca_dev; | ||
| 735 | |||
| 736 | switch (sd->sensor) { | ||
| 737 | case SENSOR_OV6650: { | ||
| 738 | /* Framerate adjust register for artificial light 50 hz flicker | ||
| 739 | compensation, identical to ov6630 0x2b register, see ov6630 | ||
| 740 | datasheet. | ||
| 741 | 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */ | ||
| 742 | __u8 i2c[] = {0xa0, 0x60, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}; | ||
| 743 | switch (sd->freq) { | ||
| 744 | default: | ||
| 745 | /* case 0: * no filter*/ | ||
| 746 | /* case 2: * 60 hz */ | ||
| 747 | i2c[3] = 0; | ||
| 748 | break; | ||
| 749 | case 1: /* 50 hz */ | ||
| 750 | i2c[3] = 0x4f; | ||
| 751 | break; | ||
| 752 | } | ||
| 753 | if (i2c_w(gspca_dev, i2c) < 0) | ||
| 754 | PDEBUG(D_ERR, "i2c error setfreq"); | ||
| 755 | break; | ||
| 756 | } | ||
| 757 | } | ||
| 758 | } | ||
| 759 | |||
| 716 | 760 | ||
| 717 | static void do_autogain(struct gspca_dev *gspca_dev) | 761 | static void do_autogain(struct gspca_dev *gspca_dev) |
| 718 | { | 762 | { |
| @@ -746,6 +790,7 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
| 746 | sd->fr_h_sz = 12; /* default size of the frame header */ | 790 | sd->fr_h_sz = 12; /* default size of the frame header */ |
| 747 | sd->sd_desc.nctrls = 2; /* default nb of ctrls */ | 791 | sd->sd_desc.nctrls = 2; /* default nb of ctrls */ |
| 748 | sd->autogain = AUTOGAIN_DEF; /* default is autogain active */ | 792 | sd->autogain = AUTOGAIN_DEF; /* default is autogain active */ |
| 793 | sd->freq = FREQ_DEF; | ||
| 749 | 794 | ||
| 750 | product = id->idProduct; | 795 | product = id->idProduct; |
| 751 | /* switch (id->idVendor) { */ | 796 | /* switch (id->idVendor) { */ |
| @@ -1004,6 +1049,7 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
| 1004 | setgain(gspca_dev); | 1049 | setgain(gspca_dev); |
| 1005 | setbrightness(gspca_dev); | 1050 | setbrightness(gspca_dev); |
| 1006 | setexposure(gspca_dev); | 1051 | setexposure(gspca_dev); |
| 1052 | setfreq(gspca_dev); | ||
| 1007 | 1053 | ||
| 1008 | sd->autogain_ignore_frames = 0; | 1054 | sd->autogain_ignore_frames = 0; |
| 1009 | atomic_set(&sd->avg_lum, -1); | 1055 | atomic_set(&sd->avg_lum, -1); |
| @@ -1161,6 +1207,45 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) | |||
| 1161 | return 0; | 1207 | return 0; |
| 1162 | } | 1208 | } |
| 1163 | 1209 | ||
| 1210 | static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) | ||
| 1211 | { | ||
| 1212 | struct sd *sd = (struct sd *) gspca_dev; | ||
| 1213 | |||
| 1214 | sd->freq = val; | ||
| 1215 | if (gspca_dev->streaming) | ||
| 1216 | setfreq(gspca_dev); | ||
| 1217 | return 0; | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) | ||
| 1221 | { | ||
| 1222 | struct sd *sd = (struct sd *) gspca_dev; | ||
| 1223 | |||
| 1224 | *val = sd->freq; | ||
| 1225 | return 0; | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | static int sd_querymenu(struct gspca_dev *gspca_dev, | ||
| 1229 | struct v4l2_querymenu *menu) | ||
| 1230 | { | ||
| 1231 | switch (menu->id) { | ||
| 1232 | case V4L2_CID_POWER_LINE_FREQUENCY: | ||
| 1233 | switch (menu->index) { | ||
| 1234 | case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ | ||
| 1235 | strcpy((char *) menu->name, "NoFliker"); | ||
| 1236 | return 0; | ||
| 1237 | case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ | ||
| 1238 | strcpy((char *) menu->name, "50 Hz"); | ||
| 1239 | return 0; | ||
| 1240 | case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ | ||
| 1241 | strcpy((char *) menu->name, "60 Hz"); | ||
| 1242 | return 0; | ||
| 1243 | } | ||
| 1244 | break; | ||
| 1245 | } | ||
| 1246 | return -EINVAL; | ||
| 1247 | } | ||
| 1248 | |||
| 1164 | /* sub-driver description */ | 1249 | /* sub-driver description */ |
| 1165 | static const struct sd_desc sd_desc = { | 1250 | static const struct sd_desc sd_desc = { |
| 1166 | .name = MODULE_NAME, | 1251 | .name = MODULE_NAME, |
| @@ -1173,6 +1258,7 @@ static const struct sd_desc sd_desc = { | |||
| 1173 | .stop0 = sd_stop0, | 1258 | .stop0 = sd_stop0, |
| 1174 | .close = sd_close, | 1259 | .close = sd_close, |
| 1175 | .pkt_scan = sd_pkt_scan, | 1260 | .pkt_scan = sd_pkt_scan, |
| 1261 | .querymenu = sd_querymenu, | ||
| 1176 | }; | 1262 | }; |
| 1177 | 1263 | ||
| 1178 | /* -- module initialisation -- */ | 1264 | /* -- module initialisation -- */ |
