aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/saa717x.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-10 18:09:54 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-10 18:09:54 -0400
commit7ae0dea900b027cd90e8a3e14deca9a19e17638b (patch)
tree428cbe411bba90f6580ae21338276c949e91f23a /drivers/media/video/saa717x.c
parent6c74700fdb8e3bc34c31790384a8ec16c4fefd97 (diff)
parent560afa7d85bdfb294506afd3032c315e6827824f (diff)
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (94 commits) V4L/DVB: tvp7002: fix write to H-PLL Feedback Divider LSB register V4L/DVB: dvb: siano: free spinlock before schedule() V4L/DVB: media: video: pvrusb2: remove custom hex_to_bin() V4L/DVB: drivers: usbvideo: remove custom implementation of hex_to_bin() V4L/DVB: Report supported QAM modes on bt8xx V4L/DVB: media: ir-keytable: null dereference in debug code V4L/DVB: ivtv: convert to the new control framework V4L/DVB: ivtv: convert gpio subdev to new control framework V4L/DVB: wm8739: convert to the new control framework V4L/DVB: cs53l32a: convert to new control framework V4L/DVB: wm8775: convert to the new control framework V4L/DVB: cx2341x: convert to the control framework V4L/DVB: cx25840: convert to the new control framework V4L/DVB: cx25840/ivtv: replace ugly priv control with s_config V4L/DVB: saa717x: convert to the new control framework V4L/DVB: msp3400: convert to the new control framework V4L/DVB: saa7115: convert to the new control framework V4L/DVB: v4l2: hook up the new control framework into the core framework V4L/DVB: Documentation: add v4l2-controls.txt documenting the new controls API V4L/DVB: v4l2-ctrls: Whitespace cleanups ...
Diffstat (limited to 'drivers/media/video/saa717x.c')
-rw-r--r--drivers/media/video/saa717x.c323
1 files changed, 81 insertions, 242 deletions
diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c
index 78d69950c00a..45f8bfc1342e 100644
--- a/drivers/media/video/saa717x.c
+++ b/drivers/media/video/saa717x.c
@@ -38,6 +38,7 @@
38#include <linux/videodev2.h> 38#include <linux/videodev2.h>
39#include <linux/i2c.h> 39#include <linux/i2c.h>
40#include <media/v4l2-device.h> 40#include <media/v4l2-device.h>
41#include <media/v4l2-ctrls.h>
41#include <media/v4l2-i2c-drv.h> 42#include <media/v4l2-i2c-drv.h>
42 43
43MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver"); 44MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
@@ -55,14 +56,11 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
55 56
56struct saa717x_state { 57struct saa717x_state {
57 struct v4l2_subdev sd; 58 struct v4l2_subdev sd;
59 struct v4l2_ctrl_handler hdl;
58 v4l2_std_id std; 60 v4l2_std_id std;
59 int input; 61 int input;
60 int enable; 62 int enable;
61 int radio; 63 int radio;
62 int bright;
63 int contrast;
64 int hue;
65 int sat;
66 int playback; 64 int playback;
67 int audio; 65 int audio;
68 int tuner_audio_mode; 66 int tuner_audio_mode;
@@ -81,6 +79,11 @@ static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
81 return container_of(sd, struct saa717x_state, sd); 79 return container_of(sd, struct saa717x_state, sd);
82} 80}
83 81
82static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
83{
84 return &container_of(ctrl->handler, struct saa717x_state, hdl)->sd;
85}
86
84/* ----------------------------------------------------------------------- */ 87/* ----------------------------------------------------------------------- */
85 88
86/* for audio mode */ 89/* for audio mode */
@@ -774,29 +777,6 @@ static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
774 saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]); 777 saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
775} 778}
776 779
777/* write regs to video output level (bright,contrast,hue,sat) */
778static void set_video_output_level_regs(struct v4l2_subdev *sd,
779 struct saa717x_state *decoder)
780{
781 /* brightness ffh (bright) - 80h (ITU level) - 00h (dark) */
782 saa717x_write(sd, 0x10a, decoder->bright);
783
784 /* contrast 7fh (max: 1.984) - 44h (ITU) - 40h (1.0) -
785 0h (luminance off) 40: i2c dump
786 c0h (-1.0 inverse chrominance)
787 80h (-2.0 inverse chrominance) */
788 saa717x_write(sd, 0x10b, decoder->contrast);
789
790 /* saturation? 7fh(max)-40h(ITU)-0h(color off)
791 c0h (-1.0 inverse chrominance)
792 80h (-2.0 inverse chrominance) */
793 saa717x_write(sd, 0x10c, decoder->sat);
794
795 /* color hue (phase) control
796 7fh (+178.6) - 0h (0 normal) - 80h (-180.0) */
797 saa717x_write(sd, 0x10d, decoder->hue);
798}
799
800/* write regs to set audio volume, bass and treble */ 780/* write regs to set audio volume, bass and treble */
801static int set_audio_regs(struct v4l2_subdev *sd, 781static int set_audio_regs(struct v4l2_subdev *sd,
802 struct saa717x_state *decoder) 782 struct saa717x_state *decoder)
@@ -829,9 +809,9 @@ static int set_audio_regs(struct v4l2_subdev *sd,
829 809
830 saa717x_write(sd, 0x480, val); 810 saa717x_write(sd, 0x480, val);
831 811
832 /* bass and treble; go to another function */
833 /* set bass and treble */ 812 /* set bass and treble */
834 val = decoder->audio_main_bass | (decoder->audio_main_treble << 8); 813 val = decoder->audio_main_bass & 0x1f;
814 val |= (decoder->audio_main_treble & 0x1f) << 5;
835 saa717x_write(sd, 0x488, val); 815 saa717x_write(sd, 0x488, val);
836 return 0; 816 return 0;
837} 817}
@@ -893,218 +873,55 @@ static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
893 saa717x_write(sd, 0x71 + task_shift, yscale >> 8); 873 saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
894} 874}
895 875
896static int saa717x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 876static int saa717x_s_ctrl(struct v4l2_ctrl *ctrl)
897{
898 struct saa717x_state *state = to_state(sd);
899
900 switch (ctrl->id) {
901 case V4L2_CID_BRIGHTNESS:
902 if (ctrl->value < 0 || ctrl->value > 255) {
903 v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
904 return -ERANGE;
905 }
906
907 state->bright = ctrl->value;
908 v4l2_dbg(1, debug, sd, "bright:%d\n", state->bright);
909 saa717x_write(sd, 0x10a, state->bright);
910 break;
911
912 case V4L2_CID_CONTRAST:
913 if (ctrl->value < 0 || ctrl->value > 127) {
914 v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
915 return -ERANGE;
916 }
917
918 state->contrast = ctrl->value;
919 v4l2_dbg(1, debug, sd, "contrast:%d\n", state->contrast);
920 saa717x_write(sd, 0x10b, state->contrast);
921 break;
922
923 case V4L2_CID_SATURATION:
924 if (ctrl->value < 0 || ctrl->value > 127) {
925 v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
926 return -ERANGE;
927 }
928
929 state->sat = ctrl->value;
930 v4l2_dbg(1, debug, sd, "sat:%d\n", state->sat);
931 saa717x_write(sd, 0x10c, state->sat);
932 break;
933
934 case V4L2_CID_HUE:
935 if (ctrl->value < -128 || ctrl->value > 127) {
936 v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
937 return -ERANGE;
938 }
939
940 state->hue = ctrl->value;
941 v4l2_dbg(1, debug, sd, "hue:%d\n", state->hue);
942 saa717x_write(sd, 0x10d, state->hue);
943 break;
944
945 case V4L2_CID_AUDIO_MUTE:
946 state->audio_main_mute = ctrl->value;
947 set_audio_regs(sd, state);
948 break;
949
950 case V4L2_CID_AUDIO_VOLUME:
951 state->audio_main_volume = ctrl->value;
952 set_audio_regs(sd, state);
953 break;
954
955 case V4L2_CID_AUDIO_BALANCE:
956 state->audio_main_balance = ctrl->value;
957 set_audio_regs(sd, state);
958 break;
959
960 case V4L2_CID_AUDIO_TREBLE:
961 state->audio_main_treble = ctrl->value;
962 set_audio_regs(sd, state);
963 break;
964
965 case V4L2_CID_AUDIO_BASS:
966 state->audio_main_bass = ctrl->value;
967 set_audio_regs(sd, state);
968 break;
969
970 default:
971 return -EINVAL;
972 }
973
974 return 0;
975}
976
977static int saa717x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
978{ 877{
878 struct v4l2_subdev *sd = to_sd(ctrl);
979 struct saa717x_state *state = to_state(sd); 879 struct saa717x_state *state = to_state(sd);
980 880
981 switch (ctrl->id) { 881 switch (ctrl->id) {
982 case V4L2_CID_BRIGHTNESS: 882 case V4L2_CID_BRIGHTNESS:
983 ctrl->value = state->bright; 883 saa717x_write(sd, 0x10a, ctrl->val);
984 break; 884 return 0;
985 885
986 case V4L2_CID_CONTRAST: 886 case V4L2_CID_CONTRAST:
987 ctrl->value = state->contrast; 887 saa717x_write(sd, 0x10b, ctrl->val);
988 break; 888 return 0;
989 889
990 case V4L2_CID_SATURATION: 890 case V4L2_CID_SATURATION:
991 ctrl->value = state->sat; 891 saa717x_write(sd, 0x10c, ctrl->val);
992 break; 892 return 0;
993 893
994 case V4L2_CID_HUE: 894 case V4L2_CID_HUE:
995 ctrl->value = state->hue; 895 saa717x_write(sd, 0x10d, ctrl->val);
996 break; 896 return 0;
997 897
998 case V4L2_CID_AUDIO_MUTE: 898 case V4L2_CID_AUDIO_MUTE:
999 ctrl->value = state->audio_main_mute; 899 state->audio_main_mute = ctrl->val;
1000 break; 900 break;
1001 901
1002 case V4L2_CID_AUDIO_VOLUME: 902 case V4L2_CID_AUDIO_VOLUME:
1003 ctrl->value = state->audio_main_volume; 903 state->audio_main_volume = ctrl->val;
1004 break; 904 break;
1005 905
1006 case V4L2_CID_AUDIO_BALANCE: 906 case V4L2_CID_AUDIO_BALANCE:
1007 ctrl->value = state->audio_main_balance; 907 state->audio_main_balance = ctrl->val;
1008 break; 908 break;
1009 909
1010 case V4L2_CID_AUDIO_TREBLE: 910 case V4L2_CID_AUDIO_TREBLE:
1011 ctrl->value = state->audio_main_treble; 911 state->audio_main_treble = ctrl->val;
1012 break; 912 break;
1013 913
1014 case V4L2_CID_AUDIO_BASS: 914 case V4L2_CID_AUDIO_BASS:
1015 ctrl->value = state->audio_main_bass; 915 state->audio_main_bass = ctrl->val;
1016 break; 916 break;
1017 917
1018 default: 918 default:
1019 return -EINVAL; 919 return 0;
1020 } 920 }
1021 921 set_audio_regs(sd, state);
1022 return 0; 922 return 0;
1023} 923}
1024 924
1025static struct v4l2_queryctrl saa717x_qctrl[] = {
1026 {
1027 .id = V4L2_CID_BRIGHTNESS,
1028 .type = V4L2_CTRL_TYPE_INTEGER,
1029 .name = "Brightness",
1030 .minimum = 0,
1031 .maximum = 255,
1032 .step = 1,
1033 .default_value = 128,
1034 .flags = 0,
1035 }, {
1036 .id = V4L2_CID_CONTRAST,
1037 .type = V4L2_CTRL_TYPE_INTEGER,
1038 .name = "Contrast",
1039 .minimum = 0,
1040 .maximum = 255,
1041 .step = 1,
1042 .default_value = 64,
1043 .flags = 0,
1044 }, {
1045 .id = V4L2_CID_SATURATION,
1046 .type = V4L2_CTRL_TYPE_INTEGER,
1047 .name = "Saturation",
1048 .minimum = 0,
1049 .maximum = 255,
1050 .step = 1,
1051 .default_value = 64,
1052 .flags = 0,
1053 }, {
1054 .id = V4L2_CID_HUE,
1055 .type = V4L2_CTRL_TYPE_INTEGER,
1056 .name = "Hue",
1057 .minimum = -128,
1058 .maximum = 127,
1059 .step = 1,
1060 .default_value = 0,
1061 .flags = 0,
1062 }, {
1063 .id = V4L2_CID_AUDIO_VOLUME,
1064 .type = V4L2_CTRL_TYPE_INTEGER,
1065 .name = "Volume",
1066 .minimum = 0,
1067 .maximum = 65535,
1068 .step = 65535 / 100,
1069 .default_value = 58880,
1070 .flags = 0,
1071 }, {
1072 .id = V4L2_CID_AUDIO_BALANCE,
1073 .type = V4L2_CTRL_TYPE_INTEGER,
1074 .name = "Balance",
1075 .minimum = 0,
1076 .maximum = 65535,
1077 .step = 65535 / 100,
1078 .default_value = 32768,
1079 .flags = 0,
1080 }, {
1081 .id = V4L2_CID_AUDIO_MUTE,
1082 .type = V4L2_CTRL_TYPE_BOOLEAN,
1083 .name = "Mute",
1084 .minimum = 0,
1085 .maximum = 1,
1086 .step = 1,
1087 .default_value = 1,
1088 .flags = 0,
1089 }, {
1090 .id = V4L2_CID_AUDIO_BASS,
1091 .type = V4L2_CTRL_TYPE_INTEGER,
1092 .name = "Bass",
1093 .minimum = 0,
1094 .maximum = 65535,
1095 .step = 65535 / 100,
1096 .default_value = 32768,
1097 }, {
1098 .id = V4L2_CID_AUDIO_TREBLE,
1099 .type = V4L2_CTRL_TYPE_INTEGER,
1100 .name = "Treble",
1101 .minimum = 0,
1102 .maximum = 65535,
1103 .step = 65535 / 100,
1104 .default_value = 32768,
1105 },
1106};
1107
1108static int saa717x_s_video_routing(struct v4l2_subdev *sd, 925static int saa717x_s_video_routing(struct v4l2_subdev *sd,
1109 u32 input, u32 output, u32 config) 926 u32 input, u32 output, u32 config)
1110{ 927{
@@ -1158,18 +975,6 @@ static int saa717x_s_video_routing(struct v4l2_subdev *sd,
1158 return 0; 975 return 0;
1159} 976}
1160 977
1161static int saa717x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
1162{
1163 int i;
1164
1165 for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
1166 if (qc->id && qc->id == saa717x_qctrl[i].id) {
1167 memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
1168 return 0;
1169 }
1170 return -EINVAL;
1171}
1172
1173#ifdef CONFIG_VIDEO_ADV_DEBUG 978#ifdef CONFIG_VIDEO_ADV_DEBUG
1174static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) 979static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
1175{ 980{
@@ -1386,17 +1191,34 @@ static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1386 return 0; 1191 return 0;
1387} 1192}
1388 1193
1194static int saa717x_log_status(struct v4l2_subdev *sd)
1195{
1196 struct saa717x_state *state = to_state(sd);
1197
1198 v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
1199 return 0;
1200}
1201
1389/* ----------------------------------------------------------------------- */ 1202/* ----------------------------------------------------------------------- */
1390 1203
1204static const struct v4l2_ctrl_ops saa717x_ctrl_ops = {
1205 .s_ctrl = saa717x_s_ctrl,
1206};
1207
1391static const struct v4l2_subdev_core_ops saa717x_core_ops = { 1208static const struct v4l2_subdev_core_ops saa717x_core_ops = {
1392#ifdef CONFIG_VIDEO_ADV_DEBUG 1209#ifdef CONFIG_VIDEO_ADV_DEBUG
1393 .g_register = saa717x_g_register, 1210 .g_register = saa717x_g_register,
1394 .s_register = saa717x_s_register, 1211 .s_register = saa717x_s_register,
1395#endif 1212#endif
1396 .queryctrl = saa717x_queryctrl,
1397 .g_ctrl = saa717x_g_ctrl,
1398 .s_ctrl = saa717x_s_ctrl,
1399 .s_std = saa717x_s_std, 1213 .s_std = saa717x_s_std,
1214 .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
1215 .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
1216 .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
1217 .g_ctrl = v4l2_subdev_g_ctrl,
1218 .s_ctrl = v4l2_subdev_s_ctrl,
1219 .queryctrl = v4l2_subdev_queryctrl,
1220 .querymenu = v4l2_subdev_querymenu,
1221 .log_status = saa717x_log_status,
1400}; 1222};
1401 1223
1402static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = { 1224static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
@@ -1432,6 +1254,7 @@ static int saa717x_probe(struct i2c_client *client,
1432 const struct i2c_device_id *did) 1254 const struct i2c_device_id *did)
1433{ 1255{
1434 struct saa717x_state *decoder; 1256 struct saa717x_state *decoder;
1257 struct v4l2_ctrl_handler *hdl;
1435 struct v4l2_subdev *sd; 1258 struct v4l2_subdev *sd;
1436 u8 id = 0; 1259 u8 id = 0;
1437 char *p = ""; 1260 char *p = "";
@@ -1467,16 +1290,41 @@ static int saa717x_probe(struct i2c_client *client,
1467 p = "saa7171"; 1290 p = "saa7171";
1468 v4l2_info(sd, "%s found @ 0x%x (%s)\n", p, 1291 v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
1469 client->addr << 1, client->adapter->name); 1292 client->addr << 1, client->adapter->name);
1293
1294 hdl = &decoder->hdl;
1295 v4l2_ctrl_handler_init(hdl, 9);
1296 /* add in ascending ID order */
1297 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1298 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
1299 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1300 V4L2_CID_CONTRAST, 0, 255, 1, 68);
1301 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1302 V4L2_CID_SATURATION, 0, 255, 1, 64);
1303 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1304 V4L2_CID_HUE, -128, 127, 1, 0);
1305 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1306 V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 42000);
1307 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1308 V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
1309 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1310 V4L2_CID_AUDIO_BASS, -16, 15, 1, 0);
1311 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1312 V4L2_CID_AUDIO_TREBLE, -16, 15, 1, 0);
1313 v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
1314 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
1315 sd->ctrl_handler = hdl;
1316 if (hdl->error) {
1317 int err = hdl->error;
1318
1319 v4l2_ctrl_handler_free(hdl);
1320 kfree(decoder);
1321 return err;
1322 }
1323
1470 decoder->std = V4L2_STD_NTSC; 1324 decoder->std = V4L2_STD_NTSC;
1471 decoder->input = -1; 1325 decoder->input = -1;
1472 decoder->enable = 1; 1326 decoder->enable = 1;
1473 1327
1474 /* tune these parameters */
1475 decoder->bright = 0x80;
1476 decoder->contrast = 0x44;
1477 decoder->sat = 0x40;
1478 decoder->hue = 0x00;
1479
1480 /* FIXME!! */ 1328 /* FIXME!! */
1481 decoder->playback = 0; /* initially capture mode used */ 1329 decoder->playback = 0; /* initially capture mode used */
1482 decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */ 1330 decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
@@ -1487,23 +1335,13 @@ static int saa717x_probe(struct i2c_client *client,
1487 /* set volume, bass and treble */ 1335 /* set volume, bass and treble */
1488 decoder->audio_main_vol_l = 6; 1336 decoder->audio_main_vol_l = 6;
1489 decoder->audio_main_vol_r = 6; 1337 decoder->audio_main_vol_r = 6;
1490 decoder->audio_main_bass = 0;
1491 decoder->audio_main_treble = 0;
1492 decoder->audio_main_mute = 0;
1493 decoder->audio_main_balance = 32768;
1494 /* normalize (24 to -40 (not -84) -> 65535 to 0) */
1495 decoder->audio_main_volume =
1496 (decoder->audio_main_vol_r + 41) * 65535 / (24 - (-40));
1497 1338
1498 v4l2_dbg(1, debug, sd, "writing init values\n"); 1339 v4l2_dbg(1, debug, sd, "writing init values\n");
1499 1340
1500 /* FIXME!! */ 1341 /* FIXME!! */
1501 saa717x_write_regs(sd, reg_init_initialize); 1342 saa717x_write_regs(sd, reg_init_initialize);
1502 set_video_output_level_regs(sd, decoder); 1343
1503 /* set bass,treble to 0db 20041101 K.Ohta */ 1344 v4l2_ctrl_handler_setup(hdl);
1504 decoder->audio_main_bass = 0;
1505 decoder->audio_main_treble = 0;
1506 set_audio_regs(sd, decoder);
1507 1345
1508 set_current_state(TASK_INTERRUPTIBLE); 1346 set_current_state(TASK_INTERRUPTIBLE);
1509 schedule_timeout(2*HZ); 1347 schedule_timeout(2*HZ);
@@ -1515,6 +1353,7 @@ static int saa717x_remove(struct i2c_client *client)
1515 struct v4l2_subdev *sd = i2c_get_clientdata(client); 1353 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1516 1354
1517 v4l2_device_unregister_subdev(sd); 1355 v4l2_device_unregister_subdev(sd);
1356 v4l2_ctrl_handler_free(sd->ctrl_handler);
1518 kfree(to_state(sd)); 1357 kfree(to_state(sd));
1519 return 0; 1358 return 0;
1520} 1359}