diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-09 22:50:49 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-09 22:50:49 -0500 |
commit | 3e7468313758913c5e4d372f35b271b96bad1298 (patch) | |
tree | eb612d252a9e2349a1173451cd779beebd18a33e /drivers/media/video/cx23885 | |
parent | 6825fbc4cb219f2c98bb7d157915d797cf5cb823 (diff) | |
parent | e97f4677961f68e29bd906022ebf60a6df7f530a (diff) |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (345 commits)
V4L/DVB (13542): ir-keytable: Allow dynamic table change
V4L/DVB (13541): atbm8830: replace 64-bit division and floating point usage
V4L/DVB (13540): ir-common: Cleanup get key evdev code
V4L/DVB (13539): ir-common: add __func__ for debug messages
V4L/DVB (13538): ir-common: Use a dynamic keycode table
V4L/DVB (13537): ir: Prepare the code for dynamic keycode table allocation
V4L/DVB (13536): em28xx: Use the full RC5 code on HVR-950 Remote Controller
V4L/DVB (13535): ir-common: Add a hauppauge new table with the complete RC5 code
V4L/DVB (13534): ir-common: Remove some unused fields/structs
V4L/DVB (13533): ir: use dynamic tables, instead of static ones
V4L/DVB (13532): ir-common: Add infrastructure to use a dynamic keycode table
V4L/DVB (13531): ir-common: rename the debug routine to allow exporting it
V4L/DVB (13458): go7007: subdev conversion
V4L/DVB (13457): s2250: subdev conversion
V4L/DVB (13456): s2250: Change module structure
V4L/DVB (13528): em28xx: add support for em2800 VC211A card
em28xx: don't reduce scale to half size for em2800
em28xx: don't load audio modules when AC97 is mis-detected
em28xx: em2800 chips support max width of 640
V4L/DVB (13523): dvb-bt8xx: fix compile warning
...
Fix up trivial conflicts due to spelling fixes from the trivial tree in
Documentation/video4linux/gspca.txt
drivers/media/video/cx18/cx18-mailbox.h
Diffstat (limited to 'drivers/media/video/cx23885')
19 files changed, 2705 insertions, 100 deletions
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index fd3fc3e3198a..bcdda9a9aa96 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig | |||
@@ -18,7 +18,9 @@ config VIDEO_CX23885 | |||
18 | select DVB_TDA10048 if !DVB_FE_CUSTOMISE | 18 | select DVB_TDA10048 if !DVB_FE_CUSTOMISE |
19 | select DVB_LNBP21 if !DVB_FE_CUSTOMISE | 19 | select DVB_LNBP21 if !DVB_FE_CUSTOMISE |
20 | select DVB_STV6110 if !DVB_FE_CUSTOMISE | 20 | select DVB_STV6110 if !DVB_FE_CUSTOMISE |
21 | select DVB_CX24116 if !DVB_FE_CUSTOMISE | ||
21 | select DVB_STV0900 if !DVB_FE_CUSTOMISE | 22 | select DVB_STV0900 if !DVB_FE_CUSTOMISE |
23 | select DVB_DS3000 if !DVB_FE_CUSTOMISE | ||
22 | select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE | 24 | select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE |
23 | select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE | 25 | select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE |
24 | select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE | 26 | select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE |
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile index ab8ea35c9bfb..5787ae243631 100644 --- a/drivers/media/video/cx23885/Makefile +++ b/drivers/media/video/cx23885/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \ | 1 | cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \ |
2 | cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \ | 2 | cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \ |
3 | netup-init.o cimax2.o netup-eeprom.o | 3 | cx23885-ioctl.o cx23885-ir.o cx23885-input.o cx23888-ir.o \ |
4 | netup-init.o cimax2.o netup-eeprom.o cx23885-f300.o | ||
4 | 5 | ||
5 | obj-$(CONFIG_VIDEO_CX23885) += cx23885.o | 6 | obj-$(CONFIG_VIDEO_CX23885) += cx23885.o |
6 | 7 | ||
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 6c3b51ce3372..0eed852c61e9 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <media/cx2341x.h> | 37 | #include <media/cx2341x.h> |
38 | 38 | ||
39 | #include "cx23885.h" | 39 | #include "cx23885.h" |
40 | #include "cx23885-ioctl.h" | ||
40 | 41 | ||
41 | #define CX23885_FIRM_IMAGE_SIZE 376836 | 42 | #define CX23885_FIRM_IMAGE_SIZE 376836 |
42 | #define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw" | 43 | #define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw" |
@@ -318,7 +319,7 @@ static int mc417_wait_ready(struct cx23885_dev *dev) | |||
318 | } | 319 | } |
319 | } | 320 | } |
320 | 321 | ||
321 | static int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value) | 322 | int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value) |
322 | { | 323 | { |
323 | u32 regval; | 324 | u32 regval; |
324 | 325 | ||
@@ -382,7 +383,7 @@ static int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value) | |||
382 | return mc417_wait_ready(dev); | 383 | return mc417_wait_ready(dev); |
383 | } | 384 | } |
384 | 385 | ||
385 | static int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value) | 386 | int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value) |
386 | { | 387 | { |
387 | int retval; | 388 | int retval; |
388 | u32 regval; | 389 | u32 regval; |
@@ -1724,6 +1725,11 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { | |||
1724 | .vidioc_log_status = vidioc_log_status, | 1725 | .vidioc_log_status = vidioc_log_status, |
1725 | .vidioc_querymenu = vidioc_querymenu, | 1726 | .vidioc_querymenu = vidioc_querymenu, |
1726 | .vidioc_queryctrl = vidioc_queryctrl, | 1727 | .vidioc_queryctrl = vidioc_queryctrl, |
1728 | .vidioc_g_chip_ident = cx23885_g_chip_ident, | ||
1729 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1730 | .vidioc_g_register = cx23885_g_register, | ||
1731 | .vidioc_s_register = cx23885_s_register, | ||
1732 | #endif | ||
1727 | }; | 1733 | }; |
1728 | 1734 | ||
1729 | static struct video_device cx23885_mpeg_template = { | 1735 | static struct video_device cx23885_mpeg_template = { |
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index bfdf79f1033c..1ec48169277d 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "cx23885.h" | 28 | #include "cx23885.h" |
29 | #include "tuner-xc2028.h" | 29 | #include "tuner-xc2028.h" |
30 | #include "netup-init.h" | 30 | #include "netup-init.h" |
31 | #include "cx23888-ir.h" | ||
31 | 32 | ||
32 | /* ------------------------------------------------------------------ */ | 33 | /* ------------------------------------------------------------------ */ |
33 | /* board config info */ | 34 | /* board config info */ |
@@ -199,11 +200,61 @@ struct cx23885_board cx23885_boards[] = { | |||
199 | }, | 200 | }, |
200 | [CX23885_BOARD_MYGICA_X8506] = { | 201 | [CX23885_BOARD_MYGICA_X8506] = { |
201 | .name = "Mygica X8506 DMB-TH", | 202 | .name = "Mygica X8506 DMB-TH", |
203 | .tuner_type = TUNER_XC5000, | ||
204 | .tuner_addr = 0x61, | ||
205 | .porta = CX23885_ANALOG_VIDEO, | ||
202 | .portb = CX23885_MPEG_DVB, | 206 | .portb = CX23885_MPEG_DVB, |
207 | .input = { | ||
208 | { | ||
209 | .type = CX23885_VMUX_TELEVISION, | ||
210 | .vmux = CX25840_COMPOSITE2, | ||
211 | }, | ||
212 | { | ||
213 | .type = CX23885_VMUX_COMPOSITE1, | ||
214 | .vmux = CX25840_COMPOSITE8, | ||
215 | }, | ||
216 | { | ||
217 | .type = CX23885_VMUX_SVIDEO, | ||
218 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
219 | CX25840_SVIDEO_CHROMA4, | ||
220 | }, | ||
221 | { | ||
222 | .type = CX23885_VMUX_COMPONENT, | ||
223 | .vmux = CX25840_COMPONENT_ON | | ||
224 | CX25840_VIN1_CH1 | | ||
225 | CX25840_VIN6_CH2 | | ||
226 | CX25840_VIN7_CH3, | ||
227 | }, | ||
228 | }, | ||
203 | }, | 229 | }, |
204 | [CX23885_BOARD_MAGICPRO_PROHDTVE2] = { | 230 | [CX23885_BOARD_MAGICPRO_PROHDTVE2] = { |
205 | .name = "Magic-Pro ProHDTV Extreme 2", | 231 | .name = "Magic-Pro ProHDTV Extreme 2", |
232 | .tuner_type = TUNER_XC5000, | ||
233 | .tuner_addr = 0x61, | ||
234 | .porta = CX23885_ANALOG_VIDEO, | ||
206 | .portb = CX23885_MPEG_DVB, | 235 | .portb = CX23885_MPEG_DVB, |
236 | .input = { | ||
237 | { | ||
238 | .type = CX23885_VMUX_TELEVISION, | ||
239 | .vmux = CX25840_COMPOSITE2, | ||
240 | }, | ||
241 | { | ||
242 | .type = CX23885_VMUX_COMPOSITE1, | ||
243 | .vmux = CX25840_COMPOSITE8, | ||
244 | }, | ||
245 | { | ||
246 | .type = CX23885_VMUX_SVIDEO, | ||
247 | .vmux = CX25840_SVIDEO_LUMA3 | | ||
248 | CX25840_SVIDEO_CHROMA4, | ||
249 | }, | ||
250 | { | ||
251 | .type = CX23885_VMUX_COMPONENT, | ||
252 | .vmux = CX25840_COMPONENT_ON | | ||
253 | CX25840_VIN1_CH1 | | ||
254 | CX25840_VIN6_CH2 | | ||
255 | CX25840_VIN7_CH3, | ||
256 | }, | ||
257 | }, | ||
207 | }, | 258 | }, |
208 | [CX23885_BOARD_HAUPPAUGE_HVR1850] = { | 259 | [CX23885_BOARD_HAUPPAUGE_HVR1850] = { |
209 | .name = "Hauppauge WinTV-HVR1850", | 260 | .name = "Hauppauge WinTV-HVR1850", |
@@ -214,6 +265,15 @@ struct cx23885_board cx23885_boards[] = { | |||
214 | .name = "Compro VideoMate E800", | 265 | .name = "Compro VideoMate E800", |
215 | .portc = CX23885_MPEG_DVB, | 266 | .portc = CX23885_MPEG_DVB, |
216 | }, | 267 | }, |
268 | [CX23885_BOARD_HAUPPAUGE_HVR1290] = { | ||
269 | .name = "Hauppauge WinTV-HVR1290", | ||
270 | .portc = CX23885_MPEG_DVB, | ||
271 | }, | ||
272 | [CX23885_BOARD_MYGICA_X8558PRO] = { | ||
273 | .name = "Mygica X8558 PRO DMB-TH", | ||
274 | .portb = CX23885_MPEG_DVB, | ||
275 | .portc = CX23885_MPEG_DVB, | ||
276 | }, | ||
217 | }; | 277 | }; |
218 | const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); | 278 | const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); |
219 | 279 | ||
@@ -349,6 +409,14 @@ struct cx23885_subid cx23885_subids[] = { | |||
349 | .subvendor = 0x1858, | 409 | .subvendor = 0x1858, |
350 | .subdevice = 0xe800, | 410 | .subdevice = 0xe800, |
351 | .card = CX23885_BOARD_COMPRO_VIDEOMATE_E800, | 411 | .card = CX23885_BOARD_COMPRO_VIDEOMATE_E800, |
412 | }, { | ||
413 | .subvendor = 0x0070, | ||
414 | .subdevice = 0x8551, | ||
415 | .card = CX23885_BOARD_HAUPPAUGE_HVR1290, | ||
416 | }, { | ||
417 | .subvendor = 0x14f1, | ||
418 | .subdevice = 0x8578, | ||
419 | .card = CX23885_BOARD_MYGICA_X8558PRO, | ||
352 | }, | 420 | }, |
353 | }; | 421 | }; |
354 | const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); | 422 | const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); |
@@ -509,9 +577,13 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) | |||
509 | * DVB-T and MPEG2 HW Encoder */ | 577 | * DVB-T and MPEG2 HW Encoder */ |
510 | break; | 578 | break; |
511 | case 85021: | 579 | case 85021: |
512 | /* WinTV-HVR1850 (PCIe, OEM, RCA in, IR, FM, | 580 | /* WinTV-HVR1850 (PCIe, Retail, 3.5mm in, IR, FM, |
513 | Dual channel ATSC and MPEG2 HW Encoder */ | 581 | Dual channel ATSC and MPEG2 HW Encoder */ |
514 | break; | 582 | break; |
583 | case 85721: | ||
584 | /* WinTV-HVR1290 (PCIe, OEM, RCA in, IR, | ||
585 | Dual channel ATSC and Basic analog */ | ||
586 | break; | ||
515 | default: | 587 | default: |
516 | printk(KERN_WARNING "%s: warning: " | 588 | printk(KERN_WARNING "%s: warning: " |
517 | "unknown hauppauge model #%d\n", | 589 | "unknown hauppauge model #%d\n", |
@@ -710,10 +782,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) | |||
710 | cx_set(GP0_IO, 0x00040004); | 782 | cx_set(GP0_IO, 0x00040004); |
711 | break; | 783 | break; |
712 | case CX23885_BOARD_TBS_6920: | 784 | case CX23885_BOARD_TBS_6920: |
713 | case CX23885_BOARD_TEVII_S470: | ||
714 | cx_write(MC417_CTL, 0x00000036); | 785 | cx_write(MC417_CTL, 0x00000036); |
715 | cx_write(MC417_OEN, 0x00001000); | 786 | cx_write(MC417_OEN, 0x00001000); |
716 | cx_write(MC417_RWD, 0x00001800); | 787 | cx_set(MC417_RWD, 0x00000002); |
788 | mdelay(200); | ||
789 | cx_clear(MC417_RWD, 0x00000800); | ||
790 | mdelay(200); | ||
791 | cx_set(MC417_RWD, 0x00000800); | ||
792 | mdelay(200); | ||
717 | break; | 793 | break; |
718 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | 794 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: |
719 | /* GPIO-0 INTA from CiMax1 | 795 | /* GPIO-0 INTA from CiMax1 |
@@ -758,15 +834,26 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) | |||
758 | break; | 834 | break; |
759 | case CX23885_BOARD_MYGICA_X8506: | 835 | case CX23885_BOARD_MYGICA_X8506: |
760 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | 836 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: |
837 | /* GPIO-0 (0)Analog / (1)Digital TV */ | ||
761 | /* GPIO-1 reset XC5000 */ | 838 | /* GPIO-1 reset XC5000 */ |
762 | /* GPIO-2 reset LGS8GL5 / LGS8G75 */ | 839 | /* GPIO-2 reset LGS8GL5 / LGS8G75 */ |
763 | cx_set(GP0_IO, 0x00060000); | 840 | cx23885_gpio_enable(dev, GPIO_0 | GPIO_1 | GPIO_2, 1); |
764 | cx_clear(GP0_IO, 0x00000006); | 841 | cx23885_gpio_clear(dev, GPIO_1 | GPIO_2); |
765 | mdelay(100); | 842 | mdelay(100); |
766 | cx_set(GP0_IO, 0x00060006); | 843 | cx23885_gpio_set(dev, GPIO_0 | GPIO_1 | GPIO_2); |
844 | mdelay(100); | ||
845 | break; | ||
846 | case CX23885_BOARD_MYGICA_X8558PRO: | ||
847 | /* GPIO-0 reset first ATBM8830 */ | ||
848 | /* GPIO-1 reset second ATBM8830 */ | ||
849 | cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1); | ||
850 | cx23885_gpio_clear(dev, GPIO_0 | GPIO_1); | ||
851 | mdelay(100); | ||
852 | cx23885_gpio_set(dev, GPIO_0 | GPIO_1); | ||
767 | mdelay(100); | 853 | mdelay(100); |
768 | break; | 854 | break; |
769 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | 855 | case CX23885_BOARD_HAUPPAUGE_HVR1850: |
856 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
770 | /* GPIO-0 656_CLK */ | 857 | /* GPIO-0 656_CLK */ |
771 | /* GPIO-1 656_D0 */ | 858 | /* GPIO-1 656_D0 */ |
772 | /* GPIO-2 Wake# */ | 859 | /* GPIO-2 Wake# */ |
@@ -801,6 +888,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) | |||
801 | 888 | ||
802 | int cx23885_ir_init(struct cx23885_dev *dev) | 889 | int cx23885_ir_init(struct cx23885_dev *dev) |
803 | { | 890 | { |
891 | int ret = 0; | ||
804 | switch (dev->board) { | 892 | switch (dev->board) { |
805 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | 893 | case CX23885_BOARD_HAUPPAUGE_HVR1250: |
806 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | 894 | case CX23885_BOARD_HAUPPAUGE_HVR1500: |
@@ -812,15 +900,46 @@ int cx23885_ir_init(struct cx23885_dev *dev) | |||
812 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | 900 | case CX23885_BOARD_HAUPPAUGE_HVR1275: |
813 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | 901 | case CX23885_BOARD_HAUPPAUGE_HVR1255: |
814 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | 902 | case CX23885_BOARD_HAUPPAUGE_HVR1210: |
815 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
816 | /* FIXME: Implement me */ | 903 | /* FIXME: Implement me */ |
817 | break; | 904 | break; |
905 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
906 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
907 | ret = cx23888_ir_probe(dev); | ||
908 | if (ret) | ||
909 | break; | ||
910 | dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR); | ||
911 | dev->pci_irqmask |= PCI_MSK_IR; | ||
912 | break; | ||
818 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: | 913 | case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: |
819 | request_module("ir-kbd-i2c"); | 914 | request_module("ir-kbd-i2c"); |
820 | break; | 915 | break; |
821 | } | 916 | } |
822 | 917 | ||
823 | return 0; | 918 | return ret; |
919 | } | ||
920 | |||
921 | void cx23885_ir_fini(struct cx23885_dev *dev) | ||
922 | { | ||
923 | switch (dev->board) { | ||
924 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
925 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
926 | dev->pci_irqmask &= ~PCI_MSK_IR; | ||
927 | cx_clear(PCI_INT_MSK, PCI_MSK_IR); | ||
928 | cx23888_ir_remove(dev); | ||
929 | dev->sd_ir = NULL; | ||
930 | break; | ||
931 | } | ||
932 | } | ||
933 | |||
934 | void cx23885_ir_pci_int_enable(struct cx23885_dev *dev) | ||
935 | { | ||
936 | switch (dev->board) { | ||
937 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
938 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
939 | if (dev->sd_ir && (dev->pci_irqmask & PCI_MSK_IR)) | ||
940 | cx_set(PCI_INT_MSK, PCI_MSK_IR); | ||
941 | break; | ||
942 | } | ||
824 | } | 943 | } |
825 | 944 | ||
826 | void cx23885_card_setup(struct cx23885_dev *dev) | 945 | void cx23885_card_setup(struct cx23885_dev *dev) |
@@ -853,6 +972,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) | |||
853 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | 972 | case CX23885_BOARD_HAUPPAUGE_HVR1255: |
854 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | 973 | case CX23885_BOARD_HAUPPAUGE_HVR1210: |
855 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | 974 | case CX23885_BOARD_HAUPPAUGE_HVR1850: |
975 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
856 | if (dev->i2c_bus[0].i2c_rc == 0) | 976 | if (dev->i2c_bus[0].i2c_rc == 0) |
857 | hauppauge_eeprom(dev, eeprom+0xc0); | 977 | hauppauge_eeprom(dev, eeprom+0xc0); |
858 | break; | 978 | break; |
@@ -886,8 +1006,12 @@ void cx23885_card_setup(struct cx23885_dev *dev) | |||
886 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | 1006 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ |
887 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | 1007 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; |
888 | break; | 1008 | break; |
889 | case CX23885_BOARD_TEVII_S470: | ||
890 | case CX23885_BOARD_TBS_6920: | 1009 | case CX23885_BOARD_TBS_6920: |
1010 | ts1->gen_ctrl_val = 0x4; /* Parallel */ | ||
1011 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1012 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1013 | break; | ||
1014 | case CX23885_BOARD_TEVII_S470: | ||
891 | case CX23885_BOARD_DVBWORLD_2005: | 1015 | case CX23885_BOARD_DVBWORLD_2005: |
892 | ts1->gen_ctrl_val = 0x5; /* Parallel */ | 1016 | ts1->gen_ctrl_val = 0x5; /* Parallel */ |
893 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | 1017 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ |
@@ -907,6 +1031,14 @@ void cx23885_card_setup(struct cx23885_dev *dev) | |||
907 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | 1031 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ |
908 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | 1032 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; |
909 | break; | 1033 | break; |
1034 | case CX23885_BOARD_MYGICA_X8558PRO: | ||
1035 | ts1->gen_ctrl_val = 0x5; /* Parallel */ | ||
1036 | ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1037 | ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1038 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | ||
1039 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | ||
1040 | ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | ||
1041 | break; | ||
910 | case CX23885_BOARD_HAUPPAUGE_HVR1250: | 1042 | case CX23885_BOARD_HAUPPAUGE_HVR1250: |
911 | case CX23885_BOARD_HAUPPAUGE_HVR1500: | 1043 | case CX23885_BOARD_HAUPPAUGE_HVR1500: |
912 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | 1044 | case CX23885_BOARD_HAUPPAUGE_HVR1500Q: |
@@ -922,6 +1054,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) | |||
922 | case CX23885_BOARD_HAUPPAUGE_HVR1210: | 1054 | case CX23885_BOARD_HAUPPAUGE_HVR1210: |
923 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | 1055 | case CX23885_BOARD_HAUPPAUGE_HVR1850: |
924 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | 1056 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: |
1057 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
925 | default: | 1058 | default: |
926 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ | 1059 | ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ |
927 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | 1060 | ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ |
@@ -939,6 +1072,10 @@ void cx23885_card_setup(struct cx23885_dev *dev) | |||
939 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: | 1072 | case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: |
940 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | 1073 | case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: |
941 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: | 1074 | case CX23885_BOARD_COMPRO_VIDEOMATE_E800: |
1075 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
1076 | case CX23885_BOARD_MYGICA_X8506: | ||
1077 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
1078 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
942 | dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, | 1079 | dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, |
943 | &dev->i2c_bus[2].i2c_adap, | 1080 | &dev->i2c_bus[2].i2c_adap, |
944 | "cx25840", "cx25840", 0x88 >> 1, NULL); | 1081 | "cx25840", "cx25840", 0x88 >> 1, NULL); |
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index fa2d350e20fd..04b12d27bc13 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c | |||
@@ -32,6 +32,9 @@ | |||
32 | 32 | ||
33 | #include "cx23885.h" | 33 | #include "cx23885.h" |
34 | #include "cimax2.h" | 34 | #include "cimax2.h" |
35 | #include "cx23888-ir.h" | ||
36 | #include "cx23885-ir.h" | ||
37 | #include "cx23885-input.h" | ||
35 | 38 | ||
36 | MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); | 39 | MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); |
37 | MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); | 40 | MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); |
@@ -753,6 +756,23 @@ static void cx23885_dev_checkrevision(struct cx23885_dev *dev) | |||
753 | __func__, dev->hwrevision); | 756 | __func__, dev->hwrevision); |
754 | } | 757 | } |
755 | 758 | ||
759 | /* Find the first v4l2_subdev member of the group id in hw */ | ||
760 | struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw) | ||
761 | { | ||
762 | struct v4l2_subdev *result = NULL; | ||
763 | struct v4l2_subdev *sd; | ||
764 | |||
765 | spin_lock(&dev->v4l2_dev.lock); | ||
766 | v4l2_device_for_each_subdev(sd, &dev->v4l2_dev) { | ||
767 | if (sd->grp_id == hw) { | ||
768 | result = sd; | ||
769 | break; | ||
770 | } | ||
771 | } | ||
772 | spin_unlock(&dev->v4l2_dev.lock); | ||
773 | return result; | ||
774 | } | ||
775 | |||
756 | static int cx23885_dev_setup(struct cx23885_dev *dev) | 776 | static int cx23885_dev_setup(struct cx23885_dev *dev) |
757 | { | 777 | { |
758 | int i; | 778 | int i; |
@@ -899,7 +919,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) | |||
899 | cx23885_i2c_register(&dev->i2c_bus[1]); | 919 | cx23885_i2c_register(&dev->i2c_bus[1]); |
900 | cx23885_i2c_register(&dev->i2c_bus[2]); | 920 | cx23885_i2c_register(&dev->i2c_bus[2]); |
901 | cx23885_card_setup(dev); | 921 | cx23885_card_setup(dev); |
902 | call_all(dev, tuner, s_standby); | 922 | call_all(dev, core, s_power, 0); |
903 | cx23885_ir_init(dev); | 923 | cx23885_ir_init(dev); |
904 | 924 | ||
905 | if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { | 925 | if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { |
@@ -1637,6 +1657,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) | |||
1637 | u32 ts1_status, ts1_mask; | 1657 | u32 ts1_status, ts1_mask; |
1638 | u32 ts2_status, ts2_mask; | 1658 | u32 ts2_status, ts2_mask; |
1639 | int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; | 1659 | int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; |
1660 | bool ir_handled = false; | ||
1640 | 1661 | ||
1641 | pci_status = cx_read(PCI_INT_STAT); | 1662 | pci_status = cx_read(PCI_INT_STAT); |
1642 | pci_mask = cx_read(PCI_INT_MSK); | 1663 | pci_mask = cx_read(PCI_INT_MSK); |
@@ -1662,18 +1683,12 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) | |||
1662 | dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", | 1683 | dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", |
1663 | ts2_status, ts2_mask, ts2_count); | 1684 | ts2_status, ts2_mask, ts2_count); |
1664 | 1685 | ||
1665 | if ((pci_status & PCI_MSK_RISC_RD) || | 1686 | if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR | |
1666 | (pci_status & PCI_MSK_RISC_WR) || | 1687 | PCI_MSK_AL_RD | PCI_MSK_AL_WR | PCI_MSK_APB_DMA | |
1667 | (pci_status & PCI_MSK_AL_RD) || | 1688 | PCI_MSK_VID_C | PCI_MSK_VID_B | PCI_MSK_VID_A | |
1668 | (pci_status & PCI_MSK_AL_WR) || | 1689 | PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT | |
1669 | (pci_status & PCI_MSK_APB_DMA) || | 1690 | PCI_MSK_GPIO0 | PCI_MSK_GPIO1 | |
1670 | (pci_status & PCI_MSK_VID_C) || | 1691 | PCI_MSK_IR)) { |
1671 | (pci_status & PCI_MSK_VID_B) || | ||
1672 | (pci_status & PCI_MSK_VID_A) || | ||
1673 | (pci_status & PCI_MSK_AUD_INT) || | ||
1674 | (pci_status & PCI_MSK_AUD_EXT) || | ||
1675 | (pci_status & PCI_MSK_GPIO0) || | ||
1676 | (pci_status & PCI_MSK_GPIO1)) { | ||
1677 | 1692 | ||
1678 | if (pci_status & PCI_MSK_RISC_RD) | 1693 | if (pci_status & PCI_MSK_RISC_RD) |
1679 | dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", | 1694 | dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", |
@@ -1722,6 +1737,10 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) | |||
1722 | if (pci_status & PCI_MSK_GPIO1) | 1737 | if (pci_status & PCI_MSK_GPIO1) |
1723 | dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n", | 1738 | dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n", |
1724 | PCI_MSK_GPIO1); | 1739 | PCI_MSK_GPIO1); |
1740 | |||
1741 | if (pci_status & PCI_MSK_IR) | ||
1742 | dprintk(7, " (PCI_MSK_IR 0x%08x)\n", | ||
1743 | PCI_MSK_IR); | ||
1725 | } | 1744 | } |
1726 | 1745 | ||
1727 | if (cx23885_boards[dev->board].cimax > 0 && | 1746 | if (cx23885_boards[dev->board].cimax > 0 && |
@@ -1752,12 +1771,48 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) | |||
1752 | if (vida_status) | 1771 | if (vida_status) |
1753 | handled += cx23885_video_irq(dev, vida_status); | 1772 | handled += cx23885_video_irq(dev, vida_status); |
1754 | 1773 | ||
1774 | if (pci_status & PCI_MSK_IR) { | ||
1775 | v4l2_subdev_call(dev->sd_ir, ir, interrupt_service_routine, | ||
1776 | pci_status, &ir_handled); | ||
1777 | if (ir_handled) | ||
1778 | handled++; | ||
1779 | } | ||
1780 | |||
1755 | if (handled) | 1781 | if (handled) |
1756 | cx_write(PCI_INT_STAT, pci_status); | 1782 | cx_write(PCI_INT_STAT, pci_status); |
1757 | out: | 1783 | out: |
1758 | return IRQ_RETVAL(handled); | 1784 | return IRQ_RETVAL(handled); |
1759 | } | 1785 | } |
1760 | 1786 | ||
1787 | static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd, | ||
1788 | unsigned int notification, void *arg) | ||
1789 | { | ||
1790 | struct cx23885_dev *dev; | ||
1791 | |||
1792 | if (sd == NULL) | ||
1793 | return; | ||
1794 | |||
1795 | dev = to_cx23885(sd->v4l2_dev); | ||
1796 | |||
1797 | switch (notification) { | ||
1798 | case V4L2_SUBDEV_IR_RX_NOTIFY: /* Called in an IRQ context */ | ||
1799 | if (sd == dev->sd_ir) | ||
1800 | cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg); | ||
1801 | break; | ||
1802 | case V4L2_SUBDEV_IR_TX_NOTIFY: /* Called in an IRQ context */ | ||
1803 | if (sd == dev->sd_ir) | ||
1804 | cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg); | ||
1805 | break; | ||
1806 | } | ||
1807 | } | ||
1808 | |||
1809 | static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev) | ||
1810 | { | ||
1811 | INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler); | ||
1812 | INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler); | ||
1813 | dev->v4l2_dev.notify = cx23885_v4l2_dev_notify; | ||
1814 | } | ||
1815 | |||
1761 | static inline int encoder_on_portb(struct cx23885_dev *dev) | 1816 | static inline int encoder_on_portb(struct cx23885_dev *dev) |
1762 | { | 1817 | { |
1763 | return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER; | 1818 | return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER; |
@@ -1816,6 +1871,26 @@ void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask) | |||
1816 | printk(KERN_INFO "%s: Unsupported\n", dev->name); | 1871 | printk(KERN_INFO "%s: Unsupported\n", dev->name); |
1817 | } | 1872 | } |
1818 | 1873 | ||
1874 | u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask) | ||
1875 | { | ||
1876 | if (mask & 0x00000007) | ||
1877 | return (cx_read(GP0_IO) >> 8) & mask & 0x7; | ||
1878 | |||
1879 | if (mask & 0x0007fff8) { | ||
1880 | if (encoder_on_portb(dev) || encoder_on_portc(dev)) | ||
1881 | printk(KERN_ERR | ||
1882 | "%s: Reading GPIO moving on encoder ports\n", | ||
1883 | dev->name); | ||
1884 | return (cx_read(MC417_RWD) & ((mask & 0x7fff8) >> 3)) << 3; | ||
1885 | } | ||
1886 | |||
1887 | /* TODO: 23-19 */ | ||
1888 | if (mask & 0x00f80000) | ||
1889 | printk(KERN_INFO "%s: Unsupported\n", dev->name); | ||
1890 | |||
1891 | return 0; | ||
1892 | } | ||
1893 | |||
1819 | void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) | 1894 | void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) |
1820 | { | 1895 | { |
1821 | if ((mask & 0x00000007) && asoutput) | 1896 | if ((mask & 0x00000007) && asoutput) |
@@ -1854,6 +1929,9 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, | |||
1854 | if (err < 0) | 1929 | if (err < 0) |
1855 | goto fail_free; | 1930 | goto fail_free; |
1856 | 1931 | ||
1932 | /* Prepare to handle notifications from subdevices */ | ||
1933 | cx23885_v4l2_dev_notify_init(dev); | ||
1934 | |||
1857 | /* pci init */ | 1935 | /* pci init */ |
1858 | dev->pci = pci_dev; | 1936 | dev->pci = pci_dev; |
1859 | if (pci_enable_device(pci_dev)) { | 1937 | if (pci_enable_device(pci_dev)) { |
@@ -1896,6 +1974,14 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, | |||
1896 | break; | 1974 | break; |
1897 | } | 1975 | } |
1898 | 1976 | ||
1977 | /* | ||
1978 | * The CX2388[58] IR controller can start firing interrupts when | ||
1979 | * enabled, so these have to take place after the cx23885_irq() handler | ||
1980 | * is hooked up by the call to request_irq() above. | ||
1981 | */ | ||
1982 | cx23885_ir_pci_int_enable(dev); | ||
1983 | cx23885_input_init(dev); | ||
1984 | |||
1899 | return 0; | 1985 | return 0; |
1900 | 1986 | ||
1901 | fail_irq: | 1987 | fail_irq: |
@@ -1912,6 +1998,9 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev) | |||
1912 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); | 1998 | struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); |
1913 | struct cx23885_dev *dev = to_cx23885(v4l2_dev); | 1999 | struct cx23885_dev *dev = to_cx23885(v4l2_dev); |
1914 | 2000 | ||
2001 | cx23885_input_fini(dev); | ||
2002 | cx23885_ir_fini(dev); | ||
2003 | |||
1915 | cx23885_shutdown(dev); | 2004 | cx23885_shutdown(dev); |
1916 | 2005 | ||
1917 | pci_disable_device(pci_dev); | 2006 | pci_disable_device(pci_dev); |
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 16c6a921f40b..e45d2df08138 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include "tda18271.h" | 38 | #include "tda18271.h" |
39 | #include "lgdt330x.h" | 39 | #include "lgdt330x.h" |
40 | #include "xc5000.h" | 40 | #include "xc5000.h" |
41 | #include "max2165.h" | ||
41 | #include "tda10048.h" | 42 | #include "tda10048.h" |
42 | #include "tuner-xc2028.h" | 43 | #include "tuner-xc2028.h" |
43 | #include "tuner-simple.h" | 44 | #include "tuner-simple.h" |
@@ -54,6 +55,9 @@ | |||
54 | #include "netup-eeprom.h" | 55 | #include "netup-eeprom.h" |
55 | #include "netup-init.h" | 56 | #include "netup-init.h" |
56 | #include "lgdt3305.h" | 57 | #include "lgdt3305.h" |
58 | #include "atbm8830.h" | ||
59 | #include "ds3000.h" | ||
60 | #include "cx23885-f300.h" | ||
57 | 61 | ||
58 | static unsigned int debug; | 62 | static unsigned int debug; |
59 | 63 | ||
@@ -400,6 +404,7 @@ static struct stv0900_reg stv0900_ts_regs[] = { | |||
400 | 404 | ||
401 | static struct stv0900_config netup_stv0900_config = { | 405 | static struct stv0900_config netup_stv0900_config = { |
402 | .demod_address = 0x68, | 406 | .demod_address = 0x68, |
407 | .demod_mode = 1, /* dual */ | ||
403 | .xtal = 8000000, | 408 | .xtal = 8000000, |
404 | .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ | 409 | .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ |
405 | .diseqc_mode = 2,/* 2/3 PWM */ | 410 | .diseqc_mode = 2,/* 2/3 PWM */ |
@@ -414,34 +419,22 @@ static struct stv6110_config netup_stv6110_tunerconfig_a = { | |||
414 | .i2c_address = 0x60, | 419 | .i2c_address = 0x60, |
415 | .mclk = 16000000, | 420 | .mclk = 16000000, |
416 | .clk_div = 1, | 421 | .clk_div = 1, |
422 | .gain = 8, /* +16 dB - maximum gain */ | ||
417 | }; | 423 | }; |
418 | 424 | ||
419 | static struct stv6110_config netup_stv6110_tunerconfig_b = { | 425 | static struct stv6110_config netup_stv6110_tunerconfig_b = { |
420 | .i2c_address = 0x63, | 426 | .i2c_address = 0x63, |
421 | .mclk = 16000000, | 427 | .mclk = 16000000, |
422 | .clk_div = 1, | 428 | .clk_div = 1, |
429 | .gain = 8, /* +16 dB - maximum gain */ | ||
423 | }; | 430 | }; |
424 | 431 | ||
425 | static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | ||
426 | { | ||
427 | struct cx23885_tsport *port = fe->dvb->priv; | ||
428 | struct cx23885_dev *dev = port->dev; | ||
429 | |||
430 | if (voltage == SEC_VOLTAGE_18) | ||
431 | cx_write(MC417_RWD, 0x00001e00);/* GPIO-13 high */ | ||
432 | else if (voltage == SEC_VOLTAGE_13) | ||
433 | cx_write(MC417_RWD, 0x00001a00);/* GPIO-13 low */ | ||
434 | else | ||
435 | cx_write(MC417_RWD, 0x00001800);/* GPIO-12 low */ | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static struct cx24116_config tbs_cx24116_config = { | 432 | static struct cx24116_config tbs_cx24116_config = { |
440 | .demod_address = 0x05, | 433 | .demod_address = 0x55, |
441 | }; | 434 | }; |
442 | 435 | ||
443 | static struct cx24116_config tevii_cx24116_config = { | 436 | static struct ds3000_config tevii_ds3000_config = { |
444 | .demod_address = 0x55, | 437 | .demod_address = 0x68, |
445 | }; | 438 | }; |
446 | 439 | ||
447 | static struct cx24116_config dvbworld_cx24116_config = { | 440 | static struct cx24116_config dvbworld_cx24116_config = { |
@@ -486,11 +479,40 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, | |||
486 | break; | 479 | break; |
487 | } | 480 | } |
488 | break; | 481 | break; |
482 | case CX23885_BOARD_MYGICA_X8506: | ||
483 | case CX23885_BOARD_MAGICPRO_PROHDTVE2: | ||
484 | /* Select Digital TV */ | ||
485 | cx23885_gpio_set(dev, GPIO_0); | ||
486 | break; | ||
489 | } | 487 | } |
490 | return (port->set_frontend_save) ? | 488 | return 0; |
491 | port->set_frontend_save(fe, param) : -ENODEV; | ||
492 | } | 489 | } |
493 | 490 | ||
491 | static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe, | ||
492 | unsigned int cmd, void *parg, | ||
493 | unsigned int stage) | ||
494 | { | ||
495 | int err = 0; | ||
496 | |||
497 | switch (stage) { | ||
498 | case DVB_FE_IOCTL_PRE: | ||
499 | |||
500 | switch (cmd) { | ||
501 | case FE_SET_FRONTEND: | ||
502 | err = cx23885_dvb_set_frontend(fe, | ||
503 | (struct dvb_frontend_parameters *) parg); | ||
504 | break; | ||
505 | } | ||
506 | break; | ||
507 | |||
508 | case DVB_FE_IOCTL_POST: | ||
509 | /* no post-ioctl handling required */ | ||
510 | break; | ||
511 | } | ||
512 | return err; | ||
513 | }; | ||
514 | |||
515 | |||
494 | static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = { | 516 | static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = { |
495 | .prod = LGS8GXX_PROD_LGS8G75, | 517 | .prod = LGS8GXX_PROD_LGS8G75, |
496 | .demod_address = 0x19, | 518 | .demod_address = 0x19, |
@@ -511,6 +533,38 @@ static struct xc5000_config magicpro_prohdtve2_xc5000_config = { | |||
511 | .if_khz = 6500, | 533 | .if_khz = 6500, |
512 | }; | 534 | }; |
513 | 535 | ||
536 | static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = { | ||
537 | .prod = ATBM8830_PROD_8830, | ||
538 | .demod_address = 0x44, | ||
539 | .serial_ts = 0, | ||
540 | .ts_sampling_edge = 1, | ||
541 | .ts_clk_gated = 0, | ||
542 | .osc_clk_freq = 30400, /* in kHz */ | ||
543 | .if_freq = 0, /* zero IF */ | ||
544 | .zif_swap_iq = 1, | ||
545 | }; | ||
546 | |||
547 | static struct max2165_config mygic_x8558pro_max2165_cfg1 = { | ||
548 | .i2c_address = 0x60, | ||
549 | .osc_clk = 20 | ||
550 | }; | ||
551 | |||
552 | static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = { | ||
553 | .prod = ATBM8830_PROD_8830, | ||
554 | .demod_address = 0x44, | ||
555 | .serial_ts = 1, | ||
556 | .ts_sampling_edge = 1, | ||
557 | .ts_clk_gated = 0, | ||
558 | .osc_clk_freq = 30400, /* in kHz */ | ||
559 | .if_freq = 0, /* zero IF */ | ||
560 | .zif_swap_iq = 1, | ||
561 | }; | ||
562 | |||
563 | static struct max2165_config mygic_x8558pro_max2165_cfg2 = { | ||
564 | .i2c_address = 0x60, | ||
565 | .osc_clk = 20 | ||
566 | }; | ||
567 | |||
514 | static int dvb_register(struct cx23885_tsport *port) | 568 | static int dvb_register(struct cx23885_tsport *port) |
515 | { | 569 | { |
516 | struct cx23885_dev *dev = port->dev; | 570 | struct cx23885_dev *dev = port->dev; |
@@ -550,12 +604,6 @@ static int dvb_register(struct cx23885_tsport *port) | |||
550 | 0x60, &dev->i2c_bus[1].i2c_adap, | 604 | 0x60, &dev->i2c_bus[1].i2c_adap, |
551 | &hauppauge_hvr127x_config); | 605 | &hauppauge_hvr127x_config); |
552 | } | 606 | } |
553 | |||
554 | /* FIXME: temporary hack */ | ||
555 | /* define bridge override to set_frontend */ | ||
556 | port->set_frontend_save = fe0->dvb.frontend->ops.set_frontend; | ||
557 | fe0->dvb.frontend->ops.set_frontend = cx23885_dvb_set_frontend; | ||
558 | |||
559 | break; | 607 | break; |
560 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | 608 | case CX23885_BOARD_HAUPPAUGE_HVR1255: |
561 | i2c_bus = &dev->i2c_bus[0]; | 609 | i2c_bus = &dev->i2c_bus[0]; |
@@ -772,23 +820,23 @@ static int dvb_register(struct cx23885_tsport *port) | |||
772 | } | 820 | } |
773 | break; | 821 | break; |
774 | case CX23885_BOARD_TBS_6920: | 822 | case CX23885_BOARD_TBS_6920: |
775 | i2c_bus = &dev->i2c_bus[0]; | 823 | i2c_bus = &dev->i2c_bus[1]; |
776 | 824 | ||
777 | fe0->dvb.frontend = dvb_attach(cx24116_attach, | 825 | fe0->dvb.frontend = dvb_attach(cx24116_attach, |
778 | &tbs_cx24116_config, | 826 | &tbs_cx24116_config, |
779 | &i2c_bus->i2c_adap); | 827 | &i2c_bus->i2c_adap); |
780 | if (fe0->dvb.frontend != NULL) | 828 | if (fe0->dvb.frontend != NULL) |
781 | fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage; | 829 | fe0->dvb.frontend->ops.set_voltage = f300_set_voltage; |
782 | 830 | ||
783 | break; | 831 | break; |
784 | case CX23885_BOARD_TEVII_S470: | 832 | case CX23885_BOARD_TEVII_S470: |
785 | i2c_bus = &dev->i2c_bus[1]; | 833 | i2c_bus = &dev->i2c_bus[1]; |
786 | 834 | ||
787 | fe0->dvb.frontend = dvb_attach(cx24116_attach, | 835 | fe0->dvb.frontend = dvb_attach(ds3000_attach, |
788 | &tevii_cx24116_config, | 836 | &tevii_ds3000_config, |
789 | &i2c_bus->i2c_adap); | 837 | &i2c_bus->i2c_adap); |
790 | if (fe0->dvb.frontend != NULL) | 838 | if (fe0->dvb.frontend != NULL) |
791 | fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage; | 839 | fe0->dvb.frontend->ops.set_voltage = f300_set_voltage; |
792 | 840 | ||
793 | break; | 841 | break; |
794 | case CX23885_BOARD_DVBWORLD_2005: | 842 | case CX23885_BOARD_DVBWORLD_2005: |
@@ -814,8 +862,8 @@ static int dvb_register(struct cx23885_tsport *port) | |||
814 | if (!dvb_attach(lnbh24_attach, | 862 | if (!dvb_attach(lnbh24_attach, |
815 | fe0->dvb.frontend, | 863 | fe0->dvb.frontend, |
816 | &i2c_bus->i2c_adap, | 864 | &i2c_bus->i2c_adap, |
817 | LNBH24_PCL, | 865 | LNBH24_PCL | LNBH24_TTX, |
818 | LNBH24_TTX, 0x09)) | 866 | LNBH24_TEN, 0x09)) |
819 | printk(KERN_ERR | 867 | printk(KERN_ERR |
820 | "No LNBH24 found!\n"); | 868 | "No LNBH24 found!\n"); |
821 | 869 | ||
@@ -835,8 +883,8 @@ static int dvb_register(struct cx23885_tsport *port) | |||
835 | if (!dvb_attach(lnbh24_attach, | 883 | if (!dvb_attach(lnbh24_attach, |
836 | fe0->dvb.frontend, | 884 | fe0->dvb.frontend, |
837 | &i2c_bus->i2c_adap, | 885 | &i2c_bus->i2c_adap, |
838 | LNBH24_PCL, | 886 | LNBH24_PCL | LNBH24_TTX, |
839 | LNBH24_TTX, 0x0a)) | 887 | LNBH24_TEN, 0x0a)) |
840 | printk(KERN_ERR | 888 | printk(KERN_ERR |
841 | "No LNBH24 found!\n"); | 889 | "No LNBH24 found!\n"); |
842 | 890 | ||
@@ -872,6 +920,7 @@ static int dvb_register(struct cx23885_tsport *port) | |||
872 | } | 920 | } |
873 | break; | 921 | break; |
874 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | 922 | case CX23885_BOARD_HAUPPAUGE_HVR1850: |
923 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
875 | i2c_bus = &dev->i2c_bus[0]; | 924 | i2c_bus = &dev->i2c_bus[0]; |
876 | fe0->dvb.frontend = dvb_attach(s5h1411_attach, | 925 | fe0->dvb.frontend = dvb_attach(s5h1411_attach, |
877 | &hcw_s5h1411_config, | 926 | &hcw_s5h1411_config, |
@@ -881,6 +930,36 @@ static int dvb_register(struct cx23885_tsport *port) | |||
881 | 0x60, &dev->i2c_bus[0].i2c_adap, | 930 | 0x60, &dev->i2c_bus[0].i2c_adap, |
882 | &hauppauge_tda18271_config); | 931 | &hauppauge_tda18271_config); |
883 | break; | 932 | break; |
933 | case CX23885_BOARD_MYGICA_X8558PRO: | ||
934 | switch (port->nr) { | ||
935 | /* port B */ | ||
936 | case 1: | ||
937 | i2c_bus = &dev->i2c_bus[0]; | ||
938 | fe0->dvb.frontend = dvb_attach(atbm8830_attach, | ||
939 | &mygica_x8558pro_atbm8830_cfg1, | ||
940 | &i2c_bus->i2c_adap); | ||
941 | if (fe0->dvb.frontend != NULL) { | ||
942 | dvb_attach(max2165_attach, | ||
943 | fe0->dvb.frontend, | ||
944 | &i2c_bus->i2c_adap, | ||
945 | &mygic_x8558pro_max2165_cfg1); | ||
946 | } | ||
947 | break; | ||
948 | /* port C */ | ||
949 | case 2: | ||
950 | i2c_bus = &dev->i2c_bus[1]; | ||
951 | fe0->dvb.frontend = dvb_attach(atbm8830_attach, | ||
952 | &mygica_x8558pro_atbm8830_cfg2, | ||
953 | &i2c_bus->i2c_adap); | ||
954 | if (fe0->dvb.frontend != NULL) { | ||
955 | dvb_attach(max2165_attach, | ||
956 | fe0->dvb.frontend, | ||
957 | &i2c_bus->i2c_adap, | ||
958 | &mygic_x8558pro_max2165_cfg2); | ||
959 | } | ||
960 | break; | ||
961 | } | ||
962 | break; | ||
884 | 963 | ||
885 | default: | 964 | default: |
886 | printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " | 965 | printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " |
@@ -897,14 +976,15 @@ static int dvb_register(struct cx23885_tsport *port) | |||
897 | fe0->dvb.frontend->callback = cx23885_tuner_callback; | 976 | fe0->dvb.frontend->callback = cx23885_tuner_callback; |
898 | 977 | ||
899 | /* Put the analog decoder in standby to keep it quiet */ | 978 | /* Put the analog decoder in standby to keep it quiet */ |
900 | call_all(dev, tuner, s_standby); | 979 | call_all(dev, core, s_power, 0); |
901 | 980 | ||
902 | if (fe0->dvb.frontend->ops.analog_ops.standby) | 981 | if (fe0->dvb.frontend->ops.analog_ops.standby) |
903 | fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend); | 982 | fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend); |
904 | 983 | ||
905 | /* register everything */ | 984 | /* register everything */ |
906 | ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, | 985 | ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, |
907 | &dev->pci->dev, adapter_nr, 0); | 986 | &dev->pci->dev, adapter_nr, 0, |
987 | cx23885_dvb_fe_ioctl_override); | ||
908 | 988 | ||
909 | /* init CI & MAC */ | 989 | /* init CI & MAC */ |
910 | switch (dev->board) { | 990 | switch (dev->board) { |
diff --git a/drivers/media/video/cx23885/cx23885-f300.c b/drivers/media/video/cx23885/cx23885-f300.c new file mode 100644 index 000000000000..93998f220986 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-f300.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * Driver for Silicon Labs C8051F300 microcontroller. | ||
3 | * | ||
4 | * It is used for LNB power control in TeVii S470, | ||
5 | * TBS 6920 PCIe DVB-S2 cards. | ||
6 | * | ||
7 | * Microcontroller connected to cx23885 GPIO pins: | ||
8 | * GPIO0 - data - P0.3 F300 | ||
9 | * GPIO1 - reset - P0.2 F300 | ||
10 | * GPIO2 - clk - P0.1 F300 | ||
11 | * GPIO3 - busy - P0.0 F300 | ||
12 | * | ||
13 | * Copyright (C) 2009 Igor M. Liplianin <liplianin@me.by> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
29 | */ | ||
30 | |||
31 | #include "cx23885.h" | ||
32 | |||
33 | #define F300_DATA GPIO_0 | ||
34 | #define F300_RESET GPIO_1 | ||
35 | #define F300_CLK GPIO_2 | ||
36 | #define F300_BUSY GPIO_3 | ||
37 | |||
38 | static void f300_set_line(struct cx23885_dev *dev, u32 line, u8 lvl) | ||
39 | { | ||
40 | cx23885_gpio_enable(dev, line, 1); | ||
41 | if (lvl == 1) | ||
42 | cx23885_gpio_set(dev, line); | ||
43 | else | ||
44 | cx23885_gpio_clear(dev, line); | ||
45 | } | ||
46 | |||
47 | static u8 f300_get_line(struct cx23885_dev *dev, u32 line) | ||
48 | { | ||
49 | cx23885_gpio_enable(dev, line, 0); | ||
50 | |||
51 | return cx23885_gpio_get(dev, line); | ||
52 | } | ||
53 | |||
54 | static void f300_send_byte(struct cx23885_dev *dev, u8 dta) | ||
55 | { | ||
56 | u8 i; | ||
57 | |||
58 | for (i = 0; i < 8; i++) { | ||
59 | f300_set_line(dev, F300_CLK, 0); | ||
60 | udelay(30); | ||
61 | f300_set_line(dev, F300_DATA, (dta & 0x80) >> 7);/* msb first */ | ||
62 | udelay(30); | ||
63 | dta <<= 1; | ||
64 | f300_set_line(dev, F300_CLK, 1); | ||
65 | udelay(30); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | static u8 f300_get_byte(struct cx23885_dev *dev) | ||
70 | { | ||
71 | u8 i, dta = 0; | ||
72 | |||
73 | for (i = 0; i < 8; i++) { | ||
74 | f300_set_line(dev, F300_CLK, 0); | ||
75 | udelay(30); | ||
76 | dta <<= 1; | ||
77 | f300_set_line(dev, F300_CLK, 1); | ||
78 | udelay(30); | ||
79 | dta |= f300_get_line(dev, F300_DATA);/* msb first */ | ||
80 | |||
81 | } | ||
82 | |||
83 | return dta; | ||
84 | } | ||
85 | |||
86 | static u8 f300_xfer(struct dvb_frontend *fe, u8 *buf) | ||
87 | { | ||
88 | struct cx23885_tsport *port = fe->dvb->priv; | ||
89 | struct cx23885_dev *dev = port->dev; | ||
90 | u8 i, temp, ret = 0; | ||
91 | |||
92 | temp = buf[0]; | ||
93 | for (i = 0; i < buf[0]; i++) | ||
94 | temp += buf[i + 1]; | ||
95 | temp = (~temp + 1);/* get check sum */ | ||
96 | buf[1 + buf[0]] = temp; | ||
97 | |||
98 | f300_set_line(dev, F300_RESET, 1); | ||
99 | f300_set_line(dev, F300_CLK, 1); | ||
100 | udelay(30); | ||
101 | f300_set_line(dev, F300_DATA, 1); | ||
102 | msleep(1); | ||
103 | |||
104 | /* question: */ | ||
105 | f300_set_line(dev, F300_RESET, 0);/* begin to send data */ | ||
106 | msleep(1); | ||
107 | |||
108 | f300_send_byte(dev, 0xe0);/* the slave address is 0xe0, write */ | ||
109 | msleep(1); | ||
110 | |||
111 | temp = buf[0]; | ||
112 | temp += 2; | ||
113 | for (i = 0; i < temp; i++) | ||
114 | f300_send_byte(dev, buf[i]); | ||
115 | |||
116 | f300_set_line(dev, F300_RESET, 1);/* sent data over */ | ||
117 | f300_set_line(dev, F300_DATA, 1); | ||
118 | |||
119 | /* answer: */ | ||
120 | temp = 0; | ||
121 | for (i = 0; ((i < 8) & (temp == 0)); i++) { | ||
122 | msleep(1); | ||
123 | if (f300_get_line(dev, F300_BUSY) == 0) | ||
124 | temp = 1; | ||
125 | } | ||
126 | |||
127 | if (i > 7) { | ||
128 | printk(KERN_ERR "%s: timeout, the slave no response\n", | ||
129 | __func__); | ||
130 | ret = 1; /* timeout, the slave no response */ | ||
131 | } else { /* the slave not busy, prepare for getting data */ | ||
132 | f300_set_line(dev, F300_RESET, 0);/*ready...*/ | ||
133 | msleep(1); | ||
134 | f300_send_byte(dev, 0xe1);/* 0xe1 is Read */ | ||
135 | msleep(1); | ||
136 | temp = f300_get_byte(dev);/*get the data length */ | ||
137 | if (temp > 14) | ||
138 | temp = 14; | ||
139 | |||
140 | for (i = 0; i < (temp + 1); i++) | ||
141 | f300_get_byte(dev);/* get data to empty buffer */ | ||
142 | |||
143 | f300_set_line(dev, F300_RESET, 1);/* received data over */ | ||
144 | f300_set_line(dev, F300_DATA, 1); | ||
145 | } | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | ||
151 | { | ||
152 | u8 buf[16]; | ||
153 | |||
154 | buf[0] = 0x05; | ||
155 | buf[1] = 0x38;/* write port */ | ||
156 | buf[2] = 0x01;/* A port, lnb power */ | ||
157 | |||
158 | switch (voltage) { | ||
159 | case SEC_VOLTAGE_13: | ||
160 | buf[3] = 0x01;/* power on */ | ||
161 | buf[4] = 0x02;/* B port, H/V */ | ||
162 | buf[5] = 0x00;/*13V v*/ | ||
163 | break; | ||
164 | case SEC_VOLTAGE_18: | ||
165 | buf[3] = 0x01; | ||
166 | buf[4] = 0x02; | ||
167 | buf[5] = 0x01;/* 18V h*/ | ||
168 | break; | ||
169 | case SEC_VOLTAGE_OFF: | ||
170 | buf[3] = 0x00;/* power off */ | ||
171 | buf[4] = 0x00; | ||
172 | buf[5] = 0x00; | ||
173 | break; | ||
174 | } | ||
175 | |||
176 | return f300_xfer(fe, buf); | ||
177 | } | ||
diff --git a/drivers/media/video/cx23885/cx23885-f300.h b/drivers/media/video/cx23885/cx23885-f300.h new file mode 100644 index 000000000000..e73344c94963 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-f300.h | |||
@@ -0,0 +1,2 @@ | |||
1 | extern int f300_set_voltage(struct dvb_frontend *fe, | ||
2 | fe_sec_voltage_t voltage); | ||
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c new file mode 100644 index 000000000000..469e083dd5f8 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-input.c | |||
@@ -0,0 +1,427 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Infrared remote control input device | ||
5 | * | ||
6 | * Most of this file is | ||
7 | * | ||
8 | * Copyright (C) 2009 Andy Walls <awalls@radix.net> | ||
9 | * | ||
10 | * However, the cx23885_input_{init,fini} functions contained herein are | ||
11 | * derived from Linux kernel files linux/media/video/.../...-input.c marked as: | ||
12 | * | ||
13 | * Copyright (C) 2008 <srinivasa.deevi at conexant dot com> | ||
14 | * Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> | ||
15 | * Markus Rechberger <mrechberger@gmail.com> | ||
16 | * Mauro Carvalho Chehab <mchehab@infradead.org> | ||
17 | * Sascha Sommer <saschasommer@freenet.de> | ||
18 | * Copyright (C) 2004, 2005 Chris Pascoe | ||
19 | * Copyright (C) 2003, 2004 Gerd Knorr | ||
20 | * Copyright (C) 2003 Pavel Machek | ||
21 | * | ||
22 | * This program is free software; you can redistribute it and/or | ||
23 | * modify it under the terms of the GNU General Public License | ||
24 | * as published by the Free Software Foundation; either version 2 | ||
25 | * of the License, or (at your option) any later version. | ||
26 | * | ||
27 | * This program is distributed in the hope that it will be useful, | ||
28 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
29 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
30 | * GNU General Public License for more details. | ||
31 | * | ||
32 | * You should have received a copy of the GNU General Public License | ||
33 | * along with this program; if not, write to the Free Software | ||
34 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
35 | * 02110-1301, USA. | ||
36 | */ | ||
37 | |||
38 | #include <linux/input.h> | ||
39 | #include <media/ir-common.h> | ||
40 | #include <media/v4l2-subdev.h> | ||
41 | |||
42 | #include "cx23885.h" | ||
43 | |||
44 | #define RC5_BITS 14 | ||
45 | #define RC5_HALF_BITS (2*RC5_BITS) | ||
46 | #define RC5_HALF_BITS_MASK ((1 << RC5_HALF_BITS) - 1) | ||
47 | |||
48 | #define RC5_START_BITS_NORMAL 0x3 /* Command range 0 - 63 */ | ||
49 | #define RC5_START_BITS_EXTENDED 0x2 /* Command range 64 - 127 */ | ||
50 | |||
51 | #define RC5_EXTENDED_COMMAND_OFFSET 64 | ||
52 | |||
53 | static inline unsigned int rc5_command(u32 rc5_baseband) | ||
54 | { | ||
55 | return RC5_INSTR(rc5_baseband) + | ||
56 | ((RC5_START(rc5_baseband) == RC5_START_BITS_EXTENDED) | ||
57 | ? RC5_EXTENDED_COMMAND_OFFSET : 0); | ||
58 | } | ||
59 | |||
60 | static void cx23885_input_process_raw_rc5(struct cx23885_dev *dev) | ||
61 | { | ||
62 | struct card_ir *ir_input = dev->ir_input; | ||
63 | unsigned int code, command; | ||
64 | u32 rc5; | ||
65 | |||
66 | /* Ignore codes that are too short to be valid RC-5 */ | ||
67 | if (ir_input->last_bit < (RC5_HALF_BITS - 1)) | ||
68 | return; | ||
69 | |||
70 | /* The library has the manchester coding backwards; XOR to adapt. */ | ||
71 | code = (ir_input->code & RC5_HALF_BITS_MASK) ^ RC5_HALF_BITS_MASK; | ||
72 | rc5 = ir_rc5_decode(code); | ||
73 | |||
74 | switch (RC5_START(rc5)) { | ||
75 | case RC5_START_BITS_NORMAL: | ||
76 | break; | ||
77 | case RC5_START_BITS_EXTENDED: | ||
78 | /* Don't allow if the remote only emits standard commands */ | ||
79 | if (ir_input->start == RC5_START_BITS_NORMAL) | ||
80 | return; | ||
81 | break; | ||
82 | default: | ||
83 | return; | ||
84 | } | ||
85 | |||
86 | if (ir_input->addr != RC5_ADDR(rc5)) | ||
87 | return; | ||
88 | |||
89 | /* Don't generate a keypress for RC-5 auto-repeated keypresses */ | ||
90 | command = rc5_command(rc5); | ||
91 | if (RC5_TOGGLE(rc5) != RC5_TOGGLE(ir_input->last_rc5) || | ||
92 | command != rc5_command(ir_input->last_rc5) || | ||
93 | /* Catch T == 0, CMD == 0 (e.g. '0') as first keypress after init */ | ||
94 | RC5_START(ir_input->last_rc5) == 0) { | ||
95 | /* This keypress is differnet: not an auto repeat */ | ||
96 | ir_input_nokey(ir_input->dev, &ir_input->ir); | ||
97 | ir_input_keydown(ir_input->dev, &ir_input->ir, command); | ||
98 | } | ||
99 | ir_input->last_rc5 = rc5; | ||
100 | |||
101 | /* Schedule when we should do the key up event: ir_input_nokey() */ | ||
102 | mod_timer(&ir_input->timer_keyup, | ||
103 | jiffies + msecs_to_jiffies(ir_input->rc5_key_timeout)); | ||
104 | } | ||
105 | |||
106 | static void cx23885_input_next_pulse_width_rc5(struct cx23885_dev *dev, | ||
107 | u32 ns_pulse) | ||
108 | { | ||
109 | const int rc5_quarterbit_ns = 444444; /* 32 cycles/36 kHz/2 = 444 us */ | ||
110 | struct card_ir *ir_input = dev->ir_input; | ||
111 | int i, level, quarterbits, halfbits; | ||
112 | |||
113 | if (!ir_input->active) { | ||
114 | ir_input->active = 1; | ||
115 | /* assume an initial space that we may not detect or measure */ | ||
116 | ir_input->code = 0; | ||
117 | ir_input->last_bit = 0; | ||
118 | } | ||
119 | |||
120 | if (ns_pulse == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) { | ||
121 | ir_input->last_bit++; /* Account for the final space */ | ||
122 | ir_input->active = 0; | ||
123 | cx23885_input_process_raw_rc5(dev); | ||
124 | return; | ||
125 | } | ||
126 | |||
127 | level = (ns_pulse & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? 1 : 0; | ||
128 | |||
129 | /* Skip any leading space to sync to the start bit */ | ||
130 | if (ir_input->last_bit == 0 && level == 0) | ||
131 | return; | ||
132 | |||
133 | /* | ||
134 | * With valid RC-5 we can get up to two consecutive half-bits in a | ||
135 | * single pulse measurment. Experiments have shown that the duration | ||
136 | * of a half-bit can vary. Make sure we always end up with an even | ||
137 | * number of quarter bits at the same level (mark or space). | ||
138 | */ | ||
139 | ns_pulse &= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; | ||
140 | quarterbits = ns_pulse / rc5_quarterbit_ns; | ||
141 | if (quarterbits & 1) | ||
142 | quarterbits++; | ||
143 | halfbits = quarterbits / 2; | ||
144 | |||
145 | for (i = 0; i < halfbits; i++) { | ||
146 | ir_input->last_bit++; | ||
147 | ir_input->code |= (level << ir_input->last_bit); | ||
148 | |||
149 | if (ir_input->last_bit >= RC5_HALF_BITS-1) { | ||
150 | ir_input->active = 0; | ||
151 | cx23885_input_process_raw_rc5(dev); | ||
152 | /* | ||
153 | * If level is 1, a leading mark is invalid for RC5. | ||
154 | * If level is 0, we scan past extra intial space. | ||
155 | * Either way we don't want to reactivate collecting | ||
156 | * marks or spaces here with any left over half-bits. | ||
157 | */ | ||
158 | break; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | static void cx23885_input_process_pulse_widths_rc5(struct cx23885_dev *dev, | ||
164 | bool add_eom) | ||
165 | { | ||
166 | struct card_ir *ir_input = dev->ir_input; | ||
167 | struct ir_input_state *ir_input_state = &ir_input->ir; | ||
168 | |||
169 | u32 ns_pulse[RC5_HALF_BITS+1]; | ||
170 | ssize_t num = 0; | ||
171 | int count, i; | ||
172 | |||
173 | do { | ||
174 | v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ns_pulse, | ||
175 | sizeof(ns_pulse), &num); | ||
176 | |||
177 | count = num / sizeof(u32); | ||
178 | |||
179 | /* Append an end of Rx seq, if the caller requested */ | ||
180 | if (add_eom && count < ARRAY_SIZE(ns_pulse)) { | ||
181 | ns_pulse[count] = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END; | ||
182 | count++; | ||
183 | } | ||
184 | |||
185 | /* Just drain the Rx FIFO, if we're called, but not RC-5 */ | ||
186 | if (ir_input_state->ir_type != IR_TYPE_RC5) | ||
187 | continue; | ||
188 | |||
189 | for (i = 0; i < count; i++) | ||
190 | cx23885_input_next_pulse_width_rc5(dev, ns_pulse[i]); | ||
191 | } while (num != 0); | ||
192 | } | ||
193 | |||
194 | void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) | ||
195 | { | ||
196 | struct v4l2_subdev_ir_parameters params; | ||
197 | int overrun, data_available; | ||
198 | |||
199 | if (dev->sd_ir == NULL || events == 0) | ||
200 | return; | ||
201 | |||
202 | switch (dev->board) { | ||
203 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
204 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
205 | /* | ||
206 | * The only board we handle right now. However other boards | ||
207 | * using the CX2388x integrated IR controller should be similar | ||
208 | */ | ||
209 | break; | ||
210 | default: | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | overrun = events & (V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN | | ||
215 | V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN); | ||
216 | |||
217 | data_available = events & (V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED | | ||
218 | V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ); | ||
219 | |||
220 | if (overrun) { | ||
221 | /* If there was a FIFO overrun, stop the device */ | ||
222 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
223 | params.enable = false; | ||
224 | /* Mitigate race with cx23885_input_ir_stop() */ | ||
225 | params.shutdown = atomic_read(&dev->ir_input_stopping); | ||
226 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
227 | } | ||
228 | |||
229 | if (data_available) | ||
230 | cx23885_input_process_pulse_widths_rc5(dev, overrun); | ||
231 | |||
232 | if (overrun) { | ||
233 | /* If there was a FIFO overrun, clear & restart the device */ | ||
234 | params.enable = true; | ||
235 | /* Mitigate race with cx23885_input_ir_stop() */ | ||
236 | params.shutdown = atomic_read(&dev->ir_input_stopping); | ||
237 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | static void cx23885_input_ir_start(struct cx23885_dev *dev) | ||
242 | { | ||
243 | struct card_ir *ir_input = dev->ir_input; | ||
244 | struct ir_input_state *ir_input_state = &ir_input->ir; | ||
245 | struct v4l2_subdev_ir_parameters params; | ||
246 | |||
247 | if (dev->sd_ir == NULL) | ||
248 | return; | ||
249 | |||
250 | atomic_set(&dev->ir_input_stopping, 0); | ||
251 | |||
252 | /* keyup timer set up, if needed */ | ||
253 | switch (dev->board) { | ||
254 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
255 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
256 | setup_timer(&ir_input->timer_keyup, | ||
257 | ir_rc5_timer_keyup, /* Not actually RC-5 specific */ | ||
258 | (unsigned long) ir_input); | ||
259 | if (ir_input_state->ir_type == IR_TYPE_RC5) { | ||
260 | /* | ||
261 | * RC-5 repeats a held key every | ||
262 | * 64 bits * (2 * 32/36000) sec/bit = 113.778 ms | ||
263 | */ | ||
264 | ir_input->rc5_key_timeout = 115; | ||
265 | } | ||
266 | break; | ||
267 | } | ||
268 | |||
269 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
270 | switch (dev->board) { | ||
271 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
272 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
273 | /* | ||
274 | * The IR controller on this board only returns pulse widths. | ||
275 | * Any other mode setting will fail to set up the device. | ||
276 | */ | ||
277 | params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
278 | params.enable = true; | ||
279 | params.interrupt_enable = true; | ||
280 | params.shutdown = false; | ||
281 | |||
282 | /* Setup for baseband compatible with both RC-5 and RC-6A */ | ||
283 | params.modulation = false; | ||
284 | /* RC-5: 2,222,222 ns = 1/36 kHz * 32 cycles * 2 marks * 1.25*/ | ||
285 | /* RC-6A: 3,333,333 ns = 1/36 kHz * 16 cycles * 6 marks * 1.25*/ | ||
286 | params.max_pulse_width = 3333333; /* ns */ | ||
287 | /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ | ||
288 | /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ | ||
289 | params.noise_filter_min_width = 333333; /* ns */ | ||
290 | /* | ||
291 | * This board has inverted receive sense: | ||
292 | * mark is received as low logic level; | ||
293 | * falling edges are detected as rising edges; etc. | ||
294 | */ | ||
295 | params.invert = true; | ||
296 | break; | ||
297 | } | ||
298 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
299 | } | ||
300 | |||
301 | static void cx23885_input_ir_stop(struct cx23885_dev *dev) | ||
302 | { | ||
303 | struct card_ir *ir_input = dev->ir_input; | ||
304 | struct v4l2_subdev_ir_parameters params; | ||
305 | |||
306 | if (dev->sd_ir == NULL) | ||
307 | return; | ||
308 | |||
309 | /* | ||
310 | * Stop the sd_ir subdevice from generating notifications and | ||
311 | * scheduling work. | ||
312 | * It is shutdown this way in order to mitigate a race with | ||
313 | * cx23885_input_rx_work_handler() in the overrun case, which could | ||
314 | * re-enable the subdevice. | ||
315 | */ | ||
316 | atomic_set(&dev->ir_input_stopping, 1); | ||
317 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
318 | while (params.shutdown == false) { | ||
319 | params.enable = false; | ||
320 | params.interrupt_enable = false; | ||
321 | params.shutdown = true; | ||
322 | v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); | ||
323 | v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); | ||
324 | } | ||
325 | |||
326 | flush_scheduled_work(); | ||
327 | |||
328 | switch (dev->board) { | ||
329 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
330 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
331 | del_timer_sync(&ir_input->timer_keyup); | ||
332 | break; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | int cx23885_input_init(struct cx23885_dev *dev) | ||
337 | { | ||
338 | struct card_ir *ir; | ||
339 | struct input_dev *input_dev; | ||
340 | struct ir_scancode_table *ir_codes = NULL; | ||
341 | int ir_type, ir_addr, ir_start; | ||
342 | int ret; | ||
343 | |||
344 | /* | ||
345 | * If the IR device (hardware registers, chip, GPIO lines, etc.) isn't | ||
346 | * encapsulated in a v4l2_subdev, then I'm not going to deal with it. | ||
347 | */ | ||
348 | if (dev->sd_ir == NULL) | ||
349 | return -ENODEV; | ||
350 | |||
351 | switch (dev->board) { | ||
352 | case CX23885_BOARD_HAUPPAUGE_HVR1850: | ||
353 | case CX23885_BOARD_HAUPPAUGE_HVR1290: | ||
354 | /* Parameters for the grey Hauppauge remote for the HVR-1850 */ | ||
355 | ir_codes = &ir_codes_hauppauge_new_table; | ||
356 | ir_type = IR_TYPE_RC5; | ||
357 | ir_addr = 0x1e; /* RC-5 system bits emitted by the remote */ | ||
358 | ir_start = RC5_START_BITS_NORMAL; /* A basic RC-5 remote */ | ||
359 | break; | ||
360 | } | ||
361 | if (ir_codes == NULL) | ||
362 | return -ENODEV; | ||
363 | |||
364 | ir = kzalloc(sizeof(*ir), GFP_KERNEL); | ||
365 | input_dev = input_allocate_device(); | ||
366 | if (!ir || !input_dev) { | ||
367 | ret = -ENOMEM; | ||
368 | goto err_out_free; | ||
369 | } | ||
370 | |||
371 | ir->dev = input_dev; | ||
372 | ir->addr = ir_addr; | ||
373 | ir->start = ir_start; | ||
374 | |||
375 | /* init input device */ | ||
376 | snprintf(ir->name, sizeof(ir->name), "cx23885 IR (%s)", | ||
377 | cx23885_boards[dev->board].name); | ||
378 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci)); | ||
379 | |||
380 | ret = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); | ||
381 | if (ret < 0) | ||
382 | goto err_out_free; | ||
383 | |||
384 | input_dev->name = ir->name; | ||
385 | input_dev->phys = ir->phys; | ||
386 | input_dev->id.bustype = BUS_PCI; | ||
387 | input_dev->id.version = 1; | ||
388 | if (dev->pci->subsystem_vendor) { | ||
389 | input_dev->id.vendor = dev->pci->subsystem_vendor; | ||
390 | input_dev->id.product = dev->pci->subsystem_device; | ||
391 | } else { | ||
392 | input_dev->id.vendor = dev->pci->vendor; | ||
393 | input_dev->id.product = dev->pci->device; | ||
394 | } | ||
395 | input_dev->dev.parent = &dev->pci->dev; | ||
396 | |||
397 | dev->ir_input = ir; | ||
398 | cx23885_input_ir_start(dev); | ||
399 | |||
400 | ret = input_register_device(ir->dev); | ||
401 | if (ret) | ||
402 | goto err_out_stop; | ||
403 | |||
404 | return 0; | ||
405 | |||
406 | err_out_stop: | ||
407 | cx23885_input_ir_stop(dev); | ||
408 | dev->ir_input = NULL; | ||
409 | err_out_free: | ||
410 | ir_input_free(input_dev); | ||
411 | input_free_device(input_dev); | ||
412 | kfree(ir); | ||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | void cx23885_input_fini(struct cx23885_dev *dev) | ||
417 | { | ||
418 | /* Always stop the IR hardware from generating interrupts */ | ||
419 | cx23885_input_ir_stop(dev); | ||
420 | |||
421 | if (dev->ir_input == NULL) | ||
422 | return; | ||
423 | ir_input_free(dev->ir_input->dev); | ||
424 | input_unregister_device(dev->ir_input->dev); | ||
425 | kfree(dev->ir_input); | ||
426 | dev->ir_input = NULL; | ||
427 | } | ||
diff --git a/drivers/media/video/cx23885/cx23885-input.h b/drivers/media/video/cx23885/cx23885-input.h new file mode 100644 index 000000000000..3572cb1ecfc2 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-input.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Infrared remote control input device | ||
5 | * | ||
6 | * Copyright (C) 2009 Andy Walls <awalls@radix.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (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 | * 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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef _CX23885_INPUT_H_ | ||
25 | #define _CX23885_INPUT_H_ | ||
26 | int cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events); | ||
27 | |||
28 | int cx23885_input_init(struct cx23885_dev *dev); | ||
29 | void cx23885_input_fini(struct cx23885_dev *dev); | ||
30 | #endif | ||
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.c b/drivers/media/video/cx23885/cx23885-ioctl.c new file mode 100644 index 000000000000..dfb4627fb340 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-ioctl.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Various common ioctl() support functions | ||
5 | * | ||
6 | * Copyright (c) 2009 Andy Walls <awalls@radix.net> | ||
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 | #include "cx23885.h" | ||
25 | #include <media/v4l2-chip-ident.h> | ||
26 | |||
27 | int cx23885_g_chip_ident(struct file *file, void *fh, | ||
28 | struct v4l2_dbg_chip_ident *chip) | ||
29 | { | ||
30 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; | ||
31 | int err = 0; | ||
32 | u8 rev; | ||
33 | |||
34 | chip->ident = V4L2_IDENT_NONE; | ||
35 | chip->revision = 0; | ||
36 | switch (chip->match.type) { | ||
37 | case V4L2_CHIP_MATCH_HOST: | ||
38 | switch (chip->match.addr) { | ||
39 | case 0: | ||
40 | rev = cx_read(RDR_CFG2) & 0xff; | ||
41 | switch (dev->pci->device) { | ||
42 | case 0x8852: | ||
43 | /* rev 0x04 could be '885 or '888. Pick '888. */ | ||
44 | if (rev == 0x04) | ||
45 | chip->ident = V4L2_IDENT_CX23888; | ||
46 | else | ||
47 | chip->ident = V4L2_IDENT_CX23885; | ||
48 | break; | ||
49 | case 0x8880: | ||
50 | if (rev == 0x0e || rev == 0x0f) | ||
51 | chip->ident = V4L2_IDENT_CX23887; | ||
52 | else | ||
53 | chip->ident = V4L2_IDENT_CX23888; | ||
54 | break; | ||
55 | default: | ||
56 | chip->ident = V4L2_IDENT_UNKNOWN; | ||
57 | break; | ||
58 | } | ||
59 | chip->revision = (dev->pci->device << 16) | (rev << 8) | | ||
60 | (dev->hwrevision & 0xff); | ||
61 | break; | ||
62 | case 1: | ||
63 | if (dev->v4l_device != NULL) { | ||
64 | chip->ident = V4L2_IDENT_CX23417; | ||
65 | chip->revision = 0; | ||
66 | } | ||
67 | break; | ||
68 | case 2: | ||
69 | /* | ||
70 | * The integrated IR controller on the CX23888 is | ||
71 | * host chip 2. It may not be used/initialized or sd_ir | ||
72 | * may be pointing at the cx25840 subdevice for the | ||
73 | * IR controller on the CX23885. Thus we find it | ||
74 | * without using the dev->sd_ir pointer. | ||
75 | */ | ||
76 | call_hw(dev, CX23885_HW_888_IR, core, g_chip_ident, | ||
77 | chip); | ||
78 | break; | ||
79 | default: | ||
80 | err = -EINVAL; /* per V4L2 spec */ | ||
81 | break; | ||
82 | } | ||
83 | break; | ||
84 | case V4L2_CHIP_MATCH_I2C_DRIVER: | ||
85 | /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */ | ||
86 | call_all(dev, core, g_chip_ident, chip); | ||
87 | break; | ||
88 | case V4L2_CHIP_MATCH_I2C_ADDR: | ||
89 | /* | ||
90 | * We could return V4L2_IDENT_UNKNOWN, but we don't do the work | ||
91 | * to look if a chip is at the address with no driver. That's a | ||
92 | * dangerous thing to do with EEPROMs anyway. | ||
93 | */ | ||
94 | call_all(dev, core, g_chip_ident, chip); | ||
95 | break; | ||
96 | default: | ||
97 | err = -EINVAL; | ||
98 | break; | ||
99 | } | ||
100 | return err; | ||
101 | } | ||
102 | |||
103 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
104 | static int cx23885_g_host_register(struct cx23885_dev *dev, | ||
105 | struct v4l2_dbg_register *reg) | ||
106 | { | ||
107 | if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) | ||
108 | return -EINVAL; | ||
109 | |||
110 | reg->size = 4; | ||
111 | reg->val = cx_read(reg->reg); | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int cx23417_g_register(struct cx23885_dev *dev, | ||
116 | struct v4l2_dbg_register *reg) | ||
117 | { | ||
118 | u32 value; | ||
119 | |||
120 | if (dev->v4l_device == NULL) | ||
121 | return -EINVAL; | ||
122 | |||
123 | if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000) | ||
124 | return -EINVAL; | ||
125 | |||
126 | if (mc417_register_read(dev, (u16) reg->reg, &value)) | ||
127 | return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ | ||
128 | |||
129 | reg->size = 4; | ||
130 | reg->val = value; | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | int cx23885_g_register(struct file *file, void *fh, | ||
135 | struct v4l2_dbg_register *reg) | ||
136 | { | ||
137 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; | ||
138 | |||
139 | if (!capable(CAP_SYS_ADMIN)) | ||
140 | return -EPERM; | ||
141 | |||
142 | if (reg->match.type == V4L2_CHIP_MATCH_HOST) { | ||
143 | switch (reg->match.addr) { | ||
144 | case 0: | ||
145 | return cx23885_g_host_register(dev, reg); | ||
146 | case 1: | ||
147 | return cx23417_g_register(dev, reg); | ||
148 | default: | ||
149 | break; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | /* FIXME - any error returns should not be ignored */ | ||
154 | call_all(dev, core, g_register, reg); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int cx23885_s_host_register(struct cx23885_dev *dev, | ||
159 | struct v4l2_dbg_register *reg) | ||
160 | { | ||
161 | if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) | ||
162 | return -EINVAL; | ||
163 | |||
164 | reg->size = 4; | ||
165 | cx_write(reg->reg, reg->val); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int cx23417_s_register(struct cx23885_dev *dev, | ||
170 | struct v4l2_dbg_register *reg) | ||
171 | { | ||
172 | if (dev->v4l_device == NULL) | ||
173 | return -EINVAL; | ||
174 | |||
175 | if ((reg->reg & 0x3) != 0 || reg->reg >= 0x10000) | ||
176 | return -EINVAL; | ||
177 | |||
178 | if (mc417_register_write(dev, (u16) reg->reg, (u32) reg->val)) | ||
179 | return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ | ||
180 | |||
181 | reg->size = 4; | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | int cx23885_s_register(struct file *file, void *fh, | ||
186 | struct v4l2_dbg_register *reg) | ||
187 | { | ||
188 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; | ||
189 | |||
190 | if (!capable(CAP_SYS_ADMIN)) | ||
191 | return -EPERM; | ||
192 | |||
193 | if (reg->match.type == V4L2_CHIP_MATCH_HOST) { | ||
194 | switch (reg->match.addr) { | ||
195 | case 0: | ||
196 | return cx23885_s_host_register(dev, reg); | ||
197 | case 1: | ||
198 | return cx23417_s_register(dev, reg); | ||
199 | default: | ||
200 | break; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /* FIXME - any error returns should not be ignored */ | ||
205 | call_all(dev, core, s_register, reg); | ||
206 | return 0; | ||
207 | } | ||
208 | #endif | ||
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.h b/drivers/media/video/cx23885/cx23885-ioctl.h new file mode 100644 index 000000000000..80b0f4923c6a --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-ioctl.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Various common ioctl() support functions | ||
5 | * | ||
6 | * Copyright (c) 2009 Andy Walls <awalls@radix.net> | ||
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 _CX23885_IOCTL_H_ | ||
25 | #define _CX23885_IOCTL_H_ | ||
26 | |||
27 | int cx23885_g_chip_ident(struct file *file, void *fh, | ||
28 | struct v4l2_dbg_chip_ident *chip); | ||
29 | |||
30 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
31 | int cx23885_g_register(struct file *file, void *fh, | ||
32 | struct v4l2_dbg_register *reg); | ||
33 | |||
34 | |||
35 | int cx23885_s_register(struct file *file, void *fh, | ||
36 | struct v4l2_dbg_register *reg); | ||
37 | |||
38 | #endif | ||
39 | #endif | ||
diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c new file mode 100644 index 000000000000..6ae982cc9856 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-ir.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Infrared device support routines - non-input, non-vl42_subdev routines | ||
5 | * | ||
6 | * Copyright (C) 2009 Andy Walls <awalls@radix.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (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 | * 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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include <media/v4l2-device.h> | ||
25 | |||
26 | #include "cx23885.h" | ||
27 | #include "cx23885-input.h" | ||
28 | |||
29 | #define CX23885_IR_RX_FIFO_SERVICE_REQ 0 | ||
30 | #define CX23885_IR_RX_END_OF_RX_DETECTED 1 | ||
31 | #define CX23885_IR_RX_HW_FIFO_OVERRUN 2 | ||
32 | #define CX23885_IR_RX_SW_FIFO_OVERRUN 3 | ||
33 | |||
34 | #define CX23885_IR_TX_FIFO_SERVICE_REQ 0 | ||
35 | |||
36 | |||
37 | void cx23885_ir_rx_work_handler(struct work_struct *work) | ||
38 | { | ||
39 | struct cx23885_dev *dev = | ||
40 | container_of(work, struct cx23885_dev, ir_rx_work); | ||
41 | u32 events = 0; | ||
42 | unsigned long *notifications = &dev->ir_rx_notifications; | ||
43 | |||
44 | if (test_and_clear_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications)) | ||
45 | events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; | ||
46 | if (test_and_clear_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications)) | ||
47 | events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; | ||
48 | if (test_and_clear_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications)) | ||
49 | events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; | ||
50 | if (test_and_clear_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications)) | ||
51 | events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; | ||
52 | |||
53 | if (events == 0) | ||
54 | return; | ||
55 | |||
56 | if (dev->ir_input) | ||
57 | cx23885_input_rx_work_handler(dev, events); | ||
58 | } | ||
59 | |||
60 | void cx23885_ir_tx_work_handler(struct work_struct *work) | ||
61 | { | ||
62 | struct cx23885_dev *dev = | ||
63 | container_of(work, struct cx23885_dev, ir_tx_work); | ||
64 | u32 events = 0; | ||
65 | unsigned long *notifications = &dev->ir_tx_notifications; | ||
66 | |||
67 | if (test_and_clear_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications)) | ||
68 | events |= V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; | ||
69 | |||
70 | if (events == 0) | ||
71 | return; | ||
72 | |||
73 | } | ||
74 | |||
75 | /* Called in an IRQ context */ | ||
76 | void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) | ||
77 | { | ||
78 | struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); | ||
79 | unsigned long *notifications = &dev->ir_rx_notifications; | ||
80 | |||
81 | if (events & V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ) | ||
82 | set_bit(CX23885_IR_RX_FIFO_SERVICE_REQ, notifications); | ||
83 | if (events & V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED) | ||
84 | set_bit(CX23885_IR_RX_END_OF_RX_DETECTED, notifications); | ||
85 | if (events & V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN) | ||
86 | set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications); | ||
87 | if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN) | ||
88 | set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications); | ||
89 | schedule_work(&dev->ir_rx_work); | ||
90 | } | ||
91 | |||
92 | /* Called in an IRQ context */ | ||
93 | void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events) | ||
94 | { | ||
95 | struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev); | ||
96 | unsigned long *notifications = &dev->ir_tx_notifications; | ||
97 | |||
98 | if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ) | ||
99 | set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications); | ||
100 | schedule_work(&dev->ir_tx_work); | ||
101 | } | ||
diff --git a/drivers/media/video/cx23885/cx23885-ir.h b/drivers/media/video/cx23885/cx23885-ir.h new file mode 100644 index 000000000000..9b8a6d5d1ef6 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-ir.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * Infrared device support routines - non-input, non-vl42_subdev routines | ||
5 | * | ||
6 | * Copyright (C) 2009 Andy Walls <awalls@radix.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (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 | * 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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef _CX23885_IR_H_ | ||
25 | #define _CX23885_IR_H_ | ||
26 | void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events); | ||
27 | void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events); | ||
28 | |||
29 | void cx23885_ir_rx_work_handler(struct work_struct *work); | ||
30 | void cx23885_ir_tx_work_handler(struct work_struct *work); | ||
31 | #endif | ||
diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index eafbe5226bae..c0bc9a068954 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h | |||
@@ -212,8 +212,9 @@ Channel manager Data Structure entry = 20 DWORD | |||
212 | 212 | ||
213 | #define DEV_CNTRL2 0x00040000 | 213 | #define DEV_CNTRL2 0x00040000 |
214 | 214 | ||
215 | #define PCI_MSK_GPIO1 (1 << 24) | 215 | #define PCI_MSK_IR (1 << 28) |
216 | #define PCI_MSK_GPIO0 (1 << 23) | 216 | #define PCI_MSK_GPIO1 (1 << 24) |
217 | #define PCI_MSK_GPIO0 (1 << 23) | ||
217 | #define PCI_MSK_APB_DMA (1 << 12) | 218 | #define PCI_MSK_APB_DMA (1 << 12) |
218 | #define PCI_MSK_AL_WR (1 << 11) | 219 | #define PCI_MSK_AL_WR (1 << 11) |
219 | #define PCI_MSK_AL_RD (1 << 10) | 220 | #define PCI_MSK_AL_RD (1 << 10) |
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 654cc253cd50..8b372b4f0de2 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "cx23885.h" | 35 | #include "cx23885.h" |
36 | #include <media/v4l2-common.h> | 36 | #include <media/v4l2-common.h> |
37 | #include <media/v4l2-ioctl.h> | 37 | #include <media/v4l2-ioctl.h> |
38 | #include "cx23885-ioctl.h" | ||
38 | 39 | ||
39 | MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); | 40 | MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); |
40 | MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); | 41 | MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); |
@@ -401,6 +402,13 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) | |||
401 | INPUT(input)->gpio2, INPUT(input)->gpio3); | 402 | INPUT(input)->gpio2, INPUT(input)->gpio3); |
402 | dev->input = input; | 403 | dev->input = input; |
403 | 404 | ||
405 | if (dev->board == CX23885_BOARD_MYGICA_X8506 || | ||
406 | dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2) { | ||
407 | /* Select Analog TV */ | ||
408 | if (INPUT(input)->type == CX23885_VMUX_TELEVISION) | ||
409 | cx23885_gpio_clear(dev, GPIO_0); | ||
410 | } | ||
411 | |||
404 | /* Tell the internal A/V decoder */ | 412 | /* Tell the internal A/V decoder */ |
405 | v4l2_subdev_call(dev->sd_cx25840, video, s_routing, | 413 | v4l2_subdev_call(dev->sd_cx25840, video, s_routing, |
406 | INPUT(input)->vmux, 0, 0); | 414 | INPUT(input)->vmux, 0, 0); |
@@ -1144,6 +1152,7 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) | |||
1144 | [CX23885_VMUX_COMPOSITE3] = "Composite3", | 1152 | [CX23885_VMUX_COMPOSITE3] = "Composite3", |
1145 | [CX23885_VMUX_COMPOSITE4] = "Composite4", | 1153 | [CX23885_VMUX_COMPOSITE4] = "Composite4", |
1146 | [CX23885_VMUX_SVIDEO] = "S-Video", | 1154 | [CX23885_VMUX_SVIDEO] = "S-Video", |
1155 | [CX23885_VMUX_COMPONENT] = "Component", | ||
1147 | [CX23885_VMUX_TELEVISION] = "Television", | 1156 | [CX23885_VMUX_TELEVISION] = "Television", |
1148 | [CX23885_VMUX_CABLE] = "Cable TV", | 1157 | [CX23885_VMUX_CABLE] = "Cable TV", |
1149 | [CX23885_VMUX_DVB] = "DVB", | 1158 | [CX23885_VMUX_DVB] = "DVB", |
@@ -1312,34 +1321,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
1312 | cx23885_set_freq(dev, f); | 1321 | cx23885_set_freq(dev, f); |
1313 | } | 1322 | } |
1314 | 1323 | ||
1315 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1316 | static int vidioc_g_register(struct file *file, void *fh, | ||
1317 | struct v4l2_dbg_register *reg) | ||
1318 | { | ||
1319 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; | ||
1320 | |||
1321 | if (!v4l2_chip_match_host(®->match)) | ||
1322 | return -EINVAL; | ||
1323 | |||
1324 | call_all(dev, core, g_register, reg); | ||
1325 | |||
1326 | return 0; | ||
1327 | } | ||
1328 | |||
1329 | static int vidioc_s_register(struct file *file, void *fh, | ||
1330 | struct v4l2_dbg_register *reg) | ||
1331 | { | ||
1332 | struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; | ||
1333 | |||
1334 | if (!v4l2_chip_match_host(®->match)) | ||
1335 | return -EINVAL; | ||
1336 | |||
1337 | call_all(dev, core, s_register, reg); | ||
1338 | |||
1339 | return 0; | ||
1340 | } | ||
1341 | #endif | ||
1342 | |||
1343 | /* ----------------------------------------------------------- */ | 1324 | /* ----------------------------------------------------------- */ |
1344 | 1325 | ||
1345 | static void cx23885_vid_timeout(unsigned long data) | 1326 | static void cx23885_vid_timeout(unsigned long data) |
@@ -1449,9 +1430,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
1449 | .vidioc_s_tuner = vidioc_s_tuner, | 1430 | .vidioc_s_tuner = vidioc_s_tuner, |
1450 | .vidioc_g_frequency = vidioc_g_frequency, | 1431 | .vidioc_g_frequency = vidioc_g_frequency, |
1451 | .vidioc_s_frequency = vidioc_s_frequency, | 1432 | .vidioc_s_frequency = vidioc_s_frequency, |
1433 | .vidioc_g_chip_ident = cx23885_g_chip_ident, | ||
1452 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1434 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1453 | .vidioc_g_register = vidioc_g_register, | 1435 | .vidioc_g_register = cx23885_g_register, |
1454 | .vidioc_s_register = vidioc_s_register, | 1436 | .vidioc_s_register = cx23885_s_register, |
1455 | #endif | 1437 | #endif |
1456 | }; | 1438 | }; |
1457 | 1439 | ||
@@ -1529,9 +1511,11 @@ int cx23885_video_register(struct cx23885_dev *dev) | |||
1529 | if (sd) { | 1511 | if (sd) { |
1530 | struct tuner_setup tun_setup; | 1512 | struct tuner_setup tun_setup; |
1531 | 1513 | ||
1514 | memset(&tun_setup, 0, sizeof(tun_setup)); | ||
1532 | tun_setup.mode_mask = T_ANALOG_TV; | 1515 | tun_setup.mode_mask = T_ANALOG_TV; |
1533 | tun_setup.type = dev->tuner_type; | 1516 | tun_setup.type = dev->tuner_type; |
1534 | tun_setup.addr = v4l2_i2c_subdev_addr(sd); | 1517 | tun_setup.addr = v4l2_i2c_subdev_addr(sd); |
1518 | tun_setup.tuner_callback = cx23885_tuner_callback; | ||
1535 | 1519 | ||
1536 | v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup); | 1520 | v4l2_subdev_call(sd, tuner, s_type_addr, &tun_setup); |
1537 | } | 1521 | } |
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index cc7a165561ff..fa744764dc8b 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h | |||
@@ -79,6 +79,8 @@ | |||
79 | #define CX23885_BOARD_MAGICPRO_PROHDTVE2 23 | 79 | #define CX23885_BOARD_MAGICPRO_PROHDTVE2 23 |
80 | #define CX23885_BOARD_HAUPPAUGE_HVR1850 24 | 80 | #define CX23885_BOARD_HAUPPAUGE_HVR1850 24 |
81 | #define CX23885_BOARD_COMPRO_VIDEOMATE_E800 25 | 81 | #define CX23885_BOARD_COMPRO_VIDEOMATE_E800 25 |
82 | #define CX23885_BOARD_HAUPPAUGE_HVR1290 26 | ||
83 | #define CX23885_BOARD_MYGICA_X8558PRO 27 | ||
82 | 84 | ||
83 | #define GPIO_0 0x00000001 | 85 | #define GPIO_0 0x00000001 |
84 | #define GPIO_1 0x00000002 | 86 | #define GPIO_1 0x00000002 |
@@ -157,6 +159,7 @@ enum cx23885_itype { | |||
157 | CX23885_VMUX_COMPOSITE3, | 159 | CX23885_VMUX_COMPOSITE3, |
158 | CX23885_VMUX_COMPOSITE4, | 160 | CX23885_VMUX_COMPOSITE4, |
159 | CX23885_VMUX_SVIDEO, | 161 | CX23885_VMUX_SVIDEO, |
162 | CX23885_VMUX_COMPONENT, | ||
160 | CX23885_VMUX_TELEVISION, | 163 | CX23885_VMUX_TELEVISION, |
161 | CX23885_VMUX_CABLE, | 164 | CX23885_VMUX_CABLE, |
162 | CX23885_VMUX_DVB, | 165 | CX23885_VMUX_DVB, |
@@ -297,10 +300,6 @@ struct cx23885_tsport { | |||
297 | /* Allow a single tsport to have multiple frontends */ | 300 | /* Allow a single tsport to have multiple frontends */ |
298 | u32 num_frontends; | 301 | u32 num_frontends; |
299 | void *port_priv; | 302 | void *port_priv; |
300 | |||
301 | /* FIXME: temporary hack */ | ||
302 | int (*set_frontend_save) (struct dvb_frontend *, | ||
303 | struct dvb_frontend_parameters *); | ||
304 | }; | 303 | }; |
305 | 304 | ||
306 | struct cx23885_dev { | 305 | struct cx23885_dev { |
@@ -356,6 +355,16 @@ struct cx23885_dev { | |||
356 | unsigned int has_radio; | 355 | unsigned int has_radio; |
357 | struct v4l2_subdev *sd_cx25840; | 356 | struct v4l2_subdev *sd_cx25840; |
358 | 357 | ||
358 | /* Infrared */ | ||
359 | struct v4l2_subdev *sd_ir; | ||
360 | struct work_struct ir_rx_work; | ||
361 | unsigned long ir_rx_notifications; | ||
362 | struct work_struct ir_tx_work; | ||
363 | unsigned long ir_tx_notifications; | ||
364 | |||
365 | struct card_ir *ir_input; | ||
366 | atomic_t ir_input_stopping; | ||
367 | |||
359 | /* V4l */ | 368 | /* V4l */ |
360 | u32 freq; | 369 | u32 freq; |
361 | struct video_device *video_dev; | 370 | struct video_device *video_dev; |
@@ -383,6 +392,13 @@ static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev) | |||
383 | #define call_all(dev, o, f, args...) \ | 392 | #define call_all(dev, o, f, args...) \ |
384 | v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) | 393 | v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) |
385 | 394 | ||
395 | #define CX23885_HW_888_IR (1 << 0) | ||
396 | |||
397 | #define call_hw(dev, grpid, o, f, args...) \ | ||
398 | v4l2_device_call_all(&dev->v4l2_dev, grpid, o, f, ##args) | ||
399 | |||
400 | extern struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw); | ||
401 | |||
386 | extern struct list_head cx23885_devlist; | 402 | extern struct list_head cx23885_devlist; |
387 | 403 | ||
388 | #define SRAM_CH01 0 /* Video A */ | 404 | #define SRAM_CH01 0 /* Video A */ |
@@ -455,6 +471,7 @@ extern void cx23885_wakeup(struct cx23885_tsport *port, | |||
455 | 471 | ||
456 | extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask); | 472 | extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask); |
457 | extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask); | 473 | extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask); |
474 | extern u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask); | ||
458 | extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, | 475 | extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, |
459 | int asoutput); | 476 | int asoutput); |
460 | 477 | ||
@@ -471,6 +488,8 @@ extern int cx23885_tuner_callback(void *priv, int component, | |||
471 | int command, int arg); | 488 | int command, int arg); |
472 | extern void cx23885_card_list(struct cx23885_dev *dev); | 489 | extern void cx23885_card_list(struct cx23885_dev *dev); |
473 | extern int cx23885_ir_init(struct cx23885_dev *dev); | 490 | extern int cx23885_ir_init(struct cx23885_dev *dev); |
491 | extern void cx23885_ir_pci_int_enable(struct cx23885_dev *dev); | ||
492 | extern void cx23885_ir_fini(struct cx23885_dev *dev); | ||
474 | extern void cx23885_gpio_setup(struct cx23885_dev *dev); | 493 | extern void cx23885_gpio_setup(struct cx23885_dev *dev); |
475 | extern void cx23885_card_setup(struct cx23885_dev *dev); | 494 | extern void cx23885_card_setup(struct cx23885_dev *dev); |
476 | extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); | 495 | extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); |
@@ -515,6 +534,10 @@ extern void cx23885_417_check_encoder(struct cx23885_dev *dev); | |||
515 | extern void cx23885_mc417_init(struct cx23885_dev *dev); | 534 | extern void cx23885_mc417_init(struct cx23885_dev *dev); |
516 | extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value); | 535 | extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value); |
517 | extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value); | 536 | extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value); |
537 | extern int mc417_register_read(struct cx23885_dev *dev, | ||
538 | u16 address, u32 *value); | ||
539 | extern int mc417_register_write(struct cx23885_dev *dev, | ||
540 | u16 address, u32 value); | ||
518 | extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask); | 541 | extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask); |
519 | extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask); | 542 | extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask); |
520 | extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput); | 543 | extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput); |
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c new file mode 100644 index 000000000000..3ccc8afeccf3 --- /dev/null +++ b/drivers/media/video/cx23885/cx23888-ir.c | |||
@@ -0,0 +1,1239 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * CX23888 Integrated Consumer Infrared Controller | ||
5 | * | ||
6 | * Copyright (C) 2009 Andy Walls <awalls@radix.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (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 | * 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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/kfifo.h> | ||
25 | |||
26 | #include <media/v4l2-device.h> | ||
27 | #include <media/v4l2-chip-ident.h> | ||
28 | |||
29 | #include "cx23885.h" | ||
30 | |||
31 | static unsigned int ir_888_debug; | ||
32 | module_param(ir_888_debug, int, 0644); | ||
33 | MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]"); | ||
34 | |||
35 | #define CX23888_IR_REG_BASE 0x170000 | ||
36 | /* | ||
37 | * These CX23888 register offsets have a straightforward one to one mapping | ||
38 | * to the CX23885 register offsets of 0x200 through 0x218 | ||
39 | */ | ||
40 | #define CX23888_IR_CNTRL_REG 0x170000 | ||
41 | #define CNTRL_WIN_3_3 0x00000000 | ||
42 | #define CNTRL_WIN_4_3 0x00000001 | ||
43 | #define CNTRL_WIN_3_4 0x00000002 | ||
44 | #define CNTRL_WIN_4_4 0x00000003 | ||
45 | #define CNTRL_WIN 0x00000003 | ||
46 | #define CNTRL_EDG_NONE 0x00000000 | ||
47 | #define CNTRL_EDG_FALL 0x00000004 | ||
48 | #define CNTRL_EDG_RISE 0x00000008 | ||
49 | #define CNTRL_EDG_BOTH 0x0000000C | ||
50 | #define CNTRL_EDG 0x0000000C | ||
51 | #define CNTRL_DMD 0x00000010 | ||
52 | #define CNTRL_MOD 0x00000020 | ||
53 | #define CNTRL_RFE 0x00000040 | ||
54 | #define CNTRL_TFE 0x00000080 | ||
55 | #define CNTRL_RXE 0x00000100 | ||
56 | #define CNTRL_TXE 0x00000200 | ||
57 | #define CNTRL_RIC 0x00000400 | ||
58 | #define CNTRL_TIC 0x00000800 | ||
59 | #define CNTRL_CPL 0x00001000 | ||
60 | #define CNTRL_LBM 0x00002000 | ||
61 | #define CNTRL_R 0x00004000 | ||
62 | |||
63 | #define CX23888_IR_TXCLK_REG 0x170004 | ||
64 | #define TXCLK_TCD 0x0000FFFF | ||
65 | |||
66 | #define CX23888_IR_RXCLK_REG 0x170008 | ||
67 | #define RXCLK_RCD 0x0000FFFF | ||
68 | |||
69 | #define CX23888_IR_CDUTY_REG 0x17000C | ||
70 | #define CDUTY_CDC 0x0000000F | ||
71 | |||
72 | #define CX23888_IR_STATS_REG 0x170010 | ||
73 | #define STATS_RTO 0x00000001 | ||
74 | #define STATS_ROR 0x00000002 | ||
75 | #define STATS_RBY 0x00000004 | ||
76 | #define STATS_TBY 0x00000008 | ||
77 | #define STATS_RSR 0x00000010 | ||
78 | #define STATS_TSR 0x00000020 | ||
79 | |||
80 | #define CX23888_IR_IRQEN_REG 0x170014 | ||
81 | #define IRQEN_RTE 0x00000001 | ||
82 | #define IRQEN_ROE 0x00000002 | ||
83 | #define IRQEN_RSE 0x00000010 | ||
84 | #define IRQEN_TSE 0x00000020 | ||
85 | |||
86 | #define CX23888_IR_FILTR_REG 0x170018 | ||
87 | #define FILTR_LPF 0x0000FFFF | ||
88 | |||
89 | /* This register doesn't follow the pattern; it's 0x23C on a CX23885 */ | ||
90 | #define CX23888_IR_FIFO_REG 0x170040 | ||
91 | #define FIFO_RXTX 0x0000FFFF | ||
92 | #define FIFO_RXTX_LVL 0x00010000 | ||
93 | #define FIFO_RXTX_RTO 0x0001FFFF | ||
94 | #define FIFO_RX_NDV 0x00020000 | ||
95 | #define FIFO_RX_DEPTH 8 | ||
96 | #define FIFO_TX_DEPTH 8 | ||
97 | |||
98 | /* CX23888 unique registers */ | ||
99 | #define CX23888_IR_SEEDP_REG 0x17001C | ||
100 | #define CX23888_IR_TIMOL_REG 0x170020 | ||
101 | #define CX23888_IR_WAKE0_REG 0x170024 | ||
102 | #define CX23888_IR_WAKE1_REG 0x170028 | ||
103 | #define CX23888_IR_WAKE2_REG 0x17002C | ||
104 | #define CX23888_IR_MASK0_REG 0x170030 | ||
105 | #define CX23888_IR_MASK1_REG 0x170034 | ||
106 | #define CX23888_IR_MAKS2_REG 0x170038 | ||
107 | #define CX23888_IR_DPIPG_REG 0x17003C | ||
108 | #define CX23888_IR_LEARN_REG 0x170044 | ||
109 | |||
110 | #define CX23888_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */ | ||
111 | #define CX23888_IR_REFCLK_FREQ (CX23888_VIDCLK_FREQ / 2) | ||
112 | |||
113 | #define CX23888_IR_RX_KFIFO_SIZE (512 * sizeof(u32)) | ||
114 | #define CX23888_IR_TX_KFIFO_SIZE (512 * sizeof(u32)) | ||
115 | |||
116 | struct cx23888_ir_state { | ||
117 | struct v4l2_subdev sd; | ||
118 | struct cx23885_dev *dev; | ||
119 | u32 id; | ||
120 | u32 rev; | ||
121 | |||
122 | struct v4l2_subdev_ir_parameters rx_params; | ||
123 | struct mutex rx_params_lock; | ||
124 | atomic_t rxclk_divider; | ||
125 | atomic_t rx_invert; | ||
126 | |||
127 | struct kfifo *rx_kfifo; | ||
128 | spinlock_t rx_kfifo_lock; | ||
129 | |||
130 | struct v4l2_subdev_ir_parameters tx_params; | ||
131 | struct mutex tx_params_lock; | ||
132 | atomic_t txclk_divider; | ||
133 | |||
134 | struct kfifo *tx_kfifo; | ||
135 | spinlock_t tx_kfifo_lock; | ||
136 | }; | ||
137 | |||
138 | static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd) | ||
139 | { | ||
140 | return v4l2_get_subdevdata(sd); | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * IR register block read and write functions | ||
145 | */ | ||
146 | static | ||
147 | inline int cx23888_ir_write4(struct cx23885_dev *dev, u32 addr, u32 value) | ||
148 | { | ||
149 | cx_write(addr, value); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static inline u32 cx23888_ir_read4(struct cx23885_dev *dev, u32 addr) | ||
154 | { | ||
155 | return cx_read(addr); | ||
156 | } | ||
157 | |||
158 | static inline int cx23888_ir_and_or4(struct cx23885_dev *dev, u32 addr, | ||
159 | u32 and_mask, u32 or_value) | ||
160 | { | ||
161 | cx_andor(addr, ~and_mask, or_value); | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Rx and Tx Clock Divider register computations | ||
167 | * | ||
168 | * Note the largest clock divider value of 0xffff corresponds to: | ||
169 | * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns | ||
170 | * which fits in 21 bits, so we'll use unsigned int for time arguments. | ||
171 | */ | ||
172 | static inline u16 count_to_clock_divider(unsigned int d) | ||
173 | { | ||
174 | if (d > RXCLK_RCD + 1) | ||
175 | d = RXCLK_RCD; | ||
176 | else if (d < 2) | ||
177 | d = 1; | ||
178 | else | ||
179 | d--; | ||
180 | return (u16) d; | ||
181 | } | ||
182 | |||
183 | static inline u16 ns_to_clock_divider(unsigned int ns) | ||
184 | { | ||
185 | return count_to_clock_divider( | ||
186 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000)); | ||
187 | } | ||
188 | |||
189 | static inline unsigned int clock_divider_to_ns(unsigned int divider) | ||
190 | { | ||
191 | /* Period of the Rx or Tx clock in ns */ | ||
192 | return DIV_ROUND_CLOSEST((divider + 1) * 1000, | ||
193 | CX23888_IR_REFCLK_FREQ / 1000000); | ||
194 | } | ||
195 | |||
196 | static inline u16 carrier_freq_to_clock_divider(unsigned int freq) | ||
197 | { | ||
198 | return count_to_clock_divider( | ||
199 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * 16)); | ||
200 | } | ||
201 | |||
202 | static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider) | ||
203 | { | ||
204 | return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, (divider + 1) * 16); | ||
205 | } | ||
206 | |||
207 | static inline u16 freq_to_clock_divider(unsigned int freq, | ||
208 | unsigned int rollovers) | ||
209 | { | ||
210 | return count_to_clock_divider( | ||
211 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, freq * rollovers)); | ||
212 | } | ||
213 | |||
214 | static inline unsigned int clock_divider_to_freq(unsigned int divider, | ||
215 | unsigned int rollovers) | ||
216 | { | ||
217 | return DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ, | ||
218 | (divider + 1) * rollovers); | ||
219 | } | ||
220 | |||
221 | /* | ||
222 | * Low Pass Filter register calculations | ||
223 | * | ||
224 | * Note the largest count value of 0xffff corresponds to: | ||
225 | * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns | ||
226 | * which fits in 21 bits, so we'll use unsigned int for time arguments. | ||
227 | */ | ||
228 | static inline u16 count_to_lpf_count(unsigned int d) | ||
229 | { | ||
230 | if (d > FILTR_LPF) | ||
231 | d = FILTR_LPF; | ||
232 | else if (d < 4) | ||
233 | d = 0; | ||
234 | return (u16) d; | ||
235 | } | ||
236 | |||
237 | static inline u16 ns_to_lpf_count(unsigned int ns) | ||
238 | { | ||
239 | return count_to_lpf_count( | ||
240 | DIV_ROUND_CLOSEST(CX23888_IR_REFCLK_FREQ / 1000000 * ns, 1000)); | ||
241 | } | ||
242 | |||
243 | static inline unsigned int lpf_count_to_ns(unsigned int count) | ||
244 | { | ||
245 | /* Duration of the Low Pass Filter rejection window in ns */ | ||
246 | return DIV_ROUND_CLOSEST(count * 1000, | ||
247 | CX23888_IR_REFCLK_FREQ / 1000000); | ||
248 | } | ||
249 | |||
250 | static inline unsigned int lpf_count_to_us(unsigned int count) | ||
251 | { | ||
252 | /* Duration of the Low Pass Filter rejection window in us */ | ||
253 | return DIV_ROUND_CLOSEST(count, CX23888_IR_REFCLK_FREQ / 1000000); | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * FIFO register pulse width count compuations | ||
258 | */ | ||
259 | static u32 clock_divider_to_resolution(u16 divider) | ||
260 | { | ||
261 | /* | ||
262 | * Resolution is the duration of 1 tick of the readable portion of | ||
263 | * of the pulse width counter as read from the FIFO. The two lsb's are | ||
264 | * not readable, hence the << 2. This function returns ns. | ||
265 | */ | ||
266 | return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000, | ||
267 | CX23888_IR_REFCLK_FREQ / 1000000); | ||
268 | } | ||
269 | |||
270 | static u64 pulse_width_count_to_ns(u16 count, u16 divider) | ||
271 | { | ||
272 | u64 n; | ||
273 | u32 rem; | ||
274 | |||
275 | /* | ||
276 | * The 2 lsb's of the pulse width timer count are not readable, hence | ||
277 | * the (count << 2) | 0x3 | ||
278 | */ | ||
279 | n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */ | ||
280 | rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => ns */ | ||
281 | if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2) | ||
282 | n++; | ||
283 | return n; | ||
284 | } | ||
285 | |||
286 | static unsigned int pulse_width_count_to_us(u16 count, u16 divider) | ||
287 | { | ||
288 | u64 n; | ||
289 | u32 rem; | ||
290 | |||
291 | /* | ||
292 | * The 2 lsb's of the pulse width timer count are not readable, hence | ||
293 | * the (count << 2) | 0x3 | ||
294 | */ | ||
295 | n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */ | ||
296 | rem = do_div(n, CX23888_IR_REFCLK_FREQ / 1000000); /* / MHz => us */ | ||
297 | if (rem >= CX23888_IR_REFCLK_FREQ / 1000000 / 2) | ||
298 | n++; | ||
299 | return (unsigned int) n; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts | ||
304 | * | ||
305 | * The total pulse clock count is an 18 bit pulse width timer count as the most | ||
306 | * significant part and (up to) 16 bit clock divider count as a modulus. | ||
307 | * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse | ||
308 | * width timer count's least significant bit. | ||
309 | */ | ||
310 | static u64 ns_to_pulse_clocks(u32 ns) | ||
311 | { | ||
312 | u64 clocks; | ||
313 | u32 rem; | ||
314 | clocks = CX23888_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles */ | ||
315 | rem = do_div(clocks, 1000); /* /1000 = cycles */ | ||
316 | if (rem >= 1000 / 2) | ||
317 | clocks++; | ||
318 | return clocks; | ||
319 | } | ||
320 | |||
321 | static u16 pulse_clocks_to_clock_divider(u64 count) | ||
322 | { | ||
323 | u32 rem; | ||
324 | |||
325 | rem = do_div(count, (FIFO_RXTX << 2) | 0x3); | ||
326 | |||
327 | /* net result needs to be rounded down and decremented by 1 */ | ||
328 | if (count > RXCLK_RCD + 1) | ||
329 | count = RXCLK_RCD; | ||
330 | else if (count < 2) | ||
331 | count = 1; | ||
332 | else | ||
333 | count--; | ||
334 | return (u16) count; | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * IR Control Register helpers | ||
339 | */ | ||
340 | enum tx_fifo_watermark { | ||
341 | TX_FIFO_HALF_EMPTY = 0, | ||
342 | TX_FIFO_EMPTY = CNTRL_TIC, | ||
343 | }; | ||
344 | |||
345 | enum rx_fifo_watermark { | ||
346 | RX_FIFO_HALF_FULL = 0, | ||
347 | RX_FIFO_NOT_EMPTY = CNTRL_RIC, | ||
348 | }; | ||
349 | |||
350 | static inline void control_tx_irq_watermark(struct cx23885_dev *dev, | ||
351 | enum tx_fifo_watermark level) | ||
352 | { | ||
353 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_TIC, level); | ||
354 | } | ||
355 | |||
356 | static inline void control_rx_irq_watermark(struct cx23885_dev *dev, | ||
357 | enum rx_fifo_watermark level) | ||
358 | { | ||
359 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_RIC, level); | ||
360 | } | ||
361 | |||
362 | static inline void control_tx_enable(struct cx23885_dev *dev, bool enable) | ||
363 | { | ||
364 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE), | ||
365 | enable ? (CNTRL_TXE | CNTRL_TFE) : 0); | ||
366 | } | ||
367 | |||
368 | static inline void control_rx_enable(struct cx23885_dev *dev, bool enable) | ||
369 | { | ||
370 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE), | ||
371 | enable ? (CNTRL_RXE | CNTRL_RFE) : 0); | ||
372 | } | ||
373 | |||
374 | static inline void control_tx_modulation_enable(struct cx23885_dev *dev, | ||
375 | bool enable) | ||
376 | { | ||
377 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_MOD, | ||
378 | enable ? CNTRL_MOD : 0); | ||
379 | } | ||
380 | |||
381 | static inline void control_rx_demodulation_enable(struct cx23885_dev *dev, | ||
382 | bool enable) | ||
383 | { | ||
384 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_DMD, | ||
385 | enable ? CNTRL_DMD : 0); | ||
386 | } | ||
387 | |||
388 | static inline void control_rx_s_edge_detection(struct cx23885_dev *dev, | ||
389 | u32 edge_types) | ||
390 | { | ||
391 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_EDG_BOTH, | ||
392 | edge_types & CNTRL_EDG_BOTH); | ||
393 | } | ||
394 | |||
395 | static void control_rx_s_carrier_window(struct cx23885_dev *dev, | ||
396 | unsigned int carrier, | ||
397 | unsigned int *carrier_range_low, | ||
398 | unsigned int *carrier_range_high) | ||
399 | { | ||
400 | u32 v; | ||
401 | unsigned int c16 = carrier * 16; | ||
402 | |||
403 | if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) { | ||
404 | v = CNTRL_WIN_3_4; | ||
405 | *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4); | ||
406 | } else { | ||
407 | v = CNTRL_WIN_3_3; | ||
408 | *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3); | ||
409 | } | ||
410 | |||
411 | if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) { | ||
412 | v |= CNTRL_WIN_4_3; | ||
413 | *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4); | ||
414 | } else { | ||
415 | v |= CNTRL_WIN_3_3; | ||
416 | *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3); | ||
417 | } | ||
418 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_WIN, v); | ||
419 | } | ||
420 | |||
421 | static inline void control_tx_polarity_invert(struct cx23885_dev *dev, | ||
422 | bool invert) | ||
423 | { | ||
424 | cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_CPL, | ||
425 | invert ? CNTRL_CPL : 0); | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | * IR Rx & Tx Clock Register helpers | ||
430 | */ | ||
431 | static unsigned int txclk_tx_s_carrier(struct cx23885_dev *dev, | ||
432 | unsigned int freq, | ||
433 | u16 *divider) | ||
434 | { | ||
435 | *divider = carrier_freq_to_clock_divider(freq); | ||
436 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); | ||
437 | return clock_divider_to_carrier_freq(*divider); | ||
438 | } | ||
439 | |||
440 | static unsigned int rxclk_rx_s_carrier(struct cx23885_dev *dev, | ||
441 | unsigned int freq, | ||
442 | u16 *divider) | ||
443 | { | ||
444 | *divider = carrier_freq_to_clock_divider(freq); | ||
445 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); | ||
446 | return clock_divider_to_carrier_freq(*divider); | ||
447 | } | ||
448 | |||
449 | static u32 txclk_tx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, | ||
450 | u16 *divider) | ||
451 | { | ||
452 | u64 pulse_clocks; | ||
453 | |||
454 | if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS) | ||
455 | ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; | ||
456 | pulse_clocks = ns_to_pulse_clocks(ns); | ||
457 | *divider = pulse_clocks_to_clock_divider(pulse_clocks); | ||
458 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider); | ||
459 | return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); | ||
460 | } | ||
461 | |||
462 | static u32 rxclk_rx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns, | ||
463 | u16 *divider) | ||
464 | { | ||
465 | u64 pulse_clocks; | ||
466 | |||
467 | if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS) | ||
468 | ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; | ||
469 | pulse_clocks = ns_to_pulse_clocks(ns); | ||
470 | *divider = pulse_clocks_to_clock_divider(pulse_clocks); | ||
471 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider); | ||
472 | return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider); | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * IR Tx Carrier Duty Cycle register helpers | ||
477 | */ | ||
478 | static unsigned int cduty_tx_s_duty_cycle(struct cx23885_dev *dev, | ||
479 | unsigned int duty_cycle) | ||
480 | { | ||
481 | u32 n; | ||
482 | n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */ | ||
483 | if (n != 0) | ||
484 | n--; | ||
485 | if (n > 15) | ||
486 | n = 15; | ||
487 | cx23888_ir_write4(dev, CX23888_IR_CDUTY_REG, n); | ||
488 | return DIV_ROUND_CLOSEST((n + 1) * 100, 16); | ||
489 | } | ||
490 | |||
491 | /* | ||
492 | * IR Filter Register helpers | ||
493 | */ | ||
494 | static u32 filter_rx_s_min_width(struct cx23885_dev *dev, u32 min_width_ns) | ||
495 | { | ||
496 | u32 count = ns_to_lpf_count(min_width_ns); | ||
497 | cx23888_ir_write4(dev, CX23888_IR_FILTR_REG, count); | ||
498 | return lpf_count_to_ns(count); | ||
499 | } | ||
500 | |||
501 | /* | ||
502 | * IR IRQ Enable Register helpers | ||
503 | */ | ||
504 | static inline void irqenable_rx(struct cx23885_dev *dev, u32 mask) | ||
505 | { | ||
506 | mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE); | ||
507 | cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, | ||
508 | ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask); | ||
509 | } | ||
510 | |||
511 | static inline void irqenable_tx(struct cx23885_dev *dev, u32 mask) | ||
512 | { | ||
513 | mask &= IRQEN_TSE; | ||
514 | cx23888_ir_and_or4(dev, CX23888_IR_IRQEN_REG, ~IRQEN_TSE, mask); | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * V4L2 Subdevice IR Ops | ||
519 | */ | ||
520 | static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status, | ||
521 | bool *handled) | ||
522 | { | ||
523 | struct cx23888_ir_state *state = to_state(sd); | ||
524 | struct cx23885_dev *dev = state->dev; | ||
525 | |||
526 | u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); | ||
527 | u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); | ||
528 | u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); | ||
529 | |||
530 | u32 rx_data[FIFO_RX_DEPTH]; | ||
531 | int i, j, k; | ||
532 | u32 events, v; | ||
533 | int tsr, rsr, rto, ror, tse, rse, rte, roe, kror; | ||
534 | |||
535 | tsr = stats & STATS_TSR; /* Tx FIFO Service Request */ | ||
536 | rsr = stats & STATS_RSR; /* Rx FIFO Service Request */ | ||
537 | rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */ | ||
538 | ror = stats & STATS_ROR; /* Rx FIFO Over Run */ | ||
539 | |||
540 | tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */ | ||
541 | rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */ | ||
542 | rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */ | ||
543 | roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */ | ||
544 | |||
545 | *handled = false; | ||
546 | v4l2_dbg(2, ir_888_debug, sd, "IRQ Status: %s %s %s %s %s %s\n", | ||
547 | tsr ? "tsr" : " ", rsr ? "rsr" : " ", | ||
548 | rto ? "rto" : " ", ror ? "ror" : " ", | ||
549 | stats & STATS_TBY ? "tby" : " ", | ||
550 | stats & STATS_RBY ? "rby" : " "); | ||
551 | |||
552 | v4l2_dbg(2, ir_888_debug, sd, "IRQ Enables: %s %s %s %s\n", | ||
553 | tse ? "tse" : " ", rse ? "rse" : " ", | ||
554 | rte ? "rte" : " ", roe ? "roe" : " "); | ||
555 | |||
556 | /* | ||
557 | * Transmitter interrupt service | ||
558 | */ | ||
559 | if (tse && tsr) { | ||
560 | /* | ||
561 | * TODO: | ||
562 | * Check the watermark threshold setting | ||
563 | * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo | ||
564 | * Push the data to the hardware FIFO. | ||
565 | * If there was nothing more to send in the tx_kfifo, disable | ||
566 | * the TSR IRQ and notify the v4l2_device. | ||
567 | * If there was something in the tx_kfifo, check the tx_kfifo | ||
568 | * level and notify the v4l2_device, if it is low. | ||
569 | */ | ||
570 | /* For now, inhibit TSR interrupt until Tx is implemented */ | ||
571 | irqenable_tx(dev, 0); | ||
572 | events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ; | ||
573 | v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events); | ||
574 | *handled = true; | ||
575 | } | ||
576 | |||
577 | /* | ||
578 | * Receiver interrupt service | ||
579 | */ | ||
580 | kror = 0; | ||
581 | if ((rse && rsr) || (rte && rto)) { | ||
582 | /* | ||
583 | * Receive data on RSR to clear the STATS_RSR. | ||
584 | * Receive data on RTO, since we may not have yet hit the RSR | ||
585 | * watermark when we receive the RTO. | ||
586 | */ | ||
587 | for (i = 0, v = FIFO_RX_NDV; | ||
588 | (v & FIFO_RX_NDV) && !kror; i = 0) { | ||
589 | for (j = 0; | ||
590 | (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) { | ||
591 | v = cx23888_ir_read4(dev, CX23888_IR_FIFO_REG); | ||
592 | rx_data[i++] = v & ~FIFO_RX_NDV; | ||
593 | } | ||
594 | if (i == 0) | ||
595 | break; | ||
596 | j = i * sizeof(u32); | ||
597 | k = kfifo_put(state->rx_kfifo, | ||
598 | (unsigned char *) rx_data, j); | ||
599 | if (k != j) | ||
600 | kror++; /* rx_kfifo over run */ | ||
601 | } | ||
602 | *handled = true; | ||
603 | } | ||
604 | |||
605 | events = 0; | ||
606 | v = 0; | ||
607 | if (kror) { | ||
608 | events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN; | ||
609 | v4l2_err(sd, "IR receiver software FIFO overrun\n"); | ||
610 | } | ||
611 | if (roe && ror) { | ||
612 | /* | ||
613 | * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear | ||
614 | * the Rx FIFO Over Run status (STATS_ROR) | ||
615 | */ | ||
616 | v |= CNTRL_RFE; | ||
617 | events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN; | ||
618 | v4l2_err(sd, "IR receiver hardware FIFO overrun\n"); | ||
619 | } | ||
620 | if (rte && rto) { | ||
621 | /* | ||
622 | * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear | ||
623 | * the Rx Pulse Width Timer Time Out (STATS_RTO) | ||
624 | */ | ||
625 | v |= CNTRL_RXE; | ||
626 | events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; | ||
627 | } | ||
628 | if (v) { | ||
629 | /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */ | ||
630 | cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl & ~v); | ||
631 | cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl); | ||
632 | *handled = true; | ||
633 | } | ||
634 | if (kfifo_len(state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) | ||
635 | events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; | ||
636 | |||
637 | if (events) | ||
638 | v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); | ||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | /* Receiver */ | ||
643 | static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, | ||
644 | ssize_t *num) | ||
645 | { | ||
646 | struct cx23888_ir_state *state = to_state(sd); | ||
647 | bool invert = (bool) atomic_read(&state->rx_invert); | ||
648 | u16 divider = (u16) atomic_read(&state->rxclk_divider); | ||
649 | |||
650 | unsigned int i, n; | ||
651 | u32 *p; | ||
652 | u32 u, v; | ||
653 | |||
654 | n = count / sizeof(u32) * sizeof(u32); | ||
655 | if (n == 0) { | ||
656 | *num = 0; | ||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | n = kfifo_get(state->rx_kfifo, buf, n); | ||
661 | |||
662 | n /= sizeof(u32); | ||
663 | *num = n * sizeof(u32); | ||
664 | |||
665 | for (p = (u32 *) buf, i = 0; i < n; p++, i++) { | ||
666 | if ((*p & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) { | ||
667 | *p = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END; | ||
668 | v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n"); | ||
669 | continue; | ||
670 | } | ||
671 | |||
672 | u = (*p & FIFO_RXTX_LVL) ? V4L2_SUBDEV_IR_PULSE_LEVEL_MASK : 0; | ||
673 | if (invert) | ||
674 | u = u ? 0 : V4L2_SUBDEV_IR_PULSE_LEVEL_MASK; | ||
675 | |||
676 | v = (u32) pulse_width_count_to_ns((u16) (*p & FIFO_RXTX), | ||
677 | divider); | ||
678 | if (v >= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS) | ||
679 | v = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS - 1; | ||
680 | |||
681 | *p = u | v; | ||
682 | |||
683 | v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s\n", | ||
684 | v, u ? "mark" : "space"); | ||
685 | } | ||
686 | return 0; | ||
687 | } | ||
688 | |||
689 | static int cx23888_ir_rx_g_parameters(struct v4l2_subdev *sd, | ||
690 | struct v4l2_subdev_ir_parameters *p) | ||
691 | { | ||
692 | struct cx23888_ir_state *state = to_state(sd); | ||
693 | mutex_lock(&state->rx_params_lock); | ||
694 | memcpy(p, &state->rx_params, sizeof(struct v4l2_subdev_ir_parameters)); | ||
695 | mutex_unlock(&state->rx_params_lock); | ||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | static int cx23888_ir_rx_shutdown(struct v4l2_subdev *sd) | ||
700 | { | ||
701 | struct cx23888_ir_state *state = to_state(sd); | ||
702 | struct cx23885_dev *dev = state->dev; | ||
703 | |||
704 | mutex_lock(&state->rx_params_lock); | ||
705 | |||
706 | /* Disable or slow down all IR Rx circuits and counters */ | ||
707 | irqenable_rx(dev, 0); | ||
708 | control_rx_enable(dev, false); | ||
709 | control_rx_demodulation_enable(dev, false); | ||
710 | control_rx_s_edge_detection(dev, CNTRL_EDG_NONE); | ||
711 | filter_rx_s_min_width(dev, 0); | ||
712 | cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, RXCLK_RCD); | ||
713 | |||
714 | state->rx_params.shutdown = true; | ||
715 | |||
716 | mutex_unlock(&state->rx_params_lock); | ||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd, | ||
721 | struct v4l2_subdev_ir_parameters *p) | ||
722 | { | ||
723 | struct cx23888_ir_state *state = to_state(sd); | ||
724 | struct cx23885_dev *dev = state->dev; | ||
725 | struct v4l2_subdev_ir_parameters *o = &state->rx_params; | ||
726 | u16 rxclk_divider; | ||
727 | |||
728 | if (p->shutdown) | ||
729 | return cx23888_ir_rx_shutdown(sd); | ||
730 | |||
731 | if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) | ||
732 | return -ENOSYS; | ||
733 | |||
734 | mutex_lock(&state->rx_params_lock); | ||
735 | |||
736 | o->shutdown = p->shutdown; | ||
737 | |||
738 | o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
739 | |||
740 | o->bytes_per_data_element = p->bytes_per_data_element = sizeof(u32); | ||
741 | |||
742 | /* Before we tweak the hardware, we have to disable the receiver */ | ||
743 | irqenable_rx(dev, 0); | ||
744 | control_rx_enable(dev, false); | ||
745 | |||
746 | control_rx_demodulation_enable(dev, p->modulation); | ||
747 | o->modulation = p->modulation; | ||
748 | |||
749 | if (p->modulation) { | ||
750 | p->carrier_freq = rxclk_rx_s_carrier(dev, p->carrier_freq, | ||
751 | &rxclk_divider); | ||
752 | |||
753 | o->carrier_freq = p->carrier_freq; | ||
754 | |||
755 | o->duty_cycle = p->duty_cycle = 50; | ||
756 | |||
757 | control_rx_s_carrier_window(dev, p->carrier_freq, | ||
758 | &p->carrier_range_lower, | ||
759 | &p->carrier_range_upper); | ||
760 | o->carrier_range_lower = p->carrier_range_lower; | ||
761 | o->carrier_range_upper = p->carrier_range_upper; | ||
762 | } else { | ||
763 | p->max_pulse_width = | ||
764 | rxclk_rx_s_max_pulse_width(dev, p->max_pulse_width, | ||
765 | &rxclk_divider); | ||
766 | o->max_pulse_width = p->max_pulse_width; | ||
767 | } | ||
768 | atomic_set(&state->rxclk_divider, rxclk_divider); | ||
769 | |||
770 | p->noise_filter_min_width = | ||
771 | filter_rx_s_min_width(dev, p->noise_filter_min_width); | ||
772 | o->noise_filter_min_width = p->noise_filter_min_width; | ||
773 | |||
774 | p->resolution = clock_divider_to_resolution(rxclk_divider); | ||
775 | o->resolution = p->resolution; | ||
776 | |||
777 | /* FIXME - make this dependent on resolution for better performance */ | ||
778 | control_rx_irq_watermark(dev, RX_FIFO_HALF_FULL); | ||
779 | |||
780 | control_rx_s_edge_detection(dev, CNTRL_EDG_BOTH); | ||
781 | |||
782 | o->invert = p->invert; | ||
783 | atomic_set(&state->rx_invert, p->invert); | ||
784 | |||
785 | o->interrupt_enable = p->interrupt_enable; | ||
786 | o->enable = p->enable; | ||
787 | if (p->enable) { | ||
788 | kfifo_reset(state->rx_kfifo); | ||
789 | if (p->interrupt_enable) | ||
790 | irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); | ||
791 | control_rx_enable(dev, p->enable); | ||
792 | } | ||
793 | |||
794 | mutex_unlock(&state->rx_params_lock); | ||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | /* Transmitter */ | ||
799 | static int cx23888_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count, | ||
800 | ssize_t *num) | ||
801 | { | ||
802 | struct cx23888_ir_state *state = to_state(sd); | ||
803 | struct cx23885_dev *dev = state->dev; | ||
804 | /* For now enable the Tx FIFO Service interrupt & pretend we did work */ | ||
805 | irqenable_tx(dev, IRQEN_TSE); | ||
806 | *num = count; | ||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | static int cx23888_ir_tx_g_parameters(struct v4l2_subdev *sd, | ||
811 | struct v4l2_subdev_ir_parameters *p) | ||
812 | { | ||
813 | struct cx23888_ir_state *state = to_state(sd); | ||
814 | mutex_lock(&state->tx_params_lock); | ||
815 | memcpy(p, &state->tx_params, sizeof(struct v4l2_subdev_ir_parameters)); | ||
816 | mutex_unlock(&state->tx_params_lock); | ||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | static int cx23888_ir_tx_shutdown(struct v4l2_subdev *sd) | ||
821 | { | ||
822 | struct cx23888_ir_state *state = to_state(sd); | ||
823 | struct cx23885_dev *dev = state->dev; | ||
824 | |||
825 | mutex_lock(&state->tx_params_lock); | ||
826 | |||
827 | /* Disable or slow down all IR Tx circuits and counters */ | ||
828 | irqenable_tx(dev, 0); | ||
829 | control_tx_enable(dev, false); | ||
830 | control_tx_modulation_enable(dev, false); | ||
831 | cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, TXCLK_TCD); | ||
832 | |||
833 | state->tx_params.shutdown = true; | ||
834 | |||
835 | mutex_unlock(&state->tx_params_lock); | ||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd, | ||
840 | struct v4l2_subdev_ir_parameters *p) | ||
841 | { | ||
842 | struct cx23888_ir_state *state = to_state(sd); | ||
843 | struct cx23885_dev *dev = state->dev; | ||
844 | struct v4l2_subdev_ir_parameters *o = &state->tx_params; | ||
845 | u16 txclk_divider; | ||
846 | |||
847 | if (p->shutdown) | ||
848 | return cx23888_ir_tx_shutdown(sd); | ||
849 | |||
850 | if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH) | ||
851 | return -ENOSYS; | ||
852 | |||
853 | mutex_lock(&state->tx_params_lock); | ||
854 | |||
855 | o->shutdown = p->shutdown; | ||
856 | |||
857 | o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH; | ||
858 | |||
859 | o->bytes_per_data_element = p->bytes_per_data_element = sizeof(u32); | ||
860 | |||
861 | /* Before we tweak the hardware, we have to disable the transmitter */ | ||
862 | irqenable_tx(dev, 0); | ||
863 | control_tx_enable(dev, false); | ||
864 | |||
865 | control_tx_modulation_enable(dev, p->modulation); | ||
866 | o->modulation = p->modulation; | ||
867 | |||
868 | if (p->modulation) { | ||
869 | p->carrier_freq = txclk_tx_s_carrier(dev, p->carrier_freq, | ||
870 | &txclk_divider); | ||
871 | o->carrier_freq = p->carrier_freq; | ||
872 | |||
873 | p->duty_cycle = cduty_tx_s_duty_cycle(dev, p->duty_cycle); | ||
874 | o->duty_cycle = p->duty_cycle; | ||
875 | } else { | ||
876 | p->max_pulse_width = | ||
877 | txclk_tx_s_max_pulse_width(dev, p->max_pulse_width, | ||
878 | &txclk_divider); | ||
879 | o->max_pulse_width = p->max_pulse_width; | ||
880 | } | ||
881 | atomic_set(&state->txclk_divider, txclk_divider); | ||
882 | |||
883 | p->resolution = clock_divider_to_resolution(txclk_divider); | ||
884 | o->resolution = p->resolution; | ||
885 | |||
886 | /* FIXME - make this dependent on resolution for better performance */ | ||
887 | control_tx_irq_watermark(dev, TX_FIFO_HALF_EMPTY); | ||
888 | |||
889 | control_tx_polarity_invert(dev, p->invert); | ||
890 | o->invert = p->invert; | ||
891 | |||
892 | o->interrupt_enable = p->interrupt_enable; | ||
893 | o->enable = p->enable; | ||
894 | if (p->enable) { | ||
895 | kfifo_reset(state->tx_kfifo); | ||
896 | if (p->interrupt_enable) | ||
897 | irqenable_tx(dev, IRQEN_TSE); | ||
898 | control_tx_enable(dev, p->enable); | ||
899 | } | ||
900 | |||
901 | mutex_unlock(&state->tx_params_lock); | ||
902 | return 0; | ||
903 | } | ||
904 | |||
905 | |||
906 | /* | ||
907 | * V4L2 Subdevice Core Ops | ||
908 | */ | ||
909 | static int cx23888_ir_log_status(struct v4l2_subdev *sd) | ||
910 | { | ||
911 | struct cx23888_ir_state *state = to_state(sd); | ||
912 | struct cx23885_dev *dev = state->dev; | ||
913 | char *s; | ||
914 | int i, j; | ||
915 | |||
916 | u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); | ||
917 | u32 txclk = cx23888_ir_read4(dev, CX23888_IR_TXCLK_REG) & TXCLK_TCD; | ||
918 | u32 rxclk = cx23888_ir_read4(dev, CX23888_IR_RXCLK_REG) & RXCLK_RCD; | ||
919 | u32 cduty = cx23888_ir_read4(dev, CX23888_IR_CDUTY_REG) & CDUTY_CDC; | ||
920 | u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG); | ||
921 | u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); | ||
922 | u32 filtr = cx23888_ir_read4(dev, CX23888_IR_FILTR_REG) & FILTR_LPF; | ||
923 | |||
924 | v4l2_info(sd, "IR Receiver:\n"); | ||
925 | v4l2_info(sd, "\tEnabled: %s\n", | ||
926 | cntrl & CNTRL_RXE ? "yes" : "no"); | ||
927 | v4l2_info(sd, "\tDemodulation from a carrier: %s\n", | ||
928 | cntrl & CNTRL_DMD ? "enabled" : "disabled"); | ||
929 | v4l2_info(sd, "\tFIFO: %s\n", | ||
930 | cntrl & CNTRL_RFE ? "enabled" : "disabled"); | ||
931 | switch (cntrl & CNTRL_EDG) { | ||
932 | case CNTRL_EDG_NONE: | ||
933 | s = "disabled"; | ||
934 | break; | ||
935 | case CNTRL_EDG_FALL: | ||
936 | s = "falling edge"; | ||
937 | break; | ||
938 | case CNTRL_EDG_RISE: | ||
939 | s = "rising edge"; | ||
940 | break; | ||
941 | case CNTRL_EDG_BOTH: | ||
942 | s = "rising & falling edges"; | ||
943 | break; | ||
944 | default: | ||
945 | s = "??? edge"; | ||
946 | break; | ||
947 | } | ||
948 | v4l2_info(sd, "\tPulse timers' start/stop trigger: %s\n", s); | ||
949 | v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n", | ||
950 | cntrl & CNTRL_R ? "not loaded" : "overflow marker"); | ||
951 | v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", | ||
952 | cntrl & CNTRL_RIC ? "not empty" : "half full or greater"); | ||
953 | v4l2_info(sd, "\tLoopback mode: %s\n", | ||
954 | cntrl & CNTRL_LBM ? "loopback active" : "normal receive"); | ||
955 | if (cntrl & CNTRL_DMD) { | ||
956 | v4l2_info(sd, "\tExpected carrier (16 clocks): %u Hz\n", | ||
957 | clock_divider_to_carrier_freq(rxclk)); | ||
958 | switch (cntrl & CNTRL_WIN) { | ||
959 | case CNTRL_WIN_3_3: | ||
960 | i = 3; | ||
961 | j = 3; | ||
962 | break; | ||
963 | case CNTRL_WIN_4_3: | ||
964 | i = 4; | ||
965 | j = 3; | ||
966 | break; | ||
967 | case CNTRL_WIN_3_4: | ||
968 | i = 3; | ||
969 | j = 4; | ||
970 | break; | ||
971 | case CNTRL_WIN_4_4: | ||
972 | i = 4; | ||
973 | j = 4; | ||
974 | break; | ||
975 | default: | ||
976 | i = 0; | ||
977 | j = 0; | ||
978 | break; | ||
979 | } | ||
980 | v4l2_info(sd, "\tNext carrier edge window: 16 clocks " | ||
981 | "-%1d/+%1d, %u to %u Hz\n", i, j, | ||
982 | clock_divider_to_freq(rxclk, 16 + j), | ||
983 | clock_divider_to_freq(rxclk, 16 - i)); | ||
984 | } else { | ||
985 | v4l2_info(sd, "\tMax measurable pulse width: %u us, " | ||
986 | "%llu ns\n", | ||
987 | pulse_width_count_to_us(FIFO_RXTX, rxclk), | ||
988 | pulse_width_count_to_ns(FIFO_RXTX, rxclk)); | ||
989 | } | ||
990 | v4l2_info(sd, "\tLow pass filter: %s\n", | ||
991 | filtr ? "enabled" : "disabled"); | ||
992 | if (filtr) | ||
993 | v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, " | ||
994 | "%u ns\n", | ||
995 | lpf_count_to_us(filtr), | ||
996 | lpf_count_to_ns(filtr)); | ||
997 | v4l2_info(sd, "\tPulse width timer timed-out: %s\n", | ||
998 | stats & STATS_RTO ? "yes" : "no"); | ||
999 | v4l2_info(sd, "\tPulse width timer time-out intr: %s\n", | ||
1000 | irqen & IRQEN_RTE ? "enabled" : "disabled"); | ||
1001 | v4l2_info(sd, "\tFIFO overrun: %s\n", | ||
1002 | stats & STATS_ROR ? "yes" : "no"); | ||
1003 | v4l2_info(sd, "\tFIFO overrun interrupt: %s\n", | ||
1004 | irqen & IRQEN_ROE ? "enabled" : "disabled"); | ||
1005 | v4l2_info(sd, "\tBusy: %s\n", | ||
1006 | stats & STATS_RBY ? "yes" : "no"); | ||
1007 | v4l2_info(sd, "\tFIFO service requested: %s\n", | ||
1008 | stats & STATS_RSR ? "yes" : "no"); | ||
1009 | v4l2_info(sd, "\tFIFO service request interrupt: %s\n", | ||
1010 | irqen & IRQEN_RSE ? "enabled" : "disabled"); | ||
1011 | |||
1012 | v4l2_info(sd, "IR Transmitter:\n"); | ||
1013 | v4l2_info(sd, "\tEnabled: %s\n", | ||
1014 | cntrl & CNTRL_TXE ? "yes" : "no"); | ||
1015 | v4l2_info(sd, "\tModulation onto a carrier: %s\n", | ||
1016 | cntrl & CNTRL_MOD ? "enabled" : "disabled"); | ||
1017 | v4l2_info(sd, "\tFIFO: %s\n", | ||
1018 | cntrl & CNTRL_TFE ? "enabled" : "disabled"); | ||
1019 | v4l2_info(sd, "\tFIFO interrupt watermark: %s\n", | ||
1020 | cntrl & CNTRL_TIC ? "not empty" : "half full or less"); | ||
1021 | v4l2_info(sd, "\tSignal polarity: %s\n", | ||
1022 | cntrl & CNTRL_CPL ? "0:mark 1:space" : "0:space 1:mark"); | ||
1023 | if (cntrl & CNTRL_MOD) { | ||
1024 | v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n", | ||
1025 | clock_divider_to_carrier_freq(txclk)); | ||
1026 | v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n", | ||
1027 | cduty + 1); | ||
1028 | } else { | ||
1029 | v4l2_info(sd, "\tMax pulse width: %u us, " | ||
1030 | "%llu ns\n", | ||
1031 | pulse_width_count_to_us(FIFO_RXTX, txclk), | ||
1032 | pulse_width_count_to_ns(FIFO_RXTX, txclk)); | ||
1033 | } | ||
1034 | v4l2_info(sd, "\tBusy: %s\n", | ||
1035 | stats & STATS_TBY ? "yes" : "no"); | ||
1036 | v4l2_info(sd, "\tFIFO service requested: %s\n", | ||
1037 | stats & STATS_TSR ? "yes" : "no"); | ||
1038 | v4l2_info(sd, "\tFIFO service request interrupt: %s\n", | ||
1039 | irqen & IRQEN_TSE ? "enabled" : "disabled"); | ||
1040 | |||
1041 | return 0; | ||
1042 | } | ||
1043 | |||
1044 | static inline int cx23888_ir_dbg_match(const struct v4l2_dbg_match *match) | ||
1045 | { | ||
1046 | return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 2; | ||
1047 | } | ||
1048 | |||
1049 | static int cx23888_ir_g_chip_ident(struct v4l2_subdev *sd, | ||
1050 | struct v4l2_dbg_chip_ident *chip) | ||
1051 | { | ||
1052 | struct cx23888_ir_state *state = to_state(sd); | ||
1053 | |||
1054 | if (cx23888_ir_dbg_match(&chip->match)) { | ||
1055 | chip->ident = state->id; | ||
1056 | chip->revision = state->rev; | ||
1057 | } | ||
1058 | return 0; | ||
1059 | } | ||
1060 | |||
1061 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1062 | static int cx23888_ir_g_register(struct v4l2_subdev *sd, | ||
1063 | struct v4l2_dbg_register *reg) | ||
1064 | { | ||
1065 | struct cx23888_ir_state *state = to_state(sd); | ||
1066 | u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; | ||
1067 | |||
1068 | if (!cx23888_ir_dbg_match(®->match)) | ||
1069 | return -EINVAL; | ||
1070 | if ((addr & 0x3) != 0) | ||
1071 | return -EINVAL; | ||
1072 | if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG) | ||
1073 | return -EINVAL; | ||
1074 | if (!capable(CAP_SYS_ADMIN)) | ||
1075 | return -EPERM; | ||
1076 | reg->size = 4; | ||
1077 | reg->val = cx23888_ir_read4(state->dev, addr); | ||
1078 | return 0; | ||
1079 | } | ||
1080 | |||
1081 | static int cx23888_ir_s_register(struct v4l2_subdev *sd, | ||
1082 | struct v4l2_dbg_register *reg) | ||
1083 | { | ||
1084 | struct cx23888_ir_state *state = to_state(sd); | ||
1085 | u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; | ||
1086 | |||
1087 | if (!cx23888_ir_dbg_match(®->match)) | ||
1088 | return -EINVAL; | ||
1089 | if ((addr & 0x3) != 0) | ||
1090 | return -EINVAL; | ||
1091 | if (addr < CX23888_IR_CNTRL_REG || addr > CX23888_IR_LEARN_REG) | ||
1092 | return -EINVAL; | ||
1093 | if (!capable(CAP_SYS_ADMIN)) | ||
1094 | return -EPERM; | ||
1095 | cx23888_ir_write4(state->dev, addr, reg->val); | ||
1096 | return 0; | ||
1097 | } | ||
1098 | #endif | ||
1099 | |||
1100 | static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = { | ||
1101 | .g_chip_ident = cx23888_ir_g_chip_ident, | ||
1102 | .log_status = cx23888_ir_log_status, | ||
1103 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1104 | .g_register = cx23888_ir_g_register, | ||
1105 | .s_register = cx23888_ir_s_register, | ||
1106 | #endif | ||
1107 | }; | ||
1108 | |||
1109 | static const struct v4l2_subdev_ir_ops cx23888_ir_ir_ops = { | ||
1110 | .interrupt_service_routine = cx23888_ir_irq_handler, | ||
1111 | |||
1112 | .rx_read = cx23888_ir_rx_read, | ||
1113 | .rx_g_parameters = cx23888_ir_rx_g_parameters, | ||
1114 | .rx_s_parameters = cx23888_ir_rx_s_parameters, | ||
1115 | |||
1116 | .tx_write = cx23888_ir_tx_write, | ||
1117 | .tx_g_parameters = cx23888_ir_tx_g_parameters, | ||
1118 | .tx_s_parameters = cx23888_ir_tx_s_parameters, | ||
1119 | }; | ||
1120 | |||
1121 | static const struct v4l2_subdev_ops cx23888_ir_controller_ops = { | ||
1122 | .core = &cx23888_ir_core_ops, | ||
1123 | .ir = &cx23888_ir_ir_ops, | ||
1124 | }; | ||
1125 | |||
1126 | static const struct v4l2_subdev_ir_parameters default_rx_params = { | ||
1127 | .bytes_per_data_element = sizeof(u32), | ||
1128 | .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, | ||
1129 | |||
1130 | .enable = false, | ||
1131 | .interrupt_enable = false, | ||
1132 | .shutdown = true, | ||
1133 | |||
1134 | .modulation = true, | ||
1135 | .carrier_freq = 36000, /* 36 kHz - RC-5, RC-6, and RC-6A carrier */ | ||
1136 | |||
1137 | /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */ | ||
1138 | /* RC-6A: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */ | ||
1139 | .noise_filter_min_width = 333333, /* ns */ | ||
1140 | .carrier_range_lower = 35000, | ||
1141 | .carrier_range_upper = 37000, | ||
1142 | .invert = false, | ||
1143 | }; | ||
1144 | |||
1145 | static const struct v4l2_subdev_ir_parameters default_tx_params = { | ||
1146 | .bytes_per_data_element = sizeof(u32), | ||
1147 | .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH, | ||
1148 | |||
1149 | .enable = false, | ||
1150 | .interrupt_enable = false, | ||
1151 | .shutdown = true, | ||
1152 | |||
1153 | .modulation = true, | ||
1154 | .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */ | ||
1155 | .duty_cycle = 25, /* 25 % - RC-5 carrier */ | ||
1156 | .invert = false, | ||
1157 | }; | ||
1158 | |||
1159 | int cx23888_ir_probe(struct cx23885_dev *dev) | ||
1160 | { | ||
1161 | struct cx23888_ir_state *state; | ||
1162 | struct v4l2_subdev *sd; | ||
1163 | struct v4l2_subdev_ir_parameters default_params; | ||
1164 | int ret; | ||
1165 | |||
1166 | state = kzalloc(sizeof(struct cx23888_ir_state), GFP_KERNEL); | ||
1167 | if (state == NULL) | ||
1168 | return -ENOMEM; | ||
1169 | |||
1170 | spin_lock_init(&state->rx_kfifo_lock); | ||
1171 | state->rx_kfifo = kfifo_alloc(CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL, | ||
1172 | &state->rx_kfifo_lock); | ||
1173 | if (state->rx_kfifo == NULL) | ||
1174 | return -ENOMEM; | ||
1175 | |||
1176 | spin_lock_init(&state->tx_kfifo_lock); | ||
1177 | state->tx_kfifo = kfifo_alloc(CX23888_IR_TX_KFIFO_SIZE, GFP_KERNEL, | ||
1178 | &state->tx_kfifo_lock); | ||
1179 | if (state->tx_kfifo == NULL) { | ||
1180 | kfifo_free(state->rx_kfifo); | ||
1181 | return -ENOMEM; | ||
1182 | } | ||
1183 | |||
1184 | state->dev = dev; | ||
1185 | state->id = V4L2_IDENT_CX23888_IR; | ||
1186 | state->rev = 0; | ||
1187 | sd = &state->sd; | ||
1188 | |||
1189 | v4l2_subdev_init(sd, &cx23888_ir_controller_ops); | ||
1190 | v4l2_set_subdevdata(sd, state); | ||
1191 | /* FIXME - fix the formatting of dev->v4l2_dev.name and use it */ | ||
1192 | snprintf(sd->name, sizeof(sd->name), "%s/888-ir", dev->name); | ||
1193 | sd->grp_id = CX23885_HW_888_IR; | ||
1194 | |||
1195 | ret = v4l2_device_register_subdev(&dev->v4l2_dev, sd); | ||
1196 | if (ret == 0) { | ||
1197 | /* | ||
1198 | * Ensure no interrupts arrive from '888 specific conditions, | ||
1199 | * since we ignore them in this driver to have commonality with | ||
1200 | * similar IR controller cores. | ||
1201 | */ | ||
1202 | cx23888_ir_write4(dev, CX23888_IR_IRQEN_REG, 0); | ||
1203 | |||
1204 | mutex_init(&state->rx_params_lock); | ||
1205 | memcpy(&default_params, &default_rx_params, | ||
1206 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1207 | v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params); | ||
1208 | |||
1209 | mutex_init(&state->tx_params_lock); | ||
1210 | memcpy(&default_params, &default_tx_params, | ||
1211 | sizeof(struct v4l2_subdev_ir_parameters)); | ||
1212 | v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); | ||
1213 | } else { | ||
1214 | kfifo_free(state->rx_kfifo); | ||
1215 | kfifo_free(state->tx_kfifo); | ||
1216 | } | ||
1217 | return ret; | ||
1218 | } | ||
1219 | |||
1220 | int cx23888_ir_remove(struct cx23885_dev *dev) | ||
1221 | { | ||
1222 | struct v4l2_subdev *sd; | ||
1223 | struct cx23888_ir_state *state; | ||
1224 | |||
1225 | sd = cx23885_find_hw(dev, CX23885_HW_888_IR); | ||
1226 | if (sd == NULL) | ||
1227 | return -ENODEV; | ||
1228 | |||
1229 | cx23888_ir_rx_shutdown(sd); | ||
1230 | cx23888_ir_tx_shutdown(sd); | ||
1231 | |||
1232 | state = to_state(sd); | ||
1233 | v4l2_device_unregister_subdev(sd); | ||
1234 | kfifo_free(state->rx_kfifo); | ||
1235 | kfifo_free(state->tx_kfifo); | ||
1236 | kfree(state); | ||
1237 | /* Nothing more to free() as state held the actual v4l2_subdev object */ | ||
1238 | return 0; | ||
1239 | } | ||
diff --git a/drivers/media/video/cx23885/cx23888-ir.h b/drivers/media/video/cx23885/cx23888-ir.h new file mode 100644 index 000000000000..3d446f9eb94b --- /dev/null +++ b/drivers/media/video/cx23885/cx23888-ir.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Driver for the Conexant CX23885/7/8 PCIe bridge | ||
3 | * | ||
4 | * CX23888 Integrated Consumer Infrared Controller | ||
5 | * | ||
6 | * Copyright (C) 2009 Andy Walls <awalls@radix.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version 2 | ||
11 | * of the License, or (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 | * 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., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef _CX23888_IR_H_ | ||
25 | #define _CX23888_IR_H_ | ||
26 | int cx23888_ir_probe(struct cx23885_dev *dev); | ||
27 | int cx23888_ir_remove(struct cx23885_dev *dev); | ||
28 | #endif | ||