Merge branch 'bkl-removal' of git://git.lwn.net/linux-2.6
[sfrench/cifs-2.6.git] / drivers / media / video / cx25840 / cx25840-core.c
index 4da8cd74f00e6e17b6301a03d0c9a31f873a587e..88f2fd32bfe357617f82f011df18a9c31ddf7997 100644 (file)
@@ -191,7 +191,7 @@ static void cx25840_work_handler(struct work_struct *work)
 static void cx25840_initialize(struct i2c_client *client)
 {
        DEFINE_WAIT(wait);
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        struct workqueue_struct *q;
 
        /* datasheet startup in numbered steps, refer to page 3-77 */
@@ -259,7 +259,7 @@ static void cx25840_initialize(struct i2c_client *client)
 static void cx23885_initialize(struct i2c_client *client)
 {
        DEFINE_WAIT(wait);
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        struct workqueue_struct *q;
 
        /* Internal Reset */
@@ -350,7 +350,7 @@ static void cx23885_initialize(struct i2c_client *client)
 
 void cx25840_std_setup(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        v4l2_std_id std = state->std;
        int hblank, hactive, burst, vblank, vactive, sc;
        int vblank656, src_decimation;
@@ -497,7 +497,7 @@ void cx25840_std_setup(struct i2c_client *client)
 
 static void input_change(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        v4l2_std_id std = state->std;
 
        /* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
@@ -551,7 +551,7 @@ static void input_change(struct i2c_client *client)
 static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
                                                enum cx25840_audio_input aud_input)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&
                           vid_input <= CX25840_COMPOSITE8);
        u8 reg;
@@ -671,7 +671,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 
 static int set_v4lstd(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        u8 fmt = 0;     /* zero is autodetect */
        u8 pal_m = 0;
 
@@ -720,9 +720,10 @@ static int set_v4lstd(struct i2c_client *client)
 
 /* ----------------------------------------------------------------------- */
 
-static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        switch (ctrl->id) {
        case CX25840_CID_ENABLE_PVR150_WORKAROUND:
@@ -786,9 +787,10 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
        return 0;
 }
 
-static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        switch (ctrl->id) {
        case CX25840_CID_ENABLE_PVR150_WORKAROUND:
@@ -823,21 +825,23 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 
 /* ----------------------------------------------------------------------- */
 
-static int get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        switch (fmt->type) {
        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
                return cx25840_vbi(client, VIDIOC_G_FMT, fmt);
        default:
                return -EINVAL;
        }
-
        return 0;
 }
 
-static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct v4l2_pix_format *pix;
        int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
        int is_50Hz = !(state->std & V4L2_STD_525_60);
@@ -914,7 +918,7 @@ static void log_video_status(struct i2c_client *client)
                "0xD", "0xE", "0xF"
        };
 
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
        u8 gen_stat1 = cx25840_read(client, 0x40d);
        u8 gen_stat2 = cx25840_read(client, 0x40e);
@@ -944,7 +948,7 @@ static void log_video_status(struct i2c_client *client)
 
 static void log_audio_status(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        u8 download_ctl = cx25840_read(client, 0x803);
        u8 mod_det_stat0 = cx25840_read(client, 0x804);
        u8 mod_det_stat1 = cx25840_read(client, 0x805);
@@ -1097,21 +1101,12 @@ static void log_audio_status(struct i2c_client *client)
 
 /* ----------------------------------------------------------------------- */
 
-static int cx25840_command(struct i2c_client *client, unsigned int cmd,
-                          void *arg)
+static int cx25840_init(struct v4l2_subdev *sd, u32 val)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
-       struct v4l2_tuner *vt = arg;
-       struct v4l2_routing *route = arg;
-
-       /* ignore these commands */
-       switch (cmd) {
-               case TUNER_SET_TYPE_ADDR:
-                       return 0;
-       }
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (!state->is_initialized) {
-               v4l_dbg(1, cx25840_debug, client, "cmd %08x triggered fw load\n", cmd);
                /* initialize on first use */
                state->is_initialized = 1;
                if (state->is_cx25836)
@@ -1121,50 +1116,68 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                else
                        cx25840_initialize(client);
        }
+       return 0;
+}
 
-       switch (cmd) {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       /* ioctls to allow direct access to the
-        * cx25840 registers for testing */
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-
-               if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
+static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               if (cmd == VIDIOC_DBG_G_REGISTER)
-                       reg->val = cx25840_read(client, reg->reg & 0x0fff);
-               else
-                       cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
-               break;
-       }
+       if (!v4l2_chip_match_i2c_client(client, &reg->match))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       reg->size = 1;
+       reg->val = cx25840_read(client, reg->reg & 0x0fff);
+       return 0;
+}
+
+static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client, &reg->match))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
+       return 0;
+}
 #endif
 
