diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-04 10:58:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-04 10:58:25 -0400 |
commit | 1046a2c428bedd64c960dcfd0c57cc69a82fea2f (patch) | |
tree | d34b83e0ac61b51305cece031f7ff49579e3fe76 /drivers/media | |
parent | 46e85f5f1c2a1d106c1ec0fa2a06280276b8e052 (diff) | |
parent | b3f4e1eba45eda5d1213810ef3bc53e5247df2df (diff) |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (144 commits)
[media] saa7134.h: Suppress compiler warnings when CONFIG_VIDEO_SAA7134_RC is not set
[media] it913x [VER 1.07] Support for single ITE 9135 devices
[media] Support for Terratec G1
[media] cx25821: off by one in cx25821_vidioc_s_input()
[media] media: tea5764: reconcile Kconfig symbol and macro
[media] omap_vout: Add poll() support
[media] omap3isp: preview: Add crop support on the sink pad
[media] omap3isp: preview: Rename min/max input/output sizes defines
[media] omap3isp: preview: Remove horizontal averager support
[media] omap3isp: Report the ISP revision through the media controller API
[media] omap3isp: ccdc: remove redundant operation
[media] omap3isp: Fix memory leaks in initialization error paths
[media] omap3isp: Add missing mutex_destroy() calls
[media] omap3isp: Move *_init_entities() functions to the init/cleanup section
[media] omap3isp: Move media_entity_cleanup() from unregister() to cleanup()
[media] MFC: Change MFC firmware binary name
[media] vb2: add vb2_get_unmapped_area in vb2 core
[media] v4l: Add v4l2 subdev driver for S5K6AAFX sensor
[media] v4l: Add AUTO option for the V4L2_CID_POWER_LINE_FREQUENCY control
[media] media: ov6650: stylistic improvements
...
Diffstat (limited to 'drivers/media')
98 files changed, 18142 insertions, 3612 deletions
diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile index cf7214edf65f..38019bafb862 100644 --- a/drivers/media/dvb/ddbridge/Makefile +++ b/drivers/media/dvb/ddbridge/Makefile | |||
@@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/dvb/frontends/ | |||
11 | ccflags-y += -Idrivers/media/common/tuners/ | 11 | ccflags-y += -Idrivers/media/common/tuners/ |
12 | 12 | ||
13 | # For the staging CI driver cxd2099 | 13 | # For the staging CI driver cxd2099 |
14 | ccflags-y += -Idrivers/staging/cxd2099/ | 14 | ccflags-y += -Idrivers/staging/media/cxd2099/ |
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 7d0710bb1978..26c8b9e57050 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile | |||
@@ -102,6 +102,7 @@ obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o | |||
102 | 102 | ||
103 | dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o | 103 | dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o |
104 | obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o | 104 | obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o |
105 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o | ||
105 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o | 106 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o |
106 | 107 | ||
107 | ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ | 108 | ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ |
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2ad33ba92ba2..2d08c9b5128a 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | |||
@@ -37,6 +37,7 @@ | |||
37 | #define USB_VID_HAUPPAUGE 0x2040 | 37 | #define USB_VID_HAUPPAUGE 0x2040 |
38 | #define USB_VID_HYPER_PALTEK 0x1025 | 38 | #define USB_VID_HYPER_PALTEK 0x1025 |
39 | #define USB_VID_INTEL 0x8086 | 39 | #define USB_VID_INTEL 0x8086 |
40 | #define USB_VID_ITETECH 0x048d | ||
40 | #define USB_VID_KWORLD 0xeb2a | 41 | #define USB_VID_KWORLD 0xeb2a |
41 | #define USB_VID_KWORLD_2 0x1b80 | 42 | #define USB_VID_KWORLD_2 0x1b80 |
42 | #define USB_VID_KYE 0x0458 | 43 | #define USB_VID_KYE 0x0458 |
@@ -126,6 +127,7 @@ | |||
126 | #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 | 127 | #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 |
127 | #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 | 128 | #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 |
128 | #define USB_PID_INTEL_CE9500 0x9500 | 129 | #define USB_PID_INTEL_CE9500 0x9500 |
130 | #define USB_PID_ITETECH_IT9135 0x9135 | ||
129 | #define USB_PID_KWORLD_399U 0xe399 | 131 | #define USB_PID_KWORLD_399U 0xe399 |
130 | #define USB_PID_KWORLD_399U_2 0xe400 | 132 | #define USB_PID_KWORLD_399U_2 0xe400 |
131 | #define USB_PID_KWORLD_395U 0xe396 | 133 | #define USB_PID_KWORLD_395U 0xe396 |
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c index f027a2c1c3e8..c46226187143 100644 --- a/drivers/media/dvb/dvb-usb/it913x.c +++ b/drivers/media/dvb/dvb-usb/it913x.c | |||
@@ -60,6 +60,17 @@ struct it913x_state { | |||
60 | u8 id; | 60 | u8 id; |
61 | }; | 61 | }; |
62 | 62 | ||
63 | struct ite_config { | ||
64 | u8 chip_ver; | ||
65 | u16 chip_type; | ||
66 | u32 firmware; | ||
67 | u8 tuner_id_0; | ||
68 | u8 tuner_id_1; | ||
69 | u8 dual_mode; | ||
70 | }; | ||
71 | |||
72 | struct ite_config it913x_config; | ||
73 | |||
63 | static int it913x_bulk_write(struct usb_device *dev, | 74 | static int it913x_bulk_write(struct usb_device *dev, |
64 | u8 *snd, int len, u8 pipe) | 75 | u8 *snd, int len, u8 pipe) |
65 | { | 76 | { |
@@ -191,18 +202,23 @@ static int it913x_read_reg(struct usb_device *udev, u32 reg) | |||
191 | static u32 it913x_query(struct usb_device *udev, u8 pro) | 202 | static u32 it913x_query(struct usb_device *udev, u8 pro) |
192 | { | 203 | { |
193 | int ret; | 204 | int ret; |
194 | u32 res = 0; | ||
195 | u8 data[4]; | 205 | u8 data[4]; |
196 | ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, | 206 | ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, |
197 | 0x1222, 0, &data[0], 1); | 207 | 0x1222, 0, &data[0], 3); |
198 | if (data[0] == 0x1) { | 208 | |
199 | ret = it913x_io(udev, READ_SHORT, pro, | 209 | it913x_config.chip_ver = data[0]; |
210 | it913x_config.chip_type = (u16)(data[2] << 8) + data[1]; | ||
211 | |||
212 | info("Chip Version=%02x Chip Type=%04x", it913x_config.chip_ver, | ||
213 | it913x_config.chip_type); | ||
214 | |||
215 | ret |= it913x_io(udev, READ_SHORT, pro, | ||
200 | CMD_QUERYINFO, 0, 0x1, &data[0], 4); | 216 | CMD_QUERYINFO, 0, 0x1, &data[0], 4); |
201 | res = (data[0] << 24) + (data[1] << 16) + | 217 | |
218 | it913x_config.firmware = (data[0] << 24) + (data[1] << 16) + | ||
202 | (data[2] << 8) + data[3]; | 219 | (data[2] << 8) + data[3]; |
203 | } | ||
204 | 220 | ||
205 | return (ret < 0) ? 0 : res; | 221 | return (ret < 0) ? 0 : it913x_config.firmware; |
206 | } | 222 | } |
207 | 223 | ||
208 | static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) | 224 | static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) |
@@ -336,26 +352,35 @@ static int it913x_identify_state(struct usb_device *udev, | |||
336 | int *cold) | 352 | int *cold) |
337 | { | 353 | { |
338 | int ret = 0, firm_no; | 354 | int ret = 0, firm_no; |
339 | u8 reg, adap, ep, tun0, tun1; | 355 | u8 reg, remote; |
340 | 356 | ||
341 | firm_no = it913x_return_status(udev); | 357 | firm_no = it913x_return_status(udev); |
342 | 358 | ||
343 | ep = it913x_read_reg(udev, 0x49ac); | 359 | /* checnk for dual mode */ |
344 | adap = it913x_read_reg(udev, 0x49c5); | 360 | it913x_config.dual_mode = it913x_read_reg(udev, 0x49c5); |
345 | tun0 = it913x_read_reg(udev, 0x49d0); | 361 | |
346 | info("No. Adapters=%x Endpoints=%x Tuner Type=%x", adap, ep, tun0); | 362 | /* TODO different remotes */ |
363 | remote = it913x_read_reg(udev, 0x49ac); /* Remote */ | ||
364 | if (remote == 0) | ||
365 | props->rc.core.rc_codes = NULL; | ||
366 | |||
367 | /* TODO at the moment tuner_id is always assigned to 0x38 */ | ||
368 | it913x_config.tuner_id_0 = it913x_read_reg(udev, 0x49d0); | ||
369 | |||
370 | info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode | ||
371 | , remote, it913x_config.tuner_id_0); | ||
347 | 372 | ||
348 | if (firm_no > 0) { | 373 | if (firm_no > 0) { |
349 | *cold = 0; | 374 | *cold = 0; |
350 | return 0; | 375 | return 0; |
351 | } | 376 | } |
352 | 377 | ||
353 | if (adap > 2) { | 378 | if (it913x_config.dual_mode) { |
354 | tun1 = it913x_read_reg(udev, 0x49e0); | 379 | it913x_config.tuner_id_1 = it913x_read_reg(udev, 0x49e0); |
355 | ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1); | 380 | ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1); |
356 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1); | 381 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1); |
357 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1); | 382 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1); |
358 | msleep(50); /* Delay noticed reset cycle ? */ | 383 | msleep(50); |
359 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0); | 384 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0); |
360 | msleep(50); | 385 | msleep(50); |
361 | reg = it913x_read_reg(udev, GPIOH1_O); | 386 | reg = it913x_read_reg(udev, GPIOH1_O); |
@@ -366,14 +391,19 @@ static int it913x_identify_state(struct usb_device *udev, | |||
366 | ret = it913x_wr_reg(udev, DEV_0, | 391 | ret = it913x_wr_reg(udev, DEV_0, |
367 | GPIOH1_O, 0x0); | 392 | GPIOH1_O, 0x0); |
368 | } | 393 | } |
394 | props->num_adapters = 2; | ||
369 | } else | 395 | } else |
370 | props->num_adapters = 1; | 396 | props->num_adapters = 1; |
371 | 397 | ||
372 | reg = it913x_read_reg(udev, IO_MUX_POWER_CLK); | 398 | reg = it913x_read_reg(udev, IO_MUX_POWER_CLK); |
373 | 399 | ||
374 | ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); | 400 | if (it913x_config.dual_mode) { |
375 | 401 | ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); | |
376 | ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); | 402 | ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); |
403 | } else { | ||
404 | ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, 0x0); | ||
405 | ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x0); | ||
406 | } | ||
377 | 407 | ||
378 | *cold = 1; | 408 | *cold = 1; |
379 | 409 | ||
@@ -403,13 +433,11 @@ static int it913x_download_firmware(struct usb_device *udev, | |||
403 | const struct firmware *fw) | 433 | const struct firmware *fw) |
404 | { | 434 | { |
405 | int ret = 0, i; | 435 | int ret = 0, i; |
406 | u8 packet_size, dlen, tun1; | 436 | u8 packet_size, dlen; |
407 | u8 *fw_data; | 437 | u8 *fw_data; |
408 | 438 | ||
409 | packet_size = 0x29; | 439 | packet_size = 0x29; |
410 | 440 | ||
411 | tun1 = it913x_read_reg(udev, 0x49e0); | ||
412 | |||
413 | ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100); | 441 | ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100); |
414 | 442 | ||
415 | info("FRM Starting Firmware Download"); | 443 | info("FRM Starting Firmware Download"); |
@@ -444,11 +472,12 @@ static int it913x_download_firmware(struct usb_device *udev, | |||
444 | ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); | 472 | ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); |
445 | 473 | ||
446 | /* Tuner function */ | 474 | /* Tuner function */ |
447 | ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0); | 475 | if (it913x_config.dual_mode) |
476 | ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0); | ||
448 | 477 | ||
449 | ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0); | 478 | ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0); |
450 | ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0); | 479 | ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0); |
451 | if (tun1 > 0) { | 480 | if (it913x_config.dual_mode) { |
452 | ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0); | 481 | ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0); |
453 | ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0); | 482 | ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0); |
454 | } | 483 | } |
@@ -475,9 +504,28 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap) | |||
475 | u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); | 504 | u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); |
476 | u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); | 505 | u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); |
477 | u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize; | 506 | u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize; |
507 | u8 tuner_id, tuner_type; | ||
508 | |||
509 | if (adap->id == 0) | ||
510 | tuner_id = it913x_config.tuner_id_0; | ||
511 | else | ||
512 | tuner_id = it913x_config.tuner_id_1; | ||
513 | |||
514 | /* TODO we always use IT9137 possible references here*/ | ||
515 | /* Documentation suggests don't care */ | ||
516 | switch (tuner_id) { | ||
517 | case 0x51: | ||
518 | case 0x52: | ||
519 | case 0x60: | ||
520 | case 0x61: | ||
521 | case 0x62: | ||
522 | default: | ||
523 | case 0x38: | ||
524 | tuner_type = IT9137; | ||
525 | } | ||
478 | 526 | ||
479 | adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach, | 527 | adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach, |
480 | &adap->dev->i2c_adap, adap_addr, adf, IT9137); | 528 | &adap->dev->i2c_adap, adap_addr, adf, tuner_type); |
481 | 529 | ||
482 | if (adap->id == 0 && adap->fe_adap[0].fe) { | 530 | if (adap->id == 0 && adap->fe_adap[0].fe) { |
483 | ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1); | 531 | ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1); |
@@ -533,6 +581,7 @@ static int it913x_probe(struct usb_interface *intf, | |||
533 | 581 | ||
534 | static struct usb_device_id it913x_table[] = { | 582 | static struct usb_device_id it913x_table[] = { |
535 | { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) }, | 583 | { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) }, |
584 | { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135) }, | ||
536 | {} /* Terminating entry */ | 585 | {} /* Terminating entry */ |
537 | }; | 586 | }; |
538 | 587 | ||
@@ -608,12 +657,14 @@ static struct dvb_usb_device_properties it913x_properties = { | |||
608 | .rc_codes = RC_MAP_KWORLD_315U, | 657 | .rc_codes = RC_MAP_KWORLD_315U, |
609 | }, | 658 | }, |
610 | .i2c_algo = &it913x_i2c_algo, | 659 | .i2c_algo = &it913x_i2c_algo, |
611 | .num_device_descs = 1, | 660 | .num_device_descs = 2, |
612 | .devices = { | 661 | .devices = { |
613 | { "Kworld UB499-2T T09(IT9137)", | 662 | { "Kworld UB499-2T T09(IT9137)", |
614 | { &it913x_table[0], NULL }, | 663 | { &it913x_table[0], NULL }, |
615 | }, | 664 | }, |
616 | 665 | { "ITE 9135 Generic", | |
666 | { &it913x_table[1], NULL }, | ||
667 | }, | ||
617 | } | 668 | } |
618 | }; | 669 | }; |
619 | 670 | ||
@@ -647,5 +698,5 @@ module_exit(it913x_module_exit); | |||
647 | 698 | ||
648 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); | 699 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); |
649 | MODULE_DESCRIPTION("it913x USB 2 Driver"); | 700 | MODULE_DESCRIPTION("it913x USB 2 Driver"); |
650 | MODULE_VERSION("1.06"); | 701 | MODULE_VERSION("1.07"); |
651 | MODULE_LICENSE("GPL"); | 702 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c new file mode 100644 index 000000000000..d1f58371c711 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c | |||
@@ -0,0 +1,614 @@ | |||
1 | /* | ||
2 | * mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator | ||
3 | * | ||
4 | * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> | ||
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 | #include "mxl111sf-demod.h" | ||
22 | #include "mxl111sf-reg.h" | ||
23 | |||
24 | /* debug */ | ||
25 | static int mxl111sf_demod_debug; | ||
26 | module_param_named(debug, mxl111sf_demod_debug, int, 0644); | ||
27 | MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); | ||
28 | |||
29 | #define mxl_dbg(fmt, arg...) \ | ||
30 | if (mxl111sf_demod_debug) \ | ||
31 | mxl_printk(KERN_DEBUG, fmt, ##arg) | ||
32 | |||
33 | /* ------------------------------------------------------------------------ */ | ||
34 | |||
35 | struct mxl111sf_demod_state { | ||
36 | struct mxl111sf_state *mxl_state; | ||
37 | |||
38 | struct mxl111sf_demod_config *cfg; | ||
39 | |||
40 | struct dvb_frontend fe; | ||
41 | }; | ||
42 | |||
43 | /* ------------------------------------------------------------------------ */ | ||
44 | |||
45 | static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state, | ||
46 | u8 addr, u8 *data) | ||
47 | { | ||
48 | return (state->cfg->read_reg) ? | ||
49 | state->cfg->read_reg(state->mxl_state, addr, data) : | ||
50 | -EINVAL; | ||
51 | } | ||
52 | |||
53 | static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state, | ||
54 | u8 addr, u8 data) | ||
55 | { | ||
56 | return (state->cfg->write_reg) ? | ||
57 | state->cfg->write_reg(state->mxl_state, addr, data) : | ||
58 | -EINVAL; | ||
59 | } | ||
60 | |||
61 | static | ||
62 | int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state, | ||
63 | struct mxl111sf_reg_ctrl_info *ctrl_reg_info) | ||
64 | { | ||
65 | return (state->cfg->program_regs) ? | ||
66 | state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : | ||
67 | -EINVAL; | ||
68 | } | ||
69 | |||
70 | /* ------------------------------------------------------------------------ */ | ||
71 | /* TPS */ | ||
72 | |||
73 | static | ||
74 | int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state, | ||
75 | fe_code_rate_t *code_rate) | ||
76 | { | ||
77 | u8 val; | ||
78 | int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val); | ||
79 | /* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */ | ||
80 | if (mxl_fail(ret)) | ||
81 | goto fail; | ||
82 | |||
83 | switch (val & V6_CODE_RATE_TPS_MASK) { | ||
84 | case 0: | ||
85 | *code_rate = FEC_1_2; | ||
86 | break; | ||
87 | case 1: | ||
88 | *code_rate = FEC_2_3; | ||
89 | break; | ||
90 | case 2: | ||
91 | *code_rate = FEC_3_4; | ||
92 | break; | ||
93 | case 3: | ||
94 | *code_rate = FEC_5_6; | ||
95 | break; | ||
96 | case 4: | ||
97 | *code_rate = FEC_7_8; | ||
98 | break; | ||
99 | } | ||
100 | fail: | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | static | ||
105 | int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state, | ||
106 | fe_modulation_t *constellation) | ||
107 | { | ||
108 | u8 val; | ||
109 | int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val); | ||
110 | /* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */ | ||
111 | if (mxl_fail(ret)) | ||
112 | goto fail; | ||
113 | |||
114 | switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) { | ||
115 | case 0: | ||
116 | *constellation = QPSK; | ||
117 | break; | ||
118 | case 1: | ||
119 | *constellation = QAM_16; | ||
120 | break; | ||
121 | case 2: | ||
122 | *constellation = QAM_64; | ||
123 | break; | ||
124 | } | ||
125 | fail: | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | static | ||
130 | int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state, | ||
131 | fe_transmit_mode_t *fft_mode) | ||
132 | { | ||
133 | u8 val; | ||
134 | int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val); | ||
135 | /* FFT Mode, 00:2K, 01:8K, 10:4K */ | ||
136 | if (mxl_fail(ret)) | ||
137 | goto fail; | ||
138 | |||
139 | switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) { | ||
140 | case 0: | ||
141 | *fft_mode = TRANSMISSION_MODE_2K; | ||
142 | break; | ||
143 | case 1: | ||
144 | *fft_mode = TRANSMISSION_MODE_8K; | ||
145 | break; | ||
146 | case 2: | ||
147 | *fft_mode = TRANSMISSION_MODE_4K; | ||
148 | break; | ||
149 | } | ||
150 | fail: | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static | ||
155 | int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state, | ||
156 | fe_guard_interval_t *guard) | ||
157 | { | ||
158 | u8 val; | ||
159 | int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val); | ||
160 | /* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */ | ||
161 | if (mxl_fail(ret)) | ||
162 | goto fail; | ||
163 | |||
164 | switch ((val & V6_PARAM_GI_MASK) >> 4) { | ||
165 | case 0: | ||
166 | *guard = GUARD_INTERVAL_1_32; | ||
167 | break; | ||
168 | case 1: | ||
169 | *guard = GUARD_INTERVAL_1_16; | ||
170 | break; | ||
171 | case 2: | ||
172 | *guard = GUARD_INTERVAL_1_8; | ||
173 | break; | ||
174 | case 3: | ||
175 | *guard = GUARD_INTERVAL_1_4; | ||
176 | break; | ||
177 | } | ||
178 | fail: | ||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | static | ||
183 | int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state, | ||
184 | fe_hierarchy_t *hierarchy) | ||
185 | { | ||
186 | u8 val; | ||
187 | int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val); | ||
188 | /* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */ | ||
189 | if (mxl_fail(ret)) | ||
190 | goto fail; | ||
191 | |||
192 | switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) { | ||
193 | case 0: | ||
194 | *hierarchy = HIERARCHY_NONE; | ||
195 | break; | ||
196 | case 1: | ||
197 | *hierarchy = HIERARCHY_1; | ||
198 | break; | ||
199 | case 2: | ||
200 | *hierarchy = HIERARCHY_2; | ||
201 | break; | ||
202 | case 3: | ||
203 | *hierarchy = HIERARCHY_4; | ||
204 | break; | ||
205 | } | ||
206 | fail: | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | /* ------------------------------------------------------------------------ */ | ||
211 | /* LOCKS */ | ||
212 | |||
213 | static | ||
214 | int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state, | ||
215 | int *sync_lock) | ||
216 | { | ||
217 | u8 val = 0; | ||
218 | int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val); | ||
219 | if (mxl_fail(ret)) | ||
220 | goto fail; | ||
221 | *sync_lock = (val & SYNC_LOCK_MASK) >> 4; | ||
222 | fail: | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | static | ||
227 | int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state, | ||
228 | int *rs_lock) | ||
229 | { | ||
230 | u8 val = 0; | ||
231 | int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val); | ||
232 | if (mxl_fail(ret)) | ||
233 | goto fail; | ||
234 | *rs_lock = (val & RS_LOCK_DET_MASK) >> 3; | ||
235 | fail: | ||
236 | return ret; | ||
237 | } | ||
238 | |||
239 | static | ||
240 | int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state, | ||
241 | int *tps_lock) | ||
242 | { | ||
243 | u8 val = 0; | ||
244 | int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val); | ||
245 | if (mxl_fail(ret)) | ||
246 | goto fail; | ||
247 | *tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6; | ||
248 | fail: | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | static | ||
253 | int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state, | ||
254 | int *fec_lock) | ||
255 | { | ||
256 | u8 val = 0; | ||
257 | int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val); | ||
258 | if (mxl_fail(ret)) | ||
259 | goto fail; | ||
260 | *fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4; | ||
261 | fail: | ||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | #if 0 | ||
266 | static | ||
267 | int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state, | ||
268 | int *cp_lock) | ||
269 | { | ||
270 | u8 val = 0; | ||
271 | int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val); | ||
272 | if (mxl_fail(ret)) | ||
273 | goto fail; | ||
274 | *cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2; | ||
275 | fail: | ||
276 | return ret; | ||
277 | } | ||
278 | #endif | ||
279 | |||
280 | static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state) | ||
281 | { | ||
282 | return mxl111sf_demod_write_reg(state, 0x0e, 0xff); | ||
283 | } | ||
284 | |||
285 | /* ------------------------------------------------------------------------ */ | ||
286 | |||
287 | static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe, | ||
288 | struct dvb_frontend_parameters *param) | ||
289 | { | ||
290 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
291 | int ret = 0; | ||
292 | |||
293 | struct mxl111sf_reg_ctrl_info phy_pll_patch[] = { | ||
294 | {0x00, 0xff, 0x01}, /* change page to 1 */ | ||
295 | {0x40, 0xff, 0x05}, | ||
296 | {0x40, 0xff, 0x01}, | ||
297 | {0x41, 0xff, 0xca}, | ||
298 | {0x41, 0xff, 0xc0}, | ||
299 | {0x00, 0xff, 0x00}, /* change page to 0 */ | ||
300 | {0, 0, 0} | ||
301 | }; | ||
302 | |||
303 | mxl_dbg("()"); | ||
304 | |||
305 | if (fe->ops.tuner_ops.set_params) { | ||
306 | ret = fe->ops.tuner_ops.set_params(fe, param); | ||
307 | if (mxl_fail(ret)) | ||
308 | goto fail; | ||
309 | msleep(50); | ||
310 | } | ||
311 | ret = mxl111sf_demod_program_regs(state, phy_pll_patch); | ||
312 | mxl_fail(ret); | ||
313 | msleep(50); | ||
314 | ret = mxl1x1sf_demod_reset_irq_status(state); | ||
315 | mxl_fail(ret); | ||
316 | msleep(100); | ||
317 | fail: | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | /* ------------------------------------------------------------------------ */ | ||
322 | |||
323 | #if 0 | ||
324 | /* resets TS Packet error count */ | ||
325 | /* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */ | ||
326 | static | ||
327 | int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state) | ||
328 | { | ||
329 | struct mxl111sf_reg_ctrl_info reset_per_count[] = { | ||
330 | {0x20, 0x01, 0x01}, | ||
331 | {0x20, 0x01, 0x00}, | ||
332 | {0, 0, 0} | ||
333 | }; | ||
334 | return mxl111sf_demod_program_regs(state, reset_per_count); | ||
335 | } | ||
336 | #endif | ||
337 | |||
338 | /* returns TS Packet error count */ | ||
339 | /* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */ | ||
340 | static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
341 | { | ||
342 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
343 | u32 fec_per_count, fec_per_scale; | ||
344 | u8 val; | ||
345 | int ret; | ||
346 | |||
347 | *ucblocks = 0; | ||
348 | |||
349 | /* FEC_PER_COUNT Register */ | ||
350 | ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val); | ||
351 | if (mxl_fail(ret)) | ||
352 | goto fail; | ||
353 | |||
354 | fec_per_count = val; | ||
355 | |||
356 | /* FEC_PER_SCALE Register */ | ||
357 | ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val); | ||
358 | if (mxl_fail(ret)) | ||
359 | goto fail; | ||
360 | |||
361 | val &= V6_FEC_PER_SCALE_MASK; | ||
362 | val *= 4; | ||
363 | |||
364 | fec_per_scale = 1 << val; | ||
365 | |||
366 | fec_per_count *= fec_per_scale; | ||
367 | |||
368 | *ucblocks = fec_per_count; | ||
369 | fail: | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | #ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS | ||
374 | /* FIXME: leaving this enabled breaks the build on some architectures, | ||
375 | * and we shouldn't have any floating point math in the kernel, anyway. | ||
376 | * | ||
377 | * These macros need to be re-written, but it's harmless to simply | ||
378 | * return zero for now. */ | ||
379 | #define CALCULATE_BER(avg_errors, count) \ | ||
380 | ((u32)(avg_errors * 4)/(count*64*188*8)) | ||
381 | #define CALCULATE_SNR(data) \ | ||
382 | ((u32)((10 * (u32)data / 64) - 2.5)) | ||
383 | #else | ||
384 | #define CALCULATE_BER(avg_errors, count) 0 | ||
385 | #define CALCULATE_SNR(data) 0 | ||
386 | #endif | ||
387 | |||
388 | static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
389 | { | ||
390 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
391 | u8 val1, val2, val3; | ||
392 | int ret; | ||
393 | |||
394 | *ber = 0; | ||
395 | |||
396 | ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1); | ||
397 | if (mxl_fail(ret)) | ||
398 | goto fail; | ||
399 | ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2); | ||
400 | if (mxl_fail(ret)) | ||
401 | goto fail; | ||
402 | ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3); | ||
403 | if (mxl_fail(ret)) | ||
404 | goto fail; | ||
405 | |||
406 | *ber = CALCULATE_BER((val1 | (val2 << 8)), val3); | ||
407 | fail: | ||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state, | ||
412 | u16 *snr) | ||
413 | { | ||
414 | u8 val1, val2; | ||
415 | int ret; | ||
416 | |||
417 | *snr = 0; | ||
418 | |||
419 | ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1); | ||
420 | if (mxl_fail(ret)) | ||
421 | goto fail; | ||
422 | ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2); | ||
423 | if (mxl_fail(ret)) | ||
424 | goto fail; | ||
425 | |||
426 | *snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8)); | ||
427 | fail: | ||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
432 | { | ||
433 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
434 | |||
435 | int ret = mxl111sf_demod_calc_snr(state, snr); | ||
436 | if (mxl_fail(ret)) | ||
437 | goto fail; | ||
438 | |||
439 | *snr /= 10; /* 0.1 dB */ | ||
440 | fail: | ||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | static int mxl111sf_demod_read_status(struct dvb_frontend *fe, | ||
445 | fe_status_t *status) | ||
446 | { | ||
447 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
448 | int ret, locked, cr_lock, sync_lock, fec_lock; | ||
449 | |||
450 | *status = 0; | ||
451 | |||
452 | ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked); | ||
453 | if (mxl_fail(ret)) | ||
454 | goto fail; | ||
455 | ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock); | ||
456 | if (mxl_fail(ret)) | ||
457 | goto fail; | ||
458 | ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock); | ||
459 | if (mxl_fail(ret)) | ||
460 | goto fail; | ||
461 | ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock); | ||
462 | if (mxl_fail(ret)) | ||
463 | goto fail; | ||
464 | |||
465 | if (locked) | ||
466 | *status |= FE_HAS_SIGNAL; | ||
467 | if (cr_lock) | ||
468 | *status |= FE_HAS_CARRIER; | ||
469 | if (sync_lock) | ||
470 | *status |= FE_HAS_SYNC; | ||
471 | if (fec_lock) /* false positives? */ | ||
472 | *status |= FE_HAS_VITERBI; | ||
473 | |||
474 | if ((locked) && (cr_lock) && (sync_lock)) | ||
475 | *status |= FE_HAS_LOCK; | ||
476 | fail: | ||
477 | return ret; | ||
478 | } | ||
479 | |||
480 | static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, | ||
481 | u16 *signal_strength) | ||
482 | { | ||
483 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
484 | fe_modulation_t constellation; | ||
485 | u16 snr; | ||
486 | |||
487 | mxl111sf_demod_calc_snr(state, &snr); | ||
488 | mxl1x1sf_demod_get_tps_constellation(state, &constellation); | ||
489 | |||
490 | switch (constellation) { | ||
491 | case QPSK: | ||
492 | *signal_strength = (snr >= 1300) ? | ||
493 | min(65535, snr * 44) : snr * 38; | ||
494 | break; | ||
495 | case QAM_16: | ||
496 | *signal_strength = (snr >= 1500) ? | ||
497 | min(65535, snr * 38) : snr * 33; | ||
498 | break; | ||
499 | case QAM_64: | ||
500 | *signal_strength = (snr >= 2000) ? | ||
501 | min(65535, snr * 29) : snr * 25; | ||
502 | break; | ||
503 | default: | ||
504 | *signal_strength = 0; | ||
505 | return -EINVAL; | ||
506 | } | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe, | ||
512 | struct dvb_frontend_parameters *p) | ||
513 | { | ||
514 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
515 | |||
516 | mxl_dbg("()"); | ||
517 | #if 0 | ||
518 | p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF; | ||
519 | #endif | ||
520 | if (fe->ops.tuner_ops.get_bandwidth) | ||
521 | fe->ops.tuner_ops.get_bandwidth(fe, &p->u.ofdm.bandwidth); | ||
522 | if (fe->ops.tuner_ops.get_frequency) | ||
523 | fe->ops.tuner_ops.get_frequency(fe, &p->frequency); | ||
524 | mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_HP); | ||
525 | mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_LP); | ||
526 | mxl1x1sf_demod_get_tps_constellation(state, &p->u.ofdm.constellation); | ||
527 | mxl1x1sf_demod_get_tps_guard_fft_mode(state, | ||
528 | &p->u.ofdm.transmission_mode); | ||
529 | mxl1x1sf_demod_get_tps_guard_interval(state, | ||
530 | &p->u.ofdm.guard_interval); | ||
531 | mxl1x1sf_demod_get_tps_hierarchy(state, | ||
532 | &p->u.ofdm.hierarchy_information); | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static | ||
538 | int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe, | ||
539 | struct dvb_frontend_tune_settings *tune) | ||
540 | { | ||
541 | tune->min_delay_ms = 1000; | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static void mxl111sf_demod_release(struct dvb_frontend *fe) | ||
546 | { | ||
547 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
548 | mxl_dbg("()"); | ||
549 | kfree(state); | ||
550 | fe->demodulator_priv = NULL; | ||
551 | } | ||
552 | |||
553 | static struct dvb_frontend_ops mxl111sf_demod_ops = { | ||
554 | |||
555 | .info = { | ||
556 | .name = "MaxLinear MxL111SF DVB-T demodulator", | ||
557 | .type = FE_OFDM, | ||
558 | .frequency_min = 177000000, | ||
559 | .frequency_max = 858000000, | ||
560 | .frequency_stepsize = 166666, | ||
561 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
562 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
563 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | | ||
564 | FE_CAN_QAM_AUTO | | ||
565 | FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | | ||
566 | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER | ||
567 | }, | ||
568 | .release = mxl111sf_demod_release, | ||
569 | #if 0 | ||
570 | .init = mxl111sf_init, | ||
571 | .i2c_gate_ctrl = mxl111sf_i2c_gate_ctrl, | ||
572 | #endif | ||
573 | .set_frontend = mxl111sf_demod_set_frontend, | ||
574 | .get_frontend = mxl111sf_demod_get_frontend, | ||
575 | .get_tune_settings = mxl111sf_demod_get_tune_settings, | ||
576 | .read_status = mxl111sf_demod_read_status, | ||
577 | .read_signal_strength = mxl111sf_demod_read_signal_strength, | ||
578 | .read_ber = mxl111sf_demod_read_ber, | ||
579 | .read_snr = mxl111sf_demod_read_snr, | ||
580 | .read_ucblocks = mxl111sf_demod_read_ucblocks, | ||
581 | }; | ||
582 | |||
583 | struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, | ||
584 | struct mxl111sf_demod_config *cfg) | ||
585 | { | ||
586 | struct mxl111sf_demod_state *state = NULL; | ||
587 | |||
588 | mxl_dbg("()"); | ||
589 | |||
590 | state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL); | ||
591 | if (state == NULL) | ||
592 | return NULL; | ||
593 | |||
594 | state->mxl_state = mxl_state; | ||
595 | state->cfg = cfg; | ||
596 | |||
597 | memcpy(&state->fe.ops, &mxl111sf_demod_ops, | ||
598 | sizeof(struct dvb_frontend_ops)); | ||
599 | |||
600 | state->fe.demodulator_priv = state; | ||
601 | return &state->fe; | ||
602 | } | ||
603 | EXPORT_SYMBOL_GPL(mxl111sf_demod_attach); | ||
604 | |||
605 | MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver"); | ||
606 | MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>"); | ||
607 | MODULE_LICENSE("GPL"); | ||
608 | MODULE_VERSION("0.1"); | ||
609 | |||
610 | /* | ||
611 | * Local variables: | ||
612 | * c-basic-offset: 8 | ||
613 | * End: | ||
614 | */ | ||
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.h b/drivers/media/dvb/dvb-usb/mxl111sf-demod.h new file mode 100644 index 000000000000..432706ae5274 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator | ||
3 | * | ||
4 | * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> | ||
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 | #ifndef __MXL111SF_DEMOD_H__ | ||
22 | #define __MXL111SF_DEMOD_H__ | ||
23 | |||
24 | #include "dvb_frontend.h" | ||
25 | #include "mxl111sf.h" | ||
26 | |||
27 | struct mxl111sf_demod_config { | ||
28 | int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); | ||
29 | int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); | ||
30 | int (*program_regs)(struct mxl111sf_state *state, | ||
31 | struct mxl111sf_reg_ctrl_info *ctrl_reg_info); | ||
32 | }; | ||
33 | |||
34 | #if defined(CONFIG_DVB_USB_MXL111SF) || \ | ||
35 | (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) | ||
36 | extern | ||
37 | struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, | ||
38 | struct mxl111sf_demod_config *cfg); | ||
39 | #else | ||
40 | static inline | ||
41 | struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, | ||
42 | struct mxl111sf_demod_config *cfg) | ||
43 | { | ||
44 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
45 | return NULL; | ||
46 | } | ||
47 | #endif /* CONFIG_DVB_USB_MXL111SF */ | ||
48 | |||
49 | #endif /* __MXL111SF_DEMOD_H__ */ | ||
50 | |||
51 | /* | ||
52 | * Local variables: | ||
53 | * c-basic-offset: 8 | ||
54 | * End: | ||
55 | */ | ||
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c index 546ba5915a5b..b5c98da5d9e2 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "mxl111sf-i2c.h" | 17 | #include "mxl111sf-i2c.h" |
18 | #include "mxl111sf-gpio.h" | 18 | #include "mxl111sf-gpio.h" |
19 | 19 | ||
20 | #include "mxl111sf-demod.h" | ||
20 | #include "mxl111sf-tuner.h" | 21 | #include "mxl111sf-tuner.h" |
21 | 22 | ||
22 | #include "lgdt3305.h" | 23 | #include "lgdt3305.h" |
@@ -362,6 +363,22 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | |||
362 | return ret; | 363 | return ret; |
363 | } | 364 | } |
364 | 365 | ||
366 | static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | ||
367 | { | ||
368 | struct dvb_usb_device *d = adap->dev; | ||
369 | struct mxl111sf_state *state = d->priv; | ||
370 | int ret = 0; | ||
371 | |||
372 | deb_info("%s(%d)\n", __func__, onoff); | ||
373 | |||
374 | if (onoff) { | ||
375 | ret = mxl111sf_enable_usb_output(state); | ||
376 | mxl_fail(ret); | ||
377 | } | ||
378 | |||
379 | return ret; | ||
380 | } | ||
381 | |||
365 | /* ------------------------------------------------------------------------ */ | 382 | /* ------------------------------------------------------------------------ */ |
366 | 383 | ||
367 | static struct lgdt3305_config hauppauge_lgdt3305_config = { | 384 | static struct lgdt3305_config hauppauge_lgdt3305_config = { |
@@ -438,6 +455,70 @@ fail: | |||
438 | return ret; | 455 | return ret; |
439 | } | 456 | } |
440 | 457 | ||
458 | static struct mxl111sf_demod_config mxl_demod_config = { | ||
459 | .read_reg = mxl111sf_read_reg, | ||
460 | .write_reg = mxl111sf_write_reg, | ||
461 | .program_regs = mxl111sf_ctrl_program_regs, | ||
462 | }; | ||
463 | |||
464 | static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap) | ||
465 | { | ||
466 | struct dvb_usb_device *d = adap->dev; | ||
467 | struct mxl111sf_state *state = d->priv; | ||
468 | int fe_id = adap->num_frontends_initialized; | ||
469 | struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; | ||
470 | int ret; | ||
471 | |||
472 | deb_adv("%s()\n", __func__); | ||
473 | |||
474 | /* save a pointer to the dvb_usb_device in device state */ | ||
475 | state->d = d; | ||
476 | adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2; | ||
477 | state->alt_mode = adap_state->alt_mode; | ||
478 | |||
479 | if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) | ||
480 | err("set interface failed"); | ||
481 | |||
482 | state->gpio_mode = MXL111SF_GPIO_MOD_DVBT; | ||
483 | adap_state->gpio_mode = state->gpio_mode; | ||
484 | adap_state->device_mode = MXL_SOC_MODE; | ||
485 | adap_state->ep6_clockphase = 1; | ||
486 | |||
487 | ret = mxl1x1sf_soft_reset(state); | ||
488 | if (mxl_fail(ret)) | ||
489 | goto fail; | ||
490 | ret = mxl111sf_init_tuner_demod(state); | ||
491 | if (mxl_fail(ret)) | ||
492 | goto fail; | ||
493 | |||
494 | ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); | ||
495 | if (mxl_fail(ret)) | ||
496 | goto fail; | ||
497 | |||
498 | ret = mxl111sf_enable_usb_output(state); | ||
499 | if (mxl_fail(ret)) | ||
500 | goto fail; | ||
501 | ret = mxl1x1sf_top_master_ctrl(state, 1); | ||
502 | if (mxl_fail(ret)) | ||
503 | goto fail; | ||
504 | |||
505 | /* dont care if this fails */ | ||
506 | mxl111sf_init_port_expander(state); | ||
507 | |||
508 | adap->fe_adap[fe_id].fe = dvb_attach(mxl111sf_demod_attach, state, | ||
509 | &mxl_demod_config); | ||
510 | if (adap->fe_adap[fe_id].fe) { | ||
511 | adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; | ||
512 | adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; | ||
513 | adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; | ||
514 | adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; | ||
515 | return 0; | ||
516 | } | ||
517 | ret = -EIO; | ||
518 | fail: | ||
519 | return ret; | ||
520 | } | ||
521 | |||
441 | static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, | 522 | static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, |
442 | int antpath) | 523 | int antpath) |
443 | { | 524 | { |
@@ -567,7 +648,8 @@ struct i2c_algorithm mxl111sf_i2c_algo = { | |||
567 | #endif | 648 | #endif |
568 | }; | 649 | }; |
569 | 650 | ||
570 | /* DVB USB Driver stuff */ | 651 | static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties; |
652 | static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties; | ||
571 | static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties; | 653 | static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties; |
572 | static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties; | 654 | static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties; |
573 | 655 | ||
@@ -580,9 +662,15 @@ static int mxl111sf_probe(struct usb_interface *intf, | |||
580 | 662 | ||
581 | if (((dvb_usb_mxl111sf_isoc) && | 663 | if (((dvb_usb_mxl111sf_isoc) && |
582 | (0 == dvb_usb_device_init(intf, | 664 | (0 == dvb_usb_device_init(intf, |
665 | &mxl111sf_dvbt_isoc_properties, | ||
666 | THIS_MODULE, &d, adapter_nr) || | ||
667 | 0 == dvb_usb_device_init(intf, | ||
583 | &mxl111sf_atsc_isoc_properties, | 668 | &mxl111sf_atsc_isoc_properties, |
584 | THIS_MODULE, &d, adapter_nr))) || | 669 | THIS_MODULE, &d, adapter_nr))) || |
585 | 0 == dvb_usb_device_init(intf, | 670 | 0 == dvb_usb_device_init(intf, |
671 | &mxl111sf_dvbt_bulk_properties, | ||
672 | THIS_MODULE, &d, adapter_nr) || | ||
673 | 0 == dvb_usb_device_init(intf, | ||
586 | &mxl111sf_atsc_bulk_properties, | 674 | &mxl111sf_atsc_bulk_properties, |
587 | THIS_MODULE, &d, adapter_nr) || 0) { | 675 | THIS_MODULE, &d, adapter_nr) || 0) { |
588 | 676 | ||
@@ -669,6 +757,36 @@ static struct usb_device_id mxl111sf_table[] = { | |||
669 | MODULE_DEVICE_TABLE(usb, mxl111sf_table); | 757 | MODULE_DEVICE_TABLE(usb, mxl111sf_table); |
670 | 758 | ||
671 | 759 | ||
760 | #define MXL111SF_EP4_BULK_STREAMING_CONFIG \ | ||
761 | .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ | ||
762 | .stream = { \ | ||
763 | .type = USB_BULK, \ | ||
764 | .count = 5, \ | ||
765 | .endpoint = 0x04, \ | ||
766 | .u = { \ | ||
767 | .bulk = { \ | ||
768 | .buffersize = 8192, \ | ||
769 | } \ | ||
770 | } \ | ||
771 | } | ||
772 | |||
773 | /* FIXME: works for v6 but not v8 silicon */ | ||
774 | #define MXL111SF_EP4_ISOC_STREAMING_CONFIG \ | ||
775 | .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ | ||
776 | .stream = { \ | ||
777 | .type = USB_ISOC, \ | ||
778 | .count = 5, \ | ||
779 | .endpoint = 0x04, \ | ||
780 | .u = { \ | ||
781 | .isoc = { \ | ||
782 | .framesperurb = 96, \ | ||
783 | /* FIXME: v6 SILICON: */ \ | ||
784 | .framesize = 564, \ | ||
785 | .interval = 1, \ | ||
786 | } \ | ||
787 | } \ | ||
788 | } | ||
789 | |||
672 | #define MXL111SF_EP6_BULK_STREAMING_CONFIG \ | 790 | #define MXL111SF_EP6_BULK_STREAMING_CONFIG \ |
673 | .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ | 791 | .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ |
674 | .stream = { \ | 792 | .stream = { \ |
@@ -712,7 +830,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); | |||
712 | .generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \ | 830 | .generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \ |
713 | .size_of_priv = sizeof(struct mxl111sf_state) | 831 | .size_of_priv = sizeof(struct mxl111sf_state) |
714 | 832 | ||
715 | static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { | 833 | static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = { |
716 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, | 834 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, |
717 | 835 | ||
718 | .num_adapters = 1, | 836 | .num_adapters = 1, |
@@ -723,10 +841,106 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { | |||
723 | .fe = {{ | 841 | .fe = {{ |
724 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | 842 | .size_of_priv = sizeof(struct mxl111sf_adap_state), |
725 | 843 | ||
844 | .frontend_attach = mxl111sf_attach_demod, | ||
845 | .tuner_attach = mxl111sf_attach_tuner, | ||
846 | |||
847 | MXL111SF_EP4_BULK_STREAMING_CONFIG, | ||
848 | } }, | ||
849 | }, | ||
850 | }, | ||
851 | .num_device_descs = 4, | ||
852 | .devices = { | ||
853 | { "Hauppauge 126xxx DVBT (bulk)", | ||
854 | { NULL }, | ||
855 | { &mxl111sf_table[4], &mxl111sf_table[8], | ||
856 | NULL }, | ||
857 | }, | ||
858 | { "Hauppauge 117xxx DVBT (bulk)", | ||
859 | { NULL }, | ||
860 | { &mxl111sf_table[15], &mxl111sf_table[18], | ||
861 | NULL }, | ||
862 | }, | ||
863 | { "Hauppauge 138xxx DVBT (bulk)", | ||
864 | { NULL }, | ||
865 | { &mxl111sf_table[20], &mxl111sf_table[22], | ||
866 | &mxl111sf_table[24], &mxl111sf_table[26], | ||
867 | NULL }, | ||
868 | }, | ||
869 | { "Hauppauge 126xxx (tp-bulk)", | ||
870 | { NULL }, | ||
871 | { &mxl111sf_table[28], &mxl111sf_table[30], | ||
872 | NULL }, | ||
873 | }, | ||
874 | } | ||
875 | }; | ||
876 | |||
877 | static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = { | ||
878 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, | ||
879 | |||
880 | .num_adapters = 1, | ||
881 | .adapter = { | ||
882 | { | ||
883 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, | ||
884 | .num_frontends = 1, | ||
885 | .fe = {{ | ||
886 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | ||
887 | |||
888 | .frontend_attach = mxl111sf_attach_demod, | ||
889 | .tuner_attach = mxl111sf_attach_tuner, | ||
890 | |||
891 | MXL111SF_EP4_ISOC_STREAMING_CONFIG, | ||
892 | } }, | ||
893 | }, | ||
894 | }, | ||
895 | .num_device_descs = 4, | ||
896 | .devices = { | ||
897 | { "Hauppauge 126xxx DVBT (isoc)", | ||
898 | { NULL }, | ||
899 | { &mxl111sf_table[4], &mxl111sf_table[8], | ||
900 | NULL }, | ||
901 | }, | ||
902 | { "Hauppauge 117xxx DVBT (isoc)", | ||
903 | { NULL }, | ||
904 | { &mxl111sf_table[15], &mxl111sf_table[18], | ||
905 | NULL }, | ||
906 | }, | ||
907 | { "Hauppauge 138xxx DVBT (isoc)", | ||
908 | { NULL }, | ||
909 | { &mxl111sf_table[20], &mxl111sf_table[22], | ||
910 | &mxl111sf_table[24], &mxl111sf_table[26], | ||
911 | NULL }, | ||
912 | }, | ||
913 | { "Hauppauge 126xxx (tp-isoc)", | ||
914 | { NULL }, | ||
915 | { &mxl111sf_table[28], &mxl111sf_table[30], | ||
916 | NULL }, | ||
917 | }, | ||
918 | } | ||
919 | }; | ||
920 | |||
921 | static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { | ||
922 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, | ||
923 | |||
924 | .num_adapters = 1, | ||
925 | .adapter = { | ||
926 | { | ||
927 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, | ||
928 | .num_frontends = 2, | ||
929 | .fe = {{ | ||
930 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | ||
931 | |||
726 | .frontend_attach = mxl111sf_lgdt3305_frontend_attach, | 932 | .frontend_attach = mxl111sf_lgdt3305_frontend_attach, |
727 | .tuner_attach = mxl111sf_attach_tuner, | 933 | .tuner_attach = mxl111sf_attach_tuner, |
728 | 934 | ||
729 | MXL111SF_EP6_BULK_STREAMING_CONFIG, | 935 | MXL111SF_EP6_BULK_STREAMING_CONFIG, |
936 | }, | ||
937 | { | ||
938 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | ||
939 | |||
940 | .frontend_attach = mxl111sf_attach_demod, | ||
941 | .tuner_attach = mxl111sf_attach_tuner, | ||
942 | |||
943 | MXL111SF_EP4_BULK_STREAMING_CONFIG, | ||
730 | }}, | 944 | }}, |
731 | }, | 945 | }, |
732 | }, | 946 | }, |
@@ -776,7 +990,7 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { | |||
776 | .adapter = { | 990 | .adapter = { |
777 | { | 991 | { |
778 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, | 992 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, |
779 | .num_frontends = 1, | 993 | .num_frontends = 2, |
780 | .fe = {{ | 994 | .fe = {{ |
781 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | 995 | .size_of_priv = sizeof(struct mxl111sf_adap_state), |
782 | 996 | ||
@@ -784,6 +998,14 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { | |||
784 | .tuner_attach = mxl111sf_attach_tuner, | 998 | .tuner_attach = mxl111sf_attach_tuner, |
785 | 999 | ||
786 | MXL111SF_EP6_ISOC_STREAMING_CONFIG, | 1000 | MXL111SF_EP6_ISOC_STREAMING_CONFIG, |
1001 | }, | ||
1002 | { | ||
1003 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | ||
1004 | |||
1005 | .frontend_attach = mxl111sf_attach_demod, | ||
1006 | .tuner_attach = mxl111sf_attach_tuner, | ||
1007 | |||
1008 | MXL111SF_EP4_ISOC_STREAMING_CONFIG, | ||
787 | }}, | 1009 | }}, |
788 | }, | 1010 | }, |
789 | }, | 1011 | }, |
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.h b/drivers/media/dvb/dvb-usb/mxl111sf.h index 5a2c7bb386cd..364d89f826bd 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.h +++ b/drivers/media/dvb/dvb-usb/mxl111sf.h | |||
@@ -133,7 +133,7 @@ extern int dvb_usb_mxl111sf_debug; | |||
133 | /* The following allows the mxl_fail() macro defined below to work | 133 | /* The following allows the mxl_fail() macro defined below to work |
134 | * in externel modules, such as mxl111sf-tuner.ko, even though | 134 | * in externel modules, such as mxl111sf-tuner.ko, even though |
135 | * dvb_usb_mxl111sf_debug is not defined within those modules */ | 135 | * dvb_usb_mxl111sf_debug is not defined within those modules */ |
136 | #ifdef __MXL111SF_TUNER_H__ | 136 | #if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__)) |
137 | #define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG | 137 | #define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG |
138 | #else | 138 | #else |
139 | #define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug | 139 | #define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug |
diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile index 89873615e683..13ebeffb705f 100644 --- a/drivers/media/dvb/ngene/Makefile +++ b/drivers/media/dvb/ngene/Makefile | |||
@@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/dvb/frontends/ | |||
11 | ccflags-y += -Idrivers/media/common/tuners/ | 11 | ccflags-y += -Idrivers/media/common/tuners/ |
12 | 12 | ||
13 | # For the staging CI driver cxd2099 | 13 | # For the staging CI driver cxd2099 |
14 | ccflags-y += -Idrivers/staging/cxd2099/ | 14 | ccflags-y += -Idrivers/staging/media/cxd2099/ |
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 95ddcc4845d3..db20904d01f0 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c | |||
@@ -128,8 +128,10 @@ struct tea5764_write_regs { | |||
128 | u16 rdsbbl; /* PAUSEDET & RDSBBL */ | 128 | u16 rdsbbl; /* PAUSEDET & RDSBBL */ |
129 | } __attribute__ ((packed)); | 129 | } __attribute__ ((packed)); |
130 | 130 | ||
131 | #ifndef RADIO_TEA5764_XTAL | 131 | #ifdef CONFIG_RADIO_TEA5764_XTAL |
132 | #define RADIO_TEA5764_XTAL 1 | 132 | #define RADIO_TEA5764_XTAL 1 |
133 | #else | ||
134 | #define RADIO_TEA5764_XTAL 0 | ||
133 | #endif | 135 | #endif |
134 | 136 | ||
135 | static int radio_nr = -1; | 137 | static int radio_nr = -1; |
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index d285c8c92819..b303a3f8a9f8 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -517,6 +517,13 @@ config VIDEO_NOON010PC30 | |||
517 | 517 | ||
518 | source "drivers/media/video/m5mols/Kconfig" | 518 | source "drivers/media/video/m5mols/Kconfig" |
519 | 519 | ||
520 | config VIDEO_S5K6AA | ||
521 | tristate "Samsung S5K6AAFX sensor support" | ||
522 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
523 | ---help--- | ||
524 | This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M | ||
525 | camera sensor with an embedded SoC image signal processor. | ||
526 | |||
520 | comment "Flash devices" | 527 | comment "Flash devices" |
521 | 528 | ||
522 | config VIDEO_ADP1653 | 529 | config VIDEO_ADP1653 |
@@ -736,6 +743,8 @@ source "drivers/media/video/cx88/Kconfig" | |||
736 | 743 | ||
737 | source "drivers/media/video/cx23885/Kconfig" | 744 | source "drivers/media/video/cx23885/Kconfig" |
738 | 745 | ||
746 | source "drivers/media/video/cx25821/Kconfig" | ||
747 | |||
739 | source "drivers/media/video/au0828/Kconfig" | 748 | source "drivers/media/video/au0828/Kconfig" |
740 | 749 | ||
741 | source "drivers/media/video/ivtv/Kconfig" | 750 | source "drivers/media/video/ivtv/Kconfig" |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 11fff97e7196..117f9c4b4cb9 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -72,6 +72,7 @@ obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o | |||
72 | obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o | 72 | obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o |
73 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o | 73 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o |
74 | obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ | 74 | obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ |
75 | obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o | ||
75 | obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o | 76 | obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o |
76 | 77 | ||
77 | obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o | 78 | obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o |
@@ -104,6 +105,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/ | |||
104 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ | 105 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ |
105 | obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/ | 106 | obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/ |
106 | obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ | 107 | obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ |
108 | obj-$(CONFIG_VIDEO_CX25821) += cx25821/ | ||
107 | obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ | 109 | obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ |
108 | obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ | 110 | obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ |
109 | obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ | 111 | obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ |
diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c index 774715d2f84f..8c775c59e120 100644 --- a/drivers/media/video/atmel-isi.c +++ b/drivers/media/video/atmel-isi.c | |||
@@ -94,6 +94,7 @@ struct atmel_isi { | |||
94 | unsigned int irq; | 94 | unsigned int irq; |
95 | 95 | ||
96 | struct isi_platform_data *pdata; | 96 | struct isi_platform_data *pdata; |
97 | u16 width_flags; /* max 12 bits */ | ||
97 | 98 | ||
98 | struct list_head video_buffer_list; | 99 | struct list_head video_buffer_list; |
99 | struct frame_buffer *active; | 100 | struct frame_buffer *active; |
@@ -248,9 +249,9 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) | |||
248 | /* ------------------------------------------------------------------ | 249 | /* ------------------------------------------------------------------ |
249 | Videobuf operations | 250 | Videobuf operations |
250 | ------------------------------------------------------------------*/ | 251 | ------------------------------------------------------------------*/ |
251 | static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | 252 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, |
252 | unsigned int *nplanes, unsigned int sizes[], | 253 | unsigned int *nbuffers, unsigned int *nplanes, |
253 | void *alloc_ctxs[]) | 254 | unsigned int sizes[], void *alloc_ctxs[]) |
254 | { | 255 | { |
255 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | 256 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); |
256 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 257 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
@@ -647,50 +648,42 @@ static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) | |||
647 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | 648 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); |
648 | } | 649 | } |
649 | 650 | ||
650 | static unsigned long make_bus_param(struct atmel_isi *isi) | 651 | #define ISI_BUS_PARAM (V4L2_MBUS_MASTER | \ |
651 | { | 652 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ |
652 | unsigned long flags; | 653 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ |
653 | /* | 654 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ |
654 | * Platform specified synchronization and pixel clock polarities are | 655 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ |
655 | * only a recommendation and are only used during probing. Atmel ISI | 656 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ |
656 | * camera interface only works in master mode, i.e., uses HSYNC and | 657 | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ |
657 | * VSYNC signals from the sensor | 658 | V4L2_MBUS_DATA_ACTIVE_HIGH) |
658 | */ | ||
659 | flags = SOCAM_MASTER | | ||
660 | SOCAM_HSYNC_ACTIVE_HIGH | | ||
661 | SOCAM_HSYNC_ACTIVE_LOW | | ||
662 | SOCAM_VSYNC_ACTIVE_HIGH | | ||
663 | SOCAM_VSYNC_ACTIVE_LOW | | ||
664 | SOCAM_PCLK_SAMPLE_RISING | | ||
665 | SOCAM_PCLK_SAMPLE_FALLING | | ||
666 | SOCAM_DATA_ACTIVE_HIGH; | ||
667 | |||
668 | if (isi->pdata->data_width_flags & ISI_DATAWIDTH_10) | ||
669 | flags |= SOCAM_DATAWIDTH_10; | ||
670 | |||
671 | if (isi->pdata->data_width_flags & ISI_DATAWIDTH_8) | ||
672 | flags |= SOCAM_DATAWIDTH_8; | ||
673 | |||
674 | if (flags & SOCAM_DATAWIDTH_MASK) | ||
675 | return flags; | ||
676 | |||
677 | return 0; | ||
678 | } | ||
679 | 659 | ||
680 | static int isi_camera_try_bus_param(struct soc_camera_device *icd, | 660 | static int isi_camera_try_bus_param(struct soc_camera_device *icd, |
681 | unsigned char buswidth) | 661 | unsigned char buswidth) |
682 | { | 662 | { |
663 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
683 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 664 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
684 | struct atmel_isi *isi = ici->priv; | 665 | struct atmel_isi *isi = ici->priv; |
685 | unsigned long camera_flags; | 666 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
667 | unsigned long common_flags; | ||
686 | int ret; | 668 | int ret; |
687 | 669 | ||
688 | camera_flags = icd->ops->query_bus_param(icd); | 670 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
689 | ret = soc_camera_bus_param_compatible(camera_flags, | 671 | if (!ret) { |
690 | make_bus_param(isi)); | 672 | common_flags = soc_mbus_config_compatible(&cfg, |
691 | if (!ret) | 673 | ISI_BUS_PARAM); |
692 | return -EINVAL; | 674 | if (!common_flags) { |
693 | return 0; | 675 | dev_warn(icd->parent, |
676 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
677 | cfg.flags, ISI_BUS_PARAM); | ||
678 | return -EINVAL; | ||
679 | } | ||
680 | } else if (ret != -ENOIOCTLCMD) { | ||
681 | return ret; | ||
682 | } | ||
683 | |||
684 | if ((1 << (buswidth - 1)) & isi->width_flags) | ||
685 | return 0; | ||
686 | return -EINVAL; | ||
694 | } | 687 | } |
695 | 688 | ||
696 | 689 | ||
@@ -812,59 +805,71 @@ static int isi_camera_querycap(struct soc_camera_host *ici, | |||
812 | 805 | ||
813 | static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) | 806 | static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) |
814 | { | 807 | { |
808 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
815 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 809 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
816 | struct atmel_isi *isi = ici->priv; | 810 | struct atmel_isi *isi = ici->priv; |
817 | unsigned long bus_flags, camera_flags, common_flags; | 811 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
812 | unsigned long common_flags; | ||
818 | int ret; | 813 | int ret; |
819 | u32 cfg1 = 0; | 814 | u32 cfg1 = 0; |
820 | 815 | ||
821 | camera_flags = icd->ops->query_bus_param(icd); | 816 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
822 | 817 | if (!ret) { | |
823 | bus_flags = make_bus_param(isi); | 818 | common_flags = soc_mbus_config_compatible(&cfg, |
824 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 819 | ISI_BUS_PARAM); |
825 | dev_dbg(icd->parent, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", | 820 | if (!common_flags) { |
826 | camera_flags, bus_flags, common_flags); | 821 | dev_warn(icd->parent, |
827 | if (!common_flags) | 822 | "Flags incompatible: camera 0x%x, host 0x%x\n", |
828 | return -EINVAL; | 823 | cfg.flags, ISI_BUS_PARAM); |
824 | return -EINVAL; | ||
825 | } | ||
826 | } else if (ret != -ENOIOCTLCMD) { | ||
827 | return ret; | ||
828 | } else { | ||
829 | common_flags = ISI_BUS_PARAM; | ||
830 | } | ||
831 | dev_dbg(icd->parent, "Flags cam: 0x%x host: 0x%x common: 0x%lx\n", | ||
832 | cfg.flags, ISI_BUS_PARAM, common_flags); | ||
829 | 833 | ||
830 | /* Make choises, based on platform preferences */ | 834 | /* Make choises, based on platform preferences */ |
831 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 835 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
832 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 836 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
833 | if (isi->pdata->hsync_act_low) | 837 | if (isi->pdata->hsync_act_low) |
834 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 838 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
835 | else | 839 | else |
836 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 840 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
837 | } | 841 | } |
838 | 842 | ||
839 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 843 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
840 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 844 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
841 | if (isi->pdata->vsync_act_low) | 845 | if (isi->pdata->vsync_act_low) |
842 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 846 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
843 | else | 847 | else |
844 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 848 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
845 | } | 849 | } |
846 | 850 | ||
847 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 851 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
848 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 852 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
849 | if (isi->pdata->pclk_act_falling) | 853 | if (isi->pdata->pclk_act_falling) |
850 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 854 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
851 | else | 855 | else |
852 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 856 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
853 | } | 857 | } |
854 | 858 | ||
855 | ret = icd->ops->set_bus_param(icd, common_flags); | 859 | cfg.flags = common_flags; |
856 | if (ret < 0) { | 860 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
857 | dev_dbg(icd->parent, "Camera set_bus_param(%lx) returned %d\n", | 861 | if (ret < 0 && ret != -ENOIOCTLCMD) { |
862 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
858 | common_flags, ret); | 863 | common_flags, ret); |
859 | return ret; | 864 | return ret; |
860 | } | 865 | } |
861 | 866 | ||
862 | /* set bus param for ISI */ | 867 | /* set bus param for ISI */ |
863 | if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) | 868 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) |
864 | cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; | 869 | cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; |
865 | if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) | 870 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) |
866 | cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; | 871 | cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; |
867 | if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) | 872 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) |
868 | cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; | 873 | cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; |
869 | 874 | ||
870 | if (isi->pdata->has_emb_sync) | 875 | if (isi->pdata->has_emb_sync) |
@@ -983,6 +988,11 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) | |||
983 | goto err_ioremap; | 988 | goto err_ioremap; |
984 | } | 989 | } |
985 | 990 | ||
991 | if (pdata->data_width_flags & ISI_DATAWIDTH_8) | ||
992 | isi->width_flags = 1 << 7; | ||
993 | if (pdata->data_width_flags & ISI_DATAWIDTH_10) | ||
994 | isi->width_flags |= 1 << 9; | ||
995 | |||
986 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | 996 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); |
987 | 997 | ||
988 | irq = platform_get_irq(pdev, 0); | 998 | irq = platform_get_irq(pdev, 0); |
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 9e2f870f4258..c6ff32a6137c 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -1085,6 +1085,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
1085 | setup.addr = ADDR_UNSET; | 1085 | setup.addr = ADDR_UNSET; |
1086 | setup.type = cx->options.tuner; | 1086 | setup.type = cx->options.tuner; |
1087 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ | 1087 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ |
1088 | if (cx->options.radio > 0) | ||
1089 | setup.mode_mask |= T_RADIO; | ||
1088 | setup.tuner_callback = (setup.type == TUNER_XC2028) ? | 1090 | setup.tuner_callback = (setup.type == TUNER_XC2028) ? |
1089 | cx18_reset_tuner_gpio : NULL; | 1091 | cx18_reset_tuner_gpio : NULL; |
1090 | cx18_call_all(cx, tuner, s_type_addr, &setup); | 1092 | cx18_call_all(cx, tuner, s_type_addr, &setup); |
diff --git a/drivers/media/video/cx25821/Kconfig b/drivers/media/video/cx25821/Kconfig new file mode 100644 index 000000000000..5f6b54213713 --- /dev/null +++ b/drivers/media/video/cx25821/Kconfig | |||
@@ -0,0 +1,34 @@ | |||
1 | config VIDEO_CX25821 | ||
2 | tristate "Conexant cx25821 support" | ||
3 | depends on DVB_CORE && VIDEO_DEV && PCI && I2C | ||
4 | select I2C_ALGOBIT | ||
5 | select VIDEO_BTCX | ||
6 | select VIDEO_TVEEPROM | ||
7 | depends on RC_CORE | ||
8 | select VIDEOBUF_DVB | ||
9 | select VIDEOBUF_DMA_SG | ||
10 | select VIDEO_CX25840 | ||
11 | select VIDEO_CX2341X | ||
12 | ---help--- | ||
13 | This is a video4linux driver for Conexant 25821 based | ||
14 | TV cards. | ||
15 | |||
16 | To compile this driver as a module, choose M here: the | ||
17 | module will be called cx25821 | ||
18 | |||
19 | config VIDEO_CX25821_ALSA | ||
20 | tristate "Conexant 25821 DMA audio support" | ||
21 | depends on VIDEO_CX25821 && SND && EXPERIMENTAL | ||
22 | select SND_PCM | ||
23 | ---help--- | ||
24 | This is a video4linux driver for direct (DMA) audio on | ||
25 | Conexant 25821 based capture cards using ALSA. | ||
26 | |||
27 | It only works with boards with function 01 enabled. | ||
28 | To check if your board supports, use lspci -n. | ||
29 | If supported, you should see 14f1:8801 or 14f1:8811 | ||
30 | PCI device. | ||
31 | |||
32 | To compile this driver as a module, choose M here: the | ||
33 | module will be called cx25821-alsa. | ||
34 | |||
diff --git a/drivers/media/video/cx25821/Makefile b/drivers/media/video/cx25821/Makefile new file mode 100644 index 000000000000..aedde18c68f9 --- /dev/null +++ b/drivers/media/video/cx25821/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \ | ||
2 | cx25821-gpio.o cx25821-medusa-video.o \ | ||
3 | cx25821-video.o cx25821-video-upstream.o \ | ||
4 | cx25821-video-upstream-ch2.o \ | ||
5 | cx25821-audio-upstream.o | ||
6 | |||
7 | obj-$(CONFIG_VIDEO_CX25821) += cx25821.o | ||
8 | obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o | ||
9 | |||
10 | ccflags-y := -Idrivers/media/video | ||
11 | ccflags-y += -Idrivers/media/common/tuners | ||
12 | ccflags-y += -Idrivers/media/dvb/dvb-core | ||
13 | ccflags-y += -Idrivers/media/dvb/frontends | ||
diff --git a/drivers/media/video/cx25821/cx25821-alsa.c b/drivers/media/video/cx25821/cx25821-alsa.c new file mode 100644 index 000000000000..09e99de5fd21 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-alsa.c | |||
@@ -0,0 +1,795 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * Based on SAA713x ALSA driver and CX88 driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation, version 2 | ||
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 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/vmalloc.h> | ||
30 | #include <linux/dma-mapping.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <linux/slab.h> | ||
33 | |||
34 | #include <linux/delay.h> | ||
35 | #include <sound/core.h> | ||
36 | #include <sound/pcm.h> | ||
37 | #include <sound/pcm_params.h> | ||
38 | #include <sound/control.h> | ||
39 | #include <sound/initval.h> | ||
40 | #include <sound/tlv.h> | ||
41 | |||
42 | #include "cx25821.h" | ||
43 | #include "cx25821-reg.h" | ||
44 | |||
45 | #define AUDIO_SRAM_CHANNEL SRAM_CH08 | ||
46 | |||
47 | #define dprintk(level, fmt, arg...) \ | ||
48 | do { \ | ||
49 | if (debug >= level) \ | ||
50 | pr_info("%s/1: " fmt, chip->dev->name, ##arg); \ | ||
51 | } while (0) | ||
52 | #define dprintk_core(level, fmt, arg...) \ | ||
53 | do { \ | ||
54 | if (debug >= level) \ | ||
55 | printk(KERN_DEBUG "%s/1: " fmt, chip->dev->name, ##arg); \ | ||
56 | } while (0) | ||
57 | |||
58 | /**************************************************************************** | ||
59 | Data type declarations - Can be moded to a header file later | ||
60 | ****************************************************************************/ | ||
61 | |||
62 | static struct snd_card *snd_cx25821_cards[SNDRV_CARDS]; | ||
63 | static int devno; | ||
64 | |||
65 | struct cx25821_audio_buffer { | ||
66 | unsigned int bpl; | ||
67 | struct btcx_riscmem risc; | ||
68 | struct videobuf_dmabuf dma; | ||
69 | }; | ||
70 | |||
71 | struct cx25821_audio_dev { | ||
72 | struct cx25821_dev *dev; | ||
73 | struct cx25821_dmaqueue q; | ||
74 | |||
75 | /* pci i/o */ | ||
76 | struct pci_dev *pci; | ||
77 | |||
78 | /* audio controls */ | ||
79 | int irq; | ||
80 | |||
81 | struct snd_card *card; | ||
82 | |||
83 | unsigned long iobase; | ||
84 | spinlock_t reg_lock; | ||
85 | atomic_t count; | ||
86 | |||
87 | unsigned int dma_size; | ||
88 | unsigned int period_size; | ||
89 | unsigned int num_periods; | ||
90 | |||
91 | struct videobuf_dmabuf *dma_risc; | ||
92 | |||
93 | struct cx25821_audio_buffer *buf; | ||
94 | |||
95 | struct snd_pcm_substream *substream; | ||
96 | }; | ||
97 | |||
98 | |||
99 | /**************************************************************************** | ||
100 | Module global static vars | ||
101 | ****************************************************************************/ | ||
102 | |||
103 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
104 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
105 | static int enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 }; | ||
106 | |||
107 | module_param_array(enable, bool, NULL, 0444); | ||
108 | MODULE_PARM_DESC(enable, "Enable cx25821 soundcard. default enabled."); | ||
109 | |||
110 | module_param_array(index, int, NULL, 0444); | ||
111 | MODULE_PARM_DESC(index, "Index value for cx25821 capture interface(s)."); | ||
112 | |||
113 | /**************************************************************************** | ||
114 | Module macros | ||
115 | ****************************************************************************/ | ||
116 | |||
117 | MODULE_DESCRIPTION("ALSA driver module for cx25821 based capture cards"); | ||
118 | MODULE_AUTHOR("Hiep Huynh"); | ||
119 | MODULE_LICENSE("GPL"); | ||
120 | MODULE_SUPPORTED_DEVICE("{{Conexant,25821}"); /* "{{Conexant,23881}," */ | ||
121 | |||
122 | static unsigned int debug; | ||
123 | module_param(debug, int, 0644); | ||
124 | MODULE_PARM_DESC(debug, "enable debug messages"); | ||
125 | |||
126 | /**************************************************************************** | ||
127 | Module specific funtions | ||
128 | ****************************************************************************/ | ||
129 | /* Constants taken from cx88-reg.h */ | ||
130 | #define AUD_INT_DN_RISCI1 (1 << 0) | ||
131 | #define AUD_INT_UP_RISCI1 (1 << 1) | ||
132 | #define AUD_INT_RDS_DN_RISCI1 (1 << 2) | ||
133 | #define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ | ||
134 | #define AUD_INT_UP_RISCI2 (1 << 5) | ||
135 | #define AUD_INT_RDS_DN_RISCI2 (1 << 6) | ||
136 | #define AUD_INT_DN_SYNC (1 << 12) | ||
137 | #define AUD_INT_UP_SYNC (1 << 13) | ||
138 | #define AUD_INT_RDS_DN_SYNC (1 << 14) | ||
139 | #define AUD_INT_OPC_ERR (1 << 16) | ||
140 | #define AUD_INT_BER_IRQ (1 << 20) | ||
141 | #define AUD_INT_MCHG_IRQ (1 << 21) | ||
142 | #define GP_COUNT_CONTROL_RESET 0x3 | ||
143 | |||
144 | #define PCI_MSK_AUD_EXT (1 << 4) | ||
145 | #define PCI_MSK_AUD_INT (1 << 3) | ||
146 | /* | ||
147 | * BOARD Specific: Sets audio DMA | ||
148 | */ | ||
149 | |||
150 | static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip) | ||
151 | { | ||
152 | struct cx25821_audio_buffer *buf = chip->buf; | ||
153 | struct cx25821_dev *dev = chip->dev; | ||
154 | struct sram_channel *audio_ch = | ||
155 | &cx25821_sram_channels[AUDIO_SRAM_CHANNEL]; | ||
156 | u32 tmp = 0; | ||
157 | |||
158 | /* enable output on the GPIO 0 for the MCLK ADC (Audio) */ | ||
159 | cx25821_set_gpiopin_direction(chip->dev, 0, 0); | ||
160 | |||
161 | /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ | ||
162 | cx_clear(AUD_INT_DMA_CTL, | ||
163 | FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); | ||
164 | |||
165 | /* setup fifo + format - out channel */ | ||
166 | cx25821_sram_channel_setup_audio(chip->dev, audio_ch, buf->bpl, | ||
167 | buf->risc.dma); | ||
168 | |||
169 | /* sets bpl size */ | ||
170 | cx_write(AUD_A_LNGTH, buf->bpl); | ||
171 | |||
172 | /* reset counter */ | ||
173 | /* GP_COUNT_CONTROL_RESET = 0x3 */ | ||
174 | cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); | ||
175 | atomic_set(&chip->count, 0); | ||
176 | |||
177 | /* Set the input mode to 16-bit */ | ||
178 | tmp = cx_read(AUD_A_CFG); | ||
179 | cx_write(AUD_A_CFG, | ||
180 | tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE | | ||
181 | FLD_AUD_CLK_ENABLE); | ||
182 | |||
183 | /* | ||
184 | pr_info("DEBUG: Start audio DMA, %d B/line, cmds_start(0x%x)= %d lines/FIFO, %d periods, %d byte buffer\n", | ||
185 | buf->bpl, audio_ch->cmds_start, | ||
186 | cx_read(audio_ch->cmds_start + 12)>>1, | ||
187 | chip->num_periods, buf->bpl * chip->num_periods); | ||
188 | */ | ||
189 | |||
190 | /* Enables corresponding bits at AUD_INT_STAT */ | ||
191 | cx_write(AUD_A_INT_MSK, | ||
192 | FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF | FLD_AUD_DST_SYNC | | ||
193 | FLD_AUD_DST_OPC_ERR); | ||
194 | |||
195 | /* Clean any pending interrupt bits already set */ | ||
196 | cx_write(AUD_A_INT_STAT, ~0); | ||
197 | |||
198 | /* enable audio irqs */ | ||
199 | cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT); | ||
200 | |||
201 | /* Turn on audio downstream fifo and risc enable 0x101 */ | ||
202 | tmp = cx_read(AUD_INT_DMA_CTL); | ||
203 | cx_set(AUD_INT_DMA_CTL, | ||
204 | tmp | (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN)); | ||
205 | |||
206 | mdelay(100); | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * BOARD Specific: Resets audio DMA | ||
212 | */ | ||
213 | static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip) | ||
214 | { | ||
215 | struct cx25821_dev *dev = chip->dev; | ||
216 | |||
217 | /* stop dma */ | ||
218 | cx_clear(AUD_INT_DMA_CTL, | ||
219 | FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); | ||
220 | |||
221 | /* disable irqs */ | ||
222 | cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT); | ||
223 | cx_clear(AUD_A_INT_MSK, | ||
224 | AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | AUD_INT_DN_RISCI2 | | ||
225 | AUD_INT_DN_RISCI1); | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | #define MAX_IRQ_LOOP 50 | ||
231 | |||
232 | /* | ||
233 | * BOARD Specific: IRQ dma bits | ||
234 | */ | ||
235 | static char *cx25821_aud_irqs[32] = { | ||
236 | "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */ | ||
237 | NULL, /* reserved */ | ||
238 | "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */ | ||
239 | NULL, /* reserved */ | ||
240 | "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */ | ||
241 | NULL, /* reserved */ | ||
242 | "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */ | ||
243 | NULL, /* reserved */ | ||
244 | "opc_err", "par_err", "rip_err", /* 16-18 */ | ||
245 | "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */ | ||
246 | }; | ||
247 | |||
248 | /* | ||
249 | * BOARD Specific: Threats IRQ audio specific calls | ||
250 | */ | ||
251 | static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status, | ||
252 | u32 mask) | ||
253 | { | ||
254 | struct cx25821_dev *dev = chip->dev; | ||
255 | |||
256 | if (0 == (status & mask)) | ||
257 | return; | ||
258 | |||
259 | cx_write(AUD_A_INT_STAT, status); | ||
260 | if (debug > 1 || (status & mask & ~0xff)) | ||
261 | cx25821_print_irqbits(dev->name, "irq aud", | ||
262 | cx25821_aud_irqs, | ||
263 | ARRAY_SIZE(cx25821_aud_irqs), status, | ||
264 | mask); | ||
265 | |||
266 | /* risc op code error */ | ||
267 | if (status & AUD_INT_OPC_ERR) { | ||
268 | pr_warn("WARNING %s/1: Audio risc op code error\n", dev->name); | ||
269 | |||
270 | cx_clear(AUD_INT_DMA_CTL, | ||
271 | FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); | ||
272 | cx25821_sram_channel_dump_audio(dev, | ||
273 | &cx25821_sram_channels | ||
274 | [AUDIO_SRAM_CHANNEL]); | ||
275 | } | ||
276 | if (status & AUD_INT_DN_SYNC) { | ||
277 | pr_warn("WARNING %s: Downstream sync error!\n", dev->name); | ||
278 | cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); | ||
279 | return; | ||
280 | } | ||
281 | |||
282 | /* risc1 downstream */ | ||
283 | if (status & AUD_INT_DN_RISCI1) { | ||
284 | atomic_set(&chip->count, cx_read(AUD_A_GPCNT)); | ||
285 | snd_pcm_period_elapsed(chip->substream); | ||
286 | } | ||
287 | } | ||
288 | |||
289 | /* | ||
290 | * BOARD Specific: Handles IRQ calls | ||
291 | */ | ||
292 | static irqreturn_t cx25821_irq(int irq, void *dev_id) | ||
293 | { | ||
294 | struct cx25821_audio_dev *chip = dev_id; | ||
295 | struct cx25821_dev *dev = chip->dev; | ||
296 | u32 status, pci_status; | ||
297 | u32 audint_status, audint_mask; | ||
298 | int loop, handled = 0; | ||
299 | int audint_count = 0; | ||
300 | |||
301 | audint_status = cx_read(AUD_A_INT_STAT); | ||
302 | audint_mask = cx_read(AUD_A_INT_MSK); | ||
303 | audint_count = cx_read(AUD_A_GPCNT); | ||
304 | status = cx_read(PCI_INT_STAT); | ||
305 | |||
306 | for (loop = 0; loop < 1; loop++) { | ||
307 | status = cx_read(PCI_INT_STAT); | ||
308 | if (0 == status) { | ||
309 | status = cx_read(PCI_INT_STAT); | ||
310 | audint_status = cx_read(AUD_A_INT_STAT); | ||
311 | audint_mask = cx_read(AUD_A_INT_MSK); | ||
312 | |||
313 | if (status) { | ||
314 | handled = 1; | ||
315 | cx_write(PCI_INT_STAT, status); | ||
316 | |||
317 | cx25821_aud_irq(chip, audint_status, | ||
318 | audint_mask); | ||
319 | break; | ||
320 | } else | ||
321 | goto out; | ||
322 | } | ||
323 | |||
324 | handled = 1; | ||
325 | cx_write(PCI_INT_STAT, status); | ||
326 | |||
327 | cx25821_aud_irq(chip, audint_status, audint_mask); | ||
328 | } | ||
329 | |||
330 | pci_status = cx_read(PCI_INT_STAT); | ||
331 | |||
332 | if (handled) | ||
333 | cx_write(PCI_INT_STAT, pci_status); | ||
334 | |||
335 | out: | ||
336 | return IRQ_RETVAL(handled); | ||
337 | } | ||
338 | |||
339 | static int dsp_buffer_free(struct cx25821_audio_dev *chip) | ||
340 | { | ||
341 | BUG_ON(!chip->dma_size); | ||
342 | |||
343 | dprintk(2, "Freeing buffer\n"); | ||
344 | videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); | ||
345 | videobuf_dma_free(chip->dma_risc); | ||
346 | btcx_riscmem_free(chip->pci, &chip->buf->risc); | ||
347 | kfree(chip->buf); | ||
348 | |||
349 | chip->dma_risc = NULL; | ||
350 | chip->dma_size = 0; | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | /**************************************************************************** | ||
356 | ALSA PCM Interface | ||
357 | ****************************************************************************/ | ||
358 | |||
359 | /* | ||
360 | * Digital hardware definition | ||
361 | */ | ||
362 | #define DEFAULT_FIFO_SIZE 384 | ||
363 | static struct snd_pcm_hardware snd_cx25821_digital_hw = { | ||
364 | .info = SNDRV_PCM_INFO_MMAP | | ||
365 | SNDRV_PCM_INFO_INTERLEAVED | | ||
366 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, | ||
367 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
368 | |||
369 | .rates = SNDRV_PCM_RATE_48000, | ||
370 | .rate_min = 48000, | ||
371 | .rate_max = 48000, | ||
372 | .channels_min = 2, | ||
373 | .channels_max = 2, | ||
374 | /* Analog audio output will be full of clicks and pops if there | ||
375 | are not exactly four lines in the SRAM FIFO buffer. */ | ||
376 | .period_bytes_min = DEFAULT_FIFO_SIZE / 3, | ||
377 | .period_bytes_max = DEFAULT_FIFO_SIZE / 3, | ||
378 | .periods_min = 1, | ||
379 | .periods_max = AUDIO_LINE_SIZE, | ||
380 | /* 128 * 128 = 16384 = 1024 * 16 */ | ||
381 | .buffer_bytes_max = (AUDIO_LINE_SIZE * AUDIO_LINE_SIZE), | ||
382 | }; | ||
383 | |||
384 | /* | ||
385 | * audio pcm capture open callback | ||
386 | */ | ||
387 | static int snd_cx25821_pcm_open(struct snd_pcm_substream *substream) | ||
388 | { | ||
389 | struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); | ||
390 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
391 | int err; | ||
392 | unsigned int bpl = 0; | ||
393 | |||
394 | if (!chip) { | ||
395 | pr_err("DEBUG: cx25821 can't find device struct. Can't proceed with open\n"); | ||
396 | return -ENODEV; | ||
397 | } | ||
398 | |||
399 | err = | ||
400 | snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS); | ||
401 | if (err < 0) | ||
402 | goto _error; | ||
403 | |||
404 | chip->substream = substream; | ||
405 | |||
406 | runtime->hw = snd_cx25821_digital_hw; | ||
407 | |||
408 | if (cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size != | ||
409 | DEFAULT_FIFO_SIZE) { | ||
410 | /* since there are 3 audio Clusters */ | ||
411 | bpl = cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 3; | ||
412 | bpl &= ~7; /* must be multiple of 8 */ | ||
413 | |||
414 | if (bpl > AUDIO_LINE_SIZE) | ||
415 | bpl = AUDIO_LINE_SIZE; | ||
416 | |||
417 | runtime->hw.period_bytes_min = bpl; | ||
418 | runtime->hw.period_bytes_max = bpl; | ||
419 | } | ||
420 | |||
421 | return 0; | ||
422 | _error: | ||
423 | dprintk(1, "Error opening PCM!\n"); | ||
424 | return err; | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * audio close callback | ||
429 | */ | ||
430 | static int snd_cx25821_close(struct snd_pcm_substream *substream) | ||
431 | { | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | * hw_params callback | ||
437 | */ | ||
438 | static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, | ||
439 | struct snd_pcm_hw_params *hw_params) | ||
440 | { | ||
441 | struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); | ||
442 | struct videobuf_dmabuf *dma; | ||
443 | |||
444 | struct cx25821_audio_buffer *buf; | ||
445 | int ret; | ||
446 | |||
447 | if (substream->runtime->dma_area) { | ||
448 | dsp_buffer_free(chip); | ||
449 | substream->runtime->dma_area = NULL; | ||
450 | } | ||
451 | |||
452 | chip->period_size = params_period_bytes(hw_params); | ||
453 | chip->num_periods = params_periods(hw_params); | ||
454 | chip->dma_size = chip->period_size * params_periods(hw_params); | ||
455 | |||
456 | BUG_ON(!chip->dma_size); | ||
457 | BUG_ON(chip->num_periods & (chip->num_periods - 1)); | ||
458 | |||
459 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); | ||
460 | if (NULL == buf) | ||
461 | return -ENOMEM; | ||
462 | |||
463 | if (chip->period_size > AUDIO_LINE_SIZE) | ||
464 | chip->period_size = AUDIO_LINE_SIZE; | ||
465 | |||
466 | buf->bpl = chip->period_size; | ||
467 | |||
468 | dma = &buf->dma; | ||
469 | videobuf_dma_init(dma); | ||
470 | ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, | ||
471 | (PAGE_ALIGN(chip->dma_size) >> | ||
472 | PAGE_SHIFT)); | ||
473 | if (ret < 0) | ||
474 | goto error; | ||
475 | |||
476 | ret = videobuf_dma_map(&chip->pci->dev, dma); | ||
477 | if (ret < 0) | ||
478 | goto error; | ||
479 | |||
480 | ret = | ||
481 | cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist, | ||
482 | chip->period_size, chip->num_periods, | ||
483 | 1); | ||
484 | if (ret < 0) { | ||
485 | pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n"); | ||
486 | goto error; | ||
487 | } | ||
488 | |||
489 | /* Loop back to start of program */ | ||
490 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
491 | buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
492 | buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ | ||
493 | |||
494 | chip->buf = buf; | ||
495 | chip->dma_risc = dma; | ||
496 | |||
497 | substream->runtime->dma_area = chip->dma_risc->vaddr; | ||
498 | substream->runtime->dma_bytes = chip->dma_size; | ||
499 | substream->runtime->dma_addr = 0; | ||
500 | |||
501 | return 0; | ||
502 | |||
503 | error: | ||
504 | kfree(buf); | ||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | /* | ||
509 | * hw free callback | ||
510 | */ | ||
511 | static int snd_cx25821_hw_free(struct snd_pcm_substream *substream) | ||
512 | { | ||
513 | struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); | ||
514 | |||
515 | if (substream->runtime->dma_area) { | ||
516 | dsp_buffer_free(chip); | ||
517 | substream->runtime->dma_area = NULL; | ||
518 | } | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | /* | ||
524 | * prepare callback | ||
525 | */ | ||
526 | static int snd_cx25821_prepare(struct snd_pcm_substream *substream) | ||
527 | { | ||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | /* | ||
532 | * trigger callback | ||
533 | */ | ||
534 | static int snd_cx25821_card_trigger(struct snd_pcm_substream *substream, | ||
535 | int cmd) | ||
536 | { | ||
537 | struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); | ||
538 | int err = 0; | ||
539 | |||
540 | /* Local interrupts are already disabled by ALSA */ | ||
541 | spin_lock(&chip->reg_lock); | ||
542 | |||
543 | switch (cmd) { | ||
544 | case SNDRV_PCM_TRIGGER_START: | ||
545 | err = _cx25821_start_audio_dma(chip); | ||
546 | break; | ||
547 | case SNDRV_PCM_TRIGGER_STOP: | ||
548 | err = _cx25821_stop_audio_dma(chip); | ||
549 | break; | ||
550 | default: | ||
551 | err = -EINVAL; | ||
552 | break; | ||
553 | } | ||
554 | |||
555 | spin_unlock(&chip->reg_lock); | ||
556 | |||
557 | return err; | ||
558 | } | ||
559 | |||
560 | /* | ||
561 | * pointer callback | ||
562 | */ | ||
563 | static snd_pcm_uframes_t snd_cx25821_pointer(struct snd_pcm_substream | ||
564 | *substream) | ||
565 | { | ||
566 | struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); | ||
567 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
568 | u16 count; | ||
569 | |||
570 | count = atomic_read(&chip->count); | ||
571 | |||
572 | return runtime->period_size * (count & (runtime->periods - 1)); | ||
573 | } | ||
574 | |||
575 | /* | ||
576 | * page callback (needed for mmap) | ||
577 | */ | ||
578 | static struct page *snd_cx25821_page(struct snd_pcm_substream *substream, | ||
579 | unsigned long offset) | ||
580 | { | ||
581 | void *pageptr = substream->runtime->dma_area + offset; | ||
582 | |||
583 | return vmalloc_to_page(pageptr); | ||
584 | } | ||
585 | |||
586 | /* | ||
587 | * operators | ||
588 | */ | ||
589 | static struct snd_pcm_ops snd_cx25821_pcm_ops = { | ||
590 | .open = snd_cx25821_pcm_open, | ||
591 | .close = snd_cx25821_close, | ||
592 | .ioctl = snd_pcm_lib_ioctl, | ||
593 | .hw_params = snd_cx25821_hw_params, | ||
594 | .hw_free = snd_cx25821_hw_free, | ||
595 | .prepare = snd_cx25821_prepare, | ||
596 | .trigger = snd_cx25821_card_trigger, | ||
597 | .pointer = snd_cx25821_pointer, | ||
598 | .page = snd_cx25821_page, | ||
599 | }; | ||
600 | |||
601 | /* | ||
602 | * ALSA create a PCM device: Called when initializing the board. | ||
603 | * Sets up the name and hooks up the callbacks | ||
604 | */ | ||
605 | static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device, | ||
606 | char *name) | ||
607 | { | ||
608 | struct snd_pcm *pcm; | ||
609 | int err; | ||
610 | |||
611 | err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm); | ||
612 | if (err < 0) { | ||
613 | pr_info("ERROR: FAILED snd_pcm_new() in %s\n", __func__); | ||
614 | return err; | ||
615 | } | ||
616 | pcm->private_data = chip; | ||
617 | pcm->info_flags = 0; | ||
618 | strcpy(pcm->name, name); | ||
619 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx25821_pcm_ops); | ||
620 | |||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | /**************************************************************************** | ||
625 | Basic Flow for Sound Devices | ||
626 | ****************************************************************************/ | ||
627 | |||
628 | /* | ||
629 | * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio | ||
630 | * Only boards with eeprom and byte 1 at eeprom=1 have it | ||
631 | */ | ||
632 | |||
633 | static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = { | ||
634 | {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
635 | {0,} | ||
636 | }; | ||
637 | |||
638 | MODULE_DEVICE_TABLE(pci, cx25821_audio_pci_tbl); | ||
639 | |||
640 | /* | ||
641 | * Not used in the function snd_cx25821_dev_free so removing | ||
642 | * from the file. | ||
643 | */ | ||
644 | /* | ||
645 | static int snd_cx25821_free(struct cx25821_audio_dev *chip) | ||
646 | { | ||
647 | if (chip->irq >= 0) | ||
648 | free_irq(chip->irq, chip); | ||
649 | |||
650 | cx25821_dev_unregister(chip->dev); | ||
651 | pci_disable_device(chip->pci); | ||
652 | |||
653 | return 0; | ||
654 | } | ||
655 | */ | ||
656 | |||
657 | /* | ||
658 | * Component Destructor | ||
659 | */ | ||
660 | static void snd_cx25821_dev_free(struct snd_card *card) | ||
661 | { | ||
662 | struct cx25821_audio_dev *chip = card->private_data; | ||
663 | |||
664 | /* snd_cx25821_free(chip); */ | ||
665 | snd_card_free(chip->card); | ||
666 | } | ||
667 | |||
668 | /* | ||
669 | * Alsa Constructor - Component probe | ||
670 | */ | ||
671 | static int cx25821_audio_initdev(struct cx25821_dev *dev) | ||
672 | { | ||
673 | struct snd_card *card; | ||
674 | struct cx25821_audio_dev *chip; | ||
675 | int err; | ||
676 | |||
677 | if (devno >= SNDRV_CARDS) { | ||
678 | pr_info("DEBUG ERROR: devno >= SNDRV_CARDS %s\n", __func__); | ||
679 | return -ENODEV; | ||
680 | } | ||
681 | |||
682 | if (!enable[devno]) { | ||
683 | ++devno; | ||
684 | pr_info("DEBUG ERROR: !enable[devno] %s\n", __func__); | ||
685 | return -ENOENT; | ||
686 | } | ||
687 | |||
688 | err = snd_card_create(index[devno], id[devno], THIS_MODULE, | ||
689 | sizeof(struct cx25821_audio_dev), &card); | ||
690 | if (err < 0) { | ||
691 | pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n", | ||
692 | __func__); | ||
693 | return err; | ||
694 | } | ||
695 | |||
696 | strcpy(card->driver, "cx25821"); | ||
697 | |||
698 | /* Card "creation" */ | ||
699 | card->private_free = snd_cx25821_dev_free; | ||
700 | chip = card->private_data; | ||
701 | spin_lock_init(&chip->reg_lock); | ||
702 | |||
703 | chip->dev = dev; | ||
704 | chip->card = card; | ||
705 | chip->pci = dev->pci; | ||
706 | chip->iobase = pci_resource_start(dev->pci, 0); | ||
707 | |||
708 | chip->irq = dev->pci->irq; | ||
709 | |||
710 | err = request_irq(dev->pci->irq, cx25821_irq, | ||
711 | IRQF_SHARED, chip->dev->name, chip); | ||
712 | |||
713 | if (err < 0) { | ||
714 | pr_err("ERROR %s: can't get IRQ %d for ALSA\n", | ||
715 | chip->dev->name, dev->pci->irq); | ||
716 | goto error; | ||
717 | } | ||
718 | |||
719 | err = snd_cx25821_pcm(chip, 0, "cx25821 Digital"); | ||
720 | if (err < 0) { | ||
721 | pr_info("DEBUG ERROR: cannot create snd_cx25821_pcm %s\n", | ||
722 | __func__); | ||
723 | goto error; | ||
724 | } | ||
725 | |||
726 | snd_card_set_dev(card, &chip->pci->dev); | ||
727 | |||
728 | strcpy(card->shortname, "cx25821"); | ||
729 | sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name, | ||
730 | chip->iobase, chip->irq); | ||
731 | strcpy(card->mixername, "CX25821"); | ||
732 | |||
733 | pr_info("%s/%i: ALSA support for cx25821 boards\n", | ||
734 | card->driver, devno); | ||
735 | |||
736 | err = snd_card_register(card); | ||
737 | if (err < 0) { | ||
738 | pr_info("DEBUG ERROR: cannot register sound card %s\n", | ||
739 | __func__); | ||
740 | goto error; | ||
741 | } | ||
742 | |||
743 | snd_cx25821_cards[devno] = card; | ||
744 | |||
745 | devno++; | ||
746 | return 0; | ||
747 | |||
748 | error: | ||
749 | snd_card_free(card); | ||
750 | return err; | ||
751 | } | ||
752 | |||
753 | /**************************************************************************** | ||
754 | LINUX MODULE INIT | ||
755 | ****************************************************************************/ | ||
756 | static void cx25821_audio_fini(void) | ||
757 | { | ||
758 | snd_card_free(snd_cx25821_cards[0]); | ||
759 | } | ||
760 | |||
761 | /* | ||
762 | * Module initializer | ||
763 | * | ||
764 | * Loops through present saa7134 cards, and assigns an ALSA device | ||
765 | * to each one | ||
766 | * | ||
767 | */ | ||
768 | static int cx25821_alsa_init(void) | ||
769 | { | ||
770 | struct cx25821_dev *dev = NULL; | ||
771 | struct list_head *list; | ||
772 | |||
773 | mutex_lock(&cx25821_devlist_mutex); | ||
774 | list_for_each(list, &cx25821_devlist) { | ||
775 | dev = list_entry(list, struct cx25821_dev, devlist); | ||
776 | cx25821_audio_initdev(dev); | ||
777 | } | ||
778 | mutex_unlock(&cx25821_devlist_mutex); | ||
779 | |||
780 | if (dev == NULL) | ||
781 | pr_info("ERROR ALSA: no cx25821 cards found\n"); | ||
782 | |||
783 | return 0; | ||
784 | |||
785 | } | ||
786 | |||
787 | late_initcall(cx25821_alsa_init); | ||
788 | module_exit(cx25821_audio_fini); | ||
789 | |||
790 | /* ----------------------------------------------------------- */ | ||
791 | /* | ||
792 | * Local variables: | ||
793 | * c-basic-offset: 8 | ||
794 | * End: | ||
795 | */ | ||
diff --git a/drivers/media/video/cx25821/cx25821-audio-upstream.c b/drivers/media/video/cx25821/cx25821-audio-upstream.c new file mode 100644 index 000000000000..c20d6dece154 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-audio-upstream.c | |||
@@ -0,0 +1,788 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
24 | |||
25 | #include "cx25821-video.h" | ||
26 | #include "cx25821-audio-upstream.h" | ||
27 | |||
28 | #include <linux/fs.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/syscalls.h> | ||
34 | #include <linux/file.h> | ||
35 | #include <linux/fcntl.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/uaccess.h> | ||
39 | |||
40 | MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); | ||
41 | MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); | ||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | static int _intr_msk = FLD_AUD_SRC_RISCI1 | FLD_AUD_SRC_OF | | ||
45 | FLD_AUD_SRC_SYNC | FLD_AUD_SRC_OPC_ERR; | ||
46 | |||
47 | int cx25821_sram_channel_setup_upstream_audio(struct cx25821_dev *dev, | ||
48 | struct sram_channel *ch, | ||
49 | unsigned int bpl, u32 risc) | ||
50 | { | ||
51 | unsigned int i, lines; | ||
52 | u32 cdt; | ||
53 | |||
54 | if (ch->cmds_start == 0) { | ||
55 | cx_write(ch->ptr1_reg, 0); | ||
56 | cx_write(ch->ptr2_reg, 0); | ||
57 | cx_write(ch->cnt2_reg, 0); | ||
58 | cx_write(ch->cnt1_reg, 0); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | bpl = (bpl + 7) & ~7; /* alignment */ | ||
63 | cdt = ch->cdt; | ||
64 | lines = ch->fifo_size / bpl; | ||
65 | |||
66 | if (lines > 3) | ||
67 | lines = 3; | ||
68 | |||
69 | BUG_ON(lines < 2); | ||
70 | |||
71 | /* write CDT */ | ||
72 | for (i = 0; i < lines; i++) { | ||
73 | cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); | ||
74 | cx_write(cdt + 16 * i + 4, 0); | ||
75 | cx_write(cdt + 16 * i + 8, 0); | ||
76 | cx_write(cdt + 16 * i + 12, 0); | ||
77 | } | ||
78 | |||
79 | /* write CMDS */ | ||
80 | cx_write(ch->cmds_start + 0, risc); | ||
81 | |||
82 | cx_write(ch->cmds_start + 4, 0); | ||
83 | cx_write(ch->cmds_start + 8, cdt); | ||
84 | cx_write(ch->cmds_start + 12, AUDIO_CDT_SIZE_QW); | ||
85 | cx_write(ch->cmds_start + 16, ch->ctrl_start); | ||
86 | |||
87 | /* IQ size */ | ||
88 | cx_write(ch->cmds_start + 20, AUDIO_IQ_SIZE_DW); | ||
89 | |||
90 | for (i = 24; i < 80; i += 4) | ||
91 | cx_write(ch->cmds_start + i, 0); | ||
92 | |||
93 | /* fill registers */ | ||
94 | cx_write(ch->ptr1_reg, ch->fifo_start); | ||
95 | cx_write(ch->ptr2_reg, cdt); | ||
96 | cx_write(ch->cnt2_reg, AUDIO_CDT_SIZE_QW); | ||
97 | cx_write(ch->cnt1_reg, AUDIO_CLUSTER_SIZE_QW - 1); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev, | ||
103 | __le32 *rp, | ||
104 | dma_addr_t databuf_phys_addr, | ||
105 | unsigned int bpl, | ||
106 | int fifo_enable) | ||
107 | { | ||
108 | unsigned int line; | ||
109 | struct sram_channel *sram_ch = | ||
110 | dev->channels[dev->_audio_upstream_channel].sram_channels; | ||
111 | int offset = 0; | ||
112 | |||
113 | /* scan lines */ | ||
114 | for (line = 0; line < LINES_PER_AUDIO_BUFFER; line++) { | ||
115 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | ||
116 | *(rp++) = cpu_to_le32(databuf_phys_addr + offset); | ||
117 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
118 | |||
119 | /* Check if we need to enable the FIFO | ||
120 | * after the first 3 lines. | ||
121 | * For the upstream audio channel, | ||
122 | * the risc engine will enable the FIFO */ | ||
123 | if (fifo_enable && line == 2) { | ||
124 | *(rp++) = RISC_WRITECR; | ||
125 | *(rp++) = sram_ch->dma_ctl; | ||
126 | *(rp++) = sram_ch->fld_aud_fifo_en; | ||
127 | *(rp++) = 0x00000020; | ||
128 | } | ||
129 | |||
130 | offset += AUDIO_LINE_SIZE; | ||
131 | } | ||
132 | |||
133 | return rp; | ||
134 | } | ||
135 | |||
136 | int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev, | ||
137 | struct pci_dev *pci, | ||
138 | unsigned int bpl, unsigned int lines) | ||
139 | { | ||
140 | __le32 *rp; | ||
141 | int fifo_enable = 0; | ||
142 | int frame = 0, i = 0; | ||
143 | int frame_size = AUDIO_DATA_BUF_SZ; | ||
144 | int databuf_offset = 0; | ||
145 | int risc_flag = RISC_CNT_INC; | ||
146 | dma_addr_t risc_phys_jump_addr; | ||
147 | |||
148 | /* Virtual address of Risc buffer program */ | ||
149 | rp = dev->_risc_virt_addr; | ||
150 | |||
151 | /* sync instruction */ | ||
152 | *(rp++) = cpu_to_le32(RISC_RESYNC | AUDIO_SYNC_LINE); | ||
153 | |||
154 | for (frame = 0; frame < NUM_AUDIO_FRAMES; frame++) { | ||
155 | databuf_offset = frame_size * frame; | ||
156 | |||
157 | if (frame == 0) { | ||
158 | fifo_enable = 1; | ||
159 | risc_flag = RISC_CNT_RESET; | ||
160 | } else { | ||
161 | fifo_enable = 0; | ||
162 | risc_flag = RISC_CNT_INC; | ||
163 | } | ||
164 | |||
165 | /* Calculate physical jump address */ | ||
166 | if ((frame + 1) == NUM_AUDIO_FRAMES) { | ||
167 | risc_phys_jump_addr = | ||
168 | dev->_risc_phys_start_addr + | ||
169 | RISC_SYNC_INSTRUCTION_SIZE; | ||
170 | } else { | ||
171 | risc_phys_jump_addr = | ||
172 | dev->_risc_phys_start_addr + | ||
173 | RISC_SYNC_INSTRUCTION_SIZE + | ||
174 | AUDIO_RISC_DMA_BUF_SIZE * (frame + 1); | ||
175 | } | ||
176 | |||
177 | rp = cx25821_risc_field_upstream_audio(dev, rp, | ||
178 | dev-> | ||
179 | _audiodata_buf_phys_addr | ||
180 | + databuf_offset, bpl, | ||
181 | fifo_enable); | ||
182 | |||
183 | if (USE_RISC_NOOP_AUDIO) { | ||
184 | for (i = 0; i < NUM_NO_OPS; i++) | ||
185 | *(rp++) = cpu_to_le32(RISC_NOOP); | ||
186 | } | ||
187 | |||
188 | /* Loop to (Nth)FrameRISC or to Start of Risc program & | ||
189 | * generate IRQ */ | ||
190 | *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); | ||
191 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
192 | *(rp++) = cpu_to_le32(0); | ||
193 | |||
194 | /* Recalculate virtual address based on frame index */ | ||
195 | rp = dev->_risc_virt_addr + RISC_SYNC_INSTRUCTION_SIZE / 4 + | ||
196 | (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4); | ||
197 | } | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | void cx25821_free_memory_audio(struct cx25821_dev *dev) | ||
203 | { | ||
204 | if (dev->_risc_virt_addr) { | ||
205 | pci_free_consistent(dev->pci, dev->_audiorisc_size, | ||
206 | dev->_risc_virt_addr, dev->_risc_phys_addr); | ||
207 | dev->_risc_virt_addr = NULL; | ||
208 | } | ||
209 | |||
210 | if (dev->_audiodata_buf_virt_addr) { | ||
211 | pci_free_consistent(dev->pci, dev->_audiodata_buf_size, | ||
212 | dev->_audiodata_buf_virt_addr, | ||
213 | dev->_audiodata_buf_phys_addr); | ||
214 | dev->_audiodata_buf_virt_addr = NULL; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | void cx25821_stop_upstream_audio(struct cx25821_dev *dev) | ||
219 | { | ||
220 | struct sram_channel *sram_ch = | ||
221 | dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels; | ||
222 | u32 tmp = 0; | ||
223 | |||
224 | if (!dev->_audio_is_running) { | ||
225 | printk(KERN_DEBUG | ||
226 | pr_fmt("No audio file is currently running so return!\n")); | ||
227 | return; | ||
228 | } | ||
229 | /* Disable RISC interrupts */ | ||
230 | cx_write(sram_ch->int_msk, 0); | ||
231 | |||
232 | /* Turn OFF risc and fifo enable in AUD_DMA_CNTRL */ | ||
233 | tmp = cx_read(sram_ch->dma_ctl); | ||
234 | cx_write(sram_ch->dma_ctl, | ||
235 | tmp & ~(sram_ch->fld_aud_fifo_en | sram_ch->fld_aud_risc_en)); | ||
236 | |||
237 | /* Clear data buffer memory */ | ||
238 | if (dev->_audiodata_buf_virt_addr) | ||
239 | memset(dev->_audiodata_buf_virt_addr, 0, | ||
240 | dev->_audiodata_buf_size); | ||
241 | |||
242 | dev->_audio_is_running = 0; | ||
243 | dev->_is_first_audio_frame = 0; | ||
244 | dev->_audioframe_count = 0; | ||
245 | dev->_audiofile_status = END_OF_FILE; | ||
246 | |||
247 | kfree(dev->_irq_audio_queues); | ||
248 | dev->_irq_audio_queues = NULL; | ||
249 | |||
250 | kfree(dev->_audiofilename); | ||
251 | } | ||
252 | |||
253 | void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev) | ||
254 | { | ||
255 | if (dev->_audio_is_running) | ||
256 | cx25821_stop_upstream_audio(dev); | ||
257 | |||
258 | cx25821_free_memory_audio(dev); | ||
259 | } | ||
260 | |||
261 | int cx25821_get_audio_data(struct cx25821_dev *dev, | ||
262 | struct sram_channel *sram_ch) | ||
263 | { | ||
264 | struct file *myfile; | ||
265 | int frame_index_temp = dev->_audioframe_index; | ||
266 | int i = 0; | ||
267 | int line_size = AUDIO_LINE_SIZE; | ||
268 | int frame_size = AUDIO_DATA_BUF_SZ; | ||
269 | int frame_offset = frame_size * frame_index_temp; | ||
270 | ssize_t vfs_read_retval = 0; | ||
271 | char mybuf[line_size]; | ||
272 | loff_t file_offset = dev->_audioframe_count * frame_size; | ||
273 | loff_t pos; | ||
274 | mm_segment_t old_fs; | ||
275 | |||
276 | if (dev->_audiofile_status == END_OF_FILE) | ||
277 | return 0; | ||
278 | |||
279 | myfile = filp_open(dev->_audiofilename, O_RDONLY | O_LARGEFILE, 0); | ||
280 | |||
281 | if (IS_ERR(myfile)) { | ||
282 | const int open_errno = -PTR_ERR(myfile); | ||
283 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
284 | __func__, dev->_audiofilename, open_errno); | ||
285 | return PTR_ERR(myfile); | ||
286 | } else { | ||
287 | if (!(myfile->f_op)) { | ||
288 | pr_err("%s(): File has no file operations registered!\n", | ||
289 | __func__); | ||
290 | filp_close(myfile, NULL); | ||
291 | return -EIO; | ||
292 | } | ||
293 | |||
294 | if (!myfile->f_op->read) { | ||
295 | pr_err("%s(): File has no READ operations registered!\n", | ||
296 | __func__); | ||
297 | filp_close(myfile, NULL); | ||
298 | return -EIO; | ||
299 | } | ||
300 | |||
301 | pos = myfile->f_pos; | ||
302 | old_fs = get_fs(); | ||
303 | set_fs(KERNEL_DS); | ||
304 | |||
305 | for (i = 0; i < dev->_audio_lines_count; i++) { | ||
306 | pos = file_offset; | ||
307 | |||
308 | vfs_read_retval = | ||
309 | vfs_read(myfile, mybuf, line_size, &pos); | ||
310 | |||
311 | if (vfs_read_retval > 0 && vfs_read_retval == line_size | ||
312 | && dev->_audiodata_buf_virt_addr != NULL) { | ||
313 | memcpy((void *)(dev->_audiodata_buf_virt_addr + | ||
314 | frame_offset / 4), mybuf, | ||
315 | vfs_read_retval); | ||
316 | } | ||
317 | |||
318 | file_offset += vfs_read_retval; | ||
319 | frame_offset += vfs_read_retval; | ||
320 | |||
321 | if (vfs_read_retval < line_size) { | ||
322 | pr_info("Done: exit %s() since no more bytes to read from Audio file\n", | ||
323 | __func__); | ||
324 | break; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | if (i > 0) | ||
329 | dev->_audioframe_count++; | ||
330 | |||
331 | dev->_audiofile_status = | ||
332 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | ||
333 | |||
334 | set_fs(old_fs); | ||
335 | filp_close(myfile, NULL); | ||
336 | } | ||
337 | |||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static void cx25821_audioups_handler(struct work_struct *work) | ||
342 | { | ||
343 | struct cx25821_dev *dev = | ||
344 | container_of(work, struct cx25821_dev, _audio_work_entry); | ||
345 | |||
346 | if (!dev) { | ||
347 | pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", | ||
348 | __func__); | ||
349 | return; | ||
350 | } | ||
351 | |||
352 | cx25821_get_audio_data(dev, dev->channels[dev->_audio_upstream_channel]. | ||
353 | sram_channels); | ||
354 | } | ||
355 | |||
356 | int cx25821_openfile_audio(struct cx25821_dev *dev, | ||
357 | struct sram_channel *sram_ch) | ||
358 | { | ||
359 | struct file *myfile; | ||
360 | int i = 0, j = 0; | ||
361 | int line_size = AUDIO_LINE_SIZE; | ||
362 | ssize_t vfs_read_retval = 0; | ||
363 | char mybuf[line_size]; | ||
364 | loff_t pos; | ||
365 | loff_t offset = (unsigned long)0; | ||
366 | mm_segment_t old_fs; | ||
367 | |||
368 | myfile = filp_open(dev->_audiofilename, O_RDONLY | O_LARGEFILE, 0); | ||
369 | |||
370 | if (IS_ERR(myfile)) { | ||
371 | const int open_errno = -PTR_ERR(myfile); | ||
372 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
373 | __func__, dev->_audiofilename, open_errno); | ||
374 | return PTR_ERR(myfile); | ||
375 | } else { | ||
376 | if (!(myfile->f_op)) { | ||
377 | pr_err("%s(): File has no file operations registered!\n", | ||
378 | __func__); | ||
379 | filp_close(myfile, NULL); | ||
380 | return -EIO; | ||
381 | } | ||
382 | |||
383 | if (!myfile->f_op->read) { | ||
384 | pr_err("%s(): File has no READ operations registered!\n", | ||
385 | __func__); | ||
386 | filp_close(myfile, NULL); | ||
387 | return -EIO; | ||
388 | } | ||
389 | |||
390 | pos = myfile->f_pos; | ||
391 | old_fs = get_fs(); | ||
392 | set_fs(KERNEL_DS); | ||
393 | |||
394 | for (j = 0; j < NUM_AUDIO_FRAMES; j++) { | ||
395 | for (i = 0; i < dev->_audio_lines_count; i++) { | ||
396 | pos = offset; | ||
397 | |||
398 | vfs_read_retval = | ||
399 | vfs_read(myfile, mybuf, line_size, &pos); | ||
400 | |||
401 | if (vfs_read_retval > 0 | ||
402 | && vfs_read_retval == line_size | ||
403 | && dev->_audiodata_buf_virt_addr != NULL) { | ||
404 | memcpy((void *)(dev-> | ||
405 | _audiodata_buf_virt_addr | ||
406 | + offset / 4), mybuf, | ||
407 | vfs_read_retval); | ||
408 | } | ||
409 | |||
410 | offset += vfs_read_retval; | ||
411 | |||
412 | if (vfs_read_retval < line_size) { | ||
413 | pr_info("Done: exit %s() since no more bytes to read from Audio file\n", | ||
414 | __func__); | ||
415 | break; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | if (i > 0) | ||
420 | dev->_audioframe_count++; | ||
421 | |||
422 | if (vfs_read_retval < line_size) | ||
423 | break; | ||
424 | } | ||
425 | |||
426 | dev->_audiofile_status = | ||
427 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | ||
428 | |||
429 | set_fs(old_fs); | ||
430 | myfile->f_pos = 0; | ||
431 | filp_close(myfile, NULL); | ||
432 | } | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev, | ||
438 | struct sram_channel *sram_ch, | ||
439 | int bpl) | ||
440 | { | ||
441 | int ret = 0; | ||
442 | dma_addr_t dma_addr; | ||
443 | dma_addr_t data_dma_addr; | ||
444 | |||
445 | cx25821_free_memory_audio(dev); | ||
446 | |||
447 | dev->_risc_virt_addr = | ||
448 | pci_alloc_consistent(dev->pci, dev->audio_upstream_riscbuf_size, | ||
449 | &dma_addr); | ||
450 | dev->_risc_virt_start_addr = dev->_risc_virt_addr; | ||
451 | dev->_risc_phys_start_addr = dma_addr; | ||
452 | dev->_risc_phys_addr = dma_addr; | ||
453 | dev->_audiorisc_size = dev->audio_upstream_riscbuf_size; | ||
454 | |||
455 | if (!dev->_risc_virt_addr) { | ||
456 | printk(KERN_DEBUG | ||
457 | pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n")); | ||
458 | return -ENOMEM; | ||
459 | } | ||
460 | /* Clear out memory at address */ | ||
461 | memset(dev->_risc_virt_addr, 0, dev->_audiorisc_size); | ||
462 | |||
463 | /* For Audio Data buffer allocation */ | ||
464 | dev->_audiodata_buf_virt_addr = | ||
465 | pci_alloc_consistent(dev->pci, dev->audio_upstream_databuf_size, | ||
466 | &data_dma_addr); | ||
467 | dev->_audiodata_buf_phys_addr = data_dma_addr; | ||
468 | dev->_audiodata_buf_size = dev->audio_upstream_databuf_size; | ||
469 | |||
470 | if (!dev->_audiodata_buf_virt_addr) { | ||
471 | printk(KERN_DEBUG | ||
472 | pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n")); | ||
473 | return -ENOMEM; | ||
474 | } | ||
475 | /* Clear out memory at address */ | ||
476 | memset(dev->_audiodata_buf_virt_addr, 0, dev->_audiodata_buf_size); | ||
477 | |||
478 | ret = cx25821_openfile_audio(dev, sram_ch); | ||
479 | if (ret < 0) | ||
480 | return ret; | ||
481 | |||
482 | /* Creating RISC programs */ | ||
483 | ret = | ||
484 | cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl, | ||
485 | dev->_audio_lines_count); | ||
486 | if (ret < 0) { | ||
487 | printk(KERN_DEBUG | ||
488 | pr_fmt("ERROR creating audio upstream RISC programs!\n")); | ||
489 | goto error; | ||
490 | } | ||
491 | |||
492 | return 0; | ||
493 | |||
494 | error: | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num, | ||
499 | u32 status) | ||
500 | { | ||
501 | int i = 0; | ||
502 | u32 int_msk_tmp; | ||
503 | struct sram_channel *channel = dev->channels[chan_num].sram_channels; | ||
504 | dma_addr_t risc_phys_jump_addr; | ||
505 | __le32 *rp; | ||
506 | |||
507 | if (status & FLD_AUD_SRC_RISCI1) { | ||
508 | /* Get interrupt_index of the program that interrupted */ | ||
509 | u32 prog_cnt = cx_read(channel->gpcnt); | ||
510 | |||
511 | /* Since we've identified our IRQ, clear our bits from the | ||
512 | * interrupt mask and interrupt status registers */ | ||
513 | cx_write(channel->int_msk, 0); | ||
514 | cx_write(channel->int_stat, cx_read(channel->int_stat)); | ||
515 | |||
516 | spin_lock(&dev->slock); | ||
517 | |||
518 | while (prog_cnt != dev->_last_index_irq) { | ||
519 | /* Update _last_index_irq */ | ||
520 | if (dev->_last_index_irq < (NUMBER_OF_PROGRAMS - 1)) | ||
521 | dev->_last_index_irq++; | ||
522 | else | ||
523 | dev->_last_index_irq = 0; | ||
524 | |||
525 | dev->_audioframe_index = dev->_last_index_irq; | ||
526 | |||
527 | queue_work(dev->_irq_audio_queues, | ||
528 | &dev->_audio_work_entry); | ||
529 | } | ||
530 | |||
531 | if (dev->_is_first_audio_frame) { | ||
532 | dev->_is_first_audio_frame = 0; | ||
533 | |||
534 | if (dev->_risc_virt_start_addr != NULL) { | ||
535 | risc_phys_jump_addr = | ||
536 | dev->_risc_phys_start_addr + | ||
537 | RISC_SYNC_INSTRUCTION_SIZE + | ||
538 | AUDIO_RISC_DMA_BUF_SIZE; | ||
539 | |||
540 | rp = cx25821_risc_field_upstream_audio(dev, | ||
541 | dev->_risc_virt_start_addr + 1, | ||
542 | dev->_audiodata_buf_phys_addr, | ||
543 | AUDIO_LINE_SIZE, FIFO_DISABLE); | ||
544 | |||
545 | if (USE_RISC_NOOP_AUDIO) { | ||
546 | for (i = 0; i < NUM_NO_OPS; i++) { | ||
547 | *(rp++) = | ||
548 | cpu_to_le32(RISC_NOOP); | ||
549 | } | ||
550 | } | ||
551 | /* Jump to 2nd Audio Frame */ | ||
552 | *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | | ||
553 | RISC_CNT_RESET); | ||
554 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
555 | *(rp++) = cpu_to_le32(0); | ||
556 | } | ||
557 | } | ||
558 | |||
559 | spin_unlock(&dev->slock); | ||
560 | } else { | ||
561 | if (status & FLD_AUD_SRC_OF) | ||
562 | pr_warn("%s(): Audio Received Overflow Error Interrupt!\n", | ||
563 | __func__); | ||
564 | |||
565 | if (status & FLD_AUD_SRC_SYNC) | ||
566 | pr_warn("%s(): Audio Received Sync Error Interrupt!\n", | ||
567 | __func__); | ||
568 | |||
569 | if (status & FLD_AUD_SRC_OPC_ERR) | ||
570 | pr_warn("%s(): Audio Received OpCode Error Interrupt!\n", | ||
571 | __func__); | ||
572 | |||
573 | /* Read and write back the interrupt status register to clear | ||
574 | * our bits */ | ||
575 | cx_write(channel->int_stat, cx_read(channel->int_stat)); | ||
576 | } | ||
577 | |||
578 | if (dev->_audiofile_status == END_OF_FILE) { | ||
579 | pr_warn("EOF Channel Audio Framecount = %d\n", | ||
580 | dev->_audioframe_count); | ||
581 | return -1; | ||
582 | } | ||
583 | /* ElSE, set the interrupt mask register, re-enable irq. */ | ||
584 | int_msk_tmp = cx_read(channel->int_msk); | ||
585 | cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id) | ||
591 | { | ||
592 | struct cx25821_dev *dev = dev_id; | ||
593 | u32 msk_stat, audio_status; | ||
594 | int handled = 0; | ||
595 | struct sram_channel *sram_ch; | ||
596 | |||
597 | if (!dev) | ||
598 | return -1; | ||
599 | |||
600 | sram_ch = dev->channels[dev->_audio_upstream_channel].sram_channels; | ||
601 | |||
602 | msk_stat = cx_read(sram_ch->int_mstat); | ||
603 | audio_status = cx_read(sram_ch->int_stat); | ||
604 | |||
605 | /* Only deal with our interrupt */ | ||
606 | if (audio_status) { | ||
607 | handled = cx25821_audio_upstream_irq(dev, | ||
608 | dev->_audio_upstream_channel, audio_status); | ||
609 | } | ||
610 | |||
611 | if (handled < 0) | ||
612 | cx25821_stop_upstream_audio(dev); | ||
613 | else | ||
614 | handled += handled; | ||
615 | |||
616 | return IRQ_RETVAL(handled); | ||
617 | } | ||
618 | |||
619 | static void cx25821_wait_fifo_enable(struct cx25821_dev *dev, | ||
620 | struct sram_channel *sram_ch) | ||
621 | { | ||
622 | int count = 0; | ||
623 | u32 tmp; | ||
624 | |||
625 | do { | ||
626 | /* Wait 10 microsecond before checking to see if the FIFO is | ||
627 | * turned ON. */ | ||
628 | udelay(10); | ||
629 | |||
630 | tmp = cx_read(sram_ch->dma_ctl); | ||
631 | |||
632 | /* 10 millisecond timeout */ | ||
633 | if (count++ > 1000) { | ||
634 | pr_err("ERROR: %s() fifo is NOT turned on. Timeout!\n", | ||
635 | __func__); | ||
636 | return; | ||
637 | } | ||
638 | |||
639 | } while (!(tmp & sram_ch->fld_aud_fifo_en)); | ||
640 | |||
641 | } | ||
642 | |||
643 | int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev, | ||
644 | struct sram_channel *sram_ch) | ||
645 | { | ||
646 | u32 tmp = 0; | ||
647 | int err = 0; | ||
648 | |||
649 | /* Set the physical start address of the RISC program in the initial | ||
650 | * program counter(IPC) member of the CMDS. */ | ||
651 | cx_write(sram_ch->cmds_start + 0, dev->_risc_phys_addr); | ||
652 | /* Risc IPC High 64 bits 63-32 */ | ||
653 | cx_write(sram_ch->cmds_start + 4, 0); | ||
654 | |||
655 | /* reset counter */ | ||
656 | cx_write(sram_ch->gpcnt_ctl, 3); | ||
657 | |||
658 | /* Set the line length (It looks like we do not need to set the | ||
659 | * line length) */ | ||
660 | cx_write(sram_ch->aud_length, AUDIO_LINE_SIZE & FLD_AUD_DST_LN_LNGTH); | ||
661 | |||
662 | /* Set the input mode to 16-bit */ | ||
663 | tmp = cx_read(sram_ch->aud_cfg); | ||
664 | tmp |= | ||
665 | FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE | | ||
666 | FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D | FLD_AUD_SONY_MODE; | ||
667 | cx_write(sram_ch->aud_cfg, tmp); | ||
668 | |||
669 | /* Read and write back the interrupt status register to clear it */ | ||
670 | tmp = cx_read(sram_ch->int_stat); | ||
671 | cx_write(sram_ch->int_stat, tmp); | ||
672 | |||
673 | /* Clear our bits from the interrupt status register. */ | ||
674 | cx_write(sram_ch->int_stat, _intr_msk); | ||
675 | |||
676 | /* Set the interrupt mask register, enable irq. */ | ||
677 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); | ||
678 | tmp = cx_read(sram_ch->int_msk); | ||
679 | cx_write(sram_ch->int_msk, tmp |= _intr_msk); | ||
680 | |||
681 | err = | ||
682 | request_irq(dev->pci->irq, cx25821_upstream_irq_audio, | ||
683 | IRQF_SHARED, dev->name, dev); | ||
684 | if (err < 0) { | ||
685 | pr_err("%s: can't get upstream IRQ %d\n", | ||
686 | dev->name, dev->pci->irq); | ||
687 | goto fail_irq; | ||
688 | } | ||
689 | |||
690 | /* Start the DMA engine */ | ||
691 | tmp = cx_read(sram_ch->dma_ctl); | ||
692 | cx_set(sram_ch->dma_ctl, tmp | sram_ch->fld_aud_risc_en); | ||
693 | |||
694 | dev->_audio_is_running = 1; | ||
695 | dev->_is_first_audio_frame = 1; | ||
696 | |||
697 | /* The fifo_en bit turns on by the first Risc program */ | ||
698 | cx25821_wait_fifo_enable(dev, sram_ch); | ||
699 | |||
700 | return 0; | ||
701 | |||
702 | fail_irq: | ||
703 | cx25821_dev_unregister(dev); | ||
704 | return err; | ||
705 | } | ||
706 | |||
707 | int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) | ||
708 | { | ||
709 | struct sram_channel *sram_ch; | ||
710 | int retval = 0; | ||
711 | int err = 0; | ||
712 | int str_length = 0; | ||
713 | |||
714 | if (dev->_audio_is_running) { | ||
715 | pr_warn("Audio Channel is still running so return!\n"); | ||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | dev->_audio_upstream_channel = channel_select; | ||
720 | sram_ch = dev->channels[channel_select].sram_channels; | ||
721 | |||
722 | /* Work queue */ | ||
723 | INIT_WORK(&dev->_audio_work_entry, cx25821_audioups_handler); | ||
724 | dev->_irq_audio_queues = | ||
725 | create_singlethread_workqueue("cx25821_audioworkqueue"); | ||
726 | |||
727 | if (!dev->_irq_audio_queues) { | ||
728 | printk(KERN_DEBUG | ||
729 | pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n")); | ||
730 | return -ENOMEM; | ||
731 | } | ||
732 | |||
733 | dev->_last_index_irq = 0; | ||
734 | dev->_audio_is_running = 0; | ||
735 | dev->_audioframe_count = 0; | ||
736 | dev->_audiofile_status = RESET_STATUS; | ||
737 | dev->_audio_lines_count = LINES_PER_AUDIO_BUFFER; | ||
738 | _line_size = AUDIO_LINE_SIZE; | ||
739 | |||
740 | if (dev->input_audiofilename) { | ||
741 | str_length = strlen(dev->input_audiofilename); | ||
742 | dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL); | ||
743 | |||
744 | if (!dev->_audiofilename) | ||
745 | goto error; | ||
746 | |||
747 | memcpy(dev->_audiofilename, dev->input_audiofilename, | ||
748 | str_length + 1); | ||
749 | |||
750 | /* Default if filename is empty string */ | ||
751 | if (strcmp(dev->input_audiofilename, "") == 0) | ||
752 | dev->_audiofilename = "/root/audioGOOD.wav"; | ||
753 | } else { | ||
754 | str_length = strlen(_defaultAudioName); | ||
755 | dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL); | ||
756 | |||
757 | if (!dev->_audiofilename) | ||
758 | goto error; | ||
759 | |||
760 | memcpy(dev->_audiofilename, _defaultAudioName, str_length + 1); | ||
761 | } | ||
762 | |||
763 | retval = cx25821_sram_channel_setup_upstream_audio(dev, sram_ch, | ||
764 | _line_size, 0); | ||
765 | |||
766 | dev->audio_upstream_riscbuf_size = | ||
767 | AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS + | ||
768 | RISC_SYNC_INSTRUCTION_SIZE; | ||
769 | dev->audio_upstream_databuf_size = AUDIO_DATA_BUF_SZ * NUM_AUDIO_PROGS; | ||
770 | |||
771 | /* Allocating buffers and prepare RISC program */ | ||
772 | retval = cx25821_audio_upstream_buffer_prepare(dev, sram_ch, | ||
773 | _line_size); | ||
774 | if (retval < 0) { | ||
775 | pr_err("%s: Failed to set up Audio upstream buffers!\n", | ||
776 | dev->name); | ||
777 | goto error; | ||
778 | } | ||
779 | /* Start RISC engine */ | ||
780 | cx25821_start_audio_dma_upstream(dev, sram_ch); | ||
781 | |||
782 | return 0; | ||
783 | |||
784 | error: | ||
785 | cx25821_dev_unregister(dev); | ||
786 | |||
787 | return err; | ||
788 | } | ||
diff --git a/drivers/media/video/cx25821/cx25821-audio-upstream.h b/drivers/media/video/cx25821/cx25821-audio-upstream.h new file mode 100644 index 000000000000..af2ae7c5815a --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-audio-upstream.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | |||
26 | #define NUM_AUDIO_PROGS 8 | ||
27 | #define NUM_AUDIO_FRAMES 8 | ||
28 | #define END_OF_FILE 0 | ||
29 | #define IN_PROGRESS 1 | ||
30 | #define RESET_STATUS -1 | ||
31 | #define FIFO_DISABLE 0 | ||
32 | #define FIFO_ENABLE 1 | ||
33 | #define NUM_NO_OPS 4 | ||
34 | |||
35 | #define RISC_READ_INSTRUCTION_SIZE 12 | ||
36 | #define RISC_JUMP_INSTRUCTION_SIZE 12 | ||
37 | #define RISC_WRITECR_INSTRUCTION_SIZE 16 | ||
38 | #define RISC_SYNC_INSTRUCTION_SIZE 4 | ||
39 | #define DWORD_SIZE 4 | ||
40 | #define AUDIO_SYNC_LINE 4 | ||
41 | |||
42 | #define LINES_PER_AUDIO_BUFFER 15 | ||
43 | #define AUDIO_LINE_SIZE 128 | ||
44 | #define AUDIO_DATA_BUF_SZ (AUDIO_LINE_SIZE * LINES_PER_AUDIO_BUFFER) | ||
45 | |||
46 | #define USE_RISC_NOOP_AUDIO 1 | ||
47 | |||
48 | #ifdef USE_RISC_NOOP_AUDIO | ||
49 | #define AUDIO_RISC_DMA_BUF_SIZE \ | ||
50 | (LINES_PER_AUDIO_BUFFER * RISC_READ_INSTRUCTION_SIZE + \ | ||
51 | RISC_WRITECR_INSTRUCTION_SIZE + NUM_NO_OPS * DWORD_SIZE + \ | ||
52 | RISC_JUMP_INSTRUCTION_SIZE) | ||
53 | #endif | ||
54 | |||
55 | #ifndef USE_RISC_NOOP_AUDIO | ||
56 | #define AUDIO_RISC_DMA_BUF_SIZE \ | ||
57 | (LINES_PER_AUDIO_BUFFER * RISC_READ_INSTRUCTION_SIZE + \ | ||
58 | RISC_WRITECR_INSTRUCTION_SIZE + RISC_JUMP_INSTRUCTION_SIZE) | ||
59 | #endif | ||
60 | |||
61 | static int _line_size; | ||
62 | char *_defaultAudioName = "/root/audioGOOD.wav"; | ||
diff --git a/drivers/media/video/cx25821/cx25821-audio.h b/drivers/media/video/cx25821/cx25821-audio.h new file mode 100644 index 000000000000..8eb55b7b88cb --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-audio.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #ifndef __CX25821_AUDIO_H__ | ||
24 | #define __CX25821_AUDIO_H__ | ||
25 | |||
26 | #define USE_RISC_NOOP 1 | ||
27 | #define LINES_PER_BUFFER 15 | ||
28 | #define AUDIO_LINE_SIZE 128 | ||
29 | |||
30 | /* Number of buffer programs to use at once. */ | ||
31 | #define NUMBER_OF_PROGRAMS 8 | ||
32 | |||
33 | /* | ||
34 | * Max size of the RISC program for a buffer. - worst case is 2 writes per line | ||
35 | * Space is also added for the 4 no-op instructions added on the end. | ||
36 | */ | ||
37 | #ifndef USE_RISC_NOOP | ||
38 | #define MAX_BUFFER_PROGRAM_SIZE \ | ||
39 | (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ | ||
40 | RISC_WRITECR_INSTRUCTION_SIZE * 4) | ||
41 | #endif | ||
42 | |||
43 | /* MAE 12 July 2005 Try to use NOOP RISC instruction instead */ | ||
44 | #ifdef USE_RISC_NOOP | ||
45 | #define MAX_BUFFER_PROGRAM_SIZE \ | ||
46 | (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ | ||
47 | RISC_NOOP_INSTRUCTION_SIZE * 4) | ||
48 | #endif | ||
49 | |||
50 | /* Sizes of various instructions in bytes. Used when adding instructions. */ | ||
51 | #define RISC_WRITE_INSTRUCTION_SIZE 12 | ||
52 | #define RISC_JUMP_INSTRUCTION_SIZE 12 | ||
53 | #define RISC_SKIP_INSTRUCTION_SIZE 4 | ||
54 | #define RISC_SYNC_INSTRUCTION_SIZE 4 | ||
55 | #define RISC_WRITECR_INSTRUCTION_SIZE 16 | ||
56 | #define RISC_NOOP_INSTRUCTION_SIZE 4 | ||
57 | |||
58 | #define MAX_AUDIO_DMA_BUFFER_SIZE \ | ||
59 | (MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS + RISC_SYNC_INSTRUCTION_SIZE) | ||
60 | |||
61 | #endif | ||
diff --git a/drivers/media/video/cx25821/cx25821-biffuncs.h b/drivers/media/video/cx25821/cx25821-biffuncs.h new file mode 100644 index 000000000000..9326a7c729ec --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-biffuncs.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #ifndef _BITFUNCS_H | ||
24 | #define _BITFUNCS_H | ||
25 | |||
26 | #define SetBit(Bit) (1 << Bit) | ||
27 | |||
28 | inline u8 getBit(u32 sample, u8 index) | ||
29 | { | ||
30 | return (u8) ((sample >> index) & 1); | ||
31 | } | ||
32 | |||
33 | inline u32 clearBitAtPos(u32 value, u8 bit) | ||
34 | { | ||
35 | return value & ~(1 << bit); | ||
36 | } | ||
37 | |||
38 | inline u32 setBitAtPos(u32 sample, u8 bit) | ||
39 | { | ||
40 | sample |= (1 << bit); | ||
41 | return sample; | ||
42 | |||
43 | } | ||
44 | |||
45 | #endif | ||
diff --git a/drivers/media/video/cx25821/cx25821-cards.c b/drivers/media/video/cx25821/cx25821-cards.c new file mode 100644 index 000000000000..6ace60313b49 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-cards.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * | ||
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 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <media/cx25840.h> | ||
31 | |||
32 | #include "cx25821.h" | ||
33 | #include "tuner-xc2028.h" | ||
34 | |||
35 | /* board config info */ | ||
36 | |||
37 | struct cx25821_board cx25821_boards[] = { | ||
38 | [UNKNOWN_BOARD] = { | ||
39 | .name = "UNKNOWN/GENERIC", | ||
40 | /* Ensure safe default for unknown boards */ | ||
41 | .clk_freq = 0, | ||
42 | }, | ||
43 | |||
44 | [CX25821_BOARD] = { | ||
45 | .name = "CX25821", | ||
46 | .portb = CX25821_RAW, | ||
47 | .portc = CX25821_264, | ||
48 | .input[0].type = CX25821_VMUX_COMPOSITE, | ||
49 | }, | ||
50 | |||
51 | }; | ||
52 | |||
53 | const unsigned int cx25821_bcount = ARRAY_SIZE(cx25821_boards); | ||
54 | |||
55 | struct cx25821_subid cx25821_subids[] = { | ||
56 | { | ||
57 | .subvendor = 0x14f1, | ||
58 | .subdevice = 0x0920, | ||
59 | .card = CX25821_BOARD, | ||
60 | }, | ||
61 | }; | ||
62 | |||
63 | void cx25821_card_setup(struct cx25821_dev *dev) | ||
64 | { | ||
65 | static u8 eeprom[256]; | ||
66 | |||
67 | if (dev->i2c_bus[0].i2c_rc == 0) { | ||
68 | dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; | ||
69 | tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, | ||
70 | sizeof(eeprom)); | ||
71 | } | ||
72 | } | ||
diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c new file mode 100644 index 000000000000..a7fa38f9594e --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-core.c | |||
@@ -0,0 +1,1517 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * | ||
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 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
25 | |||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include "cx25821.h" | ||
29 | #include "cx25821-sram.h" | ||
30 | #include "cx25821-video.h" | ||
31 | |||
32 | MODULE_DESCRIPTION("Driver for Athena cards"); | ||
33 | MODULE_AUTHOR("Shu Lin - Hiep Huynh"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static unsigned int debug; | ||
37 | module_param(debug, int, 0644); | ||
38 | MODULE_PARM_DESC(debug, "enable debug messages"); | ||
39 | |||
40 | static unsigned int card[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; | ||
41 | module_param_array(card, int, NULL, 0444); | ||
42 | MODULE_PARM_DESC(card, "card type"); | ||
43 | |||
44 | static unsigned int cx25821_devcount; | ||
45 | |||
46 | DEFINE_MUTEX(cx25821_devlist_mutex); | ||
47 | EXPORT_SYMBOL(cx25821_devlist_mutex); | ||
48 | LIST_HEAD(cx25821_devlist); | ||
49 | EXPORT_SYMBOL(cx25821_devlist); | ||
50 | |||
51 | struct sram_channel cx25821_sram_channels[] = { | ||
52 | [SRAM_CH00] = { | ||
53 | .i = SRAM_CH00, | ||
54 | .name = "VID A", | ||
55 | .cmds_start = VID_A_DOWN_CMDS, | ||
56 | .ctrl_start = VID_A_IQ, | ||
57 | .cdt = VID_A_CDT, | ||
58 | .fifo_start = VID_A_DOWN_CLUSTER_1, | ||
59 | .fifo_size = (VID_CLUSTER_SIZE << 2), | ||
60 | .ptr1_reg = DMA1_PTR1, | ||
61 | .ptr2_reg = DMA1_PTR2, | ||
62 | .cnt1_reg = DMA1_CNT1, | ||
63 | .cnt2_reg = DMA1_CNT2, | ||
64 | .int_msk = VID_A_INT_MSK, | ||
65 | .int_stat = VID_A_INT_STAT, | ||
66 | .int_mstat = VID_A_INT_MSTAT, | ||
67 | .dma_ctl = VID_DST_A_DMA_CTL, | ||
68 | .gpcnt_ctl = VID_DST_A_GPCNT_CTL, | ||
69 | .gpcnt = VID_DST_A_GPCNT, | ||
70 | .vip_ctl = VID_DST_A_VIP_CTL, | ||
71 | .pix_frmt = VID_DST_A_PIX_FRMT, | ||
72 | }, | ||
73 | |||
74 | [SRAM_CH01] = { | ||
75 | .i = SRAM_CH01, | ||
76 | .name = "VID B", | ||
77 | .cmds_start = VID_B_DOWN_CMDS, | ||
78 | .ctrl_start = VID_B_IQ, | ||
79 | .cdt = VID_B_CDT, | ||
80 | .fifo_start = VID_B_DOWN_CLUSTER_1, | ||
81 | .fifo_size = (VID_CLUSTER_SIZE << 2), | ||
82 | .ptr1_reg = DMA2_PTR1, | ||
83 | .ptr2_reg = DMA2_PTR2, | ||
84 | .cnt1_reg = DMA2_CNT1, | ||
85 | .cnt2_reg = DMA2_CNT2, | ||
86 | .int_msk = VID_B_INT_MSK, | ||
87 | .int_stat = VID_B_INT_STAT, | ||
88 | .int_mstat = VID_B_INT_MSTAT, | ||
89 | .dma_ctl = VID_DST_B_DMA_CTL, | ||
90 | .gpcnt_ctl = VID_DST_B_GPCNT_CTL, | ||
91 | .gpcnt = VID_DST_B_GPCNT, | ||
92 | .vip_ctl = VID_DST_B_VIP_CTL, | ||
93 | .pix_frmt = VID_DST_B_PIX_FRMT, | ||
94 | }, | ||
95 | |||
96 | [SRAM_CH02] = { | ||
97 | .i = SRAM_CH02, | ||
98 | .name = "VID C", | ||
99 | .cmds_start = VID_C_DOWN_CMDS, | ||
100 | .ctrl_start = VID_C_IQ, | ||
101 | .cdt = VID_C_CDT, | ||
102 | .fifo_start = VID_C_DOWN_CLUSTER_1, | ||
103 | .fifo_size = (VID_CLUSTER_SIZE << 2), | ||
104 | .ptr1_reg = DMA3_PTR1, | ||
105 | .ptr2_reg = DMA3_PTR2, | ||
106 | .cnt1_reg = DMA3_CNT1, | ||
107 | .cnt2_reg = DMA3_CNT2, | ||
108 | .int_msk = VID_C_INT_MSK, | ||
109 | .int_stat = VID_C_INT_STAT, | ||
110 | .int_mstat = VID_C_INT_MSTAT, | ||
111 | .dma_ctl = VID_DST_C_DMA_CTL, | ||
112 | .gpcnt_ctl = VID_DST_C_GPCNT_CTL, | ||
113 | .gpcnt = VID_DST_C_GPCNT, | ||
114 | .vip_ctl = VID_DST_C_VIP_CTL, | ||
115 | .pix_frmt = VID_DST_C_PIX_FRMT, | ||
116 | }, | ||
117 | |||
118 | [SRAM_CH03] = { | ||
119 | .i = SRAM_CH03, | ||
120 | .name = "VID D", | ||
121 | .cmds_start = VID_D_DOWN_CMDS, | ||
122 | .ctrl_start = VID_D_IQ, | ||
123 | .cdt = VID_D_CDT, | ||
124 | .fifo_start = VID_D_DOWN_CLUSTER_1, | ||
125 | .fifo_size = (VID_CLUSTER_SIZE << 2), | ||
126 | .ptr1_reg = DMA4_PTR1, | ||
127 | .ptr2_reg = DMA4_PTR2, | ||
128 | .cnt1_reg = DMA4_CNT1, | ||
129 | .cnt2_reg = DMA4_CNT2, | ||
130 | .int_msk = VID_D_INT_MSK, | ||
131 | .int_stat = VID_D_INT_STAT, | ||
132 | .int_mstat = VID_D_INT_MSTAT, | ||
133 | .dma_ctl = VID_DST_D_DMA_CTL, | ||
134 | .gpcnt_ctl = VID_DST_D_GPCNT_CTL, | ||
135 | .gpcnt = VID_DST_D_GPCNT, | ||
136 | .vip_ctl = VID_DST_D_VIP_CTL, | ||
137 | .pix_frmt = VID_DST_D_PIX_FRMT, | ||
138 | }, | ||
139 | |||
140 | [SRAM_CH04] = { | ||
141 | .i = SRAM_CH04, | ||
142 | .name = "VID E", | ||
143 | .cmds_start = VID_E_DOWN_CMDS, | ||
144 | .ctrl_start = VID_E_IQ, | ||
145 | .cdt = VID_E_CDT, | ||
146 | .fifo_start = VID_E_DOWN_CLUSTER_1, | ||
147 | .fifo_size = (VID_CLUSTER_SIZE << 2), | ||
148 | .ptr1_reg = DMA5_PTR1, | ||
149 | .ptr2_reg = DMA5_PTR2, | ||
150 | .cnt1_reg = DMA5_CNT1, | ||
151 | .cnt2_reg = DMA5_CNT2, | ||
152 | .int_msk = VID_E_INT_MSK, | ||
153 | .int_stat = VID_E_INT_STAT, | ||
154 | .int_mstat = VID_E_INT_MSTAT, | ||
155 | .dma_ctl = VID_DST_E_DMA_CTL, | ||
156 | .gpcnt_ctl = VID_DST_E_GPCNT_CTL, | ||
157 | .gpcnt = VID_DST_E_GPCNT, | ||
158 | .vip_ctl = VID_DST_E_VIP_CTL, | ||
159 | .pix_frmt = VID_DST_E_PIX_FRMT, | ||
160 | }, | ||
161 | |||
162 | [SRAM_CH05] = { | ||
163 | .i = SRAM_CH05, | ||
164 | .name = "VID F", | ||
165 | .cmds_start = VID_F_DOWN_CMDS, | ||
166 | .ctrl_start = VID_F_IQ, | ||
167 | .cdt = VID_F_CDT, | ||
168 | .fifo_start = VID_F_DOWN_CLUSTER_1, | ||
169 | .fifo_size = (VID_CLUSTER_SIZE << 2), | ||
170 | .ptr1_reg = DMA6_PTR1, | ||
171 | .ptr2_reg = DMA6_PTR2, | ||
172 | .cnt1_reg = DMA6_CNT1, | ||
173 | .cnt2_reg = DMA6_CNT2, | ||
174 | .int_msk = VID_F_INT_MSK, | ||
175 | .int_stat = VID_F_INT_STAT, | ||
176 | .int_mstat = VID_F_INT_MSTAT, | ||
177 | .dma_ctl = VID_DST_F_DMA_CTL, | ||
178 | .gpcnt_ctl = VID_DST_F_GPCNT_CTL, | ||
179 | .gpcnt = VID_DST_F_GPCNT, | ||
180 | .vip_ctl = VID_DST_F_VIP_CTL, | ||
181 | .pix_frmt = VID_DST_F_PIX_FRMT, | ||
182 | }, | ||
183 | |||
184 | [SRAM_CH06] = { | ||
185 | .i = SRAM_CH06, | ||
186 | .name = "VID G", | ||
187 | .cmds_start = VID_G_DOWN_CMDS, | ||
188 | .ctrl_start = VID_G_IQ, | ||
189 | .cdt = VID_G_CDT, | ||
190 | .fifo_start = VID_G_DOWN_CLUSTER_1, | ||
191 | .fifo_size = (VID_CLUSTER_SIZE << 2), | ||
192 | .ptr1_reg = DMA7_PTR1, | ||
193 | .ptr2_reg = DMA7_PTR2, | ||
194 | .cnt1_reg = DMA7_CNT1, | ||
195 | .cnt2_reg = DMA7_CNT2, | ||
196 | .int_msk = VID_G_INT_MSK, | ||
197 | .int_stat = VID_G_INT_STAT, | ||
198 | .int_mstat = VID_G_INT_MSTAT, | ||
199 | .dma_ctl = VID_DST_G_DMA_CTL, | ||
200 | .gpcnt_ctl = VID_DST_G_GPCNT_CTL, | ||
201 | .gpcnt = VID_DST_G_GPCNT, | ||
202 | .vip_ctl = VID_DST_G_VIP_CTL, | ||
203 | .pix_frmt = VID_DST_G_PIX_FRMT, | ||
204 | }, | ||
205 | |||
206 | [SRAM_CH07] = { | ||
207 | .i = SRAM_CH07, | ||
208 | .name = "VID H", | ||
209 | .cmds_start = VID_H_DOWN_CMDS, | ||
210 | .ctrl_start = VID_H_IQ, | ||
211 | .cdt = VID_H_CDT, | ||
212 | .fifo_start = VID_H_DOWN_CLUSTER_1, | ||
213 | .fifo_size = (VID_CLUSTER_SIZE << 2), | ||
214 | .ptr1_reg = DMA8_PTR1, | ||
215 | .ptr2_reg = DMA8_PTR2, | ||
216 | .cnt1_reg = DMA8_CNT1, | ||
217 | .cnt2_reg = DMA8_CNT2, | ||
218 | .int_msk = VID_H_INT_MSK, | ||
219 | .int_stat = VID_H_INT_STAT, | ||
220 | .int_mstat = VID_H_INT_MSTAT, | ||
221 | .dma_ctl = VID_DST_H_DMA_CTL, | ||
222 | .gpcnt_ctl = VID_DST_H_GPCNT_CTL, | ||
223 | .gpcnt = VID_DST_H_GPCNT, | ||
224 | .vip_ctl = VID_DST_H_VIP_CTL, | ||
225 | .pix_frmt = VID_DST_H_PIX_FRMT, | ||
226 | }, | ||
227 | |||
228 | [SRAM_CH08] = { | ||
229 | .name = "audio from", | ||
230 | .cmds_start = AUD_A_DOWN_CMDS, | ||
231 | .ctrl_start = AUD_A_IQ, | ||
232 | .cdt = AUD_A_CDT, | ||
233 | .fifo_start = AUD_A_DOWN_CLUSTER_1, | ||
234 | .fifo_size = AUDIO_CLUSTER_SIZE * 3, | ||
235 | .ptr1_reg = DMA17_PTR1, | ||
236 | .ptr2_reg = DMA17_PTR2, | ||
237 | .cnt1_reg = DMA17_CNT1, | ||
238 | .cnt2_reg = DMA17_CNT2, | ||
239 | }, | ||
240 | |||
241 | [SRAM_CH09] = { | ||
242 | .i = SRAM_CH09, | ||
243 | .name = "VID Upstream I", | ||
244 | .cmds_start = VID_I_UP_CMDS, | ||
245 | .ctrl_start = VID_I_IQ, | ||
246 | .cdt = VID_I_CDT, | ||
247 | .fifo_start = VID_I_UP_CLUSTER_1, | ||
248 | .fifo_size = (VID_CLUSTER_SIZE << 2), | ||
249 | .ptr1_reg = DMA15_PTR1, | ||
250 | .ptr2_reg = DMA15_PTR2, | ||
251 | .cnt1_reg = DMA15_CNT1, | ||
252 | .cnt2_reg = DMA15_CNT2, | ||
253 | .int_msk = VID_I_INT_MSK, | ||
254 | .int_stat = VID_I_INT_STAT, | ||
255 | .int_mstat = VID_I_INT_MSTAT, | ||
256 | .dma_ctl = VID_SRC_I_DMA_CTL, | ||
257 | .gpcnt_ctl = VID_SRC_I_GPCNT_CTL, | ||
258 | .gpcnt = VID_SRC_I_GPCNT, | ||
259 | |||
260 | .vid_fmt_ctl = VID_SRC_I_FMT_CTL, | ||
261 | .vid_active_ctl1 = VID_SRC_I_ACTIVE_CTL1, | ||
262 | .vid_active_ctl2 = VID_SRC_I_ACTIVE_CTL2, | ||
263 | .vid_cdt_size = VID_SRC_I_CDT_SZ, | ||
264 | .irq_bit = 8, | ||
265 | }, | ||
266 | |||
267 | [SRAM_CH10] = { | ||
268 | .i = SRAM_CH10, | ||
269 | .name = "VID Upstream J", | ||
270 | .cmds_start = VID_J_UP_CMDS, | ||
271 | .ctrl_start = VID_J_IQ, | ||
272 | .cdt = VID_J_CDT, | ||
273 | .fifo_start = VID_J_UP_CLUSTER_1, | ||
274 | .fifo_size = (VID_CLUSTER_SIZE << 2), | ||
275 | .ptr1_reg = DMA16_PTR1, | ||
276 | .ptr2_reg = DMA16_PTR2, | ||
277 | .cnt1_reg = DMA16_CNT1, | ||
278 | .cnt2_reg = DMA16_CNT2, | ||
279 | .int_msk = VID_J_INT_MSK, | ||
280 | .int_stat = VID_J_INT_STAT, | ||
281 | .int_mstat = VID_J_INT_MSTAT, | ||
282 | .dma_ctl = VID_SRC_J_DMA_CTL, | ||
283 | .gpcnt_ctl = VID_SRC_J_GPCNT_CTL, | ||
284 | .gpcnt = VID_SRC_J_GPCNT, | ||
285 | |||
286 | .vid_fmt_ctl = VID_SRC_J_FMT_CTL, | ||
287 | .vid_active_ctl1 = VID_SRC_J_ACTIVE_CTL1, | ||
288 | .vid_active_ctl2 = VID_SRC_J_ACTIVE_CTL2, | ||
289 | .vid_cdt_size = VID_SRC_J_CDT_SZ, | ||
290 | .irq_bit = 9, | ||
291 | }, | ||
292 | |||
293 | [SRAM_CH11] = { | ||
294 | .i = SRAM_CH11, | ||
295 | .name = "Audio Upstream Channel B", | ||
296 | .cmds_start = AUD_B_UP_CMDS, | ||
297 | .ctrl_start = AUD_B_IQ, | ||
298 | .cdt = AUD_B_CDT, | ||
299 | .fifo_start = AUD_B_UP_CLUSTER_1, | ||
300 | .fifo_size = (AUDIO_CLUSTER_SIZE * 3), | ||
301 | .ptr1_reg = DMA22_PTR1, | ||
302 | .ptr2_reg = DMA22_PTR2, | ||
303 | .cnt1_reg = DMA22_CNT1, | ||
304 | .cnt2_reg = DMA22_CNT2, | ||
305 | .int_msk = AUD_B_INT_MSK, | ||
306 | .int_stat = AUD_B_INT_STAT, | ||
307 | .int_mstat = AUD_B_INT_MSTAT, | ||
308 | .dma_ctl = AUD_INT_DMA_CTL, | ||
309 | .gpcnt_ctl = AUD_B_GPCNT_CTL, | ||
310 | .gpcnt = AUD_B_GPCNT, | ||
311 | .aud_length = AUD_B_LNGTH, | ||
312 | .aud_cfg = AUD_B_CFG, | ||
313 | .fld_aud_fifo_en = FLD_AUD_SRC_B_FIFO_EN, | ||
314 | .fld_aud_risc_en = FLD_AUD_SRC_B_RISC_EN, | ||
315 | .irq_bit = 11, | ||
316 | }, | ||
317 | }; | ||
318 | EXPORT_SYMBOL(cx25821_sram_channels); | ||
319 | |||
320 | struct sram_channel *channel0 = &cx25821_sram_channels[SRAM_CH00]; | ||
321 | struct sram_channel *channel1 = &cx25821_sram_channels[SRAM_CH01]; | ||
322 | struct sram_channel *channel2 = &cx25821_sram_channels[SRAM_CH02]; | ||
323 | struct sram_channel *channel3 = &cx25821_sram_channels[SRAM_CH03]; | ||
324 | struct sram_channel *channel4 = &cx25821_sram_channels[SRAM_CH04]; | ||
325 | struct sram_channel *channel5 = &cx25821_sram_channels[SRAM_CH05]; | ||
326 | struct sram_channel *channel6 = &cx25821_sram_channels[SRAM_CH06]; | ||
327 | struct sram_channel *channel7 = &cx25821_sram_channels[SRAM_CH07]; | ||
328 | struct sram_channel *channel9 = &cx25821_sram_channels[SRAM_CH09]; | ||
329 | struct sram_channel *channel10 = &cx25821_sram_channels[SRAM_CH10]; | ||
330 | struct sram_channel *channel11 = &cx25821_sram_channels[SRAM_CH11]; | ||
331 | |||
332 | struct cx25821_dmaqueue mpegq; | ||
333 | |||
334 | static int cx25821_risc_decode(u32 risc) | ||
335 | { | ||
336 | static const char * const instr[16] = { | ||
337 | [RISC_SYNC >> 28] = "sync", | ||
338 | [RISC_WRITE >> 28] = "write", | ||
339 | [RISC_WRITEC >> 28] = "writec", | ||
340 | [RISC_READ >> 28] = "read", | ||
341 | [RISC_READC >> 28] = "readc", | ||
342 | [RISC_JUMP >> 28] = "jump", | ||
343 | [RISC_SKIP >> 28] = "skip", | ||
344 | [RISC_WRITERM >> 28] = "writerm", | ||
345 | [RISC_WRITECM >> 28] = "writecm", | ||
346 | [RISC_WRITECR >> 28] = "writecr", | ||
347 | }; | ||
348 | static const int incr[16] = { | ||
349 | [RISC_WRITE >> 28] = 3, | ||
350 | [RISC_JUMP >> 28] = 3, | ||
351 | [RISC_SKIP >> 28] = 1, | ||
352 | [RISC_SYNC >> 28] = 1, | ||
353 | [RISC_WRITERM >> 28] = 3, | ||
354 | [RISC_WRITECM >> 28] = 3, | ||
355 | [RISC_WRITECR >> 28] = 4, | ||
356 | }; | ||
357 | static const char * const bits[] = { | ||
358 | "12", "13", "14", "resync", | ||
359 | "cnt0", "cnt1", "18", "19", | ||
360 | "20", "21", "22", "23", | ||
361 | "irq1", "irq2", "eol", "sol", | ||
362 | }; | ||
363 | int i; | ||
364 | |||
365 | pr_cont("0x%08x [ %s", | ||
366 | risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); | ||
367 | for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) { | ||
368 | if (risc & (1 << (i + 12))) | ||
369 | pr_cont(" %s", bits[i]); | ||
370 | } | ||
371 | pr_cont(" count=%d ]\n", risc & 0xfff); | ||
372 | return incr[risc >> 28] ? incr[risc >> 28] : 1; | ||
373 | } | ||
374 | |||
375 | static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) | ||
376 | { | ||
377 | struct cx25821_i2c *bus = i2c_adap->algo_data; | ||
378 | struct cx25821_dev *dev = bus->dev; | ||
379 | return cx_read(bus->reg_stat) & 0x01; | ||
380 | } | ||
381 | |||
382 | void cx_i2c_read_print(struct cx25821_dev *dev, u32 reg, const char *reg_string) | ||
383 | { | ||
384 | int tmp = 0; | ||
385 | u32 value = 0; | ||
386 | |||
387 | value = cx25821_i2c_read(&dev->i2c_bus[0], reg, &tmp); | ||
388 | } | ||
389 | |||
390 | static void cx25821_registers_init(struct cx25821_dev *dev) | ||
391 | { | ||
392 | u32 tmp; | ||
393 | |||
394 | /* enable RUN_RISC in Pecos */ | ||
395 | cx_write(DEV_CNTRL2, 0x20); | ||
396 | |||
397 | /* Set the master PCI interrupt masks to enable video, audio, MBIF, | ||
398 | * and GPIO interrupts | ||
399 | * I2C interrupt masking is handled by the I2C objects themselves. */ | ||
400 | cx_write(PCI_INT_MSK, 0x2001FFFF); | ||
401 | |||
402 | tmp = cx_read(RDR_TLCTL0); | ||
403 | tmp &= ~FLD_CFG_RCB_CK_EN; /* Clear the RCB_CK_EN bit */ | ||
404 | cx_write(RDR_TLCTL0, tmp); | ||
405 | |||
406 | /* PLL-A setting for the Audio Master Clock */ | ||
407 | cx_write(PLL_A_INT_FRAC, 0x9807A58B); | ||
408 | |||
409 | /* PLL_A_POST = 0x1C, PLL_A_OUT_TO_PIN = 0x1 */ | ||
410 | cx_write(PLL_A_POST_STAT_BIST, 0x8000019C); | ||
411 | |||
412 | /* clear reset bit [31] */ | ||
413 | tmp = cx_read(PLL_A_INT_FRAC); | ||
414 | cx_write(PLL_A_INT_FRAC, tmp & 0x7FFFFFFF); | ||
415 | |||
416 | /* PLL-B setting for Mobilygen Host Bus Interface */ | ||
417 | cx_write(PLL_B_INT_FRAC, 0x9883A86F); | ||
418 | |||
419 | /* PLL_B_POST = 0xD, PLL_B_OUT_TO_PIN = 0x0 */ | ||
420 | cx_write(PLL_B_POST_STAT_BIST, 0x8000018D); | ||
421 | |||
422 | /* clear reset bit [31] */ | ||
423 | tmp = cx_read(PLL_B_INT_FRAC); | ||
424 | cx_write(PLL_B_INT_FRAC, tmp & 0x7FFFFFFF); | ||
425 | |||
426 | /* PLL-C setting for video upstream channel */ | ||
427 | cx_write(PLL_C_INT_FRAC, 0x96A0EA3F); | ||
428 | |||
429 | /* PLL_C_POST = 0x3, PLL_C_OUT_TO_PIN = 0x0 */ | ||
430 | cx_write(PLL_C_POST_STAT_BIST, 0x80000103); | ||
431 | |||
432 | /* clear reset bit [31] */ | ||
433 | tmp = cx_read(PLL_C_INT_FRAC); | ||
434 | cx_write(PLL_C_INT_FRAC, tmp & 0x7FFFFFFF); | ||
435 | |||
436 | /* PLL-D setting for audio upstream channel */ | ||
437 | cx_write(PLL_D_INT_FRAC, 0x98757F5B); | ||
438 | |||
439 | /* PLL_D_POST = 0x13, PLL_D_OUT_TO_PIN = 0x0 */ | ||
440 | cx_write(PLL_D_POST_STAT_BIST, 0x80000113); | ||
441 | |||
442 | /* clear reset bit [31] */ | ||
443 | tmp = cx_read(PLL_D_INT_FRAC); | ||
444 | cx_write(PLL_D_INT_FRAC, tmp & 0x7FFFFFFF); | ||
445 | |||
446 | /* This selects the PLL C clock source for the video upstream channel | ||
447 | * I and J */ | ||
448 | tmp = cx_read(VID_CH_CLK_SEL); | ||
449 | cx_write(VID_CH_CLK_SEL, (tmp & 0x00FFFFFF) | 0x24000000); | ||
450 | |||
451 | /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for | ||
452 | * channel A-C | ||
453 | * select 656/VIP DST for downstream Channel A - C */ | ||
454 | tmp = cx_read(VID_CH_MODE_SEL); | ||
455 | /* cx_write( VID_CH_MODE_SEL, tmp | 0x1B0001FF); */ | ||
456 | cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); | ||
457 | |||
458 | /* enables 656 port I and J as output */ | ||
459 | tmp = cx_read(CLK_RST); | ||
460 | /* use external ALT_PLL_REF pin as its reference clock instead */ | ||
461 | tmp |= FLD_USE_ALT_PLL_REF; | ||
462 | cx_write(CLK_RST, tmp & ~(FLD_VID_I_CLK_NOE | FLD_VID_J_CLK_NOE)); | ||
463 | |||
464 | mdelay(100); | ||
465 | } | ||
466 | |||
467 | int cx25821_sram_channel_setup(struct cx25821_dev *dev, | ||
468 | struct sram_channel *ch, | ||
469 | unsigned int bpl, u32 risc) | ||
470 | { | ||
471 | unsigned int i, lines; | ||
472 | u32 cdt; | ||
473 | |||
474 | if (ch->cmds_start == 0) { | ||
475 | cx_write(ch->ptr1_reg, 0); | ||
476 | cx_write(ch->ptr2_reg, 0); | ||
477 | cx_write(ch->cnt2_reg, 0); | ||
478 | cx_write(ch->cnt1_reg, 0); | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | bpl = (bpl + 7) & ~7; /* alignment */ | ||
483 | cdt = ch->cdt; | ||
484 | lines = ch->fifo_size / bpl; | ||
485 | |||
486 | if (lines > 4) | ||
487 | lines = 4; | ||
488 | |||
489 | BUG_ON(lines < 2); | ||
490 | |||
491 | cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
492 | cx_write(8 + 4, 8); | ||
493 | cx_write(8 + 8, 0); | ||
494 | |||
495 | /* write CDT */ | ||
496 | for (i = 0; i < lines; i++) { | ||
497 | cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); | ||
498 | cx_write(cdt + 16 * i + 4, 0); | ||
499 | cx_write(cdt + 16 * i + 8, 0); | ||
500 | cx_write(cdt + 16 * i + 12, 0); | ||
501 | } | ||
502 | |||
503 | /* init the first cdt buffer */ | ||
504 | for (i = 0; i < 128; i++) | ||
505 | cx_write(ch->fifo_start + 4 * i, i); | ||
506 | |||
507 | /* write CMDS */ | ||
508 | if (ch->jumponly) | ||
509 | cx_write(ch->cmds_start + 0, 8); | ||
510 | else | ||
511 | cx_write(ch->cmds_start + 0, risc); | ||
512 | |||
513 | cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ | ||
514 | cx_write(ch->cmds_start + 8, cdt); | ||
515 | cx_write(ch->cmds_start + 12, (lines * 16) >> 3); | ||
516 | cx_write(ch->cmds_start + 16, ch->ctrl_start); | ||
517 | |||
518 | if (ch->jumponly) | ||
519 | cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); | ||
520 | else | ||
521 | cx_write(ch->cmds_start + 20, 64 >> 2); | ||
522 | |||
523 | for (i = 24; i < 80; i += 4) | ||
524 | cx_write(ch->cmds_start + i, 0); | ||
525 | |||
526 | /* fill registers */ | ||
527 | cx_write(ch->ptr1_reg, ch->fifo_start); | ||
528 | cx_write(ch->ptr2_reg, cdt); | ||
529 | cx_write(ch->cnt2_reg, (lines * 16) >> 3); | ||
530 | cx_write(ch->cnt1_reg, (bpl >> 3) - 1); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | EXPORT_SYMBOL(cx25821_sram_channel_setup); | ||
535 | |||
536 | int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, | ||
537 | struct sram_channel *ch, | ||
538 | unsigned int bpl, u32 risc) | ||
539 | { | ||
540 | unsigned int i, lines; | ||
541 | u32 cdt; | ||
542 | |||
543 | if (ch->cmds_start == 0) { | ||
544 | cx_write(ch->ptr1_reg, 0); | ||
545 | cx_write(ch->ptr2_reg, 0); | ||
546 | cx_write(ch->cnt2_reg, 0); | ||
547 | cx_write(ch->cnt1_reg, 0); | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | bpl = (bpl + 7) & ~7; /* alignment */ | ||
552 | cdt = ch->cdt; | ||
553 | lines = ch->fifo_size / bpl; | ||
554 | |||
555 | if (lines > 3) | ||
556 | lines = 3; /* for AUDIO */ | ||
557 | |||
558 | BUG_ON(lines < 2); | ||
559 | |||
560 | cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
561 | cx_write(8 + 4, 8); | ||
562 | cx_write(8 + 8, 0); | ||
563 | |||
564 | /* write CDT */ | ||
565 | for (i = 0; i < lines; i++) { | ||
566 | cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); | ||
567 | cx_write(cdt + 16 * i + 4, 0); | ||
568 | cx_write(cdt + 16 * i + 8, 0); | ||
569 | cx_write(cdt + 16 * i + 12, 0); | ||
570 | } | ||
571 | |||
572 | /* write CMDS */ | ||
573 | if (ch->jumponly) | ||
574 | cx_write(ch->cmds_start + 0, 8); | ||
575 | else | ||
576 | cx_write(ch->cmds_start + 0, risc); | ||
577 | |||
578 | cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */ | ||
579 | cx_write(ch->cmds_start + 8, cdt); | ||
580 | cx_write(ch->cmds_start + 12, (lines * 16) >> 3); | ||
581 | cx_write(ch->cmds_start + 16, ch->ctrl_start); | ||
582 | |||
583 | /* IQ size */ | ||
584 | if (ch->jumponly) | ||
585 | cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2)); | ||
586 | else | ||
587 | cx_write(ch->cmds_start + 20, 64 >> 2); | ||
588 | |||
589 | /* zero out */ | ||
590 | for (i = 24; i < 80; i += 4) | ||
591 | cx_write(ch->cmds_start + i, 0); | ||
592 | |||
593 | /* fill registers */ | ||
594 | cx_write(ch->ptr1_reg, ch->fifo_start); | ||
595 | cx_write(ch->ptr2_reg, cdt); | ||
596 | cx_write(ch->cnt2_reg, (lines * 16) >> 3); | ||
597 | cx_write(ch->cnt1_reg, (bpl >> 3) - 1); | ||
598 | |||
599 | return 0; | ||
600 | } | ||
601 | EXPORT_SYMBOL(cx25821_sram_channel_setup_audio); | ||
602 | |||
603 | void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch) | ||
604 | { | ||
605 | static char *name[] = { | ||
606 | "init risc lo", | ||
607 | "init risc hi", | ||
608 | "cdt base", | ||
609 | "cdt size", | ||
610 | "iq base", | ||
611 | "iq size", | ||
612 | "risc pc lo", | ||
613 | "risc pc hi", | ||
614 | "iq wr ptr", | ||
615 | "iq rd ptr", | ||
616 | "cdt current", | ||
617 | "pci target lo", | ||
618 | "pci target hi", | ||
619 | "line / byte", | ||
620 | }; | ||
621 | u32 risc; | ||
622 | unsigned int i, j, n; | ||
623 | |||
624 | pr_warn("%s: %s - dma channel status dump\n", dev->name, ch->name); | ||
625 | for (i = 0; i < ARRAY_SIZE(name); i++) | ||
626 | pr_warn("cmds + 0x%2x: %-15s: 0x%08x\n", | ||
627 | i * 4, name[i], cx_read(ch->cmds_start + 4 * i)); | ||
628 | |||
629 | j = i * 4; | ||
630 | for (i = 0; i < 4;) { | ||
631 | risc = cx_read(ch->cmds_start + 4 * (i + 14)); | ||
632 | pr_warn("cmds + 0x%2x: risc%d: ", j + i * 4, i); | ||
633 | i += cx25821_risc_decode(risc); | ||
634 | } | ||
635 | |||
636 | for (i = 0; i < (64 >> 2); i += n) { | ||
637 | risc = cx_read(ch->ctrl_start + 4 * i); | ||
638 | /* No consideration for bits 63-32 */ | ||
639 | |||
640 | pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ", | ||
641 | i * 4, ch->ctrl_start + 4 * i, i); | ||
642 | n = cx25821_risc_decode(risc); | ||
643 | for (j = 1; j < n; j++) { | ||
644 | risc = cx_read(ch->ctrl_start + 4 * (i + j)); | ||
645 | pr_warn("ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n", | ||
646 | 4 * (i + j), i + j, risc, j); | ||
647 | } | ||
648 | } | ||
649 | |||
650 | pr_warn(" : fifo: 0x%08x -> 0x%x\n", | ||
651 | ch->fifo_start, ch->fifo_start + ch->fifo_size); | ||
652 | pr_warn(" : ctrl: 0x%08x -> 0x%x\n", | ||
653 | ch->ctrl_start, ch->ctrl_start + 6 * 16); | ||
654 | pr_warn(" : ptr1_reg: 0x%08x\n", | ||
655 | cx_read(ch->ptr1_reg)); | ||
656 | pr_warn(" : ptr2_reg: 0x%08x\n", | ||
657 | cx_read(ch->ptr2_reg)); | ||
658 | pr_warn(" : cnt1_reg: 0x%08x\n", | ||
659 | cx_read(ch->cnt1_reg)); | ||
660 | pr_warn(" : cnt2_reg: 0x%08x\n", | ||
661 | cx_read(ch->cnt2_reg)); | ||
662 | } | ||
663 | EXPORT_SYMBOL(cx25821_sram_channel_dump); | ||
664 | |||
665 | void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev, | ||
666 | struct sram_channel *ch) | ||
667 | { | ||
668 | static const char * const name[] = { | ||
669 | "init risc lo", | ||
670 | "init risc hi", | ||
671 | "cdt base", | ||
672 | "cdt size", | ||
673 | "iq base", | ||
674 | "iq size", | ||
675 | "risc pc lo", | ||
676 | "risc pc hi", | ||
677 | "iq wr ptr", | ||
678 | "iq rd ptr", | ||
679 | "cdt current", | ||
680 | "pci target lo", | ||
681 | "pci target hi", | ||
682 | "line / byte", | ||
683 | }; | ||
684 | |||
685 | u32 risc, value, tmp; | ||
686 | unsigned int i, j, n; | ||
687 | |||
688 | pr_info("\n%s: %s - dma Audio channel status dump\n", | ||
689 | dev->name, ch->name); | ||
690 | |||
691 | for (i = 0; i < ARRAY_SIZE(name); i++) | ||
692 | pr_info("%s: cmds + 0x%2x: %-15s: 0x%08x\n", | ||
693 | dev->name, i * 4, name[i], | ||
694 | cx_read(ch->cmds_start + 4 * i)); | ||
695 | |||
696 | j = i * 4; | ||
697 | for (i = 0; i < 4;) { | ||
698 | risc = cx_read(ch->cmds_start + 4 * (i + 14)); | ||
699 | pr_warn("cmds + 0x%2x: risc%d: ", j + i * 4, i); | ||
700 | i += cx25821_risc_decode(risc); | ||
701 | } | ||
702 | |||
703 | for (i = 0; i < (64 >> 2); i += n) { | ||
704 | risc = cx_read(ch->ctrl_start + 4 * i); | ||
705 | /* No consideration for bits 63-32 */ | ||
706 | |||
707 | pr_warn("ctrl + 0x%2x (0x%08x): iq %x: ", | ||
708 | i * 4, ch->ctrl_start + 4 * i, i); | ||
709 | n = cx25821_risc_decode(risc); | ||
710 | |||
711 | for (j = 1; j < n; j++) { | ||
712 | risc = cx_read(ch->ctrl_start + 4 * (i + j)); | ||
713 | pr_warn("ctrl + 0x%2x : iq %x: 0x%08x [ arg #%d ]\n", | ||
714 | 4 * (i + j), i + j, risc, j); | ||
715 | } | ||
716 | } | ||
717 | |||
718 | pr_warn(" : fifo: 0x%08x -> 0x%x\n", | ||
719 | ch->fifo_start, ch->fifo_start + ch->fifo_size); | ||
720 | pr_warn(" : ctrl: 0x%08x -> 0x%x\n", | ||
721 | ch->ctrl_start, ch->ctrl_start + 6 * 16); | ||
722 | pr_warn(" : ptr1_reg: 0x%08x\n", | ||
723 | cx_read(ch->ptr1_reg)); | ||
724 | pr_warn(" : ptr2_reg: 0x%08x\n", | ||
725 | cx_read(ch->ptr2_reg)); | ||
726 | pr_warn(" : cnt1_reg: 0x%08x\n", | ||
727 | cx_read(ch->cnt1_reg)); | ||
728 | pr_warn(" : cnt2_reg: 0x%08x\n", | ||
729 | cx_read(ch->cnt2_reg)); | ||
730 | |||
731 | for (i = 0; i < 4; i++) { | ||
732 | risc = cx_read(ch->cmds_start + 56 + (i * 4)); | ||
733 | pr_warn("instruction %d = 0x%x\n", i, risc); | ||
734 | } | ||
735 | |||
736 | /* read data from the first cdt buffer */ | ||
737 | risc = cx_read(AUD_A_CDT); | ||
738 | pr_warn("\nread cdt loc=0x%x\n", risc); | ||
739 | for (i = 0; i < 8; i++) { | ||
740 | n = cx_read(risc + i * 4); | ||
741 | pr_cont("0x%x ", n); | ||
742 | } | ||
743 | pr_cont("\n\n"); | ||
744 | |||
745 | value = cx_read(CLK_RST); | ||
746 | CX25821_INFO(" CLK_RST = 0x%x\n\n", value); | ||
747 | |||
748 | value = cx_read(PLL_A_POST_STAT_BIST); | ||
749 | CX25821_INFO(" PLL_A_POST_STAT_BIST = 0x%x\n\n", value); | ||
750 | value = cx_read(PLL_A_INT_FRAC); | ||
751 | CX25821_INFO(" PLL_A_INT_FRAC = 0x%x\n\n", value); | ||
752 | |||
753 | value = cx_read(PLL_B_POST_STAT_BIST); | ||
754 | CX25821_INFO(" PLL_B_POST_STAT_BIST = 0x%x\n\n", value); | ||
755 | value = cx_read(PLL_B_INT_FRAC); | ||
756 | CX25821_INFO(" PLL_B_INT_FRAC = 0x%x\n\n", value); | ||
757 | |||
758 | value = cx_read(PLL_C_POST_STAT_BIST); | ||
759 | CX25821_INFO(" PLL_C_POST_STAT_BIST = 0x%x\n\n", value); | ||
760 | value = cx_read(PLL_C_INT_FRAC); | ||
761 | CX25821_INFO(" PLL_C_INT_FRAC = 0x%x\n\n", value); | ||
762 | |||
763 | value = cx_read(PLL_D_POST_STAT_BIST); | ||
764 | CX25821_INFO(" PLL_D_POST_STAT_BIST = 0x%x\n\n", value); | ||
765 | value = cx_read(PLL_D_INT_FRAC); | ||
766 | CX25821_INFO(" PLL_D_INT_FRAC = 0x%x\n\n", value); | ||
767 | |||
768 | value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp); | ||
769 | CX25821_INFO(" AFE_AB_DIAG_CTRL (0x10900090) = 0x%x\n\n", value); | ||
770 | } | ||
771 | EXPORT_SYMBOL(cx25821_sram_channel_dump_audio); | ||
772 | |||
773 | static void cx25821_shutdown(struct cx25821_dev *dev) | ||
774 | { | ||
775 | int i; | ||
776 | |||
777 | /* disable RISC controller */ | ||
778 | cx_write(DEV_CNTRL2, 0); | ||
779 | |||
780 | /* Disable Video A/B activity */ | ||
781 | for (i = 0; i < VID_CHANNEL_NUM; i++) { | ||
782 | cx_write(dev->channels[i].sram_channels->dma_ctl, 0); | ||
783 | cx_write(dev->channels[i].sram_channels->int_msk, 0); | ||
784 | } | ||
785 | |||
786 | for (i = VID_UPSTREAM_SRAM_CHANNEL_I; | ||
787 | i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) { | ||
788 | cx_write(dev->channels[i].sram_channels->dma_ctl, 0); | ||
789 | cx_write(dev->channels[i].sram_channels->int_msk, 0); | ||
790 | } | ||
791 | |||
792 | /* Disable Audio activity */ | ||
793 | cx_write(AUD_INT_DMA_CTL, 0); | ||
794 | |||
795 | /* Disable Serial port */ | ||
796 | cx_write(UART_CTL, 0); | ||
797 | |||
798 | /* Disable Interrupts */ | ||
799 | cx_write(PCI_INT_MSK, 0); | ||
800 | cx_write(AUD_A_INT_MSK, 0); | ||
801 | } | ||
802 | |||
803 | void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select, | ||
804 | u32 format) | ||
805 | { | ||
806 | if (channel_select <= 7 && channel_select >= 0) { | ||
807 | cx_write(dev->channels[channel_select]. | ||
808 | sram_channels->pix_frmt, format); | ||
809 | dev->channels[channel_select].pixel_formats = format; | ||
810 | } | ||
811 | } | ||
812 | |||
813 | static void cx25821_set_vip_mode(struct cx25821_dev *dev, | ||
814 | struct sram_channel *ch) | ||
815 | { | ||
816 | cx_write(ch->pix_frmt, PIXEL_FRMT_422); | ||
817 | cx_write(ch->vip_ctl, PIXEL_ENGINE_VIP1); | ||
818 | } | ||
819 | |||
820 | static void cx25821_initialize(struct cx25821_dev *dev) | ||
821 | { | ||
822 | int i; | ||
823 | |||
824 | dprintk(1, "%s()\n", __func__); | ||
825 | |||
826 | cx25821_shutdown(dev); | ||
827 | cx_write(PCI_INT_STAT, 0xffffffff); | ||
828 | |||
829 | for (i = 0; i < VID_CHANNEL_NUM; i++) | ||
830 | cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff); | ||
831 | |||
832 | cx_write(AUD_A_INT_STAT, 0xffffffff); | ||
833 | cx_write(AUD_B_INT_STAT, 0xffffffff); | ||
834 | cx_write(AUD_C_INT_STAT, 0xffffffff); | ||
835 | cx_write(AUD_D_INT_STAT, 0xffffffff); | ||
836 | cx_write(AUD_E_INT_STAT, 0xffffffff); | ||
837 | |||
838 | cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); | ||
839 | cx_write(PAD_CTRL, 0x12); /* for I2C */ | ||
840 | cx25821_registers_init(dev); /* init Pecos registers */ | ||
841 | mdelay(100); | ||
842 | |||
843 | for (i = 0; i < VID_CHANNEL_NUM; i++) { | ||
844 | cx25821_set_vip_mode(dev, dev->channels[i].sram_channels); | ||
845 | cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels, | ||
846 | 1440, 0); | ||
847 | dev->channels[i].pixel_formats = PIXEL_FRMT_422; | ||
848 | dev->channels[i].use_cif_resolution = FALSE; | ||
849 | } | ||
850 | |||
851 | /* Probably only affect Downstream */ | ||
852 | for (i = VID_UPSTREAM_SRAM_CHANNEL_I; | ||
853 | i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) { | ||
854 | cx25821_set_vip_mode(dev, dev->channels[i].sram_channels); | ||
855 | } | ||
856 | |||
857 | cx25821_sram_channel_setup_audio(dev, | ||
858 | dev->channels[SRAM_CH08].sram_channels, | ||
859 | 128, 0); | ||
860 | |||
861 | cx25821_gpio_init(dev); | ||
862 | } | ||
863 | |||
864 | static int cx25821_get_resources(struct cx25821_dev *dev) | ||
865 | { | ||
866 | if (request_mem_region | ||
867 | (pci_resource_start(dev->pci, 0), pci_resource_len(dev->pci, 0), | ||
868 | dev->name)) | ||
869 | return 0; | ||
870 | |||
871 | pr_err("%s: can't get MMIO memory @ 0x%llx\n", | ||
872 | dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); | ||
873 | |||
874 | return -EBUSY; | ||
875 | } | ||
876 | |||
877 | static void cx25821_dev_checkrevision(struct cx25821_dev *dev) | ||
878 | { | ||
879 | dev->hwrevision = cx_read(RDR_CFG2) & 0xff; | ||
880 | |||
881 | pr_info("%s(): Hardware revision = 0x%02x\n", | ||
882 | __func__, dev->hwrevision); | ||
883 | } | ||
884 | |||
885 | static void cx25821_iounmap(struct cx25821_dev *dev) | ||
886 | { | ||
887 | if (dev == NULL) | ||
888 | return; | ||
889 | |||
890 | /* Releasing IO memory */ | ||
891 | if (dev->lmmio != NULL) { | ||
892 | CX25821_INFO("Releasing lmmio.\n"); | ||
893 | iounmap(dev->lmmio); | ||
894 | dev->lmmio = NULL; | ||
895 | } | ||
896 | } | ||
897 | |||
898 | static int cx25821_dev_setup(struct cx25821_dev *dev) | ||
899 | { | ||
900 | int io_size = 0, i; | ||
901 | |||
902 | pr_info("\n***********************************\n"); | ||
903 | pr_info("cx25821 set up\n"); | ||
904 | pr_info("***********************************\n\n"); | ||
905 | |||
906 | mutex_init(&dev->lock); | ||
907 | |||
908 | atomic_inc(&dev->refcount); | ||
909 | |||
910 | dev->nr = ++cx25821_devcount; | ||
911 | sprintf(dev->name, "cx25821[%d]", dev->nr); | ||
912 | |||
913 | mutex_lock(&cx25821_devlist_mutex); | ||
914 | list_add_tail(&dev->devlist, &cx25821_devlist); | ||
915 | mutex_unlock(&cx25821_devlist_mutex); | ||
916 | |||
917 | strcpy(cx25821_boards[UNKNOWN_BOARD].name, "unknown"); | ||
918 | strcpy(cx25821_boards[CX25821_BOARD].name, "cx25821"); | ||
919 | |||
920 | if (dev->pci->device != 0x8210) { | ||
921 | pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", | ||
922 | __func__, dev->pci->device); | ||
923 | return -1; | ||
924 | } else { | ||
925 | pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device); | ||
926 | } | ||
927 | |||
928 | /* Apply a sensible clock frequency for the PCIe bridge */ | ||
929 | dev->clk_freq = 28000000; | ||
930 | for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) | ||
931 | dev->channels[i].sram_channels = &cx25821_sram_channels[i]; | ||
932 | |||
933 | if (dev->nr > 1) | ||
934 | CX25821_INFO("dev->nr > 1!"); | ||
935 | |||
936 | /* board config */ | ||
937 | dev->board = 1; /* card[dev->nr]; */ | ||
938 | dev->_max_num_decoders = MAX_DECODERS; | ||
939 | |||
940 | dev->pci_bus = dev->pci->bus->number; | ||
941 | dev->pci_slot = PCI_SLOT(dev->pci->devfn); | ||
942 | dev->pci_irqmask = 0x001f00; | ||
943 | |||
944 | /* External Master 1 Bus */ | ||
945 | dev->i2c_bus[0].nr = 0; | ||
946 | dev->i2c_bus[0].dev = dev; | ||
947 | dev->i2c_bus[0].reg_stat = I2C1_STAT; | ||
948 | dev->i2c_bus[0].reg_ctrl = I2C1_CTRL; | ||
949 | dev->i2c_bus[0].reg_addr = I2C1_ADDR; | ||
950 | dev->i2c_bus[0].reg_rdata = I2C1_RDATA; | ||
951 | dev->i2c_bus[0].reg_wdata = I2C1_WDATA; | ||
952 | dev->i2c_bus[0].i2c_period = (0x07 << 24); /* 1.95MHz */ | ||
953 | |||
954 | if (cx25821_get_resources(dev) < 0) { | ||
955 | pr_err("%s: No more PCIe resources for subsystem: %04x:%04x\n", | ||
956 | dev->name, dev->pci->subsystem_vendor, | ||
957 | dev->pci->subsystem_device); | ||
958 | |||
959 | cx25821_devcount--; | ||
960 | return -EBUSY; | ||
961 | } | ||
962 | |||
963 | /* PCIe stuff */ | ||
964 | dev->base_io_addr = pci_resource_start(dev->pci, 0); | ||
965 | io_size = pci_resource_len(dev->pci, 0); | ||
966 | |||
967 | if (!dev->base_io_addr) { | ||
968 | CX25821_ERR("No PCI Memory resources, exiting!\n"); | ||
969 | return -ENODEV; | ||
970 | } | ||
971 | |||
972 | dev->lmmio = ioremap(dev->base_io_addr, pci_resource_len(dev->pci, 0)); | ||
973 | |||
974 | if (!dev->lmmio) { | ||
975 | CX25821_ERR | ||
976 | ("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n"); | ||
977 | cx25821_iounmap(dev); | ||
978 | return -ENOMEM; | ||
979 | } | ||
980 | |||
981 | dev->bmmio = (u8 __iomem *) dev->lmmio; | ||
982 | |||
983 | pr_info("%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", | ||
984 | dev->name, dev->pci->subsystem_vendor, | ||
985 | dev->pci->subsystem_device, cx25821_boards[dev->board].name, | ||
986 | dev->board, card[dev->nr] == dev->board ? | ||
987 | "insmod option" : "autodetected"); | ||
988 | |||
989 | /* init hardware */ | ||
990 | cx25821_initialize(dev); | ||
991 | |||
992 | cx25821_i2c_register(&dev->i2c_bus[0]); | ||
993 | /* cx25821_i2c_register(&dev->i2c_bus[1]); | ||
994 | * cx25821_i2c_register(&dev->i2c_bus[2]); */ | ||
995 | |||
996 | CX25821_INFO("i2c register! bus->i2c_rc = %d\n", | ||
997 | dev->i2c_bus[0].i2c_rc); | ||
998 | |||
999 | cx25821_card_setup(dev); | ||
1000 | |||
1001 | if (medusa_video_init(dev) < 0) | ||
1002 | CX25821_ERR("%s(): Failed to initialize medusa!\n", __func__); | ||
1003 | |||
1004 | cx25821_video_register(dev); | ||
1005 | |||
1006 | /* register IOCTL device */ | ||
1007 | dev->ioctl_dev = | ||
1008 | cx25821_vdev_init(dev, dev->pci, &cx25821_videoioctl_template, | ||
1009 | "video"); | ||
1010 | |||
1011 | if (video_register_device | ||
1012 | (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) { | ||
1013 | cx25821_videoioctl_unregister(dev); | ||
1014 | pr_err("%s(): Failed to register video adapter for IOCTL, so unregistering videoioctl device\n", | ||
1015 | __func__); | ||
1016 | } | ||
1017 | |||
1018 | cx25821_dev_checkrevision(dev); | ||
1019 | CX25821_INFO("setup done!\n"); | ||
1020 | |||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
1024 | void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev, | ||
1025 | struct upstream_user_struct *up_data) | ||
1026 | { | ||
1027 | dev->_isNTSC = !strcmp(dev->vid_stdname, "NTSC") ? 1 : 0; | ||
1028 | |||
1029 | dev->tvnorm = !dev->_isNTSC ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M; | ||
1030 | medusa_set_videostandard(dev); | ||
1031 | |||
1032 | cx25821_vidupstream_init_ch1(dev, dev->channel_select, | ||
1033 | dev->pixel_format); | ||
1034 | } | ||
1035 | |||
1036 | void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev, | ||
1037 | struct upstream_user_struct *up_data) | ||
1038 | { | ||
1039 | dev->_isNTSC_ch2 = !strcmp(dev->vid_stdname_ch2, "NTSC") ? 1 : 0; | ||
1040 | |||
1041 | dev->tvnorm = !dev->_isNTSC_ch2 ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M; | ||
1042 | medusa_set_videostandard(dev); | ||
1043 | |||
1044 | cx25821_vidupstream_init_ch2(dev, dev->channel_select_ch2, | ||
1045 | dev->pixel_format_ch2); | ||
1046 | } | ||
1047 | |||
1048 | void cx25821_start_upstream_audio(struct cx25821_dev *dev, | ||
1049 | struct upstream_user_struct *up_data) | ||
1050 | { | ||
1051 | cx25821_audio_upstream_init(dev, AUDIO_UPSTREAM_SRAM_CHANNEL_B); | ||
1052 | } | ||
1053 | |||
1054 | void cx25821_dev_unregister(struct cx25821_dev *dev) | ||
1055 | { | ||
1056 | int i; | ||
1057 | |||
1058 | if (!dev->base_io_addr) | ||
1059 | return; | ||
1060 | |||
1061 | cx25821_free_mem_upstream_ch1(dev); | ||
1062 | cx25821_free_mem_upstream_ch2(dev); | ||
1063 | cx25821_free_mem_upstream_audio(dev); | ||
1064 | |||
1065 | release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0)); | ||
1066 | |||
1067 | if (!atomic_dec_and_test(&dev->refcount)) | ||
1068 | return; | ||
1069 | |||
1070 | for (i = 0; i < VID_CHANNEL_NUM; i++) | ||
1071 | cx25821_video_unregister(dev, i); | ||
1072 | |||
1073 | for (i = VID_UPSTREAM_SRAM_CHANNEL_I; | ||
1074 | i <= AUDIO_UPSTREAM_SRAM_CHANNEL_B; i++) { | ||
1075 | cx25821_video_unregister(dev, i); | ||
1076 | } | ||
1077 | |||
1078 | cx25821_videoioctl_unregister(dev); | ||
1079 | |||
1080 | cx25821_i2c_unregister(&dev->i2c_bus[0]); | ||
1081 | cx25821_iounmap(dev); | ||
1082 | } | ||
1083 | EXPORT_SYMBOL(cx25821_dev_unregister); | ||
1084 | |||
1085 | static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, | ||
1086 | unsigned int offset, u32 sync_line, | ||
1087 | unsigned int bpl, unsigned int padding, | ||
1088 | unsigned int lines) | ||
1089 | { | ||
1090 | struct scatterlist *sg; | ||
1091 | unsigned int line, todo; | ||
1092 | |||
1093 | /* sync instruction */ | ||
1094 | if (sync_line != NO_SYNC_LINE) | ||
1095 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
1096 | |||
1097 | /* scan lines */ | ||
1098 | sg = sglist; | ||
1099 | for (line = 0; line < lines; line++) { | ||
1100 | while (offset && offset >= sg_dma_len(sg)) { | ||
1101 | offset -= sg_dma_len(sg); | ||
1102 | sg++; | ||
1103 | } | ||
1104 | if (bpl <= sg_dma_len(sg) - offset) { | ||
1105 | /* fits into current chunk */ | ||
1106 | *(rp++) = | ||
1107 | cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL | bpl); | ||
1108 | *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); | ||
1109 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1110 | offset += bpl; | ||
1111 | } else { | ||
1112 | /* scanline needs to be split */ | ||
1113 | todo = bpl; | ||
1114 | *(rp++) = | ||
1115 | cpu_to_le32(RISC_WRITE | RISC_SOL | | ||
1116 | (sg_dma_len(sg) - offset)); | ||
1117 | *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); | ||
1118 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1119 | todo -= (sg_dma_len(sg) - offset); | ||
1120 | offset = 0; | ||
1121 | sg++; | ||
1122 | while (todo > sg_dma_len(sg)) { | ||
1123 | *(rp++) = | ||
1124 | cpu_to_le32(RISC_WRITE | sg_dma_len(sg)); | ||
1125 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); | ||
1126 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1127 | todo -= sg_dma_len(sg); | ||
1128 | sg++; | ||
1129 | } | ||
1130 | *(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo); | ||
1131 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); | ||
1132 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1133 | offset += todo; | ||
1134 | } | ||
1135 | |||
1136 | offset += padding; | ||
1137 | } | ||
1138 | |||
1139 | return rp; | ||
1140 | } | ||
1141 | |||
1142 | int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
1143 | struct scatterlist *sglist, unsigned int top_offset, | ||
1144 | unsigned int bottom_offset, unsigned int bpl, | ||
1145 | unsigned int padding, unsigned int lines) | ||
1146 | { | ||
1147 | u32 instructions; | ||
1148 | u32 fields; | ||
1149 | __le32 *rp; | ||
1150 | int rc; | ||
1151 | |||
1152 | fields = 0; | ||
1153 | if (UNSET != top_offset) | ||
1154 | fields++; | ||
1155 | if (UNSET != bottom_offset) | ||
1156 | fields++; | ||
1157 | |||
1158 | /* estimate risc mem: worst case is one write per page border + | ||
1159 | one write per scan line + syncs + jump (all 2 dwords). Padding | ||
1160 | can cause next bpl to start close to a page border. First DMA | ||
1161 | region may be smaller than PAGE_SIZE */ | ||
1162 | /* write and jump need and extra dword */ | ||
1163 | instructions = | ||
1164 | fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); | ||
1165 | instructions += 2; | ||
1166 | rc = btcx_riscmem_alloc(pci, risc, instructions * 12); | ||
1167 | |||
1168 | if (rc < 0) | ||
1169 | return rc; | ||
1170 | |||
1171 | /* write risc instructions */ | ||
1172 | rp = risc->cpu; | ||
1173 | |||
1174 | if (UNSET != top_offset) { | ||
1175 | rp = cx25821_risc_field(rp, sglist, top_offset, 0, bpl, padding, | ||
1176 | lines); | ||
1177 | } | ||
1178 | |||
1179 | if (UNSET != bottom_offset) { | ||
1180 | rp = cx25821_risc_field(rp, sglist, bottom_offset, 0x200, bpl, | ||
1181 | padding, lines); | ||
1182 | } | ||
1183 | |||
1184 | /* save pointer to jmp instruction address */ | ||
1185 | risc->jmp = rp; | ||
1186 | BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); | ||
1187 | |||
1188 | return 0; | ||
1189 | } | ||
1190 | |||
1191 | static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, | ||
1192 | unsigned int offset, u32 sync_line, | ||
1193 | unsigned int bpl, unsigned int padding, | ||
1194 | unsigned int lines, unsigned int lpi) | ||
1195 | { | ||
1196 | struct scatterlist *sg; | ||
1197 | unsigned int line, todo, sol; | ||
1198 | |||
1199 | /* sync instruction */ | ||
1200 | if (sync_line != NO_SYNC_LINE) | ||
1201 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
1202 | |||
1203 | /* scan lines */ | ||
1204 | sg = sglist; | ||
1205 | for (line = 0; line < lines; line++) { | ||
1206 | while (offset && offset >= sg_dma_len(sg)) { | ||
1207 | offset -= sg_dma_len(sg); | ||
1208 | sg++; | ||
1209 | } | ||
1210 | |||
1211 | if (lpi && line > 0 && !(line % lpi)) | ||
1212 | sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; | ||
1213 | else | ||
1214 | sol = RISC_SOL; | ||
1215 | |||
1216 | if (bpl <= sg_dma_len(sg) - offset) { | ||
1217 | /* fits into current chunk */ | ||
1218 | *(rp++) = | ||
1219 | cpu_to_le32(RISC_WRITE | sol | RISC_EOL | bpl); | ||
1220 | *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); | ||
1221 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1222 | offset += bpl; | ||
1223 | } else { | ||
1224 | /* scanline needs to be split */ | ||
1225 | todo = bpl; | ||
1226 | *(rp++) = cpu_to_le32(RISC_WRITE | sol | | ||
1227 | (sg_dma_len(sg) - offset)); | ||
1228 | *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); | ||
1229 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1230 | todo -= (sg_dma_len(sg) - offset); | ||
1231 | offset = 0; | ||
1232 | sg++; | ||
1233 | while (todo > sg_dma_len(sg)) { | ||
1234 | *(rp++) = cpu_to_le32(RISC_WRITE | | ||
1235 | sg_dma_len(sg)); | ||
1236 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); | ||
1237 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1238 | todo -= sg_dma_len(sg); | ||
1239 | sg++; | ||
1240 | } | ||
1241 | *(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo); | ||
1242 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); | ||
1243 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1244 | offset += todo; | ||
1245 | } | ||
1246 | offset += padding; | ||
1247 | } | ||
1248 | |||
1249 | return rp; | ||
1250 | } | ||
1251 | |||
1252 | int cx25821_risc_databuffer_audio(struct pci_dev *pci, | ||
1253 | struct btcx_riscmem *risc, | ||
1254 | struct scatterlist *sglist, | ||
1255 | unsigned int bpl, | ||
1256 | unsigned int lines, unsigned int lpi) | ||
1257 | { | ||
1258 | u32 instructions; | ||
1259 | __le32 *rp; | ||
1260 | int rc; | ||
1261 | |||
1262 | /* estimate risc mem: worst case is one write per page border + | ||
1263 | one write per scan line + syncs + jump (all 2 dwords). Here | ||
1264 | there is no padding and no sync. First DMA region may be smaller | ||
1265 | than PAGE_SIZE */ | ||
1266 | /* Jump and write need an extra dword */ | ||
1267 | instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; | ||
1268 | instructions += 1; | ||
1269 | |||
1270 | rc = btcx_riscmem_alloc(pci, risc, instructions * 12); | ||
1271 | if (rc < 0) | ||
1272 | return rc; | ||
1273 | |||
1274 | /* write risc instructions */ | ||
1275 | rp = risc->cpu; | ||
1276 | rp = cx25821_risc_field_audio(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, | ||
1277 | lines, lpi); | ||
1278 | |||
1279 | /* save pointer to jmp instruction address */ | ||
1280 | risc->jmp = rp; | ||
1281 | BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); | ||
1282 | return 0; | ||
1283 | } | ||
1284 | EXPORT_SYMBOL(cx25821_risc_databuffer_audio); | ||
1285 | |||
1286 | int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
1287 | u32 reg, u32 mask, u32 value) | ||
1288 | { | ||
1289 | __le32 *rp; | ||
1290 | int rc; | ||
1291 | |||
1292 | rc = btcx_riscmem_alloc(pci, risc, 4 * 16); | ||
1293 | |||
1294 | if (rc < 0) | ||
1295 | return rc; | ||
1296 | |||
1297 | /* write risc instructions */ | ||
1298 | rp = risc->cpu; | ||
1299 | |||
1300 | *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ1); | ||
1301 | *(rp++) = cpu_to_le32(reg); | ||
1302 | *(rp++) = cpu_to_le32(value); | ||
1303 | *(rp++) = cpu_to_le32(mask); | ||
1304 | *(rp++) = cpu_to_le32(RISC_JUMP); | ||
1305 | *(rp++) = cpu_to_le32(risc->dma); | ||
1306 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
1307 | return 0; | ||
1308 | } | ||
1309 | |||
1310 | void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf) | ||
1311 | { | ||
1312 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
1313 | |||
1314 | BUG_ON(in_interrupt()); | ||
1315 | videobuf_waiton(q, &buf->vb, 0, 0); | ||
1316 | videobuf_dma_unmap(q->dev, dma); | ||
1317 | videobuf_dma_free(dma); | ||
1318 | btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); | ||
1319 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
1320 | } | ||
1321 | |||
1322 | static irqreturn_t cx25821_irq(int irq, void *dev_id) | ||
1323 | { | ||
1324 | struct cx25821_dev *dev = dev_id; | ||
1325 | u32 pci_status, pci_mask; | ||
1326 | u32 vid_status; | ||
1327 | int i, handled = 0; | ||
1328 | u32 mask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; | ||
1329 | |||
1330 | pci_status = cx_read(PCI_INT_STAT); | ||
1331 | pci_mask = cx_read(PCI_INT_MSK); | ||
1332 | |||
1333 | if (pci_status == 0) | ||
1334 | goto out; | ||
1335 | |||
1336 | for (i = 0; i < VID_CHANNEL_NUM; i++) { | ||
1337 | if (pci_status & mask[i]) { | ||
1338 | vid_status = cx_read(dev->channels[i]. | ||
1339 | sram_channels->int_stat); | ||
1340 | |||
1341 | if (vid_status) | ||
1342 | handled += | ||
1343 | cx25821_video_irq(dev, i, vid_status); | ||
1344 | |||
1345 | cx_write(PCI_INT_STAT, mask[i]); | ||
1346 | } | ||
1347 | } | ||
1348 | |||
1349 | out: | ||
1350 | return IRQ_RETVAL(handled); | ||
1351 | } | ||
1352 | |||
1353 | void cx25821_print_irqbits(char *name, char *tag, char **strings, | ||
1354 | int len, u32 bits, u32 mask) | ||
1355 | { | ||
1356 | unsigned int i; | ||
1357 | |||
1358 | printk(KERN_DEBUG pr_fmt("%s: %s [0x%x]"), name, tag, bits); | ||
1359 | |||
1360 | for (i = 0; i < len; i++) { | ||
1361 | if (!(bits & (1 << i))) | ||
1362 | continue; | ||
1363 | if (strings[i]) | ||
1364 | pr_cont(" %s", strings[i]); | ||
1365 | else | ||
1366 | pr_cont(" %d", i); | ||
1367 | if (!(mask & (1 << i))) | ||
1368 | continue; | ||
1369 | pr_cont("*"); | ||
1370 | } | ||
1371 | pr_cont("\n"); | ||
1372 | } | ||
1373 | EXPORT_SYMBOL(cx25821_print_irqbits); | ||
1374 | |||
1375 | struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci) | ||
1376 | { | ||
1377 | struct cx25821_dev *dev = pci_get_drvdata(pci); | ||
1378 | return dev; | ||
1379 | } | ||
1380 | EXPORT_SYMBOL(cx25821_dev_get); | ||
1381 | |||
1382 | static int __devinit cx25821_initdev(struct pci_dev *pci_dev, | ||
1383 | const struct pci_device_id *pci_id) | ||
1384 | { | ||
1385 | struct cx25821_dev *dev; | ||
1386 | int err = 0; | ||
1387 | |||
1388 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
1389 | if (NULL == dev) | ||
1390 | return -ENOMEM; | ||
1391 | |||
1392 | err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); | ||
1393 | if (err < 0) | ||
1394 | goto fail_free; | ||
1395 | |||
1396 | /* pci init */ | ||
1397 | dev->pci = pci_dev; | ||
1398 | if (pci_enable_device(pci_dev)) { | ||
1399 | err = -EIO; | ||
1400 | |||
1401 | pr_info("pci enable failed!\n"); | ||
1402 | |||
1403 | goto fail_unregister_device; | ||
1404 | } | ||
1405 | |||
1406 | pr_info("Athena pci enable !\n"); | ||
1407 | |||
1408 | err = cx25821_dev_setup(dev); | ||
1409 | if (err) { | ||
1410 | if (err == -EBUSY) | ||
1411 | goto fail_unregister_device; | ||
1412 | else | ||
1413 | goto fail_unregister_pci; | ||
1414 | } | ||
1415 | |||
1416 | /* print pci info */ | ||
1417 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); | ||
1418 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | ||
1419 | pr_info("%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", | ||
1420 | dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, | ||
1421 | dev->pci_lat, (unsigned long long)dev->base_io_addr); | ||
1422 | |||
1423 | pci_set_master(pci_dev); | ||
1424 | if (!pci_dma_supported(pci_dev, 0xffffffff)) { | ||
1425 | pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); | ||
1426 | err = -EIO; | ||
1427 | goto fail_irq; | ||
1428 | } | ||
1429 | |||
1430 | err = | ||
1431 | request_irq(pci_dev->irq, cx25821_irq, IRQF_SHARED, | ||
1432 | dev->name, dev); | ||
1433 | |||
1434 | if (err < 0) { | ||
1435 | pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq); | ||
1436 | goto fail_irq; | ||
1437 | } | ||
1438 | |||
1439 | return 0; | ||
1440 | |||
1441 | fail_irq: | ||
1442 | pr_info("cx25821_initdev() can't get IRQ !\n"); | ||
1443 | cx25821_dev_unregister(dev); | ||
1444 | |||
1445 | fail_unregister_pci: | ||
1446 | pci_disable_device(pci_dev); | ||
1447 | fail_unregister_device: | ||
1448 | v4l2_device_unregister(&dev->v4l2_dev); | ||
1449 | |||
1450 | fail_free: | ||
1451 | kfree(dev); | ||
1452 | return err; | ||
1453 | } | ||
1454 | |||
1455 | static void __devexit cx25821_finidev(struct pci_dev *pci_dev) | ||
1456 | { | ||
1457 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | ||
1458 | struct cx25821_dev *dev = get_cx25821(v4l2_dev); | ||
1459 | |||
1460 | cx25821_shutdown(dev); | ||
1461 | pci_disable_device(pci_dev); | ||
1462 | |||
1463 | /* unregister stuff */ | ||
1464 | if (pci_dev->irq) | ||
1465 | free_irq(pci_dev->irq, dev); | ||
1466 | |||
1467 | mutex_lock(&cx25821_devlist_mutex); | ||
1468 | list_del(&dev->devlist); | ||
1469 | mutex_unlock(&cx25821_devlist_mutex); | ||
1470 | |||
1471 | cx25821_dev_unregister(dev); | ||
1472 | v4l2_device_unregister(v4l2_dev); | ||
1473 | kfree(dev); | ||
1474 | } | ||
1475 | |||
1476 | static DEFINE_PCI_DEVICE_TABLE(cx25821_pci_tbl) = { | ||
1477 | { | ||
1478 | /* CX25821 Athena */ | ||
1479 | .vendor = 0x14f1, | ||
1480 | .device = 0x8210, | ||
1481 | .subvendor = 0x14f1, | ||
1482 | .subdevice = 0x0920, | ||
1483 | }, | ||
1484 | { | ||
1485 | /* --- end of list --- */ | ||
1486 | } | ||
1487 | }; | ||
1488 | |||
1489 | MODULE_DEVICE_TABLE(pci, cx25821_pci_tbl); | ||
1490 | |||
1491 | static struct pci_driver cx25821_pci_driver = { | ||
1492 | .name = "cx25821", | ||
1493 | .id_table = cx25821_pci_tbl, | ||
1494 | .probe = cx25821_initdev, | ||
1495 | .remove = __devexit_p(cx25821_finidev), | ||
1496 | /* TODO */ | ||
1497 | .suspend = NULL, | ||
1498 | .resume = NULL, | ||
1499 | }; | ||
1500 | |||
1501 | static int __init cx25821_init(void) | ||
1502 | { | ||
1503 | pr_info("driver version %d.%d.%d loaded\n", | ||
1504 | (CX25821_VERSION_CODE >> 16) & 0xff, | ||
1505 | (CX25821_VERSION_CODE >> 8) & 0xff, | ||
1506 | CX25821_VERSION_CODE & 0xff); | ||
1507 | return pci_register_driver(&cx25821_pci_driver); | ||
1508 | } | ||
1509 | |||
1510 | static void __exit cx25821_fini(void) | ||
1511 | { | ||
1512 | pci_unregister_driver(&cx25821_pci_driver); | ||
1513 | } | ||
1514 | |||
1515 | |||
1516 | module_init(cx25821_init); | ||
1517 | module_exit(cx25821_fini); | ||
diff --git a/drivers/media/video/cx25821/cx25821-gpio.c b/drivers/media/video/cx25821/cx25821-gpio.c new file mode 100644 index 000000000000..29e43b03c85e --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-gpio.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include "cx25821.h" | ||
24 | |||
25 | /********************* GPIO stuffs *********************/ | ||
26 | void cx25821_set_gpiopin_direction(struct cx25821_dev *dev, | ||
27 | int pin_number, int pin_logic_value) | ||
28 | { | ||
29 | int bit = pin_number; | ||
30 | u32 gpio_oe_reg = GPIO_LO_OE; | ||
31 | u32 gpio_register = 0; | ||
32 | u32 value = 0; | ||
33 | |||
34 | /* Check for valid pinNumber */ | ||
35 | if (pin_number >= 47) | ||
36 | return; | ||
37 | |||
38 | if (pin_number > 31) { | ||
39 | bit = pin_number - 31; | ||
40 | gpio_oe_reg = GPIO_HI_OE; | ||
41 | } | ||
42 | /* Here we will make sure that the GPIOs 0 and 1 are output. keep the | ||
43 | * rest as is */ | ||
44 | gpio_register = cx_read(gpio_oe_reg); | ||
45 | |||
46 | if (pin_logic_value == 1) | ||
47 | value = gpio_register | Set_GPIO_Bit(bit); | ||
48 | else | ||
49 | value = gpio_register & Clear_GPIO_Bit(bit); | ||
50 | |||
51 | cx_write(gpio_oe_reg, value); | ||
52 | } | ||
53 | EXPORT_SYMBOL(cx25821_set_gpiopin_direction); | ||
54 | |||
55 | static void cx25821_set_gpiopin_logicvalue(struct cx25821_dev *dev, | ||
56 | int pin_number, int pin_logic_value) | ||
57 | { | ||
58 | int bit = pin_number; | ||
59 | u32 gpio_reg = GPIO_LO; | ||
60 | u32 value = 0; | ||
61 | |||
62 | /* Check for valid pinNumber */ | ||
63 | if (pin_number >= 47) | ||
64 | return; | ||
65 | |||
66 | /* change to output direction */ | ||
67 | cx25821_set_gpiopin_direction(dev, pin_number, 0); | ||
68 | |||
69 | if (pin_number > 31) { | ||
70 | bit = pin_number - 31; | ||
71 | gpio_reg = GPIO_HI; | ||
72 | } | ||
73 | |||
74 | value = cx_read(gpio_reg); | ||
75 | |||
76 | if (pin_logic_value == 0) | ||
77 | value &= Clear_GPIO_Bit(bit); | ||
78 | else | ||
79 | value |= Set_GPIO_Bit(bit); | ||
80 | |||
81 | cx_write(gpio_reg, value); | ||
82 | } | ||
83 | |||
84 | void cx25821_gpio_init(struct cx25821_dev *dev) | ||
85 | { | ||
86 | if (dev == NULL) | ||
87 | return; | ||
88 | |||
89 | switch (dev->board) { | ||
90 | case CX25821_BOARD_CONEXANT_ATHENA10: | ||
91 | default: | ||
92 | /* set GPIO 5 to select the path for Medusa/Athena */ | ||
93 | cx25821_set_gpiopin_logicvalue(dev, 5, 1); | ||
94 | mdelay(20); | ||
95 | break; | ||
96 | } | ||
97 | |||
98 | } | ||
diff --git a/drivers/media/video/cx25821/cx25821-i2c.c b/drivers/media/video/cx25821/cx25821-i2c.c new file mode 100644 index 000000000000..4d3d0ce40785 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-i2c.c | |||
@@ -0,0 +1,425 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * | ||
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 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
25 | |||
26 | #include "cx25821.h" | ||
27 | #include <linux/i2c.h> | ||
28 | |||
29 | static unsigned int i2c_debug; | ||
30 | module_param(i2c_debug, int, 0644); | ||
31 | MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | ||
32 | |||
33 | static unsigned int i2c_scan; | ||
34 | module_param(i2c_scan, int, 0444); | ||
35 | MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); | ||
36 | |||
37 | #define dprintk(level, fmt, arg...) \ | ||
38 | do { \ | ||
39 | if (i2c_debug >= level) \ | ||
40 | printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg); \ | ||
41 | } while (0) | ||
42 | |||
43 | #define I2C_WAIT_DELAY 32 | ||
44 | #define I2C_WAIT_RETRY 64 | ||
45 | |||
46 | #define I2C_EXTEND (1 << 3) | ||
47 | #define I2C_NOSTOP (1 << 4) | ||
48 | |||
49 | static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) | ||
50 | { | ||
51 | struct cx25821_i2c *bus = i2c_adap->algo_data; | ||
52 | struct cx25821_dev *dev = bus->dev; | ||
53 | return cx_read(bus->reg_stat) & 0x01; | ||
54 | } | ||
55 | |||
56 | static inline int i2c_is_busy(struct i2c_adapter *i2c_adap) | ||
57 | { | ||
58 | struct cx25821_i2c *bus = i2c_adap->algo_data; | ||
59 | struct cx25821_dev *dev = bus->dev; | ||
60 | return cx_read(bus->reg_stat) & 0x02 ? 1 : 0; | ||
61 | } | ||
62 | |||
63 | static int i2c_wait_done(struct i2c_adapter *i2c_adap) | ||
64 | { | ||
65 | int count; | ||
66 | |||
67 | for (count = 0; count < I2C_WAIT_RETRY; count++) { | ||
68 | if (!i2c_is_busy(i2c_adap)) | ||
69 | break; | ||
70 | udelay(I2C_WAIT_DELAY); | ||
71 | } | ||
72 | |||
73 | if (I2C_WAIT_RETRY == count) | ||
74 | return 0; | ||
75 | |||
76 | return 1; | ||
77 | } | ||
78 | |||
79 | static int i2c_sendbytes(struct i2c_adapter *i2c_adap, | ||
80 | const struct i2c_msg *msg, int joined_rlen) | ||
81 | { | ||
82 | struct cx25821_i2c *bus = i2c_adap->algo_data; | ||
83 | struct cx25821_dev *dev = bus->dev; | ||
84 | u32 wdata, addr, ctrl; | ||
85 | int retval, cnt; | ||
86 | |||
87 | if (joined_rlen) | ||
88 | dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__, | ||
89 | msg->len, joined_rlen); | ||
90 | else | ||
91 | dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len); | ||
92 | |||
93 | /* Deal with i2c probe functions with zero payload */ | ||
94 | if (msg->len == 0) { | ||
95 | cx_write(bus->reg_addr, msg->addr << 25); | ||
96 | cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2)); | ||
97 | |||
98 | if (!i2c_wait_done(i2c_adap)) | ||
99 | return -EIO; | ||
100 | |||
101 | if (!i2c_slave_did_ack(i2c_adap)) | ||
102 | return -EIO; | ||
103 | |||
104 | dprintk(1, "%s(): returns 0\n", __func__); | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | /* dev, reg + first byte */ | ||
109 | addr = (msg->addr << 25) | msg->buf[0]; | ||
110 | wdata = msg->buf[0]; | ||
111 | |||
112 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2); | ||
113 | |||
114 | if (msg->len > 1) | ||
115 | ctrl |= I2C_NOSTOP | I2C_EXTEND; | ||
116 | else if (joined_rlen) | ||
117 | ctrl |= I2C_NOSTOP; | ||
118 | |||
119 | cx_write(bus->reg_addr, addr); | ||
120 | cx_write(bus->reg_wdata, wdata); | ||
121 | cx_write(bus->reg_ctrl, ctrl); | ||
122 | |||
123 | retval = i2c_wait_done(i2c_adap); | ||
124 | if (retval < 0) | ||
125 | goto err; | ||
126 | |||
127 | if (retval == 0) | ||
128 | goto eio; | ||
129 | |||
130 | if (i2c_debug) { | ||
131 | if (!(ctrl & I2C_NOSTOP)) | ||
132 | printk(" >\n"); | ||
133 | } | ||
134 | |||
135 | for (cnt = 1; cnt < msg->len; cnt++) { | ||
136 | /* following bytes */ | ||
137 | wdata = msg->buf[cnt]; | ||
138 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2); | ||
139 | |||
140 | if (cnt < msg->len - 1) | ||
141 | ctrl |= I2C_NOSTOP | I2C_EXTEND; | ||
142 | else if (joined_rlen) | ||
143 | ctrl |= I2C_NOSTOP; | ||
144 | |||
145 | cx_write(bus->reg_addr, addr); | ||
146 | cx_write(bus->reg_wdata, wdata); | ||
147 | cx_write(bus->reg_ctrl, ctrl); | ||
148 | |||
149 | retval = i2c_wait_done(i2c_adap); | ||
150 | if (retval < 0) | ||
151 | goto err; | ||
152 | |||
153 | if (retval == 0) | ||
154 | goto eio; | ||
155 | |||
156 | if (i2c_debug) { | ||
157 | dprintk(1, " %02x", msg->buf[cnt]); | ||
158 | if (!(ctrl & I2C_NOSTOP)) | ||
159 | dprintk(1, " >\n"); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | return msg->len; | ||
164 | |||
165 | eio: | ||
166 | retval = -EIO; | ||
167 | err: | ||
168 | if (i2c_debug) | ||
169 | pr_err(" ERR: %d\n", retval); | ||
170 | return retval; | ||
171 | } | ||
172 | |||
173 | static int i2c_readbytes(struct i2c_adapter *i2c_adap, | ||
174 | const struct i2c_msg *msg, int joined) | ||
175 | { | ||
176 | struct cx25821_i2c *bus = i2c_adap->algo_data; | ||
177 | struct cx25821_dev *dev = bus->dev; | ||
178 | u32 ctrl, cnt; | ||
179 | int retval; | ||
180 | |||
181 | if (i2c_debug && !joined) | ||
182 | dprintk(1, "6-%s(msg->len=%d)\n", __func__, msg->len); | ||
183 | |||
184 | /* Deal with i2c probe functions with zero payload */ | ||
185 | if (msg->len == 0) { | ||
186 | cx_write(bus->reg_addr, msg->addr << 25); | ||
187 | cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1); | ||
188 | if (!i2c_wait_done(i2c_adap)) | ||
189 | return -EIO; | ||
190 | if (!i2c_slave_did_ack(i2c_adap)) | ||
191 | return -EIO; | ||
192 | |||
193 | dprintk(1, "%s(): returns 0\n", __func__); | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | if (i2c_debug) { | ||
198 | if (joined) | ||
199 | dprintk(1, " R"); | ||
200 | else | ||
201 | dprintk(1, " <R %02x", (msg->addr << 1) + 1); | ||
202 | } | ||
203 | |||
204 | for (cnt = 0; cnt < msg->len; cnt++) { | ||
205 | |||
206 | ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; | ||
207 | |||
208 | if (cnt < msg->len - 1) | ||
209 | ctrl |= I2C_NOSTOP | I2C_EXTEND; | ||
210 | |||
211 | cx_write(bus->reg_addr, msg->addr << 25); | ||
212 | cx_write(bus->reg_ctrl, ctrl); | ||
213 | |||
214 | retval = i2c_wait_done(i2c_adap); | ||
215 | if (retval < 0) | ||
216 | goto err; | ||
217 | if (retval == 0) | ||
218 | goto eio; | ||
219 | msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; | ||
220 | |||
221 | if (i2c_debug) { | ||
222 | dprintk(1, " %02x", msg->buf[cnt]); | ||
223 | if (!(ctrl & I2C_NOSTOP)) | ||
224 | dprintk(1, " >\n"); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | return msg->len; | ||
229 | eio: | ||
230 | retval = -EIO; | ||
231 | err: | ||
232 | if (i2c_debug) | ||
233 | pr_err(" ERR: %d\n", retval); | ||
234 | return retval; | ||
235 | } | ||
236 | |||
237 | static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) | ||
238 | { | ||
239 | struct cx25821_i2c *bus = i2c_adap->algo_data; | ||
240 | struct cx25821_dev *dev = bus->dev; | ||
241 | int i, retval = 0; | ||
242 | |||
243 | dprintk(1, "%s(num = %d)\n", __func__, num); | ||
244 | |||
245 | for (i = 0; i < num; i++) { | ||
246 | dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n", | ||
247 | __func__, num, msgs[i].addr, msgs[i].len); | ||
248 | |||
249 | if (msgs[i].flags & I2C_M_RD) { | ||
250 | /* read */ | ||
251 | retval = i2c_readbytes(i2c_adap, &msgs[i], 0); | ||
252 | } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && | ||
253 | msgs[i].addr == msgs[i + 1].addr) { | ||
254 | /* write then read from same address */ | ||
255 | retval = | ||
256 | i2c_sendbytes(i2c_adap, &msgs[i], msgs[i + 1].len); | ||
257 | |||
258 | if (retval < 0) | ||
259 | goto err; | ||
260 | i++; | ||
261 | retval = i2c_readbytes(i2c_adap, &msgs[i], 1); | ||
262 | } else { | ||
263 | /* write */ | ||
264 | retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); | ||
265 | } | ||
266 | |||
267 | if (retval < 0) | ||
268 | goto err; | ||
269 | } | ||
270 | return num; | ||
271 | |||
272 | err: | ||
273 | return retval; | ||
274 | } | ||
275 | |||
276 | |||
277 | static u32 cx25821_functionality(struct i2c_adapter *adap) | ||
278 | { | ||
279 | return I2C_FUNC_SMBUS_EMUL | | ||
280 | I2C_FUNC_I2C | | ||
281 | I2C_FUNC_SMBUS_WORD_DATA | | ||
282 | I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; | ||
283 | } | ||
284 | |||
285 | static struct i2c_algorithm cx25821_i2c_algo_template = { | ||
286 | .master_xfer = i2c_xfer, | ||
287 | .functionality = cx25821_functionality, | ||
288 | #ifdef NEED_ALGO_CONTROL | ||
289 | .algo_control = dummy_algo_control, | ||
290 | #endif | ||
291 | }; | ||
292 | |||
293 | static struct i2c_adapter cx25821_i2c_adap_template = { | ||
294 | .name = "cx25821", | ||
295 | .owner = THIS_MODULE, | ||
296 | .algo = &cx25821_i2c_algo_template, | ||
297 | }; | ||
298 | |||
299 | static struct i2c_client cx25821_i2c_client_template = { | ||
300 | .name = "cx25821 internal", | ||
301 | }; | ||
302 | |||
303 | /* init + register i2c algo-bit adapter */ | ||
304 | int cx25821_i2c_register(struct cx25821_i2c *bus) | ||
305 | { | ||
306 | struct cx25821_dev *dev = bus->dev; | ||
307 | |||
308 | dprintk(1, "%s(bus = %d)\n", __func__, bus->nr); | ||
309 | |||
310 | memcpy(&bus->i2c_adap, &cx25821_i2c_adap_template, | ||
311 | sizeof(bus->i2c_adap)); | ||
312 | memcpy(&bus->i2c_algo, &cx25821_i2c_algo_template, | ||
313 | sizeof(bus->i2c_algo)); | ||
314 | memcpy(&bus->i2c_client, &cx25821_i2c_client_template, | ||
315 | sizeof(bus->i2c_client)); | ||
316 | |||
317 | bus->i2c_adap.dev.parent = &dev->pci->dev; | ||
318 | |||
319 | strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name)); | ||
320 | |||
321 | bus->i2c_algo.data = bus; | ||
322 | bus->i2c_adap.algo_data = bus; | ||
323 | i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev); | ||
324 | i2c_add_adapter(&bus->i2c_adap); | ||
325 | |||
326 | bus->i2c_client.adapter = &bus->i2c_adap; | ||
327 | |||
328 | /* set up the I2c */ | ||
329 | bus->i2c_client.addr = (0x88 >> 1); | ||
330 | |||
331 | return bus->i2c_rc; | ||
332 | } | ||
333 | |||
334 | int cx25821_i2c_unregister(struct cx25821_i2c *bus) | ||
335 | { | ||
336 | i2c_del_adapter(&bus->i2c_adap); | ||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | void cx25821_av_clk(struct cx25821_dev *dev, int enable) | ||
341 | { | ||
342 | /* write 0 to bus 2 addr 0x144 via i2x_xfer() */ | ||
343 | char buffer[3]; | ||
344 | struct i2c_msg msg; | ||
345 | dprintk(1, "%s(enabled = %d)\n", __func__, enable); | ||
346 | |||
347 | /* Register 0x144 */ | ||
348 | buffer[0] = 0x01; | ||
349 | buffer[1] = 0x44; | ||
350 | if (enable == 1) | ||
351 | buffer[2] = 0x05; | ||
352 | else | ||
353 | buffer[2] = 0x00; | ||
354 | |||
355 | msg.addr = 0x44; | ||
356 | msg.flags = I2C_M_TEN; | ||
357 | msg.len = 3; | ||
358 | msg.buf = buffer; | ||
359 | |||
360 | i2c_xfer(&dev->i2c_bus[0].i2c_adap, &msg, 1); | ||
361 | } | ||
362 | |||
363 | int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value) | ||
364 | { | ||
365 | struct i2c_client *client = &bus->i2c_client; | ||
366 | int retval = 0; | ||
367 | int v = 0; | ||
368 | u8 addr[2] = { 0, 0 }; | ||
369 | u8 buf[4] = { 0, 0, 0, 0 }; | ||
370 | |||
371 | struct i2c_msg msgs[2] = { | ||
372 | { | ||
373 | .addr = client->addr, | ||
374 | .flags = 0, | ||
375 | .len = 2, | ||
376 | .buf = addr, | ||
377 | }, { | ||
378 | .addr = client->addr, | ||
379 | .flags = I2C_M_RD, | ||
380 | .len = 4, | ||
381 | .buf = buf, | ||
382 | } | ||
383 | }; | ||
384 | |||
385 | addr[0] = (reg_addr >> 8); | ||
386 | addr[1] = (reg_addr & 0xff); | ||
387 | msgs[0].addr = 0x44; | ||
388 | msgs[1].addr = 0x44; | ||
389 | |||
390 | retval = i2c_xfer(client->adapter, msgs, 2); | ||
391 | |||
392 | v = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||
393 | *value = v; | ||
394 | |||
395 | return v; | ||
396 | } | ||
397 | |||
398 | int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value) | ||
399 | { | ||
400 | struct i2c_client *client = &bus->i2c_client; | ||
401 | int retval = 0; | ||
402 | u8 buf[6] = { 0, 0, 0, 0, 0, 0 }; | ||
403 | |||
404 | struct i2c_msg msgs[1] = { | ||
405 | { | ||
406 | .addr = client->addr, | ||
407 | .flags = 0, | ||
408 | .len = 6, | ||
409 | .buf = buf, | ||
410 | } | ||
411 | }; | ||
412 | |||
413 | buf[0] = reg_addr >> 8; | ||
414 | buf[1] = reg_addr & 0xff; | ||
415 | buf[5] = (value >> 24) & 0xff; | ||
416 | buf[4] = (value >> 16) & 0xff; | ||
417 | buf[3] = (value >> 8) & 0xff; | ||
418 | buf[2] = value & 0xff; | ||
419 | client->flags = 0; | ||
420 | msgs[0].addr = 0x44; | ||
421 | |||
422 | retval = i2c_xfer(client->adapter, msgs, 1); | ||
423 | |||
424 | return retval; | ||
425 | } | ||
diff --git a/drivers/media/video/cx25821/cx25821-medusa-defines.h b/drivers/media/video/cx25821/cx25821-medusa-defines.h new file mode 100644 index 000000000000..60d197f57556 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-medusa-defines.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #ifndef _MEDUSA_DEF_H_ | ||
24 | #define _MEDUSA_DEF_H_ | ||
25 | |||
26 | /* Video deocder that we supported */ | ||
27 | #define VDEC_A 0 | ||
28 | #define VDEC_B 1 | ||
29 | #define VDEC_C 2 | ||
30 | #define VDEC_D 3 | ||
31 | #define VDEC_E 4 | ||
32 | #define VDEC_F 5 | ||
33 | #define VDEC_G 6 | ||
34 | #define VDEC_H 7 | ||
35 | |||
36 | /* end of display sequence */ | ||
37 | #define END_OF_SEQ 0xF; | ||
38 | |||
39 | /* registry string size */ | ||
40 | #define MAX_REGISTRY_SZ 40; | ||
41 | |||
42 | #endif | ||
diff --git a/drivers/media/video/cx25821/cx25821-medusa-reg.h b/drivers/media/video/cx25821/cx25821-medusa-reg.h new file mode 100644 index 000000000000..1c1c228352d1 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-medusa-reg.h | |||
@@ -0,0 +1,455 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #ifndef __MEDUSA_REGISTERS__ | ||
24 | #define __MEDUSA_REGISTERS__ | ||
25 | |||
26 | /* Serial Slave Registers */ | ||
27 | #define HOST_REGISTER1 0x0000 | ||
28 | #define HOST_REGISTER2 0x0001 | ||
29 | |||
30 | /* Chip Configuration Registers */ | ||
31 | #define CHIP_CTRL 0x0100 | ||
32 | #define AFE_AB_CTRL 0x0104 | ||
33 | #define AFE_CD_CTRL 0x0108 | ||
34 | #define AFE_EF_CTRL 0x010C | ||
35 | #define AFE_GH_CTRL 0x0110 | ||
36 | #define DENC_AB_CTRL 0x0114 | ||
37 | #define BYP_AB_CTRL 0x0118 | ||
38 | #define MON_A_CTRL 0x011C | ||
39 | #define DISP_SEQ_A 0x0120 | ||
40 | #define DISP_SEQ_B 0x0124 | ||
41 | #define DISP_AB_CNT 0x0128 | ||
42 | #define DISP_CD_CNT 0x012C | ||
43 | #define DISP_EF_CNT 0x0130 | ||
44 | #define DISP_GH_CNT 0x0134 | ||
45 | #define DISP_IJ_CNT 0x0138 | ||
46 | #define PIN_OE_CTRL 0x013C | ||
47 | #define PIN_SPD_CTRL 0x0140 | ||
48 | #define PIN_SPD_CTRL2 0x0144 | ||
49 | #define IRQ_STAT_CTRL 0x0148 | ||
50 | #define POWER_CTRL_AB 0x014C | ||
51 | #define POWER_CTRL_CD 0x0150 | ||
52 | #define POWER_CTRL_EF 0x0154 | ||
53 | #define POWER_CTRL_GH 0x0158 | ||
54 | #define TUNE_CTRL 0x015C | ||
55 | #define BIAS_CTRL 0x0160 | ||
56 | #define AFE_AB_DIAG_CTRL 0x0164 | ||
57 | #define AFE_CD_DIAG_CTRL 0x0168 | ||
58 | #define AFE_EF_DIAG_CTRL 0x016C | ||
59 | #define AFE_GH_DIAG_CTRL 0x0170 | ||
60 | #define PLL_AB_DIAG_CTRL 0x0174 | ||
61 | #define PLL_CD_DIAG_CTRL 0x0178 | ||
62 | #define PLL_EF_DIAG_CTRL 0x017C | ||
63 | #define PLL_GH_DIAG_CTRL 0x0180 | ||
64 | #define TEST_CTRL 0x0184 | ||
65 | #define BIST_STAT 0x0188 | ||
66 | #define BIST_STAT2 0x018C | ||
67 | #define BIST_VID_PLL_AB_STAT 0x0190 | ||
68 | #define BIST_VID_PLL_CD_STAT 0x0194 | ||
69 | #define BIST_VID_PLL_EF_STAT 0x0198 | ||
70 | #define BIST_VID_PLL_GH_STAT 0x019C | ||
71 | #define DLL_DIAG_CTRL 0x01A0 | ||
72 | #define DEV_CH_ID_CTRL 0x01A4 | ||
73 | #define ABIST_CTRL_STATUS 0x01A8 | ||
74 | #define ABIST_FREQ 0x01AC | ||
75 | #define ABIST_GOERT_SHIFT 0x01B0 | ||
76 | #define ABIST_COEF12 0x01B4 | ||
77 | #define ABIST_COEF34 0x01B8 | ||
78 | #define ABIST_COEF56 0x01BC | ||
79 | #define ABIST_COEF7_SNR 0x01C0 | ||
80 | #define ABIST_ADC_CAL 0x01C4 | ||
81 | #define ABIST_BIN1_VGA0 0x01C8 | ||
82 | #define ABIST_BIN2_VGA1 0x01CC | ||
83 | #define ABIST_BIN3_VGA2 0x01D0 | ||
84 | #define ABIST_BIN4_VGA3 0x01D4 | ||
85 | #define ABIST_BIN5_VGA4 0x01D8 | ||
86 | #define ABIST_BIN6_VGA5 0x01DC | ||
87 | #define ABIST_BIN7_VGA6 0x0x1E0 | ||
88 | #define ABIST_CLAMP_A 0x0x1E4 | ||
89 | #define ABIST_CLAMP_B 0x0x1E8 | ||
90 | #define ABIST_CLAMP_C 0x01EC | ||
91 | #define ABIST_CLAMP_D 0x01F0 | ||
92 | #define ABIST_CLAMP_E 0x01F4 | ||
93 | #define ABIST_CLAMP_F 0x01F8 | ||
94 | |||
95 | /* Digital Video Encoder A Registers */ | ||
96 | #define DENC_A_REG_1 0x0200 | ||
97 | #define DENC_A_REG_2 0x0204 | ||
98 | #define DENC_A_REG_3 0x0208 | ||
99 | #define DENC_A_REG_4 0x020C | ||
100 | #define DENC_A_REG_5 0x0210 | ||
101 | #define DENC_A_REG_6 0x0214 | ||
102 | #define DENC_A_REG_7 0x0218 | ||
103 | #define DENC_A_REG_8 0x021C | ||
104 | |||
105 | /* Digital Video Encoder B Registers */ | ||
106 | #define DENC_B_REG_1 0x0300 | ||
107 | #define DENC_B_REG_2 0x0304 | ||
108 | #define DENC_B_REG_3 0x0308 | ||
109 | #define DENC_B_REG_4 0x030C | ||
110 | #define DENC_B_REG_5 0x0310 | ||
111 | #define DENC_B_REG_6 0x0314 | ||
112 | #define DENC_B_REG_7 0x0318 | ||
113 | #define DENC_B_REG_8 0x031C | ||
114 | |||
115 | /* Video Decoder A Registers */ | ||
116 | #define MODE_CTRL 0x1000 | ||
117 | #define OUT_CTRL1 0x1004 | ||
118 | #define OUT_CTRL_NS 0x1008 | ||
119 | #define GEN_STAT 0x100C | ||
120 | #define INT_STAT_MASK 0x1010 | ||
121 | #define LUMA_CTRL 0x1014 | ||
122 | #define CHROMA_CTRL 0x1018 | ||
123 | #define CRUSH_CTRL 0x101C | ||
124 | #define HORIZ_TIM_CTRL 0x1020 | ||
125 | #define VERT_TIM_CTRL 0x1024 | ||
126 | #define MISC_TIM_CTRL 0x1028 | ||
127 | #define FIELD_COUNT 0x102C | ||
128 | #define HSCALE_CTRL 0x1030 | ||
129 | #define VSCALE_CTRL 0x1034 | ||
130 | #define MAN_VGA_CTRL 0x1038 | ||
131 | #define MAN_AGC_CTRL 0x103C | ||
132 | #define DFE_CTRL1 0x1040 | ||
133 | #define DFE_CTRL2 0x1044 | ||
134 | #define DFE_CTRL3 0x1048 | ||
135 | #define PLL_CTRL 0x104C | ||
136 | #define PLL_CTRL_FAST 0x1050 | ||
137 | #define HTL_CTRL 0x1054 | ||
138 | #define SRC_CFG 0x1058 | ||
139 | #define SC_STEP_SIZE 0x105C | ||
140 | #define SC_CONVERGE_CTRL 0x1060 | ||
141 | #define SC_LOOP_CTRL 0x1064 | ||
142 | #define COMB_2D_HFS_CFG 0x1068 | ||
143 | #define COMB_2D_HFD_CFG 0x106C | ||
144 | #define COMB_2D_LF_CFG 0x1070 | ||
145 | #define COMB_2D_BLEND 0x1074 | ||
146 | #define COMB_MISC_CTRL 0x1078 | ||
147 | #define COMB_FLAT_THRESH_CTRL 0x107C | ||
148 | #define COMB_TEST 0x1080 | ||
149 | #define BP_MISC_CTRL 0x1084 | ||
150 | #define VCR_DET_CTRL 0x1088 | ||
151 | #define NOISE_DET_CTRL 0x108C | ||
152 | #define COMB_FLAT_NOISE_CTRL 0x1090 | ||
153 | #define VERSION 0x11F8 | ||
154 | #define SOFT_RST_CTRL 0x11FC | ||
155 | |||
156 | /* Video Decoder B Registers */ | ||
157 | #define VDEC_B_MODE_CTRL 0x1200 | ||
158 | #define VDEC_B_OUT_CTRL1 0x1204 | ||
159 | #define VDEC_B_OUT_CTRL_NS 0x1208 | ||
160 | #define VDEC_B_GEN_STAT 0x120C | ||
161 | #define VDEC_B_INT_STAT_MASK 0x1210 | ||
162 | #define VDEC_B_LUMA_CTRL 0x1214 | ||
163 | #define VDEC_B_CHROMA_CTRL 0x1218 | ||
164 | #define VDEC_B_CRUSH_CTRL 0x121C | ||
165 | #define VDEC_B_HORIZ_TIM_CTRL 0x1220 | ||
166 | #define VDEC_B_VERT_TIM_CTRL 0x1224 | ||
167 | #define VDEC_B_MISC_TIM_CTRL 0x1228 | ||
168 | #define VDEC_B_FIELD_COUNT 0x122C | ||
169 | #define VDEC_B_HSCALE_CTRL 0x1230 | ||
170 | #define VDEC_B_VSCALE_CTRL 0x1234 | ||
171 | #define VDEC_B_MAN_VGA_CTRL 0x1238 | ||
172 | #define VDEC_B_MAN_AGC_CTRL 0x123C | ||
173 | #define VDEC_B_DFE_CTRL1 0x1240 | ||
174 | #define VDEC_B_DFE_CTRL2 0x1244 | ||
175 | #define VDEC_B_DFE_CTRL3 0x1248 | ||
176 | #define VDEC_B_PLL_CTRL 0x124C | ||
177 | #define VDEC_B_PLL_CTRL_FAST 0x1250 | ||
178 | #define VDEC_B_HTL_CTRL 0x1254 | ||
179 | #define VDEC_B_SRC_CFG 0x1258 | ||
180 | #define VDEC_B_SC_STEP_SIZE 0x125C | ||
181 | #define VDEC_B_SC_CONVERGE_CTRL 0x1260 | ||
182 | #define VDEC_B_SC_LOOP_CTRL 0x1264 | ||
183 | #define VDEC_B_COMB_2D_HFS_CFG 0x1268 | ||
184 | #define VDEC_B_COMB_2D_HFD_CFG 0x126C | ||
185 | #define VDEC_B_COMB_2D_LF_CFG 0x1270 | ||
186 | #define VDEC_B_COMB_2D_BLEND 0x1274 | ||
187 | #define VDEC_B_COMB_MISC_CTRL 0x1278 | ||
188 | #define VDEC_B_COMB_FLAT_THRESH_CTRL 0x127C | ||
189 | #define VDEC_B_COMB_TEST 0x1280 | ||
190 | #define VDEC_B_BP_MISC_CTRL 0x1284 | ||
191 | #define VDEC_B_VCR_DET_CTRL 0x1288 | ||
192 | #define VDEC_B_NOISE_DET_CTRL 0x128C | ||
193 | #define VDEC_B_COMB_FLAT_NOISE_CTRL 0x1290 | ||
194 | #define VDEC_B_VERSION 0x13F8 | ||
195 | #define VDEC_B_SOFT_RST_CTRL 0x13FC | ||
196 | |||
197 | /* Video Decoder C Registers */ | ||
198 | #define VDEC_C_MODE_CTRL 0x1400 | ||
199 | #define VDEC_C_OUT_CTRL1 0x1404 | ||
200 | #define VDEC_C_OUT_CTRL_NS 0x1408 | ||
201 | #define VDEC_C_GEN_STAT 0x140C | ||
202 | #define VDEC_C_INT_STAT_MASK 0x1410 | ||
203 | #define VDEC_C_LUMA_CTRL 0x1414 | ||
204 | #define VDEC_C_CHROMA_CTRL 0x1418 | ||
205 | #define VDEC_C_CRUSH_CTRL 0x141C | ||
206 | #define VDEC_C_HORIZ_TIM_CTRL 0x1420 | ||
207 | #define VDEC_C_VERT_TIM_CTRL 0x1424 | ||
208 | #define VDEC_C_MISC_TIM_CTRL 0x1428 | ||
209 | #define VDEC_C_FIELD_COUNT 0x142C | ||
210 | #define VDEC_C_HSCALE_CTRL 0x1430 | ||
211 | #define VDEC_C_VSCALE_CTRL 0x1434 | ||
212 | #define VDEC_C_MAN_VGA_CTRL 0x1438 | ||
213 | #define VDEC_C_MAN_AGC_CTRL 0x143C | ||
214 | #define VDEC_C_DFE_CTRL1 0x1440 | ||
215 | #define VDEC_C_DFE_CTRL2 0x1444 | ||
216 | #define VDEC_C_DFE_CTRL3 0x1448 | ||
217 | #define VDEC_C_PLL_CTRL 0x144C | ||
218 | #define VDEC_C_PLL_CTRL_FAST 0x1450 | ||
219 | #define VDEC_C_HTL_CTRL 0x1454 | ||
220 | #define VDEC_C_SRC_CFG 0x1458 | ||
221 | #define VDEC_C_SC_STEP_SIZE 0x145C | ||
222 | #define VDEC_C_SC_CONVERGE_CTRL 0x1460 | ||
223 | #define VDEC_C_SC_LOOP_CTRL 0x1464 | ||
224 | #define VDEC_C_COMB_2D_HFS_CFG 0x1468 | ||
225 | #define VDEC_C_COMB_2D_HFD_CFG 0x146C | ||
226 | #define VDEC_C_COMB_2D_LF_CFG 0x1470 | ||
227 | #define VDEC_C_COMB_2D_BLEND 0x1474 | ||
228 | #define VDEC_C_COMB_MISC_CTRL 0x1478 | ||
229 | #define VDEC_C_COMB_FLAT_THRESH_CTRL 0x147C | ||
230 | #define VDEC_C_COMB_TEST 0x1480 | ||
231 | #define VDEC_C_BP_MISC_CTRL 0x1484 | ||
232 | #define VDEC_C_VCR_DET_CTRL 0x1488 | ||
233 | #define VDEC_C_NOISE_DET_CTRL 0x148C | ||
234 | #define VDEC_C_COMB_FLAT_NOISE_CTRL 0x1490 | ||
235 | #define VDEC_C_VERSION 0x15F8 | ||
236 | #define VDEC_C_SOFT_RST_CTRL 0x15FC | ||
237 | |||
238 | /* Video Decoder D Registers */ | ||
239 | #define VDEC_D_MODE_CTRL 0x1600 | ||
240 | #define VDEC_D_OUT_CTRL1 0x1604 | ||
241 | #define VDEC_D_OUT_CTRL_NS 0x1608 | ||
242 | #define VDEC_D_GEN_STAT 0x160C | ||
243 | #define VDEC_D_INT_STAT_MASK 0x1610 | ||
244 | #define VDEC_D_LUMA_CTRL 0x1614 | ||
245 | #define VDEC_D_CHROMA_CTRL 0x1618 | ||
246 | #define VDEC_D_CRUSH_CTRL 0x161C | ||
247 | #define VDEC_D_HORIZ_TIM_CTRL 0x1620 | ||
248 | #define VDEC_D_VERT_TIM_CTRL 0x1624 | ||
249 | #define VDEC_D_MISC_TIM_CTRL 0x1628 | ||
250 | #define VDEC_D_FIELD_COUNT 0x162C | ||
251 | #define VDEC_D_HSCALE_CTRL 0x1630 | ||
252 | #define VDEC_D_VSCALE_CTRL 0x1634 | ||
253 | #define VDEC_D_MAN_VGA_CTRL 0x1638 | ||
254 | #define VDEC_D_MAN_AGC_CTRL 0x163C | ||
255 | #define VDEC_D_DFE_CTRL1 0x1640 | ||
256 | #define VDEC_D_DFE_CTRL2 0x1644 | ||
257 | #define VDEC_D_DFE_CTRL3 0x1648 | ||
258 | #define VDEC_D_PLL_CTRL 0x164C | ||
259 | #define VDEC_D_PLL_CTRL_FAST 0x1650 | ||
260 | #define VDEC_D_HTL_CTRL 0x1654 | ||
261 | #define VDEC_D_SRC_CFG 0x1658 | ||
262 | #define VDEC_D_SC_STEP_SIZE 0x165C | ||
263 | #define VDEC_D_SC_CONVERGE_CTRL 0x1660 | ||
264 | #define VDEC_D_SC_LOOP_CTRL 0x1664 | ||
265 | #define VDEC_D_COMB_2D_HFS_CFG 0x1668 | ||
266 | #define VDEC_D_COMB_2D_HFD_CFG 0x166C | ||
267 | #define VDEC_D_COMB_2D_LF_CFG 0x1670 | ||
268 | #define VDEC_D_COMB_2D_BLEND 0x1674 | ||
269 | #define VDEC_D_COMB_MISC_CTRL 0x1678 | ||
270 | #define VDEC_D_COMB_FLAT_THRESH_CTRL 0x167C | ||
271 | #define VDEC_D_COMB_TEST 0x1680 | ||
272 | #define VDEC_D_BP_MISC_CTRL 0x1684 | ||
273 | #define VDEC_D_VCR_DET_CTRL 0x1688 | ||
274 | #define VDEC_D_NOISE_DET_CTRL 0x168C | ||
275 | #define VDEC_D_COMB_FLAT_NOISE_CTRL 0x1690 | ||
276 | #define VDEC_D_VERSION 0x17F8 | ||
277 | #define VDEC_D_SOFT_RST_CTRL 0x17FC | ||
278 | |||
279 | /* Video Decoder E Registers */ | ||
280 | #define VDEC_E_MODE_CTRL 0x1800 | ||
281 | #define VDEC_E_OUT_CTRL1 0x1804 | ||
282 | #define VDEC_E_OUT_CTRL_NS 0x1808 | ||
283 | #define VDEC_E_GEN_STAT 0x180C | ||
284 | #define VDEC_E_INT_STAT_MASK 0x1810 | ||
285 | #define VDEC_E_LUMA_CTRL 0x1814 | ||
286 | #define VDEC_E_CHROMA_CTRL 0x1818 | ||
287 | #define VDEC_E_CRUSH_CTRL 0x181C | ||
288 | #define VDEC_E_HORIZ_TIM_CTRL 0x1820 | ||
289 | #define VDEC_E_VERT_TIM_CTRL 0x1824 | ||
290 | #define VDEC_E_MISC_TIM_CTRL 0x1828 | ||
291 | #define VDEC_E_FIELD_COUNT 0x182C | ||
292 | #define VDEC_E_HSCALE_CTRL 0x1830 | ||
293 | #define VDEC_E_VSCALE_CTRL 0x1834 | ||
294 | #define VDEC_E_MAN_VGA_CTRL 0x1838 | ||
295 | #define VDEC_E_MAN_AGC_CTRL 0x183C | ||
296 | #define VDEC_E_DFE_CTRL1 0x1840 | ||
297 | #define VDEC_E_DFE_CTRL2 0x1844 | ||
298 | #define VDEC_E_DFE_CTRL3 0x1848 | ||
299 | #define VDEC_E_PLL_CTRL 0x184C | ||
300 | #define VDEC_E_PLL_CTRL_FAST 0x1850 | ||
301 | #define VDEC_E_HTL_CTRL 0x1854 | ||
302 | #define VDEC_E_SRC_CFG 0x1858 | ||
303 | #define VDEC_E_SC_STEP_SIZE 0x185C | ||
304 | #define VDEC_E_SC_CONVERGE_CTRL 0x1860 | ||
305 | #define VDEC_E_SC_LOOP_CTRL 0x1864 | ||
306 | #define VDEC_E_COMB_2D_HFS_CFG 0x1868 | ||
307 | #define VDEC_E_COMB_2D_HFD_CFG 0x186C | ||
308 | #define VDEC_E_COMB_2D_LF_CFG 0x1870 | ||
309 | #define VDEC_E_COMB_2D_BLEND 0x1874 | ||
310 | #define VDEC_E_COMB_MISC_CTRL 0x1878 | ||
311 | #define VDEC_E_COMB_FLAT_THRESH_CTRL 0x187C | ||
312 | #define VDEC_E_COMB_TEST 0x1880 | ||
313 | #define VDEC_E_BP_MISC_CTRL 0x1884 | ||
314 | #define VDEC_E_VCR_DET_CTRL 0x1888 | ||
315 | #define VDEC_E_NOISE_DET_CTRL 0x188C | ||
316 | #define VDEC_E_COMB_FLAT_NOISE_CTRL 0x1890 | ||
317 | #define VDEC_E_VERSION 0x19F8 | ||
318 | #define VDEC_E_SOFT_RST_CTRL 0x19FC | ||
319 | |||
320 | /* Video Decoder F Registers */ | ||
321 | #define VDEC_F_MODE_CTRL 0x1A00 | ||
322 | #define VDEC_F_OUT_CTRL1 0x1A04 | ||
323 | #define VDEC_F_OUT_CTRL_NS 0x1A08 | ||
324 | #define VDEC_F_GEN_STAT 0x1A0C | ||
325 | #define VDEC_F_INT_STAT_MASK 0x1A10 | ||
326 | #define VDEC_F_LUMA_CTRL 0x1A14 | ||
327 | #define VDEC_F_CHROMA_CTRL 0x1A18 | ||
328 | #define VDEC_F_CRUSH_CTRL 0x1A1C | ||
329 | #define VDEC_F_HORIZ_TIM_CTRL 0x1A20 | ||
330 | #define VDEC_F_VERT_TIM_CTRL 0x1A24 | ||
331 | #define VDEC_F_MISC_TIM_CTRL 0x1A28 | ||
332 | #define VDEC_F_FIELD_COUNT 0x1A2C | ||
333 | #define VDEC_F_HSCALE_CTRL 0x1A30 | ||
334 | #define VDEC_F_VSCALE_CTRL 0x1A34 | ||
335 | #define VDEC_F_MAN_VGA_CTRL 0x1A38 | ||
336 | #define VDEC_F_MAN_AGC_CTRL 0x1A3C | ||
337 | #define VDEC_F_DFE_CTRL1 0x1A40 | ||
338 | #define VDEC_F_DFE_CTRL2 0x1A44 | ||
339 | #define VDEC_F_DFE_CTRL3 0x1A48 | ||
340 | #define VDEC_F_PLL_CTRL 0x1A4C | ||
341 | #define VDEC_F_PLL_CTRL_FAST 0x1A50 | ||
342 | #define VDEC_F_HTL_CTRL 0x1A54 | ||
343 | #define VDEC_F_SRC_CFG 0x1A58 | ||
344 | #define VDEC_F_SC_STEP_SIZE 0x1A5C | ||
345 | #define VDEC_F_SC_CONVERGE_CTRL 0x1A60 | ||
346 | #define VDEC_F_SC_LOOP_CTRL 0x1A64 | ||
347 | #define VDEC_F_COMB_2D_HFS_CFG 0x1A68 | ||
348 | #define VDEC_F_COMB_2D_HFD_CFG 0x1A6C | ||
349 | #define VDEC_F_COMB_2D_LF_CFG 0x1A70 | ||
350 | #define VDEC_F_COMB_2D_BLEND 0x1A74 | ||
351 | #define VDEC_F_COMB_MISC_CTRL 0x1A78 | ||
352 | #define VDEC_F_COMB_FLAT_THRESH_CTRL 0x1A7C | ||
353 | #define VDEC_F_COMB_TEST 0x1A80 | ||
354 | #define VDEC_F_BP_MISC_CTRL 0x1A84 | ||
355 | #define VDEC_F_VCR_DET_CTRL 0x1A88 | ||
356 | #define VDEC_F_NOISE_DET_CTRL 0x1A8C | ||
357 | #define VDEC_F_COMB_FLAT_NOISE_CTRL 0x1A90 | ||
358 | #define VDEC_F_VERSION 0x1BF8 | ||
359 | #define VDEC_F_SOFT_RST_CTRL 0x1BFC | ||
360 | |||
361 | /* Video Decoder G Registers */ | ||
362 | #define VDEC_G_MODE_CTRL 0x1C00 | ||
363 | #define VDEC_G_OUT_CTRL1 0x1C04 | ||
364 | #define VDEC_G_OUT_CTRL_NS 0x1C08 | ||
365 | #define VDEC_G_GEN_STAT 0x1C0C | ||
366 | #define VDEC_G_INT_STAT_MASK 0x1C10 | ||
367 | #define VDEC_G_LUMA_CTRL 0x1C14 | ||
368 | #define VDEC_G_CHROMA_CTRL 0x1C18 | ||
369 | #define VDEC_G_CRUSH_CTRL 0x1C1C | ||
370 | #define VDEC_G_HORIZ_TIM_CTRL 0x1C20 | ||
371 | #define VDEC_G_VERT_TIM_CTRL 0x1C24 | ||
372 | #define VDEC_G_MISC_TIM_CTRL 0x1C28 | ||
373 | #define VDEC_G_FIELD_COUNT 0x1C2C | ||
374 | #define VDEC_G_HSCALE_CTRL 0x1C30 | ||
375 | #define VDEC_G_VSCALE_CTRL 0x1C34 | ||
376 | #define VDEC_G_MAN_VGA_CTRL 0x1C38 | ||
377 | #define VDEC_G_MAN_AGC_CTRL 0x1C3C | ||
378 | #define VDEC_G_DFE_CTRL1 0x1C40 | ||
379 | #define VDEC_G_DFE_CTRL2 0x1C44 | ||
380 | #define VDEC_G_DFE_CTRL3 0x1C48 | ||
381 | #define VDEC_G_PLL_CTRL 0x1C4C | ||
382 | #define VDEC_G_PLL_CTRL_FAST 0x1C50 | ||
383 | #define VDEC_G_HTL_CTRL 0x1C54 | ||
384 | #define VDEC_G_SRC_CFG 0x1C58 | ||
385 | #define VDEC_G_SC_STEP_SIZE 0x1C5C | ||
386 | #define VDEC_G_SC_CONVERGE_CTRL 0x1C60 | ||
387 | #define VDEC_G_SC_LOOP_CTRL 0x1C64 | ||
388 | #define VDEC_G_COMB_2D_HFS_CFG 0x1C68 | ||
389 | #define VDEC_G_COMB_2D_HFD_CFG 0x1C6C | ||
390 | #define VDEC_G_COMB_2D_LF_CFG 0x1C70 | ||
391 | #define VDEC_G_COMB_2D_BLEND 0x1C74 | ||
392 | #define VDEC_G_COMB_MISC_CTRL 0x1C78 | ||
393 | #define VDEC_G_COMB_FLAT_THRESH_CTRL 0x1C7C | ||
394 | #define VDEC_G_COMB_TEST 0x1C80 | ||
395 | #define VDEC_G_BP_MISC_CTRL 0x1C84 | ||
396 | #define VDEC_G_VCR_DET_CTRL 0x1C88 | ||
397 | #define VDEC_G_NOISE_DET_CTRL 0x1C8C | ||
398 | #define VDEC_G_COMB_FLAT_NOISE_CTRL 0x1C90 | ||
399 | #define VDEC_G_VERSION 0x1DF8 | ||
400 | #define VDEC_G_SOFT_RST_CTRL 0x1DFC | ||
401 | |||
402 | /* Video Decoder H Registers */ | ||
403 | #define VDEC_H_MODE_CTRL 0x1E00 | ||
404 | #define VDEC_H_OUT_CTRL1 0x1E04 | ||
405 | #define VDEC_H_OUT_CTRL_NS 0x1E08 | ||
406 | #define VDEC_H_GEN_STAT 0x1E0C | ||
407 | #define VDEC_H_INT_STAT_MASK 0x1E1E | ||
408 | #define VDEC_H_LUMA_CTRL 0x1E14 | ||
409 | #define VDEC_H_CHROMA_CTRL 0x1E18 | ||
410 | #define VDEC_H_CRUSH_CTRL 0x1E1C | ||
411 | #define VDEC_H_HORIZ_TIM_CTRL 0x1E20 | ||
412 | #define VDEC_H_VERT_TIM_CTRL 0x1E24 | ||
413 | #define VDEC_H_MISC_TIM_CTRL 0x1E28 | ||
414 | #define VDEC_H_FIELD_COUNT 0x1E2C | ||
415 | #define VDEC_H_HSCALE_CTRL 0x1E30 | ||
416 | #define VDEC_H_VSCALE_CTRL 0x1E34 | ||
417 | #define VDEC_H_MAN_VGA_CTRL 0x1E38 | ||
418 | #define VDEC_H_MAN_AGC_CTRL 0x1E3C | ||
419 | #define VDEC_H_DFE_CTRL1 0x1E40 | ||
420 | #define VDEC_H_DFE_CTRL2 0x1E44 | ||
421 | #define VDEC_H_DFE_CTRL3 0x1E48 | ||
422 | #define VDEC_H_PLL_CTRL 0x1E4C | ||
423 | #define VDEC_H_PLL_CTRL_FAST 0x1E50 | ||
424 | #define VDEC_H_HTL_CTRL 0x1E54 | ||
425 | #define VDEC_H_SRC_CFG 0x1E58 | ||
426 | #define VDEC_H_SC_STEP_SIZE 0x1E5C | ||
427 | #define VDEC_H_SC_CONVERGE_CTRL 0x1E60 | ||
428 | #define VDEC_H_SC_LOOP_CTRL 0x1E64 | ||
429 | #define VDEC_H_COMB_2D_HFS_CFG 0x1E68 | ||
430 | #define VDEC_H_COMB_2D_HFD_CFG 0x1E6C | ||
431 | #define VDEC_H_COMB_2D_LF_CFG 0x1E70 | ||
432 | #define VDEC_H_COMB_2D_BLEND 0x1E74 | ||
433 | #define VDEC_H_COMB_MISC_CTRL 0x1E78 | ||
434 | #define VDEC_H_COMB_FLAT_THRESH_CTRL 0x1E7C | ||
435 | #define VDEC_H_COMB_TEST 0x1E80 | ||
436 | #define VDEC_H_BP_MISC_CTRL 0x1E84 | ||
437 | #define VDEC_H_VCR_DET_CTRL 0x1E88 | ||
438 | #define VDEC_H_NOISE_DET_CTRL 0x1E8C | ||
439 | #define VDEC_H_COMB_FLAT_NOISE_CTRL 0x1E90 | ||
440 | #define VDEC_H_VERSION 0x1FF8 | ||
441 | #define VDEC_H_SOFT_RST_CTRL 0x1FFC | ||
442 | |||
443 | /*****************************************************************************/ | ||
444 | /* LUMA_CTRL register fields */ | ||
445 | #define VDEC_A_BRITE_CTRL 0x1014 | ||
446 | #define VDEC_A_CNTRST_CTRL 0x1015 | ||
447 | #define VDEC_A_PEAK_SEL 0x1016 | ||
448 | |||
449 | /*****************************************************************************/ | ||
450 | /* CHROMA_CTRL register fields */ | ||
451 | #define VDEC_A_USAT_CTRL 0x1018 | ||
452 | #define VDEC_A_VSAT_CTRL 0x1019 | ||
453 | #define VDEC_A_HUE_CTRL 0x101A | ||
454 | |||
455 | #endif | ||
diff --git a/drivers/media/video/cx25821/cx25821-medusa-video.c b/drivers/media/video/cx25821/cx25821-medusa-video.c new file mode 100644 index 000000000000..fc780d0908dc --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-medusa-video.c | |||
@@ -0,0 +1,872 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
24 | |||
25 | #include "cx25821.h" | ||
26 | #include "cx25821-medusa-video.h" | ||
27 | #include "cx25821-biffuncs.h" | ||
28 | |||
29 | /* | ||
30 | * medusa_enable_bluefield_output() | ||
31 | * | ||
32 | * Enable the generation of blue filed output if no video | ||
33 | * | ||
34 | */ | ||
35 | static void medusa_enable_bluefield_output(struct cx25821_dev *dev, int channel, | ||
36 | int enable) | ||
37 | { | ||
38 | int ret_val = 1; | ||
39 | u32 value = 0; | ||
40 | u32 tmp = 0; | ||
41 | int out_ctrl = OUT_CTRL1; | ||
42 | int out_ctrl_ns = OUT_CTRL_NS; | ||
43 | |||
44 | switch (channel) { | ||
45 | default: | ||
46 | case VDEC_A: | ||
47 | break; | ||
48 | case VDEC_B: | ||
49 | out_ctrl = VDEC_B_OUT_CTRL1; | ||
50 | out_ctrl_ns = VDEC_B_OUT_CTRL_NS; | ||
51 | break; | ||
52 | case VDEC_C: | ||
53 | out_ctrl = VDEC_C_OUT_CTRL1; | ||
54 | out_ctrl_ns = VDEC_C_OUT_CTRL_NS; | ||
55 | break; | ||
56 | case VDEC_D: | ||
57 | out_ctrl = VDEC_D_OUT_CTRL1; | ||
58 | out_ctrl_ns = VDEC_D_OUT_CTRL_NS; | ||
59 | break; | ||
60 | case VDEC_E: | ||
61 | out_ctrl = VDEC_E_OUT_CTRL1; | ||
62 | out_ctrl_ns = VDEC_E_OUT_CTRL_NS; | ||
63 | return; | ||
64 | case VDEC_F: | ||
65 | out_ctrl = VDEC_F_OUT_CTRL1; | ||
66 | out_ctrl_ns = VDEC_F_OUT_CTRL_NS; | ||
67 | return; | ||
68 | case VDEC_G: | ||
69 | out_ctrl = VDEC_G_OUT_CTRL1; | ||
70 | out_ctrl_ns = VDEC_G_OUT_CTRL_NS; | ||
71 | return; | ||
72 | case VDEC_H: | ||
73 | out_ctrl = VDEC_H_OUT_CTRL1; | ||
74 | out_ctrl_ns = VDEC_H_OUT_CTRL_NS; | ||
75 | return; | ||
76 | } | ||
77 | |||
78 | value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl, &tmp); | ||
79 | value &= 0xFFFFFF7F; /* clear BLUE_FIELD_EN */ | ||
80 | if (enable) | ||
81 | value |= 0x00000080; /* set BLUE_FIELD_EN */ | ||
82 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl, value); | ||
83 | |||
84 | value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl_ns, &tmp); | ||
85 | value &= 0xFFFFFF7F; | ||
86 | if (enable) | ||
87 | value |= 0x00000080; /* set BLUE_FIELD_EN */ | ||
88 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl_ns, value); | ||
89 | } | ||
90 | |||
91 | static int medusa_initialize_ntsc(struct cx25821_dev *dev) | ||
92 | { | ||
93 | int ret_val = 0; | ||
94 | int i = 0; | ||
95 | u32 value = 0; | ||
96 | u32 tmp = 0; | ||
97 | |||
98 | mutex_lock(&dev->lock); | ||
99 | |||
100 | for (i = 0; i < MAX_DECODERS; i++) { | ||
101 | /* set video format NTSC-M */ | ||
102 | value = | ||
103 | cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), | ||
104 | &tmp); | ||
105 | value &= 0xFFFFFFF0; | ||
106 | /* enable the fast locking mode bit[16] */ | ||
107 | value |= 0x10001; | ||
108 | ret_val = | ||
109 | cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), | ||
110 | value); | ||
111 | |||
112 | /* resolution NTSC 720x480 */ | ||
113 | value = | ||
114 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
115 | HORIZ_TIM_CTRL + (0x200 * i), &tmp); | ||
116 | value &= 0x00C00C00; | ||
117 | value |= 0x612D0074; | ||
118 | ret_val = | ||
119 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
120 | HORIZ_TIM_CTRL + (0x200 * i), value); | ||
121 | |||
122 | value = | ||
123 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
124 | VERT_TIM_CTRL + (0x200 * i), &tmp); | ||
125 | value &= 0x00C00C00; | ||
126 | value |= 0x1C1E001A; /* vblank_cnt + 2 to get camera ID */ | ||
127 | ret_val = | ||
128 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
129 | VERT_TIM_CTRL + (0x200 * i), value); | ||
130 | |||
131 | /* chroma subcarrier step size */ | ||
132 | ret_val = | ||
133 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
134 | SC_STEP_SIZE + (0x200 * i), 0x43E00000); | ||
135 | |||
136 | /* enable VIP optional active */ | ||
137 | value = | ||
138 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
139 | OUT_CTRL_NS + (0x200 * i), &tmp); | ||
140 | value &= 0xFFFBFFFF; | ||
141 | value |= 0x00040000; | ||
142 | ret_val = | ||
143 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
144 | OUT_CTRL_NS + (0x200 * i), value); | ||
145 | |||
146 | /* enable VIP optional active (VIP_OPT_AL) for direct output. */ | ||
147 | value = | ||
148 | cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), | ||
149 | &tmp); | ||
150 | value &= 0xFFFBFFFF; | ||
151 | value |= 0x00040000; | ||
152 | ret_val = | ||
153 | cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), | ||
154 | value); | ||
155 | |||
156 | /* | ||
157 | * clear VPRES_VERT_EN bit, fixes the chroma run away problem | ||
158 | * when the input switching rate < 16 fields | ||
159 | */ | ||
160 | value = | ||
161 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
162 | MISC_TIM_CTRL + (0x200 * i), &tmp); | ||
163 | /* disable special play detection */ | ||
164 | value = setBitAtPos(value, 14); | ||
165 | value = clearBitAtPos(value, 15); | ||
166 | ret_val = | ||
167 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
168 | MISC_TIM_CTRL + (0x200 * i), value); | ||
169 | |||
170 | /* set vbi_gate_en to 0 */ | ||
171 | value = | ||
172 | cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), | ||
173 | &tmp); | ||
174 | value = clearBitAtPos(value, 29); | ||
175 | ret_val = | ||
176 | cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), | ||
177 | value); | ||
178 | |||
179 | /* Enable the generation of blue field output if no video */ | ||
180 | medusa_enable_bluefield_output(dev, i, 1); | ||
181 | } | ||
182 | |||
183 | for (i = 0; i < MAX_ENCODERS; i++) { | ||
184 | /* NTSC hclock */ | ||
185 | value = | ||
186 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
187 | DENC_A_REG_1 + (0x100 * i), &tmp); | ||
188 | value &= 0xF000FC00; | ||
189 | value |= 0x06B402D0; | ||
190 | ret_val = | ||
191 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
192 | DENC_A_REG_1 + (0x100 * i), value); | ||
193 | |||
194 | /* burst begin and burst end */ | ||
195 | value = | ||
196 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
197 | DENC_A_REG_2 + (0x100 * i), &tmp); | ||
198 | value &= 0xFF000000; | ||
199 | value |= 0x007E9054; | ||
200 | ret_val = | ||
201 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
202 | DENC_A_REG_2 + (0x100 * i), value); | ||
203 | |||
204 | value = | ||
205 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
206 | DENC_A_REG_3 + (0x100 * i), &tmp); | ||
207 | value &= 0xFC00FE00; | ||
208 | value |= 0x00EC00F0; | ||
209 | ret_val = | ||
210 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
211 | DENC_A_REG_3 + (0x100 * i), value); | ||
212 | |||
213 | /* set NTSC vblank, no phase alternation, 7.5 IRE pedestal */ | ||
214 | value = | ||
215 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
216 | DENC_A_REG_4 + (0x100 * i), &tmp); | ||
217 | value &= 0x00FCFFFF; | ||
218 | value |= 0x13020000; | ||
219 | ret_val = | ||
220 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
221 | DENC_A_REG_4 + (0x100 * i), value); | ||
222 | |||
223 | value = | ||
224 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
225 | DENC_A_REG_5 + (0x100 * i), &tmp); | ||
226 | value &= 0xFFFF0000; | ||
227 | value |= 0x0000E575; | ||
228 | ret_val = | ||
229 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
230 | DENC_A_REG_5 + (0x100 * i), value); | ||
231 | |||
232 | ret_val = | ||
233 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
234 | DENC_A_REG_6 + (0x100 * i), 0x009A89C1); | ||
235 | |||
236 | /* Subcarrier Increment */ | ||
237 | ret_val = | ||
238 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
239 | DENC_A_REG_7 + (0x100 * i), 0x21F07C1F); | ||
240 | } | ||
241 | |||
242 | /* set picture resolutions */ | ||
243 | /* 0 - 720 */ | ||
244 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0); | ||
245 | /* 0 - 480 */ | ||
246 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0); | ||
247 | |||
248 | /* set Bypass input format to NTSC 525 lines */ | ||
249 | value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp); | ||
250 | value |= 0x00080200; | ||
251 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value); | ||
252 | |||
253 | mutex_unlock(&dev->lock); | ||
254 | |||
255 | return ret_val; | ||
256 | } | ||
257 | |||
258 | static int medusa_PALCombInit(struct cx25821_dev *dev, int dec) | ||
259 | { | ||
260 | int ret_val = -1; | ||
261 | u32 value = 0, tmp = 0; | ||
262 | |||
263 | /* Setup for 2D threshold */ | ||
264 | ret_val = | ||
265 | cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFS_CFG + (0x200 * dec), | ||
266 | 0x20002861); | ||
267 | ret_val = | ||
268 | cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFD_CFG + (0x200 * dec), | ||
269 | 0x20002861); | ||
270 | ret_val = | ||
271 | cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_LF_CFG + (0x200 * dec), | ||
272 | 0x200A1023); | ||
273 | |||
274 | /* Setup flat chroma and luma thresholds */ | ||
275 | value = | ||
276 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
277 | COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp); | ||
278 | value &= 0x06230000; | ||
279 | ret_val = | ||
280 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
281 | COMB_FLAT_THRESH_CTRL + (0x200 * dec), value); | ||
282 | |||
283 | /* set comb 2D blend */ | ||
284 | ret_val = | ||
285 | cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_BLEND + (0x200 * dec), | ||
286 | 0x210F0F0F); | ||
287 | |||
288 | /* COMB MISC CONTROL */ | ||
289 | ret_val = | ||
290 | cx25821_i2c_write(&dev->i2c_bus[0], COMB_MISC_CTRL + (0x200 * dec), | ||
291 | 0x41120A7F); | ||
292 | |||
293 | return ret_val; | ||
294 | } | ||
295 | |||
296 | static int medusa_initialize_pal(struct cx25821_dev *dev) | ||
297 | { | ||
298 | int ret_val = 0; | ||
299 | int i = 0; | ||
300 | u32 value = 0; | ||
301 | u32 tmp = 0; | ||
302 | |||
303 | mutex_lock(&dev->lock); | ||
304 | |||
305 | for (i = 0; i < MAX_DECODERS; i++) { | ||
306 | /* set video format PAL-BDGHI */ | ||
307 | value = | ||
308 | cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), | ||
309 | &tmp); | ||
310 | value &= 0xFFFFFFF0; | ||
311 | /* enable the fast locking mode bit[16] */ | ||
312 | value |= 0x10004; | ||
313 | ret_val = | ||
314 | cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), | ||
315 | value); | ||
316 | |||
317 | /* resolution PAL 720x576 */ | ||
318 | value = | ||
319 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
320 | HORIZ_TIM_CTRL + (0x200 * i), &tmp); | ||
321 | value &= 0x00C00C00; | ||
322 | value |= 0x632D007D; | ||
323 | ret_val = | ||
324 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
325 | HORIZ_TIM_CTRL + (0x200 * i), value); | ||
326 | |||
327 | /* vblank656_cnt=x26, vactive_cnt=240h, vblank_cnt=x24 */ | ||
328 | value = | ||
329 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
330 | VERT_TIM_CTRL + (0x200 * i), &tmp); | ||
331 | value &= 0x00C00C00; | ||
332 | value |= 0x28240026; /* vblank_cnt + 2 to get camera ID */ | ||
333 | ret_val = | ||
334 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
335 | VERT_TIM_CTRL + (0x200 * i), value); | ||
336 | |||
337 | /* chroma subcarrier step size */ | ||
338 | ret_val = | ||
339 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
340 | SC_STEP_SIZE + (0x200 * i), 0x5411E2D0); | ||
341 | |||
342 | /* enable VIP optional active */ | ||
343 | value = | ||
344 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
345 | OUT_CTRL_NS + (0x200 * i), &tmp); | ||
346 | value &= 0xFFFBFFFF; | ||
347 | value |= 0x00040000; | ||
348 | ret_val = | ||
349 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
350 | OUT_CTRL_NS + (0x200 * i), value); | ||
351 | |||
352 | /* enable VIP optional active (VIP_OPT_AL) for direct output. */ | ||
353 | value = | ||
354 | cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), | ||
355 | &tmp); | ||
356 | value &= 0xFFFBFFFF; | ||
357 | value |= 0x00040000; | ||
358 | ret_val = | ||
359 | cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), | ||
360 | value); | ||
361 | |||
362 | /* | ||
363 | * clear VPRES_VERT_EN bit, fixes the chroma run away problem | ||
364 | * when the input switching rate < 16 fields | ||
365 | */ | ||
366 | value = | ||
367 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
368 | MISC_TIM_CTRL + (0x200 * i), &tmp); | ||
369 | /* disable special play detection */ | ||
370 | value = setBitAtPos(value, 14); | ||
371 | value = clearBitAtPos(value, 15); | ||
372 | ret_val = | ||
373 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
374 | MISC_TIM_CTRL + (0x200 * i), value); | ||
375 | |||
376 | /* set vbi_gate_en to 0 */ | ||
377 | value = | ||
378 | cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), | ||
379 | &tmp); | ||
380 | value = clearBitAtPos(value, 29); | ||
381 | ret_val = | ||
382 | cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), | ||
383 | value); | ||
384 | |||
385 | medusa_PALCombInit(dev, i); | ||
386 | |||
387 | /* Enable the generation of blue field output if no video */ | ||
388 | medusa_enable_bluefield_output(dev, i, 1); | ||
389 | } | ||
390 | |||
391 | for (i = 0; i < MAX_ENCODERS; i++) { | ||
392 | /* PAL hclock */ | ||
393 | value = | ||
394 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
395 | DENC_A_REG_1 + (0x100 * i), &tmp); | ||
396 | value &= 0xF000FC00; | ||
397 | value |= 0x06C002D0; | ||
398 | ret_val = | ||
399 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
400 | DENC_A_REG_1 + (0x100 * i), value); | ||
401 | |||
402 | /* burst begin and burst end */ | ||
403 | value = | ||
404 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
405 | DENC_A_REG_2 + (0x100 * i), &tmp); | ||
406 | value &= 0xFF000000; | ||
407 | value |= 0x007E9754; | ||
408 | ret_val = | ||
409 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
410 | DENC_A_REG_2 + (0x100 * i), value); | ||
411 | |||
412 | /* hblank and vactive */ | ||
413 | value = | ||
414 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
415 | DENC_A_REG_3 + (0x100 * i), &tmp); | ||
416 | value &= 0xFC00FE00; | ||
417 | value |= 0x00FC0120; | ||
418 | ret_val = | ||
419 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
420 | DENC_A_REG_3 + (0x100 * i), value); | ||
421 | |||
422 | /* set PAL vblank, phase alternation, 0 IRE pedestal */ | ||
423 | value = | ||
424 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
425 | DENC_A_REG_4 + (0x100 * i), &tmp); | ||
426 | value &= 0x00FCFFFF; | ||
427 | value |= 0x14010000; | ||
428 | ret_val = | ||
429 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
430 | DENC_A_REG_4 + (0x100 * i), value); | ||
431 | |||
432 | value = | ||
433 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
434 | DENC_A_REG_5 + (0x100 * i), &tmp); | ||
435 | value &= 0xFFFF0000; | ||
436 | value |= 0x0000F078; | ||
437 | ret_val = | ||
438 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
439 | DENC_A_REG_5 + (0x100 * i), value); | ||
440 | |||
441 | ret_val = | ||
442 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
443 | DENC_A_REG_6 + (0x100 * i), 0x00A493CF); | ||
444 | |||
445 | /* Subcarrier Increment */ | ||
446 | ret_val = | ||
447 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
448 | DENC_A_REG_7 + (0x100 * i), 0x2A098ACB); | ||
449 | } | ||
450 | |||
451 | /* set picture resolutions */ | ||
452 | /* 0 - 720 */ | ||
453 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], HSCALE_CTRL, 0x0); | ||
454 | /* 0 - 576 */ | ||
455 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL, 0x0); | ||
456 | |||
457 | /* set Bypass input format to PAL 625 lines */ | ||
458 | value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp); | ||
459 | value &= 0xFFF7FDFF; | ||
460 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value); | ||
461 | |||
462 | mutex_unlock(&dev->lock); | ||
463 | |||
464 | return ret_val; | ||
465 | } | ||
466 | |||
467 | int medusa_set_videostandard(struct cx25821_dev *dev) | ||
468 | { | ||
469 | int status = STATUS_SUCCESS; | ||
470 | u32 value = 0, tmp = 0; | ||
471 | |||
472 | if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK) | ||
473 | status = medusa_initialize_pal(dev); | ||
474 | else | ||
475 | status = medusa_initialize_ntsc(dev); | ||
476 | |||
477 | /* Enable DENC_A output */ | ||
478 | value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_A_REG_4, &tmp); | ||
479 | value = setBitAtPos(value, 4); | ||
480 | status = cx25821_i2c_write(&dev->i2c_bus[0], DENC_A_REG_4, value); | ||
481 | |||
482 | /* Enable DENC_B output */ | ||
483 | value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_B_REG_4, &tmp); | ||
484 | value = setBitAtPos(value, 4); | ||
485 | status = cx25821_i2c_write(&dev->i2c_bus[0], DENC_B_REG_4, value); | ||
486 | |||
487 | return status; | ||
488 | } | ||
489 | |||
490 | void medusa_set_resolution(struct cx25821_dev *dev, int width, | ||
491 | int decoder_select) | ||
492 | { | ||
493 | int decoder = 0; | ||
494 | int decoder_count = 0; | ||
495 | int ret_val = 0; | ||
496 | u32 hscale = 0x0; | ||
497 | u32 vscale = 0x0; | ||
498 | const int MAX_WIDTH = 720; | ||
499 | |||
500 | mutex_lock(&dev->lock); | ||
501 | |||
502 | /* validate the width - cannot be negative */ | ||
503 | if (width > MAX_WIDTH) { | ||
504 | pr_info("%s(): width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n", | ||
505 | __func__, width, MAX_WIDTH); | ||
506 | width = MAX_WIDTH; | ||
507 | } | ||
508 | |||
509 | if (decoder_select <= 7 && decoder_select >= 0) { | ||
510 | decoder = decoder_select; | ||
511 | decoder_count = decoder_select + 1; | ||
512 | } else { | ||
513 | decoder = 0; | ||
514 | decoder_count = _num_decoders; | ||
515 | } | ||
516 | |||
517 | switch (width) { | ||
518 | case 320: | ||
519 | hscale = 0x13E34B; | ||
520 | vscale = 0x0; | ||
521 | break; | ||
522 | |||
523 | case 352: | ||
524 | hscale = 0x10A273; | ||
525 | vscale = 0x0; | ||
526 | break; | ||
527 | |||
528 | case 176: | ||
529 | hscale = 0x3115B2; | ||
530 | vscale = 0x1E00; | ||
531 | break; | ||
532 | |||
533 | case 160: | ||
534 | hscale = 0x378D84; | ||
535 | vscale = 0x1E00; | ||
536 | break; | ||
537 | |||
538 | default: /* 720 */ | ||
539 | hscale = 0x0; | ||
540 | vscale = 0x0; | ||
541 | break; | ||
542 | } | ||
543 | |||
544 | for (; decoder < decoder_count; decoder++) { | ||
545 | /* write scaling values for each decoder */ | ||
546 | ret_val = | ||
547 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
548 | HSCALE_CTRL + (0x200 * decoder), hscale); | ||
549 | ret_val = | ||
550 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
551 | VSCALE_CTRL + (0x200 * decoder), vscale); | ||
552 | } | ||
553 | |||
554 | mutex_unlock(&dev->lock); | ||
555 | } | ||
556 | |||
557 | static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder, | ||
558 | int duration) | ||
559 | { | ||
560 | int ret_val = 0; | ||
561 | u32 fld_cnt = 0; | ||
562 | u32 tmp = 0; | ||
563 | u32 disp_cnt_reg = DISP_AB_CNT; | ||
564 | |||
565 | mutex_lock(&dev->lock); | ||
566 | |||
567 | /* no support */ | ||
568 | if (decoder < VDEC_A && decoder > VDEC_H) { | ||
569 | mutex_unlock(&dev->lock); | ||
570 | return; | ||
571 | } | ||
572 | |||
573 | switch (decoder) { | ||
574 | default: | ||
575 | break; | ||
576 | case VDEC_C: | ||
577 | case VDEC_D: | ||
578 | disp_cnt_reg = DISP_CD_CNT; | ||
579 | break; | ||
580 | case VDEC_E: | ||
581 | case VDEC_F: | ||
582 | disp_cnt_reg = DISP_EF_CNT; | ||
583 | break; | ||
584 | case VDEC_G: | ||
585 | case VDEC_H: | ||
586 | disp_cnt_reg = DISP_GH_CNT; | ||
587 | break; | ||
588 | } | ||
589 | |||
590 | _display_field_cnt[decoder] = duration; | ||
591 | |||
592 | /* update hardware */ | ||
593 | fld_cnt = cx25821_i2c_read(&dev->i2c_bus[0], disp_cnt_reg, &tmp); | ||
594 | |||
595 | if (!(decoder % 2)) { /* EVEN decoder */ | ||
596 | fld_cnt &= 0xFFFF0000; | ||
597 | fld_cnt |= duration; | ||
598 | } else { | ||
599 | fld_cnt &= 0x0000FFFF; | ||
600 | fld_cnt |= ((u32) duration) << 16; | ||
601 | } | ||
602 | |||
603 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], disp_cnt_reg, fld_cnt); | ||
604 | |||
605 | mutex_unlock(&dev->lock); | ||
606 | } | ||
607 | |||
608 | /* Map to Medusa register setting */ | ||
609 | static int mapM(int srcMin, | ||
610 | int srcMax, int srcVal, int dstMin, int dstMax, int *dstVal) | ||
611 | { | ||
612 | int numerator; | ||
613 | int denominator; | ||
614 | int quotient; | ||
615 | |||
616 | if ((srcMin == srcMax) || (srcVal < srcMin) || (srcVal > srcMax)) | ||
617 | return -1; | ||
618 | /* | ||
619 | * This is the overall expression used: | ||
620 | * *dstVal = | ||
621 | * (srcVal - srcMin)*(dstMax - dstMin) / (srcMax - srcMin) + dstMin; | ||
622 | * but we need to account for rounding so below we use the modulus | ||
623 | * operator to find the remainder and increment if necessary. | ||
624 | */ | ||
625 | numerator = (srcVal - srcMin) * (dstMax - dstMin); | ||
626 | denominator = srcMax - srcMin; | ||
627 | quotient = numerator / denominator; | ||
628 | |||
629 | if (2 * (numerator % denominator) >= denominator) | ||
630 | quotient++; | ||
631 | |||
632 | *dstVal = quotient + dstMin; | ||
633 | |||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | static unsigned long convert_to_twos(long numeric, unsigned long bits_len) | ||
638 | { | ||
639 | unsigned char temp; | ||
640 | |||
641 | if (numeric >= 0) | ||
642 | return numeric; | ||
643 | else { | ||
644 | temp = ~(abs(numeric) & 0xFF); | ||
645 | temp += 1; | ||
646 | return temp; | ||
647 | } | ||
648 | } | ||
649 | |||
650 | int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder) | ||
651 | { | ||
652 | int ret_val = 0; | ||
653 | int value = 0; | ||
654 | u32 val = 0, tmp = 0; | ||
655 | |||
656 | mutex_lock(&dev->lock); | ||
657 | if ((brightness > VIDEO_PROCAMP_MAX) | ||
658 | || (brightness < VIDEO_PROCAMP_MIN)) { | ||
659 | mutex_unlock(&dev->lock); | ||
660 | return -1; | ||
661 | } | ||
662 | ret_val = | ||
663 | mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness, | ||
664 | SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value); | ||
665 | value = convert_to_twos(value, 8); | ||
666 | val = | ||
667 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
668 | VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp); | ||
669 | val &= 0xFFFFFF00; | ||
670 | ret_val |= | ||
671 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
672 | VDEC_A_BRITE_CTRL + (0x200 * decoder), | ||
673 | val | value); | ||
674 | mutex_unlock(&dev->lock); | ||
675 | return ret_val; | ||
676 | } | ||
677 | |||
678 | int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder) | ||
679 | { | ||
680 | int ret_val = 0; | ||
681 | int value = 0; | ||
682 | u32 val = 0, tmp = 0; | ||
683 | |||
684 | mutex_lock(&dev->lock); | ||
685 | |||
686 | if ((contrast > VIDEO_PROCAMP_MAX) || (contrast < VIDEO_PROCAMP_MIN)) { | ||
687 | mutex_unlock(&dev->lock); | ||
688 | return -1; | ||
689 | } | ||
690 | |||
691 | ret_val = | ||
692 | mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast, | ||
693 | UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); | ||
694 | val = | ||
695 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
696 | VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp); | ||
697 | val &= 0xFFFFFF00; | ||
698 | ret_val |= | ||
699 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
700 | VDEC_A_CNTRST_CTRL + (0x200 * decoder), | ||
701 | val | value); | ||
702 | |||
703 | mutex_unlock(&dev->lock); | ||
704 | return ret_val; | ||
705 | } | ||
706 | |||
707 | int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder) | ||
708 | { | ||
709 | int ret_val = 0; | ||
710 | int value = 0; | ||
711 | u32 val = 0, tmp = 0; | ||
712 | |||
713 | mutex_lock(&dev->lock); | ||
714 | |||
715 | if ((hue > VIDEO_PROCAMP_MAX) || (hue < VIDEO_PROCAMP_MIN)) { | ||
716 | mutex_unlock(&dev->lock); | ||
717 | return -1; | ||
718 | } | ||
719 | |||
720 | ret_val = | ||
721 | mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue, SIGNED_BYTE_MIN, | ||
722 | SIGNED_BYTE_MAX, &value); | ||
723 | |||
724 | value = convert_to_twos(value, 8); | ||
725 | val = | ||
726 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
727 | VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp); | ||
728 | val &= 0xFFFFFF00; | ||
729 | |||
730 | ret_val |= | ||
731 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
732 | VDEC_A_HUE_CTRL + (0x200 * decoder), val | value); | ||
733 | |||
734 | mutex_unlock(&dev->lock); | ||
735 | return ret_val; | ||
736 | } | ||
737 | |||
738 | int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder) | ||
739 | { | ||
740 | int ret_val = 0; | ||
741 | int value = 0; | ||
742 | u32 val = 0, tmp = 0; | ||
743 | |||
744 | mutex_lock(&dev->lock); | ||
745 | |||
746 | if ((saturation > VIDEO_PROCAMP_MAX) | ||
747 | || (saturation < VIDEO_PROCAMP_MIN)) { | ||
748 | mutex_unlock(&dev->lock); | ||
749 | return -1; | ||
750 | } | ||
751 | |||
752 | ret_val = | ||
753 | mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation, | ||
754 | UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); | ||
755 | |||
756 | val = | ||
757 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
758 | VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp); | ||
759 | val &= 0xFFFFFF00; | ||
760 | ret_val |= | ||
761 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
762 | VDEC_A_USAT_CTRL + (0x200 * decoder), | ||
763 | val | value); | ||
764 | |||
765 | val = | ||
766 | cx25821_i2c_read(&dev->i2c_bus[0], | ||
767 | VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp); | ||
768 | val &= 0xFFFFFF00; | ||
769 | ret_val |= | ||
770 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
771 | VDEC_A_VSAT_CTRL + (0x200 * decoder), | ||
772 | val | value); | ||
773 | |||
774 | mutex_unlock(&dev->lock); | ||
775 | return ret_val; | ||
776 | } | ||
777 | |||
778 | /* Program the display sequence and monitor output. */ | ||
779 | |||
780 | int medusa_video_init(struct cx25821_dev *dev) | ||
781 | { | ||
782 | u32 value = 0, tmp = 0; | ||
783 | int ret_val = 0; | ||
784 | int i = 0; | ||
785 | |||
786 | mutex_lock(&dev->lock); | ||
787 | |||
788 | _num_decoders = dev->_max_num_decoders; | ||
789 | |||
790 | /* disable Auto source selection on all video decoders */ | ||
791 | value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp); | ||
792 | value &= 0xFFFFF0FF; | ||
793 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value); | ||
794 | |||
795 | if (ret_val < 0) | ||
796 | goto error; | ||
797 | |||
798 | /* Turn off Master source switch enable */ | ||
799 | value = cx25821_i2c_read(&dev->i2c_bus[0], MON_A_CTRL, &tmp); | ||
800 | value &= 0xFFFFFFDF; | ||
801 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], MON_A_CTRL, value); | ||
802 | |||
803 | if (ret_val < 0) | ||
804 | goto error; | ||
805 | |||
806 | mutex_unlock(&dev->lock); | ||
807 | |||
808 | for (i = 0; i < _num_decoders; i++) | ||
809 | medusa_set_decoderduration(dev, i, _display_field_cnt[i]); | ||
810 | |||
811 | mutex_lock(&dev->lock); | ||
812 | |||
813 | /* Select monitor as DENC A input, power up the DAC */ | ||
814 | value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_AB_CTRL, &tmp); | ||
815 | value &= 0xFF70FF70; | ||
816 | value |= 0x00090008; /* set en_active */ | ||
817 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], DENC_AB_CTRL, value); | ||
818 | |||
819 | if (ret_val < 0) | ||
820 | goto error; | ||
821 | |||
822 | /* enable input is VIP/656 */ | ||
823 | value = cx25821_i2c_read(&dev->i2c_bus[0], BYP_AB_CTRL, &tmp); | ||
824 | value |= 0x00040100; /* enable VIP */ | ||
825 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value); | ||
826 | |||
827 | if (ret_val < 0) | ||
828 | goto error; | ||
829 | |||
830 | /* select AFE clock to output mode */ | ||
831 | value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp); | ||
832 | value &= 0x83FFFFFF; | ||
833 | ret_val = | ||
834 | cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, | ||
835 | value | 0x10000000); | ||
836 | |||
837 | if (ret_val < 0) | ||
838 | goto error; | ||
839 | |||
840 | /* Turn on all of the data out and control output pins. */ | ||
841 | value = cx25821_i2c_read(&dev->i2c_bus[0], PIN_OE_CTRL, &tmp); | ||
842 | value &= 0xFEF0FE00; | ||
843 | if (_num_decoders == MAX_DECODERS) { | ||
844 | /* | ||
845 | * Note: The octal board does not support control pins(bit16-19) | ||
846 | * These bits are ignored in the octal board. | ||
847 | * | ||
848 | * disable VDEC A-C port, default to Mobilygen Interface | ||
849 | */ | ||
850 | value |= 0x010001F8; | ||
851 | } else { | ||
852 | /* disable VDEC A-C port, default to Mobilygen Interface */ | ||
853 | value |= 0x010F0108; | ||
854 | } | ||
855 | |||
856 | value |= 7; | ||
857 | ret_val = cx25821_i2c_write(&dev->i2c_bus[0], PIN_OE_CTRL, value); | ||
858 | |||
859 | if (ret_val < 0) | ||
860 | goto error; | ||
861 | |||
862 | |||
863 | mutex_unlock(&dev->lock); | ||
864 | |||
865 | ret_val = medusa_set_videostandard(dev); | ||
866 | |||
867 | return ret_val; | ||
868 | |||
869 | error: | ||
870 | mutex_unlock(&dev->lock); | ||
871 | return ret_val; | ||
872 | } | ||
diff --git a/drivers/media/video/cx25821/cx25821-medusa-video.h b/drivers/media/video/cx25821/cx25821-medusa-video.h new file mode 100644 index 000000000000..6175e0961855 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-medusa-video.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #ifndef _MEDUSA_VIDEO_H | ||
24 | #define _MEDUSA_VIDEO_H | ||
25 | |||
26 | #include "cx25821-medusa-defines.h" | ||
27 | |||
28 | /* Color control constants */ | ||
29 | #define VIDEO_PROCAMP_MIN 0 | ||
30 | #define VIDEO_PROCAMP_MAX 10000 | ||
31 | #define UNSIGNED_BYTE_MIN 0 | ||
32 | #define UNSIGNED_BYTE_MAX 0xFF | ||
33 | #define SIGNED_BYTE_MIN -128 | ||
34 | #define SIGNED_BYTE_MAX 127 | ||
35 | |||
36 | /* Default video color settings */ | ||
37 | #define SHARPNESS_DEFAULT 50 | ||
38 | #define SATURATION_DEFAULT 5000 | ||
39 | #define BRIGHTNESS_DEFAULT 6200 | ||
40 | #define CONTRAST_DEFAULT 5000 | ||
41 | #define HUE_DEFAULT 5000 | ||
42 | |||
43 | unsigned short _num_decoders; | ||
44 | unsigned short _num_cameras; | ||
45 | |||
46 | unsigned int _video_standard; | ||
47 | int _display_field_cnt[MAX_DECODERS]; | ||
48 | |||
49 | #endif | ||
diff --git a/drivers/media/video/cx25821/cx25821-reg.h b/drivers/media/video/cx25821/cx25821-reg.h new file mode 100644 index 000000000000..a3fc25a4dc0b --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-reg.h | |||
@@ -0,0 +1,1592 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #ifndef __CX25821_REGISTERS__ | ||
24 | #define __CX25821_REGISTERS__ | ||
25 | |||
26 | /* Risc Instructions */ | ||
27 | #define RISC_CNT_INC 0x00010000 | ||
28 | #define RISC_CNT_RESET 0x00030000 | ||
29 | #define RISC_IRQ1 0x01000000 | ||
30 | #define RISC_IRQ2 0x02000000 | ||
31 | #define RISC_EOL 0x04000000 | ||
32 | #define RISC_SOL 0x08000000 | ||
33 | #define RISC_WRITE 0x10000000 | ||
34 | #define RISC_SKIP 0x20000000 | ||
35 | #define RISC_JUMP 0x70000000 | ||
36 | #define RISC_SYNC 0x80000000 | ||
37 | #define RISC_RESYNC 0x80008000 | ||
38 | #define RISC_READ 0x90000000 | ||
39 | #define RISC_WRITERM 0xB0000000 | ||
40 | #define RISC_WRITECM 0xC0000000 | ||
41 | #define RISC_WRITECR 0xD0000000 | ||
42 | #define RISC_WRITEC 0x50000000 | ||
43 | #define RISC_READC 0xA0000000 | ||
44 | |||
45 | #define RISC_SYNC_ODD 0x00000000 | ||
46 | #define RISC_SYNC_EVEN 0x00000200 | ||
47 | #define RISC_SYNC_ODD_VBI 0x00000006 | ||
48 | #define RISC_SYNC_EVEN_VBI 0x00000207 | ||
49 | #define RISC_NOOP 0xF0000000 | ||
50 | |||
51 | /***************************************************************************** | ||
52 | * ASB SRAM | ||
53 | *****************************************************************************/ | ||
54 | #define TX_SRAM 0x000000 /* Transmit SRAM */ | ||
55 | |||
56 | /*****************************************************************************/ | ||
57 | #define RX_RAM 0x010000 /* Receive SRAM */ | ||
58 | |||
59 | /***************************************************************************** | ||
60 | * Application Layer (AL) | ||
61 | *****************************************************************************/ | ||
62 | #define DEV_CNTRL2 0x040000 /* Device control */ | ||
63 | #define FLD_RUN_RISC 0x00000020 | ||
64 | |||
65 | /* ***************************************************************************** */ | ||
66 | #define PCI_INT_MSK 0x040010 /* PCI interrupt mask */ | ||
67 | #define PCI_INT_STAT 0x040014 /* PCI interrupt status */ | ||
68 | #define PCI_INT_MSTAT 0x040018 /* PCI interrupt masked status */ | ||
69 | #define FLD_HAMMERHEAD_INT (1 << 27) | ||
70 | #define FLD_UART_INT (1 << 26) | ||
71 | #define FLD_IRQN_INT (1 << 25) | ||
72 | #define FLD_TM_INT (1 << 28) | ||
73 | #define FLD_I2C_3_RACK (1 << 27) | ||
74 | #define FLD_I2C_3_INT (1 << 26) | ||
75 | #define FLD_I2C_2_RACK (1 << 25) | ||
76 | #define FLD_I2C_2_INT (1 << 24) | ||
77 | #define FLD_I2C_1_RACK (1 << 23) | ||
78 | #define FLD_I2C_1_INT (1 << 22) | ||
79 | |||
80 | #define FLD_APB_DMA_BERR_INT (1 << 21) | ||
81 | #define FLD_AL_WR_BERR_INT (1 << 20) | ||
82 | #define FLD_AL_RD_BERR_INT (1 << 19) | ||
83 | #define FLD_RISC_WR_BERR_INT (1 << 18) | ||
84 | #define FLD_RISC_RD_BERR_INT (1 << 17) | ||
85 | |||
86 | #define FLD_VID_I_INT (1 << 8) | ||
87 | #define FLD_VID_H_INT (1 << 7) | ||
88 | #define FLD_VID_G_INT (1 << 6) | ||
89 | #define FLD_VID_F_INT (1 << 5) | ||
90 | #define FLD_VID_E_INT (1 << 4) | ||
91 | #define FLD_VID_D_INT (1 << 3) | ||
92 | #define FLD_VID_C_INT (1 << 2) | ||
93 | #define FLD_VID_B_INT (1 << 1) | ||
94 | #define FLD_VID_A_INT (1 << 0) | ||
95 | |||
96 | /* ***************************************************************************** */ | ||
97 | #define VID_A_INT_MSK 0x040020 /* Video A interrupt mask */ | ||
98 | #define VID_A_INT_STAT 0x040024 /* Video A interrupt status */ | ||
99 | #define VID_A_INT_MSTAT 0x040028 /* Video A interrupt masked status */ | ||
100 | #define VID_A_INT_SSTAT 0x04002C /* Video A interrupt set status */ | ||
101 | |||
102 | /* ***************************************************************************** */ | ||
103 | #define VID_B_INT_MSK 0x040030 /* Video B interrupt mask */ | ||
104 | #define VID_B_INT_STAT 0x040034 /* Video B interrupt status */ | ||
105 | #define VID_B_INT_MSTAT 0x040038 /* Video B interrupt masked status */ | ||
106 | #define VID_B_INT_SSTAT 0x04003C /* Video B interrupt set status */ | ||
107 | |||
108 | /* ***************************************************************************** */ | ||
109 | #define VID_C_INT_MSK 0x040040 /* Video C interrupt mask */ | ||
110 | #define VID_C_INT_STAT 0x040044 /* Video C interrupt status */ | ||
111 | #define VID_C_INT_MSTAT 0x040048 /* Video C interrupt masked status */ | ||
112 | #define VID_C_INT_SSTAT 0x04004C /* Video C interrupt set status */ | ||
113 | |||
114 | /* ***************************************************************************** */ | ||
115 | #define VID_D_INT_MSK 0x040050 /* Video D interrupt mask */ | ||
116 | #define VID_D_INT_STAT 0x040054 /* Video D interrupt status */ | ||
117 | #define VID_D_INT_MSTAT 0x040058 /* Video D interrupt masked status */ | ||
118 | #define VID_D_INT_SSTAT 0x04005C /* Video D interrupt set status */ | ||
119 | |||
120 | /* ***************************************************************************** */ | ||
121 | #define VID_E_INT_MSK 0x040060 /* Video E interrupt mask */ | ||
122 | #define VID_E_INT_STAT 0x040064 /* Video E interrupt status */ | ||
123 | #define VID_E_INT_MSTAT 0x040068 /* Video E interrupt masked status */ | ||
124 | #define VID_E_INT_SSTAT 0x04006C /* Video E interrupt set status */ | ||
125 | |||
126 | /* ***************************************************************************** */ | ||
127 | #define VID_F_INT_MSK 0x040070 /* Video F interrupt mask */ | ||
128 | #define VID_F_INT_STAT 0x040074 /* Video F interrupt status */ | ||
129 | #define VID_F_INT_MSTAT 0x040078 /* Video F interrupt masked status */ | ||
130 | #define VID_F_INT_SSTAT 0x04007C /* Video F interrupt set status */ | ||
131 | |||
132 | /* ***************************************************************************** */ | ||
133 | #define VID_G_INT_MSK 0x040080 /* Video G interrupt mask */ | ||
134 | #define VID_G_INT_STAT 0x040084 /* Video G interrupt status */ | ||
135 | #define VID_G_INT_MSTAT 0x040088 /* Video G interrupt masked status */ | ||
136 | #define VID_G_INT_SSTAT 0x04008C /* Video G interrupt set status */ | ||
137 | |||
138 | /* ***************************************************************************** */ | ||
139 | #define VID_H_INT_MSK 0x040090 /* Video H interrupt mask */ | ||
140 | #define VID_H_INT_STAT 0x040094 /* Video H interrupt status */ | ||
141 | #define VID_H_INT_MSTAT 0x040098 /* Video H interrupt masked status */ | ||
142 | #define VID_H_INT_SSTAT 0x04009C /* Video H interrupt set status */ | ||
143 | |||
144 | /* ***************************************************************************** */ | ||
145 | #define VID_I_INT_MSK 0x0400A0 /* Video I interrupt mask */ | ||
146 | #define VID_I_INT_STAT 0x0400A4 /* Video I interrupt status */ | ||
147 | #define VID_I_INT_MSTAT 0x0400A8 /* Video I interrupt masked status */ | ||
148 | #define VID_I_INT_SSTAT 0x0400AC /* Video I interrupt set status */ | ||
149 | |||
150 | /* ***************************************************************************** */ | ||
151 | #define VID_J_INT_MSK 0x0400B0 /* Video J interrupt mask */ | ||
152 | #define VID_J_INT_STAT 0x0400B4 /* Video J interrupt status */ | ||
153 | #define VID_J_INT_MSTAT 0x0400B8 /* Video J interrupt masked status */ | ||
154 | #define VID_J_INT_SSTAT 0x0400BC /* Video J interrupt set status */ | ||
155 | |||
156 | #define FLD_VID_SRC_OPC_ERR 0x00020000 | ||
157 | #define FLD_VID_DST_OPC_ERR 0x00010000 | ||
158 | #define FLD_VID_SRC_SYNC 0x00002000 | ||
159 | #define FLD_VID_DST_SYNC 0x00001000 | ||
160 | #define FLD_VID_SRC_UF 0x00000200 | ||
161 | #define FLD_VID_DST_OF 0x00000100 | ||
162 | #define FLD_VID_SRC_RISC2 0x00000020 | ||
163 | #define FLD_VID_DST_RISC2 0x00000010 | ||
164 | #define FLD_VID_SRC_RISC1 0x00000002 | ||
165 | #define FLD_VID_DST_RISC1 0x00000001 | ||
166 | #define FLD_VID_SRC_ERRORS (FLD_VID_SRC_OPC_ERR | FLD_VID_SRC_SYNC | FLD_VID_SRC_UF) | ||
167 | #define FLD_VID_DST_ERRORS (FLD_VID_DST_OPC_ERR | FLD_VID_DST_SYNC | FLD_VID_DST_OF) | ||
168 | |||
169 | /* ***************************************************************************** */ | ||
170 | #define AUD_A_INT_MSK 0x0400C0 /* Audio Int interrupt mask */ | ||
171 | #define AUD_A_INT_STAT 0x0400C4 /* Audio Int interrupt status */ | ||
172 | #define AUD_A_INT_MSTAT 0x0400C8 /* Audio Int interrupt masked status */ | ||
173 | #define AUD_A_INT_SSTAT 0x0400CC /* Audio Int interrupt set status */ | ||
174 | |||
175 | /* ***************************************************************************** */ | ||
176 | #define AUD_B_INT_MSK 0x0400D0 /* Audio Int interrupt mask */ | ||
177 | #define AUD_B_INT_STAT 0x0400D4 /* Audio Int interrupt status */ | ||
178 | #define AUD_B_INT_MSTAT 0x0400D8 /* Audio Int interrupt masked status */ | ||
179 | #define AUD_B_INT_SSTAT 0x0400DC /* Audio Int interrupt set status */ | ||
180 | |||
181 | /* ***************************************************************************** */ | ||
182 | #define AUD_C_INT_MSK 0x0400E0 /* Audio Int interrupt mask */ | ||
183 | #define AUD_C_INT_STAT 0x0400E4 /* Audio Int interrupt status */ | ||
184 | #define AUD_C_INT_MSTAT 0x0400E8 /* Audio Int interrupt masked status */ | ||
185 | #define AUD_C_INT_SSTAT 0x0400EC /* Audio Int interrupt set status */ | ||
186 | |||
187 | /* ***************************************************************************** */ | ||
188 | #define AUD_D_INT_MSK 0x0400F0 /* Audio Int interrupt mask */ | ||
189 | #define AUD_D_INT_STAT 0x0400F4 /* Audio Int interrupt status */ | ||
190 | #define AUD_D_INT_MSTAT 0x0400F8 /* Audio Int interrupt masked status */ | ||
191 | #define AUD_D_INT_SSTAT 0x0400FC /* Audio Int interrupt set status */ | ||
192 | |||
193 | /* ***************************************************************************** */ | ||
194 | #define AUD_E_INT_MSK 0x040100 /* Audio Int interrupt mask */ | ||
195 | #define AUD_E_INT_STAT 0x040104 /* Audio Int interrupt status */ | ||
196 | #define AUD_E_INT_MSTAT 0x040108 /* Audio Int interrupt masked status */ | ||
197 | #define AUD_E_INT_SSTAT 0x04010C /* Audio Int interrupt set status */ | ||
198 | |||
199 | #define FLD_AUD_SRC_OPC_ERR 0x00020000 | ||
200 | #define FLD_AUD_DST_OPC_ERR 0x00010000 | ||
201 | #define FLD_AUD_SRC_SYNC 0x00002000 | ||
202 | #define FLD_AUD_DST_SYNC 0x00001000 | ||
203 | #define FLD_AUD_SRC_OF 0x00000200 | ||
204 | #define FLD_AUD_DST_OF 0x00000100 | ||
205 | #define FLD_AUD_SRC_RISCI2 0x00000020 | ||
206 | #define FLD_AUD_DST_RISCI2 0x00000010 | ||
207 | #define FLD_AUD_SRC_RISCI1 0x00000002 | ||
208 | #define FLD_AUD_DST_RISCI1 0x00000001 | ||
209 | |||
210 | /* ***************************************************************************** */ | ||
211 | #define MBIF_A_INT_MSK 0x040110 /* MBIF Int interrupt mask */ | ||
212 | #define MBIF_A_INT_STAT 0x040114 /* MBIF Int interrupt status */ | ||
213 | #define MBIF_A_INT_MSTAT 0x040118 /* MBIF Int interrupt masked status */ | ||
214 | #define MBIF_A_INT_SSTAT 0x04011C /* MBIF Int interrupt set status */ | ||
215 | |||
216 | /* ***************************************************************************** */ | ||
217 | #define MBIF_B_INT_MSK 0x040120 /* MBIF Int interrupt mask */ | ||
218 | #define MBIF_B_INT_STAT 0x040124 /* MBIF Int interrupt status */ | ||
219 | #define MBIF_B_INT_MSTAT 0x040128 /* MBIF Int interrupt masked status */ | ||
220 | #define MBIF_B_INT_SSTAT 0x04012C /* MBIF Int interrupt set status */ | ||
221 | |||
222 | #define FLD_MBIF_DST_OPC_ERR 0x00010000 | ||
223 | #define FLD_MBIF_DST_SYNC 0x00001000 | ||
224 | #define FLD_MBIF_DST_OF 0x00000100 | ||
225 | #define FLD_MBIF_DST_RISCI2 0x00000010 | ||
226 | #define FLD_MBIF_DST_RISCI1 0x00000001 | ||
227 | |||
228 | /* ***************************************************************************** */ | ||
229 | #define AUD_EXT_INT_MSK 0x040060 /* Audio Ext interrupt mask */ | ||
230 | #define AUD_EXT_INT_STAT 0x040064 /* Audio Ext interrupt status */ | ||
231 | #define AUD_EXT_INT_MSTAT 0x040068 /* Audio Ext interrupt masked status */ | ||
232 | #define AUD_EXT_INT_SSTAT 0x04006C /* Audio Ext interrupt set status */ | ||
233 | #define FLD_AUD_EXT_OPC_ERR 0x00010000 | ||
234 | #define FLD_AUD_EXT_SYNC 0x00001000 | ||
235 | #define FLD_AUD_EXT_OF 0x00000100 | ||
236 | #define FLD_AUD_EXT_RISCI2 0x00000010 | ||
237 | #define FLD_AUD_EXT_RISCI1 0x00000001 | ||
238 | |||
239 | /* ***************************************************************************** */ | ||
240 | #define GPIO_LO 0x110010 /* Lower of GPIO pins [31:0] */ | ||
241 | #define GPIO_HI 0x110014 /* Upper WORD of GPIO pins [47:31] */ | ||
242 | |||
243 | #define GPIO_LO_OE 0x110018 /* Lower of GPIO output enable [31:0] */ | ||
244 | #define GPIO_HI_OE 0x11001C /* Upper word of GPIO output enable [47:32] */ | ||
245 | |||
246 | #define GPIO_LO_INT_MSK 0x11003C /* GPIO interrupt mask */ | ||
247 | #define GPIO_LO_INT_STAT 0x110044 /* GPIO interrupt status */ | ||
248 | #define GPIO_LO_INT_MSTAT 0x11004C /* GPIO interrupt masked status */ | ||
249 | #define GPIO_LO_ISM_SNS 0x110054 /* GPIO interrupt sensitivity */ | ||
250 | #define GPIO_LO_ISM_POL 0x11005C /* GPIO interrupt polarity */ | ||
251 | |||
252 | #define GPIO_HI_INT_MSK 0x110040 /* GPIO interrupt mask */ | ||
253 | #define GPIO_HI_INT_STAT 0x110048 /* GPIO interrupt status */ | ||
254 | #define GPIO_HI_INT_MSTAT 0x110050 /* GPIO interrupt masked status */ | ||
255 | #define GPIO_HI_ISM_SNS 0x110058 /* GPIO interrupt sensitivity */ | ||
256 | #define GPIO_HI_ISM_POL 0x110060 /* GPIO interrupt polarity */ | ||
257 | |||
258 | #define FLD_GPIO43_INT (1 << 11) | ||
259 | #define FLD_GPIO42_INT (1 << 10) | ||
260 | #define FLD_GPIO41_INT (1 << 9) | ||
261 | #define FLD_GPIO40_INT (1 << 8) | ||
262 | |||
263 | #define FLD_GPIO9_INT (1 << 9) | ||
264 | #define FLD_GPIO8_INT (1 << 8) | ||
265 | #define FLD_GPIO7_INT (1 << 7) | ||
266 | #define FLD_GPIO6_INT (1 << 6) | ||
267 | #define FLD_GPIO5_INT (1 << 5) | ||
268 | #define FLD_GPIO4_INT (1 << 4) | ||
269 | #define FLD_GPIO3_INT (1 << 3) | ||
270 | #define FLD_GPIO2_INT (1 << 2) | ||
271 | #define FLD_GPIO1_INT (1 << 1) | ||
272 | #define FLD_GPIO0_INT (1 << 0) | ||
273 | |||
274 | /* ***************************************************************************** */ | ||
275 | #define TC_REQ 0x040090 /* Rider PCI Express traFFic class request */ | ||
276 | |||
277 | /* ***************************************************************************** */ | ||
278 | #define TC_REQ_SET 0x040094 /* Rider PCI Express traFFic class request set */ | ||
279 | |||
280 | /* ***************************************************************************** */ | ||
281 | /* Rider */ | ||
282 | /* ***************************************************************************** */ | ||
283 | |||
284 | /* PCI Compatible Header */ | ||
285 | /* ***************************************************************************** */ | ||
286 | #define RDR_CFG0 0x050000 | ||
287 | #define RDR_VENDOR_DEVICE_ID_CFG 0x050000 | ||
288 | |||
289 | /* ***************************************************************************** */ | ||
290 | #define RDR_CFG1 0x050004 | ||
291 | |||
292 | /* ***************************************************************************** */ | ||
293 | #define RDR_CFG2 0x050008 | ||
294 | |||
295 | /* ***************************************************************************** */ | ||
296 | #define RDR_CFG3 0x05000C | ||
297 | |||
298 | /* ***************************************************************************** */ | ||
299 | #define RDR_CFG4 0x050010 | ||
300 | |||
301 | /* ***************************************************************************** */ | ||
302 | #define RDR_CFG5 0x050014 | ||
303 | |||
304 | /* ***************************************************************************** */ | ||
305 | #define RDR_CFG6 0x050018 | ||
306 | |||
307 | /* ***************************************************************************** */ | ||
308 | #define RDR_CFG7 0x05001C | ||
309 | |||
310 | /* ***************************************************************************** */ | ||
311 | #define RDR_CFG8 0x050020 | ||
312 | |||
313 | /* ***************************************************************************** */ | ||
314 | #define RDR_CFG9 0x050024 | ||
315 | |||
316 | /* ***************************************************************************** */ | ||
317 | #define RDR_CFGA 0x050028 | ||
318 | |||
319 | /* ***************************************************************************** */ | ||
320 | #define RDR_CFGB 0x05002C | ||
321 | #define RDR_SUSSYSTEM_ID_CFG 0x05002C | ||
322 | |||
323 | /* ***************************************************************************** */ | ||
324 | #define RDR_CFGC 0x050030 | ||
325 | |||
326 | /* ***************************************************************************** */ | ||
327 | #define RDR_CFGD 0x050034 | ||
328 | |||
329 | /* ***************************************************************************** */ | ||
330 | #define RDR_CFGE 0x050038 | ||
331 | |||
332 | /* ***************************************************************************** */ | ||
333 | #define RDR_CFGF 0x05003C | ||
334 | |||
335 | /* ***************************************************************************** */ | ||
336 | /* PCI-Express Capabilities */ | ||
337 | /* ***************************************************************************** */ | ||
338 | #define RDR_PECAP 0x050040 | ||
339 | |||
340 | /* ***************************************************************************** */ | ||
341 | #define RDR_PEDEVCAP 0x050044 | ||
342 | |||
343 | /* ***************************************************************************** */ | ||
344 | #define RDR_PEDEVSC 0x050048 | ||
345 | |||
346 | /* ***************************************************************************** */ | ||
347 | #define RDR_PELINKCAP 0x05004C | ||
348 | |||
349 | /* ***************************************************************************** */ | ||
350 | #define RDR_PELINKSC 0x050050 | ||
351 | |||
352 | /* ***************************************************************************** */ | ||
353 | #define RDR_PMICAP 0x050080 | ||
354 | |||
355 | /* ***************************************************************************** */ | ||
356 | #define RDR_PMCSR 0x050084 | ||
357 | |||
358 | /* ***************************************************************************** */ | ||
359 | #define RDR_VPDCAP 0x050090 | ||
360 | |||
361 | /* ***************************************************************************** */ | ||
362 | #define RDR_VPDDATA 0x050094 | ||
363 | |||
364 | /* ***************************************************************************** */ | ||
365 | #define RDR_MSICAP 0x0500A0 | ||
366 | |||
367 | /* ***************************************************************************** */ | ||
368 | #define RDR_MSIARL 0x0500A4 | ||
369 | |||
370 | /* ***************************************************************************** */ | ||
371 | #define RDR_MSIARU 0x0500A8 | ||
372 | |||
373 | /* ***************************************************************************** */ | ||
374 | #define RDR_MSIDATA 0x0500AC | ||
375 | |||
376 | /* ***************************************************************************** */ | ||
377 | /* PCI Express Extended Capabilities */ | ||
378 | /* ***************************************************************************** */ | ||
379 | #define RDR_AERXCAP 0x050100 | ||
380 | |||
381 | /* ***************************************************************************** */ | ||
382 | #define RDR_AERUESTA 0x050104 | ||
383 | |||
384 | /* ***************************************************************************** */ | ||
385 | #define RDR_AERUEMSK 0x050108 | ||
386 | |||
387 | /* ***************************************************************************** */ | ||
388 | #define RDR_AERUESEV 0x05010C | ||
389 | |||
390 | /* ***************************************************************************** */ | ||
391 | #define RDR_AERCESTA 0x050110 | ||
392 | |||
393 | /* ***************************************************************************** */ | ||
394 | #define RDR_AERCEMSK 0x050114 | ||
395 | |||
396 | /* ***************************************************************************** */ | ||
397 | #define RDR_AERCC 0x050118 | ||
398 | |||
399 | /* ***************************************************************************** */ | ||
400 | #define RDR_AERHL0 0x05011C | ||
401 | |||
402 | /* ***************************************************************************** */ | ||
403 | #define RDR_AERHL1 0x050120 | ||
404 | |||
405 | /* ***************************************************************************** */ | ||
406 | #define RDR_AERHL2 0x050124 | ||
407 | |||
408 | /* ***************************************************************************** */ | ||
409 | #define RDR_AERHL3 0x050128 | ||
410 | |||
411 | /* ***************************************************************************** */ | ||
412 | #define RDR_VCXCAP 0x050200 | ||
413 | |||
414 | /* ***************************************************************************** */ | ||
415 | #define RDR_VCCAP1 0x050204 | ||
416 | |||
417 | /* ***************************************************************************** */ | ||
418 | #define RDR_VCCAP2 0x050208 | ||
419 | |||
420 | /* ***************************************************************************** */ | ||
421 | #define RDR_VCSC 0x05020C | ||
422 | |||
423 | /* ***************************************************************************** */ | ||
424 | #define RDR_VCR0_CAP 0x050210 | ||
425 | |||
426 | /* ***************************************************************************** */ | ||
427 | #define RDR_VCR0_CTRL 0x050214 | ||
428 | |||
429 | /* ***************************************************************************** */ | ||
430 | #define RDR_VCR0_STAT 0x050218 | ||
431 | |||
432 | /* ***************************************************************************** */ | ||
433 | #define RDR_VCR1_CAP 0x05021C | ||
434 | |||
435 | /* ***************************************************************************** */ | ||
436 | #define RDR_VCR1_CTRL 0x050220 | ||
437 | |||
438 | /* ***************************************************************************** */ | ||
439 | #define RDR_VCR1_STAT 0x050224 | ||
440 | |||
441 | /* ***************************************************************************** */ | ||
442 | #define RDR_VCR2_CAP 0x050228 | ||
443 | |||
444 | /* ***************************************************************************** */ | ||
445 | #define RDR_VCR2_CTRL 0x05022C | ||
446 | |||
447 | /* ***************************************************************************** */ | ||
448 | #define RDR_VCR2_STAT 0x050230 | ||
449 | |||
450 | /* ***************************************************************************** */ | ||
451 | #define RDR_VCR3_CAP 0x050234 | ||
452 | |||
453 | /* ***************************************************************************** */ | ||
454 | #define RDR_VCR3_CTRL 0x050238 | ||
455 | |||
456 | /* ***************************************************************************** */ | ||
457 | #define RDR_VCR3_STAT 0x05023C | ||
458 | |||
459 | /* ***************************************************************************** */ | ||
460 | #define RDR_VCARB0 0x050240 | ||
461 | |||
462 | /* ***************************************************************************** */ | ||
463 | #define RDR_VCARB1 0x050244 | ||
464 | |||
465 | /* ***************************************************************************** */ | ||
466 | #define RDR_VCARB2 0x050248 | ||
467 | |||
468 | /* ***************************************************************************** */ | ||
469 | #define RDR_VCARB3 0x05024C | ||
470 | |||
471 | /* ***************************************************************************** */ | ||
472 | #define RDR_VCARB4 0x050250 | ||
473 | |||
474 | /* ***************************************************************************** */ | ||
475 | #define RDR_VCARB5 0x050254 | ||
476 | |||
477 | /* ***************************************************************************** */ | ||
478 | #define RDR_VCARB6 0x050258 | ||
479 | |||
480 | /* ***************************************************************************** */ | ||
481 | #define RDR_VCARB7 0x05025C | ||
482 | |||
483 | /* ***************************************************************************** */ | ||
484 | #define RDR_RDRSTAT0 0x050300 | ||
485 | |||
486 | /* ***************************************************************************** */ | ||
487 | #define RDR_RDRSTAT1 0x050304 | ||
488 | |||
489 | /* ***************************************************************************** */ | ||
490 | #define RDR_RDRCTL0 0x050308 | ||
491 | |||
492 | /* ***************************************************************************** */ | ||
493 | #define RDR_RDRCTL1 0x05030C | ||
494 | |||
495 | /* ***************************************************************************** */ | ||
496 | /* Transaction Layer Registers */ | ||
497 | /* ***************************************************************************** */ | ||
498 | #define RDR_TLSTAT0 0x050310 | ||
499 | |||
500 | /* ***************************************************************************** */ | ||
501 | #define RDR_TLSTAT1 0x050314 | ||
502 | |||
503 | /* ***************************************************************************** */ | ||
504 | #define RDR_TLCTL0 0x050318 | ||
505 | #define FLD_CFG_UR_CPL_MODE 0x00000040 | ||
506 | #define FLD_CFG_CORR_ERR_QUITE 0x00000020 | ||
507 | #define FLD_CFG_RCB_CK_EN 0x00000010 | ||
508 | #define FLD_CFG_BNDRY_CK_EN 0x00000008 | ||
509 | #define FLD_CFG_BYTE_EN_CK_EN 0x00000004 | ||
510 | #define FLD_CFG_RELAX_ORDER_MSK 0x00000002 | ||
511 | #define FLD_CFG_TAG_ORDER_EN 0x00000001 | ||
512 | |||
513 | /* ***************************************************************************** */ | ||
514 | #define RDR_TLCTL1 0x05031C | ||
515 | |||
516 | /* ***************************************************************************** */ | ||
517 | #define RDR_REQRCAL 0x050320 | ||
518 | |||
519 | /* ***************************************************************************** */ | ||
520 | #define RDR_REQRCAU 0x050324 | ||
521 | |||
522 | /* ***************************************************************************** */ | ||
523 | #define RDR_REQEPA 0x050328 | ||
524 | |||
525 | /* ***************************************************************************** */ | ||
526 | #define RDR_REQCTRL 0x05032C | ||
527 | |||
528 | /* ***************************************************************************** */ | ||
529 | #define RDR_REQSTAT 0x050330 | ||
530 | |||
531 | /* ***************************************************************************** */ | ||
532 | #define RDR_TL_TEST 0x050334 | ||
533 | |||
534 | /* ***************************************************************************** */ | ||
535 | #define RDR_VCR01_CTL 0x050348 | ||
536 | |||
537 | /* ***************************************************************************** */ | ||
538 | #define RDR_VCR23_CTL 0x05034C | ||
539 | |||
540 | /* ***************************************************************************** */ | ||
541 | #define RDR_RX_VCR0_FC 0x050350 | ||
542 | |||
543 | /* ***************************************************************************** */ | ||
544 | #define RDR_RX_VCR1_FC 0x050354 | ||
545 | |||
546 | /* ***************************************************************************** */ | ||
547 | #define RDR_RX_VCR2_FC 0x050358 | ||
548 | |||
549 | /* ***************************************************************************** */ | ||
550 | #define RDR_RX_VCR3_FC 0x05035C | ||
551 | |||
552 | /* ***************************************************************************** */ | ||
553 | /* Data Link Layer Registers */ | ||
554 | /* ***************************************************************************** */ | ||
555 | #define RDR_DLLSTAT 0x050360 | ||
556 | |||
557 | /* ***************************************************************************** */ | ||
558 | #define RDR_DLLCTRL 0x050364 | ||
559 | |||
560 | /* ***************************************************************************** */ | ||
561 | #define RDR_REPLAYTO 0x050368 | ||
562 | |||
563 | /* ***************************************************************************** */ | ||
564 | #define RDR_ACKLATTO 0x05036C | ||
565 | |||
566 | /* ***************************************************************************** */ | ||
567 | /* MAC Layer Registers */ | ||
568 | /* ***************************************************************************** */ | ||
569 | #define RDR_MACSTAT0 0x050380 | ||
570 | |||
571 | /* ***************************************************************************** */ | ||
572 | #define RDR_MACSTAT1 0x050384 | ||
573 | |||
574 | /* ***************************************************************************** */ | ||
575 | #define RDR_MACCTRL0 0x050388 | ||
576 | |||
577 | /* ***************************************************************************** */ | ||
578 | #define RDR_MACCTRL1 0x05038C | ||
579 | |||
580 | /* ***************************************************************************** */ | ||
581 | #define RDR_MACCTRL2 0x050390 | ||
582 | |||
583 | /* ***************************************************************************** */ | ||
584 | #define RDR_MAC_LB_DATA 0x050394 | ||
585 | |||
586 | /* ***************************************************************************** */ | ||
587 | #define RDR_L0S_EXIT_LAT 0x050398 | ||
588 | |||
589 | /* ***************************************************************************** */ | ||
590 | /* DMAC */ | ||
591 | /* ***************************************************************************** */ | ||
592 | #define DMA1_PTR1 0x100000 /* DMA Current Ptr : Ch#1 */ | ||
593 | |||
594 | /* ***************************************************************************** */ | ||
595 | #define DMA2_PTR1 0x100004 /* DMA Current Ptr : Ch#2 */ | ||
596 | |||
597 | /* ***************************************************************************** */ | ||
598 | #define DMA3_PTR1 0x100008 /* DMA Current Ptr : Ch#3 */ | ||
599 | |||
600 | /* ***************************************************************************** */ | ||
601 | #define DMA4_PTR1 0x10000C /* DMA Current Ptr : Ch#4 */ | ||
602 | |||
603 | /* ***************************************************************************** */ | ||
604 | #define DMA5_PTR1 0x100010 /* DMA Current Ptr : Ch#5 */ | ||
605 | |||
606 | /* ***************************************************************************** */ | ||
607 | #define DMA6_PTR1 0x100014 /* DMA Current Ptr : Ch#6 */ | ||
608 | |||
609 | /* ***************************************************************************** */ | ||
610 | #define DMA7_PTR1 0x100018 /* DMA Current Ptr : Ch#7 */ | ||
611 | |||
612 | /* ***************************************************************************** */ | ||
613 | #define DMA8_PTR1 0x10001C /* DMA Current Ptr : Ch#8 */ | ||
614 | |||
615 | /* ***************************************************************************** */ | ||
616 | #define DMA9_PTR1 0x100020 /* DMA Current Ptr : Ch#9 */ | ||
617 | |||
618 | /* ***************************************************************************** */ | ||
619 | #define DMA10_PTR1 0x100024 /* DMA Current Ptr : Ch#10 */ | ||
620 | |||
621 | /* ***************************************************************************** */ | ||
622 | #define DMA11_PTR1 0x100028 /* DMA Current Ptr : Ch#11 */ | ||
623 | |||
624 | /* ***************************************************************************** */ | ||
625 | #define DMA12_PTR1 0x10002C /* DMA Current Ptr : Ch#12 */ | ||
626 | |||
627 | /* ***************************************************************************** */ | ||
628 | #define DMA13_PTR1 0x100030 /* DMA Current Ptr : Ch#13 */ | ||
629 | |||
630 | /* ***************************************************************************** */ | ||
631 | #define DMA14_PTR1 0x100034 /* DMA Current Ptr : Ch#14 */ | ||
632 | |||
633 | /* ***************************************************************************** */ | ||
634 | #define DMA15_PTR1 0x100038 /* DMA Current Ptr : Ch#15 */ | ||
635 | |||
636 | /* ***************************************************************************** */ | ||
637 | #define DMA16_PTR1 0x10003C /* DMA Current Ptr : Ch#16 */ | ||
638 | |||
639 | /* ***************************************************************************** */ | ||
640 | #define DMA17_PTR1 0x100040 /* DMA Current Ptr : Ch#17 */ | ||
641 | |||
642 | /* ***************************************************************************** */ | ||
643 | #define DMA18_PTR1 0x100044 /* DMA Current Ptr : Ch#18 */ | ||
644 | |||
645 | /* ***************************************************************************** */ | ||
646 | #define DMA19_PTR1 0x100048 /* DMA Current Ptr : Ch#19 */ | ||
647 | |||
648 | /* ***************************************************************************** */ | ||
649 | #define DMA20_PTR1 0x10004C /* DMA Current Ptr : Ch#20 */ | ||
650 | |||
651 | /* ***************************************************************************** */ | ||
652 | #define DMA21_PTR1 0x100050 /* DMA Current Ptr : Ch#21 */ | ||
653 | |||
654 | /* ***************************************************************************** */ | ||
655 | #define DMA22_PTR1 0x100054 /* DMA Current Ptr : Ch#22 */ | ||
656 | |||
657 | /* ***************************************************************************** */ | ||
658 | #define DMA23_PTR1 0x100058 /* DMA Current Ptr : Ch#23 */ | ||
659 | |||
660 | /* ***************************************************************************** */ | ||
661 | #define DMA24_PTR1 0x10005C /* DMA Current Ptr : Ch#24 */ | ||
662 | |||
663 | /* ***************************************************************************** */ | ||
664 | #define DMA25_PTR1 0x100060 /* DMA Current Ptr : Ch#25 */ | ||
665 | |||
666 | /* ***************************************************************************** */ | ||
667 | #define DMA26_PTR1 0x100064 /* DMA Current Ptr : Ch#26 */ | ||
668 | |||
669 | /* ***************************************************************************** */ | ||
670 | #define DMA1_PTR2 0x100080 /* DMA Tab Ptr : Ch#1 */ | ||
671 | |||
672 | /* ***************************************************************************** */ | ||
673 | #define DMA2_PTR2 0x100084 /* DMA Tab Ptr : Ch#2 */ | ||
674 | |||
675 | /* ***************************************************************************** */ | ||
676 | #define DMA3_PTR2 0x100088 /* DMA Tab Ptr : Ch#3 */ | ||
677 | |||
678 | /* ***************************************************************************** */ | ||
679 | #define DMA4_PTR2 0x10008C /* DMA Tab Ptr : Ch#4 */ | ||
680 | |||
681 | /* ***************************************************************************** */ | ||
682 | #define DMA5_PTR2 0x100090 /* DMA Tab Ptr : Ch#5 */ | ||
683 | |||
684 | /* ***************************************************************************** */ | ||
685 | #define DMA6_PTR2 0x100094 /* DMA Tab Ptr : Ch#6 */ | ||
686 | |||
687 | /* ***************************************************************************** */ | ||
688 | #define DMA7_PTR2 0x100098 /* DMA Tab Ptr : Ch#7 */ | ||
689 | |||
690 | /* ***************************************************************************** */ | ||
691 | #define DMA8_PTR2 0x10009C /* DMA Tab Ptr : Ch#8 */ | ||
692 | |||
693 | /* ***************************************************************************** */ | ||
694 | #define DMA9_PTR2 0x1000A0 /* DMA Tab Ptr : Ch#9 */ | ||
695 | |||
696 | /* ***************************************************************************** */ | ||
697 | #define DMA10_PTR2 0x1000A4 /* DMA Tab Ptr : Ch#10 */ | ||
698 | |||
699 | /* ***************************************************************************** */ | ||
700 | #define DMA11_PTR2 0x1000A8 /* DMA Tab Ptr : Ch#11 */ | ||
701 | |||
702 | /* ***************************************************************************** */ | ||
703 | #define DMA12_PTR2 0x1000AC /* DMA Tab Ptr : Ch#12 */ | ||
704 | |||
705 | /* ***************************************************************************** */ | ||
706 | #define DMA13_PTR2 0x1000B0 /* DMA Tab Ptr : Ch#13 */ | ||
707 | |||
708 | /* ***************************************************************************** */ | ||
709 | #define DMA14_PTR2 0x1000B4 /* DMA Tab Ptr : Ch#14 */ | ||
710 | |||
711 | /* ***************************************************************************** */ | ||
712 | #define DMA15_PTR2 0x1000B8 /* DMA Tab Ptr : Ch#15 */ | ||
713 | |||
714 | /* ***************************************************************************** */ | ||
715 | #define DMA16_PTR2 0x1000BC /* DMA Tab Ptr : Ch#16 */ | ||
716 | |||
717 | /* ***************************************************************************** */ | ||
718 | #define DMA17_PTR2 0x1000C0 /* DMA Tab Ptr : Ch#17 */ | ||
719 | |||
720 | /* ***************************************************************************** */ | ||
721 | #define DMA18_PTR2 0x1000C4 /* DMA Tab Ptr : Ch#18 */ | ||
722 | |||
723 | /* ***************************************************************************** */ | ||
724 | #define DMA19_PTR2 0x1000C8 /* DMA Tab Ptr : Ch#19 */ | ||
725 | |||
726 | /* ***************************************************************************** */ | ||
727 | #define DMA20_PTR2 0x1000CC /* DMA Tab Ptr : Ch#20 */ | ||
728 | |||
729 | /* ***************************************************************************** */ | ||
730 | #define DMA21_PTR2 0x1000D0 /* DMA Tab Ptr : Ch#21 */ | ||
731 | |||
732 | /* ***************************************************************************** */ | ||
733 | #define DMA22_PTR2 0x1000D4 /* DMA Tab Ptr : Ch#22 */ | ||
734 | |||
735 | /* ***************************************************************************** */ | ||
736 | #define DMA23_PTR2 0x1000D8 /* DMA Tab Ptr : Ch#23 */ | ||
737 | |||
738 | /* ***************************************************************************** */ | ||
739 | #define DMA24_PTR2 0x1000DC /* DMA Tab Ptr : Ch#24 */ | ||
740 | |||
741 | /* ***************************************************************************** */ | ||
742 | #define DMA25_PTR2 0x1000E0 /* DMA Tab Ptr : Ch#25 */ | ||
743 | |||
744 | /* ***************************************************************************** */ | ||
745 | #define DMA26_PTR2 0x1000E4 /* DMA Tab Ptr : Ch#26 */ | ||
746 | |||
747 | /* ***************************************************************************** */ | ||
748 | #define DMA1_CNT1 0x100100 /* DMA BuFFer Size : Ch#1 */ | ||
749 | |||
750 | /* ***************************************************************************** */ | ||
751 | #define DMA2_CNT1 0x100104 /* DMA BuFFer Size : Ch#2 */ | ||
752 | |||
753 | /* ***************************************************************************** */ | ||
754 | #define DMA3_CNT1 0x100108 /* DMA BuFFer Size : Ch#3 */ | ||
755 | |||
756 | /* ***************************************************************************** */ | ||
757 | #define DMA4_CNT1 0x10010C /* DMA BuFFer Size : Ch#4 */ | ||
758 | |||
759 | /* ***************************************************************************** */ | ||
760 | #define DMA5_CNT1 0x100110 /* DMA BuFFer Size : Ch#5 */ | ||
761 | |||
762 | /* ***************************************************************************** */ | ||
763 | #define DMA6_CNT1 0x100114 /* DMA BuFFer Size : Ch#6 */ | ||
764 | |||
765 | /* ***************************************************************************** */ | ||
766 | #define DMA7_CNT1 0x100118 /* DMA BuFFer Size : Ch#7 */ | ||
767 | |||
768 | /* ***************************************************************************** */ | ||
769 | #define DMA8_CNT1 0x10011C /* DMA BuFFer Size : Ch#8 */ | ||
770 | |||
771 | /* ***************************************************************************** */ | ||
772 | #define DMA9_CNT1 0x100120 /* DMA BuFFer Size : Ch#9 */ | ||
773 | |||
774 | /* ***************************************************************************** */ | ||
775 | #define DMA10_CNT1 0x100124 /* DMA BuFFer Size : Ch#10 */ | ||
776 | |||
777 | /* ***************************************************************************** */ | ||
778 | #define DMA11_CNT1 0x100128 /* DMA BuFFer Size : Ch#11 */ | ||
779 | |||
780 | /* ***************************************************************************** */ | ||
781 | #define DMA12_CNT1 0x10012C /* DMA BuFFer Size : Ch#12 */ | ||
782 | |||
783 | /* ***************************************************************************** */ | ||
784 | #define DMA13_CNT1 0x100130 /* DMA BuFFer Size : Ch#13 */ | ||
785 | |||
786 | /* ***************************************************************************** */ | ||
787 | #define DMA14_CNT1 0x100134 /* DMA BuFFer Size : Ch#14 */ | ||
788 | |||
789 | /* ***************************************************************************** */ | ||
790 | #define DMA15_CNT1 0x100138 /* DMA BuFFer Size : Ch#15 */ | ||
791 | |||
792 | /* ***************************************************************************** */ | ||
793 | #define DMA16_CNT1 0x10013C /* DMA BuFFer Size : Ch#16 */ | ||
794 | |||
795 | /* ***************************************************************************** */ | ||
796 | #define DMA17_CNT1 0x100140 /* DMA BuFFer Size : Ch#17 */ | ||
797 | |||
798 | /* ***************************************************************************** */ | ||
799 | #define DMA18_CNT1 0x100144 /* DMA BuFFer Size : Ch#18 */ | ||
800 | |||
801 | /* ***************************************************************************** */ | ||
802 | #define DMA19_CNT1 0x100148 /* DMA BuFFer Size : Ch#19 */ | ||
803 | |||
804 | /* ***************************************************************************** */ | ||
805 | #define DMA20_CNT1 0x10014C /* DMA BuFFer Size : Ch#20 */ | ||
806 | |||
807 | /* ***************************************************************************** */ | ||
808 | #define DMA21_CNT1 0x100150 /* DMA BuFFer Size : Ch#21 */ | ||
809 | |||
810 | /* ***************************************************************************** */ | ||
811 | #define DMA22_CNT1 0x100154 /* DMA BuFFer Size : Ch#22 */ | ||
812 | |||
813 | /* ***************************************************************************** */ | ||
814 | #define DMA23_CNT1 0x100158 /* DMA BuFFer Size : Ch#23 */ | ||
815 | |||
816 | /* ***************************************************************************** */ | ||
817 | #define DMA24_CNT1 0x10015C /* DMA BuFFer Size : Ch#24 */ | ||
818 | |||
819 | /* ***************************************************************************** */ | ||
820 | #define DMA25_CNT1 0x100160 /* DMA BuFFer Size : Ch#25 */ | ||
821 | |||
822 | /* ***************************************************************************** */ | ||
823 | #define DMA26_CNT1 0x100164 /* DMA BuFFer Size : Ch#26 */ | ||
824 | |||
825 | /* ***************************************************************************** */ | ||
826 | #define DMA1_CNT2 0x100180 /* DMA Table Size : Ch#1 */ | ||
827 | |||
828 | /* ***************************************************************************** */ | ||
829 | #define DMA2_CNT2 0x100184 /* DMA Table Size : Ch#2 */ | ||
830 | |||
831 | /* ***************************************************************************** */ | ||
832 | #define DMA3_CNT2 0x100188 /* DMA Table Size : Ch#3 */ | ||
833 | |||
834 | /* ***************************************************************************** */ | ||
835 | #define DMA4_CNT2 0x10018C /* DMA Table Size : Ch#4 */ | ||
836 | |||
837 | /* ***************************************************************************** */ | ||
838 | #define DMA5_CNT2 0x100190 /* DMA Table Size : Ch#5 */ | ||
839 | |||
840 | /* ***************************************************************************** */ | ||
841 | #define DMA6_CNT2 0x100194 /* DMA Table Size : Ch#6 */ | ||
842 | |||
843 | /* ***************************************************************************** */ | ||
844 | #define DMA7_CNT2 0x100198 /* DMA Table Size : Ch#7 */ | ||
845 | |||
846 | /* ***************************************************************************** */ | ||
847 | #define DMA8_CNT2 0x10019C /* DMA Table Size : Ch#8 */ | ||
848 | |||
849 | /* ***************************************************************************** */ | ||
850 | #define DMA9_CNT2 0x1001A0 /* DMA Table Size : Ch#9 */ | ||
851 | |||
852 | /* ***************************************************************************** */ | ||
853 | #define DMA10_CNT2 0x1001A4 /* DMA Table Size : Ch#10 */ | ||
854 | |||
855 | /* ***************************************************************************** */ | ||
856 | #define DMA11_CNT2 0x1001A8 /* DMA Table Size : Ch#11 */ | ||
857 | |||
858 | /* ***************************************************************************** */ | ||
859 | #define DMA12_CNT2 0x1001AC /* DMA Table Size : Ch#12 */ | ||
860 | |||
861 | /* ***************************************************************************** */ | ||
862 | #define DMA13_CNT2 0x1001B0 /* DMA Table Size : Ch#13 */ | ||
863 | |||
864 | /* ***************************************************************************** */ | ||
865 | #define DMA14_CNT2 0x1001B4 /* DMA Table Size : Ch#14 */ | ||
866 | |||
867 | /* ***************************************************************************** */ | ||
868 | #define DMA15_CNT2 0x1001B8 /* DMA Table Size : Ch#15 */ | ||
869 | |||
870 | /* ***************************************************************************** */ | ||
871 | #define DMA16_CNT2 0x1001BC /* DMA Table Size : Ch#16 */ | ||
872 | |||
873 | /* ***************************************************************************** */ | ||
874 | #define DMA17_CNT2 0x1001C0 /* DMA Table Size : Ch#17 */ | ||
875 | |||
876 | /* ***************************************************************************** */ | ||
877 | #define DMA18_CNT2 0x1001C4 /* DMA Table Size : Ch#18 */ | ||
878 | |||
879 | /* ***************************************************************************** */ | ||
880 | #define DMA19_CNT2 0x1001C8 /* DMA Table Size : Ch#19 */ | ||
881 | |||
882 | /* ***************************************************************************** */ | ||
883 | #define DMA20_CNT2 0x1001CC /* DMA Table Size : Ch#20 */ | ||
884 | |||
885 | /* ***************************************************************************** */ | ||
886 | #define DMA21_CNT2 0x1001D0 /* DMA Table Size : Ch#21 */ | ||
887 | |||
888 | /* ***************************************************************************** */ | ||
889 | #define DMA22_CNT2 0x1001D4 /* DMA Table Size : Ch#22 */ | ||
890 | |||
891 | /* ***************************************************************************** */ | ||
892 | #define DMA23_CNT2 0x1001D8 /* DMA Table Size : Ch#23 */ | ||
893 | |||
894 | /* ***************************************************************************** */ | ||
895 | #define DMA24_CNT2 0x1001DC /* DMA Table Size : Ch#24 */ | ||
896 | |||
897 | /* ***************************************************************************** */ | ||
898 | #define DMA25_CNT2 0x1001E0 /* DMA Table Size : Ch#25 */ | ||
899 | |||
900 | /* ***************************************************************************** */ | ||
901 | #define DMA26_CNT2 0x1001E4 /* DMA Table Size : Ch#26 */ | ||
902 | |||
903 | /* ***************************************************************************** */ | ||
904 | /* ITG */ | ||
905 | /* ***************************************************************************** */ | ||
906 | #define TM_CNT_LDW 0x110000 /* Timer : Counter low */ | ||
907 | |||
908 | /* ***************************************************************************** */ | ||
909 | #define TM_CNT_UW 0x110004 /* Timer : Counter high word */ | ||
910 | |||
911 | /* ***************************************************************************** */ | ||
912 | #define TM_LMT_LDW 0x110008 /* Timer : Limit low */ | ||
913 | |||
914 | /* ***************************************************************************** */ | ||
915 | #define TM_LMT_UW 0x11000C /* Timer : Limit high word */ | ||
916 | |||
917 | /* ***************************************************************************** */ | ||
918 | #define GP0_IO 0x110010 /* GPIO output enables data I/O */ | ||
919 | #define FLD_GP_OE 0x00FF0000 /* GPIO: GP_OE output enable */ | ||
920 | #define FLD_GP_IN 0x0000FF00 /* GPIO: GP_IN status */ | ||
921 | #define FLD_GP_OUT 0x000000FF /* GPIO: GP_OUT control */ | ||
922 | |||
923 | /* ***************************************************************************** */ | ||
924 | #define GPIO_ISM 0x110014 /* GPIO interrupt sensitivity mode */ | ||
925 | #define FLD_GP_ISM_SNS 0x00000070 | ||
926 | #define FLD_GP_ISM_POL 0x00000007 | ||
927 | |||
928 | /* ***************************************************************************** */ | ||
929 | #define SOFT_RESET 0x11001C /* Output system reset reg */ | ||
930 | #define FLD_PECOS_SOFT_RESET 0x00000001 | ||
931 | |||
932 | /* ***************************************************************************** */ | ||
933 | #define MC416_RWD 0x110020 /* MC416 GPIO[18:3] pin */ | ||
934 | #define MC416_OEN 0x110024 /* Output enable of GPIO[18:3] */ | ||
935 | #define MC416_CTL 0x110028 | ||
936 | |||
937 | /* ***************************************************************************** */ | ||
938 | #define ALT_PIN_OUT_SEL 0x11002C /* Alternate GPIO output select */ | ||
939 | |||
940 | #define FLD_ALT_GPIO_OUT_SEL 0xF0000000 | ||
941 | /* 0 Disabled <-- default */ | ||
942 | /* 1 GPIO[0] */ | ||
943 | /* 2 GPIO[10] */ | ||
944 | /* 3 VIP_656_DATA_VAL */ | ||
945 | /* 4 VIP_656_DATA[0] */ | ||
946 | /* 5 VIP_656_CLK */ | ||
947 | /* 6 VIP_656_DATA_EXT[1] */ | ||
948 | /* 7 VIP_656_DATA_EXT[0] */ | ||
949 | /* 8 ATT_IF */ | ||
950 | |||
951 | #define FLD_AUX_PLL_CLK_ALT_SEL 0x0F000000 | ||
952 | /* 0 AUX_PLL_CLK<-- default */ | ||
953 | /* 1 GPIO[2] */ | ||
954 | /* 2 GPIO[10] */ | ||
955 | /* 3 VIP_656_DATA_VAL */ | ||
956 | /* 4 VIP_656_DATA[0] */ | ||
957 | /* 5 VIP_656_CLK */ | ||
958 | /* 6 VIP_656_DATA_EXT[1] */ | ||
959 | /* 7 VIP_656_DATA_EXT[0] */ | ||
960 | |||
961 | #define FLD_IR_TX_ALT_SEL 0x00F00000 | ||
962 | /* 0 IR_TX <-- default */ | ||
963 | /* 1 GPIO[1] */ | ||
964 | /* 2 GPIO[10] */ | ||
965 | /* 3 VIP_656_DATA_VAL */ | ||
966 | /* 4 VIP_656_DATA[0] */ | ||
967 | /* 5 VIP_656_CLK */ | ||
968 | /* 6 VIP_656_DATA_EXT[1] */ | ||
969 | /* 7 VIP_656_DATA_EXT[0] */ | ||
970 | |||
971 | #define FLD_IR_RX_ALT_SEL 0x000F0000 | ||
972 | /* 0 IR_RX <-- default */ | ||
973 | /* 1 GPIO[0] */ | ||
974 | /* 2 GPIO[10] */ | ||
975 | /* 3 VIP_656_DATA_VAL */ | ||
976 | /* 4 VIP_656_DATA[0] */ | ||
977 | /* 5 VIP_656_CLK */ | ||
978 | /* 6 VIP_656_DATA_EXT[1] */ | ||
979 | /* 7 VIP_656_DATA_EXT[0] */ | ||
980 | |||
981 | #define FLD_GPIO10_ALT_SEL 0x0000F000 | ||
982 | /* 0 GPIO[10] <-- default */ | ||
983 | /* 1 GPIO[0] */ | ||
984 | /* 2 GPIO[10] */ | ||
985 | /* 3 VIP_656_DATA_VAL */ | ||
986 | /* 4 VIP_656_DATA[0] */ | ||
987 | /* 5 VIP_656_CLK */ | ||
988 | /* 6 VIP_656_DATA_EXT[1] */ | ||
989 | /* 7 VIP_656_DATA_EXT[0] */ | ||
990 | |||
991 | #define FLD_GPIO2_ALT_SEL 0x00000F00 | ||
992 | /* 0 GPIO[2] <-- default */ | ||
993 | /* 1 GPIO[1] */ | ||
994 | /* 2 GPIO[10] */ | ||
995 | /* 3 VIP_656_DATA_VAL */ | ||
996 | /* 4 VIP_656_DATA[0] */ | ||
997 | /* 5 VIP_656_CLK */ | ||
998 | /* 6 VIP_656_DATA_EXT[1] */ | ||
999 | /* 7 VIP_656_DATA_EXT[0] */ | ||
1000 | |||
1001 | #define FLD_GPIO1_ALT_SEL 0x000000F0 | ||
1002 | /* 0 GPIO[1] <-- default */ | ||
1003 | /* 1 GPIO[0] */ | ||
1004 | /* 2 GPIO[10] */ | ||
1005 | /* 3 VIP_656_DATA_VAL */ | ||
1006 | /* 4 VIP_656_DATA[0] */ | ||
1007 | /* 5 VIP_656_CLK */ | ||
1008 | /* 6 VIP_656_DATA_EXT[1] */ | ||
1009 | /* 7 VIP_656_DATA_EXT[0] */ | ||
1010 | |||
1011 | #define FLD_GPIO0_ALT_SEL 0x0000000F | ||
1012 | /* 0 GPIO[0] <-- default */ | ||
1013 | /* 1 GPIO[1] */ | ||
1014 | /* 2 GPIO[10] */ | ||
1015 | /* 3 VIP_656_DATA_VAL */ | ||
1016 | /* 4 VIP_656_DATA[0] */ | ||
1017 | /* 5 VIP_656_CLK */ | ||
1018 | /* 6 VIP_656_DATA_EXT[1] */ | ||
1019 | /* 7 VIP_656_DATA_EXT[0] */ | ||
1020 | |||
1021 | #define ALT_PIN_IN_SEL 0x110030 /* Alternate GPIO input select */ | ||
1022 | |||
1023 | #define FLD_GPIO10_ALT_IN_SEL 0x0000F000 | ||
1024 | /* 0 GPIO[10] <-- default */ | ||
1025 | /* 1 IR_RX */ | ||
1026 | /* 2 IR_TX */ | ||
1027 | /* 3 AUX_PLL_CLK */ | ||
1028 | /* 4 IF_ATT_SEL */ | ||
1029 | /* 5 GPIO[0] */ | ||
1030 | /* 6 GPIO[1] */ | ||
1031 | /* 7 GPIO[2] */ | ||
1032 | |||
1033 | #define FLD_GPIO2_ALT_IN_SEL 0x00000F00 | ||
1034 | /* 0 GPIO[2] <-- default */ | ||
1035 | /* 1 IR_RX */ | ||
1036 | /* 2 IR_TX */ | ||
1037 | /* 3 AUX_PLL_CLK */ | ||
1038 | /* 4 IF_ATT_SEL */ | ||
1039 | |||
1040 | #define FLD_GPIO1_ALT_IN_SEL 0x000000F0 | ||
1041 | /* 0 GPIO[1] <-- default */ | ||
1042 | /* 1 IR_RX */ | ||
1043 | /* 2 IR_TX */ | ||
1044 | /* 3 AUX_PLL_CLK */ | ||
1045 | /* 4 IF_ATT_SEL */ | ||
1046 | |||
1047 | #define FLD_GPIO0_ALT_IN_SEL 0x0000000F | ||
1048 | /* 0 GPIO[0] <-- default */ | ||
1049 | /* 1 IR_RX */ | ||
1050 | /* 2 IR_TX */ | ||
1051 | /* 3 AUX_PLL_CLK */ | ||
1052 | /* 4 IF_ATT_SEL */ | ||
1053 | |||
1054 | /* ***************************************************************************** */ | ||
1055 | #define TEST_BUS_CTL1 0x110040 /* Test bus control register #1 */ | ||
1056 | |||
1057 | /* ***************************************************************************** */ | ||
1058 | #define TEST_BUS_CTL2 0x110044 /* Test bus control register #2 */ | ||
1059 | |||
1060 | /* ***************************************************************************** */ | ||
1061 | #define CLK_DELAY 0x110048 /* Clock delay */ | ||
1062 | #define FLD_MOE_CLK_DIS 0x80000000 /* Disable MoE clock */ | ||
1063 | |||
1064 | /* ***************************************************************************** */ | ||
1065 | #define PAD_CTRL 0x110068 /* Pad drive strength control */ | ||
1066 | |||
1067 | /* ***************************************************************************** */ | ||
1068 | #define MBIST_CTRL 0x110050 /* SRAM memory built-in self test control */ | ||
1069 | |||
1070 | /* ***************************************************************************** */ | ||
1071 | #define MBIST_STAT 0x110054 /* SRAM memory built-in self test status */ | ||
1072 | |||
1073 | /* ***************************************************************************** */ | ||
1074 | /* PLL registers */ | ||
1075 | /* ***************************************************************************** */ | ||
1076 | #define PLL_A_INT_FRAC 0x110088 | ||
1077 | #define PLL_A_POST_STAT_BIST 0x11008C | ||
1078 | #define PLL_B_INT_FRAC 0x110090 | ||
1079 | #define PLL_B_POST_STAT_BIST 0x110094 | ||
1080 | #define PLL_C_INT_FRAC 0x110098 | ||
1081 | #define PLL_C_POST_STAT_BIST 0x11009C | ||
1082 | #define PLL_D_INT_FRAC 0x1100A0 | ||
1083 | #define PLL_D_POST_STAT_BIST 0x1100A4 | ||
1084 | |||
1085 | #define CLK_RST 0x11002C | ||
1086 | #define FLD_VID_I_CLK_NOE 0x00001000 | ||
1087 | #define FLD_VID_J_CLK_NOE 0x00002000 | ||
1088 | #define FLD_USE_ALT_PLL_REF 0x00004000 | ||
1089 | |||
1090 | #define VID_CH_MODE_SEL 0x110078 | ||
1091 | #define VID_CH_CLK_SEL 0x11007C | ||
1092 | |||
1093 | /* ***************************************************************************** */ | ||
1094 | #define VBI_A_DMA 0x130008 /* VBI A DMA data port */ | ||
1095 | |||
1096 | /* ***************************************************************************** */ | ||
1097 | #define VID_A_VIP_CTL 0x130080 /* Video A VIP format control */ | ||
1098 | #define FLD_VIP_MODE 0x00000001 | ||
1099 | |||
1100 | /* ***************************************************************************** */ | ||
1101 | #define VID_A_PIXEL_FRMT 0x130084 /* Video A pixel format */ | ||
1102 | #define FLD_VID_A_GAMMA_DIS 0x00000008 | ||
1103 | #define FLD_VID_A_FORMAT 0x00000007 | ||
1104 | #define FLD_VID_A_GAMMA_FACTOR 0x00000010 | ||
1105 | |||
1106 | /* ***************************************************************************** */ | ||
1107 | #define VID_A_VBI_CTL 0x130088 /* Video A VBI miscellaneous control */ | ||
1108 | #define FLD_VID_A_VIP_EXT 0x00000003 | ||
1109 | |||
1110 | /* ***************************************************************************** */ | ||
1111 | #define VID_B_DMA 0x130100 /* Video B DMA data port */ | ||
1112 | |||
1113 | /* ***************************************************************************** */ | ||
1114 | #define VBI_B_DMA 0x130108 /* VBI B DMA data port */ | ||
1115 | |||
1116 | /* ***************************************************************************** */ | ||
1117 | #define VID_B_SRC_SEL 0x130144 /* Video B source select */ | ||
1118 | #define FLD_VID_B_SRC_SEL 0x00000000 | ||
1119 | |||
1120 | /* ***************************************************************************** */ | ||
1121 | #define VID_B_LNGTH 0x130150 /* Video B line length */ | ||
1122 | #define FLD_VID_B_LN_LNGTH 0x00000FFF | ||
1123 | |||
1124 | /* ***************************************************************************** */ | ||
1125 | #define VID_B_VIP_CTL 0x130180 /* Video B VIP format control */ | ||
1126 | |||
1127 | /* ***************************************************************************** */ | ||
1128 | #define VID_B_PIXEL_FRMT 0x130184 /* Video B pixel format */ | ||
1129 | #define FLD_VID_B_GAMMA_DIS 0x00000008 | ||
1130 | #define FLD_VID_B_FORMAT 0x00000007 | ||
1131 | #define FLD_VID_B_GAMMA_FACTOR 0x00000010 | ||
1132 | |||
1133 | /* ***************************************************************************** */ | ||
1134 | #define VID_C_DMA 0x130200 /* Video C DMA data port */ | ||
1135 | |||
1136 | /* ***************************************************************************** */ | ||
1137 | #define VID_C_LNGTH 0x130250 /* Video C line length */ | ||
1138 | #define FLD_VID_C_LN_LNGTH 0x00000FFF | ||
1139 | |||
1140 | /* ***************************************************************************** */ | ||
1141 | /* Video Destination Channels */ | ||
1142 | /* ***************************************************************************** */ | ||
1143 | |||
1144 | #define VID_DST_A_GPCNT 0x130020 /* Video A general purpose counter */ | ||
1145 | #define VID_DST_B_GPCNT 0x130120 /* Video B general purpose counter */ | ||
1146 | #define VID_DST_C_GPCNT 0x130220 /* Video C general purpose counter */ | ||
1147 | #define VID_DST_D_GPCNT 0x130320 /* Video D general purpose counter */ | ||
1148 | #define VID_DST_E_GPCNT 0x130420 /* Video E general purpose counter */ | ||
1149 | #define VID_DST_F_GPCNT 0x130520 /* Video F general purpose counter */ | ||
1150 | #define VID_DST_G_GPCNT 0x130620 /* Video G general purpose counter */ | ||
1151 | #define VID_DST_H_GPCNT 0x130720 /* Video H general purpose counter */ | ||
1152 | |||
1153 | /* ***************************************************************************** */ | ||
1154 | |||
1155 | #define VID_DST_A_GPCNT_CTL 0x130030 /* Video A general purpose control */ | ||
1156 | #define VID_DST_B_GPCNT_CTL 0x130130 /* Video B general purpose control */ | ||
1157 | #define VID_DST_C_GPCNT_CTL 0x130230 /* Video C general purpose control */ | ||
1158 | #define VID_DST_D_GPCNT_CTL 0x130330 /* Video D general purpose control */ | ||
1159 | #define VID_DST_E_GPCNT_CTL 0x130430 /* Video E general purpose control */ | ||
1160 | #define VID_DST_F_GPCNT_CTL 0x130530 /* Video F general purpose control */ | ||
1161 | #define VID_DST_G_GPCNT_CTL 0x130630 /* Video G general purpose control */ | ||
1162 | #define VID_DST_H_GPCNT_CTL 0x130730 /* Video H general purpose control */ | ||
1163 | |||
1164 | /* ***************************************************************************** */ | ||
1165 | |||
1166 | #define VID_DST_A_DMA_CTL 0x130040 /* Video A DMA control */ | ||
1167 | #define VID_DST_B_DMA_CTL 0x130140 /* Video B DMA control */ | ||
1168 | #define VID_DST_C_DMA_CTL 0x130240 /* Video C DMA control */ | ||
1169 | #define VID_DST_D_DMA_CTL 0x130340 /* Video D DMA control */ | ||
1170 | #define VID_DST_E_DMA_CTL 0x130440 /* Video E DMA control */ | ||
1171 | #define VID_DST_F_DMA_CTL 0x130540 /* Video F DMA control */ | ||
1172 | #define VID_DST_G_DMA_CTL 0x130640 /* Video G DMA control */ | ||
1173 | #define VID_DST_H_DMA_CTL 0x130740 /* Video H DMA control */ | ||
1174 | |||
1175 | #define FLD_VID_RISC_EN 0x00000010 | ||
1176 | #define FLD_VID_FIFO_EN 0x00000001 | ||
1177 | |||
1178 | /* ***************************************************************************** */ | ||
1179 | |||
1180 | #define VID_DST_A_VIP_CTL 0x130080 /* Video A VIP control */ | ||
1181 | #define VID_DST_B_VIP_CTL 0x130180 /* Video B VIP control */ | ||
1182 | #define VID_DST_C_VIP_CTL 0x130280 /* Video C VIP control */ | ||
1183 | #define VID_DST_D_VIP_CTL 0x130380 /* Video D VIP control */ | ||
1184 | #define VID_DST_E_VIP_CTL 0x130480 /* Video E VIP control */ | ||
1185 | #define VID_DST_F_VIP_CTL 0x130580 /* Video F VIP control */ | ||
1186 | #define VID_DST_G_VIP_CTL 0x130680 /* Video G VIP control */ | ||
1187 | #define VID_DST_H_VIP_CTL 0x130780 /* Video H VIP control */ | ||
1188 | |||
1189 | /* ***************************************************************************** */ | ||
1190 | |||
1191 | #define VID_DST_A_PIX_FRMT 0x130084 /* Video A Pixel format */ | ||
1192 | #define VID_DST_B_PIX_FRMT 0x130184 /* Video B Pixel format */ | ||
1193 | #define VID_DST_C_PIX_FRMT 0x130284 /* Video C Pixel format */ | ||
1194 | #define VID_DST_D_PIX_FRMT 0x130384 /* Video D Pixel format */ | ||
1195 | #define VID_DST_E_PIX_FRMT 0x130484 /* Video E Pixel format */ | ||
1196 | #define VID_DST_F_PIX_FRMT 0x130584 /* Video F Pixel format */ | ||
1197 | #define VID_DST_G_PIX_FRMT 0x130684 /* Video G Pixel format */ | ||
1198 | #define VID_DST_H_PIX_FRMT 0x130784 /* Video H Pixel format */ | ||
1199 | |||
1200 | /* ***************************************************************************** */ | ||
1201 | /* Video Source Channels */ | ||
1202 | /* ***************************************************************************** */ | ||
1203 | |||
1204 | #define VID_SRC_A_GPCNT_CTL 0x130804 /* Video A general purpose control */ | ||
1205 | #define VID_SRC_B_GPCNT_CTL 0x130904 /* Video B general purpose control */ | ||
1206 | #define VID_SRC_C_GPCNT_CTL 0x130A04 /* Video C general purpose control */ | ||
1207 | #define VID_SRC_D_GPCNT_CTL 0x130B04 /* Video D general purpose control */ | ||
1208 | #define VID_SRC_E_GPCNT_CTL 0x130C04 /* Video E general purpose control */ | ||
1209 | #define VID_SRC_F_GPCNT_CTL 0x130D04 /* Video F general purpose control */ | ||
1210 | #define VID_SRC_I_GPCNT_CTL 0x130E04 /* Video I general purpose control */ | ||
1211 | #define VID_SRC_J_GPCNT_CTL 0x130F04 /* Video J general purpose control */ | ||
1212 | |||
1213 | /* ***************************************************************************** */ | ||
1214 | |||
1215 | #define VID_SRC_A_GPCNT 0x130808 /* Video A general purpose counter */ | ||
1216 | #define VID_SRC_B_GPCNT 0x130908 /* Video B general purpose counter */ | ||
1217 | #define VID_SRC_C_GPCNT 0x130A08 /* Video C general purpose counter */ | ||
1218 | #define VID_SRC_D_GPCNT 0x130B08 /* Video D general purpose counter */ | ||
1219 | #define VID_SRC_E_GPCNT 0x130C08 /* Video E general purpose counter */ | ||
1220 | #define VID_SRC_F_GPCNT 0x130D08 /* Video F general purpose counter */ | ||
1221 | #define VID_SRC_I_GPCNT 0x130E08 /* Video I general purpose counter */ | ||
1222 | #define VID_SRC_J_GPCNT 0x130F08 /* Video J general purpose counter */ | ||
1223 | |||
1224 | /* ***************************************************************************** */ | ||
1225 | |||
1226 | #define VID_SRC_A_DMA_CTL 0x13080C /* Video A DMA control */ | ||
1227 | #define VID_SRC_B_DMA_CTL 0x13090C /* Video B DMA control */ | ||
1228 | #define VID_SRC_C_DMA_CTL 0x130A0C /* Video C DMA control */ | ||
1229 | #define VID_SRC_D_DMA_CTL 0x130B0C /* Video D DMA control */ | ||
1230 | #define VID_SRC_E_DMA_CTL 0x130C0C /* Video E DMA control */ | ||
1231 | #define VID_SRC_F_DMA_CTL 0x130D0C /* Video F DMA control */ | ||
1232 | #define VID_SRC_I_DMA_CTL 0x130E0C /* Video I DMA control */ | ||
1233 | #define VID_SRC_J_DMA_CTL 0x130F0C /* Video J DMA control */ | ||
1234 | |||
1235 | #define FLD_APB_RISC_EN 0x00000010 | ||
1236 | #define FLD_APB_FIFO_EN 0x00000001 | ||
1237 | |||
1238 | /* ***************************************************************************** */ | ||
1239 | |||
1240 | #define VID_SRC_A_FMT_CTL 0x130810 /* Video A format control */ | ||
1241 | #define VID_SRC_B_FMT_CTL 0x130910 /* Video B format control */ | ||
1242 | #define VID_SRC_C_FMT_CTL 0x130A10 /* Video C format control */ | ||
1243 | #define VID_SRC_D_FMT_CTL 0x130B10 /* Video D format control */ | ||
1244 | #define VID_SRC_E_FMT_CTL 0x130C10 /* Video E format control */ | ||
1245 | #define VID_SRC_F_FMT_CTL 0x130D10 /* Video F format control */ | ||
1246 | #define VID_SRC_I_FMT_CTL 0x130E10 /* Video I format control */ | ||
1247 | #define VID_SRC_J_FMT_CTL 0x130F10 /* Video J format control */ | ||
1248 | |||
1249 | /* ***************************************************************************** */ | ||
1250 | |||
1251 | #define VID_SRC_A_ACTIVE_CTL1 0x130814 /* Video A active control 1 */ | ||
1252 | #define VID_SRC_B_ACTIVE_CTL1 0x130914 /* Video B active control 1 */ | ||
1253 | #define VID_SRC_C_ACTIVE_CTL1 0x130A14 /* Video C active control 1 */ | ||
1254 | #define VID_SRC_D_ACTIVE_CTL1 0x130B14 /* Video D active control 1 */ | ||
1255 | #define VID_SRC_E_ACTIVE_CTL1 0x130C14 /* Video E active control 1 */ | ||
1256 | #define VID_SRC_F_ACTIVE_CTL1 0x130D14 /* Video F active control 1 */ | ||
1257 | #define VID_SRC_I_ACTIVE_CTL1 0x130E14 /* Video I active control 1 */ | ||
1258 | #define VID_SRC_J_ACTIVE_CTL1 0x130F14 /* Video J active control 1 */ | ||
1259 | |||
1260 | /* ***************************************************************************** */ | ||
1261 | |||
1262 | #define VID_SRC_A_ACTIVE_CTL2 0x130818 /* Video A active control 2 */ | ||
1263 | #define VID_SRC_B_ACTIVE_CTL2 0x130918 /* Video B active control 2 */ | ||
1264 | #define VID_SRC_C_ACTIVE_CTL2 0x130A18 /* Video C active control 2 */ | ||
1265 | #define VID_SRC_D_ACTIVE_CTL2 0x130B18 /* Video D active control 2 */ | ||
1266 | #define VID_SRC_E_ACTIVE_CTL2 0x130C18 /* Video E active control 2 */ | ||
1267 | #define VID_SRC_F_ACTIVE_CTL2 0x130D18 /* Video F active control 2 */ | ||
1268 | #define VID_SRC_I_ACTIVE_CTL2 0x130E18 /* Video I active control 2 */ | ||
1269 | #define VID_SRC_J_ACTIVE_CTL2 0x130F18 /* Video J active control 2 */ | ||
1270 | |||
1271 | /* ***************************************************************************** */ | ||
1272 | |||
1273 | #define VID_SRC_A_CDT_SZ 0x13081C /* Video A CDT size */ | ||
1274 | #define VID_SRC_B_CDT_SZ 0x13091C /* Video B CDT size */ | ||
1275 | #define VID_SRC_C_CDT_SZ 0x130A1C /* Video C CDT size */ | ||
1276 | #define VID_SRC_D_CDT_SZ 0x130B1C /* Video D CDT size */ | ||
1277 | #define VID_SRC_E_CDT_SZ 0x130C1C /* Video E CDT size */ | ||
1278 | #define VID_SRC_F_CDT_SZ 0x130D1C /* Video F CDT size */ | ||
1279 | #define VID_SRC_I_CDT_SZ 0x130E1C /* Video I CDT size */ | ||
1280 | #define VID_SRC_J_CDT_SZ 0x130F1C /* Video J CDT size */ | ||
1281 | |||
1282 | /* ***************************************************************************** */ | ||
1283 | /* Audio I/F */ | ||
1284 | /* ***************************************************************************** */ | ||
1285 | #define AUD_DST_A_DMA 0x140000 /* Audio Int A DMA data port */ | ||
1286 | #define AUD_SRC_A_DMA 0x140008 /* Audio Int A DMA data port */ | ||
1287 | |||
1288 | #define AUD_A_GPCNT 0x140010 /* Audio Int A gp counter */ | ||
1289 | #define FLD_AUD_A_GP_CNT 0x0000FFFF | ||
1290 | |||
1291 | #define AUD_A_GPCNT_CTL 0x140014 /* Audio Int A gp control */ | ||
1292 | |||
1293 | #define AUD_A_LNGTH 0x140018 /* Audio Int A line length */ | ||
1294 | |||
1295 | #define AUD_A_CFG 0x14001C /* Audio Int A configuration */ | ||
1296 | |||
1297 | /* ***************************************************************************** */ | ||
1298 | #define AUD_DST_B_DMA 0x140100 /* Audio Int B DMA data port */ | ||
1299 | #define AUD_SRC_B_DMA 0x140108 /* Audio Int B DMA data port */ | ||
1300 | |||
1301 | #define AUD_B_GPCNT 0x140110 /* Audio Int B gp counter */ | ||
1302 | #define FLD_AUD_B_GP_CNT 0x0000FFFF | ||
1303 | |||
1304 | #define AUD_B_GPCNT_CTL 0x140114 /* Audio Int B gp control */ | ||
1305 | |||
1306 | #define AUD_B_LNGTH 0x140118 /* Audio Int B line length */ | ||
1307 | |||
1308 | #define AUD_B_CFG 0x14011C /* Audio Int B configuration */ | ||
1309 | |||
1310 | /* ***************************************************************************** */ | ||
1311 | #define AUD_DST_C_DMA 0x140200 /* Audio Int C DMA data port */ | ||
1312 | #define AUD_SRC_C_DMA 0x140208 /* Audio Int C DMA data port */ | ||
1313 | |||
1314 | #define AUD_C_GPCNT 0x140210 /* Audio Int C gp counter */ | ||
1315 | #define FLD_AUD_C_GP_CNT 0x0000FFFF | ||
1316 | |||
1317 | #define AUD_C_GPCNT_CTL 0x140214 /* Audio Int C gp control */ | ||
1318 | |||
1319 | #define AUD_C_LNGTH 0x140218 /* Audio Int C line length */ | ||
1320 | |||
1321 | #define AUD_C_CFG 0x14021C /* Audio Int C configuration */ | ||
1322 | |||
1323 | /* ***************************************************************************** */ | ||
1324 | #define AUD_DST_D_DMA 0x140300 /* Audio Int D DMA data port */ | ||
1325 | #define AUD_SRC_D_DMA 0x140308 /* Audio Int D DMA data port */ | ||
1326 | |||
1327 | #define AUD_D_GPCNT 0x140310 /* Audio Int D gp counter */ | ||
1328 | #define FLD_AUD_D_GP_CNT 0x0000FFFF | ||
1329 | |||
1330 | #define AUD_D_GPCNT_CTL 0x140314 /* Audio Int D gp control */ | ||
1331 | |||
1332 | #define AUD_D_LNGTH 0x140318 /* Audio Int D line length */ | ||
1333 | |||
1334 | #define AUD_D_CFG 0x14031C /* Audio Int D configuration */ | ||
1335 | |||
1336 | /* ***************************************************************************** */ | ||
1337 | #define AUD_SRC_E_DMA 0x140400 /* Audio Int E DMA data port */ | ||
1338 | |||
1339 | #define AUD_E_GPCNT 0x140410 /* Audio Int E gp counter */ | ||
1340 | #define FLD_AUD_E_GP_CNT 0x0000FFFF | ||
1341 | |||
1342 | #define AUD_E_GPCNT_CTL 0x140414 /* Audio Int E gp control */ | ||
1343 | |||
1344 | #define AUD_E_CFG 0x14041C /* Audio Int E configuration */ | ||
1345 | |||
1346 | /* ***************************************************************************** */ | ||
1347 | |||
1348 | #define FLD_AUD_DST_LN_LNGTH 0x00000FFF | ||
1349 | |||
1350 | #define FLD_AUD_DST_PK_MODE 0x00004000 | ||
1351 | |||
1352 | #define FLD_AUD_CLK_ENABLE 0x00000200 | ||
1353 | |||
1354 | #define FLD_AUD_MASTER_MODE 0x00000002 | ||
1355 | |||
1356 | #define FLD_AUD_SONY_MODE 0x00000001 | ||
1357 | |||
1358 | #define FLD_AUD_CLK_SELECT_PLL_D 0x00001800 | ||
1359 | |||
1360 | #define FLD_AUD_DST_ENABLE 0x00020000 | ||
1361 | |||
1362 | #define FLD_AUD_SRC_ENABLE 0x00010000 | ||
1363 | |||
1364 | /* ***************************************************************************** */ | ||
1365 | #define AUD_INT_DMA_CTL 0x140500 /* Audio Int DMA control */ | ||
1366 | |||
1367 | #define FLD_AUD_SRC_E_RISC_EN 0x00008000 | ||
1368 | #define FLD_AUD_SRC_C_RISC_EN 0x00004000 | ||
1369 | #define FLD_AUD_SRC_B_RISC_EN 0x00002000 | ||
1370 | #define FLD_AUD_SRC_A_RISC_EN 0x00001000 | ||
1371 | |||
1372 | #define FLD_AUD_DST_D_RISC_EN 0x00000800 | ||
1373 | #define FLD_AUD_DST_C_RISC_EN 0x00000400 | ||
1374 | #define FLD_AUD_DST_B_RISC_EN 0x00000200 | ||
1375 | #define FLD_AUD_DST_A_RISC_EN 0x00000100 | ||
1376 | |||
1377 | #define FLD_AUD_SRC_E_FIFO_EN 0x00000080 | ||
1378 | #define FLD_AUD_SRC_C_FIFO_EN 0x00000040 | ||
1379 | #define FLD_AUD_SRC_B_FIFO_EN 0x00000020 | ||
1380 | #define FLD_AUD_SRC_A_FIFO_EN 0x00000010 | ||
1381 | |||
1382 | #define FLD_AUD_DST_D_FIFO_EN 0x00000008 | ||
1383 | #define FLD_AUD_DST_C_FIFO_EN 0x00000004 | ||
1384 | #define FLD_AUD_DST_B_FIFO_EN 0x00000002 | ||
1385 | #define FLD_AUD_DST_A_FIFO_EN 0x00000001 | ||
1386 | |||
1387 | /* ***************************************************************************** */ | ||
1388 | /* */ | ||
1389 | /* Mobilygen Interface Registers */ | ||
1390 | /* */ | ||
1391 | /* ***************************************************************************** */ | ||
1392 | /* Mobilygen Interface A */ | ||
1393 | /* ***************************************************************************** */ | ||
1394 | #define MB_IF_A_DMA 0x150000 /* MBIF A DMA data port */ | ||
1395 | #define MB_IF_A_GPCN 0x150008 /* MBIF A GP counter */ | ||
1396 | #define MB_IF_A_GPCN_CTRL 0x15000C | ||
1397 | #define MB_IF_A_DMA_CTRL 0x150010 | ||
1398 | #define MB_IF_A_LENGTH 0x150014 | ||
1399 | #define MB_IF_A_HDMA_XFER_SZ 0x150018 | ||
1400 | #define MB_IF_A_HCMD 0x15001C | ||
1401 | #define MB_IF_A_HCONFIG 0x150020 | ||
1402 | #define MB_IF_A_DATA_STRUCT_0 0x150024 | ||
1403 | #define MB_IF_A_DATA_STRUCT_1 0x150028 | ||
1404 | #define MB_IF_A_DATA_STRUCT_2 0x15002C | ||
1405 | #define MB_IF_A_DATA_STRUCT_3 0x150030 | ||
1406 | #define MB_IF_A_DATA_STRUCT_4 0x150034 | ||
1407 | #define MB_IF_A_DATA_STRUCT_5 0x150038 | ||
1408 | #define MB_IF_A_DATA_STRUCT_6 0x15003C | ||
1409 | #define MB_IF_A_DATA_STRUCT_7 0x150040 | ||
1410 | #define MB_IF_A_DATA_STRUCT_8 0x150044 | ||
1411 | #define MB_IF_A_DATA_STRUCT_9 0x150048 | ||
1412 | #define MB_IF_A_DATA_STRUCT_A 0x15004C | ||
1413 | #define MB_IF_A_DATA_STRUCT_B 0x150050 | ||
1414 | #define MB_IF_A_DATA_STRUCT_C 0x150054 | ||
1415 | #define MB_IF_A_DATA_STRUCT_D 0x150058 | ||
1416 | #define MB_IF_A_DATA_STRUCT_E 0x15005C | ||
1417 | #define MB_IF_A_DATA_STRUCT_F 0x150060 | ||
1418 | /* ***************************************************************************** */ | ||
1419 | /* Mobilygen Interface B */ | ||
1420 | /* ***************************************************************************** */ | ||
1421 | #define MB_IF_B_DMA 0x160000 /* MBIF A DMA data port */ | ||
1422 | #define MB_IF_B_GPCN 0x160008 /* MBIF A GP counter */ | ||
1423 | #define MB_IF_B_GPCN_CTRL 0x16000C | ||
1424 | #define MB_IF_B_DMA_CTRL 0x160010 | ||
1425 | #define MB_IF_B_LENGTH 0x160014 | ||
1426 | #define MB_IF_B_HDMA_XFER_SZ 0x160018 | ||
1427 | #define MB_IF_B_HCMD 0x16001C | ||
1428 | #define MB_IF_B_HCONFIG 0x160020 | ||
1429 | #define MB_IF_B_DATA_STRUCT_0 0x160024 | ||
1430 | #define MB_IF_B_DATA_STRUCT_1 0x160028 | ||
1431 | #define MB_IF_B_DATA_STRUCT_2 0x16002C | ||
1432 | #define MB_IF_B_DATA_STRUCT_3 0x160030 | ||
1433 | #define MB_IF_B_DATA_STRUCT_4 0x160034 | ||
1434 | #define MB_IF_B_DATA_STRUCT_5 0x160038 | ||
1435 | #define MB_IF_B_DATA_STRUCT_6 0x16003C | ||
1436 | #define MB_IF_B_DATA_STRUCT_7 0x160040 | ||
1437 | #define MB_IF_B_DATA_STRUCT_8 0x160044 | ||
1438 | #define MB_IF_B_DATA_STRUCT_9 0x160048 | ||
1439 | #define MB_IF_B_DATA_STRUCT_A 0x16004C | ||
1440 | #define MB_IF_B_DATA_STRUCT_B 0x160050 | ||
1441 | #define MB_IF_B_DATA_STRUCT_C 0x160054 | ||
1442 | #define MB_IF_B_DATA_STRUCT_D 0x160058 | ||
1443 | #define MB_IF_B_DATA_STRUCT_E 0x16005C | ||
1444 | #define MB_IF_B_DATA_STRUCT_F 0x160060 | ||
1445 | |||
1446 | /* MB_DMA_CTRL */ | ||
1447 | #define FLD_MB_IF_RISC_EN 0x00000010 | ||
1448 | #define FLD_MB_IF_FIFO_EN 0x00000001 | ||
1449 | |||
1450 | /* MB_LENGTH */ | ||
1451 | #define FLD_MB_IF_LN_LNGTH 0x00000FFF | ||
1452 | |||
1453 | /* MB_HCMD register */ | ||
1454 | #define FLD_MB_HCMD_H_GO 0x80000000 | ||
1455 | #define FLD_MB_HCMD_H_BUSY 0x40000000 | ||
1456 | #define FLD_MB_HCMD_H_DMA_HOLD 0x10000000 | ||
1457 | #define FLD_MB_HCMD_H_DMA_BUSY 0x08000000 | ||
1458 | #define FLD_MB_HCMD_H_DMA_TYPE 0x04000000 | ||
1459 | #define FLD_MB_HCMD_H_DMA_XACT 0x02000000 | ||
1460 | #define FLD_MB_HCMD_H_RW_N 0x01000000 | ||
1461 | #define FLD_MB_HCMD_H_ADDR 0x00FF0000 | ||
1462 | #define FLD_MB_HCMD_H_DATA 0x0000FFFF | ||
1463 | |||
1464 | /* ***************************************************************************** */ | ||
1465 | /* I2C #1 */ | ||
1466 | /* ***************************************************************************** */ | ||
1467 | #define I2C1_ADDR 0x180000 /* I2C #1 address */ | ||
1468 | #define FLD_I2C_DADDR 0xfe000000 /* RW [31:25] I2C Device Address */ | ||
1469 | /* RO [24] reserved */ | ||
1470 | /* ***************************************************************************** */ | ||
1471 | #define FLD_I2C_SADDR 0x00FFFFFF /* RW [23:0] I2C Sub-address */ | ||
1472 | |||
1473 | /* ***************************************************************************** */ | ||
1474 | #define I2C1_WDATA 0x180004 /* I2C #1 write data */ | ||
1475 | #define FLD_I2C_WDATA 0xFFFFFFFF /* RW [31:0] */ | ||
1476 | |||
1477 | /* ***************************************************************************** */ | ||
1478 | #define I2C1_CTRL 0x180008 /* I2C #1 control */ | ||
1479 | #define FLD_I2C_PERIOD 0xFF000000 /* RW [31:24] */ | ||
1480 | #define FLD_I2C_SCL_IN 0x00200000 /* RW [21] */ | ||
1481 | #define FLD_I2C_SDA_IN 0x00100000 /* RW [20] */ | ||
1482 | /* RO [19:18] reserved */ | ||
1483 | #define FLD_I2C_SCL_OUT 0x00020000 /* RW [17] */ | ||
1484 | #define FLD_I2C_SDA_OUT 0x00010000 /* RW [16] */ | ||
1485 | /* RO [15] reserved */ | ||
1486 | #define FLD_I2C_DATA_LEN 0x00007000 /* RW [14:12] */ | ||
1487 | #define FLD_I2C_SADDR_INC 0x00000800 /* RW [11] */ | ||
1488 | /* RO [10:9] reserved */ | ||
1489 | #define FLD_I2C_SADDR_LEN 0x00000300 /* RW [9:8] */ | ||
1490 | /* RO [7:6] reserved */ | ||
1491 | #define FLD_I2C_SOFT 0x00000020 /* RW [5] */ | ||
1492 | #define FLD_I2C_NOSTOP 0x00000010 /* RW [4] */ | ||
1493 | #define FLD_I2C_EXTEND 0x00000008 /* RW [3] */ | ||
1494 | #define FLD_I2C_SYNC 0x00000004 /* RW [2] */ | ||
1495 | #define FLD_I2C_READ_SA 0x00000002 /* RW [1] */ | ||
1496 | #define FLD_I2C_READ_WRN 0x00000001 /* RW [0] */ | ||
1497 | |||
1498 | /* ***************************************************************************** */ | ||
1499 | #define I2C1_RDATA 0x18000C /* I2C #1 read data */ | ||
1500 | #define FLD_I2C_RDATA 0xFFFFFFFF /* RO [31:0] */ | ||
1501 | |||
1502 | /* ***************************************************************************** */ | ||
1503 | #define I2C1_STAT 0x180010 /* I2C #1 status */ | ||
1504 | #define FLD_I2C_XFER_IN_PROG 0x00000002 /* RO [1] */ | ||
1505 | #define FLD_I2C_RACK 0x00000001 /* RO [0] */ | ||
1506 | |||
1507 | /* ***************************************************************************** */ | ||
1508 | /* I2C #2 */ | ||
1509 | /* ***************************************************************************** */ | ||
1510 | #define I2C2_ADDR 0x190000 /* I2C #2 address */ | ||
1511 | |||
1512 | /* ***************************************************************************** */ | ||
1513 | #define I2C2_WDATA 0x190004 /* I2C #2 write data */ | ||
1514 | |||
1515 | /* ***************************************************************************** */ | ||
1516 | #define I2C2_CTRL 0x190008 /* I2C #2 control */ | ||
1517 | |||
1518 | /* ***************************************************************************** */ | ||
1519 | #define I2C2_RDATA 0x19000C /* I2C #2 read data */ | ||
1520 | |||
1521 | /* ***************************************************************************** */ | ||
1522 | #define I2C2_STAT 0x190010 /* I2C #2 status */ | ||
1523 | |||
1524 | /* ***************************************************************************** */ | ||
1525 | /* I2C #3 */ | ||
1526 | /* ***************************************************************************** */ | ||
1527 | #define I2C3_ADDR 0x1A0000 /* I2C #3 address */ | ||
1528 | |||
1529 | /* ***************************************************************************** */ | ||
1530 | #define I2C3_WDATA 0x1A0004 /* I2C #3 write data */ | ||
1531 | |||
1532 | /* ***************************************************************************** */ | ||
1533 | #define I2C3_CTRL 0x1A0008 /* I2C #3 control */ | ||
1534 | |||
1535 | /* ***************************************************************************** */ | ||
1536 | #define I2C3_RDATA 0x1A000C /* I2C #3 read data */ | ||
1537 | |||
1538 | /* ***************************************************************************** */ | ||
1539 | #define I2C3_STAT 0x1A0010 /* I2C #3 status */ | ||
1540 | |||
1541 | /* ***************************************************************************** */ | ||
1542 | /* UART */ | ||
1543 | /* ***************************************************************************** */ | ||
1544 | #define UART_CTL 0x1B0000 /* UART Control Register */ | ||
1545 | #define FLD_LOOP_BACK_EN (1 << 7) /* RW field - default 0 */ | ||
1546 | #define FLD_RX_TRG_SZ (3 << 2) /* RW field - default 0 */ | ||
1547 | #define FLD_RX_EN (1 << 1) /* RW field - default 0 */ | ||
1548 | #define FLD_TX_EN (1 << 0) /* RW field - default 0 */ | ||
1549 | |||
1550 | /* ***************************************************************************** */ | ||
1551 | #define UART_BRD 0x1B0004 /* UART Baud Rate Divisor */ | ||
1552 | #define FLD_BRD 0x0000FFFF /* RW field - default 0x197 */ | ||
1553 | |||
1554 | /* ***************************************************************************** */ | ||
1555 | #define UART_DBUF 0x1B0008 /* UART Tx/Rx Data BuFFer */ | ||
1556 | #define FLD_DB 0xFFFFFFFF /* RW field - default 0 */ | ||
1557 | |||
1558 | /* ***************************************************************************** */ | ||
1559 | #define UART_ISR 0x1B000C /* UART Interrupt Status */ | ||
1560 | #define FLD_RXD_TIMEOUT_EN (1 << 7) /* RW field - default 0 */ | ||
1561 | #define FLD_FRM_ERR_EN (1 << 6) /* RW field - default 0 */ | ||
1562 | #define FLD_RXD_RDY_EN (1 << 5) /* RW field - default 0 */ | ||
1563 | #define FLD_TXD_EMPTY_EN (1 << 4) /* RW field - default 0 */ | ||
1564 | #define FLD_RXD_OVERFLOW (1 << 3) /* RW field - default 0 */ | ||
1565 | #define FLD_FRM_ERR (1 << 2) /* RW field - default 0 */ | ||
1566 | #define FLD_RXD_RDY (1 << 1) /* RW field - default 0 */ | ||
1567 | #define FLD_TXD_EMPTY (1 << 0) /* RW field - default 0 */ | ||
1568 | |||
1569 | /* ***************************************************************************** */ | ||
1570 | #define UART_CNT 0x1B0010 /* UART Tx/Rx FIFO Byte Count */ | ||
1571 | #define FLD_TXD_CNT (0x1F << 8) /* RW field - default 0 */ | ||
1572 | #define FLD_RXD_CNT (0x1F << 0) /* RW field - default 0 */ | ||
1573 | |||
1574 | /* ***************************************************************************** */ | ||
1575 | /* Motion Detection */ | ||
1576 | #define MD_CH0_GRID_BLOCK_YCNT 0x170014 | ||
1577 | #define MD_CH1_GRID_BLOCK_YCNT 0x170094 | ||
1578 | #define MD_CH2_GRID_BLOCK_YCNT 0x170114 | ||
1579 | #define MD_CH3_GRID_BLOCK_YCNT 0x170194 | ||
1580 | #define MD_CH4_GRID_BLOCK_YCNT 0x170214 | ||
1581 | #define MD_CH5_GRID_BLOCK_YCNT 0x170294 | ||
1582 | #define MD_CH6_GRID_BLOCK_YCNT 0x170314 | ||
1583 | #define MD_CH7_GRID_BLOCK_YCNT 0x170394 | ||
1584 | |||
1585 | #define PIXEL_FRMT_422 4 | ||
1586 | #define PIXEL_FRMT_411 5 | ||
1587 | #define PIXEL_FRMT_Y8 6 | ||
1588 | |||
1589 | #define PIXEL_ENGINE_VIP1 0 | ||
1590 | #define PIXEL_ENGINE_VIP2 1 | ||
1591 | |||
1592 | #endif /* Athena_REGISTERS */ | ||
diff --git a/drivers/media/video/cx25821/cx25821-sram.h b/drivers/media/video/cx25821/cx25821-sram.h new file mode 100644 index 000000000000..5f05d153bc4d --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-sram.h | |||
@@ -0,0 +1,261 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #ifndef __ATHENA_SRAM_H__ | ||
24 | #define __ATHENA_SRAM_H__ | ||
25 | |||
26 | /* #define RX_SRAM_START_SIZE = 0; // Start of reserved SRAM */ | ||
27 | #define VID_CMDS_SIZE 80 /* Video CMDS size in bytes */ | ||
28 | #define AUDIO_CMDS_SIZE 80 /* AUDIO CMDS size in bytes */ | ||
29 | #define MBIF_CMDS_SIZE 80 /* MBIF CMDS size in bytes */ | ||
30 | |||
31 | /* #define RX_SRAM_POOL_START_SIZE = 0; // Start of useable RX SRAM for buffers */ | ||
32 | #define VID_IQ_SIZE 64 /* VID instruction queue size in bytes */ | ||
33 | #define MBIF_IQ_SIZE 64 | ||
34 | #define AUDIO_IQ_SIZE 64 /* AUD instruction queue size in bytes */ | ||
35 | |||
36 | #define VID_CDT_SIZE 64 /* VID cluster descriptor table size in bytes */ | ||
37 | #define MBIF_CDT_SIZE 64 /* MBIF/HBI cluster descriptor table size in bytes */ | ||
38 | #define AUDIO_CDT_SIZE 48 /* AUD cluster descriptor table size in bytes */ | ||
39 | |||
40 | /* #define RX_SRAM_POOL_FREE_SIZE = 16; // Start of available RX SRAM */ | ||
41 | /* #define RX_SRAM_END_SIZE = 0; // End of RX SRAM */ | ||
42 | |||
43 | /* #define TX_SRAM_POOL_START_SIZE = 0; // Start of transmit pool SRAM */ | ||
44 | /* #define MSI_DATA_SIZE = 64; // Reserved (MSI Data, RISC working stora */ | ||
45 | |||
46 | #define VID_CLUSTER_SIZE 1440 /* VID cluster data line */ | ||
47 | #define AUDIO_CLUSTER_SIZE 128 /* AUDIO cluster data line */ | ||
48 | #define MBIF_CLUSTER_SIZE 1440 /* MBIF/HBI cluster data line */ | ||
49 | |||
50 | /* #define TX_SRAM_POOL_FREE_SIZE = 704; // Start of available TX SRAM */ | ||
51 | /* #define TX_SRAM_END_SIZE = 0; // End of TX SRAM */ | ||
52 | |||
53 | /* Receive SRAM */ | ||
54 | #define RX_SRAM_START 0x10000 | ||
55 | #define VID_A_DOWN_CMDS 0x10000 | ||
56 | #define VID_B_DOWN_CMDS 0x10050 | ||
57 | #define VID_C_DOWN_CMDS 0x100A0 | ||
58 | #define VID_D_DOWN_CMDS 0x100F0 | ||
59 | #define VID_E_DOWN_CMDS 0x10140 | ||
60 | #define VID_F_DOWN_CMDS 0x10190 | ||
61 | #define VID_G_DOWN_CMDS 0x101E0 | ||
62 | #define VID_H_DOWN_CMDS 0x10230 | ||
63 | #define VID_A_UP_CMDS 0x10280 | ||
64 | #define VID_B_UP_CMDS 0x102D0 | ||
65 | #define VID_C_UP_CMDS 0x10320 | ||
66 | #define VID_D_UP_CMDS 0x10370 | ||
67 | #define VID_E_UP_CMDS 0x103C0 | ||
68 | #define VID_F_UP_CMDS 0x10410 | ||
69 | #define VID_I_UP_CMDS 0x10460 | ||
70 | #define VID_J_UP_CMDS 0x104B0 | ||
71 | #define AUD_A_DOWN_CMDS 0x10500 | ||
72 | #define AUD_B_DOWN_CMDS 0x10550 | ||
73 | #define AUD_C_DOWN_CMDS 0x105A0 | ||
74 | #define AUD_D_DOWN_CMDS 0x105F0 | ||
75 | #define AUD_A_UP_CMDS 0x10640 | ||
76 | #define AUD_B_UP_CMDS 0x10690 | ||
77 | #define AUD_C_UP_CMDS 0x106E0 | ||
78 | #define AUD_E_UP_CMDS 0x10730 | ||
79 | #define MBIF_A_DOWN_CMDS 0x10780 | ||
80 | #define MBIF_B_DOWN_CMDS 0x107D0 | ||
81 | #define DMA_SCRATCH_PAD 0x10820 /* Scratch pad area from 0x10820 to 0x10B40 */ | ||
82 | |||
83 | /* #define RX_SRAM_POOL_START = 0x105B0; */ | ||
84 | |||
85 | #define VID_A_IQ 0x11000 | ||
86 | #define VID_B_IQ 0x11040 | ||
87 | #define VID_C_IQ 0x11080 | ||
88 | #define VID_D_IQ 0x110C0 | ||
89 | #define VID_E_IQ 0x11100 | ||
90 | #define VID_F_IQ 0x11140 | ||
91 | #define VID_G_IQ 0x11180 | ||
92 | #define VID_H_IQ 0x111C0 | ||
93 | #define VID_I_IQ 0x11200 | ||
94 | #define VID_J_IQ 0x11240 | ||
95 | #define AUD_A_IQ 0x11280 | ||
96 | #define AUD_B_IQ 0x112C0 | ||
97 | #define AUD_C_IQ 0x11300 | ||
98 | #define AUD_D_IQ 0x11340 | ||
99 | #define AUD_E_IQ 0x11380 | ||
100 | #define MBIF_A_IQ 0x11000 | ||
101 | #define MBIF_B_IQ 0x110C0 | ||
102 | |||
103 | #define VID_A_CDT 0x10C00 | ||
104 | #define VID_B_CDT 0x10C40 | ||
105 | #define VID_C_CDT 0x10C80 | ||
106 | #define VID_D_CDT 0x10CC0 | ||
107 | #define VID_E_CDT 0x10D00 | ||
108 | #define VID_F_CDT 0x10D40 | ||
109 | #define VID_G_CDT 0x10D80 | ||
110 | #define VID_H_CDT 0x10DC0 | ||
111 | #define VID_I_CDT 0x10E00 | ||
112 | #define VID_J_CDT 0x10E40 | ||
113 | #define AUD_A_CDT 0x10E80 | ||
114 | #define AUD_B_CDT 0x10EB0 | ||
115 | #define AUD_C_CDT 0x10EE0 | ||
116 | #define AUD_D_CDT 0x10F10 | ||
117 | #define AUD_E_CDT 0x10F40 | ||
118 | #define MBIF_A_CDT 0x10C00 | ||
119 | #define MBIF_B_CDT 0x10CC0 | ||
120 | |||
121 | /* Cluster Buffer for RX */ | ||
122 | #define VID_A_UP_CLUSTER_1 0x11400 | ||
123 | #define VID_A_UP_CLUSTER_2 0x119A0 | ||
124 | #define VID_A_UP_CLUSTER_3 0x11F40 | ||
125 | #define VID_A_UP_CLUSTER_4 0x124E0 | ||
126 | |||
127 | #define VID_B_UP_CLUSTER_1 0x12A80 | ||
128 | #define VID_B_UP_CLUSTER_2 0x13020 | ||
129 | #define VID_B_UP_CLUSTER_3 0x135C0 | ||
130 | #define VID_B_UP_CLUSTER_4 0x13B60 | ||
131 | |||
132 | #define VID_C_UP_CLUSTER_1 0x14100 | ||
133 | #define VID_C_UP_CLUSTER_2 0x146A0 | ||
134 | #define VID_C_UP_CLUSTER_3 0x14C40 | ||
135 | #define VID_C_UP_CLUSTER_4 0x151E0 | ||
136 | |||
137 | #define VID_D_UP_CLUSTER_1 0x15780 | ||
138 | #define VID_D_UP_CLUSTER_2 0x15D20 | ||
139 | #define VID_D_UP_CLUSTER_3 0x162C0 | ||
140 | #define VID_D_UP_CLUSTER_4 0x16860 | ||
141 | |||
142 | #define VID_E_UP_CLUSTER_1 0x16E00 | ||
143 | #define VID_E_UP_CLUSTER_2 0x173A0 | ||
144 | #define VID_E_UP_CLUSTER_3 0x17940 | ||
145 | #define VID_E_UP_CLUSTER_4 0x17EE0 | ||
146 | |||
147 | #define VID_F_UP_CLUSTER_1 0x18480 | ||
148 | #define VID_F_UP_CLUSTER_2 0x18A20 | ||
149 | #define VID_F_UP_CLUSTER_3 0x18FC0 | ||
150 | #define VID_F_UP_CLUSTER_4 0x19560 | ||
151 | |||
152 | #define VID_I_UP_CLUSTER_1 0x19B00 | ||
153 | #define VID_I_UP_CLUSTER_2 0x1A0A0 | ||
154 | #define VID_I_UP_CLUSTER_3 0x1A640 | ||
155 | #define VID_I_UP_CLUSTER_4 0x1ABE0 | ||
156 | |||
157 | #define VID_J_UP_CLUSTER_1 0x1B180 | ||
158 | #define VID_J_UP_CLUSTER_2 0x1B720 | ||
159 | #define VID_J_UP_CLUSTER_3 0x1BCC0 | ||
160 | #define VID_J_UP_CLUSTER_4 0x1C260 | ||
161 | |||
162 | #define AUD_A_UP_CLUSTER_1 0x1C800 | ||
163 | #define AUD_A_UP_CLUSTER_2 0x1C880 | ||
164 | #define AUD_A_UP_CLUSTER_3 0x1C900 | ||
165 | |||
166 | #define AUD_B_UP_CLUSTER_1 0x1C980 | ||
167 | #define AUD_B_UP_CLUSTER_2 0x1CA00 | ||
168 | #define AUD_B_UP_CLUSTER_3 0x1CA80 | ||
169 | |||
170 | #define AUD_C_UP_CLUSTER_1 0x1CB00 | ||
171 | #define AUD_C_UP_CLUSTER_2 0x1CB80 | ||
172 | #define AUD_C_UP_CLUSTER_3 0x1CC00 | ||
173 | |||
174 | #define AUD_E_UP_CLUSTER_1 0x1CC80 | ||
175 | #define AUD_E_UP_CLUSTER_2 0x1CD00 | ||
176 | #define AUD_E_UP_CLUSTER_3 0x1CD80 | ||
177 | |||
178 | #define RX_SRAM_POOL_FREE 0x1CE00 | ||
179 | #define RX_SRAM_END 0x1D000 | ||
180 | |||
181 | /* Free Receive SRAM 144 Bytes */ | ||
182 | |||
183 | /* Transmit SRAM */ | ||
184 | #define TX_SRAM_POOL_START 0x00000 | ||
185 | |||
186 | #define VID_A_DOWN_CLUSTER_1 0x00040 | ||
187 | #define VID_A_DOWN_CLUSTER_2 0x005E0 | ||
188 | #define VID_A_DOWN_CLUSTER_3 0x00B80 | ||
189 | #define VID_A_DOWN_CLUSTER_4 0x01120 | ||
190 | |||
191 | #define VID_B_DOWN_CLUSTER_1 0x016C0 | ||
192 | #define VID_B_DOWN_CLUSTER_2 0x01C60 | ||
193 | #define VID_B_DOWN_CLUSTER_3 0x02200 | ||
194 | #define VID_B_DOWN_CLUSTER_4 0x027A0 | ||
195 | |||
196 | #define VID_C_DOWN_CLUSTER_1 0x02D40 | ||
197 | #define VID_C_DOWN_CLUSTER_2 0x032E0 | ||
198 | #define VID_C_DOWN_CLUSTER_3 0x03880 | ||
199 | #define VID_C_DOWN_CLUSTER_4 0x03E20 | ||
200 | |||
201 | #define VID_D_DOWN_CLUSTER_1 0x043C0 | ||
202 | #define VID_D_DOWN_CLUSTER_2 0x04960 | ||
203 | #define VID_D_DOWN_CLUSTER_3 0x04F00 | ||
204 | #define VID_D_DOWN_CLUSTER_4 0x054A0 | ||
205 | |||
206 | #define VID_E_DOWN_CLUSTER_1 0x05a40 | ||
207 | #define VID_E_DOWN_CLUSTER_2 0x05FE0 | ||
208 | #define VID_E_DOWN_CLUSTER_3 0x06580 | ||
209 | #define VID_E_DOWN_CLUSTER_4 0x06B20 | ||
210 | |||
211 | #define VID_F_DOWN_CLUSTER_1 0x070C0 | ||
212 | #define VID_F_DOWN_CLUSTER_2 0x07660 | ||
213 | #define VID_F_DOWN_CLUSTER_3 0x07C00 | ||
214 | #define VID_F_DOWN_CLUSTER_4 0x081A0 | ||
215 | |||
216 | #define VID_G_DOWN_CLUSTER_1 0x08740 | ||
217 | #define VID_G_DOWN_CLUSTER_2 0x08CE0 | ||
218 | #define VID_G_DOWN_CLUSTER_3 0x09280 | ||
219 | #define VID_G_DOWN_CLUSTER_4 0x09820 | ||
220 | |||
221 | #define VID_H_DOWN_CLUSTER_1 0x09DC0 | ||
222 | #define VID_H_DOWN_CLUSTER_2 0x0A360 | ||
223 | #define VID_H_DOWN_CLUSTER_3 0x0A900 | ||
224 | #define VID_H_DOWN_CLUSTER_4 0x0AEA0 | ||
225 | |||
226 | #define AUD_A_DOWN_CLUSTER_1 0x0B500 | ||
227 | #define AUD_A_DOWN_CLUSTER_2 0x0B580 | ||
228 | #define AUD_A_DOWN_CLUSTER_3 0x0B600 | ||
229 | |||
230 | #define AUD_B_DOWN_CLUSTER_1 0x0B680 | ||
231 | #define AUD_B_DOWN_CLUSTER_2 0x0B700 | ||
232 | #define AUD_B_DOWN_CLUSTER_3 0x0B780 | ||
233 | |||
234 | #define AUD_C_DOWN_CLUSTER_1 0x0B800 | ||
235 | #define AUD_C_DOWN_CLUSTER_2 0x0B880 | ||
236 | #define AUD_C_DOWN_CLUSTER_3 0x0B900 | ||
237 | |||
238 | #define AUD_D_DOWN_CLUSTER_1 0x0B980 | ||
239 | #define AUD_D_DOWN_CLUSTER_2 0x0BA00 | ||
240 | #define AUD_D_DOWN_CLUSTER_3 0x0BA80 | ||
241 | |||
242 | #define TX_SRAM_POOL_FREE 0x0BB00 | ||
243 | #define TX_SRAM_END 0x0C000 | ||
244 | |||
245 | #define BYTES_TO_DWORDS(bcount) ((bcount) >> 2) | ||
246 | #define BYTES_TO_QWORDS(bcount) ((bcount) >> 3) | ||
247 | #define BYTES_TO_OWORDS(bcount) ((bcount) >> 4) | ||
248 | |||
249 | #define VID_IQ_SIZE_DW BYTES_TO_DWORDS(VID_IQ_SIZE) | ||
250 | #define VID_CDT_SIZE_QW BYTES_TO_QWORDS(VID_CDT_SIZE) | ||
251 | #define VID_CLUSTER_SIZE_OW BYTES_TO_OWORDS(VID_CLUSTER_SIZE) | ||
252 | |||
253 | #define AUDIO_IQ_SIZE_DW BYTES_TO_DWORDS(AUDIO_IQ_SIZE) | ||
254 | #define AUDIO_CDT_SIZE_QW BYTES_TO_QWORDS(AUDIO_CDT_SIZE) | ||
255 | #define AUDIO_CLUSTER_SIZE_QW BYTES_TO_QWORDS(AUDIO_CLUSTER_SIZE) | ||
256 | |||
257 | #define MBIF_IQ_SIZE_DW BYTES_TO_DWORDS(MBIF_IQ_SIZE) | ||
258 | #define MBIF_CDT_SIZE_QW BYTES_TO_QWORDS(MBIF_CDT_SIZE) | ||
259 | #define MBIF_CLUSTER_SIZE_OW BYTES_TO_OWORDS(MBIF_CLUSTER_SIZE) | ||
260 | |||
261 | #endif | ||
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c new file mode 100644 index 000000000000..2a724ddfa53f --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c | |||
@@ -0,0 +1,823 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
24 | |||
25 | #include "cx25821-video.h" | ||
26 | #include "cx25821-video-upstream-ch2.h" | ||
27 | |||
28 | #include <linux/fs.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/syscalls.h> | ||
34 | #include <linux/file.h> | ||
35 | #include <linux/fcntl.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/uaccess.h> | ||
38 | |||
39 | MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); | ||
40 | MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | | ||
44 | FLD_VID_SRC_OPC_ERR; | ||
45 | |||
46 | static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev, | ||
47 | __le32 *rp, unsigned int offset, | ||
48 | unsigned int bpl, u32 sync_line, | ||
49 | unsigned int lines, | ||
50 | int fifo_enable, int field_type) | ||
51 | { | ||
52 | unsigned int line, i; | ||
53 | int dist_betwn_starts = bpl * 2; | ||
54 | |||
55 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
56 | |||
57 | if (USE_RISC_NOOP_VIDEO) { | ||
58 | for (i = 0; i < NUM_NO_OPS; i++) | ||
59 | *(rp++) = cpu_to_le32(RISC_NOOP); | ||
60 | } | ||
61 | |||
62 | /* scan lines */ | ||
63 | for (line = 0; line < lines; line++) { | ||
64 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | ||
65 | *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset); | ||
66 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
67 | |||
68 | if ((lines <= NTSC_FIELD_HEIGHT) | ||
69 | || (line < (NTSC_FIELD_HEIGHT - 1)) | ||
70 | || !(dev->_isNTSC_ch2)) { | ||
71 | offset += dist_betwn_starts; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | return rp; | ||
76 | } | ||
77 | |||
78 | static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, | ||
79 | __le32 *rp, | ||
80 | dma_addr_t databuf_phys_addr, | ||
81 | unsigned int offset, | ||
82 | u32 sync_line, unsigned int bpl, | ||
83 | unsigned int lines, | ||
84 | int fifo_enable, int field_type) | ||
85 | { | ||
86 | unsigned int line, i; | ||
87 | struct sram_channel *sram_ch = | ||
88 | dev->channels[dev->_channel2_upstream_select].sram_channels; | ||
89 | int dist_betwn_starts = bpl * 2; | ||
90 | |||
91 | /* sync instruction */ | ||
92 | if (sync_line != NO_SYNC_LINE) | ||
93 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
94 | |||
95 | if (USE_RISC_NOOP_VIDEO) { | ||
96 | for (i = 0; i < NUM_NO_OPS; i++) | ||
97 | *(rp++) = cpu_to_le32(RISC_NOOP); | ||
98 | } | ||
99 | |||
100 | /* scan lines */ | ||
101 | for (line = 0; line < lines; line++) { | ||
102 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | ||
103 | *(rp++) = cpu_to_le32(databuf_phys_addr + offset); | ||
104 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
105 | |||
106 | if ((lines <= NTSC_FIELD_HEIGHT) | ||
107 | || (line < (NTSC_FIELD_HEIGHT - 1)) | ||
108 | || !(dev->_isNTSC_ch2)) { | ||
109 | offset += dist_betwn_starts; | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | check if we need to enable the FIFO after the first 4 lines | ||
114 | For the upstream video channel, the risc engine will enable | ||
115 | the FIFO. | ||
116 | */ | ||
117 | if (fifo_enable && line == 3) { | ||
118 | *(rp++) = RISC_WRITECR; | ||
119 | *(rp++) = sram_ch->dma_ctl; | ||
120 | *(rp++) = FLD_VID_FIFO_EN; | ||
121 | *(rp++) = 0x00000001; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | return rp; | ||
126 | } | ||
127 | |||
128 | int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, | ||
129 | struct pci_dev *pci, | ||
130 | unsigned int top_offset, unsigned int bpl, | ||
131 | unsigned int lines) | ||
132 | { | ||
133 | __le32 *rp; | ||
134 | int fifo_enable = 0; | ||
135 | int singlefield_lines = lines >> 1; /*get line count for single field */ | ||
136 | int odd_num_lines = singlefield_lines; | ||
137 | int frame = 0; | ||
138 | int frame_size = 0; | ||
139 | int databuf_offset = 0; | ||
140 | int risc_program_size = 0; | ||
141 | int risc_flag = RISC_CNT_RESET; | ||
142 | unsigned int bottom_offset = bpl; | ||
143 | dma_addr_t risc_phys_jump_addr; | ||
144 | |||
145 | if (dev->_isNTSC_ch2) { | ||
146 | odd_num_lines = singlefield_lines + 1; | ||
147 | risc_program_size = FRAME1_VID_PROG_SIZE; | ||
148 | if (bpl == Y411_LINE_SZ) | ||
149 | frame_size = FRAME_SIZE_NTSC_Y411; | ||
150 | else | ||
151 | frame_size = FRAME_SIZE_NTSC_Y422; | ||
152 | } else { | ||
153 | risc_program_size = PAL_VID_PROG_SIZE; | ||
154 | if (bpl == Y411_LINE_SZ) | ||
155 | frame_size = FRAME_SIZE_PAL_Y411; | ||
156 | else | ||
157 | frame_size = FRAME_SIZE_PAL_Y422; | ||
158 | } | ||
159 | |||
160 | /* Virtual address of Risc buffer program */ | ||
161 | rp = dev->_dma_virt_addr_ch2; | ||
162 | |||
163 | for (frame = 0; frame < NUM_FRAMES; frame++) { | ||
164 | databuf_offset = frame_size * frame; | ||
165 | |||
166 | if (UNSET != top_offset) { | ||
167 | fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; | ||
168 | rp = cx25821_risc_field_upstream_ch2(dev, rp, | ||
169 | dev->_data_buf_phys_addr_ch2 + databuf_offset, | ||
170 | top_offset, 0, bpl, odd_num_lines, fifo_enable, | ||
171 | ODD_FIELD); | ||
172 | } | ||
173 | |||
174 | fifo_enable = FIFO_DISABLE; | ||
175 | |||
176 | /* Even field */ | ||
177 | rp = cx25821_risc_field_upstream_ch2(dev, rp, | ||
178 | dev->_data_buf_phys_addr_ch2 + databuf_offset, | ||
179 | bottom_offset, 0x200, bpl, singlefield_lines, | ||
180 | fifo_enable, EVEN_FIELD); | ||
181 | |||
182 | if (frame == 0) { | ||
183 | risc_flag = RISC_CNT_RESET; | ||
184 | risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2 + | ||
185 | risc_program_size; | ||
186 | } else { | ||
187 | risc_flag = RISC_CNT_INC; | ||
188 | risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | Loop to 2ndFrameRISC or to Start of | ||
193 | Risc program & generate IRQ | ||
194 | */ | ||
195 | *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); | ||
196 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
197 | *(rp++) = cpu_to_le32(0); | ||
198 | } | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev) | ||
204 | { | ||
205 | struct sram_channel *sram_ch = | ||
206 | dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; | ||
207 | u32 tmp = 0; | ||
208 | |||
209 | if (!dev->_is_running_ch2) { | ||
210 | pr_info("No video file is currently running so return!\n"); | ||
211 | return; | ||
212 | } | ||
213 | /* Disable RISC interrupts */ | ||
214 | tmp = cx_read(sram_ch->int_msk); | ||
215 | cx_write(sram_ch->int_msk, tmp & ~_intr_msk); | ||
216 | |||
217 | /* Turn OFF risc and fifo */ | ||
218 | tmp = cx_read(sram_ch->dma_ctl); | ||
219 | cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); | ||
220 | |||
221 | /* Clear data buffer memory */ | ||
222 | if (dev->_data_buf_virt_addr_ch2) | ||
223 | memset(dev->_data_buf_virt_addr_ch2, 0, | ||
224 | dev->_data_buf_size_ch2); | ||
225 | |||
226 | dev->_is_running_ch2 = 0; | ||
227 | dev->_is_first_frame_ch2 = 0; | ||
228 | dev->_frame_count_ch2 = 0; | ||
229 | dev->_file_status_ch2 = END_OF_FILE; | ||
230 | |||
231 | kfree(dev->_irq_queues_ch2); | ||
232 | dev->_irq_queues_ch2 = NULL; | ||
233 | |||
234 | kfree(dev->_filename_ch2); | ||
235 | |||
236 | tmp = cx_read(VID_CH_MODE_SEL); | ||
237 | cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); | ||
238 | } | ||
239 | |||
240 | void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev) | ||
241 | { | ||
242 | if (dev->_is_running_ch2) | ||
243 | cx25821_stop_upstream_video_ch2(dev); | ||
244 | |||
245 | if (dev->_dma_virt_addr_ch2) { | ||
246 | pci_free_consistent(dev->pci, dev->_risc_size_ch2, | ||
247 | dev->_dma_virt_addr_ch2, | ||
248 | dev->_dma_phys_addr_ch2); | ||
249 | dev->_dma_virt_addr_ch2 = NULL; | ||
250 | } | ||
251 | |||
252 | if (dev->_data_buf_virt_addr_ch2) { | ||
253 | pci_free_consistent(dev->pci, dev->_data_buf_size_ch2, | ||
254 | dev->_data_buf_virt_addr_ch2, | ||
255 | dev->_data_buf_phys_addr_ch2); | ||
256 | dev->_data_buf_virt_addr_ch2 = NULL; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) | ||
261 | { | ||
262 | struct file *myfile; | ||
263 | int frame_index_temp = dev->_frame_index_ch2; | ||
264 | int i = 0; | ||
265 | int line_size = | ||
266 | (dev->_pixel_format_ch2 == | ||
267 | PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; | ||
268 | int frame_size = 0; | ||
269 | int frame_offset = 0; | ||
270 | ssize_t vfs_read_retval = 0; | ||
271 | char mybuf[line_size]; | ||
272 | loff_t file_offset; | ||
273 | loff_t pos; | ||
274 | mm_segment_t old_fs; | ||
275 | |||
276 | if (dev->_file_status_ch2 == END_OF_FILE) | ||
277 | return 0; | ||
278 | |||
279 | if (dev->_isNTSC_ch2) { | ||
280 | frame_size = | ||
281 | (line_size == | ||
282 | Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : | ||
283 | FRAME_SIZE_NTSC_Y422; | ||
284 | } else { | ||
285 | frame_size = | ||
286 | (line_size == | ||
287 | Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; | ||
288 | } | ||
289 | |||
290 | frame_offset = (frame_index_temp > 0) ? frame_size : 0; | ||
291 | file_offset = dev->_frame_count_ch2 * frame_size; | ||
292 | |||
293 | myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); | ||
294 | if (IS_ERR(myfile)) { | ||
295 | const int open_errno = -PTR_ERR(myfile); | ||
296 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
297 | __func__, dev->_filename_ch2, open_errno); | ||
298 | return PTR_ERR(myfile); | ||
299 | } else { | ||
300 | if (!(myfile->f_op)) { | ||
301 | pr_err("%s(): File has no file operations registered!\n", | ||
302 | __func__); | ||
303 | filp_close(myfile, NULL); | ||
304 | return -EIO; | ||
305 | } | ||
306 | |||
307 | if (!myfile->f_op->read) { | ||
308 | pr_err("%s(): File has no READ operations registered!\n", | ||
309 | __func__); | ||
310 | filp_close(myfile, NULL); | ||
311 | return -EIO; | ||
312 | } | ||
313 | |||
314 | pos = myfile->f_pos; | ||
315 | old_fs = get_fs(); | ||
316 | set_fs(KERNEL_DS); | ||
317 | |||
318 | for (i = 0; i < dev->_lines_count_ch2; i++) { | ||
319 | pos = file_offset; | ||
320 | |||
321 | vfs_read_retval = | ||
322 | vfs_read(myfile, mybuf, line_size, &pos); | ||
323 | |||
324 | if (vfs_read_retval > 0 && vfs_read_retval == line_size | ||
325 | && dev->_data_buf_virt_addr_ch2 != NULL) { | ||
326 | memcpy((void *)(dev->_data_buf_virt_addr_ch2 + | ||
327 | frame_offset / 4), mybuf, | ||
328 | vfs_read_retval); | ||
329 | } | ||
330 | |||
331 | file_offset += vfs_read_retval; | ||
332 | frame_offset += vfs_read_retval; | ||
333 | |||
334 | if (vfs_read_retval < line_size) { | ||
335 | pr_info("Done: exit %s() since no more bytes to read from Video file\n", | ||
336 | __func__); | ||
337 | break; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | if (i > 0) | ||
342 | dev->_frame_count_ch2++; | ||
343 | |||
344 | dev->_file_status_ch2 = | ||
345 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | ||
346 | |||
347 | set_fs(old_fs); | ||
348 | filp_close(myfile, NULL); | ||
349 | } | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static void cx25821_vidups_handler_ch2(struct work_struct *work) | ||
355 | { | ||
356 | struct cx25821_dev *dev = | ||
357 | container_of(work, struct cx25821_dev, _irq_work_entry_ch2); | ||
358 | |||
359 | if (!dev) { | ||
360 | pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", | ||
361 | __func__); | ||
362 | return; | ||
363 | } | ||
364 | |||
365 | cx25821_get_frame_ch2(dev, | ||
366 | dev->channels[dev-> | ||
367 | _channel2_upstream_select].sram_channels); | ||
368 | } | ||
369 | |||
370 | int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) | ||
371 | { | ||
372 | struct file *myfile; | ||
373 | int i = 0, j = 0; | ||
374 | int line_size = | ||
375 | (dev->_pixel_format_ch2 == | ||
376 | PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; | ||
377 | ssize_t vfs_read_retval = 0; | ||
378 | char mybuf[line_size]; | ||
379 | loff_t pos; | ||
380 | loff_t offset = (unsigned long)0; | ||
381 | mm_segment_t old_fs; | ||
382 | |||
383 | myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); | ||
384 | |||
385 | if (IS_ERR(myfile)) { | ||
386 | const int open_errno = -PTR_ERR(myfile); | ||
387 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
388 | __func__, dev->_filename_ch2, open_errno); | ||
389 | return PTR_ERR(myfile); | ||
390 | } else { | ||
391 | if (!(myfile->f_op)) { | ||
392 | pr_err("%s(): File has no file operations registered!\n", | ||
393 | __func__); | ||
394 | filp_close(myfile, NULL); | ||
395 | return -EIO; | ||
396 | } | ||
397 | |||
398 | if (!myfile->f_op->read) { | ||
399 | pr_err("%s(): File has no READ operations registered! Returning\n", | ||
400 | __func__); | ||
401 | filp_close(myfile, NULL); | ||
402 | return -EIO; | ||
403 | } | ||
404 | |||
405 | pos = myfile->f_pos; | ||
406 | old_fs = get_fs(); | ||
407 | set_fs(KERNEL_DS); | ||
408 | |||
409 | for (j = 0; j < NUM_FRAMES; j++) { | ||
410 | for (i = 0; i < dev->_lines_count_ch2; i++) { | ||
411 | pos = offset; | ||
412 | |||
413 | vfs_read_retval = | ||
414 | vfs_read(myfile, mybuf, line_size, &pos); | ||
415 | |||
416 | if (vfs_read_retval > 0 | ||
417 | && vfs_read_retval == line_size | ||
418 | && dev->_data_buf_virt_addr_ch2 != NULL) { | ||
419 | memcpy((void *)(dev-> | ||
420 | _data_buf_virt_addr_ch2 | ||
421 | + offset / 4), mybuf, | ||
422 | vfs_read_retval); | ||
423 | } | ||
424 | |||
425 | offset += vfs_read_retval; | ||
426 | |||
427 | if (vfs_read_retval < line_size) { | ||
428 | pr_info("Done: exit %s() since no more bytes to read from Video file\n", | ||
429 | __func__); | ||
430 | break; | ||
431 | } | ||
432 | } | ||
433 | |||
434 | if (i > 0) | ||
435 | dev->_frame_count_ch2++; | ||
436 | |||
437 | if (vfs_read_retval < line_size) | ||
438 | break; | ||
439 | } | ||
440 | |||
441 | dev->_file_status_ch2 = | ||
442 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | ||
443 | |||
444 | set_fs(old_fs); | ||
445 | myfile->f_pos = 0; | ||
446 | filp_close(myfile, NULL); | ||
447 | } | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, | ||
453 | struct sram_channel *sram_ch, | ||
454 | int bpl) | ||
455 | { | ||
456 | int ret = 0; | ||
457 | dma_addr_t dma_addr; | ||
458 | dma_addr_t data_dma_addr; | ||
459 | |||
460 | if (dev->_dma_virt_addr_ch2 != NULL) { | ||
461 | pci_free_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, | ||
462 | dev->_dma_virt_addr_ch2, | ||
463 | dev->_dma_phys_addr_ch2); | ||
464 | } | ||
465 | |||
466 | dev->_dma_virt_addr_ch2 = | ||
467 | pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, | ||
468 | &dma_addr); | ||
469 | dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2; | ||
470 | dev->_dma_phys_start_addr_ch2 = dma_addr; | ||
471 | dev->_dma_phys_addr_ch2 = dma_addr; | ||
472 | dev->_risc_size_ch2 = dev->upstream_riscbuf_size_ch2; | ||
473 | |||
474 | if (!dev->_dma_virt_addr_ch2) { | ||
475 | pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); | ||
476 | return -ENOMEM; | ||
477 | } | ||
478 | |||
479 | /* Iniitize at this address until n bytes to 0 */ | ||
480 | memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2); | ||
481 | |||
482 | if (dev->_data_buf_virt_addr_ch2 != NULL) { | ||
483 | pci_free_consistent(dev->pci, dev->upstream_databuf_size_ch2, | ||
484 | dev->_data_buf_virt_addr_ch2, | ||
485 | dev->_data_buf_phys_addr_ch2); | ||
486 | } | ||
487 | /* For Video Data buffer allocation */ | ||
488 | dev->_data_buf_virt_addr_ch2 = | ||
489 | pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2, | ||
490 | &data_dma_addr); | ||
491 | dev->_data_buf_phys_addr_ch2 = data_dma_addr; | ||
492 | dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2; | ||
493 | |||
494 | if (!dev->_data_buf_virt_addr_ch2) { | ||
495 | pr_err("FAILED to allocate memory for data buffer! Returning\n"); | ||
496 | return -ENOMEM; | ||
497 | } | ||
498 | |||
499 | /* Initialize at this address until n bytes to 0 */ | ||
500 | memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2); | ||
501 | |||
502 | ret = cx25821_openfile_ch2(dev, sram_ch); | ||
503 | if (ret < 0) | ||
504 | return ret; | ||
505 | |||
506 | /* Creating RISC programs */ | ||
507 | ret = cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl, | ||
508 | dev->_lines_count_ch2); | ||
509 | if (ret < 0) { | ||
510 | pr_info("Failed creating Video Upstream Risc programs!\n"); | ||
511 | goto error; | ||
512 | } | ||
513 | |||
514 | return 0; | ||
515 | |||
516 | error: | ||
517 | return ret; | ||
518 | } | ||
519 | |||
520 | int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num, | ||
521 | u32 status) | ||
522 | { | ||
523 | u32 int_msk_tmp; | ||
524 | struct sram_channel *channel = dev->channels[chan_num].sram_channels; | ||
525 | int singlefield_lines = NTSC_FIELD_HEIGHT; | ||
526 | int line_size_in_bytes = Y422_LINE_SZ; | ||
527 | int odd_risc_prog_size = 0; | ||
528 | dma_addr_t risc_phys_jump_addr; | ||
529 | __le32 *rp; | ||
530 | |||
531 | if (status & FLD_VID_SRC_RISC1) { | ||
532 | /* We should only process one program per call */ | ||
533 | u32 prog_cnt = cx_read(channel->gpcnt); | ||
534 | |||
535 | /* | ||
536 | * Since we've identified our IRQ, clear our bits from the | ||
537 | * interrupt mask and interrupt status registers | ||
538 | */ | ||
539 | int_msk_tmp = cx_read(channel->int_msk); | ||
540 | cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); | ||
541 | cx_write(channel->int_stat, _intr_msk); | ||
542 | |||
543 | spin_lock(&dev->slock); | ||
544 | |||
545 | dev->_frame_index_ch2 = prog_cnt; | ||
546 | |||
547 | queue_work(dev->_irq_queues_ch2, &dev->_irq_work_entry_ch2); | ||
548 | |||
549 | if (dev->_is_first_frame_ch2) { | ||
550 | dev->_is_first_frame_ch2 = 0; | ||
551 | |||
552 | if (dev->_isNTSC_ch2) { | ||
553 | singlefield_lines += 1; | ||
554 | odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; | ||
555 | } else { | ||
556 | singlefield_lines = PAL_FIELD_HEIGHT; | ||
557 | odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; | ||
558 | } | ||
559 | |||
560 | if (dev->_dma_virt_start_addr_ch2 != NULL) { | ||
561 | if (dev->_pixel_format_ch2 == PIXEL_FRMT_411) | ||
562 | line_size_in_bytes = Y411_LINE_SZ; | ||
563 | else | ||
564 | line_size_in_bytes = Y422_LINE_SZ; | ||
565 | risc_phys_jump_addr = | ||
566 | dev->_dma_phys_start_addr_ch2 + | ||
567 | odd_risc_prog_size; | ||
568 | |||
569 | rp = cx25821_update_riscprogram_ch2(dev, | ||
570 | dev->_dma_virt_start_addr_ch2, | ||
571 | TOP_OFFSET, line_size_in_bytes, | ||
572 | 0x0, singlefield_lines, | ||
573 | FIFO_DISABLE, ODD_FIELD); | ||
574 | |||
575 | /* Jump to Even Risc program of 1st Frame */ | ||
576 | *(rp++) = cpu_to_le32(RISC_JUMP); | ||
577 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
578 | *(rp++) = cpu_to_le32(0); | ||
579 | } | ||
580 | } | ||
581 | |||
582 | spin_unlock(&dev->slock); | ||
583 | } | ||
584 | |||
585 | if (dev->_file_status_ch2 == END_OF_FILE) { | ||
586 | pr_info("EOF Channel 2 Framecount = %d\n", | ||
587 | dev->_frame_count_ch2); | ||
588 | return -1; | ||
589 | } | ||
590 | /* ElSE, set the interrupt mask register, re-enable irq. */ | ||
591 | int_msk_tmp = cx_read(channel->int_msk); | ||
592 | cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id) | ||
598 | { | ||
599 | struct cx25821_dev *dev = dev_id; | ||
600 | u32 msk_stat, vid_status; | ||
601 | int handled = 0; | ||
602 | int channel_num = 0; | ||
603 | struct sram_channel *sram_ch; | ||
604 | |||
605 | if (!dev) | ||
606 | return -1; | ||
607 | |||
608 | channel_num = VID_UPSTREAM_SRAM_CHANNEL_J; | ||
609 | sram_ch = dev->channels[channel_num].sram_channels; | ||
610 | |||
611 | msk_stat = cx_read(sram_ch->int_mstat); | ||
612 | vid_status = cx_read(sram_ch->int_stat); | ||
613 | |||
614 | /* Only deal with our interrupt */ | ||
615 | if (vid_status) { | ||
616 | handled = | ||
617 | cx25821_video_upstream_irq_ch2(dev, channel_num, | ||
618 | vid_status); | ||
619 | } | ||
620 | |||
621 | if (handled < 0) | ||
622 | cx25821_stop_upstream_video_ch2(dev); | ||
623 | else | ||
624 | handled += handled; | ||
625 | |||
626 | return IRQ_RETVAL(handled); | ||
627 | } | ||
628 | |||
629 | static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev, | ||
630 | struct sram_channel *ch, int pix_format) | ||
631 | { | ||
632 | int width = WIDTH_D1; | ||
633 | int height = dev->_lines_count_ch2; | ||
634 | int num_lines, odd_num_lines; | ||
635 | u32 value; | ||
636 | int vip_mode = PIXEL_ENGINE_VIP1; | ||
637 | |||
638 | value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); | ||
639 | value &= 0xFFFFFFEF; | ||
640 | value |= dev->_isNTSC_ch2 ? 0 : 0x10; | ||
641 | cx_write(ch->vid_fmt_ctl, value); | ||
642 | |||
643 | /* | ||
644 | * set number of active pixels in each line. Default is 720 | ||
645 | * pixels in both NTSC and PAL format | ||
646 | */ | ||
647 | cx_write(ch->vid_active_ctl1, width); | ||
648 | |||
649 | num_lines = (height / 2) & 0x3FF; | ||
650 | odd_num_lines = num_lines; | ||
651 | |||
652 | if (dev->_isNTSC_ch2) | ||
653 | odd_num_lines += 1; | ||
654 | |||
655 | value = (num_lines << 16) | odd_num_lines; | ||
656 | |||
657 | /* set number of active lines in field 0 (top) and field 1 (bottom) */ | ||
658 | cx_write(ch->vid_active_ctl2, value); | ||
659 | |||
660 | cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); | ||
661 | } | ||
662 | |||
663 | int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, | ||
664 | struct sram_channel *sram_ch) | ||
665 | { | ||
666 | u32 tmp = 0; | ||
667 | int err = 0; | ||
668 | |||
669 | /* | ||
670 | * 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface | ||
671 | * for channel A-C | ||
672 | */ | ||
673 | tmp = cx_read(VID_CH_MODE_SEL); | ||
674 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | ||
675 | |||
676 | /* | ||
677 | * Set the physical start address of the RISC program in the initial | ||
678 | * program counter(IPC) member of the cmds. | ||
679 | */ | ||
680 | cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2); | ||
681 | cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */ | ||
682 | |||
683 | /* reset counter */ | ||
684 | cx_write(sram_ch->gpcnt_ctl, 3); | ||
685 | |||
686 | /* Clear our bits from the interrupt status register. */ | ||
687 | cx_write(sram_ch->int_stat, _intr_msk); | ||
688 | |||
689 | /* Set the interrupt mask register, enable irq. */ | ||
690 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); | ||
691 | tmp = cx_read(sram_ch->int_msk); | ||
692 | cx_write(sram_ch->int_msk, tmp |= _intr_msk); | ||
693 | |||
694 | err = | ||
695 | request_irq(dev->pci->irq, cx25821_upstream_irq_ch2, | ||
696 | IRQF_SHARED, dev->name, dev); | ||
697 | if (err < 0) { | ||
698 | pr_err("%s: can't get upstream IRQ %d\n", | ||
699 | dev->name, dev->pci->irq); | ||
700 | goto fail_irq; | ||
701 | } | ||
702 | /* Start the DMA engine */ | ||
703 | tmp = cx_read(sram_ch->dma_ctl); | ||
704 | cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); | ||
705 | |||
706 | dev->_is_running_ch2 = 1; | ||
707 | dev->_is_first_frame_ch2 = 1; | ||
708 | |||
709 | return 0; | ||
710 | |||
711 | fail_irq: | ||
712 | cx25821_dev_unregister(dev); | ||
713 | return err; | ||
714 | } | ||
715 | |||
716 | int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, | ||
717 | int pixel_format) | ||
718 | { | ||
719 | struct sram_channel *sram_ch; | ||
720 | u32 tmp; | ||
721 | int retval = 0; | ||
722 | int err = 0; | ||
723 | int data_frame_size = 0; | ||
724 | int risc_buffer_size = 0; | ||
725 | int str_length = 0; | ||
726 | |||
727 | if (dev->_is_running_ch2) { | ||
728 | pr_info("Video Channel is still running so return!\n"); | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | dev->_channel2_upstream_select = channel_select; | ||
733 | sram_ch = dev->channels[channel_select].sram_channels; | ||
734 | |||
735 | INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2); | ||
736 | dev->_irq_queues_ch2 = | ||
737 | create_singlethread_workqueue("cx25821_workqueue2"); | ||
738 | |||
739 | if (!dev->_irq_queues_ch2) { | ||
740 | pr_err("create_singlethread_workqueue() for Video FAILED!\n"); | ||
741 | return -ENOMEM; | ||
742 | } | ||
743 | /* | ||
744 | * 656/VIP SRC Upstream Channel I & J and 7 - | ||
745 | * Host Bus Interface for channel A-C | ||
746 | */ | ||
747 | tmp = cx_read(VID_CH_MODE_SEL); | ||
748 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | ||
749 | |||
750 | dev->_is_running_ch2 = 0; | ||
751 | dev->_frame_count_ch2 = 0; | ||
752 | dev->_file_status_ch2 = RESET_STATUS; | ||
753 | dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576; | ||
754 | dev->_pixel_format_ch2 = pixel_format; | ||
755 | dev->_line_size_ch2 = | ||
756 | (dev->_pixel_format_ch2 == | ||
757 | PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; | ||
758 | data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; | ||
759 | risc_buffer_size = | ||
760 | dev->_isNTSC_ch2 ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; | ||
761 | |||
762 | if (dev->input_filename_ch2) { | ||
763 | str_length = strlen(dev->input_filename_ch2); | ||
764 | dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); | ||
765 | |||
766 | if (!dev->_filename_ch2) | ||
767 | goto error; | ||
768 | |||
769 | memcpy(dev->_filename_ch2, dev->input_filename_ch2, | ||
770 | str_length + 1); | ||
771 | } else { | ||
772 | str_length = strlen(dev->_defaultname_ch2); | ||
773 | dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); | ||
774 | |||
775 | if (!dev->_filename_ch2) | ||
776 | goto error; | ||
777 | |||
778 | memcpy(dev->_filename_ch2, dev->_defaultname_ch2, | ||
779 | str_length + 1); | ||
780 | } | ||
781 | |||
782 | /* Default if filename is empty string */ | ||
783 | if (strcmp(dev->input_filename_ch2, "") == 0) { | ||
784 | if (dev->_isNTSC_ch2) { | ||
785 | dev->_filename_ch2 = | ||
786 | (dev->_pixel_format_ch2 == | ||
787 | PIXEL_FRMT_411) ? "/root/vid411.yuv" : | ||
788 | "/root/vidtest.yuv"; | ||
789 | } else { | ||
790 | dev->_filename_ch2 = | ||
791 | (dev->_pixel_format_ch2 == | ||
792 | PIXEL_FRMT_411) ? "/root/pal411.yuv" : | ||
793 | "/root/pal422.yuv"; | ||
794 | } | ||
795 | } | ||
796 | |||
797 | retval = cx25821_sram_channel_setup_upstream(dev, sram_ch, | ||
798 | dev->_line_size_ch2, 0); | ||
799 | |||
800 | /* setup fifo + format */ | ||
801 | cx25821_set_pixelengine_ch2(dev, sram_ch, dev->_pixel_format_ch2); | ||
802 | |||
803 | dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2; | ||
804 | dev->upstream_databuf_size_ch2 = data_frame_size * 2; | ||
805 | |||
806 | /* Allocating buffers and prepare RISC program */ | ||
807 | retval = cx25821_upstream_buffer_prepare_ch2(dev, sram_ch, | ||
808 | dev->_line_size_ch2); | ||
809 | if (retval < 0) { | ||
810 | pr_err("%s: Failed to set up Video upstream buffers!\n", | ||
811 | dev->name); | ||
812 | goto error; | ||
813 | } | ||
814 | |||
815 | cx25821_start_video_dma_upstream_ch2(dev, sram_ch); | ||
816 | |||
817 | return 0; | ||
818 | |||
819 | error: | ||
820 | cx25821_dev_unregister(dev); | ||
821 | |||
822 | return err; | ||
823 | } | ||
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.h b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.h new file mode 100644 index 000000000000..d42dab59b663 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.h | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | |||
26 | #define OPEN_FILE_1 0 | ||
27 | #define NUM_PROGS 8 | ||
28 | #define NUM_FRAMES 2 | ||
29 | #define ODD_FIELD 0 | ||
30 | #define EVEN_FIELD 1 | ||
31 | #define TOP_OFFSET 0 | ||
32 | #define FIFO_DISABLE 0 | ||
33 | #define FIFO_ENABLE 1 | ||
34 | #define TEST_FRAMES 5 | ||
35 | #define END_OF_FILE 0 | ||
36 | #define IN_PROGRESS 1 | ||
37 | #define RESET_STATUS -1 | ||
38 | #define NUM_NO_OPS 5 | ||
39 | |||
40 | /* PAL and NTSC line sizes and number of lines. */ | ||
41 | #define WIDTH_D1 720 | ||
42 | #define NTSC_LINES_PER_FRAME 480 | ||
43 | #define PAL_LINES_PER_FRAME 576 | ||
44 | #define PAL_LINE_SZ 1440 | ||
45 | #define Y422_LINE_SZ 1440 | ||
46 | #define Y411_LINE_SZ 1080 | ||
47 | #define NTSC_FIELD_HEIGHT 240 | ||
48 | #define NTSC_ODD_FLD_LINES 241 | ||
49 | #define PAL_FIELD_HEIGHT 288 | ||
50 | |||
51 | #define FRAME_SIZE_NTSC_Y422 (NTSC_LINES_PER_FRAME * Y422_LINE_SZ) | ||
52 | #define FRAME_SIZE_NTSC_Y411 (NTSC_LINES_PER_FRAME * Y411_LINE_SZ) | ||
53 | #define FRAME_SIZE_PAL_Y422 (PAL_LINES_PER_FRAME * Y422_LINE_SZ) | ||
54 | #define FRAME_SIZE_PAL_Y411 (PAL_LINES_PER_FRAME * Y411_LINE_SZ) | ||
55 | |||
56 | #define NTSC_DATA_BUF_SZ (Y422_LINE_SZ * NTSC_LINES_PER_FRAME) | ||
57 | #define PAL_DATA_BUF_SZ (Y422_LINE_SZ * PAL_LINES_PER_FRAME) | ||
58 | |||
59 | #define RISC_WRITECR_INSTRUCTION_SIZE 16 | ||
60 | #define RISC_SYNC_INSTRUCTION_SIZE 4 | ||
61 | #define JUMP_INSTRUCTION_SIZE 12 | ||
62 | #define MAXSIZE_NO_OPS 36 | ||
63 | #define DWORD_SIZE 4 | ||
64 | |||
65 | #define USE_RISC_NOOP_VIDEO 1 | ||
66 | |||
67 | #ifdef USE_RISC_NOOP_VIDEO | ||
68 | #define PAL_US_VID_PROG_SIZE \ | ||
69 | (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ | ||
70 | RISC_WRITECR_INSTRUCTION_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \ | ||
71 | NUM_NO_OPS * DWORD_SIZE) | ||
72 | |||
73 | #define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE) | ||
74 | |||
75 | #define PAL_VID_PROG_SIZE \ | ||
76 | ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \ | ||
77 | 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ | ||
78 | JUMP_INSTRUCTION_SIZE + 2 * NUM_NO_OPS * DWORD_SIZE) | ||
79 | |||
80 | #define ODD_FLD_PAL_PROG_SIZE \ | ||
81 | (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ | ||
82 | RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ | ||
83 | NUM_NO_OPS * DWORD_SIZE) | ||
84 | |||
85 | #define NTSC_US_VID_PROG_SIZE \ | ||
86 | ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \ | ||
87 | RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + \ | ||
88 | NUM_NO_OPS * DWORD_SIZE) | ||
89 | |||
90 | #define NTSC_RISC_BUF_SIZE \ | ||
91 | (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) | ||
92 | |||
93 | #define FRAME1_VID_PROG_SIZE \ | ||
94 | ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * \ | ||
95 | 3 * DWORD_SIZE + 2 * RISC_SYNC_INSTRUCTION_SIZE + \ | ||
96 | RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + \ | ||
97 | 2 * NUM_NO_OPS * DWORD_SIZE) | ||
98 | |||
99 | #define ODD_FLD_NTSC_PROG_SIZE \ | ||
100 | (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \ | ||
101 | RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ | ||
102 | NUM_NO_OPS * DWORD_SIZE) | ||
103 | #endif | ||
104 | |||
105 | #ifndef USE_RISC_NOOP_VIDEO | ||
106 | #define PAL_US_VID_PROG_SIZE \ | ||
107 | ((PAL_FIELD_HEIGHT + 1) * 3 * DWORD_SIZE + \ | ||
108 | RISC_WRITECR_INSTRUCTION_SIZE) | ||
109 | |||
110 | #define PAL_RISC_BUF_SIZE \ | ||
111 | (2 * (RISC_SYNC_INSTRUCTION_SIZE + PAL_US_VID_PROG_SIZE)) | ||
112 | |||
113 | #define PAL_VID_PROG_SIZE \ | ||
114 | ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \ | ||
115 | 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ | ||
116 | JUMP_INSTRUCTION_SIZE) | ||
117 | |||
118 | #define ODD_FLD_PAL_PROG_SIZE \ | ||
119 | (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ | ||
120 | RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) | ||
121 | |||
122 | #define ODD_FLD_NTSC_PROG_SIZE \ | ||
123 | (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \ | ||
124 | RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) | ||
125 | |||
126 | #define NTSC_US_VID_PROG_SIZE \ | ||
127 | ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \ | ||
128 | RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) | ||
129 | |||
130 | #define NTSC_RISC_BUF_SIZE \ | ||
131 | (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) | ||
132 | |||
133 | #define FRAME1_VID_PROG_SIZE \ | ||
134 | ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * \ | ||
135 | 3 * DWORD_SIZE + 2 * RISC_SYNC_INSTRUCTION_SIZE + \ | ||
136 | RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) | ||
137 | |||
138 | #endif | ||
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream.c b/drivers/media/video/cx25821/cx25821-video-upstream.c new file mode 100644 index 000000000000..c0b80068f468 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-video-upstream.c | |||
@@ -0,0 +1,885 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
24 | |||
25 | #include "cx25821-video.h" | ||
26 | #include "cx25821-video-upstream.h" | ||
27 | |||
28 | #include <linux/fs.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/syscalls.h> | ||
34 | #include <linux/file.h> | ||
35 | #include <linux/fcntl.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/uaccess.h> | ||
38 | |||
39 | MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); | ||
40 | MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | | ||
44 | FLD_VID_SRC_OPC_ERR; | ||
45 | |||
46 | int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, | ||
47 | struct sram_channel *ch, | ||
48 | unsigned int bpl, u32 risc) | ||
49 | { | ||
50 | unsigned int i, lines; | ||
51 | u32 cdt; | ||
52 | |||
53 | if (ch->cmds_start == 0) { | ||
54 | cx_write(ch->ptr1_reg, 0); | ||
55 | cx_write(ch->ptr2_reg, 0); | ||
56 | cx_write(ch->cnt2_reg, 0); | ||
57 | cx_write(ch->cnt1_reg, 0); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | bpl = (bpl + 7) & ~7; /* alignment */ | ||
62 | cdt = ch->cdt; | ||
63 | lines = ch->fifo_size / bpl; | ||
64 | |||
65 | if (lines > 4) | ||
66 | lines = 4; | ||
67 | |||
68 | BUG_ON(lines < 2); | ||
69 | |||
70 | /* write CDT */ | ||
71 | for (i = 0; i < lines; i++) { | ||
72 | cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); | ||
73 | cx_write(cdt + 16 * i + 4, 0); | ||
74 | cx_write(cdt + 16 * i + 8, 0); | ||
75 | cx_write(cdt + 16 * i + 12, 0); | ||
76 | } | ||
77 | |||
78 | /* write CMDS */ | ||
79 | cx_write(ch->cmds_start + 0, risc); | ||
80 | |||
81 | cx_write(ch->cmds_start + 4, 0); | ||
82 | cx_write(ch->cmds_start + 8, cdt); | ||
83 | cx_write(ch->cmds_start + 12, (lines * 16) >> 3); | ||
84 | cx_write(ch->cmds_start + 16, ch->ctrl_start); | ||
85 | |||
86 | cx_write(ch->cmds_start + 20, VID_IQ_SIZE_DW); | ||
87 | |||
88 | for (i = 24; i < 80; i += 4) | ||
89 | cx_write(ch->cmds_start + i, 0); | ||
90 | |||
91 | /* fill registers */ | ||
92 | cx_write(ch->ptr1_reg, ch->fifo_start); | ||
93 | cx_write(ch->ptr2_reg, cdt); | ||
94 | cx_write(ch->cnt2_reg, (lines * 16) >> 3); | ||
95 | cx_write(ch->cnt1_reg, (bpl >> 3) - 1); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev, | ||
101 | __le32 *rp, unsigned int offset, | ||
102 | unsigned int bpl, u32 sync_line, | ||
103 | unsigned int lines, int fifo_enable, | ||
104 | int field_type) | ||
105 | { | ||
106 | unsigned int line, i; | ||
107 | int dist_betwn_starts = bpl * 2; | ||
108 | |||
109 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
110 | |||
111 | if (USE_RISC_NOOP_VIDEO) { | ||
112 | for (i = 0; i < NUM_NO_OPS; i++) | ||
113 | *(rp++) = cpu_to_le32(RISC_NOOP); | ||
114 | } | ||
115 | |||
116 | /* scan lines */ | ||
117 | for (line = 0; line < lines; line++) { | ||
118 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | ||
119 | *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr + offset); | ||
120 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
121 | |||
122 | if ((lines <= NTSC_FIELD_HEIGHT) | ||
123 | || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) { | ||
124 | offset += dist_betwn_starts; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | return rp; | ||
129 | } | ||
130 | |||
131 | static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp, | ||
132 | dma_addr_t databuf_phys_addr, | ||
133 | unsigned int offset, u32 sync_line, | ||
134 | unsigned int bpl, unsigned int lines, | ||
135 | int fifo_enable, int field_type) | ||
136 | { | ||
137 | unsigned int line, i; | ||
138 | struct sram_channel *sram_ch = | ||
139 | dev->channels[dev->_channel_upstream_select].sram_channels; | ||
140 | int dist_betwn_starts = bpl * 2; | ||
141 | |||
142 | /* sync instruction */ | ||
143 | if (sync_line != NO_SYNC_LINE) | ||
144 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
145 | |||
146 | if (USE_RISC_NOOP_VIDEO) { | ||
147 | for (i = 0; i < NUM_NO_OPS; i++) | ||
148 | *(rp++) = cpu_to_le32(RISC_NOOP); | ||
149 | } | ||
150 | |||
151 | /* scan lines */ | ||
152 | for (line = 0; line < lines; line++) { | ||
153 | *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); | ||
154 | *(rp++) = cpu_to_le32(databuf_phys_addr + offset); | ||
155 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | ||
156 | |||
157 | if ((lines <= NTSC_FIELD_HEIGHT) | ||
158 | || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) | ||
159 | /* to skip the other field line */ | ||
160 | offset += dist_betwn_starts; | ||
161 | |||
162 | /* check if we need to enable the FIFO after the first 4 lines | ||
163 | * For the upstream video channel, the risc engine will enable | ||
164 | * the FIFO. */ | ||
165 | if (fifo_enable && line == 3) { | ||
166 | *(rp++) = RISC_WRITECR; | ||
167 | *(rp++) = sram_ch->dma_ctl; | ||
168 | *(rp++) = FLD_VID_FIFO_EN; | ||
169 | *(rp++) = 0x00000001; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | return rp; | ||
174 | } | ||
175 | |||
176 | int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, | ||
177 | struct pci_dev *pci, | ||
178 | unsigned int top_offset, | ||
179 | unsigned int bpl, unsigned int lines) | ||
180 | { | ||
181 | __le32 *rp; | ||
182 | int fifo_enable = 0; | ||
183 | /* get line count for single field */ | ||
184 | int singlefield_lines = lines >> 1; | ||
185 | int odd_num_lines = singlefield_lines; | ||
186 | int frame = 0; | ||
187 | int frame_size = 0; | ||
188 | int databuf_offset = 0; | ||
189 | int risc_program_size = 0; | ||
190 | int risc_flag = RISC_CNT_RESET; | ||
191 | unsigned int bottom_offset = bpl; | ||
192 | dma_addr_t risc_phys_jump_addr; | ||
193 | |||
194 | if (dev->_isNTSC) { | ||
195 | odd_num_lines = singlefield_lines + 1; | ||
196 | risc_program_size = FRAME1_VID_PROG_SIZE; | ||
197 | frame_size = | ||
198 | (bpl == | ||
199 | Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : | ||
200 | FRAME_SIZE_NTSC_Y422; | ||
201 | } else { | ||
202 | risc_program_size = PAL_VID_PROG_SIZE; | ||
203 | frame_size = | ||
204 | (bpl == | ||
205 | Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; | ||
206 | } | ||
207 | |||
208 | /* Virtual address of Risc buffer program */ | ||
209 | rp = dev->_dma_virt_addr; | ||
210 | |||
211 | for (frame = 0; frame < NUM_FRAMES; frame++) { | ||
212 | databuf_offset = frame_size * frame; | ||
213 | |||
214 | if (UNSET != top_offset) { | ||
215 | fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; | ||
216 | rp = cx25821_risc_field_upstream(dev, rp, | ||
217 | dev-> | ||
218 | _data_buf_phys_addr + | ||
219 | databuf_offset, | ||
220 | top_offset, 0, bpl, | ||
221 | odd_num_lines, | ||
222 | fifo_enable, | ||
223 | ODD_FIELD); | ||
224 | } | ||
225 | |||
226 | fifo_enable = FIFO_DISABLE; | ||
227 | |||
228 | /* Even Field */ | ||
229 | rp = cx25821_risc_field_upstream(dev, rp, | ||
230 | dev->_data_buf_phys_addr + | ||
231 | databuf_offset, bottom_offset, | ||
232 | 0x200, bpl, singlefield_lines, | ||
233 | fifo_enable, EVEN_FIELD); | ||
234 | |||
235 | if (frame == 0) { | ||
236 | risc_flag = RISC_CNT_RESET; | ||
237 | risc_phys_jump_addr = | ||
238 | dev->_dma_phys_start_addr + risc_program_size; | ||
239 | } else { | ||
240 | risc_phys_jump_addr = dev->_dma_phys_start_addr; | ||
241 | risc_flag = RISC_CNT_INC; | ||
242 | } | ||
243 | |||
244 | /* Loop to 2ndFrameRISC or to Start of Risc | ||
245 | * program & generate IRQ | ||
246 | */ | ||
247 | *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); | ||
248 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
249 | *(rp++) = cpu_to_le32(0); | ||
250 | } | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev) | ||
256 | { | ||
257 | struct sram_channel *sram_ch = | ||
258 | dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels; | ||
259 | u32 tmp = 0; | ||
260 | |||
261 | if (!dev->_is_running) { | ||
262 | pr_info("No video file is currently running so return!\n"); | ||
263 | return; | ||
264 | } | ||
265 | /* Disable RISC interrupts */ | ||
266 | tmp = cx_read(sram_ch->int_msk); | ||
267 | cx_write(sram_ch->int_msk, tmp & ~_intr_msk); | ||
268 | |||
269 | /* Turn OFF risc and fifo enable */ | ||
270 | tmp = cx_read(sram_ch->dma_ctl); | ||
271 | cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); | ||
272 | |||
273 | /* Clear data buffer memory */ | ||
274 | if (dev->_data_buf_virt_addr) | ||
275 | memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size); | ||
276 | |||
277 | dev->_is_running = 0; | ||
278 | dev->_is_first_frame = 0; | ||
279 | dev->_frame_count = 0; | ||
280 | dev->_file_status = END_OF_FILE; | ||
281 | |||
282 | kfree(dev->_irq_queues); | ||
283 | dev->_irq_queues = NULL; | ||
284 | |||
285 | kfree(dev->_filename); | ||
286 | |||
287 | tmp = cx_read(VID_CH_MODE_SEL); | ||
288 | cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); | ||
289 | } | ||
290 | |||
291 | void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev) | ||
292 | { | ||
293 | if (dev->_is_running) | ||
294 | cx25821_stop_upstream_video_ch1(dev); | ||
295 | |||
296 | if (dev->_dma_virt_addr) { | ||
297 | pci_free_consistent(dev->pci, dev->_risc_size, | ||
298 | dev->_dma_virt_addr, dev->_dma_phys_addr); | ||
299 | dev->_dma_virt_addr = NULL; | ||
300 | } | ||
301 | |||
302 | if (dev->_data_buf_virt_addr) { | ||
303 | pci_free_consistent(dev->pci, dev->_data_buf_size, | ||
304 | dev->_data_buf_virt_addr, | ||
305 | dev->_data_buf_phys_addr); | ||
306 | dev->_data_buf_virt_addr = NULL; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) | ||
311 | { | ||
312 | struct file *myfile; | ||
313 | int frame_index_temp = dev->_frame_index; | ||
314 | int i = 0; | ||
315 | int line_size = | ||
316 | (dev->_pixel_format == | ||
317 | PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; | ||
318 | int frame_size = 0; | ||
319 | int frame_offset = 0; | ||
320 | ssize_t vfs_read_retval = 0; | ||
321 | char mybuf[line_size]; | ||
322 | loff_t file_offset; | ||
323 | loff_t pos; | ||
324 | mm_segment_t old_fs; | ||
325 | |||
326 | if (dev->_file_status == END_OF_FILE) | ||
327 | return 0; | ||
328 | |||
329 | if (dev->_isNTSC) { | ||
330 | frame_size = | ||
331 | (line_size == | ||
332 | Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : | ||
333 | FRAME_SIZE_NTSC_Y422; | ||
334 | } else { | ||
335 | frame_size = | ||
336 | (line_size == | ||
337 | Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; | ||
338 | } | ||
339 | |||
340 | frame_offset = (frame_index_temp > 0) ? frame_size : 0; | ||
341 | file_offset = dev->_frame_count * frame_size; | ||
342 | |||
343 | myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0); | ||
344 | |||
345 | if (IS_ERR(myfile)) { | ||
346 | const int open_errno = -PTR_ERR(myfile); | ||
347 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
348 | __func__, dev->_filename, open_errno); | ||
349 | return PTR_ERR(myfile); | ||
350 | } else { | ||
351 | if (!(myfile->f_op)) { | ||
352 | pr_err("%s(): File has no file operations registered!\n", | ||
353 | __func__); | ||
354 | filp_close(myfile, NULL); | ||
355 | return -EIO; | ||
356 | } | ||
357 | |||
358 | if (!myfile->f_op->read) { | ||
359 | pr_err("%s(): File has no READ operations registered!\n", | ||
360 | __func__); | ||
361 | filp_close(myfile, NULL); | ||
362 | return -EIO; | ||
363 | } | ||
364 | |||
365 | pos = myfile->f_pos; | ||
366 | old_fs = get_fs(); | ||
367 | set_fs(KERNEL_DS); | ||
368 | |||
369 | for (i = 0; i < dev->_lines_count; i++) { | ||
370 | pos = file_offset; | ||
371 | |||
372 | vfs_read_retval = | ||
373 | vfs_read(myfile, mybuf, line_size, &pos); | ||
374 | |||
375 | if (vfs_read_retval > 0 && vfs_read_retval == line_size | ||
376 | && dev->_data_buf_virt_addr != NULL) { | ||
377 | memcpy((void *)(dev->_data_buf_virt_addr + | ||
378 | frame_offset / 4), mybuf, | ||
379 | vfs_read_retval); | ||
380 | } | ||
381 | |||
382 | file_offset += vfs_read_retval; | ||
383 | frame_offset += vfs_read_retval; | ||
384 | |||
385 | if (vfs_read_retval < line_size) { | ||
386 | pr_info("Done: exit %s() since no more bytes to read from Video file\n", | ||
387 | __func__); | ||
388 | break; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | if (i > 0) | ||
393 | dev->_frame_count++; | ||
394 | |||
395 | dev->_file_status = | ||
396 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | ||
397 | |||
398 | set_fs(old_fs); | ||
399 | filp_close(myfile, NULL); | ||
400 | } | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static void cx25821_vidups_handler(struct work_struct *work) | ||
406 | { | ||
407 | struct cx25821_dev *dev = | ||
408 | container_of(work, struct cx25821_dev, _irq_work_entry); | ||
409 | |||
410 | if (!dev) { | ||
411 | pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", | ||
412 | __func__); | ||
413 | return; | ||
414 | } | ||
415 | |||
416 | cx25821_get_frame(dev, | ||
417 | dev->channels[dev->_channel_upstream_select]. | ||
418 | sram_channels); | ||
419 | } | ||
420 | |||
421 | int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) | ||
422 | { | ||
423 | struct file *myfile; | ||
424 | int i = 0, j = 0; | ||
425 | int line_size = | ||
426 | (dev->_pixel_format == | ||
427 | PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; | ||
428 | ssize_t vfs_read_retval = 0; | ||
429 | char mybuf[line_size]; | ||
430 | loff_t pos; | ||
431 | loff_t offset = (unsigned long)0; | ||
432 | mm_segment_t old_fs; | ||
433 | |||
434 | myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0); | ||
435 | |||
436 | if (IS_ERR(myfile)) { | ||
437 | const int open_errno = -PTR_ERR(myfile); | ||
438 | pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", | ||
439 | __func__, dev->_filename, open_errno); | ||
440 | return PTR_ERR(myfile); | ||
441 | } else { | ||
442 | if (!(myfile->f_op)) { | ||
443 | pr_err("%s(): File has no file operations registered!\n", | ||
444 | __func__); | ||
445 | filp_close(myfile, NULL); | ||
446 | return -EIO; | ||
447 | } | ||
448 | |||
449 | if (!myfile->f_op->read) { | ||
450 | pr_err("%s(): File has no READ operations registered! Returning\n", | ||
451 | __func__); | ||
452 | filp_close(myfile, NULL); | ||
453 | return -EIO; | ||
454 | } | ||
455 | |||
456 | pos = myfile->f_pos; | ||
457 | old_fs = get_fs(); | ||
458 | set_fs(KERNEL_DS); | ||
459 | |||
460 | for (j = 0; j < NUM_FRAMES; j++) { | ||
461 | for (i = 0; i < dev->_lines_count; i++) { | ||
462 | pos = offset; | ||
463 | |||
464 | vfs_read_retval = | ||
465 | vfs_read(myfile, mybuf, line_size, &pos); | ||
466 | |||
467 | if (vfs_read_retval > 0 | ||
468 | && vfs_read_retval == line_size | ||
469 | && dev->_data_buf_virt_addr != NULL) { | ||
470 | memcpy((void *)(dev-> | ||
471 | _data_buf_virt_addr + | ||
472 | offset / 4), mybuf, | ||
473 | vfs_read_retval); | ||
474 | } | ||
475 | |||
476 | offset += vfs_read_retval; | ||
477 | |||
478 | if (vfs_read_retval < line_size) { | ||
479 | pr_info("Done: exit %s() since no more bytes to read from Video file\n", | ||
480 | __func__); | ||
481 | break; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | if (i > 0) | ||
486 | dev->_frame_count++; | ||
487 | |||
488 | if (vfs_read_retval < line_size) | ||
489 | break; | ||
490 | } | ||
491 | |||
492 | dev->_file_status = | ||
493 | (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; | ||
494 | |||
495 | set_fs(old_fs); | ||
496 | myfile->f_pos = 0; | ||
497 | filp_close(myfile, NULL); | ||
498 | } | ||
499 | |||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, | ||
504 | struct sram_channel *sram_ch, int bpl) | ||
505 | { | ||
506 | int ret = 0; | ||
507 | dma_addr_t dma_addr; | ||
508 | dma_addr_t data_dma_addr; | ||
509 | |||
510 | if (dev->_dma_virt_addr != NULL) { | ||
511 | pci_free_consistent(dev->pci, dev->upstream_riscbuf_size, | ||
512 | dev->_dma_virt_addr, dev->_dma_phys_addr); | ||
513 | } | ||
514 | |||
515 | dev->_dma_virt_addr = | ||
516 | pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size, | ||
517 | &dma_addr); | ||
518 | dev->_dma_virt_start_addr = dev->_dma_virt_addr; | ||
519 | dev->_dma_phys_start_addr = dma_addr; | ||
520 | dev->_dma_phys_addr = dma_addr; | ||
521 | dev->_risc_size = dev->upstream_riscbuf_size; | ||
522 | |||
523 | if (!dev->_dma_virt_addr) { | ||
524 | pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); | ||
525 | return -ENOMEM; | ||
526 | } | ||
527 | |||
528 | /* Clear memory at address */ | ||
529 | memset(dev->_dma_virt_addr, 0, dev->_risc_size); | ||
530 | |||
531 | if (dev->_data_buf_virt_addr != NULL) { | ||
532 | pci_free_consistent(dev->pci, dev->upstream_databuf_size, | ||
533 | dev->_data_buf_virt_addr, | ||
534 | dev->_data_buf_phys_addr); | ||
535 | } | ||
536 | /* For Video Data buffer allocation */ | ||
537 | dev->_data_buf_virt_addr = | ||
538 | pci_alloc_consistent(dev->pci, dev->upstream_databuf_size, | ||
539 | &data_dma_addr); | ||
540 | dev->_data_buf_phys_addr = data_dma_addr; | ||
541 | dev->_data_buf_size = dev->upstream_databuf_size; | ||
542 | |||
543 | if (!dev->_data_buf_virt_addr) { | ||
544 | pr_err("FAILED to allocate memory for data buffer! Returning\n"); | ||
545 | return -ENOMEM; | ||
546 | } | ||
547 | |||
548 | /* Clear memory at address */ | ||
549 | memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size); | ||
550 | |||
551 | ret = cx25821_openfile(dev, sram_ch); | ||
552 | if (ret < 0) | ||
553 | return ret; | ||
554 | |||
555 | /* Create RISC programs */ | ||
556 | ret = | ||
557 | cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl, | ||
558 | dev->_lines_count); | ||
559 | if (ret < 0) { | ||
560 | pr_info("Failed creating Video Upstream Risc programs!\n"); | ||
561 | goto error; | ||
562 | } | ||
563 | |||
564 | return 0; | ||
565 | |||
566 | error: | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, | ||
571 | u32 status) | ||
572 | { | ||
573 | u32 int_msk_tmp; | ||
574 | struct sram_channel *channel = dev->channels[chan_num].sram_channels; | ||
575 | int singlefield_lines = NTSC_FIELD_HEIGHT; | ||
576 | int line_size_in_bytes = Y422_LINE_SZ; | ||
577 | int odd_risc_prog_size = 0; | ||
578 | dma_addr_t risc_phys_jump_addr; | ||
579 | __le32 *rp; | ||
580 | |||
581 | if (status & FLD_VID_SRC_RISC1) { | ||
582 | /* We should only process one program per call */ | ||
583 | u32 prog_cnt = cx_read(channel->gpcnt); | ||
584 | |||
585 | /* Since we've identified our IRQ, clear our bits from the | ||
586 | * interrupt mask and interrupt status registers */ | ||
587 | int_msk_tmp = cx_read(channel->int_msk); | ||
588 | cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); | ||
589 | cx_write(channel->int_stat, _intr_msk); | ||
590 | |||
591 | spin_lock(&dev->slock); | ||
592 | |||
593 | dev->_frame_index = prog_cnt; | ||
594 | |||
595 | queue_work(dev->_irq_queues, &dev->_irq_work_entry); | ||
596 | |||
597 | if (dev->_is_first_frame) { | ||
598 | dev->_is_first_frame = 0; | ||
599 | |||
600 | if (dev->_isNTSC) { | ||
601 | singlefield_lines += 1; | ||
602 | odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; | ||
603 | } else { | ||
604 | singlefield_lines = PAL_FIELD_HEIGHT; | ||
605 | odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; | ||
606 | } | ||
607 | |||
608 | if (dev->_dma_virt_start_addr != NULL) { | ||
609 | line_size_in_bytes = | ||
610 | (dev->_pixel_format == | ||
611 | PIXEL_FRMT_411) ? Y411_LINE_SZ : | ||
612 | Y422_LINE_SZ; | ||
613 | risc_phys_jump_addr = | ||
614 | dev->_dma_phys_start_addr + | ||
615 | odd_risc_prog_size; | ||
616 | |||
617 | rp = cx25821_update_riscprogram(dev, | ||
618 | dev->_dma_virt_start_addr, TOP_OFFSET, | ||
619 | line_size_in_bytes, 0x0, | ||
620 | singlefield_lines, FIFO_DISABLE, | ||
621 | ODD_FIELD); | ||
622 | |||
623 | /* Jump to Even Risc program of 1st Frame */ | ||
624 | *(rp++) = cpu_to_le32(RISC_JUMP); | ||
625 | *(rp++) = cpu_to_le32(risc_phys_jump_addr); | ||
626 | *(rp++) = cpu_to_le32(0); | ||
627 | } | ||
628 | } | ||
629 | |||
630 | spin_unlock(&dev->slock); | ||
631 | } else { | ||
632 | if (status & FLD_VID_SRC_UF) | ||
633 | pr_err("%s(): Video Received Underflow Error Interrupt!\n", | ||
634 | __func__); | ||
635 | |||
636 | if (status & FLD_VID_SRC_SYNC) | ||
637 | pr_err("%s(): Video Received Sync Error Interrupt!\n", | ||
638 | __func__); | ||
639 | |||
640 | if (status & FLD_VID_SRC_OPC_ERR) | ||
641 | pr_err("%s(): Video Received OpCode Error Interrupt!\n", | ||
642 | __func__); | ||
643 | } | ||
644 | |||
645 | if (dev->_file_status == END_OF_FILE) { | ||
646 | pr_err("EOF Channel 1 Framecount = %d\n", dev->_frame_count); | ||
647 | return -1; | ||
648 | } | ||
649 | /* ElSE, set the interrupt mask register, re-enable irq. */ | ||
650 | int_msk_tmp = cx_read(channel->int_msk); | ||
651 | cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); | ||
652 | |||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id) | ||
657 | { | ||
658 | struct cx25821_dev *dev = dev_id; | ||
659 | u32 msk_stat, vid_status; | ||
660 | int handled = 0; | ||
661 | int channel_num = 0; | ||
662 | struct sram_channel *sram_ch; | ||
663 | |||
664 | if (!dev) | ||
665 | return -1; | ||
666 | |||
667 | channel_num = VID_UPSTREAM_SRAM_CHANNEL_I; | ||
668 | |||
669 | sram_ch = dev->channels[channel_num].sram_channels; | ||
670 | |||
671 | msk_stat = cx_read(sram_ch->int_mstat); | ||
672 | vid_status = cx_read(sram_ch->int_stat); | ||
673 | |||
674 | /* Only deal with our interrupt */ | ||
675 | if (vid_status) { | ||
676 | handled = | ||
677 | cx25821_video_upstream_irq(dev, channel_num, vid_status); | ||
678 | } | ||
679 | |||
680 | if (handled < 0) | ||
681 | cx25821_stop_upstream_video_ch1(dev); | ||
682 | else | ||
683 | handled += handled; | ||
684 | |||
685 | return IRQ_RETVAL(handled); | ||
686 | } | ||
687 | |||
688 | void cx25821_set_pixelengine(struct cx25821_dev *dev, struct sram_channel *ch, | ||
689 | int pix_format) | ||
690 | { | ||
691 | int width = WIDTH_D1; | ||
692 | int height = dev->_lines_count; | ||
693 | int num_lines, odd_num_lines; | ||
694 | u32 value; | ||
695 | int vip_mode = OUTPUT_FRMT_656; | ||
696 | |||
697 | value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); | ||
698 | value &= 0xFFFFFFEF; | ||
699 | value |= dev->_isNTSC ? 0 : 0x10; | ||
700 | cx_write(ch->vid_fmt_ctl, value); | ||
701 | |||
702 | /* set number of active pixels in each line. | ||
703 | * Default is 720 pixels in both NTSC and PAL format */ | ||
704 | cx_write(ch->vid_active_ctl1, width); | ||
705 | |||
706 | num_lines = (height / 2) & 0x3FF; | ||
707 | odd_num_lines = num_lines; | ||
708 | |||
709 | if (dev->_isNTSC) | ||
710 | odd_num_lines += 1; | ||
711 | |||
712 | value = (num_lines << 16) | odd_num_lines; | ||
713 | |||
714 | /* set number of active lines in field 0 (top) and field 1 (bottom) */ | ||
715 | cx_write(ch->vid_active_ctl2, value); | ||
716 | |||
717 | cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); | ||
718 | } | ||
719 | |||
720 | int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, | ||
721 | struct sram_channel *sram_ch) | ||
722 | { | ||
723 | u32 tmp = 0; | ||
724 | int err = 0; | ||
725 | |||
726 | /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for | ||
727 | * channel A-C | ||
728 | */ | ||
729 | tmp = cx_read(VID_CH_MODE_SEL); | ||
730 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | ||
731 | |||
732 | /* Set the physical start address of the RISC program in the initial | ||
733 | * program counter(IPC) member of the cmds. | ||
734 | */ | ||
735 | cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr); | ||
736 | /* Risc IPC High 64 bits 63-32 */ | ||
737 | cx_write(sram_ch->cmds_start + 4, 0); | ||
738 | |||
739 | /* reset counter */ | ||
740 | cx_write(sram_ch->gpcnt_ctl, 3); | ||
741 | |||
742 | /* Clear our bits from the interrupt status register. */ | ||
743 | cx_write(sram_ch->int_stat, _intr_msk); | ||
744 | |||
745 | /* Set the interrupt mask register, enable irq. */ | ||
746 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); | ||
747 | tmp = cx_read(sram_ch->int_msk); | ||
748 | cx_write(sram_ch->int_msk, tmp |= _intr_msk); | ||
749 | |||
750 | err = | ||
751 | request_irq(dev->pci->irq, cx25821_upstream_irq, | ||
752 | IRQF_SHARED, dev->name, dev); | ||
753 | if (err < 0) { | ||
754 | pr_err("%s: can't get upstream IRQ %d\n", | ||
755 | dev->name, dev->pci->irq); | ||
756 | goto fail_irq; | ||
757 | } | ||
758 | |||
759 | /* Start the DMA engine */ | ||
760 | tmp = cx_read(sram_ch->dma_ctl); | ||
761 | cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); | ||
762 | |||
763 | dev->_is_running = 1; | ||
764 | dev->_is_first_frame = 1; | ||
765 | |||
766 | return 0; | ||
767 | |||
768 | fail_irq: | ||
769 | cx25821_dev_unregister(dev); | ||
770 | return err; | ||
771 | } | ||
772 | |||
773 | int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, | ||
774 | int pixel_format) | ||
775 | { | ||
776 | struct sram_channel *sram_ch; | ||
777 | u32 tmp; | ||
778 | int retval = 0; | ||
779 | int err = 0; | ||
780 | int data_frame_size = 0; | ||
781 | int risc_buffer_size = 0; | ||
782 | int str_length = 0; | ||
783 | |||
784 | if (dev->_is_running) { | ||
785 | pr_info("Video Channel is still running so return!\n"); | ||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | dev->_channel_upstream_select = channel_select; | ||
790 | sram_ch = dev->channels[channel_select].sram_channels; | ||
791 | |||
792 | INIT_WORK(&dev->_irq_work_entry, cx25821_vidups_handler); | ||
793 | dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue"); | ||
794 | |||
795 | if (!dev->_irq_queues) { | ||
796 | pr_err("create_singlethread_workqueue() for Video FAILED!\n"); | ||
797 | return -ENOMEM; | ||
798 | } | ||
799 | /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for | ||
800 | * channel A-C | ||
801 | */ | ||
802 | tmp = cx_read(VID_CH_MODE_SEL); | ||
803 | cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); | ||
804 | |||
805 | dev->_is_running = 0; | ||
806 | dev->_frame_count = 0; | ||
807 | dev->_file_status = RESET_STATUS; | ||
808 | dev->_lines_count = dev->_isNTSC ? 480 : 576; | ||
809 | dev->_pixel_format = pixel_format; | ||
810 | dev->_line_size = | ||
811 | (dev->_pixel_format == | ||
812 | PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; | ||
813 | data_frame_size = dev->_isNTSC ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; | ||
814 | risc_buffer_size = | ||
815 | dev->_isNTSC ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; | ||
816 | |||
817 | if (dev->input_filename) { | ||
818 | str_length = strlen(dev->input_filename); | ||
819 | dev->_filename = kmalloc(str_length + 1, GFP_KERNEL); | ||
820 | |||
821 | if (!dev->_filename) | ||
822 | goto error; | ||
823 | |||
824 | memcpy(dev->_filename, dev->input_filename, str_length + 1); | ||
825 | } else { | ||
826 | str_length = strlen(dev->_defaultname); | ||
827 | dev->_filename = kmalloc(str_length + 1, GFP_KERNEL); | ||
828 | |||
829 | if (!dev->_filename) | ||
830 | goto error; | ||
831 | |||
832 | memcpy(dev->_filename, dev->_defaultname, str_length + 1); | ||
833 | } | ||
834 | |||
835 | /* Default if filename is empty string */ | ||
836 | if (strcmp(dev->input_filename, "") == 0) { | ||
837 | if (dev->_isNTSC) { | ||
838 | dev->_filename = | ||
839 | (dev->_pixel_format == | ||
840 | PIXEL_FRMT_411) ? "/root/vid411.yuv" : | ||
841 | "/root/vidtest.yuv"; | ||
842 | } else { | ||
843 | dev->_filename = | ||
844 | (dev->_pixel_format == | ||
845 | PIXEL_FRMT_411) ? "/root/pal411.yuv" : | ||
846 | "/root/pal422.yuv"; | ||
847 | } | ||
848 | } | ||
849 | |||
850 | dev->_is_running = 0; | ||
851 | dev->_frame_count = 0; | ||
852 | dev->_file_status = RESET_STATUS; | ||
853 | dev->_lines_count = dev->_isNTSC ? 480 : 576; | ||
854 | dev->_pixel_format = pixel_format; | ||
855 | dev->_line_size = | ||
856 | (dev->_pixel_format == | ||
857 | PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; | ||
858 | |||
859 | retval = | ||
860 | cx25821_sram_channel_setup_upstream(dev, sram_ch, dev->_line_size, | ||
861 | 0); | ||
862 | |||
863 | /* setup fifo + format */ | ||
864 | cx25821_set_pixelengine(dev, sram_ch, dev->_pixel_format); | ||
865 | |||
866 | dev->upstream_riscbuf_size = risc_buffer_size * 2; | ||
867 | dev->upstream_databuf_size = data_frame_size * 2; | ||
868 | |||
869 | /* Allocating buffers and prepare RISC program */ | ||
870 | retval = cx25821_upstream_buffer_prepare(dev, sram_ch, dev->_line_size); | ||
871 | if (retval < 0) { | ||
872 | pr_err("%s: Failed to set up Video upstream buffers!\n", | ||
873 | dev->name); | ||
874 | goto error; | ||
875 | } | ||
876 | |||
877 | cx25821_start_video_dma_upstream(dev, sram_ch); | ||
878 | |||
879 | return 0; | ||
880 | |||
881 | error: | ||
882 | cx25821_dev_unregister(dev); | ||
883 | |||
884 | return err; | ||
885 | } | ||
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream.h b/drivers/media/video/cx25821/cx25821-video-upstream.h new file mode 100644 index 000000000000..268ec8aa6a61 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-video-upstream.h | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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 | * | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | |||
26 | #define OUTPUT_FRMT_656 0 | ||
27 | #define OPEN_FILE_1 0 | ||
28 | #define NUM_PROGS 8 | ||
29 | #define NUM_FRAMES 2 | ||
30 | #define ODD_FIELD 0 | ||
31 | #define EVEN_FIELD 1 | ||
32 | #define TOP_OFFSET 0 | ||
33 | #define FIFO_DISABLE 0 | ||
34 | #define FIFO_ENABLE 1 | ||
35 | #define TEST_FRAMES 5 | ||
36 | #define END_OF_FILE 0 | ||
37 | #define IN_PROGRESS 1 | ||
38 | #define RESET_STATUS -1 | ||
39 | #define NUM_NO_OPS 5 | ||
40 | |||
41 | /* PAL and NTSC line sizes and number of lines. */ | ||
42 | #define WIDTH_D1 720 | ||
43 | #define NTSC_LINES_PER_FRAME 480 | ||
44 | #define PAL_LINES_PER_FRAME 576 | ||
45 | #define PAL_LINE_SZ 1440 | ||
46 | #define Y422_LINE_SZ 1440 | ||
47 | #define Y411_LINE_SZ 1080 | ||
48 | #define NTSC_FIELD_HEIGHT 240 | ||
49 | #define NTSC_ODD_FLD_LINES 241 | ||
50 | #define PAL_FIELD_HEIGHT 288 | ||
51 | |||
52 | #define FRAME_SIZE_NTSC_Y422 (NTSC_LINES_PER_FRAME * Y422_LINE_SZ) | ||
53 | #define FRAME_SIZE_NTSC_Y411 (NTSC_LINES_PER_FRAME * Y411_LINE_SZ) | ||
54 | #define FRAME_SIZE_PAL_Y422 (PAL_LINES_PER_FRAME * Y422_LINE_SZ) | ||
55 | #define FRAME_SIZE_PAL_Y411 (PAL_LINES_PER_FRAME * Y411_LINE_SZ) | ||
56 | |||
57 | #define NTSC_DATA_BUF_SZ (Y422_LINE_SZ * NTSC_LINES_PER_FRAME) | ||
58 | #define PAL_DATA_BUF_SZ (Y422_LINE_SZ * PAL_LINES_PER_FRAME) | ||
59 | |||
60 | #define RISC_WRITECR_INSTRUCTION_SIZE 16 | ||
61 | #define RISC_SYNC_INSTRUCTION_SIZE 4 | ||
62 | #define JUMP_INSTRUCTION_SIZE 12 | ||
63 | #define MAXSIZE_NO_OPS 36 | ||
64 | #define DWORD_SIZE 4 | ||
65 | |||
66 | #define USE_RISC_NOOP_VIDEO 1 | ||
67 | |||
68 | #ifdef USE_RISC_NOOP_VIDEO | ||
69 | #define PAL_US_VID_PROG_SIZE \ | ||
70 | (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ | ||
71 | RISC_WRITECR_INSTRUCTION_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \ | ||
72 | NUM_NO_OPS * DWORD_SIZE) | ||
73 | |||
74 | #define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE) | ||
75 | |||
76 | #define PAL_VID_PROG_SIZE \ | ||
77 | ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \ | ||
78 | 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ | ||
79 | JUMP_INSTRUCTION_SIZE + 2 * NUM_NO_OPS * DWORD_SIZE) | ||
80 | |||
81 | #define ODD_FLD_PAL_PROG_SIZE \ | ||
82 | (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ | ||
83 | RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ | ||
84 | NUM_NO_OPS * DWORD_SIZE) | ||
85 | |||
86 | #define ODD_FLD_NTSC_PROG_SIZE \ | ||
87 | (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \ | ||
88 | RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ | ||
89 | NUM_NO_OPS * DWORD_SIZE) | ||
90 | |||
91 | #define NTSC_US_VID_PROG_SIZE \ | ||
92 | ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \ | ||
93 | RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + \ | ||
94 | NUM_NO_OPS * DWORD_SIZE) | ||
95 | |||
96 | #define NTSC_RISC_BUF_SIZE \ | ||
97 | (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) | ||
98 | |||
99 | #define FRAME1_VID_PROG_SIZE \ | ||
100 | ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + \ | ||
101 | 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ | ||
102 | JUMP_INSTRUCTION_SIZE + 2 * NUM_NO_OPS * DWORD_SIZE) | ||
103 | |||
104 | #endif | ||
105 | |||
106 | #ifndef USE_RISC_NOOP_VIDEO | ||
107 | #define PAL_US_VID_PROG_SIZE \ | ||
108 | (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ | ||
109 | RISC_WRITECR_INSTRUCTION_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \ | ||
110 | JUMP_INSTRUCTION_SIZE) | ||
111 | |||
112 | #define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE) | ||
113 | |||
114 | #define PAL_VID_PROG_SIZE \ | ||
115 | ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \ | ||
116 | 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ | ||
117 | JUMP_INSTRUCTION_SIZE) | ||
118 | |||
119 | #define ODD_FLD_PAL_PROG_SIZE \ | ||
120 | (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ | ||
121 | RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) | ||
122 | |||
123 | #define ODD_FLD_NTSC_PROG_SIZE \ | ||
124 | (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \ | ||
125 | RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) | ||
126 | |||
127 | #define NTSC_US_VID_PROG_SIZE \ | ||
128 | ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \ | ||
129 | RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) | ||
130 | |||
131 | #define NTSC_RISC_BUF_SIZE \ | ||
132 | (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) | ||
133 | |||
134 | #define FRAME1_VID_PROG_SIZE \ | ||
135 | ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * 3 * DWORD_SIZE + \ | ||
136 | 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ | ||
137 | JUMP_INSTRUCTION_SIZE) | ||
138 | |||
139 | #endif | ||
diff --git a/drivers/media/video/cx25821/cx25821-video.c b/drivers/media/video/cx25821/cx25821-video.c new file mode 100644 index 000000000000..4d6907cda75b --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-video.c | |||
@@ -0,0 +1,2012 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver | ||
7 | * Parts adapted/taken from Eduardo Moscoso Rubino | ||
8 | * Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.com> | ||
9 | * | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
28 | |||
29 | #include "cx25821-video.h" | ||
30 | |||
31 | MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); | ||
32 | MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | |||
35 | static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; | ||
36 | static unsigned int radio_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; | ||
37 | |||
38 | module_param_array(video_nr, int, NULL, 0444); | ||
39 | module_param_array(radio_nr, int, NULL, 0444); | ||
40 | |||
41 | MODULE_PARM_DESC(video_nr, "video device numbers"); | ||
42 | MODULE_PARM_DESC(radio_nr, "radio device numbers"); | ||
43 | |||
44 | static unsigned int video_debug = VIDEO_DEBUG; | ||
45 | module_param(video_debug, int, 0644); | ||
46 | MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); | ||
47 | |||
48 | static unsigned int irq_debug; | ||
49 | module_param(irq_debug, int, 0644); | ||
50 | MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); | ||
51 | |||
52 | unsigned int vid_limit = 16; | ||
53 | module_param(vid_limit, int, 0644); | ||
54 | MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); | ||
55 | |||
56 | static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num); | ||
57 | |||
58 | static const struct v4l2_file_operations video_fops; | ||
59 | static const struct v4l2_ioctl_ops video_ioctl_ops; | ||
60 | |||
61 | #define FORMAT_FLAGS_PACKED 0x01 | ||
62 | |||
63 | struct cx25821_fmt formats[] = { | ||
64 | { | ||
65 | .name = "8 bpp, gray", | ||
66 | .fourcc = V4L2_PIX_FMT_GREY, | ||
67 | .depth = 8, | ||
68 | .flags = FORMAT_FLAGS_PACKED, | ||
69 | }, { | ||
70 | .name = "4:1:1, packed, Y41P", | ||
71 | .fourcc = V4L2_PIX_FMT_Y41P, | ||
72 | .depth = 12, | ||
73 | .flags = FORMAT_FLAGS_PACKED, | ||
74 | }, { | ||
75 | .name = "4:2:2, packed, YUYV", | ||
76 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
77 | .depth = 16, | ||
78 | .flags = FORMAT_FLAGS_PACKED, | ||
79 | }, { | ||
80 | .name = "4:2:2, packed, UYVY", | ||
81 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
82 | .depth = 16, | ||
83 | .flags = FORMAT_FLAGS_PACKED, | ||
84 | }, { | ||
85 | .name = "4:2:0, YUV", | ||
86 | .fourcc = V4L2_PIX_FMT_YUV420, | ||
87 | .depth = 12, | ||
88 | .flags = FORMAT_FLAGS_PACKED, | ||
89 | }, | ||
90 | }; | ||
91 | |||
92 | int cx25821_get_format_size(void) | ||
93 | { | ||
94 | return ARRAY_SIZE(formats); | ||
95 | } | ||
96 | |||
97 | struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc) | ||
98 | { | ||
99 | unsigned int i; | ||
100 | |||
101 | if (fourcc == V4L2_PIX_FMT_Y41P || fourcc == V4L2_PIX_FMT_YUV411P) | ||
102 | return formats + 1; | ||
103 | |||
104 | for (i = 0; i < ARRAY_SIZE(formats); i++) | ||
105 | if (formats[i].fourcc == fourcc) | ||
106 | return formats + i; | ||
107 | |||
108 | pr_err("%s(0x%08x) NOT FOUND\n", __func__, fourcc); | ||
109 | return NULL; | ||
110 | } | ||
111 | |||
112 | void cx25821_dump_video_queue(struct cx25821_dev *dev, | ||
113 | struct cx25821_dmaqueue *q) | ||
114 | { | ||
115 | struct cx25821_buffer *buf; | ||
116 | struct list_head *item; | ||
117 | dprintk(1, "%s()\n", __func__); | ||
118 | |||
119 | if (!list_empty(&q->active)) { | ||
120 | list_for_each(item, &q->active) | ||
121 | buf = list_entry(item, struct cx25821_buffer, vb.queue); | ||
122 | } | ||
123 | |||
124 | if (!list_empty(&q->queued)) { | ||
125 | list_for_each(item, &q->queued) | ||
126 | buf = list_entry(item, struct cx25821_buffer, vb.queue); | ||
127 | } | ||
128 | |||
129 | } | ||
130 | |||
131 | void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, | ||
132 | u32 count) | ||
133 | { | ||
134 | struct cx25821_buffer *buf; | ||
135 | int bc; | ||
136 | |||
137 | for (bc = 0;; bc++) { | ||
138 | if (list_empty(&q->active)) { | ||
139 | dprintk(1, "bc=%d (=0: active empty)\n", bc); | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | buf = | ||
144 | list_entry(q->active.next, struct cx25821_buffer, vb.queue); | ||
145 | |||
146 | /* count comes from the hw and it is 16bit wide -- | ||
147 | * this trick handles wrap-arounds correctly for | ||
148 | * up to 32767 buffers in flight... */ | ||
149 | if ((s16) (count - buf->count) < 0) | ||
150 | break; | ||
151 | |||
152 | do_gettimeofday(&buf->vb.ts); | ||
153 | buf->vb.state = VIDEOBUF_DONE; | ||
154 | list_del(&buf->vb.queue); | ||
155 | wake_up(&buf->vb.done); | ||
156 | } | ||
157 | |||
158 | if (list_empty(&q->active)) | ||
159 | del_timer(&q->timeout); | ||
160 | else | ||
161 | mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); | ||
162 | if (bc != 1) | ||
163 | pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc); | ||
164 | } | ||
165 | |||
166 | #ifdef TUNER_FLAG | ||
167 | int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) | ||
168 | { | ||
169 | dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", | ||
170 | __func__, (unsigned int)norm, v4l2_norm_to_name(norm)); | ||
171 | |||
172 | dev->tvnorm = norm; | ||
173 | |||
174 | /* Tell the internal A/V decoder */ | ||
175 | cx25821_call_all(dev, core, s_std, norm); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | #endif | ||
180 | |||
181 | struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, | ||
182 | struct pci_dev *pci, | ||
183 | struct video_device *template, | ||
184 | char *type) | ||
185 | { | ||
186 | struct video_device *vfd; | ||
187 | dprintk(1, "%s()\n", __func__); | ||
188 | |||
189 | vfd = video_device_alloc(); | ||
190 | if (NULL == vfd) | ||
191 | return NULL; | ||
192 | *vfd = *template; | ||
193 | vfd->v4l2_dev = &dev->v4l2_dev; | ||
194 | vfd->release = video_device_release; | ||
195 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, | ||
196 | cx25821_boards[dev->board].name); | ||
197 | video_set_drvdata(vfd, dev); | ||
198 | return vfd; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl) | ||
203 | { | ||
204 | int i; | ||
205 | |||
206 | if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1) | ||
207 | return -EINVAL; | ||
208 | for (i = 0; i < CX25821_CTLS; i++) | ||
209 | if (cx25821_ctls[i].v.id == qctrl->id) | ||
210 | break; | ||
211 | if (i == CX25821_CTLS) { | ||
212 | *qctrl = no_ctl; | ||
213 | return 0; | ||
214 | } | ||
215 | *qctrl = cx25821_ctls[i].v; | ||
216 | return 0; | ||
217 | } | ||
218 | */ | ||
219 | |||
220 | /* resource management */ | ||
221 | int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, | ||
222 | unsigned int bit) | ||
223 | { | ||
224 | dprintk(1, "%s()\n", __func__); | ||
225 | if (fh->resources & bit) | ||
226 | /* have it already allocated */ | ||
227 | return 1; | ||
228 | |||
229 | /* is it free? */ | ||
230 | mutex_lock(&dev->lock); | ||
231 | if (dev->channels[fh->channel_id].resources & bit) { | ||
232 | /* no, someone else uses it */ | ||
233 | mutex_unlock(&dev->lock); | ||
234 | return 0; | ||
235 | } | ||
236 | /* it's free, grab it */ | ||
237 | fh->resources |= bit; | ||
238 | dev->channels[fh->channel_id].resources |= bit; | ||
239 | dprintk(1, "res: get %d\n", bit); | ||
240 | mutex_unlock(&dev->lock); | ||
241 | return 1; | ||
242 | } | ||
243 | |||
244 | int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit) | ||
245 | { | ||
246 | return fh->resources & bit; | ||
247 | } | ||
248 | |||
249 | int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit) | ||
250 | { | ||
251 | return fh->dev->channels[fh->channel_id].resources & bit; | ||
252 | } | ||
253 | |||
254 | void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, | ||
255 | unsigned int bits) | ||
256 | { | ||
257 | BUG_ON((fh->resources & bits) != bits); | ||
258 | dprintk(1, "%s()\n", __func__); | ||
259 | |||
260 | mutex_lock(&dev->lock); | ||
261 | fh->resources &= ~bits; | ||
262 | dev->channels[fh->channel_id].resources &= ~bits; | ||
263 | dprintk(1, "res: put %d\n", bits); | ||
264 | mutex_unlock(&dev->lock); | ||
265 | } | ||
266 | |||
267 | int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input) | ||
268 | { | ||
269 | struct v4l2_routing route; | ||
270 | memset(&route, 0, sizeof(route)); | ||
271 | |||
272 | dprintk(1, "%s(): video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", | ||
273 | __func__, input, INPUT(input)->vmux, INPUT(input)->gpio0, | ||
274 | INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3); | ||
275 | dev->input = input; | ||
276 | |||
277 | route.input = INPUT(input)->vmux; | ||
278 | |||
279 | /* Tell the internal A/V decoder */ | ||
280 | cx25821_call_all(dev, video, s_routing, INPUT(input)->vmux, 0, 0); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | int cx25821_start_video_dma(struct cx25821_dev *dev, | ||
286 | struct cx25821_dmaqueue *q, | ||
287 | struct cx25821_buffer *buf, | ||
288 | struct sram_channel *channel) | ||
289 | { | ||
290 | int tmp = 0; | ||
291 | |||
292 | /* setup fifo + format */ | ||
293 | cx25821_sram_channel_setup(dev, channel, buf->bpl, buf->risc.dma); | ||
294 | |||
295 | /* reset counter */ | ||
296 | cx_write(channel->gpcnt_ctl, 3); | ||
297 | q->count = 1; | ||
298 | |||
299 | /* enable irq */ | ||
300 | cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i)); | ||
301 | cx_set(channel->int_msk, 0x11); | ||
302 | |||
303 | /* start dma */ | ||
304 | cx_write(channel->dma_ctl, 0x11); /* FIFO and RISC enable */ | ||
305 | |||
306 | /* make sure upstream setting if any is reversed */ | ||
307 | tmp = cx_read(VID_CH_MODE_SEL); | ||
308 | cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | int cx25821_restart_video_queue(struct cx25821_dev *dev, | ||
314 | struct cx25821_dmaqueue *q, | ||
315 | struct sram_channel *channel) | ||
316 | { | ||
317 | struct cx25821_buffer *buf, *prev; | ||
318 | struct list_head *item; | ||
319 | |||
320 | if (!list_empty(&q->active)) { | ||
321 | buf = | ||
322 | list_entry(q->active.next, struct cx25821_buffer, vb.queue); | ||
323 | |||
324 | cx25821_start_video_dma(dev, q, buf, channel); | ||
325 | |||
326 | list_for_each(item, &q->active) { | ||
327 | buf = list_entry(item, struct cx25821_buffer, vb.queue); | ||
328 | buf->count = q->count++; | ||
329 | } | ||
330 | |||
331 | mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | prev = NULL; | ||
336 | for (;;) { | ||
337 | if (list_empty(&q->queued)) | ||
338 | return 0; | ||
339 | |||
340 | buf = | ||
341 | list_entry(q->queued.next, struct cx25821_buffer, vb.queue); | ||
342 | |||
343 | if (NULL == prev) { | ||
344 | list_move_tail(&buf->vb.queue, &q->active); | ||
345 | cx25821_start_video_dma(dev, q, buf, channel); | ||
346 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
347 | buf->count = q->count++; | ||
348 | mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); | ||
349 | } else if (prev->vb.width == buf->vb.width && | ||
350 | prev->vb.height == buf->vb.height && | ||
351 | prev->fmt == buf->fmt) { | ||
352 | list_move_tail(&buf->vb.queue, &q->active); | ||
353 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
354 | buf->count = q->count++; | ||
355 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
356 | prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ | ||
357 | } else { | ||
358 | return 0; | ||
359 | } | ||
360 | prev = buf; | ||
361 | } | ||
362 | } | ||
363 | |||
364 | void cx25821_vid_timeout(unsigned long data) | ||
365 | { | ||
366 | struct cx25821_data *timeout_data = (struct cx25821_data *)data; | ||
367 | struct cx25821_dev *dev = timeout_data->dev; | ||
368 | struct sram_channel *channel = timeout_data->channel; | ||
369 | struct cx25821_dmaqueue *q = &dev->channels[channel->i].vidq; | ||
370 | struct cx25821_buffer *buf; | ||
371 | unsigned long flags; | ||
372 | |||
373 | /* cx25821_sram_channel_dump(dev, channel); */ | ||
374 | cx_clear(channel->dma_ctl, 0x11); | ||
375 | |||
376 | spin_lock_irqsave(&dev->slock, flags); | ||
377 | while (!list_empty(&q->active)) { | ||
378 | buf = | ||
379 | list_entry(q->active.next, struct cx25821_buffer, vb.queue); | ||
380 | list_del(&buf->vb.queue); | ||
381 | |||
382 | buf->vb.state = VIDEOBUF_ERROR; | ||
383 | wake_up(&buf->vb.done); | ||
384 | } | ||
385 | |||
386 | cx25821_restart_video_queue(dev, q, channel); | ||
387 | spin_unlock_irqrestore(&dev->slock, flags); | ||
388 | } | ||
389 | |||
390 | int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) | ||
391 | { | ||
392 | u32 count = 0; | ||
393 | int handled = 0; | ||
394 | u32 mask; | ||
395 | struct sram_channel *channel = dev->channels[chan_num].sram_channels; | ||
396 | |||
397 | mask = cx_read(channel->int_msk); | ||
398 | if (0 == (status & mask)) | ||
399 | return handled; | ||
400 | |||
401 | cx_write(channel->int_stat, status); | ||
402 | |||
403 | /* risc op code error */ | ||
404 | if (status & (1 << 16)) { | ||
405 | pr_warn("%s, %s: video risc op code error\n", | ||
406 | dev->name, channel->name); | ||
407 | cx_clear(channel->dma_ctl, 0x11); | ||
408 | cx25821_sram_channel_dump(dev, channel); | ||
409 | } | ||
410 | |||
411 | /* risc1 y */ | ||
412 | if (status & FLD_VID_DST_RISC1) { | ||
413 | spin_lock(&dev->slock); | ||
414 | count = cx_read(channel->gpcnt); | ||
415 | cx25821_video_wakeup(dev, &dev->channels[channel->i].vidq, | ||
416 | count); | ||
417 | spin_unlock(&dev->slock); | ||
418 | handled++; | ||
419 | } | ||
420 | |||
421 | /* risc2 y */ | ||
422 | if (status & 0x10) { | ||
423 | dprintk(2, "stopper video\n"); | ||
424 | spin_lock(&dev->slock); | ||
425 | cx25821_restart_video_queue(dev, | ||
426 | &dev->channels[channel->i].vidq, channel); | ||
427 | spin_unlock(&dev->slock); | ||
428 | handled++; | ||
429 | } | ||
430 | return handled; | ||
431 | } | ||
432 | |||
433 | void cx25821_videoioctl_unregister(struct cx25821_dev *dev) | ||
434 | { | ||
435 | if (dev->ioctl_dev) { | ||
436 | if (video_is_registered(dev->ioctl_dev)) | ||
437 | video_unregister_device(dev->ioctl_dev); | ||
438 | else | ||
439 | video_device_release(dev->ioctl_dev); | ||
440 | |||
441 | dev->ioctl_dev = NULL; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) | ||
446 | { | ||
447 | cx_clear(PCI_INT_MSK, 1); | ||
448 | |||
449 | if (dev->channels[chan_num].video_dev) { | ||
450 | if (video_is_registered(dev->channels[chan_num].video_dev)) | ||
451 | video_unregister_device( | ||
452 | dev->channels[chan_num].video_dev); | ||
453 | else | ||
454 | video_device_release( | ||
455 | dev->channels[chan_num].video_dev); | ||
456 | |||
457 | dev->channels[chan_num].video_dev = NULL; | ||
458 | |||
459 | btcx_riscmem_free(dev->pci, | ||
460 | &dev->channels[chan_num].vidq.stopper); | ||
461 | |||
462 | pr_warn("device %d released!\n", chan_num); | ||
463 | } | ||
464 | |||
465 | } | ||
466 | |||
467 | int cx25821_video_register(struct cx25821_dev *dev) | ||
468 | { | ||
469 | int err; | ||
470 | int i; | ||
471 | |||
472 | struct video_device cx25821_video_device = { | ||
473 | .name = "cx25821-video", | ||
474 | .fops = &video_fops, | ||
475 | .minor = -1, | ||
476 | .ioctl_ops = &video_ioctl_ops, | ||
477 | .tvnorms = CX25821_NORMS, | ||
478 | .current_norm = V4L2_STD_NTSC_M, | ||
479 | }; | ||
480 | |||
481 | spin_lock_init(&dev->slock); | ||
482 | |||
483 | for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) { | ||
484 | cx25821_init_controls(dev, i); | ||
485 | |||
486 | cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper, | ||
487 | dev->channels[i].sram_channels->dma_ctl, | ||
488 | 0x11, 0); | ||
489 | |||
490 | dev->channels[i].sram_channels = &cx25821_sram_channels[i]; | ||
491 | dev->channels[i].video_dev = NULL; | ||
492 | dev->channels[i].resources = 0; | ||
493 | |||
494 | cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff); | ||
495 | |||
496 | INIT_LIST_HEAD(&dev->channels[i].vidq.active); | ||
497 | INIT_LIST_HEAD(&dev->channels[i].vidq.queued); | ||
498 | |||
499 | dev->channels[i].timeout_data.dev = dev; | ||
500 | dev->channels[i].timeout_data.channel = | ||
501 | &cx25821_sram_channels[i]; | ||
502 | dev->channels[i].vidq.timeout.function = | ||
503 | cx25821_vid_timeout; | ||
504 | dev->channels[i].vidq.timeout.data = | ||
505 | (unsigned long)&dev->channels[i].timeout_data; | ||
506 | init_timer(&dev->channels[i].vidq.timeout); | ||
507 | |||
508 | /* register v4l devices */ | ||
509 | dev->channels[i].video_dev = cx25821_vdev_init(dev, | ||
510 | dev->pci, &cx25821_video_device, "video"); | ||
511 | |||
512 | err = video_register_device(dev->channels[i].video_dev, | ||
513 | VFL_TYPE_GRABBER, video_nr[dev->nr]); | ||
514 | |||
515 | if (err < 0) | ||
516 | goto fail_unreg; | ||
517 | |||
518 | } | ||
519 | |||
520 | /* set PCI interrupt */ | ||
521 | cx_set(PCI_INT_MSK, 0xff); | ||
522 | |||
523 | /* initial device configuration */ | ||
524 | mutex_lock(&dev->lock); | ||
525 | #ifdef TUNER_FLAG | ||
526 | dev->tvnorm = cx25821_video_device.current_norm; | ||
527 | cx25821_set_tvnorm(dev, dev->tvnorm); | ||
528 | #endif | ||
529 | mutex_unlock(&dev->lock); | ||
530 | |||
531 | |||
532 | return 0; | ||
533 | |||
534 | fail_unreg: | ||
535 | cx25821_video_unregister(dev, i); | ||
536 | return err; | ||
537 | } | ||
538 | |||
539 | int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, | ||
540 | unsigned int *size) | ||
541 | { | ||
542 | struct cx25821_fh *fh = q->priv_data; | ||
543 | |||
544 | *size = fh->fmt->depth * fh->width * fh->height >> 3; | ||
545 | |||
546 | if (0 == *count) | ||
547 | *count = 32; | ||
548 | |||
549 | if (*size * *count > vid_limit * 1024 * 1024) | ||
550 | *count = (vid_limit * 1024 * 1024) / *size; | ||
551 | |||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | ||
556 | enum v4l2_field field) | ||
557 | { | ||
558 | struct cx25821_fh *fh = q->priv_data; | ||
559 | struct cx25821_dev *dev = fh->dev; | ||
560 | struct cx25821_buffer *buf = | ||
561 | container_of(vb, struct cx25821_buffer, vb); | ||
562 | int rc, init_buffer = 0; | ||
563 | u32 line0_offset, line1_offset; | ||
564 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
565 | int bpl_local = LINE_SIZE_D1; | ||
566 | int channel_opened = fh->channel_id; | ||
567 | |||
568 | BUG_ON(NULL == fh->fmt); | ||
569 | if (fh->width < 48 || fh->width > 720 || | ||
570 | fh->height < 32 || fh->height > 576) | ||
571 | return -EINVAL; | ||
572 | |||
573 | buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; | ||
574 | |||
575 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | ||
576 | return -EINVAL; | ||
577 | |||
578 | if (buf->fmt != fh->fmt || | ||
579 | buf->vb.width != fh->width || | ||
580 | buf->vb.height != fh->height || buf->vb.field != field) { | ||
581 | buf->fmt = fh->fmt; | ||
582 | buf->vb.width = fh->width; | ||
583 | buf->vb.height = fh->height; | ||
584 | buf->vb.field = field; | ||
585 | init_buffer = 1; | ||
586 | } | ||
587 | |||
588 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
589 | init_buffer = 1; | ||
590 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
591 | if (0 != rc) { | ||
592 | printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n")); | ||
593 | goto fail; | ||
594 | } | ||
595 | } | ||
596 | |||
597 | dprintk(1, "init_buffer=%d\n", init_buffer); | ||
598 | |||
599 | if (init_buffer) { | ||
600 | |||
601 | channel_opened = dev->channel_opened; | ||
602 | if (channel_opened < 0 || channel_opened > 7) | ||
603 | channel_opened = 7; | ||
604 | |||
605 | if (dev->channels[channel_opened].pixel_formats == | ||
606 | PIXEL_FRMT_411) | ||
607 | buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3; | ||
608 | else | ||
609 | buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width); | ||
610 | |||
611 | if (dev->channels[channel_opened].pixel_formats == | ||
612 | PIXEL_FRMT_411) { | ||
613 | bpl_local = buf->bpl; | ||
614 | } else { | ||
615 | bpl_local = buf->bpl; /* Default */ | ||
616 | |||
617 | if (channel_opened >= 0 && channel_opened <= 7) { | ||
618 | if (dev->channels[channel_opened] | ||
619 | .use_cif_resolution) { | ||
620 | if (dev->tvnorm & V4L2_STD_PAL_BG | ||
621 | || dev->tvnorm & V4L2_STD_PAL_DK) | ||
622 | bpl_local = 352 << 1; | ||
623 | else | ||
624 | bpl_local = | ||
625 | dev->channels[channel_opened]. | ||
626 | cif_width << | ||
627 | 1; | ||
628 | } | ||
629 | } | ||
630 | } | ||
631 | |||
632 | switch (buf->vb.field) { | ||
633 | case V4L2_FIELD_TOP: | ||
634 | cx25821_risc_buffer(dev->pci, &buf->risc, | ||
635 | dma->sglist, 0, UNSET, | ||
636 | buf->bpl, 0, buf->vb.height); | ||
637 | break; | ||
638 | case V4L2_FIELD_BOTTOM: | ||
639 | cx25821_risc_buffer(dev->pci, &buf->risc, | ||
640 | dma->sglist, UNSET, 0, | ||
641 | buf->bpl, 0, buf->vb.height); | ||
642 | break; | ||
643 | case V4L2_FIELD_INTERLACED: | ||
644 | /* All other formats are top field first */ | ||
645 | line0_offset = 0; | ||
646 | line1_offset = buf->bpl; | ||
647 | dprintk(1, "top field first\n"); | ||
648 | |||
649 | cx25821_risc_buffer(dev->pci, &buf->risc, | ||
650 | dma->sglist, line0_offset, | ||
651 | bpl_local, bpl_local, bpl_local, | ||
652 | buf->vb.height >> 1); | ||
653 | break; | ||
654 | case V4L2_FIELD_SEQ_TB: | ||
655 | cx25821_risc_buffer(dev->pci, &buf->risc, | ||
656 | dma->sglist, | ||
657 | 0, buf->bpl * (buf->vb.height >> 1), | ||
658 | buf->bpl, 0, buf->vb.height >> 1); | ||
659 | break; | ||
660 | case V4L2_FIELD_SEQ_BT: | ||
661 | cx25821_risc_buffer(dev->pci, &buf->risc, | ||
662 | dma->sglist, | ||
663 | buf->bpl * (buf->vb.height >> 1), 0, | ||
664 | buf->bpl, 0, buf->vb.height >> 1); | ||
665 | break; | ||
666 | default: | ||
667 | BUG(); | ||
668 | } | ||
669 | } | ||
670 | |||
671 | dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", | ||
672 | buf, buf->vb.i, fh->width, fh->height, fh->fmt->depth, | ||
673 | fh->fmt->name, (unsigned long)buf->risc.dma); | ||
674 | |||
675 | buf->vb.state = VIDEOBUF_PREPARED; | ||
676 | |||
677 | return 0; | ||
678 | |||
679 | fail: | ||
680 | cx25821_free_buffer(q, buf); | ||
681 | return rc; | ||
682 | } | ||
683 | |||
684 | void cx25821_buffer_release(struct videobuf_queue *q, | ||
685 | struct videobuf_buffer *vb) | ||
686 | { | ||
687 | struct cx25821_buffer *buf = | ||
688 | container_of(vb, struct cx25821_buffer, vb); | ||
689 | |||
690 | cx25821_free_buffer(q, buf); | ||
691 | } | ||
692 | |||
693 | struct videobuf_queue *get_queue(struct cx25821_fh *fh) | ||
694 | { | ||
695 | switch (fh->type) { | ||
696 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
697 | return &fh->vidq; | ||
698 | default: | ||
699 | BUG(); | ||
700 | return NULL; | ||
701 | } | ||
702 | } | ||
703 | |||
704 | int cx25821_get_resource(struct cx25821_fh *fh, int resource) | ||
705 | { | ||
706 | switch (fh->type) { | ||
707 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
708 | return resource; | ||
709 | default: | ||
710 | BUG(); | ||
711 | return 0; | ||
712 | } | ||
713 | } | ||
714 | |||
715 | int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) | ||
716 | { | ||
717 | struct cx25821_fh *fh = file->private_data; | ||
718 | |||
719 | return videobuf_mmap_mapper(get_queue(fh), vma); | ||
720 | } | ||
721 | |||
722 | |||
723 | static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
724 | { | ||
725 | struct cx25821_buffer *buf = | ||
726 | container_of(vb, struct cx25821_buffer, vb); | ||
727 | struct cx25821_buffer *prev; | ||
728 | struct cx25821_fh *fh = vq->priv_data; | ||
729 | struct cx25821_dev *dev = fh->dev; | ||
730 | struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq; | ||
731 | |||
732 | /* add jump to stopper */ | ||
733 | buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); | ||
734 | buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); | ||
735 | buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ | ||
736 | |||
737 | dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]); | ||
738 | |||
739 | if (!list_empty(&q->queued)) { | ||
740 | list_add_tail(&buf->vb.queue, &q->queued); | ||
741 | buf->vb.state = VIDEOBUF_QUEUED; | ||
742 | dprintk(2, "[%p/%d] buffer_queue - append to queued\n", buf, | ||
743 | buf->vb.i); | ||
744 | |||
745 | } else if (list_empty(&q->active)) { | ||
746 | list_add_tail(&buf->vb.queue, &q->active); | ||
747 | cx25821_start_video_dma(dev, q, buf, | ||
748 | dev->channels[fh->channel_id].sram_channels); | ||
749 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
750 | buf->count = q->count++; | ||
751 | mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); | ||
752 | dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n", | ||
753 | buf, buf->vb.i, buf->count, q->count); | ||
754 | } else { | ||
755 | prev = list_entry(q->active.prev, struct cx25821_buffer, | ||
756 | vb.queue); | ||
757 | if (prev->vb.width == buf->vb.width | ||
758 | && prev->vb.height == buf->vb.height | ||
759 | && prev->fmt == buf->fmt) { | ||
760 | list_add_tail(&buf->vb.queue, &q->active); | ||
761 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
762 | buf->count = q->count++; | ||
763 | prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); | ||
764 | |||
765 | /* 64 bit bits 63-32 */ | ||
766 | prev->risc.jmp[2] = cpu_to_le32(0); | ||
767 | dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n", | ||
768 | buf, buf->vb.i, buf->count); | ||
769 | |||
770 | } else { | ||
771 | list_add_tail(&buf->vb.queue, &q->queued); | ||
772 | buf->vb.state = VIDEOBUF_QUEUED; | ||
773 | dprintk(2, "[%p/%d] buffer_queue - first queued\n", buf, | ||
774 | buf->vb.i); | ||
775 | } | ||
776 | } | ||
777 | |||
778 | if (list_empty(&q->active)) | ||
779 | dprintk(2, "active queue empty!\n"); | ||
780 | } | ||
781 | |||
782 | static struct videobuf_queue_ops cx25821_video_qops = { | ||
783 | .buf_setup = cx25821_buffer_setup, | ||
784 | .buf_prepare = cx25821_buffer_prepare, | ||
785 | .buf_queue = buffer_queue, | ||
786 | .buf_release = cx25821_buffer_release, | ||
787 | }; | ||
788 | |||
789 | static int video_open(struct file *file) | ||
790 | { | ||
791 | struct video_device *vdev = video_devdata(file); | ||
792 | struct cx25821_dev *h, *dev = video_drvdata(file); | ||
793 | struct cx25821_fh *fh; | ||
794 | struct list_head *list; | ||
795 | int minor = video_devdata(file)->minor; | ||
796 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
797 | u32 pix_format; | ||
798 | int ch_id = 0; | ||
799 | int i; | ||
800 | |||
801 | dprintk(1, "open dev=%s type=%s\n", video_device_node_name(vdev), | ||
802 | v4l2_type_names[type]); | ||
803 | |||
804 | /* allocate + initialize per filehandle data */ | ||
805 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
806 | if (NULL == fh) | ||
807 | return -ENOMEM; | ||
808 | |||
809 | mutex_lock(&cx25821_devlist_mutex); | ||
810 | |||
811 | list_for_each(list, &cx25821_devlist) | ||
812 | { | ||
813 | h = list_entry(list, struct cx25821_dev, devlist); | ||
814 | |||
815 | for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) { | ||
816 | if (h->channels[i].video_dev && | ||
817 | h->channels[i].video_dev->minor == minor) { | ||
818 | dev = h; | ||
819 | ch_id = i; | ||
820 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
821 | } | ||
822 | } | ||
823 | } | ||
824 | |||
825 | if (NULL == dev) { | ||
826 | mutex_unlock(&cx25821_devlist_mutex); | ||
827 | kfree(fh); | ||
828 | return -ENODEV; | ||
829 | } | ||
830 | |||
831 | file->private_data = fh; | ||
832 | fh->dev = dev; | ||
833 | fh->type = type; | ||
834 | fh->width = 720; | ||
835 | fh->channel_id = ch_id; | ||
836 | |||
837 | if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK) | ||
838 | fh->height = 576; | ||
839 | else | ||
840 | fh->height = 480; | ||
841 | |||
842 | dev->channel_opened = fh->channel_id; | ||
843 | if (dev->channels[ch_id].pixel_formats == PIXEL_FRMT_411) | ||
844 | pix_format = V4L2_PIX_FMT_Y41P; | ||
845 | else | ||
846 | pix_format = V4L2_PIX_FMT_YUYV; | ||
847 | fh->fmt = cx25821_format_by_fourcc(pix_format); | ||
848 | |||
849 | v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio); | ||
850 | |||
851 | videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, | ||
852 | &dev->pci->dev, &dev->slock, | ||
853 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
854 | V4L2_FIELD_INTERLACED, | ||
855 | sizeof(struct cx25821_buffer), fh, NULL); | ||
856 | |||
857 | dprintk(1, "post videobuf_queue_init()\n"); | ||
858 | mutex_unlock(&cx25821_devlist_mutex); | ||
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | static ssize_t video_read(struct file *file, char __user * data, size_t count, | ||
864 | loff_t *ppos) | ||
865 | { | ||
866 | struct cx25821_fh *fh = file->private_data; | ||
867 | |||
868 | switch (fh->type) { | ||
869 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
870 | if (cx25821_res_locked(fh, RESOURCE_VIDEO0)) | ||
871 | return -EBUSY; | ||
872 | |||
873 | return videobuf_read_one(&fh->vidq, data, count, ppos, | ||
874 | file->f_flags & O_NONBLOCK); | ||
875 | |||
876 | default: | ||
877 | BUG(); | ||
878 | return 0; | ||
879 | } | ||
880 | } | ||
881 | |||
882 | static unsigned int video_poll(struct file *file, | ||
883 | struct poll_table_struct *wait) | ||
884 | { | ||
885 | struct cx25821_fh *fh = file->private_data; | ||
886 | struct cx25821_buffer *buf; | ||
887 | |||
888 | if (cx25821_res_check(fh, RESOURCE_VIDEO0)) { | ||
889 | /* streaming capture */ | ||
890 | if (list_empty(&fh->vidq.stream)) | ||
891 | return POLLERR; | ||
892 | buf = list_entry(fh->vidq.stream.next, | ||
893 | struct cx25821_buffer, vb.stream); | ||
894 | } else { | ||
895 | /* read() capture */ | ||
896 | buf = (struct cx25821_buffer *)fh->vidq.read_buf; | ||
897 | if (NULL == buf) | ||
898 | return POLLERR; | ||
899 | } | ||
900 | |||
901 | poll_wait(file, &buf->vb.done, wait); | ||
902 | if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) { | ||
903 | if (buf->vb.state == VIDEOBUF_DONE) { | ||
904 | struct cx25821_dev *dev = fh->dev; | ||
905 | |||
906 | if (dev && dev->channels[fh->channel_id] | ||
907 | .use_cif_resolution) { | ||
908 | u8 cam_id = *((char *)buf->vb.baddr + 3); | ||
909 | memcpy((char *)buf->vb.baddr, | ||
910 | (char *)buf->vb.baddr + (fh->width * 2), | ||
911 | (fh->width * 2)); | ||
912 | *((char *)buf->vb.baddr + 3) = cam_id; | ||
913 | } | ||
914 | } | ||
915 | |||
916 | return POLLIN | POLLRDNORM; | ||
917 | } | ||
918 | |||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static int video_release(struct file *file) | ||
923 | { | ||
924 | struct cx25821_fh *fh = file->private_data; | ||
925 | struct cx25821_dev *dev = fh->dev; | ||
926 | |||
927 | /* stop the risc engine and fifo */ | ||
928 | cx_write(channel0->dma_ctl, 0); /* FIFO and RISC disable */ | ||
929 | |||
930 | /* stop video capture */ | ||
931 | if (cx25821_res_check(fh, RESOURCE_VIDEO0)) { | ||
932 | videobuf_queue_cancel(&fh->vidq); | ||
933 | cx25821_res_free(dev, fh, RESOURCE_VIDEO0); | ||
934 | } | ||
935 | |||
936 | if (fh->vidq.read_buf) { | ||
937 | cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf); | ||
938 | kfree(fh->vidq.read_buf); | ||
939 | } | ||
940 | |||
941 | videobuf_mmap_free(&fh->vidq); | ||
942 | |||
943 | v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio); | ||
944 | file->private_data = NULL; | ||
945 | kfree(fh); | ||
946 | |||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) | ||
951 | { | ||
952 | struct cx25821_fh *fh = priv; | ||
953 | struct cx25821_dev *dev = fh->dev; | ||
954 | |||
955 | if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) | ||
956 | return -EINVAL; | ||
957 | |||
958 | if (unlikely(i != fh->type)) | ||
959 | return -EINVAL; | ||
960 | |||
961 | if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, | ||
962 | RESOURCE_VIDEO0)))) | ||
963 | return -EBUSY; | ||
964 | |||
965 | return videobuf_streamon(get_queue(fh)); | ||
966 | } | ||
967 | |||
968 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | ||
969 | { | ||
970 | struct cx25821_fh *fh = priv; | ||
971 | struct cx25821_dev *dev = fh->dev; | ||
972 | int err, res; | ||
973 | |||
974 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
975 | return -EINVAL; | ||
976 | if (i != fh->type) | ||
977 | return -EINVAL; | ||
978 | |||
979 | res = cx25821_get_resource(fh, RESOURCE_VIDEO0); | ||
980 | err = videobuf_streamoff(get_queue(fh)); | ||
981 | if (err < 0) | ||
982 | return err; | ||
983 | cx25821_res_free(dev, fh, res); | ||
984 | return 0; | ||
985 | } | ||
986 | |||
987 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | ||
988 | struct v4l2_format *f) | ||
989 | { | ||
990 | struct cx25821_fh *fh = priv; | ||
991 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
992 | struct v4l2_mbus_framefmt mbus_fmt; | ||
993 | int err; | ||
994 | int pix_format = PIXEL_FRMT_422; | ||
995 | |||
996 | if (fh) { | ||
997 | err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, | ||
998 | fh->prio); | ||
999 | if (0 != err) | ||
1000 | return err; | ||
1001 | } | ||
1002 | |||
1003 | dprintk(2, "%s()\n", __func__); | ||
1004 | err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f); | ||
1005 | |||
1006 | if (0 != err) | ||
1007 | return err; | ||
1008 | |||
1009 | fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); | ||
1010 | fh->vidq.field = f->fmt.pix.field; | ||
1011 | |||
1012 | /* check if width and height is valid based on set standard */ | ||
1013 | if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) | ||
1014 | fh->width = f->fmt.pix.width; | ||
1015 | |||
1016 | if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) | ||
1017 | fh->height = f->fmt.pix.height; | ||
1018 | |||
1019 | if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P) | ||
1020 | pix_format = PIXEL_FRMT_411; | ||
1021 | else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) | ||
1022 | pix_format = PIXEL_FRMT_422; | ||
1023 | else | ||
1024 | return -EINVAL; | ||
1025 | |||
1026 | cx25821_set_pixel_format(dev, SRAM_CH00, pix_format); | ||
1027 | |||
1028 | /* check if cif resolution */ | ||
1029 | if (fh->width == 320 || fh->width == 352) | ||
1030 | dev->channels[fh->channel_id].use_cif_resolution = 1; | ||
1031 | else | ||
1032 | dev->channels[fh->channel_id].use_cif_resolution = 0; | ||
1033 | |||
1034 | dev->channels[fh->channel_id].cif_width = fh->width; | ||
1035 | medusa_set_resolution(dev, fh->width, SRAM_CH00); | ||
1036 | |||
1037 | dprintk(2, "%s(): width=%d height=%d field=%d\n", __func__, fh->width, | ||
1038 | fh->height, fh->vidq.field); | ||
1039 | v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); | ||
1040 | cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt); | ||
1041 | |||
1042 | return 0; | ||
1043 | } | ||
1044 | |||
1045 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
1046 | { | ||
1047 | int ret_val = 0; | ||
1048 | struct cx25821_fh *fh = priv; | ||
1049 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1050 | |||
1051 | ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK); | ||
1052 | |||
1053 | p->sequence = dev->channels[fh->channel_id].vidq.count; | ||
1054 | |||
1055 | return ret_val; | ||
1056 | } | ||
1057 | |||
1058 | static int vidioc_log_status(struct file *file, void *priv) | ||
1059 | { | ||
1060 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1061 | struct cx25821_fh *fh = priv; | ||
1062 | char name[32 + 2]; | ||
1063 | |||
1064 | struct sram_channel *sram_ch = dev->channels[fh->channel_id] | ||
1065 | .sram_channels; | ||
1066 | u32 tmp = 0; | ||
1067 | |||
1068 | snprintf(name, sizeof(name), "%s/2", dev->name); | ||
1069 | pr_info("%s/2: ============ START LOG STATUS ============\n", | ||
1070 | dev->name); | ||
1071 | cx25821_call_all(dev, core, log_status); | ||
1072 | tmp = cx_read(sram_ch->dma_ctl); | ||
1073 | pr_info("Video input 0 is %s\n", | ||
1074 | (tmp & 0x11) ? "streaming" : "stopped"); | ||
1075 | pr_info("%s/2: ============= END LOG STATUS =============\n", | ||
1076 | dev->name); | ||
1077 | return 0; | ||
1078 | } | ||
1079 | |||
1080 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
1081 | struct v4l2_control *ctl) | ||
1082 | { | ||
1083 | struct cx25821_fh *fh = priv; | ||
1084 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1085 | int err; | ||
1086 | |||
1087 | if (fh) { | ||
1088 | err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, | ||
1089 | fh->prio); | ||
1090 | if (0 != err) | ||
1091 | return err; | ||
1092 | } | ||
1093 | |||
1094 | return cx25821_set_control(dev, ctl, fh->channel_id); | ||
1095 | } | ||
1096 | |||
1097 | /* VIDEO IOCTLS */ | ||
1098 | int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
1099 | struct v4l2_format *f) | ||
1100 | { | ||
1101 | struct cx25821_fh *fh = priv; | ||
1102 | |||
1103 | f->fmt.pix.width = fh->width; | ||
1104 | f->fmt.pix.height = fh->height; | ||
1105 | f->fmt.pix.field = fh->vidq.field; | ||
1106 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | ||
1107 | f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3; | ||
1108 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
1109 | |||
1110 | return 0; | ||
1111 | } | ||
1112 | |||
1113 | int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
1114 | struct v4l2_format *f) | ||
1115 | { | ||
1116 | struct cx25821_fmt *fmt; | ||
1117 | enum v4l2_field field; | ||
1118 | unsigned int maxw, maxh; | ||
1119 | |||
1120 | fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); | ||
1121 | if (NULL == fmt) | ||
1122 | return -EINVAL; | ||
1123 | |||
1124 | field = f->fmt.pix.field; | ||
1125 | maxw = 720; | ||
1126 | maxh = 576; | ||
1127 | |||
1128 | if (V4L2_FIELD_ANY == field) { | ||
1129 | if (f->fmt.pix.height > maxh / 2) | ||
1130 | field = V4L2_FIELD_INTERLACED; | ||
1131 | else | ||
1132 | field = V4L2_FIELD_TOP; | ||
1133 | } | ||
1134 | |||
1135 | switch (field) { | ||
1136 | case V4L2_FIELD_TOP: | ||
1137 | case V4L2_FIELD_BOTTOM: | ||
1138 | maxh = maxh / 2; | ||
1139 | break; | ||
1140 | case V4L2_FIELD_INTERLACED: | ||
1141 | break; | ||
1142 | default: | ||
1143 | return -EINVAL; | ||
1144 | } | ||
1145 | |||
1146 | f->fmt.pix.field = field; | ||
1147 | if (f->fmt.pix.height < 32) | ||
1148 | f->fmt.pix.height = 32; | ||
1149 | if (f->fmt.pix.height > maxh) | ||
1150 | f->fmt.pix.height = maxh; | ||
1151 | if (f->fmt.pix.width < 48) | ||
1152 | f->fmt.pix.width = 48; | ||
1153 | if (f->fmt.pix.width > maxw) | ||
1154 | f->fmt.pix.width = maxw; | ||
1155 | f->fmt.pix.width &= ~0x03; | ||
1156 | f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; | ||
1157 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
1158 | |||
1159 | return 0; | ||
1160 | } | ||
1161 | |||
1162 | int cx25821_vidioc_querycap(struct file *file, void *priv, | ||
1163 | struct v4l2_capability *cap) | ||
1164 | { | ||
1165 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1166 | |||
1167 | strcpy(cap->driver, "cx25821"); | ||
1168 | strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card)); | ||
1169 | sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); | ||
1170 | cap->version = CX25821_VERSION_CODE; | ||
1171 | cap->capabilities = | ||
1172 | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; | ||
1173 | if (UNSET != dev->tuner_type) | ||
1174 | cap->capabilities |= V4L2_CAP_TUNER; | ||
1175 | return 0; | ||
1176 | } | ||
1177 | |||
1178 | int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
1179 | struct v4l2_fmtdesc *f) | ||
1180 | { | ||
1181 | if (unlikely(f->index >= ARRAY_SIZE(formats))) | ||
1182 | return -EINVAL; | ||
1183 | |||
1184 | strlcpy(f->description, formats[f->index].name, sizeof(f->description)); | ||
1185 | f->pixelformat = formats[f->index].fourcc; | ||
1186 | |||
1187 | return 0; | ||
1188 | } | ||
1189 | |||
1190 | int cx25821_vidioc_reqbufs(struct file *file, void *priv, | ||
1191 | struct v4l2_requestbuffers *p) | ||
1192 | { | ||
1193 | struct cx25821_fh *fh = priv; | ||
1194 | return videobuf_reqbufs(get_queue(fh), p); | ||
1195 | } | ||
1196 | |||
1197 | int cx25821_vidioc_querybuf(struct file *file, void *priv, | ||
1198 | struct v4l2_buffer *p) | ||
1199 | { | ||
1200 | struct cx25821_fh *fh = priv; | ||
1201 | return videobuf_querybuf(get_queue(fh), p); | ||
1202 | } | ||
1203 | |||
1204 | int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
1205 | { | ||
1206 | struct cx25821_fh *fh = priv; | ||
1207 | return videobuf_qbuf(get_queue(fh), p); | ||
1208 | } | ||
1209 | |||
1210 | int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) | ||
1211 | { | ||
1212 | struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev; | ||
1213 | struct cx25821_fh *fh = f; | ||
1214 | |||
1215 | *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio); | ||
1216 | |||
1217 | return 0; | ||
1218 | } | ||
1219 | |||
1220 | int cx25821_vidioc_s_priority(struct file *file, void *f, | ||
1221 | enum v4l2_priority prio) | ||
1222 | { | ||
1223 | struct cx25821_fh *fh = f; | ||
1224 | struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev; | ||
1225 | |||
1226 | return v4l2_prio_change(&dev->channels[fh->channel_id].prio, &fh->prio, | ||
1227 | prio); | ||
1228 | } | ||
1229 | |||
1230 | #ifdef TUNER_FLAG | ||
1231 | int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms) | ||
1232 | { | ||
1233 | struct cx25821_fh *fh = priv; | ||
1234 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1235 | int err; | ||
1236 | |||
1237 | dprintk(1, "%s()\n", __func__); | ||
1238 | |||
1239 | if (fh) { | ||
1240 | err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, | ||
1241 | fh->prio); | ||
1242 | if (0 != err) | ||
1243 | return err; | ||
1244 | } | ||
1245 | |||
1246 | if (dev->tvnorm == *tvnorms) | ||
1247 | return 0; | ||
1248 | |||
1249 | mutex_lock(&dev->lock); | ||
1250 | cx25821_set_tvnorm(dev, *tvnorms); | ||
1251 | mutex_unlock(&dev->lock); | ||
1252 | |||
1253 | medusa_set_videostandard(dev); | ||
1254 | |||
1255 | return 0; | ||
1256 | } | ||
1257 | #endif | ||
1258 | |||
1259 | int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i) | ||
1260 | { | ||
1261 | static const char * const iname[] = { | ||
1262 | [CX25821_VMUX_COMPOSITE] = "Composite", | ||
1263 | [CX25821_VMUX_SVIDEO] = "S-Video", | ||
1264 | [CX25821_VMUX_DEBUG] = "for debug only", | ||
1265 | }; | ||
1266 | unsigned int n; | ||
1267 | dprintk(1, "%s()\n", __func__); | ||
1268 | |||
1269 | n = i->index; | ||
1270 | if (n >= 2) | ||
1271 | return -EINVAL; | ||
1272 | |||
1273 | if (0 == INPUT(n)->type) | ||
1274 | return -EINVAL; | ||
1275 | |||
1276 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
1277 | strcpy(i->name, iname[INPUT(n)->type]); | ||
1278 | |||
1279 | i->std = CX25821_NORMS; | ||
1280 | return 0; | ||
1281 | } | ||
1282 | |||
1283 | int cx25821_vidioc_enum_input(struct file *file, void *priv, | ||
1284 | struct v4l2_input *i) | ||
1285 | { | ||
1286 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1287 | dprintk(1, "%s()\n", __func__); | ||
1288 | return cx25821_enum_input(dev, i); | ||
1289 | } | ||
1290 | |||
1291 | int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i) | ||
1292 | { | ||
1293 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1294 | |||
1295 | *i = dev->input; | ||
1296 | dprintk(1, "%s(): returns %d\n", __func__, *i); | ||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) | ||
1301 | { | ||
1302 | struct cx25821_fh *fh = priv; | ||
1303 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1304 | int err; | ||
1305 | |||
1306 | dprintk(1, "%s(%d)\n", __func__, i); | ||
1307 | |||
1308 | if (fh) { | ||
1309 | err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, | ||
1310 | fh->prio); | ||
1311 | if (0 != err) | ||
1312 | return err; | ||
1313 | } | ||
1314 | |||
1315 | if (i >= CX25821_NR_INPUT) { | ||
1316 | dprintk(1, "%s(): -EINVAL\n", __func__); | ||
1317 | return -EINVAL; | ||
1318 | } | ||
1319 | |||
1320 | mutex_lock(&dev->lock); | ||
1321 | cx25821_video_mux(dev, i); | ||
1322 | mutex_unlock(&dev->lock); | ||
1323 | return 0; | ||
1324 | } | ||
1325 | |||
1326 | #ifdef TUNER_FLAG | ||
1327 | int cx25821_vidioc_g_frequency(struct file *file, void *priv, | ||
1328 | struct v4l2_frequency *f) | ||
1329 | { | ||
1330 | struct cx25821_fh *fh = priv; | ||
1331 | struct cx25821_dev *dev = fh->dev; | ||
1332 | |||
1333 | f->frequency = dev->freq; | ||
1334 | |||
1335 | cx25821_call_all(dev, tuner, g_frequency, f); | ||
1336 | |||
1337 | return 0; | ||
1338 | } | ||
1339 | |||
1340 | int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f) | ||
1341 | { | ||
1342 | mutex_lock(&dev->lock); | ||
1343 | dev->freq = f->frequency; | ||
1344 | |||
1345 | cx25821_call_all(dev, tuner, s_frequency, f); | ||
1346 | |||
1347 | /* When changing channels it is required to reset TVAUDIO */ | ||
1348 | msleep(10); | ||
1349 | |||
1350 | mutex_unlock(&dev->lock); | ||
1351 | |||
1352 | return 0; | ||
1353 | } | ||
1354 | |||
1355 | int cx25821_vidioc_s_frequency(struct file *file, void *priv, | ||
1356 | struct v4l2_frequency *f) | ||
1357 | { | ||
1358 | struct cx25821_fh *fh = priv; | ||
1359 | struct cx25821_dev *dev; | ||
1360 | int err; | ||
1361 | |||
1362 | if (fh) { | ||
1363 | dev = fh->dev; | ||
1364 | err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, | ||
1365 | fh->prio); | ||
1366 | if (0 != err) | ||
1367 | return err; | ||
1368 | } else { | ||
1369 | pr_err("Invalid fh pointer!\n"); | ||
1370 | return -EINVAL; | ||
1371 | } | ||
1372 | |||
1373 | return cx25821_set_freq(dev, f); | ||
1374 | } | ||
1375 | #endif | ||
1376 | |||
1377 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1378 | int cx25821_vidioc_g_register(struct file *file, void *fh, | ||
1379 | struct v4l2_dbg_register *reg) | ||
1380 | { | ||
1381 | struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev; | ||
1382 | |||
1383 | if (!v4l2_chip_match_host(®->match)) | ||
1384 | return -EINVAL; | ||
1385 | |||
1386 | cx25821_call_all(dev, core, g_register, reg); | ||
1387 | |||
1388 | return 0; | ||
1389 | } | ||
1390 | |||
1391 | int cx25821_vidioc_s_register(struct file *file, void *fh, | ||
1392 | struct v4l2_dbg_register *reg) | ||
1393 | { | ||
1394 | struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev; | ||
1395 | |||
1396 | if (!v4l2_chip_match_host(®->match)) | ||
1397 | return -EINVAL; | ||
1398 | |||
1399 | cx25821_call_all(dev, core, s_register, reg); | ||
1400 | |||
1401 | return 0; | ||
1402 | } | ||
1403 | |||
1404 | #endif | ||
1405 | |||
1406 | #ifdef TUNER_FLAG | ||
1407 | int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) | ||
1408 | { | ||
1409 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1410 | |||
1411 | if (unlikely(UNSET == dev->tuner_type)) | ||
1412 | return -EINVAL; | ||
1413 | if (0 != t->index) | ||
1414 | return -EINVAL; | ||
1415 | |||
1416 | strcpy(t->name, "Television"); | ||
1417 | t->type = V4L2_TUNER_ANALOG_TV; | ||
1418 | t->capability = V4L2_TUNER_CAP_NORM; | ||
1419 | t->rangehigh = 0xffffffffUL; | ||
1420 | |||
1421 | t->signal = 0xffff; /* LOCKED */ | ||
1422 | return 0; | ||
1423 | } | ||
1424 | |||
1425 | int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) | ||
1426 | { | ||
1427 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1428 | struct cx25821_fh *fh = priv; | ||
1429 | int err; | ||
1430 | |||
1431 | if (fh) { | ||
1432 | err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, | ||
1433 | fh->prio); | ||
1434 | if (0 != err) | ||
1435 | return err; | ||
1436 | } | ||
1437 | |||
1438 | dprintk(1, "%s()\n", __func__); | ||
1439 | if (UNSET == dev->tuner_type) | ||
1440 | return -EINVAL; | ||
1441 | if (0 != t->index) | ||
1442 | return -EINVAL; | ||
1443 | |||
1444 | return 0; | ||
1445 | } | ||
1446 | |||
1447 | #endif | ||
1448 | /*****************************************************************************/ | ||
1449 | static const struct v4l2_queryctrl no_ctl = { | ||
1450 | .name = "42", | ||
1451 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
1452 | }; | ||
1453 | |||
1454 | static struct v4l2_queryctrl cx25821_ctls[] = { | ||
1455 | /* --- video --- */ | ||
1456 | { | ||
1457 | .id = V4L2_CID_BRIGHTNESS, | ||
1458 | .name = "Brightness", | ||
1459 | .minimum = 0, | ||
1460 | .maximum = 10000, | ||
1461 | .step = 1, | ||
1462 | .default_value = 6200, | ||
1463 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1464 | }, { | ||
1465 | .id = V4L2_CID_CONTRAST, | ||
1466 | .name = "Contrast", | ||
1467 | .minimum = 0, | ||
1468 | .maximum = 10000, | ||
1469 | .step = 1, | ||
1470 | .default_value = 5000, | ||
1471 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1472 | }, { | ||
1473 | .id = V4L2_CID_SATURATION, | ||
1474 | .name = "Saturation", | ||
1475 | .minimum = 0, | ||
1476 | .maximum = 10000, | ||
1477 | .step = 1, | ||
1478 | .default_value = 5000, | ||
1479 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1480 | }, { | ||
1481 | .id = V4L2_CID_HUE, | ||
1482 | .name = "Hue", | ||
1483 | .minimum = 0, | ||
1484 | .maximum = 10000, | ||
1485 | .step = 1, | ||
1486 | .default_value = 5000, | ||
1487 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1488 | } | ||
1489 | }; | ||
1490 | static const int CX25821_CTLS = ARRAY_SIZE(cx25821_ctls); | ||
1491 | |||
1492 | static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl) | ||
1493 | { | ||
1494 | int i; | ||
1495 | |||
1496 | if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1) | ||
1497 | return -EINVAL; | ||
1498 | for (i = 0; i < CX25821_CTLS; i++) | ||
1499 | if (cx25821_ctls[i].id == qctrl->id) | ||
1500 | break; | ||
1501 | if (i == CX25821_CTLS) { | ||
1502 | *qctrl = no_ctl; | ||
1503 | return 0; | ||
1504 | } | ||
1505 | *qctrl = cx25821_ctls[i]; | ||
1506 | return 0; | ||
1507 | } | ||
1508 | |||
1509 | int cx25821_vidioc_queryctrl(struct file *file, void *priv, | ||
1510 | struct v4l2_queryctrl *qctrl) | ||
1511 | { | ||
1512 | return cx25821_ctrl_query(qctrl); | ||
1513 | } | ||
1514 | |||
1515 | /* ------------------------------------------------------------------ */ | ||
1516 | /* VIDEO CTRL IOCTLS */ | ||
1517 | |||
1518 | static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) | ||
1519 | { | ||
1520 | unsigned int i; | ||
1521 | |||
1522 | for (i = 0; i < CX25821_CTLS; i++) | ||
1523 | if (cx25821_ctls[i].id == id) | ||
1524 | return cx25821_ctls + i; | ||
1525 | return NULL; | ||
1526 | } | ||
1527 | |||
1528 | int cx25821_vidioc_g_ctrl(struct file *file, void *priv, | ||
1529 | struct v4l2_control *ctl) | ||
1530 | { | ||
1531 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1532 | struct cx25821_fh *fh = priv; | ||
1533 | |||
1534 | const struct v4l2_queryctrl *ctrl; | ||
1535 | |||
1536 | ctrl = ctrl_by_id(ctl->id); | ||
1537 | |||
1538 | if (NULL == ctrl) | ||
1539 | return -EINVAL; | ||
1540 | switch (ctl->id) { | ||
1541 | case V4L2_CID_BRIGHTNESS: | ||
1542 | ctl->value = dev->channels[fh->channel_id].ctl_bright; | ||
1543 | break; | ||
1544 | case V4L2_CID_HUE: | ||
1545 | ctl->value = dev->channels[fh->channel_id].ctl_hue; | ||
1546 | break; | ||
1547 | case V4L2_CID_CONTRAST: | ||
1548 | ctl->value = dev->channels[fh->channel_id].ctl_contrast; | ||
1549 | break; | ||
1550 | case V4L2_CID_SATURATION: | ||
1551 | ctl->value = dev->channels[fh->channel_id].ctl_saturation; | ||
1552 | break; | ||
1553 | } | ||
1554 | return 0; | ||
1555 | } | ||
1556 | |||
1557 | int cx25821_set_control(struct cx25821_dev *dev, | ||
1558 | struct v4l2_control *ctl, int chan_num) | ||
1559 | { | ||
1560 | int err; | ||
1561 | const struct v4l2_queryctrl *ctrl; | ||
1562 | |||
1563 | err = -EINVAL; | ||
1564 | |||
1565 | ctrl = ctrl_by_id(ctl->id); | ||
1566 | |||
1567 | if (NULL == ctrl) | ||
1568 | return err; | ||
1569 | |||
1570 | switch (ctrl->type) { | ||
1571 | case V4L2_CTRL_TYPE_BOOLEAN: | ||
1572 | case V4L2_CTRL_TYPE_MENU: | ||
1573 | case V4L2_CTRL_TYPE_INTEGER: | ||
1574 | if (ctl->value < ctrl->minimum) | ||
1575 | ctl->value = ctrl->minimum; | ||
1576 | if (ctl->value > ctrl->maximum) | ||
1577 | ctl->value = ctrl->maximum; | ||
1578 | break; | ||
1579 | default: | ||
1580 | /* nothing */ ; | ||
1581 | } | ||
1582 | |||
1583 | switch (ctl->id) { | ||
1584 | case V4L2_CID_BRIGHTNESS: | ||
1585 | dev->channels[chan_num].ctl_bright = ctl->value; | ||
1586 | medusa_set_brightness(dev, ctl->value, chan_num); | ||
1587 | break; | ||
1588 | case V4L2_CID_HUE: | ||
1589 | dev->channels[chan_num].ctl_hue = ctl->value; | ||
1590 | medusa_set_hue(dev, ctl->value, chan_num); | ||
1591 | break; | ||
1592 | case V4L2_CID_CONTRAST: | ||
1593 | dev->channels[chan_num].ctl_contrast = ctl->value; | ||
1594 | medusa_set_contrast(dev, ctl->value, chan_num); | ||
1595 | break; | ||
1596 | case V4L2_CID_SATURATION: | ||
1597 | dev->channels[chan_num].ctl_saturation = ctl->value; | ||
1598 | medusa_set_saturation(dev, ctl->value, chan_num); | ||
1599 | break; | ||
1600 | } | ||
1601 | |||
1602 | err = 0; | ||
1603 | |||
1604 | return err; | ||
1605 | } | ||
1606 | |||
1607 | static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num) | ||
1608 | { | ||
1609 | struct v4l2_control ctrl; | ||
1610 | int i; | ||
1611 | for (i = 0; i < CX25821_CTLS; i++) { | ||
1612 | ctrl.id = cx25821_ctls[i].id; | ||
1613 | ctrl.value = cx25821_ctls[i].default_value; | ||
1614 | |||
1615 | cx25821_set_control(dev, &ctrl, chan_num); | ||
1616 | } | ||
1617 | } | ||
1618 | |||
1619 | int cx25821_vidioc_cropcap(struct file *file, void *priv, | ||
1620 | struct v4l2_cropcap *cropcap) | ||
1621 | { | ||
1622 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1623 | |||
1624 | if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1625 | return -EINVAL; | ||
1626 | cropcap->bounds.top = cropcap->bounds.left = 0; | ||
1627 | cropcap->bounds.width = 720; | ||
1628 | cropcap->bounds.height = dev->tvnorm == V4L2_STD_PAL_BG ? 576 : 480; | ||
1629 | cropcap->pixelaspect.numerator = | ||
1630 | dev->tvnorm == V4L2_STD_PAL_BG ? 59 : 10; | ||
1631 | cropcap->pixelaspect.denominator = | ||
1632 | dev->tvnorm == V4L2_STD_PAL_BG ? 54 : 11; | ||
1633 | cropcap->defrect = cropcap->bounds; | ||
1634 | return 0; | ||
1635 | } | ||
1636 | |||
1637 | int cx25821_vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop) | ||
1638 | { | ||
1639 | struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; | ||
1640 | struct cx25821_fh *fh = priv; | ||
1641 | int err; | ||
1642 | |||
1643 | if (fh) { | ||
1644 | err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, | ||
1645 | fh->prio); | ||
1646 | if (0 != err) | ||
1647 | return err; | ||
1648 | } | ||
1649 | /* cx25821_vidioc_s_crop not supported */ | ||
1650 | return -EINVAL; | ||
1651 | } | ||
1652 | |||
1653 | int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) | ||
1654 | { | ||
1655 | /* cx25821_vidioc_g_crop not supported */ | ||
1656 | return -EINVAL; | ||
1657 | } | ||
1658 | |||
1659 | int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm) | ||
1660 | { | ||
1661 | /* medusa does not support video standard sensing of current input */ | ||
1662 | *norm = CX25821_NORMS; | ||
1663 | |||
1664 | return 0; | ||
1665 | } | ||
1666 | |||
1667 | int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm) | ||
1668 | { | ||
1669 | if (tvnorm == V4L2_STD_PAL_BG) { | ||
1670 | if (width == 352 || width == 720) | ||
1671 | return 1; | ||
1672 | else | ||
1673 | return 0; | ||
1674 | } | ||
1675 | |||
1676 | if (tvnorm == V4L2_STD_NTSC_M) { | ||
1677 | if (width == 320 || width == 352 || width == 720) | ||
1678 | return 1; | ||
1679 | else | ||
1680 | return 0; | ||
1681 | } | ||
1682 | return 0; | ||
1683 | } | ||
1684 | |||
1685 | int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm) | ||
1686 | { | ||
1687 | if (tvnorm == V4L2_STD_PAL_BG) { | ||
1688 | if (height == 576 || height == 288) | ||
1689 | return 1; | ||
1690 | else | ||
1691 | return 0; | ||
1692 | } | ||
1693 | |||
1694 | if (tvnorm == V4L2_STD_NTSC_M) { | ||
1695 | if (height == 480 || height == 240) | ||
1696 | return 1; | ||
1697 | else | ||
1698 | return 0; | ||
1699 | } | ||
1700 | |||
1701 | return 0; | ||
1702 | } | ||
1703 | |||
1704 | static long video_ioctl_upstream9(struct file *file, unsigned int cmd, | ||
1705 | unsigned long arg) | ||
1706 | { | ||
1707 | struct cx25821_fh *fh = file->private_data; | ||
1708 | struct cx25821_dev *dev = fh->dev; | ||
1709 | int command = 0; | ||
1710 | struct upstream_user_struct *data_from_user; | ||
1711 | |||
1712 | data_from_user = (struct upstream_user_struct *)arg; | ||
1713 | |||
1714 | if (!data_from_user) { | ||
1715 | pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); | ||
1716 | return 0; | ||
1717 | } | ||
1718 | |||
1719 | command = data_from_user->command; | ||
1720 | |||
1721 | if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) | ||
1722 | return 0; | ||
1723 | |||
1724 | dev->input_filename = data_from_user->input_filename; | ||
1725 | dev->input_audiofilename = data_from_user->input_filename; | ||
1726 | dev->vid_stdname = data_from_user->vid_stdname; | ||
1727 | dev->pixel_format = data_from_user->pixel_format; | ||
1728 | dev->channel_select = data_from_user->channel_select; | ||
1729 | dev->command = data_from_user->command; | ||
1730 | |||
1731 | switch (command) { | ||
1732 | case UPSTREAM_START_VIDEO: | ||
1733 | cx25821_start_upstream_video_ch1(dev, data_from_user); | ||
1734 | break; | ||
1735 | |||
1736 | case UPSTREAM_STOP_VIDEO: | ||
1737 | cx25821_stop_upstream_video_ch1(dev); | ||
1738 | break; | ||
1739 | } | ||
1740 | |||
1741 | return 0; | ||
1742 | } | ||
1743 | |||
1744 | static long video_ioctl_upstream10(struct file *file, unsigned int cmd, | ||
1745 | unsigned long arg) | ||
1746 | { | ||
1747 | struct cx25821_fh *fh = file->private_data; | ||
1748 | struct cx25821_dev *dev = fh->dev; | ||
1749 | int command = 0; | ||
1750 | struct upstream_user_struct *data_from_user; | ||
1751 | |||
1752 | data_from_user = (struct upstream_user_struct *)arg; | ||
1753 | |||
1754 | if (!data_from_user) { | ||
1755 | pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); | ||
1756 | return 0; | ||
1757 | } | ||
1758 | |||
1759 | command = data_from_user->command; | ||
1760 | |||
1761 | if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) | ||
1762 | return 0; | ||
1763 | |||
1764 | dev->input_filename_ch2 = data_from_user->input_filename; | ||
1765 | dev->input_audiofilename = data_from_user->input_filename; | ||
1766 | dev->vid_stdname_ch2 = data_from_user->vid_stdname; | ||
1767 | dev->pixel_format_ch2 = data_from_user->pixel_format; | ||
1768 | dev->channel_select_ch2 = data_from_user->channel_select; | ||
1769 | dev->command_ch2 = data_from_user->command; | ||
1770 | |||
1771 | switch (command) { | ||
1772 | case UPSTREAM_START_VIDEO: | ||
1773 | cx25821_start_upstream_video_ch2(dev, data_from_user); | ||
1774 | break; | ||
1775 | |||
1776 | case UPSTREAM_STOP_VIDEO: | ||
1777 | cx25821_stop_upstream_video_ch2(dev); | ||
1778 | break; | ||
1779 | } | ||
1780 | |||
1781 | return 0; | ||
1782 | } | ||
1783 | |||
1784 | static long video_ioctl_upstream11(struct file *file, unsigned int cmd, | ||
1785 | unsigned long arg) | ||
1786 | { | ||
1787 | struct cx25821_fh *fh = file->private_data; | ||
1788 | struct cx25821_dev *dev = fh->dev; | ||
1789 | int command = 0; | ||
1790 | struct upstream_user_struct *data_from_user; | ||
1791 | |||
1792 | data_from_user = (struct upstream_user_struct *)arg; | ||
1793 | |||
1794 | if (!data_from_user) { | ||
1795 | pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); | ||
1796 | return 0; | ||
1797 | } | ||
1798 | |||
1799 | command = data_from_user->command; | ||
1800 | |||
1801 | if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO) | ||
1802 | return 0; | ||
1803 | |||
1804 | dev->input_filename = data_from_user->input_filename; | ||
1805 | dev->input_audiofilename = data_from_user->input_filename; | ||
1806 | dev->vid_stdname = data_from_user->vid_stdname; | ||
1807 | dev->pixel_format = data_from_user->pixel_format; | ||
1808 | dev->channel_select = data_from_user->channel_select; | ||
1809 | dev->command = data_from_user->command; | ||
1810 | |||
1811 | switch (command) { | ||
1812 | case UPSTREAM_START_AUDIO: | ||
1813 | cx25821_start_upstream_audio(dev, data_from_user); | ||
1814 | break; | ||
1815 | |||
1816 | case UPSTREAM_STOP_AUDIO: | ||
1817 | cx25821_stop_upstream_audio(dev); | ||
1818 | break; | ||
1819 | } | ||
1820 | |||
1821 | return 0; | ||
1822 | } | ||
1823 | |||
1824 | static long video_ioctl_set(struct file *file, unsigned int cmd, | ||
1825 | unsigned long arg) | ||
1826 | { | ||
1827 | struct cx25821_fh *fh = file->private_data; | ||
1828 | struct cx25821_dev *dev = fh->dev; | ||
1829 | struct downstream_user_struct *data_from_user; | ||
1830 | int command; | ||
1831 | int width = 720; | ||
1832 | int selected_channel = 0, pix_format = 0, i = 0; | ||
1833 | int cif_enable = 0, cif_width = 0; | ||
1834 | u32 value = 0; | ||
1835 | |||
1836 | data_from_user = (struct downstream_user_struct *)arg; | ||
1837 | |||
1838 | if (!data_from_user) { | ||
1839 | pr_err("%s(): User data is INVALID. Returning\n", __func__); | ||
1840 | return 0; | ||
1841 | } | ||
1842 | |||
1843 | command = data_from_user->command; | ||
1844 | |||
1845 | if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT | ||
1846 | && command != ENABLE_CIF_RESOLUTION && command != REG_READ | ||
1847 | && command != REG_WRITE && command != MEDUSA_READ | ||
1848 | && command != MEDUSA_WRITE) { | ||
1849 | return 0; | ||
1850 | } | ||
1851 | |||
1852 | switch (command) { | ||
1853 | case SET_VIDEO_STD: | ||
1854 | if (!strcmp(data_from_user->vid_stdname, "PAL")) | ||
1855 | dev->tvnorm = V4L2_STD_PAL_BG; | ||
1856 | else | ||
1857 | dev->tvnorm = V4L2_STD_NTSC_M; | ||
1858 | medusa_set_videostandard(dev); | ||
1859 | break; | ||
1860 | |||
1861 | case SET_PIXEL_FORMAT: | ||
1862 | selected_channel = data_from_user->decoder_select; | ||
1863 | pix_format = data_from_user->pixel_format; | ||
1864 | |||
1865 | if (!(selected_channel <= 7 && selected_channel >= 0)) { | ||
1866 | selected_channel -= 4; | ||
1867 | selected_channel = selected_channel % 8; | ||
1868 | } | ||
1869 | |||
1870 | if (selected_channel >= 0) | ||
1871 | cx25821_set_pixel_format(dev, selected_channel, | ||
1872 | pix_format); | ||
1873 | |||
1874 | break; | ||
1875 | |||
1876 | case ENABLE_CIF_RESOLUTION: | ||
1877 | selected_channel = data_from_user->decoder_select; | ||
1878 | cif_enable = data_from_user->cif_resolution_enable; | ||
1879 | cif_width = data_from_user->cif_width; | ||
1880 | |||
1881 | if (cif_enable) { | ||
1882 | if (dev->tvnorm & V4L2_STD_PAL_BG | ||
1883 | || dev->tvnorm & V4L2_STD_PAL_DK) { | ||
1884 | width = 352; | ||
1885 | } else { | ||
1886 | width = cif_width; | ||
1887 | if (cif_width != 320 && cif_width != 352) | ||
1888 | width = 320; | ||
1889 | } | ||
1890 | } | ||
1891 | |||
1892 | if (!(selected_channel <= 7 && selected_channel >= 0)) { | ||
1893 | selected_channel -= 4; | ||
1894 | selected_channel = selected_channel % 8; | ||
1895 | } | ||
1896 | |||
1897 | if (selected_channel <= 7 && selected_channel >= 0) { | ||
1898 | dev->channels[selected_channel]. | ||
1899 | use_cif_resolution = cif_enable; | ||
1900 | dev->channels[selected_channel].cif_width = width; | ||
1901 | } else { | ||
1902 | for (i = 0; i < VID_CHANNEL_NUM; i++) { | ||
1903 | dev->channels[i].use_cif_resolution = | ||
1904 | cif_enable; | ||
1905 | dev->channels[i].cif_width = width; | ||
1906 | } | ||
1907 | } | ||
1908 | |||
1909 | medusa_set_resolution(dev, width, selected_channel); | ||
1910 | break; | ||
1911 | case REG_READ: | ||
1912 | data_from_user->reg_data = cx_read(data_from_user->reg_address); | ||
1913 | break; | ||
1914 | case REG_WRITE: | ||
1915 | cx_write(data_from_user->reg_address, data_from_user->reg_data); | ||
1916 | break; | ||
1917 | case MEDUSA_READ: | ||
1918 | value = cx25821_i2c_read(&dev->i2c_bus[0], | ||
1919 | (u16) data_from_user->reg_address, | ||
1920 | &data_from_user->reg_data); | ||
1921 | break; | ||
1922 | case MEDUSA_WRITE: | ||
1923 | cx25821_i2c_write(&dev->i2c_bus[0], | ||
1924 | (u16) data_from_user->reg_address, | ||
1925 | data_from_user->reg_data); | ||
1926 | break; | ||
1927 | } | ||
1928 | |||
1929 | return 0; | ||
1930 | } | ||
1931 | |||
1932 | static long cx25821_video_ioctl(struct file *file, | ||
1933 | unsigned int cmd, unsigned long arg) | ||
1934 | { | ||
1935 | int ret = 0; | ||
1936 | |||
1937 | struct cx25821_fh *fh = file->private_data; | ||
1938 | |||
1939 | /* check to see if it's the video upstream */ | ||
1940 | if (fh->channel_id == SRAM_CH09) { | ||
1941 | ret = video_ioctl_upstream9(file, cmd, arg); | ||
1942 | return ret; | ||
1943 | } else if (fh->channel_id == SRAM_CH10) { | ||
1944 | ret = video_ioctl_upstream10(file, cmd, arg); | ||
1945 | return ret; | ||
1946 | } else if (fh->channel_id == SRAM_CH11) { | ||
1947 | ret = video_ioctl_upstream11(file, cmd, arg); | ||
1948 | ret = video_ioctl_set(file, cmd, arg); | ||
1949 | return ret; | ||
1950 | } | ||
1951 | |||
1952 | return video_ioctl2(file, cmd, arg); | ||
1953 | } | ||
1954 | |||
1955 | /* exported stuff */ | ||
1956 | static const struct v4l2_file_operations video_fops = { | ||
1957 | .owner = THIS_MODULE, | ||
1958 | .open = video_open, | ||
1959 | .release = video_release, | ||
1960 | .read = video_read, | ||
1961 | .poll = video_poll, | ||
1962 | .mmap = cx25821_video_mmap, | ||
1963 | .ioctl = cx25821_video_ioctl, | ||
1964 | }; | ||
1965 | |||
1966 | static const struct v4l2_ioctl_ops video_ioctl_ops = { | ||
1967 | .vidioc_querycap = cx25821_vidioc_querycap, | ||
1968 | .vidioc_enum_fmt_vid_cap = cx25821_vidioc_enum_fmt_vid_cap, | ||
1969 | .vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap, | ||
1970 | .vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap, | ||
1971 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1972 | .vidioc_reqbufs = cx25821_vidioc_reqbufs, | ||
1973 | .vidioc_querybuf = cx25821_vidioc_querybuf, | ||
1974 | .vidioc_qbuf = cx25821_vidioc_qbuf, | ||
1975 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1976 | #ifdef TUNER_FLAG | ||
1977 | .vidioc_s_std = cx25821_vidioc_s_std, | ||
1978 | .vidioc_querystd = cx25821_vidioc_querystd, | ||
1979 | #endif | ||
1980 | .vidioc_cropcap = cx25821_vidioc_cropcap, | ||
1981 | .vidioc_s_crop = cx25821_vidioc_s_crop, | ||
1982 | .vidioc_g_crop = cx25821_vidioc_g_crop, | ||
1983 | .vidioc_enum_input = cx25821_vidioc_enum_input, | ||
1984 | .vidioc_g_input = cx25821_vidioc_g_input, | ||
1985 | .vidioc_s_input = cx25821_vidioc_s_input, | ||
1986 | .vidioc_g_ctrl = cx25821_vidioc_g_ctrl, | ||
1987 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1988 | .vidioc_queryctrl = cx25821_vidioc_queryctrl, | ||
1989 | .vidioc_streamon = vidioc_streamon, | ||
1990 | .vidioc_streamoff = vidioc_streamoff, | ||
1991 | .vidioc_log_status = vidioc_log_status, | ||
1992 | .vidioc_g_priority = cx25821_vidioc_g_priority, | ||
1993 | .vidioc_s_priority = cx25821_vidioc_s_priority, | ||
1994 | #ifdef TUNER_FLAG | ||
1995 | .vidioc_g_tuner = cx25821_vidioc_g_tuner, | ||
1996 | .vidioc_s_tuner = cx25821_vidioc_s_tuner, | ||
1997 | .vidioc_g_frequency = cx25821_vidioc_g_frequency, | ||
1998 | .vidioc_s_frequency = cx25821_vidioc_s_frequency, | ||
1999 | #endif | ||
2000 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
2001 | .vidioc_g_register = cx25821_vidioc_g_register, | ||
2002 | .vidioc_s_register = cx25821_vidioc_s_register, | ||
2003 | #endif | ||
2004 | }; | ||
2005 | |||
2006 | struct video_device cx25821_videoioctl_template = { | ||
2007 | .name = "cx25821-videoioctl", | ||
2008 | .fops = &video_fops, | ||
2009 | .ioctl_ops = &video_ioctl_ops, | ||
2010 | .tvnorms = CX25821_NORMS, | ||
2011 | .current_norm = V4L2_STD_NTSC_M, | ||
2012 | }; | ||
diff --git a/drivers/media/video/cx25821/cx25821-video.h b/drivers/media/video/cx25821/cx25821-video.h new file mode 100644 index 000000000000..d0d9538ca5b3 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821-video.h | |||
@@ -0,0 +1,188 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * | ||
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 | #ifndef CX25821_VIDEO_H_ | ||
25 | #define CX25821_VIDEO_H_ | ||
26 | |||
27 | #include <linux/init.h> | ||
28 | #include <linux/list.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | #include <linux/kmod.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/kthread.h> | ||
37 | #include <asm/div64.h> | ||
38 | |||
39 | #include "cx25821.h" | ||
40 | #include <media/v4l2-common.h> | ||
41 | #include <media/v4l2-ioctl.h> | ||
42 | |||
43 | #define TUNER_FLAG | ||
44 | |||
45 | #define VIDEO_DEBUG 0 | ||
46 | |||
47 | #define dprintk(level, fmt, arg...) \ | ||
48 | do { \ | ||
49 | if (VIDEO_DEBUG >= level) \ | ||
50 | printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg); \ | ||
51 | } while (0) | ||
52 | |||
53 | /* For IOCTL to identify running upstream */ | ||
54 | #define UPSTREAM_START_VIDEO 700 | ||
55 | #define UPSTREAM_STOP_VIDEO 701 | ||
56 | #define UPSTREAM_START_AUDIO 702 | ||
57 | #define UPSTREAM_STOP_AUDIO 703 | ||
58 | #define UPSTREAM_DUMP_REGISTERS 702 | ||
59 | #define SET_VIDEO_STD 800 | ||
60 | #define SET_PIXEL_FORMAT 1000 | ||
61 | #define ENABLE_CIF_RESOLUTION 1001 | ||
62 | |||
63 | #define REG_READ 900 | ||
64 | #define REG_WRITE 901 | ||
65 | #define MEDUSA_READ 910 | ||
66 | #define MEDUSA_WRITE 911 | ||
67 | |||
68 | extern struct sram_channel *channel0; | ||
69 | extern struct sram_channel *channel1; | ||
70 | extern struct sram_channel *channel2; | ||
71 | extern struct sram_channel *channel3; | ||
72 | extern struct sram_channel *channel4; | ||
73 | extern struct sram_channel *channel5; | ||
74 | extern struct sram_channel *channel6; | ||
75 | extern struct sram_channel *channel7; | ||
76 | extern struct sram_channel *channel9; | ||
77 | extern struct sram_channel *channel10; | ||
78 | extern struct sram_channel *channel11; | ||
79 | extern struct video_device cx25821_videoioctl_template; | ||
80 | /* extern const u32 *ctrl_classes[]; */ | ||
81 | |||
82 | extern unsigned int vid_limit; | ||
83 | |||
84 | #define FORMAT_FLAGS_PACKED 0x01 | ||
85 | extern struct cx25821_fmt formats[]; | ||
86 | extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc); | ||
87 | extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM]; | ||
88 | |||
89 | extern void cx25821_dump_video_queue(struct cx25821_dev *dev, | ||
90 | struct cx25821_dmaqueue *q); | ||
91 | extern void cx25821_video_wakeup(struct cx25821_dev *dev, | ||
92 | struct cx25821_dmaqueue *q, u32 count); | ||
93 | |||
94 | #ifdef TUNER_FLAG | ||
95 | extern int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm); | ||
96 | #endif | ||
97 | |||
98 | extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, | ||
99 | unsigned int bit); | ||
100 | extern int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit); | ||
101 | extern int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit); | ||
102 | extern void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, | ||
103 | unsigned int bits); | ||
104 | extern int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input); | ||
105 | extern int cx25821_start_video_dma(struct cx25821_dev *dev, | ||
106 | struct cx25821_dmaqueue *q, | ||
107 | struct cx25821_buffer *buf, | ||
108 | struct sram_channel *channel); | ||
109 | |||
110 | extern int cx25821_set_scale(struct cx25821_dev *dev, unsigned int width, | ||
111 | unsigned int height, enum v4l2_field field); | ||
112 | extern int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status); | ||
113 | extern void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num); | ||
114 | extern int cx25821_video_register(struct cx25821_dev *dev); | ||
115 | extern int cx25821_get_format_size(void); | ||
116 | |||
117 | extern int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, | ||
118 | unsigned int *size); | ||
119 | extern int cx25821_buffer_prepare(struct videobuf_queue *q, | ||
120 | struct videobuf_buffer *vb, | ||
121 | enum v4l2_field field); | ||
122 | extern void cx25821_buffer_release(struct videobuf_queue *q, | ||
123 | struct videobuf_buffer *vb); | ||
124 | extern struct videobuf_queue *get_queue(struct cx25821_fh *fh); | ||
125 | extern int cx25821_get_resource(struct cx25821_fh *fh, int resource); | ||
126 | extern int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma); | ||
127 | extern int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
128 | struct v4l2_format *f); | ||
129 | extern int cx25821_vidioc_querycap(struct file *file, void *priv, | ||
130 | struct v4l2_capability *cap); | ||
131 | extern int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
132 | struct v4l2_fmtdesc *f); | ||
133 | extern int cx25821_vidioc_reqbufs(struct file *file, void *priv, | ||
134 | struct v4l2_requestbuffers *p); | ||
135 | extern int cx25821_vidioc_querybuf(struct file *file, void *priv, | ||
136 | struct v4l2_buffer *p); | ||
137 | extern int cx25821_vidioc_qbuf(struct file *file, void *priv, | ||
138 | struct v4l2_buffer *p); | ||
139 | extern int cx25821_vidioc_s_std(struct file *file, void *priv, | ||
140 | v4l2_std_id *tvnorms); | ||
141 | extern int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i); | ||
142 | extern int cx25821_vidioc_enum_input(struct file *file, void *priv, | ||
143 | struct v4l2_input *i); | ||
144 | extern int cx25821_vidioc_g_input(struct file *file, void *priv, | ||
145 | unsigned int *i); | ||
146 | extern int cx25821_vidioc_s_input(struct file *file, void *priv, | ||
147 | unsigned int i); | ||
148 | extern int cx25821_vidioc_g_ctrl(struct file *file, void *priv, | ||
149 | struct v4l2_control *ctl); | ||
150 | extern int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
151 | struct v4l2_format *f); | ||
152 | extern int cx25821_vidioc_g_frequency(struct file *file, void *priv, | ||
153 | struct v4l2_frequency *f); | ||
154 | extern int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f); | ||
155 | extern int cx25821_vidioc_s_frequency(struct file *file, void *priv, | ||
156 | struct v4l2_frequency *f); | ||
157 | extern int cx25821_vidioc_g_register(struct file *file, void *fh, | ||
158 | struct v4l2_dbg_register *reg); | ||
159 | extern int cx25821_vidioc_s_register(struct file *file, void *fh, | ||
160 | struct v4l2_dbg_register *reg); | ||
161 | extern int cx25821_vidioc_g_tuner(struct file *file, void *priv, | ||
162 | struct v4l2_tuner *t); | ||
163 | extern int cx25821_vidioc_s_tuner(struct file *file, void *priv, | ||
164 | struct v4l2_tuner *t); | ||
165 | |||
166 | extern int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm); | ||
167 | extern int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm); | ||
168 | |||
169 | extern int cx25821_vidioc_g_priority(struct file *file, void *f, | ||
170 | enum v4l2_priority *p); | ||
171 | extern int cx25821_vidioc_s_priority(struct file *file, void *f, | ||
172 | enum v4l2_priority prio); | ||
173 | |||
174 | extern int cx25821_vidioc_queryctrl(struct file *file, void *priv, | ||
175 | struct v4l2_queryctrl *qctrl); | ||
176 | extern int cx25821_set_control(struct cx25821_dev *dev, | ||
177 | struct v4l2_control *ctrl, int chan_num); | ||
178 | |||
179 | extern int cx25821_vidioc_cropcap(struct file *file, void *fh, | ||
180 | struct v4l2_cropcap *cropcap); | ||
181 | extern int cx25821_vidioc_s_crop(struct file *file, void *priv, | ||
182 | struct v4l2_crop *crop); | ||
183 | extern int cx25821_vidioc_g_crop(struct file *file, void *priv, | ||
184 | struct v4l2_crop *crop); | ||
185 | |||
186 | extern int cx25821_vidioc_querystd(struct file *file, void *priv, | ||
187 | v4l2_std_id *norm); | ||
188 | #endif | ||
diff --git a/drivers/media/video/cx25821/cx25821.h b/drivers/media/video/cx25821/cx25821.h new file mode 100644 index 000000000000..2d2d00932823 --- /dev/null +++ b/drivers/media/video/cx25821/cx25821.h | |||
@@ -0,0 +1,617 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX25821 PCIe bridge | ||
3 | * | ||
4 | * Copyright (C) 2009 Conexant Systems Inc. | ||
5 | * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> | ||
6 | * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * | ||
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 | #ifndef CX25821_H_ | ||
25 | #define CX25821_H_ | ||
26 | |||
27 | #include <linux/pci.h> | ||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/i2c-algo-bit.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/sched.h> | ||
33 | #include <linux/kdev_t.h> | ||
34 | |||
35 | #include <media/v4l2-common.h> | ||
36 | #include <media/v4l2-device.h> | ||
37 | #include <media/tuner.h> | ||
38 | #include <media/tveeprom.h> | ||
39 | #include <media/videobuf-dma-sg.h> | ||
40 | #include <media/videobuf-dvb.h> | ||
41 | |||
42 | #include "btcx-risc.h" | ||
43 | #include "cx25821-reg.h" | ||
44 | #include "cx25821-medusa-reg.h" | ||
45 | #include "cx25821-sram.h" | ||
46 | #include "cx25821-audio.h" | ||
47 | #include "media/cx2341x.h" | ||
48 | |||
49 | #include <linux/version.h> | ||
50 | #include <linux/mutex.h> | ||
51 | |||
52 | #define CX25821_VERSION_CODE KERNEL_VERSION(0, 0, 106) | ||
53 | |||
54 | #define UNSET (-1U) | ||
55 | #define NO_SYNC_LINE (-1U) | ||
56 | |||
57 | #define CX25821_MAXBOARDS 2 | ||
58 | |||
59 | #define TRUE 1 | ||
60 | #define FALSE 0 | ||
61 | #define LINE_SIZE_D1 1440 | ||
62 | |||
63 | /* Number of decoders and encoders */ | ||
64 | #define MAX_DECODERS 8 | ||
65 | #define MAX_ENCODERS 2 | ||
66 | #define QUAD_DECODERS 4 | ||
67 | #define MAX_CAMERAS 16 | ||
68 | |||
69 | /* Max number of inputs by card */ | ||
70 | #define MAX_CX25821_INPUT 8 | ||
71 | #define INPUT(nr) (&cx25821_boards[dev->board].input[nr]) | ||
72 | #define RESOURCE_VIDEO0 1 | ||
73 | #define RESOURCE_VIDEO1 2 | ||
74 | #define RESOURCE_VIDEO2 4 | ||
75 | #define RESOURCE_VIDEO3 8 | ||
76 | #define RESOURCE_VIDEO4 16 | ||
77 | #define RESOURCE_VIDEO5 32 | ||
78 | #define RESOURCE_VIDEO6 64 | ||
79 | #define RESOURCE_VIDEO7 128 | ||
80 | #define RESOURCE_VIDEO8 256 | ||
81 | #define RESOURCE_VIDEO9 512 | ||
82 | #define RESOURCE_VIDEO10 1024 | ||
83 | #define RESOURCE_VIDEO11 2048 | ||
84 | #define RESOURCE_VIDEO_IOCTL 4096 | ||
85 | |||
86 | #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ | ||
87 | |||
88 | #define UNKNOWN_BOARD 0 | ||
89 | #define CX25821_BOARD 1 | ||
90 | |||
91 | /* Currently supported by the driver */ | ||
92 | #define CX25821_NORMS (\ | ||
93 | V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR | \ | ||
94 | V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ | ||
95 | V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_H | \ | ||
96 | V4L2_STD_PAL_Nc) | ||
97 | |||
98 | #define CX25821_BOARD_CONEXANT_ATHENA10 1 | ||
99 | #define MAX_VID_CHANNEL_NUM 12 | ||
100 | #define VID_CHANNEL_NUM 8 | ||
101 | #define CX25821_NR_INPUT 2 | ||
102 | |||
103 | struct cx25821_fmt { | ||
104 | char *name; | ||
105 | u32 fourcc; /* v4l2 format id */ | ||
106 | int depth; | ||
107 | int flags; | ||
108 | u32 cxformat; | ||
109 | }; | ||
110 | |||
111 | struct cx25821_ctrl { | ||
112 | struct v4l2_queryctrl v; | ||
113 | u32 off; | ||
114 | u32 reg; | ||
115 | u32 mask; | ||
116 | u32 shift; | ||
117 | }; | ||
118 | |||
119 | struct cx25821_tvnorm { | ||
120 | char *name; | ||
121 | v4l2_std_id id; | ||
122 | u32 cxiformat; | ||
123 | u32 cxoformat; | ||
124 | }; | ||
125 | |||
126 | struct cx25821_fh { | ||
127 | struct cx25821_dev *dev; | ||
128 | enum v4l2_buf_type type; | ||
129 | int radio; | ||
130 | u32 resources; | ||
131 | |||
132 | enum v4l2_priority prio; | ||
133 | |||
134 | /* video overlay */ | ||
135 | struct v4l2_window win; | ||
136 | struct v4l2_clip *clips; | ||
137 | unsigned int nclips; | ||
138 | |||
139 | /* video capture */ | ||
140 | struct cx25821_fmt *fmt; | ||
141 | unsigned int width, height; | ||
142 | int channel_id; | ||
143 | |||
144 | /* vbi capture */ | ||
145 | struct videobuf_queue vidq; | ||
146 | struct videobuf_queue vbiq; | ||
147 | |||
148 | /* H264 Encoder specifics ONLY */ | ||
149 | struct videobuf_queue mpegq; | ||
150 | atomic_t v4l_reading; | ||
151 | }; | ||
152 | |||
153 | enum cx25821_itype { | ||
154 | CX25821_VMUX_COMPOSITE = 1, | ||
155 | CX25821_VMUX_SVIDEO, | ||
156 | CX25821_VMUX_DEBUG, | ||
157 | CX25821_RADIO, | ||
158 | }; | ||
159 | |||
160 | enum cx25821_src_sel_type { | ||
161 | CX25821_SRC_SEL_EXT_656_VIDEO = 0, | ||
162 | CX25821_SRC_SEL_PARALLEL_MPEG_VIDEO | ||
163 | }; | ||
164 | |||
165 | /* buffer for one video frame */ | ||
166 | struct cx25821_buffer { | ||
167 | /* common v4l buffer stuff -- must be first */ | ||
168 | struct videobuf_buffer vb; | ||
169 | |||
170 | /* cx25821 specific */ | ||
171 | unsigned int bpl; | ||
172 | struct btcx_riscmem risc; | ||
173 | struct cx25821_fmt *fmt; | ||
174 | u32 count; | ||
175 | }; | ||
176 | |||
177 | struct cx25821_input { | ||
178 | enum cx25821_itype type; | ||
179 | unsigned int vmux; | ||
180 | u32 gpio0, gpio1, gpio2, gpio3; | ||
181 | }; | ||
182 | |||
183 | enum port { | ||
184 | CX25821_UNDEFINED = 0, | ||
185 | CX25821_RAW, | ||
186 | CX25821_264 | ||
187 | }; | ||
188 | |||
189 | struct cx25821_board { | ||
190 | char *name; | ||
191 | enum port porta; | ||
192 | enum port portb; | ||
193 | enum port portc; | ||
194 | unsigned int tuner_type; | ||
195 | unsigned int radio_type; | ||
196 | unsigned char tuner_addr; | ||
197 | unsigned char radio_addr; | ||
198 | |||
199 | u32 clk_freq; | ||
200 | struct cx25821_input input[CX25821_NR_INPUT]; | ||
201 | }; | ||
202 | |||
203 | struct cx25821_subid { | ||
204 | u16 subvendor; | ||
205 | u16 subdevice; | ||
206 | u32 card; | ||
207 | }; | ||
208 | |||
209 | struct cx25821_i2c { | ||
210 | struct cx25821_dev *dev; | ||
211 | |||
212 | int nr; | ||
213 | |||
214 | /* i2c i/o */ | ||
215 | struct i2c_adapter i2c_adap; | ||
216 | struct i2c_algo_bit_data i2c_algo; | ||
217 | struct i2c_client i2c_client; | ||
218 | u32 i2c_rc; | ||
219 | |||
220 | /* cx25821 registers used for raw addess */ | ||
221 | u32 i2c_period; | ||
222 | u32 reg_ctrl; | ||
223 | u32 reg_stat; | ||
224 | u32 reg_addr; | ||
225 | u32 reg_rdata; | ||
226 | u32 reg_wdata; | ||
227 | }; | ||
228 | |||
229 | struct cx25821_dmaqueue { | ||
230 | struct list_head active; | ||
231 | struct list_head queued; | ||
232 | struct timer_list timeout; | ||
233 | struct btcx_riscmem stopper; | ||
234 | u32 count; | ||
235 | }; | ||
236 | |||
237 | struct cx25821_data { | ||
238 | struct cx25821_dev *dev; | ||
239 | struct sram_channel *channel; | ||
240 | }; | ||
241 | |||
242 | struct cx25821_channel { | ||
243 | struct v4l2_prio_state prio; | ||
244 | |||
245 | int ctl_bright; | ||
246 | int ctl_contrast; | ||
247 | int ctl_hue; | ||
248 | int ctl_saturation; | ||
249 | struct cx25821_data timeout_data; | ||
250 | |||
251 | struct video_device *video_dev; | ||
252 | struct cx25821_dmaqueue vidq; | ||
253 | |||
254 | struct sram_channel *sram_channels; | ||
255 | |||
256 | struct mutex lock; | ||
257 | int resources; | ||
258 | |||
259 | int pixel_formats; | ||
260 | int use_cif_resolution; | ||
261 | int cif_width; | ||
262 | }; | ||
263 | |||
264 | struct cx25821_dev { | ||
265 | struct list_head devlist; | ||
266 | atomic_t refcount; | ||
267 | struct v4l2_device v4l2_dev; | ||
268 | |||
269 | /* pci stuff */ | ||
270 | struct pci_dev *pci; | ||
271 | unsigned char pci_rev, pci_lat; | ||
272 | int pci_bus, pci_slot; | ||
273 | u32 base_io_addr; | ||
274 | u32 __iomem *lmmio; | ||
275 | u8 __iomem *bmmio; | ||
276 | int pci_irqmask; | ||
277 | int hwrevision; | ||
278 | |||
279 | u32 clk_freq; | ||
280 | |||
281 | /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ | ||
282 | struct cx25821_i2c i2c_bus[3]; | ||
283 | |||
284 | int nr; | ||
285 | struct mutex lock; | ||
286 | |||
287 | struct cx25821_channel channels[MAX_VID_CHANNEL_NUM]; | ||
288 | |||
289 | /* board details */ | ||
290 | unsigned int board; | ||
291 | char name[32]; | ||
292 | |||
293 | /* Analog video */ | ||
294 | u32 resources; | ||
295 | unsigned int input; | ||
296 | u32 tvaudio; | ||
297 | v4l2_std_id tvnorm; | ||
298 | unsigned int tuner_type; | ||
299 | unsigned char tuner_addr; | ||
300 | unsigned int radio_type; | ||
301 | unsigned char radio_addr; | ||
302 | unsigned int has_radio; | ||
303 | unsigned int videc_type; | ||
304 | unsigned char videc_addr; | ||
305 | unsigned short _max_num_decoders; | ||
306 | |||
307 | /* Analog Audio Upstream */ | ||
308 | int _audio_is_running; | ||
309 | int _audiopixel_format; | ||
310 | int _is_first_audio_frame; | ||
311 | int _audiofile_status; | ||
312 | int _audio_lines_count; | ||
313 | int _audioframe_count; | ||
314 | int _audio_upstream_channel; | ||
315 | int _last_index_irq; /* The last interrupt index processed. */ | ||
316 | |||
317 | __le32 *_risc_audio_jmp_addr; | ||
318 | __le32 *_risc_virt_start_addr; | ||
319 | __le32 *_risc_virt_addr; | ||
320 | dma_addr_t _risc_phys_addr; | ||
321 | dma_addr_t _risc_phys_start_addr; | ||
322 | |||
323 | unsigned int _audiorisc_size; | ||
324 | unsigned int _audiodata_buf_size; | ||
325 | __le32 *_audiodata_buf_virt_addr; | ||
326 | dma_addr_t _audiodata_buf_phys_addr; | ||
327 | char *_audiofilename; | ||
328 | |||
329 | /* V4l */ | ||
330 | u32 freq; | ||
331 | struct video_device *vbi_dev; | ||
332 | struct video_device *radio_dev; | ||
333 | struct video_device *ioctl_dev; | ||
334 | |||
335 | spinlock_t slock; | ||
336 | |||
337 | /* Video Upstream */ | ||
338 | int _line_size; | ||
339 | int _prog_cnt; | ||
340 | int _pixel_format; | ||
341 | int _is_first_frame; | ||
342 | int _is_running; | ||
343 | int _file_status; | ||
344 | int _lines_count; | ||
345 | int _frame_count; | ||
346 | int _channel_upstream_select; | ||
347 | unsigned int _risc_size; | ||
348 | |||
349 | __le32 *_dma_virt_start_addr; | ||
350 | __le32 *_dma_virt_addr; | ||
351 | dma_addr_t _dma_phys_addr; | ||
352 | dma_addr_t _dma_phys_start_addr; | ||
353 | |||
354 | unsigned int _data_buf_size; | ||
355 | __le32 *_data_buf_virt_addr; | ||
356 | dma_addr_t _data_buf_phys_addr; | ||
357 | char *_filename; | ||
358 | char *_defaultname; | ||
359 | |||
360 | int _line_size_ch2; | ||
361 | int _prog_cnt_ch2; | ||
362 | int _pixel_format_ch2; | ||
363 | int _is_first_frame_ch2; | ||
364 | int _is_running_ch2; | ||
365 | int _file_status_ch2; | ||
366 | int _lines_count_ch2; | ||
367 | int _frame_count_ch2; | ||
368 | int _channel2_upstream_select; | ||
369 | unsigned int _risc_size_ch2; | ||
370 | |||
371 | __le32 *_dma_virt_start_addr_ch2; | ||
372 | __le32 *_dma_virt_addr_ch2; | ||
373 | dma_addr_t _dma_phys_addr_ch2; | ||
374 | dma_addr_t _dma_phys_start_addr_ch2; | ||
375 | |||
376 | unsigned int _data_buf_size_ch2; | ||
377 | __le32 *_data_buf_virt_addr_ch2; | ||
378 | dma_addr_t _data_buf_phys_addr_ch2; | ||
379 | char *_filename_ch2; | ||
380 | char *_defaultname_ch2; | ||
381 | |||
382 | /* MPEG Encoder ONLY settings */ | ||
383 | u32 cx23417_mailbox; | ||
384 | struct cx2341x_mpeg_params mpeg_params; | ||
385 | struct video_device *v4l_device; | ||
386 | atomic_t v4l_reader_count; | ||
387 | struct cx25821_tvnorm encodernorm; | ||
388 | |||
389 | u32 upstream_riscbuf_size; | ||
390 | u32 upstream_databuf_size; | ||
391 | u32 upstream_riscbuf_size_ch2; | ||
392 | u32 upstream_databuf_size_ch2; | ||
393 | u32 audio_upstream_riscbuf_size; | ||
394 | u32 audio_upstream_databuf_size; | ||
395 | int _isNTSC; | ||
396 | int _frame_index; | ||
397 | int _audioframe_index; | ||
398 | struct workqueue_struct *_irq_queues; | ||
399 | struct work_struct _irq_work_entry; | ||
400 | struct workqueue_struct *_irq_queues_ch2; | ||
401 | struct work_struct _irq_work_entry_ch2; | ||
402 | struct workqueue_struct *_irq_audio_queues; | ||
403 | struct work_struct _audio_work_entry; | ||
404 | char *input_filename; | ||
405 | char *input_filename_ch2; | ||
406 | int _frame_index_ch2; | ||
407 | int _isNTSC_ch2; | ||
408 | char *vid_stdname_ch2; | ||
409 | int pixel_format_ch2; | ||
410 | int channel_select_ch2; | ||
411 | int command_ch2; | ||
412 | char *input_audiofilename; | ||
413 | char *vid_stdname; | ||
414 | int pixel_format; | ||
415 | int channel_select; | ||
416 | int command; | ||
417 | int channel_opened; | ||
418 | }; | ||
419 | |||
420 | struct upstream_user_struct { | ||
421 | char *input_filename; | ||
422 | char *vid_stdname; | ||
423 | int pixel_format; | ||
424 | int channel_select; | ||
425 | int command; | ||
426 | }; | ||
427 | |||
428 | struct downstream_user_struct { | ||
429 | char *vid_stdname; | ||
430 | int pixel_format; | ||
431 | int cif_resolution_enable; | ||
432 | int cif_width; | ||
433 | int decoder_select; | ||
434 | int command; | ||
435 | int reg_address; | ||
436 | int reg_data; | ||
437 | }; | ||
438 | |||
439 | extern struct upstream_user_struct *up_data; | ||
440 | |||
441 | static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev) | ||
442 | { | ||
443 | return container_of(v4l2_dev, struct cx25821_dev, v4l2_dev); | ||
444 | } | ||
445 | |||
446 | #define cx25821_call_all(dev, o, f, args...) \ | ||
447 | v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) | ||
448 | |||
449 | extern struct list_head cx25821_devlist; | ||
450 | extern struct mutex cx25821_devlist_mutex; | ||
451 | |||
452 | extern struct cx25821_board cx25821_boards[]; | ||
453 | extern struct cx25821_subid cx25821_subids[]; | ||
454 | |||
455 | #define SRAM_CH00 0 /* Video A */ | ||
456 | #define SRAM_CH01 1 /* Video B */ | ||
457 | #define SRAM_CH02 2 /* Video C */ | ||
458 | #define SRAM_CH03 3 /* Video D */ | ||
459 | #define SRAM_CH04 4 /* Video E */ | ||
460 | #define SRAM_CH05 5 /* Video F */ | ||
461 | #define SRAM_CH06 6 /* Video G */ | ||
462 | #define SRAM_CH07 7 /* Video H */ | ||
463 | |||
464 | #define SRAM_CH08 8 /* Audio A */ | ||
465 | #define SRAM_CH09 9 /* Video Upstream I */ | ||
466 | #define SRAM_CH10 10 /* Video Upstream J */ | ||
467 | #define SRAM_CH11 11 /* Audio Upstream AUD_CHANNEL_B */ | ||
468 | |||
469 | #define VID_UPSTREAM_SRAM_CHANNEL_I SRAM_CH09 | ||
470 | #define VID_UPSTREAM_SRAM_CHANNEL_J SRAM_CH10 | ||
471 | #define AUDIO_UPSTREAM_SRAM_CHANNEL_B SRAM_CH11 | ||
472 | #define VIDEO_IOCTL_CH 11 | ||
473 | |||
474 | struct sram_channel { | ||
475 | char *name; | ||
476 | u32 i; | ||
477 | u32 cmds_start; | ||
478 | u32 ctrl_start; | ||
479 | u32 cdt; | ||
480 | u32 fifo_start; | ||
481 | u32 fifo_size; | ||
482 | u32 ptr1_reg; | ||
483 | u32 ptr2_reg; | ||
484 | u32 cnt1_reg; | ||
485 | u32 cnt2_reg; | ||
486 | u32 int_msk; | ||
487 | u32 int_stat; | ||
488 | u32 int_mstat; | ||
489 | u32 dma_ctl; | ||
490 | u32 gpcnt_ctl; | ||
491 | u32 gpcnt; | ||
492 | u32 aud_length; | ||
493 | u32 aud_cfg; | ||
494 | u32 fld_aud_fifo_en; | ||
495 | u32 fld_aud_risc_en; | ||
496 | |||
497 | /* For Upstream Video */ | ||
498 | u32 vid_fmt_ctl; | ||
499 | u32 vid_active_ctl1; | ||
500 | u32 vid_active_ctl2; | ||
501 | u32 vid_cdt_size; | ||
502 | |||
503 | u32 vip_ctl; | ||
504 | u32 pix_frmt; | ||
505 | u32 jumponly; | ||
506 | u32 irq_bit; | ||
507 | }; | ||
508 | extern struct sram_channel cx25821_sram_channels[]; | ||
509 | |||
510 | #define STATUS_SUCCESS 0 | ||
511 | #define STATUS_UNSUCCESSFUL -1 | ||
512 | |||
513 | #define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) | ||
514 | #define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2)) | ||
515 | |||
516 | #define cx_andor(reg, mask, value) \ | ||
517 | writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ | ||
518 | ((value) & (mask)), dev->lmmio+((reg)>>2)) | ||
519 | |||
520 | #define cx_set(reg, bit) cx_andor((reg), (bit), (bit)) | ||
521 | #define cx_clear(reg, bit) cx_andor((reg), (bit), 0) | ||
522 | |||
523 | #define Set_GPIO_Bit(Bit) (1 << Bit) | ||
524 | #define Clear_GPIO_Bit(Bit) (~(1 << Bit)) | ||
525 | |||
526 | #define CX25821_ERR(fmt, args...) \ | ||
527 | pr_err("(%d): " fmt, dev->board, ##args) | ||
528 | #define CX25821_WARN(fmt, args...) \ | ||
529 | pr_warn("(%d): " fmt, dev->board, ##args) | ||
530 | #define CX25821_INFO(fmt, args...) \ | ||
531 | pr_info("(%d): " fmt, dev->board, ##args) | ||
532 | |||
533 | extern int cx25821_i2c_register(struct cx25821_i2c *bus); | ||
534 | extern void cx25821_card_setup(struct cx25821_dev *dev); | ||
535 | extern int cx25821_ir_init(struct cx25821_dev *dev); | ||
536 | extern int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value); | ||
537 | extern int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value); | ||
538 | extern int cx25821_i2c_unregister(struct cx25821_i2c *bus); | ||
539 | extern void cx25821_gpio_init(struct cx25821_dev *dev); | ||
540 | extern void cx25821_set_gpiopin_direction(struct cx25821_dev *dev, | ||
541 | int pin_number, int pin_logic_value); | ||
542 | |||
543 | extern int medusa_video_init(struct cx25821_dev *dev); | ||
544 | extern int medusa_set_videostandard(struct cx25821_dev *dev); | ||
545 | extern void medusa_set_resolution(struct cx25821_dev *dev, int width, | ||
546 | int decoder_select); | ||
547 | extern int medusa_set_brightness(struct cx25821_dev *dev, int brightness, | ||
548 | int decoder); | ||
549 | extern int medusa_set_contrast(struct cx25821_dev *dev, int contrast, | ||
550 | int decoder); | ||
551 | extern int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder); | ||
552 | extern int medusa_set_saturation(struct cx25821_dev *dev, int saturation, | ||
553 | int decoder); | ||
554 | |||
555 | extern int cx25821_sram_channel_setup(struct cx25821_dev *dev, | ||
556 | struct sram_channel *ch, unsigned int bpl, | ||
557 | u32 risc); | ||
558 | |||
559 | extern int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
560 | struct scatterlist *sglist, | ||
561 | unsigned int top_offset, | ||
562 | unsigned int bottom_offset, | ||
563 | unsigned int bpl, | ||
564 | unsigned int padding, unsigned int lines); | ||
565 | extern int cx25821_risc_databuffer_audio(struct pci_dev *pci, | ||
566 | struct btcx_riscmem *risc, | ||
567 | struct scatterlist *sglist, | ||
568 | unsigned int bpl, | ||
569 | unsigned int lines, unsigned int lpi); | ||
570 | extern void cx25821_free_buffer(struct videobuf_queue *q, | ||
571 | struct cx25821_buffer *buf); | ||
572 | extern int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, | ||
573 | u32 reg, u32 mask, u32 value); | ||
574 | extern void cx25821_sram_channel_dump(struct cx25821_dev *dev, | ||
575 | struct sram_channel *ch); | ||
576 | extern void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev, | ||
577 | struct sram_channel *ch); | ||
578 | |||
579 | extern struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci); | ||
580 | extern void cx25821_print_irqbits(char *name, char *tag, char **strings, | ||
581 | int len, u32 bits, u32 mask); | ||
582 | extern void cx25821_dev_unregister(struct cx25821_dev *dev); | ||
583 | extern int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, | ||
584 | struct sram_channel *ch, | ||
585 | unsigned int bpl, u32 risc); | ||
586 | |||
587 | extern int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, | ||
588 | int channel_select, int pixel_format); | ||
589 | extern int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, | ||
590 | int channel_select, int pixel_format); | ||
591 | extern int cx25821_audio_upstream_init(struct cx25821_dev *dev, | ||
592 | int channel_select); | ||
593 | extern void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev); | ||
594 | extern void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev); | ||
595 | extern void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev); | ||
596 | extern void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev, | ||
597 | struct upstream_user_struct | ||
598 | *up_data); | ||
599 | extern void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev, | ||
600 | struct upstream_user_struct | ||
601 | *up_data); | ||
602 | extern void cx25821_start_upstream_audio(struct cx25821_dev *dev, | ||
603 | struct upstream_user_struct *up_data); | ||
604 | extern void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev); | ||
605 | extern void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev); | ||
606 | extern void cx25821_stop_upstream_audio(struct cx25821_dev *dev); | ||
607 | extern int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, | ||
608 | struct sram_channel *ch, | ||
609 | unsigned int bpl, u32 risc); | ||
610 | extern void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel, | ||
611 | u32 format); | ||
612 | extern void cx25821_videoioctl_unregister(struct cx25821_dev *dev); | ||
613 | extern struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, | ||
614 | struct pci_dev *pci, | ||
615 | struct video_device *template, | ||
616 | char *type); | ||
617 | #endif | ||
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 4240f0b720fa..9b747c266afa 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c | |||
@@ -1923,6 +1923,8 @@ struct usb_device_id em28xx_id_table[] = { | |||
1923 | .driver_info = EM2860_BOARD_TERRATEC_AV350 }, | 1923 | .driver_info = EM2860_BOARD_TERRATEC_AV350 }, |
1924 | { USB_DEVICE(0x0ccd, 0x0096), | 1924 | { USB_DEVICE(0x0ccd, 0x0096), |
1925 | .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, | 1925 | .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, |
1926 | { USB_DEVICE(0x0ccd, 0x10AF), | ||
1927 | .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, | ||
1926 | { USB_DEVICE(0x0fd9, 0x0033), | 1928 | { USB_DEVICE(0x0fd9, 0x0033), |
1927 | .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, | 1929 | .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, |
1928 | { USB_DEVICE(0x185b, 0x2870), | 1930 | { USB_DEVICE(0x185b, 0x2870), |
diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 0382ea752e6f..8775e262bb6e 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c | |||
@@ -12,11 +12,11 @@ | |||
12 | 12 | ||
13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
15 | #include <linux/v4l2-mediabus.h> | ||
15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
16 | #include <linux/videodev2.h> | 17 | #include <linux/videodev2.h> |
17 | 18 | ||
18 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
19 | #include <media/soc_mediabus.h> | ||
20 | #include <media/v4l2-subdev.h> | 20 | #include <media/v4l2-subdev.h> |
21 | #include <media/v4l2-chip-ident.h> | 21 | #include <media/v4l2-chip-ident.h> |
22 | 22 | ||
@@ -267,6 +267,17 @@ static int imx074_g_chip_ident(struct v4l2_subdev *sd, | |||
267 | return 0; | 267 | return 0; |
268 | } | 268 | } |
269 | 269 | ||
270 | static int imx074_g_mbus_config(struct v4l2_subdev *sd, | ||
271 | struct v4l2_mbus_config *cfg) | ||
272 | { | ||
273 | cfg->type = V4L2_MBUS_CSI2; | ||
274 | cfg->flags = V4L2_MBUS_CSI2_2_LANE | | ||
275 | V4L2_MBUS_CSI2_CHANNEL_0 | | ||
276 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
270 | static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { | 281 | static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { |
271 | .s_stream = imx074_s_stream, | 282 | .s_stream = imx074_s_stream, |
272 | .s_mbus_fmt = imx074_s_fmt, | 283 | .s_mbus_fmt = imx074_s_fmt, |
@@ -275,6 +286,7 @@ static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { | |||
275 | .enum_mbus_fmt = imx074_enum_fmt, | 286 | .enum_mbus_fmt = imx074_enum_fmt, |
276 | .g_crop = imx074_g_crop, | 287 | .g_crop = imx074_g_crop, |
277 | .cropcap = imx074_cropcap, | 288 | .cropcap = imx074_cropcap, |
289 | .g_mbus_config = imx074_g_mbus_config, | ||
278 | }; | 290 | }; |
279 | 291 | ||
280 | static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { | 292 | static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { |
@@ -286,28 +298,7 @@ static struct v4l2_subdev_ops imx074_subdev_ops = { | |||
286 | .video = &imx074_subdev_video_ops, | 298 | .video = &imx074_subdev_video_ops, |
287 | }; | 299 | }; |
288 | 300 | ||
289 | /* | 301 | static int imx074_video_probe(struct i2c_client *client) |
290 | * We have to provide soc-camera operations, but we don't have anything to say | ||
291 | * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param | ||
292 | */ | ||
293 | static unsigned long imx074_query_bus_param(struct soc_camera_device *icd) | ||
294 | { | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int imx074_set_bus_param(struct soc_camera_device *icd, | ||
299 | unsigned long flags) | ||
300 | { | ||
301 | return -EINVAL; | ||
302 | } | ||
303 | |||
304 | static struct soc_camera_ops imx074_ops = { | ||
305 | .query_bus_param = imx074_query_bus_param, | ||
306 | .set_bus_param = imx074_set_bus_param, | ||
307 | }; | ||
308 | |||
309 | static int imx074_video_probe(struct soc_camera_device *icd, | ||
310 | struct i2c_client *client) | ||
311 | { | 302 | { |
312 | int ret; | 303 | int ret; |
313 | u16 id; | 304 | u16 id; |
@@ -417,17 +408,10 @@ static int imx074_probe(struct i2c_client *client, | |||
417 | const struct i2c_device_id *did) | 408 | const struct i2c_device_id *did) |
418 | { | 409 | { |
419 | struct imx074 *priv; | 410 | struct imx074 *priv; |
420 | struct soc_camera_device *icd = client->dev.platform_data; | ||
421 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 411 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
422 | struct soc_camera_link *icl; | 412 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
423 | int ret; | 413 | int ret; |
424 | 414 | ||
425 | if (!icd) { | ||
426 | dev_err(&client->dev, "IMX074: missing soc-camera data!\n"); | ||
427 | return -EINVAL; | ||
428 | } | ||
429 | |||
430 | icl = to_soc_camera_link(icd); | ||
431 | if (!icl) { | 415 | if (!icl) { |
432 | dev_err(&client->dev, "IMX074: missing platform data!\n"); | 416 | dev_err(&client->dev, "IMX074: missing platform data!\n"); |
433 | return -EINVAL; | 417 | return -EINVAL; |
@@ -445,12 +429,10 @@ static int imx074_probe(struct i2c_client *client, | |||
445 | 429 | ||
446 | v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops); | 430 | v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops); |
447 | 431 | ||
448 | icd->ops = &imx074_ops; | ||
449 | priv->fmt = &imx074_colour_fmts[0]; | 432 | priv->fmt = &imx074_colour_fmts[0]; |
450 | 433 | ||
451 | ret = imx074_video_probe(icd, client); | 434 | ret = imx074_video_probe(client); |
452 | if (ret < 0) { | 435 | if (ret < 0) { |
453 | icd->ops = NULL; | ||
454 | kfree(priv); | 436 | kfree(priv); |
455 | return ret; | 437 | return ret; |
456 | } | 438 | } |
@@ -461,10 +443,8 @@ static int imx074_probe(struct i2c_client *client, | |||
461 | static int imx074_remove(struct i2c_client *client) | 443 | static int imx074_remove(struct i2c_client *client) |
462 | { | 444 | { |
463 | struct imx074 *priv = to_imx074(client); | 445 | struct imx074 *priv = to_imx074(client); |
464 | struct soc_camera_device *icd = client->dev.platform_data; | 446 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
465 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
466 | 447 | ||
467 | icd->ops = NULL; | ||
468 | if (icl->free_bus) | 448 | if (icl->free_bus) |
469 | icl->free_bus(icl); | 449 | icl->free_bus(icl); |
470 | kfree(priv); | 450 | kfree(priv); |
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 0fb75524484d..41108a9a195e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c | |||
@@ -1180,6 +1180,8 @@ static int __devinit ivtv_probe(struct pci_dev *pdev, | |||
1180 | setup.addr = ADDR_UNSET; | 1180 | setup.addr = ADDR_UNSET; |
1181 | setup.type = itv->options.tuner; | 1181 | setup.type = itv->options.tuner; |
1182 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ | 1182 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ |
1183 | if (itv->options.radio > 0) | ||
1184 | setup.mode_mask |= T_RADIO; | ||
1183 | setup.tuner_callback = (setup.type == TUNER_XC2028) ? | 1185 | setup.tuner_callback = (setup.type == TUNER_XC2028) ? |
1184 | ivtv_reset_tuner_gpio : NULL; | 1186 | ivtv_reset_tuner_gpio : NULL; |
1185 | ivtv_call_all(itv, tuner, s_type_addr, &setup); | 1187 | ivtv_call_all(itv, tuner, s_type_addr, &setup); |
diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c index 1141b976dff4..80ec64d2d6d8 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.c +++ b/drivers/media/video/marvell-ccic/mcam-core.c | |||
@@ -883,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam) | |||
883 | * Videobuf2 interface code. | 883 | * Videobuf2 interface code. |
884 | */ | 884 | */ |
885 | 885 | ||
886 | static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, | 886 | static int mcam_vb_queue_setup(struct vb2_queue *vq, |
887 | const struct v4l2_format *fmt, unsigned int *nbufs, | ||
887 | unsigned int *num_planes, unsigned int sizes[], | 888 | unsigned int *num_planes, unsigned int sizes[], |
888 | void *alloc_ctxs[]) | 889 | void *alloc_ctxs[]) |
889 | { | 890 | { |
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index 9594b52f8605..12897e8a3314 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c | |||
@@ -738,9 +738,10 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = { | |||
738 | * Queue operations | 738 | * Queue operations |
739 | */ | 739 | */ |
740 | 740 | ||
741 | static int m2mtest_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | 741 | static int m2mtest_queue_setup(struct vb2_queue *vq, |
742 | unsigned int *nplanes, unsigned int sizes[], | 742 | const struct v4l2_format *fmt, |
743 | void *alloc_ctxs[]) | 743 | unsigned int *nbuffers, unsigned int *nplanes, |
744 | unsigned int sizes[], void *alloc_ctxs[]) | ||
744 | { | 745 | { |
745 | struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq); | 746 | struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq); |
746 | struct m2mtest_q_data *q_data; | 747 | struct m2mtest_q_data *q_data; |
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 4da9cca939c1..63ae5c61c9bf 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c | |||
@@ -13,9 +13,11 @@ | |||
13 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
14 | #include <linux/log2.h> | 14 | #include <linux/log2.h> |
15 | 15 | ||
16 | #include <media/soc_camera.h> | ||
17 | #include <media/soc_mediabus.h> | ||
16 | #include <media/v4l2-subdev.h> | 18 | #include <media/v4l2-subdev.h> |
17 | #include <media/v4l2-chip-ident.h> | 19 | #include <media/v4l2-chip-ident.h> |
18 | #include <media/soc_camera.h> | 20 | #include <media/v4l2-ctrls.h> |
19 | 21 | ||
20 | /* | 22 | /* |
21 | * mt9m001 i2c address 0x5d | 23 | * mt9m001 i2c address 0x5d |
@@ -84,15 +86,19 @@ static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = { | |||
84 | 86 | ||
85 | struct mt9m001 { | 87 | struct mt9m001 { |
86 | struct v4l2_subdev subdev; | 88 | struct v4l2_subdev subdev; |
89 | struct v4l2_ctrl_handler hdl; | ||
90 | struct { | ||
91 | /* exposure/auto-exposure cluster */ | ||
92 | struct v4l2_ctrl *autoexposure; | ||
93 | struct v4l2_ctrl *exposure; | ||
94 | }; | ||
87 | struct v4l2_rect rect; /* Sensor window */ | 95 | struct v4l2_rect rect; /* Sensor window */ |
88 | const struct mt9m001_datafmt *fmt; | 96 | const struct mt9m001_datafmt *fmt; |
89 | const struct mt9m001_datafmt *fmts; | 97 | const struct mt9m001_datafmt *fmts; |
90 | int num_fmts; | 98 | int num_fmts; |
91 | int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ | 99 | int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ |
92 | unsigned int gain; | 100 | unsigned int total_h; |
93 | unsigned int exposure; | ||
94 | unsigned short y_skip_top; /* Lines to skip at the top */ | 101 | unsigned short y_skip_top; /* Lines to skip at the top */ |
95 | unsigned char autoexposure; | ||
96 | }; | 102 | }; |
97 | 103 | ||
98 | static struct mt9m001 *to_mt9m001(const struct i2c_client *client) | 104 | static struct mt9m001 *to_mt9m001(const struct i2c_client *client) |
@@ -165,54 +171,13 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) | |||
165 | return 0; | 171 | return 0; |
166 | } | 172 | } |
167 | 173 | ||
168 | static int mt9m001_set_bus_param(struct soc_camera_device *icd, | ||
169 | unsigned long flags) | ||
170 | { | ||
171 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
172 | unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; | ||
173 | |||
174 | /* Only one width bit may be set */ | ||
175 | if (!is_power_of_2(width_flag)) | ||
176 | return -EINVAL; | ||
177 | |||
178 | if (icl->set_bus_param) | ||
179 | return icl->set_bus_param(icl, width_flag); | ||
180 | |||
181 | /* | ||
182 | * Without board specific bus width settings we only support the | ||
183 | * sensors native bus width | ||
184 | */ | ||
185 | if (width_flag == SOCAM_DATAWIDTH_10) | ||
186 | return 0; | ||
187 | |||
188 | return -EINVAL; | ||
189 | } | ||
190 | |||
191 | static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) | ||
192 | { | ||
193 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
194 | /* MT9M001 has all capture_format parameters fixed */ | ||
195 | unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING | | ||
196 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | ||
197 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER; | ||
198 | |||
199 | if (icl->query_bus_param) | ||
200 | flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; | ||
201 | else | ||
202 | flags |= SOCAM_DATAWIDTH_10; | ||
203 | |||
204 | return soc_camera_apply_sensor_flags(icl, flags); | ||
205 | } | ||
206 | |||
207 | static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 174 | static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
208 | { | 175 | { |
209 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 176 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
210 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 177 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
211 | struct v4l2_rect rect = a->c; | 178 | struct v4l2_rect rect = a->c; |
212 | struct soc_camera_device *icd = client->dev.platform_data; | ||
213 | int ret; | 179 | int ret; |
214 | const u16 hblank = 9, vblank = 25; | 180 | const u16 hblank = 9, vblank = 25; |
215 | unsigned int total_h; | ||
216 | 181 | ||
217 | if (mt9m001->fmts == mt9m001_colour_fmts) | 182 | if (mt9m001->fmts == mt9m001_colour_fmts) |
218 | /* | 183 | /* |
@@ -231,7 +196,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
231 | soc_camera_limit_side(&rect.top, &rect.height, | 196 | soc_camera_limit_side(&rect.top, &rect.height, |
232 | MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); | 197 | MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); |
233 | 198 | ||
234 | total_h = rect.height + mt9m001->y_skip_top + vblank; | 199 | mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank; |
235 | 200 | ||
236 | /* Blanking and start values - default... */ | 201 | /* Blanking and start values - default... */ |
237 | ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); | 202 | ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); |
@@ -240,7 +205,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
240 | 205 | ||
241 | /* | 206 | /* |
242 | * The caller provides a supported format, as verified per | 207 | * The caller provides a supported format, as verified per |
243 | * call to icd->try_fmt() | 208 | * call to .try_mbus_fmt() |
244 | */ | 209 | */ |
245 | if (!ret) | 210 | if (!ret) |
246 | ret = reg_write(client, MT9M001_COLUMN_START, rect.left); | 211 | ret = reg_write(client, MT9M001_COLUMN_START, rect.left); |
@@ -251,17 +216,8 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
251 | if (!ret) | 216 | if (!ret) |
252 | ret = reg_write(client, MT9M001_WINDOW_HEIGHT, | 217 | ret = reg_write(client, MT9M001_WINDOW_HEIGHT, |
253 | rect.height + mt9m001->y_skip_top - 1); | 218 | rect.height + mt9m001->y_skip_top - 1); |
254 | if (!ret && mt9m001->autoexposure) { | 219 | if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO) |
255 | ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); | 220 | ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h); |
256 | if (!ret) { | ||
257 | const struct v4l2_queryctrl *qctrl = | ||
258 | soc_camera_find_qctrl(icd->ops, | ||
259 | V4L2_CID_EXPOSURE); | ||
260 | mt9m001->exposure = (524 + (total_h - 1) * | ||
261 | (qctrl->maximum - qctrl->minimum)) / | ||
262 | 1048 + qctrl->minimum; | ||
263 | } | ||
264 | } | ||
265 | 221 | ||
266 | if (!ret) | 222 | if (!ret) |
267 | mt9m001->rect = rect; | 223 | mt9m001->rect = rect; |
@@ -421,107 +377,48 @@ static int mt9m001_s_register(struct v4l2_subdev *sd, | |||
421 | } | 377 | } |
422 | #endif | 378 | #endif |
423 | 379 | ||
424 | static const struct v4l2_queryctrl mt9m001_controls[] = { | 380 | static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
425 | { | ||
426 | .id = V4L2_CID_VFLIP, | ||
427 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
428 | .name = "Flip Vertically", | ||
429 | .minimum = 0, | ||
430 | .maximum = 1, | ||
431 | .step = 1, | ||
432 | .default_value = 0, | ||
433 | }, { | ||
434 | .id = V4L2_CID_GAIN, | ||
435 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
436 | .name = "Gain", | ||
437 | .minimum = 0, | ||
438 | .maximum = 127, | ||
439 | .step = 1, | ||
440 | .default_value = 64, | ||
441 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
442 | }, { | ||
443 | .id = V4L2_CID_EXPOSURE, | ||
444 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
445 | .name = "Exposure", | ||
446 | .minimum = 1, | ||
447 | .maximum = 255, | ||
448 | .step = 1, | ||
449 | .default_value = 255, | ||
450 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
451 | }, { | ||
452 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
453 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
454 | .name = "Automatic Exposure", | ||
455 | .minimum = 0, | ||
456 | .maximum = 1, | ||
457 | .step = 1, | ||
458 | .default_value = 1, | ||
459 | } | ||
460 | }; | ||
461 | |||
462 | static struct soc_camera_ops mt9m001_ops = { | ||
463 | .set_bus_param = mt9m001_set_bus_param, | ||
464 | .query_bus_param = mt9m001_query_bus_param, | ||
465 | .controls = mt9m001_controls, | ||
466 | .num_controls = ARRAY_SIZE(mt9m001_controls), | ||
467 | }; | ||
468 | |||
469 | static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
470 | { | 381 | { |
471 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 382 | struct mt9m001 *mt9m001 = container_of(ctrl->handler, |
472 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 383 | struct mt9m001, hdl); |
473 | int data; | 384 | s32 min, max; |
474 | 385 | ||
475 | switch (ctrl->id) { | 386 | switch (ctrl->id) { |
476 | case V4L2_CID_VFLIP: | ||
477 | data = reg_read(client, MT9M001_READ_OPTIONS2); | ||
478 | if (data < 0) | ||
479 | return -EIO; | ||
480 | ctrl->value = !!(data & 0x8000); | ||
481 | break; | ||
482 | case V4L2_CID_EXPOSURE_AUTO: | 387 | case V4L2_CID_EXPOSURE_AUTO: |
483 | ctrl->value = mt9m001->autoexposure; | 388 | min = mt9m001->exposure->minimum; |
484 | break; | 389 | max = mt9m001->exposure->maximum; |
485 | case V4L2_CID_GAIN: | 390 | mt9m001->exposure->val = |
486 | ctrl->value = mt9m001->gain; | 391 | (524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min; |
487 | break; | ||
488 | case V4L2_CID_EXPOSURE: | ||
489 | ctrl->value = mt9m001->exposure; | ||
490 | break; | 392 | break; |
491 | } | 393 | } |
492 | return 0; | 394 | return 0; |
493 | } | 395 | } |
494 | 396 | ||
495 | static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 397 | static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) |
496 | { | 398 | { |
399 | struct mt9m001 *mt9m001 = container_of(ctrl->handler, | ||
400 | struct mt9m001, hdl); | ||
401 | struct v4l2_subdev *sd = &mt9m001->subdev; | ||
497 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 402 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
498 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 403 | struct v4l2_ctrl *exp = mt9m001->exposure; |
499 | struct soc_camera_device *icd = client->dev.platform_data; | ||
500 | const struct v4l2_queryctrl *qctrl; | ||
501 | int data; | 404 | int data; |
502 | 405 | ||
503 | qctrl = soc_camera_find_qctrl(&mt9m001_ops, ctrl->id); | ||
504 | |||
505 | if (!qctrl) | ||
506 | return -EINVAL; | ||
507 | |||
508 | switch (ctrl->id) { | 406 | switch (ctrl->id) { |
509 | case V4L2_CID_VFLIP: | 407 | case V4L2_CID_VFLIP: |
510 | if (ctrl->value) | 408 | if (ctrl->val) |
511 | data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); | 409 | data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); |
512 | else | 410 | else |
513 | data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); | 411 | data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); |
514 | if (data < 0) | 412 | if (data < 0) |
515 | return -EIO; | 413 | return -EIO; |
516 | break; | 414 | return 0; |
415 | |||
517 | case V4L2_CID_GAIN: | 416 | case V4L2_CID_GAIN: |
518 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | ||
519 | return -EINVAL; | ||
520 | /* See Datasheet Table 7, Gain settings. */ | 417 | /* See Datasheet Table 7, Gain settings. */ |
521 | if (ctrl->value <= qctrl->default_value) { | 418 | if (ctrl->val <= ctrl->default_value) { |
522 | /* Pack it into 0..1 step 0.125, register values 0..8 */ | 419 | /* Pack it into 0..1 step 0.125, register values 0..8 */ |
523 | unsigned long range = qctrl->default_value - qctrl->minimum; | 420 | unsigned long range = ctrl->default_value - ctrl->minimum; |
524 | data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; | 421 | data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range; |
525 | 422 | ||
526 | dev_dbg(&client->dev, "Setting gain %d\n", data); | 423 | dev_dbg(&client->dev, "Setting gain %d\n", data); |
527 | data = reg_write(client, MT9M001_GLOBAL_GAIN, data); | 424 | data = reg_write(client, MT9M001_GLOBAL_GAIN, data); |
@@ -530,8 +427,8 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
530 | } else { | 427 | } else { |
531 | /* Pack it into 1.125..15 variable step, register values 9..67 */ | 428 | /* Pack it into 1.125..15 variable step, register values 9..67 */ |
532 | /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ | 429 | /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ |
533 | unsigned long range = qctrl->maximum - qctrl->default_value - 1; | 430 | unsigned long range = ctrl->maximum - ctrl->default_value - 1; |
534 | unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * | 431 | unsigned long gain = ((ctrl->val - ctrl->default_value - 1) * |
535 | 111 + range / 2) / range + 9; | 432 | 111 + range / 2) / range + 9; |
536 | 433 | ||
537 | if (gain <= 32) | 434 | if (gain <= 32) |
@@ -547,66 +444,44 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
547 | if (data < 0) | 444 | if (data < 0) |
548 | return -EIO; | 445 | return -EIO; |
549 | } | 446 | } |
447 | return 0; | ||
550 | 448 | ||
551 | /* Success */ | 449 | case V4L2_CID_EXPOSURE_AUTO: |
552 | mt9m001->gain = ctrl->value; | 450 | if (ctrl->val == V4L2_EXPOSURE_MANUAL) { |
553 | break; | 451 | unsigned long range = exp->maximum - exp->minimum; |
554 | case V4L2_CID_EXPOSURE: | 452 | unsigned long shutter = ((exp->val - exp->minimum) * 1048 + |
555 | /* mt9m001 has maximum == default */ | ||
556 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | ||
557 | return -EINVAL; | ||
558 | else { | ||
559 | unsigned long range = qctrl->maximum - qctrl->minimum; | ||
560 | unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 + | ||
561 | range / 2) / range + 1; | 453 | range / 2) / range + 1; |
562 | 454 | ||
563 | dev_dbg(&client->dev, | 455 | dev_dbg(&client->dev, |
564 | "Setting shutter width from %d to %lu\n", | 456 | "Setting shutter width from %d to %lu\n", |
565 | reg_read(client, MT9M001_SHUTTER_WIDTH), | 457 | reg_read(client, MT9M001_SHUTTER_WIDTH), shutter); |
566 | shutter); | ||
567 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) | 458 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) |
568 | return -EIO; | 459 | return -EIO; |
569 | mt9m001->exposure = ctrl->value; | 460 | } else { |
570 | mt9m001->autoexposure = 0; | ||
571 | } | ||
572 | break; | ||
573 | case V4L2_CID_EXPOSURE_AUTO: | ||
574 | if (ctrl->value) { | ||
575 | const u16 vblank = 25; | 461 | const u16 vblank = 25; |
576 | unsigned int total_h = mt9m001->rect.height + | 462 | |
463 | mt9m001->total_h = mt9m001->rect.height + | ||
577 | mt9m001->y_skip_top + vblank; | 464 | mt9m001->y_skip_top + vblank; |
578 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, | 465 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0) |
579 | total_h) < 0) | ||
580 | return -EIO; | 466 | return -EIO; |
581 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); | 467 | } |
582 | mt9m001->exposure = (524 + (total_h - 1) * | 468 | return 0; |
583 | (qctrl->maximum - qctrl->minimum)) / | ||
584 | 1048 + qctrl->minimum; | ||
585 | mt9m001->autoexposure = 1; | ||
586 | } else | ||
587 | mt9m001->autoexposure = 0; | ||
588 | break; | ||
589 | } | 469 | } |
590 | return 0; | 470 | return -EINVAL; |
591 | } | 471 | } |
592 | 472 | ||
593 | /* | 473 | /* |
594 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 474 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
595 | * this wasn't our capture interface, so, we wait for the right one | 475 | * this wasn't our capture interface, so, we wait for the right one |
596 | */ | 476 | */ |
597 | static int mt9m001_video_probe(struct soc_camera_device *icd, | 477 | static int mt9m001_video_probe(struct soc_camera_link *icl, |
598 | struct i2c_client *client) | 478 | struct i2c_client *client) |
599 | { | 479 | { |
600 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 480 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
601 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
602 | s32 data; | 481 | s32 data; |
603 | unsigned long flags; | 482 | unsigned long flags; |
604 | int ret; | 483 | int ret; |
605 | 484 | ||
606 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
607 | BUG_ON(!icd->parent || | ||
608 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
609 | |||
610 | /* Enable the chip */ | 485 | /* Enable the chip */ |
611 | data = reg_write(client, MT9M001_CHIP_ENABLE, 1); | 486 | data = reg_write(client, MT9M001_CHIP_ENABLE, 1); |
612 | dev_dbg(&client->dev, "write: %d\n", data); | 487 | dev_dbg(&client->dev, "write: %d\n", data); |
@@ -661,18 +536,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, | |||
661 | dev_err(&client->dev, "Failed to initialise the camera\n"); | 536 | dev_err(&client->dev, "Failed to initialise the camera\n"); |
662 | 537 | ||
663 | /* mt9m001_init() has reset the chip, returning registers to defaults */ | 538 | /* mt9m001_init() has reset the chip, returning registers to defaults */ |
664 | mt9m001->gain = 64; | 539 | return v4l2_ctrl_handler_setup(&mt9m001->hdl); |
665 | mt9m001->exposure = 255; | ||
666 | |||
667 | return ret; | ||
668 | } | 540 | } |
669 | 541 | ||
670 | static void mt9m001_video_remove(struct soc_camera_device *icd) | 542 | static void mt9m001_video_remove(struct soc_camera_link *icl) |
671 | { | 543 | { |
672 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
673 | |||
674 | dev_dbg(icd->pdev, "Video removed: %p, %p\n", | ||
675 | icd->parent, icd->vdev); | ||
676 | if (icl->free_bus) | 544 | if (icl->free_bus) |
677 | icl->free_bus(icl); | 545 | icl->free_bus(icl); |
678 | } | 546 | } |
@@ -687,9 +555,12 @@ static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | |||
687 | return 0; | 555 | return 0; |
688 | } | 556 | } |
689 | 557 | ||
558 | static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = { | ||
559 | .g_volatile_ctrl = mt9m001_g_volatile_ctrl, | ||
560 | .s_ctrl = mt9m001_s_ctrl, | ||
561 | }; | ||
562 | |||
690 | static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { | 563 | static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { |
691 | .g_ctrl = mt9m001_g_ctrl, | ||
692 | .s_ctrl = mt9m001_s_ctrl, | ||
693 | .g_chip_ident = mt9m001_g_chip_ident, | 564 | .g_chip_ident = mt9m001_g_chip_ident, |
694 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 565 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
695 | .g_register = mt9m001_g_register, | 566 | .g_register = mt9m001_g_register, |
@@ -710,6 +581,40 @@ static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
710 | return 0; | 581 | return 0; |
711 | } | 582 | } |
712 | 583 | ||
584 | static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, | ||
585 | struct v4l2_mbus_config *cfg) | ||
586 | { | ||
587 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
588 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
589 | |||
590 | /* MT9M001 has all capture_format parameters fixed */ | ||
591 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | | ||
592 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
593 | V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER; | ||
594 | cfg->type = V4L2_MBUS_PARALLEL; | ||
595 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, | ||
601 | const struct v4l2_mbus_config *cfg) | ||
602 | { | ||
603 | const struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
604 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
605 | struct mt9m001 *mt9m001 = to_mt9m001(client); | ||
606 | unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample; | ||
607 | |||
608 | if (icl->set_bus_param) | ||
609 | return icl->set_bus_param(icl, 1 << (bps - 1)); | ||
610 | |||
611 | /* | ||
612 | * Without board specific bus width settings we only support the | ||
613 | * sensors native bus width | ||
614 | */ | ||
615 | return bps == 10 ? 0 : -EINVAL; | ||
616 | } | ||
617 | |||
713 | static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { | 618 | static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { |
714 | .s_stream = mt9m001_s_stream, | 619 | .s_stream = mt9m001_s_stream, |
715 | .s_mbus_fmt = mt9m001_s_fmt, | 620 | .s_mbus_fmt = mt9m001_s_fmt, |
@@ -719,6 +624,8 @@ static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { | |||
719 | .g_crop = mt9m001_g_crop, | 624 | .g_crop = mt9m001_g_crop, |
720 | .cropcap = mt9m001_cropcap, | 625 | .cropcap = mt9m001_cropcap, |
721 | .enum_mbus_fmt = mt9m001_enum_fmt, | 626 | .enum_mbus_fmt = mt9m001_enum_fmt, |
627 | .g_mbus_config = mt9m001_g_mbus_config, | ||
628 | .s_mbus_config = mt9m001_s_mbus_config, | ||
722 | }; | 629 | }; |
723 | 630 | ||
724 | static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { | 631 | static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { |
@@ -735,17 +642,10 @@ static int mt9m001_probe(struct i2c_client *client, | |||
735 | const struct i2c_device_id *did) | 642 | const struct i2c_device_id *did) |
736 | { | 643 | { |
737 | struct mt9m001 *mt9m001; | 644 | struct mt9m001 *mt9m001; |
738 | struct soc_camera_device *icd = client->dev.platform_data; | ||
739 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 645 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
740 | struct soc_camera_link *icl; | 646 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
741 | int ret; | 647 | int ret; |
742 | 648 | ||
743 | if (!icd) { | ||
744 | dev_err(&client->dev, "MT9M001: missing soc-camera data!\n"); | ||
745 | return -EINVAL; | ||
746 | } | ||
747 | |||
748 | icl = to_soc_camera_link(icd); | ||
749 | if (!icl) { | 649 | if (!icl) { |
750 | dev_err(&client->dev, "MT9M001 driver needs platform data\n"); | 650 | dev_err(&client->dev, "MT9M001 driver needs platform data\n"); |
751 | return -EINVAL; | 651 | return -EINVAL; |
@@ -762,25 +662,40 @@ static int mt9m001_probe(struct i2c_client *client, | |||
762 | return -ENOMEM; | 662 | return -ENOMEM; |
763 | 663 | ||
764 | v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); | 664 | v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); |
665 | v4l2_ctrl_handler_init(&mt9m001->hdl, 4); | ||
666 | v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, | ||
667 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
668 | v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, | ||
669 | V4L2_CID_GAIN, 0, 127, 1, 64); | ||
670 | mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, | ||
671 | V4L2_CID_EXPOSURE, 1, 255, 1, 255); | ||
672 | /* | ||
673 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
674 | * ourselves in the driver based on vertical blanking and frame width | ||
675 | */ | ||
676 | mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl, | ||
677 | &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
678 | V4L2_EXPOSURE_AUTO); | ||
679 | mt9m001->subdev.ctrl_handler = &mt9m001->hdl; | ||
680 | if (mt9m001->hdl.error) { | ||
681 | int err = mt9m001->hdl.error; | ||
765 | 682 | ||
766 | /* Second stage probe - when a capture adapter is there */ | 683 | kfree(mt9m001); |
767 | icd->ops = &mt9m001_ops; | 684 | return err; |
685 | } | ||
686 | v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure, | ||
687 | V4L2_EXPOSURE_MANUAL, true); | ||
768 | 688 | ||
689 | /* Second stage probe - when a capture adapter is there */ | ||
769 | mt9m001->y_skip_top = 0; | 690 | mt9m001->y_skip_top = 0; |
770 | mt9m001->rect.left = MT9M001_COLUMN_SKIP; | 691 | mt9m001->rect.left = MT9M001_COLUMN_SKIP; |
771 | mt9m001->rect.top = MT9M001_ROW_SKIP; | 692 | mt9m001->rect.top = MT9M001_ROW_SKIP; |
772 | mt9m001->rect.width = MT9M001_MAX_WIDTH; | 693 | mt9m001->rect.width = MT9M001_MAX_WIDTH; |
773 | mt9m001->rect.height = MT9M001_MAX_HEIGHT; | 694 | mt9m001->rect.height = MT9M001_MAX_HEIGHT; |
774 | 695 | ||
775 | /* | 696 | ret = mt9m001_video_probe(icl, client); |
776 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
777 | * ourselves in the driver based on vertical blanking and frame width | ||
778 | */ | ||
779 | mt9m001->autoexposure = 1; | ||
780 | |||
781 | ret = mt9m001_video_probe(icd, client); | ||
782 | if (ret) { | 697 | if (ret) { |
783 | icd->ops = NULL; | 698 | v4l2_ctrl_handler_free(&mt9m001->hdl); |
784 | kfree(mt9m001); | 699 | kfree(mt9m001); |
785 | } | 700 | } |
786 | 701 | ||
@@ -790,10 +705,11 @@ static int mt9m001_probe(struct i2c_client *client, | |||
790 | static int mt9m001_remove(struct i2c_client *client) | 705 | static int mt9m001_remove(struct i2c_client *client) |
791 | { | 706 | { |
792 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 707 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
793 | struct soc_camera_device *icd = client->dev.platform_data; | 708 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
794 | 709 | ||
795 | icd->ops = NULL; | 710 | v4l2_device_unregister_subdev(&mt9m001->subdev); |
796 | mt9m001_video_remove(icd); | 711 | v4l2_ctrl_handler_free(&mt9m001->hdl); |
712 | mt9m001_video_remove(icl); | ||
797 | kfree(mt9m001); | 713 | kfree(mt9m001); |
798 | 714 | ||
799 | return 0; | 715 | return 0; |
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 07af26e6bebd..f023cc092c2b 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c | |||
@@ -13,10 +13,12 @@ | |||
13 | #include <linux/log2.h> | 13 | #include <linux/log2.h> |
14 | #include <linux/gpio.h> | 14 | #include <linux/gpio.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/v4l2-mediabus.h> | ||
16 | 17 | ||
18 | #include <media/soc_camera.h> | ||
17 | #include <media/v4l2-common.h> | 19 | #include <media/v4l2-common.h> |
20 | #include <media/v4l2-ctrls.h> | ||
18 | #include <media/v4l2-chip-ident.h> | 21 | #include <media/v4l2-chip-ident.h> |
19 | #include <media/soc_camera.h> | ||
20 | 22 | ||
21 | /* | 23 | /* |
22 | * MT9M111, MT9M112 and MT9M131: | 24 | * MT9M111, MT9M112 and MT9M131: |
@@ -177,6 +179,8 @@ enum mt9m111_context { | |||
177 | 179 | ||
178 | struct mt9m111 { | 180 | struct mt9m111 { |
179 | struct v4l2_subdev subdev; | 181 | struct v4l2_subdev subdev; |
182 | struct v4l2_ctrl_handler hdl; | ||
183 | struct v4l2_ctrl *gain; | ||
180 | int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code | 184 | int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code |
181 | * from v4l2-chip-ident.h */ | 185 | * from v4l2-chip-ident.h */ |
182 | enum mt9m111_context context; | 186 | enum mt9m111_context context; |
@@ -185,13 +189,8 @@ struct mt9m111 { | |||
185 | int power_count; | 189 | int power_count; |
186 | const struct mt9m111_datafmt *fmt; | 190 | const struct mt9m111_datafmt *fmt; |
187 | int lastpage; /* PageMap cache value */ | 191 | int lastpage; /* PageMap cache value */ |
188 | unsigned int gain; | ||
189 | unsigned char autoexposure; | ||
190 | unsigned char datawidth; | 192 | unsigned char datawidth; |
191 | unsigned int powered:1; | 193 | unsigned int powered:1; |
192 | unsigned int hflip:1; | ||
193 | unsigned int vflip:1; | ||
194 | unsigned int autowhitebalance:1; | ||
195 | }; | 194 | }; |
196 | 195 | ||
197 | static struct mt9m111 *to_mt9m111(const struct i2c_client *client) | 196 | static struct mt9m111 *to_mt9m111(const struct i2c_client *client) |
@@ -363,21 +362,6 @@ static int mt9m111_reset(struct mt9m111 *mt9m111) | |||
363 | return ret; | 362 | return ret; |
364 | } | 363 | } |
365 | 364 | ||
366 | static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) | ||
367 | { | ||
368 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
369 | unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | | ||
370 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | ||
371 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | ||
372 | |||
373 | return soc_camera_apply_sensor_flags(icl, flags); | ||
374 | } | ||
375 | |||
376 | static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) | ||
377 | { | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int mt9m111_make_rect(struct mt9m111 *mt9m111, | 365 | static int mt9m111_make_rect(struct mt9m111 *mt9m111, |
382 | struct v4l2_rect *rect) | 366 | struct v4l2_rect *rect) |
383 | { | 367 | { |
@@ -660,50 +644,6 @@ static int mt9m111_s_register(struct v4l2_subdev *sd, | |||
660 | } | 644 | } |
661 | #endif | 645 | #endif |
662 | 646 | ||
663 | static const struct v4l2_queryctrl mt9m111_controls[] = { | ||
664 | { | ||
665 | .id = V4L2_CID_VFLIP, | ||
666 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
667 | .name = "Flip Verticaly", | ||
668 | .minimum = 0, | ||
669 | .maximum = 1, | ||
670 | .step = 1, | ||
671 | .default_value = 0, | ||
672 | }, { | ||
673 | .id = V4L2_CID_HFLIP, | ||
674 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
675 | .name = "Flip Horizontaly", | ||
676 | .minimum = 0, | ||
677 | .maximum = 1, | ||
678 | .step = 1, | ||
679 | .default_value = 0, | ||
680 | }, { /* gain = 1/32*val (=>gain=1 if val==32) */ | ||
681 | .id = V4L2_CID_GAIN, | ||
682 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
683 | .name = "Gain", | ||
684 | .minimum = 0, | ||
685 | .maximum = 63 * 2 * 2, | ||
686 | .step = 1, | ||
687 | .default_value = 32, | ||
688 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
689 | }, { | ||
690 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
691 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
692 | .name = "Auto Exposure", | ||
693 | .minimum = 0, | ||
694 | .maximum = 1, | ||
695 | .step = 1, | ||
696 | .default_value = 1, | ||
697 | } | ||
698 | }; | ||
699 | |||
700 | static struct soc_camera_ops mt9m111_ops = { | ||
701 | .query_bus_param = mt9m111_query_bus_param, | ||
702 | .set_bus_param = mt9m111_set_bus_param, | ||
703 | .controls = mt9m111_controls, | ||
704 | .num_controls = ARRAY_SIZE(mt9m111_controls), | ||
705 | }; | ||
706 | |||
707 | static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) | 647 | static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) |
708 | { | 648 | { |
709 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 649 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
@@ -744,7 +684,6 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) | |||
744 | if (gain > 63 * 2 * 2) | 684 | if (gain > 63 * 2 * 2) |
745 | return -EINVAL; | 685 | return -EINVAL; |
746 | 686 | ||
747 | mt9m111->gain = gain; | ||
748 | if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) | 687 | if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) |
749 | val = (1 << 10) | (1 << 9) | (gain / 4); | 688 | val = (1 << 10) | (1 << 9) | (gain / 4); |
750 | else if ((gain >= 64) && (gain < 64 * 2)) | 689 | else if ((gain >= 64) && (gain < 64 * 2)) |
@@ -758,118 +697,47 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) | |||
758 | static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) | 697 | static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) |
759 | { | 698 | { |
760 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 699 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
761 | int ret; | ||
762 | 700 | ||
763 | if (on) | 701 | if (on) |
764 | ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); | 702 | return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); |
765 | else | 703 | return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); |
766 | ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); | ||
767 | |||
768 | if (!ret) | ||
769 | mt9m111->autoexposure = on; | ||
770 | |||
771 | return ret; | ||
772 | } | 704 | } |
773 | 705 | ||
774 | static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) | 706 | static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) |
775 | { | 707 | { |
776 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 708 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
777 | int ret; | ||
778 | 709 | ||
779 | if (on) | 710 | if (on) |
780 | ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); | 711 | return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); |
781 | else | 712 | return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); |
782 | ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); | ||
783 | |||
784 | if (!ret) | ||
785 | mt9m111->autowhitebalance = on; | ||
786 | |||
787 | return ret; | ||
788 | } | ||
789 | |||
790 | static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
791 | { | ||
792 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
793 | struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); | ||
794 | int data; | ||
795 | |||
796 | switch (ctrl->id) { | ||
797 | case V4L2_CID_VFLIP: | ||
798 | if (mt9m111->context == HIGHPOWER) | ||
799 | data = reg_read(READ_MODE_B); | ||
800 | else | ||
801 | data = reg_read(READ_MODE_A); | ||
802 | |||
803 | if (data < 0) | ||
804 | return -EIO; | ||
805 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS); | ||
806 | break; | ||
807 | case V4L2_CID_HFLIP: | ||
808 | if (mt9m111->context == HIGHPOWER) | ||
809 | data = reg_read(READ_MODE_B); | ||
810 | else | ||
811 | data = reg_read(READ_MODE_A); | ||
812 | |||
813 | if (data < 0) | ||
814 | return -EIO; | ||
815 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); | ||
816 | break; | ||
817 | case V4L2_CID_GAIN: | ||
818 | data = mt9m111_get_global_gain(mt9m111); | ||
819 | if (data < 0) | ||
820 | return data; | ||
821 | ctrl->value = data; | ||
822 | break; | ||
823 | case V4L2_CID_EXPOSURE_AUTO: | ||
824 | ctrl->value = mt9m111->autoexposure; | ||
825 | break; | ||
826 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
827 | ctrl->value = mt9m111->autowhitebalance; | ||
828 | break; | ||
829 | } | ||
830 | return 0; | ||
831 | } | 713 | } |
832 | 714 | ||
833 | static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 715 | static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl) |
834 | { | 716 | { |
835 | struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); | 717 | struct mt9m111 *mt9m111 = container_of(ctrl->handler, |
836 | const struct v4l2_queryctrl *qctrl; | 718 | struct mt9m111, hdl); |
837 | int ret; | ||
838 | |||
839 | qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); | ||
840 | if (!qctrl) | ||
841 | return -EINVAL; | ||
842 | 719 | ||
843 | switch (ctrl->id) { | 720 | switch (ctrl->id) { |
844 | case V4L2_CID_VFLIP: | 721 | case V4L2_CID_VFLIP: |
845 | mt9m111->vflip = ctrl->value; | 722 | return mt9m111_set_flip(mt9m111, ctrl->val, |
846 | ret = mt9m111_set_flip(mt9m111, ctrl->value, | ||
847 | MT9M111_RMB_MIRROR_ROWS); | 723 | MT9M111_RMB_MIRROR_ROWS); |
848 | break; | ||
849 | case V4L2_CID_HFLIP: | 724 | case V4L2_CID_HFLIP: |
850 | mt9m111->hflip = ctrl->value; | 725 | return mt9m111_set_flip(mt9m111, ctrl->val, |
851 | ret = mt9m111_set_flip(mt9m111, ctrl->value, | ||
852 | MT9M111_RMB_MIRROR_COLS); | 726 | MT9M111_RMB_MIRROR_COLS); |
853 | break; | ||
854 | case V4L2_CID_GAIN: | 727 | case V4L2_CID_GAIN: |
855 | ret = mt9m111_set_global_gain(mt9m111, ctrl->value); | 728 | return mt9m111_set_global_gain(mt9m111, ctrl->val); |
856 | break; | ||
857 | case V4L2_CID_EXPOSURE_AUTO: | 729 | case V4L2_CID_EXPOSURE_AUTO: |
858 | ret = mt9m111_set_autoexposure(mt9m111, ctrl->value); | 730 | return mt9m111_set_autoexposure(mt9m111, ctrl->val); |
859 | break; | ||
860 | case V4L2_CID_AUTO_WHITE_BALANCE: | 731 | case V4L2_CID_AUTO_WHITE_BALANCE: |
861 | ret = mt9m111_set_autowhitebalance(mt9m111, ctrl->value); | 732 | return mt9m111_set_autowhitebalance(mt9m111, ctrl->val); |
862 | break; | ||
863 | default: | ||
864 | ret = -EINVAL; | ||
865 | } | 733 | } |
866 | 734 | ||
867 | return ret; | 735 | return -EINVAL; |
868 | } | 736 | } |
869 | 737 | ||
870 | static int mt9m111_suspend(struct mt9m111 *mt9m111) | 738 | static int mt9m111_suspend(struct mt9m111 *mt9m111) |
871 | { | 739 | { |
872 | mt9m111->gain = mt9m111_get_global_gain(mt9m111); | 740 | v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111)); |
873 | 741 | ||
874 | return 0; | 742 | return 0; |
875 | } | 743 | } |
@@ -879,11 +747,7 @@ static void mt9m111_restore_state(struct mt9m111 *mt9m111) | |||
879 | mt9m111_set_context(mt9m111, mt9m111->context); | 747 | mt9m111_set_context(mt9m111, mt9m111->context); |
880 | mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); | 748 | mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); |
881 | mt9m111_setup_rect(mt9m111, &mt9m111->rect); | 749 | mt9m111_setup_rect(mt9m111, &mt9m111->rect); |
882 | mt9m111_set_flip(mt9m111, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); | 750 | v4l2_ctrl_handler_setup(&mt9m111->hdl); |
883 | mt9m111_set_flip(mt9m111, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); | ||
884 | mt9m111_set_global_gain(mt9m111, mt9m111->gain); | ||
885 | mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); | ||
886 | mt9m111_set_autowhitebalance(mt9m111, mt9m111->autowhitebalance); | ||
887 | } | 751 | } |
888 | 752 | ||
889 | static int mt9m111_resume(struct mt9m111 *mt9m111) | 753 | static int mt9m111_resume(struct mt9m111 *mt9m111) |
@@ -911,8 +775,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111) | |||
911 | ret = mt9m111_reset(mt9m111); | 775 | ret = mt9m111_reset(mt9m111); |
912 | if (!ret) | 776 | if (!ret) |
913 | ret = mt9m111_set_context(mt9m111, mt9m111->context); | 777 | ret = mt9m111_set_context(mt9m111, mt9m111->context); |
914 | if (!ret) | ||
915 | ret = mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); | ||
916 | if (ret) | 778 | if (ret) |
917 | dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); | 779 | dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); |
918 | return ret; | 780 | return ret; |
@@ -922,22 +784,12 @@ static int mt9m111_init(struct mt9m111 *mt9m111) | |||
922 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 784 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
923 | * this wasn't our capture interface, so, we wait for the right one | 785 | * this wasn't our capture interface, so, we wait for the right one |
924 | */ | 786 | */ |
925 | static int mt9m111_video_probe(struct soc_camera_device *icd, | 787 | static int mt9m111_video_probe(struct i2c_client *client) |
926 | struct i2c_client *client) | ||
927 | { | 788 | { |
928 | struct mt9m111 *mt9m111 = to_mt9m111(client); | 789 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
929 | s32 data; | 790 | s32 data; |
930 | int ret; | 791 | int ret; |
931 | 792 | ||
932 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
933 | BUG_ON(!icd->parent || | ||
934 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
935 | |||
936 | mt9m111->lastpage = -1; | ||
937 | |||
938 | mt9m111->autoexposure = 1; | ||
939 | mt9m111->autowhitebalance = 1; | ||
940 | |||
941 | data = reg_read(CHIP_VERSION); | 793 | data = reg_read(CHIP_VERSION); |
942 | 794 | ||
943 | switch (data) { | 795 | switch (data) { |
@@ -951,17 +803,16 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, | |||
951 | dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); | 803 | dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); |
952 | break; | 804 | break; |
953 | default: | 805 | default: |
954 | ret = -ENODEV; | ||
955 | dev_err(&client->dev, | 806 | dev_err(&client->dev, |
956 | "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", | 807 | "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", |
957 | data); | 808 | data); |
958 | goto ei2c; | 809 | return -ENODEV; |
959 | } | 810 | } |
960 | 811 | ||
961 | ret = mt9m111_init(mt9m111); | 812 | ret = mt9m111_init(mt9m111); |
962 | 813 | if (ret) | |
963 | ei2c: | 814 | return ret; |
964 | return ret; | 815 | return v4l2_ctrl_handler_setup(&mt9m111->hdl); |
965 | } | 816 | } |
966 | 817 | ||
967 | static int mt9m111_s_power(struct v4l2_subdev *sd, int on) | 818 | static int mt9m111_s_power(struct v4l2_subdev *sd, int on) |
@@ -998,9 +849,11 @@ out: | |||
998 | return ret; | 849 | return ret; |
999 | } | 850 | } |
1000 | 851 | ||
852 | static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = { | ||
853 | .s_ctrl = mt9m111_s_ctrl, | ||
854 | }; | ||
855 | |||
1001 | static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { | 856 | static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { |
1002 | .g_ctrl = mt9m111_g_ctrl, | ||
1003 | .s_ctrl = mt9m111_s_ctrl, | ||
1004 | .g_chip_ident = mt9m111_g_chip_ident, | 857 | .g_chip_ident = mt9m111_g_chip_ident, |
1005 | .s_power = mt9m111_s_power, | 858 | .s_power = mt9m111_s_power, |
1006 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 859 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
@@ -1019,6 +872,21 @@ static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
1019 | return 0; | 872 | return 0; |
1020 | } | 873 | } |
1021 | 874 | ||
875 | static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, | ||
876 | struct v4l2_mbus_config *cfg) | ||
877 | { | ||
878 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
879 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
880 | |||
881 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
882 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
883 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
884 | cfg->type = V4L2_MBUS_PARALLEL; | ||
885 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
886 | |||
887 | return 0; | ||
888 | } | ||
889 | |||
1022 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { | 890 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { |
1023 | .s_mbus_fmt = mt9m111_s_fmt, | 891 | .s_mbus_fmt = mt9m111_s_fmt, |
1024 | .g_mbus_fmt = mt9m111_g_fmt, | 892 | .g_mbus_fmt = mt9m111_g_fmt, |
@@ -1027,6 +895,7 @@ static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { | |||
1027 | .g_crop = mt9m111_g_crop, | 895 | .g_crop = mt9m111_g_crop, |
1028 | .cropcap = mt9m111_cropcap, | 896 | .cropcap = mt9m111_cropcap, |
1029 | .enum_mbus_fmt = mt9m111_enum_fmt, | 897 | .enum_mbus_fmt = mt9m111_enum_fmt, |
898 | .g_mbus_config = mt9m111_g_mbus_config, | ||
1030 | }; | 899 | }; |
1031 | 900 | ||
1032 | static struct v4l2_subdev_ops mt9m111_subdev_ops = { | 901 | static struct v4l2_subdev_ops mt9m111_subdev_ops = { |
@@ -1038,17 +907,10 @@ static int mt9m111_probe(struct i2c_client *client, | |||
1038 | const struct i2c_device_id *did) | 907 | const struct i2c_device_id *did) |
1039 | { | 908 | { |
1040 | struct mt9m111 *mt9m111; | 909 | struct mt9m111 *mt9m111; |
1041 | struct soc_camera_device *icd = client->dev.platform_data; | ||
1042 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 910 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1043 | struct soc_camera_link *icl; | 911 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
1044 | int ret; | 912 | int ret; |
1045 | 913 | ||
1046 | if (!icd) { | ||
1047 | dev_err(&client->dev, "mt9m111: soc-camera data missing!\n"); | ||
1048 | return -EINVAL; | ||
1049 | } | ||
1050 | |||
1051 | icl = to_soc_camera_link(icd); | ||
1052 | if (!icl) { | 914 | if (!icl) { |
1053 | dev_err(&client->dev, "mt9m111: driver needs platform data\n"); | 915 | dev_err(&client->dev, "mt9m111: driver needs platform data\n"); |
1054 | return -EINVAL; | 916 | return -EINVAL; |
@@ -1065,19 +927,37 @@ static int mt9m111_probe(struct i2c_client *client, | |||
1065 | return -ENOMEM; | 927 | return -ENOMEM; |
1066 | 928 | ||
1067 | v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); | 929 | v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); |
930 | v4l2_ctrl_handler_init(&mt9m111->hdl, 5); | ||
931 | v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
932 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
933 | v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
934 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
935 | v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
936 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
937 | mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
938 | V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32); | ||
939 | v4l2_ctrl_new_std_menu(&mt9m111->hdl, | ||
940 | &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
941 | V4L2_EXPOSURE_AUTO); | ||
942 | mt9m111->subdev.ctrl_handler = &mt9m111->hdl; | ||
943 | if (mt9m111->hdl.error) { | ||
944 | int err = mt9m111->hdl.error; | ||
1068 | 945 | ||
1069 | /* Second stage probe - when a capture adapter is there */ | 946 | kfree(mt9m111); |
1070 | icd->ops = &mt9m111_ops; | 947 | return err; |
948 | } | ||
1071 | 949 | ||
950 | /* Second stage probe - when a capture adapter is there */ | ||
1072 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; | 951 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; |
1073 | mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; | 952 | mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; |
1074 | mt9m111->rect.width = MT9M111_MAX_WIDTH; | 953 | mt9m111->rect.width = MT9M111_MAX_WIDTH; |
1075 | mt9m111->rect.height = MT9M111_MAX_HEIGHT; | 954 | mt9m111->rect.height = MT9M111_MAX_HEIGHT; |
1076 | mt9m111->fmt = &mt9m111_colour_fmts[0]; | 955 | mt9m111->fmt = &mt9m111_colour_fmts[0]; |
956 | mt9m111->lastpage = -1; | ||
1077 | 957 | ||
1078 | ret = mt9m111_video_probe(icd, client); | 958 | ret = mt9m111_video_probe(client); |
1079 | if (ret) { | 959 | if (ret) { |
1080 | icd->ops = NULL; | 960 | v4l2_ctrl_handler_free(&mt9m111->hdl); |
1081 | kfree(mt9m111); | 961 | kfree(mt9m111); |
1082 | } | 962 | } |
1083 | 963 | ||
@@ -1087,9 +967,9 @@ static int mt9m111_probe(struct i2c_client *client, | |||
1087 | static int mt9m111_remove(struct i2c_client *client) | 967 | static int mt9m111_remove(struct i2c_client *client) |
1088 | { | 968 | { |
1089 | struct mt9m111 *mt9m111 = to_mt9m111(client); | 969 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
1090 | struct soc_camera_device *icd = client->dev.platform_data; | ||
1091 | 970 | ||
1092 | icd->ops = NULL; | 971 | v4l2_device_unregister_subdev(&mt9m111->subdev); |
972 | v4l2_ctrl_handler_free(&mt9m111->hdl); | ||
1093 | kfree(mt9m111); | 973 | kfree(mt9m111); |
1094 | 974 | ||
1095 | return 0; | 975 | return 0; |
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 30547cc3f89b..7ee84cc578b9 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c | |||
@@ -13,11 +13,20 @@ | |||
13 | #include <linux/log2.h> | 13 | #include <linux/log2.h> |
14 | #include <linux/pm.h> | 14 | #include <linux/pm.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/v4l2-mediabus.h> | ||
16 | #include <linux/videodev2.h> | 17 | #include <linux/videodev2.h> |
17 | 18 | ||
18 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
19 | #include <media/v4l2-chip-ident.h> | 20 | #include <media/v4l2-chip-ident.h> |
20 | #include <media/v4l2-subdev.h> | 21 | #include <media/v4l2-subdev.h> |
22 | #include <media/v4l2-ctrls.h> | ||
23 | |||
24 | /* | ||
25 | * ATTENTION: this driver still cannot be used outside of the soc-camera | ||
26 | * framework because of its PM implementation, using the video_device node. | ||
27 | * If hardware becomes available for testing, alternative PM approaches shall | ||
28 | * be considered and tested. | ||
29 | */ | ||
21 | 30 | ||
22 | /* | 31 | /* |
23 | * mt9t031 i2c address 0x5d | 32 | * mt9t031 i2c address 0x5d |
@@ -57,21 +66,20 @@ | |||
57 | #define MT9T031_COLUMN_SKIP 32 | 66 | #define MT9T031_COLUMN_SKIP 32 |
58 | #define MT9T031_ROW_SKIP 20 | 67 | #define MT9T031_ROW_SKIP 20 |
59 | 68 | ||
60 | #define MT9T031_BUS_PARAM (SOCAM_PCLK_SAMPLE_RISING | \ | ||
61 | SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | \ | ||
62 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \ | ||
63 | SOCAM_MASTER | SOCAM_DATAWIDTH_10) | ||
64 | |||
65 | struct mt9t031 { | 69 | struct mt9t031 { |
66 | struct v4l2_subdev subdev; | 70 | struct v4l2_subdev subdev; |
71 | struct v4l2_ctrl_handler hdl; | ||
72 | struct { | ||
73 | /* exposure/auto-exposure cluster */ | ||
74 | struct v4l2_ctrl *autoexposure; | ||
75 | struct v4l2_ctrl *exposure; | ||
76 | }; | ||
67 | struct v4l2_rect rect; /* Sensor window */ | 77 | struct v4l2_rect rect; /* Sensor window */ |
68 | int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ | 78 | int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ |
69 | u16 xskip; | 79 | u16 xskip; |
70 | u16 yskip; | 80 | u16 yskip; |
71 | unsigned int gain; | 81 | unsigned int total_h; |
72 | unsigned short y_skip_top; /* Lines to skip at the top */ | 82 | unsigned short y_skip_top; /* Lines to skip at the top */ |
73 | unsigned int exposure; | ||
74 | unsigned char autoexposure; | ||
75 | }; | 83 | }; |
76 | 84 | ||
77 | static struct mt9t031 *to_mt9t031(const struct i2c_client *client) | 85 | static struct mt9t031 *to_mt9t031(const struct i2c_client *client) |
@@ -179,95 +187,6 @@ static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) | |||
179 | return 0; | 187 | return 0; |
180 | } | 188 | } |
181 | 189 | ||
182 | static int mt9t031_set_bus_param(struct soc_camera_device *icd, | ||
183 | unsigned long flags) | ||
184 | { | ||
185 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
186 | |||
187 | /* The caller should have queried our parameters, check anyway */ | ||
188 | if (flags & ~MT9T031_BUS_PARAM) | ||
189 | return -EINVAL; | ||
190 | |||
191 | if (flags & SOCAM_PCLK_SAMPLE_FALLING) | ||
192 | reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); | ||
193 | else | ||
194 | reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) | ||
200 | { | ||
201 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
202 | |||
203 | return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); | ||
204 | } | ||
205 | |||
206 | enum { | ||
207 | MT9T031_CTRL_VFLIP, | ||
208 | MT9T031_CTRL_HFLIP, | ||
209 | MT9T031_CTRL_GAIN, | ||
210 | MT9T031_CTRL_EXPOSURE, | ||
211 | MT9T031_CTRL_EXPOSURE_AUTO, | ||
212 | }; | ||
213 | |||
214 | static const struct v4l2_queryctrl mt9t031_controls[] = { | ||
215 | [MT9T031_CTRL_VFLIP] = { | ||
216 | .id = V4L2_CID_VFLIP, | ||
217 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
218 | .name = "Flip Vertically", | ||
219 | .minimum = 0, | ||
220 | .maximum = 1, | ||
221 | .step = 1, | ||
222 | .default_value = 0, | ||
223 | }, | ||
224 | [MT9T031_CTRL_HFLIP] = { | ||
225 | .id = V4L2_CID_HFLIP, | ||
226 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
227 | .name = "Flip Horizontally", | ||
228 | .minimum = 0, | ||
229 | .maximum = 1, | ||
230 | .step = 1, | ||
231 | .default_value = 0, | ||
232 | }, | ||
233 | [MT9T031_CTRL_GAIN] = { | ||
234 | .id = V4L2_CID_GAIN, | ||
235 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
236 | .name = "Gain", | ||
237 | .minimum = 0, | ||
238 | .maximum = 127, | ||
239 | .step = 1, | ||
240 | .default_value = 64, | ||
241 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
242 | }, | ||
243 | [MT9T031_CTRL_EXPOSURE] = { | ||
244 | .id = V4L2_CID_EXPOSURE, | ||
245 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
246 | .name = "Exposure", | ||
247 | .minimum = 1, | ||
248 | .maximum = 255, | ||
249 | .step = 1, | ||
250 | .default_value = 255, | ||
251 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
252 | }, | ||
253 | [MT9T031_CTRL_EXPOSURE_AUTO] = { | ||
254 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
255 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
256 | .name = "Automatic Exposure", | ||
257 | .minimum = 0, | ||
258 | .maximum = 1, | ||
259 | .step = 1, | ||
260 | .default_value = 1, | ||
261 | } | ||
262 | }; | ||
263 | |||
264 | static struct soc_camera_ops mt9t031_ops = { | ||
265 | .set_bus_param = mt9t031_set_bus_param, | ||
266 | .query_bus_param = mt9t031_query_bus_param, | ||
267 | .controls = mt9t031_controls, | ||
268 | .num_controls = ARRAY_SIZE(mt9t031_controls), | ||
269 | }; | ||
270 | |||
271 | /* target must be _even_ */ | 190 | /* target must be _even_ */ |
272 | static u16 mt9t031_skip(s32 *source, s32 target, s32 max) | 191 | static u16 mt9t031_skip(s32 *source, s32 target, s32 max) |
273 | { | 192 | { |
@@ -353,7 +272,7 @@ static int mt9t031_set_params(struct i2c_client *client, | |||
353 | 272 | ||
354 | /* | 273 | /* |
355 | * The caller provides a supported format, as guaranteed by | 274 | * The caller provides a supported format, as guaranteed by |
356 | * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() | 275 | * .try_mbus_fmt(), soc_camera_s_crop() and soc_camera_cropcap() |
357 | */ | 276 | */ |
358 | if (ret >= 0) | 277 | if (ret >= 0) |
359 | ret = reg_write(client, MT9T031_COLUMN_START, rect->left); | 278 | ret = reg_write(client, MT9T031_COLUMN_START, rect->left); |
@@ -364,17 +283,10 @@ static int mt9t031_set_params(struct i2c_client *client, | |||
364 | if (ret >= 0) | 283 | if (ret >= 0) |
365 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, | 284 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, |
366 | rect->height + mt9t031->y_skip_top - 1); | 285 | rect->height + mt9t031->y_skip_top - 1); |
367 | if (ret >= 0 && mt9t031->autoexposure) { | 286 | if (ret >= 0 && v4l2_ctrl_g_ctrl(mt9t031->autoexposure) == V4L2_EXPOSURE_AUTO) { |
368 | unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank; | 287 | mt9t031->total_h = rect->height + mt9t031->y_skip_top + vblank; |
369 | ret = set_shutter(client, total_h); | 288 | |
370 | if (ret >= 0) { | 289 | ret = set_shutter(client, mt9t031->total_h); |
371 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | ||
372 | const struct v4l2_queryctrl *qctrl = | ||
373 | &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; | ||
374 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * | ||
375 | (qctrl->maximum - qctrl->minimum)) / | ||
376 | shutter_max + qctrl->minimum; | ||
377 | } | ||
378 | } | 290 | } |
379 | 291 | ||
380 | /* Re-enable register update, commit all changes */ | 292 | /* Re-enable register update, commit all changes */ |
@@ -543,71 +455,57 @@ static int mt9t031_s_register(struct v4l2_subdev *sd, | |||
543 | } | 455 | } |
544 | #endif | 456 | #endif |
545 | 457 | ||
546 | static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 458 | static int mt9t031_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
547 | { | 459 | { |
548 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 460 | struct mt9t031 *mt9t031 = container_of(ctrl->handler, |
549 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 461 | struct mt9t031, hdl); |
550 | int data; | 462 | const u32 shutter_max = MT9T031_MAX_HEIGHT + MT9T031_VERTICAL_BLANK; |
463 | s32 min, max; | ||
551 | 464 | ||
552 | switch (ctrl->id) { | 465 | switch (ctrl->id) { |
553 | case V4L2_CID_VFLIP: | ||
554 | data = reg_read(client, MT9T031_READ_MODE_2); | ||
555 | if (data < 0) | ||
556 | return -EIO; | ||
557 | ctrl->value = !!(data & 0x8000); | ||
558 | break; | ||
559 | case V4L2_CID_HFLIP: | ||
560 | data = reg_read(client, MT9T031_READ_MODE_2); | ||
561 | if (data < 0) | ||
562 | return -EIO; | ||
563 | ctrl->value = !!(data & 0x4000); | ||
564 | break; | ||
565 | case V4L2_CID_EXPOSURE_AUTO: | 466 | case V4L2_CID_EXPOSURE_AUTO: |
566 | ctrl->value = mt9t031->autoexposure; | 467 | min = mt9t031->exposure->minimum; |
567 | break; | 468 | max = mt9t031->exposure->maximum; |
568 | case V4L2_CID_GAIN: | 469 | mt9t031->exposure->val = |
569 | ctrl->value = mt9t031->gain; | 470 | (shutter_max / 2 + (mt9t031->total_h - 1) * (max - min)) |
570 | break; | 471 | / shutter_max + min; |
571 | case V4L2_CID_EXPOSURE: | ||
572 | ctrl->value = mt9t031->exposure; | ||
573 | break; | 472 | break; |
574 | } | 473 | } |
575 | return 0; | 474 | return 0; |
576 | } | 475 | } |
577 | 476 | ||
578 | static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 477 | static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl) |
579 | { | 478 | { |
479 | struct mt9t031 *mt9t031 = container_of(ctrl->handler, | ||
480 | struct mt9t031, hdl); | ||
481 | struct v4l2_subdev *sd = &mt9t031->subdev; | ||
580 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 482 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
581 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 483 | struct v4l2_ctrl *exp = mt9t031->exposure; |
582 | const struct v4l2_queryctrl *qctrl; | ||
583 | int data; | 484 | int data; |
584 | 485 | ||
585 | switch (ctrl->id) { | 486 | switch (ctrl->id) { |
586 | case V4L2_CID_VFLIP: | 487 | case V4L2_CID_VFLIP: |
587 | if (ctrl->value) | 488 | if (ctrl->val) |
588 | data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); | 489 | data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); |
589 | else | 490 | else |
590 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); | 491 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); |
591 | if (data < 0) | 492 | if (data < 0) |
592 | return -EIO; | 493 | return -EIO; |
593 | break; | 494 | return 0; |
594 | case V4L2_CID_HFLIP: | 495 | case V4L2_CID_HFLIP: |
595 | if (ctrl->value) | 496 | if (ctrl->val) |
596 | data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); | 497 | data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); |
597 | else | 498 | else |
598 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); | 499 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); |
599 | if (data < 0) | 500 | if (data < 0) |
600 | return -EIO; | 501 | return -EIO; |
601 | break; | 502 | return 0; |
602 | case V4L2_CID_GAIN: | 503 | case V4L2_CID_GAIN: |
603 | qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN]; | ||
604 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | ||
605 | return -EINVAL; | ||
606 | /* See Datasheet Table 7, Gain settings. */ | 504 | /* See Datasheet Table 7, Gain settings. */ |
607 | if (ctrl->value <= qctrl->default_value) { | 505 | if (ctrl->val <= ctrl->default_value) { |
608 | /* Pack it into 0..1 step 0.125, register values 0..8 */ | 506 | /* Pack it into 0..1 step 0.125, register values 0..8 */ |
609 | unsigned long range = qctrl->default_value - qctrl->minimum; | 507 | unsigned long range = ctrl->default_value - ctrl->minimum; |
610 | data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; | 508 | data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range; |
611 | 509 | ||
612 | dev_dbg(&client->dev, "Setting gain %d\n", data); | 510 | dev_dbg(&client->dev, "Setting gain %d\n", data); |
613 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); | 511 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); |
@@ -616,9 +514,9 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
616 | } else { | 514 | } else { |
617 | /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ | 515 | /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ |
618 | /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ | 516 | /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ |
619 | unsigned long range = qctrl->maximum - qctrl->default_value - 1; | 517 | unsigned long range = ctrl->maximum - ctrl->default_value - 1; |
620 | /* calculated gain: map 65..127 to 9..1024 step 0.125 */ | 518 | /* calculated gain: map 65..127 to 9..1024 step 0.125 */ |
621 | unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * | 519 | unsigned long gain = ((ctrl->val - ctrl->default_value - 1) * |
622 | 1015 + range / 2) / range + 9; | 520 | 1015 + range / 2) / range + 9; |
623 | 521 | ||
624 | if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ | 522 | if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ |
@@ -635,19 +533,13 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
635 | if (data < 0) | 533 | if (data < 0) |
636 | return -EIO; | 534 | return -EIO; |
637 | } | 535 | } |
536 | return 0; | ||
638 | 537 | ||
639 | /* Success */ | 538 | case V4L2_CID_EXPOSURE_AUTO: |
640 | mt9t031->gain = ctrl->value; | 539 | if (ctrl->val == V4L2_EXPOSURE_MANUAL) { |
641 | break; | 540 | unsigned int range = exp->maximum - exp->minimum; |
642 | case V4L2_CID_EXPOSURE: | 541 | unsigned int shutter = ((exp->val - exp->minimum) * 1048 + |
643 | qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; | 542 | range / 2) / range + 1; |
644 | /* mt9t031 has maximum == default */ | ||
645 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | ||
646 | return -EINVAL; | ||
647 | else { | ||
648 | const unsigned long range = qctrl->maximum - qctrl->minimum; | ||
649 | const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 + | ||
650 | range / 2) / range + 1; | ||
651 | u32 old; | 543 | u32 old; |
652 | 544 | ||
653 | get_shutter(client, &old); | 545 | get_shutter(client, &old); |
@@ -655,27 +547,15 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
655 | old, shutter); | 547 | old, shutter); |
656 | if (set_shutter(client, shutter) < 0) | 548 | if (set_shutter(client, shutter) < 0) |
657 | return -EIO; | 549 | return -EIO; |
658 | mt9t031->exposure = ctrl->value; | 550 | } else { |
659 | mt9t031->autoexposure = 0; | ||
660 | } | ||
661 | break; | ||
662 | case V4L2_CID_EXPOSURE_AUTO: | ||
663 | if (ctrl->value) { | ||
664 | const u16 vblank = MT9T031_VERTICAL_BLANK; | 551 | const u16 vblank = MT9T031_VERTICAL_BLANK; |
665 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | 552 | mt9t031->total_h = mt9t031->rect.height + |
666 | unsigned int total_h = mt9t031->rect.height + | ||
667 | mt9t031->y_skip_top + vblank; | 553 | mt9t031->y_skip_top + vblank; |
668 | 554 | ||
669 | if (set_shutter(client, total_h) < 0) | 555 | if (set_shutter(client, mt9t031->total_h) < 0) |
670 | return -EIO; | 556 | return -EIO; |
671 | qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; | 557 | } |
672 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * | 558 | return 0; |
673 | (qctrl->maximum - qctrl->minimum)) / | ||
674 | shutter_max + qctrl->minimum; | ||
675 | mt9t031->autoexposure = 1; | ||
676 | } else | ||
677 | mt9t031->autoexposure = 0; | ||
678 | break; | ||
679 | default: | 559 | default: |
680 | return -EINVAL; | 560 | return -EINVAL; |
681 | } | 561 | } |
@@ -700,8 +580,7 @@ static int mt9t031_runtime_suspend(struct device *dev) | |||
700 | static int mt9t031_runtime_resume(struct device *dev) | 580 | static int mt9t031_runtime_resume(struct device *dev) |
701 | { | 581 | { |
702 | struct video_device *vdev = to_video_device(dev); | 582 | struct video_device *vdev = to_video_device(dev); |
703 | struct soc_camera_device *icd = dev_get_drvdata(vdev->parent); | 583 | struct v4l2_subdev *sd = soc_camera_vdev_to_subdev(vdev); |
704 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
705 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 584 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
706 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 585 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
707 | 586 | ||
@@ -734,6 +613,19 @@ static struct device_type mt9t031_dev_type = { | |||
734 | .pm = &mt9t031_dev_pm_ops, | 613 | .pm = &mt9t031_dev_pm_ops, |
735 | }; | 614 | }; |
736 | 615 | ||
616 | static int mt9t031_s_power(struct v4l2_subdev *sd, int on) | ||
617 | { | ||
618 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
619 | struct video_device *vdev = soc_camera_i2c_to_vdev(client); | ||
620 | |||
621 | if (on) | ||
622 | vdev->dev.type = &mt9t031_dev_type; | ||
623 | else | ||
624 | vdev->dev.type = NULL; | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
737 | /* | 629 | /* |
738 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 630 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
739 | * this wasn't our capture interface, so, we wait for the right one | 631 | * this wasn't our capture interface, so, we wait for the right one |
@@ -741,7 +633,6 @@ static struct device_type mt9t031_dev_type = { | |||
741 | static int mt9t031_video_probe(struct i2c_client *client) | 633 | static int mt9t031_video_probe(struct i2c_client *client) |
742 | { | 634 | { |
743 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 635 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
744 | struct video_device *vdev = soc_camera_i2c_to_vdev(client); | ||
745 | s32 data; | 636 | s32 data; |
746 | int ret; | 637 | int ret; |
747 | 638 | ||
@@ -768,11 +659,7 @@ static int mt9t031_video_probe(struct i2c_client *client) | |||
768 | if (ret < 0) | 659 | if (ret < 0) |
769 | dev_err(&client->dev, "Failed to initialise the camera\n"); | 660 | dev_err(&client->dev, "Failed to initialise the camera\n"); |
770 | else | 661 | else |
771 | vdev->dev.type = &mt9t031_dev_type; | 662 | v4l2_ctrl_handler_setup(&mt9t031->hdl); |
772 | |||
773 | /* mt9t031_idle() has reset the chip to default. */ | ||
774 | mt9t031->exposure = 255; | ||
775 | mt9t031->gain = 64; | ||
776 | 663 | ||
777 | return ret; | 664 | return ret; |
778 | } | 665 | } |
@@ -787,10 +674,14 @@ static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | |||
787 | return 0; | 674 | return 0; |
788 | } | 675 | } |
789 | 676 | ||
677 | static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = { | ||
678 | .g_volatile_ctrl = mt9t031_g_volatile_ctrl, | ||
679 | .s_ctrl = mt9t031_s_ctrl, | ||
680 | }; | ||
681 | |||
790 | static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { | 682 | static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { |
791 | .g_ctrl = mt9t031_g_ctrl, | ||
792 | .s_ctrl = mt9t031_s_ctrl, | ||
793 | .g_chip_ident = mt9t031_g_chip_ident, | 683 | .g_chip_ident = mt9t031_g_chip_ident, |
684 | .s_power = mt9t031_s_power, | ||
794 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 685 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
795 | .g_register = mt9t031_g_register, | 686 | .g_register = mt9t031_g_register, |
796 | .s_register = mt9t031_s_register, | 687 | .s_register = mt9t031_s_register, |
@@ -807,6 +698,34 @@ static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
807 | return 0; | 698 | return 0; |
808 | } | 699 | } |
809 | 700 | ||
701 | static int mt9t031_g_mbus_config(struct v4l2_subdev *sd, | ||
702 | struct v4l2_mbus_config *cfg) | ||
703 | { | ||
704 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
705 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
706 | |||
707 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
708 | V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
709 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
710 | cfg->type = V4L2_MBUS_PARALLEL; | ||
711 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, | ||
717 | const struct v4l2_mbus_config *cfg) | ||
718 | { | ||
719 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
720 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
721 | |||
722 | if (soc_camera_apply_board_flags(icl, cfg) & | ||
723 | V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
724 | return reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); | ||
725 | else | ||
726 | return reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); | ||
727 | } | ||
728 | |||
810 | static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { | 729 | static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { |
811 | .s_stream = mt9t031_s_stream, | 730 | .s_stream = mt9t031_s_stream, |
812 | .s_mbus_fmt = mt9t031_s_fmt, | 731 | .s_mbus_fmt = mt9t031_s_fmt, |
@@ -816,6 +735,8 @@ static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { | |||
816 | .g_crop = mt9t031_g_crop, | 735 | .g_crop = mt9t031_g_crop, |
817 | .cropcap = mt9t031_cropcap, | 736 | .cropcap = mt9t031_cropcap, |
818 | .enum_mbus_fmt = mt9t031_enum_fmt, | 737 | .enum_mbus_fmt = mt9t031_enum_fmt, |
738 | .g_mbus_config = mt9t031_g_mbus_config, | ||
739 | .s_mbus_config = mt9t031_s_mbus_config, | ||
819 | }; | 740 | }; |
820 | 741 | ||
821 | static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { | 742 | static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { |
@@ -832,18 +753,13 @@ static int mt9t031_probe(struct i2c_client *client, | |||
832 | const struct i2c_device_id *did) | 753 | const struct i2c_device_id *did) |
833 | { | 754 | { |
834 | struct mt9t031 *mt9t031; | 755 | struct mt9t031 *mt9t031; |
835 | struct soc_camera_device *icd = client->dev.platform_data; | 756 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
836 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 757 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
837 | int ret; | 758 | int ret; |
838 | 759 | ||
839 | if (icd) { | 760 | if (!icl) { |
840 | struct soc_camera_link *icl = to_soc_camera_link(icd); | 761 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); |
841 | if (!icl) { | 762 | return -EINVAL; |
842 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); | ||
843 | return -EINVAL; | ||
844 | } | ||
845 | |||
846 | icd->ops = &mt9t031_ops; | ||
847 | } | 763 | } |
848 | 764 | ||
849 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { | 765 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { |
@@ -857,6 +773,33 @@ static int mt9t031_probe(struct i2c_client *client, | |||
857 | return -ENOMEM; | 773 | return -ENOMEM; |
858 | 774 | ||
859 | v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); | 775 | v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); |
776 | v4l2_ctrl_handler_init(&mt9t031->hdl, 5); | ||
777 | v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
778 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
779 | v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
780 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
781 | v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
782 | V4L2_CID_GAIN, 0, 127, 1, 64); | ||
783 | |||
784 | /* | ||
785 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
786 | * ourselves in the driver based on vertical blanking and frame width | ||
787 | */ | ||
788 | mt9t031->autoexposure = v4l2_ctrl_new_std_menu(&mt9t031->hdl, | ||
789 | &mt9t031_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
790 | V4L2_EXPOSURE_AUTO); | ||
791 | mt9t031->exposure = v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
792 | V4L2_CID_EXPOSURE, 1, 255, 1, 255); | ||
793 | |||
794 | mt9t031->subdev.ctrl_handler = &mt9t031->hdl; | ||
795 | if (mt9t031->hdl.error) { | ||
796 | int err = mt9t031->hdl.error; | ||
797 | |||
798 | kfree(mt9t031); | ||
799 | return err; | ||
800 | } | ||
801 | v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure, | ||
802 | V4L2_EXPOSURE_MANUAL, true); | ||
860 | 803 | ||
861 | mt9t031->y_skip_top = 0; | 804 | mt9t031->y_skip_top = 0; |
862 | mt9t031->rect.left = MT9T031_COLUMN_SKIP; | 805 | mt9t031->rect.left = MT9T031_COLUMN_SKIP; |
@@ -864,12 +807,6 @@ static int mt9t031_probe(struct i2c_client *client, | |||
864 | mt9t031->rect.width = MT9T031_MAX_WIDTH; | 807 | mt9t031->rect.width = MT9T031_MAX_WIDTH; |
865 | mt9t031->rect.height = MT9T031_MAX_HEIGHT; | 808 | mt9t031->rect.height = MT9T031_MAX_HEIGHT; |
866 | 809 | ||
867 | /* | ||
868 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
869 | * ourselves in the driver based on vertical blanking and frame width | ||
870 | */ | ||
871 | mt9t031->autoexposure = 1; | ||
872 | |||
873 | mt9t031->xskip = 1; | 810 | mt9t031->xskip = 1; |
874 | mt9t031->yskip = 1; | 811 | mt9t031->yskip = 1; |
875 | 812 | ||
@@ -880,8 +817,7 @@ static int mt9t031_probe(struct i2c_client *client, | |||
880 | mt9t031_disable(client); | 817 | mt9t031_disable(client); |
881 | 818 | ||
882 | if (ret) { | 819 | if (ret) { |
883 | if (icd) | 820 | v4l2_ctrl_handler_free(&mt9t031->hdl); |
884 | icd->ops = NULL; | ||
885 | kfree(mt9t031); | 821 | kfree(mt9t031); |
886 | } | 822 | } |
887 | 823 | ||
@@ -891,10 +827,9 @@ static int mt9t031_probe(struct i2c_client *client, | |||
891 | static int mt9t031_remove(struct i2c_client *client) | 827 | static int mt9t031_remove(struct i2c_client *client) |
892 | { | 828 | { |
893 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 829 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
894 | struct soc_camera_device *icd = client->dev.platform_data; | ||
895 | 830 | ||
896 | if (icd) | 831 | v4l2_device_unregister_subdev(&mt9t031->subdev); |
897 | icd->ops = NULL; | 832 | v4l2_ctrl_handler_free(&mt9t031->hdl); |
898 | kfree(mt9t031); | 833 | kfree(mt9t031); |
899 | 834 | ||
900 | return 0; | 835 | return 0; |
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index d2e0a50063a2..32114a3c0ca7 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c | |||
@@ -22,11 +22,11 @@ | |||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/v4l2-mediabus.h> | ||
25 | #include <linux/videodev2.h> | 26 | #include <linux/videodev2.h> |
26 | 27 | ||
27 | #include <media/mt9t112.h> | 28 | #include <media/mt9t112.h> |
28 | #include <media/soc_camera.h> | 29 | #include <media/soc_camera.h> |
29 | #include <media/soc_mediabus.h> | ||
30 | #include <media/v4l2-chip-ident.h> | 30 | #include <media/v4l2-chip-ident.h> |
31 | #include <media/v4l2-common.h> | 31 | #include <media/v4l2-common.h> |
32 | 32 | ||
@@ -34,11 +34,7 @@ | |||
34 | /* #define EXT_CLOCK 24000000 */ | 34 | /* #define EXT_CLOCK 24000000 */ |
35 | 35 | ||
36 | /************************************************************************ | 36 | /************************************************************************ |
37 | |||
38 | |||
39 | macro | 37 | macro |
40 | |||
41 | |||
42 | ************************************************************************/ | 38 | ************************************************************************/ |
43 | /* | 39 | /* |
44 | * frame size | 40 | * frame size |
@@ -80,17 +76,8 @@ | |||
80 | #define VAR8(id, offset) _VAR(id, offset, 0x8000) | 76 | #define VAR8(id, offset) _VAR(id, offset, 0x8000) |
81 | 77 | ||
82 | /************************************************************************ | 78 | /************************************************************************ |
83 | |||
84 | |||
85 | struct | 79 | struct |
86 | |||
87 | |||
88 | ************************************************************************/ | 80 | ************************************************************************/ |
89 | struct mt9t112_frame_size { | ||
90 | u16 width; | ||
91 | u16 height; | ||
92 | }; | ||
93 | |||
94 | struct mt9t112_format { | 81 | struct mt9t112_format { |
95 | enum v4l2_mbus_pixelcode code; | 82 | enum v4l2_mbus_pixelcode code; |
96 | enum v4l2_colorspace colorspace; | 83 | enum v4l2_colorspace colorspace; |
@@ -102,21 +89,17 @@ struct mt9t112_priv { | |||
102 | struct v4l2_subdev subdev; | 89 | struct v4l2_subdev subdev; |
103 | struct mt9t112_camera_info *info; | 90 | struct mt9t112_camera_info *info; |
104 | struct i2c_client *client; | 91 | struct i2c_client *client; |
105 | struct soc_camera_device icd; | 92 | struct v4l2_rect frame; |
106 | struct mt9t112_frame_size frame; | ||
107 | const struct mt9t112_format *format; | 93 | const struct mt9t112_format *format; |
108 | int model; | 94 | int model; |
109 | u32 flags; | 95 | u32 flags; |
110 | /* for flags */ | 96 | /* for flags */ |
111 | #define INIT_DONE (1<<0) | 97 | #define INIT_DONE (1 << 0) |
98 | #define PCLK_RISING (1 << 1) | ||
112 | }; | 99 | }; |
113 | 100 | ||
114 | /************************************************************************ | 101 | /************************************************************************ |
115 | |||
116 | |||
117 | supported format | 102 | supported format |
118 | |||
119 | |||
120 | ************************************************************************/ | 103 | ************************************************************************/ |
121 | 104 | ||
122 | static const struct mt9t112_format mt9t112_cfmts[] = { | 105 | static const struct mt9t112_format mt9t112_cfmts[] = { |
@@ -154,11 +137,7 @@ static const struct mt9t112_format mt9t112_cfmts[] = { | |||
154 | }; | 137 | }; |
155 | 138 | ||
156 | /************************************************************************ | 139 | /************************************************************************ |
157 | |||
158 | |||
159 | general function | 140 | general function |
160 | |||
161 | |||
162 | ************************************************************************/ | 141 | ************************************************************************/ |
163 | static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) | 142 | static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) |
164 | { | 143 | { |
@@ -326,50 +305,47 @@ static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) | |||
326 | n = (n >> 8) & 0x003f; | 305 | n = (n >> 8) & 0x003f; |
327 | 306 | ||
328 | enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; | 307 | enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; |
329 | dev_info(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); | 308 | dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); |
330 | 309 | ||
331 | vco = 2 * m * ext / (n+1); | 310 | vco = 2 * m * ext / (n+1); |
332 | enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; | 311 | enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; |
333 | dev_info(&client->dev, "VCO : %10u K %s\n", vco, enable); | 312 | dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable); |
334 | 313 | ||
335 | clk = vco / (p1+1) / (p2+1); | 314 | clk = vco / (p1+1) / (p2+1); |
336 | enable = (96000 < clk) ? "X" : ""; | 315 | enable = (96000 < clk) ? "X" : ""; |
337 | dev_info(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); | 316 | dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); |
338 | 317 | ||
339 | clk = vco / (p3+1); | 318 | clk = vco / (p3+1); |
340 | enable = (768000 < clk) ? "X" : ""; | 319 | enable = (768000 < clk) ? "X" : ""; |
341 | dev_info(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); | 320 | dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); |
342 | 321 | ||
343 | clk = vco / (p6+1); | 322 | clk = vco / (p6+1); |
344 | enable = (96000 < clk) ? "X" : ""; | 323 | enable = (96000 < clk) ? "X" : ""; |
345 | dev_info(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); | 324 | dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); |
346 | 325 | ||
347 | clk = vco / (p5+1); | 326 | clk = vco / (p5+1); |
348 | enable = (54000 < clk) ? "X" : ""; | 327 | enable = (54000 < clk) ? "X" : ""; |
349 | dev_info(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); | 328 | dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); |
350 | 329 | ||
351 | clk = vco / (p4+1); | 330 | clk = vco / (p4+1); |
352 | enable = (70000 < clk) ? "X" : ""; | 331 | enable = (70000 < clk) ? "X" : ""; |
353 | dev_info(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); | 332 | dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); |
354 | 333 | ||
355 | clk = vco / (p7+1); | 334 | clk = vco / (p7+1); |
356 | dev_info(&client->dev, "External sensor : %10u K\n", clk); | 335 | dev_dbg(&client->dev, "External sensor : %10u K\n", clk); |
357 | 336 | ||
358 | clk = ext / (n+1); | 337 | clk = ext / (n+1); |
359 | enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; | 338 | enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; |
360 | dev_info(&client->dev, "PFD : %10u K %s\n", clk, enable); | 339 | dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable); |
361 | 340 | ||
362 | return 0; | 341 | return 0; |
363 | } | 342 | } |
364 | #endif | 343 | #endif |
365 | 344 | ||
366 | static void mt9t112_frame_check(u32 *width, u32 *height) | 345 | static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top) |
367 | { | 346 | { |
368 | if (*width > MAX_WIDTH) | 347 | soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH); |
369 | *width = MAX_WIDTH; | 348 | soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT); |
370 | |||
371 | if (*height > MAX_HEIGHT) | ||
372 | *height = MAX_HEIGHT; | ||
373 | } | 349 | } |
374 | 350 | ||
375 | static int mt9t112_set_a_frame_size(const struct i2c_client *client, | 351 | static int mt9t112_set_a_frame_size(const struct i2c_client *client, |
@@ -758,48 +734,7 @@ static int mt9t112_init_camera(const struct i2c_client *client) | |||
758 | } | 734 | } |
759 | 735 | ||
760 | /************************************************************************ | 736 | /************************************************************************ |
761 | |||
762 | |||
763 | soc_camera_ops | ||
764 | |||
765 | |||
766 | ************************************************************************/ | ||
767 | static int mt9t112_set_bus_param(struct soc_camera_device *icd, | ||
768 | unsigned long flags) | ||
769 | { | ||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | static unsigned long mt9t112_query_bus_param(struct soc_camera_device *icd) | ||
774 | { | ||
775 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
776 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
777 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
778 | unsigned long flags = SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | | ||
779 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH; | ||
780 | |||
781 | flags |= (priv->info->flags & MT9T112_FLAG_PCLK_RISING_EDGE) ? | ||
782 | SOCAM_PCLK_SAMPLE_RISING : SOCAM_PCLK_SAMPLE_FALLING; | ||
783 | |||
784 | if (priv->info->flags & MT9T112_FLAG_DATAWIDTH_8) | ||
785 | flags |= SOCAM_DATAWIDTH_8; | ||
786 | else | ||
787 | flags |= SOCAM_DATAWIDTH_10; | ||
788 | |||
789 | return soc_camera_apply_sensor_flags(icl, flags); | ||
790 | } | ||
791 | |||
792 | static struct soc_camera_ops mt9t112_ops = { | ||
793 | .set_bus_param = mt9t112_set_bus_param, | ||
794 | .query_bus_param = mt9t112_query_bus_param, | ||
795 | }; | ||
796 | |||
797 | /************************************************************************ | ||
798 | |||
799 | |||
800 | v4l2_subdev_core_ops | 737 | v4l2_subdev_core_ops |
801 | |||
802 | |||
803 | ************************************************************************/ | 738 | ************************************************************************/ |
804 | static int mt9t112_g_chip_ident(struct v4l2_subdev *sd, | 739 | static int mt9t112_g_chip_ident(struct v4l2_subdev *sd, |
805 | struct v4l2_dbg_chip_ident *id) | 740 | struct v4l2_dbg_chip_ident *id) |
@@ -850,11 +785,7 @@ static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { | |||
850 | 785 | ||
851 | 786 | ||
852 | /************************************************************************ | 787 | /************************************************************************ |
853 | |||
854 | |||
855 | v4l2_subdev_video_ops | 788 | v4l2_subdev_video_ops |
856 | |||
857 | |||
858 | ************************************************************************/ | 789 | ************************************************************************/ |
859 | static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) | 790 | static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) |
860 | { | 791 | { |
@@ -877,8 +808,7 @@ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) | |||
877 | } | 808 | } |
878 | 809 | ||
879 | if (!(priv->flags & INIT_DONE)) { | 810 | if (!(priv->flags & INIT_DONE)) { |
880 | u16 param = (MT9T112_FLAG_PCLK_RISING_EDGE & | 811 | u16 param = PCLK_RISING & priv->flags ? 0x0001 : 0x0000; |
881 | priv->info->flags) ? 0x0001 : 0x0000; | ||
882 | 812 | ||
883 | ECHECKER(ret, mt9t112_init_camera(client)); | 813 | ECHECKER(ret, mt9t112_init_camera(client)); |
884 | 814 | ||
@@ -910,19 +840,12 @@ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) | |||
910 | return ret; | 840 | return ret; |
911 | } | 841 | } |
912 | 842 | ||
913 | static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height, | 843 | static int mt9t112_set_params(struct mt9t112_priv *priv, |
844 | const struct v4l2_rect *rect, | ||
914 | enum v4l2_mbus_pixelcode code) | 845 | enum v4l2_mbus_pixelcode code) |
915 | { | 846 | { |
916 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
917 | int i; | 847 | int i; |
918 | 848 | ||
919 | priv->format = NULL; | ||
920 | |||
921 | /* | ||
922 | * frame size check | ||
923 | */ | ||
924 | mt9t112_frame_check(&width, &height); | ||
925 | |||
926 | /* | 849 | /* |
927 | * get color format | 850 | * get color format |
928 | */ | 851 | */ |
@@ -933,8 +856,13 @@ static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height, | |||
933 | if (i == ARRAY_SIZE(mt9t112_cfmts)) | 856 | if (i == ARRAY_SIZE(mt9t112_cfmts)) |
934 | return -EINVAL; | 857 | return -EINVAL; |
935 | 858 | ||
936 | priv->frame.width = (u16)width; | 859 | priv->frame = *rect; |
937 | priv->frame.height = (u16)height; | 860 | |
861 | /* | ||
862 | * frame size check | ||
863 | */ | ||
864 | mt9t112_frame_check(&priv->frame.width, &priv->frame.height, | ||
865 | &priv->frame.left, &priv->frame.top); | ||
938 | 866 | ||
939 | priv->format = mt9t112_cfmts + i; | 867 | priv->format = mt9t112_cfmts + i; |
940 | 868 | ||
@@ -945,9 +873,12 @@ static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
945 | { | 873 | { |
946 | a->bounds.left = 0; | 874 | a->bounds.left = 0; |
947 | a->bounds.top = 0; | 875 | a->bounds.top = 0; |
948 | a->bounds.width = VGA_WIDTH; | 876 | a->bounds.width = MAX_WIDTH; |
949 | a->bounds.height = VGA_HEIGHT; | 877 | a->bounds.height = MAX_HEIGHT; |
950 | a->defrect = a->bounds; | 878 | a->defrect.left = 0; |
879 | a->defrect.top = 0; | ||
880 | a->defrect.width = VGA_WIDTH; | ||
881 | a->defrect.height = VGA_HEIGHT; | ||
951 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 882 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
952 | a->pixelaspect.numerator = 1; | 883 | a->pixelaspect.numerator = 1; |
953 | a->pixelaspect.denominator = 1; | 884 | a->pixelaspect.denominator = 1; |
@@ -957,11 +888,11 @@ static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
957 | 888 | ||
958 | static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 889 | static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
959 | { | 890 | { |
960 | a->c.left = 0; | 891 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
961 | a->c.top = 0; | 892 | struct mt9t112_priv *priv = to_mt9t112(client); |
962 | a->c.width = VGA_WIDTH; | 893 | |
963 | a->c.height = VGA_HEIGHT; | 894 | a->c = priv->frame; |
964 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 895 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
965 | 896 | ||
966 | return 0; | 897 | return 0; |
967 | } | 898 | } |
@@ -969,10 +900,10 @@ static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
969 | static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 900 | static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
970 | { | 901 | { |
971 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 902 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
903 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
972 | struct v4l2_rect *rect = &a->c; | 904 | struct v4l2_rect *rect = &a->c; |
973 | 905 | ||
974 | return mt9t112_set_params(client, rect->width, rect->height, | 906 | return mt9t112_set_params(priv, rect, priv->format->code); |
975 | V4L2_MBUS_FMT_UYVY8_2X8); | ||
976 | } | 907 | } |
977 | 908 | ||
978 | static int mt9t112_g_fmt(struct v4l2_subdev *sd, | 909 | static int mt9t112_g_fmt(struct v4l2_subdev *sd, |
@@ -981,16 +912,9 @@ static int mt9t112_g_fmt(struct v4l2_subdev *sd, | |||
981 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 912 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
982 | struct mt9t112_priv *priv = to_mt9t112(client); | 913 | struct mt9t112_priv *priv = to_mt9t112(client); |
983 | 914 | ||
984 | if (!priv->format) { | ||
985 | int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT, | ||
986 | V4L2_MBUS_FMT_UYVY8_2X8); | ||
987 | if (ret < 0) | ||
988 | return ret; | ||
989 | } | ||
990 | |||
991 | mf->width = priv->frame.width; | 915 | mf->width = priv->frame.width; |
992 | mf->height = priv->frame.height; | 916 | mf->height = priv->frame.height; |
993 | /* TODO: set colorspace */ | 917 | mf->colorspace = priv->format->colorspace; |
994 | mf->code = priv->format->code; | 918 | mf->code = priv->format->code; |
995 | mf->field = V4L2_FIELD_NONE; | 919 | mf->field = V4L2_FIELD_NONE; |
996 | 920 | ||
@@ -1001,17 +925,42 @@ static int mt9t112_s_fmt(struct v4l2_subdev *sd, | |||
1001 | struct v4l2_mbus_framefmt *mf) | 925 | struct v4l2_mbus_framefmt *mf) |
1002 | { | 926 | { |
1003 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 927 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
928 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
929 | struct v4l2_rect rect = { | ||
930 | .width = mf->width, | ||
931 | .height = mf->height, | ||
932 | .left = priv->frame.left, | ||
933 | .top = priv->frame.top, | ||
934 | }; | ||
935 | int ret; | ||
936 | |||
937 | ret = mt9t112_set_params(priv, &rect, mf->code); | ||
938 | |||
939 | if (!ret) | ||
940 | mf->colorspace = priv->format->colorspace; | ||
1004 | 941 | ||
1005 | /* TODO: set colorspace */ | 942 | return ret; |
1006 | return mt9t112_set_params(client, mf->width, mf->height, mf->code); | ||
1007 | } | 943 | } |
1008 | 944 | ||
1009 | static int mt9t112_try_fmt(struct v4l2_subdev *sd, | 945 | static int mt9t112_try_fmt(struct v4l2_subdev *sd, |
1010 | struct v4l2_mbus_framefmt *mf) | 946 | struct v4l2_mbus_framefmt *mf) |
1011 | { | 947 | { |
1012 | mt9t112_frame_check(&mf->width, &mf->height); | 948 | unsigned int top, left; |
949 | int i; | ||
950 | |||
951 | for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++) | ||
952 | if (mt9t112_cfmts[i].code == mf->code) | ||
953 | break; | ||
954 | |||
955 | if (i == ARRAY_SIZE(mt9t112_cfmts)) { | ||
956 | mf->code = V4L2_MBUS_FMT_UYVY8_2X8; | ||
957 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
958 | } else { | ||
959 | mf->colorspace = mt9t112_cfmts[i].colorspace; | ||
960 | } | ||
961 | |||
962 | mt9t112_frame_check(&mf->width, &mf->height, &left, &top); | ||
1013 | 963 | ||
1014 | /* TODO: set colorspace */ | ||
1015 | mf->field = V4L2_FIELD_NONE; | 964 | mf->field = V4L2_FIELD_NONE; |
1016 | 965 | ||
1017 | return 0; | 966 | return 0; |
@@ -1024,6 +973,35 @@ static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
1024 | return -EINVAL; | 973 | return -EINVAL; |
1025 | 974 | ||
1026 | *code = mt9t112_cfmts[index].code; | 975 | *code = mt9t112_cfmts[index].code; |
976 | |||
977 | return 0; | ||
978 | } | ||
979 | |||
980 | static int mt9t112_g_mbus_config(struct v4l2_subdev *sd, | ||
981 | struct v4l2_mbus_config *cfg) | ||
982 | { | ||
983 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
984 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
985 | |||
986 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
987 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | | ||
988 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
989 | cfg->type = V4L2_MBUS_PARALLEL; | ||
990 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
991 | |||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, | ||
996 | const struct v4l2_mbus_config *cfg) | ||
997 | { | ||
998 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
999 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
1000 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
1001 | |||
1002 | if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) | ||
1003 | priv->flags |= PCLK_RISING; | ||
1004 | |||
1027 | return 0; | 1005 | return 0; |
1028 | } | 1006 | } |
1029 | 1007 | ||
@@ -1036,31 +1014,24 @@ static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { | |||
1036 | .g_crop = mt9t112_g_crop, | 1014 | .g_crop = mt9t112_g_crop, |
1037 | .s_crop = mt9t112_s_crop, | 1015 | .s_crop = mt9t112_s_crop, |
1038 | .enum_mbus_fmt = mt9t112_enum_fmt, | 1016 | .enum_mbus_fmt = mt9t112_enum_fmt, |
1017 | .g_mbus_config = mt9t112_g_mbus_config, | ||
1018 | .s_mbus_config = mt9t112_s_mbus_config, | ||
1039 | }; | 1019 | }; |
1040 | 1020 | ||
1041 | /************************************************************************ | 1021 | /************************************************************************ |
1042 | |||
1043 | |||
1044 | i2c driver | 1022 | i2c driver |
1045 | |||
1046 | |||
1047 | ************************************************************************/ | 1023 | ************************************************************************/ |
1048 | static struct v4l2_subdev_ops mt9t112_subdev_ops = { | 1024 | static struct v4l2_subdev_ops mt9t112_subdev_ops = { |
1049 | .core = &mt9t112_subdev_core_ops, | 1025 | .core = &mt9t112_subdev_core_ops, |
1050 | .video = &mt9t112_subdev_video_ops, | 1026 | .video = &mt9t112_subdev_video_ops, |
1051 | }; | 1027 | }; |
1052 | 1028 | ||
1053 | static int mt9t112_camera_probe(struct soc_camera_device *icd, | 1029 | static int mt9t112_camera_probe(struct i2c_client *client) |
1054 | struct i2c_client *client) | ||
1055 | { | 1030 | { |
1056 | struct mt9t112_priv *priv = to_mt9t112(client); | 1031 | struct mt9t112_priv *priv = to_mt9t112(client); |
1057 | const char *devname; | 1032 | const char *devname; |
1058 | int chipid; | 1033 | int chipid; |
1059 | 1034 | ||
1060 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
1061 | BUG_ON(!icd->parent || | ||
1062 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
1063 | |||
1064 | /* | 1035 | /* |
1065 | * check and show chip ID | 1036 | * check and show chip ID |
1066 | */ | 1037 | */ |
@@ -1088,20 +1059,21 @@ static int mt9t112_camera_probe(struct soc_camera_device *icd, | |||
1088 | static int mt9t112_probe(struct i2c_client *client, | 1059 | static int mt9t112_probe(struct i2c_client *client, |
1089 | const struct i2c_device_id *did) | 1060 | const struct i2c_device_id *did) |
1090 | { | 1061 | { |
1091 | struct mt9t112_priv *priv; | 1062 | struct mt9t112_priv *priv; |
1092 | struct soc_camera_device *icd = client->dev.platform_data; | 1063 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
1093 | struct soc_camera_link *icl; | 1064 | struct v4l2_rect rect = { |
1094 | int ret; | 1065 | .width = VGA_WIDTH, |
1066 | .height = VGA_HEIGHT, | ||
1067 | .left = (MAX_WIDTH - VGA_WIDTH) / 2, | ||
1068 | .top = (MAX_HEIGHT - VGA_HEIGHT) / 2, | ||
1069 | }; | ||
1070 | int ret; | ||
1095 | 1071 | ||
1096 | if (!icd) { | 1072 | if (!icl || !icl->priv) { |
1097 | dev_err(&client->dev, "mt9t112: missing soc-camera data!\n"); | 1073 | dev_err(&client->dev, "mt9t112: missing platform data!\n"); |
1098 | return -EINVAL; | 1074 | return -EINVAL; |
1099 | } | 1075 | } |
1100 | 1076 | ||
1101 | icl = to_soc_camera_link(icd); | ||
1102 | if (!icl || !icl->priv) | ||
1103 | return -EINVAL; | ||
1104 | |||
1105 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 1077 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
1106 | if (!priv) | 1078 | if (!priv) |
1107 | return -ENOMEM; | 1079 | return -ENOMEM; |
@@ -1110,13 +1082,12 @@ static int mt9t112_probe(struct i2c_client *client, | |||
1110 | 1082 | ||
1111 | v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); | 1083 | v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); |
1112 | 1084 | ||
1113 | icd->ops = &mt9t112_ops; | 1085 | ret = mt9t112_camera_probe(client); |
1114 | 1086 | if (ret) | |
1115 | ret = mt9t112_camera_probe(icd, client); | ||
1116 | if (ret) { | ||
1117 | icd->ops = NULL; | ||
1118 | kfree(priv); | 1087 | kfree(priv); |
1119 | } | 1088 | |
1089 | /* Cannot fail: using the default supported pixel code */ | ||
1090 | mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8); | ||
1120 | 1091 | ||
1121 | return ret; | 1092 | return ret; |
1122 | } | 1093 | } |
@@ -1124,9 +1095,7 @@ static int mt9t112_probe(struct i2c_client *client, | |||
1124 | static int mt9t112_remove(struct i2c_client *client) | 1095 | static int mt9t112_remove(struct i2c_client *client) |
1125 | { | 1096 | { |
1126 | struct mt9t112_priv *priv = to_mt9t112(client); | 1097 | struct mt9t112_priv *priv = to_mt9t112(client); |
1127 | struct soc_camera_device *icd = client->dev.platform_data; | ||
1128 | 1098 | ||
1129 | icd->ops = NULL; | ||
1130 | kfree(priv); | 1099 | kfree(priv); |
1131 | return 0; | 1100 | return 0; |
1132 | } | 1101 | } |
@@ -1147,11 +1116,7 @@ static struct i2c_driver mt9t112_i2c_driver = { | |||
1147 | }; | 1116 | }; |
1148 | 1117 | ||
1149 | /************************************************************************ | 1118 | /************************************************************************ |
1150 | |||
1151 | |||
1152 | module function | 1119 | module function |
1153 | |||
1154 | |||
1155 | ************************************************************************/ | 1120 | ************************************************************************/ |
1156 | static int __init mt9t112_module_init(void) | 1121 | static int __init mt9t112_module_init(void) |
1157 | { | 1122 | { |
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 51b0fccbfe70..b6a29f7de82c 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
@@ -14,9 +14,11 @@ | |||
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/log2.h> | 15 | #include <linux/log2.h> |
16 | 16 | ||
17 | #include <media/soc_camera.h> | ||
18 | #include <media/soc_mediabus.h> | ||
17 | #include <media/v4l2-subdev.h> | 19 | #include <media/v4l2-subdev.h> |
18 | #include <media/v4l2-chip-ident.h> | 20 | #include <media/v4l2-chip-ident.h> |
19 | #include <media/soc_camera.h> | 21 | #include <media/v4l2-ctrls.h> |
20 | 22 | ||
21 | /* | 23 | /* |
22 | * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c | 24 | * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c |
@@ -100,6 +102,17 @@ static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { | |||
100 | 102 | ||
101 | struct mt9v022 { | 103 | struct mt9v022 { |
102 | struct v4l2_subdev subdev; | 104 | struct v4l2_subdev subdev; |
105 | struct v4l2_ctrl_handler hdl; | ||
106 | struct { | ||
107 | /* exposure/auto-exposure cluster */ | ||
108 | struct v4l2_ctrl *autoexposure; | ||
109 | struct v4l2_ctrl *exposure; | ||
110 | }; | ||
111 | struct { | ||
112 | /* gain/auto-gain cluster */ | ||
113 | struct v4l2_ctrl *autogain; | ||
114 | struct v4l2_ctrl *gain; | ||
115 | }; | ||
103 | struct v4l2_rect rect; /* Sensor window */ | 116 | struct v4l2_rect rect; /* Sensor window */ |
104 | const struct mt9v022_datafmt *fmt; | 117 | const struct mt9v022_datafmt *fmt; |
105 | const struct mt9v022_datafmt *fmts; | 118 | const struct mt9v022_datafmt *fmts; |
@@ -178,6 +191,8 @@ static int mt9v022_init(struct i2c_client *client) | |||
178 | ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); | 191 | ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); |
179 | if (!ret) | 192 | if (!ret) |
180 | ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); | 193 | ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); |
194 | if (!ret) | ||
195 | return v4l2_ctrl_handler_setup(&mt9v022->hdl); | ||
181 | 196 | ||
182 | return ret; | 197 | return ret; |
183 | } | 198 | } |
@@ -199,78 +214,6 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) | |||
199 | return 0; | 214 | return 0; |
200 | } | 215 | } |
201 | 216 | ||
202 | static int mt9v022_set_bus_param(struct soc_camera_device *icd, | ||
203 | unsigned long flags) | ||
204 | { | ||
205 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
206 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
207 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
208 | unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; | ||
209 | int ret; | ||
210 | u16 pixclk = 0; | ||
211 | |||
212 | /* Only one width bit may be set */ | ||
213 | if (!is_power_of_2(width_flag)) | ||
214 | return -EINVAL; | ||
215 | |||
216 | if (icl->set_bus_param) { | ||
217 | ret = icl->set_bus_param(icl, width_flag); | ||
218 | if (ret) | ||
219 | return ret; | ||
220 | } else { | ||
221 | /* | ||
222 | * Without board specific bus width settings we only support the | ||
223 | * sensors native bus width | ||
224 | */ | ||
225 | if (width_flag != SOCAM_DATAWIDTH_10) | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | |||
229 | flags = soc_camera_apply_sensor_flags(icl, flags); | ||
230 | |||
231 | if (flags & SOCAM_PCLK_SAMPLE_FALLING) | ||
232 | pixclk |= 0x10; | ||
233 | |||
234 | if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH)) | ||
235 | pixclk |= 0x1; | ||
236 | |||
237 | if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH)) | ||
238 | pixclk |= 0x2; | ||
239 | |||
240 | ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); | ||
241 | if (ret < 0) | ||
242 | return ret; | ||
243 | |||
244 | if (!(flags & SOCAM_MASTER)) | ||
245 | mt9v022->chip_control &= ~0x8; | ||
246 | |||
247 | ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); | ||
248 | if (ret < 0) | ||
249 | return ret; | ||
250 | |||
251 | dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", | ||
252 | pixclk, mt9v022->chip_control); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) | ||
258 | { | ||
259 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
260 | unsigned int flags = SOCAM_MASTER | SOCAM_SLAVE | | ||
261 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | | ||
262 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | | ||
263 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | | ||
264 | SOCAM_DATA_ACTIVE_HIGH; | ||
265 | |||
266 | if (icl->query_bus_param) | ||
267 | flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; | ||
268 | else | ||
269 | flags |= SOCAM_DATAWIDTH_10; | ||
270 | |||
271 | return soc_camera_apply_sensor_flags(icl, flags); | ||
272 | } | ||
273 | |||
274 | static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 217 | static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
275 | { | 218 | { |
276 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 219 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
@@ -389,7 +332,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, | |||
389 | 332 | ||
390 | /* | 333 | /* |
391 | * The caller provides a supported format, as verified per call to | 334 | * The caller provides a supported format, as verified per call to |
392 | * icd->try_fmt(), datawidth is from our supported format list | 335 | * .try_mbus_fmt(), datawidth is from our supported format list |
393 | */ | 336 | */ |
394 | switch (mf->code) { | 337 | switch (mf->code) { |
395 | case V4L2_MBUS_FMT_Y8_1X8: | 338 | case V4L2_MBUS_FMT_Y8_1X8: |
@@ -502,236 +445,131 @@ static int mt9v022_s_register(struct v4l2_subdev *sd, | |||
502 | } | 445 | } |
503 | #endif | 446 | #endif |
504 | 447 | ||
505 | static const struct v4l2_queryctrl mt9v022_controls[] = { | 448 | static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
506 | { | ||
507 | .id = V4L2_CID_VFLIP, | ||
508 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
509 | .name = "Flip Vertically", | ||
510 | .minimum = 0, | ||
511 | .maximum = 1, | ||
512 | .step = 1, | ||
513 | .default_value = 0, | ||
514 | }, { | ||
515 | .id = V4L2_CID_HFLIP, | ||
516 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
517 | .name = "Flip Horizontally", | ||
518 | .minimum = 0, | ||
519 | .maximum = 1, | ||
520 | .step = 1, | ||
521 | .default_value = 0, | ||
522 | }, { | ||
523 | .id = V4L2_CID_GAIN, | ||
524 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
525 | .name = "Analog Gain", | ||
526 | .minimum = 64, | ||
527 | .maximum = 127, | ||
528 | .step = 1, | ||
529 | .default_value = 64, | ||
530 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
531 | }, { | ||
532 | .id = V4L2_CID_EXPOSURE, | ||
533 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
534 | .name = "Exposure", | ||
535 | .minimum = 1, | ||
536 | .maximum = 255, | ||
537 | .step = 1, | ||
538 | .default_value = 255, | ||
539 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
540 | }, { | ||
541 | .id = V4L2_CID_AUTOGAIN, | ||
542 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
543 | .name = "Automatic Gain", | ||
544 | .minimum = 0, | ||
545 | .maximum = 1, | ||
546 | .step = 1, | ||
547 | .default_value = 1, | ||
548 | }, { | ||
549 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
550 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
551 | .name = "Automatic Exposure", | ||
552 | .minimum = 0, | ||
553 | .maximum = 1, | ||
554 | .step = 1, | ||
555 | .default_value = 1, | ||
556 | } | ||
557 | }; | ||
558 | |||
559 | static struct soc_camera_ops mt9v022_ops = { | ||
560 | .set_bus_param = mt9v022_set_bus_param, | ||
561 | .query_bus_param = mt9v022_query_bus_param, | ||
562 | .controls = mt9v022_controls, | ||
563 | .num_controls = ARRAY_SIZE(mt9v022_controls), | ||
564 | }; | ||
565 | |||
566 | static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
567 | { | 449 | { |
450 | struct mt9v022 *mt9v022 = container_of(ctrl->handler, | ||
451 | struct mt9v022, hdl); | ||
452 | struct v4l2_subdev *sd = &mt9v022->subdev; | ||
568 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 453 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
569 | const struct v4l2_queryctrl *qctrl; | 454 | struct v4l2_ctrl *gain = mt9v022->gain; |
455 | struct v4l2_ctrl *exp = mt9v022->exposure; | ||
570 | unsigned long range; | 456 | unsigned long range; |
571 | int data; | 457 | int data; |
572 | 458 | ||
573 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); | ||
574 | |||
575 | switch (ctrl->id) { | 459 | switch (ctrl->id) { |
576 | case V4L2_CID_VFLIP: | ||
577 | data = reg_read(client, MT9V022_READ_MODE); | ||
578 | if (data < 0) | ||
579 | return -EIO; | ||
580 | ctrl->value = !!(data & 0x10); | ||
581 | break; | ||
582 | case V4L2_CID_HFLIP: | ||
583 | data = reg_read(client, MT9V022_READ_MODE); | ||
584 | if (data < 0) | ||
585 | return -EIO; | ||
586 | ctrl->value = !!(data & 0x20); | ||
587 | break; | ||
588 | case V4L2_CID_EXPOSURE_AUTO: | ||
589 | data = reg_read(client, MT9V022_AEC_AGC_ENABLE); | ||
590 | if (data < 0) | ||
591 | return -EIO; | ||
592 | ctrl->value = !!(data & 0x1); | ||
593 | break; | ||
594 | case V4L2_CID_AUTOGAIN: | 460 | case V4L2_CID_AUTOGAIN: |
595 | data = reg_read(client, MT9V022_AEC_AGC_ENABLE); | ||
596 | if (data < 0) | ||
597 | return -EIO; | ||
598 | ctrl->value = !!(data & 0x2); | ||
599 | break; | ||
600 | case V4L2_CID_GAIN: | ||
601 | data = reg_read(client, MT9V022_ANALOG_GAIN); | 461 | data = reg_read(client, MT9V022_ANALOG_GAIN); |
602 | if (data < 0) | 462 | if (data < 0) |
603 | return -EIO; | 463 | return -EIO; |
604 | 464 | ||
605 | range = qctrl->maximum - qctrl->minimum; | 465 | range = gain->maximum - gain->minimum; |
606 | ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum; | 466 | gain->val = ((data - 16) * range + 24) / 48 + gain->minimum; |
607 | 467 | return 0; | |
608 | break; | 468 | case V4L2_CID_EXPOSURE_AUTO: |
609 | case V4L2_CID_EXPOSURE: | ||
610 | data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); | 469 | data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); |
611 | if (data < 0) | 470 | if (data < 0) |
612 | return -EIO; | 471 | return -EIO; |
613 | 472 | ||
614 | range = qctrl->maximum - qctrl->minimum; | 473 | range = exp->maximum - exp->minimum; |
615 | ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum; | 474 | exp->val = ((data - 1) * range + 239) / 479 + exp->minimum; |
616 | 475 | return 0; | |
617 | break; | ||
618 | } | 476 | } |
619 | return 0; | 477 | return -EINVAL; |
620 | } | 478 | } |
621 | 479 | ||
622 | static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 480 | static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) |
623 | { | 481 | { |
624 | int data; | 482 | struct mt9v022 *mt9v022 = container_of(ctrl->handler, |
483 | struct mt9v022, hdl); | ||
484 | struct v4l2_subdev *sd = &mt9v022->subdev; | ||
625 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 485 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
626 | const struct v4l2_queryctrl *qctrl; | 486 | int data; |
627 | |||
628 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); | ||
629 | if (!qctrl) | ||
630 | return -EINVAL; | ||
631 | 487 | ||
632 | switch (ctrl->id) { | 488 | switch (ctrl->id) { |
633 | case V4L2_CID_VFLIP: | 489 | case V4L2_CID_VFLIP: |
634 | if (ctrl->value) | 490 | if (ctrl->val) |
635 | data = reg_set(client, MT9V022_READ_MODE, 0x10); | 491 | data = reg_set(client, MT9V022_READ_MODE, 0x10); |
636 | else | 492 | else |
637 | data = reg_clear(client, MT9V022_READ_MODE, 0x10); | 493 | data = reg_clear(client, MT9V022_READ_MODE, 0x10); |
638 | if (data < 0) | 494 | if (data < 0) |
639 | return -EIO; | 495 | return -EIO; |
640 | break; | 496 | return 0; |
641 | case V4L2_CID_HFLIP: | 497 | case V4L2_CID_HFLIP: |
642 | if (ctrl->value) | 498 | if (ctrl->val) |
643 | data = reg_set(client, MT9V022_READ_MODE, 0x20); | 499 | data = reg_set(client, MT9V022_READ_MODE, 0x20); |
644 | else | 500 | else |
645 | data = reg_clear(client, MT9V022_READ_MODE, 0x20); | 501 | data = reg_clear(client, MT9V022_READ_MODE, 0x20); |
646 | if (data < 0) | 502 | if (data < 0) |
647 | return -EIO; | 503 | return -EIO; |
648 | break; | 504 | return 0; |
649 | case V4L2_CID_GAIN: | 505 | case V4L2_CID_AUTOGAIN: |
650 | /* mt9v022 has minimum == default */ | 506 | if (ctrl->val) { |
651 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | 507 | if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) |
652 | return -EINVAL; | 508 | return -EIO; |
653 | else { | 509 | } else { |
654 | unsigned long range = qctrl->maximum - qctrl->minimum; | 510 | struct v4l2_ctrl *gain = mt9v022->gain; |
511 | /* mt9v022 has minimum == default */ | ||
512 | unsigned long range = gain->maximum - gain->minimum; | ||
655 | /* Valid values 16 to 64, 32 to 64 must be even. */ | 513 | /* Valid values 16 to 64, 32 to 64 must be even. */ |
656 | unsigned long gain = ((ctrl->value - qctrl->minimum) * | 514 | unsigned long gain_val = ((gain->val - gain->minimum) * |
657 | 48 + range / 2) / range + 16; | 515 | 48 + range / 2) / range + 16; |
658 | if (gain >= 32) | 516 | |
659 | gain &= ~1; | 517 | if (gain_val >= 32) |
518 | gain_val &= ~1; | ||
519 | |||
660 | /* | 520 | /* |
661 | * The user wants to set gain manually, hope, she | 521 | * The user wants to set gain manually, hope, she |
662 | * knows, what she's doing... Switch AGC off. | 522 | * knows, what she's doing... Switch AGC off. |
663 | */ | 523 | */ |
664 | |||
665 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) | 524 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) |
666 | return -EIO; | 525 | return -EIO; |
667 | 526 | ||
668 | dev_dbg(&client->dev, "Setting gain from %d to %lu\n", | 527 | dev_dbg(&client->dev, "Setting gain from %d to %lu\n", |
669 | reg_read(client, MT9V022_ANALOG_GAIN), gain); | 528 | reg_read(client, MT9V022_ANALOG_GAIN), gain_val); |
670 | if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) | 529 | if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0) |
671 | return -EIO; | 530 | return -EIO; |
672 | } | 531 | } |
673 | break; | 532 | return 0; |
674 | case V4L2_CID_EXPOSURE: | 533 | case V4L2_CID_EXPOSURE_AUTO: |
675 | /* mt9v022 has maximum == default */ | 534 | if (ctrl->val == V4L2_EXPOSURE_AUTO) { |
676 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | 535 | data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); |
677 | return -EINVAL; | 536 | } else { |
678 | else { | 537 | struct v4l2_ctrl *exp = mt9v022->exposure; |
679 | unsigned long range = qctrl->maximum - qctrl->minimum; | 538 | unsigned long range = exp->maximum - exp->minimum; |
680 | unsigned long shutter = ((ctrl->value - qctrl->minimum) * | 539 | unsigned long shutter = ((exp->val - exp->minimum) * |
681 | 479 + range / 2) / range + 1; | 540 | 479 + range / 2) / range + 1; |
541 | |||
682 | /* | 542 | /* |
683 | * The user wants to set shutter width manually, hope, | 543 | * The user wants to set shutter width manually, hope, |
684 | * she knows, what she's doing... Switch AEC off. | 544 | * she knows, what she's doing... Switch AEC off. |
685 | */ | 545 | */ |
686 | 546 | data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); | |
687 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) | 547 | if (data < 0) |
688 | return -EIO; | 548 | return -EIO; |
689 | |||
690 | dev_dbg(&client->dev, "Shutter width from %d to %lu\n", | 549 | dev_dbg(&client->dev, "Shutter width from %d to %lu\n", |
691 | reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), | 550 | reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), |
692 | shutter); | 551 | shutter); |
693 | if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, | 552 | if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, |
694 | shutter) < 0) | 553 | shutter) < 0) |
695 | return -EIO; | 554 | return -EIO; |
696 | } | 555 | } |
697 | break; | 556 | return 0; |
698 | case V4L2_CID_AUTOGAIN: | ||
699 | if (ctrl->value) | ||
700 | data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2); | ||
701 | else | ||
702 | data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2); | ||
703 | if (data < 0) | ||
704 | return -EIO; | ||
705 | break; | ||
706 | case V4L2_CID_EXPOSURE_AUTO: | ||
707 | if (ctrl->value) | ||
708 | data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); | ||
709 | else | ||
710 | data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); | ||
711 | if (data < 0) | ||
712 | return -EIO; | ||
713 | break; | ||
714 | } | 557 | } |
715 | return 0; | 558 | return -EINVAL; |
716 | } | 559 | } |
717 | 560 | ||
718 | /* | 561 | /* |
719 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 562 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
720 | * this wasn't our capture interface, so, we wait for the right one | 563 | * this wasn't our capture interface, so, we wait for the right one |
721 | */ | 564 | */ |
722 | static int mt9v022_video_probe(struct soc_camera_device *icd, | 565 | static int mt9v022_video_probe(struct i2c_client *client) |
723 | struct i2c_client *client) | ||
724 | { | 566 | { |
725 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 567 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
726 | struct soc_camera_link *icl = to_soc_camera_link(icd); | 568 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
727 | s32 data; | 569 | s32 data; |
728 | int ret; | 570 | int ret; |
729 | unsigned long flags; | 571 | unsigned long flags; |
730 | 572 | ||
731 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
732 | BUG_ON(!icd->parent || | ||
733 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
734 | |||
735 | /* Read out the chip version register */ | 573 | /* Read out the chip version register */ |
736 | data = reg_read(client, MT9V022_CHIP_VERSION); | 574 | data = reg_read(client, MT9V022_CHIP_VERSION); |
737 | 575 | ||
@@ -805,16 +643,6 @@ ei2c: | |||
805 | return ret; | 643 | return ret; |
806 | } | 644 | } |
807 | 645 | ||
808 | static void mt9v022_video_remove(struct soc_camera_device *icd) | ||
809 | { | ||
810 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
811 | |||
812 | dev_dbg(icd->pdev, "Video removed: %p, %p\n", | ||
813 | icd->parent, icd->vdev); | ||
814 | if (icl->free_bus) | ||
815 | icl->free_bus(icl); | ||
816 | } | ||
817 | |||
818 | static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | 646 | static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) |
819 | { | 647 | { |
820 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 648 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
@@ -825,9 +653,12 @@ static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | |||
825 | return 0; | 653 | return 0; |
826 | } | 654 | } |
827 | 655 | ||
656 | static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = { | ||
657 | .g_volatile_ctrl = mt9v022_g_volatile_ctrl, | ||
658 | .s_ctrl = mt9v022_s_ctrl, | ||
659 | }; | ||
660 | |||
828 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { | 661 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { |
829 | .g_ctrl = mt9v022_g_ctrl, | ||
830 | .s_ctrl = mt9v022_s_ctrl, | ||
831 | .g_chip_ident = mt9v022_g_chip_ident, | 662 | .g_chip_ident = mt9v022_g_chip_ident, |
832 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 663 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
833 | .g_register = mt9v022_g_register, | 664 | .g_register = mt9v022_g_register, |
@@ -848,6 +679,72 @@ static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
848 | return 0; | 679 | return 0; |
849 | } | 680 | } |
850 | 681 | ||
682 | static int mt9v022_g_mbus_config(struct v4l2_subdev *sd, | ||
683 | struct v4l2_mbus_config *cfg) | ||
684 | { | ||
685 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
686 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
687 | |||
688 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE | | ||
689 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | | ||
690 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | | ||
691 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | | ||
692 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
693 | cfg->type = V4L2_MBUS_PARALLEL; | ||
694 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
695 | |||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, | ||
700 | const struct v4l2_mbus_config *cfg) | ||
701 | { | ||
702 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
703 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
704 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
705 | unsigned long flags = soc_camera_apply_board_flags(icl, cfg); | ||
706 | unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample; | ||
707 | int ret; | ||
708 | u16 pixclk = 0; | ||
709 | |||
710 | if (icl->set_bus_param) { | ||
711 | ret = icl->set_bus_param(icl, 1 << (bps - 1)); | ||
712 | if (ret) | ||
713 | return ret; | ||
714 | } else if (bps != 10) { | ||
715 | /* | ||
716 | * Without board specific bus width settings we only support the | ||
717 | * sensors native bus width | ||
718 | */ | ||
719 | return -EINVAL; | ||
720 | } | ||
721 | |||
722 | if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
723 | pixclk |= 0x10; | ||
724 | |||
725 | if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)) | ||
726 | pixclk |= 0x1; | ||
727 | |||
728 | if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)) | ||
729 | pixclk |= 0x2; | ||
730 | |||
731 | ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); | ||
732 | if (ret < 0) | ||
733 | return ret; | ||
734 | |||
735 | if (!(flags & V4L2_MBUS_MASTER)) | ||
736 | mt9v022->chip_control &= ~0x8; | ||
737 | |||
738 | ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); | ||
739 | if (ret < 0) | ||
740 | return ret; | ||
741 | |||
742 | dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", | ||
743 | pixclk, mt9v022->chip_control); | ||
744 | |||
745 | return 0; | ||
746 | } | ||
747 | |||
851 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | 748 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { |
852 | .s_stream = mt9v022_s_stream, | 749 | .s_stream = mt9v022_s_stream, |
853 | .s_mbus_fmt = mt9v022_s_fmt, | 750 | .s_mbus_fmt = mt9v022_s_fmt, |
@@ -857,6 +754,8 @@ static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | |||
857 | .g_crop = mt9v022_g_crop, | 754 | .g_crop = mt9v022_g_crop, |
858 | .cropcap = mt9v022_cropcap, | 755 | .cropcap = mt9v022_cropcap, |
859 | .enum_mbus_fmt = mt9v022_enum_fmt, | 756 | .enum_mbus_fmt = mt9v022_enum_fmt, |
757 | .g_mbus_config = mt9v022_g_mbus_config, | ||
758 | .s_mbus_config = mt9v022_s_mbus_config, | ||
860 | }; | 759 | }; |
861 | 760 | ||
862 | static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { | 761 | static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { |
@@ -873,17 +772,10 @@ static int mt9v022_probe(struct i2c_client *client, | |||
873 | const struct i2c_device_id *did) | 772 | const struct i2c_device_id *did) |
874 | { | 773 | { |
875 | struct mt9v022 *mt9v022; | 774 | struct mt9v022 *mt9v022; |
876 | struct soc_camera_device *icd = client->dev.platform_data; | 775 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
877 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 776 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
878 | struct soc_camera_link *icl; | ||
879 | int ret; | 777 | int ret; |
880 | 778 | ||
881 | if (!icd) { | ||
882 | dev_err(&client->dev, "MT9V022: missing soc-camera data!\n"); | ||
883 | return -EINVAL; | ||
884 | } | ||
885 | |||
886 | icl = to_soc_camera_link(icd); | ||
887 | if (!icl) { | 779 | if (!icl) { |
888 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); | 780 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); |
889 | return -EINVAL; | 781 | return -EINVAL; |
@@ -900,10 +792,39 @@ static int mt9v022_probe(struct i2c_client *client, | |||
900 | return -ENOMEM; | 792 | return -ENOMEM; |
901 | 793 | ||
902 | v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); | 794 | v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); |
795 | v4l2_ctrl_handler_init(&mt9v022->hdl, 6); | ||
796 | v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
797 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
798 | v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
799 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
800 | mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
801 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
802 | mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
803 | V4L2_CID_GAIN, 0, 127, 1, 64); | ||
804 | |||
805 | /* | ||
806 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
807 | * ourselves in the driver based on vertical blanking and frame width | ||
808 | */ | ||
809 | mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl, | ||
810 | &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
811 | V4L2_EXPOSURE_AUTO); | ||
812 | mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
813 | V4L2_CID_EXPOSURE, 1, 255, 1, 255); | ||
814 | |||
815 | mt9v022->subdev.ctrl_handler = &mt9v022->hdl; | ||
816 | if (mt9v022->hdl.error) { | ||
817 | int err = mt9v022->hdl.error; | ||
818 | |||
819 | kfree(mt9v022); | ||
820 | return err; | ||
821 | } | ||
822 | v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure, | ||
823 | V4L2_EXPOSURE_MANUAL, true); | ||
824 | v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true); | ||
903 | 825 | ||
904 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; | 826 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; |
905 | 827 | ||
906 | icd->ops = &mt9v022_ops; | ||
907 | /* | 828 | /* |
908 | * MT9V022 _really_ corrupts the first read out line. | 829 | * MT9V022 _really_ corrupts the first read out line. |
909 | * TODO: verify on i.MX31 | 830 | * TODO: verify on i.MX31 |
@@ -914,9 +835,9 @@ static int mt9v022_probe(struct i2c_client *client, | |||
914 | mt9v022->rect.width = MT9V022_MAX_WIDTH; | 835 | mt9v022->rect.width = MT9V022_MAX_WIDTH; |
915 | mt9v022->rect.height = MT9V022_MAX_HEIGHT; | 836 | mt9v022->rect.height = MT9V022_MAX_HEIGHT; |
916 | 837 | ||
917 | ret = mt9v022_video_probe(icd, client); | 838 | ret = mt9v022_video_probe(client); |
918 | if (ret) { | 839 | if (ret) { |
919 | icd->ops = NULL; | 840 | v4l2_ctrl_handler_free(&mt9v022->hdl); |
920 | kfree(mt9v022); | 841 | kfree(mt9v022); |
921 | } | 842 | } |
922 | 843 | ||
@@ -926,10 +847,12 @@ static int mt9v022_probe(struct i2c_client *client, | |||
926 | static int mt9v022_remove(struct i2c_client *client) | 847 | static int mt9v022_remove(struct i2c_client *client) |
927 | { | 848 | { |
928 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 849 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
929 | struct soc_camera_device *icd = client->dev.platform_data; | 850 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
930 | 851 | ||
931 | icd->ops = NULL; | 852 | v4l2_device_unregister_subdev(&mt9v022->subdev); |
932 | mt9v022_video_remove(icd); | 853 | if (icl->free_bus) |
854 | icl->free_bus(icl); | ||
855 | v4l2_ctrl_handler_free(&mt9v022->hdl); | ||
933 | kfree(mt9v022); | 856 | kfree(mt9v022); |
934 | 857 | ||
935 | return 0; | 858 | return 0; |
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 087db12a3a67..18e94c7d2be8 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c | |||
@@ -78,11 +78,10 @@ | |||
78 | #define CSI_IRQ_MASK (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \ | 78 | #define CSI_IRQ_MASK (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \ |
79 | CSISR_STATFF_INT | CSISR_RXFF_INT | CSISR_SOF_INT) | 79 | CSISR_STATFF_INT | CSISR_RXFF_INT | CSISR_SOF_INT) |
80 | 80 | ||
81 | #define CSI_BUS_FLAGS (SOCAM_MASTER | SOCAM_HSYNC_ACTIVE_HIGH | \ | 81 | #define CSI_BUS_FLAGS (V4L2_MBUS_MASTER | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ |
82 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | \ | 82 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ |
83 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \ | 83 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ |
84 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW | \ | 84 | V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_LOW) |
85 | SOCAM_DATAWIDTH_8) | ||
86 | 85 | ||
87 | #define MAX_VIDEO_MEM 16 /* Video memory limit in megabytes */ | 86 | #define MAX_VIDEO_MEM 16 /* Video memory limit in megabytes */ |
88 | 87 | ||
@@ -490,59 +489,73 @@ static int mx1_camera_set_crop(struct soc_camera_device *icd, | |||
490 | 489 | ||
491 | static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | 490 | static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) |
492 | { | 491 | { |
492 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
493 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 493 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
494 | struct mx1_camera_dev *pcdev = ici->priv; | 494 | struct mx1_camera_dev *pcdev = ici->priv; |
495 | unsigned long camera_flags, common_flags; | 495 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
496 | unsigned long common_flags; | ||
496 | unsigned int csicr1; | 497 | unsigned int csicr1; |
497 | int ret; | 498 | int ret; |
498 | 499 | ||
499 | camera_flags = icd->ops->query_bus_param(icd); | ||
500 | |||
501 | /* MX1 supports only 8bit buswidth */ | 500 | /* MX1 supports only 8bit buswidth */ |
502 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 501 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
503 | CSI_BUS_FLAGS); | 502 | if (!ret) { |
504 | if (!common_flags) | 503 | common_flags = soc_mbus_config_compatible(&cfg, CSI_BUS_FLAGS); |
505 | return -EINVAL; | 504 | if (!common_flags) { |
505 | dev_warn(icd->parent, | ||
506 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
507 | cfg.flags, CSI_BUS_FLAGS); | ||
508 | return -EINVAL; | ||
509 | } | ||
510 | } else if (ret != -ENOIOCTLCMD) { | ||
511 | return ret; | ||
512 | } else { | ||
513 | common_flags = CSI_BUS_FLAGS; | ||
514 | } | ||
506 | 515 | ||
507 | /* Make choises, based on platform choice */ | 516 | /* Make choises, based on platform choice */ |
508 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 517 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
509 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 518 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
510 | if (!pcdev->pdata || | 519 | if (!pcdev->pdata || |
511 | pcdev->pdata->flags & MX1_CAMERA_VSYNC_HIGH) | 520 | pcdev->pdata->flags & MX1_CAMERA_VSYNC_HIGH) |
512 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 521 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
513 | else | 522 | else |
514 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 523 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
515 | } | 524 | } |
516 | 525 | ||
517 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 526 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
518 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 527 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
519 | if (!pcdev->pdata || | 528 | if (!pcdev->pdata || |
520 | pcdev->pdata->flags & MX1_CAMERA_PCLK_RISING) | 529 | pcdev->pdata->flags & MX1_CAMERA_PCLK_RISING) |
521 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 530 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
522 | else | 531 | else |
523 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 532 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
524 | } | 533 | } |
525 | 534 | ||
526 | if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && | 535 | if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && |
527 | (common_flags & SOCAM_DATA_ACTIVE_LOW)) { | 536 | (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { |
528 | if (!pcdev->pdata || | 537 | if (!pcdev->pdata || |
529 | pcdev->pdata->flags & MX1_CAMERA_DATA_HIGH) | 538 | pcdev->pdata->flags & MX1_CAMERA_DATA_HIGH) |
530 | common_flags &= ~SOCAM_DATA_ACTIVE_LOW; | 539 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; |
531 | else | 540 | else |
532 | common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; | 541 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; |
533 | } | 542 | } |
534 | 543 | ||
535 | ret = icd->ops->set_bus_param(icd, common_flags); | 544 | cfg.flags = common_flags; |
536 | if (ret < 0) | 545 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
546 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
547 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
548 | common_flags, ret); | ||
537 | return ret; | 549 | return ret; |
550 | } | ||
538 | 551 | ||
539 | csicr1 = __raw_readl(pcdev->base + CSICR1); | 552 | csicr1 = __raw_readl(pcdev->base + CSICR1); |
540 | 553 | ||
541 | if (common_flags & SOCAM_PCLK_SAMPLE_RISING) | 554 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) |
542 | csicr1 |= CSICR1_REDGE; | 555 | csicr1 |= CSICR1_REDGE; |
543 | if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) | 556 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) |
544 | csicr1 |= CSICR1_SOF_POL; | 557 | csicr1 |= CSICR1_SOF_POL; |
545 | if (common_flags & SOCAM_DATA_ACTIVE_LOW) | 558 | if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW) |
546 | csicr1 |= CSICR1_DATA_POL; | 559 | csicr1 |= CSICR1_DATA_POL; |
547 | 560 | ||
548 | __raw_writel(csicr1, pcdev->base + CSICR1); | 561 | __raw_writel(csicr1, pcdev->base + CSICR1); |
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index ec2410c0c806..a803d9ea8fd6 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c | |||
@@ -686,16 +686,15 @@ static void mx2_camera_init_videobuf(struct videobuf_queue *q, | |||
686 | icd, &icd->video_lock); | 686 | icd, &icd->video_lock); |
687 | } | 687 | } |
688 | 688 | ||
689 | #define MX2_BUS_FLAGS (SOCAM_DATAWIDTH_8 | \ | 689 | #define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \ |
690 | SOCAM_MASTER | \ | 690 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ |
691 | SOCAM_VSYNC_ACTIVE_HIGH | \ | 691 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ |
692 | SOCAM_VSYNC_ACTIVE_LOW | \ | 692 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ |
693 | SOCAM_HSYNC_ACTIVE_HIGH | \ | 693 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ |
694 | SOCAM_HSYNC_ACTIVE_LOW | \ | 694 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ |
695 | SOCAM_PCLK_SAMPLE_RISING | \ | 695 | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ |
696 | SOCAM_PCLK_SAMPLE_FALLING | \ | 696 | V4L2_MBUS_DATA_ACTIVE_HIGH | \ |
697 | SOCAM_DATA_ACTIVE_HIGH | \ | 697 | V4L2_MBUS_DATA_ACTIVE_LOW) |
698 | SOCAM_DATA_ACTIVE_LOW) | ||
699 | 698 | ||
700 | static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) | 699 | static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) |
701 | { | 700 | { |
@@ -770,46 +769,59 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, | |||
770 | static int mx2_camera_set_bus_param(struct soc_camera_device *icd, | 769 | static int mx2_camera_set_bus_param(struct soc_camera_device *icd, |
771 | __u32 pixfmt) | 770 | __u32 pixfmt) |
772 | { | 771 | { |
773 | struct soc_camera_host *ici = | 772 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
774 | to_soc_camera_host(icd->parent); | 773 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
775 | struct mx2_camera_dev *pcdev = ici->priv; | 774 | struct mx2_camera_dev *pcdev = ici->priv; |
776 | unsigned long camera_flags, common_flags; | 775 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
777 | int ret = 0; | 776 | unsigned long common_flags; |
777 | int ret; | ||
778 | int bytesperline; | 778 | int bytesperline; |
779 | u32 csicr1 = pcdev->csicr1; | 779 | u32 csicr1 = pcdev->csicr1; |
780 | 780 | ||
781 | camera_flags = icd->ops->query_bus_param(icd); | 781 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
782 | 782 | if (!ret) { | |
783 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 783 | common_flags = soc_mbus_config_compatible(&cfg, MX2_BUS_FLAGS); |
784 | MX2_BUS_FLAGS); | 784 | if (!common_flags) { |
785 | if (!common_flags) | 785 | dev_warn(icd->parent, |
786 | return -EINVAL; | 786 | "Flags incompatible: camera 0x%x, host 0x%x\n", |
787 | cfg.flags, MX2_BUS_FLAGS); | ||
788 | return -EINVAL; | ||
789 | } | ||
790 | } else if (ret != -ENOIOCTLCMD) { | ||
791 | return ret; | ||
792 | } else { | ||
793 | common_flags = MX2_BUS_FLAGS; | ||
794 | } | ||
787 | 795 | ||
788 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 796 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
789 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 797 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
790 | if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) | 798 | if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) |
791 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 799 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
792 | else | 800 | else |
793 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 801 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
794 | } | 802 | } |
795 | 803 | ||
796 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 804 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
797 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 805 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
798 | if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) | 806 | if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) |
799 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 807 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
800 | else | 808 | else |
801 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 809 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
802 | } | 810 | } |
803 | 811 | ||
804 | ret = icd->ops->set_bus_param(icd, common_flags); | 812 | cfg.flags = common_flags; |
805 | if (ret < 0) | 813 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
814 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
815 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
816 | common_flags, ret); | ||
806 | return ret; | 817 | return ret; |
818 | } | ||
807 | 819 | ||
808 | if (common_flags & SOCAM_PCLK_SAMPLE_RISING) | 820 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) |
809 | csicr1 |= CSICR1_REDGE; | 821 | csicr1 |= CSICR1_REDGE; |
810 | if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) | 822 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) |
811 | csicr1 |= CSICR1_SOF_POL; | 823 | csicr1 |= CSICR1_SOF_POL; |
812 | if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH) | 824 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) |
813 | csicr1 |= CSICR1_HSYNC_POL; | 825 | csicr1 |= CSICR1_HSYNC_POL; |
814 | if (pcdev->platform_flags & MX2_CAMERA_SWAP16) | 826 | if (pcdev->platform_flags & MX2_CAMERA_SWAP16) |
815 | csicr1 |= CSICR1_SWAP16_EN; | 827 | csicr1 |= CSICR1_SWAP16_EN; |
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index c8e958a07e91..f96f92f00f92 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c | |||
@@ -109,10 +109,12 @@ struct mx3_camera_dev { | |||
109 | 109 | ||
110 | unsigned long platform_flags; | 110 | unsigned long platform_flags; |
111 | unsigned long mclk; | 111 | unsigned long mclk; |
112 | u16 width_flags; /* max 15 bits */ | ||
112 | 113 | ||
113 | struct list_head capture; | 114 | struct list_head capture; |
114 | spinlock_t lock; /* Protects video buffer lists */ | 115 | spinlock_t lock; /* Protects video buffer lists */ |
115 | struct mx3_camera_buffer *active; | 116 | struct mx3_camera_buffer *active; |
117 | size_t buf_total; | ||
116 | struct vb2_alloc_ctx *alloc_ctx; | 118 | struct vb2_alloc_ctx *alloc_ctx; |
117 | enum v4l2_field field; | 119 | enum v4l2_field field; |
118 | int sequence; | 120 | int sequence; |
@@ -190,79 +192,53 @@ static void mx3_cam_dma_done(void *arg) | |||
190 | * Calculate the __buffer__ (not data) size and number of buffers. | 192 | * Calculate the __buffer__ (not data) size and number of buffers. |
191 | */ | 193 | */ |
192 | static int mx3_videobuf_setup(struct vb2_queue *vq, | 194 | static int mx3_videobuf_setup(struct vb2_queue *vq, |
195 | const struct v4l2_format *fmt, | ||
193 | unsigned int *count, unsigned int *num_planes, | 196 | unsigned int *count, unsigned int *num_planes, |
194 | unsigned int sizes[], void *alloc_ctxs[]) | 197 | unsigned int sizes[], void *alloc_ctxs[]) |
195 | { | 198 | { |
196 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | 199 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); |
197 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 200 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
198 | struct mx3_camera_dev *mx3_cam = ici->priv; | 201 | struct mx3_camera_dev *mx3_cam = ici->priv; |
199 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 202 | int bytes_per_line; |
200 | icd->current_fmt->host_fmt); | 203 | unsigned int height; |
201 | |||
202 | if (bytes_per_line < 0) | ||
203 | return bytes_per_line; | ||
204 | 204 | ||
205 | if (!mx3_cam->idmac_channel[0]) | 205 | if (!mx3_cam->idmac_channel[0]) |
206 | return -EINVAL; | 206 | return -EINVAL; |
207 | 207 | ||
208 | *num_planes = 1; | 208 | if (fmt) { |
209 | 209 | const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, | |
210 | mx3_cam->sequence = 0; | 210 | fmt->fmt.pix.pixelformat); |
211 | sizes[0] = bytes_per_line * icd->user_height; | 211 | if (!xlate) |
212 | alloc_ctxs[0] = mx3_cam->alloc_ctx; | 212 | return -EINVAL; |
213 | 213 | bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width, | |
214 | if (!*count) | 214 | xlate->host_fmt); |
215 | *count = 32; | 215 | height = fmt->fmt.pix.height; |
216 | 216 | } else { | |
217 | if (sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) | 217 | /* Called from VIDIOC_REQBUFS or in compatibility mode */ |
218 | *count = MAX_VIDEO_MEM * 1024 * 1024 / sizes[0]; | 218 | bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, |
219 | |||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static int mx3_videobuf_prepare(struct vb2_buffer *vb) | ||
224 | { | ||
225 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
226 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
227 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
228 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | ||
229 | struct scatterlist *sg; | ||
230 | struct mx3_camera_buffer *buf; | ||
231 | size_t new_size; | ||
232 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
233 | icd->current_fmt->host_fmt); | 219 | icd->current_fmt->host_fmt); |
234 | 220 | height = icd->user_height; | |
221 | } | ||
235 | if (bytes_per_line < 0) | 222 | if (bytes_per_line < 0) |
236 | return bytes_per_line; | 223 | return bytes_per_line; |
237 | 224 | ||
238 | buf = to_mx3_vb(vb); | 225 | sizes[0] = bytes_per_line * height; |
239 | sg = &buf->sg; | ||
240 | |||
241 | new_size = bytes_per_line * icd->user_height; | ||
242 | 226 | ||
243 | if (vb2_plane_size(vb, 0) < new_size) { | 227 | alloc_ctxs[0] = mx3_cam->alloc_ctx; |
244 | dev_err(icd->parent, "Buffer too small (%lu < %zu)\n", | ||
245 | vb2_plane_size(vb, 0), new_size); | ||
246 | return -ENOBUFS; | ||
247 | } | ||
248 | 228 | ||
249 | if (buf->state == CSI_BUF_NEEDS_INIT) { | 229 | if (!vq->num_buffers) |
250 | sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); | 230 | mx3_cam->sequence = 0; |
251 | sg_dma_len(sg) = new_size; | ||
252 | 231 | ||
253 | buf->txd = ichan->dma_chan.device->device_prep_slave_sg( | 232 | if (!*count) |
254 | &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, | 233 | *count = 2; |
255 | DMA_PREP_INTERRUPT); | ||
256 | if (!buf->txd) | ||
257 | return -EIO; | ||
258 | |||
259 | buf->txd->callback_param = buf->txd; | ||
260 | buf->txd->callback = mx3_cam_dma_done; | ||
261 | 234 | ||
262 | buf->state = CSI_BUF_PREPARED; | 235 | /* If *num_planes != 0, we have already verified *count. */ |
263 | } | 236 | if (!*num_planes && |
237 | sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024) | ||
238 | *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) / | ||
239 | sizes[0]; | ||
264 | 240 | ||
265 | vb2_set_plane_payload(vb, 0, new_size); | 241 | *num_planes = 1; |
266 | 242 | ||
267 | return 0; | 243 | return 0; |
268 | } | 244 | } |
@@ -286,28 +262,58 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) | |||
286 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 262 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
287 | struct mx3_camera_dev *mx3_cam = ici->priv; | 263 | struct mx3_camera_dev *mx3_cam = ici->priv; |
288 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); | 264 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); |
289 | struct dma_async_tx_descriptor *txd = buf->txd; | 265 | struct scatterlist *sg = &buf->sg; |
290 | struct idmac_channel *ichan = to_idmac_chan(txd->chan); | 266 | struct dma_async_tx_descriptor *txd; |
267 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | ||
291 | struct idmac_video_param *video = &ichan->params.video; | 268 | struct idmac_video_param *video = &ichan->params.video; |
292 | dma_cookie_t cookie; | 269 | const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt; |
293 | u32 fourcc = icd->current_fmt->host_fmt->fourcc; | 270 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, host_fmt); |
294 | unsigned long flags; | 271 | unsigned long flags; |
272 | dma_cookie_t cookie; | ||
273 | size_t new_size; | ||
274 | |||
275 | BUG_ON(bytes_per_line <= 0); | ||
276 | |||
277 | new_size = bytes_per_line * icd->user_height; | ||
278 | |||
279 | if (vb2_plane_size(vb, 0) < new_size) { | ||
280 | dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n", | ||
281 | vb->v4l2_buf.index, vb2_plane_size(vb, 0), new_size); | ||
282 | goto error; | ||
283 | } | ||
284 | |||
285 | if (buf->state == CSI_BUF_NEEDS_INIT) { | ||
286 | sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
287 | sg_dma_len(sg) = new_size; | ||
288 | |||
289 | txd = ichan->dma_chan.device->device_prep_slave_sg( | ||
290 | &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, | ||
291 | DMA_PREP_INTERRUPT); | ||
292 | if (!txd) | ||
293 | goto error; | ||
294 | |||
295 | txd->callback_param = txd; | ||
296 | txd->callback = mx3_cam_dma_done; | ||
297 | |||
298 | buf->state = CSI_BUF_PREPARED; | ||
299 | buf->txd = txd; | ||
300 | } else { | ||
301 | txd = buf->txd; | ||
302 | } | ||
303 | |||
304 | vb2_set_plane_payload(vb, 0, new_size); | ||
295 | 305 | ||
296 | /* This is the configuration of one sg-element */ | 306 | /* This is the configuration of one sg-element */ |
297 | video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); | 307 | video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc); |
298 | 308 | ||
299 | if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { | 309 | if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { |
300 | /* | 310 | /* |
301 | * If the IPU DMA channel is configured to transport | 311 | * If the IPU DMA channel is configured to transfer generic |
302 | * generic 8-bit data, we have to set up correctly the | 312 | * 8-bit data, we have to set up the geometry parameters |
303 | * geometry parameters upon the current pixel format. | 313 | * correctly, according to the current pixel format. The DMA |
304 | * So, since the DMA horizontal parameters are expressed | 314 | * horizontal parameters in this case are expressed in bytes, |
305 | * in bytes not pixels, convert these in the right unit. | 315 | * not in pixels. |
306 | */ | 316 | */ |
307 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
308 | icd->current_fmt->host_fmt); | ||
309 | BUG_ON(bytes_per_line <= 0); | ||
310 | |||
311 | video->out_width = bytes_per_line; | 317 | video->out_width = bytes_per_line; |
312 | video->out_height = icd->user_height; | 318 | video->out_height = icd->user_height; |
313 | video->out_stride = bytes_per_line; | 319 | video->out_stride = bytes_per_line; |
@@ -351,6 +357,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) | |||
351 | mx3_cam->active = NULL; | 357 | mx3_cam->active = NULL; |
352 | 358 | ||
353 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | 359 | spin_unlock_irqrestore(&mx3_cam->lock, flags); |
360 | error: | ||
354 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | 361 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); |
355 | } | 362 | } |
356 | 363 | ||
@@ -384,17 +391,24 @@ static void mx3_videobuf_release(struct vb2_buffer *vb) | |||
384 | } | 391 | } |
385 | 392 | ||
386 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | 393 | spin_unlock_irqrestore(&mx3_cam->lock, flags); |
394 | |||
395 | mx3_cam->buf_total -= vb2_plane_size(vb, 0); | ||
387 | } | 396 | } |
388 | 397 | ||
389 | static int mx3_videobuf_init(struct vb2_buffer *vb) | 398 | static int mx3_videobuf_init(struct vb2_buffer *vb) |
390 | { | 399 | { |
400 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
401 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
402 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
391 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); | 403 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); |
404 | |||
392 | /* This is for locking debugging only */ | 405 | /* This is for locking debugging only */ |
393 | INIT_LIST_HEAD(&buf->queue); | 406 | INIT_LIST_HEAD(&buf->queue); |
394 | sg_init_table(&buf->sg, 1); | 407 | sg_init_table(&buf->sg, 1); |
395 | 408 | ||
396 | buf->state = CSI_BUF_NEEDS_INIT; | 409 | buf->state = CSI_BUF_NEEDS_INIT; |
397 | buf->txd = NULL; | 410 | |
411 | mx3_cam->buf_total += vb2_plane_size(vb, 0); | ||
398 | 412 | ||
399 | return 0; | 413 | return 0; |
400 | } | 414 | } |
@@ -405,13 +419,12 @@ static int mx3_stop_streaming(struct vb2_queue *q) | |||
405 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 419 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
406 | struct mx3_camera_dev *mx3_cam = ici->priv; | 420 | struct mx3_camera_dev *mx3_cam = ici->priv; |
407 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | 421 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; |
408 | struct dma_chan *chan; | ||
409 | struct mx3_camera_buffer *buf, *tmp; | 422 | struct mx3_camera_buffer *buf, *tmp; |
410 | unsigned long flags; | 423 | unsigned long flags; |
411 | 424 | ||
412 | if (ichan) { | 425 | if (ichan) { |
413 | chan = &ichan->dma_chan; | 426 | struct dma_chan *chan = &ichan->dma_chan; |
414 | chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); | 427 | chan->device->device_control(chan, DMA_PAUSE, 0); |
415 | } | 428 | } |
416 | 429 | ||
417 | spin_lock_irqsave(&mx3_cam->lock, flags); | 430 | spin_lock_irqsave(&mx3_cam->lock, flags); |
@@ -419,8 +432,8 @@ static int mx3_stop_streaming(struct vb2_queue *q) | |||
419 | mx3_cam->active = NULL; | 432 | mx3_cam->active = NULL; |
420 | 433 | ||
421 | list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { | 434 | list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { |
422 | buf->state = CSI_BUF_NEEDS_INIT; | ||
423 | list_del_init(&buf->queue); | 435 | list_del_init(&buf->queue); |
436 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | ||
424 | } | 437 | } |
425 | 438 | ||
426 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | 439 | spin_unlock_irqrestore(&mx3_cam->lock, flags); |
@@ -430,7 +443,6 @@ static int mx3_stop_streaming(struct vb2_queue *q) | |||
430 | 443 | ||
431 | static struct vb2_ops mx3_videobuf_ops = { | 444 | static struct vb2_ops mx3_videobuf_ops = { |
432 | .queue_setup = mx3_videobuf_setup, | 445 | .queue_setup = mx3_videobuf_setup, |
433 | .buf_prepare = mx3_videobuf_prepare, | ||
434 | .buf_queue = mx3_videobuf_queue, | 446 | .buf_queue = mx3_videobuf_queue, |
435 | .buf_cleanup = mx3_videobuf_release, | 447 | .buf_cleanup = mx3_videobuf_release, |
436 | .buf_init = mx3_videobuf_init, | 448 | .buf_init = mx3_videobuf_init, |
@@ -514,6 +526,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd) | |||
514 | 526 | ||
515 | mx3_camera_activate(mx3_cam, icd); | 527 | mx3_camera_activate(mx3_cam, icd); |
516 | 528 | ||
529 | mx3_cam->buf_total = 0; | ||
517 | mx3_cam->icd = icd; | 530 | mx3_cam->icd = icd; |
518 | 531 | ||
519 | dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n", | 532 | dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n", |
@@ -548,58 +561,27 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, | |||
548 | unsigned char buswidth, unsigned long *flags) | 561 | unsigned char buswidth, unsigned long *flags) |
549 | { | 562 | { |
550 | /* | 563 | /* |
564 | * If requested data width is supported by the platform, use it or any | ||
565 | * possible lower value - i.MX31 is smart enough to shift bits | ||
566 | */ | ||
567 | if (buswidth > fls(mx3_cam->width_flags)) | ||
568 | return -EINVAL; | ||
569 | |||
570 | /* | ||
551 | * Platform specified synchronization and pixel clock polarities are | 571 | * Platform specified synchronization and pixel clock polarities are |
552 | * only a recommendation and are only used during probing. MX3x | 572 | * only a recommendation and are only used during probing. MX3x |
553 | * camera interface only works in master mode, i.e., uses HSYNC and | 573 | * camera interface only works in master mode, i.e., uses HSYNC and |
554 | * VSYNC signals from the sensor | 574 | * VSYNC signals from the sensor |
555 | */ | 575 | */ |
556 | *flags = SOCAM_MASTER | | 576 | *flags = V4L2_MBUS_MASTER | |
557 | SOCAM_HSYNC_ACTIVE_HIGH | | 577 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
558 | SOCAM_HSYNC_ACTIVE_LOW | | 578 | V4L2_MBUS_HSYNC_ACTIVE_LOW | |
559 | SOCAM_VSYNC_ACTIVE_HIGH | | 579 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | |
560 | SOCAM_VSYNC_ACTIVE_LOW | | 580 | V4L2_MBUS_VSYNC_ACTIVE_LOW | |
561 | SOCAM_PCLK_SAMPLE_RISING | | 581 | V4L2_MBUS_PCLK_SAMPLE_RISING | |
562 | SOCAM_PCLK_SAMPLE_FALLING | | 582 | V4L2_MBUS_PCLK_SAMPLE_FALLING | |
563 | SOCAM_DATA_ACTIVE_HIGH | | 583 | V4L2_MBUS_DATA_ACTIVE_HIGH | |
564 | SOCAM_DATA_ACTIVE_LOW; | 584 | V4L2_MBUS_DATA_ACTIVE_LOW; |
565 | |||
566 | /* | ||
567 | * If requested data width is supported by the platform, use it or any | ||
568 | * possible lower value - i.MX31 is smart enough to schift bits | ||
569 | */ | ||
570 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) | ||
571 | *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 | | ||
572 | SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; | ||
573 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) | ||
574 | *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 | | ||
575 | SOCAM_DATAWIDTH_4; | ||
576 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) | ||
577 | *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; | ||
578 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) | ||
579 | *flags |= SOCAM_DATAWIDTH_4; | ||
580 | |||
581 | switch (buswidth) { | ||
582 | case 15: | ||
583 | if (!(*flags & SOCAM_DATAWIDTH_15)) | ||
584 | return -EINVAL; | ||
585 | break; | ||
586 | case 10: | ||
587 | if (!(*flags & SOCAM_DATAWIDTH_10)) | ||
588 | return -EINVAL; | ||
589 | break; | ||
590 | case 8: | ||
591 | if (!(*flags & SOCAM_DATAWIDTH_8)) | ||
592 | return -EINVAL; | ||
593 | break; | ||
594 | case 4: | ||
595 | if (!(*flags & SOCAM_DATAWIDTH_4)) | ||
596 | return -EINVAL; | ||
597 | break; | ||
598 | default: | ||
599 | dev_warn(mx3_cam->soc_host.v4l2_dev.dev, | ||
600 | "Unsupported bus width %d\n", buswidth); | ||
601 | return -EINVAL; | ||
602 | } | ||
603 | 585 | ||
604 | return 0; | 586 | return 0; |
605 | } | 587 | } |
@@ -607,9 +589,11 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, | |||
607 | static int mx3_camera_try_bus_param(struct soc_camera_device *icd, | 589 | static int mx3_camera_try_bus_param(struct soc_camera_device *icd, |
608 | const unsigned int depth) | 590 | const unsigned int depth) |
609 | { | 591 | { |
592 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
610 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 593 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
611 | struct mx3_camera_dev *mx3_cam = ici->priv; | 594 | struct mx3_camera_dev *mx3_cam = ici->priv; |
612 | unsigned long bus_flags, camera_flags; | 595 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
596 | unsigned long bus_flags, common_flags; | ||
613 | int ret = test_platform_param(mx3_cam, depth, &bus_flags); | 597 | int ret = test_platform_param(mx3_cam, depth, &bus_flags); |
614 | 598 | ||
615 | dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret); | 599 | dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret); |
@@ -617,15 +601,21 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd, | |||
617 | if (ret < 0) | 601 | if (ret < 0) |
618 | return ret; | 602 | return ret; |
619 | 603 | ||
620 | camera_flags = icd->ops->query_bus_param(icd); | 604 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
621 | 605 | if (!ret) { | |
622 | ret = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 606 | common_flags = soc_mbus_config_compatible(&cfg, |
623 | if (ret < 0) | 607 | bus_flags); |
624 | dev_warn(icd->parent, | 608 | if (!common_flags) { |
625 | "Flags incompatible: camera %lx, host %lx\n", | 609 | dev_warn(icd->parent, |
626 | camera_flags, bus_flags); | 610 | "Flags incompatible: camera 0x%x, host 0x%lx\n", |
611 | cfg.flags, bus_flags); | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | } else if (ret != -ENOIOCTLCMD) { | ||
615 | return ret; | ||
616 | } | ||
627 | 617 | ||
628 | return ret; | 618 | return 0; |
629 | } | 619 | } |
630 | 620 | ||
631 | static bool chan_filter(struct dma_chan *chan, void *arg) | 621 | static bool chan_filter(struct dma_chan *chan, void *arg) |
@@ -994,9 +984,11 @@ static int mx3_camera_querycap(struct soc_camera_host *ici, | |||
994 | 984 | ||
995 | static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | 985 | static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) |
996 | { | 986 | { |
987 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
997 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 988 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
998 | struct mx3_camera_dev *mx3_cam = ici->priv; | 989 | struct mx3_camera_dev *mx3_cam = ici->priv; |
999 | unsigned long bus_flags, camera_flags, common_flags; | 990 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
991 | unsigned long bus_flags, common_flags; | ||
1000 | u32 dw, sens_conf; | 992 | u32 dw, sens_conf; |
1001 | const struct soc_mbus_pixelfmt *fmt; | 993 | const struct soc_mbus_pixelfmt *fmt; |
1002 | int buswidth; | 994 | int buswidth; |
@@ -1008,83 +1000,76 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1008 | if (!fmt) | 1000 | if (!fmt) |
1009 | return -EINVAL; | 1001 | return -EINVAL; |
1010 | 1002 | ||
1011 | buswidth = fmt->bits_per_sample; | ||
1012 | ret = test_platform_param(mx3_cam, buswidth, &bus_flags); | ||
1013 | |||
1014 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 1003 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
1015 | if (!xlate) { | 1004 | if (!xlate) { |
1016 | dev_warn(dev, "Format %x not found\n", pixfmt); | 1005 | dev_warn(dev, "Format %x not found\n", pixfmt); |
1017 | return -EINVAL; | 1006 | return -EINVAL; |
1018 | } | 1007 | } |
1019 | 1008 | ||
1009 | buswidth = fmt->bits_per_sample; | ||
1010 | ret = test_platform_param(mx3_cam, buswidth, &bus_flags); | ||
1011 | |||
1020 | dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); | 1012 | dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); |
1021 | 1013 | ||
1022 | if (ret < 0) | 1014 | if (ret < 0) |
1023 | return ret; | 1015 | return ret; |
1024 | 1016 | ||
1025 | camera_flags = icd->ops->query_bus_param(icd); | 1017 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
1026 | 1018 | if (!ret) { | |
1027 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 1019 | common_flags = soc_mbus_config_compatible(&cfg, |
1028 | dev_dbg(dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", | 1020 | bus_flags); |
1029 | camera_flags, bus_flags, common_flags); | 1021 | if (!common_flags) { |
1030 | if (!common_flags) { | 1022 | dev_warn(icd->parent, |
1031 | dev_dbg(dev, "no common flags"); | 1023 | "Flags incompatible: camera 0x%x, host 0x%lx\n", |
1032 | return -EINVAL; | 1024 | cfg.flags, bus_flags); |
1025 | return -EINVAL; | ||
1026 | } | ||
1027 | } else if (ret != -ENOIOCTLCMD) { | ||
1028 | return ret; | ||
1029 | } else { | ||
1030 | common_flags = bus_flags; | ||
1033 | } | 1031 | } |
1034 | 1032 | ||
1033 | dev_dbg(dev, "Flags cam: 0x%x host: 0x%lx common: 0x%lx\n", | ||
1034 | cfg.flags, bus_flags, common_flags); | ||
1035 | |||
1035 | /* Make choices, based on platform preferences */ | 1036 | /* Make choices, based on platform preferences */ |
1036 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 1037 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
1037 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 1038 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
1038 | if (mx3_cam->platform_flags & MX3_CAMERA_HSP) | 1039 | if (mx3_cam->platform_flags & MX3_CAMERA_HSP) |
1039 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 1040 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
1040 | else | 1041 | else |
1041 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 1042 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
1042 | } | 1043 | } |
1043 | 1044 | ||
1044 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 1045 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
1045 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 1046 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
1046 | if (mx3_cam->platform_flags & MX3_CAMERA_VSP) | 1047 | if (mx3_cam->platform_flags & MX3_CAMERA_VSP) |
1047 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 1048 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
1048 | else | 1049 | else |
1049 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 1050 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
1050 | } | 1051 | } |
1051 | 1052 | ||
1052 | if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && | 1053 | if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && |
1053 | (common_flags & SOCAM_DATA_ACTIVE_LOW)) { | 1054 | (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { |
1054 | if (mx3_cam->platform_flags & MX3_CAMERA_DP) | 1055 | if (mx3_cam->platform_flags & MX3_CAMERA_DP) |
1055 | common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; | 1056 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; |
1056 | else | 1057 | else |
1057 | common_flags &= ~SOCAM_DATA_ACTIVE_LOW; | 1058 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; |
1058 | } | 1059 | } |
1059 | 1060 | ||
1060 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 1061 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
1061 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 1062 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
1062 | if (mx3_cam->platform_flags & MX3_CAMERA_PCP) | 1063 | if (mx3_cam->platform_flags & MX3_CAMERA_PCP) |
1063 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 1064 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
1064 | else | 1065 | else |
1065 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 1066 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
1066 | } | 1067 | } |
1067 | 1068 | ||
1068 | /* | 1069 | cfg.flags = common_flags; |
1069 | * Make the camera work in widest common mode, we'll take care of | 1070 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
1070 | * the rest | 1071 | if (ret < 0 && ret != -ENOIOCTLCMD) { |
1071 | */ | 1072 | dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", |
1072 | if (common_flags & SOCAM_DATAWIDTH_15) | ||
1073 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
1074 | SOCAM_DATAWIDTH_15; | ||
1075 | else if (common_flags & SOCAM_DATAWIDTH_10) | ||
1076 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
1077 | SOCAM_DATAWIDTH_10; | ||
1078 | else if (common_flags & SOCAM_DATAWIDTH_8) | ||
1079 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
1080 | SOCAM_DATAWIDTH_8; | ||
1081 | else | ||
1082 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
1083 | SOCAM_DATAWIDTH_4; | ||
1084 | |||
1085 | ret = icd->ops->set_bus_param(icd, common_flags); | ||
1086 | if (ret < 0) { | ||
1087 | dev_dbg(dev, "camera set_bus_param(%lx) returned %d\n", | ||
1088 | common_flags, ret); | 1073 | common_flags, ret); |
1089 | return ret; | 1074 | return ret; |
1090 | } | 1075 | } |
@@ -1108,13 +1093,13 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1108 | /* This has been set in mx3_camera_activate(), but we clear it above */ | 1093 | /* This has been set in mx3_camera_activate(), but we clear it above */ |
1109 | sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; | 1094 | sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; |
1110 | 1095 | ||
1111 | if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) | 1096 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) |
1112 | sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; | 1097 | sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; |
1113 | if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) | 1098 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) |
1114 | sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; | 1099 | sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; |
1115 | if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) | 1100 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) |
1116 | sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; | 1101 | sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; |
1117 | if (common_flags & SOCAM_DATA_ACTIVE_LOW) | 1102 | if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW) |
1118 | sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; | 1103 | sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; |
1119 | 1104 | ||
1120 | /* Just do what we're asked to do */ | 1105 | /* Just do what we're asked to do */ |
@@ -1199,6 +1184,14 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev) | |||
1199 | "data widths, using default 8 bit\n"); | 1184 | "data widths, using default 8 bit\n"); |
1200 | mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; | 1185 | mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; |
1201 | } | 1186 | } |
1187 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) | ||
1188 | mx3_cam->width_flags = 1 << 3; | ||
1189 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) | ||
1190 | mx3_cam->width_flags |= 1 << 7; | ||
1191 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) | ||
1192 | mx3_cam->width_flags |= 1 << 9; | ||
1193 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) | ||
1194 | mx3_cam->width_flags |= 1 << 14; | ||
1202 | 1195 | ||
1203 | mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000; | 1196 | mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000; |
1204 | if (!mx3_cam->mclk) { | 1197 | if (!mx3_cam->mclk) { |
@@ -1281,8 +1274,6 @@ static int __devexit mx3_camera_remove(struct platform_device *pdev) | |||
1281 | 1274 | ||
1282 | dmaengine_put(); | 1275 | dmaengine_put(); |
1283 | 1276 | ||
1284 | dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n"); | ||
1285 | |||
1286 | return 0; | 1277 | return 0; |
1287 | } | 1278 | } |
1288 | 1279 | ||
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 30d8896bb710..9c5c19f142de 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c | |||
@@ -833,6 +833,15 @@ static void omap_vout_buffer_release(struct videobuf_queue *q, | |||
833 | /* | 833 | /* |
834 | * File operations | 834 | * File operations |
835 | */ | 835 | */ |
836 | static unsigned int omap_vout_poll(struct file *file, | ||
837 | struct poll_table_struct *wait) | ||
838 | { | ||
839 | struct omap_vout_device *vout = file->private_data; | ||
840 | struct videobuf_queue *q = &vout->vbq; | ||
841 | |||
842 | return videobuf_poll_stream(file, q, wait); | ||
843 | } | ||
844 | |||
836 | static void omap_vout_vm_open(struct vm_area_struct *vma) | 845 | static void omap_vout_vm_open(struct vm_area_struct *vma) |
837 | { | 846 | { |
838 | struct omap_vout_device *vout = vma->vm_private_data; | 847 | struct omap_vout_device *vout = vma->vm_private_data; |
@@ -1861,6 +1870,7 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = { | |||
1861 | 1870 | ||
1862 | static const struct v4l2_file_operations omap_vout_fops = { | 1871 | static const struct v4l2_file_operations omap_vout_fops = { |
1863 | .owner = THIS_MODULE, | 1872 | .owner = THIS_MODULE, |
1873 | .poll = omap_vout_poll, | ||
1864 | .unlocked_ioctl = video_ioctl2, | 1874 | .unlocked_ioctl = video_ioctl2, |
1865 | .mmap = omap_vout_mmap, | 1875 | .mmap = omap_vout_mmap, |
1866 | .open = omap_vout_open, | 1876 | .open = omap_vout_open, |
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c index 8a947e603aca..e87ae2f634b2 100644 --- a/drivers/media/video/omap1_camera.c +++ b/drivers/media/video/omap1_camera.c | |||
@@ -102,10 +102,10 @@ | |||
102 | /* end of OMAP1 Camera Interface registers */ | 102 | /* end of OMAP1 Camera Interface registers */ |
103 | 103 | ||
104 | 104 | ||
105 | #define SOCAM_BUS_FLAGS (SOCAM_MASTER | \ | 105 | #define SOCAM_BUS_FLAGS (V4L2_MBUS_MASTER | \ |
106 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | \ | 106 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ |
107 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \ | 107 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ |
108 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8) | 108 | V4L2_MBUS_DATA_ACTIVE_HIGH) |
109 | 109 | ||
110 | 110 | ||
111 | #define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1) | 111 | #define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1) |
@@ -1438,41 +1438,55 @@ static int omap1_cam_querycap(struct soc_camera_host *ici, | |||
1438 | static int omap1_cam_set_bus_param(struct soc_camera_device *icd, | 1438 | static int omap1_cam_set_bus_param(struct soc_camera_device *icd, |
1439 | __u32 pixfmt) | 1439 | __u32 pixfmt) |
1440 | { | 1440 | { |
1441 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1441 | struct device *dev = icd->parent; | 1442 | struct device *dev = icd->parent; |
1442 | struct soc_camera_host *ici = to_soc_camera_host(dev); | 1443 | struct soc_camera_host *ici = to_soc_camera_host(dev); |
1443 | struct omap1_cam_dev *pcdev = ici->priv; | 1444 | struct omap1_cam_dev *pcdev = ici->priv; |
1444 | const struct soc_camera_format_xlate *xlate; | 1445 | const struct soc_camera_format_xlate *xlate; |
1445 | const struct soc_mbus_pixelfmt *fmt; | 1446 | const struct soc_mbus_pixelfmt *fmt; |
1446 | unsigned long camera_flags, common_flags; | 1447 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
1448 | unsigned long common_flags; | ||
1447 | u32 ctrlclock, mode; | 1449 | u32 ctrlclock, mode; |
1448 | int ret; | 1450 | int ret; |
1449 | 1451 | ||
1450 | camera_flags = icd->ops->query_bus_param(icd); | 1452 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
1451 | 1453 | if (!ret) { | |
1452 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 1454 | common_flags = soc_mbus_config_compatible(&cfg, SOCAM_BUS_FLAGS); |
1453 | SOCAM_BUS_FLAGS); | 1455 | if (!common_flags) { |
1454 | if (!common_flags) | 1456 | dev_warn(dev, |
1455 | return -EINVAL; | 1457 | "Flags incompatible: camera 0x%x, host 0x%x\n", |
1458 | cfg.flags, SOCAM_BUS_FLAGS); | ||
1459 | return -EINVAL; | ||
1460 | } | ||
1461 | } else if (ret != -ENOIOCTLCMD) { | ||
1462 | return ret; | ||
1463 | } else { | ||
1464 | common_flags = SOCAM_BUS_FLAGS; | ||
1465 | } | ||
1456 | 1466 | ||
1457 | /* Make choices, possibly based on platform configuration */ | 1467 | /* Make choices, possibly based on platform configuration */ |
1458 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 1468 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
1459 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 1469 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
1460 | if (!pcdev->pdata || | 1470 | if (!pcdev->pdata || |
1461 | pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING) | 1471 | pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING) |
1462 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 1472 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
1463 | else | 1473 | else |
1464 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 1474 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
1465 | } | 1475 | } |
1466 | 1476 | ||
1467 | ret = icd->ops->set_bus_param(icd, common_flags); | 1477 | cfg.flags = common_flags; |
1468 | if (ret < 0) | 1478 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
1479 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
1480 | dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", | ||
1481 | common_flags, ret); | ||
1469 | return ret; | 1482 | return ret; |
1483 | } | ||
1470 | 1484 | ||
1471 | ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); | 1485 | ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); |
1472 | if (ctrlclock & LCLK_EN) | 1486 | if (ctrlclock & LCLK_EN) |
1473 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); | 1487 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); |
1474 | 1488 | ||
1475 | if (common_flags & SOCAM_PCLK_SAMPLE_RISING) { | 1489 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) { |
1476 | dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n"); | 1490 | dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n"); |
1477 | ctrlclock |= POLCLK; | 1491 | ctrlclock |= POLCLK; |
1478 | } else { | 1492 | } else { |
@@ -1565,10 +1579,10 @@ static int __init omap1_cam_probe(struct platform_device *pdev) | |||
1565 | pcdev->clk = clk; | 1579 | pcdev->clk = clk; |
1566 | 1580 | ||
1567 | pcdev->pdata = pdev->dev.platform_data; | 1581 | pcdev->pdata = pdev->dev.platform_data; |
1568 | pcdev->pflags = pcdev->pdata->flags; | 1582 | if (pcdev->pdata) { |
1569 | 1583 | pcdev->pflags = pcdev->pdata->flags; | |
1570 | if (pcdev->pdata) | ||
1571 | pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000; | 1584 | pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000; |
1585 | } | ||
1572 | 1586 | ||
1573 | switch (pcdev->camexclk) { | 1587 | switch (pcdev->camexclk) { |
1574 | case 6000000: | 1588 | case 6000000: |
@@ -1578,6 +1592,7 @@ static int __init omap1_cam_probe(struct platform_device *pdev) | |||
1578 | case 24000000: | 1592 | case 24000000: |
1579 | break; | 1593 | break; |
1580 | default: | 1594 | default: |
1595 | /* pcdev->camexclk != 0 => pcdev->pdata != NULL */ | ||
1581 | dev_warn(&pdev->dev, | 1596 | dev_warn(&pdev->dev, |
1582 | "Incorrect sensor clock frequency %ld kHz, " | 1597 | "Incorrect sensor clock frequency %ld kHz, " |
1583 | "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, " | 1598 | "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, " |
@@ -1585,8 +1600,7 @@ static int __init omap1_cam_probe(struct platform_device *pdev) | |||
1585 | pcdev->pdata->camexclk_khz); | 1600 | pcdev->pdata->camexclk_khz); |
1586 | pcdev->camexclk = 0; | 1601 | pcdev->camexclk = 0; |
1587 | case 0: | 1602 | case 0: |
1588 | dev_info(&pdev->dev, | 1603 | dev_info(&pdev->dev, "Not providing sensor clock\n"); |
1589 | "Not providing sensor clock\n"); | ||
1590 | } | 1604 | } |
1591 | 1605 | ||
1592 | INIT_LIST_HEAD(&pcdev->capture); | 1606 | INIT_LIST_HEAD(&pcdev->capture); |
@@ -1716,5 +1730,5 @@ MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg"); | |||
1716 | MODULE_DESCRIPTION("OMAP1 Camera Interface driver"); | 1730 | MODULE_DESCRIPTION("OMAP1 Camera Interface driver"); |
1717 | MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); | 1731 | MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); |
1718 | MODULE_LICENSE("GPL v2"); | 1732 | MODULE_LICENSE("GPL v2"); |
1719 | MODULE_LICENSE(DRIVER_VERSION); | 1733 | MODULE_VERSION(DRIVER_VERSION); |
1720 | MODULE_ALIAS("platform:" DRIVER_NAME); | 1734 | MODULE_ALIAS("platform:" DRIVER_NAME); |
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 678e1252047a..b818cacf420f 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c | |||
@@ -1704,6 +1704,7 @@ static int isp_register_entities(struct isp_device *isp) | |||
1704 | isp->media_dev.dev = isp->dev; | 1704 | isp->media_dev.dev = isp->dev; |
1705 | strlcpy(isp->media_dev.model, "TI OMAP3 ISP", | 1705 | strlcpy(isp->media_dev.model, "TI OMAP3 ISP", |
1706 | sizeof(isp->media_dev.model)); | 1706 | sizeof(isp->media_dev.model)); |
1707 | isp->media_dev.hw_revision = isp->revision; | ||
1707 | isp->media_dev.link_notify = isp_pipeline_link_notify; | 1708 | isp->media_dev.link_notify = isp_pipeline_link_notify; |
1708 | ret = media_device_register(&isp->media_dev); | 1709 | ret = media_device_register(&isp->media_dev); |
1709 | if (ret < 0) { | 1710 | if (ret < 0) { |
@@ -2210,6 +2211,8 @@ error: | |||
2210 | regulator_put(isp->isp_csiphy2.vdd); | 2211 | regulator_put(isp->isp_csiphy2.vdd); |
2211 | regulator_put(isp->isp_csiphy1.vdd); | 2212 | regulator_put(isp->isp_csiphy1.vdd); |
2212 | platform_set_drvdata(pdev, NULL); | 2213 | platform_set_drvdata(pdev, NULL); |
2214 | |||
2215 | mutex_destroy(&isp->isp_mutex); | ||
2213 | kfree(isp); | 2216 | kfree(isp); |
2214 | 2217 | ||
2215 | return ret; | 2218 | return ret; |
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 253fdcce2df2..b0b0fa5a3572 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c | |||
@@ -1836,7 +1836,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | |||
1836 | * callers to request an output size bigger than the input size | 1836 | * callers to request an output size bigger than the input size |
1837 | * up to the nearest multiple of 16. | 1837 | * up to the nearest multiple of 16. |
1838 | */ | 1838 | */ |
1839 | fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); | 1839 | fmt->width = clamp_t(u32, width, 32, fmt->width + 15); |
1840 | fmt->width &= ~15; | 1840 | fmt->width &= ~15; |
1841 | fmt->height = clamp_t(u32, height, 32, fmt->height); | 1841 | fmt->height = clamp_t(u32, height, 32, fmt->height); |
1842 | break; | 1842 | break; |
@@ -2152,6 +2152,37 @@ static const struct media_entity_operations ccdc_media_ops = { | |||
2152 | .link_setup = ccdc_link_setup, | 2152 | .link_setup = ccdc_link_setup, |
2153 | }; | 2153 | }; |
2154 | 2154 | ||
2155 | void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) | ||
2156 | { | ||
2157 | v4l2_device_unregister_subdev(&ccdc->subdev); | ||
2158 | omap3isp_video_unregister(&ccdc->video_out); | ||
2159 | } | ||
2160 | |||
2161 | int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, | ||
2162 | struct v4l2_device *vdev) | ||
2163 | { | ||
2164 | int ret; | ||
2165 | |||
2166 | /* Register the subdev and video node. */ | ||
2167 | ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); | ||
2168 | if (ret < 0) | ||
2169 | goto error; | ||
2170 | |||
2171 | ret = omap3isp_video_register(&ccdc->video_out, vdev); | ||
2172 | if (ret < 0) | ||
2173 | goto error; | ||
2174 | |||
2175 | return 0; | ||
2176 | |||
2177 | error: | ||
2178 | omap3isp_ccdc_unregister_entities(ccdc); | ||
2179 | return ret; | ||
2180 | } | ||
2181 | |||
2182 | /* ----------------------------------------------------------------------------- | ||
2183 | * ISP CCDC initialisation and cleanup | ||
2184 | */ | ||
2185 | |||
2155 | /* | 2186 | /* |
2156 | * ccdc_init_entities - Initialize V4L2 subdev and media entity | 2187 | * ccdc_init_entities - Initialize V4L2 subdev and media entity |
2157 | * @ccdc: ISP CCDC module | 2188 | * @ccdc: ISP CCDC module |
@@ -2193,50 +2224,23 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) | |||
2193 | 2224 | ||
2194 | ret = omap3isp_video_init(&ccdc->video_out, "CCDC"); | 2225 | ret = omap3isp_video_init(&ccdc->video_out, "CCDC"); |
2195 | if (ret < 0) | 2226 | if (ret < 0) |
2196 | return ret; | 2227 | goto error_video; |
2197 | 2228 | ||
2198 | /* Connect the CCDC subdev to the video node. */ | 2229 | /* Connect the CCDC subdev to the video node. */ |
2199 | ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF, | 2230 | ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF, |
2200 | &ccdc->video_out.video.entity, 0, 0); | 2231 | &ccdc->video_out.video.entity, 0, 0); |
2201 | if (ret < 0) | 2232 | if (ret < 0) |
2202 | return ret; | 2233 | goto error_link; |
2203 | |||
2204 | return 0; | ||
2205 | } | ||
2206 | |||
2207 | void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) | ||
2208 | { | ||
2209 | media_entity_cleanup(&ccdc->subdev.entity); | ||
2210 | |||
2211 | v4l2_device_unregister_subdev(&ccdc->subdev); | ||
2212 | omap3isp_video_unregister(&ccdc->video_out); | ||
2213 | } | ||
2214 | |||
2215 | int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, | ||
2216 | struct v4l2_device *vdev) | ||
2217 | { | ||
2218 | int ret; | ||
2219 | |||
2220 | /* Register the subdev and video node. */ | ||
2221 | ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); | ||
2222 | if (ret < 0) | ||
2223 | goto error; | ||
2224 | |||
2225 | ret = omap3isp_video_register(&ccdc->video_out, vdev); | ||
2226 | if (ret < 0) | ||
2227 | goto error; | ||
2228 | 2234 | ||
2229 | return 0; | 2235 | return 0; |
2230 | 2236 | ||
2231 | error: | 2237 | error_link: |
2232 | omap3isp_ccdc_unregister_entities(ccdc); | 2238 | omap3isp_video_cleanup(&ccdc->video_out); |
2239 | error_video: | ||
2240 | media_entity_cleanup(me); | ||
2233 | return ret; | 2241 | return ret; |
2234 | } | 2242 | } |
2235 | 2243 | ||
2236 | /* ----------------------------------------------------------------------------- | ||
2237 | * ISP CCDC initialisation and cleanup | ||
2238 | */ | ||
2239 | |||
2240 | /* | 2244 | /* |
2241 | * omap3isp_ccdc_init - CCDC module initialization. | 2245 | * omap3isp_ccdc_init - CCDC module initialization. |
2242 | * @dev: Device pointer specific to the OMAP3 ISP. | 2246 | * @dev: Device pointer specific to the OMAP3 ISP. |
@@ -2248,6 +2252,7 @@ error: | |||
2248 | int omap3isp_ccdc_init(struct isp_device *isp) | 2252 | int omap3isp_ccdc_init(struct isp_device *isp) |
2249 | { | 2253 | { |
2250 | struct isp_ccdc_device *ccdc = &isp->isp_ccdc; | 2254 | struct isp_ccdc_device *ccdc = &isp->isp_ccdc; |
2255 | int ret; | ||
2251 | 2256 | ||
2252 | spin_lock_init(&ccdc->lock); | 2257 | spin_lock_init(&ccdc->lock); |
2253 | init_waitqueue_head(&ccdc->wait); | 2258 | init_waitqueue_head(&ccdc->wait); |
@@ -2276,7 +2281,13 @@ int omap3isp_ccdc_init(struct isp_device *isp) | |||
2276 | ccdc->update = OMAP3ISP_CCDC_BLCLAMP; | 2281 | ccdc->update = OMAP3ISP_CCDC_BLCLAMP; |
2277 | ccdc_apply_controls(ccdc); | 2282 | ccdc_apply_controls(ccdc); |
2278 | 2283 | ||
2279 | return ccdc_init_entities(ccdc); | 2284 | ret = ccdc_init_entities(ccdc); |
2285 | if (ret < 0) { | ||
2286 | mutex_destroy(&ccdc->ioctl_lock); | ||
2287 | return ret; | ||
2288 | } | ||
2289 | |||
2290 | return 0; | ||
2280 | } | 2291 | } |
2281 | 2292 | ||
2282 | /* | 2293 | /* |
@@ -2287,6 +2298,9 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) | |||
2287 | { | 2298 | { |
2288 | struct isp_ccdc_device *ccdc = &isp->isp_ccdc; | 2299 | struct isp_ccdc_device *ccdc = &isp->isp_ccdc; |
2289 | 2300 | ||
2301 | omap3isp_video_cleanup(&ccdc->video_out); | ||
2302 | media_entity_cleanup(&ccdc->subdev.entity); | ||
2303 | |||
2290 | /* Free LSC requests. As the CCDC is stopped there's no active request, | 2304 | /* Free LSC requests. As the CCDC is stopped there's no active request, |
2291 | * so only the pending request and the free queue need to be handled. | 2305 | * so only the pending request and the free queue need to be handled. |
2292 | */ | 2306 | */ |
@@ -2296,4 +2310,6 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) | |||
2296 | 2310 | ||
2297 | if (ccdc->fpc.fpcaddr != 0) | 2311 | if (ccdc->fpc.fpcaddr != 0) |
2298 | omap_iommu_vfree(isp->domain, isp->iommu, ccdc->fpc.fpcaddr); | 2312 | omap_iommu_vfree(isp->domain, isp->iommu, ccdc->fpc.fpcaddr); |
2313 | |||
2314 | mutex_destroy(&ccdc->ioctl_lock); | ||
2299 | } | 2315 | } |
diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index fa1d09b0ad98..904ca8c8b17f 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c | |||
@@ -1032,6 +1032,48 @@ static const struct media_entity_operations ccp2_media_ops = { | |||
1032 | }; | 1032 | }; |
1033 | 1033 | ||
1034 | /* | 1034 | /* |
1035 | * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev | ||
1036 | * @ccp2: Pointer to ISP CCP2 device | ||
1037 | */ | ||
1038 | void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) | ||
1039 | { | ||
1040 | v4l2_device_unregister_subdev(&ccp2->subdev); | ||
1041 | omap3isp_video_unregister(&ccp2->video_in); | ||
1042 | } | ||
1043 | |||
1044 | /* | ||
1045 | * omap3isp_ccp2_register_entities - Register the subdev media entity | ||
1046 | * @ccp2: Pointer to ISP CCP2 device | ||
1047 | * @vdev: Pointer to v4l device | ||
1048 | * return negative error code or zero on success | ||
1049 | */ | ||
1050 | |||
1051 | int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, | ||
1052 | struct v4l2_device *vdev) | ||
1053 | { | ||
1054 | int ret; | ||
1055 | |||
1056 | /* Register the subdev and video nodes. */ | ||
1057 | ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); | ||
1058 | if (ret < 0) | ||
1059 | goto error; | ||
1060 | |||
1061 | ret = omap3isp_video_register(&ccp2->video_in, vdev); | ||
1062 | if (ret < 0) | ||
1063 | goto error; | ||
1064 | |||
1065 | return 0; | ||
1066 | |||
1067 | error: | ||
1068 | omap3isp_ccp2_unregister_entities(ccp2); | ||
1069 | return ret; | ||
1070 | } | ||
1071 | |||
1072 | /* ----------------------------------------------------------------------------- | ||
1073 | * ISP ccp2 initialisation and cleanup | ||
1074 | */ | ||
1075 | |||
1076 | /* | ||
1035 | * ccp2_init_entities - Initialize ccp2 subdev and media entity. | 1077 | * ccp2_init_entities - Initialize ccp2 subdev and media entity. |
1036 | * @ccp2: Pointer to ISP CCP2 device | 1078 | * @ccp2: Pointer to ISP CCP2 device |
1037 | * return negative error code or zero on success | 1079 | * return negative error code or zero on success |
@@ -1083,72 +1125,23 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) | |||
1083 | 1125 | ||
1084 | ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); | 1126 | ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); |
1085 | if (ret < 0) | 1127 | if (ret < 0) |
1086 | return ret; | 1128 | goto error_video; |
1087 | 1129 | ||
1088 | /* Connect the video node to the ccp2 subdev. */ | 1130 | /* Connect the video node to the ccp2 subdev. */ |
1089 | ret = media_entity_create_link(&ccp2->video_in.video.entity, 0, | 1131 | ret = media_entity_create_link(&ccp2->video_in.video.entity, 0, |
1090 | &ccp2->subdev.entity, CCP2_PAD_SINK, 0); | 1132 | &ccp2->subdev.entity, CCP2_PAD_SINK, 0); |
1091 | if (ret < 0) | 1133 | if (ret < 0) |
1092 | return ret; | 1134 | goto error_link; |
1093 | 1135 | ||
1094 | return 0; | 1136 | return 0; |
1095 | } | ||
1096 | 1137 | ||
1097 | /* | 1138 | error_link: |
1098 | * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev | 1139 | omap3isp_video_cleanup(&ccp2->video_in); |
1099 | * @ccp2: Pointer to ISP CCP2 device | 1140 | error_video: |
1100 | */ | ||
1101 | void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) | ||
1102 | { | ||
1103 | media_entity_cleanup(&ccp2->subdev.entity); | 1141 | media_entity_cleanup(&ccp2->subdev.entity); |
1104 | |||
1105 | v4l2_device_unregister_subdev(&ccp2->subdev); | ||
1106 | omap3isp_video_unregister(&ccp2->video_in); | ||
1107 | } | ||
1108 | |||
1109 | /* | ||
1110 | * omap3isp_ccp2_register_entities - Register the subdev media entity | ||
1111 | * @ccp2: Pointer to ISP CCP2 device | ||
1112 | * @vdev: Pointer to v4l device | ||
1113 | * return negative error code or zero on success | ||
1114 | */ | ||
1115 | |||
1116 | int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, | ||
1117 | struct v4l2_device *vdev) | ||
1118 | { | ||
1119 | int ret; | ||
1120 | |||
1121 | /* Register the subdev and video nodes. */ | ||
1122 | ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); | ||
1123 | if (ret < 0) | ||
1124 | goto error; | ||
1125 | |||
1126 | ret = omap3isp_video_register(&ccp2->video_in, vdev); | ||
1127 | if (ret < 0) | ||
1128 | goto error; | ||
1129 | |||
1130 | return 0; | ||
1131 | |||
1132 | error: | ||
1133 | omap3isp_ccp2_unregister_entities(ccp2); | ||
1134 | return ret; | 1142 | return ret; |
1135 | } | 1143 | } |
1136 | 1144 | ||
1137 | /* ----------------------------------------------------------------------------- | ||
1138 | * ISP ccp2 initialisation and cleanup | ||
1139 | */ | ||
1140 | |||
1141 | /* | ||
1142 | * omap3isp_ccp2_cleanup - CCP2 un-initialization | ||
1143 | * @isp : Pointer to ISP device | ||
1144 | */ | ||
1145 | void omap3isp_ccp2_cleanup(struct isp_device *isp) | ||
1146 | { | ||
1147 | struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; | ||
1148 | |||
1149 | regulator_put(ccp2->vdds_csib); | ||
1150 | } | ||
1151 | |||
1152 | /* | 1145 | /* |
1153 | * omap3isp_ccp2_init - CCP2 initialization. | 1146 | * omap3isp_ccp2_init - CCP2 initialization. |
1154 | * @isp : Pointer to ISP device | 1147 | * @isp : Pointer to ISP device |
@@ -1184,13 +1177,25 @@ int omap3isp_ccp2_init(struct isp_device *isp) | |||
1184 | } | 1177 | } |
1185 | 1178 | ||
1186 | ret = ccp2_init_entities(ccp2); | 1179 | ret = ccp2_init_entities(ccp2); |
1187 | if (ret < 0) | 1180 | if (ret < 0) { |
1188 | goto out; | 1181 | regulator_put(ccp2->vdds_csib); |
1182 | return ret; | ||
1183 | } | ||
1189 | 1184 | ||
1190 | ccp2_reset(ccp2); | 1185 | ccp2_reset(ccp2); |
1191 | out: | 1186 | return 0; |
1192 | if (ret) | 1187 | } |
1193 | omap3isp_ccp2_cleanup(isp); | ||
1194 | 1188 | ||
1195 | return ret; | 1189 | /* |
1190 | * omap3isp_ccp2_cleanup - CCP2 un-initialization | ||
1191 | * @isp : Pointer to ISP device | ||
1192 | */ | ||
1193 | void omap3isp_ccp2_cleanup(struct isp_device *isp) | ||
1194 | { | ||
1195 | struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; | ||
1196 | |||
1197 | omap3isp_video_cleanup(&ccp2->video_in); | ||
1198 | media_entity_cleanup(&ccp2->subdev.entity); | ||
1199 | |||
1200 | regulator_put(ccp2->vdds_csib); | ||
1196 | } | 1201 | } |
diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index 69161a682b3d..0c5f1cb9d99d 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c | |||
@@ -1187,6 +1187,37 @@ static const struct media_entity_operations csi2_media_ops = { | |||
1187 | .link_setup = csi2_link_setup, | 1187 | .link_setup = csi2_link_setup, |
1188 | }; | 1188 | }; |
1189 | 1189 | ||
1190 | void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) | ||
1191 | { | ||
1192 | v4l2_device_unregister_subdev(&csi2->subdev); | ||
1193 | omap3isp_video_unregister(&csi2->video_out); | ||
1194 | } | ||
1195 | |||
1196 | int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, | ||
1197 | struct v4l2_device *vdev) | ||
1198 | { | ||
1199 | int ret; | ||
1200 | |||
1201 | /* Register the subdev and video nodes. */ | ||
1202 | ret = v4l2_device_register_subdev(vdev, &csi2->subdev); | ||
1203 | if (ret < 0) | ||
1204 | goto error; | ||
1205 | |||
1206 | ret = omap3isp_video_register(&csi2->video_out, vdev); | ||
1207 | if (ret < 0) | ||
1208 | goto error; | ||
1209 | |||
1210 | return 0; | ||
1211 | |||
1212 | error: | ||
1213 | omap3isp_csi2_unregister_entities(csi2); | ||
1214 | return ret; | ||
1215 | } | ||
1216 | |||
1217 | /* ----------------------------------------------------------------------------- | ||
1218 | * ISP CSI2 initialisation and cleanup | ||
1219 | */ | ||
1220 | |||
1190 | /* | 1221 | /* |
1191 | * csi2_init_entities - Initialize subdev and media entity. | 1222 | * csi2_init_entities - Initialize subdev and media entity. |
1192 | * @csi2: Pointer to csi2 structure. | 1223 | * @csi2: Pointer to csi2 structure. |
@@ -1228,57 +1259,23 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) | |||
1228 | 1259 | ||
1229 | ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); | 1260 | ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); |
1230 | if (ret < 0) | 1261 | if (ret < 0) |
1231 | return ret; | 1262 | goto error_video; |
1232 | 1263 | ||
1233 | /* Connect the CSI2 subdev to the video node. */ | 1264 | /* Connect the CSI2 subdev to the video node. */ |
1234 | ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE, | 1265 | ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE, |
1235 | &csi2->video_out.video.entity, 0, 0); | 1266 | &csi2->video_out.video.entity, 0, 0); |
1236 | if (ret < 0) | 1267 | if (ret < 0) |
1237 | return ret; | 1268 | goto error_link; |
1238 | 1269 | ||
1239 | return 0; | 1270 | return 0; |
1240 | } | ||
1241 | 1271 | ||
1242 | void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) | 1272 | error_link: |
1243 | { | 1273 | omap3isp_video_cleanup(&csi2->video_out); |
1274 | error_video: | ||
1244 | media_entity_cleanup(&csi2->subdev.entity); | 1275 | media_entity_cleanup(&csi2->subdev.entity); |
1245 | |||
1246 | v4l2_device_unregister_subdev(&csi2->subdev); | ||
1247 | omap3isp_video_unregister(&csi2->video_out); | ||
1248 | } | ||
1249 | |||
1250 | int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, | ||
1251 | struct v4l2_device *vdev) | ||
1252 | { | ||
1253 | int ret; | ||
1254 | |||
1255 | /* Register the subdev and video nodes. */ | ||
1256 | ret = v4l2_device_register_subdev(vdev, &csi2->subdev); | ||
1257 | if (ret < 0) | ||
1258 | goto error; | ||
1259 | |||
1260 | ret = omap3isp_video_register(&csi2->video_out, vdev); | ||
1261 | if (ret < 0) | ||
1262 | goto error; | ||
1263 | |||
1264 | return 0; | ||
1265 | |||
1266 | error: | ||
1267 | omap3isp_csi2_unregister_entities(csi2); | ||
1268 | return ret; | 1276 | return ret; |
1269 | } | 1277 | } |
1270 | 1278 | ||
1271 | /* ----------------------------------------------------------------------------- | ||
1272 | * ISP CSI2 initialisation and cleanup | ||
1273 | */ | ||
1274 | |||
1275 | /* | ||
1276 | * omap3isp_csi2_cleanup - Routine for module driver cleanup | ||
1277 | */ | ||
1278 | void omap3isp_csi2_cleanup(struct isp_device *isp) | ||
1279 | { | ||
1280 | } | ||
1281 | |||
1282 | /* | 1279 | /* |
1283 | * omap3isp_csi2_init - Routine for module driver init | 1280 | * omap3isp_csi2_init - Routine for module driver init |
1284 | */ | 1281 | */ |
@@ -1298,7 +1295,7 @@ int omap3isp_csi2_init(struct isp_device *isp) | |||
1298 | 1295 | ||
1299 | ret = csi2_init_entities(csi2a); | 1296 | ret = csi2_init_entities(csi2a); |
1300 | if (ret < 0) | 1297 | if (ret < 0) |
1301 | goto fail; | 1298 | return ret; |
1302 | 1299 | ||
1303 | if (isp->revision == ISP_REVISION_15_0) { | 1300 | if (isp->revision == ISP_REVISION_15_0) { |
1304 | csi2c->isp = isp; | 1301 | csi2c->isp = isp; |
@@ -1311,7 +1308,15 @@ int omap3isp_csi2_init(struct isp_device *isp) | |||
1311 | } | 1308 | } |
1312 | 1309 | ||
1313 | return 0; | 1310 | return 0; |
1314 | fail: | 1311 | } |
1315 | omap3isp_csi2_cleanup(isp); | 1312 | |
1316 | return ret; | 1313 | /* |
1314 | * omap3isp_csi2_cleanup - Routine for module driver cleanup | ||
1315 | */ | ||
1316 | void omap3isp_csi2_cleanup(struct isp_device *isp) | ||
1317 | { | ||
1318 | struct isp_csi2_device *csi2a = &isp->isp_csi2a; | ||
1319 | |||
1320 | omap3isp_video_cleanup(&csi2a->video_out); | ||
1321 | media_entity_cleanup(&csi2a->subdev.entity); | ||
1317 | } | 1322 | } |
diff --git a/drivers/media/video/omap3isp/isph3a_aewb.c b/drivers/media/video/omap3isp/isph3a_aewb.c index 8068cefd8d89..a3c76bf18175 100644 --- a/drivers/media/video/omap3isp/isph3a_aewb.c +++ b/drivers/media/video/omap3isp/isph3a_aewb.c | |||
@@ -370,5 +370,5 @@ void omap3isp_h3a_aewb_cleanup(struct isp_device *isp) | |||
370 | { | 370 | { |
371 | kfree(isp->isp_aewb.priv); | 371 | kfree(isp->isp_aewb.priv); |
372 | kfree(isp->isp_aewb.recover_priv); | 372 | kfree(isp->isp_aewb.recover_priv); |
373 | omap3isp_stat_free(&isp->isp_aewb); | 373 | omap3isp_stat_cleanup(&isp->isp_aewb); |
374 | } | 374 | } |
diff --git a/drivers/media/video/omap3isp/isph3a_af.c b/drivers/media/video/omap3isp/isph3a_af.c index ba54d0acdecf..58e0bc414899 100644 --- a/drivers/media/video/omap3isp/isph3a_af.c +++ b/drivers/media/video/omap3isp/isph3a_af.c | |||
@@ -425,5 +425,5 @@ void omap3isp_h3a_af_cleanup(struct isp_device *isp) | |||
425 | { | 425 | { |
426 | kfree(isp->isp_af.priv); | 426 | kfree(isp->isp_af.priv); |
427 | kfree(isp->isp_af.recover_priv); | 427 | kfree(isp->isp_af.recover_priv); |
428 | omap3isp_stat_free(&isp->isp_af); | 428 | omap3isp_stat_cleanup(&isp->isp_af); |
429 | } | 429 | } |
diff --git a/drivers/media/video/omap3isp/isphist.c b/drivers/media/video/omap3isp/isphist.c index 1743856b30d1..1163907bcddc 100644 --- a/drivers/media/video/omap3isp/isphist.c +++ b/drivers/media/video/omap3isp/isphist.c | |||
@@ -516,5 +516,5 @@ void omap3isp_hist_cleanup(struct isp_device *isp) | |||
516 | if (HIST_USING_DMA(&isp->isp_hist)) | 516 | if (HIST_USING_DMA(&isp->isp_hist)) |
517 | omap_free_dma(isp->isp_hist.dma_ch); | 517 | omap_free_dma(isp->isp_hist.dma_ch); |
518 | kfree(isp->isp_hist.priv); | 518 | kfree(isp->isp_hist.priv); |
519 | omap3isp_stat_free(&isp->isp_hist); | 519 | omap3isp_stat_cleanup(&isp->isp_hist); |
520 | } | 520 | } |
diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index aba537af87e4..ccb876fe023f 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c | |||
@@ -76,9 +76,51 @@ static struct omap3isp_prev_csc flr_prev_csc = { | |||
76 | 76 | ||
77 | #define DEF_DETECT_CORRECT_VAL 0xe | 77 | #define DEF_DETECT_CORRECT_VAL 0xe |
78 | 78 | ||
79 | #define PREV_MIN_WIDTH 64 | 79 | /* |
80 | #define PREV_MIN_HEIGHT 8 | 80 | * Margins and image size limits. |
81 | #define PREV_MAX_HEIGHT 16384 | 81 | * |
82 | * The preview engine crops several rows and columns internally depending on | ||
83 | * which filters are enabled. To avoid format changes when the filters are | ||
84 | * enabled or disabled (which would prevent them from being turned on or off | ||
85 | * during streaming), the driver assumes all the filters are enabled when | ||
86 | * computing sink crop and source format limits. | ||
87 | * | ||
88 | * If a filter is disabled, additional cropping is automatically added at the | ||
89 | * preview engine input by the driver to avoid overflow at line and frame end. | ||
90 | * This is completely transparent for applications. | ||
91 | * | ||
92 | * Median filter 4 pixels | ||
93 | * Noise filter, | ||
94 | * Faulty pixels correction 4 pixels, 4 lines | ||
95 | * CFA filter 4 pixels, 4 lines in Bayer mode | ||
96 | * 2 lines in other modes | ||
97 | * Color suppression 2 pixels | ||
98 | * or luma enhancement | ||
99 | * ------------------------------------------------------------- | ||
100 | * Maximum total 14 pixels, 8 lines | ||
101 | * | ||
102 | * The color suppression and luma enhancement filters are applied after bayer to | ||
103 | * YUV conversion. They thus can crop one pixel on the left and one pixel on the | ||
104 | * right side of the image without changing the color pattern. When both those | ||
105 | * filters are disabled, the driver must crop the two pixels on the same side of | ||
106 | * the image to avoid changing the bayer pattern. The left margin is thus set to | ||
107 | * 8 pixels and the right margin to 6 pixels. | ||
108 | */ | ||
109 | |||
110 | #define PREV_MARGIN_LEFT 8 | ||
111 | #define PREV_MARGIN_RIGHT 6 | ||
112 | #define PREV_MARGIN_TOP 4 | ||
113 | #define PREV_MARGIN_BOTTOM 4 | ||
114 | |||
115 | #define PREV_MIN_IN_WIDTH 64 | ||
116 | #define PREV_MIN_IN_HEIGHT 8 | ||
117 | #define PREV_MAX_IN_HEIGHT 16384 | ||
118 | |||
119 | #define PREV_MIN_OUT_WIDTH 0 | ||
120 | #define PREV_MIN_OUT_HEIGHT 0 | ||
121 | #define PREV_MAX_OUT_WIDTH 1280 | ||
122 | #define PREV_MAX_OUT_WIDTH_ES2 3300 | ||
123 | #define PREV_MAX_OUT_WIDTH_3630 4096 | ||
82 | 124 | ||
83 | /* | 125 | /* |
84 | * Coeficient Tables for the submodules in Preview. | 126 | * Coeficient Tables for the submodules in Preview. |
@@ -979,52 +1021,36 @@ static void preview_config_averager(struct isp_prev_device *prev, u8 average) | |||
979 | * enabled when reporting source pad formats to userspace. If this assumption is | 1021 | * enabled when reporting source pad formats to userspace. If this assumption is |
980 | * not true, rows and columns must be manually cropped at the preview engine | 1022 | * not true, rows and columns must be manually cropped at the preview engine |
981 | * input to avoid overflows at the end of lines and frames. | 1023 | * input to avoid overflows at the end of lines and frames. |
1024 | * | ||
1025 | * See the explanation at the PREV_MARGIN_* definitions for more details. | ||
982 | */ | 1026 | */ |
983 | static void preview_config_input_size(struct isp_prev_device *prev) | 1027 | static void preview_config_input_size(struct isp_prev_device *prev) |
984 | { | 1028 | { |
985 | struct isp_device *isp = to_isp_device(prev); | 1029 | struct isp_device *isp = to_isp_device(prev); |
986 | struct prev_params *params = &prev->params; | 1030 | struct prev_params *params = &prev->params; |
987 | struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK]; | 1031 | unsigned int sph = prev->crop.left; |
988 | unsigned int sph = 0; | 1032 | unsigned int eph = prev->crop.left + prev->crop.width - 1; |
989 | unsigned int eph = format->width - 1; | 1033 | unsigned int slv = prev->crop.top; |
990 | unsigned int slv = 0; | 1034 | unsigned int elv = prev->crop.top + prev->crop.height - 1; |
991 | unsigned int elv = format->height - 1; | 1035 | |
992 | 1036 | if (params->features & PREV_CFA) { | |
993 | if (prev->input == PREVIEW_INPUT_CCDC) { | 1037 | sph -= 2; |
994 | sph += 2; | 1038 | eph += 2; |
995 | eph -= 2; | 1039 | slv -= 2; |
1040 | elv += 2; | ||
996 | } | 1041 | } |
997 | 1042 | if (params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER)) { | |
998 | /* | 1043 | sph -= 2; |
999 | * Median filter 4 pixels | 1044 | eph += 2; |
1000 | * Noise filter 4 pixels, 4 lines | 1045 | slv -= 2; |
1001 | * or faulty pixels correction | 1046 | elv += 2; |
1002 | * CFA filter 4 pixels, 4 lines in Bayer mode | ||
1003 | * 2 lines in other modes | ||
1004 | * Color suppression 2 pixels | ||
1005 | * or luma enhancement | ||
1006 | * ------------------------------------------------------------- | ||
1007 | * Maximum total 14 pixels, 8 lines | ||
1008 | */ | ||
1009 | |||
1010 | if (!(params->features & PREV_CFA)) { | ||
1011 | sph += 2; | ||
1012 | eph -= 2; | ||
1013 | slv += 2; | ||
1014 | elv -= 2; | ||
1015 | } | 1047 | } |
1016 | if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) { | 1048 | if (params->features & PREV_HORZ_MEDIAN_FILTER) { |
1017 | sph += 2; | 1049 | sph -= 2; |
1018 | eph -= 2; | 1050 | eph += 2; |
1019 | slv += 2; | ||
1020 | elv -= 2; | ||
1021 | } | 1051 | } |
1022 | if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) { | 1052 | if (params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE)) |
1023 | sph += 2; | 1053 | sph -= 2; |
1024 | eph -= 2; | ||
1025 | } | ||
1026 | if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE))) | ||
1027 | sph += 2; | ||
1028 | 1054 | ||
1029 | isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, | 1055 | isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, |
1030 | OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); | 1056 | OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); |
@@ -1228,7 +1254,6 @@ static void preview_init_params(struct isp_prev_device *prev) | |||
1228 | /* Init values */ | 1254 | /* Init values */ |
1229 | params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; | 1255 | params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; |
1230 | params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; | 1256 | params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; |
1231 | params->average = NO_AVE; | ||
1232 | params->cfa.format = OMAP3ISP_CFAFMT_BAYER; | 1257 | params->cfa.format = OMAP3ISP_CFAFMT_BAYER; |
1233 | memcpy(params->cfa.table, cfa_coef_table, | 1258 | memcpy(params->cfa.table, cfa_coef_table, |
1234 | sizeof(params->cfa.table)); | 1259 | sizeof(params->cfa.table)); |
@@ -1281,14 +1306,14 @@ static unsigned int preview_max_out_width(struct isp_prev_device *prev) | |||
1281 | 1306 | ||
1282 | switch (isp->revision) { | 1307 | switch (isp->revision) { |
1283 | case ISP_REVISION_1_0: | 1308 | case ISP_REVISION_1_0: |
1284 | return ISPPRV_MAXOUTPUT_WIDTH; | 1309 | return PREV_MAX_OUT_WIDTH; |
1285 | 1310 | ||
1286 | case ISP_REVISION_2_0: | 1311 | case ISP_REVISION_2_0: |
1287 | default: | 1312 | default: |
1288 | return ISPPRV_MAXOUTPUT_WIDTH_ES2; | 1313 | return PREV_MAX_OUT_WIDTH_ES2; |
1289 | 1314 | ||
1290 | case ISP_REVISION_15_0: | 1315 | case ISP_REVISION_15_0: |
1291 | return ISPPRV_MAXOUTPUT_WIDTH_3630; | 1316 | return PREV_MAX_OUT_WIDTH_3630; |
1292 | } | 1317 | } |
1293 | } | 1318 | } |
1294 | 1319 | ||
@@ -1296,8 +1321,6 @@ static void preview_configure(struct isp_prev_device *prev) | |||
1296 | { | 1321 | { |
1297 | struct isp_device *isp = to_isp_device(prev); | 1322 | struct isp_device *isp = to_isp_device(prev); |
1298 | struct v4l2_mbus_framefmt *format; | 1323 | struct v4l2_mbus_framefmt *format; |
1299 | unsigned int max_out_width; | ||
1300 | unsigned int format_avg; | ||
1301 | 1324 | ||
1302 | preview_setup_hw(prev); | 1325 | preview_setup_hw(prev); |
1303 | 1326 | ||
@@ -1335,10 +1358,7 @@ static void preview_configure(struct isp_prev_device *prev) | |||
1335 | preview_config_outlineoffset(prev, | 1358 | preview_config_outlineoffset(prev, |
1336 | ALIGN(format->width, 0x10) * 2); | 1359 | ALIGN(format->width, 0x10) * 2); |
1337 | 1360 | ||
1338 | max_out_width = preview_max_out_width(prev); | 1361 | preview_config_averager(prev, 0); |
1339 | |||
1340 | format_avg = fls(DIV_ROUND_UP(format->width, max_out_width) - 1); | ||
1341 | preview_config_averager(prev, format_avg); | ||
1342 | preview_config_ycpos(prev, format->code); | 1362 | preview_config_ycpos(prev, format->code); |
1343 | } | 1363 | } |
1344 | 1364 | ||
@@ -1597,6 +1617,16 @@ __preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, | |||
1597 | return &prev->formats[pad]; | 1617 | return &prev->formats[pad]; |
1598 | } | 1618 | } |
1599 | 1619 | ||
1620 | static struct v4l2_rect * | ||
1621 | __preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, | ||
1622 | enum v4l2_subdev_format_whence which) | ||
1623 | { | ||
1624 | if (which == V4L2_SUBDEV_FORMAT_TRY) | ||
1625 | return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK); | ||
1626 | else | ||
1627 | return &prev->crop; | ||
1628 | } | ||
1629 | |||
1600 | /* previewer format descriptions */ | 1630 | /* previewer format descriptions */ |
1601 | static const unsigned int preview_input_fmts[] = { | 1631 | static const unsigned int preview_input_fmts[] = { |
1602 | V4L2_MBUS_FMT_SGRBG10_1X10, | 1632 | V4L2_MBUS_FMT_SGRBG10_1X10, |
@@ -1611,24 +1641,25 @@ static const unsigned int preview_output_fmts[] = { | |||
1611 | }; | 1641 | }; |
1612 | 1642 | ||
1613 | /* | 1643 | /* |
1614 | * preview_try_format - Handle try format by pad subdev method | 1644 | * preview_try_format - Validate a format |
1615 | * @prev: ISP preview device | 1645 | * @prev: ISP preview engine |
1616 | * @fh : V4L2 subdev file handle | 1646 | * @fh: V4L2 subdev file handle |
1617 | * @pad: pad num | 1647 | * @pad: pad number |
1618 | * @fmt: pointer to v4l2 format structure | 1648 | * @fmt: format to be validated |
1649 | * @which: try/active format selector | ||
1650 | * | ||
1651 | * Validate and adjust the given format for the given pad based on the preview | ||
1652 | * engine limits and the format and crop rectangles on other pads. | ||
1619 | */ | 1653 | */ |
1620 | static void preview_try_format(struct isp_prev_device *prev, | 1654 | static void preview_try_format(struct isp_prev_device *prev, |
1621 | struct v4l2_subdev_fh *fh, unsigned int pad, | 1655 | struct v4l2_subdev_fh *fh, unsigned int pad, |
1622 | struct v4l2_mbus_framefmt *fmt, | 1656 | struct v4l2_mbus_framefmt *fmt, |
1623 | enum v4l2_subdev_format_whence which) | 1657 | enum v4l2_subdev_format_whence which) |
1624 | { | 1658 | { |
1625 | struct v4l2_mbus_framefmt *format; | ||
1626 | unsigned int max_out_width; | ||
1627 | enum v4l2_mbus_pixelcode pixelcode; | 1659 | enum v4l2_mbus_pixelcode pixelcode; |
1660 | struct v4l2_rect *crop; | ||
1628 | unsigned int i; | 1661 | unsigned int i; |
1629 | 1662 | ||
1630 | max_out_width = preview_max_out_width(prev); | ||
1631 | |||
1632 | switch (pad) { | 1663 | switch (pad) { |
1633 | case PREV_PAD_SINK: | 1664 | case PREV_PAD_SINK: |
1634 | /* When reading data from the CCDC, the input size has already | 1665 | /* When reading data from the CCDC, the input size has already |
@@ -1641,10 +1672,11 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
1641 | * filter array interpolation. | 1672 | * filter array interpolation. |
1642 | */ | 1673 | */ |
1643 | if (prev->input == PREVIEW_INPUT_MEMORY) { | 1674 | if (prev->input == PREVIEW_INPUT_MEMORY) { |
1644 | fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH, | 1675 | fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH, |
1645 | max_out_width * 8); | 1676 | preview_max_out_width(prev)); |
1646 | fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT, | 1677 | fmt->height = clamp_t(u32, fmt->height, |
1647 | PREV_MAX_HEIGHT); | 1678 | PREV_MIN_IN_HEIGHT, |
1679 | PREV_MAX_IN_HEIGHT); | ||
1648 | } | 1680 | } |
1649 | 1681 | ||
1650 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | 1682 | fmt->colorspace = V4L2_COLORSPACE_SRGB; |
@@ -1661,15 +1693,8 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
1661 | 1693 | ||
1662 | case PREV_PAD_SOURCE: | 1694 | case PREV_PAD_SOURCE: |
1663 | pixelcode = fmt->code; | 1695 | pixelcode = fmt->code; |
1664 | format = __preview_get_format(prev, fh, PREV_PAD_SINK, which); | 1696 | *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which); |
1665 | memcpy(fmt, format, sizeof(*fmt)); | ||
1666 | 1697 | ||
1667 | /* The preview module output size is configurable through the | ||
1668 | * input interface (horizontal and vertical cropping) and the | ||
1669 | * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In | ||
1670 | * spite of this, hardcode the output size to the biggest | ||
1671 | * possible value for simplicity reasons. | ||
1672 | */ | ||
1673 | switch (pixelcode) { | 1698 | switch (pixelcode) { |
1674 | case V4L2_MBUS_FMT_YUYV8_1X16: | 1699 | case V4L2_MBUS_FMT_YUYV8_1X16: |
1675 | case V4L2_MBUS_FMT_UYVY8_1X16: | 1700 | case V4L2_MBUS_FMT_UYVY8_1X16: |
@@ -1681,31 +1706,14 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
1681 | break; | 1706 | break; |
1682 | } | 1707 | } |
1683 | 1708 | ||
1684 | /* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped | 1709 | /* The preview module output size is configurable through the |
1685 | * from the left and right sides when the input source is the | 1710 | * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This |
1686 | * CCDC. This seems not to be needed in practice, investigation | 1711 | * is not supported yet, hardcode the output size to the crop |
1687 | * is required. | 1712 | * rectangle size. |
1688 | */ | ||
1689 | if (prev->input == PREVIEW_INPUT_CCDC) | ||
1690 | fmt->width -= 4; | ||
1691 | |||
1692 | /* The preview module can output a maximum of 3312 pixels | ||
1693 | * horizontally due to fixed memory-line sizes. Compute the | ||
1694 | * horizontal averaging factor accordingly. Note that the limit | ||
1695 | * applies to the noise filter and CFA interpolation blocks, so | ||
1696 | * it doesn't take cropping by further blocks into account. | ||
1697 | * | ||
1698 | * ES 1.0 hardware revision is limited to 1280 pixels | ||
1699 | * horizontally. | ||
1700 | */ | ||
1701 | fmt->width >>= fls(DIV_ROUND_UP(fmt->width, max_out_width) - 1); | ||
1702 | |||
1703 | /* Assume that all blocks are enabled and crop pixels and lines | ||
1704 | * accordingly. See preview_config_input_size() for more | ||
1705 | * information. | ||
1706 | */ | 1713 | */ |
1707 | fmt->width -= 14; | 1714 | crop = __preview_get_crop(prev, fh, which); |
1708 | fmt->height -= 8; | 1715 | fmt->width = crop->width; |
1716 | fmt->height = crop->height; | ||
1709 | 1717 | ||
1710 | fmt->colorspace = V4L2_COLORSPACE_JPEG; | 1718 | fmt->colorspace = V4L2_COLORSPACE_JPEG; |
1711 | break; | 1719 | break; |
@@ -1715,6 +1723,49 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
1715 | } | 1723 | } |
1716 | 1724 | ||
1717 | /* | 1725 | /* |
1726 | * preview_try_crop - Validate a crop rectangle | ||
1727 | * @prev: ISP preview engine | ||
1728 | * @sink: format on the sink pad | ||
1729 | * @crop: crop rectangle to be validated | ||
1730 | * | ||
1731 | * The preview engine crops lines and columns for its internal operation, | ||
1732 | * depending on which filters are enabled. Enforce minimum crop margins to | ||
1733 | * handle that transparently for userspace. | ||
1734 | * | ||
1735 | * See the explanation at the PREV_MARGIN_* definitions for more details. | ||
1736 | */ | ||
1737 | static void preview_try_crop(struct isp_prev_device *prev, | ||
1738 | const struct v4l2_mbus_framefmt *sink, | ||
1739 | struct v4l2_rect *crop) | ||
1740 | { | ||
1741 | unsigned int left = PREV_MARGIN_LEFT; | ||
1742 | unsigned int right = sink->width - PREV_MARGIN_RIGHT; | ||
1743 | unsigned int top = PREV_MARGIN_TOP; | ||
1744 | unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM; | ||
1745 | |||
1746 | /* When processing data on-the-fly from the CCDC, at least 2 pixels must | ||
1747 | * be cropped from the left and right sides of the image. As we don't | ||
1748 | * know which filters will be enabled, increase the left and right | ||
1749 | * margins by two. | ||
1750 | */ | ||
1751 | if (prev->input == PREVIEW_INPUT_CCDC) { | ||
1752 | left += 2; | ||
1753 | right -= 2; | ||
1754 | } | ||
1755 | |||
1756 | /* Restrict left/top to even values to keep the Bayer pattern. */ | ||
1757 | crop->left &= ~1; | ||
1758 | crop->top &= ~1; | ||
1759 | |||
1760 | crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH); | ||
1761 | crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT); | ||
1762 | crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH, | ||
1763 | right - crop->left); | ||
1764 | crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT, | ||
1765 | bottom - crop->top); | ||
1766 | } | ||
1767 | |||
1768 | /* | ||
1718 | * preview_enum_mbus_code - Handle pixel format enumeration | 1769 | * preview_enum_mbus_code - Handle pixel format enumeration |
1719 | * @sd : pointer to v4l2 subdev structure | 1770 | * @sd : pointer to v4l2 subdev structure |
1720 | * @fh : V4L2 subdev file handle | 1771 | * @fh : V4L2 subdev file handle |
@@ -1776,6 +1827,60 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, | |||
1776 | } | 1827 | } |
1777 | 1828 | ||
1778 | /* | 1829 | /* |
1830 | * preview_get_crop - Retrieve the crop rectangle on a pad | ||
1831 | * @sd: ISP preview V4L2 subdevice | ||
1832 | * @fh: V4L2 subdev file handle | ||
1833 | * @crop: crop rectangle | ||
1834 | * | ||
1835 | * Return 0 on success or a negative error code otherwise. | ||
1836 | */ | ||
1837 | static int preview_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
1838 | struct v4l2_subdev_crop *crop) | ||
1839 | { | ||
1840 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | ||
1841 | |||
1842 | /* Cropping is only supported on the sink pad. */ | ||
1843 | if (crop->pad != PREV_PAD_SINK) | ||
1844 | return -EINVAL; | ||
1845 | |||
1846 | crop->rect = *__preview_get_crop(prev, fh, crop->which); | ||
1847 | return 0; | ||
1848 | } | ||
1849 | |||
1850 | /* | ||
1851 | * preview_set_crop - Retrieve the crop rectangle on a pad | ||
1852 | * @sd: ISP preview V4L2 subdevice | ||
1853 | * @fh: V4L2 subdev file handle | ||
1854 | * @crop: crop rectangle | ||
1855 | * | ||
1856 | * Return 0 on success or a negative error code otherwise. | ||
1857 | */ | ||
1858 | static int preview_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
1859 | struct v4l2_subdev_crop *crop) | ||
1860 | { | ||
1861 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | ||
1862 | struct v4l2_mbus_framefmt *format; | ||
1863 | |||
1864 | /* Cropping is only supported on the sink pad. */ | ||
1865 | if (crop->pad != PREV_PAD_SINK) | ||
1866 | return -EINVAL; | ||
1867 | |||
1868 | /* The crop rectangle can't be changed while streaming. */ | ||
1869 | if (prev->state != ISP_PIPELINE_STREAM_STOPPED) | ||
1870 | return -EBUSY; | ||
1871 | |||
1872 | format = __preview_get_format(prev, fh, PREV_PAD_SINK, crop->which); | ||
1873 | preview_try_crop(prev, format, &crop->rect); | ||
1874 | *__preview_get_crop(prev, fh, crop->which) = crop->rect; | ||
1875 | |||
1876 | /* Update the source format. */ | ||
1877 | format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, crop->which); | ||
1878 | preview_try_format(prev, fh, PREV_PAD_SOURCE, format, crop->which); | ||
1879 | |||
1880 | return 0; | ||
1881 | } | ||
1882 | |||
1883 | /* | ||
1779 | * preview_get_format - Handle get format by pads subdev method | 1884 | * preview_get_format - Handle get format by pads subdev method |
1780 | * @sd : pointer to v4l2 subdev structure | 1885 | * @sd : pointer to v4l2 subdev structure |
1781 | * @fh : V4L2 subdev file handle | 1886 | * @fh : V4L2 subdev file handle |
@@ -1808,6 +1913,7 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
1808 | { | 1913 | { |
1809 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | 1914 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); |
1810 | struct v4l2_mbus_framefmt *format; | 1915 | struct v4l2_mbus_framefmt *format; |
1916 | struct v4l2_rect *crop; | ||
1811 | 1917 | ||
1812 | format = __preview_get_format(prev, fh, fmt->pad, fmt->which); | 1918 | format = __preview_get_format(prev, fh, fmt->pad, fmt->which); |
1813 | if (format == NULL) | 1919 | if (format == NULL) |
@@ -1818,9 +1924,18 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
1818 | 1924 | ||
1819 | /* Propagate the format from sink to source */ | 1925 | /* Propagate the format from sink to source */ |
1820 | if (fmt->pad == PREV_PAD_SINK) { | 1926 | if (fmt->pad == PREV_PAD_SINK) { |
1927 | /* Reset the crop rectangle. */ | ||
1928 | crop = __preview_get_crop(prev, fh, fmt->which); | ||
1929 | crop->left = 0; | ||
1930 | crop->top = 0; | ||
1931 | crop->width = fmt->format.width; | ||
1932 | crop->height = fmt->format.height; | ||
1933 | |||
1934 | preview_try_crop(prev, &fmt->format, crop); | ||
1935 | |||
1936 | /* Update the source format. */ | ||
1821 | format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, | 1937 | format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, |
1822 | fmt->which); | 1938 | fmt->which); |
1823 | *format = fmt->format; | ||
1824 | preview_try_format(prev, fh, PREV_PAD_SOURCE, format, | 1939 | preview_try_format(prev, fh, PREV_PAD_SOURCE, format, |
1825 | fmt->which); | 1940 | fmt->which); |
1826 | } | 1941 | } |
@@ -1869,6 +1984,8 @@ static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = { | |||
1869 | .enum_frame_size = preview_enum_frame_size, | 1984 | .enum_frame_size = preview_enum_frame_size, |
1870 | .get_fmt = preview_get_format, | 1985 | .get_fmt = preview_get_format, |
1871 | .set_fmt = preview_set_format, | 1986 | .set_fmt = preview_set_format, |
1987 | .get_crop = preview_get_crop, | ||
1988 | .set_crop = preview_set_crop, | ||
1872 | }; | 1989 | }; |
1873 | 1990 | ||
1874 | /* subdev operations */ | 1991 | /* subdev operations */ |
@@ -1966,8 +2083,44 @@ static const struct media_entity_operations preview_media_ops = { | |||
1966 | .link_setup = preview_link_setup, | 2083 | .link_setup = preview_link_setup, |
1967 | }; | 2084 | }; |
1968 | 2085 | ||
2086 | void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) | ||
2087 | { | ||
2088 | v4l2_device_unregister_subdev(&prev->subdev); | ||
2089 | omap3isp_video_unregister(&prev->video_in); | ||
2090 | omap3isp_video_unregister(&prev->video_out); | ||
2091 | } | ||
2092 | |||
2093 | int omap3isp_preview_register_entities(struct isp_prev_device *prev, | ||
2094 | struct v4l2_device *vdev) | ||
2095 | { | ||
2096 | int ret; | ||
2097 | |||
2098 | /* Register the subdev and video nodes. */ | ||
2099 | ret = v4l2_device_register_subdev(vdev, &prev->subdev); | ||
2100 | if (ret < 0) | ||
2101 | goto error; | ||
2102 | |||
2103 | ret = omap3isp_video_register(&prev->video_in, vdev); | ||
2104 | if (ret < 0) | ||
2105 | goto error; | ||
2106 | |||
2107 | ret = omap3isp_video_register(&prev->video_out, vdev); | ||
2108 | if (ret < 0) | ||
2109 | goto error; | ||
2110 | |||
2111 | return 0; | ||
2112 | |||
2113 | error: | ||
2114 | omap3isp_preview_unregister_entities(prev); | ||
2115 | return ret; | ||
2116 | } | ||
2117 | |||
2118 | /* ----------------------------------------------------------------------------- | ||
2119 | * ISP previewer initialisation and cleanup | ||
2120 | */ | ||
2121 | |||
1969 | /* | 2122 | /* |
1970 | * review_init_entities - Initialize subdev and media entity. | 2123 | * preview_init_entities - Initialize subdev and media entity. |
1971 | * @prev : Pointer to preview structure | 2124 | * @prev : Pointer to preview structure |
1972 | * return -ENOMEM or zero on success | 2125 | * return -ENOMEM or zero on success |
1973 | */ | 2126 | */ |
@@ -2024,69 +2177,34 @@ static int preview_init_entities(struct isp_prev_device *prev) | |||
2024 | 2177 | ||
2025 | ret = omap3isp_video_init(&prev->video_in, "preview"); | 2178 | ret = omap3isp_video_init(&prev->video_in, "preview"); |
2026 | if (ret < 0) | 2179 | if (ret < 0) |
2027 | return ret; | 2180 | goto error_video_in; |
2028 | 2181 | ||
2029 | ret = omap3isp_video_init(&prev->video_out, "preview"); | 2182 | ret = omap3isp_video_init(&prev->video_out, "preview"); |
2030 | if (ret < 0) | 2183 | if (ret < 0) |
2031 | return ret; | 2184 | goto error_video_out; |
2032 | 2185 | ||
2033 | /* Connect the video nodes to the previewer subdev. */ | 2186 | /* Connect the video nodes to the previewer subdev. */ |
2034 | ret = media_entity_create_link(&prev->video_in.video.entity, 0, | 2187 | ret = media_entity_create_link(&prev->video_in.video.entity, 0, |
2035 | &prev->subdev.entity, PREV_PAD_SINK, 0); | 2188 | &prev->subdev.entity, PREV_PAD_SINK, 0); |
2036 | if (ret < 0) | 2189 | if (ret < 0) |
2037 | return ret; | 2190 | goto error_link; |
2038 | 2191 | ||
2039 | ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, | 2192 | ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, |
2040 | &prev->video_out.video.entity, 0, 0); | 2193 | &prev->video_out.video.entity, 0, 0); |
2041 | if (ret < 0) | 2194 | if (ret < 0) |
2042 | return ret; | 2195 | goto error_link; |
2043 | 2196 | ||
2044 | return 0; | 2197 | return 0; |
2045 | } | ||
2046 | 2198 | ||
2047 | void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) | 2199 | error_link: |
2048 | { | 2200 | omap3isp_video_cleanup(&prev->video_out); |
2201 | error_video_out: | ||
2202 | omap3isp_video_cleanup(&prev->video_in); | ||
2203 | error_video_in: | ||
2049 | media_entity_cleanup(&prev->subdev.entity); | 2204 | media_entity_cleanup(&prev->subdev.entity); |
2050 | |||
2051 | v4l2_device_unregister_subdev(&prev->subdev); | ||
2052 | v4l2_ctrl_handler_free(&prev->ctrls); | ||
2053 | omap3isp_video_unregister(&prev->video_in); | ||
2054 | omap3isp_video_unregister(&prev->video_out); | ||
2055 | } | ||
2056 | |||
2057 | int omap3isp_preview_register_entities(struct isp_prev_device *prev, | ||
2058 | struct v4l2_device *vdev) | ||
2059 | { | ||
2060 | int ret; | ||
2061 | |||
2062 | /* Register the subdev and video nodes. */ | ||
2063 | ret = v4l2_device_register_subdev(vdev, &prev->subdev); | ||
2064 | if (ret < 0) | ||
2065 | goto error; | ||
2066 | |||
2067 | ret = omap3isp_video_register(&prev->video_in, vdev); | ||
2068 | if (ret < 0) | ||
2069 | goto error; | ||
2070 | |||
2071 | ret = omap3isp_video_register(&prev->video_out, vdev); | ||
2072 | if (ret < 0) | ||
2073 | goto error; | ||
2074 | |||
2075 | return 0; | ||
2076 | |||
2077 | error: | ||
2078 | omap3isp_preview_unregister_entities(prev); | ||
2079 | return ret; | 2205 | return ret; |
2080 | } | 2206 | } |
2081 | 2207 | ||
2082 | /* ----------------------------------------------------------------------------- | ||
2083 | * ISP previewer initialisation and cleanup | ||
2084 | */ | ||
2085 | |||
2086 | void omap3isp_preview_cleanup(struct isp_device *isp) | ||
2087 | { | ||
2088 | } | ||
2089 | |||
2090 | /* | 2208 | /* |
2091 | * isp_preview_init - Previewer initialization. | 2209 | * isp_preview_init - Previewer initialization. |
2092 | * @dev : Pointer to ISP device | 2210 | * @dev : Pointer to ISP device |
@@ -2095,19 +2213,20 @@ void omap3isp_preview_cleanup(struct isp_device *isp) | |||
2095 | int omap3isp_preview_init(struct isp_device *isp) | 2213 | int omap3isp_preview_init(struct isp_device *isp) |
2096 | { | 2214 | { |
2097 | struct isp_prev_device *prev = &isp->isp_prev; | 2215 | struct isp_prev_device *prev = &isp->isp_prev; |
2098 | int ret; | ||
2099 | 2216 | ||
2100 | spin_lock_init(&prev->lock); | 2217 | spin_lock_init(&prev->lock); |
2101 | init_waitqueue_head(&prev->wait); | 2218 | init_waitqueue_head(&prev->wait); |
2102 | preview_init_params(prev); | 2219 | preview_init_params(prev); |
2103 | 2220 | ||
2104 | ret = preview_init_entities(prev); | 2221 | return preview_init_entities(prev); |
2105 | if (ret < 0) | 2222 | } |
2106 | goto out; | ||
2107 | 2223 | ||
2108 | out: | 2224 | void omap3isp_preview_cleanup(struct isp_device *isp) |
2109 | if (ret) | 2225 | { |
2110 | omap3isp_preview_cleanup(isp); | 2226 | struct isp_prev_device *prev = &isp->isp_prev; |
2111 | 2227 | ||
2112 | return ret; | 2228 | v4l2_ctrl_handler_free(&prev->ctrls); |
2229 | omap3isp_video_cleanup(&prev->video_in); | ||
2230 | omap3isp_video_cleanup(&prev->video_out); | ||
2231 | media_entity_cleanup(&prev->subdev.entity); | ||
2113 | } | 2232 | } |
diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h index fa943bd05c7f..f54e775c2df4 100644 --- a/drivers/media/video/omap3isp/isppreview.h +++ b/drivers/media/video/omap3isp/isppreview.h | |||
@@ -45,11 +45,6 @@ | |||
45 | #define ISPPRV_CONTRAST_HIGH 0xFF | 45 | #define ISPPRV_CONTRAST_HIGH 0xFF |
46 | #define ISPPRV_CONTRAST_UNITS 0x1 | 46 | #define ISPPRV_CONTRAST_UNITS 0x1 |
47 | 47 | ||
48 | #define NO_AVE 0x0 | ||
49 | #define AVE_2_PIX 0x1 | ||
50 | #define AVE_4_PIX 0x2 | ||
51 | #define AVE_8_PIX 0x3 | ||
52 | |||
53 | /* Features list */ | 48 | /* Features list */ |
54 | #define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH | 49 | #define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH |
55 | #define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW | 50 | #define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW |
@@ -106,7 +101,6 @@ enum preview_ycpos_mode { | |||
106 | * @rgb2ycbcr: RGB to ycbcr parameters. | 101 | * @rgb2ycbcr: RGB to ycbcr parameters. |
107 | * @hmed: Horizontal median filter. | 102 | * @hmed: Horizontal median filter. |
108 | * @yclimit: YC limits parameters. | 103 | * @yclimit: YC limits parameters. |
109 | * @average: Downsampling rate for averager. | ||
110 | * @contrast: Contrast. | 104 | * @contrast: Contrast. |
111 | * @brightness: Brightness. | 105 | * @brightness: Brightness. |
112 | */ | 106 | */ |
@@ -124,7 +118,6 @@ struct prev_params { | |||
124 | struct omap3isp_prev_csc rgb2ycbcr; | 118 | struct omap3isp_prev_csc rgb2ycbcr; |
125 | struct omap3isp_prev_hmed hmed; | 119 | struct omap3isp_prev_hmed hmed; |
126 | struct omap3isp_prev_yclimit yclimit; | 120 | struct omap3isp_prev_yclimit yclimit; |
127 | u8 average; | ||
128 | u8 contrast; | 121 | u8 contrast; |
129 | u8 brightness; | 122 | u8 brightness; |
130 | }; | 123 | }; |
@@ -159,6 +152,7 @@ struct isptables_update { | |||
159 | * @subdev: V4L2 subdevice | 152 | * @subdev: V4L2 subdevice |
160 | * @pads: Media entity pads | 153 | * @pads: Media entity pads |
161 | * @formats: Active formats at the subdev pad | 154 | * @formats: Active formats at the subdev pad |
155 | * @crop: Active crop rectangle | ||
162 | * @input: Module currently connected to the input pad | 156 | * @input: Module currently connected to the input pad |
163 | * @output: Bitmask of the active output | 157 | * @output: Bitmask of the active output |
164 | * @video_in: Input video entity | 158 | * @video_in: Input video entity |
@@ -177,6 +171,7 @@ struct isp_prev_device { | |||
177 | struct v4l2_subdev subdev; | 171 | struct v4l2_subdev subdev; |
178 | struct media_pad pads[PREV_PADS_NUM]; | 172 | struct media_pad pads[PREV_PADS_NUM]; |
179 | struct v4l2_mbus_framefmt formats[PREV_PADS_NUM]; | 173 | struct v4l2_mbus_framefmt formats[PREV_PADS_NUM]; |
174 | struct v4l2_rect crop; | ||
180 | 175 | ||
181 | struct v4l2_ctrl_handler ctrls; | 176 | struct v4l2_ctrl_handler ctrls; |
182 | 177 | ||
diff --git a/drivers/media/video/omap3isp/ispreg.h b/drivers/media/video/omap3isp/ispreg.h index 69f6af6f6b9c..084ea77d65a7 100644 --- a/drivers/media/video/omap3isp/ispreg.h +++ b/drivers/media/video/omap3isp/ispreg.h | |||
@@ -402,9 +402,6 @@ | |||
402 | #define ISPPRV_YENH_TABLE_ADDR 0x1000 | 402 | #define ISPPRV_YENH_TABLE_ADDR 0x1000 |
403 | #define ISPPRV_CFA_TABLE_ADDR 0x1400 | 403 | #define ISPPRV_CFA_TABLE_ADDR 0x1400 |
404 | 404 | ||
405 | #define ISPPRV_MAXOUTPUT_WIDTH 1280 | ||
406 | #define ISPPRV_MAXOUTPUT_WIDTH_ES2 3300 | ||
407 | #define ISPPRV_MAXOUTPUT_WIDTH_3630 4096 | ||
408 | #define ISPRSZ_MIN_OUTPUT 64 | 405 | #define ISPRSZ_MIN_OUTPUT 64 |
409 | #define ISPRSZ_MAX_OUTPUT 3312 | 406 | #define ISPRSZ_MAX_OUTPUT 3312 |
410 | 407 | ||
diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 0bb0f8cd36f5..50e593bfcfaf 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c | |||
@@ -1608,6 +1608,42 @@ static const struct media_entity_operations resizer_media_ops = { | |||
1608 | .link_setup = resizer_link_setup, | 1608 | .link_setup = resizer_link_setup, |
1609 | }; | 1609 | }; |
1610 | 1610 | ||
1611 | void omap3isp_resizer_unregister_entities(struct isp_res_device *res) | ||
1612 | { | ||
1613 | v4l2_device_unregister_subdev(&res->subdev); | ||
1614 | omap3isp_video_unregister(&res->video_in); | ||
1615 | omap3isp_video_unregister(&res->video_out); | ||
1616 | } | ||
1617 | |||
1618 | int omap3isp_resizer_register_entities(struct isp_res_device *res, | ||
1619 | struct v4l2_device *vdev) | ||
1620 | { | ||
1621 | int ret; | ||
1622 | |||
1623 | /* Register the subdev and video nodes. */ | ||
1624 | ret = v4l2_device_register_subdev(vdev, &res->subdev); | ||
1625 | if (ret < 0) | ||
1626 | goto error; | ||
1627 | |||
1628 | ret = omap3isp_video_register(&res->video_in, vdev); | ||
1629 | if (ret < 0) | ||
1630 | goto error; | ||
1631 | |||
1632 | ret = omap3isp_video_register(&res->video_out, vdev); | ||
1633 | if (ret < 0) | ||
1634 | goto error; | ||
1635 | |||
1636 | return 0; | ||
1637 | |||
1638 | error: | ||
1639 | omap3isp_resizer_unregister_entities(res); | ||
1640 | return ret; | ||
1641 | } | ||
1642 | |||
1643 | /* ----------------------------------------------------------------------------- | ||
1644 | * ISP resizer initialization and cleanup | ||
1645 | */ | ||
1646 | |||
1611 | /* | 1647 | /* |
1612 | * resizer_init_entities - Initialize resizer subdev and media entity. | 1648 | * resizer_init_entities - Initialize resizer subdev and media entity. |
1613 | * @res : Pointer to resizer device structure | 1649 | * @res : Pointer to resizer device structure |
@@ -1652,68 +1688,34 @@ static int resizer_init_entities(struct isp_res_device *res) | |||
1652 | 1688 | ||
1653 | ret = omap3isp_video_init(&res->video_in, "resizer"); | 1689 | ret = omap3isp_video_init(&res->video_in, "resizer"); |
1654 | if (ret < 0) | 1690 | if (ret < 0) |
1655 | return ret; | 1691 | goto error_video_in; |
1656 | 1692 | ||
1657 | ret = omap3isp_video_init(&res->video_out, "resizer"); | 1693 | ret = omap3isp_video_init(&res->video_out, "resizer"); |
1658 | if (ret < 0) | 1694 | if (ret < 0) |
1659 | return ret; | 1695 | goto error_video_out; |
1660 | 1696 | ||
1661 | /* Connect the video nodes to the resizer subdev. */ | 1697 | /* Connect the video nodes to the resizer subdev. */ |
1662 | ret = media_entity_create_link(&res->video_in.video.entity, 0, | 1698 | ret = media_entity_create_link(&res->video_in.video.entity, 0, |
1663 | &res->subdev.entity, RESZ_PAD_SINK, 0); | 1699 | &res->subdev.entity, RESZ_PAD_SINK, 0); |
1664 | if (ret < 0) | 1700 | if (ret < 0) |
1665 | return ret; | 1701 | goto error_link; |
1666 | 1702 | ||
1667 | ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE, | 1703 | ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE, |
1668 | &res->video_out.video.entity, 0, 0); | 1704 | &res->video_out.video.entity, 0, 0); |
1669 | if (ret < 0) | 1705 | if (ret < 0) |
1670 | return ret; | 1706 | goto error_link; |
1671 | 1707 | ||
1672 | return 0; | 1708 | return 0; |
1673 | } | ||
1674 | 1709 | ||
1675 | void omap3isp_resizer_unregister_entities(struct isp_res_device *res) | 1710 | error_link: |
1676 | { | 1711 | omap3isp_video_cleanup(&res->video_out); |
1712 | error_video_out: | ||
1713 | omap3isp_video_cleanup(&res->video_in); | ||
1714 | error_video_in: | ||
1677 | media_entity_cleanup(&res->subdev.entity); | 1715 | media_entity_cleanup(&res->subdev.entity); |
1678 | |||
1679 | v4l2_device_unregister_subdev(&res->subdev); | ||
1680 | omap3isp_video_unregister(&res->video_in); | ||
1681 | omap3isp_video_unregister(&res->video_out); | ||
1682 | } | ||
1683 | |||
1684 | int omap3isp_resizer_register_entities(struct isp_res_device *res, | ||
1685 | struct v4l2_device *vdev) | ||
1686 | { | ||
1687 | int ret; | ||
1688 | |||
1689 | /* Register the subdev and video nodes. */ | ||
1690 | ret = v4l2_device_register_subdev(vdev, &res->subdev); | ||
1691 | if (ret < 0) | ||
1692 | goto error; | ||
1693 | |||
1694 | ret = omap3isp_video_register(&res->video_in, vdev); | ||
1695 | if (ret < 0) | ||
1696 | goto error; | ||
1697 | |||
1698 | ret = omap3isp_video_register(&res->video_out, vdev); | ||
1699 | if (ret < 0) | ||
1700 | goto error; | ||
1701 | |||
1702 | return 0; | ||
1703 | |||
1704 | error: | ||
1705 | omap3isp_resizer_unregister_entities(res); | ||
1706 | return ret; | 1716 | return ret; |
1707 | } | 1717 | } |
1708 | 1718 | ||
1709 | /* ----------------------------------------------------------------------------- | ||
1710 | * ISP resizer initialization and cleanup | ||
1711 | */ | ||
1712 | |||
1713 | void omap3isp_resizer_cleanup(struct isp_device *isp) | ||
1714 | { | ||
1715 | } | ||
1716 | |||
1717 | /* | 1719 | /* |
1718 | * isp_resizer_init - Resizer initialization. | 1720 | * isp_resizer_init - Resizer initialization. |
1719 | * @isp : Pointer to ISP device | 1721 | * @isp : Pointer to ISP device |
@@ -1722,17 +1724,17 @@ void omap3isp_resizer_cleanup(struct isp_device *isp) | |||
1722 | int omap3isp_resizer_init(struct isp_device *isp) | 1724 | int omap3isp_resizer_init(struct isp_device *isp) |
1723 | { | 1725 | { |
1724 | struct isp_res_device *res = &isp->isp_res; | 1726 | struct isp_res_device *res = &isp->isp_res; |
1725 | int ret; | ||
1726 | 1727 | ||
1727 | init_waitqueue_head(&res->wait); | 1728 | init_waitqueue_head(&res->wait); |
1728 | atomic_set(&res->stopping, 0); | 1729 | atomic_set(&res->stopping, 0); |
1729 | ret = resizer_init_entities(res); | 1730 | return resizer_init_entities(res); |
1730 | if (ret < 0) | 1731 | } |
1731 | goto out; | ||
1732 | 1732 | ||
1733 | out: | 1733 | void omap3isp_resizer_cleanup(struct isp_device *isp) |
1734 | if (ret) | 1734 | { |
1735 | omap3isp_resizer_cleanup(isp); | 1735 | struct isp_res_device *res = &isp->isp_res; |
1736 | 1736 | ||
1737 | return ret; | 1737 | omap3isp_video_cleanup(&res->video_in); |
1738 | omap3isp_video_cleanup(&res->video_out); | ||
1739 | media_entity_cleanup(&res->subdev.entity); | ||
1738 | } | 1740 | } |
diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index 732905552261..68d539456c55 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c | |||
@@ -1023,24 +1023,6 @@ void omap3isp_stat_dma_isr(struct ispstat *stat) | |||
1023 | __stat_isr(stat, 1); | 1023 | __stat_isr(stat, 1); |
1024 | } | 1024 | } |
1025 | 1025 | ||
1026 | static int isp_stat_init_entities(struct ispstat *stat, const char *name, | ||
1027 | const struct v4l2_subdev_ops *sd_ops) | ||
1028 | { | ||
1029 | struct v4l2_subdev *subdev = &stat->subdev; | ||
1030 | struct media_entity *me = &subdev->entity; | ||
1031 | |||
1032 | v4l2_subdev_init(subdev, sd_ops); | ||
1033 | snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); | ||
1034 | subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ | ||
1035 | subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
1036 | v4l2_set_subdevdata(subdev, stat); | ||
1037 | |||
1038 | stat->pad.flags = MEDIA_PAD_FL_SINK; | ||
1039 | me->ops = NULL; | ||
1040 | |||
1041 | return media_entity_init(me, 1, &stat->pad, 0); | ||
1042 | } | ||
1043 | |||
1044 | int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, | 1026 | int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, |
1045 | struct v4l2_fh *fh, | 1027 | struct v4l2_fh *fh, |
1046 | struct v4l2_event_subscription *sub) | 1028 | struct v4l2_event_subscription *sub) |
@@ -1062,7 +1044,6 @@ int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, | |||
1062 | 1044 | ||
1063 | void omap3isp_stat_unregister_entities(struct ispstat *stat) | 1045 | void omap3isp_stat_unregister_entities(struct ispstat *stat) |
1064 | { | 1046 | { |
1065 | media_entity_cleanup(&stat->subdev.entity); | ||
1066 | v4l2_device_unregister_subdev(&stat->subdev); | 1047 | v4l2_device_unregister_subdev(&stat->subdev); |
1067 | } | 1048 | } |
1068 | 1049 | ||
@@ -1072,21 +1053,50 @@ int omap3isp_stat_register_entities(struct ispstat *stat, | |||
1072 | return v4l2_device_register_subdev(vdev, &stat->subdev); | 1053 | return v4l2_device_register_subdev(vdev, &stat->subdev); |
1073 | } | 1054 | } |
1074 | 1055 | ||
1056 | static int isp_stat_init_entities(struct ispstat *stat, const char *name, | ||
1057 | const struct v4l2_subdev_ops *sd_ops) | ||
1058 | { | ||
1059 | struct v4l2_subdev *subdev = &stat->subdev; | ||
1060 | struct media_entity *me = &subdev->entity; | ||
1061 | |||
1062 | v4l2_subdev_init(subdev, sd_ops); | ||
1063 | snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); | ||
1064 | subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ | ||
1065 | subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
1066 | v4l2_set_subdevdata(subdev, stat); | ||
1067 | |||
1068 | stat->pad.flags = MEDIA_PAD_FL_SINK; | ||
1069 | me->ops = NULL; | ||
1070 | |||
1071 | return media_entity_init(me, 1, &stat->pad, 0); | ||
1072 | } | ||
1073 | |||
1075 | int omap3isp_stat_init(struct ispstat *stat, const char *name, | 1074 | int omap3isp_stat_init(struct ispstat *stat, const char *name, |
1076 | const struct v4l2_subdev_ops *sd_ops) | 1075 | const struct v4l2_subdev_ops *sd_ops) |
1077 | { | 1076 | { |
1077 | int ret; | ||
1078 | |||
1078 | stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL); | 1079 | stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL); |
1079 | if (!stat->buf) | 1080 | if (!stat->buf) |
1080 | return -ENOMEM; | 1081 | return -ENOMEM; |
1082 | |||
1081 | isp_stat_buf_clear(stat); | 1083 | isp_stat_buf_clear(stat); |
1082 | mutex_init(&stat->ioctl_lock); | 1084 | mutex_init(&stat->ioctl_lock); |
1083 | atomic_set(&stat->buf_err, 0); | 1085 | atomic_set(&stat->buf_err, 0); |
1084 | 1086 | ||
1085 | return isp_stat_init_entities(stat, name, sd_ops); | 1087 | ret = isp_stat_init_entities(stat, name, sd_ops); |
1088 | if (ret < 0) { | ||
1089 | mutex_destroy(&stat->ioctl_lock); | ||
1090 | kfree(stat->buf); | ||
1091 | } | ||
1092 | |||
1093 | return ret; | ||
1086 | } | 1094 | } |
1087 | 1095 | ||
1088 | void omap3isp_stat_free(struct ispstat *stat) | 1096 | void omap3isp_stat_cleanup(struct ispstat *stat) |
1089 | { | 1097 | { |
1098 | media_entity_cleanup(&stat->subdev.entity); | ||
1099 | mutex_destroy(&stat->ioctl_lock); | ||
1090 | isp_stat_bufs_free(stat); | 1100 | isp_stat_bufs_free(stat); |
1091 | kfree(stat->buf); | 1101 | kfree(stat->buf); |
1092 | } | 1102 | } |
diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h index d86da94fa50d..9b7c8654dc8a 100644 --- a/drivers/media/video/omap3isp/ispstat.h +++ b/drivers/media/video/omap3isp/ispstat.h | |||
@@ -144,7 +144,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat, | |||
144 | struct omap3isp_stat_data *data); | 144 | struct omap3isp_stat_data *data); |
145 | int omap3isp_stat_init(struct ispstat *stat, const char *name, | 145 | int omap3isp_stat_init(struct ispstat *stat, const char *name, |
146 | const struct v4l2_subdev_ops *sd_ops); | 146 | const struct v4l2_subdev_ops *sd_ops); |
147 | void omap3isp_stat_free(struct ispstat *stat); | 147 | void omap3isp_stat_cleanup(struct ispstat *stat); |
148 | int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, | 148 | int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, |
149 | struct v4l2_fh *fh, | 149 | struct v4l2_fh *fh, |
150 | struct v4l2_event_subscription *sub); | 150 | struct v4l2_event_subscription *sub); |
diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 0cb8a9f9d675..d1000723c5ae 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c | |||
@@ -1325,6 +1325,13 @@ int omap3isp_video_init(struct isp_video *video, const char *name) | |||
1325 | return 0; | 1325 | return 0; |
1326 | } | 1326 | } |
1327 | 1327 | ||
1328 | void omap3isp_video_cleanup(struct isp_video *video) | ||
1329 | { | ||
1330 | media_entity_cleanup(&video->video.entity); | ||
1331 | mutex_destroy(&video->stream_lock); | ||
1332 | mutex_destroy(&video->mutex); | ||
1333 | } | ||
1334 | |||
1328 | int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) | 1335 | int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) |
1329 | { | 1336 | { |
1330 | int ret; | 1337 | int ret; |
@@ -1341,8 +1348,6 @@ int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) | |||
1341 | 1348 | ||
1342 | void omap3isp_video_unregister(struct isp_video *video) | 1349 | void omap3isp_video_unregister(struct isp_video *video) |
1343 | { | 1350 | { |
1344 | if (video_is_registered(&video->video)) { | 1351 | if (video_is_registered(&video->video)) |
1345 | media_entity_cleanup(&video->video.entity); | ||
1346 | video_unregister_device(&video->video); | 1352 | video_unregister_device(&video->video); |
1347 | } | ||
1348 | } | 1353 | } |
diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 53160aa24e6e..08cbfa144e6e 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h | |||
@@ -190,6 +190,7 @@ struct isp_video_fh { | |||
190 | container_of(q, struct isp_video_fh, queue) | 190 | container_of(q, struct isp_video_fh, queue) |
191 | 191 | ||
192 | int omap3isp_video_init(struct isp_video *video, const char *name); | 192 | int omap3isp_video_init(struct isp_video *video, const char *name); |
193 | void omap3isp_video_cleanup(struct isp_video *video); | ||
193 | int omap3isp_video_register(struct isp_video *video, | 194 | int omap3isp_video_register(struct isp_video *video, |
194 | struct v4l2_device *vdev); | 195 | struct v4l2_device *vdev); |
195 | void omap3isp_video_unregister(struct isp_video *video); | 196 | void omap3isp_video_unregister(struct isp_video *video); |
diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index 9ce2fa037b94..b5247cb64fde 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c | |||
@@ -18,11 +18,13 @@ | |||
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/v4l2-mediabus.h> | ||
21 | #include <linux/videodev2.h> | 22 | #include <linux/videodev2.h> |
23 | |||
24 | #include <media/soc_camera.h> | ||
22 | #include <media/v4l2-chip-ident.h> | 25 | #include <media/v4l2-chip-ident.h> |
23 | #include <media/v4l2-subdev.h> | 26 | #include <media/v4l2-subdev.h> |
24 | #include <media/soc_camera.h> | 27 | #include <media/v4l2-ctrls.h> |
25 | #include <media/soc_mediabus.h> | ||
26 | 28 | ||
27 | #define VAL_SET(x, mask, rshift, lshift) \ | 29 | #define VAL_SET(x, mask, rshift, lshift) \ |
28 | ((((x) >> rshift) & mask) << lshift) | 30 | ((((x) >> rshift) & mask) << lshift) |
@@ -299,12 +301,10 @@ struct ov2640_win_size { | |||
299 | 301 | ||
300 | struct ov2640_priv { | 302 | struct ov2640_priv { |
301 | struct v4l2_subdev subdev; | 303 | struct v4l2_subdev subdev; |
302 | struct ov2640_camera_info *info; | 304 | struct v4l2_ctrl_handler hdl; |
303 | enum v4l2_mbus_pixelcode cfmt_code; | 305 | enum v4l2_mbus_pixelcode cfmt_code; |
304 | const struct ov2640_win_size *win; | 306 | const struct ov2640_win_size *win; |
305 | int model; | 307 | int model; |
306 | u16 flag_vflip:1; | ||
307 | u16 flag_hflip:1; | ||
308 | }; | 308 | }; |
309 | 309 | ||
310 | /* | 310 | /* |
@@ -610,29 +610,6 @@ static enum v4l2_mbus_pixelcode ov2640_codes[] = { | |||
610 | }; | 610 | }; |
611 | 611 | ||
612 | /* | 612 | /* |
613 | * Supported controls | ||
614 | */ | ||
615 | static const struct v4l2_queryctrl ov2640_controls[] = { | ||
616 | { | ||
617 | .id = V4L2_CID_VFLIP, | ||
618 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
619 | .name = "Flip Vertically", | ||
620 | .minimum = 0, | ||
621 | .maximum = 1, | ||
622 | .step = 1, | ||
623 | .default_value = 0, | ||
624 | }, { | ||
625 | .id = V4L2_CID_HFLIP, | ||
626 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
627 | .name = "Flip Horizontally", | ||
628 | .minimum = 0, | ||
629 | .maximum = 1, | ||
630 | .step = 1, | ||
631 | .default_value = 0, | ||
632 | }, | ||
633 | }; | ||
634 | |||
635 | /* | ||
636 | * General functions | 613 | * General functions |
637 | */ | 614 | */ |
638 | static struct ov2640_priv *to_ov2640(const struct i2c_client *client) | 615 | static struct ov2640_priv *to_ov2640(const struct i2c_client *client) |
@@ -701,81 +678,23 @@ static int ov2640_s_stream(struct v4l2_subdev *sd, int enable) | |||
701 | return 0; | 678 | return 0; |
702 | } | 679 | } |
703 | 680 | ||
704 | static int ov2640_set_bus_param(struct soc_camera_device *icd, | 681 | static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) |
705 | unsigned long flags) | ||
706 | { | ||
707 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
708 | unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; | ||
709 | |||
710 | /* Only one width bit may be set */ | ||
711 | if (!is_power_of_2(width_flag)) | ||
712 | return -EINVAL; | ||
713 | |||
714 | if (icl->set_bus_param) | ||
715 | return icl->set_bus_param(icl, width_flag); | ||
716 | |||
717 | /* | ||
718 | * Without board specific bus width settings we support only the | ||
719 | * sensors native bus width witch are tested working | ||
720 | */ | ||
721 | if (width_flag & (SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8)) | ||
722 | return 0; | ||
723 | |||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | static unsigned long ov2640_query_bus_param(struct soc_camera_device *icd) | ||
728 | { | ||
729 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
730 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
731 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
732 | SOCAM_DATA_ACTIVE_HIGH; | ||
733 | |||
734 | if (icl->query_bus_param) | ||
735 | flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; | ||
736 | else | ||
737 | flags |= SOCAM_DATAWIDTH_10; | ||
738 | |||
739 | return soc_camera_apply_sensor_flags(icl, flags); | ||
740 | } | ||
741 | |||
742 | static int ov2640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
743 | { | 682 | { |
683 | struct v4l2_subdev *sd = | ||
684 | &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev; | ||
744 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 685 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
745 | struct ov2640_priv *priv = to_ov2640(client); | ||
746 | |||
747 | switch (ctrl->id) { | ||
748 | case V4L2_CID_VFLIP: | ||
749 | ctrl->value = priv->flag_vflip; | ||
750 | break; | ||
751 | case V4L2_CID_HFLIP: | ||
752 | ctrl->value = priv->flag_hflip; | ||
753 | break; | ||
754 | } | ||
755 | return 0; | ||
756 | } | ||
757 | |||
758 | static int ov2640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
759 | { | ||
760 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
761 | struct ov2640_priv *priv = to_ov2640(client); | ||
762 | int ret = 0; | ||
763 | u8 val; | 686 | u8 val; |
764 | 687 | ||
765 | switch (ctrl->id) { | 688 | switch (ctrl->id) { |
766 | case V4L2_CID_VFLIP: | 689 | case V4L2_CID_VFLIP: |
767 | val = ctrl->value ? REG04_VFLIP_IMG : 0x00; | 690 | val = ctrl->val ? REG04_VFLIP_IMG : 0x00; |
768 | priv->flag_vflip = ctrl->value ? 1 : 0; | 691 | return ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); |
769 | ret = ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); | ||
770 | break; | ||
771 | case V4L2_CID_HFLIP: | 692 | case V4L2_CID_HFLIP: |
772 | val = ctrl->value ? REG04_HFLIP_IMG : 0x00; | 693 | val = ctrl->val ? REG04_HFLIP_IMG : 0x00; |
773 | priv->flag_hflip = ctrl->value ? 1 : 0; | 694 | return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); |
774 | ret = ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); | ||
775 | break; | ||
776 | } | 695 | } |
777 | 696 | ||
778 | return ret; | 697 | return -EINVAL; |
779 | } | 698 | } |
780 | 699 | ||
781 | static int ov2640_g_chip_ident(struct v4l2_subdev *sd, | 700 | static int ov2640_g_chip_ident(struct v4l2_subdev *sd, |
@@ -1023,18 +942,13 @@ static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
1023 | return 0; | 942 | return 0; |
1024 | } | 943 | } |
1025 | 944 | ||
1026 | static int ov2640_video_probe(struct soc_camera_device *icd, | 945 | static int ov2640_video_probe(struct i2c_client *client) |
1027 | struct i2c_client *client) | ||
1028 | { | 946 | { |
1029 | struct ov2640_priv *priv = to_ov2640(client); | 947 | struct ov2640_priv *priv = to_ov2640(client); |
1030 | u8 pid, ver, midh, midl; | 948 | u8 pid, ver, midh, midl; |
1031 | const char *devname; | 949 | const char *devname; |
1032 | int ret; | 950 | int ret; |
1033 | 951 | ||
1034 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
1035 | BUG_ON(!icd->parent || | ||
1036 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
1037 | |||
1038 | /* | 952 | /* |
1039 | * check and show product ID and manufacturer ID | 953 | * check and show product ID and manufacturer ID |
1040 | */ | 954 | */ |
@@ -1060,22 +974,17 @@ static int ov2640_video_probe(struct soc_camera_device *icd, | |||
1060 | "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", | 974 | "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", |
1061 | devname, pid, ver, midh, midl); | 975 | devname, pid, ver, midh, midl); |
1062 | 976 | ||
1063 | return 0; | 977 | return v4l2_ctrl_handler_setup(&priv->hdl); |
1064 | 978 | ||
1065 | err: | 979 | err: |
1066 | return ret; | 980 | return ret; |
1067 | } | 981 | } |
1068 | 982 | ||
1069 | static struct soc_camera_ops ov2640_ops = { | 983 | static const struct v4l2_ctrl_ops ov2640_ctrl_ops = { |
1070 | .set_bus_param = ov2640_set_bus_param, | 984 | .s_ctrl = ov2640_s_ctrl, |
1071 | .query_bus_param = ov2640_query_bus_param, | ||
1072 | .controls = ov2640_controls, | ||
1073 | .num_controls = ARRAY_SIZE(ov2640_controls), | ||
1074 | }; | 985 | }; |
1075 | 986 | ||
1076 | static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { | 987 | static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { |
1077 | .g_ctrl = ov2640_g_ctrl, | ||
1078 | .s_ctrl = ov2640_s_ctrl, | ||
1079 | .g_chip_ident = ov2640_g_chip_ident, | 988 | .g_chip_ident = ov2640_g_chip_ident, |
1080 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 989 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1081 | .g_register = ov2640_g_register, | 990 | .g_register = ov2640_g_register, |
@@ -1083,6 +992,21 @@ static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { | |||
1083 | #endif | 992 | #endif |
1084 | }; | 993 | }; |
1085 | 994 | ||
995 | static int ov2640_g_mbus_config(struct v4l2_subdev *sd, | ||
996 | struct v4l2_mbus_config *cfg) | ||
997 | { | ||
998 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
999 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
1000 | |||
1001 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
1002 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
1003 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
1004 | cfg->type = V4L2_MBUS_PARALLEL; | ||
1005 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
1006 | |||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
1086 | static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { | 1010 | static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { |
1087 | .s_stream = ov2640_s_stream, | 1011 | .s_stream = ov2640_s_stream, |
1088 | .g_mbus_fmt = ov2640_g_fmt, | 1012 | .g_mbus_fmt = ov2640_g_fmt, |
@@ -1091,6 +1015,7 @@ static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { | |||
1091 | .cropcap = ov2640_cropcap, | 1015 | .cropcap = ov2640_cropcap, |
1092 | .g_crop = ov2640_g_crop, | 1016 | .g_crop = ov2640_g_crop, |
1093 | .enum_mbus_fmt = ov2640_enum_fmt, | 1017 | .enum_mbus_fmt = ov2640_enum_fmt, |
1018 | .g_mbus_config = ov2640_g_mbus_config, | ||
1094 | }; | 1019 | }; |
1095 | 1020 | ||
1096 | static struct v4l2_subdev_ops ov2640_subdev_ops = { | 1021 | static struct v4l2_subdev_ops ov2640_subdev_ops = { |
@@ -1104,18 +1029,11 @@ static struct v4l2_subdev_ops ov2640_subdev_ops = { | |||
1104 | static int ov2640_probe(struct i2c_client *client, | 1029 | static int ov2640_probe(struct i2c_client *client, |
1105 | const struct i2c_device_id *did) | 1030 | const struct i2c_device_id *did) |
1106 | { | 1031 | { |
1107 | struct ov2640_priv *priv; | 1032 | struct ov2640_priv *priv; |
1108 | struct soc_camera_device *icd = client->dev.platform_data; | 1033 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
1109 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1034 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1110 | struct soc_camera_link *icl; | 1035 | int ret; |
1111 | int ret; | ||
1112 | |||
1113 | if (!icd) { | ||
1114 | dev_err(&adapter->dev, "OV2640: missing soc-camera data!\n"); | ||
1115 | return -EINVAL; | ||
1116 | } | ||
1117 | 1036 | ||
1118 | icl = to_soc_camera_link(icd); | ||
1119 | if (!icl) { | 1037 | if (!icl) { |
1120 | dev_err(&adapter->dev, | 1038 | dev_err(&adapter->dev, |
1121 | "OV2640: Missing platform_data for driver\n"); | 1039 | "OV2640: Missing platform_data for driver\n"); |
@@ -1135,15 +1053,23 @@ static int ov2640_probe(struct i2c_client *client, | |||
1135 | return -ENOMEM; | 1053 | return -ENOMEM; |
1136 | } | 1054 | } |
1137 | 1055 | ||
1138 | priv->info = icl->priv; | ||
1139 | |||
1140 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); | 1056 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); |
1057 | v4l2_ctrl_handler_init(&priv->hdl, 2); | ||
1058 | v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, | ||
1059 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
1060 | v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, | ||
1061 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
1062 | priv->subdev.ctrl_handler = &priv->hdl; | ||
1063 | if (priv->hdl.error) { | ||
1064 | int err = priv->hdl.error; | ||
1141 | 1065 | ||
1142 | icd->ops = &ov2640_ops; | 1066 | kfree(priv); |
1067 | return err; | ||
1068 | } | ||
1143 | 1069 | ||
1144 | ret = ov2640_video_probe(icd, client); | 1070 | ret = ov2640_video_probe(client); |
1145 | if (ret) { | 1071 | if (ret) { |
1146 | icd->ops = NULL; | 1072 | v4l2_ctrl_handler_free(&priv->hdl); |
1147 | kfree(priv); | 1073 | kfree(priv); |
1148 | } else { | 1074 | } else { |
1149 | dev_info(&adapter->dev, "OV2640 Probed\n"); | 1075 | dev_info(&adapter->dev, "OV2640 Probed\n"); |
@@ -1155,9 +1081,9 @@ static int ov2640_probe(struct i2c_client *client, | |||
1155 | static int ov2640_remove(struct i2c_client *client) | 1081 | static int ov2640_remove(struct i2c_client *client) |
1156 | { | 1082 | { |
1157 | struct ov2640_priv *priv = to_ov2640(client); | 1083 | struct ov2640_priv *priv = to_ov2640(client); |
1158 | struct soc_camera_device *icd = client->dev.platform_data; | ||
1159 | 1084 | ||
1160 | icd->ops = NULL; | 1085 | v4l2_device_unregister_subdev(&priv->subdev); |
1086 | v4l2_ctrl_handler_free(&priv->hdl); | ||
1161 | kfree(priv); | 1087 | kfree(priv); |
1162 | return 0; | 1088 | return 0; |
1163 | } | 1089 | } |
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 349a4ad3ccc1..bb37ec80f274 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c | |||
@@ -14,14 +14,16 @@ | |||
14 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/bitops.h> | ||
17 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
18 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
20 | #include <linux/kernel.h> | ||
19 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
20 | #include <linux/videodev2.h> | 22 | #include <linux/videodev2.h> |
21 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/v4l2-mediabus.h> | ||
22 | 25 | ||
23 | #include <media/soc_camera.h> | 26 | #include <media/soc_camera.h> |
24 | #include <media/soc_mediabus.h> | ||
25 | #include <media/v4l2-chip-ident.h> | 27 | #include <media/v4l2-chip-ident.h> |
26 | #include <media/v4l2-subdev.h> | 28 | #include <media/v4l2-subdev.h> |
27 | 29 | ||
@@ -35,7 +37,7 @@ | |||
35 | #define REG_WINDOW_START_Y_LOW 0x3803 | 37 | #define REG_WINDOW_START_Y_LOW 0x3803 |
36 | #define REG_WINDOW_WIDTH_HIGH 0x3804 | 38 | #define REG_WINDOW_WIDTH_HIGH 0x3804 |
37 | #define REG_WINDOW_WIDTH_LOW 0x3805 | 39 | #define REG_WINDOW_WIDTH_LOW 0x3805 |
38 | #define REG_WINDOW_HEIGHT_HIGH 0x3806 | 40 | #define REG_WINDOW_HEIGHT_HIGH 0x3806 |
39 | #define REG_WINDOW_HEIGHT_LOW 0x3807 | 41 | #define REG_WINDOW_HEIGHT_LOW 0x3807 |
40 | #define REG_OUT_WIDTH_HIGH 0x3808 | 42 | #define REG_OUT_WIDTH_HIGH 0x3808 |
41 | #define REG_OUT_WIDTH_LOW 0x3809 | 43 | #define REG_OUT_WIDTH_LOW 0x3809 |
@@ -45,19 +47,44 @@ | |||
45 | #define REG_OUT_TOTAL_WIDTH_LOW 0x380d | 47 | #define REG_OUT_TOTAL_WIDTH_LOW 0x380d |
46 | #define REG_OUT_TOTAL_HEIGHT_HIGH 0x380e | 48 | #define REG_OUT_TOTAL_HEIGHT_HIGH 0x380e |
47 | #define REG_OUT_TOTAL_HEIGHT_LOW 0x380f | 49 | #define REG_OUT_TOTAL_HEIGHT_LOW 0x380f |
50 | #define REG_OUTPUT_FORMAT 0x4300 | ||
51 | #define REG_ISP_CTRL_01 0x5001 | ||
52 | #define REG_AVG_WINDOW_END_X_HIGH 0x5682 | ||
53 | #define REG_AVG_WINDOW_END_X_LOW 0x5683 | ||
54 | #define REG_AVG_WINDOW_END_Y_HIGH 0x5686 | ||
55 | #define REG_AVG_WINDOW_END_Y_LOW 0x5687 | ||
56 | |||
57 | /* active pixel array size */ | ||
58 | #define OV5642_SENSOR_SIZE_X 2592 | ||
59 | #define OV5642_SENSOR_SIZE_Y 1944 | ||
48 | 60 | ||
49 | /* | 61 | /* |
50 | * define standard resolution. | 62 | * About OV5642 resolution, cropping and binning: |
51 | * Works currently only for up to 720 lines | 63 | * This sensor supports it all, at least in the feature description. |
52 | * eg. 320x240, 640x480, 800x600, 1280x720, 2048x720 | 64 | * Unfortunately, no combination of appropriate registers settings could make |
65 | * the chip work the intended way. As it works with predefined register lists, | ||
66 | * some undocumented registers are presumably changed there to achieve their | ||
67 | * goals. | ||
68 | * This driver currently only works for resolutions up to 720 lines with a | ||
69 | * 1:1 scale. Hopefully these restrictions will be removed in the future. | ||
53 | */ | 70 | */ |
71 | #define OV5642_MAX_WIDTH OV5642_SENSOR_SIZE_X | ||
72 | #define OV5642_MAX_HEIGHT 720 | ||
54 | 73 | ||
55 | #define OV5642_WIDTH 1280 | 74 | /* default sizes */ |
56 | #define OV5642_HEIGHT 720 | 75 | #define OV5642_DEFAULT_WIDTH 1280 |
57 | #define OV5642_TOTAL_WIDTH 3200 | 76 | #define OV5642_DEFAULT_HEIGHT OV5642_MAX_HEIGHT |
58 | #define OV5642_TOTAL_HEIGHT 2000 | 77 | |
59 | #define OV5642_SENSOR_SIZE_X 2592 | 78 | /* minimum extra blanking */ |
60 | #define OV5642_SENSOR_SIZE_Y 1944 | 79 | #define BLANKING_EXTRA_WIDTH 500 |
80 | #define BLANKING_EXTRA_HEIGHT 20 | ||
81 | |||
82 | /* | ||
83 | * the sensor's autoexposure is buggy when setting total_height low. | ||
84 | * It tries to expose longer than 1 frame period without taking care of it | ||
85 | * and this leads to weird output. So we set 1000 lines as minimum. | ||
86 | */ | ||
87 | #define BLANKING_MIN_HEIGHT 1000 | ||
61 | 88 | ||
62 | struct regval_list { | 89 | struct regval_list { |
63 | u16 reg_num; | 90 | u16 reg_num; |
@@ -582,6 +609,11 @@ struct ov5642_datafmt { | |||
582 | struct ov5642 { | 609 | struct ov5642 { |
583 | struct v4l2_subdev subdev; | 610 | struct v4l2_subdev subdev; |
584 | const struct ov5642_datafmt *fmt; | 611 | const struct ov5642_datafmt *fmt; |
612 | struct v4l2_rect crop_rect; | ||
613 | |||
614 | /* blanking information */ | ||
615 | int total_width; | ||
616 | int total_height; | ||
585 | }; | 617 | }; |
586 | 618 | ||
587 | static const struct ov5642_datafmt ov5642_colour_fmts[] = { | 619 | static const struct ov5642_datafmt ov5642_colour_fmts[] = { |
@@ -642,6 +674,21 @@ static int reg_write(struct i2c_client *client, u16 reg, u8 val) | |||
642 | 674 | ||
643 | return 0; | 675 | return 0; |
644 | } | 676 | } |
677 | |||
678 | /* | ||
679 | * convenience function to write 16 bit register values that are split up | ||
680 | * into two consecutive high and low parts | ||
681 | */ | ||
682 | static int reg_write16(struct i2c_client *client, u16 reg, u16 val16) | ||
683 | { | ||
684 | int ret; | ||
685 | |||
686 | ret = reg_write(client, reg, val16 >> 8); | ||
687 | if (ret) | ||
688 | return ret; | ||
689 | return reg_write(client, reg + 1, val16 & 0x00ff); | ||
690 | } | ||
691 | |||
645 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 692 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
646 | static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | 693 | static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) |
647 | { | 694 | { |
@@ -685,58 +732,55 @@ static int ov5642_write_array(struct i2c_client *client, | |||
685 | return 0; | 732 | return 0; |
686 | } | 733 | } |
687 | 734 | ||
688 | static int ov5642_set_resolution(struct i2c_client *client) | 735 | static int ov5642_set_resolution(struct v4l2_subdev *sd) |
689 | { | 736 | { |
737 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
738 | struct ov5642 *priv = to_ov5642(client); | ||
739 | int width = priv->crop_rect.width; | ||
740 | int height = priv->crop_rect.height; | ||
741 | int total_width = priv->total_width; | ||
742 | int total_height = priv->total_height; | ||
743 | int start_x = (OV5642_SENSOR_SIZE_X - width) / 2; | ||
744 | int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2; | ||
690 | int ret; | 745 | int ret; |
691 | u8 start_x_high = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) >> 8; | ||
692 | u8 start_x_low = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) & 0xff; | ||
693 | u8 start_y_high = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) >> 8; | ||
694 | u8 start_y_low = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) & 0xff; | ||
695 | |||
696 | u8 width_high = OV5642_WIDTH >> 8; | ||
697 | u8 width_low = OV5642_WIDTH & 0xff; | ||
698 | u8 height_high = OV5642_HEIGHT >> 8; | ||
699 | u8 height_low = OV5642_HEIGHT & 0xff; | ||
700 | |||
701 | u8 total_width_high = OV5642_TOTAL_WIDTH >> 8; | ||
702 | u8 total_width_low = OV5642_TOTAL_WIDTH & 0xff; | ||
703 | u8 total_height_high = OV5642_TOTAL_HEIGHT >> 8; | ||
704 | u8 total_height_low = OV5642_TOTAL_HEIGHT & 0xff; | ||
705 | |||
706 | ret = reg_write(client, REG_WINDOW_START_X_HIGH, start_x_high); | ||
707 | if (!ret) | ||
708 | ret = reg_write(client, REG_WINDOW_START_X_LOW, start_x_low); | ||
709 | if (!ret) | ||
710 | ret = reg_write(client, REG_WINDOW_START_Y_HIGH, start_y_high); | ||
711 | if (!ret) | ||
712 | ret = reg_write(client, REG_WINDOW_START_Y_LOW, start_y_low); | ||
713 | 746 | ||
747 | /* | ||
748 | * This should set the starting point for cropping. | ||
749 | * Doesn't work so far. | ||
750 | */ | ||
751 | ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x); | ||
714 | if (!ret) | 752 | if (!ret) |
715 | ret = reg_write(client, REG_WINDOW_WIDTH_HIGH, width_high); | 753 | ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y); |
716 | if (!ret) | 754 | if (!ret) { |
717 | ret = reg_write(client, REG_WINDOW_WIDTH_LOW , width_low); | 755 | priv->crop_rect.left = start_x; |
718 | if (!ret) | 756 | priv->crop_rect.top = start_y; |
719 | ret = reg_write(client, REG_WINDOW_HEIGHT_HIGH, height_high); | 757 | } |
720 | if (!ret) | ||
721 | ret = reg_write(client, REG_WINDOW_HEIGHT_LOW, height_low); | ||
722 | 758 | ||
723 | if (!ret) | 759 | if (!ret) |
724 | ret = reg_write(client, REG_OUT_WIDTH_HIGH, width_high); | 760 | ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width); |
725 | if (!ret) | 761 | if (!ret) |
726 | ret = reg_write(client, REG_OUT_WIDTH_LOW , width_low); | 762 | ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height); |
727 | if (!ret) | 763 | if (ret) |
728 | ret = reg_write(client, REG_OUT_HEIGHT_HIGH, height_high); | 764 | return ret; |
765 | priv->crop_rect.width = width; | ||
766 | priv->crop_rect.height = height; | ||
767 | |||
768 | /* Set the output window size. Only 1:1 scale is supported so far. */ | ||
769 | ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width); | ||
729 | if (!ret) | 770 | if (!ret) |
730 | ret = reg_write(client, REG_OUT_HEIGHT_LOW, height_low); | 771 | ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height); |
731 | 772 | ||
773 | /* Total width = output size + blanking */ | ||
732 | if (!ret) | 774 | if (!ret) |
733 | ret = reg_write(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width_high); | 775 | ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width); |
734 | if (!ret) | 776 | if (!ret) |
735 | ret = reg_write(client, REG_OUT_TOTAL_WIDTH_LOW, total_width_low); | 777 | ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height); |
778 | |||
779 | /* Sets the window for AWB calculations */ | ||
736 | if (!ret) | 780 | if (!ret) |
737 | ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height_high); | 781 | ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width); |
738 | if (!ret) | 782 | if (!ret) |
739 | ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_LOW, total_height_low); | 783 | ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height); |
740 | 784 | ||
741 | return ret; | 785 | return ret; |
742 | } | 786 | } |
@@ -744,18 +788,18 @@ static int ov5642_set_resolution(struct i2c_client *client) | |||
744 | static int ov5642_try_fmt(struct v4l2_subdev *sd, | 788 | static int ov5642_try_fmt(struct v4l2_subdev *sd, |
745 | struct v4l2_mbus_framefmt *mf) | 789 | struct v4l2_mbus_framefmt *mf) |
746 | { | 790 | { |
791 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
792 | struct ov5642 *priv = to_ov5642(client); | ||
747 | const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code); | 793 | const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code); |
748 | 794 | ||
749 | dev_dbg(sd->v4l2_dev->dev, "%s(%u) width: %u heigth: %u\n", | 795 | mf->width = priv->crop_rect.width; |
750 | __func__, mf->code, mf->width, mf->height); | 796 | mf->height = priv->crop_rect.height; |
751 | 797 | ||
752 | if (!fmt) { | 798 | if (!fmt) { |
753 | mf->code = ov5642_colour_fmts[0].code; | 799 | mf->code = ov5642_colour_fmts[0].code; |
754 | mf->colorspace = ov5642_colour_fmts[0].colorspace; | 800 | mf->colorspace = ov5642_colour_fmts[0].colorspace; |
755 | } | 801 | } |
756 | 802 | ||
757 | mf->width = OV5642_WIDTH; | ||
758 | mf->height = OV5642_HEIGHT; | ||
759 | mf->field = V4L2_FIELD_NONE; | 803 | mf->field = V4L2_FIELD_NONE; |
760 | 804 | ||
761 | return 0; | 805 | return 0; |
@@ -767,20 +811,13 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd, | |||
767 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 811 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
768 | struct ov5642 *priv = to_ov5642(client); | 812 | struct ov5642 *priv = to_ov5642(client); |
769 | 813 | ||
770 | dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); | ||
771 | |||
772 | /* MIPI CSI could have changed the format, double-check */ | 814 | /* MIPI CSI could have changed the format, double-check */ |
773 | if (!ov5642_find_datafmt(mf->code)) | 815 | if (!ov5642_find_datafmt(mf->code)) |
774 | return -EINVAL; | 816 | return -EINVAL; |
775 | 817 | ||
776 | ov5642_try_fmt(sd, mf); | 818 | ov5642_try_fmt(sd, mf); |
777 | |||
778 | priv->fmt = ov5642_find_datafmt(mf->code); | 819 | priv->fmt = ov5642_find_datafmt(mf->code); |
779 | 820 | ||
780 | ov5642_write_array(client, ov5642_default_regs_init); | ||
781 | ov5642_set_resolution(client); | ||
782 | ov5642_write_array(client, ov5642_default_regs_finalise); | ||
783 | |||
784 | return 0; | 821 | return 0; |
785 | } | 822 | } |
786 | 823 | ||
@@ -794,8 +831,8 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd, | |||
794 | 831 | ||
795 | mf->code = fmt->code; | 832 | mf->code = fmt->code; |
796 | mf->colorspace = fmt->colorspace; | 833 | mf->colorspace = fmt->colorspace; |
797 | mf->width = OV5642_WIDTH; | 834 | mf->width = priv->crop_rect.width; |
798 | mf->height = OV5642_HEIGHT; | 835 | mf->height = priv->crop_rect.height; |
799 | mf->field = V4L2_FIELD_NONE; | 836 | mf->field = V4L2_FIELD_NONE; |
800 | 837 | ||
801 | return 0; | 838 | return 0; |
@@ -828,15 +865,44 @@ static int ov5642_g_chip_ident(struct v4l2_subdev *sd, | |||
828 | return 0; | 865 | return 0; |
829 | } | 866 | } |
830 | 867 | ||
868 | static int ov5642_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
869 | { | ||
870 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
871 | struct ov5642 *priv = to_ov5642(client); | ||
872 | struct v4l2_rect *rect = &a->c; | ||
873 | int ret; | ||
874 | |||
875 | v4l_bound_align_image(&rect->width, 48, OV5642_MAX_WIDTH, 1, | ||
876 | &rect->height, 32, OV5642_MAX_HEIGHT, 1, 0); | ||
877 | |||
878 | priv->crop_rect.width = rect->width; | ||
879 | priv->crop_rect.height = rect->height; | ||
880 | priv->total_width = rect->width + BLANKING_EXTRA_WIDTH; | ||
881 | priv->total_height = max_t(int, rect->height + | ||
882 | BLANKING_EXTRA_HEIGHT, | ||
883 | BLANKING_MIN_HEIGHT); | ||
884 | priv->crop_rect.width = rect->width; | ||
885 | priv->crop_rect.height = rect->height; | ||
886 | |||
887 | ret = ov5642_write_array(client, ov5642_default_regs_init); | ||
888 | if (!ret) | ||
889 | ret = ov5642_set_resolution(sd); | ||
890 | if (!ret) | ||
891 | ret = ov5642_write_array(client, ov5642_default_regs_finalise); | ||
892 | |||
893 | return ret; | ||
894 | } | ||
895 | |||
831 | static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 896 | static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
832 | { | 897 | { |
898 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
899 | struct ov5642 *priv = to_ov5642(client); | ||
833 | struct v4l2_rect *rect = &a->c; | 900 | struct v4l2_rect *rect = &a->c; |
834 | 901 | ||
835 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 902 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
836 | rect->top = 0; | 903 | return -EINVAL; |
837 | rect->left = 0; | 904 | |
838 | rect->width = OV5642_WIDTH; | 905 | *rect = priv->crop_rect; |
839 | rect->height = OV5642_HEIGHT; | ||
840 | 906 | ||
841 | return 0; | 907 | return 0; |
842 | } | 908 | } |
@@ -845,8 +911,8 @@ static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
845 | { | 911 | { |
846 | a->bounds.left = 0; | 912 | a->bounds.left = 0; |
847 | a->bounds.top = 0; | 913 | a->bounds.top = 0; |
848 | a->bounds.width = OV5642_WIDTH; | 914 | a->bounds.width = OV5642_MAX_WIDTH; |
849 | a->bounds.height = OV5642_HEIGHT; | 915 | a->bounds.height = OV5642_MAX_HEIGHT; |
850 | a->defrect = a->bounds; | 916 | a->defrect = a->bounds; |
851 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 917 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
852 | a->pixelaspect.numerator = 1; | 918 | a->pixelaspect.numerator = 1; |
@@ -855,16 +921,47 @@ static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
855 | return 0; | 921 | return 0; |
856 | } | 922 | } |
857 | 923 | ||
924 | static int ov5642_g_mbus_config(struct v4l2_subdev *sd, | ||
925 | struct v4l2_mbus_config *cfg) | ||
926 | { | ||
927 | cfg->type = V4L2_MBUS_CSI2; | ||
928 | cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | | ||
929 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; | ||
930 | |||
931 | return 0; | ||
932 | } | ||
933 | |||
934 | static int ov5642_s_power(struct v4l2_subdev *sd, int on) | ||
935 | { | ||
936 | struct i2c_client *client; | ||
937 | int ret; | ||
938 | |||
939 | if (!on) | ||
940 | return 0; | ||
941 | |||
942 | client = v4l2_get_subdevdata(sd); | ||
943 | ret = ov5642_write_array(client, ov5642_default_regs_init); | ||
944 | if (!ret) | ||
945 | ret = ov5642_set_resolution(sd); | ||
946 | if (!ret) | ||
947 | ret = ov5642_write_array(client, ov5642_default_regs_finalise); | ||
948 | |||
949 | return ret; | ||
950 | } | ||
951 | |||
858 | static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { | 952 | static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { |
859 | .s_mbus_fmt = ov5642_s_fmt, | 953 | .s_mbus_fmt = ov5642_s_fmt, |
860 | .g_mbus_fmt = ov5642_g_fmt, | 954 | .g_mbus_fmt = ov5642_g_fmt, |
861 | .try_mbus_fmt = ov5642_try_fmt, | 955 | .try_mbus_fmt = ov5642_try_fmt, |
862 | .enum_mbus_fmt = ov5642_enum_fmt, | 956 | .enum_mbus_fmt = ov5642_enum_fmt, |
957 | .s_crop = ov5642_s_crop, | ||
863 | .g_crop = ov5642_g_crop, | 958 | .g_crop = ov5642_g_crop, |
864 | .cropcap = ov5642_cropcap, | 959 | .cropcap = ov5642_cropcap, |
960 | .g_mbus_config = ov5642_g_mbus_config, | ||
865 | }; | 961 | }; |
866 | 962 | ||
867 | static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { | 963 | static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { |
964 | .s_power = ov5642_s_power, | ||
868 | .g_chip_ident = ov5642_g_chip_ident, | 965 | .g_chip_ident = ov5642_g_chip_ident, |
869 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 966 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
870 | .g_register = ov5642_get_register, | 967 | .g_register = ov5642_get_register, |
@@ -877,28 +974,7 @@ static struct v4l2_subdev_ops ov5642_subdev_ops = { | |||
877 | .video = &ov5642_subdev_video_ops, | 974 | .video = &ov5642_subdev_video_ops, |
878 | }; | 975 | }; |
879 | 976 | ||
880 | /* | 977 | static int ov5642_video_probe(struct i2c_client *client) |
881 | * We have to provide soc-camera operations, but we don't have anything to say | ||
882 | * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param | ||
883 | */ | ||
884 | static unsigned long soc_ov5642_query_bus_param(struct soc_camera_device *icd) | ||
885 | { | ||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | static int soc_ov5642_set_bus_param(struct soc_camera_device *icd, | ||
890 | unsigned long flags) | ||
891 | { | ||
892 | return -EINVAL; | ||
893 | } | ||
894 | |||
895 | static struct soc_camera_ops soc_ov5642_ops = { | ||
896 | .query_bus_param = soc_ov5642_query_bus_param, | ||
897 | .set_bus_param = soc_ov5642_set_bus_param, | ||
898 | }; | ||
899 | |||
900 | static int ov5642_video_probe(struct soc_camera_device *icd, | ||
901 | struct i2c_client *client) | ||
902 | { | 978 | { |
903 | int ret; | 979 | int ret; |
904 | u8 id_high, id_low; | 980 | u8 id_high, id_low; |
@@ -929,16 +1005,9 @@ static int ov5642_probe(struct i2c_client *client, | |||
929 | const struct i2c_device_id *did) | 1005 | const struct i2c_device_id *did) |
930 | { | 1006 | { |
931 | struct ov5642 *priv; | 1007 | struct ov5642 *priv; |
932 | struct soc_camera_device *icd = client->dev.platform_data; | 1008 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
933 | struct soc_camera_link *icl; | ||
934 | int ret; | 1009 | int ret; |
935 | 1010 | ||
936 | if (!icd) { | ||
937 | dev_err(&client->dev, "OV5642: missing soc-camera data!\n"); | ||
938 | return -EINVAL; | ||
939 | } | ||
940 | |||
941 | icl = to_soc_camera_link(icd); | ||
942 | if (!icl) { | 1011 | if (!icl) { |
943 | dev_err(&client->dev, "OV5642: missing platform data!\n"); | 1012 | dev_err(&client->dev, "OV5642: missing platform data!\n"); |
944 | return -EINVAL; | 1013 | return -EINVAL; |
@@ -950,17 +1019,24 @@ static int ov5642_probe(struct i2c_client *client, | |||
950 | 1019 | ||
951 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); | 1020 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); |
952 | 1021 | ||
953 | icd->ops = &soc_ov5642_ops; | 1022 | priv->fmt = &ov5642_colour_fmts[0]; |
954 | priv->fmt = &ov5642_colour_fmts[0]; | 1023 | |
1024 | priv->crop_rect.width = OV5642_DEFAULT_WIDTH; | ||
1025 | priv->crop_rect.height = OV5642_DEFAULT_HEIGHT; | ||
1026 | priv->crop_rect.left = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2; | ||
1027 | priv->crop_rect.top = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2; | ||
1028 | priv->crop_rect.width = OV5642_DEFAULT_WIDTH; | ||
1029 | priv->crop_rect.height = OV5642_DEFAULT_HEIGHT; | ||
1030 | priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH; | ||
1031 | priv->total_height = BLANKING_MIN_HEIGHT; | ||
955 | 1032 | ||
956 | ret = ov5642_video_probe(icd, client); | 1033 | ret = ov5642_video_probe(client); |
957 | if (ret < 0) | 1034 | if (ret < 0) |
958 | goto error; | 1035 | goto error; |
959 | 1036 | ||
960 | return 0; | 1037 | return 0; |
961 | 1038 | ||
962 | error: | 1039 | error: |
963 | icd->ops = NULL; | ||
964 | kfree(priv); | 1040 | kfree(priv); |
965 | return ret; | 1041 | return ret; |
966 | } | 1042 | } |
@@ -968,10 +1044,8 @@ error: | |||
968 | static int ov5642_remove(struct i2c_client *client) | 1044 | static int ov5642_remove(struct i2c_client *client) |
969 | { | 1045 | { |
970 | struct ov5642 *priv = to_ov5642(client); | 1046 | struct ov5642 *priv = to_ov5642(client); |
971 | struct soc_camera_device *icd = client->dev.platform_data; | 1047 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
972 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
973 | 1048 | ||
974 | icd->ops = NULL; | ||
975 | if (icl->free_bus) | 1049 | if (icl->free_bus) |
976 | icl->free_bus(icl); | 1050 | icl->free_bus(icl); |
977 | kfree(priv); | 1051 | kfree(priv); |
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index 456d9ad9ae5a..d5b057207a7b 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c | |||
@@ -28,10 +28,11 @@ | |||
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/v4l2-mediabus.h> | ||
31 | 32 | ||
32 | #include <media/soc_camera.h> | 33 | #include <media/soc_camera.h> |
33 | #include <media/v4l2-chip-ident.h> | 34 | #include <media/v4l2-chip-ident.h> |
34 | 35 | #include <media/v4l2-ctrls.h> | |
35 | 36 | ||
36 | /* Register definitions */ | 37 | /* Register definitions */ |
37 | #define REG_GAIN 0x00 /* range 00 - 3F */ | 38 | #define REG_GAIN 0x00 /* range 00 - 3F */ |
@@ -177,20 +178,23 @@ struct ov6650_reg { | |||
177 | 178 | ||
178 | struct ov6650 { | 179 | struct ov6650 { |
179 | struct v4l2_subdev subdev; | 180 | struct v4l2_subdev subdev; |
180 | 181 | struct v4l2_ctrl_handler hdl; | |
181 | int gain; | 182 | struct { |
182 | int blue; | 183 | /* exposure/autoexposure cluster */ |
183 | int red; | 184 | struct v4l2_ctrl *autoexposure; |
184 | int saturation; | 185 | struct v4l2_ctrl *exposure; |
185 | int hue; | 186 | }; |
186 | int brightness; | 187 | struct { |
187 | int exposure; | 188 | /* gain/autogain cluster */ |
188 | int gamma; | 189 | struct v4l2_ctrl *autogain; |
189 | int aec; | 190 | struct v4l2_ctrl *gain; |
190 | bool vflip; | 191 | }; |
191 | bool hflip; | 192 | struct { |
192 | bool awb; | 193 | /* blue/red/autowhitebalance cluster */ |
193 | bool agc; | 194 | struct v4l2_ctrl *autowb; |
195 | struct v4l2_ctrl *blue; | ||
196 | struct v4l2_ctrl *red; | ||
197 | }; | ||
194 | bool half_scale; /* scale down output by 2 */ | 198 | bool half_scale; /* scale down output by 2 */ |
195 | struct v4l2_rect rect; /* sensor cropping window */ | 199 | struct v4l2_rect rect; /* sensor cropping window */ |
196 | unsigned long pclk_limit; /* from host */ | 200 | unsigned long pclk_limit; /* from host */ |
@@ -210,126 +214,6 @@ static enum v4l2_mbus_pixelcode ov6650_codes[] = { | |||
210 | V4L2_MBUS_FMT_Y8_1X8, | 214 | V4L2_MBUS_FMT_Y8_1X8, |
211 | }; | 215 | }; |
212 | 216 | ||
213 | static const struct v4l2_queryctrl ov6650_controls[] = { | ||
214 | { | ||
215 | .id = V4L2_CID_AUTOGAIN, | ||
216 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
217 | .name = "AGC", | ||
218 | .minimum = 0, | ||
219 | .maximum = 1, | ||
220 | .step = 1, | ||
221 | .default_value = 1, | ||
222 | }, | ||
223 | { | ||
224 | .id = V4L2_CID_GAIN, | ||
225 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
226 | .name = "Gain", | ||
227 | .minimum = 0, | ||
228 | .maximum = 0x3f, | ||
229 | .step = 1, | ||
230 | .default_value = DEF_GAIN, | ||
231 | }, | ||
232 | { | ||
233 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | ||
234 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
235 | .name = "AWB", | ||
236 | .minimum = 0, | ||
237 | .maximum = 1, | ||
238 | .step = 1, | ||
239 | .default_value = 1, | ||
240 | }, | ||
241 | { | ||
242 | .id = V4L2_CID_BLUE_BALANCE, | ||
243 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
244 | .name = "Blue", | ||
245 | .minimum = 0, | ||
246 | .maximum = 0xff, | ||
247 | .step = 1, | ||
248 | .default_value = DEF_BLUE, | ||
249 | }, | ||
250 | { | ||
251 | .id = V4L2_CID_RED_BALANCE, | ||
252 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
253 | .name = "Red", | ||
254 | .minimum = 0, | ||
255 | .maximum = 0xff, | ||
256 | .step = 1, | ||
257 | .default_value = DEF_RED, | ||
258 | }, | ||
259 | { | ||
260 | .id = V4L2_CID_SATURATION, | ||
261 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
262 | .name = "Saturation", | ||
263 | .minimum = 0, | ||
264 | .maximum = 0xf, | ||
265 | .step = 1, | ||
266 | .default_value = 0x8, | ||
267 | }, | ||
268 | { | ||
269 | .id = V4L2_CID_HUE, | ||
270 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
271 | .name = "Hue", | ||
272 | .minimum = 0, | ||
273 | .maximum = HUE_MASK, | ||
274 | .step = 1, | ||
275 | .default_value = DEF_HUE, | ||
276 | }, | ||
277 | { | ||
278 | .id = V4L2_CID_BRIGHTNESS, | ||
279 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
280 | .name = "Brightness", | ||
281 | .minimum = 0, | ||
282 | .maximum = 0xff, | ||
283 | .step = 1, | ||
284 | .default_value = 0x80, | ||
285 | }, | ||
286 | { | ||
287 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
288 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
289 | .name = "AEC", | ||
290 | .minimum = 0, | ||
291 | .maximum = 3, | ||
292 | .step = 1, | ||
293 | .default_value = 0, | ||
294 | }, | ||
295 | { | ||
296 | .id = V4L2_CID_EXPOSURE, | ||
297 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
298 | .name = "Exposure", | ||
299 | .minimum = 0, | ||
300 | .maximum = 0xff, | ||
301 | .step = 1, | ||
302 | .default_value = DEF_AECH, | ||
303 | }, | ||
304 | { | ||
305 | .id = V4L2_CID_GAMMA, | ||
306 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
307 | .name = "Gamma", | ||
308 | .minimum = 0, | ||
309 | .maximum = 0xff, | ||
310 | .step = 1, | ||
311 | .default_value = 0x12, | ||
312 | }, | ||
313 | { | ||
314 | .id = V4L2_CID_VFLIP, | ||
315 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
316 | .name = "Flip Vertically", | ||
317 | .minimum = 0, | ||
318 | .maximum = 1, | ||
319 | .step = 1, | ||
320 | .default_value = 0, | ||
321 | }, | ||
322 | { | ||
323 | .id = V4L2_CID_HFLIP, | ||
324 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
325 | .name = "Flip Horizontally", | ||
326 | .minimum = 0, | ||
327 | .maximum = 1, | ||
328 | .step = 1, | ||
329 | .default_value = 0, | ||
330 | }, | ||
331 | }; | ||
332 | |||
333 | /* read a register */ | 217 | /* read a register */ |
334 | static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) | 218 | static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) |
335 | { | 219 | { |
@@ -419,213 +303,90 @@ static int ov6650_s_stream(struct v4l2_subdev *sd, int enable) | |||
419 | return 0; | 303 | return 0; |
420 | } | 304 | } |
421 | 305 | ||
422 | /* Alter bus settings on camera side */ | ||
423 | static int ov6650_set_bus_param(struct soc_camera_device *icd, | ||
424 | unsigned long flags) | ||
425 | { | ||
426 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
427 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
428 | int ret; | ||
429 | |||
430 | flags = soc_camera_apply_sensor_flags(icl, flags); | ||
431 | |||
432 | if (flags & SOCAM_PCLK_SAMPLE_RISING) | ||
433 | ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); | ||
434 | else | ||
435 | ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); | ||
436 | if (ret) | ||
437 | return ret; | ||
438 | |||
439 | if (flags & SOCAM_HSYNC_ACTIVE_LOW) | ||
440 | ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); | ||
441 | else | ||
442 | ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); | ||
443 | if (ret) | ||
444 | return ret; | ||
445 | |||
446 | if (flags & SOCAM_VSYNC_ACTIVE_HIGH) | ||
447 | ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); | ||
448 | else | ||
449 | ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); | ||
450 | |||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | /* Request bus settings on camera side */ | ||
455 | static unsigned long ov6650_query_bus_param(struct soc_camera_device *icd) | ||
456 | { | ||
457 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
458 | |||
459 | unsigned long flags = SOCAM_MASTER | | ||
460 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | | ||
461 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | | ||
462 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | | ||
463 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | ||
464 | |||
465 | return soc_camera_apply_sensor_flags(icl, flags); | ||
466 | } | ||
467 | |||
468 | /* Get status of additional camera capabilities */ | 306 | /* Get status of additional camera capabilities */ |
469 | static int ov6650_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 307 | static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
470 | { | 308 | { |
309 | struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); | ||
310 | struct v4l2_subdev *sd = &priv->subdev; | ||
471 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 311 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
472 | struct ov6650 *priv = to_ov6650(client); | 312 | uint8_t reg, reg2; |
473 | uint8_t reg; | 313 | int ret; |
474 | int ret = 0; | ||
475 | 314 | ||
476 | switch (ctrl->id) { | 315 | switch (ctrl->id) { |
477 | case V4L2_CID_AUTOGAIN: | 316 | case V4L2_CID_AUTOGAIN: |
478 | ctrl->value = priv->agc; | 317 | ret = ov6650_reg_read(client, REG_GAIN, ®); |
479 | break; | 318 | if (!ret) |
480 | case V4L2_CID_GAIN: | 319 | priv->gain->val = reg; |
481 | if (priv->agc) { | 320 | return ret; |
482 | ret = ov6650_reg_read(client, REG_GAIN, ®); | ||
483 | ctrl->value = reg; | ||
484 | } else { | ||
485 | ctrl->value = priv->gain; | ||
486 | } | ||
487 | break; | ||
488 | case V4L2_CID_AUTO_WHITE_BALANCE: | 321 | case V4L2_CID_AUTO_WHITE_BALANCE: |
489 | ctrl->value = priv->awb; | 322 | ret = ov6650_reg_read(client, REG_BLUE, ®); |
490 | break; | 323 | if (!ret) |
491 | case V4L2_CID_BLUE_BALANCE: | 324 | ret = ov6650_reg_read(client, REG_RED, ®2); |
492 | if (priv->awb) { | 325 | if (!ret) { |
493 | ret = ov6650_reg_read(client, REG_BLUE, ®); | 326 | priv->blue->val = reg; |
494 | ctrl->value = reg; | 327 | priv->red->val = reg2; |
495 | } else { | ||
496 | ctrl->value = priv->blue; | ||
497 | } | ||
498 | break; | ||
499 | case V4L2_CID_RED_BALANCE: | ||
500 | if (priv->awb) { | ||
501 | ret = ov6650_reg_read(client, REG_RED, ®); | ||
502 | ctrl->value = reg; | ||
503 | } else { | ||
504 | ctrl->value = priv->red; | ||
505 | } | 328 | } |
506 | break; | 329 | return ret; |
507 | case V4L2_CID_SATURATION: | ||
508 | ctrl->value = priv->saturation; | ||
509 | break; | ||
510 | case V4L2_CID_HUE: | ||
511 | ctrl->value = priv->hue; | ||
512 | break; | ||
513 | case V4L2_CID_BRIGHTNESS: | ||
514 | ctrl->value = priv->brightness; | ||
515 | break; | ||
516 | case V4L2_CID_EXPOSURE_AUTO: | 330 | case V4L2_CID_EXPOSURE_AUTO: |
517 | ctrl->value = priv->aec; | 331 | ret = ov6650_reg_read(client, REG_AECH, ®); |
518 | break; | 332 | if (!ret) |
519 | case V4L2_CID_EXPOSURE: | 333 | priv->exposure->val = reg; |
520 | if (priv->aec) { | 334 | return ret; |
521 | ret = ov6650_reg_read(client, REG_AECH, ®); | ||
522 | ctrl->value = reg; | ||
523 | } else { | ||
524 | ctrl->value = priv->exposure; | ||
525 | } | ||
526 | break; | ||
527 | case V4L2_CID_GAMMA: | ||
528 | ctrl->value = priv->gamma; | ||
529 | break; | ||
530 | case V4L2_CID_VFLIP: | ||
531 | ctrl->value = priv->vflip; | ||
532 | break; | ||
533 | case V4L2_CID_HFLIP: | ||
534 | ctrl->value = priv->hflip; | ||
535 | break; | ||
536 | } | 335 | } |
537 | return ret; | 336 | return -EINVAL; |
538 | } | 337 | } |
539 | 338 | ||
540 | /* Set status of additional camera capabilities */ | 339 | /* Set status of additional camera capabilities */ |
541 | static int ov6650_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 340 | static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) |
542 | { | 341 | { |
342 | struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); | ||
343 | struct v4l2_subdev *sd = &priv->subdev; | ||
543 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 344 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
544 | struct ov6650 *priv = to_ov6650(client); | 345 | int ret; |
545 | int ret = 0; | ||
546 | 346 | ||
547 | switch (ctrl->id) { | 347 | switch (ctrl->id) { |
548 | case V4L2_CID_AUTOGAIN: | 348 | case V4L2_CID_AUTOGAIN: |
549 | ret = ov6650_reg_rmw(client, REG_COMB, | 349 | ret = ov6650_reg_rmw(client, REG_COMB, |
550 | ctrl->value ? COMB_AGC : 0, COMB_AGC); | 350 | ctrl->val ? COMB_AGC : 0, COMB_AGC); |
551 | if (!ret) | 351 | if (!ret && !ctrl->val) |
552 | priv->agc = ctrl->value; | 352 | ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val); |
553 | break; | 353 | return ret; |
554 | case V4L2_CID_GAIN: | ||
555 | ret = ov6650_reg_write(client, REG_GAIN, ctrl->value); | ||
556 | if (!ret) | ||
557 | priv->gain = ctrl->value; | ||
558 | break; | ||
559 | case V4L2_CID_AUTO_WHITE_BALANCE: | 354 | case V4L2_CID_AUTO_WHITE_BALANCE: |
560 | ret = ov6650_reg_rmw(client, REG_COMB, | 355 | ret = ov6650_reg_rmw(client, REG_COMB, |
561 | ctrl->value ? COMB_AWB : 0, COMB_AWB); | 356 | ctrl->val ? COMB_AWB : 0, COMB_AWB); |
562 | if (!ret) | 357 | if (!ret && !ctrl->val) { |
563 | priv->awb = ctrl->value; | 358 | ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val); |
564 | break; | 359 | if (!ret) |
565 | case V4L2_CID_BLUE_BALANCE: | 360 | ret = ov6650_reg_write(client, REG_RED, |
566 | ret = ov6650_reg_write(client, REG_BLUE, ctrl->value); | 361 | priv->red->val); |
567 | if (!ret) | 362 | } |
568 | priv->blue = ctrl->value; | 363 | return ret; |
569 | break; | ||
570 | case V4L2_CID_RED_BALANCE: | ||
571 | ret = ov6650_reg_write(client, REG_RED, ctrl->value); | ||
572 | if (!ret) | ||
573 | priv->red = ctrl->value; | ||
574 | break; | ||
575 | case V4L2_CID_SATURATION: | 364 | case V4L2_CID_SATURATION: |
576 | ret = ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->value), | 365 | return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val), |
577 | SAT_MASK); | 366 | SAT_MASK); |
578 | if (!ret) | ||
579 | priv->saturation = ctrl->value; | ||
580 | break; | ||
581 | case V4L2_CID_HUE: | 367 | case V4L2_CID_HUE: |
582 | ret = ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->value), | 368 | return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val), |
583 | HUE_MASK); | 369 | HUE_MASK); |
584 | if (!ret) | ||
585 | priv->hue = ctrl->value; | ||
586 | break; | ||
587 | case V4L2_CID_BRIGHTNESS: | 370 | case V4L2_CID_BRIGHTNESS: |
588 | ret = ov6650_reg_write(client, REG_BRT, ctrl->value); | 371 | return ov6650_reg_write(client, REG_BRT, ctrl->val); |
589 | if (!ret) | ||
590 | priv->brightness = ctrl->value; | ||
591 | break; | ||
592 | case V4L2_CID_EXPOSURE_AUTO: | 372 | case V4L2_CID_EXPOSURE_AUTO: |
593 | switch (ctrl->value) { | 373 | ret = ov6650_reg_rmw(client, REG_COMB, ctrl->val == |
594 | case V4L2_EXPOSURE_AUTO: | 374 | V4L2_EXPOSURE_AUTO ? COMB_AEC : 0, COMB_AEC); |
595 | ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0); | 375 | if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) |
596 | break; | 376 | ret = ov6650_reg_write(client, REG_AECH, |
597 | default: | 377 | priv->exposure->val); |
598 | ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC); | 378 | return ret; |
599 | break; | ||
600 | } | ||
601 | if (!ret) | ||
602 | priv->aec = ctrl->value; | ||
603 | break; | ||
604 | case V4L2_CID_EXPOSURE: | ||
605 | ret = ov6650_reg_write(client, REG_AECH, ctrl->value); | ||
606 | if (!ret) | ||
607 | priv->exposure = ctrl->value; | ||
608 | break; | ||
609 | case V4L2_CID_GAMMA: | 379 | case V4L2_CID_GAMMA: |
610 | ret = ov6650_reg_write(client, REG_GAM1, ctrl->value); | 380 | return ov6650_reg_write(client, REG_GAM1, ctrl->val); |
611 | if (!ret) | ||
612 | priv->gamma = ctrl->value; | ||
613 | break; | ||
614 | case V4L2_CID_VFLIP: | 381 | case V4L2_CID_VFLIP: |
615 | ret = ov6650_reg_rmw(client, REG_COMB, | 382 | return ov6650_reg_rmw(client, REG_COMB, |
616 | ctrl->value ? COMB_FLIP_V : 0, COMB_FLIP_V); | 383 | ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V); |
617 | if (!ret) | ||
618 | priv->vflip = ctrl->value; | ||
619 | break; | ||
620 | case V4L2_CID_HFLIP: | 384 | case V4L2_CID_HFLIP: |
621 | ret = ov6650_reg_rmw(client, REG_COMB, | 385 | return ov6650_reg_rmw(client, REG_COMB, |
622 | ctrl->value ? COMB_FLIP_H : 0, COMB_FLIP_H); | 386 | ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H); |
623 | if (!ret) | ||
624 | priv->hflip = ctrl->value; | ||
625 | break; | ||
626 | } | 387 | } |
627 | 388 | ||
628 | return ret; | 389 | return -EINVAL; |
629 | } | 390 | } |
630 | 391 | ||
631 | /* Get chip identification */ | 392 | /* Get chip identification */ |
@@ -778,7 +539,7 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe, | |||
778 | static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) | 539 | static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) |
779 | { | 540 | { |
780 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 541 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
781 | struct soc_camera_device *icd = client->dev.platform_data; | 542 | struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; |
782 | struct soc_camera_sense *sense = icd->sense; | 543 | struct soc_camera_sense *sense = icd->sense; |
783 | struct ov6650 *priv = to_ov6650(client); | 544 | struct ov6650 *priv = to_ov6650(client); |
784 | bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); | 545 | bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); |
@@ -1057,8 +818,7 @@ static int ov6650_prog_dflt(struct i2c_client *client) | |||
1057 | return ret; | 818 | return ret; |
1058 | } | 819 | } |
1059 | 820 | ||
1060 | static int ov6650_video_probe(struct soc_camera_device *icd, | 821 | static int ov6650_video_probe(struct i2c_client *client) |
1061 | struct i2c_client *client) | ||
1062 | { | 822 | { |
1063 | u8 pidh, pidl, midh, midl; | 823 | u8 pidh, pidl, midh, midl; |
1064 | int ret = 0; | 824 | int ret = 0; |
@@ -1094,16 +854,12 @@ static int ov6650_video_probe(struct soc_camera_device *icd, | |||
1094 | return ret; | 854 | return ret; |
1095 | } | 855 | } |
1096 | 856 | ||
1097 | static struct soc_camera_ops ov6650_ops = { | 857 | static const struct v4l2_ctrl_ops ov6550_ctrl_ops = { |
1098 | .set_bus_param = ov6650_set_bus_param, | 858 | .g_volatile_ctrl = ov6550_g_volatile_ctrl, |
1099 | .query_bus_param = ov6650_query_bus_param, | 859 | .s_ctrl = ov6550_s_ctrl, |
1100 | .controls = ov6650_controls, | ||
1101 | .num_controls = ARRAY_SIZE(ov6650_controls), | ||
1102 | }; | 860 | }; |
1103 | 861 | ||
1104 | static struct v4l2_subdev_core_ops ov6650_core_ops = { | 862 | static struct v4l2_subdev_core_ops ov6650_core_ops = { |
1105 | .g_ctrl = ov6650_g_ctrl, | ||
1106 | .s_ctrl = ov6650_s_ctrl, | ||
1107 | .g_chip_ident = ov6650_g_chip_ident, | 863 | .g_chip_ident = ov6650_g_chip_ident, |
1108 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 864 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1109 | .g_register = ov6650_get_register, | 865 | .g_register = ov6650_get_register, |
@@ -1111,6 +867,55 @@ static struct v4l2_subdev_core_ops ov6650_core_ops = { | |||
1111 | #endif | 867 | #endif |
1112 | }; | 868 | }; |
1113 | 869 | ||
870 | /* Request bus settings on camera side */ | ||
871 | static int ov6650_g_mbus_config(struct v4l2_subdev *sd, | ||
872 | struct v4l2_mbus_config *cfg) | ||
873 | { | ||
874 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
875 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
876 | |||
877 | cfg->flags = V4L2_MBUS_MASTER | | ||
878 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | | ||
879 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | | ||
880 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | | ||
881 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
882 | cfg->type = V4L2_MBUS_PARALLEL; | ||
883 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | |||
888 | /* Alter bus settings on camera side */ | ||
889 | static int ov6650_s_mbus_config(struct v4l2_subdev *sd, | ||
890 | const struct v4l2_mbus_config *cfg) | ||
891 | { | ||
892 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
893 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
894 | unsigned long flags = soc_camera_apply_board_flags(icl, cfg); | ||
895 | int ret; | ||
896 | |||
897 | if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) | ||
898 | ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); | ||
899 | else | ||
900 | ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); | ||
901 | if (ret) | ||
902 | return ret; | ||
903 | |||
904 | if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
905 | ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); | ||
906 | else | ||
907 | ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); | ||
908 | if (ret) | ||
909 | return ret; | ||
910 | |||
911 | if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) | ||
912 | ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); | ||
913 | else | ||
914 | ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); | ||
915 | |||
916 | return ret; | ||
917 | } | ||
918 | |||
1114 | static struct v4l2_subdev_video_ops ov6650_video_ops = { | 919 | static struct v4l2_subdev_video_ops ov6650_video_ops = { |
1115 | .s_stream = ov6650_s_stream, | 920 | .s_stream = ov6650_s_stream, |
1116 | .g_mbus_fmt = ov6650_g_fmt, | 921 | .g_mbus_fmt = ov6650_g_fmt, |
@@ -1122,6 +927,8 @@ static struct v4l2_subdev_video_ops ov6650_video_ops = { | |||
1122 | .s_crop = ov6650_s_crop, | 927 | .s_crop = ov6650_s_crop, |
1123 | .g_parm = ov6650_g_parm, | 928 | .g_parm = ov6650_g_parm, |
1124 | .s_parm = ov6650_s_parm, | 929 | .s_parm = ov6650_s_parm, |
930 | .g_mbus_config = ov6650_g_mbus_config, | ||
931 | .s_mbus_config = ov6650_s_mbus_config, | ||
1125 | }; | 932 | }; |
1126 | 933 | ||
1127 | static struct v4l2_subdev_ops ov6650_subdev_ops = { | 934 | static struct v4l2_subdev_ops ov6650_subdev_ops = { |
@@ -1136,16 +943,9 @@ static int ov6650_probe(struct i2c_client *client, | |||
1136 | const struct i2c_device_id *did) | 943 | const struct i2c_device_id *did) |
1137 | { | 944 | { |
1138 | struct ov6650 *priv; | 945 | struct ov6650 *priv; |
1139 | struct soc_camera_device *icd = client->dev.platform_data; | 946 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
1140 | struct soc_camera_link *icl; | ||
1141 | int ret; | 947 | int ret; |
1142 | 948 | ||
1143 | if (!icd) { | ||
1144 | dev_err(&client->dev, "Missing soc-camera data!\n"); | ||
1145 | return -EINVAL; | ||
1146 | } | ||
1147 | |||
1148 | icl = to_soc_camera_link(icd); | ||
1149 | if (!icl) { | 949 | if (!icl) { |
1150 | dev_err(&client->dev, "Missing platform_data for driver\n"); | 950 | dev_err(&client->dev, "Missing platform_data for driver\n"); |
1151 | return -EINVAL; | 951 | return -EINVAL; |
@@ -1159,8 +959,46 @@ static int ov6650_probe(struct i2c_client *client, | |||
1159 | } | 959 | } |
1160 | 960 | ||
1161 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); | 961 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); |
962 | v4l2_ctrl_handler_init(&priv->hdl, 13); | ||
963 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
964 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
965 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
966 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
967 | priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
968 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
969 | priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
970 | V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN); | ||
971 | priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
972 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
973 | priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
974 | V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE); | ||
975 | priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
976 | V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED); | ||
977 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
978 | V4L2_CID_SATURATION, 0, 0xf, 1, 0x8); | ||
979 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
980 | V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE); | ||
981 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
982 | V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80); | ||
983 | priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl, | ||
984 | &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, | ||
985 | V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); | ||
986 | priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
987 | V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH); | ||
988 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
989 | V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); | ||
990 | |||
991 | priv->subdev.ctrl_handler = &priv->hdl; | ||
992 | if (priv->hdl.error) { | ||
993 | int err = priv->hdl.error; | ||
1162 | 994 | ||
1163 | icd->ops = &ov6650_ops; | 995 | kfree(priv); |
996 | return err; | ||
997 | } | ||
998 | v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); | ||
999 | v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); | ||
1000 | v4l2_ctrl_auto_cluster(2, &priv->autoexposure, | ||
1001 | V4L2_EXPOSURE_MANUAL, true); | ||
1164 | 1002 | ||
1165 | priv->rect.left = DEF_HSTRT << 1; | 1003 | priv->rect.left = DEF_HSTRT << 1; |
1166 | priv->rect.top = DEF_VSTRT << 1; | 1004 | priv->rect.top = DEF_VSTRT << 1; |
@@ -1170,10 +1008,12 @@ static int ov6650_probe(struct i2c_client *client, | |||
1170 | priv->code = V4L2_MBUS_FMT_YUYV8_2X8; | 1008 | priv->code = V4L2_MBUS_FMT_YUYV8_2X8; |
1171 | priv->colorspace = V4L2_COLORSPACE_JPEG; | 1009 | priv->colorspace = V4L2_COLORSPACE_JPEG; |
1172 | 1010 | ||
1173 | ret = ov6650_video_probe(icd, client); | 1011 | ret = ov6650_video_probe(client); |
1012 | if (!ret) | ||
1013 | ret = v4l2_ctrl_handler_setup(&priv->hdl); | ||
1174 | 1014 | ||
1175 | if (ret) { | 1015 | if (ret) { |
1176 | icd->ops = NULL; | 1016 | v4l2_ctrl_handler_free(&priv->hdl); |
1177 | kfree(priv); | 1017 | kfree(priv); |
1178 | } | 1018 | } |
1179 | 1019 | ||
@@ -1184,6 +1024,8 @@ static int ov6650_remove(struct i2c_client *client) | |||
1184 | { | 1024 | { |
1185 | struct ov6650 *priv = to_ov6650(client); | 1025 | struct ov6650 *priv = to_ov6650(client); |
1186 | 1026 | ||
1027 | v4l2_device_unregister_subdev(&priv->subdev); | ||
1028 | v4l2_ctrl_handler_free(&priv->hdl); | ||
1187 | kfree(priv); | 1029 | kfree(priv); |
1188 | return 0; | 1030 | return 0; |
1189 | } | 1031 | } |
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 397870f076c1..9f6ce3d8a29e 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c | |||
@@ -20,12 +20,14 @@ | |||
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/v4l2-mediabus.h> | ||
23 | #include <linux/videodev2.h> | 24 | #include <linux/videodev2.h> |
25 | |||
26 | #include <media/ov772x.h> | ||
27 | #include <media/soc_camera.h> | ||
28 | #include <media/v4l2-ctrls.h> | ||
24 | #include <media/v4l2-chip-ident.h> | 29 | #include <media/v4l2-chip-ident.h> |
25 | #include <media/v4l2-subdev.h> | 30 | #include <media/v4l2-subdev.h> |
26 | #include <media/soc_camera.h> | ||
27 | #include <media/soc_mediabus.h> | ||
28 | #include <media/ov772x.h> | ||
29 | 31 | ||
30 | /* | 32 | /* |
31 | * register offset | 33 | * register offset |
@@ -400,6 +402,7 @@ struct ov772x_win_size { | |||
400 | 402 | ||
401 | struct ov772x_priv { | 403 | struct ov772x_priv { |
402 | struct v4l2_subdev subdev; | 404 | struct v4l2_subdev subdev; |
405 | struct v4l2_ctrl_handler hdl; | ||
403 | struct ov772x_camera_info *info; | 406 | struct ov772x_camera_info *info; |
404 | const struct ov772x_color_format *cfmt; | 407 | const struct ov772x_color_format *cfmt; |
405 | const struct ov772x_win_size *win; | 408 | const struct ov772x_win_size *win; |
@@ -517,36 +520,6 @@ static const struct ov772x_win_size ov772x_win_qvga = { | |||
517 | .regs = ov772x_qvga_regs, | 520 | .regs = ov772x_qvga_regs, |
518 | }; | 521 | }; |
519 | 522 | ||
520 | static const struct v4l2_queryctrl ov772x_controls[] = { | ||
521 | { | ||
522 | .id = V4L2_CID_VFLIP, | ||
523 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
524 | .name = "Flip Vertically", | ||
525 | .minimum = 0, | ||
526 | .maximum = 1, | ||
527 | .step = 1, | ||
528 | .default_value = 0, | ||
529 | }, | ||
530 | { | ||
531 | .id = V4L2_CID_HFLIP, | ||
532 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
533 | .name = "Flip Horizontally", | ||
534 | .minimum = 0, | ||
535 | .maximum = 1, | ||
536 | .step = 1, | ||
537 | .default_value = 0, | ||
538 | }, | ||
539 | { | ||
540 | .id = V4L2_CID_BAND_STOP_FILTER, | ||
541 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
542 | .name = "Band-stop filter", | ||
543 | .minimum = 0, | ||
544 | .maximum = 256, | ||
545 | .step = 1, | ||
546 | .default_value = 0, | ||
547 | }, | ||
548 | }; | ||
549 | |||
550 | /* | 523 | /* |
551 | * general function | 524 | * general function |
552 | */ | 525 | */ |
@@ -620,75 +593,30 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) | |||
620 | return 0; | 593 | return 0; |
621 | } | 594 | } |
622 | 595 | ||
623 | static int ov772x_set_bus_param(struct soc_camera_device *icd, | 596 | static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) |
624 | unsigned long flags) | ||
625 | { | ||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) | ||
630 | { | ||
631 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
632 | struct ov772x_priv *priv = i2c_get_clientdata(client); | ||
633 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
634 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
635 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
636 | SOCAM_DATA_ACTIVE_HIGH; | ||
637 | |||
638 | if (priv->info->flags & OV772X_FLAG_8BIT) | ||
639 | flags |= SOCAM_DATAWIDTH_8; | ||
640 | else | ||
641 | flags |= SOCAM_DATAWIDTH_10; | ||
642 | |||
643 | return soc_camera_apply_sensor_flags(icl, flags); | ||
644 | } | ||
645 | |||
646 | static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
647 | { | ||
648 | struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); | ||
649 | |||
650 | switch (ctrl->id) { | ||
651 | case V4L2_CID_VFLIP: | ||
652 | ctrl->value = priv->flag_vflip; | ||
653 | break; | ||
654 | case V4L2_CID_HFLIP: | ||
655 | ctrl->value = priv->flag_hflip; | ||
656 | break; | ||
657 | case V4L2_CID_BAND_STOP_FILTER: | ||
658 | ctrl->value = priv->band_filter; | ||
659 | break; | ||
660 | } | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
665 | { | 597 | { |
598 | struct ov772x_priv *priv = container_of(ctrl->handler, | ||
599 | struct ov772x_priv, hdl); | ||
600 | struct v4l2_subdev *sd = &priv->subdev; | ||
666 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 601 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
667 | struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); | ||
668 | int ret = 0; | 602 | int ret = 0; |
669 | u8 val; | 603 | u8 val; |
670 | 604 | ||
671 | switch (ctrl->id) { | 605 | switch (ctrl->id) { |
672 | case V4L2_CID_VFLIP: | 606 | case V4L2_CID_VFLIP: |
673 | val = ctrl->value ? VFLIP_IMG : 0x00; | 607 | val = ctrl->val ? VFLIP_IMG : 0x00; |
674 | priv->flag_vflip = ctrl->value; | 608 | priv->flag_vflip = ctrl->val; |
675 | if (priv->info->flags & OV772X_FLAG_VFLIP) | 609 | if (priv->info->flags & OV772X_FLAG_VFLIP) |
676 | val ^= VFLIP_IMG; | 610 | val ^= VFLIP_IMG; |
677 | ret = ov772x_mask_set(client, COM3, VFLIP_IMG, val); | 611 | return ov772x_mask_set(client, COM3, VFLIP_IMG, val); |
678 | break; | ||
679 | case V4L2_CID_HFLIP: | 612 | case V4L2_CID_HFLIP: |
680 | val = ctrl->value ? HFLIP_IMG : 0x00; | 613 | val = ctrl->val ? HFLIP_IMG : 0x00; |
681 | priv->flag_hflip = ctrl->value; | 614 | priv->flag_hflip = ctrl->val; |
682 | if (priv->info->flags & OV772X_FLAG_HFLIP) | 615 | if (priv->info->flags & OV772X_FLAG_HFLIP) |
683 | val ^= HFLIP_IMG; | 616 | val ^= HFLIP_IMG; |
684 | ret = ov772x_mask_set(client, COM3, HFLIP_IMG, val); | 617 | return ov772x_mask_set(client, COM3, HFLIP_IMG, val); |
685 | break; | ||
686 | case V4L2_CID_BAND_STOP_FILTER: | 618 | case V4L2_CID_BAND_STOP_FILTER: |
687 | if ((unsigned)ctrl->value > 256) | 619 | if (!ctrl->val) { |
688 | ctrl->value = 256; | ||
689 | if (ctrl->value == priv->band_filter) | ||
690 | break; | ||
691 | if (!ctrl->value) { | ||
692 | /* Switch the filter off, it is on now */ | 620 | /* Switch the filter off, it is on now */ |
693 | ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); | 621 | ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); |
694 | if (!ret) | 622 | if (!ret) |
@@ -696,7 +624,7 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
696 | BNDF_ON_OFF, 0); | 624 | BNDF_ON_OFF, 0); |
697 | } else { | 625 | } else { |
698 | /* Switch the filter on, set AEC low limit */ | 626 | /* Switch the filter on, set AEC low limit */ |
699 | val = 256 - ctrl->value; | 627 | val = 256 - ctrl->val; |
700 | ret = ov772x_mask_set(client, COM8, | 628 | ret = ov772x_mask_set(client, COM8, |
701 | BNDF_ON_OFF, BNDF_ON_OFF); | 629 | BNDF_ON_OFF, BNDF_ON_OFF); |
702 | if (!ret) | 630 | if (!ret) |
@@ -704,11 +632,11 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
704 | 0xff, val); | 632 | 0xff, val); |
705 | } | 633 | } |
706 | if (!ret) | 634 | if (!ret) |
707 | priv->band_filter = ctrl->value; | 635 | priv->band_filter = ctrl->val; |
708 | break; | 636 | return ret; |
709 | } | 637 | } |
710 | 638 | ||
711 | return ret; | 639 | return -EINVAL; |
712 | } | 640 | } |
713 | 641 | ||
714 | static int ov772x_g_chip_ident(struct v4l2_subdev *sd, | 642 | static int ov772x_g_chip_ident(struct v4l2_subdev *sd, |
@@ -822,13 +750,13 @@ static int ov772x_set_params(struct i2c_client *client, u32 *width, u32 *height, | |||
822 | goto ov772x_set_fmt_error; | 750 | goto ov772x_set_fmt_error; |
823 | 751 | ||
824 | ret = ov772x_mask_set(client, | 752 | ret = ov772x_mask_set(client, |
825 | EDGE_TRSHLD, EDGE_THRESHOLD_MASK, | 753 | EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK, |
826 | priv->info->edgectrl.threshold); | 754 | priv->info->edgectrl.threshold); |
827 | if (ret < 0) | 755 | if (ret < 0) |
828 | goto ov772x_set_fmt_error; | 756 | goto ov772x_set_fmt_error; |
829 | 757 | ||
830 | ret = ov772x_mask_set(client, | 758 | ret = ov772x_mask_set(client, |
831 | EDGE_STRNGT, EDGE_STRENGTH_MASK, | 759 | EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK, |
832 | priv->info->edgectrl.strength); | 760 | priv->info->edgectrl.strength); |
833 | if (ret < 0) | 761 | if (ret < 0) |
834 | goto ov772x_set_fmt_error; | 762 | goto ov772x_set_fmt_error; |
@@ -840,13 +768,13 @@ static int ov772x_set_params(struct i2c_client *client, u32 *width, u32 *height, | |||
840 | * set upper and lower limit | 768 | * set upper and lower limit |
841 | */ | 769 | */ |
842 | ret = ov772x_mask_set(client, | 770 | ret = ov772x_mask_set(client, |
843 | EDGE_UPPER, EDGE_UPPER_MASK, | 771 | EDGE_UPPER, OV772X_EDGE_UPPER_MASK, |
844 | priv->info->edgectrl.upper); | 772 | priv->info->edgectrl.upper); |
845 | if (ret < 0) | 773 | if (ret < 0) |
846 | goto ov772x_set_fmt_error; | 774 | goto ov772x_set_fmt_error; |
847 | 775 | ||
848 | ret = ov772x_mask_set(client, | 776 | ret = ov772x_mask_set(client, |
849 | EDGE_LOWER, EDGE_LOWER_MASK, | 777 | EDGE_LOWER, OV772X_EDGE_LOWER_MASK, |
850 | priv->info->edgectrl.lower); | 778 | priv->info->edgectrl.lower); |
851 | if (ret < 0) | 779 | if (ret < 0) |
852 | goto ov772x_set_fmt_error; | 780 | goto ov772x_set_fmt_error; |
@@ -1025,17 +953,12 @@ static int ov772x_try_fmt(struct v4l2_subdev *sd, | |||
1025 | return 0; | 953 | return 0; |
1026 | } | 954 | } |
1027 | 955 | ||
1028 | static int ov772x_video_probe(struct soc_camera_device *icd, | 956 | static int ov772x_video_probe(struct i2c_client *client) |
1029 | struct i2c_client *client) | ||
1030 | { | 957 | { |
1031 | struct ov772x_priv *priv = to_ov772x(client); | 958 | struct ov772x_priv *priv = to_ov772x(client); |
1032 | u8 pid, ver; | 959 | u8 pid, ver; |
1033 | const char *devname; | 960 | const char *devname; |
1034 | 961 | ||
1035 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
1036 | BUG_ON(!icd->parent || | ||
1037 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
1038 | |||
1039 | /* | 962 | /* |
1040 | * check and show product ID and manufacturer ID | 963 | * check and show product ID and manufacturer ID |
1041 | */ | 964 | */ |
@@ -1064,20 +987,14 @@ static int ov772x_video_probe(struct soc_camera_device *icd, | |||
1064 | ver, | 987 | ver, |
1065 | i2c_smbus_read_byte_data(client, MIDH), | 988 | i2c_smbus_read_byte_data(client, MIDH), |
1066 | i2c_smbus_read_byte_data(client, MIDL)); | 989 | i2c_smbus_read_byte_data(client, MIDL)); |
1067 | 990 | return v4l2_ctrl_handler_setup(&priv->hdl); | |
1068 | return 0; | ||
1069 | } | 991 | } |
1070 | 992 | ||
1071 | static struct soc_camera_ops ov772x_ops = { | 993 | static const struct v4l2_ctrl_ops ov772x_ctrl_ops = { |
1072 | .set_bus_param = ov772x_set_bus_param, | 994 | .s_ctrl = ov772x_s_ctrl, |
1073 | .query_bus_param = ov772x_query_bus_param, | ||
1074 | .controls = ov772x_controls, | ||
1075 | .num_controls = ARRAY_SIZE(ov772x_controls), | ||
1076 | }; | 995 | }; |
1077 | 996 | ||
1078 | static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { | 997 | static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { |
1079 | .g_ctrl = ov772x_g_ctrl, | ||
1080 | .s_ctrl = ov772x_s_ctrl, | ||
1081 | .g_chip_ident = ov772x_g_chip_ident, | 998 | .g_chip_ident = ov772x_g_chip_ident, |
1082 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 999 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1083 | .g_register = ov772x_g_register, | 1000 | .g_register = ov772x_g_register, |
@@ -1095,6 +1012,21 @@ static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
1095 | return 0; | 1012 | return 0; |
1096 | } | 1013 | } |
1097 | 1014 | ||
1015 | static int ov772x_g_mbus_config(struct v4l2_subdev *sd, | ||
1016 | struct v4l2_mbus_config *cfg) | ||
1017 | { | ||
1018 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1019 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
1020 | |||
1021 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
1022 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
1023 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
1024 | cfg->type = V4L2_MBUS_PARALLEL; | ||
1025 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
1026 | |||
1027 | return 0; | ||
1028 | } | ||
1029 | |||
1098 | static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { | 1030 | static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { |
1099 | .s_stream = ov772x_s_stream, | 1031 | .s_stream = ov772x_s_stream, |
1100 | .g_mbus_fmt = ov772x_g_fmt, | 1032 | .g_mbus_fmt = ov772x_g_fmt, |
@@ -1103,6 +1035,7 @@ static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { | |||
1103 | .cropcap = ov772x_cropcap, | 1035 | .cropcap = ov772x_cropcap, |
1104 | .g_crop = ov772x_g_crop, | 1036 | .g_crop = ov772x_g_crop, |
1105 | .enum_mbus_fmt = ov772x_enum_fmt, | 1037 | .enum_mbus_fmt = ov772x_enum_fmt, |
1038 | .g_mbus_config = ov772x_g_mbus_config, | ||
1106 | }; | 1039 | }; |
1107 | 1040 | ||
1108 | static struct v4l2_subdev_ops ov772x_subdev_ops = { | 1041 | static struct v4l2_subdev_ops ov772x_subdev_ops = { |
@@ -1117,20 +1050,15 @@ static struct v4l2_subdev_ops ov772x_subdev_ops = { | |||
1117 | static int ov772x_probe(struct i2c_client *client, | 1050 | static int ov772x_probe(struct i2c_client *client, |
1118 | const struct i2c_device_id *did) | 1051 | const struct i2c_device_id *did) |
1119 | { | 1052 | { |
1120 | struct ov772x_priv *priv; | 1053 | struct ov772x_priv *priv; |
1121 | struct soc_camera_device *icd = client->dev.platform_data; | 1054 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
1122 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1055 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1123 | struct soc_camera_link *icl; | 1056 | int ret; |
1124 | int ret; | ||
1125 | |||
1126 | if (!icd) { | ||
1127 | dev_err(&client->dev, "OV772X: missing soc-camera data!\n"); | ||
1128 | return -EINVAL; | ||
1129 | } | ||
1130 | 1057 | ||
1131 | icl = to_soc_camera_link(icd); | 1058 | if (!icl || !icl->priv) { |
1132 | if (!icl || !icl->priv) | 1059 | dev_err(&client->dev, "OV772X: missing platform data!\n"); |
1133 | return -EINVAL; | 1060 | return -EINVAL; |
1061 | } | ||
1134 | 1062 | ||
1135 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 1063 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
1136 | dev_err(&adapter->dev, | 1064 | dev_err(&adapter->dev, |
@@ -1146,12 +1074,24 @@ static int ov772x_probe(struct i2c_client *client, | |||
1146 | priv->info = icl->priv; | 1074 | priv->info = icl->priv; |
1147 | 1075 | ||
1148 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); | 1076 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); |
1077 | v4l2_ctrl_handler_init(&priv->hdl, 3); | ||
1078 | v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, | ||
1079 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
1080 | v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, | ||
1081 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
1082 | v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, | ||
1083 | V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); | ||
1084 | priv->subdev.ctrl_handler = &priv->hdl; | ||
1085 | if (priv->hdl.error) { | ||
1086 | int err = priv->hdl.error; | ||
1149 | 1087 | ||
1150 | icd->ops = &ov772x_ops; | 1088 | kfree(priv); |
1089 | return err; | ||
1090 | } | ||
1151 | 1091 | ||
1152 | ret = ov772x_video_probe(icd, client); | 1092 | ret = ov772x_video_probe(client); |
1153 | if (ret) { | 1093 | if (ret) { |
1154 | icd->ops = NULL; | 1094 | v4l2_ctrl_handler_free(&priv->hdl); |
1155 | kfree(priv); | 1095 | kfree(priv); |
1156 | } | 1096 | } |
1157 | 1097 | ||
@@ -1161,9 +1101,9 @@ static int ov772x_probe(struct i2c_client *client, | |||
1161 | static int ov772x_remove(struct i2c_client *client) | 1101 | static int ov772x_remove(struct i2c_client *client) |
1162 | { | 1102 | { |
1163 | struct ov772x_priv *priv = to_ov772x(client); | 1103 | struct ov772x_priv *priv = to_ov772x(client); |
1164 | struct soc_camera_device *icd = client->dev.platform_data; | ||
1165 | 1104 | ||
1166 | icd->ops = NULL; | 1105 | v4l2_device_unregister_subdev(&priv->subdev); |
1106 | v4l2_ctrl_handler_free(&priv->hdl); | ||
1167 | kfree(priv); | 1107 | kfree(priv); |
1168 | return 0; | 1108 | return 0; |
1169 | } | 1109 | } |
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 3681a6ff0815..a4f99797eb56 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c | |||
@@ -24,10 +24,13 @@ | |||
24 | #include <linux/i2c.h> | 24 | #include <linux/i2c.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/v4l2-mediabus.h> | ||
27 | #include <linux/videodev2.h> | 28 | #include <linux/videodev2.h> |
29 | |||
30 | #include <media/soc_camera.h> | ||
28 | #include <media/v4l2-chip-ident.h> | 31 | #include <media/v4l2-chip-ident.h> |
29 | #include <media/v4l2-common.h> | 32 | #include <media/v4l2-common.h> |
30 | #include <media/soc_camera.h> | 33 | #include <media/v4l2-ctrls.h> |
31 | 34 | ||
32 | #include "ov9640.h" | 35 | #include "ov9640.h" |
33 | 36 | ||
@@ -162,27 +165,6 @@ static enum v4l2_mbus_pixelcode ov9640_codes[] = { | |||
162 | V4L2_MBUS_FMT_RGB565_2X8_LE, | 165 | V4L2_MBUS_FMT_RGB565_2X8_LE, |
163 | }; | 166 | }; |
164 | 167 | ||
165 | static const struct v4l2_queryctrl ov9640_controls[] = { | ||
166 | { | ||
167 | .id = V4L2_CID_VFLIP, | ||
168 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
169 | .name = "Flip Vertically", | ||
170 | .minimum = 0, | ||
171 | .maximum = 1, | ||
172 | .step = 1, | ||
173 | .default_value = 0, | ||
174 | }, | ||
175 | { | ||
176 | .id = V4L2_CID_HFLIP, | ||
177 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
178 | .name = "Flip Horizontally", | ||
179 | .minimum = 0, | ||
180 | .maximum = 1, | ||
181 | .step = 1, | ||
182 | .default_value = 0, | ||
183 | }, | ||
184 | }; | ||
185 | |||
186 | /* read a register */ | 168 | /* read a register */ |
187 | static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) | 169 | static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) |
188 | { | 170 | { |
@@ -284,75 +266,25 @@ static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) | |||
284 | return 0; | 266 | return 0; |
285 | } | 267 | } |
286 | 268 | ||
287 | /* Alter bus settings on camera side */ | ||
288 | static int ov9640_set_bus_param(struct soc_camera_device *icd, | ||
289 | unsigned long flags) | ||
290 | { | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | /* Request bus settings on camera side */ | ||
295 | static unsigned long ov9640_query_bus_param(struct soc_camera_device *icd) | ||
296 | { | ||
297 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
298 | |||
299 | /* | ||
300 | * REVISIT: the camera probably can do 10 bit transfers, but I don't | ||
301 | * have those pins connected on my hardware. | ||
302 | */ | ||
303 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
304 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
305 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | ||
306 | |||
307 | return soc_camera_apply_sensor_flags(icl, flags); | ||
308 | } | ||
309 | |||
310 | /* Get status of additional camera capabilities */ | ||
311 | static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
312 | { | ||
313 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | ||
314 | |||
315 | switch (ctrl->id) { | ||
316 | case V4L2_CID_VFLIP: | ||
317 | ctrl->value = priv->flag_vflip; | ||
318 | break; | ||
319 | case V4L2_CID_HFLIP: | ||
320 | ctrl->value = priv->flag_hflip; | ||
321 | break; | ||
322 | } | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | /* Set status of additional camera capabilities */ | 269 | /* Set status of additional camera capabilities */ |
327 | static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 270 | static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl) |
328 | { | 271 | { |
329 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 272 | struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl); |
330 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | 273 | struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); |
331 | |||
332 | int ret = 0; | ||
333 | 274 | ||
334 | switch (ctrl->id) { | 275 | switch (ctrl->id) { |
335 | case V4L2_CID_VFLIP: | 276 | case V4L2_CID_VFLIP: |
336 | priv->flag_vflip = ctrl->value; | 277 | if (ctrl->val) |
337 | if (ctrl->value) | 278 | return ov9640_reg_rmw(client, OV9640_MVFP, |
338 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
339 | OV9640_MVFP_V, 0); | 279 | OV9640_MVFP_V, 0); |
340 | else | 280 | return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V); |
341 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
342 | 0, OV9640_MVFP_V); | ||
343 | break; | ||
344 | case V4L2_CID_HFLIP: | 281 | case V4L2_CID_HFLIP: |
345 | priv->flag_hflip = ctrl->value; | 282 | if (ctrl->val) |
346 | if (ctrl->value) | 283 | return ov9640_reg_rmw(client, OV9640_MVFP, |
347 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
348 | OV9640_MVFP_H, 0); | 284 | OV9640_MVFP_H, 0); |
349 | else | 285 | return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H); |
350 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
351 | 0, OV9640_MVFP_H); | ||
352 | break; | ||
353 | } | 286 | } |
354 | 287 | return -EINVAL; | |
355 | return ret; | ||
356 | } | 288 | } |
357 | 289 | ||
358 | /* Get chip identification */ | 290 | /* Get chip identification */ |
@@ -646,10 +578,7 @@ static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
646 | return 0; | 578 | return 0; |
647 | } | 579 | } |
648 | 580 | ||
649 | 581 | static int ov9640_video_probe(struct i2c_client *client) | |
650 | |||
651 | static int ov9640_video_probe(struct soc_camera_device *icd, | ||
652 | struct i2c_client *client) | ||
653 | { | 582 | { |
654 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 583 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
655 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | 584 | struct ov9640_priv *priv = to_ov9640_sensor(sd); |
@@ -657,29 +586,19 @@ static int ov9640_video_probe(struct soc_camera_device *icd, | |||
657 | const char *devname; | 586 | const char *devname; |
658 | int ret = 0; | 587 | int ret = 0; |
659 | 588 | ||
660 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
661 | BUG_ON(!icd->parent || | ||
662 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
663 | |||
664 | /* | 589 | /* |
665 | * check and show product ID and manufacturer ID | 590 | * check and show product ID and manufacturer ID |
666 | */ | 591 | */ |
667 | 592 | ||
668 | ret = ov9640_reg_read(client, OV9640_PID, &pid); | 593 | ret = ov9640_reg_read(client, OV9640_PID, &pid); |
594 | if (!ret) | ||
595 | ret = ov9640_reg_read(client, OV9640_VER, &ver); | ||
596 | if (!ret) | ||
597 | ret = ov9640_reg_read(client, OV9640_MIDH, &midh); | ||
598 | if (!ret) | ||
599 | ret = ov9640_reg_read(client, OV9640_MIDL, &midl); | ||
669 | if (ret) | 600 | if (ret) |
670 | goto err; | 601 | return ret; |
671 | |||
672 | ret = ov9640_reg_read(client, OV9640_VER, &ver); | ||
673 | if (ret) | ||
674 | goto err; | ||
675 | |||
676 | ret = ov9640_reg_read(client, OV9640_MIDH, &midh); | ||
677 | if (ret) | ||
678 | goto err; | ||
679 | |||
680 | ret = ov9640_reg_read(client, OV9640_MIDL, &midl); | ||
681 | if (ret) | ||
682 | goto err; | ||
683 | 602 | ||
684 | switch (VERSION(pid, ver)) { | 603 | switch (VERSION(pid, ver)) { |
685 | case OV9640_V2: | 604 | case OV9640_V2: |
@@ -693,27 +612,20 @@ static int ov9640_video_probe(struct soc_camera_device *icd, | |||
693 | break; | 612 | break; |
694 | default: | 613 | default: |
695 | dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); | 614 | dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); |
696 | ret = -ENODEV; | 615 | return -ENODEV; |
697 | goto err; | ||
698 | } | 616 | } |
699 | 617 | ||
700 | dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", | 618 | dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", |
701 | devname, pid, ver, midh, midl); | 619 | devname, pid, ver, midh, midl); |
702 | 620 | ||
703 | err: | 621 | return v4l2_ctrl_handler_setup(&priv->hdl); |
704 | return ret; | ||
705 | } | 622 | } |
706 | 623 | ||
707 | static struct soc_camera_ops ov9640_ops = { | 624 | static const struct v4l2_ctrl_ops ov9640_ctrl_ops = { |
708 | .set_bus_param = ov9640_set_bus_param, | 625 | .s_ctrl = ov9640_s_ctrl, |
709 | .query_bus_param = ov9640_query_bus_param, | ||
710 | .controls = ov9640_controls, | ||
711 | .num_controls = ARRAY_SIZE(ov9640_controls), | ||
712 | }; | 626 | }; |
713 | 627 | ||
714 | static struct v4l2_subdev_core_ops ov9640_core_ops = { | 628 | static struct v4l2_subdev_core_ops ov9640_core_ops = { |
715 | .g_ctrl = ov9640_g_ctrl, | ||
716 | .s_ctrl = ov9640_s_ctrl, | ||
717 | .g_chip_ident = ov9640_g_chip_ident, | 629 | .g_chip_ident = ov9640_g_chip_ident, |
718 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 630 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
719 | .g_register = ov9640_get_register, | 631 | .g_register = ov9640_get_register, |
@@ -722,6 +634,22 @@ static struct v4l2_subdev_core_ops ov9640_core_ops = { | |||
722 | 634 | ||
723 | }; | 635 | }; |
724 | 636 | ||
637 | /* Request bus settings on camera side */ | ||
638 | static int ov9640_g_mbus_config(struct v4l2_subdev *sd, | ||
639 | struct v4l2_mbus_config *cfg) | ||
640 | { | ||
641 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
642 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
643 | |||
644 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
645 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
646 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
647 | cfg->type = V4L2_MBUS_PARALLEL; | ||
648 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
649 | |||
650 | return 0; | ||
651 | } | ||
652 | |||
725 | static struct v4l2_subdev_video_ops ov9640_video_ops = { | 653 | static struct v4l2_subdev_video_ops ov9640_video_ops = { |
726 | .s_stream = ov9640_s_stream, | 654 | .s_stream = ov9640_s_stream, |
727 | .s_mbus_fmt = ov9640_s_fmt, | 655 | .s_mbus_fmt = ov9640_s_fmt, |
@@ -729,7 +657,7 @@ static struct v4l2_subdev_video_ops ov9640_video_ops = { | |||
729 | .enum_mbus_fmt = ov9640_enum_fmt, | 657 | .enum_mbus_fmt = ov9640_enum_fmt, |
730 | .cropcap = ov9640_cropcap, | 658 | .cropcap = ov9640_cropcap, |
731 | .g_crop = ov9640_g_crop, | 659 | .g_crop = ov9640_g_crop, |
732 | 660 | .g_mbus_config = ov9640_g_mbus_config, | |
733 | }; | 661 | }; |
734 | 662 | ||
735 | static struct v4l2_subdev_ops ov9640_subdev_ops = { | 663 | static struct v4l2_subdev_ops ov9640_subdev_ops = { |
@@ -744,16 +672,9 @@ static int ov9640_probe(struct i2c_client *client, | |||
744 | const struct i2c_device_id *did) | 672 | const struct i2c_device_id *did) |
745 | { | 673 | { |
746 | struct ov9640_priv *priv; | 674 | struct ov9640_priv *priv; |
747 | struct soc_camera_device *icd = client->dev.platform_data; | 675 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
748 | struct soc_camera_link *icl; | ||
749 | int ret; | 676 | int ret; |
750 | 677 | ||
751 | if (!icd) { | ||
752 | dev_err(&client->dev, "Missing soc-camera data!\n"); | ||
753 | return -EINVAL; | ||
754 | } | ||
755 | |||
756 | icl = to_soc_camera_link(icd); | ||
757 | if (!icl) { | 678 | if (!icl) { |
758 | dev_err(&client->dev, "Missing platform_data for driver\n"); | 679 | dev_err(&client->dev, "Missing platform_data for driver\n"); |
759 | return -EINVAL; | 680 | return -EINVAL; |
@@ -768,12 +689,23 @@ static int ov9640_probe(struct i2c_client *client, | |||
768 | 689 | ||
769 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); | 690 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); |
770 | 691 | ||
771 | icd->ops = &ov9640_ops; | 692 | v4l2_ctrl_handler_init(&priv->hdl, 2); |
693 | v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, | ||
694 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
695 | v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, | ||
696 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
697 | priv->subdev.ctrl_handler = &priv->hdl; | ||
698 | if (priv->hdl.error) { | ||
699 | int err = priv->hdl.error; | ||
700 | |||
701 | kfree(priv); | ||
702 | return err; | ||
703 | } | ||
772 | 704 | ||
773 | ret = ov9640_video_probe(icd, client); | 705 | ret = ov9640_video_probe(client); |
774 | 706 | ||
775 | if (ret) { | 707 | if (ret) { |
776 | icd->ops = NULL; | 708 | v4l2_ctrl_handler_free(&priv->hdl); |
777 | kfree(priv); | 709 | kfree(priv); |
778 | } | 710 | } |
779 | 711 | ||
@@ -785,6 +717,8 @@ static int ov9640_remove(struct i2c_client *client) | |||
785 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 717 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
786 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | 718 | struct ov9640_priv *priv = to_ov9640_sensor(sd); |
787 | 719 | ||
720 | v4l2_device_unregister_subdev(&priv->subdev); | ||
721 | v4l2_ctrl_handler_free(&priv->hdl); | ||
788 | kfree(priv); | 722 | kfree(priv); |
789 | return 0; | 723 | return 0; |
790 | } | 724 | } |
diff --git a/drivers/media/video/ov9640.h b/drivers/media/video/ov9640.h index f8a51b70792e..6b33a972c83c 100644 --- a/drivers/media/video/ov9640.h +++ b/drivers/media/video/ov9640.h | |||
@@ -198,12 +198,10 @@ struct ov9640_reg { | |||
198 | 198 | ||
199 | struct ov9640_priv { | 199 | struct ov9640_priv { |
200 | struct v4l2_subdev subdev; | 200 | struct v4l2_subdev subdev; |
201 | struct v4l2_ctrl_handler hdl; | ||
201 | 202 | ||
202 | int model; | 203 | int model; |
203 | int revision; | 204 | int revision; |
204 | |||
205 | bool flag_vflip; | ||
206 | bool flag_hflip; | ||
207 | }; | 205 | }; |
208 | 206 | ||
209 | #endif /* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */ | 207 | #endif /* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */ |
diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index edd1ffcca30b..d9a9f7174f7a 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c | |||
@@ -14,8 +14,11 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/i2c.h> | 15 | #include <linux/i2c.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <media/v4l2-chip-ident.h> | 17 | #include <linux/v4l2-mediabus.h> |
18 | |||
18 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
20 | #include <media/v4l2-chip-ident.h> | ||
21 | #include <media/v4l2-ctrls.h> | ||
19 | 22 | ||
20 | #define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) | 23 | #define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) |
21 | 24 | ||
@@ -192,6 +195,7 @@ struct ov9740_reg { | |||
192 | 195 | ||
193 | struct ov9740_priv { | 196 | struct ov9740_priv { |
194 | struct v4l2_subdev subdev; | 197 | struct v4l2_subdev subdev; |
198 | struct v4l2_ctrl_handler hdl; | ||
195 | 199 | ||
196 | int ident; | 200 | int ident; |
197 | u16 model; | 201 | u16 model; |
@@ -392,27 +396,6 @@ static enum v4l2_mbus_pixelcode ov9740_codes[] = { | |||
392 | V4L2_MBUS_FMT_YUYV8_2X8, | 396 | V4L2_MBUS_FMT_YUYV8_2X8, |
393 | }; | 397 | }; |
394 | 398 | ||
395 | static const struct v4l2_queryctrl ov9740_controls[] = { | ||
396 | { | ||
397 | .id = V4L2_CID_VFLIP, | ||
398 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
399 | .name = "Flip Vertically", | ||
400 | .minimum = 0, | ||
401 | .maximum = 1, | ||
402 | .step = 1, | ||
403 | .default_value = 0, | ||
404 | }, | ||
405 | { | ||
406 | .id = V4L2_CID_HFLIP, | ||
407 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
408 | .name = "Flip Horizontally", | ||
409 | .minimum = 0, | ||
410 | .maximum = 1, | ||
411 | .step = 1, | ||
412 | .default_value = 0, | ||
413 | }, | ||
414 | }; | ||
415 | |||
416 | /* read a register */ | 399 | /* read a register */ |
417 | static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val) | 400 | static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val) |
418 | { | 401 | { |
@@ -560,25 +543,6 @@ static int ov9740_s_stream(struct v4l2_subdev *sd, int enable) | |||
560 | return ret; | 543 | return ret; |
561 | } | 544 | } |
562 | 545 | ||
563 | /* Alter bus settings on camera side */ | ||
564 | static int ov9740_set_bus_param(struct soc_camera_device *icd, | ||
565 | unsigned long flags) | ||
566 | { | ||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | /* Request bus settings on camera side */ | ||
571 | static unsigned long ov9740_query_bus_param(struct soc_camera_device *icd) | ||
572 | { | ||
573 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
574 | |||
575 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
576 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
577 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | ||
578 | |||
579 | return soc_camera_apply_sensor_flags(icl, flags); | ||
580 | } | ||
581 | |||
582 | /* select nearest higher resolution for capture */ | 546 | /* select nearest higher resolution for capture */ |
583 | static void ov9740_res_roundup(u32 *width, u32 *height) | 547 | static void ov9740_res_roundup(u32 *width, u32 *height) |
584 | { | 548 | { |
@@ -788,36 +752,18 @@ static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
788 | return 0; | 752 | return 0; |
789 | } | 753 | } |
790 | 754 | ||
791 | /* Get status of additional camera capabilities */ | ||
792 | static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
793 | { | ||
794 | struct ov9740_priv *priv = to_ov9740(sd); | ||
795 | |||
796 | switch (ctrl->id) { | ||
797 | case V4L2_CID_VFLIP: | ||
798 | ctrl->value = priv->flag_vflip; | ||
799 | break; | ||
800 | case V4L2_CID_HFLIP: | ||
801 | ctrl->value = priv->flag_hflip; | ||
802 | break; | ||
803 | default: | ||
804 | return -EINVAL; | ||
805 | } | ||
806 | |||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | /* Set status of additional camera capabilities */ | 755 | /* Set status of additional camera capabilities */ |
811 | static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 756 | static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl) |
812 | { | 757 | { |
813 | struct ov9740_priv *priv = to_ov9740(sd); | 758 | struct ov9740_priv *priv = |
759 | container_of(ctrl->handler, struct ov9740_priv, hdl); | ||
814 | 760 | ||
815 | switch (ctrl->id) { | 761 | switch (ctrl->id) { |
816 | case V4L2_CID_VFLIP: | 762 | case V4L2_CID_VFLIP: |
817 | priv->flag_vflip = ctrl->value; | 763 | priv->flag_vflip = ctrl->val; |
818 | break; | 764 | break; |
819 | case V4L2_CID_HFLIP: | 765 | case V4L2_CID_HFLIP: |
820 | priv->flag_hflip = ctrl->value; | 766 | priv->flag_hflip = ctrl->val; |
821 | break; | 767 | break; |
822 | default: | 768 | default: |
823 | return -EINVAL; | 769 | return -EINVAL; |
@@ -890,18 +836,13 @@ static int ov9740_set_register(struct v4l2_subdev *sd, | |||
890 | } | 836 | } |
891 | #endif | 837 | #endif |
892 | 838 | ||
893 | static int ov9740_video_probe(struct soc_camera_device *icd, | 839 | static int ov9740_video_probe(struct i2c_client *client) |
894 | struct i2c_client *client) | ||
895 | { | 840 | { |
896 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 841 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
897 | struct ov9740_priv *priv = to_ov9740(sd); | 842 | struct ov9740_priv *priv = to_ov9740(sd); |
898 | u8 modelhi, modello; | 843 | u8 modelhi, modello; |
899 | int ret; | 844 | int ret; |
900 | 845 | ||
901 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
902 | BUG_ON(!icd->parent || | ||
903 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
904 | |||
905 | /* | 846 | /* |
906 | * check and show product ID and manufacturer ID | 847 | * check and show product ID and manufacturer ID |
907 | */ | 848 | */ |
@@ -942,25 +883,33 @@ err: | |||
942 | return ret; | 883 | return ret; |
943 | } | 884 | } |
944 | 885 | ||
945 | static struct soc_camera_ops ov9740_ops = { | 886 | /* Request bus settings on camera side */ |
946 | .set_bus_param = ov9740_set_bus_param, | 887 | static int ov9740_g_mbus_config(struct v4l2_subdev *sd, |
947 | .query_bus_param = ov9740_query_bus_param, | 888 | struct v4l2_mbus_config *cfg) |
948 | .controls = ov9740_controls, | 889 | { |
949 | .num_controls = ARRAY_SIZE(ov9740_controls), | 890 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
950 | }; | 891 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
892 | |||
893 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
894 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
895 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
896 | cfg->type = V4L2_MBUS_PARALLEL; | ||
897 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
898 | |||
899 | return 0; | ||
900 | } | ||
951 | 901 | ||
952 | static struct v4l2_subdev_video_ops ov9740_video_ops = { | 902 | static struct v4l2_subdev_video_ops ov9740_video_ops = { |
953 | .s_stream = ov9740_s_stream, | 903 | .s_stream = ov9740_s_stream, |
954 | .s_mbus_fmt = ov9740_s_fmt, | 904 | .s_mbus_fmt = ov9740_s_fmt, |
955 | .try_mbus_fmt = ov9740_try_fmt, | 905 | .try_mbus_fmt = ov9740_try_fmt, |
956 | .enum_mbus_fmt = ov9740_enum_fmt, | 906 | .enum_mbus_fmt = ov9740_enum_fmt, |
957 | .cropcap = ov9740_cropcap, | 907 | .cropcap = ov9740_cropcap, |
958 | .g_crop = ov9740_g_crop, | 908 | .g_crop = ov9740_g_crop, |
909 | .g_mbus_config = ov9740_g_mbus_config, | ||
959 | }; | 910 | }; |
960 | 911 | ||
961 | static struct v4l2_subdev_core_ops ov9740_core_ops = { | 912 | static struct v4l2_subdev_core_ops ov9740_core_ops = { |
962 | .g_ctrl = ov9740_g_ctrl, | ||
963 | .s_ctrl = ov9740_s_ctrl, | ||
964 | .g_chip_ident = ov9740_g_chip_ident, | 913 | .g_chip_ident = ov9740_g_chip_ident, |
965 | .s_power = ov9740_s_power, | 914 | .s_power = ov9740_s_power, |
966 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 915 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
@@ -974,6 +923,10 @@ static struct v4l2_subdev_ops ov9740_subdev_ops = { | |||
974 | .video = &ov9740_video_ops, | 923 | .video = &ov9740_video_ops, |
975 | }; | 924 | }; |
976 | 925 | ||
926 | static const struct v4l2_ctrl_ops ov9740_ctrl_ops = { | ||
927 | .s_ctrl = ov9740_s_ctrl, | ||
928 | }; | ||
929 | |||
977 | /* | 930 | /* |
978 | * i2c_driver function | 931 | * i2c_driver function |
979 | */ | 932 | */ |
@@ -981,16 +934,9 @@ static int ov9740_probe(struct i2c_client *client, | |||
981 | const struct i2c_device_id *did) | 934 | const struct i2c_device_id *did) |
982 | { | 935 | { |
983 | struct ov9740_priv *priv; | 936 | struct ov9740_priv *priv; |
984 | struct soc_camera_device *icd = client->dev.platform_data; | 937 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
985 | struct soc_camera_link *icl; | ||
986 | int ret; | 938 | int ret; |
987 | 939 | ||
988 | if (!icd) { | ||
989 | dev_err(&client->dev, "Missing soc-camera data!\n"); | ||
990 | return -EINVAL; | ||
991 | } | ||
992 | |||
993 | icl = to_soc_camera_link(icd); | ||
994 | if (!icl) { | 940 | if (!icl) { |
995 | dev_err(&client->dev, "Missing platform_data for driver\n"); | 941 | dev_err(&client->dev, "Missing platform_data for driver\n"); |
996 | return -EINVAL; | 942 | return -EINVAL; |
@@ -1003,12 +949,24 @@ static int ov9740_probe(struct i2c_client *client, | |||
1003 | } | 949 | } |
1004 | 950 | ||
1005 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); | 951 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); |
952 | v4l2_ctrl_handler_init(&priv->hdl, 13); | ||
953 | v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, | ||
954 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
955 | v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, | ||
956 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
957 | priv->subdev.ctrl_handler = &priv->hdl; | ||
958 | if (priv->hdl.error) { | ||
959 | int err = priv->hdl.error; | ||
1006 | 960 | ||
1007 | icd->ops = &ov9740_ops; | 961 | kfree(priv); |
962 | return err; | ||
963 | } | ||
1008 | 964 | ||
1009 | ret = ov9740_video_probe(icd, client); | 965 | ret = ov9740_video_probe(client); |
966 | if (!ret) | ||
967 | ret = v4l2_ctrl_handler_setup(&priv->hdl); | ||
1010 | if (ret < 0) { | 968 | if (ret < 0) { |
1011 | icd->ops = NULL; | 969 | v4l2_ctrl_handler_free(&priv->hdl); |
1012 | kfree(priv); | 970 | kfree(priv); |
1013 | } | 971 | } |
1014 | 972 | ||
@@ -1019,8 +977,9 @@ static int ov9740_remove(struct i2c_client *client) | |||
1019 | { | 977 | { |
1020 | struct ov9740_priv *priv = i2c_get_clientdata(client); | 978 | struct ov9740_priv *priv = i2c_get_clientdata(client); |
1021 | 979 | ||
980 | v4l2_device_unregister_subdev(&priv->subdev); | ||
981 | v4l2_ctrl_handler_free(&priv->hdl); | ||
1022 | kfree(priv); | 982 | kfree(priv); |
1023 | |||
1024 | return 0; | 983 | return 0; |
1025 | } | 984 | } |
1026 | 985 | ||
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 360be226718d..01ff643e682d 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c | |||
@@ -744,9 +744,9 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) | |||
744 | /***************************************************************************/ | 744 | /***************************************************************************/ |
745 | /* Videobuf2 operations */ | 745 | /* Videobuf2 operations */ |
746 | 746 | ||
747 | static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | 747 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, |
748 | unsigned int *nplanes, unsigned int sizes[], | 748 | unsigned int *nbuffers, unsigned int *nplanes, |
749 | void *alloc_ctxs[]) | 749 | unsigned int sizes[], void *alloc_ctxs[]) |
750 | { | 750 | { |
751 | struct pwc_device *pdev = vb2_get_drv_priv(vq); | 751 | struct pwc_device *pdev = vb2_get_drv_priv(vq); |
752 | 752 | ||
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index d07df22a5ec6..79fb22c89ae9 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -214,6 +214,7 @@ struct pxa_camera_dev { | |||
214 | unsigned long ciclk; | 214 | unsigned long ciclk; |
215 | unsigned long mclk; | 215 | unsigned long mclk; |
216 | u32 mclk_divisor; | 216 | u32 mclk_divisor; |
217 | u16 width_flags; /* max 10 bits */ | ||
217 | 218 | ||
218 | struct list_head capture; | 219 | struct list_head capture; |
219 | 220 | ||
@@ -1020,37 +1021,20 @@ static int test_platform_param(struct pxa_camera_dev *pcdev, | |||
1020 | * quick capture interface supports both. | 1021 | * quick capture interface supports both. |
1021 | */ | 1022 | */ |
1022 | *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? | 1023 | *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? |
1023 | SOCAM_MASTER : SOCAM_SLAVE) | | 1024 | V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) | |
1024 | SOCAM_HSYNC_ACTIVE_HIGH | | 1025 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
1025 | SOCAM_HSYNC_ACTIVE_LOW | | 1026 | V4L2_MBUS_HSYNC_ACTIVE_LOW | |
1026 | SOCAM_VSYNC_ACTIVE_HIGH | | 1027 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | |
1027 | SOCAM_VSYNC_ACTIVE_LOW | | 1028 | V4L2_MBUS_VSYNC_ACTIVE_LOW | |
1028 | SOCAM_DATA_ACTIVE_HIGH | | 1029 | V4L2_MBUS_DATA_ACTIVE_HIGH | |
1029 | SOCAM_PCLK_SAMPLE_RISING | | 1030 | V4L2_MBUS_PCLK_SAMPLE_RISING | |
1030 | SOCAM_PCLK_SAMPLE_FALLING; | 1031 | V4L2_MBUS_PCLK_SAMPLE_FALLING; |
1031 | 1032 | ||
1032 | /* If requested data width is supported by the platform, use it */ | 1033 | /* If requested data width is supported by the platform, use it */ |
1033 | switch (buswidth) { | 1034 | if ((1 << (buswidth - 1)) & pcdev->width_flags) |
1034 | case 10: | 1035 | return 0; |
1035 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10)) | ||
1036 | return -EINVAL; | ||
1037 | *flags |= SOCAM_DATAWIDTH_10; | ||
1038 | break; | ||
1039 | case 9: | ||
1040 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9)) | ||
1041 | return -EINVAL; | ||
1042 | *flags |= SOCAM_DATAWIDTH_9; | ||
1043 | break; | ||
1044 | case 8: | ||
1045 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)) | ||
1046 | return -EINVAL; | ||
1047 | *flags |= SOCAM_DATAWIDTH_8; | ||
1048 | break; | ||
1049 | default: | ||
1050 | return -EINVAL; | ||
1051 | } | ||
1052 | 1036 | ||
1053 | return 0; | 1037 | return -EINVAL; |
1054 | } | 1038 | } |
1055 | 1039 | ||
1056 | static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | 1040 | static void pxa_camera_setup_cicr(struct soc_camera_device *icd, |
@@ -1070,12 +1054,12 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1070 | * Datawidth is now guaranteed to be equal to one of the three values. | 1054 | * Datawidth is now guaranteed to be equal to one of the three values. |
1071 | * We fix bit-per-pixel equal to data-width... | 1055 | * We fix bit-per-pixel equal to data-width... |
1072 | */ | 1056 | */ |
1073 | switch (flags & SOCAM_DATAWIDTH_MASK) { | 1057 | switch (icd->current_fmt->host_fmt->bits_per_sample) { |
1074 | case SOCAM_DATAWIDTH_10: | 1058 | case 10: |
1075 | dw = 4; | 1059 | dw = 4; |
1076 | bpp = 0x40; | 1060 | bpp = 0x40; |
1077 | break; | 1061 | break; |
1078 | case SOCAM_DATAWIDTH_9: | 1062 | case 9: |
1079 | dw = 3; | 1063 | dw = 3; |
1080 | bpp = 0x20; | 1064 | bpp = 0x20; |
1081 | break; | 1065 | break; |
@@ -1084,7 +1068,7 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1084 | * Actually it can only be 8 now, | 1068 | * Actually it can only be 8 now, |
1085 | * default is just to silence compiler warnings | 1069 | * default is just to silence compiler warnings |
1086 | */ | 1070 | */ |
1087 | case SOCAM_DATAWIDTH_8: | 1071 | case 8: |
1088 | dw = 2; | 1072 | dw = 2; |
1089 | bpp = 0; | 1073 | bpp = 0; |
1090 | } | 1074 | } |
@@ -1093,11 +1077,11 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1093 | cicr4 |= CICR4_PCLK_EN; | 1077 | cicr4 |= CICR4_PCLK_EN; |
1094 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) | 1078 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) |
1095 | cicr4 |= CICR4_MCLK_EN; | 1079 | cicr4 |= CICR4_MCLK_EN; |
1096 | if (flags & SOCAM_PCLK_SAMPLE_FALLING) | 1080 | if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) |
1097 | cicr4 |= CICR4_PCP; | 1081 | cicr4 |= CICR4_PCP; |
1098 | if (flags & SOCAM_HSYNC_ACTIVE_LOW) | 1082 | if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) |
1099 | cicr4 |= CICR4_HSP; | 1083 | cicr4 |= CICR4_HSP; |
1100 | if (flags & SOCAM_VSYNC_ACTIVE_LOW) | 1084 | if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) |
1101 | cicr4 |= CICR4_VSP; | 1085 | cicr4 |= CICR4_VSP; |
1102 | 1086 | ||
1103 | cicr0 = __raw_readl(pcdev->base + CICR0); | 1087 | cicr0 = __raw_readl(pcdev->base + CICR0); |
@@ -1151,9 +1135,11 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
1151 | 1135 | ||
1152 | static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | 1136 | static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) |
1153 | { | 1137 | { |
1138 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1154 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 1139 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
1155 | struct pxa_camera_dev *pcdev = ici->priv; | 1140 | struct pxa_camera_dev *pcdev = ici->priv; |
1156 | unsigned long bus_flags, camera_flags, common_flags; | 1141 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
1142 | unsigned long bus_flags, common_flags; | ||
1157 | int ret; | 1143 | int ret; |
1158 | struct pxa_cam *cam = icd->host_priv; | 1144 | struct pxa_cam *cam = icd->host_priv; |
1159 | 1145 | ||
@@ -1162,44 +1148,58 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1162 | if (ret < 0) | 1148 | if (ret < 0) |
1163 | return ret; | 1149 | return ret; |
1164 | 1150 | ||
1165 | camera_flags = icd->ops->query_bus_param(icd); | 1151 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
1166 | 1152 | if (!ret) { | |
1167 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 1153 | common_flags = soc_mbus_config_compatible(&cfg, |
1168 | if (!common_flags) | 1154 | bus_flags); |
1169 | return -EINVAL; | 1155 | if (!common_flags) { |
1156 | dev_warn(icd->parent, | ||
1157 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
1158 | cfg.flags, bus_flags); | ||
1159 | return -EINVAL; | ||
1160 | } | ||
1161 | } else if (ret != -ENOIOCTLCMD) { | ||
1162 | return ret; | ||
1163 | } else { | ||
1164 | common_flags = bus_flags; | ||
1165 | } | ||
1170 | 1166 | ||
1171 | pcdev->channels = 1; | 1167 | pcdev->channels = 1; |
1172 | 1168 | ||
1173 | /* Make choises, based on platform preferences */ | 1169 | /* Make choises, based on platform preferences */ |
1174 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 1170 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
1175 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 1171 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
1176 | if (pcdev->platform_flags & PXA_CAMERA_HSP) | 1172 | if (pcdev->platform_flags & PXA_CAMERA_HSP) |
1177 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 1173 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
1178 | else | 1174 | else |
1179 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 1175 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
1180 | } | 1176 | } |
1181 | 1177 | ||
1182 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 1178 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
1183 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 1179 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
1184 | if (pcdev->platform_flags & PXA_CAMERA_VSP) | 1180 | if (pcdev->platform_flags & PXA_CAMERA_VSP) |
1185 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 1181 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
1186 | else | 1182 | else |
1187 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 1183 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
1188 | } | 1184 | } |
1189 | 1185 | ||
1190 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 1186 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
1191 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 1187 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
1192 | if (pcdev->platform_flags & PXA_CAMERA_PCP) | 1188 | if (pcdev->platform_flags & PXA_CAMERA_PCP) |
1193 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 1189 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
1194 | else | 1190 | else |
1195 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 1191 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
1196 | } | 1192 | } |
1197 | 1193 | ||
1198 | cam->flags = common_flags; | 1194 | cfg.flags = common_flags; |
1199 | 1195 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | |
1200 | ret = icd->ops->set_bus_param(icd, common_flags); | 1196 | if (ret < 0 && ret != -ENOIOCTLCMD) { |
1201 | if (ret < 0) | 1197 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", |
1198 | common_flags, ret); | ||
1202 | return ret; | 1199 | return ret; |
1200 | } | ||
1201 | |||
1202 | cam->flags = common_flags; | ||
1203 | 1203 | ||
1204 | pxa_camera_setup_cicr(icd, common_flags, pixfmt); | 1204 | pxa_camera_setup_cicr(icd, common_flags, pixfmt); |
1205 | 1205 | ||
@@ -1209,17 +1209,31 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
1209 | static int pxa_camera_try_bus_param(struct soc_camera_device *icd, | 1209 | static int pxa_camera_try_bus_param(struct soc_camera_device *icd, |
1210 | unsigned char buswidth) | 1210 | unsigned char buswidth) |
1211 | { | 1211 | { |
1212 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1212 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 1213 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
1213 | struct pxa_camera_dev *pcdev = ici->priv; | 1214 | struct pxa_camera_dev *pcdev = ici->priv; |
1214 | unsigned long bus_flags, camera_flags; | 1215 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
1216 | unsigned long bus_flags, common_flags; | ||
1215 | int ret = test_platform_param(pcdev, buswidth, &bus_flags); | 1217 | int ret = test_platform_param(pcdev, buswidth, &bus_flags); |
1216 | 1218 | ||
1217 | if (ret < 0) | 1219 | if (ret < 0) |
1218 | return ret; | 1220 | return ret; |
1219 | 1221 | ||
1220 | camera_flags = icd->ops->query_bus_param(icd); | 1222 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
1223 | if (!ret) { | ||
1224 | common_flags = soc_mbus_config_compatible(&cfg, | ||
1225 | bus_flags); | ||
1226 | if (!common_flags) { | ||
1227 | dev_warn(icd->parent, | ||
1228 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
1229 | cfg.flags, bus_flags); | ||
1230 | return -EINVAL; | ||
1231 | } | ||
1232 | } else if (ret == -ENOIOCTLCMD) { | ||
1233 | ret = 0; | ||
1234 | } | ||
1221 | 1235 | ||
1222 | return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; | 1236 | return ret; |
1223 | } | 1237 | } |
1224 | 1238 | ||
1225 | static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { | 1239 | static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { |
@@ -1687,6 +1701,12 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev) | |||
1687 | "data widths, using default 10 bit\n"); | 1701 | "data widths, using default 10 bit\n"); |
1688 | pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; | 1702 | pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; |
1689 | } | 1703 | } |
1704 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8) | ||
1705 | pcdev->width_flags = 1 << 7; | ||
1706 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9) | ||
1707 | pcdev->width_flags |= 1 << 8; | ||
1708 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10) | ||
1709 | pcdev->width_flags |= 1 << 9; | ||
1690 | pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; | 1710 | pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; |
1691 | if (!pcdev->mclk) { | 1711 | if (!pcdev->mclk) { |
1692 | dev_warn(&pdev->dev, | 1712 | dev_warn(&pdev->dev, |
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index 847ccc067e87..6afc61689549 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c | |||
@@ -11,13 +11,14 @@ | |||
11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
12 | #include <linux/i2c.h> | 12 | #include <linux/i2c.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/v4l2-mediabus.h> | ||
14 | #include <linux/videodev2.h> | 15 | #include <linux/videodev2.h> |
15 | 16 | ||
16 | #include <media/rj54n1cb0c.h> | 17 | #include <media/rj54n1cb0c.h> |
17 | #include <media/soc_camera.h> | 18 | #include <media/soc_camera.h> |
18 | #include <media/soc_mediabus.h> | ||
19 | #include <media/v4l2-subdev.h> | 19 | #include <media/v4l2-subdev.h> |
20 | #include <media/v4l2-chip-ident.h> | 20 | #include <media/v4l2-chip-ident.h> |
21 | #include <media/v4l2-ctrls.h> | ||
21 | 22 | ||
22 | #define RJ54N1_DEV_CODE 0x0400 | 23 | #define RJ54N1_DEV_CODE 0x0400 |
23 | #define RJ54N1_DEV_CODE2 0x0401 | 24 | #define RJ54N1_DEV_CODE2 0x0401 |
@@ -148,6 +149,7 @@ struct rj54n1_clock_div { | |||
148 | 149 | ||
149 | struct rj54n1 { | 150 | struct rj54n1 { |
150 | struct v4l2_subdev subdev; | 151 | struct v4l2_subdev subdev; |
152 | struct v4l2_ctrl_handler hdl; | ||
151 | struct rj54n1_clock_div clk_div; | 153 | struct rj54n1_clock_div clk_div; |
152 | const struct rj54n1_datafmt *fmt; | 154 | const struct rj54n1_datafmt *fmt; |
153 | struct v4l2_rect rect; /* Sensor window */ | 155 | struct v4l2_rect rect; /* Sensor window */ |
@@ -499,31 +501,6 @@ static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) | |||
499 | return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80); | 501 | return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80); |
500 | } | 502 | } |
501 | 503 | ||
502 | static int rj54n1_set_bus_param(struct soc_camera_device *icd, | ||
503 | unsigned long flags) | ||
504 | { | ||
505 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
506 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
507 | /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ | ||
508 | |||
509 | if (flags & SOCAM_PCLK_SAMPLE_RISING) | ||
510 | return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4); | ||
511 | else | ||
512 | return reg_write(client, RJ54N1_OUT_SIGPO, 0); | ||
513 | } | ||
514 | |||
515 | static unsigned long rj54n1_query_bus_param(struct soc_camera_device *icd) | ||
516 | { | ||
517 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
518 | const unsigned long flags = | ||
519 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | | ||
520 | SOCAM_MASTER | SOCAM_DATAWIDTH_8 | | ||
521 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | ||
522 | SOCAM_DATA_ACTIVE_HIGH; | ||
523 | |||
524 | return soc_camera_apply_sensor_flags(icl, flags); | ||
525 | } | ||
526 | |||
527 | static int rj54n1_set_rect(struct i2c_client *client, | 504 | static int rj54n1_set_rect(struct i2c_client *client, |
528 | u16 reg_x, u16 reg_y, u16 reg_xy, | 505 | u16 reg_x, u16 reg_y, u16 reg_xy, |
529 | u32 width, u32 height) | 506 | u32 width, u32 height) |
@@ -1202,134 +1179,51 @@ static int rj54n1_s_register(struct v4l2_subdev *sd, | |||
1202 | } | 1179 | } |
1203 | #endif | 1180 | #endif |
1204 | 1181 | ||
1205 | static const struct v4l2_queryctrl rj54n1_controls[] = { | 1182 | static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl) |
1206 | { | ||
1207 | .id = V4L2_CID_VFLIP, | ||
1208 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
1209 | .name = "Flip Vertically", | ||
1210 | .minimum = 0, | ||
1211 | .maximum = 1, | ||
1212 | .step = 1, | ||
1213 | .default_value = 0, | ||
1214 | }, { | ||
1215 | .id = V4L2_CID_HFLIP, | ||
1216 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
1217 | .name = "Flip Horizontally", | ||
1218 | .minimum = 0, | ||
1219 | .maximum = 1, | ||
1220 | .step = 1, | ||
1221 | .default_value = 0, | ||
1222 | }, { | ||
1223 | .id = V4L2_CID_GAIN, | ||
1224 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1225 | .name = "Gain", | ||
1226 | .minimum = 0, | ||
1227 | .maximum = 127, | ||
1228 | .step = 1, | ||
1229 | .default_value = 66, | ||
1230 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
1231 | }, { | ||
1232 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | ||
1233 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
1234 | .name = "Auto white balance", | ||
1235 | .minimum = 0, | ||
1236 | .maximum = 1, | ||
1237 | .step = 1, | ||
1238 | .default_value = 1, | ||
1239 | }, | ||
1240 | }; | ||
1241 | |||
1242 | static struct soc_camera_ops rj54n1_ops = { | ||
1243 | .set_bus_param = rj54n1_set_bus_param, | ||
1244 | .query_bus_param = rj54n1_query_bus_param, | ||
1245 | .controls = rj54n1_controls, | ||
1246 | .num_controls = ARRAY_SIZE(rj54n1_controls), | ||
1247 | }; | ||
1248 | |||
1249 | static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
1250 | { | 1183 | { |
1184 | struct rj54n1 *rj54n1 = container_of(ctrl->handler, struct rj54n1, hdl); | ||
1185 | struct v4l2_subdev *sd = &rj54n1->subdev; | ||
1251 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1186 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1252 | struct rj54n1 *rj54n1 = to_rj54n1(client); | ||
1253 | int data; | 1187 | int data; |
1254 | 1188 | ||
1255 | switch (ctrl->id) { | 1189 | switch (ctrl->id) { |
1256 | case V4L2_CID_VFLIP: | 1190 | case V4L2_CID_VFLIP: |
1257 | data = reg_read(client, RJ54N1_MIRROR_STILL_MODE); | 1191 | if (ctrl->val) |
1258 | if (data < 0) | ||
1259 | return -EIO; | ||
1260 | ctrl->value = !(data & 1); | ||
1261 | break; | ||
1262 | case V4L2_CID_HFLIP: | ||
1263 | data = reg_read(client, RJ54N1_MIRROR_STILL_MODE); | ||
1264 | if (data < 0) | ||
1265 | return -EIO; | ||
1266 | ctrl->value = !(data & 2); | ||
1267 | break; | ||
1268 | case V4L2_CID_GAIN: | ||
1269 | data = reg_read(client, RJ54N1_Y_GAIN); | ||
1270 | if (data < 0) | ||
1271 | return -EIO; | ||
1272 | |||
1273 | ctrl->value = data / 2; | ||
1274 | break; | ||
1275 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
1276 | ctrl->value = rj54n1->auto_wb; | ||
1277 | break; | ||
1278 | } | ||
1279 | |||
1280 | return 0; | ||
1281 | } | ||
1282 | |||
1283 | static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
1284 | { | ||
1285 | int data; | ||
1286 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1287 | struct rj54n1 *rj54n1 = to_rj54n1(client); | ||
1288 | const struct v4l2_queryctrl *qctrl; | ||
1289 | |||
1290 | qctrl = soc_camera_find_qctrl(&rj54n1_ops, ctrl->id); | ||
1291 | if (!qctrl) | ||
1292 | return -EINVAL; | ||
1293 | |||
1294 | switch (ctrl->id) { | ||
1295 | case V4L2_CID_VFLIP: | ||
1296 | if (ctrl->value) | ||
1297 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1); | 1192 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1); |
1298 | else | 1193 | else |
1299 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1); | 1194 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1); |
1300 | if (data < 0) | 1195 | if (data < 0) |
1301 | return -EIO; | 1196 | return -EIO; |
1302 | break; | 1197 | return 0; |
1303 | case V4L2_CID_HFLIP: | 1198 | case V4L2_CID_HFLIP: |
1304 | if (ctrl->value) | 1199 | if (ctrl->val) |
1305 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2); | 1200 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2); |
1306 | else | 1201 | else |
1307 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2); | 1202 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2); |
1308 | if (data < 0) | 1203 | if (data < 0) |
1309 | return -EIO; | 1204 | return -EIO; |
1310 | break; | 1205 | return 0; |
1311 | case V4L2_CID_GAIN: | 1206 | case V4L2_CID_GAIN: |
1312 | if (ctrl->value > qctrl->maximum || | 1207 | if (reg_write(client, RJ54N1_Y_GAIN, ctrl->val * 2) < 0) |
1313 | ctrl->value < qctrl->minimum) | ||
1314 | return -EINVAL; | ||
1315 | else if (reg_write(client, RJ54N1_Y_GAIN, ctrl->value * 2) < 0) | ||
1316 | return -EIO; | 1208 | return -EIO; |
1317 | break; | 1209 | return 0; |
1318 | case V4L2_CID_AUTO_WHITE_BALANCE: | 1210 | case V4L2_CID_AUTO_WHITE_BALANCE: |
1319 | /* Auto WB area - whole image */ | 1211 | /* Auto WB area - whole image */ |
1320 | if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->value << 7, | 1212 | if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->val << 7, |
1321 | 0x80) < 0) | 1213 | 0x80) < 0) |
1322 | return -EIO; | 1214 | return -EIO; |
1323 | rj54n1->auto_wb = ctrl->value; | 1215 | rj54n1->auto_wb = ctrl->val; |
1324 | break; | 1216 | return 0; |
1325 | } | 1217 | } |
1326 | 1218 | ||
1327 | return 0; | 1219 | return -EINVAL; |
1328 | } | 1220 | } |
1329 | 1221 | ||
1222 | static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = { | ||
1223 | .s_ctrl = rj54n1_s_ctrl, | ||
1224 | }; | ||
1225 | |||
1330 | static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { | 1226 | static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { |
1331 | .g_ctrl = rj54n1_g_ctrl, | ||
1332 | .s_ctrl = rj54n1_s_ctrl, | ||
1333 | .g_chip_ident = rj54n1_g_chip_ident, | 1227 | .g_chip_ident = rj54n1_g_chip_ident, |
1334 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1228 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1335 | .g_register = rj54n1_g_register, | 1229 | .g_register = rj54n1_g_register, |
@@ -1337,6 +1231,36 @@ static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { | |||
1337 | #endif | 1231 | #endif |
1338 | }; | 1232 | }; |
1339 | 1233 | ||
1234 | static int rj54n1_g_mbus_config(struct v4l2_subdev *sd, | ||
1235 | struct v4l2_mbus_config *cfg) | ||
1236 | { | ||
1237 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1238 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
1239 | |||
1240 | cfg->flags = | ||
1241 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | | ||
1242 | V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH | | ||
1243 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH; | ||
1244 | cfg->type = V4L2_MBUS_PARALLEL; | ||
1245 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
1246 | |||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, | ||
1251 | const struct v4l2_mbus_config *cfg) | ||
1252 | { | ||
1253 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1254 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
1255 | |||
1256 | /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ | ||
1257 | if (soc_camera_apply_board_flags(icl, cfg) & | ||
1258 | V4L2_MBUS_PCLK_SAMPLE_RISING) | ||
1259 | return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4); | ||
1260 | else | ||
1261 | return reg_write(client, RJ54N1_OUT_SIGPO, 0); | ||
1262 | } | ||
1263 | |||
1340 | static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { | 1264 | static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { |
1341 | .s_stream = rj54n1_s_stream, | 1265 | .s_stream = rj54n1_s_stream, |
1342 | .s_mbus_fmt = rj54n1_s_fmt, | 1266 | .s_mbus_fmt = rj54n1_s_fmt, |
@@ -1346,6 +1270,8 @@ static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { | |||
1346 | .g_crop = rj54n1_g_crop, | 1270 | .g_crop = rj54n1_g_crop, |
1347 | .s_crop = rj54n1_s_crop, | 1271 | .s_crop = rj54n1_s_crop, |
1348 | .cropcap = rj54n1_cropcap, | 1272 | .cropcap = rj54n1_cropcap, |
1273 | .g_mbus_config = rj54n1_g_mbus_config, | ||
1274 | .s_mbus_config = rj54n1_s_mbus_config, | ||
1349 | }; | 1275 | }; |
1350 | 1276 | ||
1351 | static struct v4l2_subdev_ops rj54n1_subdev_ops = { | 1277 | static struct v4l2_subdev_ops rj54n1_subdev_ops = { |
@@ -1357,17 +1283,12 @@ static struct v4l2_subdev_ops rj54n1_subdev_ops = { | |||
1357 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 1283 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
1358 | * this wasn't our capture interface, so, we wait for the right one | 1284 | * this wasn't our capture interface, so, we wait for the right one |
1359 | */ | 1285 | */ |
1360 | static int rj54n1_video_probe(struct soc_camera_device *icd, | 1286 | static int rj54n1_video_probe(struct i2c_client *client, |
1361 | struct i2c_client *client, | ||
1362 | struct rj54n1_pdata *priv) | 1287 | struct rj54n1_pdata *priv) |
1363 | { | 1288 | { |
1364 | int data1, data2; | 1289 | int data1, data2; |
1365 | int ret; | 1290 | int ret; |
1366 | 1291 | ||
1367 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
1368 | BUG_ON(!icd->parent || | ||
1369 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
1370 | |||
1371 | /* Read out the chip version register */ | 1292 | /* Read out the chip version register */ |
1372 | data1 = reg_read(client, RJ54N1_DEV_CODE); | 1293 | data1 = reg_read(client, RJ54N1_DEV_CODE); |
1373 | data2 = reg_read(client, RJ54N1_DEV_CODE2); | 1294 | data2 = reg_read(client, RJ54N1_DEV_CODE2); |
@@ -1395,18 +1316,11 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1395 | const struct i2c_device_id *did) | 1316 | const struct i2c_device_id *did) |
1396 | { | 1317 | { |
1397 | struct rj54n1 *rj54n1; | 1318 | struct rj54n1 *rj54n1; |
1398 | struct soc_camera_device *icd = client->dev.platform_data; | 1319 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
1399 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1320 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1400 | struct soc_camera_link *icl; | ||
1401 | struct rj54n1_pdata *rj54n1_priv; | 1321 | struct rj54n1_pdata *rj54n1_priv; |
1402 | int ret; | 1322 | int ret; |
1403 | 1323 | ||
1404 | if (!icd) { | ||
1405 | dev_err(&client->dev, "RJ54N1CB0C: missing soc-camera data!\n"); | ||
1406 | return -EINVAL; | ||
1407 | } | ||
1408 | |||
1409 | icl = to_soc_camera_link(icd); | ||
1410 | if (!icl || !icl->priv) { | 1324 | if (!icl || !icl->priv) { |
1411 | dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); | 1325 | dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); |
1412 | return -EINVAL; | 1326 | return -EINVAL; |
@@ -1425,8 +1339,22 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1425 | return -ENOMEM; | 1339 | return -ENOMEM; |
1426 | 1340 | ||
1427 | v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops); | 1341 | v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops); |
1342 | v4l2_ctrl_handler_init(&rj54n1->hdl, 4); | ||
1343 | v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, | ||
1344 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
1345 | v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, | ||
1346 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
1347 | v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, | ||
1348 | V4L2_CID_GAIN, 0, 127, 1, 66); | ||
1349 | v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, | ||
1350 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
1351 | rj54n1->subdev.ctrl_handler = &rj54n1->hdl; | ||
1352 | if (rj54n1->hdl.error) { | ||
1353 | int err = rj54n1->hdl.error; | ||
1428 | 1354 | ||
1429 | icd->ops = &rj54n1_ops; | 1355 | kfree(rj54n1); |
1356 | return err; | ||
1357 | } | ||
1430 | 1358 | ||
1431 | rj54n1->clk_div = clk_div; | 1359 | rj54n1->clk_div = clk_div; |
1432 | rj54n1->rect.left = RJ54N1_COLUMN_SKIP; | 1360 | rj54n1->rect.left = RJ54N1_COLUMN_SKIP; |
@@ -1440,25 +1368,24 @@ static int rj54n1_probe(struct i2c_client *client, | |||
1440 | rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) / | 1368 | rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) / |
1441 | (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); | 1369 | (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); |
1442 | 1370 | ||
1443 | ret = rj54n1_video_probe(icd, client, rj54n1_priv); | 1371 | ret = rj54n1_video_probe(client, rj54n1_priv); |
1444 | if (ret < 0) { | 1372 | if (ret < 0) { |
1445 | icd->ops = NULL; | 1373 | v4l2_ctrl_handler_free(&rj54n1->hdl); |
1446 | kfree(rj54n1); | 1374 | kfree(rj54n1); |
1447 | return ret; | 1375 | return ret; |
1448 | } | 1376 | } |
1449 | 1377 | return v4l2_ctrl_handler_setup(&rj54n1->hdl); | |
1450 | return ret; | ||
1451 | } | 1378 | } |
1452 | 1379 | ||
1453 | static int rj54n1_remove(struct i2c_client *client) | 1380 | static int rj54n1_remove(struct i2c_client *client) |
1454 | { | 1381 | { |
1455 | struct rj54n1 *rj54n1 = to_rj54n1(client); | 1382 | struct rj54n1 *rj54n1 = to_rj54n1(client); |
1456 | struct soc_camera_device *icd = client->dev.platform_data; | 1383 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
1457 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
1458 | 1384 | ||
1459 | icd->ops = NULL; | 1385 | v4l2_device_unregister_subdev(&rj54n1->subdev); |
1460 | if (icl->free_bus) | 1386 | if (icl->free_bus) |
1461 | icl->free_bus(icl); | 1387 | icl->free_bus(icl); |
1388 | v4l2_ctrl_handler_free(&rj54n1->hdl); | ||
1462 | kfree(rj54n1); | 1389 | kfree(rj54n1); |
1463 | 1390 | ||
1464 | return 0; | 1391 | return 0; |
diff --git a/drivers/media/video/s5k6aa.c b/drivers/media/video/s5k6aa.c new file mode 100644 index 000000000000..2446736b7871 --- /dev/null +++ b/drivers/media/video/s5k6aa.c | |||
@@ -0,0 +1,1680 @@ | |||
1 | /* | ||
2 | * Driver for Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor | ||
3 | * with embedded SoC ISP. | ||
4 | * | ||
5 | * Copyright (C) 2011, Samsung Electronics Co., Ltd. | ||
6 | * Sylwester Nawrocki <s.nawrocki@samsung.com> | ||
7 | * | ||
8 | * Based on a driver authored by Dongsoo Nathaniel Kim. | ||
9 | * Copyright (C) 2009, Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/clk.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/gpio.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/media.h> | ||
22 | #include <linux/regulator/consumer.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | #include <media/media-entity.h> | ||
26 | #include <media/v4l2-ctrls.h> | ||
27 | #include <media/v4l2-device.h> | ||
28 | #include <media/v4l2-subdev.h> | ||
29 | #include <media/v4l2-mediabus.h> | ||
30 | #include <media/s5k6aa.h> | ||
31 | |||
32 | static int debug; | ||
33 | module_param(debug, int, 0644); | ||
34 | |||
35 | #define DRIVER_NAME "S5K6AA" | ||
36 | |||
37 | /* The token to indicate array termination */ | ||
38 | #define S5K6AA_TERM 0xffff | ||
39 | #define S5K6AA_OUT_WIDTH_DEF 640 | ||
40 | #define S5K6AA_OUT_HEIGHT_DEF 480 | ||
41 | #define S5K6AA_WIN_WIDTH_MAX 1280 | ||
42 | #define S5K6AA_WIN_HEIGHT_MAX 1024 | ||
43 | #define S5K6AA_WIN_WIDTH_MIN 8 | ||
44 | #define S5K6AA_WIN_HEIGHT_MIN 8 | ||
45 | |||
46 | /* | ||
47 | * H/W register Interface (0xD0000000 - 0xD0000FFF) | ||
48 | */ | ||
49 | #define AHB_MSB_ADDR_PTR 0xfcfc | ||
50 | #define GEN_REG_OFFSH 0xd000 | ||
51 | #define REG_CMDWR_ADDRH 0x0028 | ||
52 | #define REG_CMDWR_ADDRL 0x002a | ||
53 | #define REG_CMDRD_ADDRH 0x002c | ||
54 | #define REG_CMDRD_ADDRL 0x002e | ||
55 | #define REG_CMDBUF0_ADDR 0x0f12 | ||
56 | #define REG_CMDBUF1_ADDR 0x0f10 | ||
57 | |||
58 | /* | ||
59 | * Host S/W Register interface (0x70000000 - 0x70002000) | ||
60 | * The value of the two most significant address bytes is 0x7000, | ||
61 | * (HOST_SWIF_OFFS_H). The register addresses below specify 2 LSBs. | ||
62 | */ | ||
63 | #define HOST_SWIF_OFFSH 0x7000 | ||
64 | |||
65 | /* Initialization parameters */ | ||
66 | /* Master clock frequency in KHz */ | ||
67 | #define REG_I_INCLK_FREQ_L 0x01b8 | ||
68 | #define REG_I_INCLK_FREQ_H 0x01ba | ||
69 | #define MIN_MCLK_FREQ_KHZ 6000U | ||
70 | #define MAX_MCLK_FREQ_KHZ 27000U | ||
71 | #define REG_I_USE_NPVI_CLOCKS 0x01c6 | ||
72 | #define REG_I_USE_NMIPI_CLOCKS 0x01c8 | ||
73 | |||
74 | /* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */ | ||
75 | #define REG_I_OPCLK_4KHZ(n) ((n) * 6 + 0x01cc) | ||
76 | #define REG_I_MIN_OUTRATE_4KHZ(n) ((n) * 6 + 0x01ce) | ||
77 | #define REG_I_MAX_OUTRATE_4KHZ(n) ((n) * 6 + 0x01d0) | ||
78 | #define SYS_PLL_OUT_FREQ (48000000 / 4000) | ||
79 | #define PCLK_FREQ_MIN (24000000 / 4000) | ||
80 | #define PCLK_FREQ_MAX (48000000 / 4000) | ||
81 | #define REG_I_INIT_PARAMS_UPDATED 0x01e0 | ||
82 | #define REG_I_ERROR_INFO 0x01e2 | ||
83 | |||
84 | /* General purpose parameters */ | ||
85 | #define REG_USER_BRIGHTNESS 0x01e4 | ||
86 | #define REG_USER_CONTRAST 0x01e6 | ||
87 | #define REG_USER_SATURATION 0x01e8 | ||
88 | #define REG_USER_SHARPBLUR 0x01ea | ||
89 | |||
90 | #define REG_G_SPEC_EFFECTS 0x01ee | ||
91 | #define REG_G_ENABLE_PREV 0x01f0 | ||
92 | #define REG_G_ENABLE_PREV_CHG 0x01f2 | ||
93 | #define REG_G_NEW_CFG_SYNC 0x01f8 | ||
94 | #define REG_G_PREVZOOM_IN_WIDTH 0x020a | ||
95 | #define REG_G_PREVZOOM_IN_HEIGHT 0x020c | ||
96 | #define REG_G_PREVZOOM_IN_XOFFS 0x020e | ||
97 | #define REG_G_PREVZOOM_IN_YOFFS 0x0210 | ||
98 | #define REG_G_INPUTS_CHANGE_REQ 0x021a | ||
99 | #define REG_G_ACTIVE_PREV_CFG 0x021c | ||
100 | #define REG_G_PREV_CFG_CHG 0x021e | ||
101 | #define REG_G_PREV_OPEN_AFTER_CH 0x0220 | ||
102 | #define REG_G_PREV_CFG_ERROR 0x0222 | ||
103 | |||
104 | /* Preview control section. n = 0...4. */ | ||
105 | #define PREG(n, x) ((n) * 0x26 + x) | ||
106 | #define REG_P_OUT_WIDTH(n) PREG(n, 0x0242) | ||
107 | #define REG_P_OUT_HEIGHT(n) PREG(n, 0x0244) | ||
108 | #define REG_P_FMT(n) PREG(n, 0x0246) | ||
109 | #define REG_P_MAX_OUT_RATE(n) PREG(n, 0x0248) | ||
110 | #define REG_P_MIN_OUT_RATE(n) PREG(n, 0x024a) | ||
111 | #define REG_P_PVI_MASK(n) PREG(n, 0x024c) | ||
112 | #define REG_P_CLK_INDEX(n) PREG(n, 0x024e) | ||
113 | #define REG_P_FR_RATE_TYPE(n) PREG(n, 0x0250) | ||
114 | #define FR_RATE_DYNAMIC 0 | ||
115 | #define FR_RATE_FIXED 1 | ||
116 | #define FR_RATE_FIXED_ACCURATE 2 | ||
117 | #define REG_P_FR_RATE_Q_TYPE(n) PREG(n, 0x0252) | ||
118 | #define FR_RATE_Q_BEST_FRRATE 1 /* Binning enabled */ | ||
119 | #define FR_RATE_Q_BEST_QUALITY 2 /* Binning disabled */ | ||
120 | /* Frame period in 0.1 ms units */ | ||
121 | #define REG_P_MAX_FR_TIME(n) PREG(n, 0x0254) | ||
122 | #define REG_P_MIN_FR_TIME(n) PREG(n, 0x0256) | ||
123 | /* Conversion to REG_P_[MAX/MIN]_FR_TIME value; __t: time in us */ | ||
124 | #define US_TO_FR_TIME(__t) ((__t) / 100) | ||
125 | #define S5K6AA_MIN_FR_TIME 33300 /* us */ | ||
126 | #define S5K6AA_MAX_FR_TIME 650000 /* us */ | ||
127 | #define S5K6AA_MAX_HIGHRES_FR_TIME 666 /* x100 us */ | ||
128 | /* The below 5 registers are for "device correction" values */ | ||
129 | #define REG_P_COLORTEMP(n) PREG(n, 0x025e) | ||
130 | #define REG_P_PREV_MIRROR(n) PREG(n, 0x0262) | ||
131 | |||
132 | /* Extended image property controls */ | ||
133 | /* Exposure time in 10 us units */ | ||
134 | #define REG_SF_USR_EXPOSURE_L 0x03c6 | ||
135 | #define REG_SF_USR_EXPOSURE_H 0x03c8 | ||
136 | #define REG_SF_USR_EXPOSURE_CHG 0x03ca | ||
137 | #define REG_SF_USR_TOT_GAIN 0x03cc | ||
138 | #define REG_SF_USR_TOT_GAIN_CHG 0x03ce | ||
139 | #define REG_SF_RGAIN 0x03d0 | ||
140 | #define REG_SF_RGAIN_CHG 0x03d2 | ||
141 | #define REG_SF_GGAIN 0x03d4 | ||
142 | #define REG_SF_GGAIN_CHG 0x03d6 | ||
143 | #define REG_SF_BGAIN 0x03d8 | ||
144 | #define REG_SF_BGAIN_CHG 0x03da | ||
145 | #define REG_SF_FLICKER_QUANT 0x03dc | ||
146 | #define REG_SF_FLICKER_QUANT_CHG 0x03de | ||
147 | |||
148 | /* Output interface (parallel/MIPI) setup */ | ||
149 | #define REG_OIF_EN_MIPI_LANES 0x03fa | ||
150 | #define REG_OIF_EN_PACKETS 0x03fc | ||
151 | #define REG_OIF_CFG_CHG 0x03fe | ||
152 | |||
153 | /* Auto-algorithms enable mask */ | ||
154 | #define REG_DBG_AUTOALG_EN 0x0400 | ||
155 | #define AALG_ALL_EN_MASK (1 << 0) | ||
156 | #define AALG_AE_EN_MASK (1 << 1) | ||
157 | #define AALG_DIVLEI_EN_MASK (1 << 2) | ||
158 | #define AALG_WB_EN_MASK (1 << 3) | ||
159 | #define AALG_FLICKER_EN_MASK (1 << 5) | ||
160 | #define AALG_FIT_EN_MASK (1 << 6) | ||
161 | #define AALG_WRHW_EN_MASK (1 << 7) | ||
162 | |||
163 | /* Firmware revision information */ | ||
164 | #define REG_FW_APIVER 0x012e | ||
165 | #define S5K6AAFX_FW_APIVER 0x0001 | ||
166 | #define REG_FW_REVISION 0x0130 | ||
167 | |||
168 | /* For now we use only one user configuration register set */ | ||
169 | #define S5K6AA_MAX_PRESETS 1 | ||
170 | |||
171 | static const char * const s5k6aa_supply_names[] = { | ||
172 | "vdd_core", /* Digital core supply 1.5V (1.4V to 1.6V) */ | ||
173 | "vdda", /* Analog power supply 2.8V (2.6V to 3.0V) */ | ||
174 | "vdd_reg", /* Regulator input power 1.8V (1.7V to 1.9V) | ||
175 | or 2.8V (2.6V to 3.0) */ | ||
176 | "vddio", /* I/O supply 1.8V (1.65V to 1.95V) | ||
177 | or 2.8V (2.5V to 3.1V) */ | ||
178 | }; | ||
179 | #define S5K6AA_NUM_SUPPLIES ARRAY_SIZE(s5k6aa_supply_names) | ||
180 | |||
181 | enum s5k6aa_gpio_id { | ||
182 | STBY, | ||
183 | RST, | ||
184 | GPIO_NUM, | ||
185 | }; | ||
186 | |||
187 | struct s5k6aa_regval { | ||
188 | u16 addr; | ||
189 | u16 val; | ||
190 | }; | ||
191 | |||
192 | struct s5k6aa_pixfmt { | ||
193 | enum v4l2_mbus_pixelcode code; | ||
194 | u32 colorspace; | ||
195 | /* REG_P_FMT(x) register value */ | ||
196 | u16 reg_p_fmt; | ||
197 | }; | ||
198 | |||
199 | struct s5k6aa_preset { | ||
200 | /* output pixel format and resolution */ | ||
201 | struct v4l2_mbus_framefmt mbus_fmt; | ||
202 | u8 clk_id; | ||
203 | u8 index; | ||
204 | }; | ||
205 | |||
206 | struct s5k6aa_ctrls { | ||
207 | struct v4l2_ctrl_handler handler; | ||
208 | /* Auto / manual white balance cluster */ | ||
209 | struct v4l2_ctrl *awb; | ||
210 | struct v4l2_ctrl *gain_red; | ||
211 | struct v4l2_ctrl *gain_blue; | ||
212 | struct v4l2_ctrl *gain_green; | ||
213 | /* Mirror cluster */ | ||
214 | struct v4l2_ctrl *hflip; | ||
215 | struct v4l2_ctrl *vflip; | ||
216 | /* Auto exposure / manual exposure and gain cluster */ | ||
217 | struct v4l2_ctrl *auto_exp; | ||
218 | struct v4l2_ctrl *exposure; | ||
219 | struct v4l2_ctrl *gain; | ||
220 | }; | ||
221 | |||
222 | struct s5k6aa_interval { | ||
223 | u16 reg_fr_time; | ||
224 | struct v4l2_fract interval; | ||
225 | /* Maximum rectangle for the interval */ | ||
226 | struct v4l2_frmsize_discrete size; | ||
227 | }; | ||
228 | |||
229 | struct s5k6aa { | ||
230 | struct v4l2_subdev sd; | ||
231 | struct media_pad pad; | ||
232 | |||
233 | enum v4l2_mbus_type bus_type; | ||
234 | u8 mipi_lanes; | ||
235 | |||
236 | int (*s_power)(int enable); | ||
237 | struct regulator_bulk_data supplies[S5K6AA_NUM_SUPPLIES]; | ||
238 | struct s5k6aa_gpio gpio[GPIO_NUM]; | ||
239 | |||
240 | /* external master clock frequency */ | ||
241 | unsigned long mclk_frequency; | ||
242 | /* ISP internal master clock frequency */ | ||
243 | u16 clk_fop; | ||
244 | /* output pixel clock frequency range */ | ||
245 | u16 pclk_fmin; | ||
246 | u16 pclk_fmax; | ||
247 | |||
248 | unsigned int inv_hflip:1; | ||
249 | unsigned int inv_vflip:1; | ||
250 | |||
251 | /* protects the struct members below */ | ||
252 | struct mutex lock; | ||
253 | |||
254 | /* sensor matrix scan window */ | ||
255 | struct v4l2_rect ccd_rect; | ||
256 | |||
257 | struct s5k6aa_ctrls ctrls; | ||
258 | struct s5k6aa_preset presets[S5K6AA_MAX_PRESETS]; | ||
259 | struct s5k6aa_preset *preset; | ||
260 | const struct s5k6aa_interval *fiv; | ||
261 | |||
262 | unsigned int streaming:1; | ||
263 | unsigned int apply_cfg:1; | ||
264 | unsigned int apply_crop:1; | ||
265 | unsigned int power; | ||
266 | }; | ||
267 | |||
268 | static struct s5k6aa_regval s5k6aa_analog_config[] = { | ||
269 | /* Analog settings */ | ||
270 | { 0x112a, 0x0000 }, { 0x1132, 0x0000 }, | ||
271 | { 0x113e, 0x0000 }, { 0x115c, 0x0000 }, | ||
272 | { 0x1164, 0x0000 }, { 0x1174, 0x0000 }, | ||
273 | { 0x1178, 0x0000 }, { 0x077a, 0x0000 }, | ||
274 | { 0x077c, 0x0000 }, { 0x077e, 0x0000 }, | ||
275 | { 0x0780, 0x0000 }, { 0x0782, 0x0000 }, | ||
276 | { 0x0784, 0x0000 }, { 0x0786, 0x0000 }, | ||
277 | { 0x0788, 0x0000 }, { 0x07a2, 0x0000 }, | ||
278 | { 0x07a4, 0x0000 }, { 0x07a6, 0x0000 }, | ||
279 | { 0x07a8, 0x0000 }, { 0x07b6, 0x0000 }, | ||
280 | { 0x07b8, 0x0002 }, { 0x07ba, 0x0004 }, | ||
281 | { 0x07bc, 0x0004 }, { 0x07be, 0x0005 }, | ||
282 | { 0x07c0, 0x0005 }, { S5K6AA_TERM, 0 }, | ||
283 | }; | ||
284 | |||
285 | /* TODO: Add RGB888 and Bayer format */ | ||
286 | static const struct s5k6aa_pixfmt s5k6aa_formats[] = { | ||
287 | { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 }, | ||
288 | /* range 16-240 */ | ||
289 | { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_REC709, 6 }, | ||
290 | { V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 }, | ||
291 | }; | ||
292 | |||
293 | static const struct s5k6aa_interval s5k6aa_intervals[] = { | ||
294 | { 1000, {10000, 1000000}, {1280, 1024} }, /* 10 fps */ | ||
295 | { 666, {15000, 1000000}, {1280, 1024} }, /* 15 fps */ | ||
296 | { 500, {20000, 1000000}, {1280, 720} }, /* 20 fps */ | ||
297 | { 400, {25000, 1000000}, {640, 480} }, /* 25 fps */ | ||
298 | { 333, {33300, 1000000}, {640, 480} }, /* 30 fps */ | ||
299 | }; | ||
300 | |||
301 | #define S5K6AA_INTERVAL_DEF_INDEX 1 /* 15 fps */ | ||
302 | |||
303 | static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) | ||
304 | { | ||
305 | return &container_of(ctrl->handler, struct s5k6aa, ctrls.handler)->sd; | ||
306 | } | ||
307 | |||
308 | static inline struct s5k6aa *to_s5k6aa(struct v4l2_subdev *sd) | ||
309 | { | ||
310 | return container_of(sd, struct s5k6aa, sd); | ||
311 | } | ||
312 | |||
313 | /* Set initial values for all preview presets */ | ||
314 | static void s5k6aa_presets_data_init(struct s5k6aa *s5k6aa) | ||
315 | { | ||
316 | struct s5k6aa_preset *preset = &s5k6aa->presets[0]; | ||
317 | int i; | ||
318 | |||
319 | for (i = 0; i < S5K6AA_MAX_PRESETS; i++) { | ||
320 | preset->mbus_fmt.width = S5K6AA_OUT_WIDTH_DEF; | ||
321 | preset->mbus_fmt.height = S5K6AA_OUT_HEIGHT_DEF; | ||
322 | preset->mbus_fmt.code = s5k6aa_formats[0].code; | ||
323 | preset->index = i; | ||
324 | preset->clk_id = 0; | ||
325 | preset++; | ||
326 | } | ||
327 | |||
328 | s5k6aa->fiv = &s5k6aa_intervals[S5K6AA_INTERVAL_DEF_INDEX]; | ||
329 | s5k6aa->preset = &s5k6aa->presets[0]; | ||
330 | } | ||
331 | |||
332 | static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val) | ||
333 | { | ||
334 | u8 wbuf[2] = {addr >> 8, addr & 0xFF}; | ||
335 | struct i2c_msg msg[2]; | ||
336 | u8 rbuf[2]; | ||
337 | int ret; | ||
338 | |||
339 | msg[0].addr = client->addr; | ||
340 | msg[0].flags = 0; | ||
341 | msg[0].len = 2; | ||
342 | msg[0].buf = wbuf; | ||
343 | |||
344 | msg[1].addr = client->addr; | ||
345 | msg[1].flags = I2C_M_RD; | ||
346 | msg[1].len = 2; | ||
347 | msg[1].buf = rbuf; | ||
348 | |||
349 | ret = i2c_transfer(client->adapter, msg, 2); | ||
350 | *val = be16_to_cpu(*((u16 *)rbuf)); | ||
351 | |||
352 | v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val); | ||
353 | |||
354 | return ret == 2 ? 0 : ret; | ||
355 | } | ||
356 | |||
357 | static int s5k6aa_i2c_write(struct i2c_client *client, u16 addr, u16 val) | ||
358 | { | ||
359 | u8 buf[4] = {addr >> 8, addr & 0xFF, val >> 8, val & 0xFF}; | ||
360 | |||
361 | int ret = i2c_master_send(client, buf, 4); | ||
362 | v4l2_dbg(3, debug, client, "i2c_write: 0x%04X : 0x%04x\n", addr, val); | ||
363 | |||
364 | return ret == 4 ? 0 : ret; | ||
365 | } | ||
366 | |||
367 | /* The command register write, assumes Command_Wr_addH = 0x7000. */ | ||
368 | static int s5k6aa_write(struct i2c_client *c, u16 addr, u16 val) | ||
369 | { | ||
370 | int ret = s5k6aa_i2c_write(c, REG_CMDWR_ADDRL, addr); | ||
371 | if (ret) | ||
372 | return ret; | ||
373 | return s5k6aa_i2c_write(c, REG_CMDBUF0_ADDR, val); | ||
374 | } | ||
375 | |||
376 | /* The command register read, assumes Command_Rd_addH = 0x7000. */ | ||
377 | static int s5k6aa_read(struct i2c_client *client, u16 addr, u16 *val) | ||
378 | { | ||
379 | int ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRL, addr); | ||
380 | if (ret) | ||
381 | return ret; | ||
382 | return s5k6aa_i2c_read(client, REG_CMDBUF0_ADDR, val); | ||
383 | } | ||
384 | |||
385 | static int s5k6aa_write_array(struct v4l2_subdev *sd, | ||
386 | const struct s5k6aa_regval *msg) | ||
387 | { | ||
388 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
389 | u16 addr_incr = 0; | ||
390 | int ret = 0; | ||
391 | |||
392 | while (msg->addr != S5K6AA_TERM) { | ||
393 | if (addr_incr != 2) | ||
394 | ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL, | ||
395 | msg->addr); | ||
396 | if (ret) | ||
397 | break; | ||
398 | ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val); | ||
399 | if (ret) | ||
400 | break; | ||
401 | /* Assume that msg->addr is always less than 0xfffc */ | ||
402 | addr_incr = (msg + 1)->addr - msg->addr; | ||
403 | msg++; | ||
404 | } | ||
405 | |||
406 | return ret; | ||
407 | } | ||
408 | |||
409 | /* Configure the AHB high address bytes for GTG registers access */ | ||
410 | static int s5k6aa_set_ahb_address(struct i2c_client *client) | ||
411 | { | ||
412 | int ret = s5k6aa_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH); | ||
413 | if (ret) | ||
414 | return ret; | ||
415 | ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRH, HOST_SWIF_OFFSH); | ||
416 | if (ret) | ||
417 | return ret; | ||
418 | return s5k6aa_i2c_write(client, REG_CMDWR_ADDRH, HOST_SWIF_OFFSH); | ||
419 | } | ||
420 | |||
421 | /** | ||
422 | * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration | ||
423 | * | ||
424 | * Configure the internal ISP PLL for the required output frequency. | ||
425 | * Locking: called with s5k6aa.lock mutex held. | ||
426 | */ | ||
427 | static int s5k6aa_configure_pixel_clocks(struct s5k6aa *s5k6aa) | ||
428 | { | ||
429 | struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | ||
430 | unsigned long fmclk = s5k6aa->mclk_frequency / 1000; | ||
431 | u16 status; | ||
432 | int ret; | ||
433 | |||
434 | if (WARN(fmclk < MIN_MCLK_FREQ_KHZ || fmclk > MAX_MCLK_FREQ_KHZ, | ||
435 | "Invalid clock frequency: %ld\n", fmclk)) | ||
436 | return -EINVAL; | ||
437 | |||
438 | s5k6aa->pclk_fmin = PCLK_FREQ_MIN; | ||
439 | s5k6aa->pclk_fmax = PCLK_FREQ_MAX; | ||
440 | s5k6aa->clk_fop = SYS_PLL_OUT_FREQ; | ||
441 | |||
442 | /* External input clock frequency in kHz */ | ||
443 | ret = s5k6aa_write(c, REG_I_INCLK_FREQ_H, fmclk >> 16); | ||
444 | if (!ret) | ||
445 | ret = s5k6aa_write(c, REG_I_INCLK_FREQ_L, fmclk & 0xFFFF); | ||
446 | if (!ret) | ||
447 | ret = s5k6aa_write(c, REG_I_USE_NPVI_CLOCKS, 1); | ||
448 | /* Internal PLL frequency */ | ||
449 | if (!ret) | ||
450 | ret = s5k6aa_write(c, REG_I_OPCLK_4KHZ(0), s5k6aa->clk_fop); | ||
451 | if (!ret) | ||
452 | ret = s5k6aa_write(c, REG_I_MIN_OUTRATE_4KHZ(0), | ||
453 | s5k6aa->pclk_fmin); | ||
454 | if (!ret) | ||
455 | ret = s5k6aa_write(c, REG_I_MAX_OUTRATE_4KHZ(0), | ||
456 | s5k6aa->pclk_fmax); | ||
457 | if (!ret) | ||
458 | ret = s5k6aa_write(c, REG_I_INIT_PARAMS_UPDATED, 1); | ||
459 | if (!ret) | ||
460 | ret = s5k6aa_read(c, REG_I_ERROR_INFO, &status); | ||
461 | |||
462 | return ret ? ret : (status ? -EINVAL : 0); | ||
463 | } | ||
464 | |||
465 | /* Set horizontal and vertical image flipping */ | ||
466 | static int s5k6aa_set_mirror(struct s5k6aa *s5k6aa, int horiz_flip) | ||
467 | { | ||
468 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
469 | int index = s5k6aa->preset->index; | ||
470 | |||
471 | unsigned int vflip = s5k6aa->ctrls.vflip->val ^ s5k6aa->inv_vflip; | ||
472 | unsigned int flip = (horiz_flip ^ s5k6aa->inv_hflip) | (vflip << 1); | ||
473 | |||
474 | return s5k6aa_write(client, REG_P_PREV_MIRROR(index), flip); | ||
475 | } | ||
476 | |||
477 | /* Configure auto/manual white balance and R/G/B gains */ | ||
478 | static int s5k6aa_set_awb(struct s5k6aa *s5k6aa, int awb) | ||
479 | { | ||
480 | struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | ||
481 | struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls; | ||
482 | u16 reg; | ||
483 | |||
484 | int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, ®); | ||
485 | |||
486 | if (!ret && !awb) { | ||
487 | ret = s5k6aa_write(c, REG_SF_RGAIN, ctrls->gain_red->val); | ||
488 | if (!ret) | ||
489 | ret = s5k6aa_write(c, REG_SF_RGAIN_CHG, 1); | ||
490 | if (ret) | ||
491 | return ret; | ||
492 | |||
493 | ret = s5k6aa_write(c, REG_SF_GGAIN, ctrls->gain_green->val); | ||
494 | if (!ret) | ||
495 | ret = s5k6aa_write(c, REG_SF_GGAIN_CHG, 1); | ||
496 | if (ret) | ||
497 | return ret; | ||
498 | |||
499 | ret = s5k6aa_write(c, REG_SF_BGAIN, ctrls->gain_blue->val); | ||
500 | if (!ret) | ||
501 | ret = s5k6aa_write(c, REG_SF_BGAIN_CHG, 1); | ||
502 | } | ||
503 | if (!ret) { | ||
504 | reg = awb ? reg | AALG_WB_EN_MASK : reg & ~AALG_WB_EN_MASK; | ||
505 | ret = s5k6aa_write(c, REG_DBG_AUTOALG_EN, reg); | ||
506 | } | ||
507 | |||
508 | return ret; | ||
509 | } | ||
510 | |||
511 | /* Program FW with exposure time, 'exposure' in us units */ | ||
512 | static int s5k6aa_set_user_exposure(struct i2c_client *client, int exposure) | ||
513 | { | ||
514 | unsigned int time = exposure / 10; | ||
515 | |||
516 | int ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_L, time & 0xffff); | ||
517 | if (!ret) | ||
518 | ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_H, time >> 16); | ||
519 | if (ret) | ||
520 | return ret; | ||
521 | return s5k6aa_write(client, REG_SF_USR_EXPOSURE_CHG, 1); | ||
522 | } | ||
523 | |||
524 | static int s5k6aa_set_user_gain(struct i2c_client *client, int gain) | ||
525 | { | ||
526 | int ret = s5k6aa_write(client, REG_SF_USR_TOT_GAIN, gain); | ||
527 | if (ret) | ||
528 | return ret; | ||
529 | return s5k6aa_write(client, REG_SF_USR_TOT_GAIN_CHG, 1); | ||
530 | } | ||
531 | |||
532 | /* Set auto/manual exposure and total gain */ | ||
533 | static int s5k6aa_set_auto_exposure(struct s5k6aa *s5k6aa, int value) | ||
534 | { | ||
535 | struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | ||
536 | unsigned int exp_time = s5k6aa->ctrls.exposure->val; | ||
537 | u16 auto_alg; | ||
538 | |||
539 | int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &auto_alg); | ||
540 | if (ret) | ||
541 | return ret; | ||
542 | |||
543 | v4l2_dbg(1, debug, c, "man_exp: %d, auto_exp: %d, a_alg: 0x%x\n", | ||
544 | exp_time, value, auto_alg); | ||
545 | |||
546 | if (value == V4L2_EXPOSURE_AUTO) { | ||
547 | auto_alg |= AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK; | ||
548 | } else { | ||
549 | ret = s5k6aa_set_user_exposure(c, exp_time); | ||
550 | if (ret) | ||
551 | return ret; | ||
552 | ret = s5k6aa_set_user_gain(c, s5k6aa->ctrls.gain->val); | ||
553 | if (ret) | ||
554 | return ret; | ||
555 | auto_alg &= ~(AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK); | ||
556 | } | ||
557 | |||
558 | return s5k6aa_write(c, REG_DBG_AUTOALG_EN, auto_alg); | ||
559 | } | ||
560 | |||
561 | static int s5k6aa_set_anti_flicker(struct s5k6aa *s5k6aa, int value) | ||
562 | { | ||
563 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
564 | u16 auto_alg; | ||
565 | int ret; | ||
566 | |||
567 | ret = s5k6aa_read(client, REG_DBG_AUTOALG_EN, &auto_alg); | ||
568 | if (ret) | ||
569 | return ret; | ||
570 | |||
571 | if (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) { | ||
572 | auto_alg |= AALG_FLICKER_EN_MASK; | ||
573 | } else { | ||
574 | auto_alg &= ~AALG_FLICKER_EN_MASK; | ||
575 | /* The V4L2_CID_LINE_FREQUENCY control values match | ||
576 | * the register values */ | ||
577 | ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT, value); | ||
578 | if (ret) | ||
579 | return ret; | ||
580 | ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT_CHG, 1); | ||
581 | if (ret) | ||
582 | return ret; | ||
583 | } | ||
584 | |||
585 | return s5k6aa_write(client, REG_DBG_AUTOALG_EN, auto_alg); | ||
586 | } | ||
587 | |||
588 | static int s5k6aa_set_colorfx(struct s5k6aa *s5k6aa, int val) | ||
589 | { | ||
590 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
591 | static const struct v4l2_control colorfx[] = { | ||
592 | { V4L2_COLORFX_NONE, 0 }, | ||
593 | { V4L2_COLORFX_BW, 1 }, | ||
594 | { V4L2_COLORFX_NEGATIVE, 2 }, | ||
595 | { V4L2_COLORFX_SEPIA, 3 }, | ||
596 | { V4L2_COLORFX_SKY_BLUE, 4 }, | ||
597 | { V4L2_COLORFX_SKETCH, 5 }, | ||
598 | }; | ||
599 | int i; | ||
600 | |||
601 | for (i = 0; i < ARRAY_SIZE(colorfx); i++) { | ||
602 | if (colorfx[i].id == val) | ||
603 | return s5k6aa_write(client, REG_G_SPEC_EFFECTS, | ||
604 | colorfx[i].value); | ||
605 | } | ||
606 | return -EINVAL; | ||
607 | } | ||
608 | |||
609 | static int s5k6aa_preview_config_status(struct i2c_client *client) | ||
610 | { | ||
611 | u16 error = 0; | ||
612 | int ret = s5k6aa_read(client, REG_G_PREV_CFG_ERROR, &error); | ||
613 | |||
614 | v4l2_dbg(1, debug, client, "error: 0x%x (%d)\n", error, ret); | ||
615 | return ret ? ret : (error ? -EINVAL : 0); | ||
616 | } | ||
617 | |||
618 | static int s5k6aa_get_pixfmt_index(struct s5k6aa *s5k6aa, | ||
619 | struct v4l2_mbus_framefmt *mf) | ||
620 | { | ||
621 | unsigned int i; | ||
622 | |||
623 | for (i = 0; i < ARRAY_SIZE(s5k6aa_formats); i++) | ||
624 | if (mf->colorspace == s5k6aa_formats[i].colorspace && | ||
625 | mf->code == s5k6aa_formats[i].code) | ||
626 | return i; | ||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | static int s5k6aa_set_output_framefmt(struct s5k6aa *s5k6aa, | ||
631 | struct s5k6aa_preset *preset) | ||
632 | { | ||
633 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
634 | int fmt_index = s5k6aa_get_pixfmt_index(s5k6aa, &preset->mbus_fmt); | ||
635 | int ret; | ||
636 | |||
637 | ret = s5k6aa_write(client, REG_P_OUT_WIDTH(preset->index), | ||
638 | preset->mbus_fmt.width); | ||
639 | if (!ret) | ||
640 | ret = s5k6aa_write(client, REG_P_OUT_HEIGHT(preset->index), | ||
641 | preset->mbus_fmt.height); | ||
642 | if (!ret) | ||
643 | ret = s5k6aa_write(client, REG_P_FMT(preset->index), | ||
644 | s5k6aa_formats[fmt_index].reg_p_fmt); | ||
645 | return ret; | ||
646 | } | ||
647 | |||
648 | static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa) | ||
649 | { | ||
650 | struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | ||
651 | struct v4l2_rect *r = &s5k6aa->ccd_rect; | ||
652 | int ret; | ||
653 | |||
654 | ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width); | ||
655 | if (!ret) | ||
656 | ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height); | ||
657 | if (!ret) | ||
658 | ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left); | ||
659 | if (!ret) | ||
660 | ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top); | ||
661 | if (!ret) | ||
662 | ret = s5k6aa_write(c, REG_G_INPUTS_CHANGE_REQ, 1); | ||
663 | if (!ret) | ||
664 | s5k6aa->apply_crop = 0; | ||
665 | |||
666 | return ret; | ||
667 | } | ||
668 | |||
669 | /** | ||
670 | * s5k6aa_configure_video_bus - configure the video output interface | ||
671 | * @bus_type: video bus type: parallel or MIPI-CSI | ||
672 | * @nlanes: number of MIPI lanes to be used (MIPI-CSI only) | ||
673 | * | ||
674 | * Note: Only parallel bus operation has been tested. | ||
675 | */ | ||
676 | static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa, | ||
677 | enum v4l2_mbus_type bus_type, int nlanes) | ||
678 | { | ||
679 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
680 | u16 cfg = 0; | ||
681 | int ret; | ||
682 | |||
683 | /* | ||
684 | * TODO: The sensor is supposed to support BT.601 and BT.656 | ||
685 | * but there is nothing indicating how to switch between both | ||
686 | * in the datasheet. For now default BT.601 interface is assumed. | ||
687 | */ | ||
688 | if (bus_type == V4L2_MBUS_CSI2) | ||
689 | cfg = nlanes; | ||
690 | else if (bus_type != V4L2_MBUS_PARALLEL) | ||
691 | return -EINVAL; | ||
692 | |||
693 | ret = s5k6aa_write(client, REG_OIF_EN_MIPI_LANES, cfg); | ||
694 | if (ret) | ||
695 | return ret; | ||
696 | return s5k6aa_write(client, REG_OIF_CFG_CHG, 1); | ||
697 | } | ||
698 | |||
699 | /* This function should be called when switching to new user configuration set*/ | ||
700 | static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout, | ||
701 | int cid) | ||
702 | { | ||
703 | unsigned long end = jiffies + msecs_to_jiffies(timeout); | ||
704 | u16 reg = 1; | ||
705 | int ret; | ||
706 | |||
707 | ret = s5k6aa_write(client, REG_G_ACTIVE_PREV_CFG, cid); | ||
708 | if (!ret) | ||
709 | ret = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); | ||
710 | if (!ret) | ||
711 | ret = s5k6aa_write(client, REG_G_NEW_CFG_SYNC, 1); | ||
712 | if (timeout == 0) | ||
713 | return ret; | ||
714 | |||
715 | while (ret >= 0 && time_is_after_jiffies(end)) { | ||
716 | ret = s5k6aa_read(client, REG_G_NEW_CFG_SYNC, ®); | ||
717 | if (!reg) | ||
718 | return 0; | ||
719 | usleep_range(1000, 5000); | ||
720 | } | ||
721 | return ret ? ret : -ETIMEDOUT; | ||
722 | } | ||
723 | |||
724 | /** | ||
725 | * s5k6aa_set_prev_config - write user preview register set | ||
726 | * | ||
727 | * Configure output resolution and color fromat, pixel clock | ||
728 | * frequency range, device frame rate type and frame period range. | ||
729 | */ | ||
730 | static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa, | ||
731 | struct s5k6aa_preset *preset) | ||
732 | { | ||
733 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
734 | int idx = preset->index; | ||
735 | u16 frame_rate_q; | ||
736 | int ret; | ||
737 | |||
738 | if (s5k6aa->fiv->reg_fr_time >= S5K6AA_MAX_HIGHRES_FR_TIME) | ||
739 | frame_rate_q = FR_RATE_Q_BEST_FRRATE; | ||
740 | else | ||
741 | frame_rate_q = FR_RATE_Q_BEST_QUALITY; | ||
742 | |||
743 | ret = s5k6aa_set_output_framefmt(s5k6aa, preset); | ||
744 | if (!ret) | ||
745 | ret = s5k6aa_write(client, REG_P_MAX_OUT_RATE(idx), | ||
746 | s5k6aa->pclk_fmax); | ||
747 | if (!ret) | ||
748 | ret = s5k6aa_write(client, REG_P_MIN_OUT_RATE(idx), | ||
749 | s5k6aa->pclk_fmin); | ||
750 | if (!ret) | ||
751 | ret = s5k6aa_write(client, REG_P_CLK_INDEX(idx), | ||
752 | preset->clk_id); | ||
753 | if (!ret) | ||
754 | ret = s5k6aa_write(client, REG_P_FR_RATE_TYPE(idx), | ||
755 | FR_RATE_DYNAMIC); | ||
756 | if (!ret) | ||
757 | ret = s5k6aa_write(client, REG_P_FR_RATE_Q_TYPE(idx), | ||
758 | frame_rate_q); | ||
759 | if (!ret) | ||
760 | ret = s5k6aa_write(client, REG_P_MAX_FR_TIME(idx), | ||
761 | s5k6aa->fiv->reg_fr_time + 33); | ||
762 | if (!ret) | ||
763 | ret = s5k6aa_write(client, REG_P_MIN_FR_TIME(idx), | ||
764 | s5k6aa->fiv->reg_fr_time - 33); | ||
765 | if (!ret) | ||
766 | ret = s5k6aa_new_config_sync(client, 250, idx); | ||
767 | if (!ret) | ||
768 | ret = s5k6aa_preview_config_status(client); | ||
769 | if (!ret) | ||
770 | s5k6aa->apply_cfg = 0; | ||
771 | |||
772 | v4l2_dbg(1, debug, client, "Frame interval: %d +/- 3.3ms. (%d)\n", | ||
773 | s5k6aa->fiv->reg_fr_time, ret); | ||
774 | return ret; | ||
775 | } | ||
776 | |||
777 | /** | ||
778 | * s5k6aa_initialize_isp - basic ISP MCU initialization | ||
779 | * | ||
780 | * Configure AHB addresses for registers read/write; configure PLLs for | ||
781 | * required output pixel clock. The ISP power supply needs to be already | ||
782 | * enabled, with an optional H/W reset. | ||
783 | * Locking: called with s5k6aa.lock mutex held. | ||
784 | */ | ||
785 | static int s5k6aa_initialize_isp(struct v4l2_subdev *sd) | ||
786 | { | ||
787 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
788 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
789 | int ret; | ||
790 | |||
791 | s5k6aa->apply_crop = 1; | ||
792 | s5k6aa->apply_cfg = 1; | ||
793 | msleep(100); | ||
794 | |||
795 | ret = s5k6aa_set_ahb_address(client); | ||
796 | if (ret) | ||
797 | return ret; | ||
798 | ret = s5k6aa_configure_video_bus(s5k6aa, s5k6aa->bus_type, | ||
799 | s5k6aa->mipi_lanes); | ||
800 | if (ret) | ||
801 | return ret; | ||
802 | ret = s5k6aa_write_array(sd, s5k6aa_analog_config); | ||
803 | if (ret) | ||
804 | return ret; | ||
805 | msleep(20); | ||
806 | |||
807 | return s5k6aa_configure_pixel_clocks(s5k6aa); | ||
808 | } | ||
809 | |||
810 | static int s5k6aa_gpio_set_value(struct s5k6aa *priv, int id, u32 val) | ||
811 | { | ||
812 | if (!gpio_is_valid(priv->gpio[id].gpio)) | ||
813 | return 0; | ||
814 | gpio_set_value(priv->gpio[id].gpio, !!val); | ||
815 | return 1; | ||
816 | } | ||
817 | |||
818 | static int s5k6aa_gpio_assert(struct s5k6aa *priv, int id) | ||
819 | { | ||
820 | return s5k6aa_gpio_set_value(priv, id, priv->gpio[id].level); | ||
821 | } | ||
822 | |||
823 | static int s5k6aa_gpio_deassert(struct s5k6aa *priv, int id) | ||
824 | { | ||
825 | return s5k6aa_gpio_set_value(priv, id, !priv->gpio[id].level); | ||
826 | } | ||
827 | |||
828 | static int __s5k6aa_power_on(struct s5k6aa *s5k6aa) | ||
829 | { | ||
830 | int ret; | ||
831 | |||
832 | ret = regulator_bulk_enable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | ||
833 | if (ret) | ||
834 | return ret; | ||
835 | if (s5k6aa_gpio_deassert(s5k6aa, STBY)) | ||
836 | usleep_range(150, 200); | ||
837 | |||
838 | if (s5k6aa->s_power) | ||
839 | ret = s5k6aa->s_power(1); | ||
840 | usleep_range(4000, 4000); | ||
841 | |||
842 | if (s5k6aa_gpio_deassert(s5k6aa, RST)) | ||
843 | msleep(20); | ||
844 | |||
845 | return ret; | ||
846 | } | ||
847 | |||
848 | static int __s5k6aa_power_off(struct s5k6aa *s5k6aa) | ||
849 | { | ||
850 | int ret; | ||
851 | |||
852 | if (s5k6aa_gpio_assert(s5k6aa, RST)) | ||
853 | usleep_range(100, 150); | ||
854 | |||
855 | if (s5k6aa->s_power) { | ||
856 | ret = s5k6aa->s_power(0); | ||
857 | if (ret) | ||
858 | return ret; | ||
859 | } | ||
860 | if (s5k6aa_gpio_assert(s5k6aa, STBY)) | ||
861 | usleep_range(50, 100); | ||
862 | s5k6aa->streaming = 0; | ||
863 | |||
864 | return regulator_bulk_disable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | ||
865 | } | ||
866 | |||
867 | /* | ||
868 | * V4L2 subdev core and video operations | ||
869 | */ | ||
870 | static int s5k6aa_set_power(struct v4l2_subdev *sd, int on) | ||
871 | { | ||
872 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
873 | int ret = 0; | ||
874 | |||
875 | mutex_lock(&s5k6aa->lock); | ||
876 | |||
877 | if (!on == s5k6aa->power) { | ||
878 | if (on) { | ||
879 | ret = __s5k6aa_power_on(s5k6aa); | ||
880 | if (!ret) | ||
881 | ret = s5k6aa_initialize_isp(sd); | ||
882 | } else { | ||
883 | ret = __s5k6aa_power_off(s5k6aa); | ||
884 | } | ||
885 | |||
886 | if (!ret) | ||
887 | s5k6aa->power += on ? 1 : -1; | ||
888 | } | ||
889 | |||
890 | mutex_unlock(&s5k6aa->lock); | ||
891 | |||
892 | if (!on || ret || s5k6aa->power != 1) | ||
893 | return ret; | ||
894 | |||
895 | return v4l2_ctrl_handler_setup(sd->ctrl_handler); | ||
896 | } | ||
897 | |||
898 | static int __s5k6aa_stream(struct s5k6aa *s5k6aa, int enable) | ||
899 | { | ||
900 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
901 | int ret = 0; | ||
902 | |||
903 | ret = s5k6aa_write(client, REG_G_ENABLE_PREV, enable); | ||
904 | if (!ret) | ||
905 | ret = s5k6aa_write(client, REG_G_ENABLE_PREV_CHG, 1); | ||
906 | if (!ret) | ||
907 | s5k6aa->streaming = enable; | ||
908 | |||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | static int s5k6aa_s_stream(struct v4l2_subdev *sd, int on) | ||
913 | { | ||
914 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
915 | int ret = 0; | ||
916 | |||
917 | mutex_lock(&s5k6aa->lock); | ||
918 | |||
919 | if (s5k6aa->streaming == !on) { | ||
920 | if (!ret && s5k6aa->apply_cfg) | ||
921 | ret = s5k6aa_set_prev_config(s5k6aa, s5k6aa->preset); | ||
922 | if (s5k6aa->apply_crop) | ||
923 | ret = s5k6aa_set_input_params(s5k6aa); | ||
924 | if (!ret) | ||
925 | ret = __s5k6aa_stream(s5k6aa, !!on); | ||
926 | } | ||
927 | mutex_unlock(&s5k6aa->lock); | ||
928 | |||
929 | return ret; | ||
930 | } | ||
931 | |||
932 | static int s5k6aa_g_frame_interval(struct v4l2_subdev *sd, | ||
933 | struct v4l2_subdev_frame_interval *fi) | ||
934 | { | ||
935 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
936 | |||
937 | mutex_lock(&s5k6aa->lock); | ||
938 | fi->interval = s5k6aa->fiv->interval; | ||
939 | mutex_unlock(&s5k6aa->lock); | ||
940 | |||
941 | return 0; | ||
942 | } | ||
943 | |||
944 | static int __s5k6aa_set_frame_interval(struct s5k6aa *s5k6aa, | ||
945 | struct v4l2_subdev_frame_interval *fi) | ||
946 | { | ||
947 | struct v4l2_mbus_framefmt *mbus_fmt = &s5k6aa->preset->mbus_fmt; | ||
948 | const struct s5k6aa_interval *fiv = &s5k6aa_intervals[0]; | ||
949 | unsigned int err, min_err = UINT_MAX; | ||
950 | unsigned int i, fr_time; | ||
951 | |||
952 | if (fi->interval.denominator == 0) | ||
953 | return -EINVAL; | ||
954 | |||
955 | fr_time = fi->interval.numerator * 10000 / fi->interval.denominator; | ||
956 | |||
957 | for (i = 0; i < ARRAY_SIZE(s5k6aa_intervals); i++) { | ||
958 | const struct s5k6aa_interval *iv = &s5k6aa_intervals[i]; | ||
959 | |||
960 | if (mbus_fmt->width > iv->size.width || | ||
961 | mbus_fmt->height > iv->size.height) | ||
962 | continue; | ||
963 | |||
964 | err = abs(iv->reg_fr_time - fr_time); | ||
965 | if (err < min_err) { | ||
966 | fiv = iv; | ||
967 | min_err = err; | ||
968 | } | ||
969 | } | ||
970 | s5k6aa->fiv = fiv; | ||
971 | |||
972 | v4l2_dbg(1, debug, &s5k6aa->sd, "Changed frame interval to %d us\n", | ||
973 | fiv->reg_fr_time * 100); | ||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd, | ||
978 | struct v4l2_subdev_frame_interval *fi) | ||
979 | { | ||
980 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
981 | int ret; | ||
982 | |||
983 | v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n", | ||
984 | fi->interval.numerator, fi->interval.denominator); | ||
985 | |||
986 | mutex_lock(&s5k6aa->lock); | ||
987 | ret = __s5k6aa_set_frame_interval(s5k6aa, fi); | ||
988 | s5k6aa->apply_cfg = 1; | ||
989 | |||
990 | mutex_unlock(&s5k6aa->lock); | ||
991 | return ret; | ||
992 | } | ||
993 | |||
994 | /* | ||
995 | * V4L2 subdev pad level and video operations | ||
996 | */ | ||
997 | static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd, | ||
998 | struct v4l2_subdev_fh *fh, | ||
999 | struct v4l2_subdev_frame_interval_enum *fie) | ||
1000 | { | ||
1001 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
1002 | const struct s5k6aa_interval *fi; | ||
1003 | int ret = 0; | ||
1004 | |||
1005 | if (fie->index > ARRAY_SIZE(s5k6aa_intervals)) | ||
1006 | return -EINVAL; | ||
1007 | |||
1008 | v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN, | ||
1009 | S5K6AA_WIN_WIDTH_MAX, 1, | ||
1010 | &fie->height, S5K6AA_WIN_HEIGHT_MIN, | ||
1011 | S5K6AA_WIN_HEIGHT_MAX, 1, 0); | ||
1012 | |||
1013 | mutex_lock(&s5k6aa->lock); | ||
1014 | fi = &s5k6aa_intervals[fie->index]; | ||
1015 | if (fie->width > fi->size.width || fie->height > fi->size.height) | ||
1016 | ret = -EINVAL; | ||
1017 | else | ||
1018 | fie->interval = fi->interval; | ||
1019 | mutex_unlock(&s5k6aa->lock); | ||
1020 | |||
1021 | return ret; | ||
1022 | } | ||
1023 | |||
1024 | static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd, | ||
1025 | struct v4l2_subdev_fh *fh, | ||
1026 | struct v4l2_subdev_mbus_code_enum *code) | ||
1027 | { | ||
1028 | if (code->index >= ARRAY_SIZE(s5k6aa_formats)) | ||
1029 | return -EINVAL; | ||
1030 | |||
1031 | code->code = s5k6aa_formats[code->index].code; | ||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd, | ||
1036 | struct v4l2_subdev_fh *fh, | ||
1037 | struct v4l2_subdev_frame_size_enum *fse) | ||
1038 | { | ||
1039 | int i = ARRAY_SIZE(s5k6aa_formats); | ||
1040 | |||
1041 | if (fse->index > 0) | ||
1042 | return -EINVAL; | ||
1043 | |||
1044 | while (--i) | ||
1045 | if (fse->code == s5k6aa_formats[i].code) | ||
1046 | break; | ||
1047 | |||
1048 | fse->code = s5k6aa_formats[i].code; | ||
1049 | fse->min_width = S5K6AA_WIN_WIDTH_MIN; | ||
1050 | fse->max_width = S5K6AA_WIN_WIDTH_MAX; | ||
1051 | fse->max_height = S5K6AA_WIN_HEIGHT_MIN; | ||
1052 | fse->min_height = S5K6AA_WIN_HEIGHT_MAX; | ||
1053 | |||
1054 | return 0; | ||
1055 | } | ||
1056 | |||
1057 | static struct v4l2_rect * | ||
1058 | __s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_fh *fh, | ||
1059 | enum v4l2_subdev_format_whence which) | ||
1060 | { | ||
1061 | if (which == V4L2_SUBDEV_FORMAT_ACTIVE) | ||
1062 | return &s5k6aa->ccd_rect; | ||
1063 | if (which == V4L2_SUBDEV_FORMAT_TRY) | ||
1064 | return v4l2_subdev_get_try_crop(fh, 0); | ||
1065 | |||
1066 | return NULL; | ||
1067 | } | ||
1068 | |||
1069 | static void s5k6aa_try_format(struct s5k6aa *s5k6aa, | ||
1070 | struct v4l2_mbus_framefmt *mf) | ||
1071 | { | ||
1072 | unsigned int index; | ||
1073 | |||
1074 | v4l_bound_align_image(&mf->width, S5K6AA_WIN_WIDTH_MIN, | ||
1075 | S5K6AA_WIN_WIDTH_MAX, 1, | ||
1076 | &mf->height, S5K6AA_WIN_HEIGHT_MIN, | ||
1077 | S5K6AA_WIN_HEIGHT_MAX, 1, 0); | ||
1078 | |||
1079 | if (mf->colorspace != V4L2_COLORSPACE_JPEG && | ||
1080 | mf->colorspace != V4L2_COLORSPACE_REC709) | ||
1081 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
1082 | |||
1083 | index = s5k6aa_get_pixfmt_index(s5k6aa, mf); | ||
1084 | |||
1085 | mf->colorspace = s5k6aa_formats[index].colorspace; | ||
1086 | mf->code = s5k6aa_formats[index].code; | ||
1087 | mf->field = V4L2_FIELD_NONE; | ||
1088 | } | ||
1089 | |||
1090 | static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
1091 | struct v4l2_subdev_format *fmt) | ||
1092 | { | ||
1093 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
1094 | struct v4l2_mbus_framefmt *mf; | ||
1095 | |||
1096 | memset(fmt->reserved, 0, sizeof(fmt->reserved)); | ||
1097 | |||
1098 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1099 | mf = v4l2_subdev_get_try_format(fh, 0); | ||
1100 | fmt->format = *mf; | ||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | mutex_lock(&s5k6aa->lock); | ||
1105 | fmt->format = s5k6aa->preset->mbus_fmt; | ||
1106 | mutex_unlock(&s5k6aa->lock); | ||
1107 | |||
1108 | return 0; | ||
1109 | } | ||
1110 | |||
1111 | static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
1112 | struct v4l2_subdev_format *fmt) | ||
1113 | { | ||
1114 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
1115 | struct s5k6aa_preset *preset = s5k6aa->preset; | ||
1116 | struct v4l2_mbus_framefmt *mf; | ||
1117 | struct v4l2_rect *crop; | ||
1118 | int ret = 0; | ||
1119 | |||
1120 | mutex_lock(&s5k6aa->lock); | ||
1121 | s5k6aa_try_format(s5k6aa, &fmt->format); | ||
1122 | |||
1123 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1124 | mf = v4l2_subdev_get_try_format(fh, fmt->pad); | ||
1125 | crop = v4l2_subdev_get_try_crop(fh, 0); | ||
1126 | } else { | ||
1127 | if (s5k6aa->streaming) { | ||
1128 | ret = -EBUSY; | ||
1129 | } else { | ||
1130 | mf = &preset->mbus_fmt; | ||
1131 | crop = &s5k6aa->ccd_rect; | ||
1132 | s5k6aa->apply_cfg = 1; | ||
1133 | } | ||
1134 | } | ||
1135 | |||
1136 | if (ret == 0) { | ||
1137 | struct v4l2_subdev_frame_interval fiv = { | ||
1138 | .interval = {0, 1} | ||
1139 | }; | ||
1140 | |||
1141 | *mf = fmt->format; | ||
1142 | /* | ||
1143 | * Make sure the crop window is valid, i.e. its size is | ||
1144 | * greater than the output window, as the ISP supports | ||
1145 | * only down-scaling. | ||
1146 | */ | ||
1147 | crop->width = clamp_t(unsigned int, crop->width, mf->width, | ||
1148 | S5K6AA_WIN_WIDTH_MAX); | ||
1149 | crop->height = clamp_t(unsigned int, crop->height, mf->height, | ||
1150 | S5K6AA_WIN_HEIGHT_MAX); | ||
1151 | crop->left = clamp_t(unsigned int, crop->left, 0, | ||
1152 | S5K6AA_WIN_WIDTH_MAX - crop->width); | ||
1153 | crop->top = clamp_t(unsigned int, crop->top, 0, | ||
1154 | S5K6AA_WIN_HEIGHT_MAX - crop->height); | ||
1155 | |||
1156 | /* Reset to minimum possible frame interval */ | ||
1157 | ret = __s5k6aa_set_frame_interval(s5k6aa, &fiv); | ||
1158 | } | ||
1159 | mutex_unlock(&s5k6aa->lock); | ||
1160 | |||
1161 | return ret; | ||
1162 | } | ||
1163 | |||
1164 | static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
1165 | struct v4l2_subdev_crop *crop) | ||
1166 | { | ||
1167 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
1168 | struct v4l2_rect *rect; | ||
1169 | |||
1170 | memset(crop->reserved, 0, sizeof(crop->reserved)); | ||
1171 | mutex_lock(&s5k6aa->lock); | ||
1172 | |||
1173 | rect = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); | ||
1174 | if (rect) | ||
1175 | crop->rect = *rect; | ||
1176 | |||
1177 | mutex_unlock(&s5k6aa->lock); | ||
1178 | |||
1179 | v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n", | ||
1180 | rect->left, rect->top, rect->width, rect->height); | ||
1181 | |||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | static int s5k6aa_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
1186 | struct v4l2_subdev_crop *crop) | ||
1187 | { | ||
1188 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
1189 | struct v4l2_mbus_framefmt *mf; | ||
1190 | unsigned int max_x, max_y; | ||
1191 | struct v4l2_rect *crop_r; | ||
1192 | |||
1193 | mutex_lock(&s5k6aa->lock); | ||
1194 | crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); | ||
1195 | |||
1196 | if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
1197 | mf = &s5k6aa->preset->mbus_fmt; | ||
1198 | s5k6aa->apply_crop = 1; | ||
1199 | } else { | ||
1200 | mf = v4l2_subdev_get_try_format(fh, 0); | ||
1201 | } | ||
1202 | v4l_bound_align_image(&crop->rect.width, mf->width, | ||
1203 | S5K6AA_WIN_WIDTH_MAX, 1, | ||
1204 | &crop->rect.height, mf->height, | ||
1205 | S5K6AA_WIN_HEIGHT_MAX, 1, 0); | ||
1206 | |||
1207 | max_x = (S5K6AA_WIN_WIDTH_MAX - crop->rect.width) & ~1; | ||
1208 | max_y = (S5K6AA_WIN_HEIGHT_MAX - crop->rect.height) & ~1; | ||
1209 | |||
1210 | crop->rect.left = clamp_t(unsigned int, crop->rect.left, 0, max_x); | ||
1211 | crop->rect.top = clamp_t(unsigned int, crop->rect.top, 0, max_y); | ||
1212 | |||
1213 | *crop_r = crop->rect; | ||
1214 | |||
1215 | mutex_unlock(&s5k6aa->lock); | ||
1216 | |||
1217 | v4l2_dbg(1, debug, sd, "Set crop rectangle: (%d,%d)/%dx%d\n", | ||
1218 | crop_r->left, crop_r->top, crop_r->width, crop_r->height); | ||
1219 | |||
1220 | return 0; | ||
1221 | } | ||
1222 | |||
1223 | static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = { | ||
1224 | .enum_mbus_code = s5k6aa_enum_mbus_code, | ||
1225 | .enum_frame_size = s5k6aa_enum_frame_size, | ||
1226 | .enum_frame_interval = s5k6aa_enum_frame_interval, | ||
1227 | .get_fmt = s5k6aa_get_fmt, | ||
1228 | .set_fmt = s5k6aa_set_fmt, | ||
1229 | .get_crop = s5k6aa_get_crop, | ||
1230 | .set_crop = s5k6aa_set_crop, | ||
1231 | }; | ||
1232 | |||
1233 | static const struct v4l2_subdev_video_ops s5k6aa_video_ops = { | ||
1234 | .g_frame_interval = s5k6aa_g_frame_interval, | ||
1235 | .s_frame_interval = s5k6aa_s_frame_interval, | ||
1236 | .s_stream = s5k6aa_s_stream, | ||
1237 | }; | ||
1238 | |||
1239 | /* | ||
1240 | * V4L2 subdev controls | ||
1241 | */ | ||
1242 | |||
1243 | static int s5k6aa_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1244 | { | ||
1245 | struct v4l2_subdev *sd = ctrl_to_sd(ctrl); | ||
1246 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1247 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
1248 | int idx, err = 0; | ||
1249 | |||
1250 | v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val); | ||
1251 | |||
1252 | mutex_lock(&s5k6aa->lock); | ||
1253 | /* | ||
1254 | * If the device is not powered up by the host driver do | ||
1255 | * not apply any controls to H/W at this time. Instead | ||
1256 | * the controls will be restored right after power-up. | ||
1257 | */ | ||
1258 | if (s5k6aa->power == 0) | ||
1259 | goto unlock; | ||
1260 | idx = s5k6aa->preset->index; | ||
1261 | |||
1262 | switch (ctrl->id) { | ||
1263 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
1264 | err = s5k6aa_set_awb(s5k6aa, ctrl->val); | ||
1265 | break; | ||
1266 | |||
1267 | case V4L2_CID_BRIGHTNESS: | ||
1268 | err = s5k6aa_write(client, REG_USER_BRIGHTNESS, ctrl->val); | ||
1269 | break; | ||
1270 | |||
1271 | case V4L2_CID_COLORFX: | ||
1272 | err = s5k6aa_set_colorfx(s5k6aa, ctrl->val); | ||
1273 | break; | ||
1274 | |||
1275 | case V4L2_CID_CONTRAST: | ||
1276 | err = s5k6aa_write(client, REG_USER_CONTRAST, ctrl->val); | ||
1277 | break; | ||
1278 | |||
1279 | case V4L2_CID_EXPOSURE_AUTO: | ||
1280 | err = s5k6aa_set_auto_exposure(s5k6aa, ctrl->val); | ||
1281 | break; | ||
1282 | |||
1283 | case V4L2_CID_HFLIP: | ||
1284 | err = s5k6aa_set_mirror(s5k6aa, ctrl->val); | ||
1285 | if (err) | ||
1286 | break; | ||
1287 | err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); | ||
1288 | break; | ||
1289 | |||
1290 | case V4L2_CID_POWER_LINE_FREQUENCY: | ||
1291 | err = s5k6aa_set_anti_flicker(s5k6aa, ctrl->val); | ||
1292 | break; | ||
1293 | |||
1294 | case V4L2_CID_SATURATION: | ||
1295 | err = s5k6aa_write(client, REG_USER_SATURATION, ctrl->val); | ||
1296 | break; | ||
1297 | |||
1298 | case V4L2_CID_SHARPNESS: | ||
1299 | err = s5k6aa_write(client, REG_USER_SHARPBLUR, ctrl->val); | ||
1300 | break; | ||
1301 | |||
1302 | case V4L2_CID_WHITE_BALANCE_TEMPERATURE: | ||
1303 | err = s5k6aa_write(client, REG_P_COLORTEMP(idx), ctrl->val); | ||
1304 | if (err) | ||
1305 | break; | ||
1306 | err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); | ||
1307 | break; | ||
1308 | } | ||
1309 | unlock: | ||
1310 | mutex_unlock(&s5k6aa->lock); | ||
1311 | return err; | ||
1312 | } | ||
1313 | |||
1314 | static const struct v4l2_ctrl_ops s5k6aa_ctrl_ops = { | ||
1315 | .s_ctrl = s5k6aa_s_ctrl, | ||
1316 | }; | ||
1317 | |||
1318 | static int s5k6aa_log_status(struct v4l2_subdev *sd) | ||
1319 | { | ||
1320 | v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name); | ||
1321 | return 0; | ||
1322 | } | ||
1323 | |||
1324 | #define V4L2_CID_RED_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1001) | ||
1325 | #define V4L2_CID_GREEN_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1002) | ||
1326 | #define V4L2_CID_BLUE_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1003) | ||
1327 | |||
1328 | static const struct v4l2_ctrl_config s5k6aa_ctrls[] = { | ||
1329 | { | ||
1330 | .ops = &s5k6aa_ctrl_ops, | ||
1331 | .id = V4L2_CID_RED_GAIN, | ||
1332 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1333 | .name = "Gain, Red", | ||
1334 | .min = 0, | ||
1335 | .max = 256, | ||
1336 | .def = 127, | ||
1337 | .step = 1, | ||
1338 | }, { | ||
1339 | .ops = &s5k6aa_ctrl_ops, | ||
1340 | .id = V4L2_CID_GREEN_GAIN, | ||
1341 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1342 | .name = "Gain, Green", | ||
1343 | .min = 0, | ||
1344 | .max = 256, | ||
1345 | .def = 127, | ||
1346 | .step = 1, | ||
1347 | }, { | ||
1348 | .ops = &s5k6aa_ctrl_ops, | ||
1349 | .id = V4L2_CID_BLUE_GAIN, | ||
1350 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1351 | .name = "Gain, Blue", | ||
1352 | .min = 0, | ||
1353 | .max = 256, | ||
1354 | .def = 127, | ||
1355 | .step = 1, | ||
1356 | }, | ||
1357 | }; | ||
1358 | |||
1359 | static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa) | ||
1360 | { | ||
1361 | const struct v4l2_ctrl_ops *ops = &s5k6aa_ctrl_ops; | ||
1362 | struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls; | ||
1363 | struct v4l2_ctrl_handler *hdl = &ctrls->handler; | ||
1364 | |||
1365 | int ret = v4l2_ctrl_handler_init(hdl, 16); | ||
1366 | if (ret) | ||
1367 | return ret; | ||
1368 | /* Auto white balance cluster */ | ||
1369 | ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, | ||
1370 | 0, 1, 1, 1); | ||
1371 | ctrls->gain_red = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[0], NULL); | ||
1372 | ctrls->gain_green = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[1], NULL); | ||
1373 | ctrls->gain_blue = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[2], NULL); | ||
1374 | v4l2_ctrl_auto_cluster(4, &ctrls->awb, 0, false); | ||
1375 | |||
1376 | ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
1377 | ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
1378 | v4l2_ctrl_cluster(2, &ctrls->hflip); | ||
1379 | |||
1380 | ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, | ||
1381 | V4L2_CID_EXPOSURE_AUTO, | ||
1382 | V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); | ||
1383 | /* Exposure time: x 1 us */ | ||
1384 | ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, | ||
1385 | 0, 6000000U, 1, 100000U); | ||
1386 | /* Total gain: 256 <=> 1x */ | ||
1387 | ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, | ||
1388 | 0, 256, 1, 256); | ||
1389 | v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false); | ||
1390 | |||
1391 | v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY, | ||
1392 | V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, | ||
1393 | V4L2_CID_POWER_LINE_FREQUENCY_AUTO); | ||
1394 | |||
1395 | v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX, | ||
1396 | V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE); | ||
1397 | |||
1398 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE, | ||
1399 | 0, 256, 1, 0); | ||
1400 | |||
1401 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0); | ||
1402 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0); | ||
1403 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0); | ||
1404 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0); | ||
1405 | |||
1406 | if (hdl->error) { | ||
1407 | ret = hdl->error; | ||
1408 | v4l2_ctrl_handler_free(hdl); | ||
1409 | return ret; | ||
1410 | } | ||
1411 | |||
1412 | s5k6aa->sd.ctrl_handler = hdl; | ||
1413 | return 0; | ||
1414 | } | ||
1415 | |||
1416 | /* | ||
1417 | * V4L2 subdev internal operations | ||
1418 | */ | ||
1419 | static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
1420 | { | ||
1421 | struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); | ||
1422 | struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0); | ||
1423 | |||
1424 | format->colorspace = s5k6aa_formats[0].colorspace; | ||
1425 | format->code = s5k6aa_formats[0].code; | ||
1426 | format->width = S5K6AA_OUT_WIDTH_DEF; | ||
1427 | format->height = S5K6AA_OUT_HEIGHT_DEF; | ||
1428 | format->field = V4L2_FIELD_NONE; | ||
1429 | |||
1430 | crop->width = S5K6AA_WIN_WIDTH_MAX; | ||
1431 | crop->height = S5K6AA_WIN_HEIGHT_MAX; | ||
1432 | crop->left = 0; | ||
1433 | crop->top = 0; | ||
1434 | |||
1435 | return 0; | ||
1436 | } | ||
1437 | |||
1438 | int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa) | ||
1439 | { | ||
1440 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
1441 | u16 api_ver = 0, fw_rev = 0; | ||
1442 | |||
1443 | int ret = s5k6aa_set_ahb_address(client); | ||
1444 | |||
1445 | if (!ret) | ||
1446 | ret = s5k6aa_read(client, REG_FW_APIVER, &api_ver); | ||
1447 | if (!ret) | ||
1448 | ret = s5k6aa_read(client, REG_FW_REVISION, &fw_rev); | ||
1449 | if (ret) { | ||
1450 | v4l2_err(&s5k6aa->sd, "FW revision check failed!\n"); | ||
1451 | return ret; | ||
1452 | } | ||
1453 | |||
1454 | v4l2_info(&s5k6aa->sd, "FW API ver.: 0x%X, FW rev.: 0x%X\n", | ||
1455 | api_ver, fw_rev); | ||
1456 | |||
1457 | return api_ver == S5K6AAFX_FW_APIVER ? 0 : -ENODEV; | ||
1458 | } | ||
1459 | |||
1460 | static int s5k6aa_registered(struct v4l2_subdev *sd) | ||
1461 | { | ||
1462 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
1463 | int ret; | ||
1464 | |||
1465 | mutex_lock(&s5k6aa->lock); | ||
1466 | ret = __s5k6aa_power_on(s5k6aa); | ||
1467 | if (!ret) { | ||
1468 | msleep(100); | ||
1469 | ret = s5k6aa_check_fw_revision(s5k6aa); | ||
1470 | __s5k6aa_power_off(s5k6aa); | ||
1471 | } | ||
1472 | mutex_unlock(&s5k6aa->lock); | ||
1473 | |||
1474 | return ret; | ||
1475 | } | ||
1476 | |||
1477 | static const struct v4l2_subdev_internal_ops s5k6aa_subdev_internal_ops = { | ||
1478 | .registered = s5k6aa_registered, | ||
1479 | .open = s5k6aa_open, | ||
1480 | }; | ||
1481 | |||
1482 | static const struct v4l2_subdev_core_ops s5k6aa_core_ops = { | ||
1483 | .s_power = s5k6aa_set_power, | ||
1484 | .log_status = s5k6aa_log_status, | ||
1485 | }; | ||
1486 | |||
1487 | static const struct v4l2_subdev_ops s5k6aa_subdev_ops = { | ||
1488 | .core = &s5k6aa_core_ops, | ||
1489 | .pad = &s5k6aa_pad_ops, | ||
1490 | .video = &s5k6aa_video_ops, | ||
1491 | }; | ||
1492 | |||
1493 | /* | ||
1494 | * GPIO setup | ||
1495 | */ | ||
1496 | static int s5k6aa_configure_gpio(int nr, int val, const char *name) | ||
1497 | { | ||
1498 | unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; | ||
1499 | int ret; | ||
1500 | |||
1501 | if (!gpio_is_valid(nr)) | ||
1502 | return 0; | ||
1503 | ret = gpio_request_one(nr, flags, name); | ||
1504 | if (!ret) | ||
1505 | gpio_export(nr, 0); | ||
1506 | return ret; | ||
1507 | } | ||
1508 | |||
1509 | static void s5k6aa_free_gpios(struct s5k6aa *s5k6aa) | ||
1510 | { | ||
1511 | int i; | ||
1512 | |||
1513 | for (i = 0; i < ARRAY_SIZE(s5k6aa->gpio); i++) { | ||
1514 | if (!gpio_is_valid(s5k6aa->gpio[i].gpio)) | ||
1515 | continue; | ||
1516 | gpio_free(s5k6aa->gpio[i].gpio); | ||
1517 | s5k6aa->gpio[i].gpio = -EINVAL; | ||
1518 | } | ||
1519 | } | ||
1520 | |||
1521 | static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa, | ||
1522 | const struct s5k6aa_platform_data *pdata) | ||
1523 | { | ||
1524 | const struct s5k6aa_gpio *gpio = &pdata->gpio_stby; | ||
1525 | int ret; | ||
1526 | |||
1527 | s5k6aa->gpio[STBY].gpio = -EINVAL; | ||
1528 | s5k6aa->gpio[RST].gpio = -EINVAL; | ||
1529 | |||
1530 | ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_STBY"); | ||
1531 | if (ret) { | ||
1532 | s5k6aa_free_gpios(s5k6aa); | ||
1533 | return ret; | ||
1534 | } | ||
1535 | s5k6aa->gpio[STBY] = *gpio; | ||
1536 | if (gpio_is_valid(gpio->gpio)) | ||
1537 | gpio_set_value(gpio->gpio, 0); | ||
1538 | |||
1539 | gpio = &pdata->gpio_reset; | ||
1540 | ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_RST"); | ||
1541 | if (ret) { | ||
1542 | s5k6aa_free_gpios(s5k6aa); | ||
1543 | return ret; | ||
1544 | } | ||
1545 | s5k6aa->gpio[RST] = *gpio; | ||
1546 | if (gpio_is_valid(gpio->gpio)) | ||
1547 | gpio_set_value(gpio->gpio, 0); | ||
1548 | |||
1549 | return 0; | ||
1550 | } | ||
1551 | |||
1552 | static int s5k6aa_probe(struct i2c_client *client, | ||
1553 | const struct i2c_device_id *id) | ||
1554 | { | ||
1555 | const struct s5k6aa_platform_data *pdata = client->dev.platform_data; | ||
1556 | struct v4l2_subdev *sd; | ||
1557 | struct s5k6aa *s5k6aa; | ||
1558 | int i, ret; | ||
1559 | |||
1560 | if (pdata == NULL) { | ||
1561 | dev_err(&client->dev, "Platform data not specified\n"); | ||
1562 | return -EINVAL; | ||
1563 | } | ||
1564 | |||
1565 | if (pdata->mclk_frequency == 0) { | ||
1566 | dev_err(&client->dev, "MCLK frequency not specified\n"); | ||
1567 | return -EINVAL; | ||
1568 | } | ||
1569 | |||
1570 | s5k6aa = kzalloc(sizeof(*s5k6aa), GFP_KERNEL); | ||
1571 | if (!s5k6aa) | ||
1572 | return -ENOMEM; | ||
1573 | |||
1574 | mutex_init(&s5k6aa->lock); | ||
1575 | |||
1576 | s5k6aa->mclk_frequency = pdata->mclk_frequency; | ||
1577 | s5k6aa->bus_type = pdata->bus_type; | ||
1578 | s5k6aa->mipi_lanes = pdata->nlanes; | ||
1579 | s5k6aa->s_power = pdata->set_power; | ||
1580 | s5k6aa->inv_hflip = pdata->horiz_flip; | ||
1581 | s5k6aa->inv_vflip = pdata->vert_flip; | ||
1582 | |||
1583 | sd = &s5k6aa->sd; | ||
1584 | strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); | ||
1585 | v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops); | ||
1586 | |||
1587 | sd->internal_ops = &s5k6aa_subdev_internal_ops; | ||
1588 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
1589 | |||
1590 | s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
1591 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
1592 | ret = media_entity_init(&sd->entity, 1, &s5k6aa->pad, 0); | ||
1593 | if (ret) | ||
1594 | goto out_err1; | ||
1595 | |||
1596 | ret = s5k6aa_configure_gpios(s5k6aa, pdata); | ||
1597 | if (ret) | ||
1598 | goto out_err2; | ||
1599 | |||
1600 | for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++) | ||
1601 | s5k6aa->supplies[i].supply = s5k6aa_supply_names[i]; | ||
1602 | |||
1603 | ret = regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES, | ||
1604 | s5k6aa->supplies); | ||
1605 | if (ret) { | ||
1606 | dev_err(&client->dev, "Failed to get regulators\n"); | ||
1607 | goto out_err3; | ||
1608 | } | ||
1609 | |||
1610 | ret = s5k6aa_initialize_ctrls(s5k6aa); | ||
1611 | if (ret) | ||
1612 | goto out_err4; | ||
1613 | |||
1614 | s5k6aa_presets_data_init(s5k6aa); | ||
1615 | |||
1616 | s5k6aa->ccd_rect.width = S5K6AA_WIN_WIDTH_MAX; | ||
1617 | s5k6aa->ccd_rect.height = S5K6AA_WIN_HEIGHT_MAX; | ||
1618 | s5k6aa->ccd_rect.left = 0; | ||
1619 | s5k6aa->ccd_rect.top = 0; | ||
1620 | |||
1621 | return 0; | ||
1622 | |||
1623 | out_err4: | ||
1624 | regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | ||
1625 | out_err3: | ||
1626 | s5k6aa_free_gpios(s5k6aa); | ||
1627 | out_err2: | ||
1628 | media_entity_cleanup(&s5k6aa->sd.entity); | ||
1629 | out_err1: | ||
1630 | kfree(s5k6aa); | ||
1631 | return ret; | ||
1632 | } | ||
1633 | |||
1634 | static int s5k6aa_remove(struct i2c_client *client) | ||
1635 | { | ||
1636 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
1637 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
1638 | |||
1639 | v4l2_device_unregister_subdev(sd); | ||
1640 | v4l2_ctrl_handler_free(sd->ctrl_handler); | ||
1641 | media_entity_cleanup(&sd->entity); | ||
1642 | regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | ||
1643 | s5k6aa_free_gpios(s5k6aa); | ||
1644 | kfree(s5k6aa); | ||
1645 | |||
1646 | return 0; | ||
1647 | } | ||
1648 | |||
1649 | static const struct i2c_device_id s5k6aa_id[] = { | ||
1650 | { DRIVER_NAME, 0 }, | ||
1651 | { }, | ||
1652 | }; | ||
1653 | MODULE_DEVICE_TABLE(i2c, s5k6aa_id); | ||
1654 | |||
1655 | |||
1656 | static struct i2c_driver s5k6aa_i2c_driver = { | ||
1657 | .driver = { | ||
1658 | .name = DRIVER_NAME | ||
1659 | }, | ||
1660 | .probe = s5k6aa_probe, | ||
1661 | .remove = s5k6aa_remove, | ||
1662 | .id_table = s5k6aa_id, | ||
1663 | }; | ||
1664 | |||
1665 | static int __init s5k6aa_init(void) | ||
1666 | { | ||
1667 | return i2c_add_driver(&s5k6aa_i2c_driver); | ||
1668 | } | ||
1669 | |||
1670 | static void __exit s5k6aa_exit(void) | ||
1671 | { | ||
1672 | i2c_del_driver(&s5k6aa_i2c_driver); | ||
1673 | } | ||
1674 | |||
1675 | module_init(s5k6aa_init); | ||
1676 | module_exit(s5k6aa_exit); | ||
1677 | |||
1678 | MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver"); | ||
1679 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); | ||
1680 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 931f469604b0..c8d91b0cd9bd 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c | |||
@@ -246,9 +246,9 @@ static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) | |||
246 | return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8; | 246 | return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8; |
247 | } | 247 | } |
248 | 248 | ||
249 | static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, | 249 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, |
250 | unsigned int *num_planes, unsigned int sizes[], | 250 | unsigned int *num_buffers, unsigned int *num_planes, |
251 | void *allocators[]) | 251 | unsigned int sizes[], void *allocators[]) |
252 | { | 252 | { |
253 | struct fimc_ctx *ctx = vq->drv_priv; | 253 | struct fimc_ctx *ctx = vq->drv_priv; |
254 | struct fimc_fmt *fmt = ctx->d_frame.fmt; | 254 | struct fimc_fmt *fmt = ctx->d_frame.fmt; |
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 6c1c9cb55378..19ca6db38b2f 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c | |||
@@ -670,9 +670,9 @@ static void fimc_job_abort(void *priv) | |||
670 | fimc_m2m_shutdown(priv); | 670 | fimc_m2m_shutdown(priv); |
671 | } | 671 | } |
672 | 672 | ||
673 | static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, | 673 | static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, |
674 | unsigned int *num_planes, unsigned int sizes[], | 674 | unsigned int *num_buffers, unsigned int *num_planes, |
675 | void *allocators[]) | 675 | unsigned int sizes[], void *allocators[]) |
676 | { | 676 | { |
677 | struct fimc_ctx *ctx = vb2_get_drv_priv(vq); | 677 | struct fimc_ctx *ctx = vb2_get_drv_priv(vq); |
678 | struct fimc_frame *f; | 678 | struct fimc_frame *f; |
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c index 5f4da80051bb..f2481a85e0a2 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c | |||
@@ -38,7 +38,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) | |||
38 | * into kernel. */ | 38 | * into kernel. */ |
39 | mfc_debug_enter(); | 39 | mfc_debug_enter(); |
40 | err = request_firmware((const struct firmware **)&fw_blob, | 40 | err = request_firmware((const struct firmware **)&fw_blob, |
41 | "s5pc110-mfc.fw", dev->v4l2_dev.dev); | 41 | "s5p-mfc.fw", dev->v4l2_dev.dev); |
42 | if (err != 0) { | 42 | if (err != 0) { |
43 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); | 43 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); |
44 | return -EINVAL; | 44 | return -EINVAL; |
@@ -116,7 +116,7 @@ int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev) | |||
116 | * into kernel. */ | 116 | * into kernel. */ |
117 | mfc_debug_enter(); | 117 | mfc_debug_enter(); |
118 | err = request_firmware((const struct firmware **)&fw_blob, | 118 | err = request_firmware((const struct firmware **)&fw_blob, |
119 | "s5pc110-mfc.fw", dev->v4l2_dev.dev); | 119 | "s5p-mfc.fw", dev->v4l2_dev.dev); |
120 | if (err != 0) { | 120 | if (err != 0) { |
121 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); | 121 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); |
122 | return -EINVAL; | 122 | return -EINVAL; |
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c index bfbe08432050..725634d9736d 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c | |||
@@ -744,9 +744,10 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { | |||
744 | .vidioc_g_crop = vidioc_g_crop, | 744 | .vidioc_g_crop = vidioc_g_crop, |
745 | }; | 745 | }; |
746 | 746 | ||
747 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count, | 747 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, |
748 | unsigned int *plane_count, unsigned int psize[], | 748 | const struct v4l2_format *fmt, unsigned int *buf_count, |
749 | void *allocators[]) | 749 | unsigned int *plane_count, unsigned int psize[], |
750 | void *allocators[]) | ||
750 | { | 751 | { |
751 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | 752 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); |
752 | 753 | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c index 4c90e53bd964..ecef127dbc66 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c | |||
@@ -1513,8 +1513,9 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) | |||
1513 | } | 1513 | } |
1514 | 1514 | ||
1515 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, | 1515 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, |
1516 | unsigned int *buf_count, unsigned int *plane_count, | 1516 | const struct v4l2_format *fmt, |
1517 | unsigned int psize[], void *allocators[]) | 1517 | unsigned int *buf_count, unsigned int *plane_count, |
1518 | unsigned int psize[], void *allocators[]) | ||
1518 | { | 1519 | { |
1519 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | 1520 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); |
1520 | 1521 | ||
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c index 4917e2c2b321..e16d3a4bc1dc 100644 --- a/drivers/media/video/s5p-tv/mixer_video.c +++ b/drivers/media/video/s5p-tv/mixer_video.c | |||
@@ -727,8 +727,8 @@ static const struct v4l2_file_operations mxr_fops = { | |||
727 | .unlocked_ioctl = video_ioctl2, | 727 | .unlocked_ioctl = video_ioctl2, |
728 | }; | 728 | }; |
729 | 729 | ||
730 | static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | 730 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, |
731 | unsigned int *nplanes, unsigned int sizes[], | 731 | unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], |
732 | void *alloc_ctxs[]) | 732 | void *alloc_ctxs[]) |
733 | { | 733 | { |
734 | struct mxr_layer *layer = vb2_get_drv_priv(vq); | 734 | struct mxr_layer *layer = vb2_get_drv_priv(vq); |
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index bc8d6bba8ee5..9b550687213a 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h | |||
@@ -843,10 +843,10 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev); | |||
843 | int saa7134_ir_start(struct saa7134_dev *dev); | 843 | int saa7134_ir_start(struct saa7134_dev *dev); |
844 | void saa7134_ir_stop(struct saa7134_dev *dev); | 844 | void saa7134_ir_stop(struct saa7134_dev *dev); |
845 | #else | 845 | #else |
846 | #define saa7134_input_init1(dev) (0) | 846 | #define saa7134_input_init1(dev) ((void)0) |
847 | #define saa7134_input_fini(dev) (0) | 847 | #define saa7134_input_fini(dev) ((void)0) |
848 | #define saa7134_input_irq(dev) (0) | 848 | #define saa7134_input_irq(dev) ((void)0) |
849 | #define saa7134_probe_i2c_ir(dev) (0) | 849 | #define saa7134_probe_i2c_ir(dev) ((void)0) |
850 | #define saa7134_ir_start(dev) (0) | 850 | #define saa7134_ir_start(dev) ((void)0) |
851 | #define saa7134_ir_stop(dev) (0) | 851 | #define saa7134_ir_stop(dev) ((void)0) |
852 | #endif | 852 | #endif |
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 8615fb81775f..f390682629cf 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
@@ -90,7 +90,6 @@ | |||
90 | struct sh_mobile_ceu_buffer { | 90 | struct sh_mobile_ceu_buffer { |
91 | struct vb2_buffer vb; /* v4l buffer must be first */ | 91 | struct vb2_buffer vb; /* v4l buffer must be first */ |
92 | struct list_head queue; | 92 | struct list_head queue; |
93 | enum v4l2_mbus_pixelcode code; | ||
94 | }; | 93 | }; |
95 | 94 | ||
96 | struct sh_mobile_ceu_dev { | 95 | struct sh_mobile_ceu_dev { |
@@ -100,7 +99,8 @@ struct sh_mobile_ceu_dev { | |||
100 | 99 | ||
101 | unsigned int irq; | 100 | unsigned int irq; |
102 | void __iomem *base; | 101 | void __iomem *base; |
103 | unsigned long video_limit; | 102 | size_t video_limit; |
103 | size_t buf_total; | ||
104 | 104 | ||
105 | spinlock_t lock; /* Protects video buffer lists */ | 105 | spinlock_t lock; /* Protects video buffer lists */ |
106 | struct list_head capture; | 106 | struct list_head capture; |
@@ -121,7 +121,7 @@ struct sh_mobile_ceu_dev { | |||
121 | }; | 121 | }; |
122 | 122 | ||
123 | struct sh_mobile_ceu_cam { | 123 | struct sh_mobile_ceu_cam { |
124 | /* CEU offsets within scaled by the CEU camera output */ | 124 | /* CEU offsets within the camera output, before the CEU scaler */ |
125 | unsigned int ceu_left; | 125 | unsigned int ceu_left; |
126 | unsigned int ceu_top; | 126 | unsigned int ceu_top; |
127 | /* Client output, as seen by the CEU */ | 127 | /* Client output, as seen by the CEU */ |
@@ -144,30 +144,6 @@ static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_buffer *vb) | |||
144 | return container_of(vb, struct sh_mobile_ceu_buffer, vb); | 144 | return container_of(vb, struct sh_mobile_ceu_buffer, vb); |
145 | } | 145 | } |
146 | 146 | ||
147 | static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev) | ||
148 | { | ||
149 | unsigned long flags; | ||
150 | |||
151 | flags = SOCAM_MASTER | | ||
152 | SOCAM_PCLK_SAMPLE_RISING | | ||
153 | SOCAM_HSYNC_ACTIVE_HIGH | | ||
154 | SOCAM_HSYNC_ACTIVE_LOW | | ||
155 | SOCAM_VSYNC_ACTIVE_HIGH | | ||
156 | SOCAM_VSYNC_ACTIVE_LOW | | ||
157 | SOCAM_DATA_ACTIVE_HIGH; | ||
158 | |||
159 | if (pcdev->pdata->flags & SH_CEU_FLAG_USE_8BIT_BUS) | ||
160 | flags |= SOCAM_DATAWIDTH_8; | ||
161 | |||
162 | if (pcdev->pdata->flags & SH_CEU_FLAG_USE_16BIT_BUS) | ||
163 | flags |= SOCAM_DATAWIDTH_16; | ||
164 | |||
165 | if (flags & SOCAM_DATAWIDTH_MASK) | ||
166 | return flags; | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static void ceu_write(struct sh_mobile_ceu_dev *priv, | 147 | static void ceu_write(struct sh_mobile_ceu_dev *priv, |
172 | unsigned long reg_offs, u32 data) | 148 | unsigned long reg_offs, u32 data) |
173 | { | 149 | { |
@@ -216,33 +192,61 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) | |||
216 | /* | 192 | /* |
217 | * Videobuf operations | 193 | * Videobuf operations |
218 | */ | 194 | */ |
195 | |||
196 | /* | ||
197 | * .queue_setup() is called to check, whether the driver can accept the | ||
198 | * requested number of buffers and to fill in plane sizes | ||
199 | * for the current frame format if required | ||
200 | */ | ||
219 | static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, | 201 | static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, |
202 | const struct v4l2_format *fmt, | ||
220 | unsigned int *count, unsigned int *num_planes, | 203 | unsigned int *count, unsigned int *num_planes, |
221 | unsigned int sizes[], void *alloc_ctxs[]) | 204 | unsigned int sizes[], void *alloc_ctxs[]) |
222 | { | 205 | { |
223 | struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); | 206 | struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); |
224 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 207 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
225 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 208 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
226 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 209 | int bytes_per_line; |
227 | icd->current_fmt->host_fmt); | 210 | unsigned int height; |
228 | 211 | ||
212 | if (fmt) { | ||
213 | const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, | ||
214 | fmt->fmt.pix.pixelformat); | ||
215 | if (!xlate) | ||
216 | return -EINVAL; | ||
217 | bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width, | ||
218 | xlate->host_fmt); | ||
219 | height = fmt->fmt.pix.height; | ||
220 | } else { | ||
221 | /* Called from VIDIOC_REQBUFS or in compatibility mode */ | ||
222 | bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
223 | icd->current_fmt->host_fmt); | ||
224 | height = icd->user_height; | ||
225 | } | ||
229 | if (bytes_per_line < 0) | 226 | if (bytes_per_line < 0) |
230 | return bytes_per_line; | 227 | return bytes_per_line; |
231 | 228 | ||
232 | *num_planes = 1; | 229 | sizes[0] = bytes_per_line * height; |
233 | 230 | ||
234 | pcdev->sequence = 0; | ||
235 | sizes[0] = bytes_per_line * icd->user_height; | ||
236 | alloc_ctxs[0] = pcdev->alloc_ctx; | 231 | alloc_ctxs[0] = pcdev->alloc_ctx; |
237 | 232 | ||
233 | if (!vq->num_buffers) | ||
234 | pcdev->sequence = 0; | ||
235 | |||
238 | if (!*count) | 236 | if (!*count) |
239 | *count = 2; | 237 | *count = 2; |
240 | 238 | ||
241 | if (pcdev->video_limit) { | 239 | /* If *num_planes != 0, we have already verified *count. */ |
242 | if (PAGE_ALIGN(sizes[0]) * *count > pcdev->video_limit) | 240 | if (pcdev->video_limit && !*num_planes) { |
243 | *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]); | 241 | size_t size = PAGE_ALIGN(sizes[0]) * *count; |
242 | |||
243 | if (size + pcdev->buf_total > pcdev->video_limit) | ||
244 | *count = (pcdev->video_limit - pcdev->buf_total) / | ||
245 | PAGE_ALIGN(sizes[0]); | ||
244 | } | 246 | } |
245 | 247 | ||
248 | *num_planes = 1; | ||
249 | |||
246 | dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); | 250 | dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); |
247 | 251 | ||
248 | return 0; | 252 | return 0; |
@@ -267,6 +271,7 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
267 | unsigned long top1, top2; | 271 | unsigned long top1, top2; |
268 | unsigned long bottom1, bottom2; | 272 | unsigned long bottom1, bottom2; |
269 | u32 status; | 273 | u32 status; |
274 | bool planar; | ||
270 | int ret = 0; | 275 | int ret = 0; |
271 | 276 | ||
272 | /* | 277 | /* |
@@ -314,17 +319,29 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
314 | 319 | ||
315 | phys_addr_top = vb2_dma_contig_plane_dma_addr(pcdev->active, 0); | 320 | phys_addr_top = vb2_dma_contig_plane_dma_addr(pcdev->active, 0); |
316 | 321 | ||
317 | ceu_write(pcdev, top1, phys_addr_top); | ||
318 | if (V4L2_FIELD_NONE != pcdev->field) { | ||
319 | phys_addr_bottom = phys_addr_top + icd->user_width; | ||
320 | ceu_write(pcdev, bottom1, phys_addr_bottom); | ||
321 | } | ||
322 | |||
323 | switch (icd->current_fmt->host_fmt->fourcc) { | 322 | switch (icd->current_fmt->host_fmt->fourcc) { |
324 | case V4L2_PIX_FMT_NV12: | 323 | case V4L2_PIX_FMT_NV12: |
325 | case V4L2_PIX_FMT_NV21: | 324 | case V4L2_PIX_FMT_NV21: |
326 | case V4L2_PIX_FMT_NV16: | 325 | case V4L2_PIX_FMT_NV16: |
327 | case V4L2_PIX_FMT_NV61: | 326 | case V4L2_PIX_FMT_NV61: |
327 | planar = true; | ||
328 | break; | ||
329 | default: | ||
330 | planar = false; | ||
331 | } | ||
332 | |||
333 | ceu_write(pcdev, top1, phys_addr_top); | ||
334 | if (V4L2_FIELD_NONE != pcdev->field) { | ||
335 | if (planar) | ||
336 | phys_addr_bottom = phys_addr_top + icd->user_width; | ||
337 | else | ||
338 | phys_addr_bottom = phys_addr_top + | ||
339 | soc_mbus_bytes_per_line(icd->user_width, | ||
340 | icd->current_fmt->host_fmt); | ||
341 | ceu_write(pcdev, bottom1, phys_addr_bottom); | ||
342 | } | ||
343 | |||
344 | if (planar) { | ||
328 | phys_addr_top += icd->user_width * | 345 | phys_addr_top += icd->user_width * |
329 | icd->user_height; | 346 | icd->user_height; |
330 | ceu_write(pcdev, top2, phys_addr_top); | 347 | ceu_write(pcdev, top2, phys_addr_top); |
@@ -341,23 +358,40 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
341 | 358 | ||
342 | static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) | 359 | static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) |
343 | { | 360 | { |
361 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
362 | |||
363 | /* Added list head initialization on alloc */ | ||
364 | WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | ||
370 | { | ||
344 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | 371 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); |
345 | struct sh_mobile_ceu_buffer *buf; | 372 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
373 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
374 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
375 | unsigned long size; | ||
346 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 376 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, |
347 | icd->current_fmt->host_fmt); | 377 | icd->current_fmt->host_fmt); |
348 | unsigned long size; | ||
349 | 378 | ||
350 | if (bytes_per_line < 0) | 379 | if (bytes_per_line < 0) |
351 | return bytes_per_line; | 380 | goto error; |
352 | 381 | ||
353 | buf = to_ceu_vb(vb); | 382 | size = icd->user_height * bytes_per_line; |
383 | |||
384 | if (vb2_plane_size(vb, 0) < size) { | ||
385 | dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n", | ||
386 | vb->v4l2_buf.index, vb2_plane_size(vb, 0), size); | ||
387 | goto error; | ||
388 | } | ||
389 | |||
390 | vb2_set_plane_payload(vb, 0, size); | ||
354 | 391 | ||
355 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | 392 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, |
356 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | 393 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); |
357 | 394 | ||
358 | /* Added list head initialization on alloc */ | ||
359 | WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); | ||
360 | |||
361 | #ifdef DEBUG | 395 | #ifdef DEBUG |
362 | /* | 396 | /* |
363 | * This can be useful if you want to see if we actually fill | 397 | * This can be useful if you want to see if we actually fill |
@@ -367,31 +401,6 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) | |||
367 | memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); | 401 | memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); |
368 | #endif | 402 | #endif |
369 | 403 | ||
370 | BUG_ON(NULL == icd->current_fmt); | ||
371 | |||
372 | size = icd->user_height * bytes_per_line; | ||
373 | |||
374 | if (vb2_plane_size(vb, 0) < size) { | ||
375 | dev_err(icd->parent, "Buffer too small (%lu < %lu)\n", | ||
376 | vb2_plane_size(vb, 0), size); | ||
377 | return -ENOBUFS; | ||
378 | } | ||
379 | |||
380 | vb2_set_plane_payload(vb, 0, size); | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | ||
386 | { | ||
387 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | ||
388 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
389 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
390 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
391 | |||
392 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | ||
393 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | ||
394 | |||
395 | spin_lock_irq(&pcdev->lock); | 404 | spin_lock_irq(&pcdev->lock); |
396 | list_add_tail(&buf->queue, &pcdev->capture); | 405 | list_add_tail(&buf->queue, &pcdev->capture); |
397 | 406 | ||
@@ -405,6 +414,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | |||
405 | sh_mobile_ceu_capture(pcdev); | 414 | sh_mobile_ceu_capture(pcdev); |
406 | } | 415 | } |
407 | spin_unlock_irq(&pcdev->lock); | 416 | spin_unlock_irq(&pcdev->lock); |
417 | |||
418 | return; | ||
419 | |||
420 | error: | ||
421 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
408 | } | 422 | } |
409 | 423 | ||
410 | static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) | 424 | static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) |
@@ -429,11 +443,23 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) | |||
429 | if (buf->queue.next) | 443 | if (buf->queue.next) |
430 | list_del_init(&buf->queue); | 444 | list_del_init(&buf->queue); |
431 | 445 | ||
446 | pcdev->buf_total -= PAGE_ALIGN(vb2_plane_size(vb, 0)); | ||
447 | dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, | ||
448 | pcdev->buf_total); | ||
449 | |||
432 | spin_unlock_irq(&pcdev->lock); | 450 | spin_unlock_irq(&pcdev->lock); |
433 | } | 451 | } |
434 | 452 | ||
435 | static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) | 453 | static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) |
436 | { | 454 | { |
455 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | ||
456 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
457 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
458 | |||
459 | pcdev->buf_total += PAGE_ALIGN(vb2_plane_size(vb, 0)); | ||
460 | dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, | ||
461 | pcdev->buf_total); | ||
462 | |||
437 | /* This is for locking debugging only */ | 463 | /* This is for locking debugging only */ |
438 | INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); | 464 | INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); |
439 | return 0; | 465 | return 0; |
@@ -535,19 +561,29 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | |||
535 | 561 | ||
536 | pm_runtime_get_sync(ici->v4l2_dev.dev); | 562 | pm_runtime_get_sync(ici->v4l2_dev.dev); |
537 | 563 | ||
564 | pcdev->buf_total = 0; | ||
565 | |||
538 | ret = sh_mobile_ceu_soft_reset(pcdev); | 566 | ret = sh_mobile_ceu_soft_reset(pcdev); |
539 | 567 | ||
540 | csi2_sd = find_csi2(pcdev); | 568 | csi2_sd = find_csi2(pcdev); |
569 | if (csi2_sd) | ||
570 | csi2_sd->grp_id = (long)icd; | ||
541 | 571 | ||
542 | ret = v4l2_subdev_call(csi2_sd, core, s_power, 1); | 572 | ret = v4l2_subdev_call(csi2_sd, core, s_power, 1); |
543 | if (ret != -ENODEV && ret != -ENOIOCTLCMD && ret < 0) { | 573 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { |
544 | pm_runtime_put_sync(ici->v4l2_dev.dev); | 574 | pm_runtime_put_sync(ici->v4l2_dev.dev); |
545 | } else { | 575 | return ret; |
546 | pcdev->icd = icd; | ||
547 | ret = 0; | ||
548 | } | 576 | } |
549 | 577 | ||
550 | return ret; | 578 | /* |
579 | * -ENODEV is special: either csi2_sd == NULL or the CSI-2 driver | ||
580 | * has not found this soc-camera device among its clients | ||
581 | */ | ||
582 | if (ret == -ENODEV && csi2_sd) | ||
583 | csi2_sd->grp_id = 0; | ||
584 | pcdev->icd = icd; | ||
585 | |||
586 | return 0; | ||
551 | } | 587 | } |
552 | 588 | ||
553 | /* Called with .video_lock held */ | 589 | /* Called with .video_lock held */ |
@@ -560,6 +596,8 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) | |||
560 | BUG_ON(icd != pcdev->icd); | 596 | BUG_ON(icd != pcdev->icd); |
561 | 597 | ||
562 | v4l2_subdev_call(csi2_sd, core, s_power, 0); | 598 | v4l2_subdev_call(csi2_sd, core, s_power, 0); |
599 | if (csi2_sd) | ||
600 | csi2_sd->grp_id = 0; | ||
563 | /* disable capture, disable interrupts */ | 601 | /* disable capture, disable interrupts */ |
564 | ceu_write(pcdev, CEIER, 0); | 602 | ceu_write(pcdev, CEIER, 0); |
565 | sh_mobile_ceu_soft_reset(pcdev); | 603 | sh_mobile_ceu_soft_reset(pcdev); |
@@ -628,22 +666,22 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) | |||
628 | left_offset = cam->ceu_left; | 666 | left_offset = cam->ceu_left; |
629 | top_offset = cam->ceu_top; | 667 | top_offset = cam->ceu_top; |
630 | 668 | ||
631 | /* CEU cropping (CFSZR) is applied _after_ the scaling filter (CFLCR) */ | 669 | WARN_ON(icd->user_width & 3 || icd->user_height & 3); |
670 | |||
671 | width = icd->user_width; | ||
672 | |||
632 | if (pcdev->image_mode) { | 673 | if (pcdev->image_mode) { |
633 | in_width = cam->width; | 674 | in_width = cam->width; |
634 | if (!pcdev->is_16bit) { | 675 | if (!pcdev->is_16bit) { |
635 | in_width *= 2; | 676 | in_width *= 2; |
636 | left_offset *= 2; | 677 | left_offset *= 2; |
637 | } | 678 | } |
638 | width = icd->user_width; | 679 | cdwdr_width = width; |
639 | cdwdr_width = icd->user_width; | ||
640 | } else { | 680 | } else { |
641 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 681 | int bytes_per_line = soc_mbus_bytes_per_line(width, |
642 | icd->current_fmt->host_fmt); | 682 | icd->current_fmt->host_fmt); |
643 | unsigned int w_factor; | 683 | unsigned int w_factor; |
644 | 684 | ||
645 | width = icd->user_width; | ||
646 | |||
647 | switch (icd->current_fmt->host_fmt->packing) { | 685 | switch (icd->current_fmt->host_fmt->packing) { |
648 | case SOC_MBUS_PACKING_2X8_PADHI: | 686 | case SOC_MBUS_PACKING_2X8_PADHI: |
649 | w_factor = 2; | 687 | w_factor = 2; |
@@ -653,10 +691,10 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) | |||
653 | } | 691 | } |
654 | 692 | ||
655 | in_width = cam->width * w_factor; | 693 | in_width = cam->width * w_factor; |
656 | left_offset = left_offset * w_factor; | 694 | left_offset *= w_factor; |
657 | 695 | ||
658 | if (bytes_per_line < 0) | 696 | if (bytes_per_line < 0) |
659 | cdwdr_width = icd->user_width; | 697 | cdwdr_width = width; |
660 | else | 698 | else |
661 | cdwdr_width = bytes_per_line; | 699 | cdwdr_width = bytes_per_line; |
662 | } | 700 | } |
@@ -664,7 +702,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) | |||
664 | height = icd->user_height; | 702 | height = icd->user_height; |
665 | in_height = cam->height; | 703 | in_height = cam->height; |
666 | if (V4L2_FIELD_NONE != pcdev->field) { | 704 | if (V4L2_FIELD_NONE != pcdev->field) { |
667 | height /= 2; | 705 | height = (height / 2) & ~3; |
668 | in_height /= 2; | 706 | in_height /= 2; |
669 | top_offset /= 2; | 707 | top_offset /= 2; |
670 | cdwdr_width *= 2; | 708 | cdwdr_width *= 2; |
@@ -686,6 +724,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) | |||
686 | 724 | ||
687 | ceu_write(pcdev, CAMOR, camor); | 725 | ceu_write(pcdev, CAMOR, camor); |
688 | ceu_write(pcdev, CAPWR, (in_height << 16) | in_width); | 726 | ceu_write(pcdev, CAPWR, (in_height << 16) | in_width); |
727 | /* CFSZR clipping is applied _after_ the scaling filter (CFLCR) */ | ||
689 | ceu_write(pcdev, CFSZR, (height << 16) | width); | 728 | ceu_write(pcdev, CFSZR, (height << 16) | width); |
690 | ceu_write(pcdev, CDWDR, cdwdr_width); | 729 | ceu_write(pcdev, CDWDR, cdwdr_width); |
691 | } | 730 | } |
@@ -723,66 +762,93 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr) | |||
723 | ceu_write(pcdev, CAPSR, capsr); | 762 | ceu_write(pcdev, CAPSR, capsr); |
724 | } | 763 | } |
725 | 764 | ||
765 | /* Find the bus subdevice driver, e.g., CSI2 */ | ||
766 | static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev, | ||
767 | struct soc_camera_device *icd) | ||
768 | { | ||
769 | if (pcdev->csi2_pdev) { | ||
770 | struct v4l2_subdev *csi2_sd = find_csi2(pcdev); | ||
771 | if (csi2_sd && csi2_sd->grp_id == (u32)icd) | ||
772 | return csi2_sd; | ||
773 | } | ||
774 | |||
775 | return soc_camera_to_subdev(icd); | ||
776 | } | ||
777 | |||
778 | #define CEU_BUS_FLAGS (V4L2_MBUS_MASTER | \ | ||
779 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ | ||
780 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | ||
781 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ | ||
782 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | ||
783 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ | ||
784 | V4L2_MBUS_DATA_ACTIVE_HIGH) | ||
785 | |||
726 | /* Capture is not running, no interrupts, no locking needed */ | 786 | /* Capture is not running, no interrupts, no locking needed */ |
727 | static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | 787 | static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, |
728 | __u32 pixfmt) | 788 | __u32 pixfmt) |
729 | { | 789 | { |
730 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 790 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
731 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 791 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
732 | int ret; | 792 | struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); |
733 | unsigned long camera_flags, common_flags, value; | ||
734 | int yuv_lineskip; | ||
735 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 793 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
794 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
795 | unsigned long value, common_flags = CEU_BUS_FLAGS; | ||
736 | u32 capsr = capture_save_reset(pcdev); | 796 | u32 capsr = capture_save_reset(pcdev); |
797 | unsigned int yuv_lineskip; | ||
798 | int ret; | ||
737 | 799 | ||
738 | camera_flags = icd->ops->query_bus_param(icd); | 800 | /* |
739 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 801 | * If the client doesn't implement g_mbus_config, we just use our |
740 | make_bus_param(pcdev)); | 802 | * platform data |
741 | if (!common_flags) | 803 | */ |
742 | return -EINVAL; | 804 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
805 | if (!ret) { | ||
806 | common_flags = soc_mbus_config_compatible(&cfg, | ||
807 | common_flags); | ||
808 | if (!common_flags) | ||
809 | return -EINVAL; | ||
810 | } else if (ret != -ENOIOCTLCMD) { | ||
811 | return ret; | ||
812 | } | ||
743 | 813 | ||
744 | /* Make choises, based on platform preferences */ | 814 | /* Make choises, based on platform preferences */ |
745 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 815 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
746 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 816 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
747 | if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW) | 817 | if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW) |
748 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 818 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
749 | else | 819 | else |
750 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 820 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
751 | } | 821 | } |
752 | 822 | ||
753 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 823 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
754 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 824 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
755 | if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW) | 825 | if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW) |
756 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 826 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
757 | else | 827 | else |
758 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 828 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
759 | } | 829 | } |
760 | 830 | ||
761 | ret = icd->ops->set_bus_param(icd, common_flags); | 831 | cfg.flags = common_flags; |
762 | if (ret < 0) | 832 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
833 | if (ret < 0 && ret != -ENOIOCTLCMD) | ||
763 | return ret; | 834 | return ret; |
764 | 835 | ||
765 | switch (common_flags & SOCAM_DATAWIDTH_MASK) { | 836 | if (icd->current_fmt->host_fmt->bits_per_sample > 8) |
766 | case SOCAM_DATAWIDTH_8: | ||
767 | pcdev->is_16bit = 0; | ||
768 | break; | ||
769 | case SOCAM_DATAWIDTH_16: | ||
770 | pcdev->is_16bit = 1; | 837 | pcdev->is_16bit = 1; |
771 | break; | 838 | else |
772 | default: | 839 | pcdev->is_16bit = 0; |
773 | return -EINVAL; | ||
774 | } | ||
775 | 840 | ||
776 | ceu_write(pcdev, CRCNTR, 0); | 841 | ceu_write(pcdev, CRCNTR, 0); |
777 | ceu_write(pcdev, CRCMPR, 0); | 842 | ceu_write(pcdev, CRCMPR, 0); |
778 | 843 | ||
779 | value = 0x00000010; /* data fetch by default */ | 844 | value = 0x00000010; /* data fetch by default */ |
780 | yuv_lineskip = 0; | 845 | yuv_lineskip = 0x10; |
781 | 846 | ||
782 | switch (icd->current_fmt->host_fmt->fourcc) { | 847 | switch (icd->current_fmt->host_fmt->fourcc) { |
783 | case V4L2_PIX_FMT_NV12: | 848 | case V4L2_PIX_FMT_NV12: |
784 | case V4L2_PIX_FMT_NV21: | 849 | case V4L2_PIX_FMT_NV21: |
785 | yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */ | 850 | /* convert 4:2:2 -> 4:2:0 */ |
851 | yuv_lineskip = 0; /* skip for NV12/21, no skip for NV16/61 */ | ||
786 | /* fall-through */ | 852 | /* fall-through */ |
787 | case V4L2_PIX_FMT_NV16: | 853 | case V4L2_PIX_FMT_NV16: |
788 | case V4L2_PIX_FMT_NV61: | 854 | case V4L2_PIX_FMT_NV61: |
@@ -808,8 +874,8 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
808 | icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61) | 874 | icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61) |
809 | value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ | 875 | value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ |
810 | 876 | ||
811 | value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; | 877 | value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; |
812 | value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; | 878 | value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; |
813 | value |= pcdev->is_16bit ? 1 << 12 : 0; | 879 | value |= pcdev->is_16bit ? 1 << 12 : 0; |
814 | 880 | ||
815 | /* CSI2 mode */ | 881 | /* CSI2 mode */ |
@@ -852,9 +918,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
852 | * using 7 we swap the data bytes to match the incoming order: | 918 | * using 7 we swap the data bytes to match the incoming order: |
853 | * D0, D1, D2, D3, D4, D5, D6, D7 | 919 | * D0, D1, D2, D3, D4, D5, D6, D7 |
854 | */ | 920 | */ |
855 | value = 0x00000017; | 921 | value = 0x00000007 | yuv_lineskip; |
856 | if (yuv_lineskip) | ||
857 | value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */ | ||
858 | 922 | ||
859 | ceu_write(pcdev, CDOCR, value); | 923 | ceu_write(pcdev, CDOCR, value); |
860 | ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ | 924 | ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ |
@@ -875,13 +939,19 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, | |||
875 | { | 939 | { |
876 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 940 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
877 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 941 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
878 | unsigned long camera_flags, common_flags; | 942 | struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); |
943 | unsigned long common_flags = CEU_BUS_FLAGS; | ||
944 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
945 | int ret; | ||
879 | 946 | ||
880 | camera_flags = icd->ops->query_bus_param(icd); | 947 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
881 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 948 | if (!ret) |
882 | make_bus_param(pcdev)); | 949 | common_flags = soc_mbus_config_compatible(&cfg, |
883 | if (!common_flags || buswidth > 16 || | 950 | common_flags); |
884 | (buswidth > 8 && !(common_flags & SOCAM_DATAWIDTH_16))) | 951 | else if (ret != -ENOIOCTLCMD) |
952 | return ret; | ||
953 | |||
954 | if (!common_flags || buswidth > 16) | ||
885 | return -EINVAL; | 955 | return -EINVAL; |
886 | 956 | ||
887 | return 0; | 957 | return 0; |
@@ -891,26 +961,26 @@ static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = { | |||
891 | { | 961 | { |
892 | .fourcc = V4L2_PIX_FMT_NV12, | 962 | .fourcc = V4L2_PIX_FMT_NV12, |
893 | .name = "NV12", | 963 | .name = "NV12", |
894 | .bits_per_sample = 12, | 964 | .bits_per_sample = 8, |
895 | .packing = SOC_MBUS_PACKING_NONE, | 965 | .packing = SOC_MBUS_PACKING_1_5X8, |
896 | .order = SOC_MBUS_ORDER_LE, | 966 | .order = SOC_MBUS_ORDER_LE, |
897 | }, { | 967 | }, { |
898 | .fourcc = V4L2_PIX_FMT_NV21, | 968 | .fourcc = V4L2_PIX_FMT_NV21, |
899 | .name = "NV21", | 969 | .name = "NV21", |
900 | .bits_per_sample = 12, | 970 | .bits_per_sample = 8, |
901 | .packing = SOC_MBUS_PACKING_NONE, | 971 | .packing = SOC_MBUS_PACKING_1_5X8, |
902 | .order = SOC_MBUS_ORDER_LE, | 972 | .order = SOC_MBUS_ORDER_LE, |
903 | }, { | 973 | }, { |
904 | .fourcc = V4L2_PIX_FMT_NV16, | 974 | .fourcc = V4L2_PIX_FMT_NV16, |
905 | .name = "NV16", | 975 | .name = "NV16", |
906 | .bits_per_sample = 16, | 976 | .bits_per_sample = 8, |
907 | .packing = SOC_MBUS_PACKING_NONE, | 977 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
908 | .order = SOC_MBUS_ORDER_LE, | 978 | .order = SOC_MBUS_ORDER_LE, |
909 | }, { | 979 | }, { |
910 | .fourcc = V4L2_PIX_FMT_NV61, | 980 | .fourcc = V4L2_PIX_FMT_NV61, |
911 | .name = "NV61", | 981 | .name = "NV61", |
912 | .bits_per_sample = 16, | 982 | .bits_per_sample = 8, |
913 | .packing = SOC_MBUS_PACKING_NONE, | 983 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
914 | .order = SOC_MBUS_ORDER_LE, | 984 | .order = SOC_MBUS_ORDER_LE, |
915 | }, | 985 | }, |
916 | }; | 986 | }; |
@@ -920,6 +990,8 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) | |||
920 | { | 990 | { |
921 | return fmt->packing == SOC_MBUS_PACKING_NONE || | 991 | return fmt->packing == SOC_MBUS_PACKING_NONE || |
922 | (fmt->bits_per_sample == 8 && | 992 | (fmt->bits_per_sample == 8 && |
993 | fmt->packing == SOC_MBUS_PACKING_1_5X8) || | ||
994 | (fmt->bits_per_sample == 8 && | ||
923 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | 995 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || |
924 | (fmt->bits_per_sample > 8 && | 996 | (fmt->bits_per_sample > 8 && |
925 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | 997 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); |
@@ -927,6 +999,38 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) | |||
927 | 999 | ||
928 | static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); | 1000 | static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); |
929 | 1001 | ||
1002 | static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl) | ||
1003 | { | ||
1004 | return container_of(ctrl->handler, struct soc_camera_device, | ||
1005 | ctrl_handler); | ||
1006 | } | ||
1007 | |||
1008 | static int sh_mobile_ceu_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1009 | { | ||
1010 | struct soc_camera_device *icd = ctrl_to_icd(ctrl); | ||
1011 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1012 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1013 | |||
1014 | switch (ctrl->id) { | ||
1015 | case V4L2_CID_SHARPNESS: | ||
1016 | switch (icd->current_fmt->host_fmt->fourcc) { | ||
1017 | case V4L2_PIX_FMT_NV12: | ||
1018 | case V4L2_PIX_FMT_NV21: | ||
1019 | case V4L2_PIX_FMT_NV16: | ||
1020 | case V4L2_PIX_FMT_NV61: | ||
1021 | ceu_write(pcdev, CLFCR, !ctrl->val); | ||
1022 | return 0; | ||
1023 | } | ||
1024 | break; | ||
1025 | } | ||
1026 | |||
1027 | return -EINVAL; | ||
1028 | } | ||
1029 | |||
1030 | static const struct v4l2_ctrl_ops sh_mobile_ceu_ctrl_ops = { | ||
1031 | .s_ctrl = sh_mobile_ceu_s_ctrl, | ||
1032 | }; | ||
1033 | |||
930 | static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx, | 1034 | static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx, |
931 | struct soc_camera_format_xlate *xlate) | 1035 | struct soc_camera_format_xlate *xlate) |
932 | { | 1036 | { |
@@ -952,6 +1056,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int | |||
952 | } | 1056 | } |
953 | 1057 | ||
954 | if (!pcdev->pdata->csi2) { | 1058 | if (!pcdev->pdata->csi2) { |
1059 | /* Are there any restrictions in the CSI-2 case? */ | ||
955 | ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); | 1060 | ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); |
956 | if (ret < 0) | 1061 | if (ret < 0) |
957 | return 0; | 1062 | return 0; |
@@ -962,6 +1067,12 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int | |||
962 | struct v4l2_rect rect; | 1067 | struct v4l2_rect rect; |
963 | int shift = 0; | 1068 | int shift = 0; |
964 | 1069 | ||
1070 | /* Add our control */ | ||
1071 | v4l2_ctrl_new_std(&icd->ctrl_handler, &sh_mobile_ceu_ctrl_ops, | ||
1072 | V4L2_CID_SHARPNESS, 0, 1, 1, 0); | ||
1073 | if (icd->ctrl_handler.error) | ||
1074 | return icd->ctrl_handler.error; | ||
1075 | |||
965 | /* FIXME: subwindow is lost between close / open */ | 1076 | /* FIXME: subwindow is lost between close / open */ |
966 | 1077 | ||
967 | /* Cache current client geometry */ | 1078 | /* Cache current client geometry */ |
@@ -1004,9 +1115,6 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int | |||
1004 | cam->width = mf.width; | 1115 | cam->width = mf.width; |
1005 | cam->height = mf.height; | 1116 | cam->height = mf.height; |
1006 | 1117 | ||
1007 | cam->width = mf.width; | ||
1008 | cam->height = mf.height; | ||
1009 | |||
1010 | icd->host_priv = cam; | 1118 | icd->host_priv = cam; |
1011 | } else { | 1119 | } else { |
1012 | cam = icd->host_priv; | 1120 | cam = icd->host_priv; |
@@ -1278,6 +1386,7 @@ static int client_s_fmt(struct soc_camera_device *icd, | |||
1278 | unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; | 1386 | unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; |
1279 | unsigned int max_width, max_height; | 1387 | unsigned int max_width, max_height; |
1280 | struct v4l2_cropcap cap; | 1388 | struct v4l2_cropcap cap; |
1389 | bool ceu_1to1; | ||
1281 | int ret; | 1390 | int ret; |
1282 | 1391 | ||
1283 | ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, | 1392 | ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, |
@@ -1287,7 +1396,14 @@ static int client_s_fmt(struct soc_camera_device *icd, | |||
1287 | 1396 | ||
1288 | dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height); | 1397 | dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height); |
1289 | 1398 | ||
1290 | if ((width == mf->width && height == mf->height) || !ceu_can_scale) | 1399 | if (width == mf->width && height == mf->height) { |
1400 | /* Perfect! The client has done it all. */ | ||
1401 | ceu_1to1 = true; | ||
1402 | goto update_cache; | ||
1403 | } | ||
1404 | |||
1405 | ceu_1to1 = false; | ||
1406 | if (!ceu_can_scale) | ||
1291 | goto update_cache; | 1407 | goto update_cache; |
1292 | 1408 | ||
1293 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1409 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
@@ -1327,7 +1443,10 @@ update_cache: | |||
1327 | if (ret < 0) | 1443 | if (ret < 0) |
1328 | return ret; | 1444 | return ret; |
1329 | 1445 | ||
1330 | update_subrect(cam); | 1446 | if (ceu_1to1) |
1447 | cam->subrect = cam->rect; | ||
1448 | else | ||
1449 | update_subrect(cam); | ||
1331 | 1450 | ||
1332 | return 0; | 1451 | return 0; |
1333 | } | 1452 | } |
@@ -1414,7 +1533,10 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1414 | capsr = capture_save_reset(pcdev); | 1533 | capsr = capture_save_reset(pcdev); |
1415 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); | 1534 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); |
1416 | 1535 | ||
1417 | /* 1. - 2. Apply iterative camera S_CROP for new input window. */ | 1536 | /* |
1537 | * 1. - 2. Apply iterative camera S_CROP for new input window, read back | ||
1538 | * actual camera rectangle. | ||
1539 | */ | ||
1418 | ret = client_s_crop(icd, a, &cam_crop); | 1540 | ret = client_s_crop(icd, a, &cam_crop); |
1419 | if (ret < 0) | 1541 | if (ret < 0) |
1420 | return ret; | 1542 | return ret; |
@@ -1498,8 +1620,9 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
1498 | ceu_write(pcdev, CFLCR, cflcr); | 1620 | ceu_write(pcdev, CFLCR, cflcr); |
1499 | } | 1621 | } |
1500 | 1622 | ||
1501 | icd->user_width = out_width; | 1623 | icd->user_width = out_width & ~3; |
1502 | icd->user_height = out_height; | 1624 | icd->user_height = out_height & ~3; |
1625 | /* Offsets are applied at the CEU scaling filter input */ | ||
1503 | cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1; | 1626 | cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1; |
1504 | cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1; | 1627 | cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1; |
1505 | 1628 | ||
@@ -1538,7 +1661,7 @@ static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd, | |||
1538 | * CEU crop, mapped backed onto the client input (subrect). | 1661 | * CEU crop, mapped backed onto the client input (subrect). |
1539 | */ | 1662 | */ |
1540 | static void calculate_client_output(struct soc_camera_device *icd, | 1663 | static void calculate_client_output(struct soc_camera_device *icd, |
1541 | struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf) | 1664 | const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf) |
1542 | { | 1665 | { |
1543 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 1666 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
1544 | struct device *dev = icd->parent; | 1667 | struct device *dev = icd->parent; |
@@ -1574,8 +1697,8 @@ static void calculate_client_output(struct soc_camera_device *icd, | |||
1574 | dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v); | 1697 | dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v); |
1575 | 1698 | ||
1576 | /* | 1699 | /* |
1577 | * 4. Calculate client output window by applying combined scales to real | 1700 | * 4. Calculate desired client output window by applying combined scales |
1578 | * input window. | 1701 | * to client (real) input window. |
1579 | */ | 1702 | */ |
1580 | mf->width = scale_down(cam->rect.width, scale_h); | 1703 | mf->width = scale_down(cam->rect.width, scale_h); |
1581 | mf->height = scale_down(cam->rect.height, scale_v); | 1704 | mf->height = scale_down(cam->rect.height, scale_v); |
@@ -1600,8 +1723,6 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1600 | bool image_mode; | 1723 | bool image_mode; |
1601 | enum v4l2_field field; | 1724 | enum v4l2_field field; |
1602 | 1725 | ||
1603 | dev_geo(dev, "S_FMT(pix=0x%x, %ux%u)\n", pixfmt, pix->width, pix->height); | ||
1604 | |||
1605 | switch (pix->field) { | 1726 | switch (pix->field) { |
1606 | default: | 1727 | default: |
1607 | pix->field = V4L2_FIELD_NONE; | 1728 | pix->field = V4L2_FIELD_NONE; |
@@ -1622,8 +1743,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1622 | return -EINVAL; | 1743 | return -EINVAL; |
1623 | } | 1744 | } |
1624 | 1745 | ||
1625 | /* 1.-4. Calculate client output geometry */ | 1746 | /* 1.-4. Calculate desired client output geometry */ |
1626 | calculate_client_output(icd, &f->fmt.pix, &mf); | 1747 | calculate_client_output(icd, pix, &mf); |
1627 | mf.field = pix->field; | 1748 | mf.field = pix->field; |
1628 | mf.colorspace = pix->colorspace; | 1749 | mf.colorspace = pix->colorspace; |
1629 | mf.code = xlate->code; | 1750 | mf.code = xlate->code; |
@@ -1639,6 +1760,9 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1639 | image_mode = false; | 1760 | image_mode = false; |
1640 | } | 1761 | } |
1641 | 1762 | ||
1763 | dev_geo(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, | ||
1764 | pix->width, pix->height); | ||
1765 | |||
1642 | dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); | 1766 | dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); |
1643 | 1767 | ||
1644 | /* 5. - 9. */ | 1768 | /* 5. - 9. */ |
@@ -1700,6 +1824,10 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1700 | pcdev->field = field; | 1824 | pcdev->field = field; |
1701 | pcdev->image_mode = image_mode; | 1825 | pcdev->image_mode = image_mode; |
1702 | 1826 | ||
1827 | /* CFSZR requirement */ | ||
1828 | pix->width &= ~3; | ||
1829 | pix->height &= ~3; | ||
1830 | |||
1703 | return 0; | 1831 | return 0; |
1704 | } | 1832 | } |
1705 | 1833 | ||
@@ -1725,7 +1853,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1725 | 1853 | ||
1726 | /* FIXME: calculate using depth and bus width */ | 1854 | /* FIXME: calculate using depth and bus width */ |
1727 | 1855 | ||
1728 | v4l_bound_align_image(&pix->width, 2, 2560, 1, | 1856 | /* CFSZR requires height and width to be 4-pixel aligned */ |
1857 | v4l_bound_align_image(&pix->width, 2, 2560, 2, | ||
1729 | &pix->height, 4, 1920, 2, 0); | 1858 | &pix->height, 4, 1920, 2, 0); |
1730 | 1859 | ||
1731 | width = pix->width; | 1860 | width = pix->width; |
@@ -1778,6 +1907,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
1778 | pix->height = height; | 1907 | pix->height = height; |
1779 | } | 1908 | } |
1780 | 1909 | ||
1910 | pix->width &= ~3; | ||
1911 | pix->height &= ~3; | ||
1912 | |||
1781 | dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n", | 1913 | dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n", |
1782 | __func__, ret, pix->pixelformat, pix->width, pix->height); | 1914 | __func__, ret, pix->pixelformat, pix->width, pix->height); |
1783 | 1915 | ||
@@ -1824,8 +1956,8 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, | |||
1824 | out_height != f.fmt.pix.height)) | 1956 | out_height != f.fmt.pix.height)) |
1825 | ret = -EINVAL; | 1957 | ret = -EINVAL; |
1826 | if (!ret) { | 1958 | if (!ret) { |
1827 | icd->user_width = out_width; | 1959 | icd->user_width = out_width & ~3; |
1828 | icd->user_height = out_height; | 1960 | icd->user_height = out_height & ~3; |
1829 | ret = sh_mobile_ceu_set_bus_param(icd, | 1961 | ret = sh_mobile_ceu_set_bus_param(icd, |
1830 | icd->current_fmt->host_fmt->fourcc); | 1962 | icd->current_fmt->host_fmt->fourcc); |
1831 | } | 1963 | } |
@@ -1869,55 +2001,6 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, | |||
1869 | return vb2_queue_init(q); | 2001 | return vb2_queue_init(q); |
1870 | } | 2002 | } |
1871 | 2003 | ||
1872 | static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd, | ||
1873 | struct v4l2_control *ctrl) | ||
1874 | { | ||
1875 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1876 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1877 | u32 val; | ||
1878 | |||
1879 | switch (ctrl->id) { | ||
1880 | case V4L2_CID_SHARPNESS: | ||
1881 | val = ceu_read(pcdev, CLFCR); | ||
1882 | ctrl->value = val ^ 1; | ||
1883 | return 0; | ||
1884 | } | ||
1885 | return -ENOIOCTLCMD; | ||
1886 | } | ||
1887 | |||
1888 | static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd, | ||
1889 | struct v4l2_control *ctrl) | ||
1890 | { | ||
1891 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1892 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
1893 | |||
1894 | switch (ctrl->id) { | ||
1895 | case V4L2_CID_SHARPNESS: | ||
1896 | switch (icd->current_fmt->host_fmt->fourcc) { | ||
1897 | case V4L2_PIX_FMT_NV12: | ||
1898 | case V4L2_PIX_FMT_NV21: | ||
1899 | case V4L2_PIX_FMT_NV16: | ||
1900 | case V4L2_PIX_FMT_NV61: | ||
1901 | ceu_write(pcdev, CLFCR, !ctrl->value); | ||
1902 | return 0; | ||
1903 | } | ||
1904 | return -EINVAL; | ||
1905 | } | ||
1906 | return -ENOIOCTLCMD; | ||
1907 | } | ||
1908 | |||
1909 | static const struct v4l2_queryctrl sh_mobile_ceu_controls[] = { | ||
1910 | { | ||
1911 | .id = V4L2_CID_SHARPNESS, | ||
1912 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
1913 | .name = "Low-pass filter", | ||
1914 | .minimum = 0, | ||
1915 | .maximum = 1, | ||
1916 | .step = 1, | ||
1917 | .default_value = 0, | ||
1918 | }, | ||
1919 | }; | ||
1920 | |||
1921 | static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { | 2004 | static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { |
1922 | .owner = THIS_MODULE, | 2005 | .owner = THIS_MODULE, |
1923 | .add = sh_mobile_ceu_add_device, | 2006 | .add = sh_mobile_ceu_add_device, |
@@ -1929,14 +2012,10 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { | |||
1929 | .set_livecrop = sh_mobile_ceu_set_livecrop, | 2012 | .set_livecrop = sh_mobile_ceu_set_livecrop, |
1930 | .set_fmt = sh_mobile_ceu_set_fmt, | 2013 | .set_fmt = sh_mobile_ceu_set_fmt, |
1931 | .try_fmt = sh_mobile_ceu_try_fmt, | 2014 | .try_fmt = sh_mobile_ceu_try_fmt, |
1932 | .set_ctrl = sh_mobile_ceu_set_ctrl, | ||
1933 | .get_ctrl = sh_mobile_ceu_get_ctrl, | ||
1934 | .poll = sh_mobile_ceu_poll, | 2015 | .poll = sh_mobile_ceu_poll, |
1935 | .querycap = sh_mobile_ceu_querycap, | 2016 | .querycap = sh_mobile_ceu_querycap, |
1936 | .set_bus_param = sh_mobile_ceu_set_bus_param, | 2017 | .set_bus_param = sh_mobile_ceu_set_bus_param, |
1937 | .init_videobuf2 = sh_mobile_ceu_init_videobuf, | 2018 | .init_videobuf2 = sh_mobile_ceu_init_videobuf, |
1938 | .controls = sh_mobile_ceu_controls, | ||
1939 | .num_controls = ARRAY_SIZE(sh_mobile_ceu_controls), | ||
1940 | }; | 2019 | }; |
1941 | 2020 | ||
1942 | struct bus_wait { | 2021 | struct bus_wait { |
diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 2893a0134c7e..37706eb81f25 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <media/sh_mobile_ceu.h> | 19 | #include <media/sh_mobile_ceu.h> |
20 | #include <media/sh_mobile_csi2.h> | 20 | #include <media/sh_mobile_csi2.h> |
21 | #include <media/soc_camera.h> | 21 | #include <media/soc_camera.h> |
22 | #include <media/soc_mediabus.h> | ||
22 | #include <media/v4l2-common.h> | 23 | #include <media/v4l2-common.h> |
23 | #include <media/v4l2-dev.h> | 24 | #include <media/v4l2-dev.h> |
24 | #include <media/v4l2-device.h> | 25 | #include <media/v4l2-device.h> |
@@ -35,11 +36,10 @@ struct sh_csi2 { | |||
35 | struct v4l2_subdev subdev; | 36 | struct v4l2_subdev subdev; |
36 | struct list_head list; | 37 | struct list_head list; |
37 | unsigned int irq; | 38 | unsigned int irq; |
39 | unsigned long mipi_flags; | ||
38 | void __iomem *base; | 40 | void __iomem *base; |
39 | struct platform_device *pdev; | 41 | struct platform_device *pdev; |
40 | struct sh_csi2_client_config *client; | 42 | struct sh_csi2_client_config *client; |
41 | unsigned long (*query_bus_param)(struct soc_camera_device *); | ||
42 | int (*set_bus_param)(struct soc_camera_device *, unsigned long); | ||
43 | }; | 43 | }; |
44 | 44 | ||
45 | static int sh_csi2_try_fmt(struct v4l2_subdev *sd, | 45 | static int sh_csi2_try_fmt(struct v4l2_subdev *sd, |
@@ -127,9 +127,34 @@ static int sh_csi2_s_fmt(struct v4l2_subdev *sd, | |||
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | static int sh_csi2_g_mbus_config(struct v4l2_subdev *sd, | ||
131 | struct v4l2_mbus_config *cfg) | ||
132 | { | ||
133 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
134 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
135 | V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
136 | cfg->type = V4L2_MBUS_PARALLEL; | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd, | ||
142 | const struct v4l2_mbus_config *cfg) | ||
143 | { | ||
144 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
145 | struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; | ||
146 | struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); | ||
147 | struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2, | ||
148 | .flags = priv->mipi_flags}; | ||
149 | |||
150 | return v4l2_subdev_call(client_sd, video, s_mbus_config, &client_cfg); | ||
151 | } | ||
152 | |||
130 | static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { | 153 | static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { |
131 | .s_mbus_fmt = sh_csi2_s_fmt, | 154 | .s_mbus_fmt = sh_csi2_s_fmt, |
132 | .try_mbus_fmt = sh_csi2_try_fmt, | 155 | .try_mbus_fmt = sh_csi2_try_fmt, |
156 | .g_mbus_config = sh_csi2_g_mbus_config, | ||
157 | .s_mbus_config = sh_csi2_s_mbus_config, | ||
133 | }; | 158 | }; |
134 | 159 | ||
135 | static void sh_csi2_hwinit(struct sh_csi2 *priv) | 160 | static void sh_csi2_hwinit(struct sh_csi2 *priv) |
@@ -144,11 +169,21 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv) | |||
144 | udelay(5); | 169 | udelay(5); |
145 | iowrite32(0x00000000, priv->base + SH_CSI2_SRST); | 170 | iowrite32(0x00000000, priv->base + SH_CSI2_SRST); |
146 | 171 | ||
147 | if (priv->client->lanes & 3) | 172 | switch (pdata->type) { |
148 | tmp |= priv->client->lanes & 3; | 173 | case SH_CSI2C: |
149 | else | 174 | if (priv->client->lanes == 1) |
150 | /* Default - both lanes */ | 175 | tmp |= 1; |
151 | tmp |= 3; | 176 | else |
177 | /* Default - both lanes */ | ||
178 | tmp |= 3; | ||
179 | break; | ||
180 | case SH_CSI2I: | ||
181 | if (!priv->client->lanes || priv->client->lanes > 4) | ||
182 | /* Default - all 4 lanes */ | ||
183 | tmp |= 0xf; | ||
184 | else | ||
185 | tmp |= (1 << priv->client->lanes) - 1; | ||
186 | } | ||
152 | 187 | ||
153 | if (priv->client->phy == SH_CSI2_PHY_MAIN) | 188 | if (priv->client->phy == SH_CSI2_PHY_MAIN) |
154 | tmp |= 0x8000; | 189 | tmp |= 0x8000; |
@@ -163,38 +198,18 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv) | |||
163 | iowrite32(tmp, priv->base + SH_CSI2_CHKSUM); | 198 | iowrite32(tmp, priv->base + SH_CSI2_CHKSUM); |
164 | } | 199 | } |
165 | 200 | ||
166 | static int sh_csi2_set_bus_param(struct soc_camera_device *icd, | ||
167 | unsigned long flags) | ||
168 | { | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd) | ||
173 | { | ||
174 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
175 | const unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | | ||
176 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | ||
177 | SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH; | ||
178 | |||
179 | return soc_camera_apply_sensor_flags(icl, flags); | ||
180 | } | ||
181 | |||
182 | static int sh_csi2_client_connect(struct sh_csi2 *priv) | 201 | static int sh_csi2_client_connect(struct sh_csi2 *priv) |
183 | { | 202 | { |
184 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | 203 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; |
185 | struct v4l2_subdev *sd, *csi2_sd = &priv->subdev; | 204 | struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id; |
186 | struct soc_camera_device *icd = NULL; | 205 | struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); |
187 | struct device *dev = v4l2_get_subdevdata(&priv->subdev); | 206 | struct device *dev = v4l2_get_subdevdata(&priv->subdev); |
188 | int i; | 207 | struct v4l2_mbus_config cfg; |
208 | unsigned long common_flags, csi2_flags; | ||
209 | int i, ret; | ||
189 | 210 | ||
190 | v4l2_device_for_each_subdev(sd, csi2_sd->v4l2_dev) | 211 | if (priv->client) |
191 | if (sd->grp_id) { | 212 | return -EBUSY; |
192 | icd = (struct soc_camera_device *)sd->grp_id; | ||
193 | break; | ||
194 | } | ||
195 | |||
196 | if (!icd) | ||
197 | return -EINVAL; | ||
198 | 213 | ||
199 | for (i = 0; i < pdata->num_clients; i++) | 214 | for (i = 0; i < pdata->num_clients; i++) |
200 | if (&pdata->clients[i].pdev->dev == icd->pdev) | 215 | if (&pdata->clients[i].pdev->dev == icd->pdev) |
@@ -205,14 +220,41 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) | |||
205 | if (i == pdata->num_clients) | 220 | if (i == pdata->num_clients) |
206 | return -ENODEV; | 221 | return -ENODEV; |
207 | 222 | ||
208 | priv->client = pdata->clients + i; | 223 | /* Check if we can support this camera */ |
224 | csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_1_LANE; | ||
225 | |||
226 | switch (pdata->type) { | ||
227 | case SH_CSI2C: | ||
228 | if (pdata->clients[i].lanes != 1) | ||
229 | csi2_flags |= V4L2_MBUS_CSI2_2_LANE; | ||
230 | break; | ||
231 | case SH_CSI2I: | ||
232 | switch (pdata->clients[i].lanes) { | ||
233 | default: | ||
234 | csi2_flags |= V4L2_MBUS_CSI2_4_LANE; | ||
235 | case 3: | ||
236 | csi2_flags |= V4L2_MBUS_CSI2_3_LANE; | ||
237 | case 2: | ||
238 | csi2_flags |= V4L2_MBUS_CSI2_2_LANE; | ||
239 | } | ||
240 | } | ||
209 | 241 | ||
210 | priv->set_bus_param = icd->ops->set_bus_param; | 242 | cfg.type = V4L2_MBUS_CSI2; |
211 | priv->query_bus_param = icd->ops->query_bus_param; | 243 | ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &cfg); |
212 | icd->ops->set_bus_param = sh_csi2_set_bus_param; | 244 | if (ret == -ENOIOCTLCMD) |
213 | icd->ops->query_bus_param = sh_csi2_query_bus_param; | 245 | common_flags = csi2_flags; |
246 | else if (!ret) | ||
247 | common_flags = soc_mbus_config_compatible(&cfg, | ||
248 | csi2_flags); | ||
249 | else | ||
250 | common_flags = 0; | ||
214 | 251 | ||
215 | csi2_sd->grp_id = (long)icd; | 252 | if (!common_flags) |
253 | return -EINVAL; | ||
254 | |||
255 | /* All good: camera MIPI configuration supported */ | ||
256 | priv->mipi_flags = common_flags; | ||
257 | priv->client = pdata->clients + i; | ||
216 | 258 | ||
217 | pm_runtime_get_sync(dev); | 259 | pm_runtime_get_sync(dev); |
218 | 260 | ||
@@ -223,16 +265,10 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) | |||
223 | 265 | ||
224 | static void sh_csi2_client_disconnect(struct sh_csi2 *priv) | 266 | static void sh_csi2_client_disconnect(struct sh_csi2 *priv) |
225 | { | 267 | { |
226 | struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id; | 268 | if (!priv->client) |
269 | return; | ||
227 | 270 | ||
228 | priv->client = NULL; | 271 | priv->client = NULL; |
229 | priv->subdev.grp_id = 0; | ||
230 | |||
231 | /* Driver is about to be unbound */ | ||
232 | icd->ops->set_bus_param = priv->set_bus_param; | ||
233 | icd->ops->query_bus_param = priv->query_bus_param; | ||
234 | priv->set_bus_param = NULL; | ||
235 | priv->query_bus_param = NULL; | ||
236 | 272 | ||
237 | pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); | 273 | pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); |
238 | } | 274 | } |
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 5bdfe7e16bc1..b72580c38957 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
@@ -50,49 +50,65 @@ static LIST_HEAD(hosts); | |||
50 | static LIST_HEAD(devices); | 50 | static LIST_HEAD(devices); |
51 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ | 51 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ |
52 | 52 | ||
53 | static int soc_camera_power_set(struct soc_camera_device *icd, | 53 | static int soc_camera_power_on(struct soc_camera_device *icd, |
54 | struct soc_camera_link *icl, | 54 | struct soc_camera_link *icl) |
55 | int power_on) | ||
56 | { | 55 | { |
57 | int ret; | 56 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
58 | 57 | int ret = regulator_bulk_enable(icl->num_regulators, | |
59 | if (power_on) { | 58 | icl->regulators); |
60 | ret = regulator_bulk_enable(icl->num_regulators, | 59 | if (ret < 0) { |
61 | icl->regulators); | 60 | dev_err(icd->pdev, "Cannot enable regulators\n"); |
62 | if (ret < 0) { | 61 | return ret; |
63 | dev_err(icd->pdev, "Cannot enable regulators\n"); | 62 | } |
64 | return ret; | ||
65 | } | ||
66 | 63 | ||
67 | if (icl->power) | 64 | if (icl->power) { |
68 | ret = icl->power(icd->pdev, power_on); | 65 | ret = icl->power(icd->pdev, 1); |
69 | if (ret < 0) { | 66 | if (ret < 0) { |
70 | dev_err(icd->pdev, | 67 | dev_err(icd->pdev, |
71 | "Platform failed to power-on the camera.\n"); | 68 | "Platform failed to power-on the camera.\n"); |
72 | 69 | goto elinkpwr; | |
73 | regulator_bulk_disable(icl->num_regulators, | ||
74 | icl->regulators); | ||
75 | return ret; | ||
76 | } | 70 | } |
77 | } else { | 71 | } |
78 | ret = 0; | 72 | |
79 | if (icl->power) | 73 | ret = v4l2_subdev_call(sd, core, s_power, 1); |
80 | ret = icl->power(icd->pdev, 0); | 74 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) |
75 | goto esdpwr; | ||
76 | |||
77 | return 0; | ||
78 | |||
79 | esdpwr: | ||
80 | if (icl->power) | ||
81 | icl->power(icd->pdev, 0); | ||
82 | elinkpwr: | ||
83 | regulator_bulk_disable(icl->num_regulators, | ||
84 | icl->regulators); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | static int soc_camera_power_off(struct soc_camera_device *icd, | ||
89 | struct soc_camera_link *icl) | ||
90 | { | ||
91 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
92 | int ret = v4l2_subdev_call(sd, core, s_power, 0); | ||
93 | |||
94 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | ||
95 | return ret; | ||
96 | |||
97 | if (icl->power) { | ||
98 | ret = icl->power(icd->pdev, 0); | ||
81 | if (ret < 0) { | 99 | if (ret < 0) { |
82 | dev_err(icd->pdev, | 100 | dev_err(icd->pdev, |
83 | "Platform failed to power-off the camera.\n"); | 101 | "Platform failed to power-off the camera.\n"); |
84 | return ret; | 102 | return ret; |
85 | } | 103 | } |
86 | |||
87 | ret = regulator_bulk_disable(icl->num_regulators, | ||
88 | icl->regulators); | ||
89 | if (ret < 0) { | ||
90 | dev_err(icd->pdev, "Cannot disable regulators\n"); | ||
91 | return ret; | ||
92 | } | ||
93 | } | 104 | } |
94 | 105 | ||
95 | return 0; | 106 | ret = regulator_bulk_disable(icl->num_regulators, |
107 | icl->regulators); | ||
108 | if (ret < 0) | ||
109 | dev_err(icd->pdev, "Cannot disable regulators\n"); | ||
110 | |||
111 | return ret; | ||
96 | } | 112 | } |
97 | 113 | ||
98 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( | 114 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( |
@@ -108,38 +124,38 @@ const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( | |||
108 | EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); | 124 | EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); |
109 | 125 | ||
110 | /** | 126 | /** |
111 | * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags | 127 | * soc_camera_apply_board_flags() - apply platform SOCAM_SENSOR_INVERT_* flags |
112 | * @icl: camera platform parameters | 128 | * @icl: camera platform parameters |
113 | * @flags: flags to be inverted according to platform configuration | 129 | * @cfg: media bus configuration |
114 | * @return: resulting flags | 130 | * @return: resulting flags |
115 | */ | 131 | */ |
116 | unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, | 132 | unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, |
117 | unsigned long flags) | 133 | const struct v4l2_mbus_config *cfg) |
118 | { | 134 | { |
119 | unsigned long f; | 135 | unsigned long f, flags = cfg->flags; |
120 | 136 | ||
121 | /* If only one of the two polarities is supported, switch to the opposite */ | 137 | /* If only one of the two polarities is supported, switch to the opposite */ |
122 | if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) { | 138 | if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) { |
123 | f = flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW); | 139 | f = flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW); |
124 | if (f == SOCAM_HSYNC_ACTIVE_HIGH || f == SOCAM_HSYNC_ACTIVE_LOW) | 140 | if (f == V4L2_MBUS_HSYNC_ACTIVE_HIGH || f == V4L2_MBUS_HSYNC_ACTIVE_LOW) |
125 | flags ^= SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW; | 141 | flags ^= V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW; |
126 | } | 142 | } |
127 | 143 | ||
128 | if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) { | 144 | if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) { |
129 | f = flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW); | 145 | f = flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW); |
130 | if (f == SOCAM_VSYNC_ACTIVE_HIGH || f == SOCAM_VSYNC_ACTIVE_LOW) | 146 | if (f == V4L2_MBUS_VSYNC_ACTIVE_HIGH || f == V4L2_MBUS_VSYNC_ACTIVE_LOW) |
131 | flags ^= SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW; | 147 | flags ^= V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW; |
132 | } | 148 | } |
133 | 149 | ||
134 | if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) { | 150 | if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) { |
135 | f = flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING); | 151 | f = flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING); |
136 | if (f == SOCAM_PCLK_SAMPLE_RISING || f == SOCAM_PCLK_SAMPLE_FALLING) | 152 | if (f == V4L2_MBUS_PCLK_SAMPLE_RISING || f == V4L2_MBUS_PCLK_SAMPLE_FALLING) |
137 | flags ^= SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING; | 153 | flags ^= V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; |
138 | } | 154 | } |
139 | 155 | ||
140 | return flags; | 156 | return flags; |
141 | } | 157 | } |
142 | EXPORT_SYMBOL(soc_camera_apply_sensor_flags); | 158 | EXPORT_SYMBOL(soc_camera_apply_board_flags); |
143 | 159 | ||
144 | #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ | 160 | #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ |
145 | ((x) >> 24) & 0xff | 161 | ((x) >> 24) & 0xff |
@@ -233,6 +249,14 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) | |||
233 | return v4l2_subdev_call(sd, core, s_std, *a); | 249 | return v4l2_subdev_call(sd, core, s_std, *a); |
234 | } | 250 | } |
235 | 251 | ||
252 | static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a) | ||
253 | { | ||
254 | struct soc_camera_device *icd = file->private_data; | ||
255 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
256 | |||
257 | return v4l2_subdev_call(sd, core, g_std, a); | ||
258 | } | ||
259 | |||
236 | static int soc_camera_enum_fsizes(struct file *file, void *fh, | 260 | static int soc_camera_enum_fsizes(struct file *file, void *fh, |
237 | struct v4l2_frmsizeenum *fsize) | 261 | struct v4l2_frmsizeenum *fsize) |
238 | { | 262 | { |
@@ -318,6 +342,32 @@ static int soc_camera_dqbuf(struct file *file, void *priv, | |||
318 | return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); | 342 | return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); |
319 | } | 343 | } |
320 | 344 | ||
345 | static int soc_camera_create_bufs(struct file *file, void *priv, | ||
346 | struct v4l2_create_buffers *create) | ||
347 | { | ||
348 | struct soc_camera_device *icd = file->private_data; | ||
349 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
350 | |||
351 | /* videobuf2 only */ | ||
352 | if (ici->ops->init_videobuf) | ||
353 | return -EINVAL; | ||
354 | else | ||
355 | return vb2_create_bufs(&icd->vb2_vidq, create); | ||
356 | } | ||
357 | |||
358 | static int soc_camera_prepare_buf(struct file *file, void *priv, | ||
359 | struct v4l2_buffer *b) | ||
360 | { | ||
361 | struct soc_camera_device *icd = file->private_data; | ||
362 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
363 | |||
364 | /* videobuf2 only */ | ||
365 | if (ici->ops->init_videobuf) | ||
366 | return -EINVAL; | ||
367 | else | ||
368 | return vb2_prepare_buf(&icd->vb2_vidq, b); | ||
369 | } | ||
370 | |||
321 | /* Always entered with .video_lock held */ | 371 | /* Always entered with .video_lock held */ |
322 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) | 372 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) |
323 | { | 373 | { |
@@ -448,7 +498,7 @@ static int soc_camera_open(struct file *file) | |||
448 | struct soc_camera_host *ici; | 498 | struct soc_camera_host *ici; |
449 | int ret; | 499 | int ret; |
450 | 500 | ||
451 | if (!icd->ops) | 501 | if (!to_soc_camera_control(icd)) |
452 | /* No device driver attached */ | 502 | /* No device driver attached */ |
453 | return -ENODEV; | 503 | return -ENODEV; |
454 | 504 | ||
@@ -476,7 +526,7 @@ static int soc_camera_open(struct file *file) | |||
476 | }, | 526 | }, |
477 | }; | 527 | }; |
478 | 528 | ||
479 | ret = soc_camera_power_set(icd, icl, 1); | 529 | ret = soc_camera_power_on(icd, icl); |
480 | if (ret < 0) | 530 | if (ret < 0) |
481 | goto epower; | 531 | goto epower; |
482 | 532 | ||
@@ -512,6 +562,7 @@ static int soc_camera_open(struct file *file) | |||
512 | if (ret < 0) | 562 | if (ret < 0) |
513 | goto einitvb; | 563 | goto einitvb; |
514 | } | 564 | } |
565 | v4l2_ctrl_handler_setup(&icd->ctrl_handler); | ||
515 | } | 566 | } |
516 | 567 | ||
517 | file->private_data = icd; | 568 | file->private_data = icd; |
@@ -529,7 +580,7 @@ esfmt: | |||
529 | eresume: | 580 | eresume: |
530 | ici->ops->remove(icd); | 581 | ici->ops->remove(icd); |
531 | eiciadd: | 582 | eiciadd: |
532 | soc_camera_power_set(icd, icl, 0); | 583 | soc_camera_power_off(icd, icl); |
533 | epower: | 584 | epower: |
534 | icd->use_count--; | 585 | icd->use_count--; |
535 | module_put(ici->ops->owner); | 586 | module_put(ici->ops->owner); |
@@ -553,7 +604,7 @@ static int soc_camera_close(struct file *file) | |||
553 | if (ici->ops->init_videobuf2) | 604 | if (ici->ops->init_videobuf2) |
554 | vb2_queue_release(&icd->vb2_vidq); | 605 | vb2_queue_release(&icd->vb2_vidq); |
555 | 606 | ||
556 | soc_camera_power_set(icd, icl, 0); | 607 | soc_camera_power_off(icd, icl); |
557 | } | 608 | } |
558 | 609 | ||
559 | if (icd->streamer == file) | 610 | if (icd->streamer == file) |
@@ -781,75 +832,6 @@ static int soc_camera_streamoff(struct file *file, void *priv, | |||
781 | return 0; | 832 | return 0; |
782 | } | 833 | } |
783 | 834 | ||
784 | static int soc_camera_queryctrl(struct file *file, void *priv, | ||
785 | struct v4l2_queryctrl *qc) | ||
786 | { | ||
787 | struct soc_camera_device *icd = file->private_data; | ||
788 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
789 | int i; | ||
790 | |||
791 | WARN_ON(priv != file->private_data); | ||
792 | |||
793 | if (!qc->id) | ||
794 | return -EINVAL; | ||
795 | |||
796 | /* First check host controls */ | ||
797 | for (i = 0; i < ici->ops->num_controls; i++) | ||
798 | if (qc->id == ici->ops->controls[i].id) { | ||
799 | memcpy(qc, &(ici->ops->controls[i]), | ||
800 | sizeof(*qc)); | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | /* Then device controls */ | ||
805 | for (i = 0; i < icd->ops->num_controls; i++) | ||
806 | if (qc->id == icd->ops->controls[i].id) { | ||
807 | memcpy(qc, &(icd->ops->controls[i]), | ||
808 | sizeof(*qc)); | ||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | return -EINVAL; | ||
813 | } | ||
814 | |||
815 | static int soc_camera_g_ctrl(struct file *file, void *priv, | ||
816 | struct v4l2_control *ctrl) | ||
817 | { | ||
818 | struct soc_camera_device *icd = file->private_data; | ||
819 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
820 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
821 | int ret; | ||
822 | |||
823 | WARN_ON(priv != file->private_data); | ||
824 | |||
825 | if (ici->ops->get_ctrl) { | ||
826 | ret = ici->ops->get_ctrl(icd, ctrl); | ||
827 | if (ret != -ENOIOCTLCMD) | ||
828 | return ret; | ||
829 | } | ||
830 | |||
831 | return v4l2_subdev_call(sd, core, g_ctrl, ctrl); | ||
832 | } | ||
833 | |||
834 | static int soc_camera_s_ctrl(struct file *file, void *priv, | ||
835 | struct v4l2_control *ctrl) | ||
836 | { | ||
837 | struct soc_camera_device *icd = file->private_data; | ||
838 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
839 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
840 | int ret; | ||
841 | |||
842 | WARN_ON(priv != file->private_data); | ||
843 | |||
844 | if (ici->ops->set_ctrl) { | ||
845 | ret = ici->ops->set_ctrl(icd, ctrl); | ||
846 | if (ret != -ENOIOCTLCMD) | ||
847 | return ret; | ||
848 | } | ||
849 | |||
850 | return v4l2_subdev_call(sd, core, s_ctrl, ctrl); | ||
851 | } | ||
852 | |||
853 | static int soc_camera_cropcap(struct file *file, void *fh, | 835 | static int soc_camera_cropcap(struct file *file, void *fh, |
854 | struct v4l2_cropcap *a) | 836 | struct v4l2_cropcap *a) |
855 | { | 837 | { |
@@ -1003,7 +985,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd, | |||
1003 | goto ei2cga; | 985 | goto ei2cga; |
1004 | } | 986 | } |
1005 | 987 | ||
1006 | icl->board_info->platform_data = icd; | 988 | icl->board_info->platform_data = icl; |
1007 | 989 | ||
1008 | subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, | 990 | subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, |
1009 | icl->board_info, NULL); | 991 | icl->board_info, NULL); |
@@ -1052,12 +1034,29 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
1052 | 1034 | ||
1053 | dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev)); | 1035 | dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev)); |
1054 | 1036 | ||
1037 | /* | ||
1038 | * Currently the subdev with the largest number of controls (13) is | ||
1039 | * ov6550. So let's pick 16 as a hint for the control handler. Note | ||
1040 | * that this is a hint only: too large and you waste some memory, too | ||
1041 | * small and there is a (very) small performance hit when looking up | ||
1042 | * controls in the internal hash. | ||
1043 | */ | ||
1044 | ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16); | ||
1045 | if (ret < 0) | ||
1046 | return ret; | ||
1047 | |||
1055 | ret = regulator_bulk_get(icd->pdev, icl->num_regulators, | 1048 | ret = regulator_bulk_get(icd->pdev, icl->num_regulators, |
1056 | icl->regulators); | 1049 | icl->regulators); |
1057 | if (ret < 0) | 1050 | if (ret < 0) |
1058 | goto ereg; | 1051 | goto ereg; |
1059 | 1052 | ||
1060 | ret = soc_camera_power_set(icd, icl, 1); | 1053 | /* |
1054 | * This will not yet call v4l2_subdev_core_ops::s_power(1), because the | ||
1055 | * subdevice has not been initialised yet. We'll have to call it once | ||
1056 | * again after initialisation, even though it shouldn't be needed, we | ||
1057 | * don't do any IO here. | ||
1058 | */ | ||
1059 | ret = soc_camera_power_on(icd, icl); | ||
1061 | if (ret < 0) | 1060 | if (ret < 0) |
1062 | goto epower; | 1061 | goto epower; |
1063 | 1062 | ||
@@ -1098,6 +1097,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
1098 | if (!control || !control->driver || !dev_get_drvdata(control) || | 1097 | if (!control || !control->driver || !dev_get_drvdata(control) || |
1099 | !try_module_get(control->driver->owner)) { | 1098 | !try_module_get(control->driver->owner)) { |
1100 | icl->del_device(icd); | 1099 | icl->del_device(icd); |
1100 | ret = -ENODEV; | ||
1101 | goto enodrv; | 1101 | goto enodrv; |
1102 | } | 1102 | } |
1103 | } | 1103 | } |
@@ -1105,6 +1105,9 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
1105 | sd = soc_camera_to_subdev(icd); | 1105 | sd = soc_camera_to_subdev(icd); |
1106 | sd->grp_id = (long)icd; | 1106 | sd->grp_id = (long)icd; |
1107 | 1107 | ||
1108 | if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler)) | ||
1109 | goto ectrl; | ||
1110 | |||
1108 | /* At this point client .probe() should have run already */ | 1111 | /* At this point client .probe() should have run already */ |
1109 | ret = soc_camera_init_user_formats(icd); | 1112 | ret = soc_camera_init_user_formats(icd); |
1110 | if (ret < 0) | 1113 | if (ret < 0) |
@@ -1123,6 +1126,10 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
1123 | if (ret < 0) | 1126 | if (ret < 0) |
1124 | goto evidstart; | 1127 | goto evidstart; |
1125 | 1128 | ||
1129 | ret = v4l2_subdev_call(sd, core, s_power, 1); | ||
1130 | if (ret < 0 && ret != -ENOIOCTLCMD) | ||
1131 | goto esdpwr; | ||
1132 | |||
1126 | /* Try to improve our guess of a reasonable window format */ | 1133 | /* Try to improve our guess of a reasonable window format */ |
1127 | if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { | 1134 | if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { |
1128 | icd->user_width = mf.width; | 1135 | icd->user_width = mf.width; |
@@ -1133,16 +1140,19 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
1133 | 1140 | ||
1134 | ici->ops->remove(icd); | 1141 | ici->ops->remove(icd); |
1135 | 1142 | ||
1136 | soc_camera_power_set(icd, icl, 0); | 1143 | soc_camera_power_off(icd, icl); |
1137 | 1144 | ||
1138 | mutex_unlock(&icd->video_lock); | 1145 | mutex_unlock(&icd->video_lock); |
1139 | 1146 | ||
1140 | return 0; | 1147 | return 0; |
1141 | 1148 | ||
1149 | esdpwr: | ||
1150 | video_unregister_device(icd->vdev); | ||
1142 | evidstart: | 1151 | evidstart: |
1143 | mutex_unlock(&icd->video_lock); | 1152 | mutex_unlock(&icd->video_lock); |
1144 | soc_camera_free_user_formats(icd); | 1153 | soc_camera_free_user_formats(icd); |
1145 | eiufmt: | 1154 | eiufmt: |
1155 | ectrl: | ||
1146 | if (icl->board_info) { | 1156 | if (icl->board_info) { |
1147 | soc_camera_free_i2c(icd); | 1157 | soc_camera_free_i2c(icd); |
1148 | } else { | 1158 | } else { |
@@ -1152,13 +1162,15 @@ eiufmt: | |||
1152 | enodrv: | 1162 | enodrv: |
1153 | eadddev: | 1163 | eadddev: |
1154 | video_device_release(icd->vdev); | 1164 | video_device_release(icd->vdev); |
1165 | icd->vdev = NULL; | ||
1155 | evdc: | 1166 | evdc: |
1156 | ici->ops->remove(icd); | 1167 | ici->ops->remove(icd); |
1157 | eadd: | 1168 | eadd: |
1158 | soc_camera_power_set(icd, icl, 0); | 1169 | soc_camera_power_off(icd, icl); |
1159 | epower: | 1170 | epower: |
1160 | regulator_bulk_free(icl->num_regulators, icl->regulators); | 1171 | regulator_bulk_free(icl->num_regulators, icl->regulators); |
1161 | ereg: | 1172 | ereg: |
1173 | v4l2_ctrl_handler_free(&icd->ctrl_handler); | ||
1162 | return ret; | 1174 | return ret; |
1163 | } | 1175 | } |
1164 | 1176 | ||
@@ -1173,6 +1185,7 @@ static int soc_camera_remove(struct soc_camera_device *icd) | |||
1173 | 1185 | ||
1174 | BUG_ON(!icd->parent); | 1186 | BUG_ON(!icd->parent); |
1175 | 1187 | ||
1188 | v4l2_ctrl_handler_free(&icd->ctrl_handler); | ||
1176 | if (vdev) { | 1189 | if (vdev) { |
1177 | video_unregister_device(vdev); | 1190 | video_unregister_device(vdev); |
1178 | icd->vdev = NULL; | 1191 | icd->vdev = NULL; |
@@ -1363,24 +1376,24 @@ static int soc_camera_device_register(struct soc_camera_device *icd) | |||
1363 | 1376 | ||
1364 | static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { | 1377 | static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { |
1365 | .vidioc_querycap = soc_camera_querycap, | 1378 | .vidioc_querycap = soc_camera_querycap, |
1379 | .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, | ||
1366 | .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, | 1380 | .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, |
1367 | .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, | ||
1368 | .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, | 1381 | .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, |
1382 | .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, | ||
1369 | .vidioc_enum_input = soc_camera_enum_input, | 1383 | .vidioc_enum_input = soc_camera_enum_input, |
1370 | .vidioc_g_input = soc_camera_g_input, | 1384 | .vidioc_g_input = soc_camera_g_input, |
1371 | .vidioc_s_input = soc_camera_s_input, | 1385 | .vidioc_s_input = soc_camera_s_input, |
1372 | .vidioc_s_std = soc_camera_s_std, | 1386 | .vidioc_s_std = soc_camera_s_std, |
1387 | .vidioc_g_std = soc_camera_g_std, | ||
1373 | .vidioc_enum_framesizes = soc_camera_enum_fsizes, | 1388 | .vidioc_enum_framesizes = soc_camera_enum_fsizes, |
1374 | .vidioc_reqbufs = soc_camera_reqbufs, | 1389 | .vidioc_reqbufs = soc_camera_reqbufs, |
1375 | .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, | ||
1376 | .vidioc_querybuf = soc_camera_querybuf, | 1390 | .vidioc_querybuf = soc_camera_querybuf, |
1377 | .vidioc_qbuf = soc_camera_qbuf, | 1391 | .vidioc_qbuf = soc_camera_qbuf, |
1378 | .vidioc_dqbuf = soc_camera_dqbuf, | 1392 | .vidioc_dqbuf = soc_camera_dqbuf, |
1393 | .vidioc_create_bufs = soc_camera_create_bufs, | ||
1394 | .vidioc_prepare_buf = soc_camera_prepare_buf, | ||
1379 | .vidioc_streamon = soc_camera_streamon, | 1395 | .vidioc_streamon = soc_camera_streamon, |
1380 | .vidioc_streamoff = soc_camera_streamoff, | 1396 | .vidioc_streamoff = soc_camera_streamoff, |
1381 | .vidioc_queryctrl = soc_camera_queryctrl, | ||
1382 | .vidioc_g_ctrl = soc_camera_g_ctrl, | ||
1383 | .vidioc_s_ctrl = soc_camera_s_ctrl, | ||
1384 | .vidioc_cropcap = soc_camera_cropcap, | 1397 | .vidioc_cropcap = soc_camera_cropcap, |
1385 | .vidioc_g_crop = soc_camera_g_crop, | 1398 | .vidioc_g_crop = soc_camera_g_crop, |
1386 | .vidioc_s_crop = soc_camera_s_crop, | 1399 | .vidioc_s_crop = soc_camera_s_crop, |
@@ -1409,6 +1422,7 @@ static int video_dev_create(struct soc_camera_device *icd) | |||
1409 | vdev->ioctl_ops = &soc_camera_ioctl_ops; | 1422 | vdev->ioctl_ops = &soc_camera_ioctl_ops; |
1410 | vdev->release = video_device_release; | 1423 | vdev->release = video_device_release; |
1411 | vdev->tvnorms = V4L2_STD_UNKNOWN; | 1424 | vdev->tvnorms = V4L2_STD_UNKNOWN; |
1425 | vdev->ctrl_handler = &icd->ctrl_handler; | ||
1412 | vdev->lock = &icd->video_lock; | 1426 | vdev->lock = &icd->video_lock; |
1413 | 1427 | ||
1414 | icd->vdev = vdev; | 1428 | icd->vdev = vdev; |
@@ -1427,11 +1441,6 @@ static int soc_camera_video_start(struct soc_camera_device *icd) | |||
1427 | if (!icd->parent) | 1441 | if (!icd->parent) |
1428 | return -ENODEV; | 1442 | return -ENODEV; |
1429 | 1443 | ||
1430 | if (!icd->ops || | ||
1431 | !icd->ops->query_bus_param || | ||
1432 | !icd->ops->set_bus_param) | ||
1433 | return -EINVAL; | ||
1434 | |||
1435 | ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1); | 1444 | ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1); |
1436 | if (ret < 0) { | 1445 | if (ret < 0) { |
1437 | dev_err(icd->pdev, "video_register_device failed: %d\n", ret); | 1446 | dev_err(icd->pdev, "video_register_device failed: %d\n", ret); |
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index 8069cd6bc5e8..4402a8a74f7a 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c | |||
@@ -30,32 +30,12 @@ static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev) | |||
30 | return container_of(subdev, struct soc_camera_platform_priv, subdev); | 30 | return container_of(subdev, struct soc_camera_platform_priv, subdev); |
31 | } | 31 | } |
32 | 32 | ||
33 | static struct soc_camera_platform_info *get_info(struct soc_camera_device *icd) | ||
34 | { | ||
35 | struct platform_device *pdev = | ||
36 | to_platform_device(to_soc_camera_control(icd)); | ||
37 | return pdev->dev.platform_data; | ||
38 | } | ||
39 | |||
40 | static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable) | 33 | static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable) |
41 | { | 34 | { |
42 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | 35 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); |
43 | return p->set_capture(p, enable); | 36 | return p->set_capture(p, enable); |
44 | } | 37 | } |
45 | 38 | ||
46 | static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd, | ||
47 | unsigned long flags) | ||
48 | { | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static unsigned long | ||
53 | soc_camera_platform_query_bus_param(struct soc_camera_device *icd) | ||
54 | { | ||
55 | struct soc_camera_platform_info *p = get_info(icd); | ||
56 | return p->bus_param; | ||
57 | } | ||
58 | |||
59 | static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd, | 39 | static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd, |
60 | struct v4l2_mbus_framefmt *mf) | 40 | struct v4l2_mbus_framefmt *mf) |
61 | { | 41 | { |
@@ -115,6 +95,17 @@ static int soc_camera_platform_cropcap(struct v4l2_subdev *sd, | |||
115 | return 0; | 95 | return 0; |
116 | } | 96 | } |
117 | 97 | ||
98 | static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd, | ||
99 | struct v4l2_mbus_config *cfg) | ||
100 | { | ||
101 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | ||
102 | |||
103 | cfg->flags = p->mbus_param; | ||
104 | cfg->type = p->mbus_type; | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
118 | static struct v4l2_subdev_video_ops platform_subdev_video_ops = { | 109 | static struct v4l2_subdev_video_ops platform_subdev_video_ops = { |
119 | .s_stream = soc_camera_platform_s_stream, | 110 | .s_stream = soc_camera_platform_s_stream, |
120 | .enum_mbus_fmt = soc_camera_platform_enum_fmt, | 111 | .enum_mbus_fmt = soc_camera_platform_enum_fmt, |
@@ -123,6 +114,7 @@ static struct v4l2_subdev_video_ops platform_subdev_video_ops = { | |||
123 | .try_mbus_fmt = soc_camera_platform_fill_fmt, | 114 | .try_mbus_fmt = soc_camera_platform_fill_fmt, |
124 | .g_mbus_fmt = soc_camera_platform_fill_fmt, | 115 | .g_mbus_fmt = soc_camera_platform_fill_fmt, |
125 | .s_mbus_fmt = soc_camera_platform_fill_fmt, | 116 | .s_mbus_fmt = soc_camera_platform_fill_fmt, |
117 | .g_mbus_config = soc_camera_platform_g_mbus_config, | ||
126 | }; | 118 | }; |
127 | 119 | ||
128 | static struct v4l2_subdev_ops platform_subdev_ops = { | 120 | static struct v4l2_subdev_ops platform_subdev_ops = { |
@@ -130,11 +122,6 @@ static struct v4l2_subdev_ops platform_subdev_ops = { | |||
130 | .video = &platform_subdev_video_ops, | 122 | .video = &platform_subdev_video_ops, |
131 | }; | 123 | }; |
132 | 124 | ||
133 | static struct soc_camera_ops soc_camera_platform_ops = { | ||
134 | .set_bus_param = soc_camera_platform_set_bus_param, | ||
135 | .query_bus_param = soc_camera_platform_query_bus_param, | ||
136 | }; | ||
137 | |||
138 | static int soc_camera_platform_probe(struct platform_device *pdev) | 125 | static int soc_camera_platform_probe(struct platform_device *pdev) |
139 | { | 126 | { |
140 | struct soc_camera_host *ici; | 127 | struct soc_camera_host *ici; |
@@ -163,8 +150,6 @@ static int soc_camera_platform_probe(struct platform_device *pdev) | |||
163 | /* Set the control device reference */ | 150 | /* Set the control device reference */ |
164 | icd->control = &pdev->dev; | 151 | icd->control = &pdev->dev; |
165 | 152 | ||
166 | icd->ops = &soc_camera_platform_ops; | ||
167 | |||
168 | ici = to_soc_camera_host(icd->parent); | 153 | ici = to_soc_camera_host(icd->parent); |
169 | 154 | ||
170 | v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); | 155 | v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); |
@@ -178,7 +163,6 @@ static int soc_camera_platform_probe(struct platform_device *pdev) | |||
178 | return ret; | 163 | return ret; |
179 | 164 | ||
180 | evdrs: | 165 | evdrs: |
181 | icd->ops = NULL; | ||
182 | platform_set_drvdata(pdev, NULL); | 166 | platform_set_drvdata(pdev, NULL); |
183 | kfree(priv); | 167 | kfree(priv); |
184 | return ret; | 168 | return ret; |
@@ -187,11 +171,10 @@ evdrs: | |||
187 | static int soc_camera_platform_remove(struct platform_device *pdev) | 171 | static int soc_camera_platform_remove(struct platform_device *pdev) |
188 | { | 172 | { |
189 | struct soc_camera_platform_priv *priv = get_priv(pdev); | 173 | struct soc_camera_platform_priv *priv = get_priv(pdev); |
190 | struct soc_camera_platform_info *p = pdev->dev.platform_data; | 174 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(&priv->subdev); |
191 | struct soc_camera_device *icd = p->icd; | ||
192 | 175 | ||
176 | p->icd->control = NULL; | ||
193 | v4l2_device_unregister_subdev(&priv->subdev); | 177 | v4l2_device_unregister_subdev(&priv->subdev); |
194 | icd->ops = NULL; | ||
195 | platform_set_drvdata(pdev, NULL); | 178 | platform_set_drvdata(pdev, NULL); |
196 | kfree(priv); | 179 | kfree(priv); |
197 | return 0; | 180 | return 0; |
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c index bea7c9cf4f88..cf7f2194ded4 100644 --- a/drivers/media/video/soc_mediabus.c +++ b/drivers/media/video/soc_mediabus.c | |||
@@ -383,6 +383,39 @@ const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( | |||
383 | } | 383 | } |
384 | EXPORT_SYMBOL(soc_mbus_get_fmtdesc); | 384 | EXPORT_SYMBOL(soc_mbus_get_fmtdesc); |
385 | 385 | ||
386 | unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg, | ||
387 | unsigned int flags) | ||
388 | { | ||
389 | unsigned long common_flags; | ||
390 | bool hsync = true, vsync = true, pclk, data, mode; | ||
391 | bool mipi_lanes, mipi_clock; | ||
392 | |||
393 | common_flags = cfg->flags & flags; | ||
394 | |||
395 | switch (cfg->type) { | ||
396 | case V4L2_MBUS_PARALLEL: | ||
397 | hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
398 | V4L2_MBUS_HSYNC_ACTIVE_LOW); | ||
399 | vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
400 | V4L2_MBUS_VSYNC_ACTIVE_LOW); | ||
401 | case V4L2_MBUS_BT656: | ||
402 | pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
403 | V4L2_MBUS_PCLK_SAMPLE_FALLING); | ||
404 | data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH | | ||
405 | V4L2_MBUS_DATA_ACTIVE_LOW); | ||
406 | mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE); | ||
407 | return (!hsync || !vsync || !pclk || !data || !mode) ? | ||
408 | 0 : common_flags; | ||
409 | case V4L2_MBUS_CSI2: | ||
410 | mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES; | ||
411 | mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | | ||
412 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); | ||
413 | return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; | ||
414 | } | ||
415 | return 0; | ||
416 | } | ||
417 | EXPORT_SYMBOL(soc_mbus_config_compatible); | ||
418 | |||
386 | static int __init soc_mbus_init(void) | 419 | static int __init soc_mbus_init(void) |
387 | { | 420 | { |
388 | return 0; | 421 | return 0; |
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 742482e30011..a514fa61116c 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c | |||
@@ -22,11 +22,13 @@ | |||
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/v4l2-mediabus.h> | ||
25 | #include <linux/videodev2.h> | 26 | #include <linux/videodev2.h> |
26 | #include <media/v4l2-chip-ident.h> | 27 | |
27 | #include <media/v4l2-subdev.h> | ||
28 | #include <media/soc_camera.h> | 28 | #include <media/soc_camera.h> |
29 | #include <media/tw9910.h> | 29 | #include <media/tw9910.h> |
30 | #include <media/v4l2-chip-ident.h> | ||
31 | #include <media/v4l2-subdev.h> | ||
30 | 32 | ||
31 | #define GET_ID(val) ((val & 0xF8) >> 3) | 33 | #define GET_ID(val) ((val & 0xF8) >> 3) |
32 | #define GET_REV(val) (val & 0x07) | 34 | #define GET_REV(val) (val & 0x07) |
@@ -203,6 +205,10 @@ | |||
203 | #define RTSEL_FIELD 0x06 /* 0110 = FIELD */ | 205 | #define RTSEL_FIELD 0x06 /* 0110 = FIELD */ |
204 | #define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */ | 206 | #define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */ |
205 | 207 | ||
208 | /* HSYNC start and end are constant for now */ | ||
209 | #define HSYNC_START 0x0260 | ||
210 | #define HSYNC_END 0x0300 | ||
211 | |||
206 | /* | 212 | /* |
207 | * structure | 213 | * structure |
208 | */ | 214 | */ |
@@ -220,22 +226,11 @@ struct tw9910_scale_ctrl { | |||
220 | u16 vscale; | 226 | u16 vscale; |
221 | }; | 227 | }; |
222 | 228 | ||
223 | struct tw9910_cropping_ctrl { | ||
224 | u16 vdelay; | ||
225 | u16 vactive; | ||
226 | u16 hdelay; | ||
227 | u16 hactive; | ||
228 | }; | ||
229 | |||
230 | struct tw9910_hsync_ctrl { | ||
231 | u16 start; | ||
232 | u16 end; | ||
233 | }; | ||
234 | |||
235 | struct tw9910_priv { | 229 | struct tw9910_priv { |
236 | struct v4l2_subdev subdev; | 230 | struct v4l2_subdev subdev; |
237 | struct tw9910_video_info *info; | 231 | struct tw9910_video_info *info; |
238 | const struct tw9910_scale_ctrl *scale; | 232 | const struct tw9910_scale_ctrl *scale; |
233 | v4l2_std_id norm; | ||
239 | u32 revision; | 234 | u32 revision; |
240 | }; | 235 | }; |
241 | 236 | ||
@@ -329,11 +324,6 @@ static const struct tw9910_scale_ctrl tw9910_pal_scales[] = { | |||
329 | }, | 324 | }, |
330 | }; | 325 | }; |
331 | 326 | ||
332 | static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = { | ||
333 | .start = 0x0260, | ||
334 | .end = 0x0300, | ||
335 | }; | ||
336 | |||
337 | /* | 327 | /* |
338 | * general function | 328 | * general function |
339 | */ | 329 | */ |
@@ -378,21 +368,20 @@ static int tw9910_set_scale(struct i2c_client *client, | |||
378 | return ret; | 368 | return ret; |
379 | } | 369 | } |
380 | 370 | ||
381 | static int tw9910_set_hsync(struct i2c_client *client, | 371 | static int tw9910_set_hsync(struct i2c_client *client) |
382 | const struct tw9910_hsync_ctrl *hsync) | ||
383 | { | 372 | { |
384 | struct tw9910_priv *priv = to_tw9910(client); | 373 | struct tw9910_priv *priv = to_tw9910(client); |
385 | int ret; | 374 | int ret; |
386 | 375 | ||
387 | /* bit 10 - 3 */ | 376 | /* bit 10 - 3 */ |
388 | ret = i2c_smbus_write_byte_data(client, HSBEGIN, | 377 | ret = i2c_smbus_write_byte_data(client, HSBEGIN, |
389 | (hsync->start & 0x07F8) >> 3); | 378 | (HSYNC_START & 0x07F8) >> 3); |
390 | if (ret < 0) | 379 | if (ret < 0) |
391 | return ret; | 380 | return ret; |
392 | 381 | ||
393 | /* bit 10 - 3 */ | 382 | /* bit 10 - 3 */ |
394 | ret = i2c_smbus_write_byte_data(client, HSEND, | 383 | ret = i2c_smbus_write_byte_data(client, HSEND, |
395 | (hsync->end & 0x07F8) >> 3); | 384 | (HSYNC_END & 0x07F8) >> 3); |
396 | if (ret < 0) | 385 | if (ret < 0) |
397 | return ret; | 386 | return ret; |
398 | 387 | ||
@@ -400,8 +389,8 @@ static int tw9910_set_hsync(struct i2c_client *client, | |||
400 | /* bit 2 - 0 */ | 389 | /* bit 2 - 0 */ |
401 | if (1 == priv->revision) | 390 | if (1 == priv->revision) |
402 | ret = tw9910_mask_set(client, HSLOWCTL, 0x77, | 391 | ret = tw9910_mask_set(client, HSLOWCTL, 0x77, |
403 | (hsync->start & 0x0007) << 4 | | 392 | (HSYNC_START & 0x0007) << 4 | |
404 | (hsync->end & 0x0007)); | 393 | (HSYNC_END & 0x0007)); |
405 | 394 | ||
406 | return ret; | 395 | return ret; |
407 | } | 396 | } |
@@ -433,12 +422,11 @@ static int tw9910_power(struct i2c_client *client, int enable) | |||
433 | return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); | 422 | return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); |
434 | } | 423 | } |
435 | 424 | ||
436 | static const struct tw9910_scale_ctrl* | 425 | static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm, |
437 | tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height) | 426 | u32 width, u32 height) |
438 | { | 427 | { |
439 | const struct tw9910_scale_ctrl *scale; | 428 | const struct tw9910_scale_ctrl *scale; |
440 | const struct tw9910_scale_ctrl *ret = NULL; | 429 | const struct tw9910_scale_ctrl *ret = NULL; |
441 | v4l2_std_id norm = icd->vdev->current_norm; | ||
442 | __u32 diff = 0xffffffff, tmp; | 430 | __u32 diff = 0xffffffff, tmp; |
443 | int size, i; | 431 | int size, i; |
444 | 432 | ||
@@ -465,7 +453,7 @@ tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height) | |||
465 | } | 453 | } |
466 | 454 | ||
467 | /* | 455 | /* |
468 | * soc_camera_ops function | 456 | * subdevice operations |
469 | */ | 457 | */ |
470 | static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) | 458 | static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) |
471 | { | 459 | { |
@@ -507,49 +495,27 @@ static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) | |||
507 | return tw9910_power(client, enable); | 495 | return tw9910_power(client, enable); |
508 | } | 496 | } |
509 | 497 | ||
510 | static int tw9910_set_bus_param(struct soc_camera_device *icd, | 498 | static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) |
511 | unsigned long flags) | ||
512 | { | 499 | { |
513 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
514 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 500 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
515 | u8 val = VSSL_VVALID | HSSL_DVALID; | 501 | struct tw9910_priv *priv = to_tw9910(client); |
516 | 502 | ||
517 | /* | 503 | *norm = priv->norm; |
518 | * set OUTCTR1 | ||
519 | * | ||
520 | * We use VVALID and DVALID signals to control VSYNC and HSYNC | ||
521 | * outputs, in this mode their polarity is inverted. | ||
522 | */ | ||
523 | if (flags & SOCAM_HSYNC_ACTIVE_LOW) | ||
524 | val |= HSP_HI; | ||
525 | 504 | ||
526 | if (flags & SOCAM_VSYNC_ACTIVE_LOW) | 505 | return 0; |
527 | val |= VSP_HI; | ||
528 | |||
529 | return i2c_smbus_write_byte_data(client, OUTCTR1, val); | ||
530 | } | 506 | } |
531 | 507 | ||
532 | static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) | 508 | static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) |
533 | { | 509 | { |
534 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | 510 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
535 | struct tw9910_priv *priv = to_tw9910(client); | 511 | struct tw9910_priv *priv = to_tw9910(client); |
536 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
537 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
538 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
539 | SOCAM_VSYNC_ACTIVE_LOW | SOCAM_HSYNC_ACTIVE_LOW | | ||
540 | SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; | ||
541 | 512 | ||
542 | return soc_camera_apply_sensor_flags(icl, flags); | 513 | if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL))) |
543 | } | 514 | return -EINVAL; |
544 | |||
545 | static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) | ||
546 | { | ||
547 | int ret = -EINVAL; | ||
548 | 515 | ||
549 | if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL)) | 516 | priv->norm = norm; |
550 | ret = 0; | ||
551 | 517 | ||
552 | return ret; | 518 | return 0; |
553 | } | 519 | } |
554 | 520 | ||
555 | static int tw9910_g_chip_ident(struct v4l2_subdev *sd, | 521 | static int tw9910_g_chip_ident(struct v4l2_subdev *sd, |
@@ -600,19 +566,17 @@ static int tw9910_s_register(struct v4l2_subdev *sd, | |||
600 | } | 566 | } |
601 | #endif | 567 | #endif |
602 | 568 | ||
603 | static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 569 | static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) |
604 | { | 570 | { |
605 | struct v4l2_rect *rect = &a->c; | ||
606 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 571 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
607 | struct tw9910_priv *priv = to_tw9910(client); | 572 | struct tw9910_priv *priv = to_tw9910(client); |
608 | struct soc_camera_device *icd = client->dev.platform_data; | 573 | int ret = -EINVAL; |
609 | int ret = -EINVAL; | 574 | u8 val; |
610 | u8 val; | ||
611 | 575 | ||
612 | /* | 576 | /* |
613 | * select suitable norm | 577 | * select suitable norm |
614 | */ | 578 | */ |
615 | priv->scale = tw9910_select_norm(icd, rect->width, rect->height); | 579 | priv->scale = tw9910_select_norm(priv->norm, *width, *height); |
616 | if (!priv->scale) | 580 | if (!priv->scale) |
617 | goto tw9910_set_fmt_error; | 581 | goto tw9910_set_fmt_error; |
618 | 582 | ||
@@ -670,14 +634,12 @@ static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
670 | /* | 634 | /* |
671 | * set hsync | 635 | * set hsync |
672 | */ | 636 | */ |
673 | ret = tw9910_set_hsync(client, &tw9910_hsync_ctrl); | 637 | ret = tw9910_set_hsync(client); |
674 | if (ret < 0) | 638 | if (ret < 0) |
675 | goto tw9910_set_fmt_error; | 639 | goto tw9910_set_fmt_error; |
676 | 640 | ||
677 | rect->width = priv->scale->width; | 641 | *width = priv->scale->width; |
678 | rect->height = priv->scale->height; | 642 | *height = priv->scale->height; |
679 | rect->left = 0; | ||
680 | rect->top = 0; | ||
681 | 643 | ||
682 | return ret; | 644 | return ret; |
683 | 645 | ||
@@ -694,25 +656,15 @@ static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
694 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 656 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
695 | struct tw9910_priv *priv = to_tw9910(client); | 657 | struct tw9910_priv *priv = to_tw9910(client); |
696 | 658 | ||
697 | if (!priv->scale) { | ||
698 | int ret; | ||
699 | struct v4l2_crop crop = { | ||
700 | .c = { | ||
701 | .left = 0, | ||
702 | .top = 0, | ||
703 | .width = 640, | ||
704 | .height = 480, | ||
705 | }, | ||
706 | }; | ||
707 | ret = tw9910_s_crop(sd, &crop); | ||
708 | if (ret < 0) | ||
709 | return ret; | ||
710 | } | ||
711 | |||
712 | a->c.left = 0; | 659 | a->c.left = 0; |
713 | a->c.top = 0; | 660 | a->c.top = 0; |
714 | a->c.width = priv->scale->width; | 661 | if (priv->norm & V4L2_STD_NTSC) { |
715 | a->c.height = priv->scale->height; | 662 | a->c.width = 640; |
663 | a->c.height = 480; | ||
664 | } else { | ||
665 | a->c.width = 768; | ||
666 | a->c.height = 576; | ||
667 | } | ||
716 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 668 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
717 | 669 | ||
718 | return 0; | 670 | return 0; |
@@ -720,14 +672,19 @@ static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
720 | 672 | ||
721 | static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | 673 | static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) |
722 | { | 674 | { |
675 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
676 | struct tw9910_priv *priv = to_tw9910(client); | ||
677 | |||
723 | a->bounds.left = 0; | 678 | a->bounds.left = 0; |
724 | a->bounds.top = 0; | 679 | a->bounds.top = 0; |
725 | a->bounds.width = 768; | 680 | if (priv->norm & V4L2_STD_NTSC) { |
726 | a->bounds.height = 576; | 681 | a->bounds.width = 640; |
727 | a->defrect.left = 0; | 682 | a->bounds.height = 480; |
728 | a->defrect.top = 0; | 683 | } else { |
729 | a->defrect.width = 640; | 684 | a->bounds.width = 768; |
730 | a->defrect.height = 480; | 685 | a->bounds.height = 576; |
686 | } | ||
687 | a->defrect = a->bounds; | ||
731 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 688 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
732 | a->pixelaspect.numerator = 1; | 689 | a->pixelaspect.numerator = 1; |
733 | a->pixelaspect.denominator = 1; | 690 | a->pixelaspect.denominator = 1; |
@@ -743,15 +700,8 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd, | |||
743 | 700 | ||
744 | if (!priv->scale) { | 701 | if (!priv->scale) { |
745 | int ret; | 702 | int ret; |
746 | struct v4l2_crop crop = { | 703 | u32 width = 640, height = 480; |
747 | .c = { | 704 | ret = tw9910_set_frame(sd, &width, &height); |
748 | .left = 0, | ||
749 | .top = 0, | ||
750 | .width = 640, | ||
751 | .height = 480, | ||
752 | }, | ||
753 | }; | ||
754 | ret = tw9910_s_crop(sd, &crop); | ||
755 | if (ret < 0) | 705 | if (ret < 0) |
756 | return ret; | 706 | return ret; |
757 | } | 707 | } |
@@ -768,17 +718,7 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd, | |||
768 | static int tw9910_s_fmt(struct v4l2_subdev *sd, | 718 | static int tw9910_s_fmt(struct v4l2_subdev *sd, |
769 | struct v4l2_mbus_framefmt *mf) | 719 | struct v4l2_mbus_framefmt *mf) |
770 | { | 720 | { |
771 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 721 | u32 width = mf->width, height = mf->height; |
772 | struct tw9910_priv *priv = to_tw9910(client); | ||
773 | /* See tw9910_s_crop() - no proper cropping support */ | ||
774 | struct v4l2_crop a = { | ||
775 | .c = { | ||
776 | .left = 0, | ||
777 | .top = 0, | ||
778 | .width = mf->width, | ||
779 | .height = mf->height, | ||
780 | }, | ||
781 | }; | ||
782 | int ret; | 722 | int ret; |
783 | 723 | ||
784 | WARN_ON(mf->field != V4L2_FIELD_ANY && | 724 | WARN_ON(mf->field != V4L2_FIELD_ANY && |
@@ -792,10 +732,10 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, | |||
792 | 732 | ||
793 | mf->colorspace = V4L2_COLORSPACE_JPEG; | 733 | mf->colorspace = V4L2_COLORSPACE_JPEG; |
794 | 734 | ||
795 | ret = tw9910_s_crop(sd, &a); | 735 | ret = tw9910_set_frame(sd, &width, &height); |
796 | if (!ret) { | 736 | if (!ret) { |
797 | mf->width = priv->scale->width; | 737 | mf->width = width; |
798 | mf->height = priv->scale->height; | 738 | mf->height = height; |
799 | } | 739 | } |
800 | return ret; | 740 | return ret; |
801 | } | 741 | } |
@@ -804,7 +744,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, | |||
804 | struct v4l2_mbus_framefmt *mf) | 744 | struct v4l2_mbus_framefmt *mf) |
805 | { | 745 | { |
806 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 746 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
807 | struct soc_camera_device *icd = client->dev.platform_data; | 747 | struct tw9910_priv *priv = to_tw9910(client); |
808 | const struct tw9910_scale_ctrl *scale; | 748 | const struct tw9910_scale_ctrl *scale; |
809 | 749 | ||
810 | if (V4L2_FIELD_ANY == mf->field) { | 750 | if (V4L2_FIELD_ANY == mf->field) { |
@@ -820,7 +760,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, | |||
820 | /* | 760 | /* |
821 | * select suitable norm | 761 | * select suitable norm |
822 | */ | 762 | */ |
823 | scale = tw9910_select_norm(icd, mf->width, mf->height); | 763 | scale = tw9910_select_norm(priv->norm, mf->width, mf->height); |
824 | if (!scale) | 764 | if (!scale) |
825 | return -EINVAL; | 765 | return -EINVAL; |
826 | 766 | ||
@@ -830,16 +770,11 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, | |||
830 | return 0; | 770 | return 0; |
831 | } | 771 | } |
832 | 772 | ||
833 | static int tw9910_video_probe(struct soc_camera_device *icd, | 773 | static int tw9910_video_probe(struct i2c_client *client) |
834 | struct i2c_client *client) | ||
835 | { | 774 | { |
836 | struct tw9910_priv *priv = to_tw9910(client); | 775 | struct tw9910_priv *priv = to_tw9910(client); |
837 | s32 id; | 776 | s32 id; |
838 | 777 | ||
839 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
840 | BUG_ON(!icd->parent || | ||
841 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
842 | |||
843 | /* | 778 | /* |
844 | * tw9910 only use 8 or 16 bit bus width | 779 | * tw9910 only use 8 or 16 bit bus width |
845 | */ | 780 | */ |
@@ -868,20 +803,15 @@ static int tw9910_video_probe(struct soc_camera_device *icd, | |||
868 | dev_info(&client->dev, | 803 | dev_info(&client->dev, |
869 | "tw9910 Product ID %0x:%0x\n", id, priv->revision); | 804 | "tw9910 Product ID %0x:%0x\n", id, priv->revision); |
870 | 805 | ||
871 | icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; | 806 | priv->norm = V4L2_STD_NTSC; |
872 | icd->vdev->current_norm = V4L2_STD_NTSC; | ||
873 | 807 | ||
874 | return 0; | 808 | return 0; |
875 | } | 809 | } |
876 | 810 | ||
877 | static struct soc_camera_ops tw9910_ops = { | ||
878 | .set_bus_param = tw9910_set_bus_param, | ||
879 | .query_bus_param = tw9910_query_bus_param, | ||
880 | }; | ||
881 | |||
882 | static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { | 811 | static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { |
883 | .g_chip_ident = tw9910_g_chip_ident, | 812 | .g_chip_ident = tw9910_g_chip_ident, |
884 | .s_std = tw9910_s_std, | 813 | .s_std = tw9910_s_std, |
814 | .g_std = tw9910_g_std, | ||
885 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 815 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
886 | .g_register = tw9910_g_register, | 816 | .g_register = tw9910_g_register, |
887 | .s_register = tw9910_s_register, | 817 | .s_register = tw9910_s_register, |
@@ -898,6 +828,45 @@ static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
898 | return 0; | 828 | return 0; |
899 | } | 829 | } |
900 | 830 | ||
831 | static int tw9910_g_mbus_config(struct v4l2_subdev *sd, | ||
832 | struct v4l2_mbus_config *cfg) | ||
833 | { | ||
834 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
835 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
836 | |||
837 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
838 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | | ||
839 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | | ||
840 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
841 | cfg->type = V4L2_MBUS_PARALLEL; | ||
842 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
843 | |||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | static int tw9910_s_mbus_config(struct v4l2_subdev *sd, | ||
848 | const struct v4l2_mbus_config *cfg) | ||
849 | { | ||
850 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
851 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
852 | u8 val = VSSL_VVALID | HSSL_DVALID; | ||
853 | unsigned long flags = soc_camera_apply_board_flags(icl, cfg); | ||
854 | |||
855 | /* | ||
856 | * set OUTCTR1 | ||
857 | * | ||
858 | * We use VVALID and DVALID signals to control VSYNC and HSYNC | ||
859 | * outputs, in this mode their polarity is inverted. | ||
860 | */ | ||
861 | if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
862 | val |= HSP_HI; | ||
863 | |||
864 | if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
865 | val |= VSP_HI; | ||
866 | |||
867 | return i2c_smbus_write_byte_data(client, OUTCTR1, val); | ||
868 | } | ||
869 | |||
901 | static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { | 870 | static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { |
902 | .s_stream = tw9910_s_stream, | 871 | .s_stream = tw9910_s_stream, |
903 | .g_mbus_fmt = tw9910_g_fmt, | 872 | .g_mbus_fmt = tw9910_g_fmt, |
@@ -905,8 +874,9 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { | |||
905 | .try_mbus_fmt = tw9910_try_fmt, | 874 | .try_mbus_fmt = tw9910_try_fmt, |
906 | .cropcap = tw9910_cropcap, | 875 | .cropcap = tw9910_cropcap, |
907 | .g_crop = tw9910_g_crop, | 876 | .g_crop = tw9910_g_crop, |
908 | .s_crop = tw9910_s_crop, | ||
909 | .enum_mbus_fmt = tw9910_enum_fmt, | 877 | .enum_mbus_fmt = tw9910_enum_fmt, |
878 | .g_mbus_config = tw9910_g_mbus_config, | ||
879 | .s_mbus_config = tw9910_s_mbus_config, | ||
910 | }; | 880 | }; |
911 | 881 | ||
912 | static struct v4l2_subdev_ops tw9910_subdev_ops = { | 882 | static struct v4l2_subdev_ops tw9910_subdev_ops = { |
@@ -922,23 +892,18 @@ static int tw9910_probe(struct i2c_client *client, | |||
922 | const struct i2c_device_id *did) | 892 | const struct i2c_device_id *did) |
923 | 893 | ||
924 | { | 894 | { |
925 | struct tw9910_priv *priv; | 895 | struct tw9910_priv *priv; |
926 | struct tw9910_video_info *info; | 896 | struct tw9910_video_info *info; |
927 | struct soc_camera_device *icd = client->dev.platform_data; | 897 | struct i2c_adapter *adapter = |
928 | struct i2c_adapter *adapter = | ||
929 | to_i2c_adapter(client->dev.parent); | 898 | to_i2c_adapter(client->dev.parent); |
930 | struct soc_camera_link *icl; | 899 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
931 | int ret; | 900 | int ret; |
932 | 901 | ||
933 | if (!icd) { | 902 | if (!icl || !icl->priv) { |
934 | dev_err(&client->dev, "TW9910: missing soc-camera data!\n"); | 903 | dev_err(&client->dev, "TW9910: missing platform data!\n"); |
935 | return -EINVAL; | 904 | return -EINVAL; |
936 | } | 905 | } |
937 | 906 | ||
938 | icl = to_soc_camera_link(icd); | ||
939 | if (!icl || !icl->priv) | ||
940 | return -EINVAL; | ||
941 | |||
942 | info = icl->priv; | 907 | info = icl->priv; |
943 | 908 | ||
944 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 909 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
@@ -956,14 +921,9 @@ static int tw9910_probe(struct i2c_client *client, | |||
956 | 921 | ||
957 | v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); | 922 | v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); |
958 | 923 | ||
959 | icd->ops = &tw9910_ops; | 924 | ret = tw9910_video_probe(client); |
960 | icd->iface = icl->bus_id; | 925 | if (ret) |
961 | |||
962 | ret = tw9910_video_probe(icd, client); | ||
963 | if (ret) { | ||
964 | icd->ops = NULL; | ||
965 | kfree(priv); | 926 | kfree(priv); |
966 | } | ||
967 | 927 | ||
968 | return ret; | 928 | return ret; |
969 | } | 929 | } |
@@ -971,9 +931,7 @@ static int tw9910_probe(struct i2c_client *client, | |||
971 | static int tw9910_remove(struct i2c_client *client) | 931 | static int tw9910_remove(struct i2c_client *client) |
972 | { | 932 | { |
973 | struct tw9910_priv *priv = to_tw9910(client); | 933 | struct tw9910_priv *priv = to_tw9910(client); |
974 | struct soc_camera_device *icd = client->dev.platform_data; | ||
975 | 934 | ||
976 | icd->ops = NULL; | ||
977 | kfree(priv); | 935 | kfree(priv); |
978 | return 0; | 936 | return 0; |
979 | } | 937 | } |
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 61979b70f388..c68531b88279 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c | |||
@@ -159,11 +159,25 @@ struct v4l2_format32 { | |||
159 | } fmt; | 159 | } fmt; |
160 | }; | 160 | }; |
161 | 161 | ||
162 | static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | 162 | /** |
163 | * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument | ||
164 | * @index: on return, index of the first created buffer | ||
165 | * @count: entry: number of requested buffers, | ||
166 | * return: number of created buffers | ||
167 | * @memory: buffer memory type | ||
168 | * @format: frame format, for which buffers are requested | ||
169 | * @reserved: future extensions | ||
170 | */ | ||
171 | struct v4l2_create_buffers32 { | ||
172 | __u32 index; | ||
173 | __u32 count; | ||
174 | enum v4l2_memory memory; | ||
175 | struct v4l2_format32 format; | ||
176 | __u32 reserved[8]; | ||
177 | }; | ||
178 | |||
179 | static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | ||
163 | { | 180 | { |
164 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) || | ||
165 | get_user(kp->type, &up->type)) | ||
166 | return -EFAULT; | ||
167 | switch (kp->type) { | 181 | switch (kp->type) { |
168 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 182 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
169 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 183 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
@@ -192,11 +206,24 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user | |||
192 | } | 206 | } |
193 | } | 207 | } |
194 | 208 | ||
195 | static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | 209 | static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) |
210 | { | ||
211 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) || | ||
212 | get_user(kp->type, &up->type)) | ||
213 | return -EFAULT; | ||
214 | return __get_v4l2_format32(kp, up); | ||
215 | } | ||
216 | |||
217 | static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) | ||
218 | { | ||
219 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) || | ||
220 | copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format.fmt))) | ||
221 | return -EFAULT; | ||
222 | return __get_v4l2_format32(&kp->format, &up->format); | ||
223 | } | ||
224 | |||
225 | static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | ||
196 | { | 226 | { |
197 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || | ||
198 | put_user(kp->type, &up->type)) | ||
199 | return -EFAULT; | ||
200 | switch (kp->type) { | 227 | switch (kp->type) { |
201 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 228 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
202 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 229 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
@@ -225,6 +252,22 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user | |||
225 | } | 252 | } |
226 | } | 253 | } |
227 | 254 | ||
255 | static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | ||
256 | { | ||
257 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || | ||
258 | put_user(kp->type, &up->type)) | ||
259 | return -EFAULT; | ||
260 | return __put_v4l2_format32(kp, up); | ||
261 | } | ||
262 | |||
263 | static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) | ||
264 | { | ||
265 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || | ||
266 | copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt))) | ||
267 | return -EFAULT; | ||
268 | return __put_v4l2_format32(&kp->format, &up->format); | ||
269 | } | ||
270 | |||
228 | struct v4l2_standard32 { | 271 | struct v4l2_standard32 { |
229 | __u32 index; | 272 | __u32 index; |
230 | __u32 id[2]; /* __u64 would get the alignment wrong */ | 273 | __u32 id[2]; /* __u64 would get the alignment wrong */ |
@@ -702,6 +745,8 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u | |||
702 | #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) | 745 | #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) |
703 | #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) | 746 | #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) |
704 | #define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32) | 747 | #define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32) |
748 | #define VIDIOC_CREATE_BUFS32 _IOWR('V', 92, struct v4l2_create_buffers32) | ||
749 | #define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32) | ||
705 | 750 | ||
706 | #define VIDIOC_OVERLAY32 _IOW ('V', 14, s32) | 751 | #define VIDIOC_OVERLAY32 _IOW ('V', 14, s32) |
707 | #define VIDIOC_STREAMON32 _IOW ('V', 18, s32) | 752 | #define VIDIOC_STREAMON32 _IOW ('V', 18, s32) |
@@ -721,6 +766,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
721 | struct v4l2_standard v2s; | 766 | struct v4l2_standard v2s; |
722 | struct v4l2_ext_controls v2ecs; | 767 | struct v4l2_ext_controls v2ecs; |
723 | struct v4l2_event v2ev; | 768 | struct v4l2_event v2ev; |
769 | struct v4l2_create_buffers v2crt; | ||
724 | unsigned long vx; | 770 | unsigned long vx; |
725 | int vi; | 771 | int vi; |
726 | } karg; | 772 | } karg; |
@@ -751,6 +797,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
751 | case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; | 797 | case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; |
752 | case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break; | 798 | case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break; |
753 | case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break; | 799 | case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break; |
800 | case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break; | ||
801 | case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break; | ||
754 | } | 802 | } |
755 | 803 | ||
756 | switch (cmd) { | 804 | switch (cmd) { |
@@ -775,6 +823,12 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
775 | compatible_arg = 0; | 823 | compatible_arg = 0; |
776 | break; | 824 | break; |
777 | 825 | ||
826 | case VIDIOC_CREATE_BUFS: | ||
827 | err = get_v4l2_create32(&karg.v2crt, up); | ||
828 | compatible_arg = 0; | ||
829 | break; | ||
830 | |||
831 | case VIDIOC_PREPARE_BUF: | ||
778 | case VIDIOC_QUERYBUF: | 832 | case VIDIOC_QUERYBUF: |
779 | case VIDIOC_QBUF: | 833 | case VIDIOC_QBUF: |
780 | case VIDIOC_DQBUF: | 834 | case VIDIOC_DQBUF: |
@@ -860,6 +914,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
860 | err = put_v4l2_format32(&karg.v2f, up); | 914 | err = put_v4l2_format32(&karg.v2f, up); |
861 | break; | 915 | break; |
862 | 916 | ||
917 | case VIDIOC_CREATE_BUFS: | ||
918 | err = put_v4l2_create32(&karg.v2crt, up); | ||
919 | break; | ||
920 | |||
863 | case VIDIOC_QUERYBUF: | 921 | case VIDIOC_QUERYBUF: |
864 | case VIDIOC_QBUF: | 922 | case VIDIOC_QBUF: |
865 | case VIDIOC_DQBUF: | 923 | case VIDIOC_DQBUF: |
@@ -959,6 +1017,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) | |||
959 | case VIDIOC_DQEVENT32: | 1017 | case VIDIOC_DQEVENT32: |
960 | case VIDIOC_SUBSCRIBE_EVENT: | 1018 | case VIDIOC_SUBSCRIBE_EVENT: |
961 | case VIDIOC_UNSUBSCRIBE_EVENT: | 1019 | case VIDIOC_UNSUBSCRIBE_EVENT: |
1020 | case VIDIOC_CREATE_BUFS32: | ||
1021 | case VIDIOC_PREPARE_BUF32: | ||
962 | ret = do_video_ioctl(file, cmd, arg); | 1022 | ret = do_video_ioctl(file, cmd, arg); |
963 | break; | 1023 | break; |
964 | 1024 | ||
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index fc8666ae408f..5552f8137571 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c | |||
@@ -210,6 +210,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) | |||
210 | "Disabled", | 210 | "Disabled", |
211 | "50 Hz", | 211 | "50 Hz", |
212 | "60 Hz", | 212 | "60 Hz", |
213 | "Auto", | ||
213 | NULL | 214 | NULL |
214 | }; | 215 | }; |
215 | static const char * const camera_exposure_auto[] = { | 216 | static const char * const camera_exposure_auto[] = { |
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index e6a2c3b302d4..9fc0ae8a526a 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | #include <linux/ioctl.h> | 22 | #include <linux/ioctl.h> |
23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
24 | #include <linux/slab.h> | ||
24 | #if defined(CONFIG_SPI) | 25 | #if defined(CONFIG_SPI) |
25 | #include <linux/spi/spi.h> | 26 | #include <linux/spi/spi.h> |
26 | #endif | 27 | #endif |
@@ -193,6 +194,13 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, | |||
193 | } | 194 | } |
194 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); | 195 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); |
195 | 196 | ||
197 | static void v4l2_device_release_subdev_node(struct video_device *vdev) | ||
198 | { | ||
199 | struct v4l2_subdev *sd = video_get_drvdata(vdev); | ||
200 | sd->devnode = NULL; | ||
201 | kfree(vdev); | ||
202 | } | ||
203 | |||
196 | int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) | 204 | int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) |
197 | { | 205 | { |
198 | struct video_device *vdev; | 206 | struct video_device *vdev; |
@@ -206,22 +214,40 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) | |||
206 | if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) | 214 | if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) |
207 | continue; | 215 | continue; |
208 | 216 | ||
209 | vdev = &sd->devnode; | 217 | vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); |
218 | if (!vdev) { | ||
219 | err = -ENOMEM; | ||
220 | goto clean_up; | ||
221 | } | ||
222 | |||
223 | video_set_drvdata(vdev, sd); | ||
210 | strlcpy(vdev->name, sd->name, sizeof(vdev->name)); | 224 | strlcpy(vdev->name, sd->name, sizeof(vdev->name)); |
211 | vdev->v4l2_dev = v4l2_dev; | 225 | vdev->v4l2_dev = v4l2_dev; |
212 | vdev->fops = &v4l2_subdev_fops; | 226 | vdev->fops = &v4l2_subdev_fops; |
213 | vdev->release = video_device_release_empty; | 227 | vdev->release = v4l2_device_release_subdev_node; |
214 | vdev->ctrl_handler = sd->ctrl_handler; | 228 | vdev->ctrl_handler = sd->ctrl_handler; |
215 | err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, | 229 | err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, |
216 | sd->owner); | 230 | sd->owner); |
217 | if (err < 0) | 231 | if (err < 0) { |
218 | return err; | 232 | kfree(vdev); |
233 | goto clean_up; | ||
234 | } | ||
219 | #if defined(CONFIG_MEDIA_CONTROLLER) | 235 | #if defined(CONFIG_MEDIA_CONTROLLER) |
220 | sd->entity.v4l.major = VIDEO_MAJOR; | 236 | sd->entity.v4l.major = VIDEO_MAJOR; |
221 | sd->entity.v4l.minor = vdev->minor; | 237 | sd->entity.v4l.minor = vdev->minor; |
222 | #endif | 238 | #endif |
239 | sd->devnode = vdev; | ||
223 | } | 240 | } |
224 | return 0; | 241 | return 0; |
242 | |||
243 | clean_up: | ||
244 | list_for_each_entry(sd, &v4l2_dev->subdevs, list) { | ||
245 | if (!sd->devnode) | ||
246 | break; | ||
247 | video_unregister_device(sd->devnode); | ||
248 | } | ||
249 | |||
250 | return err; | ||
225 | } | 251 | } |
226 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); | 252 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); |
227 | 253 | ||
@@ -247,7 +273,7 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) | |||
247 | if (v4l2_dev->mdev) | 273 | if (v4l2_dev->mdev) |
248 | media_device_unregister_entity(&sd->entity); | 274 | media_device_unregister_entity(&sd->entity); |
249 | #endif | 275 | #endif |
250 | video_unregister_device(&sd->devnode); | 276 | video_unregister_device(sd->devnode); |
251 | module_put(sd->owner); | 277 | module_put(sd->owner); |
252 | } | 278 | } |
253 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); | 279 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); |
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 24fd43322150..e1da8fc9dd2f 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c | |||
@@ -273,6 +273,8 @@ static const char *v4l2_ioctls[] = { | |||
273 | [_IOC_NR(VIDIOC_DQEVENT)] = "VIDIOC_DQEVENT", | 273 | [_IOC_NR(VIDIOC_DQEVENT)] = "VIDIOC_DQEVENT", |
274 | [_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)] = "VIDIOC_SUBSCRIBE_EVENT", | 274 | [_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)] = "VIDIOC_SUBSCRIBE_EVENT", |
275 | [_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT", | 275 | [_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT", |
276 | [_IOC_NR(VIDIOC_CREATE_BUFS)] = "VIDIOC_CREATE_BUFS", | ||
277 | [_IOC_NR(VIDIOC_PREPARE_BUF)] = "VIDIOC_PREPARE_BUF", | ||
276 | }; | 278 | }; |
277 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) | 279 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) |
278 | 280 | ||
@@ -2104,6 +2106,40 @@ static long __video_do_ioctl(struct file *file, | |||
2104 | dbgarg(cmd, "type=0x%8.8x", sub->type); | 2106 | dbgarg(cmd, "type=0x%8.8x", sub->type); |
2105 | break; | 2107 | break; |
2106 | } | 2108 | } |
2109 | case VIDIOC_CREATE_BUFS: | ||
2110 | { | ||
2111 | struct v4l2_create_buffers *create = arg; | ||
2112 | |||
2113 | if (!ops->vidioc_create_bufs) | ||
2114 | break; | ||
2115 | if (ret_prio) { | ||
2116 | ret = ret_prio; | ||
2117 | break; | ||
2118 | } | ||
2119 | ret = check_fmt(ops, create->format.type); | ||
2120 | if (ret) | ||
2121 | break; | ||
2122 | |||
2123 | ret = ops->vidioc_create_bufs(file, fh, create); | ||
2124 | |||
2125 | dbgarg(cmd, "count=%d @ %d\n", create->count, create->index); | ||
2126 | break; | ||
2127 | } | ||
2128 | case VIDIOC_PREPARE_BUF: | ||
2129 | { | ||
2130 | struct v4l2_buffer *b = arg; | ||
2131 | |||
2132 | if (!ops->vidioc_prepare_buf) | ||
2133 | break; | ||
2134 | ret = check_fmt(ops, b->type); | ||
2135 | if (ret) | ||
2136 | break; | ||
2137 | |||
2138 | ret = ops->vidioc_prepare_buf(file, fh, b); | ||
2139 | |||
2140 | dbgarg(cmd, "index=%d", b->index); | ||
2141 | break; | ||
2142 | } | ||
2107 | default: | 2143 | default: |
2108 | if (!ops->vidioc_default) | 2144 | if (!ops->vidioc_default) |
2109 | break; | 2145 | break; |
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 3f5c7a38e6e8..979e544388cb 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c | |||
@@ -38,7 +38,8 @@ module_param(debug, int, 0644); | |||
38 | (((q)->ops->op) ? ((q)->ops->op(args)) : 0) | 38 | (((q)->ops->op) ? ((q)->ops->op(args)) : 0) |
39 | 39 | ||
40 | #define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ | 40 | #define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ |
41 | V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR) | 41 | V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \ |
42 | V4L2_BUF_FLAG_PREPARED) | ||
42 | 43 | ||
43 | /** | 44 | /** |
44 | * __vb2_buf_mem_alloc() - allocate video memory for the given buffer | 45 | * __vb2_buf_mem_alloc() - allocate video memory for the given buffer |
@@ -109,13 +110,22 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) | |||
109 | * __setup_offsets() - setup unique offsets ("cookies") for every plane in | 110 | * __setup_offsets() - setup unique offsets ("cookies") for every plane in |
110 | * every buffer on the queue | 111 | * every buffer on the queue |
111 | */ | 112 | */ |
112 | static void __setup_offsets(struct vb2_queue *q) | 113 | static void __setup_offsets(struct vb2_queue *q, unsigned int n) |
113 | { | 114 | { |
114 | unsigned int buffer, plane; | 115 | unsigned int buffer, plane; |
115 | struct vb2_buffer *vb; | 116 | struct vb2_buffer *vb; |
116 | unsigned long off = 0; | 117 | unsigned long off; |
117 | 118 | ||
118 | for (buffer = 0; buffer < q->num_buffers; ++buffer) { | 119 | if (q->num_buffers) { |
120 | struct v4l2_plane *p; | ||
121 | vb = q->bufs[q->num_buffers - 1]; | ||
122 | p = &vb->v4l2_planes[vb->num_planes - 1]; | ||
123 | off = PAGE_ALIGN(p->m.mem_offset + p->length); | ||
124 | } else { | ||
125 | off = 0; | ||
126 | } | ||
127 | |||
128 | for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) { | ||
119 | vb = q->bufs[buffer]; | 129 | vb = q->bufs[buffer]; |
120 | if (!vb) | 130 | if (!vb) |
121 | continue; | 131 | continue; |
@@ -161,7 +171,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, | |||
161 | vb->state = VB2_BUF_STATE_DEQUEUED; | 171 | vb->state = VB2_BUF_STATE_DEQUEUED; |
162 | vb->vb2_queue = q; | 172 | vb->vb2_queue = q; |
163 | vb->num_planes = num_planes; | 173 | vb->num_planes = num_planes; |
164 | vb->v4l2_buf.index = buffer; | 174 | vb->v4l2_buf.index = q->num_buffers + buffer; |
165 | vb->v4l2_buf.type = q->type; | 175 | vb->v4l2_buf.type = q->type; |
166 | vb->v4l2_buf.memory = memory; | 176 | vb->v4l2_buf.memory = memory; |
167 | 177 | ||
@@ -189,15 +199,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, | |||
189 | } | 199 | } |
190 | } | 200 | } |
191 | 201 | ||
192 | q->bufs[buffer] = vb; | 202 | q->bufs[q->num_buffers + buffer] = vb; |
193 | } | 203 | } |
194 | 204 | ||
195 | q->num_buffers = buffer; | 205 | __setup_offsets(q, buffer); |
196 | |||
197 | __setup_offsets(q); | ||
198 | 206 | ||
199 | dprintk(1, "Allocated %d buffers, %d plane(s) each\n", | 207 | dprintk(1, "Allocated %d buffers, %d plane(s) each\n", |
200 | q->num_buffers, num_planes); | 208 | buffer, num_planes); |
201 | 209 | ||
202 | return buffer; | 210 | return buffer; |
203 | } | 211 | } |
@@ -205,12 +213,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, | |||
205 | /** | 213 | /** |
206 | * __vb2_free_mem() - release all video buffer memory for a given queue | 214 | * __vb2_free_mem() - release all video buffer memory for a given queue |
207 | */ | 215 | */ |
208 | static void __vb2_free_mem(struct vb2_queue *q) | 216 | static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) |
209 | { | 217 | { |
210 | unsigned int buffer; | 218 | unsigned int buffer; |
211 | struct vb2_buffer *vb; | 219 | struct vb2_buffer *vb; |
212 | 220 | ||
213 | for (buffer = 0; buffer < q->num_buffers; ++buffer) { | 221 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; |
222 | ++buffer) { | ||
214 | vb = q->bufs[buffer]; | 223 | vb = q->bufs[buffer]; |
215 | if (!vb) | 224 | if (!vb) |
216 | continue; | 225 | continue; |
@@ -224,17 +233,18 @@ static void __vb2_free_mem(struct vb2_queue *q) | |||
224 | } | 233 | } |
225 | 234 | ||
226 | /** | 235 | /** |
227 | * __vb2_queue_free() - free the queue - video memory and related information | 236 | * __vb2_queue_free() - free buffers at the end of the queue - video memory and |
228 | * and return the queue to an uninitialized state. Might be called even if the | 237 | * related information, if no buffers are left return the queue to an |
229 | * queue has already been freed. | 238 | * uninitialized state. Might be called even if the queue has already been freed. |
230 | */ | 239 | */ |
231 | static void __vb2_queue_free(struct vb2_queue *q) | 240 | static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) |
232 | { | 241 | { |
233 | unsigned int buffer; | 242 | unsigned int buffer; |
234 | 243 | ||
235 | /* Call driver-provided cleanup function for each buffer, if provided */ | 244 | /* Call driver-provided cleanup function for each buffer, if provided */ |
236 | if (q->ops->buf_cleanup) { | 245 | if (q->ops->buf_cleanup) { |
237 | for (buffer = 0; buffer < q->num_buffers; ++buffer) { | 246 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; |
247 | ++buffer) { | ||
238 | if (NULL == q->bufs[buffer]) | 248 | if (NULL == q->bufs[buffer]) |
239 | continue; | 249 | continue; |
240 | q->ops->buf_cleanup(q->bufs[buffer]); | 250 | q->ops->buf_cleanup(q->bufs[buffer]); |
@@ -242,23 +252,25 @@ static void __vb2_queue_free(struct vb2_queue *q) | |||
242 | } | 252 | } |
243 | 253 | ||
244 | /* Release video buffer memory */ | 254 | /* Release video buffer memory */ |
245 | __vb2_free_mem(q); | 255 | __vb2_free_mem(q, buffers); |
246 | 256 | ||
247 | /* Free videobuf buffers */ | 257 | /* Free videobuf buffers */ |
248 | for (buffer = 0; buffer < q->num_buffers; ++buffer) { | 258 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; |
259 | ++buffer) { | ||
249 | kfree(q->bufs[buffer]); | 260 | kfree(q->bufs[buffer]); |
250 | q->bufs[buffer] = NULL; | 261 | q->bufs[buffer] = NULL; |
251 | } | 262 | } |
252 | 263 | ||
253 | q->num_buffers = 0; | 264 | q->num_buffers -= buffers; |
254 | q->memory = 0; | 265 | if (!q->num_buffers) |
266 | q->memory = 0; | ||
255 | } | 267 | } |
256 | 268 | ||
257 | /** | 269 | /** |
258 | * __verify_planes_array() - verify that the planes array passed in struct | 270 | * __verify_planes_array() - verify that the planes array passed in struct |
259 | * v4l2_buffer from userspace can be safely used | 271 | * v4l2_buffer from userspace can be safely used |
260 | */ | 272 | */ |
261 | static int __verify_planes_array(struct vb2_buffer *vb, struct v4l2_buffer *b) | 273 | static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b) |
262 | { | 274 | { |
263 | /* Is memory for copying plane information present? */ | 275 | /* Is memory for copying plane information present? */ |
264 | if (NULL == b->m.planes) { | 276 | if (NULL == b->m.planes) { |
@@ -318,7 +330,7 @@ static bool __buffers_in_use(struct vb2_queue *q) | |||
318 | static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) | 330 | static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) |
319 | { | 331 | { |
320 | struct vb2_queue *q = vb->vb2_queue; | 332 | struct vb2_queue *q = vb->vb2_queue; |
321 | int ret = 0; | 333 | int ret; |
322 | 334 | ||
323 | /* Copy back data such as timestamp, flags, input, etc. */ | 335 | /* Copy back data such as timestamp, flags, input, etc. */ |
324 | memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); | 336 | memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); |
@@ -365,6 +377,9 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) | |||
365 | case VB2_BUF_STATE_DONE: | 377 | case VB2_BUF_STATE_DONE: |
366 | b->flags |= V4L2_BUF_FLAG_DONE; | 378 | b->flags |= V4L2_BUF_FLAG_DONE; |
367 | break; | 379 | break; |
380 | case VB2_BUF_STATE_PREPARED: | ||
381 | b->flags |= V4L2_BUF_FLAG_PREPARED; | ||
382 | break; | ||
368 | case VB2_BUF_STATE_DEQUEUED: | 383 | case VB2_BUF_STATE_DEQUEUED: |
369 | /* nothing */ | 384 | /* nothing */ |
370 | break; | 385 | break; |
@@ -373,7 +388,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) | |||
373 | if (__buffer_in_use(q, vb)) | 388 | if (__buffer_in_use(q, vb)) |
374 | b->flags |= V4L2_BUF_FLAG_MAPPED; | 389 | b->flags |= V4L2_BUF_FLAG_MAPPED; |
375 | 390 | ||
376 | return ret; | 391 | return 0; |
377 | } | 392 | } |
378 | 393 | ||
379 | /** | 394 | /** |
@@ -459,7 +474,7 @@ static int __verify_mmap_ops(struct vb2_queue *q) | |||
459 | */ | 474 | */ |
460 | int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | 475 | int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) |
461 | { | 476 | { |
462 | unsigned int num_buffers, num_planes; | 477 | unsigned int num_buffers, allocated_buffers, num_planes = 0; |
463 | int ret = 0; | 478 | int ret = 0; |
464 | 479 | ||
465 | if (q->fileio) { | 480 | if (q->fileio) { |
@@ -507,7 +522,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | |||
507 | return -EBUSY; | 522 | return -EBUSY; |
508 | } | 523 | } |
509 | 524 | ||
510 | __vb2_queue_free(q); | 525 | __vb2_queue_free(q, q->num_buffers); |
511 | 526 | ||
512 | /* | 527 | /* |
513 | * In case of REQBUFS(0) return immediately without calling | 528 | * In case of REQBUFS(0) return immediately without calling |
@@ -529,7 +544,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | |||
529 | * Ask the driver how many buffers and planes per buffer it requires. | 544 | * Ask the driver how many buffers and planes per buffer it requires. |
530 | * Driver also sets the size and allocator context for each plane. | 545 | * Driver also sets the size and allocator context for each plane. |
531 | */ | 546 | */ |
532 | ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, | 547 | ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, |
533 | q->plane_sizes, q->alloc_ctx); | 548 | q->plane_sizes, q->alloc_ctx); |
534 | if (ret) | 549 | if (ret) |
535 | return ret; | 550 | return ret; |
@@ -541,44 +556,168 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | |||
541 | return -ENOMEM; | 556 | return -ENOMEM; |
542 | } | 557 | } |
543 | 558 | ||
559 | allocated_buffers = ret; | ||
560 | |||
544 | /* | 561 | /* |
545 | * Check if driver can handle the allocated number of buffers. | 562 | * Check if driver can handle the allocated number of buffers. |
546 | */ | 563 | */ |
547 | if (ret < num_buffers) { | 564 | if (allocated_buffers < num_buffers) { |
548 | unsigned int orig_num_buffers; | 565 | num_buffers = allocated_buffers; |
549 | 566 | ||
550 | orig_num_buffers = num_buffers = ret; | 567 | ret = call_qop(q, queue_setup, q, NULL, &num_buffers, |
551 | ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, | 568 | &num_planes, q->plane_sizes, q->alloc_ctx); |
552 | q->plane_sizes, q->alloc_ctx); | ||
553 | if (ret) | ||
554 | goto free_mem; | ||
555 | 569 | ||
556 | if (orig_num_buffers < num_buffers) { | 570 | if (!ret && allocated_buffers < num_buffers) |
557 | ret = -ENOMEM; | 571 | ret = -ENOMEM; |
558 | goto free_mem; | ||
559 | } | ||
560 | 572 | ||
561 | /* | 573 | /* |
562 | * Ok, driver accepted smaller number of buffers. | 574 | * Either the driver has accepted a smaller number of buffers, |
575 | * or .queue_setup() returned an error | ||
563 | */ | 576 | */ |
564 | ret = num_buffers; | 577 | } |
578 | |||
579 | q->num_buffers = allocated_buffers; | ||
580 | |||
581 | if (ret < 0) { | ||
582 | __vb2_queue_free(q, allocated_buffers); | ||
583 | return ret; | ||
565 | } | 584 | } |
566 | 585 | ||
567 | /* | 586 | /* |
568 | * Return the number of successfully allocated buffers | 587 | * Return the number of successfully allocated buffers |
569 | * to the userspace. | 588 | * to the userspace. |
570 | */ | 589 | */ |
571 | req->count = ret; | 590 | req->count = allocated_buffers; |
572 | 591 | ||
573 | return 0; | 592 | return 0; |
574 | |||
575 | free_mem: | ||
576 | __vb2_queue_free(q); | ||
577 | return ret; | ||
578 | } | 593 | } |
579 | EXPORT_SYMBOL_GPL(vb2_reqbufs); | 594 | EXPORT_SYMBOL_GPL(vb2_reqbufs); |
580 | 595 | ||
581 | /** | 596 | /** |
597 | * vb2_create_bufs() - Allocate buffers and any required auxiliary structs | ||
598 | * @q: videobuf2 queue | ||
599 | * @create: creation parameters, passed from userspace to vidioc_create_bufs | ||
600 | * handler in driver | ||
601 | * | ||
602 | * Should be called from vidioc_create_bufs ioctl handler of a driver. | ||
603 | * This function: | ||
604 | * 1) verifies parameter sanity | ||
605 | * 2) calls the .queue_setup() queue operation | ||
606 | * 3) performs any necessary memory allocations | ||
607 | * | ||
608 | * The return values from this function are intended to be directly returned | ||
609 | * from vidioc_create_bufs handler in driver. | ||
610 | */ | ||
611 | int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) | ||
612 | { | ||
613 | unsigned int num_planes = 0, num_buffers, allocated_buffers; | ||
614 | int ret = 0; | ||
615 | |||
616 | if (q->fileio) { | ||
617 | dprintk(1, "%s(): file io in progress\n", __func__); | ||
618 | return -EBUSY; | ||
619 | } | ||
620 | |||
621 | if (create->memory != V4L2_MEMORY_MMAP | ||
622 | && create->memory != V4L2_MEMORY_USERPTR) { | ||
623 | dprintk(1, "%s(): unsupported memory type\n", __func__); | ||
624 | return -EINVAL; | ||
625 | } | ||
626 | |||
627 | if (create->format.type != q->type) { | ||
628 | dprintk(1, "%s(): requested type is incorrect\n", __func__); | ||
629 | return -EINVAL; | ||
630 | } | ||
631 | |||
632 | /* | ||
633 | * Make sure all the required memory ops for given memory type | ||
634 | * are available. | ||
635 | */ | ||
636 | if (create->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) { | ||
637 | dprintk(1, "%s(): MMAP for current setup unsupported\n", __func__); | ||
638 | return -EINVAL; | ||
639 | } | ||
640 | |||
641 | if (create->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) { | ||
642 | dprintk(1, "%s(): USERPTR for current setup unsupported\n", __func__); | ||
643 | return -EINVAL; | ||
644 | } | ||
645 | |||
646 | if (q->num_buffers == VIDEO_MAX_FRAME) { | ||
647 | dprintk(1, "%s(): maximum number of buffers already allocated\n", | ||
648 | __func__); | ||
649 | return -ENOBUFS; | ||
650 | } | ||
651 | |||
652 | create->index = q->num_buffers; | ||
653 | |||
654 | if (!q->num_buffers) { | ||
655 | memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); | ||
656 | memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); | ||
657 | q->memory = create->memory; | ||
658 | } | ||
659 | |||
660 | num_buffers = min(create->count, VIDEO_MAX_FRAME - q->num_buffers); | ||
661 | |||
662 | /* | ||
663 | * Ask the driver, whether the requested number of buffers, planes per | ||
664 | * buffer and their sizes are acceptable | ||
665 | */ | ||
666 | ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, | ||
667 | &num_planes, q->plane_sizes, q->alloc_ctx); | ||
668 | if (ret) | ||
669 | return ret; | ||
670 | |||
671 | /* Finally, allocate buffers and video memory */ | ||
672 | ret = __vb2_queue_alloc(q, create->memory, num_buffers, | ||
673 | num_planes); | ||
674 | if (ret < 0) { | ||
675 | dprintk(1, "Memory allocation failed with error: %d\n", ret); | ||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | allocated_buffers = ret; | ||
680 | |||
681 | /* | ||
682 | * Check if driver can handle the so far allocated number of buffers. | ||
683 | */ | ||
684 | if (ret < num_buffers) { | ||
685 | num_buffers = ret; | ||
686 | |||
687 | /* | ||
688 | * q->num_buffers contains the total number of buffers, that the | ||
689 | * queue driver has set up | ||
690 | */ | ||
691 | ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, | ||
692 | &num_planes, q->plane_sizes, q->alloc_ctx); | ||
693 | |||
694 | if (!ret && allocated_buffers < num_buffers) | ||
695 | ret = -ENOMEM; | ||
696 | |||
697 | /* | ||
698 | * Either the driver has accepted a smaller number of buffers, | ||
699 | * or .queue_setup() returned an error | ||
700 | */ | ||
701 | } | ||
702 | |||
703 | q->num_buffers += allocated_buffers; | ||
704 | |||
705 | if (ret < 0) { | ||
706 | __vb2_queue_free(q, allocated_buffers); | ||
707 | return ret; | ||
708 | } | ||
709 | |||
710 | /* | ||
711 | * Return the number of successfully allocated buffers | ||
712 | * to the userspace. | ||
713 | */ | ||
714 | create->count = allocated_buffers; | ||
715 | |||
716 | return 0; | ||
717 | } | ||
718 | EXPORT_SYMBOL_GPL(vb2_create_bufs); | ||
719 | |||
720 | /** | ||
582 | * vb2_plane_vaddr() - Return a kernel virtual address of a given plane | 721 | * vb2_plane_vaddr() - Return a kernel virtual address of a given plane |
583 | * @vb: vb2_buffer to which the plane in question belongs to | 722 | * @vb: vb2_buffer to which the plane in question belongs to |
584 | * @plane_no: plane number for which the address is to be returned | 723 | * @plane_no: plane number for which the address is to be returned |
@@ -662,7 +801,7 @@ EXPORT_SYMBOL_GPL(vb2_buffer_done); | |||
662 | * __fill_vb2_buffer() - fill a vb2_buffer with information provided in | 801 | * __fill_vb2_buffer() - fill a vb2_buffer with information provided in |
663 | * a v4l2_buffer by the userspace | 802 | * a v4l2_buffer by the userspace |
664 | */ | 803 | */ |
665 | static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, | 804 | static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, |
666 | struct v4l2_plane *v4l2_planes) | 805 | struct v4l2_plane *v4l2_planes) |
667 | { | 806 | { |
668 | unsigned int plane; | 807 | unsigned int plane; |
@@ -726,7 +865,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, | |||
726 | /** | 865 | /** |
727 | * __qbuf_userptr() - handle qbuf of a USERPTR buffer | 866 | * __qbuf_userptr() - handle qbuf of a USERPTR buffer |
728 | */ | 867 | */ |
729 | static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) | 868 | static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) |
730 | { | 869 | { |
731 | struct v4l2_plane planes[VIDEO_MAX_PLANES]; | 870 | struct v4l2_plane planes[VIDEO_MAX_PLANES]; |
732 | struct vb2_queue *q = vb->vb2_queue; | 871 | struct vb2_queue *q = vb->vb2_queue; |
@@ -815,7 +954,7 @@ err: | |||
815 | /** | 954 | /** |
816 | * __qbuf_mmap() - handle qbuf of an MMAP buffer | 955 | * __qbuf_mmap() - handle qbuf of an MMAP buffer |
817 | */ | 956 | */ |
818 | static int __qbuf_mmap(struct vb2_buffer *vb, struct v4l2_buffer *b) | 957 | static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) |
819 | { | 958 | { |
820 | return __fill_vb2_buffer(vb, b, vb->v4l2_planes); | 959 | return __fill_vb2_buffer(vb, b, vb->v4l2_planes); |
821 | } | 960 | } |
@@ -832,6 +971,95 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) | |||
832 | q->ops->buf_queue(vb); | 971 | q->ops->buf_queue(vb); |
833 | } | 972 | } |
834 | 973 | ||
974 | static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) | ||
975 | { | ||
976 | struct vb2_queue *q = vb->vb2_queue; | ||
977 | int ret; | ||
978 | |||
979 | switch (q->memory) { | ||
980 | case V4L2_MEMORY_MMAP: | ||
981 | ret = __qbuf_mmap(vb, b); | ||
982 | break; | ||
983 | case V4L2_MEMORY_USERPTR: | ||
984 | ret = __qbuf_userptr(vb, b); | ||
985 | break; | ||
986 | default: | ||
987 | WARN(1, "Invalid queue type\n"); | ||
988 | ret = -EINVAL; | ||
989 | } | ||
990 | |||
991 | if (!ret) | ||
992 | ret = call_qop(q, buf_prepare, vb); | ||
993 | if (ret) | ||
994 | dprintk(1, "qbuf: buffer preparation failed: %d\n", ret); | ||
995 | else | ||
996 | vb->state = VB2_BUF_STATE_PREPARED; | ||
997 | |||
998 | return ret; | ||
999 | } | ||
1000 | |||
1001 | /** | ||
1002 | * vb2_prepare_buf() - Pass ownership of a buffer from userspace to the kernel | ||
1003 | * @q: videobuf2 queue | ||
1004 | * @b: buffer structure passed from userspace to vidioc_prepare_buf | ||
1005 | * handler in driver | ||
1006 | * | ||
1007 | * Should be called from vidioc_prepare_buf ioctl handler of a driver. | ||
1008 | * This function: | ||
1009 | * 1) verifies the passed buffer, | ||
1010 | * 2) calls buf_prepare callback in the driver (if provided), in which | ||
1011 | * driver-specific buffer initialization can be performed, | ||
1012 | * | ||
1013 | * The return values from this function are intended to be directly returned | ||
1014 | * from vidioc_prepare_buf handler in driver. | ||
1015 | */ | ||
1016 | int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) | ||
1017 | { | ||
1018 | struct vb2_buffer *vb; | ||
1019 | int ret; | ||
1020 | |||
1021 | if (q->fileio) { | ||
1022 | dprintk(1, "%s(): file io in progress\n", __func__); | ||
1023 | return -EBUSY; | ||
1024 | } | ||
1025 | |||
1026 | if (b->type != q->type) { | ||
1027 | dprintk(1, "%s(): invalid buffer type\n", __func__); | ||
1028 | return -EINVAL; | ||
1029 | } | ||
1030 | |||
1031 | if (b->index >= q->num_buffers) { | ||
1032 | dprintk(1, "%s(): buffer index out of range\n", __func__); | ||
1033 | return -EINVAL; | ||
1034 | } | ||
1035 | |||
1036 | vb = q->bufs[b->index]; | ||
1037 | if (NULL == vb) { | ||
1038 | /* Should never happen */ | ||
1039 | dprintk(1, "%s(): buffer is NULL\n", __func__); | ||
1040 | return -EINVAL; | ||
1041 | } | ||
1042 | |||
1043 | if (b->memory != q->memory) { | ||
1044 | dprintk(1, "%s(): invalid memory type\n", __func__); | ||
1045 | return -EINVAL; | ||
1046 | } | ||
1047 | |||
1048 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { | ||
1049 | dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state); | ||
1050 | return -EINVAL; | ||
1051 | } | ||
1052 | |||
1053 | ret = __buf_prepare(vb, b); | ||
1054 | if (ret < 0) | ||
1055 | return ret; | ||
1056 | |||
1057 | __fill_v4l2_buffer(vb, b); | ||
1058 | |||
1059 | return 0; | ||
1060 | } | ||
1061 | EXPORT_SYMBOL_GPL(vb2_prepare_buf); | ||
1062 | |||
835 | /** | 1063 | /** |
836 | * vb2_qbuf() - Queue a buffer from userspace | 1064 | * vb2_qbuf() - Queue a buffer from userspace |
837 | * @q: videobuf2 queue | 1065 | * @q: videobuf2 queue |
@@ -841,8 +1069,8 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) | |||
841 | * Should be called from vidioc_qbuf ioctl handler of a driver. | 1069 | * Should be called from vidioc_qbuf ioctl handler of a driver. |
842 | * This function: | 1070 | * This function: |
843 | * 1) verifies the passed buffer, | 1071 | * 1) verifies the passed buffer, |
844 | * 2) calls buf_prepare callback in the driver (if provided), in which | 1072 | * 2) if necessary, calls buf_prepare callback in the driver (if provided), in |
845 | * driver-specific buffer initialization can be performed, | 1073 | * which driver-specific buffer initialization can be performed, |
846 | * 3) if streaming is on, queues the buffer in driver by the means of buf_queue | 1074 | * 3) if streaming is on, queues the buffer in driver by the means of buf_queue |
847 | * callback for processing. | 1075 | * callback for processing. |
848 | * | 1076 | * |
@@ -852,7 +1080,7 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) | |||
852 | int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) | 1080 | int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) |
853 | { | 1081 | { |
854 | struct vb2_buffer *vb; | 1082 | struct vb2_buffer *vb; |
855 | int ret = 0; | 1083 | int ret; |
856 | 1084 | ||
857 | if (q->fileio) { | 1085 | if (q->fileio) { |
858 | dprintk(1, "qbuf: file io in progress\n"); | 1086 | dprintk(1, "qbuf: file io in progress\n"); |
@@ -881,29 +1109,18 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) | |||
881 | return -EINVAL; | 1109 | return -EINVAL; |
882 | } | 1110 | } |
883 | 1111 | ||
884 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { | 1112 | switch (vb->state) { |
1113 | case VB2_BUF_STATE_DEQUEUED: | ||
1114 | ret = __buf_prepare(vb, b); | ||
1115 | if (ret) | ||
1116 | return ret; | ||
1117 | case VB2_BUF_STATE_PREPARED: | ||
1118 | break; | ||
1119 | default: | ||
885 | dprintk(1, "qbuf: buffer already in use\n"); | 1120 | dprintk(1, "qbuf: buffer already in use\n"); |
886 | return -EINVAL; | 1121 | return -EINVAL; |
887 | } | 1122 | } |
888 | 1123 | ||
889 | if (q->memory == V4L2_MEMORY_MMAP) | ||
890 | ret = __qbuf_mmap(vb, b); | ||
891 | else if (q->memory == V4L2_MEMORY_USERPTR) | ||
892 | ret = __qbuf_userptr(vb, b); | ||
893 | else { | ||
894 | WARN(1, "Invalid queue type\n"); | ||
895 | return -EINVAL; | ||
896 | } | ||
897 | |||
898 | if (ret) | ||
899 | return ret; | ||
900 | |||
901 | ret = call_qop(q, buf_prepare, vb); | ||
902 | if (ret) { | ||
903 | dprintk(1, "qbuf: buffer preparation failed\n"); | ||
904 | return ret; | ||
905 | } | ||
906 | |||
907 | /* | 1124 | /* |
908 | * Add to the queued buffers list, a buffer will stay on it until | 1125 | * Add to the queued buffers list, a buffer will stay on it until |
909 | * dequeued in dqbuf. | 1126 | * dequeued in dqbuf. |
@@ -918,6 +1135,9 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) | |||
918 | if (q->streaming) | 1135 | if (q->streaming) |
919 | __enqueue_in_driver(vb); | 1136 | __enqueue_in_driver(vb); |
920 | 1137 | ||
1138 | /* Fill buffer information for the userspace */ | ||
1139 | __fill_v4l2_buffer(vb, b); | ||
1140 | |||
921 | dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index); | 1141 | dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index); |
922 | return 0; | 1142 | return 0; |
923 | } | 1143 | } |
@@ -1347,6 +1567,37 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) | |||
1347 | } | 1567 | } |
1348 | EXPORT_SYMBOL_GPL(vb2_mmap); | 1568 | EXPORT_SYMBOL_GPL(vb2_mmap); |
1349 | 1569 | ||
1570 | #ifndef CONFIG_MMU | ||
1571 | unsigned long vb2_get_unmapped_area(struct vb2_queue *q, | ||
1572 | unsigned long addr, | ||
1573 | unsigned long len, | ||
1574 | unsigned long pgoff, | ||
1575 | unsigned long flags) | ||
1576 | { | ||
1577 | unsigned long off = pgoff << PAGE_SHIFT; | ||
1578 | struct vb2_buffer *vb; | ||
1579 | unsigned int buffer, plane; | ||
1580 | int ret; | ||
1581 | |||
1582 | if (q->memory != V4L2_MEMORY_MMAP) { | ||
1583 | dprintk(1, "Queue is not currently set up for mmap\n"); | ||
1584 | return -EINVAL; | ||
1585 | } | ||
1586 | |||
1587 | /* | ||
1588 | * Find the plane corresponding to the offset passed by userspace. | ||
1589 | */ | ||
1590 | ret = __find_plane_by_offset(q, off, &buffer, &plane); | ||
1591 | if (ret) | ||
1592 | return ret; | ||
1593 | |||
1594 | vb = q->bufs[buffer]; | ||
1595 | |||
1596 | return (unsigned long)vb2_plane_vaddr(vb, plane); | ||
1597 | } | ||
1598 | EXPORT_SYMBOL_GPL(vb2_get_unmapped_area); | ||
1599 | #endif | ||
1600 | |||
1350 | static int __vb2_init_fileio(struct vb2_queue *q, int read); | 1601 | static int __vb2_init_fileio(struct vb2_queue *q, int read); |
1351 | static int __vb2_cleanup_fileio(struct vb2_queue *q); | 1602 | static int __vb2_cleanup_fileio(struct vb2_queue *q); |
1352 | 1603 | ||
@@ -1464,7 +1715,7 @@ void vb2_queue_release(struct vb2_queue *q) | |||
1464 | { | 1715 | { |
1465 | __vb2_cleanup_fileio(q); | 1716 | __vb2_cleanup_fileio(q); |
1466 | __vb2_queue_cancel(q); | 1717 | __vb2_queue_cancel(q); |
1467 | __vb2_queue_free(q); | 1718 | __vb2_queue_free(q, q->num_buffers); |
1468 | } | 1719 | } |
1469 | EXPORT_SYMBOL_GPL(vb2_queue_release); | 1720 | EXPORT_SYMBOL_GPL(vb2_queue_release); |
1470 | 1721 | ||
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 7cf94c09d99a..7d754fbcccbf 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c | |||
@@ -650,9 +650,9 @@ static void vivi_stop_generating(struct vivi_dev *dev) | |||
650 | /* ------------------------------------------------------------------ | 650 | /* ------------------------------------------------------------------ |
651 | Videobuf operations | 651 | Videobuf operations |
652 | ------------------------------------------------------------------*/ | 652 | ------------------------------------------------------------------*/ |
653 | static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | 653 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, |
654 | unsigned int *nplanes, unsigned int sizes[], | 654 | unsigned int *nbuffers, unsigned int *nplanes, |
655 | void *alloc_ctxs[]) | 655 | unsigned int sizes[], void *alloc_ctxs[]) |
656 | { | 656 | { |
657 | struct vivi_dev *dev = vb2_get_drv_priv(vq); | 657 | struct vivi_dev *dev = vb2_get_drv_priv(vq); |
658 | unsigned long size; | 658 | unsigned long size; |