diff options
Diffstat (limited to 'drivers/media/video/saa7115.c')
-rw-r--r-- | drivers/media/video/saa7115.c | 137 |
1 files changed, 52 insertions, 85 deletions
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index dceebc0b1250..b59c11717273 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c | |||
@@ -72,6 +72,10 @@ struct saa7115_state { | |||
72 | int sat; | 72 | int sat; |
73 | enum v4l2_chip_ident ident; | 73 | enum v4l2_chip_ident ident; |
74 | u32 audclk_freq; | 74 | u32 audclk_freq; |
75 | u32 crystal_freq; | ||
76 | u8 ucgc; | ||
77 | u8 cgcdiv; | ||
78 | u8 apll; | ||
75 | }; | 79 | }; |
76 | 80 | ||
77 | /* ----------------------------------------------------------------------- */ | 81 | /* ----------------------------------------------------------------------- */ |
@@ -375,10 +379,6 @@ static const unsigned char saa7113_init_auto_input[] = { | |||
375 | }; | 379 | }; |
376 | 380 | ||
377 | static const unsigned char saa7115_init_misc[] = { | 381 | static const unsigned char saa7115_init_misc[] = { |
378 | 0x38, 0x03, /* audio stuff */ | ||
379 | 0x39, 0x10, | ||
380 | 0x3a, 0x08, | ||
381 | |||
382 | 0x81, 0x01, /* reg 0x15,0x16 define blanking window */ | 382 | 0x81, 0x01, /* reg 0x15,0x16 define blanking window */ |
383 | 0x82, 0x00, | 383 | 0x82, 0x00, |
384 | 0x83, 0x01, /* I port settings */ | 384 | 0x83, 0x01, /* I port settings */ |
@@ -584,6 +584,7 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq) | |||
584 | u32 acni; | 584 | u32 acni; |
585 | u32 hz; | 585 | u32 hz; |
586 | u64 f; | 586 | u64 f; |
587 | u8 acc = 0; /* reg 0x3a, audio clock control */ | ||
587 | 588 | ||
588 | v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq); | 589 | v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq); |
589 | 590 | ||
@@ -591,18 +592,34 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq) | |||
591 | if (freq < 32000 || freq > 48000) | 592 | if (freq < 32000 || freq > 48000) |
592 | return -EINVAL; | 593 | return -EINVAL; |
593 | 594 | ||
595 | /* The saa7113 has no audio clock */ | ||
596 | if (state->ident == V4L2_IDENT_SAA7113) | ||
597 | return 0; | ||
598 | |||
594 | /* hz is the refresh rate times 100 */ | 599 | /* hz is the refresh rate times 100 */ |
595 | hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000; | 600 | hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000; |
596 | /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */ | 601 | /* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */ |
597 | acpf = (25600 * freq) / hz; | 602 | acpf = (25600 * freq) / hz; |
598 | /* acni = (256 * freq * 2^23) / crystal_frequency = | 603 | /* acni = (256 * freq * 2^23) / crystal_frequency = |
599 | (freq * 2^(8+23)) / crystal_frequency = | 604 | (freq * 2^(8+23)) / crystal_frequency = |
600 | (freq << 31) / 32.11 MHz */ | 605 | (freq << 31) / crystal_frequency */ |
601 | f = freq; | 606 | f = freq; |
602 | f = f << 31; | 607 | f = f << 31; |
603 | do_div(f, 32110000); | 608 | do_div(f, state->crystal_freq); |
604 | acni = f; | 609 | acni = f; |
610 | if (state->ucgc) { | ||
611 | acpf = acpf * state->cgcdiv / 16; | ||
612 | acni = acni * state->cgcdiv / 16; | ||
613 | acc = 0x80; | ||
614 | if (state->cgcdiv == 3) | ||
615 | acc |= 0x40; | ||
616 | } | ||
617 | if (state->apll) | ||
618 | acc |= 0x08; | ||
605 | 619 | ||
620 | saa7115_write(client, 0x38, 0x03); | ||
621 | saa7115_write(client, 0x39, 0x10); | ||
622 | saa7115_write(client, 0x3a, acc); | ||
606 | saa7115_write(client, 0x30, acpf & 0xff); | 623 | saa7115_write(client, 0x30, acpf & 0xff); |
607 | saa7115_write(client, 0x31, (acpf >> 8) & 0xff); | 624 | saa7115_write(client, 0x31, (acpf >> 8) & 0xff); |
608 | saa7115_write(client, 0x32, (acpf >> 16) & 0x03); | 625 | saa7115_write(client, 0x32, (acpf >> 16) & 0x03); |
@@ -1073,48 +1090,6 @@ static void saa7115_decode_vbi_line(struct i2c_client *client, | |||
1073 | 1090 | ||
1074 | /* ============ SAA7115 AUDIO settings (end) ============= */ | 1091 | /* ============ SAA7115 AUDIO settings (end) ============= */ |
1075 | 1092 | ||
1076 | static struct v4l2_queryctrl saa7115_qctrl[] = { | ||
1077 | { | ||
1078 | .id = V4L2_CID_BRIGHTNESS, | ||
1079 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1080 | .name = "Brightness", | ||
1081 | .minimum = 0, | ||
1082 | .maximum = 255, | ||
1083 | .step = 1, | ||
1084 | .default_value = 128, | ||
1085 | .flags = 0, | ||
1086 | }, { | ||
1087 | .id = V4L2_CID_CONTRAST, | ||
1088 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1089 | .name = "Contrast", | ||
1090 | .minimum = 0, | ||
1091 | .maximum = 127, | ||
1092 | .step = 1, | ||
1093 | .default_value = 64, | ||
1094 | .flags = 0, | ||
1095 | }, { | ||
1096 | .id = V4L2_CID_SATURATION, | ||
1097 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1098 | .name = "Saturation", | ||
1099 | .minimum = 0, | ||
1100 | .maximum = 127, | ||
1101 | .step = 1, | ||
1102 | .default_value = 64, | ||
1103 | .flags = 0, | ||
1104 | }, { | ||
1105 | .id = V4L2_CID_HUE, | ||
1106 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1107 | .name = "Hue", | ||
1108 | .minimum = -128, | ||
1109 | .maximum = 127, | ||
1110 | .step = 1, | ||
1111 | .default_value = 0, | ||
1112 | .flags = 0, | ||
1113 | }, | ||
1114 | }; | ||
1115 | |||
1116 | /* ----------------------------------------------------------------------- */ | ||
1117 | |||
1118 | static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg) | 1093 | static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg) |
1119 | { | 1094 | { |
1120 | struct saa7115_state *state = i2c_get_clientdata(client); | 1095 | struct saa7115_state *state = i2c_get_clientdata(client); |
@@ -1158,14 +1133,16 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar | |||
1158 | case VIDIOC_QUERYCTRL: | 1133 | case VIDIOC_QUERYCTRL: |
1159 | { | 1134 | { |
1160 | struct v4l2_queryctrl *qc = arg; | 1135 | struct v4l2_queryctrl *qc = arg; |
1161 | int i; | ||
1162 | 1136 | ||
1163 | for (i = 0; i < ARRAY_SIZE(saa7115_qctrl); i++) | 1137 | switch (qc->id) { |
1164 | if (qc->id && qc->id == saa7115_qctrl[i].id) { | 1138 | case V4L2_CID_BRIGHTNESS: |
1165 | memcpy(qc, &saa7115_qctrl[i], sizeof(*qc)); | 1139 | case V4L2_CID_CONTRAST: |
1166 | return 0; | 1140 | case V4L2_CID_SATURATION: |
1167 | } | 1141 | case V4L2_CID_HUE: |
1168 | return -EINVAL; | 1142 | return v4l2_ctrl_query_fill_std(qc); |
1143 | default: | ||
1144 | return -EINVAL; | ||
1145 | } | ||
1169 | } | 1146 | } |
1170 | 1147 | ||
1171 | case VIDIOC_G_STD: | 1148 | case VIDIOC_G_STD: |
@@ -1221,34 +1198,6 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar | |||
1221 | break; | 1198 | break; |
1222 | } | 1199 | } |
1223 | 1200 | ||
1224 | case VIDIOC_G_INPUT: | ||
1225 | *(int *)arg = state->input; | ||
1226 | break; | ||
1227 | |||
1228 | case VIDIOC_S_INPUT: | ||
1229 | v4l_dbg(1, debug, client, "decoder set input %d\n", *iarg); | ||
1230 | /* inputs from 0-9 are available */ | ||
1231 | if (*iarg < 0 || *iarg > 9) { | ||
1232 | return -EINVAL; | ||
1233 | } | ||
1234 | |||
1235 | if (state->input == *iarg) | ||
1236 | break; | ||
1237 | v4l_dbg(1, debug, client, "now setting %s input\n", | ||
1238 | *iarg >= 6 ? "S-Video" : "Composite"); | ||
1239 | state->input = *iarg; | ||
1240 | |||
1241 | /* select mode */ | ||
1242 | saa7115_write(client, 0x02, | ||
1243 | (saa7115_read(client, 0x02) & 0xf0) | | ||
1244 | state->input); | ||
1245 | |||
1246 | /* bypass chrominance trap for modes 6..9 */ | ||
1247 | saa7115_write(client, 0x09, | ||
1248 | (saa7115_read(client, 0x09) & 0x7f) | | ||
1249 | (state->input < 6 ? 0x0 : 0x80)); | ||
1250 | break; | ||
1251 | |||
1252 | case VIDIOC_STREAMON: | 1201 | case VIDIOC_STREAMON: |
1253 | case VIDIOC_STREAMOFF: | 1202 | case VIDIOC_STREAMOFF: |
1254 | v4l_dbg(1, debug, client, "%s output\n", | 1203 | v4l_dbg(1, debug, client, "%s output\n", |
@@ -1260,6 +1209,21 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar | |||
1260 | } | 1209 | } |
1261 | break; | 1210 | break; |
1262 | 1211 | ||
1212 | case VIDIOC_INT_S_CRYSTAL_FREQ: | ||
1213 | { | ||
1214 | struct v4l2_crystal_freq *freq = arg; | ||
1215 | |||
1216 | if (freq->freq != SAA7115_FREQ_32_11_MHZ && | ||
1217 | freq->freq != SAA7115_FREQ_24_576_MHZ) | ||
1218 | return -EINVAL; | ||
1219 | state->crystal_freq = freq->freq; | ||
1220 | state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4; | ||
1221 | state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0; | ||
1222 | state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0; | ||
1223 | saa7115_set_audio_clock_freq(client, state->audclk_freq); | ||
1224 | break; | ||
1225 | } | ||
1226 | |||
1263 | case VIDIOC_INT_DECODE_VBI_LINE: | 1227 | case VIDIOC_INT_DECODE_VBI_LINE: |
1264 | saa7115_decode_vbi_line(client, arg); | 1228 | saa7115_decode_vbi_line(client, arg); |
1265 | break; | 1229 | break; |
@@ -1401,10 +1365,13 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) | |||
1401 | v4l_dbg(1, debug, client, "writing init values\n"); | 1365 | v4l_dbg(1, debug, client, "writing init values\n"); |
1402 | 1366 | ||
1403 | /* init to 60hz/48khz */ | 1367 | /* init to 60hz/48khz */ |
1404 | if (state->ident == V4L2_IDENT_SAA7113) | 1368 | if (state->ident == V4L2_IDENT_SAA7113) { |
1369 | state->crystal_freq = SAA7115_FREQ_24_576_MHZ; | ||
1405 | saa7115_writeregs(client, saa7113_init_auto_input); | 1370 | saa7115_writeregs(client, saa7113_init_auto_input); |
1406 | else | 1371 | } else { |
1372 | state->crystal_freq = SAA7115_FREQ_32_11_MHZ; | ||
1407 | saa7115_writeregs(client, saa7115_init_auto_input); | 1373 | saa7115_writeregs(client, saa7115_init_auto_input); |
1374 | } | ||
1408 | saa7115_writeregs(client, saa7115_init_misc); | 1375 | saa7115_writeregs(client, saa7115_init_misc); |
1409 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x); | 1376 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x); |
1410 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); | 1377 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); |