-       case VIDIOC_INT_DECODE_VBI_LINE:
-               return cx25840_vbi(client, cmd, arg);
+static int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               return cx25840_audio(client, cmd, arg);
+       return cx25840_vbi(client, VIDIOC_INT_DECODE_VBI_LINE, vbi);
+}
+
+static int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return cx25840_audio(client, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freq);
+}
+
+static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_STREAMON:
-               v4l_dbg(1, cx25840_debug, client, "enable output\n");
+       v4l_dbg(1, cx25840_debug, client, "%s output\n",
+                       enable ? "enable" : "disable");
+       if (enable) {
                if (state->is_cx23885) {
                        u8 v = (cx25840_read(client, 0x421) | 0x0b);
                        cx25840_write(client, 0x421, v);
                } else {
                        cx25840_write(client, 0x115,
-                               state->is_cx25836 ? 0x0c : 0x8c);
+                                       state->is_cx25836 ? 0x0c : 0x8c);
                        cx25840_write(client, 0x116,
-                               state->is_cx25836 ? 0x04 : 0x07);
+                                       state->is_cx25836 ? 0x04 : 0x07);
                }
-               break;
-
-       case VIDIOC_STREAMOFF:
-               v4l_dbg(1, cx25840_debug, client, "disable output\n");
+       } else {
                if (state->is_cx23885) {
                        u8 v = cx25840_read(client, 0x421) & ~(0x0b);
                        cx25840_write(client, 0x421, v);
@@ -1172,133 +1185,136 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                        cx25840_write(client, 0x115, 0x00);
                        cx25840_write(client, 0x116, 0x00);
                }
-               break;
+       }
+       return 0;
+}
 
-       case VIDIOC_LOG_STATUS:
-               log_video_status(client);
-               if (!state->is_cx25836)
-                       log_audio_status(client);
-               break;
+static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       struct cx25840_state *state = to_state(sd);
 
-       case VIDIOC_G_CTRL:
-               return get_v4lctrl(client, (struct v4l2_control *)arg);
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill_std(qc);
+       default:
+               break;
+       }
+       if (state->is_cx25836)
+               return -EINVAL;
 
-       case VIDIOC_S_CTRL:
-               return set_v4lctrl(client, (struct v4l2_control *)arg);
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 65535,
+                               65535 / 100, state->default_volume);
+       case V4L2_CID_AUDIO_MUTE:
+       case V4L2_CID_AUDIO_BALANCE:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+               return v4l2_ctrl_query_fill_std(qc);
+       default:
+               return -EINVAL;
+       }
+       return -EINVAL;
+}
 
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
+static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               switch (qc->id) {
-                       case V4L2_CID_BRIGHTNESS:
-                       case V4L2_CID_CONTRAST:
-                       case V4L2_CID_SATURATION:
-                       case V4L2_CID_HUE:
-                               return v4l2_ctrl_query_fill_std(qc);
-                       default:
-                               break;
-               }
-               if (state->is_cx25836)
-                       return -EINVAL;
+       if (state->radio == 0 && state->std == std)
+               return 0;
+       state->radio = 0;
+       state->std = std;
+       return set_v4lstd(client);
+}
 
