diff options
Diffstat (limited to 'drivers/media/i2c')
38 files changed, 5209 insertions, 3738 deletions
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 24d78e28e493..7b771baa2212 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig | |||
@@ -1,16 +1,4 @@ | |||
1 | # | 1 | # |
2 | # Generic video config states | ||
3 | # | ||
4 | |||
5 | config VIDEO_BTCX | ||
6 | depends on PCI | ||
7 | tristate | ||
8 | |||
9 | config VIDEO_TVEEPROM | ||
10 | tristate | ||
11 | depends on I2C | ||
12 | |||
13 | # | ||
14 | # Multimedia Video device configuration | 2 | # Multimedia Video device configuration |
15 | # | 3 | # |
16 | 4 | ||
@@ -317,20 +305,6 @@ config VIDEO_SAA717X | |||
317 | 305 | ||
318 | source "drivers/media/i2c/cx25840/Kconfig" | 306 | source "drivers/media/i2c/cx25840/Kconfig" |
319 | 307 | ||
320 | comment "MPEG video encoders" | ||
321 | |||
322 | config VIDEO_CX2341X | ||
323 | tristate "Conexant CX2341x MPEG encoders" | ||
324 | depends on VIDEO_V4L2 | ||
325 | ---help--- | ||
326 | Support for the Conexant CX23416 MPEG encoders | ||
327 | and CX23415 MPEG encoder/decoders. | ||
328 | |||
329 | This module currently supports the encoding functions only. | ||
330 | |||
331 | To compile this driver as a module, choose M here: the | ||
332 | module will be called cx2341x. | ||
333 | |||
334 | comment "Video encoders" | 308 | comment "Video encoders" |
335 | 309 | ||
336 | config VIDEO_SAA7127 | 310 | config VIDEO_SAA7127 |
@@ -421,6 +395,13 @@ config VIDEO_OV7670 | |||
421 | OV7670 VGA camera. It currently only works with the M88ALP01 | 395 | OV7670 VGA camera. It currently only works with the M88ALP01 |
422 | controller. | 396 | controller. |
423 | 397 | ||
398 | config VIDEO_OV9650 | ||
399 | tristate "OmniVision OV9650/OV9652 sensor support" | ||
400 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
401 | ---help--- | ||
402 | This is a V4L2 sensor-level driver for the Omnivision | ||
403 | OV9650 and OV9652 camera sensors. | ||
404 | |||
424 | config VIDEO_VS6624 | 405 | config VIDEO_VS6624 |
425 | tristate "ST VS6624 sensor support" | 406 | tristate "ST VS6624 sensor support" |
426 | depends on VIDEO_V4L2 && I2C | 407 | depends on VIDEO_V4L2 && I2C |
@@ -477,7 +458,7 @@ config VIDEO_MT9V032 | |||
477 | 458 | ||
478 | config VIDEO_TCM825X | 459 | config VIDEO_TCM825X |
479 | tristate "TCM825x camera sensor support" | 460 | tristate "TCM825x camera sensor support" |
480 | depends on I2C && VIDEO_V4L2 | 461 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_INT_DEVICE |
481 | depends on MEDIA_CAMERA_SUPPORT | 462 | depends on MEDIA_CAMERA_SUPPORT |
482 | ---help--- | 463 | ---help--- |
483 | This is a driver for the Toshiba TCM825x VGA camera sensor. | 464 | This is a driver for the Toshiba TCM825x VGA camera sensor. |
@@ -516,6 +497,13 @@ config VIDEO_S5K4ECGX | |||
516 | 497 | ||
517 | source "drivers/media/i2c/smiapp/Kconfig" | 498 | source "drivers/media/i2c/smiapp/Kconfig" |
518 | 499 | ||
500 | config VIDEO_S5C73M3 | ||
501 | tristate "Samsung S5C73M3 sensor support" | ||
502 | depends on I2C && SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
503 | ---help--- | ||
504 | This is a V4L2 sensor-level driver for Samsung S5C73M3 | ||
505 | 8 Mpixel camera. | ||
506 | |||
519 | comment "Flash devices" | 507 | comment "Flash devices" |
520 | 508 | ||
521 | config VIDEO_ADP1653 | 509 | config VIDEO_ADP1653 |
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index b1d62dfd49b8..cfefd30cc1bc 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile | |||
@@ -47,8 +47,8 @@ obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o | |||
47 | obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o | 47 | obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o |
48 | obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o | 48 | obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o |
49 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o | 49 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o |
50 | obj-$(CONFIG_VIDEO_OV9650) += ov9650.o | ||
50 | obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o | 51 | obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o |
51 | obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o | ||
52 | obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o | 52 | obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o |
53 | obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o | 53 | obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o |
54 | obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o | 54 | obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o |
@@ -58,10 +58,9 @@ obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o | |||
58 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o | 58 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o |
59 | obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o | 59 | obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o |
60 | obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o | 60 | obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o |
61 | obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/ | ||
61 | obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o | 62 | obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o |
62 | obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o | 63 | obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o |
63 | obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o | 64 | obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o |
64 | obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o | ||
65 | obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o | ||
66 | obj-$(CONFIG_VIDEO_AK881X) += ak881x.o | 65 | obj-$(CONFIG_VIDEO_AK881X) += ak881x.o |
67 | obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o | 66 | obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o |
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 64d71fb87a96..34f39d3b3e3e 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c | |||
@@ -402,9 +402,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = { | |||
402 | static const struct v4l2_subdev_core_ops adv7180_core_ops = { | 402 | static const struct v4l2_subdev_core_ops adv7180_core_ops = { |
403 | .g_chip_ident = adv7180_g_chip_ident, | 403 | .g_chip_ident = adv7180_g_chip_ident, |
404 | .s_std = adv7180_s_std, | 404 | .s_std = adv7180_s_std, |
405 | .queryctrl = v4l2_subdev_queryctrl, | ||
406 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
407 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
408 | }; | 405 | }; |
409 | 406 | ||
410 | static const struct v4l2_subdev_ops adv7180_ops = { | 407 | static const struct v4l2_subdev_ops adv7180_ops = { |
diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index 2b5aa676a84e..9fc2b985df0e 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c | |||
@@ -43,6 +43,7 @@ MODULE_PARM_DESC(debug, "Debug level 0-1"); | |||
43 | struct adv7343_state { | 43 | struct adv7343_state { |
44 | struct v4l2_subdev sd; | 44 | struct v4l2_subdev sd; |
45 | struct v4l2_ctrl_handler hdl; | 45 | struct v4l2_ctrl_handler hdl; |
46 | const struct adv7343_platform_data *pdata; | ||
46 | u8 reg00; | 47 | u8 reg00; |
47 | u8 reg01; | 48 | u8 reg01; |
48 | u8 reg02; | 49 | u8 reg02; |
@@ -215,12 +216,23 @@ static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type) | |||
215 | /* Enable Appropriate DAC */ | 216 | /* Enable Appropriate DAC */ |
216 | val = state->reg00 & 0x03; | 217 | val = state->reg00 & 0x03; |
217 | 218 | ||
218 | if (output_type == ADV7343_COMPOSITE_ID) | 219 | /* configure default configuration */ |
219 | val |= ADV7343_COMPOSITE_POWER_VALUE; | 220 | if (!state->pdata) |
220 | else if (output_type == ADV7343_COMPONENT_ID) | 221 | if (output_type == ADV7343_COMPOSITE_ID) |
221 | val |= ADV7343_COMPONENT_POWER_VALUE; | 222 | val |= ADV7343_COMPOSITE_POWER_VALUE; |
223 | else if (output_type == ADV7343_COMPONENT_ID) | ||
224 | val |= ADV7343_COMPONENT_POWER_VALUE; | ||
225 | else | ||
226 | val |= ADV7343_SVIDEO_POWER_VALUE; | ||
222 | else | 227 | else |
223 | val |= ADV7343_SVIDEO_POWER_VALUE; | 228 | val = state->pdata->mode_config.sleep_mode << 0 | |
229 | state->pdata->mode_config.pll_control << 1 | | ||
230 | state->pdata->mode_config.dac_3 << 2 | | ||
231 | state->pdata->mode_config.dac_2 << 3 | | ||
232 | state->pdata->mode_config.dac_1 << 4 | | ||
233 | state->pdata->mode_config.dac_6 << 5 | | ||
234 | state->pdata->mode_config.dac_5 << 6 | | ||
235 | state->pdata->mode_config.dac_4 << 7; | ||
224 | 236 | ||
225 | err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val); | 237 | err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val); |
226 | if (err < 0) | 238 | if (err < 0) |
@@ -238,6 +250,17 @@ static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type) | |||
238 | 250 | ||
239 | /* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */ | 251 | /* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */ |
240 | val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI); | 252 | val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI); |
253 | |||
254 | if (state->pdata && state->pdata->sd_config.sd_dac_out1) | ||
255 | val = val | (state->pdata->sd_config.sd_dac_out1 << 1); | ||
256 | else if (state->pdata && !state->pdata->sd_config.sd_dac_out1) | ||
257 | val = val & ~(state->pdata->sd_config.sd_dac_out1 << 1); | ||
258 | |||
259 | if (state->pdata && state->pdata->sd_config.sd_dac_out2) | ||
260 | val = val | (state->pdata->sd_config.sd_dac_out2 << 2); | ||
261 | else if (state->pdata && !state->pdata->sd_config.sd_dac_out2) | ||
262 | val = val & ~(state->pdata->sd_config.sd_dac_out2 << 2); | ||
263 | |||
241 | err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val); | 264 | err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val); |
242 | if (err < 0) | 265 | if (err < 0) |
243 | goto setoutput_exit; | 266 | goto setoutput_exit; |
@@ -397,10 +420,14 @@ static int adv7343_probe(struct i2c_client *client, | |||
397 | v4l_info(client, "chip found @ 0x%x (%s)\n", | 420 | v4l_info(client, "chip found @ 0x%x (%s)\n", |
398 | client->addr << 1, client->adapter->name); | 421 | client->addr << 1, client->adapter->name); |
399 | 422 | ||
400 | state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL); | 423 | state = devm_kzalloc(&client->dev, sizeof(struct adv7343_state), |
424 | GFP_KERNEL); | ||
401 | if (state == NULL) | 425 | if (state == NULL) |
402 | return -ENOMEM; | 426 | return -ENOMEM; |
403 | 427 | ||
428 | /* Copy board specific information here */ | ||
429 | state->pdata = client->dev.platform_data; | ||
430 | |||
404 | state->reg00 = 0x80; | 431 | state->reg00 = 0x80; |
405 | state->reg01 = 0x00; | 432 | state->reg01 = 0x00; |
406 | state->reg02 = 0x20; | 433 | state->reg02 = 0x20; |
@@ -431,16 +458,13 @@ static int adv7343_probe(struct i2c_client *client, | |||
431 | int err = state->hdl.error; | 458 | int err = state->hdl.error; |
432 | 459 | ||
433 | v4l2_ctrl_handler_free(&state->hdl); | 460 | v4l2_ctrl_handler_free(&state->hdl); |
434 | kfree(state); | ||
435 | return err; | 461 | return err; |
436 | } | 462 | } |
437 | v4l2_ctrl_handler_setup(&state->hdl); | 463 | v4l2_ctrl_handler_setup(&state->hdl); |
438 | 464 | ||
439 | err = adv7343_initialize(&state->sd); | 465 | err = adv7343_initialize(&state->sd); |
440 | if (err) { | 466 | if (err) |
441 | v4l2_ctrl_handler_free(&state->hdl); | 467 | v4l2_ctrl_handler_free(&state->hdl); |
442 | kfree(state); | ||
443 | } | ||
444 | return err; | 468 | return err; |
445 | } | 469 | } |
446 | 470 | ||
@@ -451,7 +475,6 @@ static int adv7343_remove(struct i2c_client *client) | |||
451 | 475 | ||
452 | v4l2_device_unregister_subdev(sd); | 476 | v4l2_device_unregister_subdev(sd); |
453 | v4l2_ctrl_handler_free(&state->hdl); | 477 | v4l2_ctrl_handler_free(&state->hdl); |
454 | kfree(state); | ||
455 | 478 | ||
456 | return 0; | 479 | return 0; |
457 | } | 480 | } |
diff --git a/drivers/media/i2c/btcx-risc.c b/drivers/media/i2c/btcx-risc.c deleted file mode 100644 index ac1b2687a20d..000000000000 --- a/drivers/media/i2c/btcx-risc.c +++ /dev/null | |||
@@ -1,260 +0,0 @@ | |||
1 | /* | ||
2 | |||
3 | btcx-risc.c | ||
4 | |||
5 | bt848/bt878/cx2388x risc code generator. | ||
6 | |||
7 | (c) 2000-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
8 | |||
9 | This program is free software; you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License as published by | ||
11 | the Free Software Foundation; either version 2 of the License, or | ||
12 | (at your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; if not, write to the Free Software | ||
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | |||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/videodev2.h> | ||
30 | #include <asm/page.h> | ||
31 | #include <asm/pgtable.h> | ||
32 | |||
33 | #include "btcx-risc.h" | ||
34 | |||
35 | MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers"); | ||
36 | MODULE_AUTHOR("Gerd Knorr"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | |||
39 | static unsigned int debug; | ||
40 | module_param(debug, int, 0644); | ||
41 | MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)"); | ||
42 | |||
43 | /* ---------------------------------------------------------- */ | ||
44 | /* allocate/free risc memory */ | ||
45 | |||
46 | static int memcnt; | ||
47 | |||
48 | void btcx_riscmem_free(struct pci_dev *pci, | ||
49 | struct btcx_riscmem *risc) | ||
50 | { | ||
51 | if (NULL == risc->cpu) | ||
52 | return; | ||
53 | if (debug) { | ||
54 | memcnt--; | ||
55 | printk("btcx: riscmem free [%d] dma=%lx\n", | ||
56 | memcnt, (unsigned long)risc->dma); | ||
57 | } | ||
58 | pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); | ||
59 | memset(risc,0,sizeof(*risc)); | ||
60 | } | ||
61 | |||
62 | int btcx_riscmem_alloc(struct pci_dev *pci, | ||
63 | struct btcx_riscmem *risc, | ||
64 | unsigned int size) | ||
65 | { | ||
66 | __le32 *cpu; | ||
67 | dma_addr_t dma = 0; | ||
68 | |||
69 | if (NULL != risc->cpu && risc->size < size) | ||
70 | btcx_riscmem_free(pci,risc); | ||
71 | if (NULL == risc->cpu) { | ||
72 | cpu = pci_alloc_consistent(pci, size, &dma); | ||
73 | if (NULL == cpu) | ||
74 | return -ENOMEM; | ||
75 | risc->cpu = cpu; | ||
76 | risc->dma = dma; | ||
77 | risc->size = size; | ||
78 | if (debug) { | ||
79 | memcnt++; | ||
80 | printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n", | ||
81 | memcnt, (unsigned long)dma, cpu, size); | ||
82 | } | ||
83 | } | ||
84 | memset(risc->cpu,0,risc->size); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | /* ---------------------------------------------------------- */ | ||
89 | /* screen overlay helpers */ | ||
90 | |||
91 | int | ||
92 | btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, | ||
93 | struct v4l2_clip *clips, unsigned int n) | ||
94 | { | ||
95 | if (win->left < 0) { | ||
96 | /* left */ | ||
97 | clips[n].c.left = 0; | ||
98 | clips[n].c.top = 0; | ||
99 | clips[n].c.width = -win->left; | ||
100 | clips[n].c.height = win->height; | ||
101 | n++; | ||
102 | } | ||
103 | if (win->left + win->width > swidth) { | ||
104 | /* right */ | ||
105 | clips[n].c.left = swidth - win->left; | ||
106 | clips[n].c.top = 0; | ||
107 | clips[n].c.width = win->width - clips[n].c.left; | ||
108 | clips[n].c.height = win->height; | ||
109 | n++; | ||
110 | } | ||
111 | if (win->top < 0) { | ||
112 | /* top */ | ||
113 | clips[n].c.left = 0; | ||
114 | clips[n].c.top = 0; | ||
115 | clips[n].c.width = win->width; | ||
116 | clips[n].c.height = -win->top; | ||
117 | n++; | ||
118 | } | ||
119 | if (win->top + win->height > sheight) { | ||
120 | /* bottom */ | ||
121 | clips[n].c.left = 0; | ||
122 | clips[n].c.top = sheight - win->top; | ||
123 | clips[n].c.width = win->width; | ||
124 | clips[n].c.height = win->height - clips[n].c.top; | ||
125 | n++; | ||
126 | } | ||
127 | return n; | ||
128 | } | ||
129 | |||
130 | int | ||
131 | btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask) | ||
132 | { | ||
133 | s32 nx,nw,dx; | ||
134 | unsigned int i; | ||
135 | |||
136 | /* fixup window */ | ||
137 | nx = (win->left + mask) & ~mask; | ||
138 | nw = (win->width) & ~mask; | ||
139 | if (nx + nw > win->left + win->width) | ||
140 | nw -= mask+1; | ||
141 | dx = nx - win->left; | ||
142 | win->left = nx; | ||
143 | win->width = nw; | ||
144 | if (debug) | ||
145 | printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n", | ||
146 | win->width, win->height, win->left, win->top, dx); | ||
147 | |||
148 | /* fixup clips */ | ||
149 | for (i = 0; i < n; i++) { | ||
150 | nx = (clips[i].c.left-dx) & ~mask; | ||
151 | nw = (clips[i].c.width) & ~mask; | ||
152 | if (nx + nw < clips[i].c.left-dx + clips[i].c.width) | ||
153 | nw += mask+1; | ||
154 | clips[i].c.left = nx; | ||
155 | clips[i].c.width = nw; | ||
156 | if (debug) | ||
157 | printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n", | ||
158 | clips[i].c.width, clips[i].c.height, | ||
159 | clips[i].c.left, clips[i].c.top); | ||
160 | } | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | void | ||
165 | btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) | ||
166 | { | ||
167 | struct v4l2_clip swap; | ||
168 | int i,j,n; | ||
169 | |||
170 | if (nclips < 2) | ||
171 | return; | ||
172 | for (i = nclips-2; i >= 0; i--) { | ||
173 | for (n = 0, j = 0; j <= i; j++) { | ||
174 | if (clips[j].c.left > clips[j+1].c.left) { | ||
175 | swap = clips[j]; | ||
176 | clips[j] = clips[j+1]; | ||
177 | clips[j+1] = swap; | ||
178 | n++; | ||
179 | } | ||
180 | } | ||
181 | if (0 == n) | ||
182 | break; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | void | ||
187 | btcx_calc_skips(int line, int width, int *maxy, | ||
188 | struct btcx_skiplist *skips, unsigned int *nskips, | ||
189 | const struct v4l2_clip *clips, unsigned int nclips) | ||
190 | { | ||
191 | unsigned int clip,skip; | ||
192 | int end, maxline; | ||
193 | |||
194 | skip=0; | ||
195 | maxline = 9999; | ||
196 | for (clip = 0; clip < nclips; clip++) { | ||
197 | |||
198 | /* sanity checks */ | ||
199 | if (clips[clip].c.left + clips[clip].c.width <= 0) | ||
200 | continue; | ||
201 | if (clips[clip].c.left > (signed)width) | ||
202 | break; | ||
203 | |||
204 | /* vertical range */ | ||
205 | if (line > clips[clip].c.top+clips[clip].c.height-1) | ||
206 | continue; | ||
207 | if (line < clips[clip].c.top) { | ||
208 | if (maxline > clips[clip].c.top-1) | ||
209 | maxline = clips[clip].c.top-1; | ||
210 | continue; | ||
211 | } | ||
212 | if (maxline > clips[clip].c.top+clips[clip].c.height-1) | ||
213 | maxline = clips[clip].c.top+clips[clip].c.height-1; | ||
214 | |||
215 | /* horizontal range */ | ||
216 | if (0 == skip || clips[clip].c.left > skips[skip-1].end) { | ||
217 | /* new one */ | ||
218 | skips[skip].start = clips[clip].c.left; | ||
219 | if (skips[skip].start < 0) | ||
220 | skips[skip].start = 0; | ||
221 | skips[skip].end = clips[clip].c.left + clips[clip].c.width; | ||
222 | if (skips[skip].end > width) | ||
223 | skips[skip].end = width; | ||
224 | skip++; | ||
225 | } else { | ||
226 | /* overlaps -- expand last one */ | ||
227 | end = clips[clip].c.left + clips[clip].c.width; | ||
228 | if (skips[skip-1].end < end) | ||
229 | skips[skip-1].end = end; | ||
230 | if (skips[skip-1].end > width) | ||
231 | skips[skip-1].end = width; | ||
232 | } | ||
233 | } | ||
234 | *nskips = skip; | ||
235 | *maxy = maxline; | ||
236 | |||
237 | if (debug) { | ||
238 | printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline); | ||
239 | for (skip = 0; skip < *nskips; skip++) { | ||
240 | printk(" %d-%d",skips[skip].start,skips[skip].end); | ||
241 | } | ||
242 | printk("\n"); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | /* ---------------------------------------------------------- */ | ||
247 | |||
248 | EXPORT_SYMBOL(btcx_riscmem_alloc); | ||
249 | EXPORT_SYMBOL(btcx_riscmem_free); | ||
250 | |||
251 | EXPORT_SYMBOL(btcx_screen_clips); | ||
252 | EXPORT_SYMBOL(btcx_align); | ||
253 | EXPORT_SYMBOL(btcx_sort_clips); | ||
254 | EXPORT_SYMBOL(btcx_calc_skips); | ||
255 | |||
256 | /* | ||
257 | * Local variables: | ||
258 | * c-basic-offset: 8 | ||
259 | * End: | ||
260 | */ | ||
diff --git a/drivers/media/i2c/btcx-risc.h b/drivers/media/i2c/btcx-risc.h deleted file mode 100644 index f8bc6e8e7b51..000000000000 --- a/drivers/media/i2c/btcx-risc.h +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | /* | ||
2 | */ | ||
3 | struct btcx_riscmem { | ||
4 | unsigned int size; | ||
5 | __le32 *cpu; | ||
6 | __le32 *jmp; | ||
7 | dma_addr_t dma; | ||
8 | }; | ||
9 | |||
10 | struct btcx_skiplist { | ||
11 | int start; | ||
12 | int end; | ||
13 | }; | ||
14 | |||
15 | int btcx_riscmem_alloc(struct pci_dev *pci, | ||
16 | struct btcx_riscmem *risc, | ||
17 | unsigned int size); | ||
18 | void btcx_riscmem_free(struct pci_dev *pci, | ||
19 | struct btcx_riscmem *risc); | ||
20 | |||
21 | int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, | ||
22 | struct v4l2_clip *clips, unsigned int n); | ||
23 | int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, | ||
24 | unsigned int n, int mask); | ||
25 | void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); | ||
26 | void btcx_calc_skips(int line, int width, int *maxy, | ||
27 | struct btcx_skiplist *skips, unsigned int *nskips, | ||
28 | const struct v4l2_clip *clips, unsigned int nclips); | ||
29 | |||
30 | /* | ||
31 | * Local variables: | ||
32 | * c-basic-offset: 8 | ||
33 | * End: | ||
34 | */ | ||
diff --git a/drivers/media/i2c/cx2341x.c b/drivers/media/i2c/cx2341x.c deleted file mode 100644 index 103ef6bad2e2..000000000000 --- a/drivers/media/i2c/cx2341x.c +++ /dev/null | |||
@@ -1,1726 +0,0 @@ | |||
1 | /* | ||
2 | * cx2341x - generic code for cx23415/6/8 based devices | ||
3 | * | ||
4 | * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/types.h> | ||
27 | #include <linux/videodev2.h> | ||
28 | |||
29 | #include <media/tuner.h> | ||
30 | #include <media/cx2341x.h> | ||
31 | #include <media/v4l2-common.h> | ||
32 | |||
33 | MODULE_DESCRIPTION("cx23415/6/8 driver"); | ||
34 | MODULE_AUTHOR("Hans Verkuil"); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | static int debug; | ||
38 | module_param(debug, int, 0644); | ||
39 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); | ||
40 | |||
41 | /********************** COMMON CODE *********************/ | ||
42 | |||
43 | /* definitions for audio properties bits 29-28 */ | ||
44 | #define CX2341X_AUDIO_ENCODING_METHOD_MPEG 0 | ||
45 | #define CX2341X_AUDIO_ENCODING_METHOD_AC3 1 | ||
46 | #define CX2341X_AUDIO_ENCODING_METHOD_LPCM 2 | ||
47 | |||
48 | static const char *cx2341x_get_name(u32 id) | ||
49 | { | ||
50 | switch (id) { | ||
51 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | ||
52 | return "Spatial Filter Mode"; | ||
53 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: | ||
54 | return "Spatial Filter"; | ||
55 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: | ||
56 | return "Spatial Luma Filter Type"; | ||
57 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: | ||
58 | return "Spatial Chroma Filter Type"; | ||
59 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: | ||
60 | return "Temporal Filter Mode"; | ||
61 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: | ||
62 | return "Temporal Filter"; | ||
63 | case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: | ||
64 | return "Median Filter Type"; | ||
65 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: | ||
66 | return "Median Luma Filter Maximum"; | ||
67 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: | ||
68 | return "Median Luma Filter Minimum"; | ||
69 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: | ||
70 | return "Median Chroma Filter Maximum"; | ||
71 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | ||
72 | return "Median Chroma Filter Minimum"; | ||
73 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
74 | return "Insert Navigation Packets"; | ||
75 | } | ||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | static const char **cx2341x_get_menu(u32 id) | ||
80 | { | ||
81 | static const char *cx2341x_video_spatial_filter_mode_menu[] = { | ||
82 | "Manual", | ||
83 | "Auto", | ||
84 | NULL | ||
85 | }; | ||
86 | |||
87 | static const char *cx2341x_video_luma_spatial_filter_type_menu[] = { | ||
88 | "Off", | ||
89 | "1D Horizontal", | ||
90 | "1D Vertical", | ||
91 | "2D H/V Separable", | ||
92 | "2D Symmetric non-separable", | ||
93 | NULL | ||
94 | }; | ||
95 | |||
96 | static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = { | ||
97 | "Off", | ||
98 | "1D Horizontal", | ||
99 | NULL | ||
100 | }; | ||
101 | |||
102 | static const char *cx2341x_video_temporal_filter_mode_menu[] = { | ||
103 | "Manual", | ||
104 | "Auto", | ||
105 | NULL | ||
106 | }; | ||
107 | |||
108 | static const char *cx2341x_video_median_filter_type_menu[] = { | ||
109 | "Off", | ||
110 | "Horizontal", | ||
111 | "Vertical", | ||
112 | "Horizontal/Vertical", | ||
113 | "Diagonal", | ||
114 | NULL | ||
115 | }; | ||
116 | |||
117 | switch (id) { | ||
118 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | ||
119 | return cx2341x_video_spatial_filter_mode_menu; | ||
120 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: | ||
121 | return cx2341x_video_luma_spatial_filter_type_menu; | ||
122 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: | ||
123 | return cx2341x_video_chroma_spatial_filter_type_menu; | ||
124 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: | ||
125 | return cx2341x_video_temporal_filter_mode_menu; | ||
126 | case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: | ||
127 | return cx2341x_video_median_filter_type_menu; | ||
128 | } | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | static void cx2341x_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, | ||
133 | s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags) | ||
134 | { | ||
135 | *name = cx2341x_get_name(id); | ||
136 | *flags = 0; | ||
137 | |||
138 | switch (id) { | ||
139 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | ||
140 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: | ||
141 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: | ||
142 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: | ||
143 | case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: | ||
144 | *type = V4L2_CTRL_TYPE_MENU; | ||
145 | *min = 0; | ||
146 | *step = 0; | ||
147 | break; | ||
148 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
149 | *type = V4L2_CTRL_TYPE_BOOLEAN; | ||
150 | *min = 0; | ||
151 | *max = *step = 1; | ||
152 | break; | ||
153 | default: | ||
154 | *type = V4L2_CTRL_TYPE_INTEGER; | ||
155 | break; | ||
156 | } | ||
157 | switch (id) { | ||
158 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | ||
159 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: | ||
160 | case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: | ||
161 | *flags |= V4L2_CTRL_FLAG_UPDATE; | ||
162 | break; | ||
163 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: | ||
164 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: | ||
165 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: | ||
166 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: | ||
167 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: | ||
168 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | ||
169 | *flags |= V4L2_CTRL_FLAG_SLIDER; | ||
170 | break; | ||
171 | case V4L2_CID_MPEG_VIDEO_ENCODING: | ||
172 | *flags |= V4L2_CTRL_FLAG_READ_ONLY; | ||
173 | break; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | |||
178 | /********************** OLD CODE *********************/ | ||
179 | |||
180 | /* Must be sorted from low to high control ID! */ | ||
181 | const u32 cx2341x_mpeg_ctrls[] = { | ||
182 | V4L2_CID_MPEG_CLASS, | ||
183 | V4L2_CID_MPEG_STREAM_TYPE, | ||
184 | V4L2_CID_MPEG_STREAM_VBI_FMT, | ||
185 | V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, | ||
186 | V4L2_CID_MPEG_AUDIO_ENCODING, | ||
187 | V4L2_CID_MPEG_AUDIO_L2_BITRATE, | ||
188 | V4L2_CID_MPEG_AUDIO_MODE, | ||
189 | V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, | ||
190 | V4L2_CID_MPEG_AUDIO_EMPHASIS, | ||
191 | V4L2_CID_MPEG_AUDIO_CRC, | ||
192 | V4L2_CID_MPEG_AUDIO_MUTE, | ||
193 | V4L2_CID_MPEG_AUDIO_AC3_BITRATE, | ||
194 | V4L2_CID_MPEG_VIDEO_ENCODING, | ||
195 | V4L2_CID_MPEG_VIDEO_ASPECT, | ||
196 | V4L2_CID_MPEG_VIDEO_B_FRAMES, | ||
197 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, | ||
198 | V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, | ||
199 | V4L2_CID_MPEG_VIDEO_BITRATE_MODE, | ||
200 | V4L2_CID_MPEG_VIDEO_BITRATE, | ||
201 | V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, | ||
202 | V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, | ||
203 | V4L2_CID_MPEG_VIDEO_MUTE, | ||
204 | V4L2_CID_MPEG_VIDEO_MUTE_YUV, | ||
205 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, | ||
206 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, | ||
207 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, | ||
208 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, | ||
209 | V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, | ||
210 | V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, | ||
211 | V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, | ||
212 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, | ||
213 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, | ||
214 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, | ||
215 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, | ||
216 | V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, | ||
217 | 0 | ||
218 | }; | ||
219 | EXPORT_SYMBOL(cx2341x_mpeg_ctrls); | ||
220 | |||
221 | static const struct cx2341x_mpeg_params default_params = { | ||
222 | /* misc */ | ||
223 | .capabilities = 0, | ||
224 | .port = CX2341X_PORT_MEMORY, | ||
225 | .width = 720, | ||
226 | .height = 480, | ||
227 | .is_50hz = 0, | ||
228 | |||
229 | /* stream */ | ||
230 | .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, | ||
231 | .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, | ||
232 | .stream_insert_nav_packets = 0, | ||
233 | |||
234 | /* audio */ | ||
235 | .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, | ||
236 | .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2, | ||
237 | .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K, | ||
238 | .audio_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_224K, | ||
239 | .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO, | ||
240 | .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, | ||
241 | .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, | ||
242 | .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE, | ||
243 | .audio_mute = 0, | ||
244 | |||
245 | /* video */ | ||
246 | .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2, | ||
247 | .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3, | ||
248 | .video_b_frames = 2, | ||
249 | .video_gop_size = 12, | ||
250 | .video_gop_closure = 1, | ||
251 | .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, | ||
252 | .video_bitrate = 6000000, | ||
253 | .video_bitrate_peak = 8000000, | ||
254 | .video_temporal_decimation = 0, | ||
255 | .video_mute = 0, | ||
256 | .video_mute_yuv = 0x008080, /* YCbCr value for black */ | ||
257 | |||
258 | /* encoding filters */ | ||
259 | .video_spatial_filter_mode = | ||
260 | V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, | ||
261 | .video_spatial_filter = 0, | ||
262 | .video_luma_spatial_filter_type = | ||
263 | V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, | ||
264 | .video_chroma_spatial_filter_type = | ||
265 | V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, | ||
266 | .video_temporal_filter_mode = | ||
267 | V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, | ||
268 | .video_temporal_filter = 8, | ||
269 | .video_median_filter_type = | ||
270 | V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, | ||
271 | .video_luma_median_filter_top = 255, | ||
272 | .video_luma_median_filter_bottom = 0, | ||
273 | .video_chroma_median_filter_top = 255, | ||
274 | .video_chroma_median_filter_bottom = 0, | ||
275 | }; | ||
276 | /* Map the control ID to the correct field in the cx2341x_mpeg_params | ||
277 | struct. Return -EINVAL if the ID is unknown, else return 0. */ | ||
278 | static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params, | ||
279 | struct v4l2_ext_control *ctrl) | ||
280 | { | ||
281 | switch (ctrl->id) { | ||
282 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: | ||
283 | ctrl->value = params->audio_sampling_freq; | ||
284 | break; | ||
285 | case V4L2_CID_MPEG_AUDIO_ENCODING: | ||
286 | ctrl->value = params->audio_encoding; | ||
287 | break; | ||
288 | case V4L2_CID_MPEG_AUDIO_L2_BITRATE: | ||
289 | ctrl->value = params->audio_l2_bitrate; | ||
290 | break; | ||
291 | case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: | ||
292 | ctrl->value = params->audio_ac3_bitrate; | ||
293 | break; | ||
294 | case V4L2_CID_MPEG_AUDIO_MODE: | ||
295 | ctrl->value = params->audio_mode; | ||
296 | break; | ||
297 | case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: | ||
298 | ctrl->value = params->audio_mode_extension; | ||
299 | break; | ||
300 | case V4L2_CID_MPEG_AUDIO_EMPHASIS: | ||
301 | ctrl->value = params->audio_emphasis; | ||
302 | break; | ||
303 | case V4L2_CID_MPEG_AUDIO_CRC: | ||
304 | ctrl->value = params->audio_crc; | ||
305 | break; | ||
306 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
307 | ctrl->value = params->audio_mute; | ||
308 | break; | ||
309 | case V4L2_CID_MPEG_VIDEO_ENCODING: | ||
310 | ctrl->value = params->video_encoding; | ||
311 | break; | ||
312 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
313 | ctrl->value = params->video_aspect; | ||
314 | break; | ||
315 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
316 | ctrl->value = params->video_b_frames; | ||
317 | break; | ||
318 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
319 | ctrl->value = params->video_gop_size; | ||
320 | break; | ||
321 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: | ||
322 | ctrl->value = params->video_gop_closure; | ||
323 | break; | ||
324 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | ||
325 | ctrl->value = params->video_bitrate_mode; | ||
326 | break; | ||
327 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
328 | ctrl->value = params->video_bitrate; | ||
329 | break; | ||
330 | case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: | ||
331 | ctrl->value = params->video_bitrate_peak; | ||
332 | break; | ||
333 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: | ||
334 | ctrl->value = params->video_temporal_decimation; | ||
335 | break; | ||
336 | case V4L2_CID_MPEG_VIDEO_MUTE: | ||
337 | ctrl->value = params->video_mute; | ||
338 | break; | ||
339 | case V4L2_CID_MPEG_VIDEO_MUTE_YUV: | ||
340 | ctrl->value = params->video_mute_yuv; | ||
341 | break; | ||
342 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
343 | ctrl->value = params->stream_type; | ||
344 | break; | ||
345 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
346 | ctrl->value = params->stream_vbi_fmt; | ||
347 | break; | ||
348 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | ||
349 | ctrl->value = params->video_spatial_filter_mode; | ||
350 | break; | ||
351 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: | ||
352 | ctrl->value = params->video_spatial_filter; | ||
353 | break; | ||
354 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: | ||
355 | ctrl->value = params->video_luma_spatial_filter_type; | ||
356 | break; | ||
357 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: | ||
358 | ctrl->value = params->video_chroma_spatial_filter_type; | ||
359 | break; | ||
360 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: | ||
361 | ctrl->value = params->video_temporal_filter_mode; | ||
362 | break; | ||
363 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: | ||
364 | ctrl->value = params->video_temporal_filter; | ||
365 | break; | ||
366 | case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: | ||
367 | ctrl->value = params->video_median_filter_type; | ||
368 | break; | ||
369 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: | ||
370 | ctrl->value = params->video_luma_median_filter_top; | ||
371 | break; | ||
372 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: | ||
373 | ctrl->value = params->video_luma_median_filter_bottom; | ||
374 | break; | ||
375 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: | ||
376 | ctrl->value = params->video_chroma_median_filter_top; | ||
377 | break; | ||
378 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | ||
379 | ctrl->value = params->video_chroma_median_filter_bottom; | ||
380 | break; | ||
381 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
382 | ctrl->value = params->stream_insert_nav_packets; | ||
383 | break; | ||
384 | default: | ||
385 | return -EINVAL; | ||
386 | } | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | /* Map the control ID to the correct field in the cx2341x_mpeg_params | ||
391 | struct. Return -EINVAL if the ID is unknown, else return 0. */ | ||
392 | static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, | ||
393 | struct v4l2_ext_control *ctrl) | ||
394 | { | ||
395 | switch (ctrl->id) { | ||
396 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: | ||
397 | if (busy) | ||
398 | return -EBUSY; | ||
399 | params->audio_sampling_freq = ctrl->value; | ||
400 | break; | ||
401 | case V4L2_CID_MPEG_AUDIO_ENCODING: | ||
402 | if (busy) | ||
403 | return -EBUSY; | ||
404 | if (params->capabilities & CX2341X_CAP_HAS_AC3) | ||
405 | if (ctrl->value != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && | ||
406 | ctrl->value != V4L2_MPEG_AUDIO_ENCODING_AC3) | ||
407 | return -ERANGE; | ||
408 | params->audio_encoding = ctrl->value; | ||
409 | break; | ||
410 | case V4L2_CID_MPEG_AUDIO_L2_BITRATE: | ||
411 | if (busy) | ||
412 | return -EBUSY; | ||
413 | params->audio_l2_bitrate = ctrl->value; | ||
414 | break; | ||
415 | case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: | ||
416 | if (busy) | ||
417 | return -EBUSY; | ||
418 | if (!(params->capabilities & CX2341X_CAP_HAS_AC3)) | ||
419 | return -EINVAL; | ||
420 | params->audio_ac3_bitrate = ctrl->value; | ||
421 | break; | ||
422 | case V4L2_CID_MPEG_AUDIO_MODE: | ||
423 | params->audio_mode = ctrl->value; | ||
424 | break; | ||
425 | case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: | ||
426 | params->audio_mode_extension = ctrl->value; | ||
427 | break; | ||
428 | case V4L2_CID_MPEG_AUDIO_EMPHASIS: | ||
429 | params->audio_emphasis = ctrl->value; | ||
430 | break; | ||
431 | case V4L2_CID_MPEG_AUDIO_CRC: | ||
432 | params->audio_crc = ctrl->value; | ||
433 | break; | ||
434 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
435 | params->audio_mute = ctrl->value; | ||
436 | break; | ||
437 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
438 | params->video_aspect = ctrl->value; | ||
439 | break; | ||
440 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: { | ||
441 | int b = ctrl->value + 1; | ||
442 | int gop = params->video_gop_size; | ||
443 | params->video_b_frames = ctrl->value; | ||
444 | params->video_gop_size = b * ((gop + b - 1) / b); | ||
445 | /* Max GOP size = 34 */ | ||
446 | while (params->video_gop_size > 34) | ||
447 | params->video_gop_size -= b; | ||
448 | break; | ||
449 | } | ||
450 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: { | ||
451 | int b = params->video_b_frames + 1; | ||
452 | int gop = ctrl->value; | ||
453 | params->video_gop_size = b * ((gop + b - 1) / b); | ||
454 | /* Max GOP size = 34 */ | ||
455 | while (params->video_gop_size > 34) | ||
456 | params->video_gop_size -= b; | ||
457 | ctrl->value = params->video_gop_size; | ||
458 | break; | ||
459 | } | ||
460 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: | ||
461 | params->video_gop_closure = ctrl->value; | ||
462 | break; | ||
463 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | ||
464 | if (busy) | ||
465 | return -EBUSY; | ||
466 | /* MPEG-1 only allows CBR */ | ||
467 | if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 && | ||
468 | ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | ||
469 | return -EINVAL; | ||
470 | params->video_bitrate_mode = ctrl->value; | ||
471 | break; | ||
472 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
473 | if (busy) | ||
474 | return -EBUSY; | ||
475 | params->video_bitrate = ctrl->value; | ||
476 | break; | ||
477 | case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: | ||
478 | if (busy) | ||
479 | return -EBUSY; | ||
480 | params->video_bitrate_peak = ctrl->value; | ||
481 | break; | ||
482 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: | ||
483 | params->video_temporal_decimation = ctrl->value; | ||
484 | break; | ||
485 | case V4L2_CID_MPEG_VIDEO_MUTE: | ||
486 | params->video_mute = (ctrl->value != 0); | ||
487 | break; | ||
488 | case V4L2_CID_MPEG_VIDEO_MUTE_YUV: | ||
489 | params->video_mute_yuv = ctrl->value; | ||
490 | break; | ||
491 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
492 | if (busy) | ||
493 | return -EBUSY; | ||
494 | params->stream_type = ctrl->value; | ||
495 | params->video_encoding = | ||
496 | (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || | ||
497 | params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? | ||
498 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : | ||
499 | V4L2_MPEG_VIDEO_ENCODING_MPEG_2; | ||
500 | if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) | ||
501 | /* MPEG-1 implies CBR */ | ||
502 | params->video_bitrate_mode = | ||
503 | V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; | ||
504 | break; | ||
505 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
506 | params->stream_vbi_fmt = ctrl->value; | ||
507 | break; | ||
508 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | ||
509 | params->video_spatial_filter_mode = ctrl->value; | ||
510 | break; | ||
511 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: | ||
512 | params->video_spatial_filter = ctrl->value; | ||
513 | break; | ||
514 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: | ||
515 | params->video_luma_spatial_filter_type = ctrl->value; | ||
516 | break; | ||
517 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: | ||
518 | params->video_chroma_spatial_filter_type = ctrl->value; | ||
519 | break; | ||
520 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: | ||
521 | params->video_temporal_filter_mode = ctrl->value; | ||
522 | break; | ||
523 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: | ||
524 | params->video_temporal_filter = ctrl->value; | ||
525 | break; | ||
526 | case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: | ||
527 | params->video_median_filter_type = ctrl->value; | ||
528 | break; | ||
529 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: | ||
530 | params->video_luma_median_filter_top = ctrl->value; | ||
531 | break; | ||
532 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: | ||
533 | params->video_luma_median_filter_bottom = ctrl->value; | ||
534 | break; | ||
535 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: | ||
536 | params->video_chroma_median_filter_top = ctrl->value; | ||
537 | break; | ||
538 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | ||
539 | params->video_chroma_median_filter_bottom = ctrl->value; | ||
540 | break; | ||
541 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
542 | params->stream_insert_nav_packets = ctrl->value; | ||
543 | break; | ||
544 | default: | ||
545 | return -EINVAL; | ||
546 | } | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, | ||
551 | s32 min, s32 max, s32 step, s32 def) | ||
552 | { | ||
553 | const char *name; | ||
554 | |||
555 | switch (qctrl->id) { | ||
556 | /* MPEG controls */ | ||
557 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | ||
558 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: | ||
559 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: | ||
560 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: | ||
561 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: | ||
562 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: | ||
563 | case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: | ||
564 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: | ||
565 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: | ||
566 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: | ||
567 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | ||
568 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
569 | cx2341x_ctrl_fill(qctrl->id, &name, &qctrl->type, | ||
570 | &min, &max, &step, &def, &qctrl->flags); | ||
571 | qctrl->minimum = min; | ||
572 | qctrl->maximum = max; | ||
573 | qctrl->step = step; | ||
574 | qctrl->default_value = def; | ||
575 | qctrl->reserved[0] = qctrl->reserved[1] = 0; | ||
576 | strlcpy(qctrl->name, name, sizeof(qctrl->name)); | ||
577 | return 0; | ||
578 | |||
579 | default: | ||
580 | return v4l2_ctrl_query_fill(qctrl, min, max, step, def); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, | ||
585 | struct v4l2_queryctrl *qctrl) | ||
586 | { | ||
587 | int err; | ||
588 | |||
589 | switch (qctrl->id) { | ||
590 | case V4L2_CID_MPEG_CLASS: | ||
591 | return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); | ||
592 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
593 | return v4l2_ctrl_query_fill(qctrl, | ||
594 | V4L2_MPEG_STREAM_TYPE_MPEG2_PS, | ||
595 | V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1, | ||
596 | V4L2_MPEG_STREAM_TYPE_MPEG2_PS); | ||
597 | |||
598 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
599 | if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI) | ||
600 | return v4l2_ctrl_query_fill(qctrl, | ||
601 | V4L2_MPEG_STREAM_VBI_FMT_NONE, | ||
602 | V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1, | ||
603 | V4L2_MPEG_STREAM_VBI_FMT_NONE); | ||
604 | return cx2341x_ctrl_query_fill(qctrl, | ||
605 | V4L2_MPEG_STREAM_VBI_FMT_NONE, | ||
606 | V4L2_MPEG_STREAM_VBI_FMT_NONE, 1, | ||
607 | default_params.stream_vbi_fmt); | ||
608 | |||
609 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: | ||
610 | return v4l2_ctrl_query_fill(qctrl, | ||
611 | V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100, | ||
612 | V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1, | ||
613 | V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); | ||
614 | |||
615 | case V4L2_CID_MPEG_AUDIO_ENCODING: | ||
616 | if (params->capabilities & CX2341X_CAP_HAS_AC3) { | ||
617 | /* | ||
618 | * The state of L2 & AC3 bitrate controls can change | ||
619 | * when this control changes, but v4l2_ctrl_query_fill() | ||
620 | * already sets V4L2_CTRL_FLAG_UPDATE for | ||
621 | * V4L2_CID_MPEG_AUDIO_ENCODING, so we don't here. | ||
622 | */ | ||
623 | return v4l2_ctrl_query_fill(qctrl, | ||
624 | V4L2_MPEG_AUDIO_ENCODING_LAYER_2, | ||
625 | V4L2_MPEG_AUDIO_ENCODING_AC3, 1, | ||
626 | default_params.audio_encoding); | ||
627 | } | ||
628 | |||
629 | return v4l2_ctrl_query_fill(qctrl, | ||
630 | V4L2_MPEG_AUDIO_ENCODING_LAYER_2, | ||
631 | V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1, | ||
632 | default_params.audio_encoding); | ||
633 | |||
634 | case V4L2_CID_MPEG_AUDIO_L2_BITRATE: | ||
635 | err = v4l2_ctrl_query_fill(qctrl, | ||
636 | V4L2_MPEG_AUDIO_L2_BITRATE_192K, | ||
637 | V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, | ||
638 | default_params.audio_l2_bitrate); | ||
639 | if (err) | ||
640 | return err; | ||
641 | if (params->capabilities & CX2341X_CAP_HAS_AC3 && | ||
642 | params->audio_encoding != V4L2_MPEG_AUDIO_ENCODING_LAYER_2) | ||
643 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
644 | return 0; | ||
645 | |||
646 | case V4L2_CID_MPEG_AUDIO_MODE: | ||
647 | return v4l2_ctrl_query_fill(qctrl, | ||
648 | V4L2_MPEG_AUDIO_MODE_STEREO, | ||
649 | V4L2_MPEG_AUDIO_MODE_MONO, 1, | ||
650 | V4L2_MPEG_AUDIO_MODE_STEREO); | ||
651 | |||
652 | case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: | ||
653 | err = v4l2_ctrl_query_fill(qctrl, | ||
654 | V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, | ||
655 | V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1, | ||
656 | V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4); | ||
657 | if (err == 0 && | ||
658 | params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) | ||
659 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
660 | return err; | ||
661 | |||
662 | case V4L2_CID_MPEG_AUDIO_EMPHASIS: | ||
663 | return v4l2_ctrl_query_fill(qctrl, | ||
664 | V4L2_MPEG_AUDIO_EMPHASIS_NONE, | ||
665 | V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1, | ||
666 | V4L2_MPEG_AUDIO_EMPHASIS_NONE); | ||
667 | |||
668 | case V4L2_CID_MPEG_AUDIO_CRC: | ||
669 | return v4l2_ctrl_query_fill(qctrl, | ||
670 | V4L2_MPEG_AUDIO_CRC_NONE, | ||
671 | V4L2_MPEG_AUDIO_CRC_CRC16, 1, | ||
672 | V4L2_MPEG_AUDIO_CRC_NONE); | ||
673 | |||
674 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
675 | return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); | ||
676 | |||
677 | case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: | ||
678 | err = v4l2_ctrl_query_fill(qctrl, | ||
679 | V4L2_MPEG_AUDIO_AC3_BITRATE_48K, | ||
680 | V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 1, | ||
681 | default_params.audio_ac3_bitrate); | ||
682 | if (err) | ||
683 | return err; | ||
684 | if (params->capabilities & CX2341X_CAP_HAS_AC3) { | ||
685 | if (params->audio_encoding != | ||
686 | V4L2_MPEG_AUDIO_ENCODING_AC3) | ||
687 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
688 | } else | ||
689 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
690 | return 0; | ||
691 | |||
692 | case V4L2_CID_MPEG_VIDEO_ENCODING: | ||
693 | /* this setting is read-only for the cx2341x since the | ||
694 | V4L2_CID_MPEG_STREAM_TYPE really determines the | ||
695 | MPEG-1/2 setting */ | ||
696 | err = v4l2_ctrl_query_fill(qctrl, | ||
697 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1, | ||
698 | V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1, | ||
699 | V4L2_MPEG_VIDEO_ENCODING_MPEG_2); | ||
700 | if (err == 0) | ||
701 | qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; | ||
702 | return err; | ||
703 | |||
704 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
705 | return v4l2_ctrl_query_fill(qctrl, | ||
706 | V4L2_MPEG_VIDEO_ASPECT_1x1, | ||
707 | V4L2_MPEG_VIDEO_ASPECT_221x100, 1, | ||
708 | V4L2_MPEG_VIDEO_ASPECT_4x3); | ||
709 | |||
710 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
711 | return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2); | ||
712 | |||
713 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
714 | return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, | ||
715 | params->is_50hz ? 12 : 15); | ||
716 | |||
717 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: | ||
718 | return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1); | ||
719 | |||
720 | case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | ||
721 | err = v4l2_ctrl_query_fill(qctrl, | ||
722 | V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, | ||
723 | V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, | ||
724 | V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); | ||
725 | if (err == 0 && | ||
726 | params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) | ||
727 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
728 | return err; | ||
729 | |||
730 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
731 | return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000); | ||
732 | |||
733 | case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: | ||
734 | err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); | ||
735 | if (err == 0 && | ||
736 | params->video_bitrate_mode == | ||
737 | V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | ||
738 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
739 | return err; | ||
740 | |||
741 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: | ||
742 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); | ||
743 | |||
744 | case V4L2_CID_MPEG_VIDEO_MUTE: | ||
745 | return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); | ||
746 | |||
747 | case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */ | ||
748 | return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080); | ||
749 | |||
750 | /* CX23415/6 specific */ | ||
751 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | ||
752 | return cx2341x_ctrl_query_fill(qctrl, | ||
753 | V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, | ||
754 | V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1, | ||
755 | default_params.video_spatial_filter_mode); | ||
756 | |||
757 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: | ||
758 | cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, | ||
759 | default_params.video_spatial_filter); | ||
760 | qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; | ||
761 | if (params->video_spatial_filter_mode == | ||
762 | V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) | ||
763 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
764 | return 0; | ||
765 | |||
766 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: | ||
767 | cx2341x_ctrl_query_fill(qctrl, | ||
768 | V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, | ||
769 | V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, | ||
770 | 1, | ||
771 | default_params.video_luma_spatial_filter_type); | ||
772 | if (params->video_spatial_filter_mode == | ||
773 | V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) | ||
774 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
775 | return 0; | ||
776 | |||
777 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: | ||
778 | cx2341x_ctrl_query_fill(qctrl, | ||
779 | V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, | ||
780 | V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, | ||
781 | 1, | ||
782 | default_params.video_chroma_spatial_filter_type); | ||
783 | if (params->video_spatial_filter_mode == | ||
784 | V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) | ||
785 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
786 | return 0; | ||
787 | |||
788 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: | ||
789 | return cx2341x_ctrl_query_fill(qctrl, | ||
790 | V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, | ||
791 | V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1, | ||
792 | default_params.video_temporal_filter_mode); | ||
793 | |||
794 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: | ||
795 | cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, | ||
796 | default_params.video_temporal_filter); | ||
797 | qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; | ||
798 | if (params->video_temporal_filter_mode == | ||
799 | V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO) | ||
800 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
801 | return 0; | ||
802 | |||
803 | case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: | ||
804 | return cx2341x_ctrl_query_fill(qctrl, | ||
805 | V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, | ||
806 | V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1, | ||
807 | default_params.video_median_filter_type); | ||
808 | |||
809 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: | ||
810 | cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, | ||
811 | default_params.video_luma_median_filter_top); | ||
812 | qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; | ||
813 | if (params->video_median_filter_type == | ||
814 | V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) | ||
815 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
816 | return 0; | ||
817 | |||
818 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: | ||
819 | cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, | ||
820 | default_params.video_luma_median_filter_bottom); | ||
821 | qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; | ||
822 | if (params->video_median_filter_type == | ||
823 | V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) | ||
824 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
825 | return 0; | ||
826 | |||
827 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: | ||
828 | cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, | ||
829 | default_params.video_chroma_median_filter_top); | ||
830 | qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; | ||
831 | if (params->video_median_filter_type == | ||
832 | V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) | ||
833 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
834 | return 0; | ||
835 | |||
836 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | ||
837 | cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, | ||
838 | default_params.video_chroma_median_filter_bottom); | ||
839 | qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; | ||
840 | if (params->video_median_filter_type == | ||
841 | V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) | ||
842 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | ||
843 | return 0; | ||
844 | |||
845 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
846 | return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, | ||
847 | default_params.stream_insert_nav_packets); | ||
848 | |||
849 | default: | ||
850 | return -EINVAL; | ||
851 | |||
852 | } | ||
853 | } | ||
854 | EXPORT_SYMBOL(cx2341x_ctrl_query); | ||
855 | |||
856 | const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id) | ||
857 | { | ||
858 | static const char * const mpeg_stream_type_without_ts[] = { | ||
859 | "MPEG-2 Program Stream", | ||
860 | "", | ||
861 | "MPEG-1 System Stream", | ||
862 | "MPEG-2 DVD-compatible Stream", | ||
863 | "MPEG-1 VCD-compatible Stream", | ||
864 | "MPEG-2 SVCD-compatible Stream", | ||
865 | NULL | ||
866 | }; | ||
867 | |||
868 | static const char *mpeg_stream_type_with_ts[] = { | ||
869 | "MPEG-2 Program Stream", | ||
870 | "MPEG-2 Transport Stream", | ||
871 | "MPEG-1 System Stream", | ||
872 | "MPEG-2 DVD-compatible Stream", | ||
873 | "MPEG-1 VCD-compatible Stream", | ||
874 | "MPEG-2 SVCD-compatible Stream", | ||
875 | NULL | ||
876 | }; | ||
877 | |||
878 | static const char *mpeg_audio_encoding_l2_ac3[] = { | ||
879 | "", | ||
880 | "MPEG-1/2 Layer II", | ||
881 | "", | ||
882 | "", | ||
883 | "AC-3", | ||
884 | NULL | ||
885 | }; | ||
886 | |||
887 | switch (id) { | ||
888 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
889 | return (p->capabilities & CX2341X_CAP_HAS_TS) ? | ||
890 | mpeg_stream_type_with_ts : mpeg_stream_type_without_ts; | ||
891 | case V4L2_CID_MPEG_AUDIO_ENCODING: | ||
892 | return (p->capabilities & CX2341X_CAP_HAS_AC3) ? | ||
893 | mpeg_audio_encoding_l2_ac3 : v4l2_ctrl_get_menu(id); | ||
894 | case V4L2_CID_MPEG_AUDIO_L1_BITRATE: | ||
895 | case V4L2_CID_MPEG_AUDIO_L3_BITRATE: | ||
896 | return NULL; | ||
897 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: | ||
898 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: | ||
899 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: | ||
900 | case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: | ||
901 | case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: | ||
902 | return cx2341x_get_menu(id); | ||
903 | default: | ||
904 | return v4l2_ctrl_get_menu(id); | ||
905 | } | ||
906 | } | ||
907 | EXPORT_SYMBOL(cx2341x_ctrl_get_menu); | ||
908 | |||
909 | static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) | ||
910 | { | ||
911 | params->audio_properties = | ||
912 | (params->audio_sampling_freq << 0) | | ||
913 | (params->audio_mode << 8) | | ||
914 | (params->audio_mode_extension << 10) | | ||
915 | (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) | ||
916 | ? 3 : params->audio_emphasis) << 12) | | ||
917 | (params->audio_crc << 14); | ||
918 | |||
919 | if ((params->capabilities & CX2341X_CAP_HAS_AC3) && | ||
920 | params->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) { | ||
921 | params->audio_properties |= | ||
922 | /* Not sure if this MPEG Layer II setting is required */ | ||
923 | ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) | | ||
924 | (params->audio_ac3_bitrate << 4) | | ||
925 | (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28); | ||
926 | } else { | ||
927 | /* Assuming MPEG Layer II */ | ||
928 | params->audio_properties |= | ||
929 | ((3 - params->audio_encoding) << 2) | | ||
930 | ((1 + params->audio_l2_bitrate) << 4); | ||
931 | } | ||
932 | } | ||
933 | |||
934 | int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, | ||
935 | struct v4l2_ext_controls *ctrls, unsigned int cmd) | ||
936 | { | ||
937 | int err = 0; | ||
938 | int i; | ||
939 | |||
940 | if (cmd == VIDIOC_G_EXT_CTRLS) { | ||
941 | for (i = 0; i < ctrls->count; i++) { | ||
942 | struct v4l2_ext_control *ctrl = ctrls->controls + i; | ||
943 | |||
944 | err = cx2341x_get_ctrl(params, ctrl); | ||
945 | if (err) { | ||
946 | ctrls->error_idx = i; | ||
947 | break; | ||
948 | } | ||
949 | } | ||
950 | return err; | ||
951 | } | ||
952 | for (i = 0; i < ctrls->count; i++) { | ||
953 | struct v4l2_ext_control *ctrl = ctrls->controls + i; | ||
954 | struct v4l2_queryctrl qctrl; | ||
955 | const char * const *menu_items = NULL; | ||
956 | |||
957 | qctrl.id = ctrl->id; | ||
958 | err = cx2341x_ctrl_query(params, &qctrl); | ||
959 | if (err) | ||
960 | break; | ||
961 | if (qctrl.type == V4L2_CTRL_TYPE_MENU) | ||
962 | menu_items = cx2341x_ctrl_get_menu(params, qctrl.id); | ||
963 | err = v4l2_ctrl_check(ctrl, &qctrl, menu_items); | ||
964 | if (err) | ||
965 | break; | ||
966 | err = cx2341x_set_ctrl(params, busy, ctrl); | ||
967 | if (err) | ||
968 | break; | ||
969 | } | ||
970 | if (err == 0 && | ||
971 | params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && | ||
972 | params->video_bitrate_peak < params->video_bitrate) { | ||
973 | err = -ERANGE; | ||
974 | ctrls->error_idx = ctrls->count; | ||
975 | } | ||
976 | if (err) | ||
977 | ctrls->error_idx = i; | ||
978 | else | ||
979 | cx2341x_calc_audio_properties(params); | ||
980 | return err; | ||
981 | } | ||
982 | EXPORT_SYMBOL(cx2341x_ext_ctrls); | ||
983 | |||
984 | void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) | ||
985 | { | ||
986 | *p = default_params; | ||
987 | cx2341x_calc_audio_properties(p); | ||
988 | } | ||
989 | EXPORT_SYMBOL(cx2341x_fill_defaults); | ||
990 | |||
991 | static int cx2341x_api(void *priv, cx2341x_mbox_func func, | ||
992 | u32 cmd, int args, ...) | ||
993 | { | ||
994 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
995 | va_list vargs; | ||
996 | int i; | ||
997 | |||
998 | va_start(vargs, args); | ||
999 | |||
1000 | for (i = 0; i < args; i++) | ||
1001 | data[i] = va_arg(vargs, int); | ||
1002 | va_end(vargs); | ||
1003 | return func(priv, cmd, args, 0, data); | ||
1004 | } | ||
1005 | |||
1006 | #define NEQ(field) (old->field != new->field) | ||
1007 | |||
1008 | int cx2341x_update(void *priv, cx2341x_mbox_func func, | ||
1009 | const struct cx2341x_mpeg_params *old, | ||
1010 | const struct cx2341x_mpeg_params *new) | ||
1011 | { | ||
1012 | static int mpeg_stream_type[] = { | ||
1013 | 0, /* MPEG-2 PS */ | ||
1014 | 1, /* MPEG-2 TS */ | ||
1015 | 2, /* MPEG-1 SS */ | ||
1016 | 14, /* DVD */ | ||
1017 | 11, /* VCD */ | ||
1018 | 12, /* SVCD */ | ||
1019 | }; | ||
1020 | |||
1021 | int err = 0; | ||
1022 | int force = (old == NULL); | ||
1023 | u16 temporal = new->video_temporal_filter; | ||
1024 | |||
1025 | cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0); | ||
1026 | |||
1027 | if (force || NEQ(is_50hz)) { | ||
1028 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, | ||
1029 | new->is_50hz); | ||
1030 | if (err) return err; | ||
1031 | } | ||
1032 | |||
1033 | if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) { | ||
1034 | u16 w = new->width; | ||
1035 | u16 h = new->height; | ||
1036 | |||
1037 | if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) { | ||
1038 | w /= 2; | ||
1039 | h /= 2; | ||
1040 | } | ||
1041 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, | ||
1042 | h, w); | ||
1043 | if (err) return err; | ||
1044 | } | ||
1045 | if (force || NEQ(stream_type)) { | ||
1046 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, | ||
1047 | mpeg_stream_type[new->stream_type]); | ||
1048 | if (err) return err; | ||
1049 | } | ||
1050 | if (force || NEQ(video_aspect)) { | ||
1051 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, | ||
1052 | 1 + new->video_aspect); | ||
1053 | if (err) return err; | ||
1054 | } | ||
1055 | if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) { | ||
1056 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2, | ||
1057 | new->video_gop_size, new->video_b_frames + 1); | ||
1058 | if (err) return err; | ||
1059 | } | ||
1060 | if (force || NEQ(video_gop_closure)) { | ||
1061 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, | ||
1062 | new->video_gop_closure); | ||
1063 | if (err) return err; | ||
1064 | } | ||
1065 | if (force || NEQ(audio_properties)) { | ||
1066 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, | ||
1067 | 1, new->audio_properties); | ||
1068 | if (err) return err; | ||
1069 | } | ||
1070 | if (force || NEQ(audio_mute)) { | ||
1071 | err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, | ||
1072 | new->audio_mute); | ||
1073 | if (err) return err; | ||
1074 | } | ||
1075 | if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) || | ||
1076 | NEQ(video_bitrate_peak)) { | ||
1077 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5, | ||
1078 | new->video_bitrate_mode, new->video_bitrate, | ||
1079 | new->video_bitrate_peak / 400, 0, 0); | ||
1080 | if (err) return err; | ||
1081 | } | ||
1082 | if (force || NEQ(video_spatial_filter_mode) || | ||
1083 | NEQ(video_temporal_filter_mode) || | ||
1084 | NEQ(video_median_filter_type)) { | ||
1085 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, | ||
1086 | 2, new->video_spatial_filter_mode | | ||
1087 | (new->video_temporal_filter_mode << 1), | ||
1088 | new->video_median_filter_type); | ||
1089 | if (err) return err; | ||
1090 | } | ||
1091 | if (force || NEQ(video_luma_median_filter_bottom) || | ||
1092 | NEQ(video_luma_median_filter_top) || | ||
1093 | NEQ(video_chroma_median_filter_bottom) || | ||
1094 | NEQ(video_chroma_median_filter_top)) { | ||
1095 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4, | ||
1096 | new->video_luma_median_filter_bottom, | ||
1097 | new->video_luma_median_filter_top, | ||
1098 | new->video_chroma_median_filter_bottom, | ||
1099 | new->video_chroma_median_filter_top); | ||
1100 | if (err) return err; | ||
1101 | } | ||
1102 | if (force || NEQ(video_luma_spatial_filter_type) || | ||
1103 | NEQ(video_chroma_spatial_filter_type)) { | ||
1104 | err = cx2341x_api(priv, func, | ||
1105 | CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, | ||
1106 | 2, new->video_luma_spatial_filter_type, | ||
1107 | new->video_chroma_spatial_filter_type); | ||
1108 | if (err) return err; | ||
1109 | } | ||
1110 | if (force || NEQ(video_spatial_filter) || | ||
1111 | old->video_temporal_filter != temporal) { | ||
1112 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, | ||
1113 | 2, new->video_spatial_filter, temporal); | ||
1114 | if (err) return err; | ||
1115 | } | ||
1116 | if (force || NEQ(video_temporal_decimation)) { | ||
1117 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, | ||
1118 | 1, new->video_temporal_decimation); | ||
1119 | if (err) return err; | ||
1120 | } | ||
1121 | if (force || NEQ(video_mute) || | ||
1122 | (new->video_mute && NEQ(video_mute_yuv))) { | ||
1123 | err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, | ||
1124 | new->video_mute | (new->video_mute_yuv << 8)); | ||
1125 | if (err) return err; | ||
1126 | } | ||
1127 | if (force || NEQ(stream_insert_nav_packets)) { | ||
1128 | err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, | ||
1129 | 7, new->stream_insert_nav_packets); | ||
1130 | if (err) return err; | ||
1131 | } | ||
1132 | return 0; | ||
1133 | } | ||
1134 | EXPORT_SYMBOL(cx2341x_update); | ||
1135 | |||
1136 | static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id) | ||
1137 | { | ||
1138 | const char * const *menu = cx2341x_ctrl_get_menu(p, id); | ||
1139 | struct v4l2_ext_control ctrl; | ||
1140 | |||
1141 | if (menu == NULL) | ||
1142 | goto invalid; | ||
1143 | ctrl.id = id; | ||
1144 | if (cx2341x_get_ctrl(p, &ctrl)) | ||
1145 | goto invalid; | ||
1146 | while (ctrl.value-- && *menu) menu++; | ||
1147 | if (*menu == NULL) | ||
1148 | goto invalid; | ||
1149 | return *menu; | ||
1150 | |||
1151 | invalid: | ||
1152 | return "<invalid>"; | ||
1153 | } | ||
1154 | |||
1155 | void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) | ||
1156 | { | ||
1157 | int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; | ||
1158 | |||
1159 | /* Stream */ | ||
1160 | printk(KERN_INFO "%s: Stream: %s", | ||
1161 | prefix, | ||
1162 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); | ||
1163 | if (p->stream_insert_nav_packets) | ||
1164 | printk(" (with navigation packets)"); | ||
1165 | printk("\n"); | ||
1166 | printk(KERN_INFO "%s: VBI Format: %s\n", | ||
1167 | prefix, | ||
1168 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT)); | ||
1169 | |||
1170 | /* Video */ | ||
1171 | printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n", | ||
1172 | prefix, | ||
1173 | p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1), | ||
1174 | p->is_50hz ? 25 : 30, | ||
1175 | (p->video_mute) ? " (muted)" : ""); | ||
1176 | printk(KERN_INFO "%s: Video: %s, %s, %s, %d", | ||
1177 | prefix, | ||
1178 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING), | ||
1179 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT), | ||
1180 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE), | ||
1181 | p->video_bitrate); | ||
1182 | if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | ||
1183 | printk(", Peak %d", p->video_bitrate_peak); | ||
1184 | printk("\n"); | ||
1185 | printk(KERN_INFO | ||
1186 | "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n", | ||
1187 | prefix, | ||
1188 | p->video_gop_size, p->video_b_frames, | ||
1189 | p->video_gop_closure ? "" : "No "); | ||
1190 | if (p->video_temporal_decimation) | ||
1191 | printk(KERN_INFO "%s: Video: Temporal Decimation %d\n", | ||
1192 | prefix, p->video_temporal_decimation); | ||
1193 | |||
1194 | /* Audio */ | ||
1195 | printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s", | ||
1196 | prefix, | ||
1197 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), | ||
1198 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), | ||
1199 | cx2341x_menu_item(p, | ||
1200 | p->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3 | ||
1201 | ? V4L2_CID_MPEG_AUDIO_AC3_BITRATE | ||
1202 | : V4L2_CID_MPEG_AUDIO_L2_BITRATE), | ||
1203 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), | ||
1204 | p->audio_mute ? " (muted)" : ""); | ||
1205 | if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) | ||
1206 | printk(", %s", cx2341x_menu_item(p, | ||
1207 | V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); | ||
1208 | printk(", %s, %s\n", | ||
1209 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS), | ||
1210 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC)); | ||
1211 | |||
1212 | /* Encoding filters */ | ||
1213 | printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n", | ||
1214 | prefix, | ||
1215 | cx2341x_menu_item(p, | ||
1216 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), | ||
1217 | cx2341x_menu_item(p, | ||
1218 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), | ||
1219 | cx2341x_menu_item(p, | ||
1220 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), | ||
1221 | p->video_spatial_filter); | ||
1222 | |||
1223 | printk(KERN_INFO "%s: Temporal Filter: %s, %d\n", | ||
1224 | prefix, | ||
1225 | cx2341x_menu_item(p, | ||
1226 | V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), | ||
1227 | p->video_temporal_filter); | ||
1228 | printk(KERN_INFO | ||
1229 | "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", | ||
1230 | prefix, | ||
1231 | cx2341x_menu_item(p, | ||
1232 | V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), | ||
1233 | p->video_luma_median_filter_bottom, | ||
1234 | p->video_luma_median_filter_top, | ||
1235 | p->video_chroma_median_filter_bottom, | ||
1236 | p->video_chroma_median_filter_top); | ||
1237 | } | ||
1238 | EXPORT_SYMBOL(cx2341x_log_status); | ||
1239 | |||
1240 | |||
1241 | |||
1242 | /********************** NEW CODE *********************/ | ||
1243 | |||
1244 | static inline struct cx2341x_handler *to_cxhdl(struct v4l2_ctrl *ctrl) | ||
1245 | { | ||
1246 | return container_of(ctrl->handler, struct cx2341x_handler, hdl); | ||
1247 | } | ||
1248 | |||
1249 | static int cx2341x_hdl_api(struct cx2341x_handler *hdl, | ||
1250 | u32 cmd, int args, ...) | ||
1251 | { | ||
1252 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
1253 | va_list vargs; | ||
1254 | int i; | ||
1255 | |||
1256 | va_start(vargs, args); | ||
1257 | |||
1258 | for (i = 0; i < args; i++) | ||
1259 | data[i] = va_arg(vargs, int); | ||
1260 | va_end(vargs); | ||
1261 | return hdl->func(hdl->priv, cmd, args, 0, data); | ||
1262 | } | ||
1263 | |||
1264 | /* ctrl->handler->lock is held, so it is safe to access cur.val */ | ||
1265 | static inline int cx2341x_neq(struct v4l2_ctrl *ctrl) | ||
1266 | { | ||
1267 | return ctrl && ctrl->val != ctrl->cur.val; | ||
1268 | } | ||
1269 | |||
1270 | static int cx2341x_try_ctrl(struct v4l2_ctrl *ctrl) | ||
1271 | { | ||
1272 | struct cx2341x_handler *hdl = to_cxhdl(ctrl); | ||
1273 | s32 val = ctrl->val; | ||
1274 | |||
1275 | switch (ctrl->id) { | ||
1276 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: { | ||
1277 | /* video gop cluster */ | ||
1278 | int b = val + 1; | ||
1279 | int gop = hdl->video_gop_size->val; | ||
1280 | |||
1281 | gop = b * ((gop + b - 1) / b); | ||
1282 | |||
1283 | /* Max GOP size = 34 */ | ||
1284 | while (gop > 34) | ||
1285 | gop -= b; | ||
1286 | hdl->video_gop_size->val = gop; | ||
1287 | break; | ||
1288 | } | ||
1289 | |||
1290 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
1291 | /* stream type cluster */ | ||
1292 | hdl->video_encoding->val = | ||
1293 | (hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || | ||
1294 | hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? | ||
1295 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : | ||
1296 | V4L2_MPEG_VIDEO_ENCODING_MPEG_2; | ||
1297 | if (hdl->video_encoding->val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) | ||
1298 | /* MPEG-1 implies CBR */ | ||
1299 | hdl->video_bitrate_mode->val = | ||
1300 | V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; | ||
1301 | /* peak bitrate shall be >= normal bitrate */ | ||
1302 | if (hdl->video_bitrate_mode->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && | ||
1303 | hdl->video_bitrate_peak->val < hdl->video_bitrate->val) | ||
1304 | hdl->video_bitrate_peak->val = hdl->video_bitrate->val; | ||
1305 | break; | ||
1306 | } | ||
1307 | return 0; | ||
1308 | } | ||
1309 | |||
1310 | static int cx2341x_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1311 | { | ||
1312 | static const int mpeg_stream_type[] = { | ||
1313 | 0, /* MPEG-2 PS */ | ||
1314 | 1, /* MPEG-2 TS */ | ||
1315 | 2, /* MPEG-1 SS */ | ||
1316 | 14, /* DVD */ | ||
1317 | 11, /* VCD */ | ||
1318 | 12, /* SVCD */ | ||
1319 | }; | ||
1320 | struct cx2341x_handler *hdl = to_cxhdl(ctrl); | ||
1321 | s32 val = ctrl->val; | ||
1322 | u32 props; | ||
1323 | int err; | ||
1324 | |||
1325 | switch (ctrl->id) { | ||
1326 | case V4L2_CID_MPEG_STREAM_VBI_FMT: | ||
1327 | if (hdl->ops && hdl->ops->s_stream_vbi_fmt) | ||
1328 | return hdl->ops->s_stream_vbi_fmt(hdl, val); | ||
1329 | return 0; | ||
1330 | |||
1331 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
1332 | return cx2341x_hdl_api(hdl, | ||
1333 | CX2341X_ENC_SET_ASPECT_RATIO, 1, val + 1); | ||
1334 | |||
1335 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: | ||
1336 | return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_CLOSURE, 1, val); | ||
1337 | |||
1338 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
1339 | return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_AUDIO, 1, val); | ||
1340 | |||
1341 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: | ||
1342 | return cx2341x_hdl_api(hdl, | ||
1343 | CX2341X_ENC_SET_FRAME_DROP_RATE, 1, val); | ||
1344 | |||
1345 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
1346 | return cx2341x_hdl_api(hdl, CX2341X_ENC_MISC, 2, 7, val); | ||
1347 | |||
1348 | case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: | ||
1349 | /* audio properties cluster */ | ||
1350 | props = (hdl->audio_sampling_freq->val << 0) | | ||
1351 | (hdl->audio_mode->val << 8) | | ||
1352 | (hdl->audio_mode_extension->val << 10) | | ||
1353 | (hdl->audio_crc->val << 14); | ||
1354 | if (hdl->audio_emphasis->val == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) | ||
1355 | props |= 3 << 12; | ||
1356 | else | ||
1357 | props |= hdl->audio_emphasis->val << 12; | ||
1358 | |||
1359 | if (hdl->audio_encoding->val == V4L2_MPEG_AUDIO_ENCODING_AC3) { | ||
1360 | props |= | ||
1361 | #if 1 | ||
1362 | /* Not sure if this MPEG Layer II setting is required */ | ||
1363 | ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) | | ||
1364 | #endif | ||
1365 | (hdl->audio_ac3_bitrate->val << 4) | | ||
1366 | (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28); | ||
1367 | } else { | ||
1368 | /* Assuming MPEG Layer II */ | ||
1369 | props |= | ||
1370 | ((3 - hdl->audio_encoding->val) << 2) | | ||
1371 | ((1 + hdl->audio_l2_bitrate->val) << 4); | ||
1372 | } | ||
1373 | err = cx2341x_hdl_api(hdl, | ||
1374 | CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, props); | ||
1375 | if (err) | ||
1376 | return err; | ||
1377 | |||
1378 | hdl->audio_properties = props; | ||
1379 | if (hdl->audio_ac3_bitrate) { | ||
1380 | int is_ac3 = hdl->audio_encoding->val == | ||
1381 | V4L2_MPEG_AUDIO_ENCODING_AC3; | ||
1382 | |||
1383 | v4l2_ctrl_activate(hdl->audio_ac3_bitrate, is_ac3); | ||
1384 | v4l2_ctrl_activate(hdl->audio_l2_bitrate, !is_ac3); | ||
1385 | } | ||
1386 | v4l2_ctrl_activate(hdl->audio_mode_extension, | ||
1387 | hdl->audio_mode->val == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO); | ||
1388 | if (cx2341x_neq(hdl->audio_sampling_freq) && | ||
1389 | hdl->ops && hdl->ops->s_audio_sampling_freq) | ||
1390 | return hdl->ops->s_audio_sampling_freq(hdl, hdl->audio_sampling_freq->val); | ||
1391 | if (cx2341x_neq(hdl->audio_mode) && | ||
1392 | hdl->ops && hdl->ops->s_audio_mode) | ||
1393 | return hdl->ops->s_audio_mode(hdl, hdl->audio_mode->val); | ||
1394 | return 0; | ||
1395 | |||
1396 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
1397 | /* video gop cluster */ | ||
1398 | return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_PROPERTIES, 2, | ||
1399 | hdl->video_gop_size->val, | ||
1400 | hdl->video_b_frames->val + 1); | ||
1401 | |||
1402 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
1403 | /* stream type cluster */ | ||
1404 | err = cx2341x_hdl_api(hdl, | ||
1405 | CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[val]); | ||
1406 | if (err) | ||
1407 | return err; | ||
1408 | |||
1409 | err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_BIT_RATE, 5, | ||
1410 | hdl->video_bitrate_mode->val, | ||
1411 | hdl->video_bitrate->val, | ||
1412 | hdl->video_bitrate_peak->val / 400, 0, 0); | ||
1413 | if (err) | ||
1414 | return err; | ||
1415 | |||
1416 | v4l2_ctrl_activate(hdl->video_bitrate_mode, | ||
1417 | hdl->video_encoding->val != V4L2_MPEG_VIDEO_ENCODING_MPEG_1); | ||
1418 | v4l2_ctrl_activate(hdl->video_bitrate_peak, | ||
1419 | hdl->video_bitrate_mode->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); | ||
1420 | if (cx2341x_neq(hdl->video_encoding) && | ||
1421 | hdl->ops && hdl->ops->s_video_encoding) | ||
1422 | return hdl->ops->s_video_encoding(hdl, hdl->video_encoding->val); | ||
1423 | return 0; | ||
1424 | |||
1425 | case V4L2_CID_MPEG_VIDEO_MUTE: | ||
1426 | /* video mute cluster */ | ||
1427 | return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_VIDEO, 1, | ||
1428 | hdl->video_mute->val | | ||
1429 | (hdl->video_mute_yuv->val << 8)); | ||
1430 | |||
1431 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: { | ||
1432 | int active_filter; | ||
1433 | |||
1434 | /* video filter mode */ | ||
1435 | err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_MODE, 2, | ||
1436 | hdl->video_spatial_filter_mode->val | | ||
1437 | (hdl->video_temporal_filter_mode->val << 1), | ||
1438 | hdl->video_median_filter_type->val); | ||
1439 | if (err) | ||
1440 | return err; | ||
1441 | |||
1442 | active_filter = hdl->video_spatial_filter_mode->val != | ||
1443 | V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO; | ||
1444 | v4l2_ctrl_activate(hdl->video_spatial_filter, active_filter); | ||
1445 | v4l2_ctrl_activate(hdl->video_luma_spatial_filter_type, active_filter); | ||
1446 | v4l2_ctrl_activate(hdl->video_chroma_spatial_filter_type, active_filter); | ||
1447 | active_filter = hdl->video_temporal_filter_mode->val != | ||
1448 | V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO; | ||
1449 | v4l2_ctrl_activate(hdl->video_temporal_filter, active_filter); | ||
1450 | active_filter = hdl->video_median_filter_type->val != | ||
1451 | V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF; | ||
1452 | v4l2_ctrl_activate(hdl->video_luma_median_filter_bottom, active_filter); | ||
1453 | v4l2_ctrl_activate(hdl->video_luma_median_filter_top, active_filter); | ||
1454 | v4l2_ctrl_activate(hdl->video_chroma_median_filter_bottom, active_filter); | ||
1455 | v4l2_ctrl_activate(hdl->video_chroma_median_filter_top, active_filter); | ||
1456 | return 0; | ||
1457 | } | ||
1458 | |||
1459 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: | ||
1460 | /* video filter type cluster */ | ||
1461 | return cx2341x_hdl_api(hdl, | ||
1462 | CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2, | ||
1463 | hdl->video_luma_spatial_filter_type->val, | ||
1464 | hdl->video_chroma_spatial_filter_type->val); | ||
1465 | |||
1466 | case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: | ||
1467 | /* video filter cluster */ | ||
1468 | return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2, | ||
1469 | hdl->video_spatial_filter->val, | ||
1470 | hdl->video_temporal_filter->val); | ||
1471 | |||
1472 | case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: | ||
1473 | /* video median cluster */ | ||
1474 | return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_CORING_LEVELS, 4, | ||
1475 | hdl->video_luma_median_filter_bottom->val, | ||
1476 | hdl->video_luma_median_filter_top->val, | ||
1477 | hdl->video_chroma_median_filter_bottom->val, | ||
1478 | hdl->video_chroma_median_filter_top->val); | ||
1479 | } | ||
1480 | return -EINVAL; | ||
1481 | } | ||
1482 | |||
1483 | static const struct v4l2_ctrl_ops cx2341x_ops = { | ||
1484 | .try_ctrl = cx2341x_try_ctrl, | ||
1485 | .s_ctrl = cx2341x_s_ctrl, | ||
1486 | }; | ||
1487 | |||
1488 | static struct v4l2_ctrl *cx2341x_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, | ||
1489 | u32 id, s32 min, s32 max, s32 step, s32 def) | ||
1490 | { | ||
1491 | struct v4l2_ctrl_config cfg; | ||
1492 | |||
1493 | cx2341x_ctrl_fill(id, &cfg.name, &cfg.type, &min, &max, &step, &def, &cfg.flags); | ||
1494 | cfg.ops = &cx2341x_ops; | ||
1495 | cfg.id = id; | ||
1496 | cfg.min = min; | ||
1497 | cfg.max = max; | ||
1498 | cfg.def = def; | ||
1499 | if (cfg.type == V4L2_CTRL_TYPE_MENU) { | ||
1500 | cfg.step = 0; | ||
1501 | cfg.menu_skip_mask = step; | ||
1502 | cfg.qmenu = cx2341x_get_menu(id); | ||
1503 | } else { | ||
1504 | cfg.step = step; | ||
1505 | cfg.menu_skip_mask = 0; | ||
1506 | } | ||
1507 | return v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
1508 | } | ||
1509 | |||
1510 | static struct v4l2_ctrl *cx2341x_ctrl_new_std(struct v4l2_ctrl_handler *hdl, | ||
1511 | u32 id, s32 min, s32 max, s32 step, s32 def) | ||
1512 | { | ||
1513 | return v4l2_ctrl_new_std(hdl, &cx2341x_ops, id, min, max, step, def); | ||
1514 | } | ||
1515 | |||
1516 | static struct v4l2_ctrl *cx2341x_ctrl_new_menu(struct v4l2_ctrl_handler *hdl, | ||
1517 | u32 id, s32 max, s32 mask, s32 def) | ||
1518 | { | ||
1519 | return v4l2_ctrl_new_std_menu(hdl, &cx2341x_ops, id, max, mask, def); | ||
1520 | } | ||
1521 | |||
1522 | int cx2341x_handler_init(struct cx2341x_handler *cxhdl, | ||
1523 | unsigned nr_of_controls_hint) | ||
1524 | { | ||
1525 | struct v4l2_ctrl_handler *hdl = &cxhdl->hdl; | ||
1526 | u32 caps = cxhdl->capabilities; | ||
1527 | int has_sliced_vbi = caps & CX2341X_CAP_HAS_SLICED_VBI; | ||
1528 | int has_ac3 = caps & CX2341X_CAP_HAS_AC3; | ||
1529 | int has_ts = caps & CX2341X_CAP_HAS_TS; | ||
1530 | |||
1531 | cxhdl->width = 720; | ||
1532 | cxhdl->height = 480; | ||
1533 | |||
1534 | v4l2_ctrl_handler_init(hdl, nr_of_controls_hint); | ||
1535 | |||
1536 | /* Add controls in ascending control ID order for fastest | ||
1537 | insertion time. */ | ||
1538 | cxhdl->stream_type = cx2341x_ctrl_new_menu(hdl, | ||
1539 | V4L2_CID_MPEG_STREAM_TYPE, | ||
1540 | V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, has_ts ? 0 : 2, | ||
1541 | V4L2_MPEG_STREAM_TYPE_MPEG2_PS); | ||
1542 | cxhdl->stream_vbi_fmt = cx2341x_ctrl_new_menu(hdl, | ||
1543 | V4L2_CID_MPEG_STREAM_VBI_FMT, | ||
1544 | V4L2_MPEG_STREAM_VBI_FMT_IVTV, has_sliced_vbi ? 0 : 2, | ||
1545 | V4L2_MPEG_STREAM_VBI_FMT_NONE); | ||
1546 | cxhdl->audio_sampling_freq = cx2341x_ctrl_new_menu(hdl, | ||
1547 | V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, | ||
1548 | V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 0, | ||
1549 | V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000); | ||
1550 | cxhdl->audio_encoding = cx2341x_ctrl_new_menu(hdl, | ||
1551 | V4L2_CID_MPEG_AUDIO_ENCODING, | ||
1552 | V4L2_MPEG_AUDIO_ENCODING_AC3, has_ac3 ? ~0x12 : ~0x2, | ||
1553 | V4L2_MPEG_AUDIO_ENCODING_LAYER_2); | ||
1554 | cxhdl->audio_l2_bitrate = cx2341x_ctrl_new_menu(hdl, | ||
1555 | V4L2_CID_MPEG_AUDIO_L2_BITRATE, | ||
1556 | V4L2_MPEG_AUDIO_L2_BITRATE_384K, 0x1ff, | ||
1557 | V4L2_MPEG_AUDIO_L2_BITRATE_224K); | ||
1558 | cxhdl->audio_mode = cx2341x_ctrl_new_menu(hdl, | ||
1559 | V4L2_CID_MPEG_AUDIO_MODE, | ||
1560 | V4L2_MPEG_AUDIO_MODE_MONO, 0, | ||
1561 | V4L2_MPEG_AUDIO_MODE_STEREO); | ||
1562 | cxhdl->audio_mode_extension = cx2341x_ctrl_new_menu(hdl, | ||
1563 | V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, | ||
1564 | V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 0, | ||
1565 | V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4); | ||
1566 | cxhdl->audio_emphasis = cx2341x_ctrl_new_menu(hdl, | ||
1567 | V4L2_CID_MPEG_AUDIO_EMPHASIS, | ||
1568 | V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 0, | ||
1569 | V4L2_MPEG_AUDIO_EMPHASIS_NONE); | ||
1570 | cxhdl->audio_crc = cx2341x_ctrl_new_menu(hdl, | ||
1571 | V4L2_CID_MPEG_AUDIO_CRC, | ||
1572 | V4L2_MPEG_AUDIO_CRC_CRC16, 0, | ||
1573 | V4L2_MPEG_AUDIO_CRC_NONE); | ||
1574 | |||
1575 | cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_AUDIO_MUTE, 0, 1, 1, 0); | ||
1576 | if (has_ac3) | ||
1577 | cxhdl->audio_ac3_bitrate = cx2341x_ctrl_new_menu(hdl, | ||
1578 | V4L2_CID_MPEG_AUDIO_AC3_BITRATE, | ||
1579 | V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 0x03, | ||
1580 | V4L2_MPEG_AUDIO_AC3_BITRATE_224K); | ||
1581 | cxhdl->video_encoding = cx2341x_ctrl_new_menu(hdl, | ||
1582 | V4L2_CID_MPEG_VIDEO_ENCODING, | ||
1583 | V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 0, | ||
1584 | V4L2_MPEG_VIDEO_ENCODING_MPEG_2); | ||
1585 | cx2341x_ctrl_new_menu(hdl, | ||
1586 | V4L2_CID_MPEG_VIDEO_ASPECT, | ||
1587 | V4L2_MPEG_VIDEO_ASPECT_221x100, 0, | ||
1588 | V4L2_MPEG_VIDEO_ASPECT_4x3); | ||
1589 | cxhdl->video_b_frames = cx2341x_ctrl_new_std(hdl, | ||
1590 | V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 33, 1, 2); | ||
1591 | cxhdl->video_gop_size = cx2341x_ctrl_new_std(hdl, | ||
1592 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, | ||
1593 | 1, 34, 1, cxhdl->is_50hz ? 12 : 15); | ||
1594 | cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1); | ||
1595 | cxhdl->video_bitrate_mode = cx2341x_ctrl_new_menu(hdl, | ||
1596 | V4L2_CID_MPEG_VIDEO_BITRATE_MODE, | ||
1597 | V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, | ||
1598 | V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); | ||
1599 | cxhdl->video_bitrate = cx2341x_ctrl_new_std(hdl, | ||
1600 | V4L2_CID_MPEG_VIDEO_BITRATE, | ||
1601 | 0, 27000000, 1, 6000000); | ||
1602 | cxhdl->video_bitrate_peak = cx2341x_ctrl_new_std(hdl, | ||
1603 | V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, | ||
1604 | 0, 27000000, 1, 8000000); | ||
1605 | cx2341x_ctrl_new_std(hdl, | ||
1606 | V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, 0, 255, 1, 0); | ||
1607 | cxhdl->video_mute = cx2341x_ctrl_new_std(hdl, | ||
1608 | V4L2_CID_MPEG_VIDEO_MUTE, 0, 1, 1, 0); | ||
1609 | cxhdl->video_mute_yuv = cx2341x_ctrl_new_std(hdl, | ||
1610 | V4L2_CID_MPEG_VIDEO_MUTE_YUV, 0, 0xffffff, 1, 0x008080); | ||
1611 | |||
1612 | /* CX23415/6 specific */ | ||
1613 | cxhdl->video_spatial_filter_mode = cx2341x_ctrl_new_custom(hdl, | ||
1614 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, | ||
1615 | V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, | ||
1616 | V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 0, | ||
1617 | V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL); | ||
1618 | cxhdl->video_spatial_filter = cx2341x_ctrl_new_custom(hdl, | ||
1619 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, | ||
1620 | 0, 15, 1, 0); | ||
1621 | cxhdl->video_luma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl, | ||
1622 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, | ||
1623 | V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, | ||
1624 | V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, | ||
1625 | 0, | ||
1626 | V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR); | ||
1627 | cxhdl->video_chroma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl, | ||
1628 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, | ||
1629 | V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, | ||
1630 | V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, | ||
1631 | 0, | ||
1632 | V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR); | ||
1633 | cxhdl->video_temporal_filter_mode = cx2341x_ctrl_new_custom(hdl, | ||
1634 | V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, | ||
1635 | V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, | ||
1636 | V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, | ||
1637 | 0, | ||
1638 | V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL); | ||
1639 | cxhdl->video_temporal_filter = cx2341x_ctrl_new_custom(hdl, | ||
1640 | V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, | ||
1641 | 0, 31, 1, 8); | ||
1642 | cxhdl->video_median_filter_type = cx2341x_ctrl_new_custom(hdl, | ||
1643 | V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, | ||
1644 | V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, | ||
1645 | V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, | ||
1646 | 0, | ||
1647 | V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF); | ||
1648 | cxhdl->video_luma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl, | ||
1649 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, | ||
1650 | 0, 255, 1, 0); | ||
1651 | cxhdl->video_luma_median_filter_top = cx2341x_ctrl_new_custom(hdl, | ||
1652 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, | ||
1653 | 0, 255, 1, 255); | ||
1654 | cxhdl->video_chroma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl, | ||
1655 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, | ||
1656 | 0, 255, 1, 0); | ||
1657 | cxhdl->video_chroma_median_filter_top = cx2341x_ctrl_new_custom(hdl, | ||
1658 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, | ||
1659 | 0, 255, 1, 255); | ||
1660 | cx2341x_ctrl_new_custom(hdl, V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, | ||
1661 | 0, 1, 1, 0); | ||
1662 | |||
1663 | if (hdl->error) { | ||
1664 | int err = hdl->error; | ||
1665 | |||
1666 | v4l2_ctrl_handler_free(hdl); | ||
1667 | return err; | ||
1668 | } | ||
1669 | |||
1670 | v4l2_ctrl_cluster(8, &cxhdl->audio_sampling_freq); | ||
1671 | v4l2_ctrl_cluster(2, &cxhdl->video_b_frames); | ||
1672 | v4l2_ctrl_cluster(5, &cxhdl->stream_type); | ||
1673 | v4l2_ctrl_cluster(2, &cxhdl->video_mute); | ||
1674 | v4l2_ctrl_cluster(3, &cxhdl->video_spatial_filter_mode); | ||
1675 | v4l2_ctrl_cluster(2, &cxhdl->video_luma_spatial_filter_type); | ||
1676 | v4l2_ctrl_cluster(2, &cxhdl->video_spatial_filter); | ||
1677 | v4l2_ctrl_cluster(4, &cxhdl->video_luma_median_filter_top); | ||
1678 | |||
1679 | return 0; | ||
1680 | } | ||
1681 | EXPORT_SYMBOL(cx2341x_handler_init); | ||
1682 | |||
1683 | void cx2341x_handler_set_50hz(struct cx2341x_handler *cxhdl, int is_50hz) | ||
1684 | { | ||
1685 | cxhdl->is_50hz = is_50hz; | ||
1686 | cxhdl->video_gop_size->default_value = cxhdl->is_50hz ? 12 : 15; | ||
1687 | } | ||
1688 | EXPORT_SYMBOL(cx2341x_handler_set_50hz); | ||
1689 | |||
1690 | int cx2341x_handler_setup(struct cx2341x_handler *cxhdl) | ||
1691 | { | ||
1692 | int h = cxhdl->height; | ||
1693 | int w = cxhdl->width; | ||
1694 | int err; | ||
1695 | |||
1696 | err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_OUTPUT_PORT, 2, cxhdl->port, 0); | ||
1697 | if (err) | ||
1698 | return err; | ||
1699 | err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_RATE, 1, cxhdl->is_50hz); | ||
1700 | if (err) | ||
1701 | return err; | ||
1702 | |||
1703 | if (v4l2_ctrl_g_ctrl(cxhdl->video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) { | ||
1704 | w /= 2; | ||
1705 | h /= 2; | ||
1706 | } | ||
1707 | err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w); | ||
1708 | if (err) | ||
1709 | return err; | ||
1710 | return v4l2_ctrl_handler_setup(&cxhdl->hdl); | ||
1711 | } | ||
1712 | EXPORT_SYMBOL(cx2341x_handler_setup); | ||
1713 | |||
1714 | void cx2341x_handler_set_busy(struct cx2341x_handler *cxhdl, int busy) | ||
1715 | { | ||
1716 | v4l2_ctrl_grab(cxhdl->audio_sampling_freq, busy); | ||
1717 | v4l2_ctrl_grab(cxhdl->audio_encoding, busy); | ||
1718 | v4l2_ctrl_grab(cxhdl->audio_l2_bitrate, busy); | ||
1719 | v4l2_ctrl_grab(cxhdl->audio_ac3_bitrate, busy); | ||
1720 | v4l2_ctrl_grab(cxhdl->stream_vbi_fmt, busy); | ||
1721 | v4l2_ctrl_grab(cxhdl->stream_type, busy); | ||
1722 | v4l2_ctrl_grab(cxhdl->video_bitrate_mode, busy); | ||
1723 | v4l2_ctrl_grab(cxhdl->video_bitrate, busy); | ||
1724 | v4l2_ctrl_grab(cxhdl->video_bitrate_peak, busy); | ||
1725 | } | ||
1726 | EXPORT_SYMBOL(cx2341x_handler_set_busy); | ||
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c index 38ce76ed1924..9ae977b5983a 100644 --- a/drivers/media/i2c/cx25840/cx25840-ir.c +++ b/drivers/media/i2c/cx25840/cx25840-ir.c | |||
@@ -1251,13 +1251,11 @@ int cx25840_ir_probe(struct v4l2_subdev *sd) | |||
1251 | cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, 0); | 1251 | cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, 0); |
1252 | 1252 | ||
1253 | mutex_init(&ir_state->rx_params_lock); | 1253 | mutex_init(&ir_state->rx_params_lock); |
1254 | memcpy(&default_params, &default_rx_params, | 1254 | default_params = default_rx_params; |
1255 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1256 | v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params); | 1255 | v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params); |
1257 | 1256 | ||
1258 | mutex_init(&ir_state->tx_params_lock); | 1257 | mutex_init(&ir_state->tx_params_lock); |
1259 | memcpy(&default_params, &default_tx_params, | 1258 | default_params = default_tx_params; |
1260 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1261 | v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); | 1259 | v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); |
1262 | 1260 | ||
1263 | return 0; | 1261 | return 0; |
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 6bf01ad62765..73b7688cbebd 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <asm/div64.h> | 13 | #include <asm/div64.h> |
14 | #include <media/v4l2-device.h> | 14 | #include <media/v4l2-device.h> |
15 | #include <media/v4l2-chip-ident.h> | 15 | #include <media/v4l2-chip-ident.h> |
16 | #include <media/v4l2-ctrls.h> | ||
16 | #include <media/mt9v011.h> | 17 | #include <media/mt9v011.h> |
17 | 18 | ||
18 | MODULE_DESCRIPTION("Micron mt9v011 sensor driver"); | 19 | MODULE_DESCRIPTION("Micron mt9v011 sensor driver"); |
@@ -48,68 +49,9 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); | |||
48 | #define MT9V011_VERSION 0x8232 | 49 | #define MT9V011_VERSION 0x8232 |
49 | #define MT9V011_REV_B_VERSION 0x8243 | 50 | #define MT9V011_REV_B_VERSION 0x8243 |
50 | 51 | ||
51 | /* supported controls */ | ||
52 | static struct v4l2_queryctrl mt9v011_qctrl[] = { | ||
53 | { | ||
54 | .id = V4L2_CID_GAIN, | ||
55 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
56 | .name = "Gain", | ||
57 | .minimum = 0, | ||
58 | .maximum = (1 << 12) - 1 - 0x0020, | ||
59 | .step = 1, | ||
60 | .default_value = 0x0020, | ||
61 | .flags = 0, | ||
62 | }, { | ||
63 | .id = V4L2_CID_EXPOSURE, | ||
64 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
65 | .name = "Exposure", | ||
66 | .minimum = 0, | ||
67 | .maximum = 2047, | ||
68 | .step = 1, | ||
69 | .default_value = 0x01fc, | ||
70 | .flags = 0, | ||
71 | }, { | ||
72 | .id = V4L2_CID_RED_BALANCE, | ||
73 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
74 | .name = "Red Balance", | ||
75 | .minimum = -1 << 9, | ||
76 | .maximum = (1 << 9) - 1, | ||
77 | .step = 1, | ||
78 | .default_value = 0, | ||
79 | .flags = 0, | ||
80 | }, { | ||
81 | .id = V4L2_CID_BLUE_BALANCE, | ||
82 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
83 | .name = "Blue Balance", | ||
84 | .minimum = -1 << 9, | ||
85 | .maximum = (1 << 9) - 1, | ||
86 | .step = 1, | ||
87 | .default_value = 0, | ||
88 | .flags = 0, | ||
89 | }, { | ||
90 | .id = V4L2_CID_HFLIP, | ||
91 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
92 | .name = "Mirror", | ||
93 | .minimum = 0, | ||
94 | .maximum = 1, | ||
95 | .step = 1, | ||
96 | .default_value = 0, | ||
97 | .flags = 0, | ||
98 | }, { | ||
99 | .id = V4L2_CID_VFLIP, | ||
100 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
101 | .name = "Vflip", | ||
102 | .minimum = 0, | ||
103 | .maximum = 1, | ||
104 | .step = 1, | ||
105 | .default_value = 0, | ||
106 | .flags = 0, | ||
107 | }, { | ||
108 | } | ||
109 | }; | ||
110 | |||
111 | struct mt9v011 { | 52 | struct mt9v011 { |
112 | struct v4l2_subdev sd; | 53 | struct v4l2_subdev sd; |
54 | struct v4l2_ctrl_handler ctrls; | ||
113 | unsigned width, height; | 55 | unsigned width, height; |
114 | unsigned xtal; | 56 | unsigned xtal; |
115 | unsigned hflip:1; | 57 | unsigned hflip:1; |
@@ -381,99 +323,6 @@ static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) | |||
381 | set_read_mode(sd); | 323 | set_read_mode(sd); |
382 | 324 | ||
383 | return 0; | 325 | return 0; |
384 | }; | ||
385 | |||
386 | static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
387 | { | ||
388 | struct mt9v011 *core = to_mt9v011(sd); | ||
389 | |||
390 | v4l2_dbg(1, debug, sd, "g_ctrl called\n"); | ||
391 | |||
392 | switch (ctrl->id) { | ||
393 | case V4L2_CID_GAIN: | ||
394 | ctrl->value = core->global_gain; | ||
395 | return 0; | ||
396 | case V4L2_CID_EXPOSURE: | ||
397 | ctrl->value = core->exposure; | ||
398 | return 0; | ||
399 | case V4L2_CID_RED_BALANCE: | ||
400 | ctrl->value = core->red_bal; | ||
401 | return 0; | ||
402 | case V4L2_CID_BLUE_BALANCE: | ||
403 | ctrl->value = core->blue_bal; | ||
404 | return 0; | ||
405 | case V4L2_CID_HFLIP: | ||
406 | ctrl->value = core->hflip ? 1 : 0; | ||
407 | return 0; | ||
408 | case V4L2_CID_VFLIP: | ||
409 | ctrl->value = core->vflip ? 1 : 0; | ||
410 | return 0; | ||
411 | } | ||
412 | return -EINVAL; | ||
413 | } | ||
414 | |||
415 | static int mt9v011_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | ||
416 | { | ||
417 | int i; | ||
418 | |||
419 | v4l2_dbg(1, debug, sd, "queryctrl called\n"); | ||
420 | |||
421 | for (i = 0; i < ARRAY_SIZE(mt9v011_qctrl); i++) | ||
422 | if (qc->id && qc->id == mt9v011_qctrl[i].id) { | ||
423 | memcpy(qc, &(mt9v011_qctrl[i]), | ||
424 | sizeof(*qc)); | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | return -EINVAL; | ||
429 | } | ||
430 | |||
431 | |||
432 | static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
433 | { | ||
434 | struct mt9v011 *core = to_mt9v011(sd); | ||
435 | u8 i, n; | ||
436 | n = ARRAY_SIZE(mt9v011_qctrl); | ||
437 | |||
438 | for (i = 0; i < n; i++) { | ||
439 | if (ctrl->id != mt9v011_qctrl[i].id) | ||
440 | continue; | ||
441 | if (ctrl->value < mt9v011_qctrl[i].minimum || | ||
442 | ctrl->value > mt9v011_qctrl[i].maximum) | ||
443 | return -ERANGE; | ||
444 | v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n", | ||
445 | ctrl->id, ctrl->value); | ||
446 | break; | ||
447 | } | ||
448 | |||
449 | switch (ctrl->id) { | ||
450 | case V4L2_CID_GAIN: | ||
451 | core->global_gain = ctrl->value; | ||
452 | break; | ||
453 | case V4L2_CID_EXPOSURE: | ||
454 | core->exposure = ctrl->value; | ||
455 | break; | ||
456 | case V4L2_CID_RED_BALANCE: | ||
457 | core->red_bal = ctrl->value; | ||
458 | break; | ||
459 | case V4L2_CID_BLUE_BALANCE: | ||
460 | core->blue_bal = ctrl->value; | ||
461 | break; | ||
462 | case V4L2_CID_HFLIP: | ||
463 | core->hflip = ctrl->value; | ||
464 | set_read_mode(sd); | ||
465 | return 0; | ||
466 | case V4L2_CID_VFLIP: | ||
467 | core->vflip = ctrl->value; | ||
468 | set_read_mode(sd); | ||
469 | return 0; | ||
470 | default: | ||
471 | return -EINVAL; | ||
472 | } | ||
473 | |||
474 | set_balance(sd); | ||
475 | |||
476 | return 0; | ||
477 | } | 326 | } |
478 | 327 | ||
479 | static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, | 328 | static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, |
@@ -599,10 +448,46 @@ static int mt9v011_g_chip_ident(struct v4l2_subdev *sd, | |||
599 | version); | 448 | version); |
600 | } | 449 | } |
601 | 450 | ||
602 | static const struct v4l2_subdev_core_ops mt9v011_core_ops = { | 451 | static int mt9v011_s_ctrl(struct v4l2_ctrl *ctrl) |
603 | .queryctrl = mt9v011_queryctrl, | 452 | { |
604 | .g_ctrl = mt9v011_g_ctrl, | 453 | struct mt9v011 *core = |
454 | container_of(ctrl->handler, struct mt9v011, ctrls); | ||
455 | struct v4l2_subdev *sd = &core->sd; | ||
456 | |||
457 | switch (ctrl->id) { | ||
458 | case V4L2_CID_GAIN: | ||
459 | core->global_gain = ctrl->val; | ||
460 | break; | ||
461 | case V4L2_CID_EXPOSURE: | ||
462 | core->exposure = ctrl->val; | ||
463 | break; | ||
464 | case V4L2_CID_RED_BALANCE: | ||
465 | core->red_bal = ctrl->val; | ||
466 | break; | ||
467 | case V4L2_CID_BLUE_BALANCE: | ||
468 | core->blue_bal = ctrl->val; | ||
469 | break; | ||
470 | case V4L2_CID_HFLIP: | ||
471 | core->hflip = ctrl->val; | ||
472 | set_read_mode(sd); | ||
473 | return 0; | ||
474 | case V4L2_CID_VFLIP: | ||
475 | core->vflip = ctrl->val; | ||
476 | set_read_mode(sd); | ||
477 | return 0; | ||
478 | default: | ||
479 | return -EINVAL; | ||
480 | } | ||
481 | |||
482 | set_balance(sd); | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static struct v4l2_ctrl_ops mt9v011_ctrl_ops = { | ||
605 | .s_ctrl = mt9v011_s_ctrl, | 487 | .s_ctrl = mt9v011_s_ctrl, |
488 | }; | ||
489 | |||
490 | static const struct v4l2_subdev_core_ops mt9v011_core_ops = { | ||
606 | .reset = mt9v011_reset, | 491 | .reset = mt9v011_reset, |
607 | .g_chip_ident = mt9v011_g_chip_ident, | 492 | .g_chip_ident = mt9v011_g_chip_ident, |
608 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 493 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
@@ -658,6 +543,30 @@ static int mt9v011_probe(struct i2c_client *c, | |||
658 | return -EINVAL; | 543 | return -EINVAL; |
659 | } | 544 | } |
660 | 545 | ||
546 | v4l2_ctrl_handler_init(&core->ctrls, 5); | ||
547 | v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops, | ||
548 | V4L2_CID_GAIN, 0, (1 << 12) - 1 - 0x20, 1, 0x20); | ||
549 | v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops, | ||
550 | V4L2_CID_EXPOSURE, 0, 2047, 1, 0x01fc); | ||
551 | v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops, | ||
552 | V4L2_CID_RED_BALANCE, -(1 << 9), (1 << 9) - 1, 1, 0); | ||
553 | v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops, | ||
554 | V4L2_CID_BLUE_BALANCE, -(1 << 9), (1 << 9) - 1, 1, 0); | ||
555 | v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops, | ||
556 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
557 | v4l2_ctrl_new_std(&core->ctrls, &mt9v011_ctrl_ops, | ||
558 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
559 | |||
560 | if (core->ctrls.error) { | ||
561 | int ret = core->ctrls.error; | ||
562 | |||
563 | v4l2_err(sd, "control initialization error %d\n", ret); | ||
564 | v4l2_ctrl_handler_free(&core->ctrls); | ||
565 | kfree(core); | ||
566 | return ret; | ||
567 | } | ||
568 | core->sd.ctrl_handler = &core->ctrls; | ||
569 | |||
661 | core->global_gain = 0x0024; | 570 | core->global_gain = 0x0024; |
662 | core->exposure = 0x01fc; | 571 | core->exposure = 0x01fc; |
663 | core->width = 640; | 572 | core->width = 640; |
@@ -681,12 +590,14 @@ static int mt9v011_probe(struct i2c_client *c, | |||
681 | static int mt9v011_remove(struct i2c_client *c) | 590 | static int mt9v011_remove(struct i2c_client *c) |
682 | { | 591 | { |
683 | struct v4l2_subdev *sd = i2c_get_clientdata(c); | 592 | struct v4l2_subdev *sd = i2c_get_clientdata(c); |
593 | struct mt9v011 *core = to_mt9v011(sd); | ||
684 | 594 | ||
685 | v4l2_dbg(1, debug, sd, | 595 | v4l2_dbg(1, debug, sd, |
686 | "mt9v011.c: removing mt9v011 adapter on address 0x%x\n", | 596 | "mt9v011.c: removing mt9v011 adapter on address 0x%x\n", |
687 | c->addr << 1); | 597 | c->addr << 1); |
688 | 598 | ||
689 | v4l2_device_unregister_subdev(sd); | 599 | v4l2_device_unregister_subdev(sd); |
600 | v4l2_ctrl_handler_free(&core->ctrls); | ||
690 | kfree(to_mt9v011(sd)); | 601 | kfree(to_mt9v011(sd)); |
691 | return 0; | 602 | return 0; |
692 | } | 603 | } |
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c index 440c12962bae..8554b47f993a 100644 --- a/drivers/media/i2c/noon010pc30.c +++ b/drivers/media/i2c/noon010pc30.c | |||
@@ -660,13 +660,6 @@ static const struct v4l2_ctrl_ops noon010_ctrl_ops = { | |||
660 | 660 | ||
661 | static const struct v4l2_subdev_core_ops noon010_core_ops = { | 661 | static const struct v4l2_subdev_core_ops noon010_core_ops = { |
662 | .s_power = noon010_s_power, | 662 | .s_power = noon010_s_power, |
663 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
664 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
665 | .queryctrl = v4l2_subdev_queryctrl, | ||
666 | .querymenu = v4l2_subdev_querymenu, | ||
667 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | ||
668 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | ||
669 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | ||
670 | .log_status = noon010_log_status, | 663 | .log_status = noon010_log_status, |
671 | }; | 664 | }; |
672 | 665 | ||
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index e7c82b297514..05ed5b8e7f88 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/videodev2.h> | 18 | #include <linux/videodev2.h> |
19 | #include <media/v4l2-device.h> | 19 | #include <media/v4l2-device.h> |
20 | #include <media/v4l2-chip-ident.h> | 20 | #include <media/v4l2-chip-ident.h> |
21 | #include <media/v4l2-ctrls.h> | ||
21 | #include <media/v4l2-mediabus.h> | 22 | #include <media/v4l2-mediabus.h> |
22 | #include <media/ov7670.h> | 23 | #include <media/ov7670.h> |
23 | 24 | ||
@@ -47,6 +48,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); | |||
47 | */ | 48 | */ |
48 | #define OV7670_I2C_ADDR 0x42 | 49 | #define OV7670_I2C_ADDR 0x42 |
49 | 50 | ||
51 | #define PLL_FACTOR 4 | ||
52 | |||
50 | /* Registers */ | 53 | /* Registers */ |
51 | #define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ | 54 | #define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ |
52 | #define REG_BLUE 0x01 /* blue gain */ | 55 | #define REG_BLUE 0x01 /* blue gain */ |
@@ -164,6 +167,12 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); | |||
164 | 167 | ||
165 | #define REG_GFIX 0x69 /* Fix gain control */ | 168 | #define REG_GFIX 0x69 /* Fix gain control */ |
166 | 169 | ||
170 | #define REG_DBLV 0x6b /* PLL control an debugging */ | ||
171 | #define DBLV_BYPASS 0x00 /* Bypass PLL */ | ||
172 | #define DBLV_X4 0x01 /* clock x4 */ | ||
173 | #define DBLV_X6 0x10 /* clock x6 */ | ||
174 | #define DBLV_X8 0x11 /* clock x8 */ | ||
175 | |||
167 | #define REG_REG76 0x76 /* OV's name */ | 176 | #define REG_REG76 0x76 /* OV's name */ |
168 | #define R76_BLKPCOR 0x80 /* Black pixel correction enable */ | 177 | #define R76_BLKPCOR 0x80 /* Black pixel correction enable */ |
169 | #define R76_WHTPCOR 0x40 /* White pixel correction enable */ | 178 | #define R76_WHTPCOR 0x40 /* White pixel correction enable */ |
@@ -183,6 +192,30 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); | |||
183 | #define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ | 192 | #define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ |
184 | #define REG_BD60MAX 0xab /* 60hz banding step limit */ | 193 | #define REG_BD60MAX 0xab /* 60hz banding step limit */ |
185 | 194 | ||
195 | enum ov7670_model { | ||
196 | MODEL_OV7670 = 0, | ||
197 | MODEL_OV7675, | ||
198 | }; | ||
199 | |||
200 | struct ov7670_win_size { | ||
201 | int width; | ||
202 | int height; | ||
203 | unsigned char com7_bit; | ||
204 | int hstart; /* Start/stop values for the camera. Note */ | ||
205 | int hstop; /* that they do not always make complete */ | ||
206 | int vstart; /* sense to humans, but evidently the sensor */ | ||
207 | int vstop; /* will do the right thing... */ | ||
208 | struct regval_list *regs; /* Regs to tweak */ | ||
209 | }; | ||
210 | |||
211 | struct ov7670_devtype { | ||
212 | /* formats supported for each model */ | ||
213 | struct ov7670_win_size *win_sizes; | ||
214 | unsigned int n_win_sizes; | ||
215 | /* callbacks for frame rate control */ | ||
216 | int (*set_framerate)(struct v4l2_subdev *, struct v4l2_fract *); | ||
217 | void (*get_framerate)(struct v4l2_subdev *, struct v4l2_fract *); | ||
218 | }; | ||
186 | 219 | ||
187 | /* | 220 | /* |
188 | * Information we maintain about a known sensor. | 221 | * Information we maintain about a known sensor. |
@@ -190,14 +223,31 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); | |||
190 | struct ov7670_format_struct; /* coming later */ | 223 | struct ov7670_format_struct; /* coming later */ |
191 | struct ov7670_info { | 224 | struct ov7670_info { |
192 | struct v4l2_subdev sd; | 225 | struct v4l2_subdev sd; |
226 | struct v4l2_ctrl_handler hdl; | ||
227 | struct { | ||
228 | /* gain cluster */ | ||
229 | struct v4l2_ctrl *auto_gain; | ||
230 | struct v4l2_ctrl *gain; | ||
231 | }; | ||
232 | struct { | ||
233 | /* exposure cluster */ | ||
234 | struct v4l2_ctrl *auto_exposure; | ||
235 | struct v4l2_ctrl *exposure; | ||
236 | }; | ||
237 | struct { | ||
238 | /* saturation/hue cluster */ | ||
239 | struct v4l2_ctrl *saturation; | ||
240 | struct v4l2_ctrl *hue; | ||
241 | }; | ||
193 | struct ov7670_format_struct *fmt; /* Current format */ | 242 | struct ov7670_format_struct *fmt; /* Current format */ |
194 | unsigned char sat; /* Saturation value */ | ||
195 | int hue; /* Hue value */ | ||
196 | int min_width; /* Filter out smaller sizes */ | 243 | int min_width; /* Filter out smaller sizes */ |
197 | int min_height; /* Filter out smaller sizes */ | 244 | int min_height; /* Filter out smaller sizes */ |
198 | int clock_speed; /* External clock speed (MHz) */ | 245 | int clock_speed; /* External clock speed (MHz) */ |
199 | u8 clkrc; /* Clock divider value */ | 246 | u8 clkrc; /* Clock divider value */ |
200 | bool use_smbus; /* Use smbus I/O instead of I2C */ | 247 | bool use_smbus; /* Use smbus I/O instead of I2C */ |
248 | bool pll_bypass; | ||
249 | bool pclk_hb_disable; | ||
250 | const struct ov7670_devtype *devtype; /* Device specifics */ | ||
201 | }; | 251 | }; |
202 | 252 | ||
203 | static inline struct ov7670_info *to_state(struct v4l2_subdev *sd) | 253 | static inline struct ov7670_info *to_state(struct v4l2_subdev *sd) |
@@ -205,6 +255,11 @@ static inline struct ov7670_info *to_state(struct v4l2_subdev *sd) | |||
205 | return container_of(sd, struct ov7670_info, sd); | 255 | return container_of(sd, struct ov7670_info, sd); |
206 | } | 256 | } |
207 | 257 | ||
258 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
259 | { | ||
260 | return &container_of(ctrl->handler, struct ov7670_info, hdl)->sd; | ||
261 | } | ||
262 | |||
208 | 263 | ||
209 | 264 | ||
210 | /* | 265 | /* |
@@ -353,7 +408,7 @@ static struct regval_list ov7670_fmt_yuv422[] = { | |||
353 | { REG_RGB444, 0 }, /* No RGB444 please */ | 408 | { REG_RGB444, 0 }, /* No RGB444 please */ |
354 | { REG_COM1, 0 }, /* CCIR601 */ | 409 | { REG_COM1, 0 }, /* CCIR601 */ |
355 | { REG_COM15, COM15_R00FF }, | 410 | { REG_COM15, COM15_R00FF }, |
356 | { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */ | 411 | { REG_COM9, 0x48 }, /* 32x gain ceiling; 0x8 is reserved bit */ |
357 | { 0x4f, 0x80 }, /* "matrix coefficient 1" */ | 412 | { 0x4f, 0x80 }, /* "matrix coefficient 1" */ |
358 | { 0x50, 0x80 }, /* "matrix coefficient 2" */ | 413 | { 0x50, 0x80 }, /* "matrix coefficient 2" */ |
359 | { 0x51, 0 }, /* vb */ | 414 | { 0x51, 0 }, /* vb */ |
@@ -652,65 +707,178 @@ static struct regval_list ov7670_qcif_regs[] = { | |||
652 | { 0xff, 0xff }, | 707 | { 0xff, 0xff }, |
653 | }; | 708 | }; |
654 | 709 | ||
655 | static struct ov7670_win_size { | 710 | static struct ov7670_win_size ov7670_win_sizes[] = { |
656 | int width; | ||
657 | int height; | ||
658 | unsigned char com7_bit; | ||
659 | int hstart; /* Start/stop values for the camera. Note */ | ||
660 | int hstop; /* that they do not always make complete */ | ||
661 | int vstart; /* sense to humans, but evidently the sensor */ | ||
662 | int vstop; /* will do the right thing... */ | ||
663 | struct regval_list *regs; /* Regs to tweak */ | ||
664 | /* h/vref stuff */ | ||
665 | } ov7670_win_sizes[] = { | ||
666 | /* VGA */ | 711 | /* VGA */ |
667 | { | 712 | { |
668 | .width = VGA_WIDTH, | 713 | .width = VGA_WIDTH, |
669 | .height = VGA_HEIGHT, | 714 | .height = VGA_HEIGHT, |
670 | .com7_bit = COM7_FMT_VGA, | 715 | .com7_bit = COM7_FMT_VGA, |
671 | .hstart = 158, /* These values from */ | 716 | .hstart = 158, /* These values from */ |
672 | .hstop = 14, /* Omnivision */ | 717 | .hstop = 14, /* Omnivision */ |
673 | .vstart = 10, | 718 | .vstart = 10, |
674 | .vstop = 490, | 719 | .vstop = 490, |
675 | .regs = NULL, | 720 | .regs = NULL, |
676 | }, | 721 | }, |
677 | /* CIF */ | 722 | /* CIF */ |
678 | { | 723 | { |
679 | .width = CIF_WIDTH, | 724 | .width = CIF_WIDTH, |
680 | .height = CIF_HEIGHT, | 725 | .height = CIF_HEIGHT, |
681 | .com7_bit = COM7_FMT_CIF, | 726 | .com7_bit = COM7_FMT_CIF, |
682 | .hstart = 170, /* Empirically determined */ | 727 | .hstart = 170, /* Empirically determined */ |
683 | .hstop = 90, | 728 | .hstop = 90, |
684 | .vstart = 14, | 729 | .vstart = 14, |
685 | .vstop = 494, | 730 | .vstop = 494, |
686 | .regs = NULL, | 731 | .regs = NULL, |
687 | }, | 732 | }, |
688 | /* QVGA */ | 733 | /* QVGA */ |
689 | { | 734 | { |
690 | .width = QVGA_WIDTH, | 735 | .width = QVGA_WIDTH, |
691 | .height = QVGA_HEIGHT, | 736 | .height = QVGA_HEIGHT, |
692 | .com7_bit = COM7_FMT_QVGA, | 737 | .com7_bit = COM7_FMT_QVGA, |
693 | .hstart = 168, /* Empirically determined */ | 738 | .hstart = 168, /* Empirically determined */ |
694 | .hstop = 24, | 739 | .hstop = 24, |
695 | .vstart = 12, | 740 | .vstart = 12, |
696 | .vstop = 492, | 741 | .vstop = 492, |
697 | .regs = NULL, | 742 | .regs = NULL, |
698 | }, | 743 | }, |
699 | /* QCIF */ | 744 | /* QCIF */ |
700 | { | 745 | { |
701 | .width = QCIF_WIDTH, | 746 | .width = QCIF_WIDTH, |
702 | .height = QCIF_HEIGHT, | 747 | .height = QCIF_HEIGHT, |
703 | .com7_bit = COM7_FMT_VGA, /* see comment above */ | 748 | .com7_bit = COM7_FMT_VGA, /* see comment above */ |
704 | .hstart = 456, /* Empirically determined */ | 749 | .hstart = 456, /* Empirically determined */ |
705 | .hstop = 24, | 750 | .hstop = 24, |
706 | .vstart = 14, | 751 | .vstart = 14, |
707 | .vstop = 494, | 752 | .vstop = 494, |
708 | .regs = ov7670_qcif_regs, | 753 | .regs = ov7670_qcif_regs, |
709 | }, | 754 | } |
755 | }; | ||
756 | |||
757 | static struct ov7670_win_size ov7675_win_sizes[] = { | ||
758 | /* | ||
759 | * Currently, only VGA is supported. Theoretically it could be possible | ||
760 | * to support CIF, QVGA and QCIF too. Taking values for ov7670 as a | ||
761 | * base and tweak them empirically could be required. | ||
762 | */ | ||
763 | { | ||
764 | .width = VGA_WIDTH, | ||
765 | .height = VGA_HEIGHT, | ||
766 | .com7_bit = COM7_FMT_VGA, | ||
767 | .hstart = 158, /* These values from */ | ||
768 | .hstop = 14, /* Omnivision */ | ||
769 | .vstart = 14, /* Empirically determined */ | ||
770 | .vstop = 494, | ||
771 | .regs = NULL, | ||
772 | } | ||
710 | }; | 773 | }; |
711 | 774 | ||
712 | #define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes)) | 775 | static void ov7675_get_framerate(struct v4l2_subdev *sd, |
776 | struct v4l2_fract *tpf) | ||
777 | { | ||
778 | struct ov7670_info *info = to_state(sd); | ||
779 | u32 clkrc = info->clkrc; | ||
780 | int pll_factor; | ||
781 | |||
782 | if (info->pll_bypass) | ||
783 | pll_factor = 1; | ||
784 | else | ||
785 | pll_factor = PLL_FACTOR; | ||
786 | |||
787 | clkrc++; | ||
788 | if (info->fmt->mbus_code == V4L2_MBUS_FMT_SBGGR8_1X8) | ||
789 | clkrc = (clkrc >> 1); | ||
790 | |||
791 | tpf->numerator = 1; | ||
792 | tpf->denominator = (5 * pll_factor * info->clock_speed) / | ||
793 | (4 * clkrc); | ||
794 | } | ||
795 | |||
796 | static int ov7675_set_framerate(struct v4l2_subdev *sd, | ||
797 | struct v4l2_fract *tpf) | ||
798 | { | ||
799 | struct ov7670_info *info = to_state(sd); | ||
800 | u32 clkrc; | ||
801 | int pll_factor; | ||
802 | int ret; | ||
803 | |||
804 | /* | ||
805 | * The formula is fps = 5/4*pixclk for YUV/RGB and | ||
806 | * fps = 5/2*pixclk for RAW. | ||
807 | * | ||
808 | * pixclk = clock_speed / (clkrc + 1) * PLLfactor | ||
809 | * | ||
810 | */ | ||
811 | if (info->pll_bypass) { | ||
812 | pll_factor = 1; | ||
813 | ret = ov7670_write(sd, REG_DBLV, DBLV_BYPASS); | ||
814 | } else { | ||
815 | pll_factor = PLL_FACTOR; | ||
816 | ret = ov7670_write(sd, REG_DBLV, DBLV_X4); | ||
817 | } | ||
818 | if (ret < 0) | ||
819 | return ret; | ||
820 | |||
821 | if (tpf->numerator == 0 || tpf->denominator == 0) { | ||
822 | clkrc = 0; | ||
823 | } else { | ||
824 | clkrc = (5 * pll_factor * info->clock_speed * tpf->numerator) / | ||
825 | (4 * tpf->denominator); | ||
826 | if (info->fmt->mbus_code == V4L2_MBUS_FMT_SBGGR8_1X8) | ||
827 | clkrc = (clkrc << 1); | ||
828 | clkrc--; | ||
829 | } | ||
830 | |||
831 | /* | ||
832 | * The datasheet claims that clkrc = 0 will divide the input clock by 1 | ||
833 | * but we've checked with an oscilloscope that it divides by 2 instead. | ||
834 | * So, if clkrc = 0 just bypass the divider. | ||
835 | */ | ||
836 | if (clkrc <= 0) | ||
837 | clkrc = CLK_EXT; | ||
838 | else if (clkrc > CLK_SCALE) | ||
839 | clkrc = CLK_SCALE; | ||
840 | info->clkrc = clkrc; | ||
841 | |||
842 | /* Recalculate frame rate */ | ||
843 | ov7675_get_framerate(sd, tpf); | ||
844 | |||
845 | ret = ov7670_write(sd, REG_CLKRC, info->clkrc); | ||
846 | if (ret < 0) | ||
847 | return ret; | ||
848 | |||
849 | return ov7670_write(sd, REG_DBLV, DBLV_X4); | ||
850 | } | ||
851 | |||
852 | static void ov7670_get_framerate_legacy(struct v4l2_subdev *sd, | ||
853 | struct v4l2_fract *tpf) | ||
854 | { | ||
855 | struct ov7670_info *info = to_state(sd); | ||
856 | |||
857 | tpf->numerator = 1; | ||
858 | tpf->denominator = info->clock_speed; | ||
859 | if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1) | ||
860 | tpf->denominator /= (info->clkrc & CLK_SCALE); | ||
861 | } | ||
862 | |||
863 | static int ov7670_set_framerate_legacy(struct v4l2_subdev *sd, | ||
864 | struct v4l2_fract *tpf) | ||
865 | { | ||
866 | struct ov7670_info *info = to_state(sd); | ||
867 | int div; | ||
713 | 868 | ||
869 | if (tpf->numerator == 0 || tpf->denominator == 0) | ||
870 | div = 1; /* Reset to full rate */ | ||
871 | else | ||
872 | div = (tpf->numerator * info->clock_speed) / tpf->denominator; | ||
873 | if (div == 0) | ||
874 | div = 1; | ||
875 | else if (div > CLK_SCALE) | ||
876 | div = CLK_SCALE; | ||
877 | info->clkrc = (info->clkrc & 0x80) | div; | ||
878 | tpf->numerator = 1; | ||
879 | tpf->denominator = info->clock_speed / div; | ||
880 | return ov7670_write(sd, REG_CLKRC, info->clkrc); | ||
881 | } | ||
714 | 882 | ||
715 | /* | 883 | /* |
716 | * Store a set of start/stop values into the camera. | 884 | * Store a set of start/stop values into the camera. |
@@ -759,8 +927,11 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd, | |||
759 | struct ov7670_format_struct **ret_fmt, | 927 | struct ov7670_format_struct **ret_fmt, |
760 | struct ov7670_win_size **ret_wsize) | 928 | struct ov7670_win_size **ret_wsize) |
761 | { | 929 | { |
762 | int index; | 930 | int index, i; |
763 | struct ov7670_win_size *wsize; | 931 | struct ov7670_win_size *wsize; |
932 | struct ov7670_info *info = to_state(sd); | ||
933 | unsigned int n_win_sizes = info->devtype->n_win_sizes; | ||
934 | unsigned int win_sizes_limit = n_win_sizes; | ||
764 | 935 | ||
765 | for (index = 0; index < N_OV7670_FMTS; index++) | 936 | for (index = 0; index < N_OV7670_FMTS; index++) |
766 | if (ov7670_formats[index].mbus_code == fmt->code) | 937 | if (ov7670_formats[index].mbus_code == fmt->code) |
@@ -776,15 +947,30 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd, | |||
776 | * Fields: the OV devices claim to be progressive. | 947 | * Fields: the OV devices claim to be progressive. |
777 | */ | 948 | */ |
778 | fmt->field = V4L2_FIELD_NONE; | 949 | fmt->field = V4L2_FIELD_NONE; |
950 | |||
951 | /* | ||
952 | * Don't consider values that don't match min_height and min_width | ||
953 | * constraints. | ||
954 | */ | ||
955 | if (info->min_width || info->min_height) | ||
956 | for (i = 0; i < n_win_sizes; i++) { | ||
957 | wsize = info->devtype->win_sizes + i; | ||
958 | |||
959 | if (wsize->width < info->min_width || | ||
960 | wsize->height < info->min_height) { | ||
961 | win_sizes_limit = i; | ||
962 | break; | ||
963 | } | ||
964 | } | ||
779 | /* | 965 | /* |
780 | * Round requested image size down to the nearest | 966 | * Round requested image size down to the nearest |
781 | * we support, but not below the smallest. | 967 | * we support, but not below the smallest. |
782 | */ | 968 | */ |
783 | for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES; | 969 | for (wsize = info->devtype->win_sizes; |
784 | wsize++) | 970 | wsize < info->devtype->win_sizes + win_sizes_limit; wsize++) |
785 | if (fmt->width >= wsize->width && fmt->height >= wsize->height) | 971 | if (fmt->width >= wsize->width && fmt->height >= wsize->height) |
786 | break; | 972 | break; |
787 | if (wsize >= ov7670_win_sizes + N_WIN_SIZES) | 973 | if (wsize >= info->devtype->win_sizes + win_sizes_limit) |
788 | wsize--; /* Take the smallest one */ | 974 | wsize--; /* Take the smallest one */ |
789 | if (ret_wsize != NULL) | 975 | if (ret_wsize != NULL) |
790 | *ret_wsize = wsize; | 976 | *ret_wsize = wsize; |
@@ -868,10 +1054,8 @@ static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) | |||
868 | 1054 | ||
869 | memset(cp, 0, sizeof(struct v4l2_captureparm)); | 1055 | memset(cp, 0, sizeof(struct v4l2_captureparm)); |
870 | cp->capability = V4L2_CAP_TIMEPERFRAME; | 1056 | cp->capability = V4L2_CAP_TIMEPERFRAME; |
871 | cp->timeperframe.numerator = 1; | 1057 | info->devtype->get_framerate(sd, &cp->timeperframe); |
872 | cp->timeperframe.denominator = info->clock_speed; | 1058 | |
873 | if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1) | ||
874 | cp->timeperframe.denominator /= (info->clkrc & CLK_SCALE); | ||
875 | return 0; | 1059 | return 0; |
876 | } | 1060 | } |
877 | 1061 | ||
@@ -880,25 +1064,13 @@ static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) | |||
880 | struct v4l2_captureparm *cp = &parms->parm.capture; | 1064 | struct v4l2_captureparm *cp = &parms->parm.capture; |
881 | struct v4l2_fract *tpf = &cp->timeperframe; | 1065 | struct v4l2_fract *tpf = &cp->timeperframe; |
882 | struct ov7670_info *info = to_state(sd); | 1066 | struct ov7670_info *info = to_state(sd); |
883 | int div; | ||
884 | 1067 | ||
885 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1068 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
886 | return -EINVAL; | 1069 | return -EINVAL; |
887 | if (cp->extendedmode != 0) | 1070 | if (cp->extendedmode != 0) |
888 | return -EINVAL; | 1071 | return -EINVAL; |
889 | 1072 | ||
890 | if (tpf->numerator == 0 || tpf->denominator == 0) | 1073 | return info->devtype->set_framerate(sd, tpf); |
891 | div = 1; /* Reset to full rate */ | ||
892 | else | ||
893 | div = (tpf->numerator * info->clock_speed) / tpf->denominator; | ||
894 | if (div == 0) | ||
895 | div = 1; | ||
896 | else if (div > CLK_SCALE) | ||
897 | div = CLK_SCALE; | ||
898 | info->clkrc = (info->clkrc & 0x80) | div; | ||
899 | tpf->numerator = 1; | ||
900 | tpf->denominator = info->clock_speed / div; | ||
901 | return ov7670_write(sd, REG_CLKRC, info->clkrc); | ||
902 | } | 1074 | } |
903 | 1075 | ||
904 | 1076 | ||
@@ -931,13 +1103,14 @@ static int ov7670_enum_framesizes(struct v4l2_subdev *sd, | |||
931 | int i; | 1103 | int i; |
932 | int num_valid = -1; | 1104 | int num_valid = -1; |
933 | __u32 index = fsize->index; | 1105 | __u32 index = fsize->index; |
1106 | unsigned int n_win_sizes = info->devtype->n_win_sizes; | ||
934 | 1107 | ||
935 | /* | 1108 | /* |
936 | * If a minimum width/height was requested, filter out the capture | 1109 | * If a minimum width/height was requested, filter out the capture |
937 | * windows that fall outside that. | 1110 | * windows that fall outside that. |
938 | */ | 1111 | */ |
939 | for (i = 0; i < N_WIN_SIZES; i++) { | 1112 | for (i = 0; i < n_win_sizes; i++) { |
940 | struct ov7670_win_size *win = &ov7670_win_sizes[index]; | 1113 | struct ov7670_win_size *win = &info->devtype->win_sizes[index]; |
941 | if (info->min_width && win->width < info->min_width) | 1114 | if (info->min_width && win->width < info->min_width) |
942 | continue; | 1115 | continue; |
943 | if (info->min_height && win->height < info->min_height) | 1116 | if (info->min_height && win->height < info->min_height) |
@@ -1042,23 +1215,23 @@ static int ov7670_cosine(int theta) | |||
1042 | 1215 | ||
1043 | 1216 | ||
1044 | static void ov7670_calc_cmatrix(struct ov7670_info *info, | 1217 | static void ov7670_calc_cmatrix(struct ov7670_info *info, |
1045 | int matrix[CMATRIX_LEN]) | 1218 | int matrix[CMATRIX_LEN], int sat, int hue) |
1046 | { | 1219 | { |
1047 | int i; | 1220 | int i; |
1048 | /* | 1221 | /* |
1049 | * Apply the current saturation setting first. | 1222 | * Apply the current saturation setting first. |
1050 | */ | 1223 | */ |
1051 | for (i = 0; i < CMATRIX_LEN; i++) | 1224 | for (i = 0; i < CMATRIX_LEN; i++) |
1052 | matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7; | 1225 | matrix[i] = (info->fmt->cmatrix[i] * sat) >> 7; |
1053 | /* | 1226 | /* |
1054 | * Then, if need be, rotate the hue value. | 1227 | * Then, if need be, rotate the hue value. |
1055 | */ | 1228 | */ |
1056 | if (info->hue != 0) { | 1229 | if (hue != 0) { |
1057 | int sinth, costh, tmpmatrix[CMATRIX_LEN]; | 1230 | int sinth, costh, tmpmatrix[CMATRIX_LEN]; |
1058 | 1231 | ||
1059 | memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int)); | 1232 | memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int)); |
1060 | sinth = ov7670_sine(info->hue); | 1233 | sinth = ov7670_sine(hue); |
1061 | costh = ov7670_cosine(info->hue); | 1234 | costh = ov7670_cosine(hue); |
1062 | 1235 | ||
1063 | matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000; | 1236 | matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000; |
1064 | matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000; | 1237 | matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000; |
@@ -1071,60 +1244,21 @@ static void ov7670_calc_cmatrix(struct ov7670_info *info, | |||
1071 | 1244 | ||
1072 | 1245 | ||
1073 | 1246 | ||
1074 | static int ov7670_s_sat(struct v4l2_subdev *sd, int value) | 1247 | static int ov7670_s_sat_hue(struct v4l2_subdev *sd, int sat, int hue) |
1075 | { | ||
1076 | struct ov7670_info *info = to_state(sd); | ||
1077 | int matrix[CMATRIX_LEN]; | ||
1078 | int ret; | ||
1079 | |||
1080 | info->sat = value; | ||
1081 | ov7670_calc_cmatrix(info, matrix); | ||
1082 | ret = ov7670_store_cmatrix(sd, matrix); | ||
1083 | return ret; | ||
1084 | } | ||
1085 | |||
1086 | static int ov7670_g_sat(struct v4l2_subdev *sd, __s32 *value) | ||
1087 | { | ||
1088 | struct ov7670_info *info = to_state(sd); | ||
1089 | |||
1090 | *value = info->sat; | ||
1091 | return 0; | ||
1092 | } | ||
1093 | |||
1094 | static int ov7670_s_hue(struct v4l2_subdev *sd, int value) | ||
1095 | { | 1248 | { |
1096 | struct ov7670_info *info = to_state(sd); | 1249 | struct ov7670_info *info = to_state(sd); |
1097 | int matrix[CMATRIX_LEN]; | 1250 | int matrix[CMATRIX_LEN]; |
1098 | int ret; | 1251 | int ret; |
1099 | 1252 | ||
1100 | if (value < -180 || value > 180) | 1253 | ov7670_calc_cmatrix(info, matrix, sat, hue); |
1101 | return -EINVAL; | ||
1102 | info->hue = value; | ||
1103 | ov7670_calc_cmatrix(info, matrix); | ||
1104 | ret = ov7670_store_cmatrix(sd, matrix); | 1254 | ret = ov7670_store_cmatrix(sd, matrix); |
1105 | return ret; | 1255 | return ret; |
1106 | } | 1256 | } |
1107 | 1257 | ||
1108 | 1258 | ||
1109 | static int ov7670_g_hue(struct v4l2_subdev *sd, __s32 *value) | ||
1110 | { | ||
1111 | struct ov7670_info *info = to_state(sd); | ||
1112 | |||
1113 | *value = info->hue; | ||
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | |||
1118 | /* | 1259 | /* |
1119 | * Some weird registers seem to store values in a sign/magnitude format! | 1260 | * Some weird registers seem to store values in a sign/magnitude format! |
1120 | */ | 1261 | */ |
1121 | static unsigned char ov7670_sm_to_abs(unsigned char v) | ||
1122 | { | ||
1123 | if ((v & 0x80) == 0) | ||
1124 | return v + 128; | ||
1125 | return 128 - (v & 0x7f); | ||
1126 | } | ||
1127 | |||
1128 | 1262 | ||
1129 | static unsigned char ov7670_abs_to_sm(unsigned char v) | 1263 | static unsigned char ov7670_abs_to_sm(unsigned char v) |
1130 | { | 1264 | { |
@@ -1146,40 +1280,11 @@ static int ov7670_s_brightness(struct v4l2_subdev *sd, int value) | |||
1146 | return ret; | 1280 | return ret; |
1147 | } | 1281 | } |
1148 | 1282 | ||
1149 | static int ov7670_g_brightness(struct v4l2_subdev *sd, __s32 *value) | ||
1150 | { | ||
1151 | unsigned char v = 0; | ||
1152 | int ret = ov7670_read(sd, REG_BRIGHT, &v); | ||
1153 | |||
1154 | *value = ov7670_sm_to_abs(v); | ||
1155 | return ret; | ||
1156 | } | ||
1157 | |||
1158 | static int ov7670_s_contrast(struct v4l2_subdev *sd, int value) | 1283 | static int ov7670_s_contrast(struct v4l2_subdev *sd, int value) |
1159 | { | 1284 | { |
1160 | return ov7670_write(sd, REG_CONTRAS, (unsigned char) value); | 1285 | return ov7670_write(sd, REG_CONTRAS, (unsigned char) value); |
1161 | } | 1286 | } |
1162 | 1287 | ||
1163 | static int ov7670_g_contrast(struct v4l2_subdev *sd, __s32 *value) | ||
1164 | { | ||
1165 | unsigned char v = 0; | ||
1166 | int ret = ov7670_read(sd, REG_CONTRAS, &v); | ||
1167 | |||
1168 | *value = v; | ||
1169 | return ret; | ||
1170 | } | ||
1171 | |||
1172 | static int ov7670_g_hflip(struct v4l2_subdev *sd, __s32 *value) | ||
1173 | { | ||
1174 | int ret; | ||
1175 | unsigned char v = 0; | ||
1176 | |||
1177 | ret = ov7670_read(sd, REG_MVFP, &v); | ||
1178 | *value = (v & MVFP_MIRROR) == MVFP_MIRROR; | ||
1179 | return ret; | ||
1180 | } | ||
1181 | |||
1182 | |||
1183 | static int ov7670_s_hflip(struct v4l2_subdev *sd, int value) | 1288 | static int ov7670_s_hflip(struct v4l2_subdev *sd, int value) |
1184 | { | 1289 | { |
1185 | unsigned char v = 0; | 1290 | unsigned char v = 0; |
@@ -1195,19 +1300,6 @@ static int ov7670_s_hflip(struct v4l2_subdev *sd, int value) | |||
1195 | return ret; | 1300 | return ret; |
1196 | } | 1301 | } |
1197 | 1302 | ||
1198 | |||
1199 | |||
1200 | static int ov7670_g_vflip(struct v4l2_subdev *sd, __s32 *value) | ||
1201 | { | ||
1202 | int ret; | ||
1203 | unsigned char v = 0; | ||
1204 | |||
1205 | ret = ov7670_read(sd, REG_MVFP, &v); | ||
1206 | *value = (v & MVFP_FLIP) == MVFP_FLIP; | ||
1207 | return ret; | ||
1208 | } | ||
1209 | |||
1210 | |||
1211 | static int ov7670_s_vflip(struct v4l2_subdev *sd, int value) | 1303 | static int ov7670_s_vflip(struct v4l2_subdev *sd, int value) |
1212 | { | 1304 | { |
1213 | unsigned char v = 0; | 1305 | unsigned char v = 0; |
@@ -1256,16 +1348,6 @@ static int ov7670_s_gain(struct v4l2_subdev *sd, int value) | |||
1256 | /* | 1348 | /* |
1257 | * Tweak autogain. | 1349 | * Tweak autogain. |
1258 | */ | 1350 | */ |
1259 | static int ov7670_g_autogain(struct v4l2_subdev *sd, __s32 *value) | ||
1260 | { | ||
1261 | int ret; | ||
1262 | unsigned char com8; | ||
1263 | |||
1264 | ret = ov7670_read(sd, REG_COM8, &com8); | ||
1265 | *value = (com8 & COM8_AGC) != 0; | ||
1266 | return ret; | ||
1267 | } | ||
1268 | |||
1269 | static int ov7670_s_autogain(struct v4l2_subdev *sd, int value) | 1351 | static int ov7670_s_autogain(struct v4l2_subdev *sd, int value) |
1270 | { | 1352 | { |
1271 | int ret; | 1353 | int ret; |
@@ -1282,22 +1364,6 @@ static int ov7670_s_autogain(struct v4l2_subdev *sd, int value) | |||
1282 | return ret; | 1364 | return ret; |
1283 | } | 1365 | } |
1284 | 1366 | ||
1285 | /* | ||
1286 | * Exposure is spread all over the place: top 6 bits in AECHH, middle | ||
1287 | * 8 in AECH, and two stashed in COM1 just for the hell of it. | ||
1288 | */ | ||
1289 | static int ov7670_g_exp(struct v4l2_subdev *sd, __s32 *value) | ||
1290 | { | ||
1291 | int ret; | ||
1292 | unsigned char com1, aech, aechh; | ||
1293 | |||
1294 | ret = ov7670_read(sd, REG_COM1, &com1) + | ||
1295 | ov7670_read(sd, REG_AECH, &aech) + | ||
1296 | ov7670_read(sd, REG_AECHH, &aechh); | ||
1297 | *value = ((aechh & 0x3f) << 10) | (aech << 2) | (com1 & 0x03); | ||
1298 | return ret; | ||
1299 | } | ||
1300 | |||
1301 | static int ov7670_s_exp(struct v4l2_subdev *sd, int value) | 1367 | static int ov7670_s_exp(struct v4l2_subdev *sd, int value) |
1302 | { | 1368 | { |
1303 | int ret; | 1369 | int ret; |
@@ -1324,20 +1390,6 @@ static int ov7670_s_exp(struct v4l2_subdev *sd, int value) | |||
1324 | /* | 1390 | /* |
1325 | * Tweak autoexposure. | 1391 | * Tweak autoexposure. |
1326 | */ | 1392 | */ |
1327 | static int ov7670_g_autoexp(struct v4l2_subdev *sd, __s32 *value) | ||
1328 | { | ||
1329 | int ret; | ||
1330 | unsigned char com8; | ||
1331 | enum v4l2_exposure_auto_type *atype = (enum v4l2_exposure_auto_type *) value; | ||
1332 | |||
1333 | ret = ov7670_read(sd, REG_COM8, &com8); | ||
1334 | if (com8 & COM8_AEC) | ||
1335 | *atype = V4L2_EXPOSURE_AUTO; | ||
1336 | else | ||
1337 | *atype = V4L2_EXPOSURE_MANUAL; | ||
1338 | return ret; | ||
1339 | } | ||
1340 | |||
1341 | static int ov7670_s_autoexp(struct v4l2_subdev *sd, | 1393 | static int ov7670_s_autoexp(struct v4l2_subdev *sd, |
1342 | enum v4l2_exposure_auto_type value) | 1394 | enum v4l2_exposure_auto_type value) |
1343 | { | 1395 | { |
@@ -1356,90 +1408,60 @@ static int ov7670_s_autoexp(struct v4l2_subdev *sd, | |||
1356 | } | 1408 | } |
1357 | 1409 | ||
1358 | 1410 | ||
1359 | 1411 | static int ov7670_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | |
1360 | static int ov7670_queryctrl(struct v4l2_subdev *sd, | ||
1361 | struct v4l2_queryctrl *qc) | ||
1362 | { | 1412 | { |
1363 | /* Fill in min, max, step and default value for these controls. */ | 1413 | struct v4l2_subdev *sd = to_sd(ctrl); |
1364 | switch (qc->id) { | 1414 | struct ov7670_info *info = to_state(sd); |
1365 | case V4L2_CID_BRIGHTNESS: | ||
1366 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); | ||
1367 | case V4L2_CID_CONTRAST: | ||
1368 | return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); | ||
1369 | case V4L2_CID_VFLIP: | ||
1370 | case V4L2_CID_HFLIP: | ||
1371 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
1372 | case V4L2_CID_SATURATION: | ||
1373 | return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128); | ||
1374 | case V4L2_CID_HUE: | ||
1375 | return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0); | ||
1376 | case V4L2_CID_GAIN: | ||
1377 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); | ||
1378 | case V4L2_CID_AUTOGAIN: | ||
1379 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
1380 | case V4L2_CID_EXPOSURE: | ||
1381 | return v4l2_ctrl_query_fill(qc, 0, 65535, 1, 500); | ||
1382 | case V4L2_CID_EXPOSURE_AUTO: | ||
1383 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
1384 | } | ||
1385 | return -EINVAL; | ||
1386 | } | ||
1387 | 1415 | ||
1388 | static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
1389 | { | ||
1390 | switch (ctrl->id) { | 1416 | switch (ctrl->id) { |
1391 | case V4L2_CID_BRIGHTNESS: | ||
1392 | return ov7670_g_brightness(sd, &ctrl->value); | ||
1393 | case V4L2_CID_CONTRAST: | ||
1394 | return ov7670_g_contrast(sd, &ctrl->value); | ||
1395 | case V4L2_CID_SATURATION: | ||
1396 | return ov7670_g_sat(sd, &ctrl->value); | ||
1397 | case V4L2_CID_HUE: | ||
1398 | return ov7670_g_hue(sd, &ctrl->value); | ||
1399 | case V4L2_CID_VFLIP: | ||
1400 | return ov7670_g_vflip(sd, &ctrl->value); | ||
1401 | case V4L2_CID_HFLIP: | ||
1402 | return ov7670_g_hflip(sd, &ctrl->value); | ||
1403 | case V4L2_CID_GAIN: | ||
1404 | return ov7670_g_gain(sd, &ctrl->value); | ||
1405 | case V4L2_CID_AUTOGAIN: | 1417 | case V4L2_CID_AUTOGAIN: |
1406 | return ov7670_g_autogain(sd, &ctrl->value); | 1418 | return ov7670_g_gain(sd, &info->gain->val); |
1407 | case V4L2_CID_EXPOSURE: | ||
1408 | return ov7670_g_exp(sd, &ctrl->value); | ||
1409 | case V4L2_CID_EXPOSURE_AUTO: | ||
1410 | return ov7670_g_autoexp(sd, &ctrl->value); | ||
1411 | } | 1419 | } |
1412 | return -EINVAL; | 1420 | return -EINVAL; |
1413 | } | 1421 | } |
1414 | 1422 | ||
1415 | static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 1423 | static int ov7670_s_ctrl(struct v4l2_ctrl *ctrl) |
1416 | { | 1424 | { |
1425 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
1426 | struct ov7670_info *info = to_state(sd); | ||
1427 | |||
1417 | switch (ctrl->id) { | 1428 | switch (ctrl->id) { |
1418 | case V4L2_CID_BRIGHTNESS: | 1429 | case V4L2_CID_BRIGHTNESS: |
1419 | return ov7670_s_brightness(sd, ctrl->value); | 1430 | return ov7670_s_brightness(sd, ctrl->val); |
1420 | case V4L2_CID_CONTRAST: | 1431 | case V4L2_CID_CONTRAST: |
1421 | return ov7670_s_contrast(sd, ctrl->value); | 1432 | return ov7670_s_contrast(sd, ctrl->val); |
1422 | case V4L2_CID_SATURATION: | 1433 | case V4L2_CID_SATURATION: |
1423 | return ov7670_s_sat(sd, ctrl->value); | 1434 | return ov7670_s_sat_hue(sd, |
1424 | case V4L2_CID_HUE: | 1435 | info->saturation->val, info->hue->val); |
1425 | return ov7670_s_hue(sd, ctrl->value); | ||
1426 | case V4L2_CID_VFLIP: | 1436 | case V4L2_CID_VFLIP: |
1427 | return ov7670_s_vflip(sd, ctrl->value); | 1437 | return ov7670_s_vflip(sd, ctrl->val); |
1428 | case V4L2_CID_HFLIP: | 1438 | case V4L2_CID_HFLIP: |
1429 | return ov7670_s_hflip(sd, ctrl->value); | 1439 | return ov7670_s_hflip(sd, ctrl->val); |
1430 | case V4L2_CID_GAIN: | ||
1431 | return ov7670_s_gain(sd, ctrl->value); | ||
1432 | case V4L2_CID_AUTOGAIN: | 1440 | case V4L2_CID_AUTOGAIN: |
1433 | return ov7670_s_autogain(sd, ctrl->value); | 1441 | /* Only set manual gain if auto gain is not explicitly |
1434 | case V4L2_CID_EXPOSURE: | 1442 | turned on. */ |
1435 | return ov7670_s_exp(sd, ctrl->value); | 1443 | if (!ctrl->val) { |
1444 | /* ov7670_s_gain turns off auto gain */ | ||
1445 | return ov7670_s_gain(sd, info->gain->val); | ||
1446 | } | ||
1447 | return ov7670_s_autogain(sd, ctrl->val); | ||
1436 | case V4L2_CID_EXPOSURE_AUTO: | 1448 | case V4L2_CID_EXPOSURE_AUTO: |
1437 | return ov7670_s_autoexp(sd, | 1449 | /* Only set manual exposure if auto exposure is not explicitly |
1438 | (enum v4l2_exposure_auto_type) ctrl->value); | 1450 | turned on. */ |
1451 | if (ctrl->val == V4L2_EXPOSURE_MANUAL) { | ||
1452 | /* ov7670_s_exp turns off auto exposure */ | ||
1453 | return ov7670_s_exp(sd, info->exposure->val); | ||
1454 | } | ||
1455 | return ov7670_s_autoexp(sd, ctrl->val); | ||
1439 | } | 1456 | } |
1440 | return -EINVAL; | 1457 | return -EINVAL; |
1441 | } | 1458 | } |
1442 | 1459 | ||
1460 | static const struct v4l2_ctrl_ops ov7670_ctrl_ops = { | ||
1461 | .s_ctrl = ov7670_s_ctrl, | ||
1462 | .g_volatile_ctrl = ov7670_g_volatile_ctrl, | ||
1463 | }; | ||
1464 | |||
1443 | static int ov7670_g_chip_ident(struct v4l2_subdev *sd, | 1465 | static int ov7670_g_chip_ident(struct v4l2_subdev *sd, |
1444 | struct v4l2_dbg_chip_ident *chip) | 1466 | struct v4l2_dbg_chip_ident *chip) |
1445 | { | 1467 | { |
@@ -1482,9 +1504,6 @@ static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r | |||
1482 | 1504 | ||
1483 | static const struct v4l2_subdev_core_ops ov7670_core_ops = { | 1505 | static const struct v4l2_subdev_core_ops ov7670_core_ops = { |
1484 | .g_chip_ident = ov7670_g_chip_ident, | 1506 | .g_chip_ident = ov7670_g_chip_ident, |
1485 | .g_ctrl = ov7670_g_ctrl, | ||
1486 | .s_ctrl = ov7670_s_ctrl, | ||
1487 | .queryctrl = ov7670_queryctrl, | ||
1488 | .reset = ov7670_reset, | 1507 | .reset = ov7670_reset, |
1489 | .init = ov7670_init, | 1508 | .init = ov7670_init, |
1490 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1509 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
@@ -1510,9 +1529,25 @@ static const struct v4l2_subdev_ops ov7670_ops = { | |||
1510 | 1529 | ||
1511 | /* ----------------------------------------------------------------------- */ | 1530 | /* ----------------------------------------------------------------------- */ |
1512 | 1531 | ||
1532 | static const struct ov7670_devtype ov7670_devdata[] = { | ||
1533 | [MODEL_OV7670] = { | ||
1534 | .win_sizes = ov7670_win_sizes, | ||
1535 | .n_win_sizes = ARRAY_SIZE(ov7670_win_sizes), | ||
1536 | .set_framerate = ov7670_set_framerate_legacy, | ||
1537 | .get_framerate = ov7670_get_framerate_legacy, | ||
1538 | }, | ||
1539 | [MODEL_OV7675] = { | ||
1540 | .win_sizes = ov7675_win_sizes, | ||
1541 | .n_win_sizes = ARRAY_SIZE(ov7675_win_sizes), | ||
1542 | .set_framerate = ov7675_set_framerate, | ||
1543 | .get_framerate = ov7675_get_framerate, | ||
1544 | }, | ||
1545 | }; | ||
1546 | |||
1513 | static int ov7670_probe(struct i2c_client *client, | 1547 | static int ov7670_probe(struct i2c_client *client, |
1514 | const struct i2c_device_id *id) | 1548 | const struct i2c_device_id *id) |
1515 | { | 1549 | { |
1550 | struct v4l2_fract tpf; | ||
1516 | struct v4l2_subdev *sd; | 1551 | struct v4l2_subdev *sd; |
1517 | struct ov7670_info *info; | 1552 | struct ov7670_info *info; |
1518 | int ret; | 1553 | int ret; |
@@ -1537,6 +1572,16 @@ static int ov7670_probe(struct i2c_client *client, | |||
1537 | 1572 | ||
1538 | if (config->clock_speed) | 1573 | if (config->clock_speed) |
1539 | info->clock_speed = config->clock_speed; | 1574 | info->clock_speed = config->clock_speed; |
1575 | |||
1576 | /* | ||
1577 | * It should be allowed for ov7670 too when it is migrated to | ||
1578 | * the new frame rate formula. | ||
1579 | */ | ||
1580 | if (config->pll_bypass && id->driver_data != MODEL_OV7670) | ||
1581 | info->pll_bypass = true; | ||
1582 | |||
1583 | if (config->pclk_hb_disable) | ||
1584 | info->pclk_hb_disable = true; | ||
1540 | } | 1585 | } |
1541 | 1586 | ||
1542 | /* Make sure it's an ov7670 */ | 1587 | /* Make sure it's an ov7670 */ |
@@ -1551,9 +1596,58 @@ static int ov7670_probe(struct i2c_client *client, | |||
1551 | v4l_info(client, "chip found @ 0x%02x (%s)\n", | 1596 | v4l_info(client, "chip found @ 0x%02x (%s)\n", |
1552 | client->addr << 1, client->adapter->name); | 1597 | client->addr << 1, client->adapter->name); |
1553 | 1598 | ||
1599 | info->devtype = &ov7670_devdata[id->driver_data]; | ||
1554 | info->fmt = &ov7670_formats[0]; | 1600 | info->fmt = &ov7670_formats[0]; |
1555 | info->sat = 128; /* Review this */ | 1601 | info->clkrc = 0; |
1556 | info->clkrc = info->clock_speed / 30; | 1602 | |
1603 | /* Set default frame rate to 30 fps */ | ||
1604 | tpf.numerator = 1; | ||
1605 | tpf.denominator = 30; | ||
1606 | info->devtype->set_framerate(sd, &tpf); | ||
1607 | |||
1608 | if (info->pclk_hb_disable) | ||
1609 | ov7670_write(sd, REG_COM10, COM10_PCLK_HB); | ||
1610 | |||
1611 | v4l2_ctrl_handler_init(&info->hdl, 10); | ||
1612 | v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1613 | V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); | ||
1614 | v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1615 | V4L2_CID_CONTRAST, 0, 127, 1, 64); | ||
1616 | v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1617 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
1618 | v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1619 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
1620 | info->saturation = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1621 | V4L2_CID_SATURATION, 0, 256, 1, 128); | ||
1622 | info->hue = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1623 | V4L2_CID_HUE, -180, 180, 5, 0); | ||
1624 | info->gain = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1625 | V4L2_CID_GAIN, 0, 255, 1, 128); | ||
1626 | info->auto_gain = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1627 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
1628 | info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops, | ||
1629 | V4L2_CID_EXPOSURE, 0, 65535, 1, 500); | ||
1630 | info->auto_exposure = v4l2_ctrl_new_std_menu(&info->hdl, &ov7670_ctrl_ops, | ||
1631 | V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0, | ||
1632 | V4L2_EXPOSURE_AUTO); | ||
1633 | sd->ctrl_handler = &info->hdl; | ||
1634 | if (info->hdl.error) { | ||
1635 | int err = info->hdl.error; | ||
1636 | |||
1637 | v4l2_ctrl_handler_free(&info->hdl); | ||
1638 | kfree(info); | ||
1639 | return err; | ||
1640 | } | ||
1641 | /* | ||
1642 | * We have checked empirically that hw allows to read back the gain | ||
1643 | * value chosen by auto gain but that's not the case for auto exposure. | ||
1644 | */ | ||
1645 | v4l2_ctrl_auto_cluster(2, &info->auto_gain, 0, true); | ||
1646 | v4l2_ctrl_auto_cluster(2, &info->auto_exposure, | ||
1647 | V4L2_EXPOSURE_MANUAL, false); | ||
1648 | v4l2_ctrl_cluster(2, &info->saturation); | ||
1649 | v4l2_ctrl_handler_setup(&info->hdl); | ||
1650 | |||
1557 | return 0; | 1651 | return 0; |
1558 | } | 1652 | } |
1559 | 1653 | ||
@@ -1561,14 +1655,17 @@ static int ov7670_probe(struct i2c_client *client, | |||
1561 | static int ov7670_remove(struct i2c_client *client) | 1655 | static int ov7670_remove(struct i2c_client *client) |
1562 | { | 1656 | { |
1563 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 1657 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
1658 | struct ov7670_info *info = to_state(sd); | ||
1564 | 1659 | ||
1565 | v4l2_device_unregister_subdev(sd); | 1660 | v4l2_device_unregister_subdev(sd); |
1566 | kfree(to_state(sd)); | 1661 | v4l2_ctrl_handler_free(&info->hdl); |
1662 | kfree(info); | ||
1567 | return 0; | 1663 | return 0; |
1568 | } | 1664 | } |
1569 | 1665 | ||
1570 | static const struct i2c_device_id ov7670_id[] = { | 1666 | static const struct i2c_device_id ov7670_id[] = { |
1571 | { "ov7670", 0 }, | 1667 | { "ov7670", MODEL_OV7670 }, |
1668 | { "ov7675", MODEL_OV7675 }, | ||
1572 | { } | 1669 | { } |
1573 | }; | 1670 | }; |
1574 | MODULE_DEVICE_TABLE(i2c, ov7670_id); | 1671 | MODULE_DEVICE_TABLE(i2c, ov7670_id); |
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c new file mode 100644 index 000000000000..1dbb8118a285 --- /dev/null +++ b/drivers/media/i2c/ov9650.c | |||
@@ -0,0 +1,1562 @@ | |||
1 | /* | ||
2 | * Omnivision OV9650/OV9652 CMOS Image Sensor driver | ||
3 | * | ||
4 | * Copyright (C) 2013, Sylwester Nawrocki <sylvester.nawrocki@gmail.com> | ||
5 | * | ||
6 | * Register definitions and initial settings based on a driver written | ||
7 | * by Vladimir Fonov. | ||
8 | * Copyright (c) 2010, Vladimir Fonov | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/gpio.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/media.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/ratelimit.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/videodev2.h> | ||
24 | |||
25 | #include <media/media-entity.h> | ||
26 | #include <media/v4l2-ctrls.h> | ||
27 | #include <media/v4l2-device.h> | ||
28 | #include <media/v4l2-event.h> | ||
29 | #include <media/v4l2-image-sizes.h> | ||
30 | #include <media/v4l2-subdev.h> | ||
31 | #include <media/v4l2-mediabus.h> | ||
32 | #include <media/ov9650.h> | ||
33 | |||
34 | static int debug; | ||
35 | module_param(debug, int, 0644); | ||
36 | MODULE_PARM_DESC(debug, "Debug level (0-2)"); | ||
37 | |||
38 | #define DRIVER_NAME "OV9650" | ||
39 | |||
40 | /* | ||
41 | * OV9650/OV9652 register definitions | ||
42 | */ | ||
43 | #define REG_GAIN 0x00 /* Gain control, AGC[7:0] */ | ||
44 | #define REG_BLUE 0x01 /* AWB - Blue chanel gain */ | ||
45 | #define REG_RED 0x02 /* AWB - Red chanel gain */ | ||
46 | #define REG_VREF 0x03 /* [7:6] - AGC[9:8], [5:3]/[2:0] */ | ||
47 | #define VREF_GAIN_MASK 0xc0 /* - VREF end/start low 3 bits */ | ||
48 | #define REG_COM1 0x04 | ||
49 | #define COM1_CCIR656 0x40 | ||
50 | #define REG_B_AVE 0x05 | ||
51 | #define REG_GB_AVE 0x06 | ||
52 | #define REG_GR_AVE 0x07 | ||
53 | #define REG_R_AVE 0x08 | ||
54 | #define REG_COM2 0x09 | ||
55 | #define REG_PID 0x0a /* Product ID MSB */ | ||
56 | #define REG_VER 0x0b /* Product ID LSB */ | ||
57 | #define REG_COM3 0x0c | ||
58 | #define COM3_SWAP 0x40 | ||
59 | #define COM3_VARIOPIXEL1 0x04 | ||
60 | #define REG_COM4 0x0d /* Vario Pixels */ | ||
61 | #define COM4_VARIOPIXEL2 0x80 | ||
62 | #define REG_COM5 0x0e /* System clock options */ | ||
63 | #define COM5_SLAVE_MODE 0x10 | ||
64 | #define COM5_SYSTEMCLOCK48MHZ 0x80 | ||
65 | #define REG_COM6 0x0f /* HREF & ADBLC options */ | ||
66 | #define REG_AECH 0x10 /* Exposure value, AEC[9:2] */ | ||
67 | #define REG_CLKRC 0x11 /* Clock control */ | ||
68 | #define CLK_EXT 0x40 /* Use external clock directly */ | ||
69 | #define CLK_SCALE 0x3f /* Mask for internal clock scale */ | ||
70 | #define REG_COM7 0x12 /* SCCB reset, output format */ | ||
71 | #define COM7_RESET 0x80 | ||
72 | #define COM7_FMT_MASK 0x38 | ||
73 | #define COM7_FMT_VGA 0x40 | ||
74 | #define COM7_FMT_CIF 0x20 | ||
75 | #define COM7_FMT_QVGA 0x10 | ||
76 | #define COM7_FMT_QCIF 0x08 | ||
77 | #define COM7_RGB 0x04 | ||
78 | #define COM7_YUV 0x00 | ||
79 | #define COM7_BAYER 0x01 | ||
80 | #define COM7_PBAYER 0x05 | ||
81 | #define REG_COM8 0x13 /* AGC/AEC options */ | ||
82 | #define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ | ||
83 | #define COM8_AECSTEP 0x40 /* Unlimited AEC step size */ | ||
84 | #define COM8_BFILT 0x20 /* Band filter enable */ | ||
85 | #define COM8_AGC 0x04 /* Auto gain enable */ | ||
86 | #define COM8_AWB 0x02 /* White balance enable */ | ||
87 | #define COM8_AEC 0x01 /* Auto exposure enable */ | ||
88 | #define REG_COM9 0x14 /* Gain ceiling */ | ||
89 | #define COM9_GAIN_CEIL_MASK 0x70 /* */ | ||
90 | #define REG_COM10 0x15 /* PCLK, HREF, HSYNC signals polarity */ | ||
91 | #define COM10_HSYNC 0x40 /* HSYNC instead of HREF */ | ||
92 | #define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */ | ||
93 | #define COM10_HREF_REV 0x08 /* Reverse HREF */ | ||
94 | #define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */ | ||
95 | #define COM10_VS_NEG 0x02 /* VSYNC negative */ | ||
96 | #define COM10_HS_NEG 0x01 /* HSYNC negative */ | ||
97 | #define REG_HSTART 0x17 /* Horiz start high bits */ | ||
98 | #define REG_HSTOP 0x18 /* Horiz stop high bits */ | ||
99 | #define REG_VSTART 0x19 /* Vert start high bits */ | ||
100 | #define REG_VSTOP 0x1a /* Vert stop high bits */ | ||
101 | #define REG_PSHFT 0x1b /* Pixel delay after HREF */ | ||
102 | #define REG_MIDH 0x1c /* Manufacturer ID MSB */ | ||
103 | #define REG_MIDL 0x1d /* Manufufacturer ID LSB */ | ||
104 | #define REG_MVFP 0x1e /* Image mirror/flip */ | ||
105 | #define MVFP_MIRROR 0x20 /* Mirror image */ | ||
106 | #define MVFP_FLIP 0x10 /* Vertical flip */ | ||
107 | #define REG_BOS 0x20 /* B channel Offset */ | ||
108 | #define REG_GBOS 0x21 /* Gb channel Offset */ | ||
109 | #define REG_GROS 0x22 /* Gr channel Offset */ | ||
110 | #define REG_ROS 0x23 /* R channel Offset */ | ||
111 | #define REG_AEW 0x24 /* AGC upper limit */ | ||
112 | #define REG_AEB 0x25 /* AGC lower limit */ | ||
113 | #define REG_VPT 0x26 /* AGC/AEC fast mode op region */ | ||
114 | #define REG_BBIAS 0x27 /* B channel output bias */ | ||
115 | #define REG_GBBIAS 0x28 /* Gb channel output bias */ | ||
116 | #define REG_GRCOM 0x29 /* Analog BLC & regulator */ | ||
117 | #define REG_EXHCH 0x2a /* Dummy pixel insert MSB */ | ||
118 | #define REG_EXHCL 0x2b /* Dummy pixel insert LSB */ | ||
119 | #define REG_RBIAS 0x2c /* R channel output bias */ | ||
120 | #define REG_ADVFL 0x2d /* LSB of dummy line insert */ | ||
121 | #define REG_ADVFH 0x2e /* MSB of dummy line insert */ | ||
122 | #define REG_YAVE 0x2f /* Y/G channel average value */ | ||
123 | #define REG_HSYST 0x30 /* HSYNC rising edge delay LSB*/ | ||
124 | #define REG_HSYEN 0x31 /* HSYNC falling edge delay LSB*/ | ||
125 | #define REG_HREF 0x32 /* HREF pieces */ | ||
126 | #define REG_CHLF 0x33 /* reserved */ | ||
127 | #define REG_ADC 0x37 /* reserved */ | ||
128 | #define REG_ACOM 0x38 /* reserved */ | ||
129 | #define REG_OFON 0x39 /* Power down register */ | ||
130 | #define OFON_PWRDN 0x08 /* Power down bit */ | ||
131 | #define REG_TSLB 0x3a /* YUVU format */ | ||
132 | #define TSLB_YUYV_MASK 0x0c /* UYVY or VYUY - see com13 */ | ||
133 | #define REG_COM11 0x3b /* Night mode, banding filter enable */ | ||
134 | #define COM11_NIGHT 0x80 /* Night mode enable */ | ||
135 | #define COM11_NMFR 0x60 /* Two bit NM frame rate */ | ||
136 | #define COM11_BANDING 0x01 /* Banding filter */ | ||
137 | #define COM11_AEC_REF_MASK 0x18 /* AEC reference area selection */ | ||
138 | #define REG_COM12 0x3c /* HREF option, UV average */ | ||
139 | #define COM12_HREF 0x80 /* HREF always */ | ||
140 | #define REG_COM13 0x3d /* Gamma selection, Color matrix en. */ | ||
141 | #define COM13_GAMMA 0x80 /* Gamma enable */ | ||
142 | #define COM13_UVSAT 0x40 /* UV saturation auto adjustment */ | ||
143 | #define COM13_UVSWAP 0x01 /* V before U - w/TSLB */ | ||
144 | #define REG_COM14 0x3e /* Edge enhancement options */ | ||
145 | #define COM14_EDGE_EN 0x02 | ||
146 | #define COM14_EEF_X2 0x01 | ||
147 | #define REG_EDGE 0x3f /* Edge enhancement factor */ | ||
148 | #define EDGE_FACTOR_MASK 0x0f | ||
149 | #define REG_COM15 0x40 /* Output range, RGB 555/565 */ | ||
150 | #define COM15_R10F0 0x00 /* Data range 10 to F0 */ | ||
151 | #define COM15_R01FE 0x80 /* 01 to FE */ | ||
152 | #define COM15_R00FF 0xc0 /* 00 to FF */ | ||
153 | #define COM15_RGB565 0x10 /* RGB565 output */ | ||
154 | #define COM15_RGB555 0x30 /* RGB555 output */ | ||
155 | #define COM15_SWAPRB 0x04 /* Swap R&B */ | ||
156 | #define REG_COM16 0x41 /* Color matrix coeff options */ | ||
157 | #define REG_COM17 0x42 /* Single frame out, banding filter */ | ||
158 | /* n = 1...9, 0x4f..0x57 */ | ||
159 | #define REG_MTX(__n) (0x4f + (__n) - 1) | ||
160 | #define REG_MTXS 0x58 | ||
161 | /* Lens Correction Option 1...5, __n = 0...5 */ | ||
162 | #define REG_LCC(__n) (0x62 + (__n) - 1) | ||
163 | #define LCC5_LCC_ENABLE 0x01 /* LCC5, enable lens correction */ | ||
164 | #define LCC5_LCC_COLOR 0x04 | ||
165 | #define REG_MANU 0x67 /* Manual U value */ | ||
166 | #define REG_MANV 0x68 /* Manual V value */ | ||
167 | #define REG_HV 0x69 /* Manual banding filter MSB */ | ||
168 | #define REG_MBD 0x6a /* Manual banding filter value */ | ||
169 | #define REG_DBLV 0x6b /* reserved */ | ||
170 | #define REG_GSP 0x6c /* Gamma curve */ | ||
171 | #define GSP_LEN 15 | ||
172 | #define REG_GST 0x7c /* Gamma curve */ | ||
173 | #define GST_LEN 15 | ||
174 | #define REG_COM21 0x8b | ||
175 | #define REG_COM22 0x8c /* Edge enhancement, denoising */ | ||
176 | #define COM22_WHTPCOR 0x02 /* White pixel correction enable */ | ||
177 | #define COM22_WHTPCOROPT 0x01 /* White pixel correction option */ | ||
178 | #define COM22_DENOISE 0x10 /* White pixel correction option */ | ||
179 | #define REG_COM23 0x8d /* Color bar test, color gain */ | ||
180 | #define COM23_TEST_MODE 0x10 | ||
181 | #define REG_DBLC1 0x8f /* Digital BLC */ | ||
182 | #define REG_DBLC_B 0x90 /* Digital BLC B channel offset */ | ||
183 | #define REG_DBLC_R 0x91 /* Digital BLC R channel offset */ | ||
184 | #define REG_DM_LNL 0x92 /* Dummy line low 8 bits */ | ||
185 | #define REG_DM_LNH 0x93 /* Dummy line high 8 bits */ | ||
186 | #define REG_LCCFB 0x9d /* Lens Correction B channel */ | ||
187 | #define REG_LCCFR 0x9e /* Lens Correction R channel */ | ||
188 | #define REG_DBLC_GB 0x9f /* Digital BLC GB chan offset */ | ||
189 | #define REG_DBLC_GR 0xa0 /* Digital BLC GR chan offset */ | ||
190 | #define REG_AECHM 0xa1 /* Exposure value - bits AEC[15:10] */ | ||
191 | #define REG_BD50ST 0xa2 /* Banding filter value for 50Hz */ | ||
192 | #define REG_BD60ST 0xa3 /* Banding filter value for 60Hz */ | ||
193 | #define REG_NULL 0xff /* Array end token */ | ||
194 | |||
195 | #define DEF_CLKRC 0x80 | ||
196 | |||
197 | #define OV965X_ID(_msb, _lsb) ((_msb) << 8 | (_lsb)) | ||
198 | #define OV9650_ID 0x9650 | ||
199 | #define OV9652_ID 0x9652 | ||
200 | |||
201 | struct ov965x_ctrls { | ||
202 | struct v4l2_ctrl_handler handler; | ||
203 | struct { | ||
204 | struct v4l2_ctrl *auto_exp; | ||
205 | struct v4l2_ctrl *exposure; | ||
206 | }; | ||
207 | struct { | ||
208 | struct v4l2_ctrl *auto_wb; | ||
209 | struct v4l2_ctrl *blue_balance; | ||
210 | struct v4l2_ctrl *red_balance; | ||
211 | }; | ||
212 | struct { | ||
213 | struct v4l2_ctrl *hflip; | ||
214 | struct v4l2_ctrl *vflip; | ||
215 | }; | ||
216 | struct { | ||
217 | struct v4l2_ctrl *auto_gain; | ||
218 | struct v4l2_ctrl *gain; | ||
219 | }; | ||
220 | struct v4l2_ctrl *brightness; | ||
221 | struct v4l2_ctrl *saturation; | ||
222 | struct v4l2_ctrl *sharpness; | ||
223 | struct v4l2_ctrl *light_freq; | ||
224 | u8 update; | ||
225 | }; | ||
226 | |||
227 | struct ov965x_framesize { | ||
228 | u16 width; | ||
229 | u16 height; | ||
230 | u16 max_exp_lines; | ||
231 | const u8 *regs; | ||
232 | }; | ||
233 | |||
234 | struct ov965x_interval { | ||
235 | struct v4l2_fract interval; | ||
236 | /* Maximum resolution for this interval */ | ||
237 | struct v4l2_frmsize_discrete size; | ||
238 | u8 clkrc_div; | ||
239 | }; | ||
240 | |||
241 | enum gpio_id { | ||
242 | GPIO_PWDN, | ||
243 | GPIO_RST, | ||
244 | NUM_GPIOS, | ||
245 | }; | ||
246 | |||
247 | struct ov965x { | ||
248 | struct v4l2_subdev sd; | ||
249 | struct media_pad pad; | ||
250 | enum v4l2_mbus_type bus_type; | ||
251 | int gpios[NUM_GPIOS]; | ||
252 | /* External master clock frequency */ | ||
253 | unsigned long mclk_frequency; | ||
254 | |||
255 | /* Protects the struct fields below */ | ||
256 | struct mutex lock; | ||
257 | |||
258 | struct i2c_client *client; | ||
259 | |||
260 | /* Exposure row interval in us */ | ||
261 | unsigned int exp_row_interval; | ||
262 | |||
263 | unsigned short id; | ||
264 | const struct ov965x_framesize *frame_size; | ||
265 | /* YUYV sequence (pixel format) control register */ | ||
266 | u8 tslb_reg; | ||
267 | struct v4l2_mbus_framefmt format; | ||
268 | |||
269 | struct ov965x_ctrls ctrls; | ||
270 | /* Pointer to frame rate control data structure */ | ||
271 | const struct ov965x_interval *fiv; | ||
272 | |||
273 | int streaming; | ||
274 | int power; | ||
275 | |||
276 | u8 apply_frame_fmt; | ||
277 | }; | ||
278 | |||
279 | struct i2c_rv { | ||
280 | u8 addr; | ||
281 | u8 value; | ||
282 | }; | ||
283 | |||
284 | static const struct i2c_rv ov965x_init_regs[] = { | ||
285 | { REG_COM2, 0x10 }, /* Set soft sleep mode */ | ||
286 | { REG_COM5, 0x00 }, /* System clock options */ | ||
287 | { REG_COM2, 0x01 }, /* Output drive, soft sleep mode */ | ||
288 | { REG_COM10, 0x00 }, /* Slave mode, HREF vs HSYNC, signals negate */ | ||
289 | { REG_EDGE, 0xa6 }, /* Edge enhancement treshhold and factor */ | ||
290 | { REG_COM16, 0x02 }, /* Color matrix coeff double option */ | ||
291 | { REG_COM17, 0x08 }, /* Single frame out, banding filter */ | ||
292 | { 0x16, 0x06 }, | ||
293 | { REG_CHLF, 0xc0 }, /* Reserved */ | ||
294 | { 0x34, 0xbf }, | ||
295 | { 0xa8, 0x80 }, | ||
296 | { 0x96, 0x04 }, | ||
297 | { 0x8e, 0x00 }, | ||
298 | { REG_COM12, 0x77 }, /* HREF option, UV average */ | ||
299 | { 0x8b, 0x06 }, | ||
300 | { 0x35, 0x91 }, | ||
301 | { 0x94, 0x88 }, | ||
302 | { 0x95, 0x88 }, | ||
303 | { REG_COM15, 0xc1 }, /* Output range, RGB 555/565 */ | ||
304 | { REG_GRCOM, 0x2f }, /* Analog BLC & regulator */ | ||
305 | { REG_COM6, 0x43 }, /* HREF & ADBLC options */ | ||
306 | { REG_COM8, 0xe5 }, /* AGC/AEC options */ | ||
307 | { REG_COM13, 0x90 }, /* Gamma selection, colour matrix, UV delay */ | ||
308 | { REG_HV, 0x80 }, /* Manual banding filter MSB */ | ||
309 | { 0x5c, 0x96 }, /* Reserved up to 0xa5 */ | ||
310 | { 0x5d, 0x96 }, | ||
311 | { 0x5e, 0x10 }, | ||
312 | { 0x59, 0xeb }, | ||
313 | { 0x5a, 0x9c }, | ||
314 | { 0x5b, 0x55 }, | ||
315 | { 0x43, 0xf0 }, | ||
316 | { 0x44, 0x10 }, | ||
317 | { 0x45, 0x55 }, | ||
318 | { 0x46, 0x86 }, | ||
319 | { 0x47, 0x64 }, | ||
320 | { 0x48, 0x86 }, | ||
321 | { 0x5f, 0xe0 }, | ||
322 | { 0x60, 0x8c }, | ||
323 | { 0x61, 0x20 }, | ||
324 | { 0xa5, 0xd9 }, | ||
325 | { 0xa4, 0x74 }, /* reserved */ | ||
326 | { REG_COM23, 0x02 }, /* Color gain analog/_digital_ */ | ||
327 | { REG_COM8, 0xe7 }, /* Enable AEC, AWB, AEC */ | ||
328 | { REG_COM22, 0x23 }, /* Edge enhancement, denoising */ | ||
329 | { 0xa9, 0xb8 }, | ||
330 | { 0xaa, 0x92 }, | ||
331 | { 0xab, 0x0a }, | ||
332 | { REG_DBLC1, 0xdf }, /* Digital BLC */ | ||
333 | { REG_DBLC_B, 0x00 }, /* Digital BLC B chan offset */ | ||
334 | { REG_DBLC_R, 0x00 }, /* Digital BLC R chan offset */ | ||
335 | { REG_DBLC_GB, 0x00 }, /* Digital BLC GB chan offset */ | ||
336 | { REG_DBLC_GR, 0x00 }, | ||
337 | { REG_COM9, 0x3a }, /* Gain ceiling 16x */ | ||
338 | { REG_NULL, 0 } | ||
339 | }; | ||
340 | |||
341 | #define NUM_FMT_REGS 14 | ||
342 | /* | ||
343 | * COM7, COM3, COM4, HSTART, HSTOP, HREF, VSTART, VSTOP, VREF, | ||
344 | * EXHCH, EXHCL, ADC, OCOM, OFON | ||
345 | */ | ||
346 | static const u8 frame_size_reg_addr[NUM_FMT_REGS] = { | ||
347 | 0x12, 0x0c, 0x0d, 0x17, 0x18, 0x32, 0x19, 0x1a, 0x03, | ||
348 | 0x2a, 0x2b, 0x37, 0x38, 0x39, | ||
349 | }; | ||
350 | |||
351 | static const u8 ov965x_sxga_regs[NUM_FMT_REGS] = { | ||
352 | 0x00, 0x00, 0x00, 0x1e, 0xbe, 0xbf, 0x01, 0x81, 0x12, | ||
353 | 0x10, 0x34, 0x81, 0x93, 0x51, | ||
354 | }; | ||
355 | |||
356 | static const u8 ov965x_vga_regs[NUM_FMT_REGS] = { | ||
357 | 0x40, 0x04, 0x80, 0x26, 0xc6, 0xed, 0x01, 0x3d, 0x00, | ||
358 | 0x10, 0x40, 0x91, 0x12, 0x43, | ||
359 | }; | ||
360 | |||
361 | /* Determined empirically. */ | ||
362 | static const u8 ov965x_qvga_regs[NUM_FMT_REGS] = { | ||
363 | 0x10, 0x04, 0x80, 0x25, 0xc5, 0xbf, 0x00, 0x80, 0x12, | ||
364 | 0x10, 0x40, 0x91, 0x12, 0x43, | ||
365 | }; | ||
366 | |||
367 | static const struct ov965x_framesize ov965x_framesizes[] = { | ||
368 | { | ||
369 | .width = SXGA_WIDTH, | ||
370 | .height = SXGA_HEIGHT, | ||
371 | .regs = ov965x_sxga_regs, | ||
372 | .max_exp_lines = 1048, | ||
373 | }, { | ||
374 | .width = VGA_WIDTH, | ||
375 | .height = VGA_HEIGHT, | ||
376 | .regs = ov965x_vga_regs, | ||
377 | .max_exp_lines = 498, | ||
378 | }, { | ||
379 | .width = QVGA_WIDTH, | ||
380 | .height = QVGA_HEIGHT, | ||
381 | .regs = ov965x_qvga_regs, | ||
382 | .max_exp_lines = 248, | ||
383 | }, | ||
384 | }; | ||
385 | |||
386 | struct ov965x_pixfmt { | ||
387 | enum v4l2_mbus_pixelcode code; | ||
388 | u32 colorspace; | ||
389 | /* REG_TSLB value, only bits [3:2] may be set. */ | ||
390 | u8 tslb_reg; | ||
391 | }; | ||
392 | |||
393 | static const struct ov965x_pixfmt ov965x_formats[] = { | ||
394 | { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 0x00}, | ||
395 | { V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG, 0x04}, | ||
396 | { V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG, 0x0c}, | ||
397 | { V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG, 0x08}, | ||
398 | }; | ||
399 | |||
400 | /* | ||
401 | * This table specifies possible frame resolution and interval | ||
402 | * combinations. Default CLKRC[5:0] divider values are valid | ||
403 | * only for 24 MHz external clock frequency. | ||
404 | */ | ||
405 | static struct ov965x_interval ov965x_intervals[] = { | ||
406 | {{ 100, 625 }, { SXGA_WIDTH, SXGA_HEIGHT }, 0 }, /* 6.25 fps */ | ||
407 | {{ 10, 125 }, { VGA_WIDTH, VGA_HEIGHT }, 1 }, /* 12.5 fps */ | ||
408 | {{ 10, 125 }, { QVGA_WIDTH, QVGA_HEIGHT }, 3 }, /* 12.5 fps */ | ||
409 | {{ 1, 25 }, { VGA_WIDTH, VGA_HEIGHT }, 0 }, /* 25 fps */ | ||
410 | {{ 1, 25 }, { QVGA_WIDTH, QVGA_HEIGHT }, 1 }, /* 25 fps */ | ||
411 | }; | ||
412 | |||
413 | static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) | ||
414 | { | ||
415 | return &container_of(ctrl->handler, struct ov965x, ctrls.handler)->sd; | ||
416 | } | ||
417 | |||
418 | static inline struct ov965x *to_ov965x(struct v4l2_subdev *sd) | ||
419 | { | ||
420 | return container_of(sd, struct ov965x, sd); | ||
421 | } | ||
422 | |||
423 | static int ov965x_read(struct i2c_client *client, u8 addr, u8 *val) | ||
424 | { | ||
425 | u8 buf = addr; | ||
426 | struct i2c_msg msg = { | ||
427 | .addr = client->addr, | ||
428 | .flags = 0, | ||
429 | .len = 1, | ||
430 | .buf = &buf | ||
431 | }; | ||
432 | int ret; | ||
433 | |||
434 | ret = i2c_transfer(client->adapter, &msg, 1); | ||
435 | if (ret == 1) { | ||
436 | msg.flags = I2C_M_RD; | ||
437 | ret = i2c_transfer(client->adapter, &msg, 1); | ||
438 | |||
439 | if (ret == 1) | ||
440 | *val = buf; | ||
441 | } | ||
442 | |||
443 | v4l2_dbg(2, debug, client, "%s: 0x%02x @ 0x%02x. (%d)\n", | ||
444 | __func__, *val, addr, ret); | ||
445 | |||
446 | return ret == 1 ? 0 : ret; | ||
447 | } | ||
448 | |||
449 | static int ov965x_write(struct i2c_client *client, u8 addr, u8 val) | ||
450 | { | ||
451 | u8 buf[2] = { addr, val }; | ||
452 | |||
453 | int ret = i2c_master_send(client, buf, 2); | ||
454 | |||
455 | v4l2_dbg(2, debug, client, "%s: 0x%02x @ 0x%02X (%d)\n", | ||
456 | __func__, val, addr, ret); | ||
457 | |||
458 | return ret == 2 ? 0 : ret; | ||
459 | } | ||
460 | |||
461 | static int ov965x_write_array(struct i2c_client *client, | ||
462 | const struct i2c_rv *regs) | ||
463 | { | ||
464 | int i, ret = 0; | ||
465 | |||
466 | for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++) | ||
467 | ret = ov965x_write(client, regs[i].addr, regs[i].value); | ||
468 | |||
469 | return ret; | ||
470 | } | ||
471 | |||
472 | static int ov965x_set_default_gamma_curve(struct ov965x *ov965x) | ||
473 | { | ||
474 | static const u8 gamma_curve[] = { | ||
475 | /* Values taken from OV application note. */ | ||
476 | 0x40, 0x30, 0x4b, 0x60, 0x70, 0x70, 0x70, 0x70, | ||
477 | 0x60, 0x60, 0x50, 0x48, 0x3a, 0x2e, 0x28, 0x22, | ||
478 | 0x04, 0x07, 0x10, 0x28, 0x36, 0x44, 0x52, 0x60, | ||
479 | 0x6c, 0x78, 0x8c, 0x9e, 0xbb, 0xd2, 0xe6 | ||
480 | }; | ||
481 | u8 addr = REG_GSP; | ||
482 | unsigned int i; | ||
483 | |||
484 | for (i = 0; i < ARRAY_SIZE(gamma_curve); i++) { | ||
485 | int ret = ov965x_write(ov965x->client, addr, gamma_curve[i]); | ||
486 | if (ret < 0) | ||
487 | return ret; | ||
488 | addr++; | ||
489 | } | ||
490 | |||
491 | return 0; | ||
492 | }; | ||
493 | |||
494 | static int ov965x_set_color_matrix(struct ov965x *ov965x) | ||
495 | { | ||
496 | static const u8 mtx[] = { | ||
497 | /* MTX1..MTX9, MTXS */ | ||
498 | 0x3a, 0x3d, 0x03, 0x12, 0x26, 0x38, 0x40, 0x40, 0x40, 0x0d | ||
499 | }; | ||
500 | u8 addr = REG_MTX(1); | ||
501 | unsigned int i; | ||
502 | |||
503 | for (i = 0; i < ARRAY_SIZE(mtx); i++) { | ||
504 | int ret = ov965x_write(ov965x->client, addr, mtx[i]); | ||
505 | if (ret < 0) | ||
506 | return ret; | ||
507 | addr++; | ||
508 | } | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static void ov965x_gpio_set(int gpio, int val) | ||
514 | { | ||
515 | if (gpio_is_valid(gpio)) | ||
516 | gpio_set_value(gpio, val); | ||
517 | } | ||
518 | |||
519 | static void __ov965x_set_power(struct ov965x *ov965x, int on) | ||
520 | { | ||
521 | if (on) { | ||
522 | ov965x_gpio_set(ov965x->gpios[GPIO_PWDN], 0); | ||
523 | ov965x_gpio_set(ov965x->gpios[GPIO_RST], 0); | ||
524 | usleep_range(25000, 26000); | ||
525 | } else { | ||
526 | ov965x_gpio_set(ov965x->gpios[GPIO_RST], 1); | ||
527 | ov965x_gpio_set(ov965x->gpios[GPIO_PWDN], 1); | ||
528 | } | ||
529 | |||
530 | ov965x->streaming = 0; | ||
531 | } | ||
532 | |||
533 | static int ov965x_s_power(struct v4l2_subdev *sd, int on) | ||
534 | { | ||
535 | struct ov965x *ov965x = to_ov965x(sd); | ||
536 | struct i2c_client *client = ov965x->client; | ||
537 | int ret = 0; | ||
538 | |||
539 | v4l2_dbg(1, debug, client, "%s: on: %d\n", __func__, on); | ||
540 | |||
541 | mutex_lock(&ov965x->lock); | ||
542 | if (ov965x->power == !on) { | ||
543 | __ov965x_set_power(ov965x, on); | ||
544 | if (on) { | ||
545 | ret = ov965x_write_array(client, | ||
546 | ov965x_init_regs); | ||
547 | ov965x->apply_frame_fmt = 1; | ||
548 | ov965x->ctrls.update = 1; | ||
549 | } | ||
550 | } | ||
551 | if (!ret) | ||
552 | ov965x->power += on ? 1 : -1; | ||
553 | |||
554 | WARN_ON(ov965x->power < 0); | ||
555 | mutex_unlock(&ov965x->lock); | ||
556 | return ret; | ||
557 | } | ||
558 | |||
559 | /* | ||
560 | * V4L2 controls | ||
561 | */ | ||
562 | |||
563 | static void ov965x_update_exposure_ctrl(struct ov965x *ov965x) | ||
564 | { | ||
565 | struct v4l2_ctrl *ctrl = ov965x->ctrls.exposure; | ||
566 | unsigned long fint, trow; | ||
567 | int min, max, def; | ||
568 | u8 clkrc; | ||
569 | |||
570 | mutex_lock(&ov965x->lock); | ||
571 | if (WARN_ON(!ctrl || !ov965x->frame_size)) { | ||
572 | mutex_unlock(&ov965x->lock); | ||
573 | return; | ||
574 | } | ||
575 | clkrc = DEF_CLKRC + ov965x->fiv->clkrc_div; | ||
576 | /* Calculate internal clock frequency */ | ||
577 | fint = ov965x->mclk_frequency * ((clkrc >> 7) + 1) / | ||
578 | ((2 * ((clkrc & 0x3f) + 1))); | ||
579 | /* and the row interval (in us). */ | ||
580 | trow = (2 * 1520 * 1000000UL) / fint; | ||
581 | max = ov965x->frame_size->max_exp_lines * trow; | ||
582 | ov965x->exp_row_interval = trow; | ||
583 | mutex_unlock(&ov965x->lock); | ||
584 | |||
585 | v4l2_dbg(1, debug, &ov965x->sd, "clkrc: %#x, fi: %lu, tr: %lu, %d\n", | ||
586 | clkrc, fint, trow, max); | ||
587 | |||
588 | /* Update exposure time range to match current frame format. */ | ||
589 | min = (trow + 100) / 100; | ||
590 | max = (max - 100) / 100; | ||
591 | def = min + (max - min) / 2; | ||
592 | |||
593 | if (v4l2_ctrl_modify_range(ctrl, min, max, 1, def)) | ||
594 | v4l2_err(&ov965x->sd, "Exposure ctrl range update failed\n"); | ||
595 | } | ||
596 | |||
597 | static int ov965x_set_banding_filter(struct ov965x *ov965x, int value) | ||
598 | { | ||
599 | unsigned long mbd, light_freq; | ||
600 | int ret; | ||
601 | u8 reg; | ||
602 | |||
603 | ret = ov965x_read(ov965x->client, REG_COM8, ®); | ||
604 | if (!ret) { | ||
605 | if (value == V4L2_CID_POWER_LINE_FREQUENCY_DISABLED) | ||
606 | reg &= ~COM8_BFILT; | ||
607 | else | ||
608 | reg |= COM8_BFILT; | ||
609 | ret = ov965x_write(ov965x->client, REG_COM8, reg); | ||
610 | } | ||
611 | if (value == V4L2_CID_POWER_LINE_FREQUENCY_DISABLED) | ||
612 | return 0; | ||
613 | if (WARN_ON(ov965x->fiv == NULL)) | ||
614 | return -EINVAL; | ||
615 | /* Set minimal exposure time for 50/60 HZ lighting */ | ||
616 | if (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) | ||
617 | light_freq = 50; | ||
618 | else | ||
619 | light_freq = 60; | ||
620 | mbd = (1000UL * ov965x->fiv->interval.denominator * | ||
621 | ov965x->frame_size->max_exp_lines) / | ||
622 | ov965x->fiv->interval.numerator; | ||
623 | mbd = ((mbd / (light_freq * 2)) + 500) / 1000UL; | ||
624 | |||
625 | return ov965x_write(ov965x->client, REG_MBD, mbd); | ||
626 | } | ||
627 | |||
628 | static int ov965x_set_white_balance(struct ov965x *ov965x, int awb) | ||
629 | { | ||
630 | int ret; | ||
631 | u8 reg; | ||
632 | |||
633 | ret = ov965x_read(ov965x->client, REG_COM8, ®); | ||
634 | if (!ret) { | ||
635 | reg = awb ? reg | REG_COM8 : reg & ~REG_COM8; | ||
636 | ret = ov965x_write(ov965x->client, REG_COM8, reg); | ||
637 | } | ||
638 | if (!ret && !awb) { | ||
639 | ret = ov965x_write(ov965x->client, REG_BLUE, | ||
640 | ov965x->ctrls.blue_balance->val); | ||
641 | if (ret < 0) | ||
642 | return ret; | ||
643 | ret = ov965x_write(ov965x->client, REG_RED, | ||
644 | ov965x->ctrls.red_balance->val); | ||
645 | } | ||
646 | return ret; | ||
647 | } | ||
648 | |||
649 | #define NUM_BR_LEVELS 7 | ||
650 | #define NUM_BR_REGS 3 | ||
651 | |||
652 | static int ov965x_set_brightness(struct ov965x *ov965x, int val) | ||
653 | { | ||
654 | static const u8 regs[NUM_BR_LEVELS + 1][NUM_BR_REGS] = { | ||
655 | { REG_AEW, REG_AEB, REG_VPT }, | ||
656 | { 0x1c, 0x12, 0x50 }, /* -3 */ | ||
657 | { 0x3d, 0x30, 0x71 }, /* -2 */ | ||
658 | { 0x50, 0x44, 0x92 }, /* -1 */ | ||
659 | { 0x70, 0x64, 0xc3 }, /* 0 */ | ||
660 | { 0x90, 0x84, 0xd4 }, /* +1 */ | ||
661 | { 0xc4, 0xbf, 0xf9 }, /* +2 */ | ||
662 | { 0xd8, 0xd0, 0xfa }, /* +3 */ | ||
663 | }; | ||
664 | int i, ret = 0; | ||
665 | |||
666 | val += (NUM_BR_LEVELS / 2 + 1); | ||
667 | if (val > NUM_BR_LEVELS) | ||
668 | return -EINVAL; | ||
669 | |||
670 | for (i = 0; i < NUM_BR_REGS && !ret; i++) | ||
671 | ret = ov965x_write(ov965x->client, regs[0][i], | ||
672 | regs[val][i]); | ||
673 | return ret; | ||
674 | } | ||
675 | |||
676 | static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain) | ||
677 | { | ||
678 | struct i2c_client *client = ov965x->client; | ||
679 | struct ov965x_ctrls *ctrls = &ov965x->ctrls; | ||
680 | int ret = 0; | ||
681 | u8 reg; | ||
682 | /* | ||
683 | * For manual mode we need to disable AGC first, so | ||
684 | * gain value in REG_VREF, REG_GAIN is not overwritten. | ||
685 | */ | ||
686 | if (ctrls->auto_gain->is_new) { | ||
687 | ret = ov965x_read(client, REG_COM8, ®); | ||
688 | if (ret < 0) | ||
689 | return ret; | ||
690 | if (ctrls->auto_gain->val) | ||
691 | reg |= COM8_AGC; | ||
692 | else | ||
693 | reg &= ~COM8_AGC; | ||
694 | ret = ov965x_write(client, REG_COM8, reg); | ||
695 | if (ret < 0) | ||
696 | return ret; | ||
697 | } | ||
698 | |||
699 | if (ctrls->gain->is_new && !auto_gain) { | ||
700 | unsigned int gain = ctrls->gain->val; | ||
701 | unsigned int rgain; | ||
702 | int m; | ||
703 | /* | ||
704 | * Convert gain control value to the sensor's gain | ||
705 | * registers (VREF[7:6], GAIN[7:0]) format. | ||
706 | */ | ||
707 | for (m = 6; m >= 0; m--) | ||
708 | if (gain >= (1 << m) * 16) | ||
709 | break; | ||
710 | rgain = (gain - ((1 << m) * 16)) / (1 << m); | ||
711 | rgain |= (((1 << m) - 1) << 4); | ||
712 | |||
713 | ret = ov965x_write(client, REG_GAIN, rgain & 0xff); | ||
714 | if (ret < 0) | ||
715 | return ret; | ||
716 | ret = ov965x_read(client, REG_VREF, ®); | ||
717 | if (ret < 0) | ||
718 | return ret; | ||
719 | reg &= ~VREF_GAIN_MASK; | ||
720 | reg |= (((rgain >> 8) & 0x3) << 6); | ||
721 | ret = ov965x_write(client, REG_VREF, reg); | ||
722 | if (ret < 0) | ||
723 | return ret; | ||
724 | /* Return updated control's value to userspace */ | ||
725 | ctrls->gain->val = (1 << m) * (16 + (rgain & 0xf)); | ||
726 | } | ||
727 | |||
728 | return ret; | ||
729 | } | ||
730 | |||
731 | static int ov965x_set_sharpness(struct ov965x *ov965x, unsigned int value) | ||
732 | { | ||
733 | u8 com14, edge; | ||
734 | int ret; | ||
735 | |||
736 | ret = ov965x_read(ov965x->client, REG_COM14, &com14); | ||
737 | if (ret < 0) | ||
738 | return ret; | ||
739 | ret = ov965x_read(ov965x->client, REG_EDGE, &edge); | ||
740 | if (ret < 0) | ||
741 | return ret; | ||
742 | com14 = value ? com14 | COM14_EDGE_EN : com14 & ~COM14_EDGE_EN; | ||
743 | value--; | ||
744 | if (value > 0x0f) { | ||
745 | com14 |= COM14_EEF_X2; | ||
746 | value >>= 1; | ||
747 | } else { | ||
748 | com14 &= ~COM14_EEF_X2; | ||
749 | } | ||
750 | ret = ov965x_write(ov965x->client, REG_COM14, com14); | ||
751 | if (ret < 0) | ||
752 | return ret; | ||
753 | |||
754 | edge &= ~EDGE_FACTOR_MASK; | ||
755 | edge |= ((u8)value & 0x0f); | ||
756 | |||
757 | return ov965x_write(ov965x->client, REG_EDGE, edge); | ||
758 | } | ||
759 | |||
760 | static int ov965x_set_exposure(struct ov965x *ov965x, int exp) | ||
761 | { | ||
762 | struct i2c_client *client = ov965x->client; | ||
763 | struct ov965x_ctrls *ctrls = &ov965x->ctrls; | ||
764 | bool auto_exposure = (exp == V4L2_EXPOSURE_AUTO); | ||
765 | int ret; | ||
766 | u8 reg; | ||
767 | |||
768 | if (ctrls->auto_exp->is_new) { | ||
769 | ret = ov965x_read(client, REG_COM8, ®); | ||
770 | if (ret < 0) | ||
771 | return ret; | ||
772 | if (auto_exposure) | ||
773 | reg |= (COM8_AEC | COM8_AGC); | ||
774 | else | ||
775 | reg &= ~(COM8_AEC | COM8_AGC); | ||
776 | ret = ov965x_write(client, REG_COM8, reg); | ||
777 | if (ret < 0) | ||
778 | return ret; | ||
779 | } | ||
780 | |||
781 | if (!auto_exposure && ctrls->exposure->is_new) { | ||
782 | unsigned int exposure = (ctrls->exposure->val * 100) | ||
783 | / ov965x->exp_row_interval; | ||
784 | /* | ||
785 | * Manual exposure value | ||
786 | * [b15:b0] - AECHM (b15:b10), AECH (b9:b2), COM1 (b1:b0) | ||
787 | */ | ||
788 | ret = ov965x_write(client, REG_COM1, exposure & 0x3); | ||
789 | if (!ret) | ||
790 | ret = ov965x_write(client, REG_AECH, | ||
791 | (exposure >> 2) & 0xff); | ||
792 | if (!ret) | ||
793 | ret = ov965x_write(client, REG_AECHM, | ||
794 | (exposure >> 10) & 0x3f); | ||
795 | /* Update the value to minimize rounding errors */ | ||
796 | ctrls->exposure->val = ((exposure * ov965x->exp_row_interval) | ||
797 | + 50) / 100; | ||
798 | if (ret < 0) | ||
799 | return ret; | ||
800 | } | ||
801 | |||
802 | v4l2_ctrl_activate(ov965x->ctrls.brightness, !exp); | ||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | static int ov965x_set_flip(struct ov965x *ov965x) | ||
807 | { | ||
808 | u8 mvfp = 0; | ||
809 | |||
810 | if (ov965x->ctrls.hflip->val) | ||
811 | mvfp |= MVFP_MIRROR; | ||
812 | |||
813 | if (ov965x->ctrls.vflip->val) | ||
814 | mvfp |= MVFP_FLIP; | ||
815 | |||
816 | return ov965x_write(ov965x->client, REG_MVFP, mvfp); | ||
817 | } | ||
818 | |||
819 | #define NUM_SAT_LEVELS 5 | ||
820 | #define NUM_SAT_REGS 6 | ||
821 | |||
822 | static int ov965x_set_saturation(struct ov965x *ov965x, int val) | ||
823 | { | ||
824 | static const u8 regs[NUM_SAT_LEVELS][NUM_SAT_REGS] = { | ||
825 | /* MTX(1)...MTX(6) */ | ||
826 | { 0x1d, 0x1f, 0x02, 0x09, 0x13, 0x1c }, /* -2 */ | ||
827 | { 0x2e, 0x31, 0x02, 0x0e, 0x1e, 0x2d }, /* -1 */ | ||
828 | { 0x3a, 0x3d, 0x03, 0x12, 0x26, 0x38 }, /* 0 */ | ||
829 | { 0x46, 0x49, 0x04, 0x16, 0x2e, 0x43 }, /* +1 */ | ||
830 | { 0x57, 0x5c, 0x05, 0x1b, 0x39, 0x54 }, /* +2 */ | ||
831 | }; | ||
832 | u8 addr = REG_MTX(1); | ||
833 | int i, ret = 0; | ||
834 | |||
835 | val += (NUM_SAT_LEVELS / 2); | ||
836 | if (val >= NUM_SAT_LEVELS) | ||
837 | return -EINVAL; | ||
838 | |||
839 | for (i = 0; i < NUM_SAT_REGS && !ret; i++) | ||
840 | ret = ov965x_write(ov965x->client, addr + i, regs[val][i]); | ||
841 | |||
842 | return ret; | ||
843 | } | ||
844 | |||
845 | static int ov965x_set_test_pattern(struct ov965x *ov965x, int value) | ||
846 | { | ||
847 | int ret; | ||
848 | u8 reg; | ||
849 | |||
850 | ret = ov965x_read(ov965x->client, REG_COM23, ®); | ||
851 | if (ret < 0) | ||
852 | return ret; | ||
853 | reg = value ? reg | COM23_TEST_MODE : reg & ~COM23_TEST_MODE; | ||
854 | return ov965x_write(ov965x->client, REG_COM23, reg); | ||
855 | } | ||
856 | |||
857 | static int __g_volatile_ctrl(struct ov965x *ov965x, struct v4l2_ctrl *ctrl) | ||
858 | { | ||
859 | struct i2c_client *client = ov965x->client; | ||
860 | unsigned int exposure, gain, m; | ||
861 | u8 reg0, reg1, reg2; | ||
862 | int ret; | ||
863 | |||
864 | if (!ov965x->power) | ||
865 | return 0; | ||
866 | |||
867 | switch (ctrl->id) { | ||
868 | case V4L2_CID_AUTOGAIN: | ||
869 | if (!ctrl->val) | ||
870 | return 0; | ||
871 | ret = ov965x_read(client, REG_GAIN, ®0); | ||
872 | if (ret < 0) | ||
873 | return ret; | ||
874 | ret = ov965x_read(client, REG_VREF, ®1); | ||
875 | if (ret < 0) | ||
876 | return ret; | ||
877 | gain = ((reg1 >> 6) << 8) | reg0; | ||
878 | m = 0x01 << fls(gain >> 4); | ||
879 | ov965x->ctrls.gain->val = m * (16 + (gain & 0xf)); | ||
880 | break; | ||
881 | |||
882 | case V4L2_CID_EXPOSURE_AUTO: | ||
883 | if (ctrl->val == V4L2_EXPOSURE_MANUAL) | ||
884 | return 0; | ||
885 | ret = ov965x_read(client, REG_COM1, ®0); | ||
886 | if (!ret) | ||
887 | ret = ov965x_read(client, REG_AECH, ®1); | ||
888 | if (!ret) | ||
889 | ret = ov965x_read(client, REG_AECHM, ®2); | ||
890 | if (ret < 0) | ||
891 | return ret; | ||
892 | exposure = ((reg2 & 0x3f) << 10) | (reg1 << 2) | | ||
893 | (reg0 & 0x3); | ||
894 | ov965x->ctrls.exposure->val = ((exposure * | ||
895 | ov965x->exp_row_interval) + 50) / 100; | ||
896 | break; | ||
897 | } | ||
898 | |||
899 | return 0; | ||
900 | } | ||
901 | |||
902 | static int ov965x_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
903 | { | ||
904 | struct v4l2_subdev *sd = ctrl_to_sd(ctrl); | ||
905 | struct ov965x *ov965x = to_ov965x(sd); | ||
906 | int ret; | ||
907 | |||
908 | v4l2_dbg(1, debug, sd, "g_ctrl: %s\n", ctrl->name); | ||
909 | |||
910 | mutex_lock(&ov965x->lock); | ||
911 | ret = __g_volatile_ctrl(ov965x, ctrl); | ||
912 | mutex_unlock(&ov965x->lock); | ||
913 | return ret; | ||
914 | } | ||
915 | |||
916 | static int ov965x_s_ctrl(struct v4l2_ctrl *ctrl) | ||
917 | { | ||
918 | struct v4l2_subdev *sd = ctrl_to_sd(ctrl); | ||
919 | struct ov965x *ov965x = to_ov965x(sd); | ||
920 | int ret = -EINVAL; | ||
921 | |||
922 | v4l2_dbg(1, debug, sd, "s_ctrl: %s, value: %d. power: %d\n", | ||
923 | ctrl->name, ctrl->val, ov965x->power); | ||
924 | |||
925 | mutex_lock(&ov965x->lock); | ||
926 | /* | ||
927 | * If the device is not powered up now postpone applying control's | ||
928 | * value to the hardware, until it is ready to accept commands. | ||
929 | */ | ||
930 | if (ov965x->power == 0) { | ||
931 | mutex_unlock(&ov965x->lock); | ||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | switch (ctrl->id) { | ||
936 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
937 | ret = ov965x_set_white_balance(ov965x, ctrl->val); | ||
938 | break; | ||
939 | |||
940 | case V4L2_CID_BRIGHTNESS: | ||
941 | ret = ov965x_set_brightness(ov965x, ctrl->val); | ||
942 | break; | ||
943 | |||
944 | case V4L2_CID_EXPOSURE_AUTO: | ||
945 | ret = ov965x_set_exposure(ov965x, ctrl->val); | ||
946 | break; | ||
947 | |||
948 | case V4L2_CID_AUTOGAIN: | ||
949 | ret = ov965x_set_gain(ov965x, ctrl->val); | ||
950 | break; | ||
951 | |||
952 | case V4L2_CID_HFLIP: | ||
953 | ret = ov965x_set_flip(ov965x); | ||
954 | break; | ||
955 | |||
956 | case V4L2_CID_POWER_LINE_FREQUENCY: | ||
957 | ret = ov965x_set_banding_filter(ov965x, ctrl->val); | ||
958 | break; | ||
959 | |||
960 | case V4L2_CID_SATURATION: | ||
961 | ret = ov965x_set_saturation(ov965x, ctrl->val); | ||
962 | break; | ||
963 | |||
964 | case V4L2_CID_SHARPNESS: | ||
965 | ret = ov965x_set_sharpness(ov965x, ctrl->val); | ||
966 | break; | ||
967 | |||
968 | case V4L2_CID_TEST_PATTERN: | ||
969 | ret = ov965x_set_test_pattern(ov965x, ctrl->val); | ||
970 | break; | ||
971 | } | ||
972 | |||
973 | mutex_unlock(&ov965x->lock); | ||
974 | return ret; | ||
975 | } | ||
976 | |||
977 | static const struct v4l2_ctrl_ops ov965x_ctrl_ops = { | ||
978 | .g_volatile_ctrl = ov965x_g_volatile_ctrl, | ||
979 | .s_ctrl = ov965x_s_ctrl, | ||
980 | }; | ||
981 | |||
982 | static const char * const test_pattern_menu[] = { | ||
983 | "Disabled", | ||
984 | "Color bars", | ||
985 | NULL | ||
986 | }; | ||
987 | |||
988 | static int ov965x_initialize_controls(struct ov965x *ov965x) | ||
989 | { | ||
990 | const struct v4l2_ctrl_ops *ops = &ov965x_ctrl_ops; | ||
991 | struct ov965x_ctrls *ctrls = &ov965x->ctrls; | ||
992 | struct v4l2_ctrl_handler *hdl = &ctrls->handler; | ||
993 | int ret; | ||
994 | |||
995 | ret = v4l2_ctrl_handler_init(hdl, 16); | ||
996 | if (ret < 0) | ||
997 | return ret; | ||
998 | |||
999 | /* Auto/manual white balance */ | ||
1000 | ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, | ||
1001 | V4L2_CID_AUTO_WHITE_BALANCE, | ||
1002 | 0, 1, 1, 1); | ||
1003 | ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE, | ||
1004 | 0, 0xff, 1, 0x80); | ||
1005 | ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE, | ||
1006 | 0, 0xff, 1, 0x80); | ||
1007 | /* Auto/manual exposure */ | ||
1008 | ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, | ||
1009 | V4L2_CID_EXPOSURE_AUTO, | ||
1010 | V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); | ||
1011 | /* Exposure time, in 100 us units. min/max is updated dynamically. */ | ||
1012 | ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, | ||
1013 | V4L2_CID_EXPOSURE_ABSOLUTE, | ||
1014 | 2, 1500, 1, 500); | ||
1015 | /* Auto/manual gain */ | ||
1016 | ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, | ||
1017 | 0, 1, 1, 1); | ||
1018 | ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, | ||
1019 | 16, 64 * (16 + 15), 1, 64 * 16); | ||
1020 | |||
1021 | ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, | ||
1022 | -2, 2, 1, 0); | ||
1023 | ctrls->brightness = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, | ||
1024 | -3, 3, 1, 0); | ||
1025 | ctrls->sharpness = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, | ||
1026 | 0, 32, 1, 6); | ||
1027 | |||
1028 | ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
1029 | ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
1030 | |||
1031 | ctrls->light_freq = v4l2_ctrl_new_std_menu(hdl, ops, | ||
1032 | V4L2_CID_POWER_LINE_FREQUENCY, | ||
1033 | V4L2_CID_POWER_LINE_FREQUENCY_60HZ, ~0x7, | ||
1034 | V4L2_CID_POWER_LINE_FREQUENCY_50HZ); | ||
1035 | |||
1036 | v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, | ||
1037 | ARRAY_SIZE(test_pattern_menu) - 1, 0, 0, | ||
1038 | test_pattern_menu); | ||
1039 | if (hdl->error) { | ||
1040 | ret = hdl->error; | ||
1041 | v4l2_ctrl_handler_free(hdl); | ||
1042 | return ret; | ||
1043 | } | ||
1044 | |||
1045 | ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; | ||
1046 | ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; | ||
1047 | |||
1048 | v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false); | ||
1049 | v4l2_ctrl_auto_cluster(3, &ctrls->auto_gain, 0, true); | ||
1050 | v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 1, true); | ||
1051 | v4l2_ctrl_cluster(2, &ctrls->hflip); | ||
1052 | |||
1053 | ov965x->sd.ctrl_handler = hdl; | ||
1054 | return 0; | ||
1055 | } | ||
1056 | |||
1057 | /* | ||
1058 | * V4L2 subdev video and pad level operations | ||
1059 | */ | ||
1060 | static void ov965x_get_default_format(struct v4l2_mbus_framefmt *mf) | ||
1061 | { | ||
1062 | mf->width = ov965x_framesizes[0].width; | ||
1063 | mf->height = ov965x_framesizes[0].height; | ||
1064 | mf->colorspace = ov965x_formats[0].colorspace; | ||
1065 | mf->code = ov965x_formats[0].code; | ||
1066 | mf->field = V4L2_FIELD_NONE; | ||
1067 | } | ||
1068 | |||
1069 | static int ov965x_enum_mbus_code(struct v4l2_subdev *sd, | ||
1070 | struct v4l2_subdev_fh *fh, | ||
1071 | struct v4l2_subdev_mbus_code_enum *code) | ||
1072 | { | ||
1073 | if (code->index >= ARRAY_SIZE(ov965x_formats)) | ||
1074 | return -EINVAL; | ||
1075 | |||
1076 | code->code = ov965x_formats[code->index].code; | ||
1077 | return 0; | ||
1078 | } | ||
1079 | |||
1080 | static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd, | ||
1081 | struct v4l2_subdev_fh *fh, | ||
1082 | struct v4l2_subdev_frame_size_enum *fse) | ||
1083 | { | ||
1084 | int i = ARRAY_SIZE(ov965x_formats); | ||
1085 | |||
1086 | if (fse->index > ARRAY_SIZE(ov965x_framesizes)) | ||
1087 | return -EINVAL; | ||
1088 | |||
1089 | while (--i) | ||
1090 | if (fse->code == ov965x_formats[i].code) | ||
1091 | break; | ||
1092 | |||
1093 | fse->code = ov965x_formats[i].code; | ||
1094 | |||
1095 | fse->min_width = ov965x_framesizes[fse->index].width; | ||
1096 | fse->max_width = fse->min_width; | ||
1097 | fse->max_height = ov965x_framesizes[fse->index].height; | ||
1098 | fse->min_height = fse->max_height; | ||
1099 | |||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | static int ov965x_g_frame_interval(struct v4l2_subdev *sd, | ||
1104 | struct v4l2_subdev_frame_interval *fi) | ||
1105 | { | ||
1106 | struct ov965x *ov965x = to_ov965x(sd); | ||
1107 | |||
1108 | mutex_lock(&ov965x->lock); | ||
1109 | fi->interval = ov965x->fiv->interval; | ||
1110 | mutex_unlock(&ov965x->lock); | ||
1111 | |||
1112 | return 0; | ||
1113 | } | ||
1114 | |||
1115 | static int __ov965x_set_frame_interval(struct ov965x *ov965x, | ||
1116 | struct v4l2_subdev_frame_interval *fi) | ||
1117 | { | ||
1118 | struct v4l2_mbus_framefmt *mbus_fmt = &ov965x->format; | ||
1119 | const struct ov965x_interval *fiv = &ov965x_intervals[0]; | ||
1120 | u64 req_int, err, min_err = ~0ULL; | ||
1121 | unsigned int i; | ||
1122 | |||
1123 | |||
1124 | if (fi->interval.denominator == 0) | ||
1125 | return -EINVAL; | ||
1126 | |||
1127 | req_int = (u64)(fi->interval.numerator * 10000) / | ||
1128 | fi->interval.denominator; | ||
1129 | |||
1130 | for (i = 0; i < ARRAY_SIZE(ov965x_intervals); i++) { | ||
1131 | const struct ov965x_interval *iv = &ov965x_intervals[i]; | ||
1132 | |||
1133 | if (mbus_fmt->width != iv->size.width || | ||
1134 | mbus_fmt->height != iv->size.height) | ||
1135 | continue; | ||
1136 | err = abs64((u64)(iv->interval.numerator * 10000) / | ||
1137 | iv->interval.denominator - req_int); | ||
1138 | if (err < min_err) { | ||
1139 | fiv = iv; | ||
1140 | min_err = err; | ||
1141 | } | ||
1142 | } | ||
1143 | ov965x->fiv = fiv; | ||
1144 | |||
1145 | v4l2_dbg(1, debug, &ov965x->sd, "Changed frame interval to %u us\n", | ||
1146 | fiv->interval.numerator * 1000000 / fiv->interval.denominator); | ||
1147 | |||
1148 | return 0; | ||
1149 | } | ||
1150 | |||
1151 | static int ov965x_s_frame_interval(struct v4l2_subdev *sd, | ||
1152 | struct v4l2_subdev_frame_interval *fi) | ||
1153 | { | ||
1154 | struct ov965x *ov965x = to_ov965x(sd); | ||
1155 | int ret; | ||
1156 | |||
1157 | v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n", | ||
1158 | fi->interval.numerator, fi->interval.denominator); | ||
1159 | |||
1160 | mutex_lock(&ov965x->lock); | ||
1161 | ret = __ov965x_set_frame_interval(ov965x, fi); | ||
1162 | ov965x->apply_frame_fmt = 1; | ||
1163 | mutex_unlock(&ov965x->lock); | ||
1164 | return ret; | ||
1165 | } | ||
1166 | |||
1167 | static int ov965x_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
1168 | struct v4l2_subdev_format *fmt) | ||
1169 | { | ||
1170 | struct ov965x *ov965x = to_ov965x(sd); | ||
1171 | struct v4l2_mbus_framefmt *mf; | ||
1172 | |||
1173 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1174 | mf = v4l2_subdev_get_try_format(fh, 0); | ||
1175 | fmt->format = *mf; | ||
1176 | return 0; | ||
1177 | } | ||
1178 | |||
1179 | mutex_lock(&ov965x->lock); | ||
1180 | fmt->format = ov965x->format; | ||
1181 | mutex_unlock(&ov965x->lock); | ||
1182 | |||
1183 | return 0; | ||
1184 | } | ||
1185 | |||
1186 | static void __ov965x_try_frame_size(struct v4l2_mbus_framefmt *mf, | ||
1187 | const struct ov965x_framesize **size) | ||
1188 | { | ||
1189 | const struct ov965x_framesize *fsize = &ov965x_framesizes[0], | ||
1190 | *match = NULL; | ||
1191 | int i = ARRAY_SIZE(ov965x_framesizes); | ||
1192 | unsigned int min_err = UINT_MAX; | ||
1193 | |||
1194 | while (i--) { | ||
1195 | int err = abs(fsize->width - mf->width) | ||
1196 | + abs(fsize->height - mf->height); | ||
1197 | if (err < min_err) { | ||
1198 | min_err = err; | ||
1199 | match = fsize; | ||
1200 | } | ||
1201 | fsize++; | ||
1202 | } | ||
1203 | if (!match) | ||
1204 | match = &ov965x_framesizes[0]; | ||
1205 | mf->width = match->width; | ||
1206 | mf->height = match->height; | ||
1207 | if (size) | ||
1208 | *size = match; | ||
1209 | } | ||
1210 | |||
1211 | static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
1212 | struct v4l2_subdev_format *fmt) | ||
1213 | { | ||
1214 | unsigned int index = ARRAY_SIZE(ov965x_formats); | ||
1215 | struct v4l2_mbus_framefmt *mf = &fmt->format; | ||
1216 | struct ov965x *ov965x = to_ov965x(sd); | ||
1217 | const struct ov965x_framesize *size = NULL; | ||
1218 | int ret = 0; | ||
1219 | |||
1220 | __ov965x_try_frame_size(mf, &size); | ||
1221 | |||
1222 | while (--index) | ||
1223 | if (ov965x_formats[index].code == mf->code) | ||
1224 | break; | ||
1225 | |||
1226 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
1227 | mf->code = ov965x_formats[index].code; | ||
1228 | mf->field = V4L2_FIELD_NONE; | ||
1229 | |||
1230 | mutex_lock(&ov965x->lock); | ||
1231 | |||
1232 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1233 | if (fh != NULL) { | ||
1234 | mf = v4l2_subdev_get_try_format(fh, fmt->pad); | ||
1235 | *mf = fmt->format; | ||
1236 | } | ||
1237 | } else { | ||
1238 | if (ov965x->streaming) { | ||
1239 | ret = -EBUSY; | ||
1240 | } else { | ||
1241 | ov965x->frame_size = size; | ||
1242 | ov965x->format = fmt->format; | ||
1243 | ov965x->tslb_reg = ov965x_formats[index].tslb_reg; | ||
1244 | ov965x->apply_frame_fmt = 1; | ||
1245 | } | ||
1246 | } | ||
1247 | |||
1248 | if (!ret && fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
1249 | struct v4l2_subdev_frame_interval fiv = { | ||
1250 | .interval = { 0, 1 } | ||
1251 | }; | ||
1252 | /* Reset to minimum possible frame interval */ | ||
1253 | __ov965x_set_frame_interval(ov965x, &fiv); | ||
1254 | } | ||
1255 | mutex_unlock(&ov965x->lock); | ||
1256 | |||
1257 | if (!ret) | ||
1258 | ov965x_update_exposure_ctrl(ov965x); | ||
1259 | |||
1260 | return ret; | ||
1261 | } | ||
1262 | |||
1263 | static int ov965x_set_frame_size(struct ov965x *ov965x) | ||
1264 | { | ||
1265 | int i, ret = 0; | ||
1266 | |||
1267 | for (i = 0; ret == 0 && i < NUM_FMT_REGS; i++) | ||
1268 | ret = ov965x_write(ov965x->client, frame_size_reg_addr[i], | ||
1269 | ov965x->frame_size->regs[i]); | ||
1270 | return ret; | ||
1271 | } | ||
1272 | |||
1273 | static int __ov965x_set_params(struct ov965x *ov965x) | ||
1274 | { | ||
1275 | struct i2c_client *client = ov965x->client; | ||
1276 | struct ov965x_ctrls *ctrls = &ov965x->ctrls; | ||
1277 | int ret = 0; | ||
1278 | u8 reg; | ||
1279 | |||
1280 | if (ov965x->apply_frame_fmt) { | ||
1281 | reg = DEF_CLKRC + ov965x->fiv->clkrc_div; | ||
1282 | ret = ov965x_write(client, REG_CLKRC, reg); | ||
1283 | if (ret < 0) | ||
1284 | return ret; | ||
1285 | ret = ov965x_set_frame_size(ov965x); | ||
1286 | if (ret < 0) | ||
1287 | return ret; | ||
1288 | ret = ov965x_read(client, REG_TSLB, ®); | ||
1289 | if (ret < 0) | ||
1290 | return ret; | ||
1291 | reg &= ~TSLB_YUYV_MASK; | ||
1292 | reg |= ov965x->tslb_reg; | ||
1293 | ret = ov965x_write(client, REG_TSLB, reg); | ||
1294 | if (ret < 0) | ||
1295 | return ret; | ||
1296 | } | ||
1297 | ret = ov965x_set_default_gamma_curve(ov965x); | ||
1298 | if (ret < 0) | ||
1299 | return ret; | ||
1300 | ret = ov965x_set_color_matrix(ov965x); | ||
1301 | if (ret < 0) | ||
1302 | return ret; | ||
1303 | /* | ||
1304 | * Select manual banding filter, the filter will | ||
1305 | * be enabled further if required. | ||
1306 | */ | ||
1307 | ret = ov965x_read(client, REG_COM11, ®); | ||
1308 | if (!ret) | ||
1309 | reg |= COM11_BANDING; | ||
1310 | ret = ov965x_write(client, REG_COM11, reg); | ||
1311 | if (ret < 0) | ||
1312 | return ret; | ||
1313 | /* | ||
1314 | * Banding filter (REG_MBD value) needs to match selected | ||
1315 | * resolution and frame rate, so it's always updated here. | ||
1316 | */ | ||
1317 | return ov965x_set_banding_filter(ov965x, ctrls->light_freq->val); | ||
1318 | } | ||
1319 | |||
1320 | static int ov965x_s_stream(struct v4l2_subdev *sd, int on) | ||
1321 | { | ||
1322 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1323 | struct ov965x *ov965x = to_ov965x(sd); | ||
1324 | struct ov965x_ctrls *ctrls = &ov965x->ctrls; | ||
1325 | int ret = 0; | ||
1326 | |||
1327 | v4l2_dbg(1, debug, client, "%s: on: %d\n", __func__, on); | ||
1328 | |||
1329 | mutex_lock(&ov965x->lock); | ||
1330 | if (ov965x->streaming == !on) { | ||
1331 | if (on) | ||
1332 | ret = __ov965x_set_params(ov965x); | ||
1333 | |||
1334 | if (!ret && ctrls->update) { | ||
1335 | /* | ||
1336 | * ov965x_s_ctrl callback takes the mutex | ||
1337 | * so it needs to be released here. | ||
1338 | */ | ||
1339 | mutex_unlock(&ov965x->lock); | ||
1340 | ret = v4l2_ctrl_handler_setup(&ctrls->handler); | ||
1341 | |||
1342 | mutex_lock(&ov965x->lock); | ||
1343 | if (!ret) | ||
1344 | ctrls->update = 0; | ||
1345 | } | ||
1346 | if (!ret) | ||
1347 | ret = ov965x_write(client, REG_COM2, | ||
1348 | on ? 0x01 : 0x11); | ||
1349 | } | ||
1350 | if (!ret) | ||
1351 | ov965x->streaming += on ? 1 : -1; | ||
1352 | |||
1353 | WARN_ON(ov965x->streaming < 0); | ||
1354 | mutex_unlock(&ov965x->lock); | ||
1355 | |||
1356 | return ret; | ||
1357 | } | ||
1358 | |||
1359 | /* | ||
1360 | * V4L2 subdev internal operations | ||
1361 | */ | ||
1362 | static int ov965x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
1363 | { | ||
1364 | struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0); | ||
1365 | |||
1366 | ov965x_get_default_format(mf); | ||
1367 | return 0; | ||
1368 | } | ||
1369 | |||
1370 | static const struct v4l2_subdev_pad_ops ov965x_pad_ops = { | ||
1371 | .enum_mbus_code = ov965x_enum_mbus_code, | ||
1372 | .enum_frame_size = ov965x_enum_frame_sizes, | ||
1373 | .get_fmt = ov965x_get_fmt, | ||
1374 | .set_fmt = ov965x_set_fmt, | ||
1375 | }; | ||
1376 | |||
1377 | static const struct v4l2_subdev_video_ops ov965x_video_ops = { | ||
1378 | .s_stream = ov965x_s_stream, | ||
1379 | .g_frame_interval = ov965x_g_frame_interval, | ||
1380 | .s_frame_interval = ov965x_s_frame_interval, | ||
1381 | |||
1382 | }; | ||
1383 | |||
1384 | static const struct v4l2_subdev_internal_ops ov965x_sd_internal_ops = { | ||
1385 | .open = ov965x_open, | ||
1386 | }; | ||
1387 | |||
1388 | static const struct v4l2_subdev_core_ops ov965x_core_ops = { | ||
1389 | .s_power = ov965x_s_power, | ||
1390 | .log_status = v4l2_ctrl_subdev_log_status, | ||
1391 | .subscribe_event = v4l2_ctrl_subdev_subscribe_event, | ||
1392 | .unsubscribe_event = v4l2_event_subdev_unsubscribe, | ||
1393 | }; | ||
1394 | |||
1395 | static const struct v4l2_subdev_ops ov965x_subdev_ops = { | ||
1396 | .core = &ov965x_core_ops, | ||
1397 | .pad = &ov965x_pad_ops, | ||
1398 | .video = &ov965x_video_ops, | ||
1399 | }; | ||
1400 | |||
1401 | /* | ||
1402 | * Reset and power down GPIOs configuration | ||
1403 | */ | ||
1404 | static int ov965x_configure_gpios(struct ov965x *ov965x, | ||
1405 | const struct ov9650_platform_data *pdata) | ||
1406 | { | ||
1407 | int ret, i; | ||
1408 | |||
1409 | ov965x->gpios[GPIO_PWDN] = pdata->gpio_pwdn; | ||
1410 | ov965x->gpios[GPIO_RST] = pdata->gpio_reset; | ||
1411 | |||
1412 | for (i = 0; i < ARRAY_SIZE(ov965x->gpios); i++) { | ||
1413 | int gpio = ov965x->gpios[i]; | ||
1414 | |||
1415 | if (!gpio_is_valid(gpio)) | ||
1416 | continue; | ||
1417 | ret = devm_gpio_request_one(&ov965x->client->dev, gpio, | ||
1418 | GPIOF_OUT_INIT_HIGH, "OV965X"); | ||
1419 | if (ret < 0) | ||
1420 | return ret; | ||
1421 | v4l2_dbg(1, debug, &ov965x->sd, "set gpio %d to 1\n", gpio); | ||
1422 | |||
1423 | gpio_set_value(gpio, 1); | ||
1424 | gpio_export(gpio, 0); | ||
1425 | ov965x->gpios[i] = gpio; | ||
1426 | } | ||
1427 | |||
1428 | return 0; | ||
1429 | } | ||
1430 | |||
1431 | static int ov965x_detect_sensor(struct v4l2_subdev *sd) | ||
1432 | { | ||
1433 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1434 | struct ov965x *ov965x = to_ov965x(sd); | ||
1435 | u8 pid, ver; | ||
1436 | int ret; | ||
1437 | |||
1438 | mutex_lock(&ov965x->lock); | ||
1439 | __ov965x_set_power(ov965x, 1); | ||
1440 | usleep_range(25000, 26000); | ||
1441 | |||
1442 | /* Check sensor revision */ | ||
1443 | ret = ov965x_read(client, REG_PID, &pid); | ||
1444 | if (!ret) | ||
1445 | ret = ov965x_read(client, REG_VER, &ver); | ||
1446 | |||
1447 | __ov965x_set_power(ov965x, 0); | ||
1448 | |||
1449 | if (!ret) { | ||
1450 | ov965x->id = OV965X_ID(pid, ver); | ||
1451 | if (ov965x->id == OV9650_ID || ov965x->id == OV9652_ID) { | ||
1452 | v4l2_info(sd, "Found OV%04X sensor\n", ov965x->id); | ||
1453 | } else { | ||
1454 | v4l2_err(sd, "Sensor detection failed (%04X, %d)\n", | ||
1455 | ov965x->id, ret); | ||
1456 | ret = -ENODEV; | ||
1457 | } | ||
1458 | } | ||
1459 | mutex_unlock(&ov965x->lock); | ||
1460 | |||
1461 | return ret; | ||
1462 | } | ||
1463 | |||
1464 | static int ov965x_probe(struct i2c_client *client, | ||
1465 | const struct i2c_device_id *id) | ||
1466 | { | ||
1467 | const struct ov9650_platform_data *pdata = client->dev.platform_data; | ||
1468 | struct v4l2_subdev *sd; | ||
1469 | struct ov965x *ov965x; | ||
1470 | int ret; | ||
1471 | |||
1472 | if (pdata == NULL) { | ||
1473 | dev_err(&client->dev, "platform data not specified\n"); | ||
1474 | return -EINVAL; | ||
1475 | } | ||
1476 | |||
1477 | if (pdata->mclk_frequency == 0) { | ||
1478 | dev_err(&client->dev, "MCLK frequency not specified\n"); | ||
1479 | return -EINVAL; | ||
1480 | } | ||
1481 | |||
1482 | ov965x = devm_kzalloc(&client->dev, sizeof(*ov965x), GFP_KERNEL); | ||
1483 | if (!ov965x) | ||
1484 | return -ENOMEM; | ||
1485 | |||
1486 | mutex_init(&ov965x->lock); | ||
1487 | ov965x->client = client; | ||
1488 | ov965x->mclk_frequency = pdata->mclk_frequency; | ||
1489 | |||
1490 | sd = &ov965x->sd; | ||
1491 | v4l2_i2c_subdev_init(sd, client, &ov965x_subdev_ops); | ||
1492 | strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); | ||
1493 | |||
1494 | sd->internal_ops = &ov965x_sd_internal_ops; | ||
1495 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | ||
1496 | V4L2_SUBDEV_FL_HAS_EVENTS; | ||
1497 | |||
1498 | ret = ov965x_configure_gpios(ov965x, pdata); | ||
1499 | if (ret < 0) | ||
1500 | return ret; | ||
1501 | |||
1502 | ov965x->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
1503 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
1504 | ret = media_entity_init(&sd->entity, 1, &ov965x->pad, 0); | ||
1505 | if (ret < 0) | ||
1506 | return ret; | ||
1507 | |||
1508 | ret = ov965x_initialize_controls(ov965x); | ||
1509 | if (ret < 0) | ||
1510 | goto err_me; | ||
1511 | |||
1512 | ov965x_get_default_format(&ov965x->format); | ||
1513 | ov965x->frame_size = &ov965x_framesizes[0]; | ||
1514 | ov965x->fiv = &ov965x_intervals[0]; | ||
1515 | |||
1516 | ret = ov965x_detect_sensor(sd); | ||
1517 | if (ret < 0) | ||
1518 | goto err_ctrls; | ||
1519 | |||
1520 | /* Update exposure time min/max to match frame format */ | ||
1521 | ov965x_update_exposure_ctrl(ov965x); | ||
1522 | |||
1523 | return 0; | ||
1524 | err_ctrls: | ||
1525 | v4l2_ctrl_handler_free(sd->ctrl_handler); | ||
1526 | err_me: | ||
1527 | media_entity_cleanup(&sd->entity); | ||
1528 | return ret; | ||
1529 | } | ||
1530 | |||
1531 | static int ov965x_remove(struct i2c_client *client) | ||
1532 | { | ||
1533 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
1534 | |||
1535 | v4l2_device_unregister_subdev(sd); | ||
1536 | v4l2_ctrl_handler_free(sd->ctrl_handler); | ||
1537 | media_entity_cleanup(&sd->entity); | ||
1538 | |||
1539 | return 0; | ||
1540 | } | ||
1541 | |||
1542 | static const struct i2c_device_id ov965x_id[] = { | ||
1543 | { "OV9650", 0 }, | ||
1544 | { "OV9652", 0 }, | ||
1545 | { /* sentinel */ } | ||
1546 | }; | ||
1547 | MODULE_DEVICE_TABLE(i2c, ov965x_id); | ||
1548 | |||
1549 | static struct i2c_driver ov965x_i2c_driver = { | ||
1550 | .driver = { | ||
1551 | .name = DRIVER_NAME, | ||
1552 | }, | ||
1553 | .probe = ov965x_probe, | ||
1554 | .remove = ov965x_remove, | ||
1555 | .id_table = ov965x_id, | ||
1556 | }; | ||
1557 | |||
1558 | module_i2c_driver(ov965x_i2c_driver); | ||
1559 | |||
1560 | MODULE_AUTHOR("Sylwester Nawrocki <sylvester.nawrocki@gmail.com>"); | ||
1561 | MODULE_DESCRIPTION("OV9650/OV9652 CMOS Image Sensor driver"); | ||
1562 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/i2c/s5c73m3/Makefile b/drivers/media/i2c/s5c73m3/Makefile new file mode 100644 index 000000000000..fa4df342d1f1 --- /dev/null +++ b/drivers/media/i2c/s5c73m3/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | s5c73m3-objs := s5c73m3-core.o s5c73m3-spi.o s5c73m3-ctrls.o | ||
2 | obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3.o | ||
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c new file mode 100644 index 000000000000..5dbb65e1f6b7 --- /dev/null +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c | |||
@@ -0,0 +1,1704 @@ | |||
1 | /* | ||
2 | * Samsung LSI S5C73M3 8M pixel camera driver | ||
3 | * | ||
4 | * Copyright (C) 2012, Samsung Electronics, Co., Ltd. | ||
5 | * Sylwester Nawrocki <s.nawrocki@samsung.com> | ||
6 | * Andrzej Hajda <a.hajda@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/sizes.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/firmware.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/i2c.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/media.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/regulator/consumer.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/spi/spi.h> | ||
29 | #include <linux/videodev2.h> | ||
30 | #include <media/media-entity.h> | ||
31 | #include <media/v4l2-ctrls.h> | ||
32 | #include <media/v4l2-device.h> | ||
33 | #include <media/v4l2-subdev.h> | ||
34 | #include <media/v4l2-mediabus.h> | ||
35 | #include <media/s5c73m3.h> | ||
36 | |||
37 | #include "s5c73m3.h" | ||
38 | |||
39 | int s5c73m3_dbg; | ||
40 | module_param_named(debug, s5c73m3_dbg, int, 0644); | ||
41 | |||
42 | static int boot_from_rom = 1; | ||
43 | module_param(boot_from_rom, int, 0644); | ||
44 | |||
45 | static int update_fw; | ||
46 | module_param(update_fw, int, 0644); | ||
47 | |||
48 | #define S5C73M3_EMBEDDED_DATA_MAXLEN SZ_4K | ||
49 | |||
50 | static const char * const s5c73m3_supply_names[S5C73M3_MAX_SUPPLIES] = { | ||
51 | "vdd-int", /* Digital Core supply (1.2V), CAM_ISP_CORE_1.2V */ | ||
52 | "vdda", /* Analog Core supply (1.2V), CAM_SENSOR_CORE_1.2V */ | ||
53 | "vdd-reg", /* Regulator input supply (2.8V), CAM_SENSOR_A2.8V */ | ||
54 | "vddio-host", /* Digital Host I/O power supply (1.8V...2.8V), | ||
55 | CAM_ISP_SENSOR_1.8V */ | ||
56 | "vddio-cis", /* Digital CIS I/O power (1.2V...1.8V), | ||
57 | CAM_ISP_MIPI_1.2V */ | ||
58 | "vdd-af", /* Lens, CAM_AF_2.8V */ | ||
59 | }; | ||
60 | |||
61 | static const struct s5c73m3_frame_size s5c73m3_isp_resolutions[] = { | ||
62 | { 320, 240, COMM_CHG_MODE_YUV_320_240 }, | ||
63 | { 352, 288, COMM_CHG_MODE_YUV_352_288 }, | ||
64 | { 640, 480, COMM_CHG_MODE_YUV_640_480 }, | ||
65 | { 880, 720, COMM_CHG_MODE_YUV_880_720 }, | ||
66 | { 960, 720, COMM_CHG_MODE_YUV_960_720 }, | ||
67 | { 1008, 672, COMM_CHG_MODE_YUV_1008_672 }, | ||
68 | { 1184, 666, COMM_CHG_MODE_YUV_1184_666 }, | ||
69 | { 1280, 720, COMM_CHG_MODE_YUV_1280_720 }, | ||
70 | { 1536, 864, COMM_CHG_MODE_YUV_1536_864 }, | ||
71 | { 1600, 1200, COMM_CHG_MODE_YUV_1600_1200 }, | ||
72 | { 1632, 1224, COMM_CHG_MODE_YUV_1632_1224 }, | ||
73 | { 1920, 1080, COMM_CHG_MODE_YUV_1920_1080 }, | ||
74 | { 1920, 1440, COMM_CHG_MODE_YUV_1920_1440 }, | ||
75 | { 2304, 1296, COMM_CHG_MODE_YUV_2304_1296 }, | ||
76 | { 3264, 2448, COMM_CHG_MODE_YUV_3264_2448 }, | ||
77 | }; | ||
78 | |||
79 | static const struct s5c73m3_frame_size s5c73m3_jpeg_resolutions[] = { | ||
80 | { 640, 480, COMM_CHG_MODE_JPEG_640_480 }, | ||
81 | { 800, 450, COMM_CHG_MODE_JPEG_800_450 }, | ||
82 | { 800, 600, COMM_CHG_MODE_JPEG_800_600 }, | ||
83 | { 1024, 768, COMM_CHG_MODE_JPEG_1024_768 }, | ||
84 | { 1280, 720, COMM_CHG_MODE_JPEG_1280_720 }, | ||
85 | { 1280, 960, COMM_CHG_MODE_JPEG_1280_960 }, | ||
86 | { 1600, 900, COMM_CHG_MODE_JPEG_1600_900 }, | ||
87 | { 1600, 1200, COMM_CHG_MODE_JPEG_1600_1200 }, | ||
88 | { 2048, 1152, COMM_CHG_MODE_JPEG_2048_1152 }, | ||
89 | { 2048, 1536, COMM_CHG_MODE_JPEG_2048_1536 }, | ||
90 | { 2560, 1440, COMM_CHG_MODE_JPEG_2560_1440 }, | ||
91 | { 2560, 1920, COMM_CHG_MODE_JPEG_2560_1920 }, | ||
92 | { 3264, 1836, COMM_CHG_MODE_JPEG_3264_1836 }, | ||
93 | { 3264, 2176, COMM_CHG_MODE_JPEG_3264_2176 }, | ||
94 | { 3264, 2448, COMM_CHG_MODE_JPEG_3264_2448 }, | ||
95 | }; | ||
96 | |||
97 | static const struct s5c73m3_frame_size * const s5c73m3_resolutions[] = { | ||
98 | [RES_ISP] = s5c73m3_isp_resolutions, | ||
99 | [RES_JPEG] = s5c73m3_jpeg_resolutions | ||
100 | }; | ||
101 | |||
102 | static const int s5c73m3_resolutions_len[] = { | ||
103 | [RES_ISP] = ARRAY_SIZE(s5c73m3_isp_resolutions), | ||
104 | [RES_JPEG] = ARRAY_SIZE(s5c73m3_jpeg_resolutions) | ||
105 | }; | ||
106 | |||
107 | static const struct s5c73m3_interval s5c73m3_intervals[] = { | ||
108 | { COMM_FRAME_RATE_FIXED_7FPS, {142857, 1000000}, {3264, 2448} }, | ||
109 | { COMM_FRAME_RATE_FIXED_15FPS, {66667, 1000000}, {3264, 2448} }, | ||
110 | { COMM_FRAME_RATE_FIXED_20FPS, {50000, 1000000}, {2304, 1296} }, | ||
111 | { COMM_FRAME_RATE_FIXED_30FPS, {33333, 1000000}, {2304, 1296} }, | ||
112 | }; | ||
113 | |||
114 | #define S5C73M3_DEFAULT_FRAME_INTERVAL 3 /* 30 fps */ | ||
115 | |||
116 | static void s5c73m3_fill_mbus_fmt(struct v4l2_mbus_framefmt *mf, | ||
117 | const struct s5c73m3_frame_size *fs, | ||
118 | u32 code) | ||
119 | { | ||
120 | mf->width = fs->width; | ||
121 | mf->height = fs->height; | ||
122 | mf->code = code; | ||
123 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
124 | mf->field = V4L2_FIELD_NONE; | ||
125 | } | ||
126 | |||
127 | static int s5c73m3_i2c_write(struct i2c_client *client, u16 addr, u16 data) | ||
128 | { | ||
129 | u8 buf[4] = { addr >> 8, addr & 0xff, data >> 8, data & 0xff }; | ||
130 | |||
131 | int ret = i2c_master_send(client, buf, sizeof(buf)); | ||
132 | |||
133 | v4l_dbg(4, s5c73m3_dbg, client, "%s: addr 0x%04x, data 0x%04x\n", | ||
134 | __func__, addr, data); | ||
135 | |||
136 | if (ret == 4) | ||
137 | return 0; | ||
138 | |||
139 | return ret < 0 ? ret : -EREMOTEIO; | ||
140 | } | ||
141 | |||
142 | static int s5c73m3_i2c_read(struct i2c_client *client, u16 addr, u16 *data) | ||
143 | { | ||
144 | int ret; | ||
145 | u8 rbuf[2], wbuf[2] = { addr >> 8, addr & 0xff }; | ||
146 | struct i2c_msg msg[2] = { | ||
147 | { | ||
148 | .addr = client->addr, | ||
149 | .flags = 0, | ||
150 | .len = sizeof(wbuf), | ||
151 | .buf = wbuf | ||
152 | }, { | ||
153 | .addr = client->addr, | ||
154 | .flags = I2C_M_RD, | ||
155 | .len = sizeof(rbuf), | ||
156 | .buf = rbuf | ||
157 | } | ||
158 | }; | ||
159 | /* | ||
160 | * Issue repeated START after writing 2 address bytes and | ||
161 | * just one STOP only after reading the data bytes. | ||
162 | */ | ||
163 | ret = i2c_transfer(client->adapter, msg, 2); | ||
164 | if (ret == 2) { | ||
165 | *data = be16_to_cpup((u16 *)rbuf); | ||
166 | v4l2_dbg(4, s5c73m3_dbg, client, | ||
167 | "%s: addr: 0x%04x, data: 0x%04x\n", | ||
168 | __func__, addr, *data); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | v4l2_err(client, "I2C read failed: addr: %04x, (%d)\n", addr, ret); | ||
173 | |||
174 | return ret >= 0 ? -EREMOTEIO : ret; | ||
175 | } | ||
176 | |||
177 | int s5c73m3_write(struct s5c73m3 *state, u32 addr, u16 data) | ||
178 | { | ||
179 | struct i2c_client *client = state->i2c_client; | ||
180 | int ret; | ||
181 | |||
182 | if ((addr ^ state->i2c_write_address) & 0xffff0000) { | ||
183 | ret = s5c73m3_i2c_write(client, REG_CMDWR_ADDRH, addr >> 16); | ||
184 | if (ret < 0) { | ||
185 | state->i2c_write_address = 0; | ||
186 | return ret; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | if ((addr ^ state->i2c_write_address) & 0xffff) { | ||
191 | ret = s5c73m3_i2c_write(client, REG_CMDWR_ADDRL, addr & 0xffff); | ||
192 | if (ret < 0) { | ||
193 | state->i2c_write_address = 0; | ||
194 | return ret; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | state->i2c_write_address = addr; | ||
199 | |||
200 | ret = s5c73m3_i2c_write(client, REG_CMDBUF_ADDR, data); | ||
201 | if (ret < 0) | ||
202 | return ret; | ||
203 | |||
204 | state->i2c_write_address += 2; | ||
205 | |||
206 | return ret; | ||
207 | } | ||
208 | |||
209 | int s5c73m3_read(struct s5c73m3 *state, u32 addr, u16 *data) | ||
210 | { | ||
211 | struct i2c_client *client = state->i2c_client; | ||
212 | int ret; | ||
213 | |||
214 | if ((addr ^ state->i2c_read_address) & 0xffff0000) { | ||
215 | ret = s5c73m3_i2c_write(client, REG_CMDRD_ADDRH, addr >> 16); | ||
216 | if (ret < 0) { | ||
217 | state->i2c_read_address = 0; | ||
218 | return ret; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | if ((addr ^ state->i2c_read_address) & 0xffff) { | ||
223 | ret = s5c73m3_i2c_write(client, REG_CMDRD_ADDRL, addr & 0xffff); | ||
224 | if (ret < 0) { | ||
225 | state->i2c_read_address = 0; | ||
226 | return ret; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | state->i2c_read_address = addr; | ||
231 | |||
232 | ret = s5c73m3_i2c_read(client, REG_CMDBUF_ADDR, data); | ||
233 | if (ret < 0) | ||
234 | return ret; | ||
235 | |||
236 | state->i2c_read_address += 2; | ||
237 | |||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | static int s5c73m3_check_status(struct s5c73m3 *state, unsigned int value) | ||
242 | { | ||
243 | unsigned long start = jiffies; | ||
244 | unsigned long end = start + msecs_to_jiffies(2000); | ||
245 | int ret = 0; | ||
246 | u16 status; | ||
247 | int count = 0; | ||
248 | |||
249 | while (time_is_after_jiffies(end)) { | ||
250 | ret = s5c73m3_read(state, REG_STATUS, &status); | ||
251 | if (ret < 0 || status == value) | ||
252 | break; | ||
253 | usleep_range(500, 1000); | ||
254 | ++count; | ||
255 | } | ||
256 | |||
257 | if (count > 0) | ||
258 | v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, | ||
259 | "status check took %dms\n", | ||
260 | jiffies_to_msecs(jiffies - start)); | ||
261 | |||
262 | if (ret == 0 && status != value) { | ||
263 | u16 i2c_status = 0; | ||
264 | u16 i2c_seq_status = 0; | ||
265 | |||
266 | s5c73m3_read(state, REG_I2C_STATUS, &i2c_status); | ||
267 | s5c73m3_read(state, REG_I2C_SEQ_STATUS, &i2c_seq_status); | ||
268 | |||
269 | v4l2_err(&state->sensor_sd, | ||
270 | "wrong status %#x, expected: %#x, i2c_status: %#x/%#x\n", | ||
271 | status, value, i2c_status, i2c_seq_status); | ||
272 | |||
273 | return -ETIMEDOUT; | ||
274 | } | ||
275 | |||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | int s5c73m3_isp_command(struct s5c73m3 *state, u16 command, u16 data) | ||
280 | { | ||
281 | int ret; | ||
282 | |||
283 | ret = s5c73m3_check_status(state, REG_STATUS_ISP_COMMAND_COMPLETED); | ||
284 | if (ret < 0) | ||
285 | return ret; | ||
286 | |||
287 | ret = s5c73m3_write(state, 0x00095000, command); | ||
288 | if (ret < 0) | ||
289 | return ret; | ||
290 | |||
291 | ret = s5c73m3_write(state, 0x00095002, data); | ||
292 | if (ret < 0) | ||
293 | return ret; | ||
294 | |||
295 | return s5c73m3_write(state, REG_STATUS, 0x0001); | ||
296 | } | ||
297 | |||
298 | static int s5c73m3_isp_comm_result(struct s5c73m3 *state, u16 command, | ||
299 | u16 *data) | ||
300 | { | ||
301 | return s5c73m3_read(state, COMM_RESULT_OFFSET + command, data); | ||
302 | } | ||
303 | |||
304 | static int s5c73m3_set_af_softlanding(struct s5c73m3 *state) | ||
305 | { | ||
306 | unsigned long start = jiffies; | ||
307 | u16 af_softlanding; | ||
308 | int count = 0; | ||
309 | int ret; | ||
310 | const char *msg; | ||
311 | |||
312 | ret = s5c73m3_isp_command(state, COMM_AF_SOFTLANDING, | ||
313 | COMM_AF_SOFTLANDING_ON); | ||
314 | if (ret < 0) { | ||
315 | v4l2_info(&state->sensor_sd, "AF soft-landing failed\n"); | ||
316 | return ret; | ||
317 | } | ||
318 | |||
319 | for (;;) { | ||
320 | ret = s5c73m3_isp_comm_result(state, COMM_AF_SOFTLANDING, | ||
321 | &af_softlanding); | ||
322 | if (ret < 0) { | ||
323 | msg = "failed"; | ||
324 | break; | ||
325 | } | ||
326 | if (af_softlanding == COMM_AF_SOFTLANDING_RES_COMPLETE) { | ||
327 | msg = "succeeded"; | ||
328 | break; | ||
329 | } | ||
330 | if (++count > 100) { | ||
331 | ret = -ETIME; | ||
332 | msg = "timed out"; | ||
333 | break; | ||
334 | } | ||
335 | msleep(25); | ||
336 | } | ||
337 | |||
338 | v4l2_info(&state->sensor_sd, "AF soft-landing %s after %dms\n", | ||
339 | msg, jiffies_to_msecs(jiffies - start)); | ||
340 | |||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | static int s5c73m3_load_fw(struct v4l2_subdev *sd) | ||
345 | { | ||
346 | struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); | ||
347 | struct i2c_client *client = state->i2c_client; | ||
348 | const struct firmware *fw; | ||
349 | int ret; | ||
350 | char fw_name[20]; | ||
351 | |||
352 | snprintf(fw_name, sizeof(fw_name), "SlimISP_%.2s.bin", | ||
353 | state->fw_file_version); | ||
354 | ret = request_firmware(&fw, fw_name, &client->dev); | ||
355 | if (ret < 0) { | ||
356 | v4l2_err(sd, "Firmware request failed (%s)\n", fw_name); | ||
357 | return -EINVAL; | ||
358 | } | ||
359 | |||
360 | v4l2_info(sd, "Loading firmware (%s, %d B)\n", fw_name, fw->size); | ||
361 | |||
362 | ret = s5c73m3_spi_write(state, fw->data, fw->size, 64); | ||
363 | |||
364 | if (ret >= 0) | ||
365 | state->isp_ready = 1; | ||
366 | else | ||
367 | v4l2_err(sd, "SPI write failed\n"); | ||
368 | |||
369 | release_firmware(fw); | ||
370 | |||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | static int s5c73m3_set_frame_size(struct s5c73m3 *state) | ||
375 | { | ||
376 | const struct s5c73m3_frame_size *prev_size = | ||
377 | state->sensor_pix_size[RES_ISP]; | ||
378 | const struct s5c73m3_frame_size *cap_size = | ||
379 | state->sensor_pix_size[RES_JPEG]; | ||
380 | unsigned int chg_mode; | ||
381 | |||
382 | v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, | ||
383 | "Preview size: %dx%d, reg_val: 0x%x\n", | ||
384 | prev_size->width, prev_size->height, prev_size->reg_val); | ||
385 | |||
386 | chg_mode = prev_size->reg_val | COMM_CHG_MODE_NEW; | ||
387 | |||
388 | if (state->mbus_code == S5C73M3_JPEG_FMT) { | ||
389 | v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, | ||
390 | "Capture size: %dx%d, reg_val: 0x%x\n", | ||
391 | cap_size->width, cap_size->height, cap_size->reg_val); | ||
392 | chg_mode |= cap_size->reg_val; | ||
393 | } | ||
394 | |||
395 | return s5c73m3_isp_command(state, COMM_CHG_MODE, chg_mode); | ||
396 | } | ||
397 | |||
398 | static int s5c73m3_set_frame_rate(struct s5c73m3 *state) | ||
399 | { | ||
400 | int ret; | ||
401 | |||
402 | if (state->ctrls.stabilization->val) | ||
403 | return 0; | ||
404 | |||
405 | if (WARN_ON(state->fiv == NULL)) | ||
406 | return -EINVAL; | ||
407 | |||
408 | ret = s5c73m3_isp_command(state, COMM_FRAME_RATE, state->fiv->fps_reg); | ||
409 | if (!ret) | ||
410 | state->apply_fiv = 0; | ||
411 | |||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | static int __s5c73m3_s_stream(struct s5c73m3 *state, struct v4l2_subdev *sd, | ||
416 | int on) | ||
417 | { | ||
418 | u16 mode; | ||
419 | int ret; | ||
420 | |||
421 | if (on && state->apply_fmt) { | ||
422 | if (state->mbus_code == S5C73M3_JPEG_FMT) | ||
423 | mode = COMM_IMG_OUTPUT_INTERLEAVED; | ||
424 | else | ||
425 | mode = COMM_IMG_OUTPUT_YUV; | ||
426 | |||
427 | ret = s5c73m3_isp_command(state, COMM_IMG_OUTPUT, mode); | ||
428 | if (!ret) | ||
429 | ret = s5c73m3_set_frame_size(state); | ||
430 | if (ret) | ||
431 | return ret; | ||
432 | state->apply_fmt = 0; | ||
433 | } | ||
434 | |||
435 | ret = s5c73m3_isp_command(state, COMM_SENSOR_STREAMING, !!on); | ||
436 | if (ret) | ||
437 | return ret; | ||
438 | |||
439 | state->streaming = !!on; | ||
440 | |||
441 | if (!on) | ||
442 | return ret; | ||
443 | |||
444 | if (state->apply_fiv) { | ||
445 | ret = s5c73m3_set_frame_rate(state); | ||
446 | if (ret < 0) | ||
447 | v4l2_err(sd, "Error setting frame rate(%d)\n", ret); | ||
448 | } | ||
449 | |||
450 | return s5c73m3_check_status(state, REG_STATUS_ISP_COMMAND_COMPLETED); | ||
451 | } | ||
452 | |||
453 | static int s5c73m3_oif_s_stream(struct v4l2_subdev *sd, int on) | ||
454 | { | ||
455 | struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); | ||
456 | int ret; | ||
457 | |||
458 | mutex_lock(&state->lock); | ||
459 | ret = __s5c73m3_s_stream(state, sd, on); | ||
460 | mutex_unlock(&state->lock); | ||
461 | |||
462 | return ret; | ||
463 | } | ||
464 | |||
465 | static int s5c73m3_system_status_wait(struct s5c73m3 *state, u32 value, | ||
466 | unsigned int delay, unsigned int steps) | ||
467 | { | ||
468 | u16 reg = 0; | ||
469 | |||
470 | while (steps-- > 0) { | ||
471 | int ret = s5c73m3_read(state, 0x30100010, ®); | ||
472 | if (ret < 0) | ||
473 | return ret; | ||
474 | if (reg == value) | ||
475 | return 0; | ||
476 | usleep_range(delay, delay + 25); | ||
477 | } | ||
478 | return -ETIMEDOUT; | ||
479 | } | ||
480 | |||
481 | static int s5c73m3_read_fw_version(struct s5c73m3 *state) | ||
482 | { | ||
483 | struct v4l2_subdev *sd = &state->sensor_sd; | ||
484 | int i, ret; | ||
485 | u16 data[2]; | ||
486 | int offset; | ||
487 | |||
488 | offset = state->isp_ready ? 0x60 : 0; | ||
489 | |||
490 | for (i = 0; i < S5C73M3_SENSOR_FW_LEN / 2; i++) { | ||
491 | ret = s5c73m3_read(state, offset + i * 2, data); | ||
492 | if (ret < 0) | ||
493 | return ret; | ||
494 | state->sensor_fw[i * 2] = (char)(*data & 0xff); | ||
495 | state->sensor_fw[i * 2 + 1] = (char)(*data >> 8); | ||
496 | } | ||
497 | state->sensor_fw[S5C73M3_SENSOR_FW_LEN] = '\0'; | ||
498 | |||
499 | |||
500 | for (i = 0; i < S5C73M3_SENSOR_TYPE_LEN / 2; i++) { | ||
501 | ret = s5c73m3_read(state, offset + 6 + i * 2, data); | ||
502 | if (ret < 0) | ||
503 | return ret; | ||
504 | state->sensor_type[i * 2] = (char)(*data & 0xff); | ||
505 | state->sensor_type[i * 2 + 1] = (char)(*data >> 8); | ||
506 | } | ||
507 | state->sensor_type[S5C73M3_SENSOR_TYPE_LEN] = '\0'; | ||
508 | |||
509 | ret = s5c73m3_read(state, offset + 0x14, data); | ||
510 | if (ret >= 0) { | ||
511 | ret = s5c73m3_read(state, offset + 0x16, data + 1); | ||
512 | if (ret >= 0) | ||
513 | state->fw_size = data[0] + (data[1] << 16); | ||
514 | } | ||
515 | |||
516 | v4l2_info(sd, "Sensor type: %s, FW version: %s\n", | ||
517 | state->sensor_type, state->sensor_fw); | ||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | static int s5c73m3_fw_update_from(struct s5c73m3 *state) | ||
522 | { | ||
523 | struct v4l2_subdev *sd = &state->sensor_sd; | ||
524 | u16 status = COMM_FW_UPDATE_NOT_READY; | ||
525 | int ret; | ||
526 | int count = 0; | ||
527 | |||
528 | v4l2_warn(sd, "Updating F-ROM firmware.\n"); | ||
529 | do { | ||
530 | if (status == COMM_FW_UPDATE_NOT_READY) { | ||
531 | ret = s5c73m3_isp_command(state, COMM_FW_UPDATE, 0); | ||
532 | if (ret < 0) | ||
533 | return ret; | ||
534 | } | ||
535 | |||
536 | ret = s5c73m3_read(state, 0x00095906, &status); | ||
537 | if (ret < 0) | ||
538 | return ret; | ||
539 | switch (status) { | ||
540 | case COMM_FW_UPDATE_FAIL: | ||
541 | v4l2_warn(sd, "Updating F-ROM firmware failed.\n"); | ||
542 | return -EIO; | ||
543 | case COMM_FW_UPDATE_SUCCESS: | ||
544 | v4l2_warn(sd, "Updating F-ROM firmware finished.\n"); | ||
545 | return 0; | ||
546 | } | ||
547 | ++count; | ||
548 | msleep(20); | ||
549 | } while (count < 500); | ||
550 | |||
551 | v4l2_warn(sd, "Updating F-ROM firmware timed-out.\n"); | ||
552 | return -ETIMEDOUT; | ||
553 | } | ||
554 | |||
555 | static int s5c73m3_spi_boot(struct s5c73m3 *state, bool load_fw) | ||
556 | { | ||
557 | struct v4l2_subdev *sd = &state->sensor_sd; | ||
558 | int ret; | ||
559 | |||
560 | /* Run ARM MCU */ | ||
561 | ret = s5c73m3_write(state, 0x30000004, 0xffff); | ||
562 | if (ret < 0) | ||
563 | return ret; | ||
564 | |||
565 | usleep_range(400, 500); | ||
566 | |||
567 | /* Check booting status */ | ||
568 | ret = s5c73m3_system_status_wait(state, 0x0c, 100, 3); | ||
569 | if (ret < 0) { | ||
570 | v4l2_err(sd, "booting failed: %d\n", ret); | ||
571 | return ret; | ||
572 | } | ||
573 | |||
574 | /* P,M,S and Boot Mode */ | ||
575 | ret = s5c73m3_write(state, 0x30100014, 0x2146); | ||
576 | if (ret < 0) | ||
577 | return ret; | ||
578 | |||
579 | ret = s5c73m3_write(state, 0x30100010, 0x210c); | ||
580 | if (ret < 0) | ||
581 | return ret; | ||
582 | |||
583 | usleep_range(200, 250); | ||
584 | |||
585 | /* Check SPI status */ | ||
586 | ret = s5c73m3_system_status_wait(state, 0x210d, 100, 300); | ||
587 | if (ret < 0) | ||
588 | v4l2_err(sd, "SPI not ready: %d\n", ret); | ||
589 | |||
590 | /* Firmware download over SPI */ | ||
591 | if (load_fw) | ||
592 | s5c73m3_load_fw(sd); | ||
593 | |||
594 | /* MCU reset */ | ||
595 | ret = s5c73m3_write(state, 0x30000004, 0xfffd); | ||
596 | if (ret < 0) | ||
597 | return ret; | ||
598 | |||
599 | /* Remap */ | ||
600 | ret = s5c73m3_write(state, 0x301000a4, 0x0183); | ||
601 | if (ret < 0) | ||
602 | return ret; | ||
603 | |||
604 | /* MCU restart */ | ||
605 | ret = s5c73m3_write(state, 0x30000004, 0xffff); | ||
606 | if (ret < 0 || !load_fw) | ||
607 | return ret; | ||
608 | |||
609 | ret = s5c73m3_read_fw_version(state); | ||
610 | if (ret < 0) | ||
611 | return ret; | ||
612 | |||
613 | if (load_fw && update_fw) { | ||
614 | ret = s5c73m3_fw_update_from(state); | ||
615 | update_fw = 0; | ||
616 | } | ||
617 | |||
618 | return ret; | ||
619 | } | ||
620 | |||
621 | static int s5c73m3_set_timing_register_for_vdd(struct s5c73m3 *state) | ||
622 | { | ||
623 | static const u32 regs[][2] = { | ||
624 | { 0x30100018, 0x0618 }, | ||
625 | { 0x3010001c, 0x10c1 }, | ||
626 | { 0x30100020, 0x249e } | ||
627 | }; | ||
628 | int ret; | ||
629 | int i; | ||
630 | |||
631 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
632 | ret = s5c73m3_write(state, regs[i][0], regs[i][1]); | ||
633 | if (ret < 0) | ||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | static void s5c73m3_set_fw_file_version(struct s5c73m3 *state) | ||
641 | { | ||
642 | switch (state->sensor_fw[0]) { | ||
643 | case 'G': | ||
644 | case 'O': | ||
645 | state->fw_file_version[0] = 'G'; | ||
646 | break; | ||
647 | case 'S': | ||
648 | case 'Z': | ||
649 | state->fw_file_version[0] = 'Z'; | ||
650 | break; | ||
651 | } | ||
652 | |||
653 | switch (state->sensor_fw[1]) { | ||
654 | case 'C'...'F': | ||
655 | state->fw_file_version[1] = state->sensor_fw[1]; | ||
656 | break; | ||
657 | } | ||
658 | } | ||
659 | |||
660 | static int s5c73m3_get_fw_version(struct s5c73m3 *state) | ||
661 | { | ||
662 | struct v4l2_subdev *sd = &state->sensor_sd; | ||
663 | int ret; | ||
664 | |||
665 | /* Run ARM MCU */ | ||
666 | ret = s5c73m3_write(state, 0x30000004, 0xffff); | ||
667 | if (ret < 0) | ||
668 | return ret; | ||
669 | usleep_range(400, 500); | ||
670 | |||
671 | /* Check booting status */ | ||
672 | ret = s5c73m3_system_status_wait(state, 0x0c, 100, 3); | ||
673 | if (ret < 0) { | ||
674 | |||
675 | v4l2_err(sd, "%s: booting failed: %d\n", __func__, ret); | ||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | /* Change I/O Driver Current in order to read from F-ROM */ | ||
680 | ret = s5c73m3_write(state, 0x30100120, 0x0820); | ||
681 | ret = s5c73m3_write(state, 0x30100124, 0x0820); | ||
682 | |||
683 | /* Offset Setting */ | ||
684 | ret = s5c73m3_write(state, 0x00010418, 0x0008); | ||
685 | |||
686 | /* P,M,S and Boot Mode */ | ||
687 | ret = s5c73m3_write(state, 0x30100014, 0x2146); | ||
688 | if (ret < 0) | ||
689 | return ret; | ||
690 | ret = s5c73m3_write(state, 0x30100010, 0x230c); | ||
691 | if (ret < 0) | ||
692 | return ret; | ||
693 | |||
694 | usleep_range(200, 250); | ||
695 | |||
696 | /* Check SPI status */ | ||
697 | ret = s5c73m3_system_status_wait(state, 0x230e, 100, 300); | ||
698 | if (ret < 0) | ||
699 | v4l2_err(sd, "SPI not ready: %d\n", ret); | ||
700 | |||
701 | /* ARM reset */ | ||
702 | ret = s5c73m3_write(state, 0x30000004, 0xfffd); | ||
703 | if (ret < 0) | ||
704 | return ret; | ||
705 | |||
706 | /* Remap */ | ||
707 | ret = s5c73m3_write(state, 0x301000a4, 0x0183); | ||
708 | if (ret < 0) | ||
709 | return ret; | ||
710 | |||
711 | s5c73m3_set_timing_register_for_vdd(state); | ||
712 | |||
713 | ret = s5c73m3_read_fw_version(state); | ||
714 | |||
715 | s5c73m3_set_fw_file_version(state); | ||
716 | |||
717 | return ret; | ||
718 | } | ||
719 | |||
720 | static int s5c73m3_rom_boot(struct s5c73m3 *state, bool load_fw) | ||
721 | { | ||
722 | static const u32 boot_regs[][2] = { | ||
723 | { 0x3100010c, 0x0044 }, | ||
724 | { 0x31000108, 0x000d }, | ||
725 | { 0x31000304, 0x0001 }, | ||
726 | { 0x00010000, 0x5800 }, | ||
727 | { 0x00010002, 0x0002 }, | ||
728 | { 0x31000000, 0x0001 }, | ||
729 | { 0x30100014, 0x1b85 }, | ||
730 | { 0x30100010, 0x230c } | ||
731 | }; | ||
732 | struct v4l2_subdev *sd = &state->sensor_sd; | ||
733 | int i, ret; | ||
734 | |||
735 | /* Run ARM MCU */ | ||
736 | ret = s5c73m3_write(state, 0x30000004, 0xffff); | ||
737 | if (ret < 0) | ||
738 | return ret; | ||
739 | usleep_range(400, 450); | ||
740 | |||
741 | /* Check booting status */ | ||
742 | ret = s5c73m3_system_status_wait(state, 0x0c, 100, 4); | ||
743 | if (ret < 0) { | ||
744 | v4l2_err(sd, "Booting failed: %d\n", ret); | ||
745 | return ret; | ||
746 | } | ||
747 | |||
748 | for (i = 0; i < ARRAY_SIZE(boot_regs); i++) { | ||
749 | ret = s5c73m3_write(state, boot_regs[i][0], boot_regs[i][1]); | ||
750 | if (ret < 0) | ||
751 | return ret; | ||
752 | } | ||
753 | msleep(200); | ||
754 | |||
755 | /* Check the binary read status */ | ||
756 | ret = s5c73m3_system_status_wait(state, 0x230e, 1000, 150); | ||
757 | if (ret < 0) { | ||
758 | v4l2_err(sd, "Binary read failed: %d\n", ret); | ||
759 | return ret; | ||
760 | } | ||
761 | |||
762 | /* ARM reset */ | ||
763 | ret = s5c73m3_write(state, 0x30000004, 0xfffd); | ||
764 | if (ret < 0) | ||
765 | return ret; | ||
766 | /* Remap */ | ||
767 | ret = s5c73m3_write(state, 0x301000a4, 0x0183); | ||
768 | if (ret < 0) | ||
769 | return ret; | ||
770 | /* MCU re-start */ | ||
771 | ret = s5c73m3_write(state, 0x30000004, 0xffff); | ||
772 | if (ret < 0) | ||
773 | return ret; | ||
774 | |||
775 | state->isp_ready = 1; | ||
776 | |||
777 | return s5c73m3_read_fw_version(state); | ||
778 | } | ||
779 | |||
780 | static int s5c73m3_isp_init(struct s5c73m3 *state) | ||
781 | { | ||
782 | int ret; | ||
783 | |||
784 | state->i2c_read_address = 0; | ||
785 | state->i2c_write_address = 0; | ||
786 | |||
787 | ret = s5c73m3_i2c_write(state->i2c_client, AHB_MSB_ADDR_PTR, 0x3310); | ||
788 | if (ret < 0) | ||
789 | return ret; | ||
790 | |||
791 | if (boot_from_rom) | ||
792 | return s5c73m3_rom_boot(state, true); | ||
793 | else | ||
794 | return s5c73m3_spi_boot(state, true); | ||
795 | } | ||
796 | |||
797 | static const struct s5c73m3_frame_size *s5c73m3_find_frame_size( | ||
798 | struct v4l2_mbus_framefmt *fmt, | ||
799 | enum s5c73m3_resolution_types idx) | ||
800 | { | ||
801 | const struct s5c73m3_frame_size *fs; | ||
802 | const struct s5c73m3_frame_size *best_fs; | ||
803 | int best_dist = INT_MAX; | ||
804 | int i; | ||
805 | |||
806 | fs = s5c73m3_resolutions[idx]; | ||
807 | best_fs = NULL; | ||
808 | for (i = 0; i < s5c73m3_resolutions_len[idx]; ++i) { | ||
809 | int dist = abs(fs->width - fmt->width) + | ||
810 | abs(fs->height - fmt->height); | ||
811 | if (dist < best_dist) { | ||
812 | best_dist = dist; | ||
813 | best_fs = fs; | ||
814 | } | ||
815 | ++fs; | ||
816 | } | ||
817 | |||
818 | return best_fs; | ||
819 | } | ||
820 | |||
821 | static void s5c73m3_oif_try_format(struct s5c73m3 *state, | ||
822 | struct v4l2_subdev_fh *fh, | ||
823 | struct v4l2_subdev_format *fmt, | ||
824 | const struct s5c73m3_frame_size **fs) | ||
825 | { | ||
826 | u32 code; | ||
827 | |||
828 | switch (fmt->pad) { | ||
829 | case OIF_ISP_PAD: | ||
830 | *fs = s5c73m3_find_frame_size(&fmt->format, RES_ISP); | ||
831 | code = S5C73M3_ISP_FMT; | ||
832 | break; | ||
833 | case OIF_JPEG_PAD: | ||
834 | *fs = s5c73m3_find_frame_size(&fmt->format, RES_JPEG); | ||
835 | code = S5C73M3_JPEG_FMT; | ||
836 | break; | ||
837 | case OIF_SOURCE_PAD: | ||
838 | default: | ||
839 | if (fmt->format.code == S5C73M3_JPEG_FMT) | ||
840 | code = S5C73M3_JPEG_FMT; | ||
841 | else | ||
842 | code = S5C73M3_ISP_FMT; | ||
843 | |||
844 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) | ||
845 | *fs = state->oif_pix_size[RES_ISP]; | ||
846 | else | ||
847 | *fs = s5c73m3_find_frame_size( | ||
848 | v4l2_subdev_get_try_format(fh, | ||
849 | OIF_ISP_PAD), | ||
850 | RES_ISP); | ||
851 | break; | ||
852 | } | ||
853 | |||
854 | s5c73m3_fill_mbus_fmt(&fmt->format, *fs, code); | ||
855 | } | ||
856 | |||
857 | static void s5c73m3_try_format(struct s5c73m3 *state, | ||
858 | struct v4l2_subdev_fh *fh, | ||
859 | struct v4l2_subdev_format *fmt, | ||
860 | const struct s5c73m3_frame_size **fs) | ||
861 | { | ||
862 | u32 code; | ||
863 | |||
864 | if (fmt->pad == S5C73M3_ISP_PAD) { | ||
865 | *fs = s5c73m3_find_frame_size(&fmt->format, RES_ISP); | ||
866 | code = S5C73M3_ISP_FMT; | ||
867 | } else { | ||
868 | *fs = s5c73m3_find_frame_size(&fmt->format, RES_JPEG); | ||
869 | code = S5C73M3_JPEG_FMT; | ||
870 | } | ||
871 | |||
872 | s5c73m3_fill_mbus_fmt(&fmt->format, *fs, code); | ||
873 | } | ||
874 | |||
875 | static int s5c73m3_oif_g_frame_interval(struct v4l2_subdev *sd, | ||
876 | struct v4l2_subdev_frame_interval *fi) | ||
877 | { | ||
878 | struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); | ||
879 | |||
880 | if (fi->pad != OIF_SOURCE_PAD) | ||
881 | return -EINVAL; | ||
882 | |||
883 | mutex_lock(&state->lock); | ||
884 | fi->interval = state->fiv->interval; | ||
885 | mutex_unlock(&state->lock); | ||
886 | |||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | static int __s5c73m3_set_frame_interval(struct s5c73m3 *state, | ||
891 | struct v4l2_subdev_frame_interval *fi) | ||
892 | { | ||
893 | const struct s5c73m3_frame_size *prev_size = | ||
894 | state->sensor_pix_size[RES_ISP]; | ||
895 | const struct s5c73m3_interval *fiv = &s5c73m3_intervals[0]; | ||
896 | unsigned int ret, min_err = UINT_MAX; | ||
897 | unsigned int i, fr_time; | ||
898 | |||
899 | if (fi->interval.denominator == 0) | ||
900 | return -EINVAL; | ||
901 | |||
902 | fr_time = fi->interval.numerator * 1000 / fi->interval.denominator; | ||
903 | |||
904 | for (i = 0; i < ARRAY_SIZE(s5c73m3_intervals); i++) { | ||
905 | const struct s5c73m3_interval *iv = &s5c73m3_intervals[i]; | ||
906 | |||
907 | if (prev_size->width > iv->size.width || | ||
908 | prev_size->height > iv->size.height) | ||
909 | continue; | ||
910 | |||
911 | ret = abs(iv->interval.numerator / 1000 - fr_time); | ||
912 | if (ret < min_err) { | ||
913 | fiv = iv; | ||
914 | min_err = ret; | ||
915 | } | ||
916 | } | ||
917 | state->fiv = fiv; | ||
918 | |||
919 | v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, | ||
920 | "Changed frame interval to %u us\n", fiv->interval.numerator); | ||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | static int s5c73m3_oif_s_frame_interval(struct v4l2_subdev *sd, | ||
925 | struct v4l2_subdev_frame_interval *fi) | ||
926 | { | ||
927 | struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); | ||
928 | int ret; | ||
929 | |||
930 | if (fi->pad != OIF_SOURCE_PAD) | ||
931 | return -EINVAL; | ||
932 | |||
933 | v4l2_dbg(1, s5c73m3_dbg, sd, "Setting %d/%d frame interval\n", | ||
934 | fi->interval.numerator, fi->interval.denominator); | ||
935 | |||
936 | mutex_lock(&state->lock); | ||
937 | |||
938 | ret = __s5c73m3_set_frame_interval(state, fi); | ||
939 | if (!ret) { | ||
940 | if (state->streaming) | ||
941 | ret = s5c73m3_set_frame_rate(state); | ||
942 | else | ||
943 | state->apply_fiv = 1; | ||
944 | } | ||
945 | mutex_unlock(&state->lock); | ||
946 | return ret; | ||
947 | } | ||
948 | |||
949 | static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd, | ||
950 | struct v4l2_subdev_fh *fh, | ||
951 | struct v4l2_subdev_frame_interval_enum *fie) | ||
952 | { | ||
953 | struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); | ||
954 | const struct s5c73m3_interval *fi; | ||
955 | int ret = 0; | ||
956 | |||
957 | if (fie->pad != OIF_SOURCE_PAD) | ||
958 | return -EINVAL; | ||
959 | if (fie->index > ARRAY_SIZE(s5c73m3_intervals)) | ||
960 | return -EINVAL; | ||
961 | |||
962 | mutex_lock(&state->lock); | ||
963 | fi = &s5c73m3_intervals[fie->index]; | ||
964 | if (fie->width > fi->size.width || fie->height > fi->size.height) | ||
965 | ret = -EINVAL; | ||
966 | else | ||
967 | fie->interval = fi->interval; | ||
968 | mutex_unlock(&state->lock); | ||
969 | |||
970 | return ret; | ||
971 | } | ||
972 | |||
973 | static int s5c73m3_oif_get_pad_code(int pad, int index) | ||
974 | { | ||
975 | if (pad == OIF_SOURCE_PAD) { | ||
976 | if (index > 1) | ||
977 | return -EINVAL; | ||
978 | return (index == 0) ? S5C73M3_ISP_FMT : S5C73M3_JPEG_FMT; | ||
979 | } | ||
980 | |||
981 | if (index > 0) | ||
982 | return -EINVAL; | ||
983 | |||
984 | return (pad == OIF_ISP_PAD) ? S5C73M3_ISP_FMT : S5C73M3_JPEG_FMT; | ||
985 | } | ||
986 | |||
987 | static int s5c73m3_get_fmt(struct v4l2_subdev *sd, | ||
988 | struct v4l2_subdev_fh *fh, | ||
989 | struct v4l2_subdev_format *fmt) | ||
990 | { | ||
991 | struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); | ||
992 | const struct s5c73m3_frame_size *fs; | ||
993 | u32 code; | ||
994 | |||
995 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
996 | fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); | ||
997 | return 0; | ||
998 | } | ||
999 | |||
1000 | mutex_lock(&state->lock); | ||
1001 | |||
1002 | switch (fmt->pad) { | ||
1003 | case S5C73M3_ISP_PAD: | ||
1004 | code = S5C73M3_ISP_FMT; | ||
1005 | fs = state->sensor_pix_size[RES_ISP]; | ||
1006 | break; | ||
1007 | case S5C73M3_JPEG_PAD: | ||
1008 | code = S5C73M3_JPEG_FMT; | ||
1009 | fs = state->sensor_pix_size[RES_JPEG]; | ||
1010 | break; | ||
1011 | default: | ||
1012 | mutex_unlock(&state->lock); | ||
1013 | return -EINVAL; | ||
1014 | } | ||
1015 | s5c73m3_fill_mbus_fmt(&fmt->format, fs, code); | ||
1016 | |||
1017 | mutex_unlock(&state->lock); | ||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
1021 | static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd, | ||
1022 | struct v4l2_subdev_fh *fh, | ||
1023 | struct v4l2_subdev_format *fmt) | ||
1024 | { | ||
1025 | struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); | ||
1026 | const struct s5c73m3_frame_size *fs; | ||
1027 | u32 code; | ||
1028 | |||
1029 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1030 | fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); | ||
1031 | return 0; | ||
1032 | } | ||
1033 | |||
1034 | mutex_lock(&state->lock); | ||
1035 | |||
1036 | switch (fmt->pad) { | ||
1037 | case OIF_ISP_PAD: | ||
1038 | code = S5C73M3_ISP_FMT; | ||
1039 | fs = state->oif_pix_size[RES_ISP]; | ||
1040 | break; | ||
1041 | case OIF_JPEG_PAD: | ||
1042 | code = S5C73M3_JPEG_FMT; | ||
1043 | fs = state->oif_pix_size[RES_JPEG]; | ||
1044 | break; | ||
1045 | case OIF_SOURCE_PAD: | ||
1046 | code = state->mbus_code; | ||
1047 | fs = state->oif_pix_size[RES_ISP]; | ||
1048 | break; | ||
1049 | default: | ||
1050 | mutex_unlock(&state->lock); | ||
1051 | return -EINVAL; | ||
1052 | } | ||
1053 | s5c73m3_fill_mbus_fmt(&fmt->format, fs, code); | ||
1054 | |||
1055 | mutex_unlock(&state->lock); | ||
1056 | return 0; | ||
1057 | } | ||
1058 | |||
1059 | static int s5c73m3_set_fmt(struct v4l2_subdev *sd, | ||
1060 | struct v4l2_subdev_fh *fh, | ||
1061 | struct v4l2_subdev_format *fmt) | ||
1062 | { | ||
1063 | const struct s5c73m3_frame_size *frame_size = NULL; | ||
1064 | struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); | ||
1065 | struct v4l2_mbus_framefmt *mf; | ||
1066 | int ret = 0; | ||
1067 | |||
1068 | mutex_lock(&state->lock); | ||
1069 | |||
1070 | s5c73m3_try_format(state, fh, fmt, &frame_size); | ||
1071 | |||
1072 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1073 | mf = v4l2_subdev_get_try_format(fh, fmt->pad); | ||
1074 | *mf = fmt->format; | ||
1075 | } else { | ||
1076 | switch (fmt->pad) { | ||
1077 | case S5C73M3_ISP_PAD: | ||
1078 | state->sensor_pix_size[RES_ISP] = frame_size; | ||
1079 | break; | ||
1080 | case S5C73M3_JPEG_PAD: | ||
1081 | state->sensor_pix_size[RES_JPEG] = frame_size; | ||
1082 | break; | ||
1083 | default: | ||
1084 | ret = -EBUSY; | ||
1085 | } | ||
1086 | |||
1087 | if (state->streaming) | ||
1088 | ret = -EBUSY; | ||
1089 | else | ||
1090 | state->apply_fmt = 1; | ||
1091 | } | ||
1092 | |||
1093 | mutex_unlock(&state->lock); | ||
1094 | |||
1095 | return ret; | ||
1096 | } | ||
1097 | |||
1098 | static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd, | ||
1099 | struct v4l2_subdev_fh *fh, | ||
1100 | struct v4l2_subdev_format *fmt) | ||
1101 | { | ||
1102 | const struct s5c73m3_frame_size *frame_size = NULL; | ||
1103 | struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); | ||
1104 | struct v4l2_mbus_framefmt *mf; | ||
1105 | int ret = 0; | ||
1106 | |||
1107 | mutex_lock(&state->lock); | ||
1108 | |||
1109 | s5c73m3_oif_try_format(state, fh, fmt, &frame_size); | ||
1110 | |||
1111 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1112 | mf = v4l2_subdev_get_try_format(fh, fmt->pad); | ||
1113 | *mf = fmt->format; | ||
1114 | } else { | ||
1115 | switch (fmt->pad) { | ||
1116 | case OIF_ISP_PAD: | ||
1117 | state->oif_pix_size[RES_ISP] = frame_size; | ||
1118 | break; | ||
1119 | case OIF_JPEG_PAD: | ||
1120 | state->oif_pix_size[RES_JPEG] = frame_size; | ||
1121 | break; | ||
1122 | case OIF_SOURCE_PAD: | ||
1123 | state->mbus_code = fmt->format.code; | ||
1124 | break; | ||
1125 | default: | ||
1126 | ret = -EBUSY; | ||
1127 | } | ||
1128 | |||
1129 | if (state->streaming) | ||
1130 | ret = -EBUSY; | ||
1131 | else | ||
1132 | state->apply_fmt = 1; | ||
1133 | } | ||
1134 | |||
1135 | mutex_unlock(&state->lock); | ||
1136 | |||
1137 | return ret; | ||
1138 | } | ||
1139 | |||
1140 | static int s5c73m3_oif_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, | ||
1141 | struct v4l2_mbus_frame_desc *fd) | ||
1142 | { | ||
1143 | struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); | ||
1144 | int i; | ||
1145 | |||
1146 | if (pad != OIF_SOURCE_PAD || fd == NULL) | ||
1147 | return -EINVAL; | ||
1148 | |||
1149 | mutex_lock(&state->lock); | ||
1150 | fd->num_entries = 2; | ||
1151 | for (i = 0; i < fd->num_entries; i++) | ||
1152 | fd->entry[i] = state->frame_desc.entry[i]; | ||
1153 | mutex_unlock(&state->lock); | ||
1154 | |||
1155 | return 0; | ||
1156 | } | ||
1157 | |||
1158 | static int s5c73m3_oif_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad, | ||
1159 | struct v4l2_mbus_frame_desc *fd) | ||
1160 | { | ||
1161 | struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); | ||
1162 | struct v4l2_mbus_frame_desc *frame_desc = &state->frame_desc; | ||
1163 | int i; | ||
1164 | |||
1165 | if (pad != OIF_SOURCE_PAD || fd == NULL) | ||
1166 | return -EINVAL; | ||
1167 | |||
1168 | fd->entry[0].length = 10 * SZ_1M; | ||
1169 | fd->entry[1].length = max_t(u32, fd->entry[1].length, | ||
1170 | S5C73M3_EMBEDDED_DATA_MAXLEN); | ||
1171 | fd->num_entries = 2; | ||
1172 | |||
1173 | mutex_lock(&state->lock); | ||
1174 | for (i = 0; i < fd->num_entries; i++) | ||
1175 | frame_desc->entry[i] = fd->entry[i]; | ||
1176 | mutex_unlock(&state->lock); | ||
1177 | |||
1178 | return 0; | ||
1179 | } | ||
1180 | |||
1181 | static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd, | ||
1182 | struct v4l2_subdev_fh *fh, | ||
1183 | struct v4l2_subdev_mbus_code_enum *code) | ||
1184 | { | ||
1185 | static const int codes[] = { | ||
1186 | [S5C73M3_ISP_PAD] = S5C73M3_ISP_FMT, | ||
1187 | [S5C73M3_JPEG_PAD] = S5C73M3_JPEG_FMT}; | ||
1188 | |||
1189 | if (code->index > 0 || code->pad >= S5C73M3_NUM_PADS) | ||
1190 | return -EINVAL; | ||
1191 | |||
1192 | code->code = codes[code->pad]; | ||
1193 | |||
1194 | return 0; | ||
1195 | } | ||
1196 | |||
1197 | static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd, | ||
1198 | struct v4l2_subdev_fh *fh, | ||
1199 | struct v4l2_subdev_mbus_code_enum *code) | ||
1200 | { | ||
1201 | int ret; | ||
1202 | |||
1203 | ret = s5c73m3_oif_get_pad_code(code->pad, code->index); | ||
1204 | if (ret < 0) | ||
1205 | return ret; | ||
1206 | |||
1207 | code->code = ret; | ||
1208 | |||
1209 | return 0; | ||
1210 | } | ||
1211 | |||
1212 | static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd, | ||
1213 | struct v4l2_subdev_fh *fh, | ||
1214 | struct v4l2_subdev_frame_size_enum *fse) | ||
1215 | { | ||
1216 | int idx; | ||
1217 | |||
1218 | if (fse->pad == S5C73M3_ISP_PAD) { | ||
1219 | if (fse->code != S5C73M3_ISP_FMT) | ||
1220 | return -EINVAL; | ||
1221 | idx = RES_ISP; | ||
1222 | } else{ | ||
1223 | if (fse->code != S5C73M3_JPEG_FMT) | ||
1224 | return -EINVAL; | ||
1225 | idx = RES_JPEG; | ||
1226 | } | ||
1227 | |||
1228 | if (fse->index >= s5c73m3_resolutions_len[idx]) | ||
1229 | return -EINVAL; | ||
1230 | |||
1231 | fse->min_width = s5c73m3_resolutions[idx][fse->index].width; | ||
1232 | fse->max_width = fse->min_width; | ||
1233 | fse->max_height = s5c73m3_resolutions[idx][fse->index].height; | ||
1234 | fse->min_height = fse->max_height; | ||
1235 | |||
1236 | return 0; | ||
1237 | } | ||
1238 | |||
1239 | static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd, | ||
1240 | struct v4l2_subdev_fh *fh, | ||
1241 | struct v4l2_subdev_frame_size_enum *fse) | ||
1242 | { | ||
1243 | int idx; | ||
1244 | |||
1245 | if (fse->pad == OIF_SOURCE_PAD) { | ||
1246 | if (fse->index > 0) | ||
1247 | return -EINVAL; | ||
1248 | |||
1249 | switch (fse->code) { | ||
1250 | case S5C73M3_JPEG_FMT: | ||
1251 | case S5C73M3_ISP_FMT: { | ||
1252 | struct v4l2_mbus_framefmt *mf = | ||
1253 | v4l2_subdev_get_try_format(fh, OIF_ISP_PAD); | ||
1254 | |||
1255 | fse->max_width = fse->min_width = mf->width; | ||
1256 | fse->max_height = fse->min_height = mf->height; | ||
1257 | return 0; | ||
1258 | } | ||
1259 | default: | ||
1260 | return -EINVAL; | ||
1261 | } | ||
1262 | } | ||
1263 | |||
1264 | if (fse->code != s5c73m3_oif_get_pad_code(fse->pad, 0)) | ||
1265 | return -EINVAL; | ||
1266 | |||
1267 | if (fse->pad == OIF_JPEG_PAD) | ||
1268 | idx = RES_JPEG; | ||
1269 | else | ||
1270 | idx = RES_ISP; | ||
1271 | |||
1272 | if (fse->index >= s5c73m3_resolutions_len[idx]) | ||
1273 | return -EINVAL; | ||
1274 | |||
1275 | fse->min_width = s5c73m3_resolutions[idx][fse->index].width; | ||
1276 | fse->max_width = fse->min_width; | ||
1277 | fse->max_height = s5c73m3_resolutions[idx][fse->index].height; | ||
1278 | fse->min_height = fse->max_height; | ||
1279 | |||
1280 | return 0; | ||
1281 | } | ||
1282 | |||
1283 | static int s5c73m3_oif_log_status(struct v4l2_subdev *sd) | ||
1284 | { | ||
1285 | struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); | ||
1286 | |||
1287 | v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name); | ||
1288 | |||
1289 | v4l2_info(sd, "power: %d, apply_fmt: %d\n", state->power, | ||
1290 | state->apply_fmt); | ||
1291 | |||
1292 | return 0; | ||
1293 | } | ||
1294 | |||
1295 | static int s5c73m3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
1296 | { | ||
1297 | struct v4l2_mbus_framefmt *mf; | ||
1298 | |||
1299 | mf = v4l2_subdev_get_try_format(fh, S5C73M3_ISP_PAD); | ||
1300 | s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], | ||
1301 | S5C73M3_ISP_FMT); | ||
1302 | |||
1303 | mf = v4l2_subdev_get_try_format(fh, S5C73M3_JPEG_PAD); | ||
1304 | s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], | ||
1305 | S5C73M3_JPEG_FMT); | ||
1306 | |||
1307 | return 0; | ||
1308 | } | ||
1309 | |||
1310 | static int s5c73m3_oif_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
1311 | { | ||
1312 | struct v4l2_mbus_framefmt *mf; | ||
1313 | |||
1314 | mf = v4l2_subdev_get_try_format(fh, OIF_ISP_PAD); | ||
1315 | s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], | ||
1316 | S5C73M3_ISP_FMT); | ||
1317 | |||
1318 | mf = v4l2_subdev_get_try_format(fh, OIF_JPEG_PAD); | ||
1319 | s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], | ||
1320 | S5C73M3_JPEG_FMT); | ||
1321 | |||
1322 | mf = v4l2_subdev_get_try_format(fh, OIF_SOURCE_PAD); | ||
1323 | s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], | ||
1324 | S5C73M3_ISP_FMT); | ||
1325 | return 0; | ||
1326 | } | ||
1327 | |||
1328 | static int s5c73m3_gpio_set_value(struct s5c73m3 *priv, int id, u32 val) | ||
1329 | { | ||
1330 | if (!gpio_is_valid(priv->gpio[id].gpio)) | ||
1331 | return 0; | ||
1332 | gpio_set_value(priv->gpio[id].gpio, !!val); | ||
1333 | return 1; | ||
1334 | } | ||
1335 | |||
1336 | static int s5c73m3_gpio_assert(struct s5c73m3 *priv, int id) | ||
1337 | { | ||
1338 | return s5c73m3_gpio_set_value(priv, id, priv->gpio[id].level); | ||
1339 | } | ||
1340 | |||
1341 | static int s5c73m3_gpio_deassert(struct s5c73m3 *priv, int id) | ||
1342 | { | ||
1343 | return s5c73m3_gpio_set_value(priv, id, !priv->gpio[id].level); | ||
1344 | } | ||
1345 | |||
1346 | static int __s5c73m3_power_on(struct s5c73m3 *state) | ||
1347 | { | ||
1348 | int i, ret; | ||
1349 | |||
1350 | for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++) { | ||
1351 | ret = regulator_enable(state->supplies[i].consumer); | ||
1352 | if (ret) | ||
1353 | goto err; | ||
1354 | } | ||
1355 | |||
1356 | s5c73m3_gpio_deassert(state, STBY); | ||
1357 | usleep_range(100, 200); | ||
1358 | |||
1359 | s5c73m3_gpio_deassert(state, RST); | ||
1360 | usleep_range(50, 100); | ||
1361 | |||
1362 | return 0; | ||
1363 | err: | ||
1364 | for (--i; i >= 0; i--) | ||
1365 | regulator_disable(state->supplies[i].consumer); | ||
1366 | return ret; | ||
1367 | } | ||
1368 | |||
1369 | static int __s5c73m3_power_off(struct s5c73m3 *state) | ||
1370 | { | ||
1371 | int i, ret; | ||
1372 | |||
1373 | if (s5c73m3_gpio_assert(state, RST)) | ||
1374 | usleep_range(10, 50); | ||
1375 | |||
1376 | if (s5c73m3_gpio_assert(state, STBY)) | ||
1377 | usleep_range(100, 200); | ||
1378 | state->streaming = 0; | ||
1379 | state->isp_ready = 0; | ||
1380 | |||
1381 | for (i = S5C73M3_MAX_SUPPLIES - 1; i >= 0; i--) { | ||
1382 | ret = regulator_disable(state->supplies[i].consumer); | ||
1383 | if (ret) | ||
1384 | goto err; | ||
1385 | } | ||
1386 | return 0; | ||
1387 | err: | ||
1388 | for (++i; i < S5C73M3_MAX_SUPPLIES; i++) | ||
1389 | regulator_enable(state->supplies[i].consumer); | ||
1390 | |||
1391 | return ret; | ||
1392 | } | ||
1393 | |||
1394 | static int s5c73m3_oif_set_power(struct v4l2_subdev *sd, int on) | ||
1395 | { | ||
1396 | struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); | ||
1397 | int ret = 0; | ||
1398 | |||
1399 | mutex_lock(&state->lock); | ||
1400 | |||
1401 | if (on && !state->power) { | ||
1402 | ret = __s5c73m3_power_on(state); | ||
1403 | if (!ret) | ||
1404 | ret = s5c73m3_isp_init(state); | ||
1405 | if (!ret) { | ||
1406 | state->apply_fiv = 1; | ||
1407 | state->apply_fmt = 1; | ||
1408 | } | ||
1409 | } else if (!on == state->power) { | ||
1410 | ret = s5c73m3_set_af_softlanding(state); | ||
1411 | if (!ret) | ||
1412 | ret = __s5c73m3_power_off(state); | ||
1413 | else | ||
1414 | v4l2_err(sd, "Soft landing lens failed\n"); | ||
1415 | } | ||
1416 | if (!ret) | ||
1417 | state->power += on ? 1 : -1; | ||
1418 | |||
1419 | v4l2_dbg(1, s5c73m3_dbg, sd, "%s: power: %d\n", | ||
1420 | __func__, state->power); | ||
1421 | |||
1422 | mutex_unlock(&state->lock); | ||
1423 | return ret; | ||
1424 | } | ||
1425 | |||
1426 | static int s5c73m3_oif_registered(struct v4l2_subdev *sd) | ||
1427 | { | ||
1428 | struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); | ||
1429 | int ret; | ||
1430 | |||
1431 | ret = v4l2_device_register_subdev(sd->v4l2_dev, &state->sensor_sd); | ||
1432 | if (ret) { | ||
1433 | v4l2_err(sd->v4l2_dev, "Failed to register %s\n", | ||
1434 | state->oif_sd.name); | ||
1435 | return ret; | ||
1436 | } | ||
1437 | |||
1438 | ret = media_entity_create_link(&state->sensor_sd.entity, | ||
1439 | S5C73M3_ISP_PAD, &state->oif_sd.entity, OIF_ISP_PAD, | ||
1440 | MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); | ||
1441 | |||
1442 | ret = media_entity_create_link(&state->sensor_sd.entity, | ||
1443 | S5C73M3_JPEG_PAD, &state->oif_sd.entity, OIF_JPEG_PAD, | ||
1444 | MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); | ||
1445 | |||
1446 | mutex_lock(&state->lock); | ||
1447 | ret = __s5c73m3_power_on(state); | ||
1448 | if (ret == 0) | ||
1449 | s5c73m3_get_fw_version(state); | ||
1450 | |||
1451 | __s5c73m3_power_off(state); | ||
1452 | mutex_unlock(&state->lock); | ||
1453 | |||
1454 | v4l2_dbg(1, s5c73m3_dbg, sd, "%s: Booting %s (%d)\n", | ||
1455 | __func__, ret ? "failed" : "succeded", ret); | ||
1456 | |||
1457 | return ret; | ||
1458 | } | ||
1459 | |||
1460 | static const struct v4l2_subdev_internal_ops s5c73m3_internal_ops = { | ||
1461 | .open = s5c73m3_open, | ||
1462 | }; | ||
1463 | |||
1464 | static const struct v4l2_subdev_pad_ops s5c73m3_pad_ops = { | ||
1465 | .enum_mbus_code = s5c73m3_enum_mbus_code, | ||
1466 | .enum_frame_size = s5c73m3_enum_frame_size, | ||
1467 | .get_fmt = s5c73m3_get_fmt, | ||
1468 | .set_fmt = s5c73m3_set_fmt, | ||
1469 | }; | ||
1470 | |||
1471 | static const struct v4l2_subdev_ops s5c73m3_subdev_ops = { | ||
1472 | .pad = &s5c73m3_pad_ops, | ||
1473 | }; | ||
1474 | |||
1475 | static const struct v4l2_subdev_internal_ops oif_internal_ops = { | ||
1476 | .registered = s5c73m3_oif_registered, | ||
1477 | .open = s5c73m3_oif_open, | ||
1478 | }; | ||
1479 | |||
1480 | static const struct v4l2_subdev_pad_ops s5c73m3_oif_pad_ops = { | ||
1481 | .enum_mbus_code = s5c73m3_oif_enum_mbus_code, | ||
1482 | .enum_frame_size = s5c73m3_oif_enum_frame_size, | ||
1483 | .enum_frame_interval = s5c73m3_oif_enum_frame_interval, | ||
1484 | .get_fmt = s5c73m3_oif_get_fmt, | ||
1485 | .set_fmt = s5c73m3_oif_set_fmt, | ||
1486 | .get_frame_desc = s5c73m3_oif_get_frame_desc, | ||
1487 | .set_frame_desc = s5c73m3_oif_set_frame_desc, | ||
1488 | }; | ||
1489 | |||
1490 | static const struct v4l2_subdev_core_ops s5c73m3_oif_core_ops = { | ||
1491 | .s_power = s5c73m3_oif_set_power, | ||
1492 | .log_status = s5c73m3_oif_log_status, | ||
1493 | }; | ||
1494 | |||
1495 | static const struct v4l2_subdev_video_ops s5c73m3_oif_video_ops = { | ||
1496 | .s_stream = s5c73m3_oif_s_stream, | ||
1497 | .g_frame_interval = s5c73m3_oif_g_frame_interval, | ||
1498 | .s_frame_interval = s5c73m3_oif_s_frame_interval, | ||
1499 | }; | ||
1500 | |||
1501 | static const struct v4l2_subdev_ops oif_subdev_ops = { | ||
1502 | .core = &s5c73m3_oif_core_ops, | ||
1503 | .pad = &s5c73m3_oif_pad_ops, | ||
1504 | .video = &s5c73m3_oif_video_ops, | ||
1505 | }; | ||
1506 | |||
1507 | static int s5c73m3_configure_gpio(int nr, int val, const char *name) | ||
1508 | { | ||
1509 | unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; | ||
1510 | int ret; | ||
1511 | |||
1512 | if (!gpio_is_valid(nr)) | ||
1513 | return 0; | ||
1514 | ret = gpio_request_one(nr, flags, name); | ||
1515 | if (!ret) | ||
1516 | gpio_export(nr, 0); | ||
1517 | return ret; | ||
1518 | } | ||
1519 | |||
1520 | static int s5c73m3_free_gpios(struct s5c73m3 *state) | ||
1521 | { | ||
1522 | int i; | ||
1523 | |||
1524 | for (i = 0; i < ARRAY_SIZE(state->gpio); i++) { | ||
1525 | if (!gpio_is_valid(state->gpio[i].gpio)) | ||
1526 | continue; | ||
1527 | gpio_free(state->gpio[i].gpio); | ||
1528 | state->gpio[i].gpio = -EINVAL; | ||
1529 | } | ||
1530 | return 0; | ||
1531 | } | ||
1532 | |||
1533 | static int s5c73m3_configure_gpios(struct s5c73m3 *state, | ||
1534 | const struct s5c73m3_platform_data *pdata) | ||
1535 | { | ||
1536 | const struct s5c73m3_gpio *gpio = &pdata->gpio_stby; | ||
1537 | int ret; | ||
1538 | |||
1539 | state->gpio[STBY].gpio = -EINVAL; | ||
1540 | state->gpio[RST].gpio = -EINVAL; | ||
1541 | |||
1542 | ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_STBY"); | ||
1543 | if (ret) { | ||
1544 | s5c73m3_free_gpios(state); | ||
1545 | return ret; | ||
1546 | } | ||
1547 | state->gpio[STBY] = *gpio; | ||
1548 | if (gpio_is_valid(gpio->gpio)) | ||
1549 | gpio_set_value(gpio->gpio, 0); | ||
1550 | |||
1551 | gpio = &pdata->gpio_reset; | ||
1552 | ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_RST"); | ||
1553 | if (ret) { | ||
1554 | s5c73m3_free_gpios(state); | ||
1555 | return ret; | ||
1556 | } | ||
1557 | state->gpio[RST] = *gpio; | ||
1558 | if (gpio_is_valid(gpio->gpio)) | ||
1559 | gpio_set_value(gpio->gpio, 0); | ||
1560 | |||
1561 | return 0; | ||
1562 | } | ||
1563 | |||
1564 | static int s5c73m3_probe(struct i2c_client *client, | ||
1565 | const struct i2c_device_id *id) | ||
1566 | { | ||
1567 | struct device *dev = &client->dev; | ||
1568 | const struct s5c73m3_platform_data *pdata = client->dev.platform_data; | ||
1569 | struct v4l2_subdev *sd; | ||
1570 | struct v4l2_subdev *oif_sd; | ||
1571 | struct s5c73m3 *state; | ||
1572 | int ret, i; | ||
1573 | |||
1574 | if (pdata == NULL) { | ||
1575 | dev_err(&client->dev, "Platform data not specified\n"); | ||
1576 | return -EINVAL; | ||
1577 | } | ||
1578 | |||
1579 | state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); | ||
1580 | if (!state) | ||
1581 | return -ENOMEM; | ||
1582 | |||
1583 | mutex_init(&state->lock); | ||
1584 | sd = &state->sensor_sd; | ||
1585 | oif_sd = &state->oif_sd; | ||
1586 | |||
1587 | v4l2_subdev_init(sd, &s5c73m3_subdev_ops); | ||
1588 | sd->owner = client->driver->driver.owner; | ||
1589 | v4l2_set_subdevdata(sd, state); | ||
1590 | strlcpy(sd->name, "S5C73M3", sizeof(sd->name)); | ||
1591 | |||
1592 | sd->internal_ops = &s5c73m3_internal_ops; | ||
1593 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
1594 | |||
1595 | state->sensor_pads[S5C73M3_JPEG_PAD].flags = MEDIA_PAD_FL_SOURCE; | ||
1596 | state->sensor_pads[S5C73M3_ISP_PAD].flags = MEDIA_PAD_FL_SOURCE; | ||
1597 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; | ||
1598 | |||
1599 | ret = media_entity_init(&sd->entity, S5C73M3_NUM_PADS, | ||
1600 | state->sensor_pads, 0); | ||
1601 | if (ret < 0) | ||
1602 | return ret; | ||
1603 | |||
1604 | v4l2_i2c_subdev_init(oif_sd, client, &oif_subdev_ops); | ||
1605 | strcpy(oif_sd->name, "S5C73M3-OIF"); | ||
1606 | |||
1607 | oif_sd->internal_ops = &oif_internal_ops; | ||
1608 | oif_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
1609 | |||
1610 | state->oif_pads[OIF_ISP_PAD].flags = MEDIA_PAD_FL_SINK; | ||
1611 | state->oif_pads[OIF_JPEG_PAD].flags = MEDIA_PAD_FL_SINK; | ||
1612 | state->oif_pads[OIF_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE; | ||
1613 | oif_sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; | ||
1614 | |||
1615 | ret = media_entity_init(&oif_sd->entity, OIF_NUM_PADS, | ||
1616 | state->oif_pads, 0); | ||
1617 | if (ret < 0) | ||
1618 | return ret; | ||
1619 | |||
1620 | state->mclk_frequency = pdata->mclk_frequency; | ||
1621 | state->bus_type = pdata->bus_type; | ||
1622 | |||
1623 | ret = s5c73m3_configure_gpios(state, pdata); | ||
1624 | if (ret) | ||
1625 | goto out_err1; | ||
1626 | |||
1627 | for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++) | ||
1628 | state->supplies[i].supply = s5c73m3_supply_names[i]; | ||
1629 | |||
1630 | ret = devm_regulator_bulk_get(dev, S5C73M3_MAX_SUPPLIES, | ||
1631 | state->supplies); | ||
1632 | if (ret) { | ||
1633 | dev_err(dev, "failed to get regulators\n"); | ||
1634 | goto out_err2; | ||
1635 | } | ||
1636 | |||
1637 | ret = s5c73m3_init_controls(state); | ||
1638 | if (ret) | ||
1639 | goto out_err2; | ||
1640 | |||
1641 | state->sensor_pix_size[RES_ISP] = &s5c73m3_isp_resolutions[1]; | ||
1642 | state->sensor_pix_size[RES_JPEG] = &s5c73m3_jpeg_resolutions[1]; | ||
1643 | state->oif_pix_size[RES_ISP] = state->sensor_pix_size[RES_ISP]; | ||
1644 | state->oif_pix_size[RES_JPEG] = state->sensor_pix_size[RES_JPEG]; | ||
1645 | |||
1646 | state->mbus_code = S5C73M3_ISP_FMT; | ||
1647 | |||
1648 | state->fiv = &s5c73m3_intervals[S5C73M3_DEFAULT_FRAME_INTERVAL]; | ||
1649 | |||
1650 | state->fw_file_version[0] = 'G'; | ||
1651 | state->fw_file_version[1] = 'C'; | ||
1652 | |||
1653 | ret = s5c73m3_register_spi_driver(state); | ||
1654 | if (ret < 0) | ||
1655 | goto out_err2; | ||
1656 | |||
1657 | state->i2c_client = client; | ||
1658 | |||
1659 | v4l2_info(sd, "%s: completed succesfully\n", __func__); | ||
1660 | return 0; | ||
1661 | |||
1662 | out_err2: | ||
1663 | s5c73m3_free_gpios(state); | ||
1664 | out_err1: | ||
1665 | media_entity_cleanup(&sd->entity); | ||
1666 | return ret; | ||
1667 | } | ||
1668 | |||
1669 | static int s5c73m3_remove(struct i2c_client *client) | ||
1670 | { | ||
1671 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
1672 | struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); | ||
1673 | |||
1674 | v4l2_device_unregister_subdev(sd); | ||
1675 | |||
1676 | v4l2_ctrl_handler_free(sd->ctrl_handler); | ||
1677 | media_entity_cleanup(&sd->entity); | ||
1678 | |||
1679 | s5c73m3_unregister_spi_driver(state); | ||
1680 | s5c73m3_free_gpios(state); | ||
1681 | |||
1682 | return 0; | ||
1683 | } | ||
1684 | |||
1685 | static const struct i2c_device_id s5c73m3_id[] = { | ||
1686 | { DRIVER_NAME, 0 }, | ||
1687 | { } | ||
1688 | }; | ||
1689 | MODULE_DEVICE_TABLE(i2c, s5c73m3_id); | ||
1690 | |||
1691 | static struct i2c_driver s5c73m3_i2c_driver = { | ||
1692 | .driver = { | ||
1693 | .name = DRIVER_NAME, | ||
1694 | }, | ||
1695 | .probe = s5c73m3_probe, | ||
1696 | .remove = s5c73m3_remove, | ||
1697 | .id_table = s5c73m3_id, | ||
1698 | }; | ||
1699 | |||
1700 | module_i2c_driver(s5c73m3_i2c_driver); | ||
1701 | |||
1702 | MODULE_DESCRIPTION("Samsung S5C73M3 camera driver"); | ||
1703 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); | ||
1704 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c new file mode 100644 index 000000000000..8001cde1db1e --- /dev/null +++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c | |||
@@ -0,0 +1,563 @@ | |||
1 | /* | ||
2 | * Samsung LSI S5C73M3 8M pixel camera driver | ||
3 | * | ||
4 | * Copyright (C) 2012, Samsung Electronics, Co., Ltd. | ||
5 | * Sylwester Nawrocki <s.nawrocki@samsung.com> | ||
6 | * Andrzej Hajda <a.hajda@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/sizes.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/firmware.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/i2c.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/media.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/regulator/consumer.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/spi/spi.h> | ||
29 | #include <linux/videodev2.h> | ||
30 | #include <media/media-entity.h> | ||
31 | #include <media/v4l2-ctrls.h> | ||
32 | #include <media/v4l2-device.h> | ||
33 | #include <media/v4l2-subdev.h> | ||
34 | #include <media/v4l2-mediabus.h> | ||
35 | #include <media/s5c73m3.h> | ||
36 | |||
37 | #include "s5c73m3.h" | ||
38 | |||
39 | static int s5c73m3_get_af_status(struct s5c73m3 *state, struct v4l2_ctrl *ctrl) | ||
40 | { | ||
41 | u16 reg = REG_AF_STATUS_UNFOCUSED; | ||
42 | |||
43 | int ret = s5c73m3_read(state, REG_AF_STATUS, ®); | ||
44 | |||
45 | switch (reg) { | ||
46 | case REG_CAF_STATUS_FIND_SEARCH_DIR: | ||
47 | case REG_AF_STATUS_FOCUSING: | ||
48 | case REG_CAF_STATUS_FOCUSING: | ||
49 | ctrl->val = V4L2_AUTO_FOCUS_STATUS_BUSY; | ||
50 | break; | ||
51 | case REG_CAF_STATUS_FOCUSED: | ||
52 | case REG_AF_STATUS_FOCUSED: | ||
53 | ctrl->val = V4L2_AUTO_FOCUS_STATUS_REACHED; | ||
54 | break; | ||
55 | default: | ||
56 | v4l2_info(&state->sensor_sd, "Unknown AF status %#x\n", reg); | ||
57 | /* Fall through */ | ||
58 | case REG_CAF_STATUS_UNFOCUSED: | ||
59 | case REG_AF_STATUS_UNFOCUSED: | ||
60 | case REG_AF_STATUS_INVALID: | ||
61 | ctrl->val = V4L2_AUTO_FOCUS_STATUS_FAILED; | ||
62 | break; | ||
63 | } | ||
64 | |||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | static int s5c73m3_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
69 | { | ||
70 | struct v4l2_subdev *sd = ctrl_to_sensor_sd(ctrl); | ||
71 | struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); | ||
72 | int ret; | ||
73 | |||
74 | if (state->power == 0) | ||
75 | return -EBUSY; | ||
76 | |||
77 | switch (ctrl->id) { | ||
78 | case V4L2_CID_FOCUS_AUTO: | ||
79 | ret = s5c73m3_get_af_status(state, state->ctrls.af_status); | ||
80 | if (ret) | ||
81 | return ret; | ||
82 | break; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int s5c73m3_set_colorfx(struct s5c73m3 *state, int val) | ||
89 | { | ||
90 | static const unsigned short colorfx[][2] = { | ||
91 | { V4L2_COLORFX_NONE, COMM_IMAGE_EFFECT_NONE }, | ||
92 | { V4L2_COLORFX_BW, COMM_IMAGE_EFFECT_MONO }, | ||
93 | { V4L2_COLORFX_SEPIA, COMM_IMAGE_EFFECT_SEPIA }, | ||
94 | { V4L2_COLORFX_NEGATIVE, COMM_IMAGE_EFFECT_NEGATIVE }, | ||
95 | { V4L2_COLORFX_AQUA, COMM_IMAGE_EFFECT_AQUA }, | ||
96 | }; | ||
97 | int i; | ||
98 | |||
99 | for (i = 0; i < ARRAY_SIZE(colorfx); i++) { | ||
100 | if (colorfx[i][0] != val) | ||
101 | continue; | ||
102 | |||
103 | v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, | ||
104 | "Setting %s color effect\n", | ||
105 | v4l2_ctrl_get_menu(state->ctrls.colorfx->id)[i]); | ||
106 | |||
107 | return s5c73m3_isp_command(state, COMM_IMAGE_EFFECT, | ||
108 | colorfx[i][1]); | ||
109 | } | ||
110 | return -EINVAL; | ||
111 | } | ||
112 | |||
113 | /* Set exposure metering/exposure bias */ | ||
114 | static int s5c73m3_set_exposure(struct s5c73m3 *state, int auto_exp) | ||
115 | { | ||
116 | struct v4l2_subdev *sd = &state->sensor_sd; | ||
117 | struct s5c73m3_ctrls *ctrls = &state->ctrls; | ||
118 | int ret = 0; | ||
119 | |||
120 | if (ctrls->exposure_metering->is_new) { | ||
121 | u16 metering; | ||
122 | |||
123 | switch (ctrls->exposure_metering->val) { | ||
124 | case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: | ||
125 | metering = COMM_METERING_CENTER; | ||
126 | break; | ||
127 | case V4L2_EXPOSURE_METERING_SPOT: | ||
128 | metering = COMM_METERING_SPOT; | ||
129 | break; | ||
130 | default: | ||
131 | metering = COMM_METERING_AVERAGE; | ||
132 | break; | ||
133 | } | ||
134 | |||
135 | ret = s5c73m3_isp_command(state, COMM_METERING, metering); | ||
136 | } | ||
137 | |||
138 | if (!ret && ctrls->exposure_bias->is_new) { | ||
139 | u16 exp_bias = ctrls->exposure_bias->val; | ||
140 | ret = s5c73m3_isp_command(state, COMM_EV, exp_bias); | ||
141 | } | ||
142 | |||
143 | v4l2_dbg(1, s5c73m3_dbg, sd, | ||
144 | "%s: exposure bias: %#x, metering: %#x (%d)\n", __func__, | ||
145 | ctrls->exposure_bias->val, ctrls->exposure_metering->val, ret); | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static int s5c73m3_set_white_balance(struct s5c73m3 *state, int val) | ||
151 | { | ||
152 | static const unsigned short wb[][2] = { | ||
153 | { V4L2_WHITE_BALANCE_INCANDESCENT, COMM_AWB_MODE_INCANDESCENT}, | ||
154 | { V4L2_WHITE_BALANCE_FLUORESCENT, COMM_AWB_MODE_FLUORESCENT1}, | ||
155 | { V4L2_WHITE_BALANCE_FLUORESCENT_H, COMM_AWB_MODE_FLUORESCENT2}, | ||
156 | { V4L2_WHITE_BALANCE_CLOUDY, COMM_AWB_MODE_CLOUDY}, | ||
157 | { V4L2_WHITE_BALANCE_DAYLIGHT, COMM_AWB_MODE_DAYLIGHT}, | ||
158 | { V4L2_WHITE_BALANCE_AUTO, COMM_AWB_MODE_AUTO}, | ||
159 | }; | ||
160 | int i; | ||
161 | |||
162 | for (i = 0; i < ARRAY_SIZE(wb); i++) { | ||
163 | if (wb[i][0] != val) | ||
164 | continue; | ||
165 | |||
166 | v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, | ||
167 | "Setting white balance to: %s\n", | ||
168 | v4l2_ctrl_get_menu(state->ctrls.auto_wb->id)[i]); | ||
169 | |||
170 | return s5c73m3_isp_command(state, COMM_AWB_MODE, wb[i][1]); | ||
171 | } | ||
172 | |||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | static int s5c73m3_af_run(struct s5c73m3 *state, bool on) | ||
177 | { | ||
178 | struct s5c73m3_ctrls *c = &state->ctrls; | ||
179 | |||
180 | if (!on) | ||
181 | return s5c73m3_isp_command(state, COMM_AF_CON, | ||
182 | COMM_AF_CON_STOP); | ||
183 | |||
184 | if (c->focus_auto->val) | ||
185 | return s5c73m3_isp_command(state, COMM_AF_MODE, | ||
186 | COMM_AF_MODE_PREVIEW_CAF_START); | ||
187 | |||
188 | return s5c73m3_isp_command(state, COMM_AF_CON, COMM_AF_CON_START); | ||
189 | } | ||
190 | |||
191 | static int s5c73m3_3a_lock(struct s5c73m3 *state, struct v4l2_ctrl *ctrl) | ||
192 | { | ||
193 | bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE; | ||
194 | bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE; | ||
195 | bool af_lock = ctrl->val & V4L2_LOCK_FOCUS; | ||
196 | int ret = 0; | ||
197 | |||
198 | if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) { | ||
199 | ret = s5c73m3_isp_command(state, COMM_AE_CON, | ||
200 | ae_lock ? COMM_AE_STOP : COMM_AE_START); | ||
201 | if (ret) | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE) | ||
206 | && state->ctrls.auto_wb->val) { | ||
207 | ret = s5c73m3_isp_command(state, COMM_AWB_CON, | ||
208 | awb_lock ? COMM_AWB_STOP : COMM_AWB_START); | ||
209 | if (ret) | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS) | ||
214 | ret = s5c73m3_af_run(state, ~af_lock); | ||
215 | |||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | static int s5c73m3_set_auto_focus(struct s5c73m3 *state, int caf) | ||
220 | { | ||
221 | struct s5c73m3_ctrls *c = &state->ctrls; | ||
222 | int ret = 1; | ||
223 | |||
224 | if (c->af_distance->is_new) { | ||
225 | u16 mode = (c->af_distance->val == V4L2_AUTO_FOCUS_RANGE_MACRO) | ||
226 | ? COMM_AF_MODE_MACRO : COMM_AF_MODE_NORMAL; | ||
227 | ret = s5c73m3_isp_command(state, COMM_AF_MODE, mode); | ||
228 | if (ret != 0) | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | if (!ret || (c->focus_auto->is_new && c->focus_auto->val) || | ||
233 | c->af_start->is_new) | ||
234 | ret = s5c73m3_af_run(state, 1); | ||
235 | else if ((c->focus_auto->is_new && !c->focus_auto->val) || | ||
236 | c->af_stop->is_new) | ||
237 | ret = s5c73m3_af_run(state, 0); | ||
238 | else | ||
239 | ret = 0; | ||
240 | |||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | static int s5c73m3_set_contrast(struct s5c73m3 *state, int val) | ||
245 | { | ||
246 | u16 reg = (val < 0) ? -val + 2 : val; | ||
247 | return s5c73m3_isp_command(state, COMM_CONTRAST, reg); | ||
248 | } | ||
249 | |||
250 | static int s5c73m3_set_saturation(struct s5c73m3 *state, int val) | ||
251 | { | ||
252 | u16 reg = (val < 0) ? -val + 2 : val; | ||
253 | return s5c73m3_isp_command(state, COMM_SATURATION, reg); | ||
254 | } | ||
255 | |||
256 | static int s5c73m3_set_sharpness(struct s5c73m3 *state, int val) | ||
257 | { | ||
258 | u16 reg = (val < 0) ? -val + 2 : val; | ||
259 | return s5c73m3_isp_command(state, COMM_SHARPNESS, reg); | ||
260 | } | ||
261 | |||
262 | static int s5c73m3_set_iso(struct s5c73m3 *state, int val) | ||
263 | { | ||
264 | u32 iso; | ||
265 | |||
266 | if (val == V4L2_ISO_SENSITIVITY_MANUAL) | ||
267 | iso = state->ctrls.iso->val + 1; | ||
268 | else | ||
269 | iso = 0; | ||
270 | |||
271 | return s5c73m3_isp_command(state, COMM_ISO, iso); | ||
272 | } | ||
273 | |||
274 | static int s5c73m3_set_stabilization(struct s5c73m3 *state, int val) | ||
275 | { | ||
276 | struct v4l2_subdev *sd = &state->sensor_sd; | ||
277 | |||
278 | v4l2_dbg(1, s5c73m3_dbg, sd, "Image stabilization: %d\n", val); | ||
279 | |||
280 | return s5c73m3_isp_command(state, COMM_FRAME_RATE, val ? | ||
281 | COMM_FRAME_RATE_ANTI_SHAKE : COMM_FRAME_RATE_AUTO_SET); | ||
282 | } | ||
283 | |||
284 | static int s5c73m3_set_jpeg_quality(struct s5c73m3 *state, int quality) | ||
285 | { | ||
286 | int reg; | ||
287 | |||
288 | if (quality <= 65) | ||
289 | reg = COMM_IMAGE_QUALITY_NORMAL; | ||
290 | else if (quality <= 75) | ||
291 | reg = COMM_IMAGE_QUALITY_FINE; | ||
292 | else | ||
293 | reg = COMM_IMAGE_QUALITY_SUPERFINE; | ||
294 | |||
295 | return s5c73m3_isp_command(state, COMM_IMAGE_QUALITY, reg); | ||
296 | } | ||
297 | |||
298 | static int s5c73m3_set_scene_program(struct s5c73m3 *state, int val) | ||
299 | { | ||
300 | static const unsigned short scene_lookup[] = { | ||
301 | COMM_SCENE_MODE_NONE, /* V4L2_SCENE_MODE_NONE */ | ||
302 | COMM_SCENE_MODE_AGAINST_LIGHT,/* V4L2_SCENE_MODE_BACKLIGHT */ | ||
303 | COMM_SCENE_MODE_BEACH, /* V4L2_SCENE_MODE_BEACH_SNOW */ | ||
304 | COMM_SCENE_MODE_CANDLE, /* V4L2_SCENE_MODE_CANDLE_LIGHT */ | ||
305 | COMM_SCENE_MODE_DAWN, /* V4L2_SCENE_MODE_DAWN_DUSK */ | ||
306 | COMM_SCENE_MODE_FALL, /* V4L2_SCENE_MODE_FALL_COLORS */ | ||
307 | COMM_SCENE_MODE_FIRE, /* V4L2_SCENE_MODE_FIREWORKS */ | ||
308 | COMM_SCENE_MODE_LANDSCAPE, /* V4L2_SCENE_MODE_LANDSCAPE */ | ||
309 | COMM_SCENE_MODE_NIGHT, /* V4L2_SCENE_MODE_NIGHT */ | ||
310 | COMM_SCENE_MODE_INDOOR, /* V4L2_SCENE_MODE_PARTY_INDOOR */ | ||
311 | COMM_SCENE_MODE_PORTRAIT, /* V4L2_SCENE_MODE_PORTRAIT */ | ||
312 | COMM_SCENE_MODE_SPORTS, /* V4L2_SCENE_MODE_SPORTS */ | ||
313 | COMM_SCENE_MODE_SUNSET, /* V4L2_SCENE_MODE_SUNSET */ | ||
314 | COMM_SCENE_MODE_TEXT, /* V4L2_SCENE_MODE_TEXT */ | ||
315 | }; | ||
316 | |||
317 | v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, "Setting %s scene mode\n", | ||
318 | v4l2_ctrl_get_menu(state->ctrls.scene_mode->id)[val]); | ||
319 | |||
320 | return s5c73m3_isp_command(state, COMM_SCENE_MODE, scene_lookup[val]); | ||
321 | } | ||
322 | |||
323 | static int s5c73m3_set_power_line_freq(struct s5c73m3 *state, int val) | ||
324 | { | ||
325 | unsigned int pwr_line_freq = COMM_FLICKER_NONE; | ||
326 | |||
327 | switch (val) { | ||
328 | case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: | ||
329 | pwr_line_freq = COMM_FLICKER_NONE; | ||
330 | break; | ||
331 | case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: | ||
332 | pwr_line_freq = COMM_FLICKER_AUTO_50HZ; | ||
333 | break; | ||
334 | case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: | ||
335 | pwr_line_freq = COMM_FLICKER_AUTO_60HZ; | ||
336 | break; | ||
337 | default: | ||
338 | case V4L2_CID_POWER_LINE_FREQUENCY_AUTO: | ||
339 | pwr_line_freq = COMM_FLICKER_NONE; | ||
340 | } | ||
341 | |||
342 | return s5c73m3_isp_command(state, COMM_FLICKER_MODE, pwr_line_freq); | ||
343 | } | ||
344 | |||
345 | static int s5c73m3_s_ctrl(struct v4l2_ctrl *ctrl) | ||
346 | { | ||
347 | struct v4l2_subdev *sd = ctrl_to_sensor_sd(ctrl); | ||
348 | struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); | ||
349 | int ret = 0; | ||
350 | |||
351 | v4l2_dbg(1, s5c73m3_dbg, sd, "set_ctrl: %s, value: %d\n", | ||
352 | ctrl->name, ctrl->val); | ||
353 | |||
354 | mutex_lock(&state->lock); | ||
355 | /* | ||
356 | * If the device is not powered up by the host driver do | ||
357 | * not apply any controls to H/W at this time. Instead | ||
358 | * the controls will be restored right after power-up. | ||
359 | */ | ||
360 | if (state->power == 0) | ||
361 | goto unlock; | ||
362 | |||
363 | if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) { | ||
364 | ret = -EINVAL; | ||
365 | goto unlock; | ||
366 | } | ||
367 | |||
368 | switch (ctrl->id) { | ||
369 | case V4L2_CID_3A_LOCK: | ||
370 | ret = s5c73m3_3a_lock(state, ctrl); | ||
371 | break; | ||
372 | |||
373 | case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: | ||
374 | ret = s5c73m3_set_white_balance(state, ctrl->val); | ||
375 | break; | ||
376 | |||
377 | case V4L2_CID_CONTRAST: | ||
378 | ret = s5c73m3_set_contrast(state, ctrl->val); | ||
379 | break; | ||
380 | |||
381 | case V4L2_CID_COLORFX: | ||
382 | ret = s5c73m3_set_colorfx(state, ctrl->val); | ||
383 | break; | ||
384 | |||
385 | case V4L2_CID_EXPOSURE_AUTO: | ||
386 | ret = s5c73m3_set_exposure(state, ctrl->val); | ||
387 | break; | ||
388 | |||
389 | case V4L2_CID_FOCUS_AUTO: | ||
390 | ret = s5c73m3_set_auto_focus(state, ctrl->val); | ||
391 | break; | ||
392 | |||
393 | case V4L2_CID_IMAGE_STABILIZATION: | ||
394 | ret = s5c73m3_set_stabilization(state, ctrl->val); | ||
395 | break; | ||
396 | |||
397 | case V4L2_CID_ISO_SENSITIVITY: | ||
398 | ret = s5c73m3_set_iso(state, ctrl->val); | ||
399 | break; | ||
400 | |||
401 | case V4L2_CID_JPEG_COMPRESSION_QUALITY: | ||
402 | ret = s5c73m3_set_jpeg_quality(state, ctrl->val); | ||
403 | break; | ||
404 | |||
405 | case V4L2_CID_POWER_LINE_FREQUENCY: | ||
406 | ret = s5c73m3_set_power_line_freq(state, ctrl->val); | ||
407 | break; | ||
408 | |||
409 | case V4L2_CID_SATURATION: | ||
410 | ret = s5c73m3_set_saturation(state, ctrl->val); | ||
411 | break; | ||
412 | |||
413 | case V4L2_CID_SCENE_MODE: | ||
414 | ret = s5c73m3_set_scene_program(state, ctrl->val); | ||
415 | break; | ||
416 | |||
417 | case V4L2_CID_SHARPNESS: | ||
418 | ret = s5c73m3_set_sharpness(state, ctrl->val); | ||
419 | break; | ||
420 | |||
421 | case V4L2_CID_WIDE_DYNAMIC_RANGE: | ||
422 | ret = s5c73m3_isp_command(state, COMM_WDR, !!ctrl->val); | ||
423 | break; | ||
424 | |||
425 | case V4L2_CID_ZOOM_ABSOLUTE: | ||
426 | ret = s5c73m3_isp_command(state, COMM_ZOOM_STEP, ctrl->val); | ||
427 | break; | ||
428 | } | ||
429 | unlock: | ||
430 | mutex_unlock(&state->lock); | ||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | static const struct v4l2_ctrl_ops s5c73m3_ctrl_ops = { | ||
435 | .g_volatile_ctrl = s5c73m3_g_volatile_ctrl, | ||
436 | .s_ctrl = s5c73m3_s_ctrl, | ||
437 | }; | ||
438 | |||
439 | /* Supported manual ISO values */ | ||
440 | static const s64 iso_qmenu[] = { | ||
441 | /* COMM_ISO: 0x0001...0x0004 */ | ||
442 | 100, 200, 400, 800, | ||
443 | }; | ||
444 | |||
445 | /* Supported exposure bias values (-2.0EV...+2.0EV) */ | ||
446 | static const s64 ev_bias_qmenu[] = { | ||
447 | /* COMM_EV: 0x0000...0x0008 */ | ||
448 | -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000 | ||
449 | }; | ||
450 | |||
451 | int s5c73m3_init_controls(struct s5c73m3 *state) | ||
452 | { | ||
453 | const struct v4l2_ctrl_ops *ops = &s5c73m3_ctrl_ops; | ||
454 | struct s5c73m3_ctrls *ctrls = &state->ctrls; | ||
455 | struct v4l2_ctrl_handler *hdl = &ctrls->handler; | ||
456 | |||
457 | int ret = v4l2_ctrl_handler_init(hdl, 22); | ||
458 | if (ret) | ||
459 | return ret; | ||
460 | |||
461 | /* White balance */ | ||
462 | ctrls->auto_wb = v4l2_ctrl_new_std_menu(hdl, ops, | ||
463 | V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, | ||
464 | 9, ~0x15e, V4L2_WHITE_BALANCE_AUTO); | ||
465 | |||
466 | /* Exposure (only automatic exposure) */ | ||
467 | ctrls->auto_exposure = v4l2_ctrl_new_std_menu(hdl, ops, | ||
468 | V4L2_CID_EXPOSURE_AUTO, 0, ~0x01, V4L2_EXPOSURE_AUTO); | ||
469 | |||
470 | ctrls->exposure_bias = v4l2_ctrl_new_int_menu(hdl, ops, | ||
471 | V4L2_CID_AUTO_EXPOSURE_BIAS, | ||
472 | ARRAY_SIZE(ev_bias_qmenu) - 1, | ||
473 | ARRAY_SIZE(ev_bias_qmenu)/2 - 1, | ||
474 | ev_bias_qmenu); | ||
475 | |||
476 | ctrls->exposure_metering = v4l2_ctrl_new_std_menu(hdl, ops, | ||
477 | V4L2_CID_EXPOSURE_METERING, | ||
478 | 2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE); | ||
479 | |||
480 | /* Auto focus */ | ||
481 | ctrls->focus_auto = v4l2_ctrl_new_std(hdl, ops, | ||
482 | V4L2_CID_FOCUS_AUTO, 0, 1, 1, 0); | ||
483 | |||
484 | ctrls->af_start = v4l2_ctrl_new_std(hdl, ops, | ||
485 | V4L2_CID_AUTO_FOCUS_START, 0, 1, 1, 0); | ||
486 | |||
487 | ctrls->af_stop = v4l2_ctrl_new_std(hdl, ops, | ||
488 | V4L2_CID_AUTO_FOCUS_STOP, 0, 1, 1, 0); | ||
489 | |||
490 | ctrls->af_status = v4l2_ctrl_new_std(hdl, ops, | ||
491 | V4L2_CID_AUTO_FOCUS_STATUS, 0, | ||
492 | (V4L2_AUTO_FOCUS_STATUS_BUSY | | ||
493 | V4L2_AUTO_FOCUS_STATUS_REACHED | | ||
494 | V4L2_AUTO_FOCUS_STATUS_FAILED), | ||
495 | 0, V4L2_AUTO_FOCUS_STATUS_IDLE); | ||
496 | |||
497 | ctrls->af_distance = v4l2_ctrl_new_std_menu(hdl, ops, | ||
498 | V4L2_CID_AUTO_FOCUS_RANGE, | ||
499 | V4L2_AUTO_FOCUS_RANGE_MACRO, | ||
500 | ~(1 << V4L2_AUTO_FOCUS_RANGE_NORMAL | | ||
501 | 1 << V4L2_AUTO_FOCUS_RANGE_MACRO), | ||
502 | V4L2_AUTO_FOCUS_RANGE_NORMAL); | ||
503 | /* ISO sensitivity */ | ||
504 | ctrls->auto_iso = v4l2_ctrl_new_std_menu(hdl, ops, | ||
505 | V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0, | ||
506 | V4L2_ISO_SENSITIVITY_AUTO); | ||
507 | |||
508 | ctrls->iso = v4l2_ctrl_new_int_menu(hdl, ops, | ||
509 | V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1, | ||
510 | ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu); | ||
511 | |||
512 | ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, | ||
513 | V4L2_CID_CONTRAST, -2, 2, 1, 0); | ||
514 | |||
515 | ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, | ||
516 | V4L2_CID_SATURATION, -2, 2, 1, 0); | ||
517 | |||
518 | ctrls->sharpness = v4l2_ctrl_new_std(hdl, ops, | ||
519 | V4L2_CID_SHARPNESS, -2, 2, 1, 0); | ||
520 | |||
521 | ctrls->zoom = v4l2_ctrl_new_std(hdl, ops, | ||
522 | V4L2_CID_ZOOM_ABSOLUTE, 0, 30, 1, 0); | ||
523 | |||
524 | ctrls->colorfx = v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX, | ||
525 | V4L2_COLORFX_AQUA, ~0x40f, V4L2_COLORFX_NONE); | ||
526 | |||
527 | ctrls->wdr = v4l2_ctrl_new_std(hdl, ops, | ||
528 | V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0); | ||
529 | |||
530 | ctrls->stabilization = v4l2_ctrl_new_std(hdl, ops, | ||
531 | V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0); | ||
532 | |||
533 | v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY, | ||
534 | V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, | ||
535 | V4L2_CID_POWER_LINE_FREQUENCY_AUTO); | ||
536 | |||
537 | ctrls->jpeg_quality = v4l2_ctrl_new_std(hdl, ops, | ||
538 | V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80); | ||
539 | |||
540 | ctrls->scene_mode = v4l2_ctrl_new_std_menu(hdl, ops, | ||
541 | V4L2_CID_SCENE_MODE, V4L2_SCENE_MODE_TEXT, ~0x3fff, | ||
542 | V4L2_SCENE_MODE_NONE); | ||
543 | |||
544 | ctrls->aaa_lock = v4l2_ctrl_new_std(hdl, ops, | ||
545 | V4L2_CID_3A_LOCK, 0, 0x7, 0, 0); | ||
546 | |||
547 | if (hdl->error) { | ||
548 | ret = hdl->error; | ||
549 | v4l2_ctrl_handler_free(hdl); | ||
550 | return ret; | ||
551 | } | ||
552 | |||
553 | v4l2_ctrl_auto_cluster(3, &ctrls->auto_exposure, 0, false); | ||
554 | ctrls->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE | | ||
555 | V4L2_CTRL_FLAG_UPDATE; | ||
556 | v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso, 0, false); | ||
557 | ctrls->af_status->flags |= V4L2_CTRL_FLAG_VOLATILE; | ||
558 | v4l2_ctrl_cluster(6, &ctrls->focus_auto); | ||
559 | |||
560 | state->sensor_sd.ctrl_handler = hdl; | ||
561 | |||
562 | return 0; | ||
563 | } | ||
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c new file mode 100644 index 000000000000..6f3a9c00fe65 --- /dev/null +++ b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * Samsung LSI S5C73M3 8M pixel camera driver | ||
3 | * | ||
4 | * Copyright (C) 2012, Samsung Electronics, Co., Ltd. | ||
5 | * Sylwester Nawrocki <s.nawrocki@samsung.com> | ||
6 | * Andrzej Hajda <a.hajda@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/sizes.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/media.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/spi/spi.h> | ||
25 | |||
26 | #include "s5c73m3.h" | ||
27 | |||
28 | #define S5C73M3_SPI_DRV_NAME "S5C73M3-SPI" | ||
29 | |||
30 | enum spi_direction { | ||
31 | SPI_DIR_RX, | ||
32 | SPI_DIR_TX | ||
33 | }; | ||
34 | |||
35 | static int spi_xmit(struct spi_device *spi_dev, void *addr, const int len, | ||
36 | enum spi_direction dir) | ||
37 | { | ||
38 | struct spi_message msg; | ||
39 | int r; | ||
40 | struct spi_transfer xfer = { | ||
41 | .len = len, | ||
42 | }; | ||
43 | |||
44 | if (dir == SPI_DIR_TX) | ||
45 | xfer.tx_buf = addr; | ||
46 | else | ||
47 | xfer.rx_buf = addr; | ||
48 | |||
49 | if (spi_dev == NULL) { | ||
50 | dev_err(&spi_dev->dev, "SPI device is uninitialized\n"); | ||
51 | return -ENODEV; | ||
52 | } | ||
53 | |||
54 | spi_message_init(&msg); | ||
55 | spi_message_add_tail(&xfer, &msg); | ||
56 | |||
57 | r = spi_sync(spi_dev, &msg); | ||
58 | if (r < 0) | ||
59 | dev_err(&spi_dev->dev, "%s spi_sync failed %d\n", __func__, r); | ||
60 | |||
61 | return r; | ||
62 | } | ||
63 | |||
64 | int s5c73m3_spi_write(struct s5c73m3 *state, const void *addr, | ||
65 | const unsigned int len, const unsigned int tx_size) | ||
66 | { | ||
67 | struct spi_device *spi_dev = state->spi_dev; | ||
68 | u32 count = len / tx_size; | ||
69 | u32 extra = len % tx_size; | ||
70 | unsigned int i, j = 0; | ||
71 | u8 padding[32]; | ||
72 | int r = 0; | ||
73 | |||
74 | memset(padding, 0, sizeof(padding)); | ||
75 | |||
76 | for (i = 0; i < count ; i++) { | ||
77 | r = spi_xmit(spi_dev, (void *)addr + j, tx_size, SPI_DIR_TX); | ||
78 | if (r < 0) | ||
79 | return r; | ||
80 | j += tx_size; | ||
81 | } | ||
82 | |||
83 | if (extra > 0) { | ||
84 | r = spi_xmit(spi_dev, (void *)addr + j, extra, SPI_DIR_TX); | ||
85 | if (r < 0) | ||
86 | return r; | ||
87 | } | ||
88 | |||
89 | return spi_xmit(spi_dev, padding, sizeof(padding), SPI_DIR_TX); | ||
90 | } | ||
91 | |||
92 | int s5c73m3_spi_read(struct s5c73m3 *state, void *addr, | ||
93 | const unsigned int len, const unsigned int tx_size) | ||
94 | { | ||
95 | struct spi_device *spi_dev = state->spi_dev; | ||
96 | u32 count = len / tx_size; | ||
97 | u32 extra = len % tx_size; | ||
98 | unsigned int i, j = 0; | ||
99 | int r = 0; | ||
100 | |||
101 | for (i = 0; i < count ; i++) { | ||
102 | r = spi_xmit(spi_dev, addr + j, tx_size, SPI_DIR_RX); | ||
103 | if (r < 0) | ||
104 | return r; | ||
105 | j += tx_size; | ||
106 | } | ||
107 | |||
108 | if (extra > 0) | ||
109 | return spi_xmit(spi_dev, addr + j, extra, SPI_DIR_RX); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static int s5c73m3_spi_probe(struct spi_device *spi) | ||
115 | { | ||
116 | int r; | ||
117 | struct s5c73m3 *state = container_of(spi->dev.driver, struct s5c73m3, | ||
118 | spidrv.driver); | ||
119 | spi->bits_per_word = 32; | ||
120 | |||
121 | r = spi_setup(spi); | ||
122 | if (r < 0) { | ||
123 | dev_err(&spi->dev, "spi_setup() failed\n"); | ||
124 | return r; | ||
125 | } | ||
126 | |||
127 | mutex_lock(&state->lock); | ||
128 | state->spi_dev = spi; | ||
129 | mutex_unlock(&state->lock); | ||
130 | |||
131 | v4l2_info(&state->sensor_sd, "S5C73M3 SPI probed successfully\n"); | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int s5c73m3_spi_remove(struct spi_device *spi) | ||
136 | { | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | int s5c73m3_register_spi_driver(struct s5c73m3 *state) | ||
141 | { | ||
142 | struct spi_driver *spidrv = &state->spidrv; | ||
143 | |||
144 | spidrv->remove = s5c73m3_spi_remove; | ||
145 | spidrv->probe = s5c73m3_spi_probe; | ||
146 | spidrv->driver.name = S5C73M3_SPI_DRV_NAME; | ||
147 | spidrv->driver.bus = &spi_bus_type; | ||
148 | spidrv->driver.owner = THIS_MODULE; | ||
149 | |||
150 | return spi_register_driver(spidrv); | ||
151 | } | ||
152 | |||
153 | void s5c73m3_unregister_spi_driver(struct s5c73m3 *state) | ||
154 | { | ||
155 | spi_unregister_driver(&state->spidrv); | ||
156 | } | ||
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h new file mode 100644 index 000000000000..9d2c08652246 --- /dev/null +++ b/drivers/media/i2c/s5c73m3/s5c73m3.h | |||
@@ -0,0 +1,459 @@ | |||
1 | /* | ||
2 | * Samsung LSI S5C73M3 8M pixel camera driver | ||
3 | * | ||
4 | * Copyright (C) 2012, Samsung Electronics, Co., Ltd. | ||
5 | * Sylwester Nawrocki <s.nawrocki@samsung.com> | ||
6 | * Andrzej Hajda <a.hajda@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | #ifndef S5C73M3_H_ | ||
18 | #define S5C73M3_H_ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <media/v4l2-common.h> | ||
23 | #include <media/v4l2-ctrls.h> | ||
24 | #include <media/v4l2-subdev.h> | ||
25 | #include <media/s5c73m3.h> | ||
26 | |||
27 | #define DRIVER_NAME "S5C73M3" | ||
28 | |||
29 | #define S5C73M3_ISP_FMT V4L2_MBUS_FMT_VYUY8_2X8 | ||
30 | #define S5C73M3_JPEG_FMT V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8 | ||
31 | |||
32 | /* Subdevs pad index definitions */ | ||
33 | enum s5c73m3_pads { | ||
34 | S5C73M3_ISP_PAD, | ||
35 | S5C73M3_JPEG_PAD, | ||
36 | S5C73M3_NUM_PADS | ||
37 | }; | ||
38 | |||
39 | enum s5c73m3_oif_pads { | ||
40 | OIF_ISP_PAD, | ||
41 | OIF_JPEG_PAD, | ||
42 | OIF_SOURCE_PAD, | ||
43 | OIF_NUM_PADS | ||
44 | }; | ||
45 | |||
46 | #define S5C73M3_SENSOR_FW_LEN 6 | ||
47 | #define S5C73M3_SENSOR_TYPE_LEN 12 | ||
48 | |||
49 | #define S5C73M3_REG(_addrh, _addrl) (((_addrh) << 16) | _addrl) | ||
50 | |||
51 | #define AHB_MSB_ADDR_PTR 0xfcfc | ||
52 | #define REG_CMDWR_ADDRH 0x0050 | ||
53 | #define REG_CMDWR_ADDRL 0x0054 | ||
54 | #define REG_CMDRD_ADDRH 0x0058 | ||
55 | #define REG_CMDRD_ADDRL 0x005c | ||
56 | #define REG_CMDBUF_ADDR 0x0f14 | ||
57 | |||
58 | #define REG_I2C_SEQ_STATUS S5C73M3_REG(0x0009, 0x59A6) | ||
59 | #define SEQ_END_PLL (1<<0x0) | ||
60 | #define SEQ_END_SENSOR (1<<0x1) | ||
61 | #define SEQ_END_GPIO (1<<0x2) | ||
62 | #define SEQ_END_FROM (1<<0x3) | ||
63 | #define SEQ_END_STABLE_AE_AWB (1<<0x4) | ||
64 | #define SEQ_END_READY_I2C_CMD (1<<0x5) | ||
65 | |||
66 | #define REG_I2C_STATUS S5C73M3_REG(0x0009, 0x599E) | ||
67 | #define I2C_STATUS_CIS_I2C (1<<0x0) | ||
68 | #define I2C_STATUS_AF_INIT (1<<0x1) | ||
69 | #define I2C_STATUS_CAL_DATA (1<<0x2) | ||
70 | #define I2C_STATUS_FRAME_COUNT (1<<0x3) | ||
71 | #define I2C_STATUS_FROM_INIT (1<<0x4) | ||
72 | #define I2C_STATUS_I2C_CIS_STREAM_OFF (1<<0x5) | ||
73 | #define I2C_STATUS_I2C_N_CMD_OVER (1<<0x6) | ||
74 | #define I2C_STATUS_I2C_N_CMD_MISMATCH (1<<0x7) | ||
75 | #define I2C_STATUS_CHECK_BIN_CRC (1<<0x8) | ||
76 | #define I2C_STATUS_EXCEPTION (1<<0x9) | ||
77 | #define I2C_STATUS_INIF_INIT_STATE (0x8) | ||
78 | |||
79 | #define REG_STATUS S5C73M3_REG(0x0009, 0x5080) | ||
80 | #define REG_STATUS_BOOT_SUB_MAIN_ENTER 0xff01 | ||
81 | #define REG_STATUS_BOOT_SRAM_TIMING_OK 0xff02 | ||
82 | #define REG_STATUS_BOOT_INTERRUPTS_EN 0xff03 | ||
83 | #define REG_STATUS_BOOT_R_PLL_DONE 0xff04 | ||
84 | #define REG_STATUS_BOOT_R_PLL_LOCKTIME_DONE 0xff05 | ||
85 | #define REG_STATUS_BOOT_DELAY_COUNT_DONE 0xff06 | ||
86 | #define REG_STATUS_BOOT_I_PLL_DONE 0xff07 | ||
87 | #define REG_STATUS_BOOT_I_PLL_LOCKTIME_DONE 0xff08 | ||
88 | #define REG_STATUS_BOOT_PLL_INIT_OK 0xff09 | ||
89 | #define REG_STATUS_BOOT_SENSOR_INIT_OK 0xff0a | ||
90 | #define REG_STATUS_BOOT_GPIO_SETTING_OK 0xff0b | ||
91 | #define REG_STATUS_BOOT_READ_CAL_DATA_OK 0xff0c | ||
92 | #define REG_STATUS_BOOT_STABLE_AE_AWB_OK 0xff0d | ||
93 | #define REG_STATUS_ISP_COMMAND_COMPLETED 0xffff | ||
94 | #define REG_STATUS_EXCEPTION_OCCURED 0xdead | ||
95 | |||
96 | #define COMM_RESULT_OFFSET S5C73M3_REG(0x0009, 0x5000) | ||
97 | |||
98 | #define COMM_IMG_OUTPUT 0x0902 | ||
99 | #define COMM_IMG_OUTPUT_HDR 0x0008 | ||
100 | #define COMM_IMG_OUTPUT_YUV 0x0009 | ||
101 | #define COMM_IMG_OUTPUT_INTERLEAVED 0x000d | ||
102 | |||
103 | #define COMM_STILL_PRE_FLASH 0x0a00 | ||
104 | #define COMM_STILL_PRE_FLASH_FIRE 0x0000 | ||
105 | #define COMM_STILL_PRE_FLASH_NON_FIRED 0x0000 | ||
106 | #define COMM_STILL_PRE_FLASH_FIRED 0x0001 | ||
107 | |||
108 | #define COMM_STILL_MAIN_FLASH 0x0a02 | ||
109 | #define COMM_STILL_MAIN_FLASH_CANCEL 0x0001 | ||
110 | #define COMM_STILL_MAIN_FLASH_FIRE 0x0002 | ||
111 | |||
112 | #define COMM_ZOOM_STEP 0x0b00 | ||
113 | |||
114 | #define COMM_IMAGE_EFFECT 0x0b0a | ||
115 | #define COMM_IMAGE_EFFECT_NONE 0x0001 | ||
116 | #define COMM_IMAGE_EFFECT_NEGATIVE 0x0002 | ||
117 | #define COMM_IMAGE_EFFECT_AQUA 0x0003 | ||
118 | #define COMM_IMAGE_EFFECT_SEPIA 0x0004 | ||
119 | #define COMM_IMAGE_EFFECT_MONO 0x0005 | ||
120 | |||
121 | #define COMM_IMAGE_QUALITY 0x0b0c | ||
122 | #define COMM_IMAGE_QUALITY_SUPERFINE 0x0000 | ||
123 | #define COMM_IMAGE_QUALITY_FINE 0x0001 | ||
124 | #define COMM_IMAGE_QUALITY_NORMAL 0x0002 | ||
125 | |||
126 | #define COMM_FLASH_MODE 0x0b0e | ||
127 | #define COMM_FLASH_MODE_OFF 0x0000 | ||
128 | #define COMM_FLASH_MODE_ON 0x0001 | ||
129 | #define COMM_FLASH_MODE_AUTO 0x0002 | ||
130 | |||
131 | #define COMM_FLASH_STATUS 0x0b80 | ||
132 | #define COMM_FLASH_STATUS_OFF 0x0001 | ||
133 | #define COMM_FLASH_STATUS_ON 0x0002 | ||
134 | #define COMM_FLASH_STATUS_AUTO 0x0003 | ||
135 | |||
136 | #define COMM_FLASH_TORCH 0x0b12 | ||
137 | #define COMM_FLASH_TORCH_OFF 0x0000 | ||
138 | #define COMM_FLASH_TORCH_ON 0x0001 | ||
139 | |||
140 | #define COMM_AE_NEEDS_FLASH 0x0cba | ||
141 | #define COMM_AE_NEEDS_FLASH_OFF 0x0000 | ||
142 | #define COMM_AE_NEEDS_FLASH_ON 0x0001 | ||
143 | |||
144 | #define COMM_CHG_MODE 0x0b10 | ||
145 | #define COMM_CHG_MODE_NEW 0x8000 | ||
146 | #define COMM_CHG_MODE_SUBSAMPLING_HALF 0x2000 | ||
147 | #define COMM_CHG_MODE_SUBSAMPLING_QUARTER 0x4000 | ||
148 | |||
149 | #define COMM_CHG_MODE_YUV_320_240 0x0001 | ||
150 | #define COMM_CHG_MODE_YUV_640_480 0x0002 | ||
151 | #define COMM_CHG_MODE_YUV_880_720 0x0003 | ||
152 | #define COMM_CHG_MODE_YUV_960_720 0x0004 | ||
153 | #define COMM_CHG_MODE_YUV_1184_666 0x0005 | ||
154 | #define COMM_CHG_MODE_YUV_1280_720 0x0006 | ||
155 | #define COMM_CHG_MODE_YUV_1536_864 0x0007 | ||
156 | #define COMM_CHG_MODE_YUV_1600_1200 0x0008 | ||
157 | #define COMM_CHG_MODE_YUV_1632_1224 0x0009 | ||
158 | #define COMM_CHG_MODE_YUV_1920_1080 0x000a | ||
159 | #define COMM_CHG_MODE_YUV_1920_1440 0x000b | ||
160 | #define COMM_CHG_MODE_YUV_2304_1296 0x000c | ||
161 | #define COMM_CHG_MODE_YUV_3264_2448 0x000d | ||
162 | #define COMM_CHG_MODE_YUV_352_288 0x000e | ||
163 | #define COMM_CHG_MODE_YUV_1008_672 0x000f | ||
164 | |||
165 | #define COMM_CHG_MODE_JPEG_640_480 0x0010 | ||
166 | #define COMM_CHG_MODE_JPEG_800_450 0x0020 | ||
167 | #define COMM_CHG_MODE_JPEG_800_600 0x0030 | ||
168 | #define COMM_CHG_MODE_JPEG_1280_720 0x0040 | ||
169 | #define COMM_CHG_MODE_JPEG_1280_960 0x0050 | ||
170 | #define COMM_CHG_MODE_JPEG_1600_900 0x0060 | ||
171 | #define COMM_CHG_MODE_JPEG_1600_1200 0x0070 | ||
172 | #define COMM_CHG_MODE_JPEG_2048_1152 0x0080 | ||
173 | #define COMM_CHG_MODE_JPEG_2048_1536 0x0090 | ||
174 | #define COMM_CHG_MODE_JPEG_2560_1440 0x00a0 | ||
175 | #define COMM_CHG_MODE_JPEG_2560_1920 0x00b0 | ||
176 | #define COMM_CHG_MODE_JPEG_3264_2176 0x00c0 | ||
177 | #define COMM_CHG_MODE_JPEG_1024_768 0x00d0 | ||
178 | #define COMM_CHG_MODE_JPEG_3264_1836 0x00e0 | ||
179 | #define COMM_CHG_MODE_JPEG_3264_2448 0x00f0 | ||
180 | |||
181 | #define COMM_AF_CON 0x0e00 | ||
182 | #define COMM_AF_CON_STOP 0x0000 | ||
183 | #define COMM_AF_CON_SCAN 0x0001 /* Full Search */ | ||
184 | #define COMM_AF_CON_START 0x0002 /* Fast Search */ | ||
185 | |||
186 | #define COMM_AF_CAL 0x0e06 | ||
187 | #define COMM_AF_TOUCH_AF 0x0e0a | ||
188 | |||
189 | #define REG_AF_STATUS S5C73M3_REG(0x0009, 0x5e80) | ||
190 | #define REG_CAF_STATUS_FIND_SEARCH_DIR 0x0001 | ||
191 | #define REG_CAF_STATUS_FOCUSING 0x0002 | ||
192 | #define REG_CAF_STATUS_FOCUSED 0x0003 | ||
193 | #define REG_CAF_STATUS_UNFOCUSED 0x0004 | ||
194 | #define REG_AF_STATUS_INVALID 0x0010 | ||
195 | #define REG_AF_STATUS_FOCUSING 0x0020 | ||
196 | #define REG_AF_STATUS_FOCUSED 0x0030 | ||
197 | #define REG_AF_STATUS_UNFOCUSED 0x0040 | ||
198 | |||
199 | #define REG_AF_TOUCH_POSITION S5C73M3_REG(0x0009, 0x5e8e) | ||
200 | #define COMM_AF_FACE_ZOOM 0x0e10 | ||
201 | |||
202 | #define COMM_AF_MODE 0x0e02 | ||
203 | #define COMM_AF_MODE_NORMAL 0x0000 | ||
204 | #define COMM_AF_MODE_MACRO 0x0001 | ||
205 | #define COMM_AF_MODE_MOVIE_CAF_START 0x0002 | ||
206 | #define COMM_AF_MODE_MOVIE_CAF_STOP 0x0003 | ||
207 | #define COMM_AF_MODE_PREVIEW_CAF_START 0x0004 | ||
208 | #define COMM_AF_MODE_PREVIEW_CAF_STOP 0x0005 | ||
209 | |||
210 | #define COMM_AF_SOFTLANDING 0x0e16 | ||
211 | #define COMM_AF_SOFTLANDING_ON 0x0000 | ||
212 | #define COMM_AF_SOFTLANDING_RES_COMPLETE 0x0001 | ||
213 | |||
214 | #define COMM_FACE_DET 0x0e0c | ||
215 | #define COMM_FACE_DET_OFF 0x0000 | ||
216 | #define COMM_FACE_DET_ON 0x0001 | ||
217 | |||
218 | #define COMM_FACE_DET_OSD 0x0e0e | ||
219 | #define COMM_FACE_DET_OSD_OFF 0x0000 | ||
220 | #define COMM_FACE_DET_OSD_ON 0x0001 | ||
221 | |||
222 | #define COMM_AE_CON 0x0c00 | ||
223 | #define COMM_AE_STOP 0x0000 /* lock */ | ||
224 | #define COMM_AE_START 0x0001 /* unlock */ | ||
225 | |||
226 | #define COMM_ISO 0x0c02 | ||
227 | #define COMM_ISO_AUTO 0x0000 | ||
228 | #define COMM_ISO_100 0x0001 | ||
229 | #define COMM_ISO_200 0x0002 | ||
230 | #define COMM_ISO_400 0x0003 | ||
231 | #define COMM_ISO_800 0x0004 | ||
232 | #define COMM_ISO_SPORTS 0x0005 | ||
233 | #define COMM_ISO_NIGHT 0x0006 | ||
234 | #define COMM_ISO_INDOOR 0x0007 | ||
235 | |||
236 | /* 0x00000 (-2.0 EV)...0x0008 (2.0 EV), 0.5EV step */ | ||
237 | #define COMM_EV 0x0c04 | ||
238 | |||
239 | #define COMM_METERING 0x0c06 | ||
240 | #define COMM_METERING_CENTER 0x0000 | ||
241 | #define COMM_METERING_SPOT 0x0001 | ||
242 | #define COMM_METERING_AVERAGE 0x0002 | ||
243 | #define COMM_METERING_SMART 0x0003 | ||
244 | |||
245 | #define COMM_WDR 0x0c08 | ||
246 | #define COMM_WDR_OFF 0x0000 | ||
247 | #define COMM_WDR_ON 0x0001 | ||
248 | |||
249 | #define COMM_FLICKER_MODE 0x0c12 | ||
250 | #define COMM_FLICKER_NONE 0x0000 | ||
251 | #define COMM_FLICKER_MANUAL_50HZ 0x0001 | ||
252 | #define COMM_FLICKER_MANUAL_60HZ 0x0002 | ||
253 | #define COMM_FLICKER_AUTO 0x0003 | ||
254 | #define COMM_FLICKER_AUTO_50HZ 0x0004 | ||
255 | #define COMM_FLICKER_AUTO_60HZ 0x0005 | ||
256 | |||
257 | #define COMM_FRAME_RATE 0x0c1e | ||
258 | #define COMM_FRAME_RATE_AUTO_SET 0x0000 | ||
259 | #define COMM_FRAME_RATE_FIXED_30FPS 0x0002 | ||
260 | #define COMM_FRAME_RATE_FIXED_20FPS 0x0003 | ||
261 | #define COMM_FRAME_RATE_FIXED_15FPS 0x0004 | ||
262 | #define COMM_FRAME_RATE_FIXED_60FPS 0x0007 | ||
263 | #define COMM_FRAME_RATE_FIXED_120FPS 0x0008 | ||
264 | #define COMM_FRAME_RATE_FIXED_7FPS 0x0009 | ||
265 | #define COMM_FRAME_RATE_FIXED_10FPS 0x000a | ||
266 | #define COMM_FRAME_RATE_FIXED_90FPS 0x000b | ||
267 | #define COMM_FRAME_RATE_ANTI_SHAKE 0x0013 | ||
268 | |||
269 | /* 0x0000...0x0004 -> sharpness: 0, 1, 2, -1, -2 */ | ||
270 | #define COMM_SHARPNESS 0x0c14 | ||
271 | |||
272 | /* 0x0000...0x0004 -> saturation: 0, 1, 2, -1, -2 */ | ||
273 | #define COMM_SATURATION 0x0c16 | ||
274 | |||
275 | /* 0x0000...0x0004 -> contrast: 0, 1, 2, -1, -2 */ | ||
276 | #define COMM_CONTRAST 0x0c18 | ||
277 | |||
278 | #define COMM_SCENE_MODE 0x0c1a | ||
279 | #define COMM_SCENE_MODE_NONE 0x0000 | ||
280 | #define COMM_SCENE_MODE_PORTRAIT 0x0001 | ||
281 | #define COMM_SCENE_MODE_LANDSCAPE 0x0002 | ||
282 | #define COMM_SCENE_MODE_SPORTS 0x0003 | ||
283 | #define COMM_SCENE_MODE_INDOOR 0x0004 | ||
284 | #define COMM_SCENE_MODE_BEACH 0x0005 | ||
285 | #define COMM_SCENE_MODE_SUNSET 0x0006 | ||
286 | #define COMM_SCENE_MODE_DAWN 0x0007 | ||
287 | #define COMM_SCENE_MODE_FALL 0x0008 | ||
288 | #define COMM_SCENE_MODE_NIGHT 0x0009 | ||
289 | #define COMM_SCENE_MODE_AGAINST_LIGHT 0x000a | ||
290 | #define COMM_SCENE_MODE_FIRE 0x000b | ||
291 | #define COMM_SCENE_MODE_TEXT 0x000c | ||
292 | #define COMM_SCENE_MODE_CANDLE 0x000d | ||
293 | |||
294 | #define COMM_AE_AUTO_BRACKET 0x0b14 | ||
295 | #define COMM_AE_AUTO_BRAKET_EV05 0x0080 | ||
296 | #define COMM_AE_AUTO_BRAKET_EV10 0x0100 | ||
297 | #define COMM_AE_AUTO_BRAKET_EV15 0x0180 | ||
298 | #define COMM_AE_AUTO_BRAKET_EV20 0x0200 | ||
299 | |||
300 | #define COMM_SENSOR_STREAMING 0x090a | ||
301 | #define COMM_SENSOR_STREAMING_OFF 0x0000 | ||
302 | #define COMM_SENSOR_STREAMING_ON 0x0001 | ||
303 | |||
304 | #define COMM_AWB_MODE 0x0d02 | ||
305 | #define COMM_AWB_MODE_INCANDESCENT 0x0000 | ||
306 | #define COMM_AWB_MODE_FLUORESCENT1 0x0001 | ||
307 | #define COMM_AWB_MODE_FLUORESCENT2 0x0002 | ||
308 | #define COMM_AWB_MODE_DAYLIGHT 0x0003 | ||
309 | #define COMM_AWB_MODE_CLOUDY 0x0004 | ||
310 | #define COMM_AWB_MODE_AUTO 0x0005 | ||
311 | |||
312 | #define COMM_AWB_CON 0x0d00 | ||
313 | #define COMM_AWB_STOP 0x0000 /* lock */ | ||
314 | #define COMM_AWB_START 0x0001 /* unlock */ | ||
315 | |||
316 | #define COMM_FW_UPDATE 0x0906 | ||
317 | #define COMM_FW_UPDATE_NOT_READY 0x0000 | ||
318 | #define COMM_FW_UPDATE_SUCCESS 0x0005 | ||
319 | #define COMM_FW_UPDATE_FAIL 0x0007 | ||
320 | #define COMM_FW_UPDATE_BUSY 0xffff | ||
321 | |||
322 | |||
323 | #define S5C73M3_MAX_SUPPLIES 6 | ||
324 | |||
325 | struct s5c73m3_ctrls { | ||
326 | struct v4l2_ctrl_handler handler; | ||
327 | struct { | ||
328 | /* exposure/exposure bias cluster */ | ||
329 | struct v4l2_ctrl *auto_exposure; | ||
330 | struct v4l2_ctrl *exposure_bias; | ||
331 | struct v4l2_ctrl *exposure_metering; | ||
332 | }; | ||
333 | struct { | ||
334 | /* iso/auto iso cluster */ | ||
335 | struct v4l2_ctrl *auto_iso; | ||
336 | struct v4l2_ctrl *iso; | ||
337 | }; | ||
338 | struct v4l2_ctrl *auto_wb; | ||
339 | struct { | ||
340 | /* continuous auto focus/auto focus cluster */ | ||
341 | struct v4l2_ctrl *focus_auto; | ||
342 | struct v4l2_ctrl *af_start; | ||
343 | struct v4l2_ctrl *af_stop; | ||
344 | struct v4l2_ctrl *af_status; | ||
345 | struct v4l2_ctrl *af_distance; | ||
346 | }; | ||
347 | |||
348 | struct v4l2_ctrl *aaa_lock; | ||
349 | struct v4l2_ctrl *colorfx; | ||
350 | struct v4l2_ctrl *contrast; | ||
351 | struct v4l2_ctrl *saturation; | ||
352 | struct v4l2_ctrl *sharpness; | ||
353 | struct v4l2_ctrl *zoom; | ||
354 | struct v4l2_ctrl *wdr; | ||
355 | struct v4l2_ctrl *stabilization; | ||
356 | struct v4l2_ctrl *jpeg_quality; | ||
357 | struct v4l2_ctrl *scene_mode; | ||
358 | }; | ||
359 | |||
360 | enum s5c73m3_gpio_id { | ||
361 | STBY, | ||
362 | RST, | ||
363 | GPIO_NUM, | ||
364 | }; | ||
365 | |||
366 | enum s5c73m3_resolution_types { | ||
367 | RES_ISP, | ||
368 | RES_JPEG, | ||
369 | }; | ||
370 | |||
371 | struct s5c73m3_interval { | ||
372 | u16 fps_reg; | ||
373 | struct v4l2_fract interval; | ||
374 | /* Maximum rectangle for the interval */ | ||
375 | struct v4l2_frmsize_discrete size; | ||
376 | }; | ||
377 | |||
378 | struct s5c73m3 { | ||
379 | struct v4l2_subdev sensor_sd; | ||
380 | struct media_pad sensor_pads[S5C73M3_NUM_PADS]; | ||
381 | |||
382 | struct v4l2_subdev oif_sd; | ||
383 | struct media_pad oif_pads[OIF_NUM_PADS]; | ||
384 | |||
385 | struct spi_driver spidrv; | ||
386 | struct spi_device *spi_dev; | ||
387 | struct i2c_client *i2c_client; | ||
388 | u32 i2c_write_address; | ||
389 | u32 i2c_read_address; | ||
390 | |||
391 | struct regulator_bulk_data supplies[S5C73M3_MAX_SUPPLIES]; | ||
392 | struct s5c73m3_gpio gpio[GPIO_NUM]; | ||
393 | |||
394 | /* External master clock frequency */ | ||
395 | u32 mclk_frequency; | ||
396 | /* Video bus type - MIPI-CSI2/paralell */ | ||
397 | enum v4l2_mbus_type bus_type; | ||
398 | |||
399 | const struct s5c73m3_frame_size *sensor_pix_size[2]; | ||
400 | const struct s5c73m3_frame_size *oif_pix_size[2]; | ||
401 | enum v4l2_mbus_pixelcode mbus_code; | ||
402 | |||
403 | const struct s5c73m3_interval *fiv; | ||
404 | |||
405 | struct v4l2_mbus_frame_desc frame_desc; | ||
406 | /* protects the struct members below */ | ||
407 | struct mutex lock; | ||
408 | |||
409 | struct s5c73m3_ctrls ctrls; | ||
410 | |||
411 | u8 streaming:1; | ||
412 | u8 apply_fmt:1; | ||
413 | u8 apply_fiv:1; | ||
414 | u8 isp_ready:1; | ||
415 | |||
416 | short power; | ||
417 | |||
418 | char sensor_fw[S5C73M3_SENSOR_FW_LEN + 2]; | ||
419 | char sensor_type[S5C73M3_SENSOR_TYPE_LEN + 2]; | ||
420 | char fw_file_version[2]; | ||
421 | unsigned int fw_size; | ||
422 | }; | ||
423 | |||
424 | struct s5c73m3_frame_size { | ||
425 | u32 width; | ||
426 | u32 height; | ||
427 | u8 reg_val; | ||
428 | }; | ||
429 | |||
430 | extern int s5c73m3_dbg; | ||
431 | |||
432 | int s5c73m3_register_spi_driver(struct s5c73m3 *state); | ||
433 | void s5c73m3_unregister_spi_driver(struct s5c73m3 *state); | ||
434 | int s5c73m3_spi_write(struct s5c73m3 *state, const void *addr, | ||
435 | const unsigned int len, const unsigned int tx_size); | ||
436 | int s5c73m3_spi_read(struct s5c73m3 *state, void *addr, | ||
437 | const unsigned int len, const unsigned int tx_size); | ||
438 | |||
439 | int s5c73m3_read(struct s5c73m3 *state, u32 addr, u16 *data); | ||
440 | int s5c73m3_write(struct s5c73m3 *state, u32 addr, u16 data); | ||
441 | int s5c73m3_isp_command(struct s5c73m3 *state, u16 command, u16 data); | ||
442 | int s5c73m3_init_controls(struct s5c73m3 *state); | ||
443 | |||
444 | static inline struct v4l2_subdev *ctrl_to_sensor_sd(struct v4l2_ctrl *ctrl) | ||
445 | { | ||
446 | return &container_of(ctrl->handler, struct s5c73m3, | ||
447 | ctrls.handler)->sensor_sd; | ||
448 | } | ||
449 | |||
450 | static inline struct s5c73m3 *sensor_sd_to_s5c73m3(struct v4l2_subdev *sd) | ||
451 | { | ||
452 | return container_of(sd, struct s5c73m3, sensor_sd); | ||
453 | } | ||
454 | |||
455 | static inline struct s5c73m3 *oif_sd_to_s5c73m3(struct v4l2_subdev *sd) | ||
456 | { | ||
457 | return container_of(sd, struct s5c73m3, oif_sd); | ||
458 | } | ||
459 | #endif /* S5C73M3_H_ */ | ||
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index 57cd4fa0193d..bdf5e3db31d1 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c | |||
@@ -1598,7 +1598,7 @@ static int s5k6aa_probe(struct i2c_client *client, | |||
1598 | for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++) | 1598 | for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++) |
1599 | s5k6aa->supplies[i].supply = s5k6aa_supply_names[i]; | 1599 | s5k6aa->supplies[i].supply = s5k6aa_supply_names[i]; |
1600 | 1600 | ||
1601 | ret = regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES, | 1601 | ret = devm_regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES, |
1602 | s5k6aa->supplies); | 1602 | s5k6aa->supplies); |
1603 | if (ret) { | 1603 | if (ret) { |
1604 | dev_err(&client->dev, "Failed to get regulators\n"); | 1604 | dev_err(&client->dev, "Failed to get regulators\n"); |
@@ -1607,7 +1607,7 @@ static int s5k6aa_probe(struct i2c_client *client, | |||
1607 | 1607 | ||
1608 | ret = s5k6aa_initialize_ctrls(s5k6aa); | 1608 | ret = s5k6aa_initialize_ctrls(s5k6aa); |
1609 | if (ret) | 1609 | if (ret) |
1610 | goto out_err4; | 1610 | goto out_err3; |
1611 | 1611 | ||
1612 | s5k6aa_presets_data_init(s5k6aa); | 1612 | s5k6aa_presets_data_init(s5k6aa); |
1613 | 1613 | ||
@@ -1618,8 +1618,6 @@ static int s5k6aa_probe(struct i2c_client *client, | |||
1618 | 1618 | ||
1619 | return 0; | 1619 | return 0; |
1620 | 1620 | ||
1621 | out_err4: | ||
1622 | regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | ||
1623 | out_err3: | 1621 | out_err3: |
1624 | s5k6aa_free_gpios(s5k6aa); | 1622 | s5k6aa_free_gpios(s5k6aa); |
1625 | out_err2: | 1623 | out_err2: |
@@ -1635,7 +1633,6 @@ static int s5k6aa_remove(struct i2c_client *client) | |||
1635 | v4l2_device_unregister_subdev(sd); | 1633 | v4l2_device_unregister_subdev(sd); |
1636 | v4l2_ctrl_handler_free(sd->ctrl_handler); | 1634 | v4l2_ctrl_handler_free(sd->ctrl_handler); |
1637 | media_entity_cleanup(&sd->entity); | 1635 | media_entity_cleanup(&sd->entity); |
1638 | regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | ||
1639 | s5k6aa_free_gpios(s5k6aa); | 1636 | s5k6aa_free_gpios(s5k6aa); |
1640 | 1637 | ||
1641 | return 0; | 1638 | return 0; |
diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c index f8534eec9de9..a2a5cbbdbe28 100644 --- a/drivers/media/i2c/soc_camera/imx074.c +++ b/drivers/media/i2c/soc_camera/imx074.c | |||
@@ -271,9 +271,9 @@ static int imx074_g_chip_ident(struct v4l2_subdev *sd, | |||
271 | static int imx074_s_power(struct v4l2_subdev *sd, int on) | 271 | static int imx074_s_power(struct v4l2_subdev *sd, int on) |
272 | { | 272 | { |
273 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 273 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
274 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 274 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
275 | 275 | ||
276 | return soc_camera_set_power(&client->dev, icl, on); | 276 | return soc_camera_set_power(&client->dev, ssdd, on); |
277 | } | 277 | } |
278 | 278 | ||
279 | static int imx074_g_mbus_config(struct v4l2_subdev *sd, | 279 | static int imx074_g_mbus_config(struct v4l2_subdev *sd, |
@@ -430,10 +430,9 @@ static int imx074_probe(struct i2c_client *client, | |||
430 | { | 430 | { |
431 | struct imx074 *priv; | 431 | struct imx074 *priv; |
432 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 432 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
433 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 433 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
434 | int ret; | ||
435 | 434 | ||
436 | if (!icl) { | 435 | if (!ssdd) { |
437 | dev_err(&client->dev, "IMX074: missing platform data!\n"); | 436 | dev_err(&client->dev, "IMX074: missing platform data!\n"); |
438 | return -EINVAL; | 437 | return -EINVAL; |
439 | } | 438 | } |
@@ -444,7 +443,7 @@ static int imx074_probe(struct i2c_client *client, | |||
444 | return -EIO; | 443 | return -EIO; |
445 | } | 444 | } |
446 | 445 | ||
447 | priv = kzalloc(sizeof(struct imx074), GFP_KERNEL); | 446 | priv = devm_kzalloc(&client->dev, sizeof(struct imx074), GFP_KERNEL); |
448 | if (!priv) | 447 | if (!priv) |
449 | return -ENOMEM; | 448 | return -ENOMEM; |
450 | 449 | ||
@@ -452,23 +451,15 @@ static int imx074_probe(struct i2c_client *client, | |||
452 | 451 | ||
453 | priv->fmt = &imx074_colour_fmts[0]; | 452 | priv->fmt = &imx074_colour_fmts[0]; |
454 | 453 | ||
455 | ret = imx074_video_probe(client); | 454 | return imx074_video_probe(client); |
456 | if (ret < 0) { | ||
457 | kfree(priv); | ||
458 | return ret; | ||
459 | } | ||
460 | |||
461 | return ret; | ||
462 | } | 455 | } |
463 | 456 | ||
464 | static int imx074_remove(struct i2c_client *client) | 457 | static int imx074_remove(struct i2c_client *client) |
465 | { | 458 | { |
466 | struct imx074 *priv = to_imx074(client); | 459 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
467 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
468 | 460 | ||
469 | if (icl->free_bus) | 461 | if (ssdd->free_bus) |
470 | icl->free_bus(icl); | 462 | ssdd->free_bus(ssdd); |
471 | kfree(priv); | ||
472 | 463 | ||
473 | return 0; | 464 | return 0; |
474 | } | 465 | } |
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index 19f8a07764f9..bcdc86175549 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c | |||
@@ -23,7 +23,7 @@ | |||
23 | /* | 23 | /* |
24 | * mt9m001 i2c address 0x5d | 24 | * mt9m001 i2c address 0x5d |
25 | * The platform has to define struct i2c_board_info objects and link to them | 25 | * The platform has to define struct i2c_board_info objects and link to them |
26 | * from struct soc_camera_link | 26 | * from struct soc_camera_host_desc |
27 | */ | 27 | */ |
28 | 28 | ||
29 | /* mt9m001 selected register addresses */ | 29 | /* mt9m001 selected register addresses */ |
@@ -380,9 +380,9 @@ static int mt9m001_s_register(struct v4l2_subdev *sd, | |||
380 | static int mt9m001_s_power(struct v4l2_subdev *sd, int on) | 380 | static int mt9m001_s_power(struct v4l2_subdev *sd, int on) |
381 | { | 381 | { |
382 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 382 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
383 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 383 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
384 | 384 | ||
385 | return soc_camera_set_power(&client->dev, icl, on); | 385 | return soc_camera_set_power(&client->dev, ssdd, on); |
386 | } | 386 | } |
387 | 387 | ||
388 | static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | 388 | static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
@@ -482,7 +482,7 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) | |||
482 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 482 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
483 | * this wasn't our capture interface, so, we wait for the right one | 483 | * this wasn't our capture interface, so, we wait for the right one |
484 | */ | 484 | */ |
485 | static int mt9m001_video_probe(struct soc_camera_link *icl, | 485 | static int mt9m001_video_probe(struct soc_camera_subdev_desc *ssdd, |
486 | struct i2c_client *client) | 486 | struct i2c_client *client) |
487 | { | 487 | { |
488 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 488 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
@@ -526,8 +526,8 @@ static int mt9m001_video_probe(struct soc_camera_link *icl, | |||
526 | * The platform may support different bus widths due to | 526 | * The platform may support different bus widths due to |
527 | * different routing of the data lines. | 527 | * different routing of the data lines. |
528 | */ | 528 | */ |
529 | if (icl->query_bus_param) | 529 | if (ssdd->query_bus_param) |
530 | flags = icl->query_bus_param(icl); | 530 | flags = ssdd->query_bus_param(ssdd); |
531 | else | 531 | else |
532 | flags = SOCAM_DATAWIDTH_10; | 532 | flags = SOCAM_DATAWIDTH_10; |
533 | 533 | ||
@@ -558,10 +558,10 @@ done: | |||
558 | return ret; | 558 | return ret; |
559 | } | 559 | } |
560 | 560 | ||
561 | static void mt9m001_video_remove(struct soc_camera_link *icl) | 561 | static void mt9m001_video_remove(struct soc_camera_subdev_desc *ssdd) |
562 | { | 562 | { |
563 | if (icl->free_bus) | 563 | if (ssdd->free_bus) |
564 | icl->free_bus(icl); | 564 | ssdd->free_bus(ssdd); |
565 | } | 565 | } |
566 | 566 | ||
567 | static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | 567 | static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) |
@@ -605,14 +605,14 @@ static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, | |||
605 | struct v4l2_mbus_config *cfg) | 605 | struct v4l2_mbus_config *cfg) |
606 | { | 606 | { |
607 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 607 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
608 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 608 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
609 | 609 | ||
610 | /* MT9M001 has all capture_format parameters fixed */ | 610 | /* MT9M001 has all capture_format parameters fixed */ |
611 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | | 611 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | |
612 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | 612 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | |
613 | V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER; | 613 | V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER; |
614 | cfg->type = V4L2_MBUS_PARALLEL; | 614 | cfg->type = V4L2_MBUS_PARALLEL; |
615 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 615 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
616 | 616 | ||
617 | return 0; | 617 | return 0; |
618 | } | 618 | } |
@@ -621,12 +621,12 @@ static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, | |||
621 | const struct v4l2_mbus_config *cfg) | 621 | const struct v4l2_mbus_config *cfg) |
622 | { | 622 | { |
623 | const struct i2c_client *client = v4l2_get_subdevdata(sd); | 623 | const struct i2c_client *client = v4l2_get_subdevdata(sd); |
624 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 624 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
625 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 625 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
626 | unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample; | 626 | unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample; |
627 | 627 | ||
628 | if (icl->set_bus_param) | 628 | if (ssdd->set_bus_param) |
629 | return icl->set_bus_param(icl, 1 << (bps - 1)); | 629 | return ssdd->set_bus_param(ssdd, 1 << (bps - 1)); |
630 | 630 | ||
631 | /* | 631 | /* |
632 | * Without board specific bus width settings we only support the | 632 | * Without board specific bus width settings we only support the |
@@ -663,10 +663,10 @@ static int mt9m001_probe(struct i2c_client *client, | |||
663 | { | 663 | { |
664 | struct mt9m001 *mt9m001; | 664 | struct mt9m001 *mt9m001; |
665 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 665 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
666 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 666 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
667 | int ret; | 667 | int ret; |
668 | 668 | ||
669 | if (!icl) { | 669 | if (!ssdd) { |
670 | dev_err(&client->dev, "MT9M001 driver needs platform data\n"); | 670 | dev_err(&client->dev, "MT9M001 driver needs platform data\n"); |
671 | return -EINVAL; | 671 | return -EINVAL; |
672 | } | 672 | } |
@@ -677,7 +677,7 @@ static int mt9m001_probe(struct i2c_client *client, | |||
677 | return -EIO; | 677 | return -EIO; |
678 | } | 678 | } |
679 | 679 | ||
680 | mt9m001 = kzalloc(sizeof(struct mt9m001), GFP_KERNEL); | 680 | mt9m001 = devm_kzalloc(&client->dev, sizeof(struct mt9m001), GFP_KERNEL); |
681 | if (!mt9m001) | 681 | if (!mt9m001) |
682 | return -ENOMEM; | 682 | return -ENOMEM; |
683 | 683 | ||
@@ -697,12 +697,9 @@ static int mt9m001_probe(struct i2c_client *client, | |||
697 | &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | 697 | &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, |
698 | V4L2_EXPOSURE_AUTO); | 698 | V4L2_EXPOSURE_AUTO); |
699 | mt9m001->subdev.ctrl_handler = &mt9m001->hdl; | 699 | mt9m001->subdev.ctrl_handler = &mt9m001->hdl; |
700 | if (mt9m001->hdl.error) { | 700 | if (mt9m001->hdl.error) |
701 | int err = mt9m001->hdl.error; | 701 | return mt9m001->hdl.error; |
702 | 702 | ||
703 | kfree(mt9m001); | ||
704 | return err; | ||
705 | } | ||
706 | v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure, | 703 | v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure, |
707 | V4L2_EXPOSURE_MANUAL, true); | 704 | V4L2_EXPOSURE_MANUAL, true); |
708 | 705 | ||
@@ -713,11 +710,9 @@ static int mt9m001_probe(struct i2c_client *client, | |||
713 | mt9m001->rect.width = MT9M001_MAX_WIDTH; | 710 | mt9m001->rect.width = MT9M001_MAX_WIDTH; |
714 | mt9m001->rect.height = MT9M001_MAX_HEIGHT; | 711 | mt9m001->rect.height = MT9M001_MAX_HEIGHT; |
715 | 712 | ||
716 | ret = mt9m001_video_probe(icl, client); | 713 | ret = mt9m001_video_probe(ssdd, client); |
717 | if (ret) { | 714 | if (ret) |
718 | v4l2_ctrl_handler_free(&mt9m001->hdl); | 715 | v4l2_ctrl_handler_free(&mt9m001->hdl); |
719 | kfree(mt9m001); | ||
720 | } | ||
721 | 716 | ||
722 | return ret; | 717 | return ret; |
723 | } | 718 | } |
@@ -725,12 +720,11 @@ static int mt9m001_probe(struct i2c_client *client, | |||
725 | static int mt9m001_remove(struct i2c_client *client) | 720 | static int mt9m001_remove(struct i2c_client *client) |
726 | { | 721 | { |
727 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 722 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
728 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 723 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
729 | 724 | ||
730 | v4l2_device_unregister_subdev(&mt9m001->subdev); | 725 | v4l2_device_unregister_subdev(&mt9m001->subdev); |
731 | v4l2_ctrl_handler_free(&mt9m001->hdl); | 726 | v4l2_ctrl_handler_free(&mt9m001->hdl); |
732 | mt9m001_video_remove(icl); | 727 | mt9m001_video_remove(ssdd); |
733 | kfree(mt9m001); | ||
734 | 728 | ||
735 | return 0; | 729 | return 0; |
736 | } | 730 | } |
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 62fd94af599b..bbc4ff99603c 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c | |||
@@ -24,7 +24,8 @@ | |||
24 | /* | 24 | /* |
25 | * MT9M111, MT9M112 and MT9M131: | 25 | * MT9M111, MT9M112 and MT9M131: |
26 | * i2c address is 0x48 or 0x5d (depending on SADDR pin) | 26 | * i2c address is 0x48 or 0x5d (depending on SADDR pin) |
27 | * The platform has to define i2c_board_info and call i2c_register_board_info() | 27 | * The platform has to define struct i2c_board_info objects and link to them |
28 | * from struct soc_camera_host_desc | ||
28 | */ | 29 | */ |
29 | 30 | ||
30 | /* | 31 | /* |
@@ -799,17 +800,17 @@ static int mt9m111_init(struct mt9m111 *mt9m111) | |||
799 | static int mt9m111_power_on(struct mt9m111 *mt9m111) | 800 | static int mt9m111_power_on(struct mt9m111 *mt9m111) |
800 | { | 801 | { |
801 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 802 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
802 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 803 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
803 | int ret; | 804 | int ret; |
804 | 805 | ||
805 | ret = soc_camera_power_on(&client->dev, icl); | 806 | ret = soc_camera_power_on(&client->dev, ssdd); |
806 | if (ret < 0) | 807 | if (ret < 0) |
807 | return ret; | 808 | return ret; |
808 | 809 | ||
809 | ret = mt9m111_resume(mt9m111); | 810 | ret = mt9m111_resume(mt9m111); |
810 | if (ret < 0) { | 811 | if (ret < 0) { |
811 | dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret); | 812 | dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret); |
812 | soc_camera_power_off(&client->dev, icl); | 813 | soc_camera_power_off(&client->dev, ssdd); |
813 | } | 814 | } |
814 | 815 | ||
815 | return ret; | 816 | return ret; |
@@ -818,10 +819,10 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111) | |||
818 | static void mt9m111_power_off(struct mt9m111 *mt9m111) | 819 | static void mt9m111_power_off(struct mt9m111 *mt9m111) |
819 | { | 820 | { |
820 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 821 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
821 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 822 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
822 | 823 | ||
823 | mt9m111_suspend(mt9m111); | 824 | mt9m111_suspend(mt9m111); |
824 | soc_camera_power_off(&client->dev, icl); | 825 | soc_camera_power_off(&client->dev, ssdd); |
825 | } | 826 | } |
826 | 827 | ||
827 | static int mt9m111_s_power(struct v4l2_subdev *sd, int on) | 828 | static int mt9m111_s_power(struct v4l2_subdev *sd, int on) |
@@ -879,13 +880,13 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, | |||
879 | struct v4l2_mbus_config *cfg) | 880 | struct v4l2_mbus_config *cfg) |
880 | { | 881 | { |
881 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 882 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
882 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 883 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
883 | 884 | ||
884 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | | 885 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | |
885 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | 886 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | |
886 | V4L2_MBUS_DATA_ACTIVE_HIGH; | 887 | V4L2_MBUS_DATA_ACTIVE_HIGH; |
887 | cfg->type = V4L2_MBUS_PARALLEL; | 888 | cfg->type = V4L2_MBUS_PARALLEL; |
888 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 889 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
889 | 890 | ||
890 | return 0; | 891 | return 0; |
891 | } | 892 | } |
@@ -956,10 +957,10 @@ static int mt9m111_probe(struct i2c_client *client, | |||
956 | { | 957 | { |
957 | struct mt9m111 *mt9m111; | 958 | struct mt9m111 *mt9m111; |
958 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 959 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
959 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 960 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
960 | int ret; | 961 | int ret; |
961 | 962 | ||
962 | if (!icl) { | 963 | if (!ssdd) { |
963 | dev_err(&client->dev, "mt9m111: driver needs platform data\n"); | 964 | dev_err(&client->dev, "mt9m111: driver needs platform data\n"); |
964 | return -EINVAL; | 965 | return -EINVAL; |
965 | } | 966 | } |
@@ -970,7 +971,7 @@ static int mt9m111_probe(struct i2c_client *client, | |||
970 | return -EIO; | 971 | return -EIO; |
971 | } | 972 | } |
972 | 973 | ||
973 | mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL); | 974 | mt9m111 = devm_kzalloc(&client->dev, sizeof(struct mt9m111), GFP_KERNEL); |
974 | if (!mt9m111) | 975 | if (!mt9m111) |
975 | return -ENOMEM; | 976 | return -ENOMEM; |
976 | 977 | ||
@@ -988,12 +989,8 @@ static int mt9m111_probe(struct i2c_client *client, | |||
988 | &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | 989 | &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, |
989 | V4L2_EXPOSURE_AUTO); | 990 | V4L2_EXPOSURE_AUTO); |
990 | mt9m111->subdev.ctrl_handler = &mt9m111->hdl; | 991 | mt9m111->subdev.ctrl_handler = &mt9m111->hdl; |
991 | if (mt9m111->hdl.error) { | 992 | if (mt9m111->hdl.error) |
992 | int err = mt9m111->hdl.error; | 993 | return mt9m111->hdl.error; |
993 | |||
994 | kfree(mt9m111); | ||
995 | return err; | ||
996 | } | ||
997 | 994 | ||
998 | /* Second stage probe - when a capture adapter is there */ | 995 | /* Second stage probe - when a capture adapter is there */ |
999 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; | 996 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; |
@@ -1005,10 +1002,8 @@ static int mt9m111_probe(struct i2c_client *client, | |||
1005 | mutex_init(&mt9m111->power_lock); | 1002 | mutex_init(&mt9m111->power_lock); |
1006 | 1003 | ||
1007 | ret = mt9m111_video_probe(client); | 1004 | ret = mt9m111_video_probe(client); |
1008 | if (ret) { | 1005 | if (ret) |
1009 | v4l2_ctrl_handler_free(&mt9m111->hdl); | 1006 | v4l2_ctrl_handler_free(&mt9m111->hdl); |
1010 | kfree(mt9m111); | ||
1011 | } | ||
1012 | 1007 | ||
1013 | return ret; | 1008 | return ret; |
1014 | } | 1009 | } |
@@ -1019,7 +1014,6 @@ static int mt9m111_remove(struct i2c_client *client) | |||
1019 | 1014 | ||
1020 | v4l2_device_unregister_subdev(&mt9m111->subdev); | 1015 | v4l2_device_unregister_subdev(&mt9m111->subdev); |
1021 | v4l2_ctrl_handler_free(&mt9m111->hdl); | 1016 | v4l2_ctrl_handler_free(&mt9m111->hdl); |
1022 | kfree(mt9m111); | ||
1023 | 1017 | ||
1024 | return 0; | 1018 | return 0; |
1025 | } | 1019 | } |
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index 40800b10a080..d80d044ebf15 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c | |||
@@ -31,8 +31,8 @@ | |||
31 | 31 | ||
32 | /* | 32 | /* |
33 | * mt9t031 i2c address 0x5d | 33 | * mt9t031 i2c address 0x5d |
34 | * The platform has to define i2c_board_info and link to it from | 34 | * The platform has to define struct i2c_board_info objects and link to them |
35 | * struct soc_camera_link | 35 | * from struct soc_camera_host_desc |
36 | */ | 36 | */ |
37 | 37 | ||
38 | /* mt9t031 selected register addresses */ | 38 | /* mt9t031 selected register addresses */ |
@@ -608,18 +608,18 @@ static struct device_type mt9t031_dev_type = { | |||
608 | static int mt9t031_s_power(struct v4l2_subdev *sd, int on) | 608 | static int mt9t031_s_power(struct v4l2_subdev *sd, int on) |
609 | { | 609 | { |
610 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 610 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
611 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 611 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
612 | struct video_device *vdev = soc_camera_i2c_to_vdev(client); | 612 | struct video_device *vdev = soc_camera_i2c_to_vdev(client); |
613 | int ret; | 613 | int ret; |
614 | 614 | ||
615 | if (on) { | 615 | if (on) { |
616 | ret = soc_camera_power_on(&client->dev, icl); | 616 | ret = soc_camera_power_on(&client->dev, ssdd); |
617 | if (ret < 0) | 617 | if (ret < 0) |
618 | return ret; | 618 | return ret; |
619 | vdev->dev.type = &mt9t031_dev_type; | 619 | vdev->dev.type = &mt9t031_dev_type; |
620 | } else { | 620 | } else { |
621 | vdev->dev.type = NULL; | 621 | vdev->dev.type = NULL; |
622 | soc_camera_power_off(&client->dev, icl); | 622 | soc_camera_power_off(&client->dev, ssdd); |
623 | } | 623 | } |
624 | 624 | ||
625 | return 0; | 625 | return 0; |
@@ -707,13 +707,13 @@ static int mt9t031_g_mbus_config(struct v4l2_subdev *sd, | |||
707 | struct v4l2_mbus_config *cfg) | 707 | struct v4l2_mbus_config *cfg) |
708 | { | 708 | { |
709 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 709 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
710 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 710 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
711 | 711 | ||
712 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | | 712 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | |
713 | V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | 713 | V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
714 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH; | 714 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH; |
715 | cfg->type = V4L2_MBUS_PARALLEL; | 715 | cfg->type = V4L2_MBUS_PARALLEL; |
716 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 716 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
717 | 717 | ||
718 | return 0; | 718 | return 0; |
719 | } | 719 | } |
@@ -722,9 +722,9 @@ static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, | |||
722 | const struct v4l2_mbus_config *cfg) | 722 | const struct v4l2_mbus_config *cfg) |
723 | { | 723 | { |
724 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 724 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
725 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 725 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
726 | 726 | ||
727 | if (soc_camera_apply_board_flags(icl, cfg) & | 727 | if (soc_camera_apply_board_flags(ssdd, cfg) & |
728 | V4L2_MBUS_PCLK_SAMPLE_FALLING) | 728 | V4L2_MBUS_PCLK_SAMPLE_FALLING) |
729 | return reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); | 729 | return reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); |
730 | else | 730 | else |
@@ -758,11 +758,11 @@ static int mt9t031_probe(struct i2c_client *client, | |||
758 | const struct i2c_device_id *did) | 758 | const struct i2c_device_id *did) |
759 | { | 759 | { |
760 | struct mt9t031 *mt9t031; | 760 | struct mt9t031 *mt9t031; |
761 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 761 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
762 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 762 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
763 | int ret; | 763 | int ret; |
764 | 764 | ||
765 | if (!icl) { | 765 | if (!ssdd) { |
766 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); | 766 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); |
767 | return -EINVAL; | 767 | return -EINVAL; |
768 | } | 768 | } |
@@ -773,7 +773,7 @@ static int mt9t031_probe(struct i2c_client *client, | |||
773 | return -EIO; | 773 | return -EIO; |
774 | } | 774 | } |
775 | 775 | ||
776 | mt9t031 = kzalloc(sizeof(struct mt9t031), GFP_KERNEL); | 776 | mt9t031 = devm_kzalloc(&client->dev, sizeof(struct mt9t031), GFP_KERNEL); |
777 | if (!mt9t031) | 777 | if (!mt9t031) |
778 | return -ENOMEM; | 778 | return -ENOMEM; |
779 | 779 | ||
@@ -797,12 +797,9 @@ static int mt9t031_probe(struct i2c_client *client, | |||
797 | V4L2_CID_EXPOSURE, 1, 255, 1, 255); | 797 | V4L2_CID_EXPOSURE, 1, 255, 1, 255); |
798 | 798 | ||
799 | mt9t031->subdev.ctrl_handler = &mt9t031->hdl; | 799 | mt9t031->subdev.ctrl_handler = &mt9t031->hdl; |
800 | if (mt9t031->hdl.error) { | 800 | if (mt9t031->hdl.error) |
801 | int err = mt9t031->hdl.error; | 801 | return mt9t031->hdl.error; |
802 | 802 | ||
803 | kfree(mt9t031); | ||
804 | return err; | ||
805 | } | ||
806 | v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure, | 803 | v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure, |
807 | V4L2_EXPOSURE_MANUAL, true); | 804 | V4L2_EXPOSURE_MANUAL, true); |
808 | 805 | ||
@@ -816,10 +813,8 @@ static int mt9t031_probe(struct i2c_client *client, | |||
816 | mt9t031->yskip = 1; | 813 | mt9t031->yskip = 1; |
817 | 814 | ||
818 | ret = mt9t031_video_probe(client); | 815 | ret = mt9t031_video_probe(client); |
819 | if (ret) { | 816 | if (ret) |
820 | v4l2_ctrl_handler_free(&mt9t031->hdl); | 817 | v4l2_ctrl_handler_free(&mt9t031->hdl); |
821 | kfree(mt9t031); | ||
822 | } | ||
823 | 818 | ||
824 | return ret; | 819 | return ret; |
825 | } | 820 | } |
@@ -830,7 +825,6 @@ static int mt9t031_remove(struct i2c_client *client) | |||
830 | 825 | ||
831 | v4l2_device_unregister_subdev(&mt9t031->subdev); | 826 | v4l2_device_unregister_subdev(&mt9t031->subdev); |
832 | v4l2_ctrl_handler_free(&mt9t031->hdl); | 827 | v4l2_ctrl_handler_free(&mt9t031->hdl); |
833 | kfree(mt9t031); | ||
834 | 828 | ||
835 | return 0; | 829 | return 0; |
836 | } | 830 | } |
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index de7cd836b0a2..188e29b03273 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c | |||
@@ -92,6 +92,7 @@ struct mt9t112_priv { | |||
92 | struct v4l2_rect frame; | 92 | struct v4l2_rect frame; |
93 | const struct mt9t112_format *format; | 93 | const struct mt9t112_format *format; |
94 | int model; | 94 | int model; |
95 | int num_formats; | ||
95 | u32 flags; | 96 | u32 flags; |
96 | /* for flags */ | 97 | /* for flags */ |
97 | #define INIT_DONE (1 << 0) | 98 | #define INIT_DONE (1 << 0) |
@@ -779,9 +780,9 @@ static int mt9t112_s_register(struct v4l2_subdev *sd, | |||
779 | static int mt9t112_s_power(struct v4l2_subdev *sd, int on) | 780 | static int mt9t112_s_power(struct v4l2_subdev *sd, int on) |
780 | { | 781 | { |
781 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 782 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
782 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 783 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
783 | 784 | ||
784 | return soc_camera_set_power(&client->dev, icl, on); | 785 | return soc_camera_set_power(&client->dev, ssdd, on); |
785 | } | 786 | } |
786 | 787 | ||
787 | static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { | 788 | static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { |
@@ -859,11 +860,11 @@ static int mt9t112_set_params(struct mt9t112_priv *priv, | |||
859 | /* | 860 | /* |
860 | * get color format | 861 | * get color format |
861 | */ | 862 | */ |
862 | for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++) | 863 | for (i = 0; i < priv->num_formats; i++) |
863 | if (mt9t112_cfmts[i].code == code) | 864 | if (mt9t112_cfmts[i].code == code) |
864 | break; | 865 | break; |
865 | 866 | ||
866 | if (i == ARRAY_SIZE(mt9t112_cfmts)) | 867 | if (i == priv->num_formats) |
867 | return -EINVAL; | 868 | return -EINVAL; |
868 | 869 | ||
869 | priv->frame = *rect; | 870 | priv->frame = *rect; |
@@ -955,14 +956,16 @@ static int mt9t112_s_fmt(struct v4l2_subdev *sd, | |||
955 | static int mt9t112_try_fmt(struct v4l2_subdev *sd, | 956 | static int mt9t112_try_fmt(struct v4l2_subdev *sd, |
956 | struct v4l2_mbus_framefmt *mf) | 957 | struct v4l2_mbus_framefmt *mf) |
957 | { | 958 | { |
959 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
960 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
958 | unsigned int top, left; | 961 | unsigned int top, left; |
959 | int i; | 962 | int i; |
960 | 963 | ||
961 | for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++) | 964 | for (i = 0; i < priv->num_formats; i++) |
962 | if (mt9t112_cfmts[i].code == mf->code) | 965 | if (mt9t112_cfmts[i].code == mf->code) |
963 | break; | 966 | break; |
964 | 967 | ||
965 | if (i == ARRAY_SIZE(mt9t112_cfmts)) { | 968 | if (i == priv->num_formats) { |
966 | mf->code = V4L2_MBUS_FMT_UYVY8_2X8; | 969 | mf->code = V4L2_MBUS_FMT_UYVY8_2X8; |
967 | mf->colorspace = V4L2_COLORSPACE_JPEG; | 970 | mf->colorspace = V4L2_COLORSPACE_JPEG; |
968 | } else { | 971 | } else { |
@@ -979,7 +982,10 @@ static int mt9t112_try_fmt(struct v4l2_subdev *sd, | |||
979 | static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | 982 | static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, |
980 | enum v4l2_mbus_pixelcode *code) | 983 | enum v4l2_mbus_pixelcode *code) |
981 | { | 984 | { |
982 | if (index >= ARRAY_SIZE(mt9t112_cfmts)) | 985 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
986 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
987 | |||
988 | if (index >= priv->num_formats) | ||
983 | return -EINVAL; | 989 | return -EINVAL; |
984 | 990 | ||
985 | *code = mt9t112_cfmts[index].code; | 991 | *code = mt9t112_cfmts[index].code; |
@@ -991,13 +997,13 @@ static int mt9t112_g_mbus_config(struct v4l2_subdev *sd, | |||
991 | struct v4l2_mbus_config *cfg) | 997 | struct v4l2_mbus_config *cfg) |
992 | { | 998 | { |
993 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 999 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
994 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1000 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
995 | 1001 | ||
996 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | 1002 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | |
997 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | | 1003 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | |
998 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; | 1004 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; |
999 | cfg->type = V4L2_MBUS_PARALLEL; | 1005 | cfg->type = V4L2_MBUS_PARALLEL; |
1000 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 1006 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
1001 | 1007 | ||
1002 | return 0; | 1008 | return 0; |
1003 | } | 1009 | } |
@@ -1006,10 +1012,10 @@ static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, | |||
1006 | const struct v4l2_mbus_config *cfg) | 1012 | const struct v4l2_mbus_config *cfg) |
1007 | { | 1013 | { |
1008 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1014 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1009 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1015 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1010 | struct mt9t112_priv *priv = to_mt9t112(client); | 1016 | struct mt9t112_priv *priv = to_mt9t112(client); |
1011 | 1017 | ||
1012 | if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) | 1018 | if (soc_camera_apply_board_flags(ssdd, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) |
1013 | priv->flags |= PCLK_RISING; | 1019 | priv->flags |= PCLK_RISING; |
1014 | 1020 | ||
1015 | return 0; | 1021 | return 0; |
@@ -1056,10 +1062,12 @@ static int mt9t112_camera_probe(struct i2c_client *client) | |||
1056 | case 0x2680: | 1062 | case 0x2680: |
1057 | devname = "mt9t111"; | 1063 | devname = "mt9t111"; |
1058 | priv->model = V4L2_IDENT_MT9T111; | 1064 | priv->model = V4L2_IDENT_MT9T111; |
1065 | priv->num_formats = 1; | ||
1059 | break; | 1066 | break; |
1060 | case 0x2682: | 1067 | case 0x2682: |
1061 | devname = "mt9t112"; | 1068 | devname = "mt9t112"; |
1062 | priv->model = V4L2_IDENT_MT9T112; | 1069 | priv->model = V4L2_IDENT_MT9T112; |
1070 | priv->num_formats = ARRAY_SIZE(mt9t112_cfmts); | ||
1063 | break; | 1071 | break; |
1064 | default: | 1072 | default: |
1065 | dev_err(&client->dev, "Product ID error %04x\n", chipid); | 1073 | dev_err(&client->dev, "Product ID error %04x\n", chipid); |
@@ -1078,7 +1086,7 @@ static int mt9t112_probe(struct i2c_client *client, | |||
1078 | const struct i2c_device_id *did) | 1086 | const struct i2c_device_id *did) |
1079 | { | 1087 | { |
1080 | struct mt9t112_priv *priv; | 1088 | struct mt9t112_priv *priv; |
1081 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1089 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1082 | struct v4l2_rect rect = { | 1090 | struct v4l2_rect rect = { |
1083 | .width = VGA_WIDTH, | 1091 | .width = VGA_WIDTH, |
1084 | .height = VGA_HEIGHT, | 1092 | .height = VGA_HEIGHT, |
@@ -1087,24 +1095,22 @@ static int mt9t112_probe(struct i2c_client *client, | |||
1087 | }; | 1095 | }; |
1088 | int ret; | 1096 | int ret; |
1089 | 1097 | ||
1090 | if (!icl || !icl->priv) { | 1098 | if (!ssdd || !ssdd->drv_priv) { |
1091 | dev_err(&client->dev, "mt9t112: missing platform data!\n"); | 1099 | dev_err(&client->dev, "mt9t112: missing platform data!\n"); |
1092 | return -EINVAL; | 1100 | return -EINVAL; |
1093 | } | 1101 | } |
1094 | 1102 | ||
1095 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 1103 | priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); |
1096 | if (!priv) | 1104 | if (!priv) |
1097 | return -ENOMEM; | 1105 | return -ENOMEM; |
1098 | 1106 | ||
1099 | priv->info = icl->priv; | 1107 | priv->info = ssdd->drv_priv; |
1100 | 1108 | ||
1101 | v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); | 1109 | v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); |
1102 | 1110 | ||
1103 | ret = mt9t112_camera_probe(client); | 1111 | ret = mt9t112_camera_probe(client); |
1104 | if (ret) { | 1112 | if (ret) |
1105 | kfree(priv); | ||
1106 | return ret; | 1113 | return ret; |
1107 | } | ||
1108 | 1114 | ||
1109 | /* Cannot fail: using the default supported pixel code */ | 1115 | /* Cannot fail: using the default supported pixel code */ |
1110 | mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8); | 1116 | mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8); |
@@ -1114,9 +1120,6 @@ static int mt9t112_probe(struct i2c_client *client, | |||
1114 | 1120 | ||
1115 | static int mt9t112_remove(struct i2c_client *client) | 1121 | static int mt9t112_remove(struct i2c_client *client) |
1116 | { | 1122 | { |
1117 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
1118 | |||
1119 | kfree(priv); | ||
1120 | return 0; | 1123 | return 0; |
1121 | } | 1124 | } |
1122 | 1125 | ||
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index d40a8858be01..a5e65d6a0781 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c | |||
@@ -25,7 +25,7 @@ | |||
25 | /* | 25 | /* |
26 | * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c | 26 | * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c |
27 | * The platform has to define struct i2c_board_info objects and link to them | 27 | * The platform has to define struct i2c_board_info objects and link to them |
28 | * from struct soc_camera_link | 28 | * from struct soc_camera_host_desc |
29 | */ | 29 | */ |
30 | 30 | ||
31 | static char *sensor_type; | 31 | static char *sensor_type; |
@@ -508,9 +508,9 @@ static int mt9v022_s_register(struct v4l2_subdev *sd, | |||
508 | static int mt9v022_s_power(struct v4l2_subdev *sd, int on) | 508 | static int mt9v022_s_power(struct v4l2_subdev *sd, int on) |
509 | { | 509 | { |
510 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 510 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
511 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 511 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
512 | 512 | ||
513 | return soc_camera_set_power(&client->dev, icl, on); | 513 | return soc_camera_set_power(&client->dev, ssdd, on); |
514 | } | 514 | } |
515 | 515 | ||
516 | static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | 516 | static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
@@ -655,7 +655,7 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) | |||
655 | static int mt9v022_video_probe(struct i2c_client *client) | 655 | static int mt9v022_video_probe(struct i2c_client *client) |
656 | { | 656 | { |
657 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 657 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
658 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 658 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
659 | s32 data; | 659 | s32 data; |
660 | int ret; | 660 | int ret; |
661 | unsigned long flags; | 661 | unsigned long flags; |
@@ -715,8 +715,8 @@ static int mt9v022_video_probe(struct i2c_client *client) | |||
715 | * The platform may support different bus widths due to | 715 | * The platform may support different bus widths due to |
716 | * different routing of the data lines. | 716 | * different routing of the data lines. |
717 | */ | 717 | */ |
718 | if (icl->query_bus_param) | 718 | if (ssdd->query_bus_param) |
719 | flags = icl->query_bus_param(icl); | 719 | flags = ssdd->query_bus_param(ssdd); |
720 | else | 720 | else |
721 | flags = SOCAM_DATAWIDTH_10; | 721 | flags = SOCAM_DATAWIDTH_10; |
722 | 722 | ||
@@ -784,7 +784,7 @@ static int mt9v022_g_mbus_config(struct v4l2_subdev *sd, | |||
784 | struct v4l2_mbus_config *cfg) | 784 | struct v4l2_mbus_config *cfg) |
785 | { | 785 | { |
786 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 786 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
787 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 787 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
788 | 788 | ||
789 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE | | 789 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE | |
790 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | | 790 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | |
@@ -792,7 +792,7 @@ static int mt9v022_g_mbus_config(struct v4l2_subdev *sd, | |||
792 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | | 792 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | |
793 | V4L2_MBUS_DATA_ACTIVE_HIGH; | 793 | V4L2_MBUS_DATA_ACTIVE_HIGH; |
794 | cfg->type = V4L2_MBUS_PARALLEL; | 794 | cfg->type = V4L2_MBUS_PARALLEL; |
795 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 795 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
796 | 796 | ||
797 | return 0; | 797 | return 0; |
798 | } | 798 | } |
@@ -801,15 +801,15 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, | |||
801 | const struct v4l2_mbus_config *cfg) | 801 | const struct v4l2_mbus_config *cfg) |
802 | { | 802 | { |
803 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 803 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
804 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 804 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
805 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 805 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
806 | unsigned long flags = soc_camera_apply_board_flags(icl, cfg); | 806 | unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg); |
807 | unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample; | 807 | unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample; |
808 | int ret; | 808 | int ret; |
809 | u16 pixclk = 0; | 809 | u16 pixclk = 0; |
810 | 810 | ||
811 | if (icl->set_bus_param) { | 811 | if (ssdd->set_bus_param) { |
812 | ret = icl->set_bus_param(icl, 1 << (bps - 1)); | 812 | ret = ssdd->set_bus_param(ssdd, 1 << (bps - 1)); |
813 | if (ret) | 813 | if (ret) |
814 | return ret; | 814 | return ret; |
815 | } else if (bps != 10) { | 815 | } else if (bps != 10) { |
@@ -873,12 +873,12 @@ static int mt9v022_probe(struct i2c_client *client, | |||
873 | const struct i2c_device_id *did) | 873 | const struct i2c_device_id *did) |
874 | { | 874 | { |
875 | struct mt9v022 *mt9v022; | 875 | struct mt9v022 *mt9v022; |
876 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 876 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
877 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 877 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
878 | struct mt9v022_platform_data *pdata = icl->priv; | 878 | struct mt9v022_platform_data *pdata; |
879 | int ret; | 879 | int ret; |
880 | 880 | ||
881 | if (!icl) { | 881 | if (!ssdd) { |
882 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); | 882 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); |
883 | return -EINVAL; | 883 | return -EINVAL; |
884 | } | 884 | } |
@@ -889,10 +889,11 @@ static int mt9v022_probe(struct i2c_client *client, | |||
889 | return -EIO; | 889 | return -EIO; |
890 | } | 890 | } |
891 | 891 | ||
892 | mt9v022 = kzalloc(sizeof(struct mt9v022), GFP_KERNEL); | 892 | mt9v022 = devm_kzalloc(&client->dev, sizeof(struct mt9v022), GFP_KERNEL); |
893 | if (!mt9v022) | 893 | if (!mt9v022) |
894 | return -ENOMEM; | 894 | return -ENOMEM; |
895 | 895 | ||
896 | pdata = ssdd->drv_priv; | ||
896 | v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); | 897 | v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); |
897 | v4l2_ctrl_handler_init(&mt9v022->hdl, 6); | 898 | v4l2_ctrl_handler_init(&mt9v022->hdl, 6); |
898 | v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | 899 | v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, |
@@ -929,7 +930,6 @@ static int mt9v022_probe(struct i2c_client *client, | |||
929 | int err = mt9v022->hdl.error; | 930 | int err = mt9v022->hdl.error; |
930 | 931 | ||
931 | dev_err(&client->dev, "control initialisation err %d\n", err); | 932 | dev_err(&client->dev, "control initialisation err %d\n", err); |
932 | kfree(mt9v022); | ||
933 | return err; | 933 | return err; |
934 | } | 934 | } |
935 | v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure, | 935 | v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure, |
@@ -949,10 +949,8 @@ static int mt9v022_probe(struct i2c_client *client, | |||
949 | mt9v022->rect.height = MT9V022_MAX_HEIGHT; | 949 | mt9v022->rect.height = MT9V022_MAX_HEIGHT; |
950 | 950 | ||
951 | ret = mt9v022_video_probe(client); | 951 | ret = mt9v022_video_probe(client); |
952 | if (ret) { | 952 | if (ret) |
953 | v4l2_ctrl_handler_free(&mt9v022->hdl); | 953 | v4l2_ctrl_handler_free(&mt9v022->hdl); |
954 | kfree(mt9v022); | ||
955 | } | ||
956 | 954 | ||
957 | return ret; | 955 | return ret; |
958 | } | 956 | } |
@@ -960,13 +958,12 @@ static int mt9v022_probe(struct i2c_client *client, | |||
960 | static int mt9v022_remove(struct i2c_client *client) | 958 | static int mt9v022_remove(struct i2c_client *client) |
961 | { | 959 | { |
962 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 960 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
963 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 961 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
964 | 962 | ||
965 | v4l2_device_unregister_subdev(&mt9v022->subdev); | 963 | v4l2_device_unregister_subdev(&mt9v022->subdev); |
966 | if (icl->free_bus) | 964 | if (ssdd->free_bus) |
967 | icl->free_bus(icl); | 965 | ssdd->free_bus(ssdd); |
968 | v4l2_ctrl_handler_free(&mt9v022->hdl); | 966 | v4l2_ctrl_handler_free(&mt9v022->hdl); |
969 | kfree(mt9v022); | ||
970 | 967 | ||
971 | return 0; | 968 | return 0; |
972 | } | 969 | } |
diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 66698a83bda2..0f520f693b6e 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c | |||
@@ -771,9 +771,9 @@ static int ov2640_s_register(struct v4l2_subdev *sd, | |||
771 | static int ov2640_s_power(struct v4l2_subdev *sd, int on) | 771 | static int ov2640_s_power(struct v4l2_subdev *sd, int on) |
772 | { | 772 | { |
773 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 773 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
774 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 774 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
775 | 775 | ||
776 | return soc_camera_set_power(&client->dev, icl, on); | 776 | return soc_camera_set_power(&client->dev, ssdd, on); |
777 | } | 777 | } |
778 | 778 | ||
779 | /* Select the nearest higher resolution for capture */ | 779 | /* Select the nearest higher resolution for capture */ |
@@ -1046,13 +1046,13 @@ static int ov2640_g_mbus_config(struct v4l2_subdev *sd, | |||
1046 | struct v4l2_mbus_config *cfg) | 1046 | struct v4l2_mbus_config *cfg) |
1047 | { | 1047 | { |
1048 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1048 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1049 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1049 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1050 | 1050 | ||
1051 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | 1051 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | |
1052 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | 1052 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
1053 | V4L2_MBUS_DATA_ACTIVE_HIGH; | 1053 | V4L2_MBUS_DATA_ACTIVE_HIGH; |
1054 | cfg->type = V4L2_MBUS_PARALLEL; | 1054 | cfg->type = V4L2_MBUS_PARALLEL; |
1055 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 1055 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
1056 | 1056 | ||
1057 | return 0; | 1057 | return 0; |
1058 | } | 1058 | } |
@@ -1080,11 +1080,11 @@ static int ov2640_probe(struct i2c_client *client, | |||
1080 | const struct i2c_device_id *did) | 1080 | const struct i2c_device_id *did) |
1081 | { | 1081 | { |
1082 | struct ov2640_priv *priv; | 1082 | struct ov2640_priv *priv; |
1083 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1083 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1084 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1084 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1085 | int ret; | 1085 | int ret; |
1086 | 1086 | ||
1087 | if (!icl) { | 1087 | if (!ssdd) { |
1088 | dev_err(&adapter->dev, | 1088 | dev_err(&adapter->dev, |
1089 | "OV2640: Missing platform_data for driver\n"); | 1089 | "OV2640: Missing platform_data for driver\n"); |
1090 | return -EINVAL; | 1090 | return -EINVAL; |
@@ -1096,7 +1096,7 @@ static int ov2640_probe(struct i2c_client *client, | |||
1096 | return -EIO; | 1096 | return -EIO; |
1097 | } | 1097 | } |
1098 | 1098 | ||
1099 | priv = kzalloc(sizeof(struct ov2640_priv), GFP_KERNEL); | 1099 | priv = devm_kzalloc(&client->dev, sizeof(struct ov2640_priv), GFP_KERNEL); |
1100 | if (!priv) { | 1100 | if (!priv) { |
1101 | dev_err(&adapter->dev, | 1101 | dev_err(&adapter->dev, |
1102 | "Failed to allocate memory for private data!\n"); | 1102 | "Failed to allocate memory for private data!\n"); |
@@ -1110,20 +1110,14 @@ static int ov2640_probe(struct i2c_client *client, | |||
1110 | v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, | 1110 | v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, |
1111 | V4L2_CID_HFLIP, 0, 1, 1, 0); | 1111 | V4L2_CID_HFLIP, 0, 1, 1, 0); |
1112 | priv->subdev.ctrl_handler = &priv->hdl; | 1112 | priv->subdev.ctrl_handler = &priv->hdl; |
1113 | if (priv->hdl.error) { | 1113 | if (priv->hdl.error) |
1114 | int err = priv->hdl.error; | 1114 | return priv->hdl.error; |
1115 | |||
1116 | kfree(priv); | ||
1117 | return err; | ||
1118 | } | ||
1119 | 1115 | ||
1120 | ret = ov2640_video_probe(client); | 1116 | ret = ov2640_video_probe(client); |
1121 | if (ret) { | 1117 | if (ret) |
1122 | v4l2_ctrl_handler_free(&priv->hdl); | 1118 | v4l2_ctrl_handler_free(&priv->hdl); |
1123 | kfree(priv); | 1119 | else |
1124 | } else { | ||
1125 | dev_info(&adapter->dev, "OV2640 Probed\n"); | 1120 | dev_info(&adapter->dev, "OV2640 Probed\n"); |
1126 | } | ||
1127 | 1121 | ||
1128 | return ret; | 1122 | return ret; |
1129 | } | 1123 | } |
@@ -1134,7 +1128,6 @@ static int ov2640_remove(struct i2c_client *client) | |||
1134 | 1128 | ||
1135 | v4l2_device_unregister_subdev(&priv->subdev); | 1129 | v4l2_device_unregister_subdev(&priv->subdev); |
1136 | v4l2_ctrl_handler_free(&priv->hdl); | 1130 | v4l2_ctrl_handler_free(&priv->hdl); |
1137 | kfree(priv); | ||
1138 | return 0; | 1131 | return 0; |
1139 | } | 1132 | } |
1140 | 1133 | ||
diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index 8577e0cfb7fe..9d53309619d2 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c | |||
@@ -934,13 +934,13 @@ static int ov5642_g_mbus_config(struct v4l2_subdev *sd, | |||
934 | static int ov5642_s_power(struct v4l2_subdev *sd, int on) | 934 | static int ov5642_s_power(struct v4l2_subdev *sd, int on) |
935 | { | 935 | { |
936 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 936 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
937 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 937 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
938 | int ret; | 938 | int ret; |
939 | 939 | ||
940 | if (!on) | 940 | if (!on) |
941 | return soc_camera_power_off(&client->dev, icl); | 941 | return soc_camera_power_off(&client->dev, ssdd); |
942 | 942 | ||
943 | ret = soc_camera_power_on(&client->dev, icl); | 943 | ret = soc_camera_power_on(&client->dev, ssdd); |
944 | if (ret < 0) | 944 | if (ret < 0) |
945 | return ret; | 945 | return ret; |
946 | 946 | ||
@@ -1020,15 +1020,14 @@ static int ov5642_probe(struct i2c_client *client, | |||
1020 | const struct i2c_device_id *did) | 1020 | const struct i2c_device_id *did) |
1021 | { | 1021 | { |
1022 | struct ov5642 *priv; | 1022 | struct ov5642 *priv; |
1023 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1023 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1024 | int ret; | ||
1025 | 1024 | ||
1026 | if (!icl) { | 1025 | if (!ssdd) { |
1027 | dev_err(&client->dev, "OV5642: missing platform data!\n"); | 1026 | dev_err(&client->dev, "OV5642: missing platform data!\n"); |
1028 | return -EINVAL; | 1027 | return -EINVAL; |
1029 | } | 1028 | } |
1030 | 1029 | ||
1031 | priv = kzalloc(sizeof(struct ov5642), GFP_KERNEL); | 1030 | priv = devm_kzalloc(&client->dev, sizeof(struct ov5642), GFP_KERNEL); |
1032 | if (!priv) | 1031 | if (!priv) |
1033 | return -ENOMEM; | 1032 | return -ENOMEM; |
1034 | 1033 | ||
@@ -1043,25 +1042,15 @@ static int ov5642_probe(struct i2c_client *client, | |||
1043 | priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH; | 1042 | priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH; |
1044 | priv->total_height = BLANKING_MIN_HEIGHT; | 1043 | priv->total_height = BLANKING_MIN_HEIGHT; |
1045 | 1044 | ||
1046 | ret = ov5642_video_probe(client); | 1045 | return ov5642_video_probe(client); |
1047 | if (ret < 0) | ||
1048 | goto error; | ||
1049 | |||
1050 | return 0; | ||
1051 | |||
1052 | error: | ||
1053 | kfree(priv); | ||
1054 | return ret; | ||
1055 | } | 1046 | } |
1056 | 1047 | ||
1057 | static int ov5642_remove(struct i2c_client *client) | 1048 | static int ov5642_remove(struct i2c_client *client) |
1058 | { | 1049 | { |
1059 | struct ov5642 *priv = to_ov5642(client); | 1050 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1060 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
1061 | 1051 | ||
1062 | if (icl->free_bus) | 1052 | if (ssdd->free_bus) |
1063 | icl->free_bus(icl); | 1053 | ssdd->free_bus(ssdd); |
1064 | kfree(priv); | ||
1065 | 1054 | ||
1066 | return 0; | 1055 | return 0; |
1067 | } | 1056 | } |
diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index e87feb0881e3..dbe4f564e6b2 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c | |||
@@ -435,9 +435,9 @@ static int ov6650_set_register(struct v4l2_subdev *sd, | |||
435 | static int ov6650_s_power(struct v4l2_subdev *sd, int on) | 435 | static int ov6650_s_power(struct v4l2_subdev *sd, int on) |
436 | { | 436 | { |
437 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 437 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
438 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 438 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
439 | 439 | ||
440 | return soc_camera_set_power(&client->dev, icl, on); | 440 | return soc_camera_set_power(&client->dev, ssdd, on); |
441 | } | 441 | } |
442 | 442 | ||
443 | static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 443 | static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
@@ -892,7 +892,7 @@ static int ov6650_g_mbus_config(struct v4l2_subdev *sd, | |||
892 | struct v4l2_mbus_config *cfg) | 892 | struct v4l2_mbus_config *cfg) |
893 | { | 893 | { |
894 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 894 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
895 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 895 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
896 | 896 | ||
897 | cfg->flags = V4L2_MBUS_MASTER | | 897 | cfg->flags = V4L2_MBUS_MASTER | |
898 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | | 898 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | |
@@ -900,7 +900,7 @@ static int ov6650_g_mbus_config(struct v4l2_subdev *sd, | |||
900 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | | 900 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | |
901 | V4L2_MBUS_DATA_ACTIVE_HIGH; | 901 | V4L2_MBUS_DATA_ACTIVE_HIGH; |
902 | cfg->type = V4L2_MBUS_PARALLEL; | 902 | cfg->type = V4L2_MBUS_PARALLEL; |
903 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 903 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
904 | 904 | ||
905 | return 0; | 905 | return 0; |
906 | } | 906 | } |
@@ -910,8 +910,8 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, | |||
910 | const struct v4l2_mbus_config *cfg) | 910 | const struct v4l2_mbus_config *cfg) |
911 | { | 911 | { |
912 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 912 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
913 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 913 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
914 | unsigned long flags = soc_camera_apply_board_flags(icl, cfg); | 914 | unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg); |
915 | int ret; | 915 | int ret; |
916 | 916 | ||
917 | if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) | 917 | if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) |
@@ -963,15 +963,15 @@ static int ov6650_probe(struct i2c_client *client, | |||
963 | const struct i2c_device_id *did) | 963 | const struct i2c_device_id *did) |
964 | { | 964 | { |
965 | struct ov6650 *priv; | 965 | struct ov6650 *priv; |
966 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 966 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
967 | int ret; | 967 | int ret; |
968 | 968 | ||
969 | if (!icl) { | 969 | if (!ssdd) { |
970 | dev_err(&client->dev, "Missing platform_data for driver\n"); | 970 | dev_err(&client->dev, "Missing platform_data for driver\n"); |
971 | return -EINVAL; | 971 | return -EINVAL; |
972 | } | 972 | } |
973 | 973 | ||
974 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 974 | priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); |
975 | if (!priv) { | 975 | if (!priv) { |
976 | dev_err(&client->dev, | 976 | dev_err(&client->dev, |
977 | "Failed to allocate memory for private data!\n"); | 977 | "Failed to allocate memory for private data!\n"); |
@@ -1009,12 +1009,9 @@ static int ov6650_probe(struct i2c_client *client, | |||
1009 | V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); | 1009 | V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); |
1010 | 1010 | ||
1011 | priv->subdev.ctrl_handler = &priv->hdl; | 1011 | priv->subdev.ctrl_handler = &priv->hdl; |
1012 | if (priv->hdl.error) { | 1012 | if (priv->hdl.error) |
1013 | int err = priv->hdl.error; | 1013 | return priv->hdl.error; |
1014 | 1014 | ||
1015 | kfree(priv); | ||
1016 | return err; | ||
1017 | } | ||
1018 | v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); | 1015 | v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); |
1019 | v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); | 1016 | v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); |
1020 | v4l2_ctrl_auto_cluster(2, &priv->autoexposure, | 1017 | v4l2_ctrl_auto_cluster(2, &priv->autoexposure, |
@@ -1029,10 +1026,8 @@ static int ov6650_probe(struct i2c_client *client, | |||
1029 | priv->colorspace = V4L2_COLORSPACE_JPEG; | 1026 | priv->colorspace = V4L2_COLORSPACE_JPEG; |
1030 | 1027 | ||
1031 | ret = ov6650_video_probe(client); | 1028 | ret = ov6650_video_probe(client); |
1032 | if (ret) { | 1029 | if (ret) |
1033 | v4l2_ctrl_handler_free(&priv->hdl); | 1030 | v4l2_ctrl_handler_free(&priv->hdl); |
1034 | kfree(priv); | ||
1035 | } | ||
1036 | 1031 | ||
1037 | return ret; | 1032 | return ret; |
1038 | } | 1033 | } |
@@ -1043,7 +1038,6 @@ static int ov6650_remove(struct i2c_client *client) | |||
1043 | 1038 | ||
1044 | v4l2_device_unregister_subdev(&priv->subdev); | 1039 | v4l2_device_unregister_subdev(&priv->subdev); |
1045 | v4l2_ctrl_handler_free(&priv->hdl); | 1040 | v4l2_ctrl_handler_free(&priv->hdl); |
1046 | kfree(priv); | ||
1047 | return 0; | 1041 | return 0; |
1048 | } | 1042 | } |
1049 | 1043 | ||
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index e4a10751894d..fbeb5b2f3ae5 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c | |||
@@ -667,9 +667,9 @@ static int ov772x_s_register(struct v4l2_subdev *sd, | |||
667 | static int ov772x_s_power(struct v4l2_subdev *sd, int on) | 667 | static int ov772x_s_power(struct v4l2_subdev *sd, int on) |
668 | { | 668 | { |
669 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 669 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
670 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 670 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
671 | 671 | ||
672 | return soc_camera_set_power(&client->dev, icl, on); | 672 | return soc_camera_set_power(&client->dev, ssdd, on); |
673 | } | 673 | } |
674 | 674 | ||
675 | static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) | 675 | static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) |
@@ -1019,13 +1019,13 @@ static int ov772x_g_mbus_config(struct v4l2_subdev *sd, | |||
1019 | struct v4l2_mbus_config *cfg) | 1019 | struct v4l2_mbus_config *cfg) |
1020 | { | 1020 | { |
1021 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1021 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1022 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1022 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1023 | 1023 | ||
1024 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | 1024 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | |
1025 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | 1025 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
1026 | V4L2_MBUS_DATA_ACTIVE_HIGH; | 1026 | V4L2_MBUS_DATA_ACTIVE_HIGH; |
1027 | cfg->type = V4L2_MBUS_PARALLEL; | 1027 | cfg->type = V4L2_MBUS_PARALLEL; |
1028 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 1028 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
1029 | 1029 | ||
1030 | return 0; | 1030 | return 0; |
1031 | } | 1031 | } |
@@ -1054,11 +1054,11 @@ static int ov772x_probe(struct i2c_client *client, | |||
1054 | const struct i2c_device_id *did) | 1054 | const struct i2c_device_id *did) |
1055 | { | 1055 | { |
1056 | struct ov772x_priv *priv; | 1056 | struct ov772x_priv *priv; |
1057 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1057 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1058 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1058 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1059 | int ret; | 1059 | int ret; |
1060 | 1060 | ||
1061 | if (!icl || !icl->priv) { | 1061 | if (!ssdd || !ssdd->drv_priv) { |
1062 | dev_err(&client->dev, "OV772X: missing platform data!\n"); | 1062 | dev_err(&client->dev, "OV772X: missing platform data!\n"); |
1063 | return -EINVAL; | 1063 | return -EINVAL; |
1064 | } | 1064 | } |
@@ -1070,11 +1070,11 @@ static int ov772x_probe(struct i2c_client *client, | |||
1070 | return -EIO; | 1070 | return -EIO; |
1071 | } | 1071 | } |
1072 | 1072 | ||
1073 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 1073 | priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); |
1074 | if (!priv) | 1074 | if (!priv) |
1075 | return -ENOMEM; | 1075 | return -ENOMEM; |
1076 | 1076 | ||
1077 | priv->info = icl->priv; | 1077 | priv->info = ssdd->drv_priv; |
1078 | 1078 | ||
1079 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); | 1079 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); |
1080 | v4l2_ctrl_handler_init(&priv->hdl, 3); | 1080 | v4l2_ctrl_handler_init(&priv->hdl, 3); |
@@ -1085,22 +1085,15 @@ static int ov772x_probe(struct i2c_client *client, | |||
1085 | v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, | 1085 | v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, |
1086 | V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); | 1086 | V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); |
1087 | priv->subdev.ctrl_handler = &priv->hdl; | 1087 | priv->subdev.ctrl_handler = &priv->hdl; |
1088 | if (priv->hdl.error) { | 1088 | if (priv->hdl.error) |
1089 | ret = priv->hdl.error; | 1089 | return priv->hdl.error; |
1090 | goto done; | ||
1091 | } | ||
1092 | 1090 | ||
1093 | ret = ov772x_video_probe(priv); | 1091 | ret = ov772x_video_probe(priv); |
1094 | if (ret < 0) | 1092 | if (ret < 0) { |
1095 | goto done; | ||
1096 | |||
1097 | priv->cfmt = &ov772x_cfmts[0]; | ||
1098 | priv->win = &ov772x_win_sizes[0]; | ||
1099 | |||
1100 | done: | ||
1101 | if (ret) { | ||
1102 | v4l2_ctrl_handler_free(&priv->hdl); | 1093 | v4l2_ctrl_handler_free(&priv->hdl); |
1103 | kfree(priv); | 1094 | } else { |
1095 | priv->cfmt = &ov772x_cfmts[0]; | ||
1096 | priv->win = &ov772x_win_sizes[0]; | ||
1104 | } | 1097 | } |
1105 | return ret; | 1098 | return ret; |
1106 | } | 1099 | } |
@@ -1111,7 +1104,6 @@ static int ov772x_remove(struct i2c_client *client) | |||
1111 | 1104 | ||
1112 | v4l2_device_unregister_subdev(&priv->subdev); | 1105 | v4l2_device_unregister_subdev(&priv->subdev); |
1113 | v4l2_ctrl_handler_free(&priv->hdl); | 1106 | v4l2_ctrl_handler_free(&priv->hdl); |
1114 | kfree(priv); | ||
1115 | return 0; | 1107 | return 0; |
1116 | } | 1108 | } |
1117 | 1109 | ||
diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index b323684eaf77..05993041be31 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c | |||
@@ -336,9 +336,9 @@ static int ov9640_set_register(struct v4l2_subdev *sd, | |||
336 | static int ov9640_s_power(struct v4l2_subdev *sd, int on) | 336 | static int ov9640_s_power(struct v4l2_subdev *sd, int on) |
337 | { | 337 | { |
338 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 338 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
339 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 339 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
340 | 340 | ||
341 | return soc_camera_set_power(&client->dev, icl, on); | 341 | return soc_camera_set_power(&client->dev, ssdd, on); |
342 | } | 342 | } |
343 | 343 | ||
344 | /* select nearest higher resolution for capture */ | 344 | /* select nearest higher resolution for capture */ |
@@ -657,13 +657,13 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd, | |||
657 | struct v4l2_mbus_config *cfg) | 657 | struct v4l2_mbus_config *cfg) |
658 | { | 658 | { |
659 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 659 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
660 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 660 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
661 | 661 | ||
662 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | 662 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | |
663 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | 663 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
664 | V4L2_MBUS_DATA_ACTIVE_HIGH; | 664 | V4L2_MBUS_DATA_ACTIVE_HIGH; |
665 | cfg->type = V4L2_MBUS_PARALLEL; | 665 | cfg->type = V4L2_MBUS_PARALLEL; |
666 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 666 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
667 | 667 | ||
668 | return 0; | 668 | return 0; |
669 | } | 669 | } |
@@ -690,15 +690,15 @@ static int ov9640_probe(struct i2c_client *client, | |||
690 | const struct i2c_device_id *did) | 690 | const struct i2c_device_id *did) |
691 | { | 691 | { |
692 | struct ov9640_priv *priv; | 692 | struct ov9640_priv *priv; |
693 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 693 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
694 | int ret; | 694 | int ret; |
695 | 695 | ||
696 | if (!icl) { | 696 | if (!ssdd) { |
697 | dev_err(&client->dev, "Missing platform_data for driver\n"); | 697 | dev_err(&client->dev, "Missing platform_data for driver\n"); |
698 | return -EINVAL; | 698 | return -EINVAL; |
699 | } | 699 | } |
700 | 700 | ||
701 | priv = kzalloc(sizeof(struct ov9640_priv), GFP_KERNEL); | 701 | priv = devm_kzalloc(&client->dev, sizeof(struct ov9640_priv), GFP_KERNEL); |
702 | if (!priv) { | 702 | if (!priv) { |
703 | dev_err(&client->dev, | 703 | dev_err(&client->dev, |
704 | "Failed to allocate memory for private data!\n"); | 704 | "Failed to allocate memory for private data!\n"); |
@@ -713,19 +713,13 @@ static int ov9640_probe(struct i2c_client *client, | |||
713 | v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, | 713 | v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, |
714 | V4L2_CID_HFLIP, 0, 1, 1, 0); | 714 | V4L2_CID_HFLIP, 0, 1, 1, 0); |
715 | priv->subdev.ctrl_handler = &priv->hdl; | 715 | priv->subdev.ctrl_handler = &priv->hdl; |
716 | if (priv->hdl.error) { | 716 | if (priv->hdl.error) |
717 | int err = priv->hdl.error; | 717 | return priv->hdl.error; |
718 | |||
719 | kfree(priv); | ||
720 | return err; | ||
721 | } | ||
722 | 718 | ||
723 | ret = ov9640_video_probe(client); | 719 | ret = ov9640_video_probe(client); |
724 | 720 | ||
725 | if (ret) { | 721 | if (ret) |
726 | v4l2_ctrl_handler_free(&priv->hdl); | 722 | v4l2_ctrl_handler_free(&priv->hdl); |
727 | kfree(priv); | ||
728 | } | ||
729 | 723 | ||
730 | return ret; | 724 | return ret; |
731 | } | 725 | } |
@@ -737,7 +731,6 @@ static int ov9640_remove(struct i2c_client *client) | |||
737 | 731 | ||
738 | v4l2_device_unregister_subdev(&priv->subdev); | 732 | v4l2_device_unregister_subdev(&priv->subdev); |
739 | v4l2_ctrl_handler_free(&priv->hdl); | 733 | v4l2_ctrl_handler_free(&priv->hdl); |
740 | kfree(priv); | ||
741 | return 0; | 734 | return 0; |
742 | } | 735 | } |
743 | 736 | ||
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index 7a55889e397b..2f236da80165 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c | |||
@@ -787,12 +787,12 @@ static int ov9740_g_chip_ident(struct v4l2_subdev *sd, | |||
787 | static int ov9740_s_power(struct v4l2_subdev *sd, int on) | 787 | static int ov9740_s_power(struct v4l2_subdev *sd, int on) |
788 | { | 788 | { |
789 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 789 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
790 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 790 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
791 | struct ov9740_priv *priv = to_ov9740(sd); | 791 | struct ov9740_priv *priv = to_ov9740(sd); |
792 | int ret; | 792 | int ret; |
793 | 793 | ||
794 | if (on) { | 794 | if (on) { |
795 | ret = soc_camera_power_on(&client->dev, icl); | 795 | ret = soc_camera_power_on(&client->dev, ssdd); |
796 | if (ret < 0) | 796 | if (ret < 0) |
797 | return ret; | 797 | return ret; |
798 | 798 | ||
@@ -806,7 +806,7 @@ static int ov9740_s_power(struct v4l2_subdev *sd, int on) | |||
806 | priv->current_enable = true; | 806 | priv->current_enable = true; |
807 | } | 807 | } |
808 | 808 | ||
809 | soc_camera_power_off(&client->dev, icl); | 809 | soc_camera_power_off(&client->dev, ssdd); |
810 | } | 810 | } |
811 | 811 | ||
812 | return 0; | 812 | return 0; |
@@ -905,13 +905,13 @@ static int ov9740_g_mbus_config(struct v4l2_subdev *sd, | |||
905 | struct v4l2_mbus_config *cfg) | 905 | struct v4l2_mbus_config *cfg) |
906 | { | 906 | { |
907 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 907 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
908 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 908 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
909 | 909 | ||
910 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | 910 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | |
911 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | 911 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
912 | V4L2_MBUS_DATA_ACTIVE_HIGH; | 912 | V4L2_MBUS_DATA_ACTIVE_HIGH; |
913 | cfg->type = V4L2_MBUS_PARALLEL; | 913 | cfg->type = V4L2_MBUS_PARALLEL; |
914 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 914 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
915 | 915 | ||
916 | return 0; | 916 | return 0; |
917 | } | 917 | } |
@@ -951,15 +951,15 @@ static int ov9740_probe(struct i2c_client *client, | |||
951 | const struct i2c_device_id *did) | 951 | const struct i2c_device_id *did) |
952 | { | 952 | { |
953 | struct ov9740_priv *priv; | 953 | struct ov9740_priv *priv; |
954 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 954 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
955 | int ret; | 955 | int ret; |
956 | 956 | ||
957 | if (!icl) { | 957 | if (!ssdd) { |
958 | dev_err(&client->dev, "Missing platform_data for driver\n"); | 958 | dev_err(&client->dev, "Missing platform_data for driver\n"); |
959 | return -EINVAL; | 959 | return -EINVAL; |
960 | } | 960 | } |
961 | 961 | ||
962 | priv = kzalloc(sizeof(struct ov9740_priv), GFP_KERNEL); | 962 | priv = devm_kzalloc(&client->dev, sizeof(struct ov9740_priv), GFP_KERNEL); |
963 | if (!priv) { | 963 | if (!priv) { |
964 | dev_err(&client->dev, "Failed to allocate private data!\n"); | 964 | dev_err(&client->dev, "Failed to allocate private data!\n"); |
965 | return -ENOMEM; | 965 | return -ENOMEM; |
@@ -972,18 +972,12 @@ static int ov9740_probe(struct i2c_client *client, | |||
972 | v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, | 972 | v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, |
973 | V4L2_CID_HFLIP, 0, 1, 1, 0); | 973 | V4L2_CID_HFLIP, 0, 1, 1, 0); |
974 | priv->subdev.ctrl_handler = &priv->hdl; | 974 | priv->subdev.ctrl_handler = &priv->hdl; |
975 | if (priv->hdl.error) { | 975 | if (priv->hdl.error) |
976 | int err = priv->hdl.error; | 976 | return priv->hdl.error; |
977 | |||
978 | kfree(priv); | ||
979 | return err; | ||
980 | } | ||
981 | 977 | ||
982 | ret = ov9740_video_probe(client); | 978 | ret = ov9740_video_probe(client); |
983 | if (ret < 0) { | 979 | if (ret < 0) |
984 | v4l2_ctrl_handler_free(&priv->hdl); | 980 | v4l2_ctrl_handler_free(&priv->hdl); |
985 | kfree(priv); | ||
986 | } | ||
987 | 981 | ||
988 | return ret; | 982 | return ret; |
989 | } | 983 | } |
@@ -994,7 +988,6 @@ static int ov9740_remove(struct i2c_client *client) | |||
994 | 988 | ||
995 | v4l2_device_unregister_subdev(&priv->subdev); | 989 | v4l2_device_unregister_subdev(&priv->subdev); |
996 | v4l2_ctrl_handler_free(&priv->hdl); | 990 | v4l2_ctrl_handler_free(&priv->hdl); |
997 | kfree(priv); | ||
998 | return 0; | 991 | return 0; |
999 | } | 992 | } |
1000 | 993 | ||
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index 02f0400051d9..5c92679bfefb 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c | |||
@@ -1183,9 +1183,9 @@ static int rj54n1_s_register(struct v4l2_subdev *sd, | |||
1183 | static int rj54n1_s_power(struct v4l2_subdev *sd, int on) | 1183 | static int rj54n1_s_power(struct v4l2_subdev *sd, int on) |
1184 | { | 1184 | { |
1185 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1185 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1186 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1186 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1187 | 1187 | ||
1188 | return soc_camera_set_power(&client->dev, icl, on); | 1188 | return soc_camera_set_power(&client->dev, ssdd, on); |
1189 | } | 1189 | } |
1190 | 1190 | ||
1191 | static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl) | 1191 | static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl) |
@@ -1245,14 +1245,14 @@ static int rj54n1_g_mbus_config(struct v4l2_subdev *sd, | |||
1245 | struct v4l2_mbus_config *cfg) | 1245 | struct v4l2_mbus_config *cfg) |
1246 | { | 1246 | { |
1247 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1247 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1248 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1248 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1249 | 1249 | ||
1250 | cfg->flags = | 1250 | cfg->flags = |
1251 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | | 1251 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | |
1252 | V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH | | 1252 | V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH | |
1253 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH; | 1253 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
1254 | cfg->type = V4L2_MBUS_PARALLEL; | 1254 | cfg->type = V4L2_MBUS_PARALLEL; |
1255 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 1255 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
1256 | 1256 | ||
1257 | return 0; | 1257 | return 0; |
1258 | } | 1258 | } |
@@ -1261,10 +1261,10 @@ static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, | |||
1261 | const struct v4l2_mbus_config *cfg) | 1261 | const struct v4l2_mbus_config *cfg) |
1262 | { | 1262 | { |
1263 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1263 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1264 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1264 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1265 | 1265 | ||
1266 | /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ | 1266 | /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ |
1267 | if (soc_camera_apply_board_flags(icl, cfg) & | 1267 | if (soc_camera_apply_board_flags(ssdd, cfg) & |
1268 | V4L2_MBUS_PCLK_SAMPLE_RISING) | 1268 | V4L2_MBUS_PCLK_SAMPLE_RISING) |
1269 | return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4); | 1269 | return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4); |
1270 | else | 1270 | else |
@@ -1334,17 +1334,17 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1334 | const struct i2c_device_id *did) | 1334 | const struct i2c_device_id *did) |
1335 | { | 1335 | { |
1336 | struct rj54n1 *rj54n1; | 1336 | struct rj54n1 *rj54n1; |
1337 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1337 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1338 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1338 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1339 | struct rj54n1_pdata *rj54n1_priv; | 1339 | struct rj54n1_pdata *rj54n1_priv; |
1340 | int ret; | 1340 | int ret; |
1341 | 1341 | ||
1342 | if (!icl || !icl->priv) { | 1342 | if (!ssdd || !ssdd->drv_priv) { |
1343 | dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); | 1343 | dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); |
1344 | return -EINVAL; | 1344 | return -EINVAL; |
1345 | } | 1345 | } |
1346 | 1346 | ||
1347 | rj54n1_priv = icl->priv; | 1347 | rj54n1_priv = ssdd->drv_priv; |
1348 | 1348 | ||
1349 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 1349 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
1350 | dev_warn(&adapter->dev, | 1350 | dev_warn(&adapter->dev, |
@@ -1352,7 +1352,7 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1352 | return -EIO; | 1352 | return -EIO; |
1353 | } | 1353 | } |
1354 | 1354 | ||
1355 | rj54n1 = kzalloc(sizeof(struct rj54n1), GFP_KERNEL); | 1355 | rj54n1 = devm_kzalloc(&client->dev, sizeof(struct rj54n1), GFP_KERNEL); |
1356 | if (!rj54n1) | 1356 | if (!rj54n1) |
1357 | return -ENOMEM; | 1357 | return -ENOMEM; |
1358 | 1358 | ||
@@ -1367,12 +1367,8 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1367 | v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, | 1367 | v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, |
1368 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | 1368 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); |
1369 | rj54n1->subdev.ctrl_handler = &rj54n1->hdl; | 1369 | rj54n1->subdev.ctrl_handler = &rj54n1->hdl; |
1370 | if (rj54n1->hdl.error) { | 1370 | if (rj54n1->hdl.error) |
1371 | int err = rj54n1->hdl.error; | 1371 | return rj54n1->hdl.error; |
1372 | |||
1373 | kfree(rj54n1); | ||
1374 | return err; | ||
1375 | } | ||
1376 | 1372 | ||
1377 | rj54n1->clk_div = clk_div; | 1373 | rj54n1->clk_div = clk_div; |
1378 | rj54n1->rect.left = RJ54N1_COLUMN_SKIP; | 1374 | rj54n1->rect.left = RJ54N1_COLUMN_SKIP; |
@@ -1387,10 +1383,8 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1387 | (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); | 1383 | (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); |
1388 | 1384 | ||
1389 | ret = rj54n1_video_probe(client, rj54n1_priv); | 1385 | ret = rj54n1_video_probe(client, rj54n1_priv); |
1390 | if (ret < 0) { | 1386 | if (ret < 0) |
1391 | v4l2_ctrl_handler_free(&rj54n1->hdl); | 1387 | v4l2_ctrl_handler_free(&rj54n1->hdl); |
1392 | kfree(rj54n1); | ||
1393 | } | ||
1394 | 1388 | ||
1395 | return ret; | 1389 | return ret; |
1396 | } | 1390 | } |
@@ -1398,13 +1392,12 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1398 | static int rj54n1_remove(struct i2c_client *client) | 1392 | static int rj54n1_remove(struct i2c_client *client) |
1399 | { | 1393 | { |
1400 | struct rj54n1 *rj54n1 = to_rj54n1(client); | 1394 | struct rj54n1 *rj54n1 = to_rj54n1(client); |
1401 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 1395 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
1402 | 1396 | ||
1403 | v4l2_device_unregister_subdev(&rj54n1->subdev); | 1397 | v4l2_device_unregister_subdev(&rj54n1->subdev); |
1404 | if (icl->free_bus) | 1398 | if (ssdd->free_bus) |
1405 | icl->free_bus(icl); | 1399 | ssdd->free_bus(ssdd); |
1406 | v4l2_ctrl_handler_free(&rj54n1->hdl); | 1400 | v4l2_ctrl_handler_free(&rj54n1->hdl); |
1407 | kfree(rj54n1); | ||
1408 | 1401 | ||
1409 | return 0; | 1402 | return 0; |
1410 | } | 1403 | } |
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index 140716e71a15..7d2074601881 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c | |||
@@ -569,9 +569,9 @@ static int tw9910_s_register(struct v4l2_subdev *sd, | |||
569 | static int tw9910_s_power(struct v4l2_subdev *sd, int on) | 569 | static int tw9910_s_power(struct v4l2_subdev *sd, int on) |
570 | { | 570 | { |
571 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 571 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
572 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 572 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
573 | 573 | ||
574 | return soc_camera_set_power(&client->dev, icl, on); | 574 | return soc_camera_set_power(&client->dev, ssdd, on); |
575 | } | 575 | } |
576 | 576 | ||
577 | static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) | 577 | static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) |
@@ -847,14 +847,14 @@ static int tw9910_g_mbus_config(struct v4l2_subdev *sd, | |||
847 | struct v4l2_mbus_config *cfg) | 847 | struct v4l2_mbus_config *cfg) |
848 | { | 848 | { |
849 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 849 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
850 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 850 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
851 | 851 | ||
852 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | 852 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | |
853 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | | 853 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | |
854 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | | 854 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | |
855 | V4L2_MBUS_DATA_ACTIVE_HIGH; | 855 | V4L2_MBUS_DATA_ACTIVE_HIGH; |
856 | cfg->type = V4L2_MBUS_PARALLEL; | 856 | cfg->type = V4L2_MBUS_PARALLEL; |
857 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | 857 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); |
858 | 858 | ||
859 | return 0; | 859 | return 0; |
860 | } | 860 | } |
@@ -863,9 +863,9 @@ static int tw9910_s_mbus_config(struct v4l2_subdev *sd, | |||
863 | const struct v4l2_mbus_config *cfg) | 863 | const struct v4l2_mbus_config *cfg) |
864 | { | 864 | { |
865 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 865 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
866 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 866 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
867 | u8 val = VSSL_VVALID | HSSL_DVALID; | 867 | u8 val = VSSL_VVALID | HSSL_DVALID; |
868 | unsigned long flags = soc_camera_apply_board_flags(icl, cfg); | 868 | unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg); |
869 | 869 | ||
870 | /* | 870 | /* |
871 | * set OUTCTR1 | 871 | * set OUTCTR1 |
@@ -911,15 +911,14 @@ static int tw9910_probe(struct i2c_client *client, | |||
911 | struct tw9910_video_info *info; | 911 | struct tw9910_video_info *info; |
912 | struct i2c_adapter *adapter = | 912 | struct i2c_adapter *adapter = |
913 | to_i2c_adapter(client->dev.parent); | 913 | to_i2c_adapter(client->dev.parent); |
914 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | 914 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); |
915 | int ret; | ||
916 | 915 | ||
917 | if (!icl || !icl->priv) { | 916 | if (!ssdd || !ssdd->drv_priv) { |
918 | dev_err(&client->dev, "TW9910: missing platform data!\n"); | 917 | dev_err(&client->dev, "TW9910: missing platform data!\n"); |
919 | return -EINVAL; | 918 | return -EINVAL; |
920 | } | 919 | } |
921 | 920 | ||
922 | info = icl->priv; | 921 | info = ssdd->drv_priv; |
923 | 922 | ||
924 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 923 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
925 | dev_err(&client->dev, | 924 | dev_err(&client->dev, |
@@ -928,7 +927,7 @@ static int tw9910_probe(struct i2c_client *client, | |||
928 | return -EIO; | 927 | return -EIO; |
929 | } | 928 | } |
930 | 929 | ||
931 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 930 | priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); |
932 | if (!priv) | 931 | if (!priv) |
933 | return -ENOMEM; | 932 | return -ENOMEM; |
934 | 933 | ||
@@ -936,18 +935,11 @@ static int tw9910_probe(struct i2c_client *client, | |||
936 | 935 | ||
937 | v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); | 936 | v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); |
938 | 937 | ||
939 | ret = tw9910_video_probe(client); | 938 | return tw9910_video_probe(client); |
940 | if (ret) | ||
941 | kfree(priv); | ||
942 | |||
943 | return ret; | ||
944 | } | 939 | } |
945 | 940 | ||
946 | static int tw9910_remove(struct i2c_client *client) | 941 | static int tw9910_remove(struct i2c_client *client) |
947 | { | 942 | { |
948 | struct tw9910_priv *priv = to_tw9910(client); | ||
949 | |||
950 | kfree(priv); | ||
951 | return 0; | 943 | return 0; |
952 | } | 944 | } |
953 | 945 | ||
diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index c31cc04fffd2..e747524ba6ed 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c | |||
@@ -175,7 +175,7 @@ static int ths7303_probe(struct i2c_client *client, | |||
175 | v4l_info(client, "chip found @ 0x%x (%s)\n", | 175 | v4l_info(client, "chip found @ 0x%x (%s)\n", |
176 | client->addr << 1, client->adapter->name); | 176 | client->addr << 1, client->adapter->name); |
177 | 177 | ||
178 | sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); | 178 | sd = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev), GFP_KERNEL); |
179 | if (sd == NULL) | 179 | if (sd == NULL) |
180 | return -ENOMEM; | 180 | return -ENOMEM; |
181 | 181 | ||
@@ -189,7 +189,6 @@ static int ths7303_remove(struct i2c_client *client) | |||
189 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 189 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
190 | 190 | ||
191 | v4l2_device_unregister_subdev(sd); | 191 | v4l2_device_unregister_subdev(sd); |
192 | kfree(sd); | ||
193 | 192 | ||
194 | return 0; | 193 | return 0; |
195 | } | 194 | } |
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 3b24d3fc1866..e3b33b78dd21 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <media/tvaudio.h> | 39 | #include <media/tvaudio.h> |
40 | #include <media/v4l2-device.h> | 40 | #include <media/v4l2-device.h> |
41 | #include <media/v4l2-chip-ident.h> | 41 | #include <media/v4l2-chip-ident.h> |
42 | #include <media/v4l2-ctrls.h> | ||
42 | 43 | ||
43 | #include <media/i2c-addr.h> | 44 | #include <media/i2c-addr.h> |
44 | 45 | ||
@@ -91,13 +92,13 @@ struct CHIPDESC { | |||
91 | audiocmd init; | 92 | audiocmd init; |
92 | 93 | ||
93 | /* which register has which value */ | 94 | /* which register has which value */ |
94 | int leftreg,rightreg,treblereg,bassreg; | 95 | int leftreg, rightreg, treblereg, bassreg; |
95 | 96 | ||
96 | /* initialize with (defaults to 65535/65535/32768/32768 */ | 97 | /* initialize with (defaults to 65535/32768/32768 */ |
97 | int leftinit,rightinit,trebleinit,bassinit; | 98 | int volinit, trebleinit, bassinit; |
98 | 99 | ||
99 | /* functions to convert the values (v4l -> chip) */ | 100 | /* functions to convert the values (v4l -> chip) */ |
100 | getvalue volfunc,treblefunc,bassfunc; | 101 | getvalue volfunc, treblefunc, bassfunc; |
101 | 102 | ||
102 | /* get/set mode */ | 103 | /* get/set mode */ |
103 | getrxsubchans getrxsubchans; | 104 | getrxsubchans getrxsubchans; |
@@ -113,6 +114,12 @@ struct CHIPDESC { | |||
113 | /* current state of the chip */ | 114 | /* current state of the chip */ |
114 | struct CHIPSTATE { | 115 | struct CHIPSTATE { |
115 | struct v4l2_subdev sd; | 116 | struct v4l2_subdev sd; |
117 | struct v4l2_ctrl_handler hdl; | ||
118 | struct { | ||
119 | /* volume/balance cluster */ | ||
120 | struct v4l2_ctrl *volume; | ||
121 | struct v4l2_ctrl *balance; | ||
122 | }; | ||
116 | 123 | ||
117 | /* chip-specific description - should point to | 124 | /* chip-specific description - should point to |
118 | an entry at CHIPDESC table */ | 125 | an entry at CHIPDESC table */ |
@@ -122,7 +129,7 @@ struct CHIPSTATE { | |||
122 | audiocmd shadow; | 129 | audiocmd shadow; |
123 | 130 | ||
124 | /* current settings */ | 131 | /* current settings */ |
125 | __u16 left, right, treble, bass, muted; | 132 | u16 muted; |
126 | int prevmode; | 133 | int prevmode; |
127 | int radio; | 134 | int radio; |
128 | int input; | 135 | int input; |
@@ -138,6 +145,11 @@ static inline struct CHIPSTATE *to_state(struct v4l2_subdev *sd) | |||
138 | return container_of(sd, struct CHIPSTATE, sd); | 145 | return container_of(sd, struct CHIPSTATE, sd); |
139 | } | 146 | } |
140 | 147 | ||
148 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
149 | { | ||
150 | return &container_of(ctrl->handler, struct CHIPSTATE, hdl)->sd; | ||
151 | } | ||
152 | |||
141 | 153 | ||
142 | /* ---------------------------------------------------------------------- */ | 154 | /* ---------------------------------------------------------------------- */ |
143 | /* i2c I/O functions */ | 155 | /* i2c I/O functions */ |
@@ -1523,8 +1535,7 @@ static struct CHIPDESC chiplist[] = { | |||
1523 | .rightreg = TDA9875_MVR, | 1535 | .rightreg = TDA9875_MVR, |
1524 | .bassreg = TDA9875_MBA, | 1536 | .bassreg = TDA9875_MBA, |
1525 | .treblereg = TDA9875_MTR, | 1537 | .treblereg = TDA9875_MTR, |
1526 | .leftinit = 58880, | 1538 | .volinit = 58880, |
1527 | .rightinit = 58880, | ||
1528 | }, | 1539 | }, |
1529 | { | 1540 | { |
1530 | .name = "tda9850", | 1541 | .name = "tda9850", |
@@ -1618,7 +1629,8 @@ static struct CHIPDESC chiplist[] = { | |||
1618 | 1629 | ||
1619 | .inputreg = -1, | 1630 | .inputreg = -1, |
1620 | .inputmap = { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC }, | 1631 | .inputmap = { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC }, |
1621 | .inputmute = TEA6300_S_GMU, | 1632 | .inputmute = TEA6420_S_GMU, |
1633 | .inputmask = 0x07, | ||
1622 | }, | 1634 | }, |
1623 | { | 1635 | { |
1624 | .name = "tda8425", | 1636 | .name = "tda8425", |
@@ -1679,121 +1691,39 @@ static struct CHIPDESC chiplist[] = { | |||
1679 | 1691 | ||
1680 | /* ---------------------------------------------------------------------- */ | 1692 | /* ---------------------------------------------------------------------- */ |
1681 | 1693 | ||
1682 | static int tvaudio_g_ctrl(struct v4l2_subdev *sd, | 1694 | static int tvaudio_s_ctrl(struct v4l2_ctrl *ctrl) |
1683 | struct v4l2_control *ctrl) | ||
1684 | { | 1695 | { |
1696 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
1685 | struct CHIPSTATE *chip = to_state(sd); | 1697 | struct CHIPSTATE *chip = to_state(sd); |
1686 | struct CHIPDESC *desc = chip->desc; | 1698 | struct CHIPDESC *desc = chip->desc; |
1687 | 1699 | ||
1688 | switch (ctrl->id) { | 1700 | switch (ctrl->id) { |
1689 | case V4L2_CID_AUDIO_MUTE: | 1701 | case V4L2_CID_AUDIO_MUTE: |
1690 | if (!(desc->flags & CHIP_HAS_INPUTSEL)) | 1702 | chip->muted = ctrl->val; |
1691 | break; | ||
1692 | ctrl->value=chip->muted; | ||
1693 | return 0; | ||
1694 | case V4L2_CID_AUDIO_VOLUME: | ||
1695 | if (!(desc->flags & CHIP_HAS_VOLUME)) | ||
1696 | break; | ||
1697 | ctrl->value = max(chip->left,chip->right); | ||
1698 | return 0; | ||
1699 | case V4L2_CID_AUDIO_BALANCE: | ||
1700 | { | ||
1701 | int volume; | ||
1702 | if (!(desc->flags & CHIP_HAS_VOLUME)) | ||
1703 | break; | ||
1704 | volume = max(chip->left,chip->right); | ||
1705 | if (volume) | ||
1706 | ctrl->value=(32768*min(chip->left,chip->right))/volume; | ||
1707 | else | ||
1708 | ctrl->value=32768; | ||
1709 | return 0; | ||
1710 | } | ||
1711 | case V4L2_CID_AUDIO_BASS: | ||
1712 | if (!(desc->flags & CHIP_HAS_BASSTREBLE)) | ||
1713 | break; | ||
1714 | ctrl->value = chip->bass; | ||
1715 | return 0; | ||
1716 | case V4L2_CID_AUDIO_TREBLE: | ||
1717 | if (!(desc->flags & CHIP_HAS_BASSTREBLE)) | ||
1718 | break; | ||
1719 | ctrl->value = chip->treble; | ||
1720 | return 0; | ||
1721 | } | ||
1722 | return -EINVAL; | ||
1723 | } | ||
1724 | |||
1725 | static int tvaudio_s_ctrl(struct v4l2_subdev *sd, | ||
1726 | struct v4l2_control *ctrl) | ||
1727 | { | ||
1728 | struct CHIPSTATE *chip = to_state(sd); | ||
1729 | struct CHIPDESC *desc = chip->desc; | ||
1730 | |||
1731 | switch (ctrl->id) { | ||
1732 | case V4L2_CID_AUDIO_MUTE: | ||
1733 | if (!(desc->flags & CHIP_HAS_INPUTSEL)) | ||
1734 | break; | ||
1735 | |||
1736 | if (ctrl->value < 0 || ctrl->value >= 2) | ||
1737 | return -ERANGE; | ||
1738 | chip->muted = ctrl->value; | ||
1739 | if (chip->muted) | 1703 | if (chip->muted) |
1740 | chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask); | 1704 | chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask); |
1741 | else | 1705 | else |
1742 | chip_write_masked(chip,desc->inputreg, | 1706 | chip_write_masked(chip,desc->inputreg, |
1743 | desc->inputmap[chip->input],desc->inputmask); | 1707 | desc->inputmap[chip->input],desc->inputmask); |
1744 | return 0; | 1708 | return 0; |
1745 | case V4L2_CID_AUDIO_VOLUME: | 1709 | case V4L2_CID_AUDIO_VOLUME: { |
1746 | { | 1710 | u32 volume, balance; |
1747 | int volume,balance; | 1711 | u32 left, right; |
1748 | |||
1749 | if (!(desc->flags & CHIP_HAS_VOLUME)) | ||
1750 | break; | ||
1751 | |||
1752 | volume = max(chip->left,chip->right); | ||
1753 | if (volume) | ||
1754 | balance=(32768*min(chip->left,chip->right))/volume; | ||
1755 | else | ||
1756 | balance=32768; | ||
1757 | |||
1758 | volume=ctrl->value; | ||
1759 | chip->left = (min(65536 - balance,32768) * volume) / 32768; | ||
1760 | chip->right = (min(balance,volume *(__u16)32768)) / 32768; | ||
1761 | |||
1762 | chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); | ||
1763 | chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); | ||
1764 | |||
1765 | return 0; | ||
1766 | } | ||
1767 | case V4L2_CID_AUDIO_BALANCE: | ||
1768 | { | ||
1769 | int volume, balance; | ||
1770 | |||
1771 | if (!(desc->flags & CHIP_HAS_VOLUME)) | ||
1772 | break; | ||
1773 | |||
1774 | volume = max(chip->left, chip->right); | ||
1775 | balance = ctrl->value; | ||
1776 | chip->left = (min(65536 - balance, 32768) * volume) / 32768; | ||
1777 | chip->right = (min(balance, volume * (__u16)32768)) / 32768; | ||
1778 | 1712 | ||
1779 | chip_write(chip, desc->leftreg, desc->volfunc(chip->left)); | 1713 | volume = chip->volume->val; |
1780 | chip_write(chip, desc->rightreg, desc->volfunc(chip->right)); | 1714 | balance = chip->balance->val; |
1715 | left = (min(65536U - balance, 32768U) * volume) / 32768U; | ||
1716 | right = (min(balance, 32768U) * volume) / 32768U; | ||
1781 | 1717 | ||
1718 | chip_write(chip, desc->leftreg, desc->volfunc(left)); | ||
1719 | chip_write(chip, desc->rightreg, desc->volfunc(right)); | ||
1782 | return 0; | 1720 | return 0; |
1783 | } | 1721 | } |
1784 | case V4L2_CID_AUDIO_BASS: | 1722 | case V4L2_CID_AUDIO_BASS: |
1785 | if (!(desc->flags & CHIP_HAS_BASSTREBLE)) | 1723 | chip_write(chip, desc->bassreg, desc->bassfunc(ctrl->val)); |
1786 | break; | ||
1787 | chip->bass = ctrl->value; | ||
1788 | chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); | ||
1789 | |||
1790 | return 0; | 1724 | return 0; |
1791 | case V4L2_CID_AUDIO_TREBLE: | 1725 | case V4L2_CID_AUDIO_TREBLE: |
1792 | if (!(desc->flags & CHIP_HAS_BASSTREBLE)) | 1726 | chip_write(chip, desc->treblereg, desc->treblefunc(ctrl->val)); |
1793 | break; | ||
1794 | chip->treble = ctrl->value; | ||
1795 | chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); | ||
1796 | |||
1797 | return 0; | 1727 | return 0; |
1798 | } | 1728 | } |
1799 | return -EINVAL; | 1729 | return -EINVAL; |
@@ -1812,35 +1742,6 @@ static int tvaudio_s_radio(struct v4l2_subdev *sd) | |||
1812 | return 0; | 1742 | return 0; |
1813 | } | 1743 | } |
1814 | 1744 | ||
1815 | static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | ||
1816 | { | ||
1817 | struct CHIPSTATE *chip = to_state(sd); | ||
1818 | struct CHIPDESC *desc = chip->desc; | ||
1819 | |||
1820 | switch (qc->id) { | ||
1821 | case V4L2_CID_AUDIO_MUTE: | ||
1822 | if (desc->flags & CHIP_HAS_INPUTSEL) | ||
1823 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | ||
1824 | break; | ||
1825 | case V4L2_CID_AUDIO_VOLUME: | ||
1826 | if (desc->flags & CHIP_HAS_VOLUME) | ||
1827 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); | ||
1828 | break; | ||
1829 | case V4L2_CID_AUDIO_BALANCE: | ||
1830 | if (desc->flags & CHIP_HAS_VOLUME) | ||
1831 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); | ||
1832 | break; | ||
1833 | case V4L2_CID_AUDIO_BASS: | ||
1834 | case V4L2_CID_AUDIO_TREBLE: | ||
1835 | if (desc->flags & CHIP_HAS_BASSTREBLE) | ||
1836 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); | ||
1837 | break; | ||
1838 | default: | ||
1839 | break; | ||
1840 | } | ||
1841 | return -EINVAL; | ||
1842 | } | ||
1843 | |||
1844 | static int tvaudio_s_routing(struct v4l2_subdev *sd, | 1745 | static int tvaudio_s_routing(struct v4l2_subdev *sd, |
1845 | u32 input, u32 output, u32 config) | 1746 | u32 input, u32 output, u32 config) |
1846 | { | 1747 | { |
@@ -1944,13 +1845,32 @@ static int tvaudio_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide | |||
1944 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVAUDIO, 0); | 1845 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVAUDIO, 0); |
1945 | } | 1846 | } |
1946 | 1847 | ||
1848 | static int tvaudio_log_status(struct v4l2_subdev *sd) | ||
1849 | { | ||
1850 | struct CHIPSTATE *chip = to_state(sd); | ||
1851 | struct CHIPDESC *desc = chip->desc; | ||
1852 | |||
1853 | v4l2_info(sd, "Chip: %s\n", desc->name); | ||
1854 | v4l2_ctrl_handler_log_status(&chip->hdl, sd->name); | ||
1855 | return 0; | ||
1856 | } | ||
1857 | |||
1947 | /* ----------------------------------------------------------------------- */ | 1858 | /* ----------------------------------------------------------------------- */ |
1948 | 1859 | ||
1860 | static const struct v4l2_ctrl_ops tvaudio_ctrl_ops = { | ||
1861 | .s_ctrl = tvaudio_s_ctrl, | ||
1862 | }; | ||
1863 | |||
1949 | static const struct v4l2_subdev_core_ops tvaudio_core_ops = { | 1864 | static const struct v4l2_subdev_core_ops tvaudio_core_ops = { |
1865 | .log_status = tvaudio_log_status, | ||
1950 | .g_chip_ident = tvaudio_g_chip_ident, | 1866 | .g_chip_ident = tvaudio_g_chip_ident, |
1951 | .queryctrl = tvaudio_queryctrl, | 1867 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, |
1952 | .g_ctrl = tvaudio_g_ctrl, | 1868 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, |
1953 | .s_ctrl = tvaudio_s_ctrl, | 1869 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, |
1870 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
1871 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
1872 | .queryctrl = v4l2_subdev_queryctrl, | ||
1873 | .querymenu = v4l2_subdev_querymenu, | ||
1954 | .s_std = tvaudio_s_std, | 1874 | .s_std = tvaudio_s_std, |
1955 | }; | 1875 | }; |
1956 | 1876 | ||
@@ -2035,6 +1955,10 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * | |||
2035 | else | 1955 | else |
2036 | chip_cmd(chip, "init", &desc->init); | 1956 | chip_cmd(chip, "init", &desc->init); |
2037 | 1957 | ||
1958 | v4l2_ctrl_handler_init(&chip->hdl, 5); | ||
1959 | if (desc->flags & CHIP_HAS_INPUTSEL) | ||
1960 | v4l2_ctrl_new_std(&chip->hdl, &tvaudio_ctrl_ops, | ||
1961 | V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); | ||
2038 | if (desc->flags & CHIP_HAS_VOLUME) { | 1962 | if (desc->flags & CHIP_HAS_VOLUME) { |
2039 | if (!desc->volfunc) { | 1963 | if (!desc->volfunc) { |
2040 | /* This shouldn't be happen. Warn user, but keep working | 1964 | /* This shouldn't be happen. Warn user, but keep working |
@@ -2043,12 +1967,14 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * | |||
2043 | v4l2_info(sd, "volume callback undefined!\n"); | 1967 | v4l2_info(sd, "volume callback undefined!\n"); |
2044 | desc->flags &= ~CHIP_HAS_VOLUME; | 1968 | desc->flags &= ~CHIP_HAS_VOLUME; |
2045 | } else { | 1969 | } else { |
2046 | chip->left = desc->leftinit ? desc->leftinit : 65535; | 1970 | chip->volume = v4l2_ctrl_new_std(&chip->hdl, |
2047 | chip->right = desc->rightinit ? desc->rightinit : 65535; | 1971 | &tvaudio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, |
2048 | chip_write(chip, desc->leftreg, | 1972 | 0, 65535, 65535 / 100, |
2049 | desc->volfunc(chip->left)); | 1973 | desc->volinit ? desc->volinit : 65535); |
2050 | chip_write(chip, desc->rightreg, | 1974 | chip->balance = v4l2_ctrl_new_std(&chip->hdl, |
2051 | desc->volfunc(chip->right)); | 1975 | &tvaudio_ctrl_ops, V4L2_CID_AUDIO_BALANCE, |
1976 | 0, 65535, 65535 / 100, 32768); | ||
1977 | v4l2_ctrl_cluster(2, &chip->volume); | ||
2052 | } | 1978 | } |
2053 | } | 1979 | } |
2054 | if (desc->flags & CHIP_HAS_BASSTREBLE) { | 1980 | if (desc->flags & CHIP_HAS_BASSTREBLE) { |
@@ -2059,17 +1985,28 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * | |||
2059 | v4l2_info(sd, "bass/treble callbacks undefined!\n"); | 1985 | v4l2_info(sd, "bass/treble callbacks undefined!\n"); |
2060 | desc->flags &= ~CHIP_HAS_BASSTREBLE; | 1986 | desc->flags &= ~CHIP_HAS_BASSTREBLE; |
2061 | } else { | 1987 | } else { |
2062 | chip->treble = desc->trebleinit ? | 1988 | v4l2_ctrl_new_std(&chip->hdl, |
2063 | desc->trebleinit : 32768; | 1989 | &tvaudio_ctrl_ops, V4L2_CID_AUDIO_BASS, |
2064 | chip->bass = desc->bassinit ? | 1990 | 0, 65535, 65535 / 100, |
2065 | desc->bassinit : 32768; | 1991 | desc->bassinit ? desc->bassinit : 32768); |
2066 | chip_write(chip, desc->bassreg, | 1992 | v4l2_ctrl_new_std(&chip->hdl, |
2067 | desc->bassfunc(chip->bass)); | 1993 | &tvaudio_ctrl_ops, V4L2_CID_AUDIO_TREBLE, |
2068 | chip_write(chip, desc->treblereg, | 1994 | 0, 65535, 65535 / 100, |
2069 | desc->treblefunc(chip->treble)); | 1995 | desc->trebleinit ? desc->trebleinit : 32768); |
2070 | } | 1996 | } |
2071 | } | 1997 | } |
2072 | 1998 | ||
1999 | sd->ctrl_handler = &chip->hdl; | ||
2000 | if (chip->hdl.error) { | ||
2001 | int err = chip->hdl.error; | ||
2002 | |||
2003 | v4l2_ctrl_handler_free(&chip->hdl); | ||
2004 | kfree(chip); | ||
2005 | return err; | ||
2006 | } | ||
2007 | /* set controls to the default values */ | ||
2008 | v4l2_ctrl_handler_setup(&chip->hdl); | ||
2009 | |||
2073 | chip->thread = NULL; | 2010 | chip->thread = NULL; |
2074 | init_timer(&chip->wt); | 2011 | init_timer(&chip->wt); |
2075 | if (desc->flags & CHIP_NEED_CHECKMODE) { | 2012 | if (desc->flags & CHIP_NEED_CHECKMODE) { |
@@ -2105,6 +2042,7 @@ static int tvaudio_remove(struct i2c_client *client) | |||
2105 | } | 2042 | } |
2106 | 2043 | ||
2107 | v4l2_device_unregister_subdev(sd); | 2044 | v4l2_device_unregister_subdev(sd); |
2045 | v4l2_ctrl_handler_free(&chip->hdl); | ||
2108 | kfree(chip); | 2046 | kfree(chip); |
2109 | return 0; | 2047 | return 0; |
2110 | } | 2048 | } |
diff --git a/drivers/media/i2c/tveeprom.c b/drivers/media/i2c/tveeprom.c deleted file mode 100644 index 3b6cf034976a..000000000000 --- a/drivers/media/i2c/tveeprom.c +++ /dev/null | |||
@@ -1,792 +0,0 @@ | |||
1 | /* | ||
2 | * tveeprom - eeprom decoder for tvcard configuration eeproms | ||
3 | * | ||
4 | * Data and decoding routines shamelessly borrowed from bttv-cards.c | ||
5 | * eeprom access routine shamelessly borrowed from bttv-if.c | ||
6 | * which are: | ||
7 | |||
8 | Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) | ||
9 | & Marcus Metzler (mocm@thp.uni-koeln.de) | ||
10 | (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de> | ||
11 | |||
12 | * Adjustments to fit a more general model and all bugs: | ||
13 | |||
14 | Copyright (C) 2003 John Klar <linpvr at projectplasma.com> | ||
15 | |||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
29 | */ | ||
30 | |||
31 | |||
32 | #include <linux/module.h> | ||
33 | #include <linux/errno.h> | ||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/types.h> | ||
37 | #include <linux/videodev2.h> | ||
38 | #include <linux/i2c.h> | ||
39 | |||
40 | #include <media/tuner.h> | ||
41 | #include <media/tveeprom.h> | ||
42 | #include <media/v4l2-common.h> | ||
43 | #include <media/v4l2-chip-ident.h> | ||
44 | |||
45 | MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver"); | ||
46 | MODULE_AUTHOR("John Klar"); | ||
47 | MODULE_LICENSE("GPL"); | ||
48 | |||
49 | static int debug; | ||
50 | module_param(debug, int, 0644); | ||
51 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); | ||
52 | |||
53 | #define STRM(array, i) \ | ||
54 | (i < sizeof(array) / sizeof(char *) ? array[i] : "unknown") | ||
55 | |||
56 | #define tveeprom_info(fmt, arg...) \ | ||
57 | v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg) | ||
58 | #define tveeprom_warn(fmt, arg...) \ | ||
59 | v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg) | ||
60 | #define tveeprom_dbg(fmt, arg...) do { \ | ||
61 | if (debug) \ | ||
62 | v4l_printk(KERN_DEBUG, "tveeprom", \ | ||
63 | c->adapter, c->addr, fmt , ## arg); \ | ||
64 | } while (0) | ||
65 | |||
66 | /* | ||
67 | * The Hauppauge eeprom uses an 8bit field to determine which | ||
68 | * tuner formats the tuner supports. | ||
69 | */ | ||
70 | static struct HAUPPAUGE_TUNER_FMT | ||
71 | { | ||
72 | int id; | ||
73 | char *name; | ||
74 | } | ||
75 | hauppauge_tuner_fmt[] = | ||
76 | { | ||
77 | { V4L2_STD_UNKNOWN, " UNKNOWN" }, | ||
78 | { V4L2_STD_UNKNOWN, " FM" }, | ||
79 | { V4L2_STD_B|V4L2_STD_GH, " PAL(B/G)" }, | ||
80 | { V4L2_STD_MN, " NTSC(M)" }, | ||
81 | { V4L2_STD_PAL_I, " PAL(I)" }, | ||
82 | { V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, " SECAM(L/L')" }, | ||
83 | { V4L2_STD_DK, " PAL(D/D1/K)" }, | ||
84 | { V4L2_STD_ATSC, " ATSC/DVB Digital" }, | ||
85 | }; | ||
86 | |||
87 | /* This is the full list of possible tuners. Many thanks to Hauppauge for | ||
88 | supplying this information. Note that many tuners where only used for | ||
89 | testing and never made it to the outside world. So you will only see | ||
90 | a subset in actual produced cards. */ | ||
91 | static struct HAUPPAUGE_TUNER | ||
92 | { | ||
93 | int id; | ||
94 | char *name; | ||
95 | } | ||
96 | hauppauge_tuner[] = | ||
97 | { | ||
98 | /* 0-9 */ | ||
99 | { TUNER_ABSENT, "None" }, | ||
100 | { TUNER_ABSENT, "External" }, | ||
101 | { TUNER_ABSENT, "Unspecified" }, | ||
102 | { TUNER_PHILIPS_PAL, "Philips FI1216" }, | ||
103 | { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, | ||
104 | { TUNER_PHILIPS_NTSC, "Philips FI1236" }, | ||
105 | { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, | ||
106 | { TUNER_PHILIPS_PAL_DK, "Philips FI1256" }, | ||
107 | { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, | ||
108 | { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, | ||
109 | /* 10-19 */ | ||
110 | { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, | ||
111 | { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, | ||
112 | { TUNER_PHILIPS_PAL_DK, "Philips FI1256 MK2" }, | ||
113 | { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, | ||
114 | { TUNER_TEMIC_PAL, "Temic 4002FH5" }, | ||
115 | { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, | ||
116 | { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, | ||
117 | { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, | ||
118 | { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, | ||
119 | { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, | ||
120 | /* 20-29 */ | ||
121 | { TUNER_PHILIPS_PAL_DK, "Philips FR1256 MK2" }, | ||
122 | { TUNER_PHILIPS_PAL, "Philips FM1216" }, | ||
123 | { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, | ||
124 | { TUNER_PHILIPS_NTSC, "Philips FM1236" }, | ||
125 | { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, | ||
126 | { TUNER_PHILIPS_PAL_DK, "Philips FM1256" }, | ||
127 | { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, | ||
128 | { TUNER_ABSENT, "Samsung TCPN9082D" }, | ||
129 | { TUNER_ABSENT, "Samsung TCPM9092P" }, | ||
130 | { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, | ||
131 | /* 30-39 */ | ||
132 | { TUNER_ABSENT, "Samsung TCPN9085D" }, | ||
133 | { TUNER_ABSENT, "Samsung TCPB9085P" }, | ||
134 | { TUNER_ABSENT, "Samsung TCPL9091P" }, | ||
135 | { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, | ||
136 | { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, | ||
137 | { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, | ||
138 | { TUNER_PHILIPS_NTSC, "Philips TD1536" }, | ||
139 | { TUNER_PHILIPS_NTSC, "Philips TD1536D" }, | ||
140 | { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ | ||
141 | { TUNER_ABSENT, "Philips FI1256MP" }, | ||
142 | /* 40-49 */ | ||
143 | { TUNER_ABSENT, "Samsung TCPQ9091P" }, | ||
144 | { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" }, | ||
145 | { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, | ||
146 | { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, | ||
147 | { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" }, | ||
148 | { TUNER_ABSENT, "Philips TD1536D FH 44"}, | ||
149 | { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, | ||
150 | { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, | ||
151 | { TUNER_LG_PAL, "LG TP18PSB11D"}, | ||
152 | { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, | ||
153 | /* 50-59 */ | ||
154 | { TUNER_LG_PAL_I, "LG TAPC-I701D"}, | ||
155 | { TUNER_ABSENT, "Temic 4042FI5"}, | ||
156 | { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"}, | ||
157 | { TUNER_ABSENT, "LG TPI8NSR11F"}, | ||
158 | { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"}, | ||
159 | { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"}, | ||
160 | { TUNER_ABSENT, "Philips FI1236 MK3"}, | ||
161 | { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, | ||
162 | { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, | ||
163 | { TUNER_ABSENT, "Philips FM1216MP MK3"}, | ||
164 | /* 60-69 */ | ||
165 | { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, | ||
166 | { TUNER_ABSENT, "LG M001D MK3"}, | ||
167 | { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, | ||
168 | { TUNER_ABSENT, "LG M701D MK3"}, | ||
169 | { TUNER_ABSENT, "Temic 4146FM5"}, | ||
170 | { TUNER_ABSENT, "Temic 4136FY5"}, | ||
171 | { TUNER_ABSENT, "Temic 4106FH5"}, | ||
172 | { TUNER_ABSENT, "Philips FQ1216LMP MK3"}, | ||
173 | { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"}, | ||
174 | { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"}, | ||
175 | /* 70-79 */ | ||
176 | { TUNER_ABSENT, "LG TALN H200T"}, | ||
177 | { TUNER_ABSENT, "LG TALN H250T"}, | ||
178 | { TUNER_ABSENT, "LG TALN M200T"}, | ||
179 | { TUNER_ABSENT, "LG TALN Z200T"}, | ||
180 | { TUNER_ABSENT, "LG TALN S200T"}, | ||
181 | { TUNER_ABSENT, "Thompson DTT7595"}, | ||
182 | { TUNER_ABSENT, "Thompson DTT7592"}, | ||
183 | { TUNER_ABSENT, "Silicon TDA8275C1 8290"}, | ||
184 | { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"}, | ||
185 | { TUNER_ABSENT, "Thompson DTT757"}, | ||
186 | /* 80-89 */ | ||
187 | { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK3"}, | ||
188 | { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, | ||
189 | { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, | ||
190 | { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, | ||
191 | { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, | ||
192 | { TUNER_TCL_2002N, "TCL 2002N 6A"}, | ||
193 | { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"}, | ||
194 | { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"}, | ||
195 | { TUNER_ABSENT, "Samsung TCPE 4121P30A"}, | ||
196 | { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"}, | ||
197 | /* 90-99 */ | ||
198 | { TUNER_ABSENT, "LG TALN H202T"}, | ||
199 | { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"}, | ||
200 | { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"}, | ||
201 | { TUNER_ABSENT, "Philips FQ1286A MK4"}, | ||
202 | { TUNER_ABSENT, "Philips FQ1216ME MK5"}, | ||
203 | { TUNER_ABSENT, "Philips FQ1236 MK5"}, | ||
204 | { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"}, | ||
205 | { TUNER_TCL_2002MB, "TCL 2002MB_3H"}, | ||
206 | { TUNER_ABSENT, "TCL 2002MI_3H"}, | ||
207 | { TUNER_TCL_2002N, "TCL 2002N 5H"}, | ||
208 | /* 100-109 */ | ||
209 | { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"}, | ||
210 | { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, | ||
211 | { TUNER_ABSENT, "Panasonic ENV57H12D5"}, | ||
212 | { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, | ||
213 | { TUNER_PHILIPS_FM1236_MK3, "TCL MNM05-4"}, | ||
214 | { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, | ||
215 | { TUNER_ABSENT, "TCL MQNM05-4"}, | ||
216 | { TUNER_ABSENT, "LG TAPC-W701D"}, | ||
217 | { TUNER_ABSENT, "TCL 9886P-WM"}, | ||
218 | { TUNER_ABSENT, "TCL 1676NM-WM"}, | ||
219 | /* 110-119 */ | ||
220 | { TUNER_ABSENT, "Thompson DTT75105"}, | ||
221 | { TUNER_ABSENT, "Conexant_CX24109"}, | ||
222 | { TUNER_TCL_2002N, "TCL M2523_5N_E"}, | ||
223 | { TUNER_TCL_2002MB, "TCL M2523_3DB_E"}, | ||
224 | { TUNER_ABSENT, "Philips 8275A"}, | ||
225 | { TUNER_ABSENT, "Microtune MT2060"}, | ||
226 | { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"}, | ||
227 | { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"}, | ||
228 | { TUNER_ABSENT, "TCL M2523_3DI_E"}, | ||
229 | { TUNER_ABSENT, "Samsung THPD5222FG30A"}, | ||
230 | /* 120-129 */ | ||
231 | { TUNER_XC2028, "Xceive XC3028"}, | ||
232 | { TUNER_PHILIPS_FQ1216LME_MK3, "Philips FQ1216LME MK5"}, | ||
233 | { TUNER_ABSENT, "Philips FQD1216LME"}, | ||
234 | { TUNER_ABSENT, "Conexant CX24118A"}, | ||
235 | { TUNER_ABSENT, "TCL DMF11WIP"}, | ||
236 | { TUNER_ABSENT, "TCL MFNM05_4H_E"}, | ||
237 | { TUNER_ABSENT, "TCL MNM05_4H_E"}, | ||
238 | { TUNER_ABSENT, "TCL MPE05_2H_E"}, | ||
239 | { TUNER_ABSENT, "TCL MQNM05_4_U"}, | ||
240 | { TUNER_ABSENT, "TCL M2523_5NH_E"}, | ||
241 | /* 130-139 */ | ||
242 | { TUNER_ABSENT, "TCL M2523_3DBH_E"}, | ||
243 | { TUNER_ABSENT, "TCL M2523_3DIH_E"}, | ||
244 | { TUNER_ABSENT, "TCL MFPE05_2_U"}, | ||
245 | { TUNER_PHILIPS_FMD1216MEX_MK3, "Philips FMD1216MEX"}, | ||
246 | { TUNER_ABSENT, "Philips FRH2036B"}, | ||
247 | { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, | ||
248 | { TUNER_ABSENT, "MaxLinear MXL5005"}, | ||
249 | { TUNER_ABSENT, "MaxLinear MXL5003"}, | ||
250 | { TUNER_ABSENT, "Xceive XC2028"}, | ||
251 | { TUNER_ABSENT, "Microtune MT2131"}, | ||
252 | /* 140-149 */ | ||
253 | { TUNER_ABSENT, "Philips 8275A_8295"}, | ||
254 | { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, | ||
255 | { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, | ||
256 | { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, | ||
257 | { TUNER_ABSENT, "Microtune MT2266"}, | ||
258 | { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, | ||
259 | { TUNER_ABSENT, "LG TAPQ_H702F"}, | ||
260 | { TUNER_ABSENT, "TCL M09WPP_4N_E"}, | ||
261 | { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, | ||
262 | { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, | ||
263 | /* 150-159 */ | ||
264 | { TUNER_XC5000, "Xceive XC5000"}, | ||
265 | { TUNER_ABSENT, "Xceive XC3028L"}, | ||
266 | { TUNER_ABSENT, "NXP 18271C2_716x"}, | ||
267 | { TUNER_ABSENT, "Xceive XC4000"}, | ||
268 | { TUNER_ABSENT, "Dibcom 7070"}, | ||
269 | { TUNER_PHILIPS_TDA8290, "NXP 18271C2"}, | ||
270 | { TUNER_ABSENT, "Siano SMS1010"}, | ||
271 | { TUNER_ABSENT, "Siano SMS1150"}, | ||
272 | { TUNER_ABSENT, "MaxLinear 5007"}, | ||
273 | { TUNER_ABSENT, "TCL M09WPP_2P_E"}, | ||
274 | /* 160-169 */ | ||
275 | { TUNER_ABSENT, "Siano SMS1180"}, | ||
276 | { TUNER_ABSENT, "Maxim_MAX2165"}, | ||
277 | { TUNER_ABSENT, "Siano SMS1140"}, | ||
278 | { TUNER_ABSENT, "Siano SMS1150 B1"}, | ||
279 | { TUNER_ABSENT, "MaxLinear 111"}, | ||
280 | { TUNER_ABSENT, "Dibcom 7770"}, | ||
281 | { TUNER_ABSENT, "Siano SMS1180VNS"}, | ||
282 | { TUNER_ABSENT, "Siano SMS1184"}, | ||
283 | { TUNER_PHILIPS_FQ1236_MK5, "TCL M30WTP-4N-E"}, | ||
284 | { TUNER_ABSENT, "TCL_M11WPP_2PN_E"}, | ||
285 | /* 170-179 */ | ||
286 | { TUNER_ABSENT, "MaxLinear 301"}, | ||
287 | { TUNER_ABSENT, "Mirics MSi001"}, | ||
288 | { TUNER_ABSENT, "MaxLinear MxL241SF"}, | ||
289 | { TUNER_XC5000C, "Xceive XC5000C"}, | ||
290 | { TUNER_ABSENT, "Montage M68TS2020"}, | ||
291 | { TUNER_ABSENT, "Siano SMS1530"}, | ||
292 | { TUNER_ABSENT, "Dibcom 7090"}, | ||
293 | { TUNER_ABSENT, "Xceive XC5200C"}, | ||
294 | { TUNER_ABSENT, "NXP 18273"}, | ||
295 | { TUNER_ABSENT, "Montage M88TS2022"}, | ||
296 | /* 180-189 */ | ||
297 | { TUNER_ABSENT, "NXP 18272M"}, | ||
298 | { TUNER_ABSENT, "NXP 18272S"}, | ||
299 | }; | ||
300 | |||
301 | /* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are | ||
302 | * internal to a video chip, i.e. not a separate audio chip. */ | ||
303 | static struct HAUPPAUGE_AUDIOIC | ||
304 | { | ||
305 | u32 id; | ||
306 | char *name; | ||
307 | } | ||
308 | audioIC[] = | ||
309 | { | ||
310 | /* 0-4 */ | ||
311 | { V4L2_IDENT_NONE, "None" }, | ||
312 | { V4L2_IDENT_UNKNOWN, "TEA6300" }, | ||
313 | { V4L2_IDENT_UNKNOWN, "TEA6320" }, | ||
314 | { V4L2_IDENT_UNKNOWN, "TDA9850" }, | ||
315 | { V4L2_IDENT_MSPX4XX, "MSP3400C" }, | ||
316 | /* 5-9 */ | ||
317 | { V4L2_IDENT_MSPX4XX, "MSP3410D" }, | ||
318 | { V4L2_IDENT_MSPX4XX, "MSP3415" }, | ||
319 | { V4L2_IDENT_MSPX4XX, "MSP3430" }, | ||
320 | { V4L2_IDENT_MSPX4XX, "MSP3438" }, | ||
321 | { V4L2_IDENT_UNKNOWN, "CS5331" }, | ||
322 | /* 10-14 */ | ||
323 | { V4L2_IDENT_MSPX4XX, "MSP3435" }, | ||
324 | { V4L2_IDENT_MSPX4XX, "MSP3440" }, | ||
325 | { V4L2_IDENT_MSPX4XX, "MSP3445" }, | ||
326 | { V4L2_IDENT_MSPX4XX, "MSP3411" }, | ||
327 | { V4L2_IDENT_MSPX4XX, "MSP3416" }, | ||
328 | /* 15-19 */ | ||
329 | { V4L2_IDENT_MSPX4XX, "MSP3425" }, | ||
330 | { V4L2_IDENT_MSPX4XX, "MSP3451" }, | ||
331 | { V4L2_IDENT_MSPX4XX, "MSP3418" }, | ||
332 | { V4L2_IDENT_UNKNOWN, "Type 0x12" }, | ||
333 | { V4L2_IDENT_UNKNOWN, "OKI7716" }, | ||
334 | /* 20-24 */ | ||
335 | { V4L2_IDENT_MSPX4XX, "MSP4410" }, | ||
336 | { V4L2_IDENT_MSPX4XX, "MSP4420" }, | ||
337 | { V4L2_IDENT_MSPX4XX, "MSP4440" }, | ||
338 | { V4L2_IDENT_MSPX4XX, "MSP4450" }, | ||
339 | { V4L2_IDENT_MSPX4XX, "MSP4408" }, | ||
340 | /* 25-29 */ | ||
341 | { V4L2_IDENT_MSPX4XX, "MSP4418" }, | ||
342 | { V4L2_IDENT_MSPX4XX, "MSP4428" }, | ||
343 | { V4L2_IDENT_MSPX4XX, "MSP4448" }, | ||
344 | { V4L2_IDENT_MSPX4XX, "MSP4458" }, | ||
345 | { V4L2_IDENT_MSPX4XX, "Type 0x1d" }, | ||
346 | /* 30-34 */ | ||
347 | { V4L2_IDENT_AMBIGUOUS, "CX880" }, | ||
348 | { V4L2_IDENT_AMBIGUOUS, "CX881" }, | ||
349 | { V4L2_IDENT_AMBIGUOUS, "CX883" }, | ||
350 | { V4L2_IDENT_AMBIGUOUS, "CX882" }, | ||
351 | { V4L2_IDENT_AMBIGUOUS, "CX25840" }, | ||
352 | /* 35-39 */ | ||
353 | { V4L2_IDENT_AMBIGUOUS, "CX25841" }, | ||
354 | { V4L2_IDENT_AMBIGUOUS, "CX25842" }, | ||
355 | { V4L2_IDENT_AMBIGUOUS, "CX25843" }, | ||
356 | { V4L2_IDENT_AMBIGUOUS, "CX23418" }, | ||
357 | { V4L2_IDENT_AMBIGUOUS, "CX23885" }, | ||
358 | /* 40-44 */ | ||
359 | { V4L2_IDENT_AMBIGUOUS, "CX23888" }, | ||
360 | { V4L2_IDENT_AMBIGUOUS, "SAA7131" }, | ||
361 | { V4L2_IDENT_AMBIGUOUS, "CX23887" }, | ||
362 | { V4L2_IDENT_AMBIGUOUS, "SAA7164" }, | ||
363 | { V4L2_IDENT_AMBIGUOUS, "AU8522" }, | ||
364 | }; | ||
365 | |||
366 | /* This list is supplied by Hauppauge. Thanks! */ | ||
367 | static const char *decoderIC[] = { | ||
368 | /* 0-4 */ | ||
369 | "None", "BT815", "BT817", "BT819", "BT815A", | ||
370 | /* 5-9 */ | ||
371 | "BT817A", "BT819A", "BT827", "BT829", "BT848", | ||
372 | /* 10-14 */ | ||
373 | "BT848A", "BT849A", "BT829A", "BT827A", "BT878", | ||
374 | /* 15-19 */ | ||
375 | "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115", | ||
376 | /* 20-24 */ | ||
377 | "CX880", "CX881", "CX883", "SAA7111", "SAA7113", | ||
378 | /* 25-29 */ | ||
379 | "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842", | ||
380 | /* 30-34 */ | ||
381 | "CX25843", "CX23418", "NEC61153", "CX23885", "CX23888", | ||
382 | /* 35-39 */ | ||
383 | "SAA7131", "CX25837", "CX23887", "CX23885A", "CX23887A", | ||
384 | /* 40-42 */ | ||
385 | "SAA7164", "CX23885B", "AU8522" | ||
386 | }; | ||
387 | |||
388 | static int hasRadioTuner(int tunerType) | ||
389 | { | ||
390 | switch (tunerType) { | ||
391 | case 18: /* PNPEnv_TUNER_FR1236_MK2 */ | ||
392 | case 23: /* PNPEnv_TUNER_FM1236 */ | ||
393 | case 38: /* PNPEnv_TUNER_FMR1236 */ | ||
394 | case 16: /* PNPEnv_TUNER_FR1216_MK2 */ | ||
395 | case 19: /* PNPEnv_TUNER_FR1246_MK2 */ | ||
396 | case 21: /* PNPEnv_TUNER_FM1216 */ | ||
397 | case 24: /* PNPEnv_TUNER_FM1246 */ | ||
398 | case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */ | ||
399 | case 22: /* PNPEnv_TUNER_FM1216MF */ | ||
400 | case 20: /* PNPEnv_TUNER_FR1256_MK2 */ | ||
401 | case 25: /* PNPEnv_TUNER_FM1256 */ | ||
402 | case 33: /* PNPEnv_TUNER_4039FR5 */ | ||
403 | case 42: /* PNPEnv_TUNER_4009FR5 */ | ||
404 | case 52: /* PNPEnv_TUNER_4049FM5 */ | ||
405 | case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */ | ||
406 | case 44: /* PNPEnv_TUNER_4009FN5 */ | ||
407 | case 31: /* PNPEnv_TUNER_TCPB9085P */ | ||
408 | case 30: /* PNPEnv_TUNER_TCPN9085D */ | ||
409 | case 46: /* PNPEnv_TUNER_TP18NSR01F */ | ||
410 | case 47: /* PNPEnv_TUNER_TP18PSB01D */ | ||
411 | case 49: /* PNPEnv_TUNER_TAPC_I001D */ | ||
412 | case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */ | ||
413 | case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */ | ||
414 | case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */ | ||
415 | case 58: /* PNPEnv_TUNER_FM1236_MK3 */ | ||
416 | case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */ | ||
417 | case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */ | ||
418 | case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */ | ||
419 | case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */ | ||
420 | case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */ | ||
421 | case 105: | ||
422 | return 1; | ||
423 | } | ||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, | ||
428 | unsigned char *eeprom_data) | ||
429 | { | ||
430 | /* ---------------------------------------------- | ||
431 | ** The hauppauge eeprom format is tagged | ||
432 | ** | ||
433 | ** if packet[0] == 0x84, then packet[0..1] == length | ||
434 | ** else length = packet[0] & 3f; | ||
435 | ** if packet[0] & f8 == f8, then EOD and packet[1] == checksum | ||
436 | ** | ||
437 | ** In our (ivtv) case we're interested in the following: | ||
438 | ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) | ||
439 | ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into | ||
440 | ** hauppauge_tuner_fmt) | ||
441 | ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) | ||
442 | ** audio proc: tag [02].01 or [05].00 (mask with 0x7f) | ||
443 | ** decoder proc: tag [09].01) | ||
444 | |||
445 | ** Fun info: | ||
446 | ** model: tag [00].07-08 or [06].00-01 | ||
447 | ** revision: tag [00].09-0b or [06].04-06 | ||
448 | ** serial#: tag [01].05-07 or [04].04-06 | ||
449 | |||
450 | ** # of inputs/outputs ??? | ||
451 | */ | ||
452 | |||
453 | int i, j, len, done, beenhere, tag, start; | ||
454 | |||
455 | int tuner1 = 0, t_format1 = 0, audioic = -1; | ||
456 | char *t_name1 = NULL; | ||
457 | const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" }; | ||
458 | |||
459 | int tuner2 = 0, t_format2 = 0; | ||
460 | char *t_name2 = NULL; | ||
461 | const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" }; | ||
462 | |||
463 | memset(tvee, 0, sizeof(*tvee)); | ||
464 | tvee->tuner_type = TUNER_ABSENT; | ||
465 | tvee->tuner2_type = TUNER_ABSENT; | ||
466 | |||
467 | done = len = beenhere = 0; | ||
468 | |||
469 | /* Different eeprom start offsets for em28xx, cx2388x and cx23418 */ | ||
470 | if (eeprom_data[0] == 0x1a && | ||
471 | eeprom_data[1] == 0xeb && | ||
472 | eeprom_data[2] == 0x67 && | ||
473 | eeprom_data[3] == 0x95) | ||
474 | start = 0xa0; /* Generic em28xx offset */ | ||
475 | else if ((eeprom_data[0] & 0xe1) == 0x01 && | ||
476 | eeprom_data[1] == 0x00 && | ||
477 | eeprom_data[2] == 0x00 && | ||
478 | eeprom_data[8] == 0x84) | ||
479 | start = 8; /* Generic cx2388x offset */ | ||
480 | else if (eeprom_data[1] == 0x70 && | ||
481 | eeprom_data[2] == 0x00 && | ||
482 | eeprom_data[4] == 0x74 && | ||
483 | eeprom_data[8] == 0x84) | ||
484 | start = 8; /* Generic cx23418 offset (models 74xxx) */ | ||
485 | else | ||
486 | start = 0; | ||
487 | |||
488 | for (i = start; !done && i < 256; i += len) { | ||
489 | if (eeprom_data[i] == 0x84) { | ||
490 | len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8); | ||
491 | i += 3; | ||
492 | } else if ((eeprom_data[i] & 0xf0) == 0x70) { | ||
493 | if (eeprom_data[i] & 0x08) { | ||
494 | /* verify checksum! */ | ||
495 | done = 1; | ||
496 | break; | ||
497 | } | ||
498 | len = eeprom_data[i] & 0x07; | ||
499 | ++i; | ||
500 | } else { | ||
501 | tveeprom_warn("Encountered bad packet header [%02x]. " | ||
502 | "Corrupt or not a Hauppauge eeprom.\n", | ||
503 | eeprom_data[i]); | ||
504 | return; | ||
505 | } | ||
506 | |||
507 | if (debug) { | ||
508 | tveeprom_info("Tag [%02x] + %d bytes:", | ||
509 | eeprom_data[i], len - 1); | ||
510 | for (j = 1; j < len; j++) | ||
511 | printk(KERN_CONT " %02x", eeprom_data[i + j]); | ||
512 | printk(KERN_CONT "\n"); | ||
513 | } | ||
514 | |||
515 | /* process by tag */ | ||
516 | tag = eeprom_data[i]; | ||
517 | switch (tag) { | ||
518 | case 0x00: | ||
519 | /* tag: 'Comprehensive' */ | ||
520 | tuner1 = eeprom_data[i+6]; | ||
521 | t_format1 = eeprom_data[i+5]; | ||
522 | tvee->has_radio = eeprom_data[i+len-1]; | ||
523 | /* old style tag, don't know how to detect | ||
524 | IR presence, mark as unknown. */ | ||
525 | tvee->has_ir = 0; | ||
526 | tvee->model = | ||
527 | eeprom_data[i+8] + | ||
528 | (eeprom_data[i+9] << 8); | ||
529 | tvee->revision = eeprom_data[i+10] + | ||
530 | (eeprom_data[i+11] << 8) + | ||
531 | (eeprom_data[i+12] << 16); | ||
532 | break; | ||
533 | |||
534 | case 0x01: | ||
535 | /* tag: 'SerialID' */ | ||
536 | tvee->serial_number = | ||
537 | eeprom_data[i+6] + | ||
538 | (eeprom_data[i+7] << 8) + | ||
539 | (eeprom_data[i+8] << 16); | ||
540 | break; | ||
541 | |||
542 | case 0x02: | ||
543 | /* tag 'AudioInfo' | ||
544 | Note mask with 0x7F, high bit used on some older models | ||
545 | to indicate 4052 mux was removed in favor of using MSP | ||
546 | inputs directly. */ | ||
547 | audioic = eeprom_data[i+2] & 0x7f; | ||
548 | if (audioic < ARRAY_SIZE(audioIC)) | ||
549 | tvee->audio_processor = audioIC[audioic].id; | ||
550 | else | ||
551 | tvee->audio_processor = V4L2_IDENT_UNKNOWN; | ||
552 | break; | ||
553 | |||
554 | /* case 0x03: tag 'EEInfo' */ | ||
555 | |||
556 | case 0x04: | ||
557 | /* tag 'SerialID2' */ | ||
558 | tvee->serial_number = | ||
559 | eeprom_data[i+5] + | ||
560 | (eeprom_data[i+6] << 8) + | ||
561 | (eeprom_data[i+7] << 16); | ||
562 | |||
563 | if ((eeprom_data[i + 8] & 0xf0) && | ||
564 | (tvee->serial_number < 0xffffff)) { | ||
565 | tvee->MAC_address[0] = 0x00; | ||
566 | tvee->MAC_address[1] = 0x0D; | ||
567 | tvee->MAC_address[2] = 0xFE; | ||
568 | tvee->MAC_address[3] = eeprom_data[i + 7]; | ||
569 | tvee->MAC_address[4] = eeprom_data[i + 6]; | ||
570 | tvee->MAC_address[5] = eeprom_data[i + 5]; | ||
571 | tvee->has_MAC_address = 1; | ||
572 | } | ||
573 | break; | ||
574 | |||
575 | case 0x05: | ||
576 | /* tag 'Audio2' | ||
577 | Note mask with 0x7F, high bit used on some older models | ||
578 | to indicate 4052 mux was removed in favor of using MSP | ||
579 | inputs directly. */ | ||
580 | audioic = eeprom_data[i+1] & 0x7f; | ||
581 | if (audioic < ARRAY_SIZE(audioIC)) | ||
582 | tvee->audio_processor = audioIC[audioic].id; | ||
583 | else | ||
584 | tvee->audio_processor = V4L2_IDENT_UNKNOWN; | ||
585 | |||
586 | break; | ||
587 | |||
588 | case 0x06: | ||
589 | /* tag 'ModelRev' */ | ||
590 | tvee->model = | ||
591 | eeprom_data[i + 1] + | ||
592 | (eeprom_data[i + 2] << 8) + | ||
593 | (eeprom_data[i + 3] << 16) + | ||
594 | (eeprom_data[i + 4] << 24); | ||
595 | tvee->revision = | ||
596 | eeprom_data[i + 5] + | ||
597 | (eeprom_data[i + 6] << 8) + | ||
598 | (eeprom_data[i + 7] << 16); | ||
599 | break; | ||
600 | |||
601 | case 0x07: | ||
602 | /* tag 'Details': according to Hauppauge not interesting | ||
603 | on any PCI-era or later boards. */ | ||
604 | break; | ||
605 | |||
606 | /* there is no tag 0x08 defined */ | ||
607 | |||
608 | case 0x09: | ||
609 | /* tag 'Video' */ | ||
610 | tvee->decoder_processor = eeprom_data[i + 1]; | ||
611 | break; | ||
612 | |||
613 | case 0x0a: | ||
614 | /* tag 'Tuner' */ | ||
615 | if (beenhere == 0) { | ||
616 | tuner1 = eeprom_data[i + 2]; | ||
617 | t_format1 = eeprom_data[i + 1]; | ||
618 | beenhere = 1; | ||
619 | } else { | ||
620 | /* a second (radio) tuner may be present */ | ||
621 | tuner2 = eeprom_data[i + 2]; | ||
622 | t_format2 = eeprom_data[i + 1]; | ||
623 | /* not a TV tuner? */ | ||
624 | if (t_format2 == 0) | ||
625 | tvee->has_radio = 1; /* must be radio */ | ||
626 | } | ||
627 | break; | ||
628 | |||
629 | case 0x0b: | ||
630 | /* tag 'Inputs': according to Hauppauge this is specific | ||
631 | to each driver family, so no good assumptions can be | ||
632 | made. */ | ||
633 | break; | ||
634 | |||
635 | /* case 0x0c: tag 'Balun' */ | ||
636 | /* case 0x0d: tag 'Teletext' */ | ||
637 | |||
638 | case 0x0e: | ||
639 | /* tag: 'Radio' */ | ||
640 | tvee->has_radio = eeprom_data[i+1]; | ||
641 | break; | ||
642 | |||
643 | case 0x0f: | ||
644 | /* tag 'IRInfo' */ | ||
645 | tvee->has_ir = 1 | (eeprom_data[i+1] << 1); | ||
646 | break; | ||
647 | |||
648 | /* case 0x10: tag 'VBIInfo' */ | ||
649 | /* case 0x11: tag 'QCInfo' */ | ||
650 | /* case 0x12: tag 'InfoBits' */ | ||
651 | |||
652 | default: | ||
653 | tveeprom_dbg("Not sure what to do with tag [%02x]\n", | ||
654 | tag); | ||
655 | /* dump the rest of the packet? */ | ||
656 | } | ||
657 | } | ||
658 | |||
659 | if (!done) { | ||
660 | tveeprom_warn("Ran out of data!\n"); | ||
661 | return; | ||
662 | } | ||
663 | |||
664 | if (tvee->revision != 0) { | ||
665 | tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f); | ||
666 | tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f); | ||
667 | tvee->rev_str[2] = 32 + ((tvee->revision >> 6) & 0x3f); | ||
668 | tvee->rev_str[3] = 32 + (tvee->revision & 0x3f); | ||
669 | tvee->rev_str[4] = 0; | ||
670 | } | ||
671 | |||
672 | if (hasRadioTuner(tuner1) && !tvee->has_radio) { | ||
673 | tveeprom_info("The eeprom says no radio is present, but the tuner type\n"); | ||
674 | tveeprom_info("indicates otherwise. I will assume that radio is present.\n"); | ||
675 | tvee->has_radio = 1; | ||
676 | } | ||
677 | |||
678 | if (tuner1 < ARRAY_SIZE(hauppauge_tuner)) { | ||
679 | tvee->tuner_type = hauppauge_tuner[tuner1].id; | ||
680 | t_name1 = hauppauge_tuner[tuner1].name; | ||
681 | } else { | ||
682 | t_name1 = "unknown"; | ||
683 | } | ||
684 | |||
685 | if (tuner2 < ARRAY_SIZE(hauppauge_tuner)) { | ||
686 | tvee->tuner2_type = hauppauge_tuner[tuner2].id; | ||
687 | t_name2 = hauppauge_tuner[tuner2].name; | ||
688 | } else { | ||
689 | t_name2 = "unknown"; | ||
690 | } | ||
691 | |||
692 | tvee->tuner_hauppauge_model = tuner1; | ||
693 | tvee->tuner2_hauppauge_model = tuner2; | ||
694 | tvee->tuner_formats = 0; | ||
695 | tvee->tuner2_formats = 0; | ||
696 | for (i = j = 0; i < 8; i++) { | ||
697 | if (t_format1 & (1 << i)) { | ||
698 | tvee->tuner_formats |= hauppauge_tuner_fmt[i].id; | ||
699 | t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name; | ||
700 | } | ||
701 | } | ||
702 | for (i = j = 0; i < 8; i++) { | ||
703 | if (t_format2 & (1 << i)) { | ||
704 | tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id; | ||
705 | t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name; | ||
706 | } | ||
707 | } | ||
708 | |||
709 | tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n", | ||
710 | tvee->model, tvee->rev_str, tvee->serial_number); | ||
711 | if (tvee->has_MAC_address == 1) | ||
712 | tveeprom_info("MAC address is %pM\n", tvee->MAC_address); | ||
713 | tveeprom_info("tuner model is %s (idx %d, type %d)\n", | ||
714 | t_name1, tuner1, tvee->tuner_type); | ||
715 | tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", | ||
716 | t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], | ||
717 | t_fmt_name1[3], t_fmt_name1[4], t_fmt_name1[5], | ||
718 | t_fmt_name1[6], t_fmt_name1[7], t_format1); | ||
719 | if (tuner2) | ||
720 | tveeprom_info("second tuner model is %s (idx %d, type %d)\n", | ||
721 | t_name2, tuner2, tvee->tuner2_type); | ||
722 | if (t_format2) | ||
723 | tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", | ||
724 | t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], | ||
725 | t_fmt_name2[3], t_fmt_name2[4], t_fmt_name2[5], | ||
726 | t_fmt_name2[6], t_fmt_name2[7], t_format2); | ||
727 | if (audioic < 0) { | ||
728 | tveeprom_info("audio processor is unknown (no idx)\n"); | ||
729 | tvee->audio_processor = V4L2_IDENT_UNKNOWN; | ||
730 | } else { | ||
731 | if (audioic < ARRAY_SIZE(audioIC)) | ||
732 | tveeprom_info("audio processor is %s (idx %d)\n", | ||
733 | audioIC[audioic].name, audioic); | ||
734 | else | ||
735 | tveeprom_info("audio processor is unknown (idx %d)\n", | ||
736 | audioic); | ||
737 | } | ||
738 | if (tvee->decoder_processor) | ||
739 | tveeprom_info("decoder processor is %s (idx %d)\n", | ||
740 | STRM(decoderIC, tvee->decoder_processor), | ||
741 | tvee->decoder_processor); | ||
742 | if (tvee->has_ir) | ||
743 | tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n", | ||
744 | tvee->has_radio ? "" : "no ", | ||
745 | (tvee->has_ir & 2) ? "" : "no ", | ||
746 | (tvee->has_ir & 4) ? "" : "no "); | ||
747 | else | ||
748 | tveeprom_info("has %sradio\n", | ||
749 | tvee->has_radio ? "" : "no "); | ||
750 | } | ||
751 | EXPORT_SYMBOL(tveeprom_hauppauge_analog); | ||
752 | |||
753 | /* ----------------------------------------------------------------------- */ | ||
754 | /* generic helper functions */ | ||
755 | |||
756 | int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) | ||
757 | { | ||
758 | unsigned char buf; | ||
759 | int err; | ||
760 | |||
761 | buf = 0; | ||
762 | err = i2c_master_send(c, &buf, 1); | ||
763 | if (err != 1) { | ||
764 | tveeprom_info("Huh, no eeprom present (err=%d)?\n", err); | ||
765 | return -1; | ||
766 | } | ||
767 | err = i2c_master_recv(c, eedata, len); | ||
768 | if (err != len) { | ||
769 | tveeprom_warn("i2c eeprom read error (err=%d)\n", err); | ||
770 | return -1; | ||
771 | } | ||
772 | if (debug) { | ||
773 | int i; | ||
774 | |||
775 | tveeprom_info("full 256-byte eeprom dump:\n"); | ||
776 | for (i = 0; i < len; i++) { | ||
777 | if (0 == (i % 16)) | ||
778 | tveeprom_info("%02x:", i); | ||
779 | printk(KERN_CONT " %02x", eedata[i]); | ||
780 | if (15 == (i % 16)) | ||
781 | printk(KERN_CONT "\n"); | ||
782 | } | ||
783 | } | ||
784 | return 0; | ||
785 | } | ||
786 | EXPORT_SYMBOL(tveeprom_read); | ||
787 | |||
788 | /* | ||
789 | * Local variables: | ||
790 | * c-basic-offset: 8 | ||
791 | * End: | ||
792 | */ | ||
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index d5e10215a28f..aa94ebc2d755 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c | |||
@@ -951,7 +951,7 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
951 | return -ENODEV; | 951 | return -ENODEV; |
952 | } | 952 | } |
953 | 953 | ||
954 | decoder = kzalloc(sizeof(*decoder), GFP_KERNEL); | 954 | decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL); |
955 | if (!decoder) | 955 | if (!decoder) |
956 | return -ENOMEM; | 956 | return -ENOMEM; |
957 | 957 | ||
@@ -998,7 +998,6 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
998 | int err = decoder->hdl.error; | 998 | int err = decoder->hdl.error; |
999 | 999 | ||
1000 | v4l2_ctrl_handler_free(&decoder->hdl); | 1000 | v4l2_ctrl_handler_free(&decoder->hdl); |
1001 | kfree(decoder); | ||
1002 | return err; | 1001 | return err; |
1003 | } | 1002 | } |
1004 | v4l2_ctrl_handler_setup(&decoder->hdl); | 1003 | v4l2_ctrl_handler_setup(&decoder->hdl); |
@@ -1023,7 +1022,6 @@ static int tvp514x_remove(struct i2c_client *client) | |||
1023 | 1022 | ||
1024 | v4l2_device_unregister_subdev(sd); | 1023 | v4l2_device_unregister_subdev(sd); |
1025 | v4l2_ctrl_handler_free(&decoder->hdl); | 1024 | v4l2_ctrl_handler_free(&decoder->hdl); |
1026 | kfree(decoder); | ||
1027 | return 0; | 1025 | return 0; |
1028 | } | 1026 | } |
1029 | /* TVP5146 Init/Power on Sequence */ | 1027 | /* TVP5146 Init/Power on Sequence */ |
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 31104a960652..5967e1a0c809 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c | |||
@@ -1096,13 +1096,6 @@ static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = { | |||
1096 | 1096 | ||
1097 | static const struct v4l2_subdev_core_ops tvp5150_core_ops = { | 1097 | static const struct v4l2_subdev_core_ops tvp5150_core_ops = { |
1098 | .log_status = tvp5150_log_status, | 1098 | .log_status = tvp5150_log_status, |
1099 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | ||
1100 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | ||
1101 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | ||
1102 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
1103 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
1104 | .queryctrl = v4l2_subdev_queryctrl, | ||
1105 | .querymenu = v4l2_subdev_querymenu, | ||
1106 | .s_std = tvp5150_s_std, | 1099 | .s_std = tvp5150_s_std, |
1107 | .reset = tvp5150_reset, | 1100 | .reset = tvp5150_reset, |
1108 | .g_chip_ident = tvp5150_g_chip_ident, | 1101 | .g_chip_ident = tvp5150_g_chip_ident, |
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index fb6a5b57eb83..537f6b4d4918 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c | |||
@@ -1036,7 +1036,7 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) | |||
1036 | return -ENODEV; | 1036 | return -ENODEV; |
1037 | } | 1037 | } |
1038 | 1038 | ||
1039 | device = kzalloc(sizeof(struct tvp7002), GFP_KERNEL); | 1039 | device = devm_kzalloc(&c->dev, sizeof(struct tvp7002), GFP_KERNEL); |
1040 | 1040 | ||
1041 | if (!device) | 1041 | if (!device) |
1042 | return -ENOMEM; | 1042 | return -ENOMEM; |
@@ -1052,7 +1052,7 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) | |||
1052 | 1052 | ||
1053 | error = tvp7002_read(sd, TVP7002_CHIP_REV, &revision); | 1053 | error = tvp7002_read(sd, TVP7002_CHIP_REV, &revision); |
1054 | if (error < 0) | 1054 | if (error < 0) |
1055 | goto found_error; | 1055 | return error; |
1056 | 1056 | ||
1057 | /* Get revision number */ | 1057 | /* Get revision number */ |
1058 | v4l2_info(sd, "Rev. %02x detected.\n", revision); | 1058 | v4l2_info(sd, "Rev. %02x detected.\n", revision); |
@@ -1063,21 +1063,21 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) | |||
1063 | error = tvp7002_write_inittab(sd, tvp7002_init_default); | 1063 | error = tvp7002_write_inittab(sd, tvp7002_init_default); |
1064 | 1064 | ||
1065 | if (error < 0) | 1065 | if (error < 0) |
1066 | goto found_error; | 1066 | return error; |
1067 | 1067 | ||
1068 | /* Set polarity information after registers have been set */ | 1068 | /* Set polarity information after registers have been set */ |
1069 | polarity_a = 0x20 | device->pdata->hs_polarity << 5 | 1069 | polarity_a = 0x20 | device->pdata->hs_polarity << 5 |
1070 | | device->pdata->vs_polarity << 2; | 1070 | | device->pdata->vs_polarity << 2; |
1071 | error = tvp7002_write(sd, TVP7002_SYNC_CTL_1, polarity_a); | 1071 | error = tvp7002_write(sd, TVP7002_SYNC_CTL_1, polarity_a); |
1072 | if (error < 0) | 1072 | if (error < 0) |
1073 | goto found_error; | 1073 | return error; |
1074 | 1074 | ||
1075 | polarity_b = 0x01 | device->pdata->fid_polarity << 2 | 1075 | polarity_b = 0x01 | device->pdata->fid_polarity << 2 |
1076 | | device->pdata->sog_polarity << 1 | 1076 | | device->pdata->sog_polarity << 1 |
1077 | | device->pdata->clk_polarity; | 1077 | | device->pdata->clk_polarity; |
1078 | error = tvp7002_write(sd, TVP7002_MISC_CTL_3, polarity_b); | 1078 | error = tvp7002_write(sd, TVP7002_MISC_CTL_3, polarity_b); |
1079 | if (error < 0) | 1079 | if (error < 0) |
1080 | goto found_error; | 1080 | return error; |
1081 | 1081 | ||
1082 | /* Set registers according to default video mode */ | 1082 | /* Set registers according to default video mode */ |
1083 | preset.preset = device->current_preset->preset; | 1083 | preset.preset = device->current_preset->preset; |
@@ -1091,16 +1091,11 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) | |||
1091 | int err = device->hdl.error; | 1091 | int err = device->hdl.error; |
1092 | 1092 | ||
1093 | v4l2_ctrl_handler_free(&device->hdl); | 1093 | v4l2_ctrl_handler_free(&device->hdl); |
1094 | kfree(device); | ||
1095 | return err; | 1094 | return err; |
1096 | } | 1095 | } |
1097 | v4l2_ctrl_handler_setup(&device->hdl); | 1096 | v4l2_ctrl_handler_setup(&device->hdl); |
1098 | 1097 | ||
1099 | found_error: | 1098 | return 0; |
1100 | if (error < 0) | ||
1101 | kfree(device); | ||
1102 | |||
1103 | return error; | ||
1104 | } | 1099 | } |
1105 | 1100 | ||
1106 | /* | 1101 | /* |
@@ -1120,7 +1115,6 @@ static int tvp7002_remove(struct i2c_client *c) | |||
1120 | 1115 | ||
1121 | v4l2_device_unregister_subdev(sd); | 1116 | v4l2_device_unregister_subdev(sd); |
1122 | v4l2_ctrl_handler_free(&device->hdl); | 1117 | v4l2_ctrl_handler_free(&device->hdl); |
1123 | kfree(device); | ||
1124 | return 0; | 1118 | return 0; |
1125 | } | 1119 | } |
1126 | 1120 | ||