diff options
Diffstat (limited to 'drivers/media/video/mt9t031.c')
-rw-r--r-- | drivers/media/video/mt9t031.c | 491 |
1 files changed, 261 insertions, 230 deletions
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 4207fb342670..6966f644977e 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c | |||
@@ -13,13 +13,13 @@ | |||
13 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
14 | #include <linux/log2.h> | 14 | #include <linux/log2.h> |
15 | 15 | ||
16 | #include <media/v4l2-common.h> | 16 | #include <media/v4l2-subdev.h> |
17 | #include <media/v4l2-chip-ident.h> | 17 | #include <media/v4l2-chip-ident.h> |
18 | #include <media/soc_camera.h> | 18 | #include <media/soc_camera.h> |
19 | 19 | ||
20 | /* mt9t031 i2c address 0x5d | 20 | /* mt9t031 i2c address 0x5d |
21 | * The platform has to define i2c_board_info | 21 | * The platform has to define i2c_board_info and link to it from |
22 | * and call i2c_register_board_info() */ | 22 | * struct soc_camera_link */ |
23 | 23 | ||
24 | /* mt9t031 selected register addresses */ | 24 | /* mt9t031 selected register addresses */ |
25 | #define MT9T031_CHIP_VERSION 0x00 | 25 | #define MT9T031_CHIP_VERSION 0x00 |
@@ -47,7 +47,7 @@ | |||
47 | #define MT9T031_MAX_HEIGHT 1536 | 47 | #define MT9T031_MAX_HEIGHT 1536 |
48 | #define MT9T031_MAX_WIDTH 2048 | 48 | #define MT9T031_MAX_WIDTH 2048 |
49 | #define MT9T031_MIN_HEIGHT 2 | 49 | #define MT9T031_MIN_HEIGHT 2 |
50 | #define MT9T031_MIN_WIDTH 2 | 50 | #define MT9T031_MIN_WIDTH 18 |
51 | #define MT9T031_HORIZONTAL_BLANK 142 | 51 | #define MT9T031_HORIZONTAL_BLANK 142 |
52 | #define MT9T031_VERTICAL_BLANK 25 | 52 | #define MT9T031_VERTICAL_BLANK 25 |
53 | #define MT9T031_COLUMN_SKIP 32 | 53 | #define MT9T031_COLUMN_SKIP 32 |
@@ -68,14 +68,21 @@ static const struct soc_camera_data_format mt9t031_colour_formats[] = { | |||
68 | }; | 68 | }; |
69 | 69 | ||
70 | struct mt9t031 { | 70 | struct mt9t031 { |
71 | struct i2c_client *client; | 71 | struct v4l2_subdev subdev; |
72 | struct soc_camera_device icd; | 72 | struct v4l2_rect rect; /* Sensor window */ |
73 | int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ | 73 | int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ |
74 | unsigned char autoexposure; | ||
75 | u16 xskip; | 74 | u16 xskip; |
76 | u16 yskip; | 75 | u16 yskip; |
76 | unsigned int gain; | ||
77 | unsigned int exposure; | ||
78 | unsigned char autoexposure; | ||
77 | }; | 79 | }; |
78 | 80 | ||
81 | static struct mt9t031 *to_mt9t031(const struct i2c_client *client) | ||
82 | { | ||
83 | return container_of(i2c_get_clientdata(client), struct mt9t031, subdev); | ||
84 | } | ||
85 | |||
79 | static int reg_read(struct i2c_client *client, const u8 reg) | 86 | static int reg_read(struct i2c_client *client, const u8 reg) |
80 | { | 87 | { |
81 | s32 data = i2c_smbus_read_word_data(client, reg); | 88 | s32 data = i2c_smbus_read_word_data(client, reg); |
@@ -136,21 +143,10 @@ static int get_shutter(struct i2c_client *client, u32 *data) | |||
136 | return ret < 0 ? ret : 0; | 143 | return ret < 0 ? ret : 0; |
137 | } | 144 | } |
138 | 145 | ||
139 | static int mt9t031_init(struct soc_camera_device *icd) | 146 | static int mt9t031_idle(struct i2c_client *client) |
140 | { | 147 | { |
141 | struct i2c_client *client = to_i2c_client(icd->control); | ||
142 | struct soc_camera_link *icl = client->dev.platform_data; | ||
143 | int ret; | 148 | int ret; |
144 | 149 | ||
145 | if (icl->power) { | ||
146 | ret = icl->power(&client->dev, 1); | ||
147 | if (ret < 0) { | ||
148 | dev_err(icd->vdev->parent, | ||
149 | "Platform failed to power-on the camera.\n"); | ||
150 | return ret; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* Disable chip output, synchronous option update */ | 150 | /* Disable chip output, synchronous option update */ |
155 | ret = reg_write(client, MT9T031_RESET, 1); | 151 | ret = reg_write(client, MT9T031_RESET, 1); |
156 | if (ret >= 0) | 152 | if (ret >= 0) |
@@ -158,50 +154,39 @@ static int mt9t031_init(struct soc_camera_device *icd) | |||
158 | if (ret >= 0) | 154 | if (ret >= 0) |
159 | ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); | 155 | ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); |
160 | 156 | ||
161 | if (ret < 0 && icl->power) | ||
162 | icl->power(&client->dev, 0); | ||
163 | |||
164 | return ret >= 0 ? 0 : -EIO; | 157 | return ret >= 0 ? 0 : -EIO; |
165 | } | 158 | } |
166 | 159 | ||
167 | static int mt9t031_release(struct soc_camera_device *icd) | 160 | static int mt9t031_disable(struct i2c_client *client) |
168 | { | 161 | { |
169 | struct i2c_client *client = to_i2c_client(icd->control); | ||
170 | struct soc_camera_link *icl = client->dev.platform_data; | ||
171 | |||
172 | /* Disable the chip */ | 162 | /* Disable the chip */ |
173 | reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); | 163 | reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); |
174 | 164 | ||
175 | if (icl->power) | ||
176 | icl->power(&client->dev, 0); | ||
177 | |||
178 | return 0; | 165 | return 0; |
179 | } | 166 | } |
180 | 167 | ||
181 | static int mt9t031_start_capture(struct soc_camera_device *icd) | 168 | static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) |
182 | { | 169 | { |
183 | struct i2c_client *client = to_i2c_client(icd->control); | 170 | struct i2c_client *client = sd->priv; |
184 | 171 | int ret; | |
185 | /* Switch to master "normal" mode */ | ||
186 | if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0) | ||
187 | return -EIO; | ||
188 | return 0; | ||
189 | } | ||
190 | 172 | ||
191 | static int mt9t031_stop_capture(struct soc_camera_device *icd) | 173 | if (enable) |
192 | { | 174 | /* Switch to master "normal" mode */ |
193 | struct i2c_client *client = to_i2c_client(icd->control); | 175 | ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 2); |
176 | else | ||
177 | /* Stop sensor readout */ | ||
178 | ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); | ||
194 | 179 | ||
195 | /* Stop sensor readout */ | 180 | if (ret < 0) |
196 | if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0) | ||
197 | return -EIO; | 181 | return -EIO; |
182 | |||
198 | return 0; | 183 | return 0; |
199 | } | 184 | } |
200 | 185 | ||
201 | static int mt9t031_set_bus_param(struct soc_camera_device *icd, | 186 | static int mt9t031_set_bus_param(struct soc_camera_device *icd, |
202 | unsigned long flags) | 187 | unsigned long flags) |
203 | { | 188 | { |
204 | struct i2c_client *client = to_i2c_client(icd->control); | 189 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
205 | 190 | ||
206 | /* The caller should have queried our parameters, check anyway */ | 191 | /* The caller should have queried our parameters, check anyway */ |
207 | if (flags & ~MT9T031_BUS_PARAM) | 192 | if (flags & ~MT9T031_BUS_PARAM) |
@@ -217,69 +202,73 @@ static int mt9t031_set_bus_param(struct soc_camera_device *icd, | |||
217 | 202 | ||
218 | static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) | 203 | static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) |
219 | { | 204 | { |
220 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 205 | struct soc_camera_link *icl = to_soc_camera_link(icd); |
221 | struct soc_camera_link *icl = mt9t031->client->dev.platform_data; | ||
222 | 206 | ||
223 | return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); | 207 | return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); |
224 | } | 208 | } |
225 | 209 | ||
226 | /* Round up minima and round down maxima */ | 210 | /* target must be _even_ */ |
227 | static void recalculate_limits(struct soc_camera_device *icd, | 211 | static u16 mt9t031_skip(s32 *source, s32 target, s32 max) |
228 | u16 xskip, u16 yskip) | ||
229 | { | 212 | { |
230 | icd->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip; | 213 | unsigned int skip; |
231 | icd->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip; | 214 | |
232 | icd->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip; | 215 | if (*source < target + target / 2) { |
233 | icd->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip; | 216 | *source = target; |
234 | icd->width_max = MT9T031_MAX_WIDTH / xskip; | 217 | return 1; |
235 | icd->height_max = MT9T031_MAX_HEIGHT / yskip; | 218 | } |
219 | |||
220 | skip = min(max, *source + target / 2) / target; | ||
221 | if (skip > 8) | ||
222 | skip = 8; | ||
223 | *source = target * skip; | ||
224 | |||
225 | return skip; | ||
236 | } | 226 | } |
237 | 227 | ||
228 | /* rect is the sensor rectangle, the caller guarantees parameter validity */ | ||
238 | static int mt9t031_set_params(struct soc_camera_device *icd, | 229 | static int mt9t031_set_params(struct soc_camera_device *icd, |
239 | struct v4l2_rect *rect, u16 xskip, u16 yskip) | 230 | struct v4l2_rect *rect, u16 xskip, u16 yskip) |
240 | { | 231 | { |
241 | struct i2c_client *client = to_i2c_client(icd->control); | 232 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
242 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 233 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
243 | int ret; | 234 | int ret; |
244 | u16 xbin, ybin, width, height, left, top; | 235 | u16 xbin, ybin; |
245 | const u16 hblank = MT9T031_HORIZONTAL_BLANK, | 236 | const u16 hblank = MT9T031_HORIZONTAL_BLANK, |
246 | vblank = MT9T031_VERTICAL_BLANK; | 237 | vblank = MT9T031_VERTICAL_BLANK; |
247 | 238 | ||
248 | /* Make sure we don't exceed sensor limits */ | ||
249 | if (rect->left + rect->width > icd->width_max) | ||
250 | rect->left = (icd->width_max - rect->width) / 2 + icd->x_min; | ||
251 | |||
252 | if (rect->top + rect->height > icd->height_max) | ||
253 | rect->top = (icd->height_max - rect->height) / 2 + icd->y_min; | ||
254 | |||
255 | width = rect->width * xskip; | ||
256 | height = rect->height * yskip; | ||
257 | left = rect->left * xskip; | ||
258 | top = rect->top * yskip; | ||
259 | |||
260 | xbin = min(xskip, (u16)3); | 239 | xbin = min(xskip, (u16)3); |
261 | ybin = min(yskip, (u16)3); | 240 | ybin = min(yskip, (u16)3); |
262 | 241 | ||
263 | dev_dbg(&icd->dev, "xskip %u, width %u/%u, yskip %u, height %u/%u\n", | 242 | /* |
264 | xskip, width, rect->width, yskip, height, rect->height); | 243 | * Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper. |
265 | 244 | * There is always a valid suitably aligned value. The worst case is | |
266 | /* Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper */ | 245 | * xbin = 3, width = 2048. Then we will start at 36, the last read out |
246 | * pixel will be 2083, which is < 2085 - first black pixel. | ||
247 | * | ||
248 | * MT9T031 datasheet imposes window left border alignment, depending on | ||
249 | * the selected xskip. Failing to conform to this requirement produces | ||
250 | * dark horizontal stripes in the image. However, even obeying to this | ||
251 | * requirement doesn't eliminate the stripes in all configurations. They | ||
252 | * appear "locally reproducibly," but can differ between tests under | ||
253 | * different lighting conditions. | ||
254 | */ | ||
267 | switch (xbin) { | 255 | switch (xbin) { |
268 | case 2: | 256 | case 1: |
269 | left = (left + 3) & ~3; | 257 | rect->left &= ~1; |
270 | break; | 258 | break; |
271 | case 3: | ||
272 | left = roundup(left, 6); | ||
273 | } | ||
274 | |||
275 | switch (ybin) { | ||
276 | case 2: | 259 | case 2: |
277 | top = (top + 3) & ~3; | 260 | rect->left &= ~3; |
278 | break; | 261 | break; |
279 | case 3: | 262 | case 3: |
280 | top = roundup(top, 6); | 263 | rect->left = rect->left > roundup(MT9T031_COLUMN_SKIP, 6) ? |
264 | (rect->left / 6) * 6 : roundup(MT9T031_COLUMN_SKIP, 6); | ||
281 | } | 265 | } |
282 | 266 | ||
267 | rect->top &= ~1; | ||
268 | |||
269 | dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n", | ||
270 | xskip, yskip, rect->width, rect->height, rect->left, rect->top); | ||
271 | |||
283 | /* Disable register update, reconfigure atomically */ | 272 | /* Disable register update, reconfigure atomically */ |
284 | ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1); | 273 | ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1); |
285 | if (ret < 0) | 274 | if (ret < 0) |
@@ -299,29 +288,30 @@ static int mt9t031_set_params(struct soc_camera_device *icd, | |||
299 | ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, | 288 | ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, |
300 | ((ybin - 1) << 4) | (yskip - 1)); | 289 | ((ybin - 1) << 4) | (yskip - 1)); |
301 | } | 290 | } |
302 | dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top); | 291 | dev_dbg(&client->dev, "new physical left %u, top %u\n", |
292 | rect->left, rect->top); | ||
303 | 293 | ||
304 | /* The caller provides a supported format, as guaranteed by | 294 | /* The caller provides a supported format, as guaranteed by |
305 | * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */ | 295 | * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */ |
306 | if (ret >= 0) | 296 | if (ret >= 0) |
307 | ret = reg_write(client, MT9T031_COLUMN_START, left); | 297 | ret = reg_write(client, MT9T031_COLUMN_START, rect->left); |
308 | if (ret >= 0) | 298 | if (ret >= 0) |
309 | ret = reg_write(client, MT9T031_ROW_START, top); | 299 | ret = reg_write(client, MT9T031_ROW_START, rect->top); |
310 | if (ret >= 0) | 300 | if (ret >= 0) |
311 | ret = reg_write(client, MT9T031_WINDOW_WIDTH, width - 1); | 301 | ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1); |
312 | if (ret >= 0) | 302 | if (ret >= 0) |
313 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, | 303 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, |
314 | height + icd->y_skip_top - 1); | 304 | rect->height + icd->y_skip_top - 1); |
315 | if (ret >= 0 && mt9t031->autoexposure) { | 305 | if (ret >= 0 && mt9t031->autoexposure) { |
316 | ret = set_shutter(client, height + icd->y_skip_top + vblank); | 306 | unsigned int total_h = rect->height + icd->y_skip_top + vblank; |
307 | ret = set_shutter(client, total_h); | ||
317 | if (ret >= 0) { | 308 | if (ret >= 0) { |
318 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | 309 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; |
319 | const struct v4l2_queryctrl *qctrl = | 310 | const struct v4l2_queryctrl *qctrl = |
320 | soc_camera_find_qctrl(icd->ops, | 311 | soc_camera_find_qctrl(icd->ops, |
321 | V4L2_CID_EXPOSURE); | 312 | V4L2_CID_EXPOSURE); |
322 | icd->exposure = (shutter_max / 2 + (height + | 313 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * |
323 | icd->y_skip_top + vblank - 1) * | 314 | (qctrl->maximum - qctrl->minimum)) / |
324 | (qctrl->maximum - qctrl->minimum)) / | ||
325 | shutter_max + qctrl->minimum; | 315 | shutter_max + qctrl->minimum; |
326 | } | 316 | } |
327 | } | 317 | } |
@@ -330,58 +320,99 @@ static int mt9t031_set_params(struct soc_camera_device *icd, | |||
330 | if (ret >= 0) | 320 | if (ret >= 0) |
331 | ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1); | 321 | ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1); |
332 | 322 | ||
323 | if (ret >= 0) { | ||
324 | mt9t031->rect = *rect; | ||
325 | mt9t031->xskip = xskip; | ||
326 | mt9t031->yskip = yskip; | ||
327 | } | ||
328 | |||
333 | return ret < 0 ? ret : 0; | 329 | return ret < 0 ? ret : 0; |
334 | } | 330 | } |
335 | 331 | ||
336 | static int mt9t031_set_crop(struct soc_camera_device *icd, | 332 | static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
337 | struct v4l2_rect *rect) | ||
338 | { | 333 | { |
339 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 334 | struct v4l2_rect rect = a->c; |
335 | struct i2c_client *client = sd->priv; | ||
336 | struct mt9t031 *mt9t031 = to_mt9t031(client); | ||
337 | struct soc_camera_device *icd = client->dev.platform_data; | ||
338 | |||
339 | rect.width = ALIGN(rect.width, 2); | ||
340 | rect.height = ALIGN(rect.height, 2); | ||
341 | |||
342 | soc_camera_limit_side(&rect.left, &rect.width, | ||
343 | MT9T031_COLUMN_SKIP, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH); | ||
344 | |||
345 | soc_camera_limit_side(&rect.top, &rect.height, | ||
346 | MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT); | ||
340 | 347 | ||
341 | /* CROP - no change in scaling, or in limits */ | 348 | return mt9t031_set_params(icd, &rect, mt9t031->xskip, mt9t031->yskip); |
342 | return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip); | ||
343 | } | 349 | } |
344 | 350 | ||
345 | static int mt9t031_set_fmt(struct soc_camera_device *icd, | 351 | static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
346 | struct v4l2_format *f) | ||
347 | { | 352 | { |
348 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 353 | struct i2c_client *client = sd->priv; |
349 | int ret; | 354 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
350 | u16 xskip, yskip; | ||
351 | struct v4l2_rect rect = { | ||
352 | .left = icd->x_current, | ||
353 | .top = icd->y_current, | ||
354 | .width = f->fmt.pix.width, | ||
355 | .height = f->fmt.pix.height, | ||
356 | }; | ||
357 | 355 | ||
358 | /* | 356 | a->c = mt9t031->rect; |
359 | * try_fmt has put rectangle within limits. | 357 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
360 | * S_FMT - use binning and skipping for scaling, recalculate | ||
361 | * limits, used for cropping | ||
362 | */ | ||
363 | /* Is this more optimal than just a division? */ | ||
364 | for (xskip = 8; xskip > 1; xskip--) | ||
365 | if (rect.width * xskip <= MT9T031_MAX_WIDTH) | ||
366 | break; | ||
367 | 358 | ||
368 | for (yskip = 8; yskip > 1; yskip--) | 359 | return 0; |
369 | if (rect.height * yskip <= MT9T031_MAX_HEIGHT) | 360 | } |
370 | break; | ||
371 | 361 | ||
372 | recalculate_limits(icd, xskip, yskip); | 362 | static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) |
363 | { | ||
364 | a->bounds.left = MT9T031_COLUMN_SKIP; | ||
365 | a->bounds.top = MT9T031_ROW_SKIP; | ||
366 | a->bounds.width = MT9T031_MAX_WIDTH; | ||
367 | a->bounds.height = MT9T031_MAX_HEIGHT; | ||
368 | a->defrect = a->bounds; | ||
369 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
370 | a->pixelaspect.numerator = 1; | ||
371 | a->pixelaspect.denominator = 1; | ||
373 | 372 | ||
374 | ret = mt9t031_set_params(icd, &rect, xskip, yskip); | 373 | return 0; |
375 | if (!ret) { | 374 | } |
376 | mt9t031->xskip = xskip; | ||
377 | mt9t031->yskip = yskip; | ||
378 | } | ||
379 | 375 | ||
380 | return ret; | 376 | static int mt9t031_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
377 | { | ||
378 | struct i2c_client *client = sd->priv; | ||
379 | struct mt9t031 *mt9t031 = to_mt9t031(client); | ||
380 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
381 | |||
382 | pix->width = mt9t031->rect.width / mt9t031->xskip; | ||
383 | pix->height = mt9t031->rect.height / mt9t031->yskip; | ||
384 | pix->pixelformat = V4L2_PIX_FMT_SGRBG10; | ||
385 | pix->field = V4L2_FIELD_NONE; | ||
386 | pix->colorspace = V4L2_COLORSPACE_SRGB; | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
392 | { | ||
393 | struct i2c_client *client = sd->priv; | ||
394 | struct mt9t031 *mt9t031 = to_mt9t031(client); | ||
395 | struct soc_camera_device *icd = client->dev.platform_data; | ||
396 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
397 | u16 xskip, yskip; | ||
398 | struct v4l2_rect rect = mt9t031->rect; | ||
399 | |||
400 | /* | ||
401 | * try_fmt has put width and height within limits. | ||
402 | * S_FMT: use binning and skipping for scaling | ||
403 | */ | ||
404 | xskip = mt9t031_skip(&rect.width, pix->width, MT9T031_MAX_WIDTH); | ||
405 | yskip = mt9t031_skip(&rect.height, pix->height, MT9T031_MAX_HEIGHT); | ||
406 | |||
407 | /* mt9t031_set_params() doesn't change width and height */ | ||
408 | return mt9t031_set_params(icd, &rect, xskip, yskip); | ||
381 | } | 409 | } |
382 | 410 | ||
383 | static int mt9t031_try_fmt(struct soc_camera_device *icd, | 411 | /* |
384 | struct v4l2_format *f) | 412 | * If a user window larger than sensor window is requested, we'll increase the |
413 | * sensor window. | ||
414 | */ | ||
415 | static int mt9t031_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
385 | { | 416 | { |
386 | struct v4l2_pix_format *pix = &f->fmt.pix; | 417 | struct v4l2_pix_format *pix = &f->fmt.pix; |
387 | 418 | ||
@@ -392,15 +423,16 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd, | |||
392 | return 0; | 423 | return 0; |
393 | } | 424 | } |
394 | 425 | ||
395 | static int mt9t031_get_chip_id(struct soc_camera_device *icd, | 426 | static int mt9t031_g_chip_ident(struct v4l2_subdev *sd, |
396 | struct v4l2_dbg_chip_ident *id) | 427 | struct v4l2_dbg_chip_ident *id) |
397 | { | 428 | { |
398 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 429 | struct i2c_client *client = sd->priv; |
430 | struct mt9t031 *mt9t031 = to_mt9t031(client); | ||
399 | 431 | ||
400 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) | 432 | if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR) |
401 | return -EINVAL; | 433 | return -EINVAL; |
402 | 434 | ||
403 | if (id->match.addr != mt9t031->client->addr) | 435 | if (id->match.addr != client->addr) |
404 | return -ENODEV; | 436 | return -ENODEV; |
405 | 437 | ||
406 | id->ident = mt9t031->model; | 438 | id->ident = mt9t031->model; |
@@ -410,10 +442,10 @@ static int mt9t031_get_chip_id(struct soc_camera_device *icd, | |||
410 | } | 442 | } |
411 | 443 | ||
412 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 444 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
413 | static int mt9t031_get_register(struct soc_camera_device *icd, | 445 | static int mt9t031_g_register(struct v4l2_subdev *sd, |
414 | struct v4l2_dbg_register *reg) | 446 | struct v4l2_dbg_register *reg) |
415 | { | 447 | { |
416 | struct i2c_client *client = to_i2c_client(icd->control); | 448 | struct i2c_client *client = sd->priv; |
417 | 449 | ||
418 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 450 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
419 | return -EINVAL; | 451 | return -EINVAL; |
@@ -429,10 +461,10 @@ static int mt9t031_get_register(struct soc_camera_device *icd, | |||
429 | return 0; | 461 | return 0; |
430 | } | 462 | } |
431 | 463 | ||
432 | static int mt9t031_set_register(struct soc_camera_device *icd, | 464 | static int mt9t031_s_register(struct v4l2_subdev *sd, |
433 | struct v4l2_dbg_register *reg) | 465 | struct v4l2_dbg_register *reg) |
434 | { | 466 | { |
435 | struct i2c_client *client = to_i2c_client(icd->control); | 467 | struct i2c_client *client = sd->priv; |
436 | 468 | ||
437 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) | 469 | if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) |
438 | return -EINVAL; | 470 | return -EINVAL; |
@@ -493,39 +525,17 @@ static const struct v4l2_queryctrl mt9t031_controls[] = { | |||
493 | } | 525 | } |
494 | }; | 526 | }; |
495 | 527 | ||
496 | static int mt9t031_video_probe(struct soc_camera_device *); | ||
497 | static void mt9t031_video_remove(struct soc_camera_device *); | ||
498 | static int mt9t031_get_control(struct soc_camera_device *, struct v4l2_control *); | ||
499 | static int mt9t031_set_control(struct soc_camera_device *, struct v4l2_control *); | ||
500 | |||
501 | static struct soc_camera_ops mt9t031_ops = { | 528 | static struct soc_camera_ops mt9t031_ops = { |
502 | .owner = THIS_MODULE, | ||
503 | .probe = mt9t031_video_probe, | ||
504 | .remove = mt9t031_video_remove, | ||
505 | .init = mt9t031_init, | ||
506 | .release = mt9t031_release, | ||
507 | .start_capture = mt9t031_start_capture, | ||
508 | .stop_capture = mt9t031_stop_capture, | ||
509 | .set_crop = mt9t031_set_crop, | ||
510 | .set_fmt = mt9t031_set_fmt, | ||
511 | .try_fmt = mt9t031_try_fmt, | ||
512 | .set_bus_param = mt9t031_set_bus_param, | 529 | .set_bus_param = mt9t031_set_bus_param, |
513 | .query_bus_param = mt9t031_query_bus_param, | 530 | .query_bus_param = mt9t031_query_bus_param, |
514 | .controls = mt9t031_controls, | 531 | .controls = mt9t031_controls, |
515 | .num_controls = ARRAY_SIZE(mt9t031_controls), | 532 | .num_controls = ARRAY_SIZE(mt9t031_controls), |
516 | .get_control = mt9t031_get_control, | ||
517 | .set_control = mt9t031_set_control, | ||
518 | .get_chip_id = mt9t031_get_chip_id, | ||
519 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
520 | .get_register = mt9t031_get_register, | ||
521 | .set_register = mt9t031_set_register, | ||
522 | #endif | ||
523 | }; | 533 | }; |
524 | 534 | ||
525 | static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) | 535 | static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
526 | { | 536 | { |
527 | struct i2c_client *client = to_i2c_client(icd->control); | 537 | struct i2c_client *client = sd->priv; |
528 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 538 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
529 | int data; | 539 | int data; |
530 | 540 | ||
531 | switch (ctrl->id) { | 541 | switch (ctrl->id) { |
@@ -544,14 +554,21 @@ static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro | |||
544 | case V4L2_CID_EXPOSURE_AUTO: | 554 | case V4L2_CID_EXPOSURE_AUTO: |
545 | ctrl->value = mt9t031->autoexposure; | 555 | ctrl->value = mt9t031->autoexposure; |
546 | break; | 556 | break; |
557 | case V4L2_CID_GAIN: | ||
558 | ctrl->value = mt9t031->gain; | ||
559 | break; | ||
560 | case V4L2_CID_EXPOSURE: | ||
561 | ctrl->value = mt9t031->exposure; | ||
562 | break; | ||
547 | } | 563 | } |
548 | return 0; | 564 | return 0; |
549 | } | 565 | } |
550 | 566 | ||
551 | static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) | 567 | static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
552 | { | 568 | { |
553 | struct i2c_client *client = to_i2c_client(icd->control); | 569 | struct i2c_client *client = sd->priv; |
554 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 570 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
571 | struct soc_camera_device *icd = client->dev.platform_data; | ||
555 | const struct v4l2_queryctrl *qctrl; | 572 | const struct v4l2_queryctrl *qctrl; |
556 | int data; | 573 | int data; |
557 | 574 | ||
@@ -586,7 +603,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
586 | unsigned long range = qctrl->default_value - qctrl->minimum; | 603 | unsigned long range = qctrl->default_value - qctrl->minimum; |
587 | data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; | 604 | data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; |
588 | 605 | ||
589 | dev_dbg(&icd->dev, "Setting gain %d\n", data); | 606 | dev_dbg(&client->dev, "Setting gain %d\n", data); |
590 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); | 607 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); |
591 | if (data < 0) | 608 | if (data < 0) |
592 | return -EIO; | 609 | return -EIO; |
@@ -606,7 +623,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
606 | /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */ | 623 | /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */ |
607 | data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60; | 624 | data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60; |
608 | 625 | ||
609 | dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n", | 626 | dev_dbg(&client->dev, "Set gain from 0x%x to 0x%x\n", |
610 | reg_read(client, MT9T031_GLOBAL_GAIN), data); | 627 | reg_read(client, MT9T031_GLOBAL_GAIN), data); |
611 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); | 628 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); |
612 | if (data < 0) | 629 | if (data < 0) |
@@ -614,7 +631,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
614 | } | 631 | } |
615 | 632 | ||
616 | /* Success */ | 633 | /* Success */ |
617 | icd->gain = ctrl->value; | 634 | mt9t031->gain = ctrl->value; |
618 | break; | 635 | break; |
619 | case V4L2_CID_EXPOSURE: | 636 | case V4L2_CID_EXPOSURE: |
620 | /* mt9t031 has maximum == default */ | 637 | /* mt9t031 has maximum == default */ |
@@ -627,11 +644,11 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
627 | u32 old; | 644 | u32 old; |
628 | 645 | ||
629 | get_shutter(client, &old); | 646 | get_shutter(client, &old); |
630 | dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n", | 647 | dev_dbg(&client->dev, "Set shutter from %u to %u\n", |
631 | old, shutter); | 648 | old, shutter); |
632 | if (set_shutter(client, shutter) < 0) | 649 | if (set_shutter(client, shutter) < 0) |
633 | return -EIO; | 650 | return -EIO; |
634 | icd->exposure = ctrl->value; | 651 | mt9t031->exposure = ctrl->value; |
635 | mt9t031->autoexposure = 0; | 652 | mt9t031->autoexposure = 0; |
636 | } | 653 | } |
637 | break; | 654 | break; |
@@ -639,13 +656,14 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
639 | if (ctrl->value) { | 656 | if (ctrl->value) { |
640 | const u16 vblank = MT9T031_VERTICAL_BLANK; | 657 | const u16 vblank = MT9T031_VERTICAL_BLANK; |
641 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | 658 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; |
642 | if (set_shutter(client, icd->height + | 659 | unsigned int total_h = mt9t031->rect.height + |
643 | icd->y_skip_top + vblank) < 0) | 660 | icd->y_skip_top + vblank; |
661 | |||
662 | if (set_shutter(client, total_h) < 0) | ||
644 | return -EIO; | 663 | return -EIO; |
645 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); | 664 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); |
646 | icd->exposure = (shutter_max / 2 + (icd->height + | 665 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * |
647 | icd->y_skip_top + vblank - 1) * | 666 | (qctrl->maximum - qctrl->minimum)) / |
648 | (qctrl->maximum - qctrl->minimum)) / | ||
649 | shutter_max + qctrl->minimum; | 667 | shutter_max + qctrl->minimum; |
650 | mt9t031->autoexposure = 1; | 668 | mt9t031->autoexposure = 1; |
651 | } else | 669 | } else |
@@ -657,22 +675,16 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro | |||
657 | 675 | ||
658 | /* Interface active, can use i2c. If it fails, it can indeed mean, that | 676 | /* Interface active, can use i2c. If it fails, it can indeed mean, that |
659 | * this wasn't our capture interface, so, we wait for the right one */ | 677 | * this wasn't our capture interface, so, we wait for the right one */ |
660 | static int mt9t031_video_probe(struct soc_camera_device *icd) | 678 | static int mt9t031_video_probe(struct i2c_client *client) |
661 | { | 679 | { |
662 | struct i2c_client *client = to_i2c_client(icd->control); | 680 | struct soc_camera_device *icd = client->dev.platform_data; |
663 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 681 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
664 | s32 data; | 682 | s32 data; |
665 | int ret; | 683 | int ret; |
666 | 684 | ||
667 | /* We must have a parent by now. And it cannot be a wrong one. | ||
668 | * So this entire test is completely redundant. */ | ||
669 | if (!icd->dev.parent || | ||
670 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) | ||
671 | return -ENODEV; | ||
672 | |||
673 | /* Enable the chip */ | 685 | /* Enable the chip */ |
674 | data = reg_write(client, MT9T031_CHIP_ENABLE, 1); | 686 | data = reg_write(client, MT9T031_CHIP_ENABLE, 1); |
675 | dev_dbg(&icd->dev, "write: %d\n", data); | 687 | dev_dbg(&client->dev, "write: %d\n", data); |
676 | 688 | ||
677 | /* Read out the chip version register */ | 689 | /* Read out the chip version register */ |
678 | data = reg_read(client, MT9T031_CHIP_VERSION); | 690 | data = reg_read(client, MT9T031_CHIP_VERSION); |
@@ -684,44 +696,64 @@ static int mt9t031_video_probe(struct soc_camera_device *icd) | |||
684 | icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats); | 696 | icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats); |
685 | break; | 697 | break; |
686 | default: | 698 | default: |
687 | ret = -ENODEV; | 699 | dev_err(&client->dev, |
688 | dev_err(&icd->dev, | ||
689 | "No MT9T031 chip detected, register read %x\n", data); | 700 | "No MT9T031 chip detected, register read %x\n", data); |
690 | goto ei2c; | 701 | return -ENODEV; |
691 | } | 702 | } |
692 | 703 | ||
693 | dev_info(&icd->dev, "Detected a MT9T031 chip ID %x\n", data); | 704 | dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data); |
694 | 705 | ||
695 | /* Now that we know the model, we can start video */ | 706 | ret = mt9t031_idle(client); |
696 | ret = soc_camera_video_start(icd); | 707 | if (ret < 0) |
697 | if (ret) | 708 | dev_err(&client->dev, "Failed to initialise the camera\n"); |
698 | goto evstart; | ||
699 | 709 | ||
700 | return 0; | 710 | /* mt9t031_idle() has reset the chip to default. */ |
711 | mt9t031->exposure = 255; | ||
712 | mt9t031->gain = 64; | ||
701 | 713 | ||
702 | evstart: | ||
703 | ei2c: | ||
704 | return ret; | 714 | return ret; |
705 | } | 715 | } |
706 | 716 | ||
707 | static void mt9t031_video_remove(struct soc_camera_device *icd) | 717 | static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { |
708 | { | 718 | .g_ctrl = mt9t031_g_ctrl, |
709 | struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); | 719 | .s_ctrl = mt9t031_s_ctrl, |
720 | .g_chip_ident = mt9t031_g_chip_ident, | ||
721 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
722 | .g_register = mt9t031_g_register, | ||
723 | .s_register = mt9t031_s_register, | ||
724 | #endif | ||
725 | }; | ||
710 | 726 | ||
711 | dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9t031->client->addr, | 727 | static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { |
712 | icd->dev.parent, icd->vdev); | 728 | .s_stream = mt9t031_s_stream, |
713 | soc_camera_video_stop(icd); | 729 | .s_fmt = mt9t031_s_fmt, |
714 | } | 730 | .g_fmt = mt9t031_g_fmt, |
731 | .try_fmt = mt9t031_try_fmt, | ||
732 | .s_crop = mt9t031_s_crop, | ||
733 | .g_crop = mt9t031_g_crop, | ||
734 | .cropcap = mt9t031_cropcap, | ||
735 | }; | ||
736 | |||
737 | static struct v4l2_subdev_ops mt9t031_subdev_ops = { | ||
738 | .core = &mt9t031_subdev_core_ops, | ||
739 | .video = &mt9t031_subdev_video_ops, | ||
740 | }; | ||
715 | 741 | ||
716 | static int mt9t031_probe(struct i2c_client *client, | 742 | static int mt9t031_probe(struct i2c_client *client, |
717 | const struct i2c_device_id *did) | 743 | const struct i2c_device_id *did) |
718 | { | 744 | { |
719 | struct mt9t031 *mt9t031; | 745 | struct mt9t031 *mt9t031; |
720 | struct soc_camera_device *icd; | 746 | struct soc_camera_device *icd = client->dev.platform_data; |
721 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 747 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
722 | struct soc_camera_link *icl = client->dev.platform_data; | 748 | struct soc_camera_link *icl; |
723 | int ret; | 749 | int ret; |
724 | 750 | ||
751 | if (!icd) { | ||
752 | dev_err(&client->dev, "MT9T031: missing soc-camera data!\n"); | ||
753 | return -EINVAL; | ||
754 | } | ||
755 | |||
756 | icl = to_soc_camera_link(icd); | ||
725 | if (!icl) { | 757 | if (!icl) { |
726 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); | 758 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); |
727 | return -EINVAL; | 759 | return -EINVAL; |
@@ -737,23 +769,17 @@ static int mt9t031_probe(struct i2c_client *client, | |||
737 | if (!mt9t031) | 769 | if (!mt9t031) |
738 | return -ENOMEM; | 770 | return -ENOMEM; |
739 | 771 | ||
740 | mt9t031->client = client; | 772 | v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); |
741 | i2c_set_clientdata(client, mt9t031); | ||
742 | 773 | ||
743 | /* Second stage probe - when a capture adapter is there */ | 774 | /* Second stage probe - when a capture adapter is there */ |
744 | icd = &mt9t031->icd; | 775 | icd->ops = &mt9t031_ops; |
745 | icd->ops = &mt9t031_ops; | 776 | icd->y_skip_top = 0; |
746 | icd->control = &client->dev; | 777 | |
747 | icd->x_min = MT9T031_COLUMN_SKIP; | 778 | mt9t031->rect.left = MT9T031_COLUMN_SKIP; |
748 | icd->y_min = MT9T031_ROW_SKIP; | 779 | mt9t031->rect.top = MT9T031_ROW_SKIP; |
749 | icd->x_current = icd->x_min; | 780 | mt9t031->rect.width = MT9T031_MAX_WIDTH; |
750 | icd->y_current = icd->y_min; | 781 | mt9t031->rect.height = MT9T031_MAX_HEIGHT; |
751 | icd->width_min = MT9T031_MIN_WIDTH; | 782 | |
752 | icd->width_max = MT9T031_MAX_WIDTH; | ||
753 | icd->height_min = MT9T031_MIN_HEIGHT; | ||
754 | icd->height_max = MT9T031_MAX_HEIGHT; | ||
755 | icd->y_skip_top = 0; | ||
756 | icd->iface = icl->bus_id; | ||
757 | /* Simulated autoexposure. If enabled, we calculate shutter width | 783 | /* Simulated autoexposure. If enabled, we calculate shutter width |
758 | * ourselves in the driver based on vertical blanking and frame width */ | 784 | * ourselves in the driver based on vertical blanking and frame width */ |
759 | mt9t031->autoexposure = 1; | 785 | mt9t031->autoexposure = 1; |
@@ -761,24 +787,29 @@ static int mt9t031_probe(struct i2c_client *client, | |||
761 | mt9t031->xskip = 1; | 787 | mt9t031->xskip = 1; |
762 | mt9t031->yskip = 1; | 788 | mt9t031->yskip = 1; |
763 | 789 | ||
764 | ret = soc_camera_device_register(icd); | 790 | mt9t031_idle(client); |
765 | if (ret) | ||
766 | goto eisdr; | ||
767 | 791 | ||
768 | return 0; | 792 | ret = mt9t031_video_probe(client); |
793 | |||
794 | mt9t031_disable(client); | ||
795 | |||
796 | if (ret) { | ||
797 | icd->ops = NULL; | ||
798 | i2c_set_clientdata(client, NULL); | ||
799 | kfree(mt9t031); | ||
800 | } | ||
769 | 801 | ||
770 | eisdr: | ||
771 | i2c_set_clientdata(client, NULL); | ||
772 | kfree(mt9t031); | ||
773 | return ret; | 802 | return ret; |
774 | } | 803 | } |
775 | 804 | ||
776 | static int mt9t031_remove(struct i2c_client *client) | 805 | static int mt9t031_remove(struct i2c_client *client) |
777 | { | 806 | { |
778 | struct mt9t031 *mt9t031 = i2c_get_clientdata(client); | 807 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
808 | struct soc_camera_device *icd = client->dev.platform_data; | ||
779 | 809 | ||
780 | soc_camera_device_unregister(&mt9t031->icd); | 810 | icd->ops = NULL; |
781 | i2c_set_clientdata(client, NULL); | 811 | i2c_set_clientdata(client, NULL); |
812 | client->driver = NULL; | ||
782 | kfree(mt9t031); | 813 | kfree(mt9t031); |
783 | 814 | ||
784 | return 0; | 815 | return 0; |