-               switch (qc->id) {
-                       case V4L2_CID_AUDIO_VOLUME:
-                               return v4l2_ctrl_query_fill(qc, 0, 65535,
-                                       65535 / 100, state->default_volume);
-                       case V4L2_CID_AUDIO_MUTE:
-                       case V4L2_CID_AUDIO_BALANCE:
-                       case V4L2_CID_AUDIO_BASS:
-                       case V4L2_CID_AUDIO_TREBLE:
-                               return v4l2_ctrl_query_fill_std(qc);
-                       default:
-                               return -EINVAL;
-               }
-               return -EINVAL;
-       }
+static int cx25840_s_radio(struct v4l2_subdev *sd)
+{
+       struct cx25840_state *state = to_state(sd);
 
-       case VIDIOC_G_STD:
-               *(v4l2_std_id *)arg = state->std;
-               break;
+       state->radio = 1;
+       return 0;
+}
 
-       case VIDIOC_S_STD:
-               if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
-                       return 0;
-               state->radio = 0;
-               state->std = *(v4l2_std_id *)arg;
-               return set_v4lstd(client);
+static int cx25840_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case AUDC_SET_RADIO:
-               state->radio = 1;
-               break;
+       return set_input(client, route->input, state->aud_input);
+}
 
-       case VIDIOC_INT_G_VIDEO_ROUTING:
-               route->input = state->vid_input;
-               route->output = 0;
-               break;
+static int cx25840_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-               return set_input(client, route->input, state->aud_input);
+       if (state->is_cx25836)
+               return -EINVAL;
+       return set_input(client, state->vid_input, route->input);
+}
 
-       case VIDIOC_INT_G_AUDIO_ROUTING:
-               if (state->is_cx25836)
-                       return -EINVAL;
-               route->input = state->aud_input;
-               route->output = 0;
-               break;
+static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-               if (state->is_cx25836)
-                       return -EINVAL;
-               return set_input(client, state->vid_input, route->input);
+       if (!state->is_cx25836)
+               input_change(client);
+       return 0;
+}
 
-       case VIDIOC_S_FREQUENCY:
-               if (!state->is_cx25836) {
-                       input_change(client);
-               }
-               break;
+static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 vpres = cx25840_read(client, 0x40e) & 0x20;
+       u8 mode;
+       int val = 0;
 
-       case VIDIOC_G_TUNER:
-       {
-               u8 vpres = cx25840_read(client, 0x40e) & 0x20;
-               u8 mode;
-               int val = 0;
+       if (state->radio)
+               return 0;
 
-               if (state->radio)
-                       break;
+       vt->signal = vpres ? 0xffff : 0x0;
+       if (state->is_cx25836)
+               return 0;
 
-               vt->signal = vpres ? 0xffff : 0x0;
-               if (state->is_cx25836)
-                       break;
+       vt->capability |=
+               V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+               V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
 
-               vt->capability |=
-                   V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
-                   V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+       mode = cx25840_read(client, 0x804);
 
-               mode = cx25840_read(client, 0x804);
+       /* get rxsubchans and audmode */
+       if ((mode & 0xf) == 1)
+               val |= V4L2_TUNER_SUB_STEREO;
+       else
+               val |= V4L2_TUNER_SUB_MONO;
 
-               /* get rxsubchans and audmode */
-               if ((mode & 0xf) == 1)
-                       val |= V4L2_TUNER_SUB_STEREO;
-               else
-                       val |= V4L2_TUNER_SUB_MONO;
+       if (mode == 2 || mode == 4)
+               val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 
-               if (mode == 2 || mode == 4)
-                       val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+       if (mode & 0x10)
+               val |= V4L2_TUNER_SUB_SAP;
 
-               if (mode & 0x10)
-                       val |= V4L2_TUNER_SUB_SAP;
+       vt->rxsubchans = val;
+       vt->audmode = state->audmode;
+       return 0;
+}
 
-               vt->rxsubchans = val;
-               vt->audmode = state->audmode;
-               break;
-       }
+static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_S_TUNER:
-               if (state->radio || state->is_cx25836)
-                       break;
+       if (state->radio || state->is_cx25836)
+               return 0;
 
-               switch (vt->audmode) {
+       switch (vt->audmode) {
                case V4L2_TUNER_MODE_MONO:
                        /* mono      -> mono
                           stereo    -> mono
@@ -1326,41 +1342,100 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                        break;
                default:
                        return -EINVAL;
-               }
-               state->audmode = vt->audmode;
-               break;
+       }
+       state->audmode = vt->audmode;
+       return 0;
+}
 
-       case VIDIOC_G_FMT:
-               return get_v4lfmt(client, (struct v4l2_format *)arg);
+static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_S_FMT:
-               return set_v4lfmt(client, (struct v4l2_format *)arg);
+       if (state->is_cx25836)
+               cx25836_initialize(client);
+       else if (state->is_cx23885)
+               cx23885_initialize(client);
+       else
+               cx25840_initialize(client);
+       return 0;
+}
 
-       case VIDIOC_INT_RESET:
-               if (state->is_cx25836)
-                       cx25836_initialize(client);
-               else if (state->is_cx23885)
-                       cx23885_initialize(client);
-               else
-                       cx25840_initialize(client);
-               break;
+static int cx25840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, state->id, state->rev);
+       return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
+}
 
-       default:
-               return -EINVAL;
-       }
+static int cx25840_log_status(struct v4l2_subdev *sd)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
+       log_video_status(client);
+       if (!state->is_cx25836)
+               log_audio_status(client);
        return 0;
 }
 
+static int cx25840_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops cx25840_core_ops = {
+       .log_status = cx25840_log_status,
+       .g_chip_ident = cx25840_g_chip_ident,
+       .g_ctrl = cx25840_g_ctrl,
+       .s_ctrl = cx25840_s_ctrl,
+       .queryctrl = cx25840_queryctrl,
+       .reset = cx25840_reset,
+       .init = cx25840_init,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = cx25840_g_register,
+       .s_register = cx25840_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
+       .s_frequency = cx25840_s_frequency,
+       .s_std = cx25840_s_std,
+       .s_radio = cx25840_s_radio,
+       .g_tuner = cx25840_g_tuner,
+       .s_tuner = cx25840_s_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
+       .s_clock_freq = cx25840_s_clock_freq,
+       .s_routing = cx25840_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops cx25840_video_ops = {
+       .s_routing = cx25840_s_video_routing,
+       .g_fmt = cx25840_g_fmt,
+       .s_fmt = cx25840_s_fmt,
+       .decode_vbi_line = cx25840_decode_vbi_line,
+       .s_stream = cx25840_s_stream,
+};
+
+static const struct v4l2_subdev_ops cx25840_ops = {
+       .core = &cx25840_core_ops,
+       .tuner = &cx25840_tuner_ops,
+       .audio = &cx25840_audio_ops,
+       .video = &cx25840_video_ops,
+};
+
 /* ----------------------------------------------------------------------- */
 
 static int cx25840_probe(struct i2c_client *client,
                         const struct i2c_device_id *did)
 {
        struct cx25840_state *state;
+       struct v4l2_subdev *sd;
        u32 id;
        u16 device_id;
 
@@ -1392,10 +1467,11 @@ static int cx25840_probe(struct i2c_client *client,
        }
 
        state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
-       if (state == NULL) {
+       if (state == NULL)
                return -ENOMEM;
-       }
 
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
        /* Note: revision '(device_id & 0x0f) == 2' was never built. The
           marking skips from 0x1 == 22 to 0x3 == 23. */
        v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
@@ -1403,7 +1479,6 @@ static int cx25840_probe(struct i2c_client *client,
                    (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
                    client->addr << 1, client->adapter->name);
 
-       i2c_set_clientdata(client, state);
        state->c = client;
        state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
        state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
@@ -1430,7 +1505,10 @@ static int cx25840_probe(struct i2c_client *client,
 
 static int cx25840_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }