Jelajahi Sumber

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: (425 commits)
  V4L/DVB (11870): gspca - main: VIDIOC_ENUM_FRAMESIZES ioctl added.
  V4L/DVB (12004): poll method lose race condition
  V4L/DVB (11894): flexcop-pci: dmesg visible names broken
  V4L/DVB (11892): Siano: smsendian - declare function as extern
  V4L/DVB (11891): Siano: smscore - bind the GPIO SMS protocol
  V4L/DVB (11890): Siano: smscore - remove redundant code
  V4L/DVB (11889): Siano: smsdvb - add DVB v3 events
  V4L/DVB (11888): Siano: smsusb - remove redundant ifdef
  V4L/DVB (11887): Siano: smscards - add board (target) events
  V4L/DVB (11886): Siano: smscore - fix some new GPIO definitions names
  V4L/DVB (11885): Siano: Add new GPIO management interface
  V4L/DVB (11884): Siano: smssdio - revert to stand alone module
  V4L/DVB (11883): Siano: cards - add two additional (USB) devices
  V4L/DVB (11824): Siano: smsusb - change exit func debug msg
  V4L/DVB (11823): Siano: smsusb - fix typo in module description
  V4L/DVB (11822): Siano: smscore - bug fix at get_device_mode
  V4L/DVB (11821): Siano: smscore - fix isdb-t firmware name
  V4L/DVB (11820): Siano: smscore - fix byte ordering bug
  V4L/DVB (11819): Siano: smscore - fix get_common_buffer bug
  V4L/DVB (11818): Siano: smscards - assign gpio to HPG targets
  ...
Linus Torvalds 16 tahun lalu
induk
melakukan
0dd5198672
100 mengubah file dengan 13642 tambahan dan 1430 penghapusan
  1. 4 4
      Documentation/dvb/get_dvb_firmware
  2. 5 0
      Documentation/video4linux/CARDLIST.cx23885
  3. 2 0
      Documentation/video4linux/CARDLIST.cx88
  4. 5 1
      Documentation/video4linux/CARDLIST.em28xx
  5. 17 5
      Documentation/video4linux/CARDLIST.saa7134
  6. 2 0
      Documentation/video4linux/CARDLIST.tuner
  7. 10 2
      Documentation/video4linux/gspca.txt
  8. 49 0
      Documentation/video4linux/pxa_camera.txt
  9. 5 0
      Documentation/video4linux/v4l2-framework.txt
  10. 16 7
      arch/arm/mach-pxa/pcm990-baseboard.c
  11. 8 2
      drivers/media/Kconfig
  12. 30 14
      drivers/media/common/tuners/tuner-simple.c
  13. 59 0
      drivers/media/common/tuners/tuner-types.c
  14. 31 25
      drivers/media/common/tuners/tuner-xc2028.c
  15. 138 126
      drivers/media/common/tuners/xc5000.c
  16. 3 5
      drivers/media/dvb/b2c2/flexcop-common.h
  17. 440 349
      drivers/media/dvb/b2c2/flexcop-fe-tuner.c
  18. 1 1
      drivers/media/dvb/b2c2/flexcop-i2c.c
  19. 10 10
      drivers/media/dvb/b2c2/flexcop-misc.c
  20. 1 7
      drivers/media/dvb/bt8xx/bt878.c
  21. 80 41
      drivers/media/dvb/dm1105/dm1105.c
  22. 4 10
      drivers/media/dvb/dvb-core/dmxdev.c
  23. 42 0
      drivers/media/dvb/dvb-core/dvb_demux.c
  24. 4 0
      drivers/media/dvb/dvb-core/dvb_demux.h
  25. 2 0
      drivers/media/dvb/dvb-core/dvb_frontend.c
  26. 1 0
      drivers/media/dvb/dvb-usb/Kconfig
  27. 88 6
      drivers/media/dvb/dvb-usb/af9015.c
  28. 23 8
      drivers/media/dvb/dvb-usb/dib0700_devices.c
  29. 5 2
      drivers/media/dvb/dvb-usb/dibusb-common.c
  30. 8 0
      drivers/media/dvb/dvb-usb/dvb-usb-ids.h
  31. 1 1
      drivers/media/dvb/dvb-usb/dvb-usb.h
  32. 293 32
      drivers/media/dvb/dvb-usb/dw2102.c
  33. 1 0
      drivers/media/dvb/dvb-usb/dw2102.h
  34. 2 6
      drivers/media/dvb/dvb-usb/gp8psk.c
  35. 2 2
      drivers/media/dvb/firewire/firedtv-rc.c
  36. 22 0
      drivers/media/dvb/frontends/Kconfig
  37. 3 1
      drivers/media/dvb/frontends/Makefile
  38. 1 1
      drivers/media/dvb/frontends/af9013.c
  39. 92 6
      drivers/media/dvb/frontends/au8522_dig.c
  40. 1 1
      drivers/media/dvb/frontends/cx24116.c
  41. 2 2
      drivers/media/dvb/frontends/drx397xD.c
  42. 308 0
      drivers/media/dvb/frontends/isl6423.c
  43. 63 0
      drivers/media/dvb/frontends/isl6423.h
  44. 3 14
      drivers/media/dvb/frontends/lgdt3305.c
  45. 5 5
      drivers/media/dvb/frontends/lgs8gxx.c
  46. 1 1
      drivers/media/dvb/frontends/lnbp21.c
  47. 1 1
      drivers/media/dvb/frontends/mt312.c
  48. 4 2
      drivers/media/dvb/frontends/nxt200x.c
  49. 1 1
      drivers/media/dvb/frontends/or51132.c
  50. 0 2
      drivers/media/dvb/frontends/stv0900_priv.h
  51. 4299 0
      drivers/media/dvb/frontends/stv090x.c
  52. 106 0
      drivers/media/dvb/frontends/stv090x.h
  53. 269 0
      drivers/media/dvb/frontends/stv090x_priv.h
  54. 2373 0
      drivers/media/dvb/frontends/stv090x_reg.h
  55. 373 0
      drivers/media/dvb/frontends/stv6110x.c
  56. 71 0
      drivers/media/dvb/frontends/stv6110x.h
  57. 75 0
      drivers/media/dvb/frontends/stv6110x_priv.h
  58. 82 0
      drivers/media/dvb/frontends/stv6110x_reg.h
  59. 298 14
      drivers/media/dvb/frontends/tda10048.c
  60. 20 1
      drivers/media/dvb/frontends/tda10048.h
  61. 1 1
      drivers/media/dvb/siano/Makefile
  62. 184 4
      drivers/media/dvb/siano/sms-cards.c
  63. 64 0
      drivers/media/dvb/siano/sms-cards.h
  64. 387 81
      drivers/media/dvb/siano/smscoreapi.c
  65. 372 116
      drivers/media/dvb/siano/smscoreapi.h
  66. 237 135
      drivers/media/dvb/siano/smsdvb.c
  67. 102 0
      drivers/media/dvb/siano/smsendian.c
  68. 32 0
      drivers/media/dvb/siano/smsendian.h
  69. 301 0
      drivers/media/dvb/siano/smsir.c
  70. 93 0
      drivers/media/dvb/siano/smsir.h
  71. 357 0
      drivers/media/dvb/siano/smssdio.c
  72. 42 33
      drivers/media/dvb/siano/smsusb.c
  73. 91 33
      drivers/media/dvb/ttpci/av7110_av.c
  74. 1 1
      drivers/media/dvb/ttpci/av7110_hw.c
  75. 1 1
      drivers/media/dvb/ttpci/av7110_v4l.c
  76. 1 1
      drivers/media/dvb/ttpci/budget-av.c
  77. 85 0
      drivers/media/dvb/ttpci/budget.c
  78. 38 71
      drivers/media/radio/dsbr100.c
  79. 1 0
      drivers/media/radio/radio-mr800.c
  80. 4 12
      drivers/media/radio/radio-sf16fmi.c
  81. 7 15
      drivers/media/radio/radio-sf16fmr2.c
  82. 0 1
      drivers/media/radio/radio-si470x.c
  83. 19 1
      drivers/media/video/Kconfig
  84. 43 36
      drivers/media/video/Makefile
  85. 534 0
      drivers/media/video/adv7343.c
  86. 185 0
      drivers/media/video/adv7343_regs.h
  87. 2 2
      drivers/media/video/au0828/au0828-cards.c
  88. 17 0
      drivers/media/video/au0828/au0828-core.c
  89. 3 5
      drivers/media/video/au0828/au0828-video.c
  90. 8 6
      drivers/media/video/bt8xx/bttv-driver.c
  91. 21 0
      drivers/media/video/bt8xx/bttv-i2c.c
  92. 3 3
      drivers/media/video/cpia2/cpia2_v4l.c
  93. 38 6
      drivers/media/video/cx18/cx18-audio.c
  94. 273 101
      drivers/media/video/cx18/cx18-av-core.c
  95. 78 4
      drivers/media/video/cx18/cx18-av-firmware.c
  96. 2 2
      drivers/media/video/cx18/cx18-av-vbi.c
  97. 56 7
      drivers/media/video/cx18/cx18-cards.c
  98. 4 2
      drivers/media/video/cx18/cx18-controls.c
  99. 75 25
      drivers/media/video/cx18/cx18-driver.c
  100. 15 7
      drivers/media/video/cx18/cx18-driver.h

+ 4 - 4
Documentation/dvb/get_dvb_firmware

@@ -112,7 +112,7 @@ sub tda10045 {
 
 
 sub tda10046 {
 sub tda10046 {
 	my $sourcefile = "TT_PCI_2.19h_28_11_2006.zip";
 	my $sourcefile = "TT_PCI_2.19h_28_11_2006.zip";
-	my $url = "http://technotrend-online.com/download/software/219/$sourcefile";
+	my $url = "http://www.tt-download.com/download/updates/219/$sourcefile";
 	my $hash = "6a7e1e2f2644b162ff0502367553c72d";
 	my $hash = "6a7e1e2f2644b162ff0502367553c72d";
 	my $outfile = "dvb-fe-tda10046.fw";
 	my $outfile = "dvb-fe-tda10046.fw";
 	my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
 	my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@@ -129,8 +129,8 @@ sub tda10046 {
 }
 }
 
 
 sub tda10046lifeview {
 sub tda10046lifeview {
-    my $sourcefile = "Drv_2.11.02.zip";
-    my $url = "http://www.lifeview.com.tw/drivers/pci_card/FlyDVB-T/$sourcefile";
+    my $sourcefile = "7%5Cdrv_2.11.02.zip";
+    my $url = "http://www.lifeview.hk/dbimages/document/$sourcefile";
     my $hash = "1ea24dee4eea8fe971686981f34fd2e0";
     my $hash = "1ea24dee4eea8fe971686981f34fd2e0";
     my $outfile = "dvb-fe-tda10046.fw";
     my $outfile = "dvb-fe-tda10046.fw";
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@@ -317,7 +317,7 @@ sub nxt2002 {
 
 
 sub nxt2004 {
 sub nxt2004 {
     my $sourcefile = "AVerTVHD_MCE_A180_Drv_v1.2.2.16.zip";
     my $sourcefile = "AVerTVHD_MCE_A180_Drv_v1.2.2.16.zip";
-    my $url = "http://www.aver.com/support/Drivers/$sourcefile";
+    my $url = "http://www.avermedia-usa.com/support/Drivers/$sourcefile";
     my $hash = "111cb885b1e009188346d72acfed024c";
     my $hash = "111cb885b1e009188346d72acfed024c";
     my $outfile = "dvb-fe-nxt2004.fw";
     my $outfile = "dvb-fe-nxt2004.fw";
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

+ 5 - 0
Documentation/video4linux/CARDLIST.cx23885

@@ -16,3 +16,8 @@
  15 -> TeVii S470                                          [d470:9022]
  15 -> TeVii S470                                          [d470:9022]
  16 -> DVBWorld DVB-S2 2005                                [0001:2005]
  16 -> DVBWorld DVB-S2 2005                                [0001:2005]
  17 -> NetUP Dual DVB-S2 CI                                [1b55:2a2c]
  17 -> NetUP Dual DVB-S2 CI                                [1b55:2a2c]
+ 18 -> Hauppauge WinTV-HVR1270                             [0070:2211]
+ 19 -> Hauppauge WinTV-HVR1275                             [0070:2215]
+ 20 -> Hauppauge WinTV-HVR1255                             [0070:2251]
+ 21 -> Hauppauge WinTV-HVR1210                             [0070:2291,0070:2295]
+ 22 -> Mygica X8506 DMB-TH                                 [14f1:8651]

+ 2 - 0
Documentation/video4linux/CARDLIST.cx88

@@ -78,3 +78,5 @@
  77 -> TBS 8910 DVB-S                                      [8910:8888]
  77 -> TBS 8910 DVB-S                                      [8910:8888]
  78 -> Prof 6200 DVB-S                                     [b022:3022]
  78 -> Prof 6200 DVB-S                                     [b022:3022]
  79 -> Terratec Cinergy HT PCI MKII                        [153b:1177]
  79 -> Terratec Cinergy HT PCI MKII                        [153b:1177]
+ 80 -> Hauppauge WinTV-IR Only                             [0070:9290]
+ 81 -> Leadtek WinFast DTV1800 Hybrid                      [107d:6654]

+ 5 - 1
Documentation/video4linux/CARDLIST.em28xx

@@ -17,7 +17,7 @@
  16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b]
  16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b]
  17 -> Pinnacle PCTV HD Pro Stick               (em2880)        [2304:0227]
  17 -> Pinnacle PCTV HD Pro Stick               (em2880)        [2304:0227]
  18 -> Hauppauge WinTV HVR 900 (R2)             (em2880)        [2040:6502]
  18 -> Hauppauge WinTV HVR 900 (R2)             (em2880)        [2040:6502]
- 19 -> PointNix Intra-Oral Camera               (em2860)
+ 19 -> EM2860/SAA711X Reference Design          (em2860)
  20 -> AMD ATI TV Wonder HD 600                 (em2880)        [0438:b002]
  20 -> AMD ATI TV Wonder HD 600                 (em2880)        [0438:b002]
  21 -> eMPIA Technology, Inc. GrabBeeX+ Video Encoder (em2800)        [eb1a:2801]
  21 -> eMPIA Technology, Inc. GrabBeeX+ Video Encoder (em2800)        [eb1a:2801]
  22 -> Unknown EM2750/EM2751 webcam grabber     (em2750)        [eb1a:2750,eb1a:2751]
  22 -> Unknown EM2750/EM2751 webcam grabber     (em2750)        [eb1a:2750,eb1a:2751]
@@ -61,3 +61,7 @@
  63 -> Kaiomy TVnPC U2                          (em2860)        [eb1a:e303]
  63 -> Kaiomy TVnPC U2                          (em2860)        [eb1a:e303]
  64 -> Easy Cap Capture DC-60                   (em2860)
  64 -> Easy Cap Capture DC-60                   (em2860)
  65 -> IO-DATA GV-MVP/SZ                        (em2820/em2840) [04bb:0515]
  65 -> IO-DATA GV-MVP/SZ                        (em2820/em2840) [04bb:0515]
+ 66 -> Empire dual TV                           (em2880)
+ 67 -> Terratec Grabby                          (em2860)        [0ccd:0096]
+ 68 -> Terratec AV350                           (em2860)        [0ccd:0084]
+ 69 -> KWorld ATSC 315U HDTV TV Box             (em2882)        [eb1a:a313]

+ 17 - 5
Documentation/video4linux/CARDLIST.saa7134

@@ -124,10 +124,10 @@
 123 -> Beholder BeholdTV 407                    [0000:4070]
 123 -> Beholder BeholdTV 407                    [0000:4070]
 124 -> Beholder BeholdTV 407 FM                 [0000:4071]
 124 -> Beholder BeholdTV 407 FM                 [0000:4071]
 125 -> Beholder BeholdTV 409                    [0000:4090]
 125 -> Beholder BeholdTV 409                    [0000:4090]
-126 -> Beholder BeholdTV 505 FM/RDS             [0000:5051,0000:505B,5ace:5050]
-127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090]
+126 -> Beholder BeholdTV 505 FM                 [5ace:5050]
+127 -> Beholder BeholdTV 507 FM / BeholdTV 509 FM [5ace:5070,5ace:5090]
 128 -> Beholder BeholdTV Columbus TVFM          [0000:5201]
 128 -> Beholder BeholdTV Columbus TVFM          [0000:5201]
-129 -> Beholder BeholdTV 607 / BeholdTV 609     [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093]
+129 -> Beholder BeholdTV 607 FM                 [5ace:6070]
 130 -> Beholder BeholdTV M6                     [5ace:6190]
 130 -> Beholder BeholdTV M6                     [5ace:6190]
 131 -> Twinhan Hybrid DTV-DVB 3056 PCI          [1822:0022]
 131 -> Twinhan Hybrid DTV-DVB 3056 PCI          [1822:0022]
 132 -> Genius TVGO AM11MCE
 132 -> Genius TVGO AM11MCE
@@ -143,7 +143,7 @@
 142 -> Beholder BeholdTV H6                     [5ace:6290]
 142 -> Beholder BeholdTV H6                     [5ace:6290]
 143 -> Beholder BeholdTV M63                    [5ace:6191]
 143 -> Beholder BeholdTV M63                    [5ace:6191]
 144 -> Beholder BeholdTV M6 Extra               [5ace:6193]
 144 -> Beholder BeholdTV M6 Extra               [5ace:6193]
-145 -> AVerMedia MiniPCI DVB-T Hybrid M103      [1461:f636]
+145 -> AVerMedia MiniPCI DVB-T Hybrid M103      [1461:f636,1461:f736]
 146 -> ASUSTeK P7131 Analog
 146 -> ASUSTeK P7131 Analog
 147 -> Asus Tiger 3in1                          [1043:4878]
 147 -> Asus Tiger 3in1                          [1043:4878]
 148 -> Encore ENLTV-FM v5.3                     [1a7f:2008]
 148 -> Encore ENLTV-FM v5.3                     [1a7f:2008]
@@ -154,4 +154,16 @@
 153 -> Kworld Plus TV Analog Lite PCI           [17de:7128]
 153 -> Kworld Plus TV Analog Lite PCI           [17de:7128]
 154 -> Avermedia AVerTV GO 007 FM Plus          [1461:f31d]
 154 -> Avermedia AVerTV GO 007 FM Plus          [1461:f31d]
 155 -> Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid  [0070:6706,0070:6708]
 155 -> Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid  [0070:6706,0070:6708]
-156 -> Hauppauge WinTV-HVR1110r3                [0070:6707,0070:6709,0070:670a]
+156 -> Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid   [0070:6707,0070:6709,0070:670a]
+157 -> Avermedia AVerTV Studio 507UA            [1461:a11b]
+158 -> AVerMedia Cardbus TV/Radio (E501R)       [1461:b7e9]
+159 -> Beholder BeholdTV 505 RDS                [0000:505B]
+160 -> Beholder BeholdTV 507 RDS                [0000:5071]
+161 -> Beholder BeholdTV 507 RDS                [0000:507B]
+162 -> Beholder BeholdTV 607 FM                 [5ace:6071]
+163 -> Beholder BeholdTV 609 FM                 [5ace:6090]
+164 -> Beholder BeholdTV 609 FM                 [5ace:6091]
+165 -> Beholder BeholdTV 607 RDS                [5ace:6072]
+166 -> Beholder BeholdTV 607 RDS                [5ace:6073]
+167 -> Beholder BeholdTV 609 RDS                [5ace:6092]
+168 -> Beholder BeholdTV 609 RDS                [5ace:6093]

+ 2 - 0
Documentation/video4linux/CARDLIST.tuner

@@ -76,3 +76,5 @@ tuner=75 - Philips TEA5761 FM Radio
 tuner=76 - Xceive 5000 tuner
 tuner=76 - Xceive 5000 tuner
 tuner=77 - TCL tuner MF02GIP-5N-E
 tuner=77 - TCL tuner MF02GIP-5N-E
 tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
 tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
+tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
+tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough

+ 10 - 2
Documentation/video4linux/gspca.txt

@@ -163,10 +163,11 @@ sunplus		055f:c650	Mustek MDC5500Z
 zc3xx		055f:d003	Mustek WCam300A
 zc3xx		055f:d003	Mustek WCam300A
 zc3xx		055f:d004	Mustek WCam300 AN
 zc3xx		055f:d004	Mustek WCam300 AN
 conex		0572:0041	Creative Notebook cx11646
 conex		0572:0041	Creative Notebook cx11646
-ov519		05a9:0519	OmniVision
+ov519		05a9:0519	OV519 Microphone
 ov519		05a9:0530	OmniVision
 ov519		05a9:0530	OmniVision
-ov519		05a9:4519	OmniVision
+ov519		05a9:4519	Webcam Classic
 ov519		05a9:8519	OmniVision
 ov519		05a9:8519	OmniVision
+ov519		05a9:a518	D-Link DSB-C310 Webcam
 sunplus		05da:1018	Digital Dream Enigma 1.3
 sunplus		05da:1018	Digital Dream Enigma 1.3
 stk014		05e1:0893	Syntek DV4000
 stk014		05e1:0893	Syntek DV4000
 spca561		060b:a001	Maxell Compact Pc PM3
 spca561		060b:a001	Maxell Compact Pc PM3
@@ -178,6 +179,7 @@ spca506		06e1:a190	ADS Instant VCD
 ov534		06f8:3002	Hercules Blog Webcam
 ov534		06f8:3002	Hercules Blog Webcam
 ov534		06f8:3003	Hercules Dualpix HD Weblog
 ov534		06f8:3003	Hercules Dualpix HD Weblog
 sonixj		06f8:3004	Hercules Classic Silver
 sonixj		06f8:3004	Hercules Classic Silver
+sonixj		06f8:3008	Hercules Deluxe Optical Glass
 spca508		0733:0110	ViewQuest VQ110
 spca508		0733:0110	ViewQuest VQ110
 spca508		0130:0130	Clone Digital Webcam 11043
 spca508		0130:0130	Clone Digital Webcam 11043
 spca501		0733:0401	Intel Create and Share
 spca501		0733:0401	Intel Create and Share
@@ -209,6 +211,7 @@ sunplus		08ca:2050	Medion MD 41437
 sunplus		08ca:2060	Aiptek PocketDV5300
 sunplus		08ca:2060	Aiptek PocketDV5300
 tv8532		0923:010f	ICM532 cams
 tv8532		0923:010f	ICM532 cams
 mars		093a:050f	Mars-Semi Pc-Camera
 mars		093a:050f	Mars-Semi Pc-Camera
+mr97310a	093a:010f	Sakar Digital no. 77379
 pac207		093a:2460	Qtec Webcam 100
 pac207		093a:2460	Qtec Webcam 100
 pac207		093a:2461	HP Webcam
 pac207		093a:2461	HP Webcam
 pac207		093a:2463	Philips SPC 220 NC
 pac207		093a:2463	Philips SPC 220 NC
@@ -265,6 +268,11 @@ sonixj		0c45:60ec	SN9C105+MO4000
 sonixj		0c45:60fb	Surfer NoName
 sonixj		0c45:60fb	Surfer NoName
 sonixj		0c45:60fc	LG-LIC300
 sonixj		0c45:60fc	LG-LIC300
 sonixj		0c45:60fe	Microdia Audio
 sonixj		0c45:60fe	Microdia Audio
+sonixj		0c45:6100	PC Camera (SN9C128)
+sonixj		0c45:610a	PC Camera (SN9C128)
+sonixj		0c45:610b	PC Camera (SN9C128)
+sonixj		0c45:610c	PC Camera (SN9C128)
+sonixj		0c45:610e	PC Camera (SN9C128)
 sonixj		0c45:6128	Microdia/Sonix SNP325
 sonixj		0c45:6128	Microdia/Sonix SNP325
 sonixj		0c45:612a	Avant Camera
 sonixj		0c45:612a	Avant Camera
 sonixj		0c45:612c	Typhoon Rasy Cam 1.3MPix
 sonixj		0c45:612c	Typhoon Rasy Cam 1.3MPix

+ 49 - 0
Documentation/video4linux/pxa_camera.txt

@@ -26,6 +26,55 @@ Global video workflow
 
 
      Once the last buffer is filled in, the QCI interface stops.
      Once the last buffer is filled in, the QCI interface stops.
 
 
+  c) Capture global finite state machine schema
+
+      +----+                             +---+  +----+
+      | DQ |                             | Q |  | DQ |
+      |    v                             |   v  |    v
+    +-----------+                     +------------------------+
+    |   STOP    |                     | Wait for capture start |
+    +-----------+         Q           +------------------------+
++-> | QCI: stop | ------------------> | QCI: run               | <------------+
+|   | DMA: stop |                     | DMA: stop              |              |
+|   +-----------+             +-----> +------------------------+              |
+|                            /                            |                   |
+|                           /             +---+  +----+   |                   |
+|capture list empty        /              | Q |  | DQ |   | QCI Irq EOF       |
+|                         /               |   v  |    v   v                   |
+|   +--------------------+             +----------------------+               |
+|   | DMA hotlink missed |             |    Capture running   |               |
+|   +--------------------+             +----------------------+               |
+|   | QCI: run           |     +-----> | QCI: run             | <-+           |
+|   | DMA: stop          |    /        | DMA: run             |   |           |
+|   +--------------------+   /         +----------------------+   | Other     |
+|     ^                     /DMA still            |               | channels  |
+|     | capture list       /  running             | DMA Irq End   | not       |
+|     | not empty         /                       |               | finished  |
+|     |                  /                        v               | yet       |
+|   +----------------------+           +----------------------+   |           |
+|   |  Videobuf released   |           |  Channel completed   |   |           |
+|   +----------------------+           +----------------------+   |           |
++-- | QCI: run             |           | QCI: run             | --+           |
+    | DMA: run             |           | DMA: run             |               |
+    +----------------------+           +----------------------+               |
+               ^                      /           |                           |
+               |          no overrun /            | overrun                   |
+               |                    /             v                           |
+    +--------------------+         /   +----------------------+               |
+    |  Frame completed   |        /    |     Frame overran    |               |
+    +--------------------+ <-----+     +----------------------+ restart frame |
+    | QCI: run           |             | QCI: stop            | --------------+
+    | DMA: run           |             | DMA: stop            |
+    +--------------------+             +----------------------+
+
+    Legend: - each box is a FSM state
+            - each arrow is the condition to transition to another state
+            - an arrow with a comment is a mandatory transition (no condition)
+            - arrow "Q" means : a buffer was enqueued
+            - arrow "DQ" means : a buffer was dequeued
+            - "QCI: stop" means the QCI interface is not enabled
+            - "DMA: stop" means all 3 DMA channels are stopped
+            - "DMA: run" means at least 1 DMA channel is still running
 
 
 DMA usage
 DMA usage
 ---------
 ---------

+ 5 - 0
Documentation/video4linux/v4l2-framework.txt

@@ -89,6 +89,11 @@ from dev (driver name followed by the bus_id, to be precise). If you set it
 up before calling v4l2_device_register then it will be untouched. If dev is
 up before calling v4l2_device_register then it will be untouched. If dev is
 NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
 NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
 
 
+You can use v4l2_device_set_name() to set the name based on a driver name and
+a driver-global atomic_t instance. This will generate names like ivtv0, ivtv1,
+etc. If the name ends with a digit, then it will insert a dash: cx18-0,
+cx18-1, etc. This function returns the instance number.
+
 The first 'dev' argument is normally the struct device pointer of a pci_dev,
 The first 'dev' argument is normally the struct device pointer of a pci_dev,
 usb_interface or platform_device. It is rare for dev to be NULL, but it happens
 usb_interface or platform_device. It is rare for dev to be NULL, but it happens
 with ISA devices or when one device creates multiple PCI devices, thus making
 with ISA devices or when one device creates multiple PCI devices, thus making

+ 16 - 7
arch/arm/mach-pxa/pcm990-baseboard.c

@@ -380,12 +380,12 @@ static struct pca953x_platform_data pca9536_data = {
 	.gpio_base	= NR_BUILTIN_GPIO,
 	.gpio_base	= NR_BUILTIN_GPIO,
 };
 };
 
 
-static int gpio_bus_switch;
+static int gpio_bus_switch = -EINVAL;
 
 
 static int pcm990_camera_set_bus_param(struct soc_camera_link *link,
 static int pcm990_camera_set_bus_param(struct soc_camera_link *link,
-		unsigned long flags)
+				       unsigned long flags)
 {
 {
-	if (gpio_bus_switch <= 0) {
+	if (gpio_bus_switch < 0) {
 		if (flags == SOCAM_DATAWIDTH_10)
 		if (flags == SOCAM_DATAWIDTH_10)
 			return 0;
 			return 0;
 		else
 		else
@@ -404,25 +404,34 @@ static unsigned long pcm990_camera_query_bus_param(struct soc_camera_link *link)
 {
 {
 	int ret;
 	int ret;
 
 
-	if (!gpio_bus_switch) {
+	if (gpio_bus_switch < 0) {
 		ret = gpio_request(NR_BUILTIN_GPIO, "camera");
 		ret = gpio_request(NR_BUILTIN_GPIO, "camera");
 		if (!ret) {
 		if (!ret) {
 			gpio_bus_switch = NR_BUILTIN_GPIO;
 			gpio_bus_switch = NR_BUILTIN_GPIO;
 			gpio_direction_output(gpio_bus_switch, 0);
 			gpio_direction_output(gpio_bus_switch, 0);
-		} else
-			gpio_bus_switch = -EINVAL;
+		}
 	}
 	}
 
 
-	if (gpio_bus_switch > 0)
+	if (gpio_bus_switch >= 0)
 		return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10;
 		return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10;
 	else
 	else
 		return SOCAM_DATAWIDTH_10;
 		return SOCAM_DATAWIDTH_10;
 }
 }
 
 
+static void pcm990_camera_free_bus(struct soc_camera_link *link)
+{
+	if (gpio_bus_switch < 0)
+		return;
+
+	gpio_free(gpio_bus_switch);
+	gpio_bus_switch = -EINVAL;
+}
+
 static struct soc_camera_link iclink = {
 static struct soc_camera_link iclink = {
 	.bus_id	= 0, /* Must match with the camera ID above */
 	.bus_id	= 0, /* Must match with the camera ID above */
 	.query_bus_param = pcm990_camera_query_bus_param,
 	.query_bus_param = pcm990_camera_query_bus_param,
 	.set_bus_param = pcm990_camera_set_bus_param,
 	.set_bus_param = pcm990_camera_set_bus_param,
+	.free_bus = pcm990_camera_free_bus,
 };
 };
 
 
 /* Board I2C devices. */
 /* Board I2C devices. */

+ 8 - 2
drivers/media/Kconfig

@@ -2,8 +2,14 @@
 # Multimedia device configuration
 # Multimedia device configuration
 #
 #
 
 
-menu "Multimedia devices"
+menuconfig MEDIA_SUPPORT
+	tristate "Multimedia support"
 	depends on HAS_IOMEM
 	depends on HAS_IOMEM
+	help
+	  If you want to use Video for Linux, DVB for Linux, or DAB adapters,
+	  enable this option and other options below.
+
+if MEDIA_SUPPORT
 
 
 comment "Multimedia core support"
 comment "Multimedia core support"
 
 
@@ -136,4 +142,4 @@ config USB_DABUSB
 	  module will be called dabusb.
 	  module will be called dabusb.
 endif # DAB
 endif # DAB
 
 
-endmenu
+endif # MEDIA_SUPPORT

+ 30 - 14
drivers/media/common/tuners/tuner-simple.c

@@ -416,6 +416,24 @@ static int simple_std_setup(struct dvb_frontend *fe,
 	return 0;
 	return 0;
 }
 }
 
 
+static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int rc;
+	u8 buffer[2];
+
+	buffer[0] = (config & ~0x38) | 0x18;
+	buffer[1] = aux;
+
+	tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+
+	rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
+	if (2 != rc)
+		tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc);
+
+	return rc == 2 ? 0 : rc;
+}
+
 static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
 static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
 			    u16 div, u8 config, u8 cb)
 			    u16 div, u8 config, u8 cb)
 {
 {
@@ -424,17 +442,10 @@ static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
 
 
 	switch (priv->type) {
 	switch (priv->type) {
 	case TUNER_LG_TDVS_H06XF:
 	case TUNER_LG_TDVS_H06XF:
-		/* Set the Auxiliary Byte. */
-		buffer[0] = buffer[2];
-		buffer[0] &= ~0x20;
-		buffer[0] |= 0x18;
-		buffer[1] = 0x20;
-		tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]);
-
-		rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
-		if (2 != rc)
-			tuner_warn("i2c i/o error: rc == %d "
-				   "(should be 2)\n", rc);
+		simple_set_aux_byte(fe, config, 0x20);
+		break;
+	case TUNER_PHILIPS_FQ1216LME_MK3:
+		simple_set_aux_byte(fe, config, 0x60); /* External AGC */
 		break;
 		break;
 	case TUNER_MICROTUNE_4042FI5:
 	case TUNER_MICROTUNE_4042FI5:
 	{
 	{
@@ -506,6 +517,11 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
 	case TUNER_THOMSON_DTT761X:
 	case TUNER_THOMSON_DTT761X:
 		buffer[3] = 0x39;
 		buffer[3] = 0x39;
 		break;
 		break;
+	case TUNER_PHILIPS_FQ1216LME_MK3:
+		tuner_err("This tuner doesn't have FM\n");
+		/* Set the low band for sanity, since it covers 88-108 MHz */
+		buffer[3] = 0x01;
+		break;
 	case TUNER_MICROTUNE_4049FM5:
 	case TUNER_MICROTUNE_4049FM5:
 	default:
 	default:
 		buffer[3] = 0xa4;
 		buffer[3] = 0xa4;
@@ -678,12 +694,12 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
 		return 0;
 		return 0;
 	}
 	}
 
 
-	/* Bandswitch byte */
-	simple_radio_bandswitch(fe, &buffer[0]);
-
 	buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
 	buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
 		    TUNER_RATIO_SELECT_50; /* 50 kHz step */
 		    TUNER_RATIO_SELECT_50; /* 50 kHz step */
 
 
+	/* Bandswitch byte */
+	simple_radio_bandswitch(fe, &buffer[0]);
+
 	/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
 	/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
 	   freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
 	   freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
 	   freq * (1/800) */
 	   freq * (1/800) */

+ 59 - 0
drivers/media/common/tuners/tuner-types.c

@@ -578,6 +578,31 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = {
 	},
 	},
 };
 };
 
 
+/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */
+
+static struct tuner_range tuner_fm1216mk5_pal_ranges[] = {
+	{ 16 * 158.00 /*MHz*/, 0xce, 0x01, },
+	{ 16 * 441.00 /*MHz*/, 0xce, 0x02, },
+	{ 16 * 864.00        , 0xce, 0x04, },
+};
+
+static struct tuner_params tuner_fm1216mk5_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_fm1216mk5_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges),
+		.cb_first_if_lower_freq = 1,
+		.has_tda9887 = 1,
+		.port1_active = 1,
+		.port2_active = 1,
+		.port2_invert_for_secam_lc = 1,
+		.port1_fm_high_sensitivity = 1,
+		.default_top_mid = -2,
+		.default_top_secam_mid = -2,
+		.default_top_secam_high = -2,
+	},
+};
+
 /* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */
 /* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */
 
 
 static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = {
 static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = {
@@ -1254,6 +1279,28 @@ static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
 	},
 	},
 };
 };
 
 
+/* 80-89 */
+/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */
+
+static struct tuner_params tuner_fq1216lme_mk3_params[] = {
+	{
+		.type   = TUNER_PARAM_TYPE_PAL,
+		.ranges = tuner_fm1216me_mk3_pal_ranges,
+		.count  = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
+		.cb_first_if_lower_freq = 1, /* not specified, but safe to do */
+		.has_tda9887 = 1, /* TDA9886 */
+		.port1_active = 1,
+		.port2_active = 1,
+		.port2_invert_for_secam_lc = 1,
+		.default_top_low = 4,
+		.default_top_mid = 4,
+		.default_top_high = 4,
+		.default_top_secam_low = 4,
+		.default_top_secam_mid = 4,
+		.default_top_secam_high = 4,
+	},
+};
+
 /* --------------------------------------------------------------------- */
 /* --------------------------------------------------------------------- */
 
 
 struct tunertype tuners[] = {
 struct tunertype tuners[] = {
@@ -1694,6 +1741,18 @@ struct tunertype tuners[] = {
 		.initdata = tua603x_agc112,
 		.initdata = tua603x_agc112,
 		.sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
 		.sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
 	},
 	},
+		[TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */
+		.name   = "Philips PAL/SECAM multi (FM1216 MK5)",
+		.params = tuner_fm1216mk5_params,
+		.count  = ARRAY_SIZE(tuner_fm1216mk5_params),
+	},
+
+	/* 80-89 */
+	[TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */
+		.name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough",
+		.params = tuner_fq1216lme_mk3_params,
+		.count  = ARRAY_SIZE(tuner_fq1216lme_mk3_params),
+	},
 };
 };
 EXPORT_SYMBOL(tuners);
 EXPORT_SYMBOL(tuners);
 
 

+ 31 - 25
drivers/media/common/tuners/tuner-xc2028.c

@@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
 
 static int no_poweroff;
 static int no_poweroff;
 module_param(no_poweroff, int, 0644);
 module_param(no_poweroff, int, 0644);
-MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n"
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
 	"1 keep device energized and with tuner ready all the times.\n"
 	"1 keep device energized and with tuner ready all the times.\n"
 	"  Faster, but consumes more power and keeps the device hotter\n");
 	"  Faster, but consumes more power and keeps the device hotter\n");
 
 
@@ -272,7 +272,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
 		fname = firmware_name;
 		fname = firmware_name;
 
 
 	tuner_dbg("Reading firmware %s\n", fname);
 	tuner_dbg("Reading firmware %s\n", fname);
-	rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev);
+	rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
 	if (rc < 0) {
 	if (rc < 0) {
 		if (rc == -ENOENT)
 		if (rc == -ENOENT)
 			tuner_err("Error: firmware %s not found.\n",
 			tuner_err("Error: firmware %s not found.\n",
@@ -917,22 +917,29 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
 	 * that xc2028 will be in a safe state.
 	 * that xc2028 will be in a safe state.
 	 * Maybe this might also be needed for DTV.
 	 * Maybe this might also be needed for DTV.
 	 */
 	 */
-	if (new_mode == T_ANALOG_TV) {
+	if (new_mode == T_ANALOG_TV)
 		rc = send_seq(priv, {0x00, 0x00});
 		rc = send_seq(priv, {0x00, 0x00});
-	} else if (priv->cur_fw.type & ATSC) {
-		offset = 1750000;
-	} else {
-		offset = 2750000;
+
+	/*
+	 * Digital modes require an offset to adjust to the
+	 * proper frequency.
+	 * Analog modes require offset = 0
+	 */
+	if (new_mode == T_DIGITAL_TV) {
+		/* Sets the offset according with firmware */
+		if (priv->cur_fw.type & DTV6)
+			offset = 1750000;
+		else if (priv->cur_fw.type & DTV7)
+			offset = 2250000;
+		else	/* DTV8 or DTV78 */
+			offset = 2750000;
+
 		/*
 		/*
-		 * We must adjust the offset by 500kHz in two cases in order
-		 * to correctly center the IF output:
-		 * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly
-		 *    selected and a 7MHz channel is tuned;
-		 * 2) When tuning a VHF channel with DTV78 firmware.
+		 * We must adjust the offset by 500kHz  when
+		 * tuning a 7MHz VHF channel with DTV78 firmware
+		 * (used in Australia, Italy and Germany)
 		 */
 		 */
-		if (((priv->cur_fw.type & DTV7) &&
-		     (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) ||
-		    ((priv->cur_fw.type & DTV78) && freq < 470000000))
+		if ((priv->cur_fw.type & DTV78) && freq < 470000000)
 			offset -= 500000;
 			offset -= 500000;
 	}
 	}
 
 
@@ -991,7 +998,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
 		if (priv->ctrl.input1)
 		if (priv->ctrl.input1)
 			type |= INPUT1;
 			type |= INPUT1;
 		return generic_set_freq(fe, (625l * p->frequency) / 10,
 		return generic_set_freq(fe, (625l * p->frequency) / 10,
-				T_ANALOG_TV, type, 0, 0);
+				T_RADIO, type, 0, 0);
 	}
 	}
 
 
 	/* if std is not defined, choose one */
 	/* if std is not defined, choose one */
@@ -1022,21 +1029,20 @@ static int xc2028_set_params(struct dvb_frontend *fe,
 	switch(fe->ops.info.type) {
 	switch(fe->ops.info.type) {
 	case FE_OFDM:
 	case FE_OFDM:
 		bw = p->u.ofdm.bandwidth;
 		bw = p->u.ofdm.bandwidth;
-		break;
-	case FE_QAM:
-		tuner_info("WARN: There are some reports that "
-			   "QAM 6 MHz doesn't work.\n"
-			   "If this works for you, please report by "
-			   "e-mail to: v4l-dvb-maintainer@linuxtv.org\n");
-		bw = BANDWIDTH_6_MHZ;
-		type |= QAM;
+		/*
+		 * The only countries with 6MHz seem to be Taiwan/Uruguay.
+		 * Both seem to require QAM firmware for OFDM decoding
+		 * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com>
+		 */
+		if (bw == BANDWIDTH_6_MHZ)
+			type |= QAM;
 		break;
 		break;
 	case FE_ATSC:
 	case FE_ATSC:
 		bw = BANDWIDTH_6_MHZ;
 		bw = BANDWIDTH_6_MHZ;
 		/* The only ATSC firmware (at least on v2.7) is D2633 */
 		/* The only ATSC firmware (at least on v2.7) is D2633 */
 		type |= ATSC | D2633;
 		type |= ATSC | D2633;
 		break;
 		break;
-	/* DVB-S is not supported */
+	/* DVB-S and pure QAM (FE_QAM) are not supported */
 	default:
 	default:
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}

+ 138 - 126
drivers/media/common/tuners/xc5000.c

@@ -3,6 +3,7 @@
  *
  *
  *  Copyright (c) 2007 Xceive Corporation
  *  Copyright (c) 2007 Xceive Corporation
  *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
  *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *  Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  it under the terms of the GNU General Public License as published by
@@ -36,14 +37,20 @@ static int debug;
 module_param(debug, int, 0644);
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
 
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
+	"\t\t1 keep device energized and with tuner ready all the times.\n"
+	"\t\tFaster, but consumes more power and keeps the device hotter");
+
 static DEFINE_MUTEX(xc5000_list_mutex);
 static DEFINE_MUTEX(xc5000_list_mutex);
 static LIST_HEAD(hybrid_tuner_instance_list);
 static LIST_HEAD(hybrid_tuner_instance_list);
 
 
 #define dprintk(level, fmt, arg...) if (debug >= level) \
 #define dprintk(level, fmt, arg...) if (debug >= level) \
 	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 
 
-#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
-#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
+#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
+#define XC5000_DEFAULT_FIRMWARE_SIZE 12401
 
 
 struct xc5000_priv {
 struct xc5000_priv {
 	struct tuner_i2c_props i2c_props;
 	struct tuner_i2c_props i2c_props;
@@ -83,11 +90,11 @@ struct xc5000_priv {
 #define XREG_D_CODE       0x04
 #define XREG_D_CODE       0x04
 #define XREG_IF_OUT       0x05
 #define XREG_IF_OUT       0x05
 #define XREG_SEEK_MODE    0x07
 #define XREG_SEEK_MODE    0x07
-#define XREG_POWER_DOWN   0x0A
+#define XREG_POWER_DOWN   0x0A /* Obsolete */
 #define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
 #define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
 #define XREG_SMOOTHEDCVBS 0x0E
 #define XREG_SMOOTHEDCVBS 0x0E
 #define XREG_XTALFREQ     0x0F
 #define XREG_XTALFREQ     0x0F
-#define XREG_FINERFFREQ   0x10
+#define XREG_FINERFREQ    0x10
 #define XREG_DDIMODE      0x11
 #define XREG_DDIMODE      0x11
 
 
 #define XREG_ADC_ENV      0x00
 #define XREG_ADC_ENV      0x00
@@ -100,6 +107,7 @@ struct xc5000_priv {
 #define XREG_VERSION      0x07
 #define XREG_VERSION      0x07
 #define XREG_PRODUCT_ID   0x08
 #define XREG_PRODUCT_ID   0x08
 #define XREG_BUSY         0x09
 #define XREG_BUSY         0x09
+#define XREG_BUILD        0x0D
 
 
 /*
 /*
    Basic firmware description. This will remain with
    Basic firmware description. This will remain with
@@ -191,27 +199,36 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
 	{"FM Radio-INPUT1",   0x0208, 0x9002}
 	{"FM Radio-INPUT1",   0x0208, 0x9002}
 };
 };
 
 
-static int  xc5000_is_firmware_loaded(struct dvb_frontend *fe);
-static int  xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
-static int  xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
-static void xc5000_TunerReset(struct dvb_frontend *fe);
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
+static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
+static int xc5000_TunerReset(struct dvb_frontend *fe);
 
 
 static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
 static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
 {
 {
-	return xc5000_writeregs(priv, buf, len)
-		? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS;
+	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+			       .flags = 0, .buf = buf, .len = len };
+
+	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+		printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len);
+		return XC_RESULT_I2C_WRITE_FAILURE;
+	}
+	return XC_RESULT_SUCCESS;
 }
 }
 
 
+/* This routine is never used because the only time we read data from the
+   i2c bus is when we read registers, and we want that to be an atomic i2c
+   transaction in case we are on a multi-master bus */
 static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
 static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
 {
 {
-	return xc5000_readregs(priv, buf, len)
-		? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS;
-}
+	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+		.flags = I2C_M_RD, .buf = buf, .len = len };
 
 
-static int xc_reset(struct dvb_frontend *fe)
-{
-	xc5000_TunerReset(fe);
-	return XC_RESULT_SUCCESS;
+	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+		printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len);
+		return -EREMOTEIO;
+	}
+	return 0;
 }
 }
 
 
 static void xc_wait(int wait_ms)
 static void xc_wait(int wait_ms)
@@ -219,7 +236,7 @@ static void xc_wait(int wait_ms)
 	msleep(wait_ms);
 	msleep(wait_ms);
 }
 }
 
 
-static void xc5000_TunerReset(struct dvb_frontend *fe)
+static int xc5000_TunerReset(struct dvb_frontend *fe)
 {
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
 	struct xc5000_priv *priv = fe->tuner_priv;
 	int ret;
 	int ret;
@@ -232,16 +249,21 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
 					   priv->i2c_props.adap->algo_data,
 					   priv->i2c_props.adap->algo_data,
 					   DVB_FRONTEND_COMPONENT_TUNER,
 					   DVB_FRONTEND_COMPONENT_TUNER,
 					   XC5000_TUNER_RESET, 0);
 					   XC5000_TUNER_RESET, 0);
-		if (ret)
+		if (ret) {
 			printk(KERN_ERR "xc5000: reset failed\n");
 			printk(KERN_ERR "xc5000: reset failed\n");
-	} else
+			return XC_RESULT_RESET_FAILURE;
+		}
+	} else {
 		printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
 		printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
+		return XC_RESULT_RESET_FAILURE;
+	}
+	return XC_RESULT_SUCCESS;
 }
 }
 
 
 static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
 static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
 {
 {
 	u8 buf[4];
 	u8 buf[4];
-	int WatchDogTimer = 5;
+	int WatchDogTimer = 100;
 	int result;
 	int result;
 
 
 	buf[0] = (regAddr >> 8) & 0xFF;
 	buf[0] = (regAddr >> 8) & 0xFF;
@@ -263,7 +285,7 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
 						/* busy flag cleared */
 						/* busy flag cleared */
 					break;
 					break;
 					} else {
 					} else {
-						xc_wait(100); /* wait 5 ms */
+						xc_wait(5); /* wait 5 ms */
 						WatchDogTimer--;
 						WatchDogTimer--;
 					}
 					}
 				}
 				}
@@ -276,25 +298,6 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
 	return result;
 	return result;
 }
 }
 
 
-static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData)
-{
-	u8 buf[2];
-	int result;
-
-	buf[0] = (regAddr >> 8) & 0xFF;
-	buf[1] = regAddr & 0xFF;
-	result = xc_send_i2c_data(priv, buf, 2);
-	if (result != XC_RESULT_SUCCESS)
-		return result;
-
-	result = xc_read_i2c_data(priv, buf, 2);
-	if (result != XC_RESULT_SUCCESS)
-		return result;
-
-	*i2cData = buf[0] * 256 + buf[1];
-	return result;
-}
-
 static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
 static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
 {
 {
 	struct xc5000_priv *priv = fe->tuner_priv;
 	struct xc5000_priv *priv = fe->tuner_priv;
@@ -309,7 +312,7 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
 		len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
 		len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
 		if (len == 0x0000) {
 		if (len == 0x0000) {
 			/* RESET command */
 			/* RESET command */
-			result = xc_reset(fe);
+			result = xc5000_TunerReset(fe);
 			index += 2;
 			index += 2;
 			if (result != XC_RESULT_SUCCESS)
 			if (result != XC_RESULT_SUCCESS)
 				return result;
 				return result;
@@ -371,15 +374,6 @@ static int xc_SetTVStandard(struct xc5000_priv *priv,
 	return ret;
 	return ret;
 }
 }
 
 
-static int xc_shutdown(struct xc5000_priv *priv)
-{
-	return XC_RESULT_SUCCESS;
-	/* Fixme: cannot bring tuner back alive once shutdown
-	 *        without reloading the driver modules.
-	 *    return xc_write_reg(priv, XREG_POWER_DOWN, 0);
-	 */
-}
-
 static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
 static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
 {
 {
 	dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
 	dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
@@ -408,7 +402,10 @@ static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
 
 
 	freq_code = (u16)(freq_hz / 15625);
 	freq_code = (u16)(freq_hz / 15625);
 
 
-	return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+	/* Starting in firmware version 1.1.44, Xceive recommends using the
+	   FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
+	   only be used for fast scanning for channel lock) */
+	return xc_write_reg(priv, XREG_FINERFREQ, freq_code);
 }
 }
 
 
 
 
@@ -424,7 +421,7 @@ static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
 
 
 static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
 static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
 {
 {
-	return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope);
+	return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope);
 }
 }
 
 
 static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
 static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
@@ -433,8 +430,8 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
 	u16 regData;
 	u16 regData;
 	u32 tmp;
 	u32 tmp;
 
 
-	result = xc_read_reg(priv, XREG_FREQ_ERROR, &regData);
-	if (result)
+	result = xc5000_readreg(priv, XREG_FREQ_ERROR, &regData);
+	if (result != XC_RESULT_SUCCESS)
 		return result;
 		return result;
 
 
 	tmp = (u32)regData;
 	tmp = (u32)regData;
@@ -444,7 +441,7 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
 
 
 static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
 static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
 {
 {
-	return xc_read_reg(priv, XREG_LOCK, lock_status);
+	return xc5000_readreg(priv, XREG_LOCK, lock_status);
 }
 }
 
 
 static int xc_get_version(struct xc5000_priv *priv,
 static int xc_get_version(struct xc5000_priv *priv,
@@ -454,8 +451,8 @@ static int xc_get_version(struct xc5000_priv *priv,
 	u16 data;
 	u16 data;
 	int result;
 	int result;
 
 
-	result = xc_read_reg(priv, XREG_VERSION, &data);
-	if (result)
+	result = xc5000_readreg(priv, XREG_VERSION, &data);
+	if (result != XC_RESULT_SUCCESS)
 		return result;
 		return result;
 
 
 	(*hw_majorversion) = (data >> 12) & 0x0F;
 	(*hw_majorversion) = (data >> 12) & 0x0F;
@@ -466,13 +463,18 @@ static int xc_get_version(struct xc5000_priv *priv,
 	return 0;
 	return 0;
 }
 }
 
 
+static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev)
+{
+	return xc5000_readreg(priv, XREG_BUILD, buildrev);
+}
+
 static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
 static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
 {
 {
 	u16 regData;
 	u16 regData;
 	int result;
 	int result;
 
 
-	result = xc_read_reg(priv, XREG_HSYNC_FREQ, &regData);
-	if (result)
+	result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &regData);
+	if (result != XC_RESULT_SUCCESS)
 		return result;
 		return result;
 
 
 	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
 	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
@@ -481,12 +483,12 @@ static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
 
 
 static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
 static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
 {
 {
-	return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines);
+	return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines);
 }
 }
 
 
 static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
 static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
 {
 {
-	return xc_read_reg(priv, XREG_QUALITY, quality);
+	return xc5000_readreg(priv, XREG_QUALITY, quality);
 }
 }
 
 
 static u16 WaitForLock(struct xc5000_priv *priv)
 static u16 WaitForLock(struct xc5000_priv *priv)
@@ -504,7 +506,9 @@ static u16 WaitForLock(struct xc5000_priv *priv)
 	return lockState;
 	return lockState;
 }
 }
 
 
-static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
+#define XC_TUNE_ANALOG  0
+#define XC_TUNE_DIGITAL 1
+static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
 {
 {
 	int found = 0;
 	int found = 0;
 
 
@@ -513,8 +517,10 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
 	if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
 	if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
 		return 0;
 		return 0;
 
 
-	if (WaitForLock(priv) == 1)
-		found = 1;
+	if (mode == XC_TUNE_ANALOG) {
+		if (WaitForLock(priv) == 1)
+			found = 1;
+	}
 
 
 	return found;
 	return found;
 }
 }
@@ -536,32 +542,7 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
 	}
 	}
 
 
 	*val = (bval[0] << 8) | bval[1];
 	*val = (bval[0] << 8) | bval[1];
-	return 0;
-}
-
-static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
-{
-	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
-		.flags = 0, .buf = buf, .len = len };
-
-	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
-		printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
-			(int)len);
-		return -EREMOTEIO;
-	}
-	return 0;
-}
-
-static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
-{
-	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
-		.flags = I2C_M_RD, .buf = buf, .len = len };
-
-	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
-		printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", (int)len);
-		return -EREMOTEIO;
-	}
-	return 0;
+	return XC_RESULT_SUCCESS;
 }
 }
 
 
 static int xc5000_fwupload(struct dvb_frontend *fe)
 static int xc5000_fwupload(struct dvb_frontend *fe)
@@ -575,13 +556,13 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
 		XC5000_DEFAULT_FIRMWARE);
 		XC5000_DEFAULT_FIRMWARE);
 
 
 	ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE,
 	ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE,
-		&priv->i2c_props.adap->dev);
+		priv->i2c_props.adap->dev.parent);
 	if (ret) {
 	if (ret) {
 		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
 		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
 		ret = XC_RESULT_RESET_FAILURE;
 		ret = XC_RESULT_RESET_FAILURE;
 		goto out;
 		goto out;
 	} else {
 	} else {
-		printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n",
+		printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n",
 		       fw->size);
 		       fw->size);
 		ret = XC_RESULT_SUCCESS;
 		ret = XC_RESULT_SUCCESS;
 	}
 	}
@@ -590,8 +571,9 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
 		printk(KERN_ERR "xc5000: firmware incorrect size\n");
 		printk(KERN_ERR "xc5000: firmware incorrect size\n");
 		ret = XC_RESULT_RESET_FAILURE;
 		ret = XC_RESULT_RESET_FAILURE;
 	} else {
 	} else {
-		printk(KERN_INFO "xc5000: firmware upload\n");
+		printk(KERN_INFO "xc5000: firmware uploading...\n");
 		ret = xc_load_i2c_sequence(fe,  fw->data);
 		ret = xc_load_i2c_sequence(fe,  fw->data);
+		printk(KERN_INFO "xc5000: firmware upload complete...\n");
 	}
 	}
 
 
 out:
 out:
@@ -609,6 +591,7 @@ static void xc_debug_dump(struct xc5000_priv *priv)
 	u16 quality;
 	u16 quality;
 	u8 hw_majorversion = 0, hw_minorversion = 0;
 	u8 hw_majorversion = 0, hw_minorversion = 0;
 	u8 fw_majorversion = 0, fw_minorversion = 0;
 	u8 fw_majorversion = 0, fw_minorversion = 0;
+	u16 fw_buildversion = 0;
 
 
 	/* Wait for stats to stabilize.
 	/* Wait for stats to stabilize.
 	 * Frame Lines needs two frame times after initial lock
 	 * Frame Lines needs two frame times after initial lock
@@ -628,9 +611,10 @@ static void xc_debug_dump(struct xc5000_priv *priv)
 
 
 	xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
 	xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
 		&fw_majorversion, &fw_minorversion);
 		&fw_majorversion, &fw_minorversion);
-	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+	xc_get_buildversion(priv,  &fw_buildversion);
+	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n",
 		hw_majorversion, hw_minorversion,
 		hw_majorversion, hw_minorversion,
-		fw_majorversion, fw_minorversion);
+		fw_majorversion, fw_minorversion, fw_buildversion);
 
 
 	xc_get_hsync_freq(priv,  &hsync_freq_hz);
 	xc_get_hsync_freq(priv,  &hsync_freq_hz);
 	dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
 	dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
@@ -648,27 +632,57 @@ static int xc5000_set_params(struct dvb_frontend *fe,
 	struct xc5000_priv *priv = fe->tuner_priv;
 	struct xc5000_priv *priv = fe->tuner_priv;
 	int ret;
 	int ret;
 
 
+	if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS)
+		xc_load_fw_and_init_tuner(fe);
+
 	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
 	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
 
 
-	switch (params->u.vsb.modulation) {
-	case VSB_8:
-	case VSB_16:
-		dprintk(1, "%s() VSB modulation\n", __func__);
+	if (fe->ops.info.type == FE_ATSC) {
+		dprintk(1, "%s() ATSC\n", __func__);
+		switch (params->u.vsb.modulation) {
+		case VSB_8:
+		case VSB_16:
+			dprintk(1, "%s() VSB modulation\n", __func__);
+			priv->rf_mode = XC_RF_MODE_AIR;
+			priv->freq_hz = params->frequency - 1750000;
+			priv->bandwidth = BANDWIDTH_6_MHZ;
+			priv->video_standard = DTV6;
+			break;
+		case QAM_64:
+		case QAM_256:
+		case QAM_AUTO:
+			dprintk(1, "%s() QAM modulation\n", __func__);
+			priv->rf_mode = XC_RF_MODE_CABLE;
+			priv->freq_hz = params->frequency - 1750000;
+			priv->bandwidth = BANDWIDTH_6_MHZ;
+			priv->video_standard = DTV6;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (fe->ops.info.type == FE_OFDM) {
+		dprintk(1, "%s() OFDM\n", __func__);
+		switch (params->u.ofdm.bandwidth) {
+		case BANDWIDTH_6_MHZ:
+			priv->bandwidth = BANDWIDTH_6_MHZ;
+			priv->video_standard = DTV6;
+			priv->freq_hz = params->frequency - 1750000;
+			break;
+		case BANDWIDTH_7_MHZ:
+			printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n");
+			return -EINVAL;
+		case BANDWIDTH_8_MHZ:
+			priv->bandwidth = BANDWIDTH_8_MHZ;
+			priv->video_standard = DTV8;
+			priv->freq_hz = params->frequency - 2750000;
+			break;
+		default:
+			printk(KERN_ERR "xc5000 bandwidth not set!\n");
+			return -EINVAL;
+		}
 		priv->rf_mode = XC_RF_MODE_AIR;
 		priv->rf_mode = XC_RF_MODE_AIR;
-		priv->freq_hz = params->frequency - 1750000;
-		priv->bandwidth = BANDWIDTH_6_MHZ;
-		priv->video_standard = DTV6;
-		break;
-	case QAM_64:
-	case QAM_256:
-	case QAM_AUTO:
-		dprintk(1, "%s() QAM modulation\n", __func__);
-		priv->rf_mode = XC_RF_MODE_CABLE;
-		priv->freq_hz = params->frequency - 1750000;
-		priv->bandwidth = BANDWIDTH_6_MHZ;
-		priv->video_standard = DTV6;
-		break;
-	default:
+	} else {
+		printk(KERN_ERR "xc5000 modulation type not supported!\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
@@ -698,7 +712,7 @@ static int xc5000_set_params(struct dvb_frontend *fe,
 		return -EIO;
 		return -EIO;
 	}
 	}
 
 
-	xc_tune_channel(priv, priv->freq_hz);
+	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
 
 
 	if (debug)
 	if (debug)
 		xc_debug_dump(priv);
 		xc_debug_dump(priv);
@@ -725,8 +739,6 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
 	return ret;
 	return ret;
 }
 }
 
 
-static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
-
 static int xc5000_set_analog_params(struct dvb_frontend *fe,
 static int xc5000_set_analog_params(struct dvb_frontend *fe,
 	struct analog_parameters *params)
 	struct analog_parameters *params)
 {
 {
@@ -807,7 +819,7 @@ tune_channel:
 		return -EREMOTEIO;
 		return -EREMOTEIO;
 	}
 	}
 
 
-	xc_tune_channel(priv, priv->freq_hz);
+	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
 
 
 	if (debug)
 	if (debug)
 		xc_debug_dump(priv);
 		xc_debug_dump(priv);
@@ -875,18 +887,18 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
 
 
 static int xc5000_sleep(struct dvb_frontend *fe)
 static int xc5000_sleep(struct dvb_frontend *fe)
 {
 {
-	struct xc5000_priv *priv = fe->tuner_priv;
 	int ret;
 	int ret;
 
 
 	dprintk(1, "%s()\n", __func__);
 	dprintk(1, "%s()\n", __func__);
 
 
-	/* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
-	 * once shutdown without reloading the driver. Maybe I am not
-	 * doing something right.
-	 *
-	 */
+	/* Avoid firmware reload on slow devices */
+	if (no_poweroff)
+		return 0;
 
 
-	ret = xc_shutdown(priv);
+	/* According to Xceive technical support, the "powerdown" register
+	   was removed in newer versions of the firmware.  The "supported"
+	   way to sleep the tuner is to pull the reset pin low for 10ms */
+	ret = xc5000_TunerReset(fe);
 	if (ret != XC_RESULT_SUCCESS) {
 	if (ret != XC_RESULT_SUCCESS) {
 		printk(KERN_ERR
 		printk(KERN_ERR
 			"xc5000: %s() unable to shutdown tuner\n",
 			"xc5000: %s() unable to shutdown tuner\n",
@@ -991,7 +1003,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
 	/* Check if firmware has been loaded. It is possible that another
 	/* Check if firmware has been loaded. It is possible that another
 	   instance of the driver has loaded the firmware.
 	   instance of the driver has loaded the firmware.
 	 */
 	 */
-	if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+	if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS)
 		goto fail;
 		goto fail;
 
 
 	switch (id) {
 	switch (id) {

+ 3 - 5
drivers/media/dvb/b2c2/flexcop-common.h

@@ -1,9 +1,7 @@
 /*
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-common.h - common header file for device-specific source files also.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-common.h - common header file for device-specific source files
+ * see flexcop.c for copyright information
  */
  */
 #ifndef __FLEXCOP_COMMON_H__
 #ifndef __FLEXCOP_COMMON_H__
 #define __FLEXCOP_COMMON_H__
 #define __FLEXCOP_COMMON_H__

File diff ditekan karena terlalu besar
+ 440 - 349
drivers/media/dvb/b2c2/flexcop-fe-tuner.c


+ 1 - 1
drivers/media/dvb/b2c2/flexcop-i2c.c

@@ -200,7 +200,7 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
 					msgs[i].buf[0], &msgs[i].buf[1],
 					msgs[i].buf[0], &msgs[i].buf[1],
 					msgs[i].len - 1);
 					msgs[i].len - 1);
 		if (ret < 0) {
 		if (ret < 0) {
-			err("i2c master_xfer failed");
+			deb_i2c("i2c master_xfer failed");
 			break;
 			break;
 		}
 		}
 	}
 	}

+ 10 - 10
drivers/media/dvb/b2c2/flexcop-misc.c

@@ -46,16 +46,16 @@ static const char *flexcop_revision_names[] = {
 };
 };
 
 
 static const char *flexcop_device_names[] = {
 static const char *flexcop_device_names[] = {
-	"Unknown device",
-	"Air2PC/AirStar 2 DVB-T",
-	"Air2PC/AirStar 2 ATSC 1st generation",
-	"Air2PC/AirStar 2 ATSC 2nd generation",
-	"Sky2PC/SkyStar 2 DVB-S",
-	"Sky2PC/SkyStar 2 DVB-S (old version)",
-	"Cable2PC/CableStar 2 DVB-C",
-	"Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
-	"Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
-	"Sky2PC/SkyStar 2 DVB-S rev 2.8",
+	[FC_UNK]	= "Unknown device",
+	[FC_CABLE]	= "Cable2PC/CableStar 2 DVB-C",
+	[FC_AIR_DVBT]	= "Air2PC/AirStar 2 DVB-T",
+	[FC_AIR_ATSC1]	= "Air2PC/AirStar 2 ATSC 1st generation",
+	[FC_AIR_ATSC2]	= "Air2PC/AirStar 2 ATSC 2nd generation",
+	[FC_AIR_ATSC3]	= "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
+	[FC_SKY_REV23]	= "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)",
+	[FC_SKY_REV26]	= "Sky2PC/SkyStar 2 DVB-S rev 2.6",
+	[FC_SKY_REV27]	= "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
+	[FC_SKY_REV28]	= "Sky2PC/SkyStar 2 DVB-S rev 2.8",
 };
 };
 
 
 static const char *flexcop_bus_names[] = {
 static const char *flexcop_bus_names[] = {

+ 1 - 7
drivers/media/dvb/bt8xx/bt878.c

@@ -508,12 +508,6 @@ static int __devinit bt878_probe(struct pci_dev *dev,
 	pci_set_master(dev);
 	pci_set_master(dev);
 	pci_set_drvdata(dev, bt);
 	pci_set_drvdata(dev, bt);
 
 
-/*        if(init_bt878(btv) < 0) {
-		bt878_remove(dev);
-		return -EIO;
-	}
-*/
-
 	if ((result = bt878_mem_alloc(bt))) {
 	if ((result = bt878_mem_alloc(bt))) {
 		printk(KERN_ERR "bt878: failed to allocate memory!\n");
 		printk(KERN_ERR "bt878: failed to allocate memory!\n");
 		goto fail2;
 		goto fail2;
@@ -579,7 +573,7 @@ static struct pci_driver bt878_pci_driver = {
       .name	= "bt878",
       .name	= "bt878",
       .id_table = bt878_pci_tbl,
       .id_table = bt878_pci_tbl,
       .probe	= bt878_probe,
       .probe	= bt878_probe,
-      .remove	= bt878_remove,
+      .remove	= __devexit_p(bt878_remove),
 };
 };
 
 
 static int bt878_pci_driver_registered;
 static int bt878_pci_driver_registered;

+ 80 - 41
drivers/media/dvb/dm1105/dm1105.c

@@ -51,6 +51,9 @@
 #ifndef PCI_VENDOR_ID_TRIGEM
 #ifndef PCI_VENDOR_ID_TRIGEM
 #define PCI_VENDOR_ID_TRIGEM	0x109f
 #define PCI_VENDOR_ID_TRIGEM	0x109f
 #endif
 #endif
+#ifndef PCI_VENDOR_ID_AXESS
+#define PCI_VENDOR_ID_AXESS	0x195d
+#endif
 #ifndef PCI_DEVICE_ID_DM1105
 #ifndef PCI_DEVICE_ID_DM1105
 #define PCI_DEVICE_ID_DM1105	0x036f
 #define PCI_DEVICE_ID_DM1105	0x036f
 #endif
 #endif
@@ -60,6 +63,9 @@
 #ifndef PCI_DEVICE_ID_DW2004
 #ifndef PCI_DEVICE_ID_DW2004
 #define PCI_DEVICE_ID_DW2004	0x2004
 #define PCI_DEVICE_ID_DW2004	0x2004
 #endif
 #endif
+#ifndef PCI_DEVICE_ID_DM05
+#define PCI_DEVICE_ID_DM05	0x1105
+#endif
 /* ----------------------------------------------- */
 /* ----------------------------------------------- */
 /* sdmc dm1105 registers */
 /* sdmc dm1105 registers */
 
 
@@ -150,6 +156,11 @@
 #define DM1105_LNB_13V				0x00010100
 #define DM1105_LNB_13V				0x00010100
 #define DM1105_LNB_18V				0x00000100
 #define DM1105_LNB_18V				0x00000100
 
 
+/* GPIO's for LNB power control for Axess DM05 */
+#define DM05_LNB_MASK				0x00000000
+#define DM05_LNB_13V				0x00020000
+#define DM05_LNB_18V				0x00030000
+
 static int ir_debug;
 static int ir_debug;
 module_param(ir_debug, int, 0644);
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
 MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
@@ -188,6 +199,8 @@ struct dm1105dvb {
 
 
 	/* irq */
 	/* irq */
 	struct work_struct work;
 	struct work_struct work;
+	struct workqueue_struct *wq;
+	char wqn[16];
 
 
 	/* dma */
 	/* dma */
 	dma_addr_t dma_addr;
 	dma_addr_t dma_addr;
@@ -313,15 +326,25 @@ static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
 static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
 {
 	struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
 	struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
+	u32 lnb_mask, lnb_13v, lnb_18v;
 
 
-		if (voltage == SEC_VOLTAGE_18) {
-			outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
-			outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL));
-		} else	{
-		/*LNB ON-13V by default!*/
-			outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
-			outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL));
-		}
+	switch (dm1105dvb->pdev->subsystem_device) {
+	case PCI_DEVICE_ID_DM05:
+		lnb_mask = DM05_LNB_MASK;
+		lnb_13v = DM05_LNB_13V;
+		lnb_18v = DM05_LNB_18V;
+		break;
+	default:
+		lnb_mask = DM1105_LNB_MASK;
+		lnb_13v = DM1105_LNB_13V;
+		lnb_18v = DM1105_LNB_18V;
+	}
+
+	outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR));
+	if (voltage == SEC_VOLTAGE_18)
+		outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL));
+	else
+		outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL));
 
 
 	return 0;
 	return 0;
 }
 }
@@ -440,7 +463,7 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
 	case (INTSTS_TSIRQ | INTSTS_IR):
 	case (INTSTS_TSIRQ | INTSTS_IR):
 		dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
 		dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
 					inl(dm_io_mem(DM1105_STADR));
 					inl(dm_io_mem(DM1105_STADR));
-		schedule_work(&dm1105dvb->work);
+		queue_work(dm1105dvb->wq, &dm1105dvb->work);
 		break;
 		break;
 	case INTSTS_IR:
 	case INTSTS_IR:
 		dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
 		dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
@@ -567,46 +590,44 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
 	int ret;
 	int ret;
 
 
 	switch (dm1105dvb->pdev->subsystem_device) {
 	switch (dm1105dvb->pdev->subsystem_device) {
-	case PCI_DEVICE_ID_DW2002:
+	case PCI_DEVICE_ID_DW2004:
 		dm1105dvb->fe = dvb_attach(
 		dm1105dvb->fe = dvb_attach(
-			stv0299_attach, &sharp_z0194a_config,
+			cx24116_attach, &serit_sp2633_config,
 			&dm1105dvb->i2c_adap);
 			&dm1105dvb->i2c_adap);
+		if (dm1105dvb->fe)
+			dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
 
 
+		break;
+	default:
+		dm1105dvb->fe = dvb_attach(
+			stv0299_attach, &sharp_z0194a_config,
+			&dm1105dvb->i2c_adap);
 		if (dm1105dvb->fe) {
 		if (dm1105dvb->fe) {
 			dm1105dvb->fe->ops.set_voltage =
 			dm1105dvb->fe->ops.set_voltage =
 							dm1105dvb_set_voltage;
 							dm1105dvb_set_voltage;
 			dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
 			dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
 					&dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
 					&dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
+			break;
 		}
 		}
 
 
-		if (!dm1105dvb->fe) {
-			dm1105dvb->fe = dvb_attach(
-				stv0288_attach, &earda_config,
-				&dm1105dvb->i2c_adap);
-			if (dm1105dvb->fe) {
-				dm1105dvb->fe->ops.set_voltage =
-							dm1105dvb_set_voltage;
-				dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
-						&dm1105dvb->i2c_adap);
-			}
+		dm1105dvb->fe = dvb_attach(
+			stv0288_attach, &earda_config,
+			&dm1105dvb->i2c_adap);
+		if (dm1105dvb->fe) {
+			dm1105dvb->fe->ops.set_voltage =
+						dm1105dvb_set_voltage;
+			dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
+					&dm1105dvb->i2c_adap);
+			break;
 		}
 		}
 
 
-		if (!dm1105dvb->fe) {
-			dm1105dvb->fe = dvb_attach(
-				si21xx_attach, &serit_config,
-				&dm1105dvb->i2c_adap);
-			if (dm1105dvb->fe)
-				dm1105dvb->fe->ops.set_voltage =
-							dm1105dvb_set_voltage;
-		}
-		break;
-	case PCI_DEVICE_ID_DW2004:
 		dm1105dvb->fe = dvb_attach(
 		dm1105dvb->fe = dvb_attach(
-			cx24116_attach, &serit_sp2633_config,
+			si21xx_attach, &serit_config,
 			&dm1105dvb->i2c_adap);
 			&dm1105dvb->i2c_adap);
 		if (dm1105dvb->fe)
 		if (dm1105dvb->fe)
-			dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
-		break;
+			dm1105dvb->fe->ops.set_voltage =
+						dm1105dvb_set_voltage;
+
 	}
 	}
 
 
 	if (!dm1105dvb->fe) {
 	if (!dm1105dvb->fe) {
@@ -630,10 +651,17 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
 	static u8 command[1] = { 0x28 };
 	static u8 command[1] = { 0x28 };
 
 
 	struct i2c_msg msg[] = {
 	struct i2c_msg msg[] = {
-		{ .addr = IIC_24C01_addr >> 1, .flags = 0,
-				.buf = command, .len = 1 },
-		{ .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD,
-				.buf = mac, .len = 6 },
+		{
+			.addr = IIC_24C01_addr >> 1,
+			.flags = 0,
+			.buf = command,
+			.len = 1
+		}, {
+			.addr = IIC_24C01_addr >> 1,
+			.flags = I2C_M_RD,
+			.buf = mac,
+			.len = 6
+		},
 	};
 	};
 
 
 	dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
 	dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
@@ -752,14 +780,22 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
 	dm1105_ir_init(dm1105dvb);
 	dm1105_ir_init(dm1105dvb);
 
 
 	INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
 	INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
+	sprintf(dm1105dvb->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
+	dm1105dvb->wq = create_singlethread_workqueue(dm1105dvb->wqn);
+	if (!dm1105dvb->wq)
+		goto err_dvb_net;
 
 
 	ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
 	ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
 						DRIVER_NAME, dm1105dvb);
 						DRIVER_NAME, dm1105dvb);
 	if (ret < 0)
 	if (ret < 0)
-		goto err_free_irq;
+		goto err_workqueue;
 
 
 	return 0;
 	return 0;
 
 
+err_workqueue:
+	destroy_workqueue(dm1105dvb->wq);
+err_dvb_net:
+	dvb_net_release(&dm1105dvb->dvbnet);
 err_disconnect_frontend:
 err_disconnect_frontend:
 	dmx->disconnect_frontend(dmx);
 	dmx->disconnect_frontend(dmx);
 err_remove_mem_frontend:
 err_remove_mem_frontend:
@@ -776,8 +812,6 @@ err_i2c_del_adapter:
 	i2c_del_adapter(&dm1105dvb->i2c_adap);
 	i2c_del_adapter(&dm1105dvb->i2c_adap);
 err_dm1105dvb_hw_exit:
 err_dm1105dvb_hw_exit:
 	dm1105dvb_hw_exit(dm1105dvb);
 	dm1105dvb_hw_exit(dm1105dvb);
-err_free_irq:
-	free_irq(pdev->irq, dm1105dvb);
 err_pci_iounmap:
 err_pci_iounmap:
 	pci_iounmap(pdev, dm1105dvb->io_mem);
 	pci_iounmap(pdev, dm1105dvb->io_mem);
 err_pci_release_regions:
 err_pci_release_regions:
@@ -833,6 +867,11 @@ static struct pci_device_id dm1105_id_table[] __devinitdata = {
 		.device = PCI_DEVICE_ID_DM1105,
 		.device = PCI_DEVICE_ID_DM1105,
 		.subvendor = PCI_ANY_ID,
 		.subvendor = PCI_ANY_ID,
 		.subdevice = PCI_DEVICE_ID_DW2004,
 		.subdevice = PCI_DEVICE_ID_DW2004,
+	}, {
+		.vendor = PCI_VENDOR_ID_AXESS,
+		.device = PCI_DEVICE_ID_DM05,
+		.subvendor = PCI_VENDOR_ID_AXESS,
+		.subdevice = PCI_DEVICE_ID_DM05,
 	}, {
 	}, {
 		/* empty */
 		/* empty */
 	},
 	},

+ 4 - 10
drivers/media/dvb/dvb-core/dmxdev.c

@@ -244,19 +244,13 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
 {
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_device *dvbdev = file->private_data;
 	struct dmxdev *dmxdev = dvbdev->priv;
 	struct dmxdev *dmxdev = dvbdev->priv;
-	int ret;
 
 
-	if (dmxdev->exit) {
-		mutex_unlock(&dmxdev->mutex);
+	if (dmxdev->exit)
 		return -ENODEV;
 		return -ENODEV;
-	}
 
 
-	//mutex_lock(&dmxdev->mutex);
-	ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
-				     file->f_flags & O_NONBLOCK,
-				     buf, count, ppos);
-	//mutex_unlock(&dmxdev->mutex);
-	return ret;
+	return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+				      file->f_flags & O_NONBLOCK,
+				      buf, count, ppos);
 }
 }
 
 
 static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
 static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,

+ 42 - 0
drivers/media/dvb/dvb-core/dvb_demux.c

@@ -38,6 +38,16 @@
 */
 */
 // #define DVB_DEMUX_SECTION_LOSS_LOG
 // #define DVB_DEMUX_SECTION_LOSS_LOG
 
 
+static int dvb_demux_tscheck;
+module_param(dvb_demux_tscheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_tscheck,
+		"enable transport stream continuity and TEI check");
+
+#define dprintk_tscheck(x...) do {                              \
+		if (dvb_demux_tscheck && printk_ratelimit())    \
+			printk(x);                              \
+	} while (0)
+
 /******************************************************************************
 /******************************************************************************
  * static inlined helper functions
  * static inlined helper functions
  ******************************************************************************/
  ******************************************************************************/
@@ -376,6 +386,36 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
 	u16 pid = ts_pid(buf);
 	u16 pid = ts_pid(buf);
 	int dvr_done = 0;
 	int dvr_done = 0;
 
 
+	if (dvb_demux_tscheck) {
+		if (!demux->cnt_storage)
+			demux->cnt_storage = vmalloc(MAX_PID + 1);
+
+		if (!demux->cnt_storage) {
+			printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
+			dvb_demux_tscheck = 0;
+			goto no_dvb_demux_tscheck;
+		}
+
+		/* check pkt counter */
+		if (pid < MAX_PID) {
+			if (buf[1] & 0x80)
+				dprintk_tscheck("TEI detected. "
+						"PID=0x%x data1=0x%x\n",
+						pid, buf[1]);
+
+			if ((buf[3] & 0xf) != demux->cnt_storage[pid])
+				dprintk_tscheck("TS packet counter mismatch. "
+						"PID=0x%x expected 0x%x "
+						"got 0x%x\n",
+						pid, demux->cnt_storage[pid],
+						buf[3] & 0xf);
+
+			demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
+		};
+		/* end check */
+	};
+no_dvb_demux_tscheck:
+
 	list_for_each_entry(feed, &demux->feed_list, list_head) {
 	list_for_each_entry(feed, &demux->feed_list, list_head) {
 		if ((feed->pid != pid) && (feed->pid != 0x2000))
 		if ((feed->pid != pid) && (feed->pid != 0x2000))
 			continue;
 			continue;
@@ -1160,6 +1200,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
 	int i;
 	int i;
 	struct dmx_demux *dmx = &dvbdemux->dmx;
 	struct dmx_demux *dmx = &dvbdemux->dmx;
 
 
+	dvbdemux->cnt_storage = NULL;
 	dvbdemux->users = 0;
 	dvbdemux->users = 0;
 	dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
 	dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
 
 
@@ -1226,6 +1267,7 @@ EXPORT_SYMBOL(dvb_dmx_init);
 
 
 void dvb_dmx_release(struct dvb_demux *dvbdemux)
 void dvb_dmx_release(struct dvb_demux *dvbdemux)
 {
 {
+	vfree(dvbdemux->cnt_storage);
 	vfree(dvbdemux->filter);
 	vfree(dvbdemux->filter);
 	vfree(dvbdemux->feed);
 	vfree(dvbdemux->feed);
 }
 }

+ 4 - 0
drivers/media/dvb/dvb-core/dvb_demux.h

@@ -42,6 +42,8 @@
 
 
 #define DVB_DEMUX_MASK_MAX 18
 #define DVB_DEMUX_MASK_MAX 18
 
 
+#define MAX_PID 0x1fff
+
 struct dvb_demux_filter {
 struct dvb_demux_filter {
 	struct dmx_section_filter filter;
 	struct dmx_section_filter filter;
 	u8 maskandmode[DMX_MAX_FILTER_SIZE];
 	u8 maskandmode[DMX_MAX_FILTER_SIZE];
@@ -127,6 +129,8 @@ struct dvb_demux {
 
 
 	struct mutex mutex;
 	struct mutex mutex;
 	spinlock_t lock;
 	spinlock_t lock;
+
+	uint8_t *cnt_storage; /* for TS continuity check */
 };
 };
 
 
 int dvb_dmx_init(struct dvb_demux *dvbdemux);
 int dvb_dmx_init(struct dvb_demux *dvbdemux);

+ 2 - 0
drivers/media/dvb/dvb-core/dvb_frontend.c

@@ -543,6 +543,7 @@ restart:
 
 
 		if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
 		if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
 			/* got signal or quitting */
 			/* got signal or quitting */
+			fepriv->exit = 1;
 			break;
 			break;
 		}
 		}
 
 
@@ -656,6 +657,7 @@ restart:
 	}
 	}
 
 
 	fepriv->thread = NULL;
 	fepriv->thread = NULL;
+	fepriv->exit = 0;
 	mb();
 	mb();
 
 
 	dvb_frontend_wakeup(fe);
 	dvb_frontend_wakeup(fe);

+ 1 - 0
drivers/media/dvb/dvb-usb/Kconfig

@@ -261,6 +261,7 @@ config DVB_USB_DW2102
 	select DVB_STB6000 if !DVB_FE_CUSTOMISE
 	select DVB_STB6000 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
 	select DVB_CX24116 if !DVB_FE_CUSTOMISE
 	select DVB_SI21XX if !DVB_FE_CUSTOMISE
 	select DVB_SI21XX if !DVB_FE_CUSTOMISE
+	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
 	help
 	help
 	  Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
 	  Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
 	  and the TeVii S650.
 	  and the TeVii S650.

+ 88 - 6
drivers/media/dvb/dvb-usb/af9015.c

@@ -40,7 +40,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 static DEFINE_MUTEX(af9015_usb_mutex);
 static DEFINE_MUTEX(af9015_usb_mutex);
 
 
 static struct af9015_config af9015_config;
 static struct af9015_config af9015_config;
-static struct dvb_usb_device_properties af9015_properties[2];
+static struct dvb_usb_device_properties af9015_properties[3];
 static int af9015_properties_count = ARRAY_SIZE(af9015_properties);
 static int af9015_properties_count = ARRAY_SIZE(af9015_properties);
 
 
 static struct af9013_config af9015_af9013_config[] = {
 static struct af9013_config af9015_af9013_config[] = {
@@ -538,7 +538,7 @@ exit:
 /* dump eeprom */
 /* dump eeprom */
 static int af9015_eeprom_dump(struct dvb_usb_device *d)
 static int af9015_eeprom_dump(struct dvb_usb_device *d)
 {
 {
-	char buf[52], buf2[4];
+	char buf[4+3*16+1], buf2[4];
 	u8 reg, val;
 	u8 reg, val;
 
 
 	for (reg = 0; ; reg++) {
 	for (reg = 0; ; reg++) {
@@ -1261,7 +1261,11 @@ static struct usb_device_id af9015_usb_table[] = {
 	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_2)},
 	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_2)},
 	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_3)},
 	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_3)},
 	{USB_DEVICE(USB_VID_AFATECH,   USB_PID_TREKSTOR_DVBT)},
 	{USB_DEVICE(USB_VID_AFATECH,   USB_PID_TREKSTOR_DVBT)},
-	{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
+/* 20 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
+	{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
+	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_CONCEPTRONIC_CTVDIGRCU)},
+	{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_MC810)},
+	{USB_DEVICE(USB_VID_KYE,       USB_PID_GENIUS_TVGO_DVB_T03)},
 	{0},
 	{0},
 };
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1321,7 +1325,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
 
 		.i2c_algo = &af9015_i2c_algo,
 		.i2c_algo = &af9015_i2c_algo,
 
 
-		.num_device_descs = 9,
+		.num_device_descs = 9, /* max 9 */
 		.devices = {
 		.devices = {
 			{
 			{
 				.name = "Afatech AF9015 DVB-T USB2.0 stick",
 				.name = "Afatech AF9015 DVB-T USB2.0 stick",
@@ -1426,7 +1430,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
 
 		.i2c_algo = &af9015_i2c_algo,
 		.i2c_algo = &af9015_i2c_algo,
 
 
-		.num_device_descs = 9,
+		.num_device_descs = 9, /* max 9 */
 		.devices = {
 		.devices = {
 			{
 			{
 				.name = "Xtensions XD-380",
 				.name = "Xtensions XD-380",
@@ -1478,7 +1482,85 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 				.warm_ids = {NULL},
 				.warm_ids = {NULL},
 			},
 			},
 		}
 		}
-	}
+	}, {
+		.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+		.usb_ctrl = DEVICE_SPECIFIC,
+		.download_firmware = af9015_download_firmware,
+		.firmware = "dvb-usb-af9015.fw",
+		.no_reconnect = 1,
+
+		.size_of_priv = sizeof(struct af9015_state), \
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+				.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+				.pid_filter_count = 32,
+				.pid_filter       = af9015_pid_filter,
+				.pid_filter_ctrl  = af9015_pid_filter_ctrl,
+
+				.frontend_attach =
+					af9015_af9013_frontend_attach,
+				.tuner_attach    = af9015_tuner_attach,
+				.stream = {
+					.type = USB_BULK,
+					.count = 6,
+					.endpoint = 0x84,
+				},
+			},
+			{
+				.frontend_attach =
+					af9015_af9013_frontend_attach,
+				.tuner_attach    = af9015_tuner_attach,
+				.stream = {
+					.type = USB_BULK,
+					.count = 6,
+					.endpoint = 0x85,
+					.u = {
+						.bulk = {
+							.buffersize =
+						TS_USB20_MAX_PACKET_SIZE,
+						}
+					}
+				},
+			}
+		},
+
+		.identify_state = af9015_identify_state,
+
+		.rc_query         = af9015_rc_query,
+		.rc_interval      = 150,
+
+		.i2c_algo = &af9015_i2c_algo,
+
+		.num_device_descs = 4, /* max 9 */
+		.devices = {
+			{
+				.name = "AverMedia AVerTV Volar GPS 805 (A805)",
+				.cold_ids = {&af9015_usb_table[21], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \
+					"V3.0",
+				.cold_ids = {&af9015_usb_table[22], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "KWorld Digial MC-810",
+				.cold_ids = {&af9015_usb_table[23], NULL},
+				.warm_ids = {NULL},
+			},
+			{
+				.name = "Genius TVGo DVB-T03",
+				.cold_ids = {&af9015_usb_table[24], NULL},
+				.warm_ids = {NULL},
+			},
+		}
+	},
 };
 };
 
 
 static int af9015_usb_probe(struct usb_interface *intf,
 static int af9015_usb_probe(struct usb_interface *intf,

+ 23 - 8
drivers/media/dvb/dvb-usb/dib0700_devices.c

@@ -1346,9 +1346,9 @@ static int dib0700_xc5000_tuner_callback(void *priv, int component,
 	if (command == XC5000_TUNER_RESET) {
 	if (command == XC5000_TUNER_RESET) {
 		/* Reset the tuner */
 		/* Reset the tuner */
 		dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0);
 		dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0);
-		msleep(330); /* from Windows USB trace */
+		msleep(10);
 		dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1);
 		dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1);
-		msleep(330); /* from Windows USB trace */
+		msleep(10);
 	} else {
 	} else {
 		err("xc5000: unknown tuner callback command: %d\n", command);
 		err("xc5000: unknown tuner callback command: %d\n", command);
 		return -EINVAL;
 		return -EINVAL;
@@ -1493,6 +1493,10 @@ struct usb_device_id dib0700_usb_id_table[] = {
 	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) },
 	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) },
 	{ USB_DEVICE(USB_VID_YUAN,	USB_PID_YUAN_MC770) },
 	{ USB_DEVICE(USB_VID_YUAN,	USB_PID_YUAN_MC770) },
 	{ USB_DEVICE(USB_VID_ELGATO,	USB_PID_ELGATO_EYETV_DTT) },
 	{ USB_DEVICE(USB_VID_ELGATO,	USB_PID_ELGATO_EYETV_DTT) },
+/* 50 */{ USB_DEVICE(USB_VID_ELGATO,	USB_PID_ELGATO_EYETV_DTT_Dlx) },
+	{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_H) },
+	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_T3) },
+	{ USB_DEVICE(USB_VID_TERRATEC,	USB_PID_TERRATEC_T5) },
 	{ 0 }		/* Terminating entry */
 	{ 0 }		/* Terminating entry */
 };
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1692,7 +1696,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			},
 			},
 		},
 		},
 
 
-		.num_device_descs = 11,
+		.num_device_descs = 12,
 		.devices = {
 		.devices = {
 			{   "DiBcom STK7070P reference design",
 			{   "DiBcom STK7070P reference design",
 				{ &dib0700_usb_id_table[15], NULL },
 				{ &dib0700_usb_id_table[15], NULL },
@@ -1726,8 +1730,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 				{ &dib0700_usb_id_table[30], NULL },
 				{ &dib0700_usb_id_table[30], NULL },
 				{ NULL },
 				{ NULL },
 			},
 			},
-			{   "Terratec Cinergy T USB XXS",
-				{ &dib0700_usb_id_table[33], NULL },
+			{   "Terratec Cinergy T USB XXS/ T3",
+				{ &dib0700_usb_id_table[33],
+					&dib0700_usb_id_table[52], NULL },
 				{ NULL },
 				{ NULL },
 			},
 			},
 			{   "Elgato EyeTV DTT",
 			{   "Elgato EyeTV DTT",
@@ -1738,6 +1743,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 				{ &dib0700_usb_id_table[45], NULL },
 				{ &dib0700_usb_id_table[45], NULL },
 				{ NULL },
 				{ NULL },
 			},
 			},
+			{   "Elgato EyeTV Dtt Dlx PD378S",
+				{ &dib0700_usb_id_table[50], NULL },
+				{ NULL },
+			},
 		},
 		},
 
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
 		.rc_interval      = DEFAULT_RC_INTERVAL,
@@ -1784,8 +1793,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 				{ &dib0700_usb_id_table[36], NULL },
 				{ &dib0700_usb_id_table[36], NULL },
 				{ NULL },
 				{ NULL },
 			},
 			},
-			{  "Terratec Cinergy DT USB XS Diversity",
-				{ &dib0700_usb_id_table[43], NULL },
+			{  "Terratec Cinergy DT USB XS Diversity/ T5",
+				{ &dib0700_usb_id_table[43],
+					&dib0700_usb_id_table[53], NULL},
 				{ NULL },
 				{ NULL },
 			},
 			},
 			{  "Sony PlayTV",
 			{  "Sony PlayTV",
@@ -1812,7 +1822,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			},
 			},
 		},
 		},
 
 
-		.num_device_descs = 7,
+		.num_device_descs = 8,
 		.devices = {
 		.devices = {
 			{   "Terratec Cinergy HT USB XE",
 			{   "Terratec Cinergy HT USB XE",
 				{ &dib0700_usb_id_table[27], NULL },
 				{ &dib0700_usb_id_table[27], NULL },
@@ -1842,6 +1852,11 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 				{ &dib0700_usb_id_table[48], NULL },
 				{ &dib0700_usb_id_table[48], NULL },
 				{ NULL },
 				{ NULL },
 			},
 			},
+			{   "Leadtek WinFast DTV Dongle H",
+				{ &dib0700_usb_id_table[51], NULL },
+				{ NULL },
+			},
+
 		},
 		},
 		.rc_interval      = DEFAULT_RC_INTERVAL,
 		.rc_interval      = DEFAULT_RC_INTERVAL,
 		.rc_key_map       = dib0700_rc_keys,
 		.rc_key_map       = dib0700_rc_keys,

+ 5 - 2
drivers/media/dvb/dvb-usb/dibusb-common.c

@@ -133,14 +133,17 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
 
 
 	for (i = 0; i < num; i++) {
 	for (i = 0; i < num; i++) {
 		/* write/read request */
 		/* write/read request */
-		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+		if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0
+					  && (msg[i+1].flags & I2C_M_RD)) {
 			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
 			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
 						msg[i+1].buf,msg[i+1].len) < 0)
 						msg[i+1].buf,msg[i+1].len) < 0)
 				break;
 				break;
 			i++;
 			i++;
-		} else
+		} else if ((msg[i].flags & I2C_M_RD) == 0) {
 			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
 			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
 				break;
 				break;
+		} else
+			break;
 	}
 	}
 
 
 	mutex_unlock(&d->i2c_mutex);
 	mutex_unlock(&d->i2c_mutex);

+ 8 - 0
drivers/media/dvb/dvb-usb/dvb-usb-ids.h

@@ -80,6 +80,7 @@
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM		0x010d
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM		0x010d
 #define USB_PID_COMPRO_VIDEOMATE_U500			0x1e78
 #define USB_PID_COMPRO_VIDEOMATE_U500			0x1e78
 #define USB_PID_COMPRO_VIDEOMATE_U500_PC		0x1e80
 #define USB_PID_COMPRO_VIDEOMATE_U500_PC		0x1e80
+#define USB_PID_CONCEPTRONIC_CTVDIGRCU			0xe397
 #define USB_PID_CONEXANT_D680_DMB			0x86d6
 #define USB_PID_CONEXANT_D680_DMB			0x86d6
 #define USB_PID_DIBCOM_HOOK_DEFAULT			0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT			0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM		0x0065
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM		0x0065
@@ -97,6 +98,7 @@
 #define USB_PID_DPOSH_M9206_COLD			0x9206
 #define USB_PID_DPOSH_M9206_COLD			0x9206
 #define USB_PID_DPOSH_M9206_WARM			0xa090
 #define USB_PID_DPOSH_M9206_WARM			0xa090
 #define USB_PID_UNIWILL_STK7700P			0x6003
 #define USB_PID_UNIWILL_STK7700P			0x6003
+#define USB_PID_GENIUS_TVGO_DVB_T03			0x4012
 #define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
 #define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
 #define USB_PID_INTEL_CE9500				0x9500
 #define USB_PID_INTEL_CE9500				0x9500
@@ -104,6 +106,7 @@
 #define USB_PID_KWORLD_395U				0xe396
 #define USB_PID_KWORLD_395U				0xe396
 #define USB_PID_KWORLD_395U_2				0xe39b
 #define USB_PID_KWORLD_395U_2				0xe39b
 #define USB_PID_KWORLD_395U_3				0xe395
 #define USB_PID_KWORLD_395U_3				0xe395
+#define USB_PID_KWORLD_MC810				0xc810
 #define USB_PID_KWORLD_PC160_2T				0xc160
 #define USB_PID_KWORLD_PC160_2T				0xc160
 #define USB_PID_KWORLD_VSTREAM_COLD			0x17de
 #define USB_PID_KWORLD_VSTREAM_COLD			0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM			0x17df
 #define USB_PID_KWORLD_VSTREAM_WARM			0x17df
@@ -171,6 +174,7 @@
 #define USB_PID_AVERMEDIA_A309				0xa309
 #define USB_PID_AVERMEDIA_A309				0xa309
 #define USB_PID_AVERMEDIA_A310				0xa310
 #define USB_PID_AVERMEDIA_A310				0xa310
 #define USB_PID_AVERMEDIA_A850				0x850a
 #define USB_PID_AVERMEDIA_A850				0x850a
+#define USB_PID_AVERMEDIA_A805				0xa805
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2	0x0081
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2	0x0081
@@ -178,6 +182,8 @@
 #define USB_PID_TERRATEC_CINERGY_HT_EXPRESS		0x0060
 #define USB_PID_TERRATEC_CINERGY_HT_EXPRESS		0x0060
 #define USB_PID_TERRATEC_CINERGY_T_EXPRESS		0x0062
 #define USB_PID_TERRATEC_CINERGY_T_EXPRESS		0x0062
 #define USB_PID_TERRATEC_CINERGY_T_XXS			0x0078
 #define USB_PID_TERRATEC_CINERGY_T_XXS			0x0078
+#define USB_PID_TERRATEC_T3				0x10a0
+#define USB_PID_TERRATEC_T5				0x10a1
 #define USB_PID_PINNACLE_EXPRESSCARD_320CX		0x022e
 #define USB_PID_PINNACLE_EXPRESSCARD_320CX		0x022e
 #define USB_PID_PINNACLE_PCTV2000E			0x022c
 #define USB_PID_PINNACLE_PCTV2000E			0x022c
 #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH		0x0228
 #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH		0x0228
@@ -222,6 +228,7 @@
 #define USB_PID_WINFAST_DTV_DONGLE_COLD			0x6025
 #define USB_PID_WINFAST_DTV_DONGLE_COLD			0x6025
 #define USB_PID_WINFAST_DTV_DONGLE_WARM			0x6026
 #define USB_PID_WINFAST_DTV_DONGLE_WARM			0x6026
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P		0x6f00
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P		0x6f00
+#define USB_PID_WINFAST_DTV_DONGLE_H			0x60f6
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2		0x6f01
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2		0x6f01
 #define USB_PID_WINFAST_DTV_DONGLE_GOLD			0x6029
 #define USB_PID_WINFAST_DTV_DONGLE_GOLD			0x6029
 #define USB_PID_GENPIX_8PSK_REV_1_COLD			0x0200
 #define USB_PID_GENPIX_8PSK_REV_1_COLD			0x0200
@@ -251,5 +258,6 @@
 #define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
 #define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
 #define USB_PID_SONY_PLAYTV				0x0003
 #define USB_PID_SONY_PLAYTV				0x0003
 #define USB_PID_ELGATO_EYETV_DTT			0x0021
 #define USB_PID_ELGATO_EYETV_DTT			0x0021
+#define USB_PID_ELGATO_EYETV_DTT_Dlx			0x0020
 
 
 #endif
 #endif

+ 1 - 1
drivers/media/dvb/dvb-usb/dvb-usb.h

@@ -223,7 +223,7 @@ struct dvb_usb_device_properties {
 	int generic_bulk_ctrl_endpoint;
 	int generic_bulk_ctrl_endpoint;
 
 
 	int num_device_descs;
 	int num_device_descs;
-	struct dvb_usb_device_description devices[11];
+	struct dvb_usb_device_description devices[12];
 };
 };
 
 
 /**
 /**

+ 293 - 32
drivers/media/dvb/dvb-usb/dw2102.c

@@ -1,7 +1,7 @@
 /* DVB USB framework compliant Linux driver for the
 /* DVB USB framework compliant Linux driver for the
-*	DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card
-*
-* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*	DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
+*	TeVii S600, S650 Cards
+* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
 *
 *
 *	This program is free software; you can redistribute it and/or modify it
 *	This program is free software; you can redistribute it and/or modify it
 *	under the terms of the GNU General Public License as published by the
 *	under the terms of the GNU General Public License as published by the
@@ -17,6 +17,7 @@
 #include "stb6000.h"
 #include "stb6000.h"
 #include "eds1547.h"
 #include "eds1547.h"
 #include "cx24116.h"
 #include "cx24116.h"
+#include "tda1002x.h"
 
 
 #ifndef USB_PID_DW2102
 #ifndef USB_PID_DW2102
 #define USB_PID_DW2102 0x2102
 #define USB_PID_DW2102 0x2102
@@ -26,10 +27,18 @@
 #define USB_PID_DW2104 0x2104
 #define USB_PID_DW2104 0x2104
 #endif
 #endif
 
 
+#ifndef USB_PID_DW3101
+#define USB_PID_DW3101 0x3101
+#endif
+
 #ifndef USB_PID_CINERGY_S
 #ifndef USB_PID_CINERGY_S
 #define USB_PID_CINERGY_S 0x0064
 #define USB_PID_CINERGY_S 0x0064
 #endif
 #endif
 
 
+#ifndef USB_PID_TEVII_S650
+#define USB_PID_TEVII_S650 0xd650
+#endif
+
 #define DW210X_READ_MSG 0
 #define DW210X_READ_MSG 0
 #define DW210X_WRITE_MSG 1
 #define DW210X_WRITE_MSG 1
 
 
@@ -40,18 +49,21 @@
 #define DW2102_VOLTAGE_CTRL (0x1800)
 #define DW2102_VOLTAGE_CTRL (0x1800)
 #define DW2102_RC_QUERY (0x1a00)
 #define DW2102_RC_QUERY (0x1a00)
 
 
-struct dw210x_state {
-	u32 last_key_pressed;
-};
-struct dw210x_rc_keys {
-	u32 keycode;
-	u32 event;
+struct dvb_usb_rc_keys_table {
+	struct dvb_usb_rc_key *rc_keys;
+	int rc_keys_size;
 };
 };
 
 
 /* debug */
 /* debug */
 static int dvb_usb_dw2102_debug;
 static int dvb_usb_dw2102_debug;
 module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
 module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS);
+MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
+						DVB_USB_DEBUG_STATUS);
+
+/* keymaps */
+static int ir_keymap;
+module_param_named(keymap, ir_keymap, int, 0644);
+MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs  ...");
 
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 
@@ -79,7 +91,7 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
 static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 		int num)
 		int num)
 {
 {
-struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i = 0, ret = 0;
 	int i = 0, ret = 0;
 	u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
 	u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
 	u16 value;
 	u16 value;
@@ -205,6 +217,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
 	mutex_unlock(&d->i2c_mutex);
 	mutex_unlock(&d->i2c_mutex);
 	return num;
 	return num;
 }
 }
+
 static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
 static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
 {
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
@@ -219,7 +232,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
 	case 2: {
 	case 2: {
 		/* read */
 		/* read */
 		/* first write first register number */
 		/* first write first register number */
-		u8 ibuf [msg[1].len + 2], obuf[3];
+		u8 ibuf[msg[1].len + 2], obuf[3];
 		obuf[0] = 0xd0;
 		obuf[0] = 0xd0;
 		obuf[1] = msg[0].len;
 		obuf[1] = msg[0].len;
 		obuf[2] = msg[0].buf[0];
 		obuf[2] = msg[0].buf[0];
@@ -293,7 +306,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
 	case 2: {
 	case 2: {
 		/* read */
 		/* read */
 		/* first write first register number */
 		/* first write first register number */
-		u8 ibuf [msg[1].len + 2], obuf[3];
+		u8 ibuf[msg[1].len + 2], obuf[3];
 		obuf[0] = 0xaa;
 		obuf[0] = 0xaa;
 		obuf[1] = msg[0].len;
 		obuf[1] = msg[0].len;
 		obuf[2] = msg[0].buf[0];
 		obuf[2] = msg[0].buf[0];
@@ -360,6 +373,69 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
 	return num;
 	return num;
 }
 }
 
 
+static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+								int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret = 0, i;
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	switch (num) {
+	case 2: {
+		/* read */
+		/* first write first register number */
+		u8 ibuf[msg[1].len + 2], obuf[3];
+		obuf[0] = msg[0].addr << 1;
+		obuf[1] = msg[0].len;
+		obuf[2] = msg[0].buf[0];
+		ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+		/* second read registers */
+		ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
+				ibuf, msg[1].len + 2, DW210X_READ_MSG);
+		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
+
+		break;
+	}
+	case 1:
+		switch (msg[0].addr) {
+		case 0x60:
+		case 0x0c: {
+			/* write to register */
+			u8 obuf[msg[0].len + 2];
+			obuf[0] = msg[0].addr << 1;
+			obuf[1] = msg[0].len;
+			memcpy(obuf + 2, msg[0].buf, msg[0].len);
+			ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+			break;
+		}
+		case(DW2102_RC_QUERY): {
+			u8 ibuf[2];
+			ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+					ibuf, 2, DW210X_READ_MSG);
+			memcpy(msg[0].buf, ibuf , 2);
+			break;
+		}
+		}
+
+		break;
+	}
+
+	for (i = 0; i < num; i++) {
+		deb_xfer("%02x:%02x: %s ", i, msg[i].addr,
+				msg[i].flags == 0 ? ">>>" : "<<<");
+		debug_dump(msg[i].buf, msg[i].len, deb_xfer);
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
 static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
 static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
 {
 {
 	return I2C_FUNC_I2C;
 	return I2C_FUNC_I2C;
@@ -385,6 +461,11 @@ static struct i2c_algorithm dw2104_i2c_algo = {
 	.functionality = dw210x_i2c_func,
 	.functionality = dw210x_i2c_func,
 };
 };
 
 
+static struct i2c_algorithm dw3101_i2c_algo = {
+	.master_xfer = dw3101_i2c_transfer,
+	.functionality = dw210x_i2c_func,
+};
+
 static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 {
 {
 	int i;
 	int i;
@@ -404,6 +485,7 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 			debug_dump(eepromline, 16, deb_xfer);
 			debug_dump(eepromline, 16, deb_xfer);
 		}
 		}
 	}
 	}
+
 	memcpy(mac, eeprom + 8, 6);
 	memcpy(mac, eeprom + 8, 6);
 	return 0;
 	return 0;
 };
 };
@@ -448,6 +530,11 @@ static struct si21xx_config serit_sp1511lhb_config = {
 
 
 };
 };
 
 
+static struct tda10023_config dw3101_tda10023_config = {
+	.demod_address = 0x0c,
+	.invert = 1,
+};
+
 static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 {
 {
 	if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
 	if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
@@ -460,6 +547,7 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 }
 }
 
 
 static struct dvb_usb_device_properties dw2102_properties;
 static struct dvb_usb_device_properties dw2102_properties;
+static struct dvb_usb_device_properties dw2104_properties;
 
 
 static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 {
 {
@@ -497,6 +585,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 	return -EIO;
 	return -EIO;
 }
 }
 
 
+static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
+{
+	d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
+				&d->dev->i2c_adap, 0x48);
+	if (d->fe != NULL) {
+		info("Attached tda10023!\n");
+		return 0;
+	}
+	return -EIO;
+}
+
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 {
 {
 	dvb_attach(dvb_pll_attach, adap->fe, 0x60,
 	dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -512,6 +611,14 @@ static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap)
 	return 0;
 	return 0;
 }
 }
 
 
+static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(dvb_pll_attach, adap->fe, 0x60,
+		&adap->dev->i2c_adap, DVB_PLL_TUA6034);
+
+	return 0;
+}
+
 static struct dvb_usb_rc_key dw210x_rc_keys[] = {
 static struct dvb_usb_rc_key dw210x_rc_keys[] = {
 	{ 0xf8,	0x0a, KEY_Q },		/*power*/
 	{ 0xf8,	0x0a, KEY_Q },		/*power*/
 	{ 0xf8,	0x0c, KEY_M },		/*mute*/
 	{ 0xf8,	0x0c, KEY_M },		/*mute*/
@@ -544,44 +651,147 @@ static struct dvb_usb_rc_key dw210x_rc_keys[] = {
 	{ 0xf8, 0x40, KEY_F },		/*full*/
 	{ 0xf8, 0x40, KEY_F },		/*full*/
 	{ 0xf8, 0x1e, KEY_W },		/*tvmode*/
 	{ 0xf8, 0x1e, KEY_W },		/*tvmode*/
 	{ 0xf8, 0x1b, KEY_B },		/*recall*/
 	{ 0xf8, 0x1b, KEY_B },		/*recall*/
+};
 
 
+static struct dvb_usb_rc_key tevii_rc_keys[] = {
+	{ 0xf8, 0x0a, KEY_POWER },
+	{ 0xf8, 0x0c, KEY_MUTE },
+	{ 0xf8, 0x11, KEY_1 },
+	{ 0xf8, 0x12, KEY_2 },
+	{ 0xf8, 0x13, KEY_3 },
+	{ 0xf8, 0x14, KEY_4 },
+	{ 0xf8, 0x15, KEY_5 },
+	{ 0xf8, 0x16, KEY_6 },
+	{ 0xf8, 0x17, KEY_7 },
+	{ 0xf8, 0x18, KEY_8 },
+	{ 0xf8, 0x19, KEY_9 },
+	{ 0xf8, 0x10, KEY_0 },
+	{ 0xf8, 0x1c, KEY_MENU },
+	{ 0xf8, 0x0f, KEY_VOLUMEDOWN },
+	{ 0xf8, 0x1a, KEY_LAST },
+	{ 0xf8, 0x0e, KEY_OPEN },
+	{ 0xf8, 0x04, KEY_RECORD },
+	{ 0xf8, 0x09, KEY_VOLUMEUP },
+	{ 0xf8, 0x08, KEY_CHANNELUP },
+	{ 0xf8, 0x07, KEY_PVR },
+	{ 0xf8, 0x0b, KEY_TIME },
+	{ 0xf8, 0x02, KEY_RIGHT },
+	{ 0xf8, 0x03, KEY_LEFT },
+	{ 0xf8, 0x00, KEY_UP },
+	{ 0xf8, 0x1f, KEY_OK },
+	{ 0xf8, 0x01, KEY_DOWN },
+	{ 0xf8, 0x05, KEY_TUNER },
+	{ 0xf8, 0x06, KEY_CHANNELDOWN },
+	{ 0xf8, 0x40, KEY_PLAYPAUSE },
+	{ 0xf8, 0x1e, KEY_REWIND },
+	{ 0xf8, 0x1b, KEY_FAVORITES },
+	{ 0xf8, 0x1d, KEY_BACK },
+	{ 0xf8, 0x4d, KEY_FASTFORWARD },
+	{ 0xf8, 0x44, KEY_EPG },
+	{ 0xf8, 0x4c, KEY_INFO },
+	{ 0xf8, 0x41, KEY_AB },
+	{ 0xf8, 0x43, KEY_AUDIO },
+	{ 0xf8, 0x45, KEY_SUBTITLE },
+	{ 0xf8, 0x4a, KEY_LIST },
+	{ 0xf8, 0x46, KEY_F1 },
+	{ 0xf8, 0x47, KEY_F2 },
+	{ 0xf8, 0x5e, KEY_F3 },
+	{ 0xf8, 0x5c, KEY_F4 },
+	{ 0xf8, 0x52, KEY_F5 },
+	{ 0xf8, 0x5a, KEY_F6 },
+	{ 0xf8, 0x56, KEY_MODE },
+	{ 0xf8, 0x58, KEY_SWITCHVIDEOMODE },
 };
 };
 
 
+static struct dvb_usb_rc_key tbs_rc_keys[] = {
+	{ 0xf8,	0x84, KEY_POWER },
+	{ 0xf8,	0x94, KEY_MUTE },
+	{ 0xf8,	0x87, KEY_1 },
+	{ 0xf8,	0x86, KEY_2 },
+	{ 0xf8,	0x85, KEY_3 },
+	{ 0xf8,	0x8b, KEY_4 },
+	{ 0xf8,	0x8a, KEY_5 },
+	{ 0xf8,	0x89, KEY_6 },
+	{ 0xf8,	0x8f, KEY_7 },
+	{ 0xf8,	0x8e, KEY_8 },
+	{ 0xf8,	0x8d, KEY_9 },
+	{ 0xf8, 0x92, KEY_0 },
+	{ 0xf8, 0x96, KEY_CHANNELUP },
+	{ 0xf8, 0x91, KEY_CHANNELDOWN },
+	{ 0xf8, 0x93, KEY_VOLUMEUP },
+	{ 0xf8, 0x8c, KEY_VOLUMEDOWN },
+	{ 0xf8, 0x83, KEY_RECORD },
+	{ 0xf8, 0x98, KEY_PAUSE  },
+	{ 0xf8, 0x99, KEY_OK },
+	{ 0xf8, 0x9a, KEY_SHUFFLE },
+	{ 0xf8, 0x81, KEY_UP },
+	{ 0xf8, 0x90, KEY_LEFT },
+	{ 0xf8, 0x82, KEY_RIGHT },
+	{ 0xf8, 0x88, KEY_DOWN },
+	{ 0xf8, 0x95, KEY_FAVORITES },
+	{ 0xf8, 0x97, KEY_SUBTITLE },
+	{ 0xf8, 0x9d, KEY_ZOOM },
+	{ 0xf8, 0x9f, KEY_EXIT },
+	{ 0xf8, 0x9e, KEY_MENU },
+	{ 0xf8, 0x9c, KEY_EPG },
+	{ 0xf8, 0x80, KEY_PREVIOUS },
+	{ 0xf8, 0x9b, KEY_MODE }
+};
 
 
+static struct dvb_usb_rc_keys_table keys_tables[] = {
+	{ dw210x_rc_keys, ARRAY_SIZE(dw210x_rc_keys) },
+	{ tevii_rc_keys, ARRAY_SIZE(tevii_rc_keys) },
+	{ tbs_rc_keys, ARRAY_SIZE(tbs_rc_keys) },
+};
 
 
 static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
 {
-	struct dw210x_state *st = d->priv;
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	int keymap_size = d->props.rc_key_map_size;
 	u8 key[2];
 	u8 key[2];
-	struct i2c_msg msg[] = {
-		{.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key,
-		.len = 2},
+	struct i2c_msg msg = {
+		.addr = DW2102_RC_QUERY,
+		.flags = I2C_M_RD,
+		.buf = key,
+		.len = 2
 	};
 	};
 	int i;
 	int i;
+	/* override keymap */
+	if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) {
+		keymap = keys_tables[ir_keymap - 1].rc_keys ;
+		keymap_size = keys_tables[ir_keymap - 1].rc_keys_size;
+	}
 
 
 	*state = REMOTE_NO_KEY_PRESSED;
 	*state = REMOTE_NO_KEY_PRESSED;
-	if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) {
-		for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) {
-			if (dw210x_rc_keys[i].data == msg[0].buf[0]) {
+	if (dw2102_i2c_transfer(&d->i2c_adap, &msg, 1) == 1) {
+		for (i = 0; i < keymap_size ; i++) {
+			if (keymap[i].data == msg.buf[0]) {
 				*state = REMOTE_KEY_PRESSED;
 				*state = REMOTE_KEY_PRESSED;
-				*event = dw210x_rc_keys[i].event;
-				st->last_key_pressed =
-					dw210x_rc_keys[i].event;
+				*event = keymap[i].event;
 				break;
 				break;
 			}
 			}
-		st->last_key_pressed = 0;
+
 		}
 		}
+
+		if ((*state) == REMOTE_KEY_PRESSED)
+			deb_rc("%s: found rc key: %x, %x, event: %x\n",
+					__func__, key[0], key[1], (*event));
+		else if (key[0] != 0xff)
+			deb_rc("%s: unknown rc key: %x, %x\n",
+					__func__, key[0], key[1]);
+
 	}
 	}
-	/* info("key: %x %x\n",key[0],key[1]); */
+
 	return 0;
 	return 0;
 }
 }
 
 
 static struct usb_device_id dw2102_table[] = {
 static struct usb_device_id dw2102_table[] = {
 	{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
 	{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
 	{USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
 	{USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
-	{USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
-	{USB_DEVICE(0x9022, 0xd650)},
+	{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
+	{USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
 	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
 	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
+	{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
 	{ }
 	{ }
 };
 };
 
 
@@ -642,11 +852,16 @@ static int dw2102_load_firmware(struct usb_device *dev,
 		}
 		}
 		/* init registers */
 		/* init registers */
 		switch (dev->descriptor.idProduct) {
 		switch (dev->descriptor.idProduct) {
+		case USB_PID_TEVII_S650:
+			dw2104_properties.rc_key_map = tevii_rc_keys;
+			dw2104_properties.rc_key_map_size =
+					ARRAY_SIZE(tevii_rc_keys);
 		case USB_PID_DW2104:
 		case USB_PID_DW2104:
-		case 0xd650:
 			reset = 1;
 			reset = 1;
 			dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
 			dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
 					DW210X_WRITE_MSG);
 					DW210X_WRITE_MSG);
+			/* break omitted intentionally */
+		case USB_PID_DW3101:
 			reset = 0;
 			reset = 0;
 			dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
 			dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
 					DW210X_WRITE_MSG);
 					DW210X_WRITE_MSG);
@@ -690,6 +905,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
 					DW210X_READ_MSG);
 					DW210X_READ_MSG);
 			break;
 			break;
 		}
 		}
+
 		msleep(100);
 		msleep(100);
 		kfree(p);
 		kfree(p);
 	}
 	}
@@ -700,7 +916,6 @@ static struct dvb_usb_device_properties dw2102_properties = {
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
 	.usb_ctrl = DEVICE_SPECIFIC,
 	.usb_ctrl = DEVICE_SPECIFIC,
 	.firmware = "dvb-usb-dw2102.fw",
 	.firmware = "dvb-usb-dw2102.fw",
-	.size_of_priv = sizeof(struct dw210x_state),
 	.no_reconnect = 1,
 	.no_reconnect = 1,
 
 
 	.i2c_algo = &dw2102_serit_i2c_algo,
 	.i2c_algo = &dw2102_serit_i2c_algo,
@@ -714,7 +929,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
 	.num_adapters = 1,
 	.num_adapters = 1,
 	.download_firmware = dw2102_load_firmware,
 	.download_firmware = dw2102_load_firmware,
 	.read_mac_address = dw210x_read_mac_address,
 	.read_mac_address = dw210x_read_mac_address,
-		.adapter = {
+	.adapter = {
 		{
 		{
 			.frontend_attach = dw2102_frontend_attach,
 			.frontend_attach = dw2102_frontend_attach,
 			.streaming_ctrl = NULL,
 			.streaming_ctrl = NULL,
@@ -752,7 +967,6 @@ static struct dvb_usb_device_properties dw2104_properties = {
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
 	.usb_ctrl = DEVICE_SPECIFIC,
 	.usb_ctrl = DEVICE_SPECIFIC,
 	.firmware = "dvb-usb-dw2104.fw",
 	.firmware = "dvb-usb-dw2104.fw",
-	.size_of_priv = sizeof(struct dw210x_state),
 	.no_reconnect = 1,
 	.no_reconnect = 1,
 
 
 	.i2c_algo = &dw2104_i2c_algo,
 	.i2c_algo = &dw2104_i2c_algo,
@@ -796,12 +1010,57 @@ static struct dvb_usb_device_properties dw2104_properties = {
 	}
 	}
 };
 };
 
 
+static struct dvb_usb_device_properties dw3101_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "dvb-usb-dw3101.fw",
+	.no_reconnect = 1,
+
+	.i2c_algo = &dw3101_i2c_algo,
+	.rc_key_map = dw210x_rc_keys,
+	.rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
+	.rc_interval = 150,
+	.rc_query = dw2102_rc_query,
+
+	.generic_bulk_ctrl_endpoint = 0x81,
+	/* parameter for the MPEG2-data transfer */
+	.num_adapters = 1,
+	.download_firmware = dw2102_load_firmware,
+	.read_mac_address = dw210x_read_mac_address,
+	.adapter = {
+		{
+			.frontend_attach = dw3101_frontend_attach,
+			.streaming_ctrl = NULL,
+			.tuner_attach = dw3101_tuner_attach,
+			.stream = {
+				.type = USB_BULK,
+				.count = 8,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{ "DVBWorld DVB-C 3101 USB2.0",
+			{&dw2102_table[5], NULL},
+			{NULL},
+		},
+	}
+};
+
 static int dw2102_probe(struct usb_interface *intf,
 static int dw2102_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 		const struct usb_device_id *id)
 {
 {
 	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
 	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
 			THIS_MODULE, NULL, adapter_nr) ||
 			THIS_MODULE, NULL, adapter_nr) ||
 	    0 == dvb_usb_device_init(intf, &dw2104_properties,
 	    0 == dvb_usb_device_init(intf, &dw2104_properties,
+			THIS_MODULE, NULL, adapter_nr) ||
+	    0 == dvb_usb_device_init(intf, &dw3101_properties,
 			THIS_MODULE, NULL, adapter_nr)) {
 			THIS_MODULE, NULL, adapter_nr)) {
 		return 0;
 		return 0;
 	}
 	}
@@ -833,6 +1092,8 @@ module_init(dw2102_module_init);
 module_exit(dw2102_module_exit);
 module_exit(dw2102_module_exit);
 
 
 MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
 MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
-MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device");
+MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
+				" DVB-C 3101 USB2.0,"
+				" TeVii S600, S650 USB2.0 devices");
 MODULE_VERSION("0.1");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 1 - 0
drivers/media/dvb/dvb-usb/dw2102.h

@@ -5,4 +5,5 @@
 #include "dvb-usb.h"
 #include "dvb-usb.h"
 
 
 #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
 #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
+#define deb_rc(args...)   dprintk(dvb_usb_dw2102_debug, 0x04, args)
 #endif
 #endif

+ 2 - 6
drivers/media/dvb/dvb-usb/gp8psk.c

@@ -223,7 +223,7 @@ static struct usb_device_id gp8psk_usb_table [] = {
 	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
 	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
 	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
 	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
 	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
 	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
-	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) },
+/*	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
 	    { 0 },
 	    { 0 },
 };
 };
 MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
 MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
@@ -254,7 +254,7 @@ static struct dvb_usb_device_properties gp8psk_properties = {
 
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 	.generic_bulk_ctrl_endpoint = 0x01,
 
 
-	.num_device_descs = 4,
+	.num_device_descs = 3,
 	.devices = {
 	.devices = {
 		{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
 		{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
 		  .cold_ids = { &gp8psk_usb_table[0], NULL },
 		  .cold_ids = { &gp8psk_usb_table[0], NULL },
@@ -268,10 +268,6 @@ static struct dvb_usb_device_properties gp8psk_properties = {
 		  .cold_ids = { NULL },
 		  .cold_ids = { NULL },
 		  .warm_ids = { &gp8psk_usb_table[3], NULL },
 		  .warm_ids = { &gp8psk_usb_table[3], NULL },
 		},
 		},
-		{ .name = "Genpix SkyWalker-CW3K DVB-S receiver",
-		  .cold_ids = { NULL },
-		  .warm_ids = { &gp8psk_usb_table[4], NULL },
-		},
 		{ NULL },
 		{ NULL },
 	}
 	}
 };
 };

+ 2 - 2
drivers/media/dvb/firewire/firedtv-rc.c

@@ -18,7 +18,7 @@
 #include "firedtv.h"
 #include "firedtv.h"
 
 
 /* fixed table with older keycodes, geared towards MythTV */
 /* fixed table with older keycodes, geared towards MythTV */
-const static u16 oldtable[] = {
+static const u16 oldtable[] = {
 
 
 	/* code from device: 0x4501...0x451f */
 	/* code from device: 0x4501...0x451f */
 
 
@@ -62,7 +62,7 @@ const static u16 oldtable[] = {
 };
 };
 
 
 /* user-modifiable table for a remote as sold in 2008 */
 /* user-modifiable table for a remote as sold in 2008 */
-const static u16 keytable[] = {
+static const u16 keytable[] = {
 
 
 	/* code from device: 0x0300...0x031f */
 	/* code from device: 0x0300...0x031f */
 
 

+ 22 - 0
drivers/media/dvb/frontends/Kconfig

@@ -35,6 +35,21 @@ config DVB_STB6100
 	  A Silicon tuner from ST used in conjunction with the STB0899
 	  A Silicon tuner from ST used in conjunction with the STB0899
 	  demodulator. Say Y when you want to support this tuner.
 	  demodulator. Say Y when you want to support this tuner.
 
 
+config DVB_STV090x
+	tristate "STV0900/STV0903(A/B) based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
+	  Say Y when you want to support these frontends.
+
+config DVB_STV6110x
+	tristate "STV6110/(A) based tuners"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A Silicon tuner that supports DVB-S and DVB-S2 modes
+
 comment "DVB-S (satellite) frontends"
 comment "DVB-S (satellite) frontends"
 	depends on DVB_CORE
 	depends on DVB_CORE
 
 
@@ -506,6 +521,13 @@ config DVB_ISL6421
 	help
 	help
 	  An SEC control chip.
 	  An SEC control chip.
 
 
+config DVB_ISL6423
+	tristate "ISL6423 SEC controller"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A SEC controller chip from Intersil
+
 config DVB_LGS8GL5
 config DVB_LGS8GL5
 	tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
 	tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
 	depends on DVB_CORE && I2C
 	depends on DVB_CORE && I2C

+ 3 - 1
drivers/media/dvb/frontends/Makefile

@@ -71,4 +71,6 @@ obj-$(CONFIG_DVB_STB6000) += stb6000.o
 obj-$(CONFIG_DVB_S921) += s921.o
 obj-$(CONFIG_DVB_S921) += s921.o
 obj-$(CONFIG_DVB_STV6110) += stv6110.o
 obj-$(CONFIG_DVB_STV6110) += stv6110.o
 obj-$(CONFIG_DVB_STV0900) += stv0900.o
 obj-$(CONFIG_DVB_STV0900) += stv0900.o
-
+obj-$(CONFIG_DVB_STV090x) += stv090x.o
+obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
+obj-$(CONFIG_DVB_ISL6423) += isl6423.o

+ 1 - 1
drivers/media/dvb/frontends/af9013.c

@@ -1455,7 +1455,7 @@ static int af9013_download_firmware(struct af9013_state *state)
 		af9013_ops.info.name);
 		af9013_ops.info.name);
 
 
 	/* request the firmware, this will block and timeout */
 	/* request the firmware, this will block and timeout */
-	ret = request_firmware(&fw, fw_file,  &state->i2c->dev);
+	ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
 	if (ret) {
 	if (ret) {
 		err("did not find the firmware file. (%s) "
 		err("did not find the firmware file. (%s) "
 			"Please see linux/Documentation/dvb/ for more details" \
 			"Please see linux/Documentation/dvb/ for more details" \

+ 92 - 6
drivers/media/dvb/frontends/au8522_dig.c

@@ -367,11 +367,90 @@ static struct {
 	{ 0x8231, 0x13 },
 	{ 0x8231, 0x13 },
 };
 };
 
 
-/* QAM Modulation table */
+/* QAM64 Modulation table */
 static struct {
 static struct {
 	u16 reg;
 	u16 reg;
 	u16 data;
 	u16 data;
-} QAM_mod_tab[] = {
+} QAM64_mod_tab[] = {
+	{ 0x00a3, 0x09 },
+	{ 0x00a4, 0x00 },
+	{ 0x0081, 0xc4 },
+	{ 0x00a5, 0x40 },
+	{ 0x00aa, 0x77 },
+	{ 0x00ad, 0x77 },
+	{ 0x00a6, 0x67 },
+	{ 0x0262, 0x20 },
+	{ 0x021c, 0x30 },
+	{ 0x00b8, 0x3e },
+	{ 0x00b9, 0xf0 },
+	{ 0x00ba, 0x01 },
+	{ 0x00bb, 0x18 },
+	{ 0x00bc, 0x50 },
+	{ 0x00bd, 0x00 },
+	{ 0x00be, 0xea },
+	{ 0x00bf, 0xef },
+	{ 0x00c0, 0xfc },
+	{ 0x00c1, 0xbd },
+	{ 0x00c2, 0x1f },
+	{ 0x00c3, 0xfc },
+	{ 0x00c4, 0xdd },
+	{ 0x00c5, 0xaf },
+	{ 0x00c6, 0x00 },
+	{ 0x00c7, 0x38 },
+	{ 0x00c8, 0x30 },
+	{ 0x00c9, 0x05 },
+	{ 0x00ca, 0x4a },
+	{ 0x00cb, 0xd0 },
+	{ 0x00cc, 0x01 },
+	{ 0x00cd, 0xd9 },
+	{ 0x00ce, 0x6f },
+	{ 0x00cf, 0xf9 },
+	{ 0x00d0, 0x70 },
+	{ 0x00d1, 0xdf },
+	{ 0x00d2, 0xf7 },
+	{ 0x00d3, 0xc2 },
+	{ 0x00d4, 0xdf },
+	{ 0x00d5, 0x02 },
+	{ 0x00d6, 0x9a },
+	{ 0x00d7, 0xd0 },
+	{ 0x0250, 0x0d },
+	{ 0x0251, 0xcd },
+	{ 0x0252, 0xe0 },
+	{ 0x0253, 0x05 },
+	{ 0x0254, 0xa7 },
+	{ 0x0255, 0xff },
+	{ 0x0256, 0xed },
+	{ 0x0257, 0x5b },
+	{ 0x0258, 0xae },
+	{ 0x0259, 0xe6 },
+	{ 0x025a, 0x3d },
+	{ 0x025b, 0x0f },
+	{ 0x025c, 0x0d },
+	{ 0x025d, 0xea },
+	{ 0x025e, 0xf2 },
+	{ 0x025f, 0x51 },
+	{ 0x0260, 0xf5 },
+	{ 0x0261, 0x06 },
+	{ 0x021a, 0x00 },
+	{ 0x0546, 0x40 },
+	{ 0x0210, 0xc7 },
+	{ 0x0211, 0xaa },
+	{ 0x0212, 0xab },
+	{ 0x0213, 0x02 },
+	{ 0x0502, 0x00 },
+	{ 0x0121, 0x04 },
+	{ 0x0122, 0x04 },
+	{ 0x052e, 0x10 },
+	{ 0x00a4, 0xca },
+	{ 0x00a7, 0x40 },
+	{ 0x0526, 0x01 },
+};
+
+/* QAM256 Modulation table */
+static struct {
+	u16 reg;
+	u16 data;
+} QAM256_mod_tab[] = {
 	{ 0x80a3, 0x09 },
 	{ 0x80a3, 0x09 },
 	{ 0x80a4, 0x00 },
 	{ 0x80a4, 0x00 },
 	{ 0x8081, 0xc4 },
 	{ 0x8081, 0xc4 },
@@ -464,12 +543,19 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
 		au8522_set_if(fe, state->config->vsb_if);
 		au8522_set_if(fe, state->config->vsb_if);
 		break;
 		break;
 	case QAM_64:
 	case QAM_64:
+		dprintk("%s() QAM 64\n", __func__);
+		for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
+			au8522_writereg(state,
+				QAM64_mod_tab[i].reg,
+				QAM64_mod_tab[i].data);
+		au8522_set_if(fe, state->config->qam_if);
+		break;
 	case QAM_256:
 	case QAM_256:
-		dprintk("%s() QAM 64/256\n", __func__);
-		for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++)
+		dprintk("%s() QAM 256\n", __func__);
+		for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
 			au8522_writereg(state,
 			au8522_writereg(state,
-				QAM_mod_tab[i].reg,
-				QAM_mod_tab[i].data);
+				QAM256_mod_tab[i].reg,
+				QAM256_mod_tab[i].data);
 		au8522_set_if(fe, state->config->qam_if);
 		au8522_set_if(fe, state->config->qam_if);
 		break;
 		break;
 	default:
 	default:

+ 1 - 1
drivers/media/dvb/frontends/cx24116.c

@@ -492,7 +492,7 @@ static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
 		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
 		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
 			__func__, CX24116_DEFAULT_FIRMWARE);
 			__func__, CX24116_DEFAULT_FIRMWARE);
 		ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
 		ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
-			&state->i2c->dev);
+			state->i2c->dev.parent);
 		printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
 		printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
 			__func__);
 			__func__);
 		if (ret) {
 		if (ret) {

+ 2 - 2
drivers/media/dvb/frontends/drx397xD.c

@@ -123,10 +123,10 @@ static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix)
 	}
 	}
 	memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
 	memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
 
 
-	if (request_firmware(&fw[ix].file, fw[ix].name, &s->i2c->dev) != 0) {
+	rc = request_firmware(&fw[ix].file, fw[ix].name, s->i2c->dev.parent);
+	if (rc != 0) {
 		printk(KERN_ERR "%s: Firmware \"%s\" not available\n",
 		printk(KERN_ERR "%s: Firmware \"%s\" not available\n",
 		       mod_name, fw[ix].name);
 		       mod_name, fw[ix].name);
-		rc = -ENOENT;
 		goto exit_err;
 		goto exit_err;
 	}
 	}
 
 

+ 308 - 0
drivers/media/dvb/frontends/isl6423.c

@@ -0,0 +1,308 @@
+/*
+	Intersil ISL6423 SEC and LNB Power supply controller
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6423.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+
+#define FE_ERROR				0
+#define FE_NOTICE				1
+#define FE_INFO					2
+#define FE_DEBUG				3
+#define FE_DEBUGREG				4
+
+#define dprintk(__y, __z, format, arg...) do {						\
+	if (__z) {									\
+		if	((verbose > FE_ERROR) && (verbose > __y))			\
+			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
+		else if	((verbose > FE_NOTICE) && (verbose > __y))			\
+			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
+		else if ((verbose > FE_INFO) && (verbose > __y))			\
+			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
+		else if ((verbose > FE_DEBUG) && (verbose > __y))			\
+			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
+	} else {									\
+		if (verbose > __y)							\
+			printk(format, ##arg);						\
+	}										\
+} while (0)
+
+struct isl6423_dev {
+	const struct isl6423_config	*config;
+	struct i2c_adapter		*i2c;
+
+	u8 reg_3;
+	u8 reg_4;
+
+	unsigned int verbose;
+};
+
+static int isl6423_write(struct isl6423_dev *isl6423, u8 reg)
+{
+	struct i2c_adapter *i2c = isl6423->i2c;
+	u8 addr			= isl6423->config->addr;
+	int err = 0;
+
+	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = &reg, .len = 1 };
+
+	dprintk(FE_DEBUG, 1, "write reg %02X", reg);
+	err = i2c_transfer(i2c, &msg, 1);
+	if (err < 0)
+		goto exit;
+	return 0;
+
+exit:
+	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+	return err;
+}
+
+static int isl6423_set_modulation(struct dvb_frontend *fe)
+{
+	struct isl6423_dev *isl6423		= (struct isl6423_dev *) fe->sec_priv;
+	const struct isl6423_config *config	= isl6423->config;
+	int err = 0;
+	u8 reg_2 = 0;
+
+	reg_2 = 0x01 << 5;
+
+	if (config->mod_extern)
+		reg_2 |= (1 << 3);
+	else
+		reg_2 |= (1 << 4);
+
+	err = isl6423_write(isl6423, reg_2);
+	if (err < 0)
+		goto exit;
+	return 0;
+
+exit:
+	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+	return err;
+}
+
+static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg)
+{
+	struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
+	u8 reg_3 = isl6423->reg_3;
+	u8 reg_4 = isl6423->reg_4;
+	int err = 0;
+
+	if (arg) {
+		/* EN = 1, VSPEN = 1, VBOT = 1 */
+		reg_4 |= (1 << 4);
+		reg_4 |= 0x1;
+		reg_3 |= (1 << 3);
+	} else {
+		/* EN = 1, VSPEN = 1, VBOT = 0 */
+		reg_4 |= (1 << 4);
+		reg_4 &= ~0x1;
+		reg_3 |= (1 << 3);
+	}
+	err = isl6423_write(isl6423, reg_3);
+	if (err < 0)
+		goto exit;
+
+	err = isl6423_write(isl6423, reg_4);
+	if (err < 0)
+		goto exit;
+
+	isl6423->reg_3 = reg_3;
+	isl6423->reg_4 = reg_4;
+
+	return 0;
+exit:
+	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+	return err;
+}
+
+
+static int isl6423_set_voltage(struct dvb_frontend *fe,
+			       enum fe_sec_voltage voltage)
+{
+	struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
+	u8 reg_3 = isl6423->reg_3;
+	u8 reg_4 = isl6423->reg_4;
+	int err = 0;
+
+	switch (voltage) {
+	case SEC_VOLTAGE_OFF:
+		/* EN = 0 */
+		reg_4 &= ~(1 << 4);
+		break;
+
+	case SEC_VOLTAGE_13:
+		/* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */
+		reg_4 |= (1 << 4);
+		reg_4 &= ~0x3;
+		reg_3 |= (1 << 3);
+		break;
+
+	case SEC_VOLTAGE_18:
+		/* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */
+		reg_4 |= (1 << 4);
+		reg_4 |=  0x2;
+		reg_4 &= ~0x1;
+		reg_3 |= (1 << 3);
+		break;
+
+	default:
+		break;
+	}
+	err = isl6423_write(isl6423, reg_3);
+	if (err < 0)
+		goto exit;
+
+	err = isl6423_write(isl6423, reg_4);
+	if (err < 0)
+		goto exit;
+
+	isl6423->reg_3 = reg_3;
+	isl6423->reg_4 = reg_4;
+
+	return 0;
+exit:
+	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+	return err;
+}
+
+static int isl6423_set_current(struct dvb_frontend *fe)
+{
+	struct isl6423_dev *isl6423		= (struct isl6423_dev *) fe->sec_priv;
+	u8 reg_3 = isl6423->reg_3;
+	const struct isl6423_config *config	= isl6423->config;
+	int err = 0;
+
+	switch (config->current_max) {
+	case SEC_CURRENT_275m:
+		/* 275mA */
+		/* ISELH = 0, ISELL = 0 */
+		reg_3 &= ~0x3;
+		break;
+
+	case SEC_CURRENT_515m:
+		/* 515mA */
+		/* ISELH = 0, ISELL = 1 */
+		reg_3 &= ~0x2;
+		reg_3 |=  0x1;
+		break;
+
+	case SEC_CURRENT_635m:
+		/* 635mA */
+		/* ISELH = 1, ISELL = 0 */
+		reg_3 &= ~0x1;
+		reg_3 |=  0x2;
+		break;
+
+	case SEC_CURRENT_800m:
+		/* 800mA */
+		/* ISELH = 1, ISELL = 1 */
+		reg_3 |= 0x3;
+		break;
+	}
+
+	err = isl6423_write(isl6423, reg_3);
+	if (err < 0)
+		goto exit;
+
+	switch (config->curlim) {
+	case SEC_CURRENT_LIM_ON:
+		/* DCL = 0 */
+		reg_3 &= ~0x10;
+		break;
+
+	case SEC_CURRENT_LIM_OFF:
+		/* DCL = 1 */
+		reg_3 |= 0x10;
+		break;
+	}
+
+	err = isl6423_write(isl6423, reg_3);
+	if (err < 0)
+		goto exit;
+
+	isl6423->reg_3 = reg_3;
+
+	return 0;
+exit:
+	dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+	return err;
+}
+
+static void isl6423_release(struct dvb_frontend *fe)
+{
+	isl6423_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+	kfree(fe->sec_priv);
+	fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter *i2c,
+				    const struct isl6423_config *config)
+{
+	struct isl6423_dev *isl6423;
+
+	isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL);
+	if (!isl6423)
+		return NULL;
+
+	isl6423->config	= config;
+	isl6423->i2c	= i2c;
+	fe->sec_priv	= isl6423;
+
+	/* SR3H = 0, SR3M = 1, SR3L = 0 */
+	isl6423->reg_3 = 0x02 << 5;
+	/* SR4H = 0, SR4M = 1, SR4L = 1 */
+	isl6423->reg_4 = 0x03 << 5;
+
+	if (isl6423_set_current(fe))
+		goto exit;
+
+	if (isl6423_set_modulation(fe))
+		goto exit;
+
+	fe->ops.release_sec		= isl6423_release;
+	fe->ops.set_voltage		= isl6423_set_voltage;
+	fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost;
+	isl6423->verbose		= verbose;
+
+	return fe;
+
+exit:
+	kfree(isl6423);
+	fe->sec_priv = NULL;
+	return NULL;
+}
+EXPORT_SYMBOL(isl6423_attach);
+
+MODULE_DESCRIPTION("ISL6423 SEC");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");

+ 63 - 0
drivers/media/dvb/frontends/isl6423.h

@@ -0,0 +1,63 @@
+/*
+	Intersil ISL6423 SEC and LNB Power supply controller
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __ISL_6423_H
+#define __ISL_6423_H
+
+#include <linux/dvb/frontend.h>
+
+enum isl6423_current {
+	SEC_CURRENT_275m = 0,
+	SEC_CURRENT_515m,
+	SEC_CURRENT_635m,
+	SEC_CURRENT_800m,
+};
+
+enum isl6423_curlim {
+	SEC_CURRENT_LIM_ON = 1,
+	SEC_CURRENT_LIM_OFF
+};
+
+struct isl6423_config {
+	enum isl6423_current current_max;
+	enum isl6423_curlim curlim;
+	u8 addr;
+	u8 mod_extern;
+};
+
+#if defined(CONFIG_DVB_ISL6423) || (defined(CONFIG_DVB_ISL6423_MODULE) && defined(MODULE))
+
+
+extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+					   struct i2c_adapter *i2c,
+					   const struct isl6423_config *config);
+
+#else
+static inline struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+						  struct i2c_adapter *i2c,
+						  const struct isl6423_config *config)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+#endif /* CONFIG_DVB_ISL6423 */
+
+#endif /* __ISL_6423_H */

+ 3 - 14
drivers/media/dvb/frontends/lgdt3305.c

@@ -19,6 +19,7 @@
  *
  *
  */
  */
 
 
+#include <asm/div64.h>
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/frontend.h>
 #include "dvb_math.h"
 #include "dvb_math.h"
 #include "lgdt3305.h"
 #include "lgdt3305.h"
@@ -496,27 +497,15 @@ static int lgdt3305_set_if(struct lgdt3305_state *state,
 
 
 	nco = if_freq_khz / 10;
 	nco = if_freq_khz / 10;
 
 
-#define LGDT3305_64BIT_DIVISION_ENABLED 0
-	/* FIXME: 64bit division disabled to avoid linking error:
-	 * WARNING: "__udivdi3" [lgdt3305.ko] undefined!
-	 */
 	switch (param->u.vsb.modulation) {
 	switch (param->u.vsb.modulation) {
 	case VSB_8:
 	case VSB_8:
-#if LGDT3305_64BIT_DIVISION_ENABLED
 		nco <<= 24;
 		nco <<= 24;
-		nco /= 625;
-#else
-		nco *= ((1 << 24) / 625);
-#endif
+		do_div(nco, 625);
 		break;
 		break;
 	case QAM_64:
 	case QAM_64:
 	case QAM_256:
 	case QAM_256:
-#if LGDT3305_64BIT_DIVISION_ENABLED
 		nco <<= 28;
 		nco <<= 28;
-		nco /= 625;
-#else
-		nco *= ((1 << 28) / 625);
-#endif
+		do_div(nco, 625);
 		break;
 		break;
 	default:
 	default:
 		return -EINVAL;
 		return -EINVAL;

+ 5 - 5
drivers/media/dvb/frontends/lgs8gxx.c

@@ -37,14 +37,14 @@
 	} while (0)
 	} while (0)
 
 
 static int debug;
 static int debug;
-static int fake_signal_str;
+static int fake_signal_str = 1;
 
 
 module_param(debug, int, 0644);
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
 
 module_param(fake_signal_str, int, 0644);
 module_param(fake_signal_str, int, 0644);
 MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
 MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
-"Signal strength calculation is slow.(default:off).");
+"Signal strength calculation is slow.(default:on).");
 
 
 /* LGS8GXX internal helper functions */
 /* LGS8GXX internal helper functions */
 
 
@@ -610,7 +610,7 @@ static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal)
 	else
 	else
 		cat = 0;
 		cat = 0;
 
 
-	*signal = cat;
+	*signal = cat * 65535 / 5;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -630,8 +630,8 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
 
 
 	if (fake_signal_str) {
 	if (fake_signal_str) {
 		if ((t & 0xC0) == 0xC0) {
 		if ((t & 0xC0) == 0xC0) {
-			dprintk("Fake signal strength as 50\n");
-			*signal = 0x32;
+			dprintk("Fake signal strength\n");
+			*signal = 0x7FFF;
 		} else
 		} else
 			*signal = 0;
 			*signal = 0;
 		return 0;
 		return 0;

+ 1 - 1
drivers/media/dvb/frontends/lnbp21.c

@@ -133,7 +133,7 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
 	/* override frontend ops */
 	/* override frontend ops */
 	fe->ops.set_voltage = lnbp21_set_voltage;
 	fe->ops.set_voltage = lnbp21_set_voltage;
 	fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
 	fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-	printk(KERN_INFO "LNBx2x attached on addr=%x", lnbp21->i2c_addr);
+	printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
 
 
 	return fe;
 	return fe;
 }
 }

+ 1 - 1
drivers/media/dvb/frontends/mt312.c

@@ -77,7 +77,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
 	ret = i2c_transfer(state->i2c, msg, 2);
 	ret = i2c_transfer(state->i2c, msg, 2);
 
 
 	if (ret != 2) {
 	if (ret != 2) {
-		printk(KERN_ERR "%s: ret == %d\n", __func__, ret);
+		printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret);
 		return -EREMOTEIO;
 		return -EREMOTEIO;
 	}
 	}
 
 

+ 4 - 2
drivers/media/dvb/frontends/nxt200x.c

@@ -879,7 +879,8 @@ static int nxt2002_init(struct dvb_frontend* fe)
 
 
 	/* request the firmware, this will block until someone uploads it */
 	/* request the firmware, this will block until someone uploads it */
 	printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
 	printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
-	ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, &state->i2c->dev);
+	ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE,
+			       state->i2c->dev.parent);
 	printk("nxt2002: Waiting for firmware upload(2)...\n");
 	printk("nxt2002: Waiting for firmware upload(2)...\n");
 	if (ret) {
 	if (ret) {
 		printk("nxt2002: No firmware uploaded (timeout or file not found?)\n");
 		printk("nxt2002: No firmware uploaded (timeout or file not found?)\n");
@@ -943,7 +944,8 @@ static int nxt2004_init(struct dvb_frontend* fe)
 
 
 	/* request the firmware, this will block until someone uploads it */
 	/* request the firmware, this will block until someone uploads it */
 	printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE);
 	printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE);
-	ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, &state->i2c->dev);
+	ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE,
+			       state->i2c->dev.parent);
 	printk("nxt2004: Waiting for firmware upload(2)...\n");
 	printk("nxt2004: Waiting for firmware upload(2)...\n");
 	if (ret) {
 	if (ret) {
 		printk("nxt2004: No firmware uploaded (timeout or file not found?)\n");
 		printk("nxt2004: No firmware uploaded (timeout or file not found?)\n");

+ 1 - 1
drivers/media/dvb/frontends/or51132.c

@@ -340,7 +340,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
 		}
 		}
 		printk("or51132: Waiting for firmware upload(%s)...\n",
 		printk("or51132: Waiting for firmware upload(%s)...\n",
 		       fwname);
 		       fwname);
-		ret = request_firmware(&fw, fwname, &state->i2c->dev);
+		ret = request_firmware(&fw, fwname, state->i2c->dev.parent);
 		if (ret) {
 		if (ret) {
 			printk(KERN_WARNING "or51132: No firmware up"
 			printk(KERN_WARNING "or51132: No firmware up"
 			       "loaded(timeout or file not found?)\n");
 			       "loaded(timeout or file not found?)\n");

+ 0 - 2
drivers/media/dvb/frontends/stv0900_priv.h

@@ -60,8 +60,6 @@
 		} \
 		} \
 	} while (0)
 	} while (0)
 
 
-#define dmd_choose(a, b)	(demod = STV0900_DEMOD_2 ? b : a))
-
 static int stvdebug;
 static int stvdebug;
 
 
 #define dprintk(args...) \
 #define dprintk(args...) \

+ 4299 - 0
drivers/media/dvb/frontends/stv090x.c

@@ -0,0 +1,4299 @@
+/*
+	STV0900/0903 Multistandard Broadcast Frontend driver
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#include "stv6110x.h" /* for demodulator internal modes */
+
+#include "stv090x_reg.h"
+#include "stv090x.h"
+#include "stv090x_priv.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+
+struct mutex demod_lock;
+
+/* DVBS1 and DSS C/N Lookup table */
+static const struct stv090x_tab stv090x_s1cn_tab[] = {
+	{   0, 8917 }, /*  0.0dB */
+	{   5, 8801 }, /*  0.5dB */
+	{  10, 8667 }, /*  1.0dB */
+	{  15, 8522 }, /*  1.5dB */
+	{  20, 8355 }, /*  2.0dB */
+	{  25, 8175 }, /*  2.5dB */
+	{  30, 7979 }, /*  3.0dB */
+	{  35, 7763 }, /*  3.5dB */
+	{  40, 7530 }, /*  4.0dB */
+	{  45, 7282 }, /*  4.5dB */
+	{  50, 7026 }, /*  5.0dB */
+	{  55, 6781 }, /*  5.5dB */
+	{  60, 6514 }, /*  6.0dB */
+	{  65, 6241 }, /*  6.5dB */
+	{  70, 5965 }, /*  7.0dB */
+	{  75, 5690 }, /*  7.5dB */
+	{  80, 5424 }, /*  8.0dB */
+	{  85, 5161 }, /*  8.5dB */
+	{  90, 4902 }, /*  9.0dB */
+	{  95, 4654 }, /*  9.5dB */
+	{ 100, 4417 }, /* 10.0dB */
+	{ 105, 4186 }, /* 10.5dB */
+	{ 110, 3968 }, /* 11.0dB */
+	{ 115, 3757 }, /* 11.5dB */
+	{ 120, 3558 }, /* 12.0dB */
+	{ 125, 3366 }, /* 12.5dB */
+	{ 130, 3185 }, /* 13.0dB */
+	{ 135, 3012 }, /* 13.5dB */
+	{ 140, 2850 }, /* 14.0dB */
+	{ 145, 2698 }, /* 14.5dB */
+	{ 150, 2550 }, /* 15.0dB */
+	{ 160, 2283 }, /* 16.0dB */
+	{ 170, 2042 }, /* 17.0dB */
+	{ 180, 1827 }, /* 18.0dB */
+	{ 190, 1636 }, /* 19.0dB */
+	{ 200, 1466 }, /* 20.0dB */
+	{ 210, 1315 }, /* 21.0dB */
+	{ 220, 1181 }, /* 22.0dB */
+	{ 230, 1064 }, /* 23.0dB */
+	{ 240,	960 }, /* 24.0dB */
+	{ 250,	869 }, /* 25.0dB */
+	{ 260,	792 }, /* 26.0dB */
+	{ 270,	724 }, /* 27.0dB */
+	{ 280,	665 }, /* 28.0dB */
+	{ 290,	616 }, /* 29.0dB */
+	{ 300,	573 }, /* 30.0dB */
+	{ 310,	537 }, /* 31.0dB */
+	{ 320,	507 }, /* 32.0dB */
+	{ 330,	483 }, /* 33.0dB */
+	{ 400,	398 }, /* 40.0dB */
+	{ 450,	381 }, /* 45.0dB */
+	{ 500,	377 }  /* 50.0dB */
+};
+
+/* DVBS2 C/N Lookup table */
+static const struct stv090x_tab stv090x_s2cn_tab[] = {
+	{ -30, 13348 }, /* -3.0dB */
+	{ -20, 12640 }, /* -2d.0B */
+	{ -10, 11883 }, /* -1.0dB */
+	{   0, 11101 }, /* -0.0dB */
+	{   5, 10718 }, /*  0.5dB */
+	{  10, 10339 }, /*  1.0dB */
+	{  15,  9947 }, /*  1.5dB */
+	{  20,  9552 }, /*  2.0dB */
+	{  25,  9183 }, /*  2.5dB */
+	{  30,  8799 }, /*  3.0dB */
+	{  35,  8422 }, /*  3.5dB */
+	{  40,  8062 }, /*  4.0dB */
+	{  45,  7707 }, /*  4.5dB */
+	{  50,  7353 }, /*  5.0dB */
+	{  55,  7025 }, /*  5.5dB */
+	{  60,  6684 }, /*  6.0dB */
+	{  65,  6331 }, /*  6.5dB */
+	{  70,  6036 }, /*  7.0dB */
+	{  75,  5727 }, /*  7.5dB */
+	{  80,  5437 }, /*  8.0dB */
+	{  85,  5164 }, /*  8.5dB */
+	{  90,  4902 }, /*  9.0dB */
+	{  95,  4653 }, /*  9.5dB */
+	{ 100,  4408 }, /* 10.0dB */
+	{ 105,  4187 }, /* 10.5dB */
+	{ 110,  3961 }, /* 11.0dB */
+	{ 115,  3751 }, /* 11.5dB */
+	{ 120,  3558 }, /* 12.0dB */
+	{ 125,  3368 }, /* 12.5dB */
+	{ 130,  3191 }, /* 13.0dB */
+	{ 135,  3017 }, /* 13.5dB */
+	{ 140,  2862 }, /* 14.0dB */
+	{ 145,  2710 }, /* 14.5dB */
+	{ 150,  2565 }, /* 15.0dB */
+	{ 160,  2300 }, /* 16.0dB */
+	{ 170,  2058 }, /* 17.0dB */
+	{ 180,  1849 }, /* 18.0dB */
+	{ 190,  1663 }, /* 19.0dB */
+	{ 200,  1495 }, /* 20.0dB */
+	{ 210,  1349 }, /* 21.0dB */
+	{ 220,  1222 }, /* 22.0dB */
+	{ 230,  1110 }, /* 23.0dB */
+	{ 240,  1011 }, /* 24.0dB */
+	{ 250,   925 }, /* 25.0dB */
+	{ 260,   853 }, /* 26.0dB */
+	{ 270,   789 }, /* 27.0dB */
+	{ 280,   734 }, /* 28.0dB */
+	{ 290,   690 }, /* 29.0dB */
+	{ 300,   650 }, /* 30.0dB */
+	{ 310,   619 }, /* 31.0dB */
+	{ 320,   593 }, /* 32.0dB */
+	{ 330,   571 }, /* 33.0dB */
+	{ 400,   498 }, /* 40.0dB */
+	{ 450,	 484 }, /* 45.0dB */
+	{ 500,	 481 }	/* 50.0dB */
+};
+
+/* RF level C/N lookup table */
+static const struct stv090x_tab stv090x_rf_tab[] = {
+	{  -5, 0xcaa1 }, /*  -5dBm */
+	{ -10, 0xc229 }, /* -10dBm */
+	{ -15, 0xbb08 }, /* -15dBm */
+	{ -20, 0xb4bc }, /* -20dBm */
+	{ -25, 0xad5a }, /* -25dBm */
+	{ -30, 0xa298 }, /* -30dBm */
+	{ -35, 0x98a8 }, /* -35dBm */
+	{ -40, 0x8389 }, /* -40dBm */
+	{ -45, 0x59be }, /* -45dBm */
+	{ -50, 0x3a14 }, /* -50dBm */
+	{ -55, 0x2d11 }, /* -55dBm */
+	{ -60, 0x210d }, /* -60dBm */
+	{ -65, 0xa14f }, /* -65dBm */
+	{ -70, 0x07aa }	 /* -70dBm */
+};
+
+
+static struct stv090x_reg stv0900_initval[] = {
+
+	{ STV090x_OUTCFG,		0x00 },
+	{ STV090x_MODECFG,		0xff },
+	{ STV090x_AGCRF1CFG,		0x11 },
+	{ STV090x_AGCRF2CFG,		0x13 },
+	{ STV090x_TSGENERAL1X,		0x14 },
+	{ STV090x_TSTTNR2,		0x21 },
+	{ STV090x_TSTTNR4,		0x21 },
+	{ STV090x_P2_DISTXCTL,		0x22 },
+	{ STV090x_P2_F22TX,		0xc0 },
+	{ STV090x_P2_F22RX,		0xc0 },
+	{ STV090x_P2_DISRXCTL,		0x00 },
+	{ STV090x_P2_DMDCFGMD,		0xF9 },
+	{ STV090x_P2_DEMOD,		0x08 },
+	{ STV090x_P2_DMDCFG3,		0xc4 },
+	{ STV090x_P2_CARFREQ,		0xed },
+	{ STV090x_P2_LDT,		0xd0 },
+	{ STV090x_P2_LDT2,		0xb8 },
+	{ STV090x_P2_TMGCFG,		0xd2 },
+	{ STV090x_P2_TMGTHRISE,		0x20 },
+	{ STV090x_P1_TMGCFG,		0xd2 },
+
+	{ STV090x_P2_TMGTHFALL,		0x00 },
+	{ STV090x_P2_FECSPY,		0x88 },
+	{ STV090x_P2_FSPYDATA,		0x3a },
+	{ STV090x_P2_FBERCPT4,		0x00 },
+	{ STV090x_P2_FSPYBER,		0x10 },
+	{ STV090x_P2_ERRCTRL1,		0x35 },
+	{ STV090x_P2_ERRCTRL2,		0xc1 },
+	{ STV090x_P2_CFRICFG,		0xf8 },
+	{ STV090x_P2_NOSCFG,		0x1c },
+	{ STV090x_P2_DMDTOM,		0x20 },
+	{ STV090x_P2_CORRELMANT,	0x70 },
+	{ STV090x_P2_CORRELABS,		0x88 },
+	{ STV090x_P2_AGC2O,		0x5b },
+	{ STV090x_P2_AGC2REF,		0x38 },
+	{ STV090x_P2_CARCFG,		0xe4 },
+	{ STV090x_P2_ACLC,		0x1A },
+	{ STV090x_P2_BCLC,		0x09 },
+	{ STV090x_P2_CARHDR,		0x08 },
+	{ STV090x_P2_KREFTMG,		0xc1 },
+	{ STV090x_P2_SFRUPRATIO,	0xf0 },
+	{ STV090x_P2_SFRLOWRATIO,	0x70 },
+	{ STV090x_P2_SFRSTEP,		0x58 },
+	{ STV090x_P2_TMGCFG2,		0x01 },
+	{ STV090x_P2_CAR2CFG,		0x26 },
+	{ STV090x_P2_BCLC2S2Q,		0x86 },
+	{ STV090x_P2_BCLC2S28,		0x86 },
+	{ STV090x_P2_SMAPCOEF7,		0x77 },
+	{ STV090x_P2_SMAPCOEF6,		0x85 },
+	{ STV090x_P2_SMAPCOEF5,		0x77 },
+	{ STV090x_P2_TSCFGL,		0x20 },
+	{ STV090x_P2_DMDCFG2,		0x3b },
+	{ STV090x_P2_MODCODLST0,	0xff },
+	{ STV090x_P2_MODCODLST1,	0xff },
+	{ STV090x_P2_MODCODLST2,	0xff },
+	{ STV090x_P2_MODCODLST3,	0xff },
+	{ STV090x_P2_MODCODLST4,	0xff },
+	{ STV090x_P2_MODCODLST5,	0xff },
+	{ STV090x_P2_MODCODLST6,	0xff },
+	{ STV090x_P2_MODCODLST7,	0xcc },
+	{ STV090x_P2_MODCODLST8,	0xcc },
+	{ STV090x_P2_MODCODLST9,	0xcc },
+	{ STV090x_P2_MODCODLSTA,	0xcc },
+	{ STV090x_P2_MODCODLSTB,	0xcc },
+	{ STV090x_P2_MODCODLSTC,	0xcc },
+	{ STV090x_P2_MODCODLSTD,	0xcc },
+	{ STV090x_P2_MODCODLSTE,	0xcc },
+	{ STV090x_P2_MODCODLSTF,	0xcf },
+	{ STV090x_P1_DISTXCTL,		0x22 },
+	{ STV090x_P1_F22TX,		0xc0 },
+	{ STV090x_P1_F22RX,		0xc0 },
+	{ STV090x_P1_DISRXCTL,		0x00 },
+	{ STV090x_P1_DMDCFGMD,		0xf9 },
+	{ STV090x_P1_DEMOD,		0x08 },
+	{ STV090x_P1_DMDCFG3,		0xc4 },
+	{ STV090x_P1_DMDTOM,		0x20 },
+	{ STV090x_P1_CARFREQ,		0xed },
+	{ STV090x_P1_LDT,		0xd0 },
+	{ STV090x_P1_LDT2,		0xb8 },
+	{ STV090x_P1_TMGCFG,		0xd2 },
+	{ STV090x_P1_TMGTHRISE,		0x20 },
+	{ STV090x_P1_TMGTHFALL,		0x00 },
+	{ STV090x_P1_SFRUPRATIO,	0xf0 },
+	{ STV090x_P1_SFRLOWRATIO,	0x70 },
+	{ STV090x_P1_TSCFGL,		0x20 },
+	{ STV090x_P1_FECSPY,		0x88 },
+	{ STV090x_P1_FSPYDATA,		0x3a },
+	{ STV090x_P1_FBERCPT4,		0x00 },
+	{ STV090x_P1_FSPYBER,		0x10 },
+	{ STV090x_P1_ERRCTRL1,		0x35 },
+	{ STV090x_P1_ERRCTRL2,		0xc1 },
+	{ STV090x_P1_CFRICFG,		0xf8 },
+	{ STV090x_P1_NOSCFG,		0x1c },
+	{ STV090x_P1_CORRELMANT,	0x70 },
+	{ STV090x_P1_CORRELABS,		0x88 },
+	{ STV090x_P1_AGC2O,		0x5b },
+	{ STV090x_P1_AGC2REF,		0x38 },
+	{ STV090x_P1_CARCFG,		0xe4 },
+	{ STV090x_P1_ACLC,		0x1A },
+	{ STV090x_P1_BCLC,		0x09 },
+	{ STV090x_P1_CARHDR,		0x08 },
+	{ STV090x_P1_KREFTMG,		0xc1 },
+	{ STV090x_P1_SFRSTEP,		0x58 },
+	{ STV090x_P1_TMGCFG2,		0x01 },
+	{ STV090x_P1_CAR2CFG,		0x26 },
+	{ STV090x_P1_BCLC2S2Q,		0x86 },
+	{ STV090x_P1_BCLC2S28,		0x86 },
+	{ STV090x_P1_SMAPCOEF7,		0x77 },
+	{ STV090x_P1_SMAPCOEF6,		0x85 },
+	{ STV090x_P1_SMAPCOEF5,		0x77 },
+	{ STV090x_P1_DMDCFG2,		0x3b },
+	{ STV090x_P1_MODCODLST0,	0xff },
+	{ STV090x_P1_MODCODLST1,	0xff },
+	{ STV090x_P1_MODCODLST2,	0xff },
+	{ STV090x_P1_MODCODLST3,	0xff },
+	{ STV090x_P1_MODCODLST4,	0xff },
+	{ STV090x_P1_MODCODLST5,	0xff },
+	{ STV090x_P1_MODCODLST6,	0xff },
+	{ STV090x_P1_MODCODLST7,	0xcc },
+	{ STV090x_P1_MODCODLST8,	0xcc },
+	{ STV090x_P1_MODCODLST9,	0xcc },
+	{ STV090x_P1_MODCODLSTA,	0xcc },
+	{ STV090x_P1_MODCODLSTB,	0xcc },
+	{ STV090x_P1_MODCODLSTC,	0xcc },
+	{ STV090x_P1_MODCODLSTD,	0xcc },
+	{ STV090x_P1_MODCODLSTE,	0xcc },
+	{ STV090x_P1_MODCODLSTF,	0xcf },
+	{ STV090x_GENCFG,		0x1d },
+	{ STV090x_NBITER_NF4,		0x37 },
+	{ STV090x_NBITER_NF5,		0x29 },
+	{ STV090x_NBITER_NF6,		0x37 },
+	{ STV090x_NBITER_NF7,		0x33 },
+	{ STV090x_NBITER_NF8,		0x31 },
+	{ STV090x_NBITER_NF9,		0x2f },
+	{ STV090x_NBITER_NF10,		0x39 },
+	{ STV090x_NBITER_NF11,		0x3a },
+	{ STV090x_NBITER_NF12,		0x29 },
+	{ STV090x_NBITER_NF13,		0x37 },
+	{ STV090x_NBITER_NF14,		0x33 },
+	{ STV090x_NBITER_NF15,		0x2f },
+	{ STV090x_NBITER_NF16,		0x39 },
+	{ STV090x_NBITER_NF17,		0x3a },
+	{ STV090x_NBITERNOERR,		0x04 },
+	{ STV090x_GAINLLR_NF4,		0x0C },
+	{ STV090x_GAINLLR_NF5,		0x0F },
+	{ STV090x_GAINLLR_NF6,		0x11 },
+	{ STV090x_GAINLLR_NF7,		0x14 },
+	{ STV090x_GAINLLR_NF8,		0x17 },
+	{ STV090x_GAINLLR_NF9,		0x19 },
+	{ STV090x_GAINLLR_NF10,		0x20 },
+	{ STV090x_GAINLLR_NF11,		0x21 },
+	{ STV090x_GAINLLR_NF12,		0x0D },
+	{ STV090x_GAINLLR_NF13,		0x0F },
+	{ STV090x_GAINLLR_NF14,		0x13 },
+	{ STV090x_GAINLLR_NF15,		0x1A },
+	{ STV090x_GAINLLR_NF16,		0x1F },
+	{ STV090x_GAINLLR_NF17,		0x21 },
+	{ STV090x_RCCFGH,		0x20 },
+	{ STV090x_P1_FECM,		0x01 }, /* disable DSS modes */
+	{ STV090x_P2_FECM,		0x01 }, /* disable DSS modes */
+	{ STV090x_P1_PRVIT,		0x2F }, /* disable PR 6/7 */
+	{ STV090x_P2_PRVIT,		0x2F }, /* disable PR 6/7 */
+};
+
+static struct stv090x_reg stv0903_initval[] = {
+	{ STV090x_OUTCFG,		0x00 },
+	{ STV090x_AGCRF1CFG,		0x11 },
+	{ STV090x_STOPCLK1,		0x48 },
+	{ STV090x_STOPCLK2,		0x14 },
+	{ STV090x_TSTTNR1,		0x27 },
+	{ STV090x_TSTTNR2,		0x21 },
+	{ STV090x_P1_DISTXCTL,		0x22 },
+	{ STV090x_P1_F22TX,		0xc0 },
+	{ STV090x_P1_F22RX,		0xc0 },
+	{ STV090x_P1_DISRXCTL,		0x00 },
+	{ STV090x_P1_DMDCFGMD,		0xF9 },
+	{ STV090x_P1_DEMOD,		0x08 },
+	{ STV090x_P1_DMDCFG3,		0xc4 },
+	{ STV090x_P1_CARFREQ,		0xed },
+	{ STV090x_P1_TNRCFG2,		0x82 },
+	{ STV090x_P1_LDT,		0xd0 },
+	{ STV090x_P1_LDT2,		0xb8 },
+	{ STV090x_P1_TMGCFG,		0xd2 },
+	{ STV090x_P1_TMGTHRISE,		0x20 },
+	{ STV090x_P1_TMGTHFALL,		0x00 },
+	{ STV090x_P1_SFRUPRATIO,	0xf0 },
+	{ STV090x_P1_SFRLOWRATIO,	0x70 },
+	{ STV090x_P1_TSCFGL,		0x20 },
+	{ STV090x_P1_FECSPY,		0x88 },
+	{ STV090x_P1_FSPYDATA,		0x3a },
+	{ STV090x_P1_FBERCPT4,		0x00 },
+	{ STV090x_P1_FSPYBER,		0x10 },
+	{ STV090x_P1_ERRCTRL1,		0x35 },
+	{ STV090x_P1_ERRCTRL2,		0xc1 },
+	{ STV090x_P1_CFRICFG,		0xf8 },
+	{ STV090x_P1_NOSCFG,		0x1c },
+	{ STV090x_P1_DMDTOM,		0x20 },
+	{ STV090x_P1_CORRELMANT,	0x70 },
+	{ STV090x_P1_CORRELABS,		0x88 },
+	{ STV090x_P1_AGC2O,		0x5b },
+	{ STV090x_P1_AGC2REF,		0x38 },
+	{ STV090x_P1_CARCFG,		0xe4 },
+	{ STV090x_P1_ACLC,		0x1A },
+	{ STV090x_P1_BCLC,		0x09 },
+	{ STV090x_P1_CARHDR,		0x08 },
+	{ STV090x_P1_KREFTMG,		0xc1 },
+	{ STV090x_P1_SFRSTEP,		0x58 },
+	{ STV090x_P1_TMGCFG2,		0x01 },
+	{ STV090x_P1_CAR2CFG,		0x26 },
+	{ STV090x_P1_BCLC2S2Q,		0x86 },
+	{ STV090x_P1_BCLC2S28,		0x86 },
+	{ STV090x_P1_SMAPCOEF7,		0x77 },
+	{ STV090x_P1_SMAPCOEF6,		0x85 },
+	{ STV090x_P1_SMAPCOEF5,		0x77 },
+	{ STV090x_P1_DMDCFG2,		0x3b },
+	{ STV090x_P1_MODCODLST0,	0xff },
+	{ STV090x_P1_MODCODLST1,	0xff },
+	{ STV090x_P1_MODCODLST2,	0xff },
+	{ STV090x_P1_MODCODLST3,	0xff },
+	{ STV090x_P1_MODCODLST4,	0xff },
+	{ STV090x_P1_MODCODLST5,	0xff },
+	{ STV090x_P1_MODCODLST6,	0xff },
+	{ STV090x_P1_MODCODLST7,	0xcc },
+	{ STV090x_P1_MODCODLST8,	0xcc },
+	{ STV090x_P1_MODCODLST9,	0xcc },
+	{ STV090x_P1_MODCODLSTA,	0xcc },
+	{ STV090x_P1_MODCODLSTB,	0xcc },
+	{ STV090x_P1_MODCODLSTC,	0xcc },
+	{ STV090x_P1_MODCODLSTD,	0xcc },
+	{ STV090x_P1_MODCODLSTE,	0xcc },
+	{ STV090x_P1_MODCODLSTF,	0xcf },
+	{ STV090x_GENCFG,		0x1c },
+	{ STV090x_NBITER_NF4,		0x37 },
+	{ STV090x_NBITER_NF5,		0x29 },
+	{ STV090x_NBITER_NF6,		0x37 },
+	{ STV090x_NBITER_NF7,		0x33 },
+	{ STV090x_NBITER_NF8,		0x31 },
+	{ STV090x_NBITER_NF9,		0x2f },
+	{ STV090x_NBITER_NF10,		0x39 },
+	{ STV090x_NBITER_NF11,		0x3a },
+	{ STV090x_NBITER_NF12,		0x29 },
+	{ STV090x_NBITER_NF13,		0x37 },
+	{ STV090x_NBITER_NF14,		0x33 },
+	{ STV090x_NBITER_NF15,		0x2f },
+	{ STV090x_NBITER_NF16,		0x39 },
+	{ STV090x_NBITER_NF17,		0x3a },
+	{ STV090x_NBITERNOERR,		0x04 },
+	{ STV090x_GAINLLR_NF4,		0x0C },
+	{ STV090x_GAINLLR_NF5,		0x0F },
+	{ STV090x_GAINLLR_NF6,		0x11 },
+	{ STV090x_GAINLLR_NF7,		0x14 },
+	{ STV090x_GAINLLR_NF8,		0x17 },
+	{ STV090x_GAINLLR_NF9,		0x19 },
+	{ STV090x_GAINLLR_NF10,		0x20 },
+	{ STV090x_GAINLLR_NF11,		0x21 },
+	{ STV090x_GAINLLR_NF12,		0x0D },
+	{ STV090x_GAINLLR_NF13,		0x0F },
+	{ STV090x_GAINLLR_NF14,		0x13 },
+	{ STV090x_GAINLLR_NF15,		0x1A },
+	{ STV090x_GAINLLR_NF16,		0x1F },
+	{ STV090x_GAINLLR_NF17,		0x21 },
+	{ STV090x_RCCFGH,		0x20 },
+	{ STV090x_P1_FECM,		0x01 }, /*disable the DSS mode */
+	{ STV090x_P1_PRVIT,		0x2f }  /*disable puncture rate 6/7*/
+};
+
+static struct stv090x_reg stv0900_cut20_val[] = {
+
+	{ STV090x_P2_DMDCFG3,		0xe8 },
+	{ STV090x_P2_DMDCFG4,		0x10 },
+	{ STV090x_P2_CARFREQ,		0x38 },
+	{ STV090x_P2_CARHDR,		0x20 },
+	{ STV090x_P2_KREFTMG,		0x5a },
+	{ STV090x_P2_SMAPCOEF7,		0x06 },
+	{ STV090x_P2_SMAPCOEF6,		0x00 },
+	{ STV090x_P2_SMAPCOEF5,		0x04 },
+	{ STV090x_P2_NOSCFG,		0x0c },
+	{ STV090x_P1_DMDCFG3,		0xe8 },
+	{ STV090x_P1_DMDCFG4,		0x10 },
+	{ STV090x_P1_CARFREQ,		0x38 },
+	{ STV090x_P1_CARHDR,		0x20 },
+	{ STV090x_P1_KREFTMG,		0x5a },
+	{ STV090x_P1_SMAPCOEF7,		0x06 },
+	{ STV090x_P1_SMAPCOEF6,		0x00 },
+	{ STV090x_P1_SMAPCOEF5,		0x04 },
+	{ STV090x_P1_NOSCFG,		0x0c },
+	{ STV090x_GAINLLR_NF4,		0x21 },
+	{ STV090x_GAINLLR_NF5,		0x21 },
+	{ STV090x_GAINLLR_NF6,		0x20 },
+	{ STV090x_GAINLLR_NF7,		0x1F },
+	{ STV090x_GAINLLR_NF8,		0x1E },
+	{ STV090x_GAINLLR_NF9,		0x1E },
+	{ STV090x_GAINLLR_NF10,		0x1D },
+	{ STV090x_GAINLLR_NF11,		0x1B },
+	{ STV090x_GAINLLR_NF12,		0x20 },
+	{ STV090x_GAINLLR_NF13,		0x20 },
+	{ STV090x_GAINLLR_NF14,		0x20 },
+	{ STV090x_GAINLLR_NF15,		0x20 },
+	{ STV090x_GAINLLR_NF16,		0x20 },
+	{ STV090x_GAINLLR_NF17,		0x21 },
+};
+
+static struct stv090x_reg stv0903_cut20_val[] = {
+	{ STV090x_P1_DMDCFG3,		0xe8 },
+	{ STV090x_P1_DMDCFG4,		0x10 },
+	{ STV090x_P1_CARFREQ,		0x38 },
+	{ STV090x_P1_CARHDR,		0x20 },
+	{ STV090x_P1_KREFTMG,		0x5a },
+	{ STV090x_P1_SMAPCOEF7,		0x06 },
+	{ STV090x_P1_SMAPCOEF6,		0x00 },
+	{ STV090x_P1_SMAPCOEF5,		0x04 },
+	{ STV090x_P1_NOSCFG,		0x0c },
+	{ STV090x_GAINLLR_NF4,		0x21 },
+	{ STV090x_GAINLLR_NF5,		0x21 },
+	{ STV090x_GAINLLR_NF6,		0x20 },
+	{ STV090x_GAINLLR_NF7,		0x1F },
+	{ STV090x_GAINLLR_NF8,		0x1E },
+	{ STV090x_GAINLLR_NF9,		0x1E },
+	{ STV090x_GAINLLR_NF10,		0x1D },
+	{ STV090x_GAINLLR_NF11,		0x1B },
+	{ STV090x_GAINLLR_NF12,		0x20 },
+	{ STV090x_GAINLLR_NF13,		0x20 },
+	{ STV090x_GAINLLR_NF14,		0x20 },
+	{ STV090x_GAINLLR_NF15,		0x20 },
+	{ STV090x_GAINLLR_NF16,		0x20 },
+	{ STV090x_GAINLLR_NF17,		0x21 }
+};
+
+/* Cut 2.0 Long Frame Tracking CR loop */
+static struct stv090x_long_frame_crloop stv090x_s2_crl_cut20[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_QPSK_12,  0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x1e },
+	{ STV090x_QPSK_35,  0x2f, 0x3f, 0x2e, 0x2f, 0x3d, 0x0f, 0x0e, 0x2e, 0x3d, 0x0e },
+	{ STV090x_QPSK_23,  0x2f, 0x3f, 0x2e, 0x2f, 0x0e, 0x0f, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_QPSK_34,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_QPSK_45,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_QPSK_56,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_QPSK_89,  0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_QPSK_910, 0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+	{ STV090x_8PSK_35,  0x3c, 0x3e, 0x1c, 0x2e, 0x0c, 0x1e, 0x2b, 0x2d, 0x1b, 0x1d },
+	{ STV090x_8PSK_23,  0x1d, 0x3e, 0x3c, 0x2e, 0x2c, 0x1e, 0x0c, 0x2d, 0x2b, 0x1d },
+	{ STV090x_8PSK_34,  0x0e, 0x3e, 0x3d, 0x2e, 0x0d, 0x1e, 0x2c, 0x2d, 0x0c, 0x1d },
+	{ STV090x_8PSK_56,  0x2e, 0x3e, 0x1e, 0x2e, 0x2d, 0x1e, 0x3c, 0x2d, 0x2c, 0x1d },
+	{ STV090x_8PSK_89,  0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x0d, 0x2d, 0x3c, 0x1d },
+	{ STV090x_8PSK_910, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x1d, 0x2d, 0x0d, 0x1d }
+};
+
+/* Cut 3.0 Long Frame Tracking CR loop */
+static	struct stv090x_long_frame_crloop stv090x_s2_crl_cut30[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_QPSK_12,  0x3c, 0x2c, 0x0c, 0x2c, 0x1b, 0x2c, 0x1b, 0x1c, 0x0b, 0x3b },
+	{ STV090x_QPSK_35,  0x0d, 0x0d, 0x0c, 0x0d, 0x1b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+	{ STV090x_QPSK_23,  0x1d, 0x0d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+	{ STV090x_QPSK_34,  0x1d, 0x1d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+	{ STV090x_QPSK_45,  0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+	{ STV090x_QPSK_56,  0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+	{ STV090x_QPSK_89,  0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+	{ STV090x_QPSK_910, 0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+	{ STV090x_8PSK_35,  0x39, 0x29, 0x39, 0x19, 0x19, 0x19, 0x19, 0x19, 0x09, 0x19 },
+	{ STV090x_8PSK_23,  0x2a, 0x39, 0x1a, 0x0a, 0x39, 0x0a, 0x29, 0x39, 0x29, 0x0a },
+	{ STV090x_8PSK_34,  0x2b, 0x3a, 0x1b, 0x1b, 0x3a, 0x1b, 0x1a, 0x0b, 0x1a, 0x3a },
+	{ STV090x_8PSK_56,  0x0c, 0x1b, 0x3b, 0x3b, 0x1b, 0x3b, 0x3a, 0x3b, 0x3a, 0x1b },
+	{ STV090x_8PSK_89,  0x0d, 0x3c, 0x2c, 0x2c, 0x2b, 0x0c, 0x0b, 0x3b, 0x0b, 0x1b },
+	{ STV090x_8PSK_910, 0x0d, 0x0d, 0x2c, 0x3c, 0x3b, 0x1c, 0x0b, 0x3b, 0x0b, 0x1b }
+};
+
+/* Cut 2.0 Long Frame Tracking CR Loop */
+static struct stv090x_long_frame_crloop stv090x_s2_apsk_crl_cut20[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_16APSK_23,  0x0c, 0x0c, 0x0c, 0x0c, 0x1d, 0x0c, 0x3c, 0x0c, 0x2c, 0x0c },
+	{ STV090x_16APSK_34,  0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0c, 0x2d, 0x0c, 0x1d, 0x0c },
+	{ STV090x_16APSK_45,  0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c },
+	{ STV090x_16APSK_56,  0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c },
+	{ STV090x_16APSK_89,  0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c },
+	{ STV090x_16APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c },
+	{ STV090x_32APSK_34,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+	{ STV090x_32APSK_45,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+	{ STV090x_32APSK_56,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+	{ STV090x_32APSK_89,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+	{ STV090x_32APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }
+};
+
+/* Cut 3.0 Long Frame Tracking CR Loop */
+static struct stv090x_long_frame_crloop	stv090x_s2_apsk_crl_cut30[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_16APSK_23,  0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x0a, 0x3a, 0x0a, 0x2a, 0x0a },
+	{ STV090x_16APSK_34,  0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0a, 0x3b, 0x0a, 0x1b, 0x0a },
+	{ STV090x_16APSK_45,  0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a },
+	{ STV090x_16APSK_56,  0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a },
+	{ STV090x_16APSK_89,  0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a },
+	{ STV090x_16APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a },
+	{ STV090x_32APSK_34,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+	{ STV090x_32APSK_45,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+	{ STV090x_32APSK_56,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+	{ STV090x_32APSK_89,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+	{ STV090x_32APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }
+};
+
+static struct stv090x_long_frame_crloop stv090x_s2_lowqpsk_crl_cut20[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_QPSK_14,  0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x2d, 0x1f, 0x3d, 0x3e },
+	{ STV090x_QPSK_13,  0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x3d, 0x0f, 0x3d, 0x2e },
+	{ STV090x_QPSK_25,  0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x2e }
+};
+
+static struct stv090x_long_frame_crloop	stv090x_s2_lowqpsk_crl_cut30[] = {
+	/* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+	{ STV090x_QPSK_14,  0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x2a, 0x1c, 0x3a, 0x3b },
+	{ STV090x_QPSK_13,  0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x3a, 0x0c, 0x3a, 0x2b },
+	{ STV090x_QPSK_25,  0x1c, 0x3c, 0x1b, 0x3c, 0x3a, 0x1c, 0x3a, 0x3b, 0x3a, 0x2b }
+};
+
+/* Cut 2.0 Short Frame Tracking CR Loop */
+static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut20[] = {
+	/* MODCOD	  2M    5M    10M   20M   30M */
+	{ STV090x_QPSK,   0x2f, 0x2e, 0x0e, 0x0e, 0x3d },
+	{ STV090x_8PSK,   0x3e, 0x0e, 0x2d, 0x0d, 0x3c },
+	{ STV090x_16APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d },
+	{ STV090x_32APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d }
+};
+
+/* Cut 3.0 Short Frame Tracking CR Loop */
+static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut30[] = {
+	/* MODCOD  	  2M	5M    10M   20M	  30M */
+	{ STV090x_QPSK,   0x2C, 0x2B, 0x0B, 0x0B, 0x3A },
+	{ STV090x_8PSK,   0x3B, 0x0B, 0x2A, 0x0A, 0x39 },
+	{ STV090x_16APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A },
+	{ STV090x_32APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A }
+};
+
+static inline s32 comp2(s32 __x, s32 __width)
+{
+	if (__width == 32)
+		return __x;
+	else
+		return (__x >= (1 << (__width - 1))) ? (__x - (1 << __width)) : __x;
+}
+
+static int stv090x_read_reg(struct stv090x_state *state, unsigned int reg)
+{
+	const struct stv090x_config *config = state->config;
+	int ret;
+
+	u8 b0[] = { reg >> 8, reg & 0xff };
+	u8 buf;
+
+	struct i2c_msg msg[] = {
+		{ .addr	= config->address, .flags	= 0, 		.buf = b0,   .len = 2 },
+		{ .addr	= config->address, .flags	= I2C_M_RD,	.buf = &buf, .len = 1 }
+	};
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+	if (ret != 2) {
+		if (ret != -ERESTARTSYS)
+			dprintk(FE_ERROR, 1,
+				"Read error, Reg=[0x%02x], Status=%d",
+				reg, ret);
+
+		return ret < 0 ? ret : -EREMOTEIO;
+	}
+	if (unlikely(*state->verbose >= FE_DEBUGREG))
+		dprintk(FE_ERROR, 1, "Reg=[0x%02x], data=%02x",
+			reg, buf);
+
+	return (unsigned int) buf;
+}
+
+static int stv090x_write_regs(struct stv090x_state *state, unsigned int reg, u8 *data, u32 count)
+{
+	const struct stv090x_config *config = state->config;
+	int ret;
+	u8 buf[2 + count];
+	struct i2c_msg i2c_msg = { .addr = config->address, .flags = 0, .buf = buf, .len = 2 + count };
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+	memcpy(&buf[2], data, count);
+
+	if (unlikely(*state->verbose >= FE_DEBUGREG)) {
+		int i;
+
+		printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg);
+		for (i = 0; i < count; i++)
+			printk(" %02x", data[i]);
+		printk("\n");
+	}
+
+	ret = i2c_transfer(state->i2c, &i2c_msg, 1);
+	if (ret != 1) {
+		if (ret != -ERESTARTSYS)
+			dprintk(FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d",
+				reg, data[0], count, ret);
+		return ret < 0 ? ret : -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data)
+{
+	return stv090x_write_regs(state, reg, &data, 1);
+}
+
+static int stv090x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg;
+
+	reg = STV090x_READ_DEMOD(state, I2CRPT);
+	if (enable) {
+		dprintk(FE_DEBUG, 1, "Enable Gate");
+		STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0)
+			goto err;
+
+	} else {
+		dprintk(FE_DEBUG, 1, "Disable Gate");
+		STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 0);
+		if ((STV090x_WRITE_DEMOD(state, I2CRPT, reg)) < 0)
+			goto err;
+	}
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static void stv090x_get_lock_tmg(struct stv090x_state *state)
+{
+	switch (state->algo) {
+	case STV090x_BLIND_SEARCH:
+		dprintk(FE_DEBUG, 1, "Blind Search");
+		if (state->srate <= 1500000) {  /*10Msps< SR <=15Msps*/
+			state->DemodTimeout = 1500;
+			state->FecTimeout = 400;
+		} else if (state->srate <= 5000000) {  /*10Msps< SR <=15Msps*/
+			state->DemodTimeout = 1000;
+			state->FecTimeout = 300;
+		} else {  /*SR >20Msps*/
+			state->DemodTimeout = 700;
+			state->FecTimeout = 100;
+		}
+		break;
+
+	case STV090x_COLD_SEARCH:
+	case STV090x_WARM_SEARCH:
+	default:
+		dprintk(FE_DEBUG, 1, "Normal Search");
+		if (state->srate <= 1000000) {  /*SR <=1Msps*/
+			state->DemodTimeout = 4500;
+			state->FecTimeout = 1700;
+		} else if (state->srate <= 2000000) { /*1Msps < SR <= 2Msps */
+			state->DemodTimeout = 2500;
+			state->FecTimeout = 1100;
+		} else if (state->srate <= 5000000) { /*2Msps < SR <= 5Msps */
+			state->DemodTimeout = 1000;
+			state->FecTimeout = 550;
+		} else if (state->srate <= 10000000) { /*5Msps < SR <= 10Msps */
+			state->DemodTimeout = 700;
+			state->FecTimeout = 250;
+		} else if (state->srate <= 20000000) { /*10Msps < SR <= 20Msps */
+			state->DemodTimeout = 400;
+			state->FecTimeout = 130;
+		} else {   /*SR >20Msps*/
+			state->DemodTimeout = 300;
+			state->FecTimeout = 100;
+		}
+		break;
+	}
+
+	if (state->algo == STV090x_WARM_SEARCH)
+		state->DemodTimeout /= 2;
+}
+
+static int stv090x_set_srate(struct stv090x_state *state, u32 srate)
+{
+	u32 sym;
+
+	if (srate > 60000000) {
+		sym  = (srate << 4); /* SR * 2^16 / master_clk */
+		sym /= (state->mclk >> 12);
+	} else if (srate > 6000000) {
+		sym  = (srate << 6);
+		sym /= (state->mclk >> 10);
+	} else {
+		sym  = (srate << 9);
+		sym /= (state->mclk >> 7);
+	}
+
+	if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0x7f) < 0) /* MSB */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRINIT0, (sym & 0xff)) < 0) /* LSB */
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_set_max_srate(struct stv090x_state *state, u32 clk, u32 srate)
+{
+	u32 sym;
+
+	srate = 105 * (srate / 100);
+	if (srate > 60000000) {
+		sym  = (srate << 4); /* SR * 2^16 / master_clk */
+		sym /= (state->mclk >> 12);
+	} else if (srate > 6000000) {
+		sym  = (srate << 6);
+		sym /= (state->mclk >> 10);
+	} else {
+		sym  = (srate << 9);
+		sym /= (state->mclk >> 7);
+	}
+
+	if (sym < 0x7fff) {
+		if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) /* MSB */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) /* LSB */
+			goto err;
+	} else {
+		if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x7f) < 0) /* MSB */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xff) < 0) /* LSB */
+			goto err;
+	}
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate)
+{
+	u32 sym;
+
+	srate = 95 * (srate / 100);
+	if (srate > 60000000) {
+		sym  = (srate << 4); /* SR * 2^16 / master_clk */
+		sym /= (state->mclk >> 12);
+	} else if (srate > 6000000) {
+		sym  = (srate << 6);
+		sym /= (state->mclk >> 10);
+	} else {
+		sym  = (srate << 9);
+		sym /= (state->mclk >> 7);
+	}
+
+	if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0xff)) < 0) /* MSB */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRLOW0, (sym & 0xff)) < 0) /* LSB */
+		goto err;
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static u32 stv090x_car_width(u32 srate, enum stv090x_rolloff rolloff)
+{
+	u32 ro;
+
+	switch (rolloff) {
+	case STV090x_RO_20:
+		ro = 20;
+		break;
+	case STV090x_RO_25:
+		ro = 25;
+		break;
+	case STV090x_RO_35:
+	default:
+		ro = 35;
+		break;
+	}
+
+	return srate + (srate * ro) / 100;
+}
+
+static int stv090x_set_vit_thacq(struct stv090x_state *state)
+{
+	if (STV090x_WRITE_DEMOD(state, VTH12, 0x96) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH23, 0x64) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH34, 0x36) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH56, 0x23) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH67, 0x1e) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH78, 0x19) < 0)
+		goto err;
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_set_vit_thtracq(struct stv090x_state *state)
+{
+	if (STV090x_WRITE_DEMOD(state, VTH12, 0xd0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH23, 0x7d) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH34, 0x53) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH56, 0x2f) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH67, 0x24) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, VTH78, 0x1f) < 0)
+		goto err;
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_set_viterbi(struct stv090x_state *state)
+{
+	switch (state->search_mode) {
+	case STV090x_SEARCH_AUTO:
+		if (STV090x_WRITE_DEMOD(state, FECM, 0x10) < 0) /* DVB-S and DVB-S2 */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, PRVIT, 0x3f) < 0) /* all puncture rate */
+			goto err;
+		break;
+	case STV090x_SEARCH_DVBS1:
+		if (STV090x_WRITE_DEMOD(state, FECM, 0x00) < 0) /* disable DSS */
+			goto err;
+		switch (state->fec) {
+		case STV090x_PR12:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR23:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR34:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x04) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR56:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x08) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR78:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x20) < 0)
+				goto err;
+			break;
+
+		default:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x2f) < 0) /* all */
+				goto err;
+			break;
+		}
+		break;
+	case STV090x_SEARCH_DSS:
+		if (STV090x_WRITE_DEMOD(state, FECM, 0x80) < 0)
+			goto err;
+		switch (state->fec) {
+		case STV090x_PR12:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR23:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0)
+				goto err;
+			break;
+
+		case STV090x_PR67:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x10) < 0)
+				goto err;
+			break;
+
+		default:
+			if (STV090x_WRITE_DEMOD(state, PRVIT, 0x13) < 0) /* 1/2, 2/3, 6/7 */
+				goto err;
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_stop_modcod(struct stv090x_state *state)
+{
+	if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xff) < 0)
+		goto err;
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_activate_modcod(struct stv090x_state *state)
+{
+	if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xfc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xcc) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_activate_modcod_single(struct stv090x_state *state)
+{
+
+	if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xf0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0x0f) < 0)
+		goto err;
+
+	return 0;
+
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable)
+{
+	u32 reg;
+
+	switch (state->demod) {
+	case STV090x_DEMODULATOR_0:
+		mutex_lock(&demod_lock);
+		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+		STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, enable);
+		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+			goto err;
+		mutex_unlock(&demod_lock);
+		break;
+
+	case STV090x_DEMODULATOR_1:
+		mutex_lock(&demod_lock);
+		reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+		STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, enable);
+		if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+			goto err;
+		mutex_unlock(&demod_lock);
+		break;
+
+	default:
+		dprintk(FE_ERROR, 1, "Wrong demodulator!");
+		break;
+	}
+	return 0;
+err:
+	mutex_unlock(&demod_lock);
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_dvbs_track_crl(struct stv090x_state *state)
+{
+	if (state->dev_ver >= 0x30) {
+		/* Set ACLC BCLC optimised value vs SR */
+		if (state->srate >= 15000000) {
+			if (STV090x_WRITE_DEMOD(state, ACLC, 0x2b) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, BCLC, 0x1a) < 0)
+				goto err;
+		} else if ((state->srate >= 7000000) && (15000000 > state->srate)) {
+			if (STV090x_WRITE_DEMOD(state, ACLC, 0x0c) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, BCLC, 0x1b) < 0)
+				goto err;
+		} else if (state->srate < 7000000) {
+			if (STV090x_WRITE_DEMOD(state, ACLC, 0x2c) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, BCLC, 0x1c) < 0)
+				goto err;
+		}
+
+	} else {
+		/* Cut 2.0 */
+		if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
+			goto err;
+	}
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_delivery_search(struct stv090x_state *state)
+{
+	u32 reg;
+
+	switch (state->search_mode) {
+	case STV090x_SEARCH_DVBS1:
+	case STV090x_SEARCH_DSS:
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+
+		/* Activate Viterbi decoder in legacy search,
+		 * do not use FRESVIT1, might impact VITERBI2
+		 */
+		if (stv090x_vitclk_ctl(state, 0) < 0)
+			goto err;
+
+		if (stv090x_dvbs_track_crl(state) < 0)
+			goto err;
+
+		if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x22) < 0) /* disable DVB-S2 */
+			goto err;
+
+		if (stv090x_set_vit_thacq(state) < 0)
+			goto err;
+		if (stv090x_set_viterbi(state) < 0)
+			goto err;
+		break;
+
+	case STV090x_SEARCH_DVBS2:
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+
+		if (stv090x_vitclk_ctl(state, 1) < 0)
+			goto err;
+
+		if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0) /* stop DVB-S CR loop */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
+			goto err;
+
+		if (state->dev_ver <= 0x20) {
+			/* enable S2 carrier loop */
+			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
+				goto err;
+		} else {
+			/* > Cut 3: Stop carrier 3 */
+			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0)
+				goto err;
+		}
+
+		if (state->demod_mode != STV090x_SINGLE) {
+			/* Cut 2: enable link during search */
+			if (stv090x_activate_modcod(state) < 0)
+				goto err;
+		} else {
+			/* Single demodulator
+			 * Authorize SHORT and LONG frames,
+			 * QPSK, 8PSK, 16APSK and 32APSK
+			 */
+			if (stv090x_activate_modcod_single(state) < 0)
+				goto err;
+		}
+
+		break;
+
+	case STV090x_SEARCH_AUTO:
+	default:
+		/* enable DVB-S2 and DVB-S2 in Auto MODE */
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+
+		if (stv090x_vitclk_ctl(state, 0) < 0)
+			goto err;
+
+		if (stv090x_dvbs_track_crl(state) < 0)
+			goto err;
+
+		if (state->dev_ver <= 0x20) {
+			/* enable S2 carrier loop */
+			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
+				goto err;
+		} else {
+			/* > Cut 3: Stop carrier 3 */
+			if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0)
+				goto err;
+		}
+
+		if (state->demod_mode != STV090x_SINGLE) {
+			/* Cut 2: enable link during search */
+			if (stv090x_activate_modcod(state) < 0)
+				goto err;
+		} else {
+			/* Single demodulator
+			 * Authorize SHORT and LONG frames,
+			 * QPSK, 8PSK, 16APSK and 32APSK
+			 */
+			if (stv090x_activate_modcod_single(state) < 0)
+				goto err;
+		}
+
+		if (state->srate >= 2000000) {
+			/* Srate >= 2MSPS, Viterbi threshold to acquire */
+			if (stv090x_set_vit_thacq(state) < 0)
+				goto err;
+		} else {
+			/* Srate < 2MSPS, Reset Viterbi thresholdto track
+			 * and then re-acquire
+			 */
+			if (stv090x_set_vit_thtracq(state) < 0)
+				goto err;
+		}
+
+		if (stv090x_set_viterbi(state) < 0)
+			goto err;
+		break;
+	}
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_start_search(struct stv090x_state *state)
+{
+	u32 reg, freq_abs;
+	s16 freq;
+
+	/* Reset demodulator */
+	reg = STV090x_READ_DEMOD(state, DMDISTATE);
+	STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f);
+	if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+		goto err;
+
+	if (state->dev_ver <= 0x20) {
+		if (state->srate <= 5000000) {
+			if (STV090x_WRITE_DEMOD(state, CARCFG, 0x44) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRUP1, 0x0f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRUP1, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRLOW1, 0xf0) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRLOW0, 0x00) < 0)
+				goto err;
+
+			/*enlarge the timing bandwith for Low SR*/
+			if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0)
+				goto err;
+		} else {
+			/* If the symbol rate is >5 Msps
+			Set The carrier search up and low to auto mode */
+			if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
+				goto err;
+			/*reduce the timing bandwith for high SR*/
+			if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
+				goto err;
+		}
+	} else {
+		/* >= Cut 3 */
+		if (state->srate <= 5000000) {
+			/* enlarge the timing bandwith for Low SR */
+			STV090x_WRITE_DEMOD(state, RTCS2, 0x68);
+		} else {
+			/* reduce timing bandwith for high SR */
+			STV090x_WRITE_DEMOD(state, RTCS2, 0x44);
+		}
+
+		/* Set CFR min and max to manual mode */
+		STV090x_WRITE_DEMOD(state, CARCFG, 0x46);
+
+		if (state->algo == STV090x_WARM_SEARCH) {
+			/* WARM Start
+			 * CFR min = -1MHz,
+			 * CFR max = +1MHz
+			 */
+			freq_abs  = 1000 << 16;
+			freq_abs /= (state->mclk / 1000);
+			freq      = (s16) freq_abs;
+		} else {
+			/* COLD Start
+			 * CFR min =- (SearchRange / 2 + 600KHz)
+			 * CFR max = +(SearchRange / 2 + 600KHz)
+			 * (600KHz for the tuner step size)
+			 */
+			freq_abs  = (state->search_range / 2000) + 600;
+			freq_abs  = freq_abs << 16;
+			freq_abs /= (state->mclk / 1000);
+			freq      = (s16) freq_abs;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, CFRUP1, MSB(freq)) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRUP1, LSB(freq)) < 0)
+			goto err;
+
+		freq *= -1;
+
+		if (STV090x_WRITE_DEMOD(state, CFRLOW1, MSB(freq)) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRLOW0, LSB(freq)) < 0)
+			goto err;
+
+	}
+
+	if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0) < 0)
+		goto err;
+
+	if (state->dev_ver >= 0x20) {
+		if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
+			goto err;
+
+		if ((state->search_mode == STV090x_DVBS1)	||
+			(state->search_mode == STV090x_DSS)	||
+			(state->search_mode == STV090x_SEARCH_AUTO)) {
+
+			if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0)
+				goto err;
+		}
+	}
+
+	if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xe0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xc0) < 0)
+		goto err;
+
+	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0);
+	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+		goto err;
+	reg = STV090x_READ_DEMOD(state, DMDCFG2);
+	STV090x_SETFIELD_Px(reg, S1S2_SEQUENTIAL_FIELD, 0x0);
+	if (STV090x_WRITE_DEMOD(state, DMDCFG2, reg) < 0)
+		goto err;
+
+	if (state->dev_ver >= 0x20) {
+		/*Frequency offset detector setting*/
+		if (state->srate < 2000000) {
+			if (state->dev_ver <= 0x20) {
+				/* Cut 2 */
+				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0)
+					goto err;
+			} else {
+				/* Cut 2 */
+				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x89) < 0)
+					goto err;
+			}
+			if (STV090x_WRITE_DEMOD(state, CARHDR, 0x40) < 0)
+				goto err;
+		}
+
+		if (state->srate < 10000000) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4c) < 0)
+				goto err;
+		} else {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4b) < 0)
+				goto err;
+		}
+	} else {
+		if (state->srate < 10000000) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xef) < 0)
+				goto err;
+		} else {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xed) < 0)
+				goto err;
+		}
+	}
+
+	switch (state->algo) {
+	case STV090x_WARM_SEARCH:
+		/* The symbol rate and the exact
+		 * carrier Frequency are known
+		 */
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+			goto err;
+		break;
+
+	case STV090x_COLD_SEARCH:
+		/* The symbol rate is known */
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+			goto err;
+		break;
+
+	default:
+		break;
+	}
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_get_agc2_min_level(struct stv090x_state *state)
+{
+	u32 agc2_min = 0, agc2 = 0, freq_init, freq_step, reg;
+	s32 i, j, steps, dir;
+
+	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+		goto err;
+	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
+	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1);
+	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0) /* SR = 65 Msps Max */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0) /* SR= 400 ksps Min */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0) /* stop acq @ coarse carrier state */
+		goto err;
+	if (stv090x_set_srate(state, 1000000) < 0)
+		goto err;
+
+	steps  = -1 + state->search_range / 1000000;
+	steps /= 2;
+	steps  = (2 * steps) + 1;
+	if (steps < 0)
+		steps = 1;
+
+	dir = 1;
+	freq_step = (1000000 * 256) / (state->mclk / 256);
+	freq_init = 0;
+
+	for (i = 0; i < steps; i++) {
+		if (dir > 0)
+			freq_init = freq_init + (freq_step * i);
+		else
+			freq_init = freq_init - (freq_step * i);
+
+		dir = -1;
+
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod RESET */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_init >> 8) & 0xff) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_init & 0xff) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x58) < 0) /* Demod RESET */
+			goto err;
+		msleep(10);
+		for (j = 0; j < 10; j++) {
+			agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8;
+			agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+		}
+		agc2 /= 10;
+		agc2_min = 0xffff;
+		if (agc2 < 0xffff)
+			agc2_min = agc2;
+	}
+
+	return agc2_min;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static u32 stv090x_get_srate(struct stv090x_state *state, u32 clk)
+{
+	u8 r3, r2, r1, r0;
+	s32 srate, int_1, int_2, tmp_1, tmp_2;
+
+	r3 = STV090x_READ_DEMOD(state, SFR3);
+	r2 = STV090x_READ_DEMOD(state, SFR2);
+	r1 = STV090x_READ_DEMOD(state, SFR1);
+	r0 = STV090x_READ_DEMOD(state, SFR0);
+
+	srate = ((r3 << 24) | (r2 << 16) | (r1 <<  8) | r0);
+
+	int_1 = clk >> 16;
+	int_2 = srate >> 16;
+
+	tmp_1 = clk % 0x10000;
+	tmp_2 = srate % 0x10000;
+
+	srate = (int_1 * int_2) +
+		((int_1 * tmp_2) >> 16) +
+		((int_2 * tmp_1) >> 16);
+
+	return srate;
+}
+
+static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
+{
+	struct dvb_frontend *fe = &state->frontend;
+
+	int tmg_lock = 0, i;
+	s32 tmg_cpt = 0, dir = 1, steps, cur_step = 0, freq;
+	u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg;
+
+	reg = STV090x_READ_DEMOD(state, DMDISTATE);
+	STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); /* Demod RESET */
+	if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGCFG, 0x12) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xf0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xe0) < 0)
+		goto err;
+	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+	STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
+	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1);
+	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x60) < 0)
+		goto err;
+
+	if (state->dev_ver >= 0x30) {
+		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
+			goto err;
+
+	} else if (state->dev_ver >= 0x20) {
+		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x6a) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
+			goto err;
+	}
+
+	if (state->srate <= 2000000)
+		car_step = 1000;
+	else if (state->srate <= 5000000)
+		car_step = 2000;
+	else if (state->srate <= 12000000)
+		car_step = 3000;
+	else
+		car_step = 5000;
+
+	steps  = -1 + ((state->search_range / 1000) / car_step);
+	steps /= 2;
+	steps  = (2 * steps) + 1;
+	if (steps < 0)
+		steps = 1;
+	else if (steps > 10) {
+		steps = 11;
+		car_step = (state->search_range / 1000) / 10;
+	}
+	cur_step = 0;
+	dir = 1;
+	freq = state->frequency;
+
+	while ((!tmg_lock) && (cur_step < steps)) {
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5f) < 0) /* Demod RESET */
+			goto err;
+		reg = STV090x_READ_DEMOD(state, DMDISTATE);
+		STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x00); /* trigger acquisition */
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+			goto err;
+		msleep(50);
+		for (i = 0; i < 10; i++) {
+			reg = STV090x_READ_DEMOD(state, DSTATUS);
+			if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
+				tmg_cpt++;
+			agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8;
+			agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+		}
+		agc2 /= 10;
+		srate_coarse = stv090x_get_srate(state, state->mclk);
+		cur_step++;
+		dir *= -1;
+		if ((tmg_cpt >= 5) && (agc2 < 0x1f00) && (srate_coarse < 55000000) && (srate_coarse > 850000))
+			tmg_lock = 1;
+		else if (cur_step < steps) {
+			if (dir > 0)
+				freq += cur_step * car_step;
+			else
+				freq -= cur_step * car_step;
+
+			/* Setup tuner */
+			if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+				goto err;
+
+			if (state->config->tuner_set_frequency) {
+				if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+					goto err;
+			}
+
+			if (state->config->tuner_set_bandwidth) {
+				if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+					goto err;
+			}
+
+			if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+				goto err;
+
+			msleep(50);
+
+			if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+				goto err;
+
+			if (state->config->tuner_get_status) {
+				if (state->config->tuner_get_status(fe, &reg) < 0)
+					goto err;
+			}
+
+			if (reg)
+				dprintk(FE_DEBUG, 1, "Tuner phase locked");
+			else
+				dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+			if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+				goto err;
+
+		}
+	}
+	if (!tmg_lock)
+		srate_coarse = 0;
+	else
+		srate_coarse = stv090x_get_srate(state, state->mclk);
+
+	return srate_coarse;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
+{
+	u32 srate_coarse, freq_coarse, sym, reg;
+
+	srate_coarse = stv090x_get_srate(state, state->mclk);
+	freq_coarse  = STV090x_READ_DEMOD(state, CFR2) << 8;
+	freq_coarse |= STV090x_READ_DEMOD(state, CFR1);
+	sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+
+	if (sym < state->srate)
+		srate_coarse = 0;
+	else {
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) /* Demod RESET */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0x01) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0)
+			goto err;
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+
+		if (state->dev_ver >= 0x30) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0)
+				goto err;
+		} else if (state->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+				goto err;
+		}
+
+		if (srate_coarse > 3000000) {
+			sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+			sym  = (sym / 1000) * 65536;
+			sym /= (state->mclk / 1000);
+			if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
+				goto err;
+			sym  = 10 * (srate_coarse / 13); /* SFRLOW = SFR - 30% */
+			sym  = (sym / 1000) * 65536;
+			sym /= (state->mclk / 1000);
+			if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
+				goto err;
+			sym  = (srate_coarse / 1000) * 65536;
+			sym /= (state->mclk / 1000);
+			if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
+				goto err;
+		} else {
+			sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+			sym  = (sym / 100) * 65536;
+			sym /= (state->mclk / 100);
+			if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
+				goto err;
+			sym  = 10 * (srate_coarse / 14); /* SFRLOW = SFR - 30% */
+			sym  = (sym / 100) * 65536;
+			sym /= (state->mclk / 100);
+			if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
+				goto err;
+			sym  = (srate_coarse / 100) * 65536;
+			sym /= (state->mclk / 100);
+			if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
+				goto err;
+		}
+		if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_coarse >> 8) & 0xff) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_coarse & 0xff) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) /* trigger acquisition */
+			goto err;
+	}
+
+	return srate_coarse;
+
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_get_dmdlock(struct stv090x_state *state, s32 timeout)
+{
+	s32 timer = 0, lock = 0;
+	u32 reg;
+	u8 stat;
+
+	while ((timer < timeout) && (!lock)) {
+		reg = STV090x_READ_DEMOD(state, DMDSTATE);
+		stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+		switch (stat) {
+		case 0: /* searching */
+		case 1: /* first PLH detected */
+		default:
+			dprintk(FE_DEBUG, 1, "Demodulator searching ..");
+			lock = 0;
+			break;
+		case 2: /* DVB-S2 mode */
+		case 3: /* DVB-S1/legacy mode */
+			reg = STV090x_READ_DEMOD(state, DSTATUS);
+			lock = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+			break;
+		}
+
+		if (!lock)
+			msleep(10);
+		else
+			dprintk(FE_DEBUG, 1, "Demodulator acquired LOCK");
+
+		timer += 10;
+	}
+	return lock;
+}
+
+static int stv090x_blind_search(struct stv090x_state *state)
+{
+	u32 agc2, reg, srate_coarse;
+	s32 timeout_dmd = 500, cpt_fail, agc2_ovflw, i;
+	u8 k_ref, k_max, k_min;
+	int coarse_fail, lock;
+
+	k_max = 120;
+	k_min = 30;
+
+	agc2 = stv090x_get_agc2_min_level(state);
+
+	if (agc2 > STV090x_SEARCH_AGC2_TH(state->dev_ver)) {
+		lock = 0;
+	} else {
+
+		if (state->dev_ver <= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
+				goto err;
+		} else {
+			/* > Cut 3 */
+			if (STV090x_WRITE_DEMOD(state, CARCFG, 0x06) < 0)
+				goto err;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
+			goto err;
+
+		if (state->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0) /* set viterbi hysteresis */
+				goto err;
+		}
+
+		k_ref = k_max;
+		do {
+			if (STV090x_WRITE_DEMOD(state, KREFTMG, k_ref) < 0)
+				goto err;
+			if (stv090x_srate_srch_coarse(state) != 0) {
+				srate_coarse = stv090x_srate_srch_fine(state);
+				if (srate_coarse != 0) {
+					stv090x_get_lock_tmg(state);
+					lock = stv090x_get_dmdlock(state, timeout_dmd);
+				} else {
+					lock = 0;
+				}
+			} else {
+				cpt_fail = 0;
+				agc2_ovflw = 0;
+				for (i = 0; i < 10; i++) {
+					agc2  = STV090x_READ_DEMOD(state, AGC2I1) << 8;
+					agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+					if (agc2 >= 0xff00)
+						agc2_ovflw++;
+					reg = STV090x_READ_DEMOD(state, DSTATUS2);
+					if ((STV090x_GETFIELD_Px(reg, CFR_OVERFLOW_FIELD) == 0x01) &&
+					    (STV090x_GETFIELD_Px(reg, DEMOD_DELOCK_FIELD) == 0x01))
+
+						cpt_fail++;
+				}
+				if ((cpt_fail > 7) || (agc2_ovflw > 7))
+					coarse_fail = 1;
+
+				lock = 0;
+			}
+			k_ref -= 30;
+		} while ((k_ref >= k_min) && (!lock) && (!coarse_fail));
+	}
+
+	return lock;
+
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_chk_tmg(struct stv090x_state *state)
+{
+	u32 reg;
+	s32 tmg_cpt = 0, i;
+	u8 freq, tmg_thh, tmg_thl;
+	int tmg_lock;
+
+	freq = STV090x_READ_DEMOD(state, CARFREQ);
+	tmg_thh = STV090x_READ_DEMOD(state, TMGTHRISE);
+	tmg_thl = STV090x_READ_DEMOD(state, TMGTHFALL);
+	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0)
+		goto err;
+
+	reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+	STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); /* stop carrier offset search */
+	if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, RTC, 0x80) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, RTCS2, 0x40) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x00) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) /* set car ofset to 0 */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x65) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) /* trigger acquisition */
+		goto err;
+	msleep(10);
+
+	for (i = 0; i < 10; i++) {
+		reg = STV090x_READ_DEMOD(state, DSTATUS);
+		if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
+			tmg_cpt++;
+		msleep(1);
+	}
+	if (tmg_cpt >= 3)
+		tmg_lock = 1;
+
+	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0) /* DVB-S1 timing */
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) /* DVB-S2 timing */
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, CARFREQ, freq) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHRISE, tmg_thh) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, TMGTHFALL, tmg_thl) < 0)
+		goto err;
+
+	return	tmg_lock;
+
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
+{
+	struct dvb_frontend *fe = &state->frontend;
+
+	u32 reg;
+	s32 car_step, steps, cur_step, dir, freq, timeout_lock;
+	int lock = 0;
+
+	if (state->srate >= 10000000)
+		timeout_lock = timeout_dmd / 3;
+	else
+		timeout_lock = timeout_dmd / 2;
+
+	lock = stv090x_get_dmdlock(state, timeout_lock); /* cold start wait */
+	if (!lock) {
+		if (state->srate >= 10000000) {
+			if (stv090x_chk_tmg(state)) {
+				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+					goto err;
+				lock = stv090x_get_dmdlock(state, timeout_dmd);
+			} else {
+				lock = 0;
+			}
+		} else {
+			if (state->srate <= 4000000)
+				car_step = 1000;
+			else if (state->srate <= 7000000)
+				car_step = 2000;
+			else if (state->srate <= 10000000)
+				car_step = 3000;
+			else
+				car_step = 5000;
+
+			steps  = (state->search_range / 1000) / car_step;
+			steps /= 2;
+			steps  = 2 * (steps + 1);
+			if (steps < 0)
+				steps = 2;
+			else if (steps > 12)
+				steps = 12;
+
+			cur_step = 1;
+			dir = 1;
+
+			if (!lock) {
+				freq = state->frequency;
+				state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate;
+				while ((cur_step <= steps) && (!lock)) {
+					if (dir > 0)
+						freq += cur_step * car_step;
+					else
+						freq -= cur_step * car_step;
+
+					/* Setup tuner */
+					if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+						goto err;
+
+					if (state->config->tuner_set_frequency) {
+						if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+							goto err;
+					}
+
+					if (state->config->tuner_set_bandwidth) {
+						if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+							goto err;
+					}
+
+					if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+						goto err;
+
+					msleep(50);
+
+					if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+						goto err;
+
+					if (state->config->tuner_get_status) {
+						if (state->config->tuner_get_status(fe, &reg) < 0)
+							goto err;
+					}
+
+					if (reg)
+						dprintk(FE_DEBUG, 1, "Tuner phase locked");
+					else
+						dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+					if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+						goto err;
+
+					STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c);
+					if (state->delsys == STV090x_DVBS2) {
+						reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+						STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+						STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+						if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+							goto err;
+						STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+						STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+						if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+							goto err;
+					}
+					if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
+						goto err;
+					if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
+						goto err;
+					if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+						goto err;
+					if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+						goto err;
+					lock = stv090x_get_dmdlock(state, (timeout_dmd / 3));
+
+					dir *= -1;
+					cur_step++;
+				}
+			}
+		}
+	}
+
+	return lock;
+
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_get_loop_params(struct stv090x_state *state, s32 *freq_inc, s32 *timeout_sw, s32 *steps)
+{
+	s32 timeout, inc, steps_max, srate, car_max;
+
+	srate = state->srate;
+	car_max = state->search_range / 1000;
+	car_max += car_max / 10;
+	car_max  = 65536 * (car_max / 2);
+	car_max /= (state->mclk / 1000);
+
+	if (car_max > 0x4000)
+		car_max = 0x4000 ; /* maxcarrier should be<= +-1/4 Mclk */
+
+	inc  = srate;
+	inc /= state->mclk / 1000;
+	inc *= 256;
+	inc *= 256;
+	inc /= 1000;
+
+	switch (state->search_mode) {
+	case STV090x_SEARCH_DVBS1:
+	case STV090x_SEARCH_DSS:
+		inc *= 3; /* freq step = 3% of srate */
+		timeout = 20;
+		break;
+
+	case STV090x_SEARCH_DVBS2:
+		inc *= 4;
+		timeout = 25;
+		break;
+
+	case STV090x_SEARCH_AUTO:
+	default:
+		inc *= 3;
+		timeout = 25;
+		break;
+	}
+	inc /= 100;
+	if ((inc > car_max) || (inc < 0))
+		inc = car_max / 2; /* increment <= 1/8 Mclk */
+
+	timeout *= 27500; /* 27.5 Msps reference */
+	if (srate > 0)
+		timeout /= (srate / 1000);
+
+	if ((timeout > 100) || (timeout < 0))
+		timeout = 100;
+
+	steps_max = (car_max / inc) + 1; /* min steps = 3 */
+	if ((steps_max > 100) || (steps_max < 0)) {
+		steps_max = 100; /* max steps <= 100 */
+		inc = car_max / steps_max;
+	}
+	*freq_inc = inc;
+	*timeout_sw = timeout;
+	*steps = steps_max;
+
+	return 0;
+}
+
+static int stv090x_chk_signal(struct stv090x_state *state)
+{
+	s32 offst_car, agc2, car_max;
+	int no_signal;
+
+	offst_car  = STV090x_READ_DEMOD(state, CFR2) << 8;
+	offst_car |= STV090x_READ_DEMOD(state, CFR1);
+	offst_car = comp2(offst_car, 16);
+
+	agc2  = STV090x_READ_DEMOD(state, AGC2I1) << 8;
+	agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+	car_max = state->search_range / 1000;
+
+	car_max += (car_max / 10); /* 10% margin */
+	car_max  = (65536 * car_max / 2);
+	car_max /= state->mclk / 1000;
+
+	if (car_max > 0x4000)
+		car_max = 0x4000;
+
+	if ((agc2 > 0x2000) || (offst_car > 2 * car_max) || (offst_car < -2 * car_max)) {
+		no_signal = 1;
+		dprintk(FE_DEBUG, 1, "No Signal");
+	} else {
+		no_signal = 0;
+		dprintk(FE_DEBUG, 1, "Found Signal");
+	}
+
+	return no_signal;
+}
+
+static int stv090x_search_car_loop(struct stv090x_state *state, s32 inc, s32 timeout, int zigzag, s32 steps_max)
+{
+	int no_signal, lock = 0;
+	s32 cpt_step = 0, offst_freq, car_max;
+	u32 reg;
+
+	car_max  = state->search_range / 1000;
+	car_max += (car_max / 10);
+	car_max  = (65536 * car_max / 2);
+	car_max /= (state->mclk / 1000);
+	if (car_max > 0x4000)
+		car_max = 0x4000;
+
+	if (zigzag)
+		offst_freq = 0;
+	else
+		offst_freq = -car_max + inc;
+
+	do {
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT1, ((offst_freq / 256) & 0xff)) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT0, offst_freq & 0xff) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+			goto err;
+
+		reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+		STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x1); /* stop DVB-S2 packet delin */
+		if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+			goto err;
+
+		if (zigzag) {
+			if (offst_freq >= 0)
+				offst_freq = -offst_freq - 2 * inc;
+			else
+				offst_freq = -offst_freq;
+		} else {
+			offst_freq += 2 * inc;
+		}
+
+		cpt_step++;
+
+		lock = stv090x_get_dmdlock(state, timeout);
+		no_signal = stv090x_chk_signal(state);
+
+	} while ((!lock) &&
+		 (!no_signal) &&
+		  ((offst_freq - inc) < car_max) &&
+		  ((offst_freq + inc) > -car_max) &&
+		  (cpt_step < steps_max));
+
+	reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+	STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+			goto err;
+
+	return lock;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_sw_algo(struct stv090x_state *state)
+{
+	int no_signal, zigzag, lock = 0;
+	u32 reg;
+
+	s32 dvbs2_fly_wheel;
+	s32 inc, timeout_step, trials, steps_max;
+
+	/* get params */
+	stv090x_get_loop_params(state, &inc, &timeout_step, &steps_max);
+
+	switch (state->search_mode) {
+	case STV090x_SEARCH_DVBS1:
+	case STV090x_SEARCH_DSS:
+		/* accelerate the frequency detector */
+		if (state->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3B) < 0)
+				goto err;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x49) < 0)
+			goto err;
+		zigzag = 0;
+		break;
+
+	case STV090x_SEARCH_DVBS2:
+		if (state->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+				goto err;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0)
+			goto err;
+		zigzag = 1;
+		break;
+
+	case STV090x_SEARCH_AUTO:
+	default:
+		/* accelerate the frequency detector */
+		if (state->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3b) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+				goto err;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0xc9) < 0)
+			goto err;
+		zigzag = 0;
+		break;
+	}
+
+	trials = 0;
+	do {
+		lock = stv090x_search_car_loop(state, inc, timeout_step, zigzag, steps_max);
+		no_signal = stv090x_chk_signal(state);
+		trials++;
+
+		/*run the SW search 2 times maximum*/
+		if (lock || no_signal || (trials == 2)) {
+			/*Check if the demod is not losing lock in DVBS2*/
+			if (state->dev_ver >= 0x20) {
+				if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
+					goto err;
+			}
+
+			reg = STV090x_READ_DEMOD(state, DMDSTATE);
+			if ((lock) && (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == STV090x_DVBS2)) {
+				/*Check if the demod is not losing lock in DVBS2*/
+				msleep(timeout_step);
+				reg = STV090x_READ_DEMOD(state, DMDFLYW);
+				dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD);
+				if (dvbs2_fly_wheel < 0xd) {	 /*if correct frames is decrementing */
+					msleep(timeout_step);
+					reg = STV090x_READ_DEMOD(state, DMDFLYW);
+					dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD);
+				}
+				if (dvbs2_fly_wheel < 0xd) {
+					/*FALSE lock, The demod is loosing lock */
+					lock = 0;
+					if (trials < 2) {
+						if (state->dev_ver >= 0x20) {
+							if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+								goto err;
+						}
+
+						if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0)
+							goto err;
+					}
+				}
+			}
+		}
+	} while ((!lock) && (trials < 2) && (!no_signal));
+
+	return lock;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static enum stv090x_delsys stv090x_get_std(struct stv090x_state *state)
+{
+	u32 reg;
+	enum stv090x_delsys delsys;
+
+	reg = STV090x_READ_DEMOD(state, DMDSTATE);
+	if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 2)
+		delsys = STV090x_DVBS2;
+	else if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 3) {
+		reg = STV090x_READ_DEMOD(state, FECM);
+		if (STV090x_GETFIELD_Px(reg, DSS_DVB_FIELD) == 1)
+			delsys = STV090x_DSS;
+		else
+			delsys = STV090x_DVBS1;
+	} else {
+		delsys = STV090x_ERROR;
+	}
+
+	return delsys;
+}
+
+/* in Hz */
+static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk)
+{
+	s32 derot, int_1, int_2, tmp_1, tmp_2;
+
+	derot  = STV090x_READ_DEMOD(state, CFR2) << 16;
+	derot |= STV090x_READ_DEMOD(state, CFR1) <<  8;
+	derot |= STV090x_READ_DEMOD(state, CFR0);
+
+	derot = comp2(derot, 24);
+	int_1 = state->mclk >> 12;
+	int_2 = derot >> 12;
+
+	/* carrier_frequency = MasterClock * Reg / 2^24 */
+	tmp_1 = state->mclk % 0x1000;
+	tmp_2 = derot % 0x1000;
+
+	derot = (int_1 * int_2) +
+		((int_1 * tmp_2) >> 12) +
+		((int_1 * tmp_1) >> 12);
+
+	return derot;
+}
+
+static int stv090x_get_viterbi(struct stv090x_state *state)
+{
+	u32 reg, rate;
+
+	reg = STV090x_READ_DEMOD(state, VITCURPUN);
+	rate = STV090x_GETFIELD_Px(reg, VIT_CURPUN_FIELD);
+
+	switch (rate) {
+	case 13:
+		state->fec = STV090x_PR12;
+		break;
+
+	case 18:
+		state->fec = STV090x_PR23;
+		break;
+
+	case 21:
+		state->fec = STV090x_PR34;
+		break;
+
+	case 24:
+		state->fec = STV090x_PR56;
+		break;
+
+	case 25:
+		state->fec = STV090x_PR67;
+		break;
+
+	case 26:
+		state->fec = STV090x_PR78;
+		break;
+
+	default:
+		state->fec = STV090x_PRERR;
+		break;
+	}
+
+	return 0;
+}
+
+static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *state)
+{
+	struct dvb_frontend *fe = &state->frontend;
+
+	u8 tmg;
+	u32 reg;
+	s32 i = 0, offst_freq;
+
+	msleep(5);
+
+	if (state->algo == STV090x_BLIND_SEARCH) {
+		tmg = STV090x_READ_DEMOD(state, TMGREG2);
+		STV090x_WRITE_DEMOD(state, SFRSTEP, 0x5c);
+		while ((i <= 50) && (tmg != 0) && (tmg != 0xff)) {
+			tmg = STV090x_READ_DEMOD(state, TMGREG2);
+			msleep(5);
+			i += 5;
+		}
+	}
+	state->delsys = stv090x_get_std(state);
+
+	if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+		goto err;
+
+	if (state->config->tuner_get_frequency) {
+		if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
+			goto err;
+	}
+
+	if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+		goto err;
+
+	offst_freq = stv090x_get_car_freq(state, state->mclk) / 1000;
+	state->frequency += offst_freq;
+
+	if (stv090x_get_viterbi(state) < 0)
+		goto err;
+
+	reg = STV090x_READ_DEMOD(state, DMDMODCOD);
+	state->modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD);
+	state->pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01;
+	state->frame_len = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) >> 1;
+	reg = STV090x_READ_DEMOD(state, TMGOBS);
+	state->rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD);
+	reg = STV090x_READ_DEMOD(state, FECM);
+	state->inversion = STV090x_GETFIELD_Px(reg, IQINV_FIELD);
+
+	if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) {
+
+		if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+			goto err;
+
+		if (state->config->tuner_get_frequency) {
+			if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
+				goto err;
+		}
+
+		if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+			goto err;
+
+		if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
+			return STV090x_RANGEOK;
+		else if (abs(offst_freq) <= (stv090x_car_width(state->srate, state->rolloff) / 2000))
+			return STV090x_RANGEOK;
+		else
+			return STV090x_OUTOFRANGE; /* Out of Range */
+	} else {
+		if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
+			return STV090x_RANGEOK;
+		else
+			return STV090x_OUTOFRANGE;
+	}
+
+	return STV090x_OUTOFRANGE;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static u32 stv090x_get_tmgoffst(struct stv090x_state *state, u32 srate)
+{
+	s32 offst_tmg;
+
+	offst_tmg  = STV090x_READ_DEMOD(state, TMGREG2) << 16;
+	offst_tmg |= STV090x_READ_DEMOD(state, TMGREG1) <<  8;
+	offst_tmg |= STV090x_READ_DEMOD(state, TMGREG0);
+
+	offst_tmg = comp2(offst_tmg, 24); /* 2's complement */
+	if (!offst_tmg)
+		offst_tmg = 1;
+
+	offst_tmg  = ((s32) srate * 10) / ((s32) 0x1000000 / offst_tmg);
+	offst_tmg /= 320;
+
+	return offst_tmg;
+}
+
+static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_modcod modcod, s32 pilots)
+{
+	u8 aclc = 0x29;
+	s32 i;
+	struct stv090x_long_frame_crloop *car_loop, *car_loop_qpsk_low, *car_loop_apsk_low;
+
+	if (state->dev_ver == 0x20) {
+		car_loop		= stv090x_s2_crl_cut20;
+		car_loop_qpsk_low	= stv090x_s2_lowqpsk_crl_cut20;
+		car_loop_apsk_low	= stv090x_s2_apsk_crl_cut20;
+	} else {
+		/* >= Cut 3 */
+		car_loop		= stv090x_s2_crl_cut30;
+		car_loop_qpsk_low	= stv090x_s2_lowqpsk_crl_cut30;
+		car_loop_apsk_low	= stv090x_s2_apsk_crl_cut30;
+	}
+
+	if (modcod < STV090x_QPSK_12) {
+		i = 0;
+		while ((i < 3) && (modcod != car_loop_qpsk_low[i].modcod))
+			i++;
+
+		if (i >= 3)
+			i = 2;
+
+	} else {
+		i = 0;
+		while ((i < 14) && (modcod != car_loop[i].modcod))
+			i++;
+
+		if (i >= 14) {
+			i = 0;
+			while ((i < 11) && (modcod != car_loop_apsk_low[i].modcod))
+				i++;
+
+			if (i >= 11)
+				i = 10;
+		}
+	}
+
+	if (modcod <= STV090x_QPSK_25) {
+		if (pilots) {
+			if (state->srate <= 3000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_on_2;
+			else if (state->srate <= 7000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_on_5;
+			else if (state->srate <= 15000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_on_10;
+			else if (state->srate <= 25000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_on_20;
+			else
+				aclc = car_loop_qpsk_low[i].crl_pilots_on_30;
+		} else {
+			if (state->srate <= 3000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_off_2;
+			else if (state->srate <= 7000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_off_5;
+			else if (state->srate <= 15000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_off_10;
+			else if (state->srate <= 25000000)
+				aclc = car_loop_qpsk_low[i].crl_pilots_off_20;
+			else
+				aclc = car_loop_qpsk_low[i].crl_pilots_off_30;
+		}
+
+	} else if (modcod <= STV090x_8PSK_910) {
+		if (pilots) {
+			if (state->srate <= 3000000)
+				aclc = car_loop[i].crl_pilots_on_2;
+			else if (state->srate <= 7000000)
+				aclc = car_loop[i].crl_pilots_on_5;
+			else if (state->srate <= 15000000)
+				aclc = car_loop[i].crl_pilots_on_10;
+			else if (state->srate <= 25000000)
+				aclc = car_loop[i].crl_pilots_on_20;
+			else
+				aclc = car_loop[i].crl_pilots_on_30;
+		} else {
+			if (state->srate <= 3000000)
+				aclc = car_loop[i].crl_pilots_off_2;
+			else if (state->srate <= 7000000)
+				aclc = car_loop[i].crl_pilots_off_5;
+			else if (state->srate <= 15000000)
+				aclc = car_loop[i].crl_pilots_off_10;
+			else if (state->srate <= 25000000)
+				aclc = car_loop[i].crl_pilots_off_20;
+			else
+				aclc = car_loop[i].crl_pilots_off_30;
+		}
+	} else { /* 16APSK and 32APSK */
+		if (state->srate <= 3000000)
+			aclc = car_loop_apsk_low[i].crl_pilots_on_2;
+		else if (state->srate <= 7000000)
+			aclc = car_loop_apsk_low[i].crl_pilots_on_5;
+		else if (state->srate <= 15000000)
+			aclc = car_loop_apsk_low[i].crl_pilots_on_10;
+		else if (state->srate <= 25000000)
+			aclc = car_loop_apsk_low[i].crl_pilots_on_20;
+		else
+			aclc = car_loop_apsk_low[i].crl_pilots_on_30;
+	}
+
+	return aclc;
+}
+
+static u8 stv090x_optimize_carloop_short(struct stv090x_state *state)
+{
+	struct stv090x_short_frame_crloop *short_crl;
+	s32 index = 0;
+	u8 aclc = 0x0b;
+
+	switch (state->modulation) {
+	case STV090x_QPSK:
+	default:
+		index = 0;
+		break;
+	case STV090x_8PSK:
+		index = 1;
+		break;
+	case STV090x_16APSK:
+		index = 2;
+		break;
+	case STV090x_32APSK:
+		index = 3;
+		break;
+	}
+
+	if (state->dev_ver >= 0x30)
+		short_crl = stv090x_s2_short_crl_cut20;
+	else if (state->dev_ver >= 0x20)
+		short_crl = stv090x_s2_short_crl_cut30;
+
+	if (state->srate <= 3000000)
+		aclc = short_crl[index].crl_2;
+	else if (state->srate <= 7000000)
+		aclc = short_crl[index].crl_5;
+	else if (state->srate <= 15000000)
+		aclc = short_crl[index].crl_10;
+	else if (state->srate <= 25000000)
+		aclc = short_crl[index].crl_20;
+	else
+		aclc = short_crl[index].crl_30;
+
+	return aclc;
+}
+
+static int stv090x_optimize_track(struct stv090x_state *state)
+{
+	struct dvb_frontend *fe = &state->frontend;
+
+	enum stv090x_rolloff rolloff;
+	enum stv090x_modcod modcod;
+
+	s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0;
+	u32 reg;
+
+	srate  = stv090x_get_srate(state, state->mclk);
+	srate += stv090x_get_tmgoffst(state, srate);
+
+	switch (state->delsys) {
+	case STV090x_DVBS1:
+	case STV090x_DSS:
+		if (state->algo == STV090x_SEARCH_AUTO) {
+			reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+			STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+			STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+			if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+				goto err;
+		}
+		reg = STV090x_READ_DEMOD(state, DEMOD);
+		STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff);
+		STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x01);
+		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+			goto err;
+
+		if (state->dev_ver >= 0x30) {
+			if (stv090x_get_viterbi(state) < 0)
+				goto err;
+
+			if (state->fec == STV090x_PR12) {
+				if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x98) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0)
+					goto err;
+			} else {
+				if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x18) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0)
+					goto err;
+			}
+		}
+
+		if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0)
+			goto err;
+		break;
+
+	case STV090x_DVBS2:
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0)
+			goto err;
+		if (state->frame_len == STV090x_LONG_FRAME) {
+			reg = STV090x_READ_DEMOD(state, DMDMODCOD);
+			modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD);
+			pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01;
+			aclc = stv090x_optimize_carloop(state, modcod, pilots);
+			if (modcod <= STV090x_QPSK_910) {
+				STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc);
+			} else if (modcod <= STV090x_8PSK_910) {
+				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0)
+					goto err;
+			}
+			if ((state->demod_mode == STV090x_SINGLE) && (modcod > STV090x_8PSK_910)) {
+				if (modcod <= STV090x_16APSK_910) {
+					if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+						goto err;
+					if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0)
+						goto err;
+				} else {
+					if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+						goto err;
+					if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0)
+						goto err;
+				}
+			}
+		} else {
+			/*Carrier loop setting for short frame*/
+			aclc = stv090x_optimize_carloop_short(state);
+			if (state->modulation == STV090x_QPSK) {
+				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc) < 0)
+					goto err;
+			} else if (state->modulation == STV090x_8PSK) {
+				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0)
+					goto err;
+			} else if (state->modulation == STV090x_16APSK) {
+				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0)
+					goto err;
+			} else if (state->modulation == STV090x_32APSK)  {
+				if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0)
+					goto err;
+			}
+		}
+
+		STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67); /* PER */
+		break;
+
+	case STV090x_UNKNOWN:
+	default:
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+		STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+		break;
+	}
+
+	f_1 = STV090x_READ_DEMOD(state, CFR2);
+	f_0 = STV090x_READ_DEMOD(state, CFR1);
+	reg = STV090x_READ_DEMOD(state, TMGOBS);
+	rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD);
+
+	if (state->algo == STV090x_BLIND_SEARCH) {
+		STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00);
+		reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+		STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0x00);
+		STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00);
+		if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0)
+			goto err;
+
+		if (stv090x_set_srate(state, srate) < 0)
+			goto err;
+		blind_tune = 1;
+	}
+
+	if (state->dev_ver >= 0x20) {
+		if ((state->search_mode == STV090x_SEARCH_DVBS1)	||
+		    (state->search_mode == STV090x_SEARCH_DSS)		||
+		    (state->search_mode == STV090x_SEARCH_AUTO)) {
+
+			if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x0a) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x00) < 0)
+				goto err;
+		}
+	}
+
+	if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+		goto err;
+
+	/* AUTO tracking MODE */
+	if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x80) < 0)
+		goto err;
+	/* AUTO tracking MODE */
+	if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x80) < 0)
+		goto err;
+
+	if ((state->dev_ver >= 0x20) || (blind_tune == 1) || (state->srate < 10000000)) {
+		/* update initial carrier freq with the found freq offset */
+		if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+			goto err;
+		state->tuner_bw = stv090x_car_width(srate, state->rolloff) + 10000000;
+
+		if ((state->dev_ver >= 0x20) || (blind_tune == 1)) {
+
+			if (state->algo != STV090x_WARM_SEARCH) {
+
+				if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+					goto err;
+
+				if (state->config->tuner_set_bandwidth) {
+					if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+						goto err;
+				}
+
+				if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+					goto err;
+
+			}
+		}
+		if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000))
+			msleep(50); /* blind search: wait 50ms for SR stabilization */
+		else
+			msleep(5);
+
+		stv090x_get_lock_tmg(state);
+
+		if (!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) {
+			if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+				goto err;
+
+			i = 0;
+
+			while ((!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) && (i <= 2)) {
+
+				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+					goto err;
+				if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+					goto err;
+				i++;
+			}
+		}
+
+	}
+
+	if (state->dev_ver >= 0x20) {
+		if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+			goto err;
+	}
+
+	if ((state->delsys == STV090x_DVBS1) || (state->delsys == STV090x_DSS))
+		stv090x_set_vit_thtracq(state);
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_get_feclock(struct stv090x_state *state, s32 timeout)
+{
+	s32 timer = 0, lock = 0, stat;
+	u32 reg;
+
+	while ((timer < timeout) && (!lock)) {
+		reg = STV090x_READ_DEMOD(state, DMDSTATE);
+		stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+		switch (stat) {
+		case 0: /* searching */
+		case 1: /* first PLH detected */
+		default:
+			lock = 0;
+			break;
+
+		case 2: /* DVB-S2 mode */
+			reg = STV090x_READ_DEMOD(state, PDELSTATUS1);
+			lock = STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD);
+			break;
+
+		case 3: /* DVB-S1/legacy mode */
+			reg = STV090x_READ_DEMOD(state, VSTATUSVIT);
+			lock = STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD);
+			break;
+		}
+		if (!lock) {
+			msleep(10);
+			timer += 10;
+		}
+	}
+	return lock;
+}
+
+static int stv090x_get_lock(struct stv090x_state *state, s32 timeout_dmd, s32 timeout_fec)
+{
+	u32 reg;
+	s32 timer = 0;
+	int lock;
+
+	lock = stv090x_get_dmdlock(state, timeout_dmd);
+	if (lock)
+		lock = stv090x_get_feclock(state, timeout_fec);
+
+	if (lock) {
+		lock = 0;
+
+		while ((timer < timeout_fec) && (!lock)) {
+			reg = STV090x_READ_DEMOD(state, TSSTATUS);
+			lock = STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD);
+			msleep(1);
+			timer++;
+		}
+	}
+
+	return lock;
+}
+
+static int stv090x_set_s2rolloff(struct stv090x_state *state)
+{
+	u32 reg;
+
+	if (state->dev_ver <= 0x20) {
+		/* rolloff to auto mode if DVBS2 */
+		reg = STV090x_READ_DEMOD(state, DEMOD);
+		STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x00);
+		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+			goto err;
+	} else {
+		/* DVB-S2 rolloff to auto mode if DVBS2 */
+		reg = STV090x_READ_DEMOD(state, DEMOD);
+		STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 0x00);
+		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+			goto err;
+	}
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+
+static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
+{
+	struct dvb_frontend *fe = &state->frontend;
+	enum stv090x_signal_state signal_state = STV090x_NOCARRIER;
+	u32 reg;
+	s32 timeout_dmd = 500, timeout_fec = 50, agc1_power, power_iq = 0, i;
+	int lock = 0, low_sr = 0, no_signal = 0;
+
+	reg = STV090x_READ_DEMOD(state, TSCFGH);
+	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */
+	if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+		goto err;
+
+	if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod stop */
+		goto err;
+
+	if (state->dev_ver >= 0x20) {
+		if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0) /* cut 2.0 */
+			goto err;
+	}
+
+	stv090x_get_lock_tmg(state);
+
+	if (state->algo == STV090x_BLIND_SEARCH) {
+		state->tuner_bw = 2 * 36000000; /* wide bw for unknown srate */
+		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0) /* wider srate scan */
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0)
+			goto err;
+		if (stv090x_set_srate(state, 1000000) < 0) /* inital srate = 1Msps */
+			goto err;
+	} else {
+		/* known srate */
+		if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0)
+			goto err;
+		if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0)
+			goto err;
+
+		if (state->srate < 2000000) {
+			/* SR < 2MSPS */
+			if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x63) < 0)
+				goto err;
+		} else {
+			/* SR >= 2Msps */
+			if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0)
+				goto err;
+		}
+
+		if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+			goto err;
+
+		if (state->dev_ver >= 0x20) {
+			if (STV090x_WRITE_DEMOD(state, KREFTMG, 0x5a) < 0)
+				goto err;
+			if (state->algo == STV090x_COLD_SEARCH)
+				state->tuner_bw = (15 * (stv090x_car_width(state->srate, state->rolloff) + 10000000)) / 10;
+			else if (state->algo == STV090x_WARM_SEARCH)
+				state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + 10000000;
+		}
+
+		/* if cold start or warm  (Symbolrate is known)
+		 * use a Narrow symbol rate scan range
+		 */
+		if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) /* narrow srate scan */
+			goto err;
+
+		if (stv090x_set_srate(state, state->srate) < 0)
+			goto err;
+
+		if (stv090x_set_max_srate(state, state->mclk, state->srate) < 0)
+			goto err;
+		if (stv090x_set_min_srate(state, state->mclk, state->srate) < 0)
+			goto err;
+
+		if (state->srate >= 10000000)
+			low_sr = 0;
+		else
+			low_sr = 1;
+	}
+
+	/* Setup tuner */
+	if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+		goto err;
+
+	if (state->config->tuner_set_bbgain) {
+		if (state->config->tuner_set_bbgain(fe, 10) < 0) /* 10dB */
+			goto err;
+	}
+
+	if (state->config->tuner_set_frequency) {
+		if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+			goto err;
+	}
+
+	if (state->config->tuner_set_bandwidth) {
+		if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+			goto err;
+	}
+
+	if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+		goto err;
+
+	msleep(50);
+
+	if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+		goto err;
+
+	if (state->config->tuner_get_status) {
+		if (state->config->tuner_get_status(fe, &reg) < 0)
+			goto err;
+	}
+
+	if (reg)
+		dprintk(FE_DEBUG, 1, "Tuner phase locked");
+	else
+		dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+	if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+		goto err;
+
+	msleep(10);
+	agc1_power = MAKEWORD16(STV090x_READ_DEMOD(state, AGCIQIN1),
+				STV090x_READ_DEMOD(state, AGCIQIN0));
+
+	if (agc1_power == 0) {
+		/* If AGC1 integrator value is 0
+		 * then read POWERI, POWERQ
+		 */
+		for (i = 0; i < 5; i++) {
+			power_iq += (STV090x_READ_DEMOD(state, POWERI) +
+				     STV090x_READ_DEMOD(state, POWERQ)) >> 1;
+		}
+		power_iq /= 5;
+	}
+
+	if ((agc1_power == 0) && (power_iq < STV090x_IQPOWER_THRESHOLD)) {
+		dprintk(FE_ERROR, 1, "No Signal: POWER_IQ=0x%02x", power_iq);
+		lock = 0;
+
+	} else {
+		reg = STV090x_READ_DEMOD(state, DEMOD);
+		STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion);
+
+		if (state->dev_ver <= 0x20) {
+			/* rolloff to auto mode if DVBS2 */
+			STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 1);
+		} else {
+			/* DVB-S2 rolloff to auto mode if DVBS2 */
+			STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 1);
+		}
+		if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+			goto err;
+
+		if (stv090x_delivery_search(state) < 0)
+			goto err;
+
+		if (state->algo != STV090x_BLIND_SEARCH) {
+			if (stv090x_start_search(state) < 0)
+				goto err;
+		}
+	}
+
+	/* need to check for AGC1 state */
+
+
+
+	if (state->algo == STV090x_BLIND_SEARCH)
+		lock = stv090x_blind_search(state);
+
+	else if (state->algo == STV090x_COLD_SEARCH)
+		lock = stv090x_get_coldlock(state, timeout_dmd);
+
+	else if (state->algo == STV090x_WARM_SEARCH)
+		lock = stv090x_get_dmdlock(state, timeout_dmd);
+
+	if ((!lock) && (state->algo == STV090x_COLD_SEARCH)) {
+		if (!low_sr) {
+			if (stv090x_chk_tmg(state))
+				lock = stv090x_sw_algo(state);
+		}
+	}
+
+	if (lock)
+		signal_state = stv090x_get_sig_params(state);
+
+	if ((lock) && (signal_state == STV090x_RANGEOK)) { /* signal within Range */
+		stv090x_optimize_track(state);
+
+		if (state->dev_ver >= 0x20) {
+			/* >= Cut 2.0 :release TS reset after
+			 * demod lock and optimized Tracking
+			 */
+			reg = STV090x_READ_DEMOD(state, TSCFGH);
+			STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */
+			if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+				goto err;
+
+			msleep(3);
+
+			STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* merger reset */
+			if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+				goto err;
+
+			STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */
+			if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+				goto err;
+		}
+
+		if (stv090x_get_lock(state, timeout_fec, timeout_fec)) {
+			lock = 1;
+			if (state->delsys == STV090x_DVBS2) {
+				stv090x_set_s2rolloff(state);
+
+				reg = STV090x_READ_DEMOD(state, PDELCTRL2);
+				STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 1);
+				if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
+					goto err;
+				/* Reset DVBS2 packet delinator error counter */
+				reg = STV090x_READ_DEMOD(state, PDELCTRL2);
+				STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 0);
+				if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
+					goto err;
+
+				if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67) < 0) /* PER */
+					goto err;
+			} else {
+				if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0)
+					goto err;
+			}
+			/* Reset the Total packet counter */
+			if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0x00) < 0)
+				goto err;
+			/* Reset the packet Error counter2 */
+			if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
+				goto err;
+		} else {
+			lock = 0;
+			signal_state = STV090x_NODATA;
+			no_signal = stv090x_chk_signal(state);
+		}
+	}
+	return signal_state;
+
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *props = &fe->dtv_property_cache;
+
+	state->delsys = props->delivery_system;
+	state->frequency = p->frequency;
+	state->srate = p->u.qpsk.symbol_rate;
+	state->search_mode = STV090x_SEARCH_AUTO;
+	state->algo = STV090x_COLD_SEARCH;
+	state->fec = STV090x_PRERR;
+	state->search_range = 2000000;
+
+	if (stv090x_algo(state) == STV090x_RANGEOK) {
+		dprintk(FE_DEBUG, 1, "Search success!");
+		return DVBFE_ALGO_SEARCH_SUCCESS;
+	} else {
+		dprintk(FE_DEBUG, 1, "Search failed!");
+		return DVBFE_ALGO_SEARCH_FAILED;
+	}
+
+	return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+/* FIXME! */
+static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg;
+	u8 search_state;
+
+	reg = STV090x_READ_DEMOD(state, DMDSTATE);
+	search_state = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+	switch (search_state) {
+	case 0: /* searching */
+	case 1: /* first PLH detected */
+	default:
+		dprintk(FE_DEBUG, 1, "Status: Unlocked (Searching ..)");
+		*status = 0;
+		break;
+
+	case 2: /* DVB-S2 mode */
+		dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2");
+		reg = STV090x_READ_DEMOD(state, DSTATUS);
+		if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) {
+			reg = STV090x_READ_DEMOD(state, TSSTATUS);
+			if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
+				*status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+			}
+		}
+		break;
+
+	case 3: /* DVB-S1/legacy mode */
+		dprintk(FE_DEBUG, 1, "Delivery system: DVB-S");
+		reg = STV090x_READ_DEMOD(state, DSTATUS);
+		if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) {
+			reg = STV090x_READ_DEMOD(state, VSTATUSVIT);
+			if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) {
+				reg = STV090x_READ_DEMOD(state, TSSTATUS);
+				if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
+					*status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+				}
+			}
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static int stv090x_read_per(struct dvb_frontend *fe, u32 *per)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+
+	s32 count_4, count_3, count_2, count_1, count_0, count;
+	u32 reg, h, m, l;
+	enum fe_status status;
+
+	stv090x_read_status(fe, &status);
+	if (!(status & FE_HAS_LOCK)) {
+		*per = 1 << 23; /* Max PER */
+	} else {
+		/* Counter 2 */
+		reg = STV090x_READ_DEMOD(state, ERRCNT22);
+		h = STV090x_GETFIELD_Px(reg, ERR_CNT2_FIELD);
+
+		reg = STV090x_READ_DEMOD(state, ERRCNT21);
+		m = STV090x_GETFIELD_Px(reg, ERR_CNT21_FIELD);
+
+		reg = STV090x_READ_DEMOD(state, ERRCNT20);
+		l = STV090x_GETFIELD_Px(reg, ERR_CNT20_FIELD);
+
+		*per = ((h << 16) | (m << 8) | l);
+
+		count_4 = STV090x_READ_DEMOD(state, FBERCPT4);
+		count_3 = STV090x_READ_DEMOD(state, FBERCPT3);
+		count_2 = STV090x_READ_DEMOD(state, FBERCPT2);
+		count_1 = STV090x_READ_DEMOD(state, FBERCPT1);
+		count_0 = STV090x_READ_DEMOD(state, FBERCPT0);
+
+		if ((!count_4) && (!count_3)) {
+			count  = (count_2 & 0xff) << 16;
+			count |= (count_1 & 0xff) <<  8;
+			count |=  count_0 & 0xff;
+		} else {
+			count = 1 << 24;
+		}
+		if (count == 0)
+			*per = 1;
+	}
+	if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val)
+{
+	int res = 0;
+	int min = 0, med;
+
+	if (val < tab[min].read)
+		res = tab[min].real;
+	else if (val >= tab[max].read)
+		res = tab[max].real;
+	else {
+		while ((max - min) > 1) {
+			med = (max + min) / 2;
+			if (val >= tab[min].read && val < tab[med].read)
+				max = med;
+			else
+				min = med;
+		}
+		res = ((val - tab[min].read) *
+		       (tab[max].real - tab[min].real) /
+		       (tab[max].read - tab[min].read)) +
+			tab[min].real;
+	}
+
+	return res;
+}
+
+static int stv090x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg;
+	s32 agc;
+
+	reg = STV090x_READ_DEMOD(state, AGCIQIN1);
+	agc = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
+
+	*strength = stv090x_table_lookup(stv090x_rf_tab, ARRAY_SIZE(stv090x_rf_tab) - 1, agc);
+	if (agc > stv090x_rf_tab[0].read)
+		*strength = 5;
+	else if (agc < stv090x_rf_tab[ARRAY_SIZE(stv090x_rf_tab) - 1].read)
+		*strength = -100;
+
+	return 0;
+}
+
+static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg_0, reg_1, reg, i;
+	s32 val_0, val_1, val = 0;
+	u8 lock_f;
+
+	switch (state->delsys) {
+	case STV090x_DVBS2:
+		reg = STV090x_READ_DEMOD(state, DSTATUS);
+		lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+		if (lock_f) {
+			msleep(5);
+			for (i = 0; i < 16; i++) {
+				reg_1 = STV090x_READ_DEMOD(state, NNOSPLHT1);
+				val_1 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
+				reg_0 = STV090x_READ_DEMOD(state, NNOSPLHT0);
+				val_0 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
+				val  += MAKEWORD16(val_1, val_0);
+				msleep(1);
+			}
+			val /= 16;
+			*cnr = stv090x_table_lookup(stv090x_s2cn_tab, ARRAY_SIZE(stv090x_s2cn_tab) - 1, val);
+			if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s2cn_tab) - 1].read)
+				*cnr = 1000;
+		}
+		break;
+
+	case STV090x_DVBS1:
+	case STV090x_DSS:
+		reg = STV090x_READ_DEMOD(state, DSTATUS);
+		lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+		if (lock_f) {
+			msleep(5);
+			for (i = 0; i < 16; i++) {
+				reg_1 = STV090x_READ_DEMOD(state, NOSDATAT1);
+				val_1 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
+				reg_0 = STV090x_READ_DEMOD(state, NOSDATAT0);
+				val_0 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
+				val  += MAKEWORD16(val_1, val_0);
+				msleep(1);
+			}
+			val /= 16;
+			*cnr = stv090x_table_lookup(stv090x_s1cn_tab, ARRAY_SIZE(stv090x_s1cn_tab) - 1, val);
+			if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s1cn_tab) - 1].read)
+				*cnr = 1000;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int stv090x_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg;
+
+	reg = STV090x_READ_DEMOD(state, DISTXCTL);
+	switch (tone) {
+	case SEC_TONE_ON:
+		STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0);
+		STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+			goto err;
+		STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+		if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+			goto err;
+		break;
+
+	case SEC_TONE_OFF:
+		STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0);
+		STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+		if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+			goto err;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+
+static enum dvbfe_algo stv090x_frontend_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_CUSTOM;
+}
+
+static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg, idle = 0, fifo_full = 1;
+	int i;
+
+	reg = STV090x_READ_DEMOD(state, DISTXCTL);
+
+	STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 2);
+	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	for (i = 0; i < cmd->msg_len; i++) {
+
+		while (fifo_full) {
+			reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+			fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD);
+		}
+
+		if (STV090x_WRITE_DEMOD(state, DISTXDATA, cmd->msg[i]) < 0)
+			goto err;
+	}
+	reg = STV090x_READ_DEMOD(state, DISTXCTL);
+	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	i = 0;
+
+	while ((!idle) && (i < 10)) {
+		reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+		idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD);
+		msleep(10);
+		i++;
+	}
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg, idle = 0, fifo_full = 1;
+	u8 mode, value;
+	int i;
+
+	reg = STV090x_READ_DEMOD(state, DISTXCTL);
+
+	if (burst == SEC_MINI_A) {
+		mode = 3;
+		value = 0x00;
+	} else {
+		mode = 2;
+		value = 0xFF;
+	}
+
+	STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, mode);
+	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+	STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	while (fifo_full) {
+		reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+		fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD);
+	}
+
+	if (STV090x_WRITE_DEMOD(state, DISTXDATA, value) < 0)
+		goto err;
+
+	reg = STV090x_READ_DEMOD(state, DISTXCTL);
+	STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0);
+	if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+		goto err;
+
+	i = 0;
+
+	while ((!idle) && (i < 10)) {
+		reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+		idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD);
+		msleep(10);
+		i++;
+	}
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg = 0, i = 0, rx_end = 0;
+
+	while ((rx_end != 1) && (i < 10)) {
+		msleep(10);
+		i++;
+		reg = STV090x_READ_DEMOD(state, DISRX_ST0);
+		rx_end = STV090x_GETFIELD_Px(reg, RX_END_FIELD);
+	}
+
+	if (rx_end) {
+		reply->msg_len = STV090x_GETFIELD_Px(reg, FIFO_BYTENBR_FIELD);
+		for (i = 0; i < reply->msg_len; i++)
+			reply->msg[i] = STV090x_READ_DEMOD(state, DISRXDATA);
+	}
+
+	return 0;
+}
+
+static int stv090x_sleep(struct dvb_frontend *fe)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg;
+
+	dprintk(FE_DEBUG, 1, "Set %s to sleep",
+		state->device == STV0900 ? "STV0900" : "STV0903");
+
+	reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+	STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01);
+	if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
+		goto err;
+
+	reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+	STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0);
+	if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_wakeup(struct dvb_frontend *fe)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	u32 reg;
+
+	dprintk(FE_DEBUG, 1, "Wake %s from standby",
+		state->device == STV0900 ? "STV0900" : "STV0903");
+
+	reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+	STV090x_SETFIELD(reg, STANDBY_FIELD, 0x00);
+	if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
+		goto err;
+
+	reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+	STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1);
+	if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static void stv090x_release(struct dvb_frontend *fe)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+
+	kfree(state);
+}
+
+static int stv090x_ldpc_mode(struct stv090x_state *state, enum stv090x_mode ldpc_mode)
+{
+	u32 reg = 0;
+
+	switch (ldpc_mode) {
+	case STV090x_DUAL:
+	default:
+		if ((state->demod_mode != STV090x_DUAL) || (STV090x_GETFIELD(reg, DDEMOD_FIELD) != 1)) {
+			/* set LDPC to dual mode */
+			if (stv090x_write_reg(state, STV090x_GENCFG, 0x1d) < 0)
+				goto err;
+
+			state->demod_mode = STV090x_DUAL;
+
+			reg = stv090x_read_reg(state, STV090x_TSTRES0);
+			STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1);
+			if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+				goto err;
+			STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0);
+			if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+				goto err;
+
+			if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0)
+				goto err;
+
+			if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0)
+				goto err;
+
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0)
+				goto err;
+			if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0)
+				goto err;
+		}
+		break;
+
+	case STV090x_SINGLE:
+		if (stv090x_stop_modcod(state) < 0)
+			goto err;
+		if (stv090x_activate_modcod_single(state) < 0)
+			goto err;
+
+		if (state->demod == STV090x_DEMODULATOR_1) {
+			if (stv090x_write_reg(state, STV090x_GENCFG, 0x06) < 0) /* path 2 */
+				goto err;
+		} else {
+			if (stv090x_write_reg(state, STV090x_GENCFG, 0x04) < 0) /* path 1 */
+				goto err;
+		}
+
+		reg = stv090x_read_reg(state, STV090x_TSTRES0);
+		STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1);
+		if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+			goto err;
+		STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0);
+		if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+			goto err;
+
+		reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+		STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x01);
+		if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+			goto err;
+		STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x00);
+		if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+			goto err;
+		break;
+	}
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+/* return (Hz), clk in Hz*/
+static u32 stv090x_get_mclk(struct stv090x_state *state)
+{
+	const struct stv090x_config *config = state->config;
+	u32 div, reg;
+	u8 ratio;
+
+	div = stv090x_read_reg(state, STV090x_NCOARSE);
+	reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+	ratio = STV090x_GETFIELD(reg, SELX1RATIO_FIELD) ? 4 : 6;
+
+	return (div + 1) * config->xtal / ratio; /* kHz */
+}
+
+static int stv090x_set_mclk(struct stv090x_state *state, u32 mclk, u32 clk)
+{
+	const struct stv090x_config *config = state->config;
+	u32 reg, div, clk_sel;
+
+	reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+	clk_sel = ((STV090x_GETFIELD(reg, SELX1RATIO_FIELD) == 1) ? 4 : 6);
+
+	div = ((clk_sel * mclk) / config->xtal) - 1;
+
+	reg = stv090x_read_reg(state, STV090x_NCOARSE);
+	STV090x_SETFIELD(reg, M_DIV_FIELD, div);
+	if (stv090x_write_reg(state, STV090x_NCOARSE, reg) < 0)
+		goto err;
+
+	state->mclk = stv090x_get_mclk(state);
+
+	/*Set the DiseqC frequency to 22KHz */
+	div = state->mclk / 704000;
+	if (STV090x_WRITE_DEMOD(state, F22TX, div) < 0)
+		goto err;
+	if (STV090x_WRITE_DEMOD(state, F22RX, div) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_set_tspath(struct stv090x_state *state)
+{
+	u32 reg;
+
+	if (state->dev_ver >= 0x20) {
+		switch (state->config->ts1_mode) {
+		case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		case STV090x_TSMODE_DVBCI:
+			switch (state->config->ts2_mode) {
+			case STV090x_TSMODE_SERIAL_PUNCTURED:
+			case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			default:
+				stv090x_write_reg(state, STV090x_TSGENERAL, 0x00);
+				break;
+
+			case STV090x_TSMODE_PARALLEL_PUNCTURED:
+			case STV090x_TSMODE_DVBCI:
+				if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x06) < 0) /* Mux'd stream mode */
+					goto err;
+				reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+				if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+					goto err;
+				reg = stv090x_read_reg(state, STV090x_P2_TSCFGM);
+				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+				if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0)
+					goto err;
+				if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0)
+					goto err;
+				if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0)
+					goto err;
+				break;
+			}
+			break;
+
+		case STV090x_TSMODE_SERIAL_PUNCTURED:
+		case STV090x_TSMODE_SERIAL_CONTINUOUS:
+		default:
+			switch (state->config->ts2_mode) {
+			case STV090x_TSMODE_SERIAL_PUNCTURED:
+			case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			default:
+				if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
+					goto err;
+				break;
+
+			case STV090x_TSMODE_PARALLEL_PUNCTURED:
+			case STV090x_TSMODE_DVBCI:
+				if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0a) < 0)
+					goto err;
+				break;
+			}
+			break;
+		}
+	} else {
+		switch (state->config->ts1_mode) {
+		case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		case STV090x_TSMODE_DVBCI:
+			switch (state->config->ts2_mode) {
+			case STV090x_TSMODE_SERIAL_PUNCTURED:
+			case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			default:
+				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x10);
+				break;
+
+			case STV090x_TSMODE_PARALLEL_PUNCTURED:
+			case STV090x_TSMODE_DVBCI:
+				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x16);
+				reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+				if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+					goto err;
+				reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+				STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 0);
+				if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+					goto err;
+				if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0)
+					goto err;
+				if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0)
+					goto err;
+				break;
+			}
+			break;
+
+		case STV090x_TSMODE_SERIAL_PUNCTURED:
+		case STV090x_TSMODE_SERIAL_CONTINUOUS:
+		default:
+			switch (state->config->ts2_mode) {
+			case STV090x_TSMODE_SERIAL_PUNCTURED:
+			case STV090x_TSMODE_SERIAL_CONTINUOUS:
+			default:
+				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x14);
+				break;
+
+			case STV090x_TSMODE_PARALLEL_PUNCTURED:
+			case STV090x_TSMODE_DVBCI:
+				stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x12);
+				break;
+			}
+			break;
+		}
+	}
+
+	switch (state->config->ts1_mode) {
+	case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_DVBCI:
+		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_SERIAL_PUNCTURED:
+		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_SERIAL_CONTINUOUS:
+		reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+		if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	default:
+		break;
+	}
+
+	switch (state->config->ts2_mode) {
+	case STV090x_TSMODE_PARALLEL_PUNCTURED:
+		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_DVBCI:
+		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_SERIAL_PUNCTURED:
+		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	case STV090x_TSMODE_SERIAL_CONTINUOUS:
+		reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+		STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+		STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+		if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+			goto err;
+		break;
+
+	default:
+		break;
+	}
+	reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
+	if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+		goto err;
+	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
+	if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+		goto err;
+
+	reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
+	if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+		goto err;
+	STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
+	if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_init(struct dvb_frontend *fe)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	const struct stv090x_config *config = state->config;
+	u32 reg;
+
+	if (stv090x_wakeup(fe) < 0) {
+		dprintk(FE_ERROR, 1, "Error waking device");
+		goto err;
+	}
+
+	if (stv090x_ldpc_mode(state, state->demod_mode) < 0)
+		goto err;
+
+	reg = STV090x_READ_DEMOD(state, TNRCFG2);
+	STV090x_SETFIELD_Px(reg, TUN_IQSWAP_FIELD, state->inversion);
+	if (STV090x_WRITE_DEMOD(state, TNRCFG2, reg) < 0)
+		goto err;
+	reg = STV090x_READ_DEMOD(state, DEMOD);
+	STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff);
+	if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+		goto err;
+
+	if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+		goto err;
+
+	if (config->tuner_set_mode) {
+		if (config->tuner_set_mode(fe, TUNER_WAKE) < 0)
+			goto err;
+	}
+
+	if (config->tuner_init) {
+		if (config->tuner_init(fe) < 0)
+			goto err;
+	}
+
+	if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+		goto err;
+
+	if (stv090x_set_tspath(state) < 0)
+		goto err;
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static int stv090x_setup(struct dvb_frontend *fe)
+{
+	struct stv090x_state *state = fe->demodulator_priv;
+	const struct stv090x_config *config = state->config;
+	const struct stv090x_reg *stv090x_initval = NULL;
+	const struct stv090x_reg *stv090x_cut20_val = NULL;
+	unsigned long t1_size = 0, t2_size = 0;
+	u32 reg = 0;
+
+	int i;
+
+	if (state->device == STV0900) {
+		dprintk(FE_DEBUG, 1, "Initializing STV0900");
+		stv090x_initval = stv0900_initval;
+		t1_size = ARRAY_SIZE(stv0900_initval);
+		stv090x_cut20_val = stv0900_cut20_val;
+		t2_size = ARRAY_SIZE(stv0900_cut20_val);
+	} else if (state->device == STV0903) {
+		dprintk(FE_DEBUG, 1, "Initializing STV0903");
+		stv090x_initval = stv0903_initval;
+		t1_size = ARRAY_SIZE(stv0903_initval);
+		stv090x_cut20_val = stv0903_cut20_val;
+		t2_size = ARRAY_SIZE(stv0903_cut20_val);
+	}
+
+	/* STV090x init */
+	if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Stop Demod */
+		goto err;
+
+	msleep(5);
+
+	if (STV090x_WRITE_DEMOD(state, TNRCFG, 0x6c) < 0) /* check register ! (No Tuner Mode) */
+		goto err;
+
+	STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level);
+	if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0) /* repeater OFF */
+		goto err;
+
+	if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */
+		goto err;
+	msleep(5);
+	if (stv090x_write_reg(state, STV090x_I2CCFG, 0x08) < 0) /* 1/41 oversampling */
+		goto err;
+	if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0) /* enable PLL */
+		goto err;
+	msleep(5);
+
+	/* write initval */
+	dprintk(FE_DEBUG, 1, "Setting up initial values");
+	for (i = 0; i < t1_size; i++) {
+		if (stv090x_write_reg(state, stv090x_initval[i].addr, stv090x_initval[i].data) < 0)
+			goto err;
+	}
+
+	state->dev_ver = stv090x_read_reg(state, STV090x_MID);
+	if (state->dev_ver >= 0x20) {
+		if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
+			goto err;
+
+		/* write cut20_val*/
+		dprintk(FE_DEBUG, 1, "Setting up Cut 2.0 initial values");
+		for (i = 0; i < t2_size; i++) {
+			if (stv090x_write_reg(state, stv090x_cut20_val[i].addr, stv090x_cut20_val[i].data) < 0)
+				goto err;
+		}
+
+	} else if (state->dev_ver < 0x20) {
+		dprintk(FE_ERROR, 1, "ERROR: Unsupported Cut: 0x%02x!",
+			state->dev_ver);
+
+		goto err;
+	} else if (state->dev_ver > 0x30) {
+		/* we shouldn't bail out from here */
+		dprintk(FE_ERROR, 1, "INFO: Cut: 0x%02x probably incomplete support!",
+			state->dev_ver);
+	}
+
+	if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0)
+		goto err;
+	if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0)
+		goto err;
+
+	stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */
+	msleep(5);
+	if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0)
+		goto err;
+	stv090x_get_mclk(state);
+
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "I/O error");
+	return -1;
+}
+
+static struct dvb_frontend_ops stv090x_ops = {
+
+	.info = {
+		.name			= "STV090x Multistandard",
+		.type			= FE_QPSK,
+		.frequency_min		= 950000,
+		.frequency_max 		= 2150000,
+		.frequency_stepsize	= 0,
+		.frequency_tolerance	= 0,
+		.symbol_rate_min 	= 1000000,
+		.symbol_rate_max 	= 45000000,
+		.caps			= FE_CAN_INVERSION_AUTO |
+					  FE_CAN_FEC_AUTO       |
+					  FE_CAN_QPSK           |
+					  FE_CAN_2G_MODULATION
+	},
+
+	.release			= stv090x_release,
+	.init				= stv090x_init,
+
+	.sleep				= stv090x_sleep,
+	.get_frontend_algo		= stv090x_frontend_algo,
+
+	.i2c_gate_ctrl			= stv090x_i2c_gate_ctrl,
+
+	.diseqc_send_master_cmd		= stv090x_send_diseqc_msg,
+	.diseqc_send_burst		= stv090x_send_diseqc_burst,
+	.diseqc_recv_slave_reply	= stv090x_recv_slave_reply,
+	.set_tone			= stv090x_set_tone,
+
+	.search				= stv090x_search,
+	.read_status			= stv090x_read_status,
+	.read_ber			= stv090x_read_per,
+	.read_signal_strength		= stv090x_read_signal_strength,
+	.read_snr			= stv090x_read_cnr
+};
+
+
+struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+				    struct i2c_adapter *i2c,
+				    enum stv090x_demodulator demod)
+{
+	struct stv090x_state *state = NULL;
+
+	state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	state->verbose				= &verbose;
+	state->config				= config;
+	state->i2c				= i2c;
+	state->frontend.ops			= stv090x_ops;
+	state->frontend.demodulator_priv	= state;
+	state->demod				= demod;
+	state->demod_mode 			= config->demod_mode; /* Single or Dual mode */
+	state->device				= config->device;
+	state->rolloff				= STV090x_RO_35; /* default */
+
+	if (state->demod == STV090x_DEMODULATOR_0)
+		mutex_init(&demod_lock);
+
+	if (stv090x_sleep(&state->frontend) < 0) {
+		dprintk(FE_ERROR, 1, "Error putting device to sleep");
+		goto error;
+	}
+
+	if (stv090x_setup(&state->frontend) < 0) {
+		dprintk(FE_ERROR, 1, "Error setting up device");
+		goto error;
+	}
+	if (stv090x_wakeup(&state->frontend) < 0) {
+		dprintk(FE_ERROR, 1, "Error waking device");
+		goto error;
+	}
+
+	dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x\n",
+	       state->device == STV0900 ? "STV0900" : "STV0903",
+	       demod,
+	       state->dev_ver);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(stv090x_attach);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend");
+MODULE_LICENSE("GPL");

+ 106 - 0
drivers/media/dvb/frontends/stv090x.h

@@ -0,0 +1,106 @@
+/*
+	STV0900/0903 Multistandard Broadcast Frontend driver
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV090x_H
+#define __STV090x_H
+
+enum stv090x_demodulator {
+	STV090x_DEMODULATOR_0 = 1,
+	STV090x_DEMODULATOR_1
+};
+
+enum stv090x_device {
+	STV0903	=  0,
+	STV0900,
+};
+
+enum stv090x_mode {
+	STV090x_DUAL = 0,
+	STV090x_SINGLE
+};
+
+enum stv090x_tsmode {
+	STV090x_TSMODE_SERIAL_PUNCTURED	= 1,
+	STV090x_TSMODE_SERIAL_CONTINUOUS,
+	STV090x_TSMODE_PARALLEL_PUNCTURED,
+	STV090x_TSMODE_DVBCI
+};
+
+enum stv090x_clkmode {
+	STV090x_CLK_INT = 0, /* Clk i/p = CLKI */
+	STV090x_CLK_EXT = 2 /* Clk i/p = XTALI */
+};
+
+enum stv090x_i2crpt {
+	STV090x_RPTLEVEL_256	= 0,
+	STV090x_RPTLEVEL_128	= 1,
+	STV090x_RPTLEVEL_64	= 2,
+	STV090x_RPTLEVEL_32	= 3,
+	STV090x_RPTLEVEL_16	= 4,
+	STV090x_RPTLEVEL_8	= 5,
+	STV090x_RPTLEVEL_4	= 6,
+	STV090x_RPTLEVEL_2	= 7,
+};
+
+struct stv090x_config {
+	enum stv090x_device	device;
+	enum stv090x_mode	demod_mode;
+	enum stv090x_clkmode	clk_mode;
+
+	u32 xtal; /* default: 8000000 */
+	u8 address; /* default: 0x68 */
+
+	u32 ref_clk; /* default: 16000000 FIXME to tuner config */
+
+	u8 ts1_mode;
+	u8 ts2_mode;
+
+	enum stv090x_i2crpt	repeater_level;
+
+	int (*tuner_init) (struct dvb_frontend *fe);
+	int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
+	int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
+	int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
+	int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
+	int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
+	int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
+	int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
+	int (*tuner_set_refclk)  (struct dvb_frontend *fe, u32 refclk);
+	int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
+};
+
+#if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+					   struct i2c_adapter *i2c,
+					   enum stv090x_demodulator demod);
+#else
+
+static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+						  struct i2c_adapter *i2c,
+						  enum stv090x_demodulator demod)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_STV090x */
+
+#endif /* __STV090x_H */

+ 269 - 0
drivers/media/dvb/frontends/stv090x_priv.h

@@ -0,0 +1,269 @@
+/*
+	STV0900/0903 Multistandard Broadcast Frontend driver
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV090x_PRIV_H
+#define __STV090x_PRIV_H
+
+#include "dvb_frontend.h"
+
+#define FE_ERROR				0
+#define FE_NOTICE				1
+#define FE_INFO					2
+#define FE_DEBUG				3
+#define FE_DEBUGREG				4
+
+#define dprintk(__y, __z, format, arg...) do {						\
+	if (__z) {									\
+		if	((verbose > FE_ERROR) && (verbose > __y))			\
+			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
+		else if	((verbose > FE_NOTICE) && (verbose > __y))			\
+			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
+		else if ((verbose > FE_INFO) && (verbose > __y))			\
+			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
+		else if ((verbose > FE_DEBUG) && (verbose > __y))			\
+			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
+	} else {									\
+		if (verbose > __y)							\
+			printk(format, ##arg);						\
+	}										\
+} while (0)
+
+#define STV090x_READ_DEMOD(__state, __reg) ((			\
+	(__state)->demod == STV090x_DEMODULATOR_1)	?	\
+	stv090x_read_reg(__state, STV090x_P2_##__reg) :		\
+	stv090x_read_reg(__state, STV090x_P1_##__reg))
+
+#define STV090x_WRITE_DEMOD(__state, __reg, __data) ((		\
+	(__state)->demod == STV090x_DEMODULATOR_1)	?	\
+	stv090x_write_reg(__state, STV090x_P2_##__reg, __data) :\
+	stv090x_write_reg(__state, STV090x_P1_##__reg, __data))
+
+#define STV090x_ADDR_OFFST(__state, __x) ((			\
+	(__state->demod) == STV090x_DEMODULATOR_1)	?	\
+		STV090x_P1_##__x :				\
+		STV090x_P2_##__x)
+
+
+#define STV090x_SETFIELD(mask, bitf, val)	(mask = (mask & (~(((1 << STV090x_WIDTH_##bitf) - 1) <<\
+							 STV090x_OFFST_##bitf))) | \
+							 (val << STV090x_OFFST_##bitf))
+
+#define STV090x_GETFIELD(val, bitf)		((val >> STV090x_OFFST_##bitf) & ((1 << STV090x_WIDTH_##bitf) - 1))
+
+
+#define STV090x_SETFIELD_Px(mask, bitf, val)	(mask = (mask & (~(((1 << STV090x_WIDTH_Px_##bitf) - 1) <<\
+							 STV090x_OFFST_Px_##bitf))) | \
+							 (val << STV090x_OFFST_Px_##bitf))
+
+#define STV090x_GETFIELD_Px(val, bitf)		((val >> STV090x_OFFST_Px_##bitf) & ((1 << STV090x_WIDTH_Px_##bitf) - 1))
+
+#define MAKEWORD16(__a, __b)			(((__a) << 8) | (__b))
+
+#define MSB(__x)				((__x >> 8) & 0xff)
+#define LSB(__x)				(__x & 0xff)
+
+
+#define STV090x_IQPOWER_THRESHOLD	  30
+#define STV090x_SEARCH_AGC2_TH_CUT20	 700
+#define STV090x_SEARCH_AGC2_TH_CUT30	1200
+
+#define STV090x_SEARCH_AGC2_TH(__ver)	\
+	((__ver <= 0x20) ?		\
+	STV090x_SEARCH_AGC2_TH_CUT20 :	\
+	STV090x_SEARCH_AGC2_TH_CUT30)
+
+enum stv090x_signal_state {
+	STV090x_NOCARRIER,
+	STV090x_NODATA,
+	STV090x_DATAOK,
+	STV090x_RANGEOK,
+	STV090x_OUTOFRANGE
+};
+
+enum stv090x_fec {
+	STV090x_PR12 = 0,
+	STV090x_PR23,
+	STV090x_PR34,
+	STV090x_PR45,
+	STV090x_PR56,
+	STV090x_PR67,
+	STV090x_PR78,
+	STV090x_PR89,
+	STV090x_PR910,
+	STV090x_PRERR
+};
+
+enum stv090x_modulation {
+	STV090x_QPSK,
+	STV090x_8PSK,
+	STV090x_16APSK,
+	STV090x_32APSK,
+	STV090x_UNKNOWN
+};
+
+enum stv090x_frame {
+	STV090x_LONG_FRAME,
+	STV090x_SHORT_FRAME
+};
+
+enum stv090x_pilot {
+	STV090x_PILOTS_OFF,
+	STV090x_PILOTS_ON
+};
+
+enum stv090x_rolloff {
+	STV090x_RO_35,
+	STV090x_RO_25,
+	STV090x_RO_20
+};
+
+enum stv090x_inversion {
+	STV090x_IQ_AUTO,
+	STV090x_IQ_NORMAL,
+	STV090x_IQ_SWAP
+};
+
+enum stv090x_modcod {
+	STV090x_DUMMY_PLF = 0,
+	STV090x_QPSK_14,
+	STV090x_QPSK_13,
+	STV090x_QPSK_25,
+	STV090x_QPSK_12,
+	STV090x_QPSK_35,
+	STV090x_QPSK_23,
+	STV090x_QPSK_34,
+	STV090x_QPSK_45,
+	STV090x_QPSK_56,
+	STV090x_QPSK_89,
+	STV090x_QPSK_910,
+	STV090x_8PSK_35,
+	STV090x_8PSK_23,
+	STV090x_8PSK_34,
+	STV090x_8PSK_56,
+	STV090x_8PSK_89,
+	STV090x_8PSK_910,
+	STV090x_16APSK_23,
+	STV090x_16APSK_34,
+	STV090x_16APSK_45,
+	STV090x_16APSK_56,
+	STV090x_16APSK_89,
+	STV090x_16APSK_910,
+	STV090x_32APSK_34,
+	STV090x_32APSK_45,
+	STV090x_32APSK_56,
+	STV090x_32APSK_89,
+	STV090x_32APSK_910,
+	STV090x_MODCODE_UNKNOWN
+};
+
+enum stv090x_search {
+	STV090x_SEARCH_DSS = 0,
+	STV090x_SEARCH_DVBS1,
+	STV090x_SEARCH_DVBS2,
+	STV090x_SEARCH_AUTO
+};
+
+enum stv090x_algo {
+	STV090x_BLIND_SEARCH,
+	STV090x_COLD_SEARCH,
+	STV090x_WARM_SEARCH
+};
+
+enum stv090x_delsys {
+	STV090x_ERROR = 0,
+	STV090x_DVBS1 = 1,
+	STV090x_DVBS2,
+	STV090x_DSS
+};
+
+struct stv090x_long_frame_crloop {
+	enum stv090x_modcod	modcod;
+
+	u8 crl_pilots_on_2;
+	u8 crl_pilots_off_2;
+	u8 crl_pilots_on_5;
+	u8 crl_pilots_off_5;
+	u8 crl_pilots_on_10;
+	u8 crl_pilots_off_10;
+	u8 crl_pilots_on_20;
+	u8 crl_pilots_off_20;
+	u8 crl_pilots_on_30;
+	u8 crl_pilots_off_30;
+};
+
+struct stv090x_short_frame_crloop {
+	enum stv090x_modulation	modulation;
+
+	u8 crl_2;  /*      SR <   3M */
+	u8 crl_5;  /*  3 < SR <=  7M */
+	u8 crl_10; /*  7 < SR <= 15M */
+	u8 crl_20; /* 10 < SR <= 25M */
+	u8 crl_30; /* 10 < SR <= 45M */
+};
+
+struct stv090x_reg {
+	u16 addr;
+	u8  data;
+};
+
+struct stv090x_tab {
+	s32 real;
+	s32 read;
+};
+
+struct stv090x_state {
+	enum stv090x_device		device;
+	enum stv090x_demodulator	demod;
+	enum stv090x_mode		demod_mode;
+	u32				dev_ver;
+
+	struct i2c_adapter		*i2c;
+	const struct stv090x_config	*config;
+	struct dvb_frontend		frontend;
+
+	u32				*verbose; /* Cached module verbosity */
+
+	enum stv090x_delsys		delsys;
+	enum stv090x_fec		fec;
+	enum stv090x_modulation		modulation;
+	enum stv090x_modcod		modcod;
+	enum stv090x_search		search_mode;
+	enum stv090x_frame		frame_len;
+	enum stv090x_pilot		pilots;
+	enum stv090x_rolloff		rolloff;
+	enum stv090x_inversion		inversion;
+	enum stv090x_algo		algo;
+
+	u32				frequency;
+	u32				srate;
+
+	s32				mclk; /* Masterclock Divider factor */
+	s32				tuner_bw;
+
+	u32				tuner_refclk;
+
+	s32				search_range;
+
+	s32				DemodTimeout;
+	s32				FecTimeout;
+};
+
+#endif /* __STV090x_PRIV_H */

+ 2373 - 0
drivers/media/dvb/frontends/stv090x_reg.h

@@ -0,0 +1,2373 @@
+/*
+	STV0900/0903 Multistandard Broadcast Frontend driver
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV090x_REG_H
+#define __STV090x_REG_H
+
+#define STV090x_MID				0xf100
+#define STV090x_OFFST_MCHIP_IDENT_FIELD		4
+#define STV090x_WIDTH_MCHIP_IDENT_FIELD		4
+#define STV090x_OFFST_MRELEASE_FIELD		0
+#define STV090x_WIDTH_MRELEASE_FIELD		4
+
+#define STV090x_DACR1				0xf113
+#define STV090x_OFFST_DACR1_MODE_FIELD		5
+#define STV090x_WIDTH_DACR1_MODE_FIELD		3
+#define STV090x_OFFST_DACR1_VALUE_FIELD		0
+#define STV090x_WIDTH_DACR1_VALUE_FIELD		4
+
+#define STV090x_DACR2				0xf114
+#define STV090x_OFFST_DACR2_VALUE_FIELD		0
+#define STV090x_WIDTH_DACR2_VALUE_FIELD		8
+
+#define STV090x_OUTCFG				0xf11c
+#define STV090x_OFFST_OUTSERRS1_HZ_FIELD	6
+#define STV090x_WIDTH_OUTSERRS1_HZ_FIELD	1
+#define STV090x_OFFST_OUTSERRS2_HZ_FIELD	5
+#define STV090x_WIDTH_OUTSERRS2_HZ_FIELD	1
+#define STV090x_OFFST_OUTSERRS3_HZ_FIELD	4
+#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD	1
+#define STV090x_OFFST_OUTPARRS3_HZ_FIELD	3
+#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD	1
+
+#define STV090x_MODECFG				0xf11d
+
+#define STV090x_IRQSTATUS3			0xf120
+#define STV090x_OFFST_SPLL_LOCK_FIELD		5
+#define STV090x_WIDTH_SPLL_LOCK_FIELD		1
+#define STV090x_OFFST_SSTREAM_LCK_3_FIELD	4
+#define STV090x_WIDTH_SSTREAM_LCK_3_FIELD	1
+#define STV090x_OFFST_SSTREAM_LCK_2_FIELD	3
+#define STV090x_WIDTH_SSTREAM_LCK_2_FIELD	1
+#define STV090x_OFFST_SSTREAM_LCK_1_FIELD	2
+#define STV090x_WIDTH_SSTREAM_LCK_1_FIELD	1
+#define STV090x_OFFST_SDVBS1_PRF_2_FIELD	1
+#define STV090x_WIDTH_SDVBS1_PRF_2_FIELD	1
+#define STV090x_OFFST_SDVBS1_PRF_1_FIELD	0
+#define STV090x_WIDTH_SDVBS1_PRF_1_FIELD	1
+
+#define STV090x_IRQSTATUS2			0xf121
+#define STV090x_OFFST_SSPY_ENDSIM_3_FIELD	7
+#define STV090x_WIDTH_SSPY_ENDSIM_3_FIELD	1
+#define STV090x_OFFST_SSPY_ENDSIM_2_FIELD	6
+#define STV090x_WIDTH_SSPY_ENDSIM_2_FIELD	1
+#define STV090x_OFFST_SSPY_ENDSIM_1_FIELD	5
+#define STV090x_WIDTH_SSPY_ENDSIM_1_FIELD	1
+#define STV090x_OFFST_SPKTDEL_ERROR_2_FIELD	4
+#define STV090x_WIDTH_SPKTDEL_ERROR_2_FIELD	1
+#define STV090x_OFFST_SPKTDEL_LOCKB_2_FIELD	3
+#define STV090x_WIDTH_SPKTDEL_LOCKB_2_FIELD	1
+#define STV090x_OFFST_SPKTDEL_LOCK_2_FIELD	2
+#define STV090x_WIDTH_SPKTDEL_LOCK_2_FIELD	1
+#define STV090x_OFFST_SPKTDEL_ERROR_1_FIELD	1
+#define STV090x_WIDTH_SPKTDEL_ERROR_1_FIELD	1
+#define STV090x_OFFST_SPKTDEL_LOCKB_1_FIELD	0
+#define STV090x_WIDTH_SPKTDEL_LOCKB_1_FIELD	1
+
+#define STV090x_IRQSTATUS1			0xf122
+#define STV090x_OFFST_SPKTDEL_LOCK_1_FIELD	7
+#define STV090x_WIDTH_SPKTDEL_LOCK_1_FIELD	1
+#define STV090x_OFFST_SDEMOD_LOCKB_2_FIELD	2
+#define STV090x_WIDTH_SDEMOD_LOCKB_2_FIELD	1
+#define STV090x_OFFST_SDEMOD_LOCK_2_FIELD	1
+#define STV090x_WIDTH_SDEMOD_LOCK_2_FIELD	1
+#define STV090x_OFFST_SDEMOD_IRQ_2_FIELD	0
+#define STV090x_WIDTH_SDEMOD_IRQ_2_FIELD	1
+
+#define STV090x_IRQSTATUS0			0xf123
+#define STV090x_OFFST_SDEMOD_LOCKB_1_FIELD	7
+#define STV090x_WIDTH_SDEMOD_LOCKB_1_FIELD	1
+#define STV090x_OFFST_SDEMOD_LOCK_1_FIELD	6
+#define STV090x_WIDTH_SDEMOD_LOCK_1_FIELD	1
+#define STV090x_OFFST_SDEMOD_IRQ_1_FIELD	5
+#define STV090x_WIDTH_SDEMOD_IRQ_1_FIELD	1
+#define STV090x_OFFST_SBCH_ERRFLAG_FIELD	4
+#define STV090x_WIDTH_SBCH_ERRFLAG_FIELD	1
+#define STV090x_OFFST_SDISEQC2RX_IRQ_FIELD	3
+#define STV090x_WIDTH_SDISEQC2RX_IRQ_FIELD	1
+#define STV090x_OFFST_SDISEQC2TX_IRQ_FIELD	2
+#define STV090x_WIDTH_SDISEQC2TX_IRQ_FIELD	1
+#define STV090x_OFFST_SDISEQC1RX_IRQ_FIELD	1
+#define STV090x_WIDTH_SDISEQC1RX_IRQ_FIELD	1
+#define STV090x_OFFST_SDISEQC1TX_IRQ_FIELD	0
+#define STV090x_WIDTH_SDISEQC1TX_IRQ_FIELD	1
+
+#define STV090x_IRQMASK3			0xf124
+#define STV090x_OFFST_MPLL_LOCK_FIELD		5
+#define STV090x_WIDTH_MPLL_LOCK_FIELD		1
+#define STV090x_OFFST_MSTREAM_LCK_3_FIELD	2
+#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD	3
+#define STV090x_OFFST_MSTREAM_LCK_2_FIELD	2
+#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD	3
+#define STV090x_OFFST_MSTREAM_LCK_1_FIELD	2
+#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD	3
+#define STV090x_OFFST_MDVBS1_PRF_2_FIELD	1
+#define STV090x_WIDTH_MDVBS1_PRF_2_FIELD	1
+#define STV090x_OFFST_MDVBS1_PRF_1_FIELD	0
+#define STV090x_WIDTH_MDVBS1_PRF_1_FIELD	1
+
+#define STV090x_IRQMASK2			0xf125
+#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD	5
+#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD	3
+#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD	5
+#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD	3
+#define STV090x_OFFST_MSPY_ENDSIM_1_FIELD	5
+#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD	3
+#define STV090x_OFFST_MPKTDEL_ERROR_2_FIELD	4
+#define STV090x_WIDTH_MPKTDEL_ERROR_2_FIELD	1
+#define STV090x_OFFST_MPKTDEL_LOCKB_2_FIELD	3
+#define STV090x_WIDTH_MPKTDEL_LOCKB_2_FIELD	1
+#define STV090x_OFFST_MPKTDEL_LOCK_2_FIELD	2
+#define STV090x_WIDTH_MPKTDEL_LOCK_2_FIELD	1
+#define STV090x_OFFST_MPKTDEL_ERROR_1_FIELD	1
+#define STV090x_WIDTH_MPKTDEL_ERROR_1_FIELD	1
+#define STV090x_OFFST_MPKTDEL_LOCKB_1_FIELD	0
+#define STV090x_WIDTH_MPKTDEL_LOCKB_1_FIELD	1
+
+#define STV090x_IRQMASK1			0xf126
+#define STV090x_OFFST_MPKTDEL_LOCK_1_FIELD	7
+#define STV090x_WIDTH_MPKTDEL_LOCK_1_FIELD	1
+#define STV090x_OFFST_MEXTPINB2_FIELD		6
+#define STV090x_WIDTH_MEXTPINB2_FIELD		1
+#define STV090x_OFFST_MEXTPIN2_FIELD		5
+#define STV090x_WIDTH_MEXTPIN2_FIELD		1
+#define STV090x_OFFST_MEXTPINB1_FIELD		4
+#define STV090x_WIDTH_MEXTPINB1_FIELD		1
+#define STV090x_OFFST_MEXTPIN1_FIELD		3
+#define STV090x_WIDTH_MEXTPIN1_FIELD		1
+#define STV090x_OFFST_MDEMOD_LOCKB_2_FIELD	2
+#define STV090x_WIDTH_MDEMOD_LOCKB_2_FIELD	1
+#define STV090x_OFFST_MDEMOD_LOCK_2_FIELD	1
+#define STV090x_WIDTH_MDEMOD_LOCK_2_FIELD	1
+#define STV090x_OFFST_MDEMOD_IRQ_2_FIELD	0
+#define STV090x_WIDTH_MDEMOD_IRQ_2_FIELD	1
+
+#define STV090x_IRQMASK0			0xf127
+#define STV090x_OFFST_MDEMOD_LOCKB_1_FIELD	7
+#define STV090x_WIDTH_MDEMOD_LOCKB_1_FIELD	1
+#define STV090x_OFFST_MDEMOD_LOCK_1_FIELD	6
+#define STV090x_WIDTH_MDEMOD_LOCK_1_FIELD	1
+#define STV090x_OFFST_MDEMOD_IRQ_1_FIELD	5
+#define STV090x_WIDTH_MDEMOD_IRQ_1_FIELD	1
+#define STV090x_OFFST_MBCH_ERRFLAG_FIELD	4
+#define STV090x_WIDTH_MBCH_ERRFLAG_FIELD	1
+#define STV090x_OFFST_MDISEQC2RX_IRQ_FIELD	3
+#define STV090x_WIDTH_MDISEQC2RX_IRQ_FIELD	1
+#define STV090x_OFFST_MDISEQC2TX_IRQ_FIELD	2
+#define STV090x_WIDTH_MDISEQC2TX_IRQ_FIELD	1
+#define STV090x_OFFST_MDISEQC1RX_IRQ_FIELD	1
+#define STV090x_WIDTH_MDISEQC1RX_IRQ_FIELD	1
+#define STV090x_OFFST_MDISEQC1TX_IRQ_FIELD	0
+#define STV090x_WIDTH_MDISEQC1TX_IRQ_FIELD	1
+
+#define STV090x_I2CCFG				0xf129
+#define STV090x_OFFST_12C_FASTMODE_FIELD	3
+#define STV090x_WIDTH_12C_FASTMODE_FIELD	1
+#define STV090x_OFFST_12CADDR_INC_FIELD		0
+#define STV090x_WIDTH_12CADDR_INC_FIELD		2
+
+#define STV090x_Px_I2CRPT(__x)			(0xf12a + (__x - 1) * 0x1)
+#define STV090x_P1_I2CRPT			STV090x_Px_I2CRPT(1)
+#define STV090x_P2_I2CRPT			STV090x_Px_I2CRPT(2)
+#define STV090x_OFFST_Px_I2CT_ON_FIELD		7
+#define STV090x_WIDTH_Px_I2CT_ON_FIELD		1
+#define STV090x_OFFST_Px_ENARPT_LEVEL_FIELD	4
+#define STV090x_WIDTH_Px_ENARPT_LEVEL_FIELD	3
+#define STV090x_OFFST_Px_SCLT_DELAY_FIELD	3
+#define STV090x_WIDTH_Px_SCLT_DELAY_FIELD	1
+#define STV090x_OFFST_Px_STOP_ENABLE_FIELD	2
+#define STV090x_WIDTH_Px_STOP_ENABLE_FIELD	1
+#define STV090x_OFFST_Px_STOP_SDAT2SDA_FIELD	1
+#define STV090x_WIDTH_Px_STOP_SDAT2SDA_FIELD	1
+
+#define STV090x_CLKI2CFG			0xf140
+#define STV090x_OFFST_CLKI2_OPD_FIELD		7
+#define STV090x_WIDTH_CLKI2_OPD_FIELD		1
+#define STV090x_OFFST_CLKI2_CONFIG_FIELD	1
+#define STV090x_WIDTH_CLKI2_CONFIG_FIELD	6
+#define STV090x_OFFST_CLKI2_XOR_FIELD		0
+#define STV090x_WIDTH_CLKI2_XOR_FIELD		1
+
+#define STV090x_GPIOxCFG(__x)			(0xf141 + (__x - 1))
+#define STV090x_GPIO1CFG			STV090x_GPIOxCFG(1)
+#define STV090x_GPIO2CFG			STV090x_GPIOxCFG(2)
+#define STV090x_GPIO3CFG			STV090x_GPIOxCFG(3)
+#define STV090x_GPIO4CFG			STV090x_GPIOxCFG(4)
+#define STV090x_GPIO5CFG			STV090x_GPIOxCFG(5)
+#define STV090x_GPIO6CFG			STV090x_GPIOxCFG(6)
+#define STV090x_GPIO7CFG			STV090x_GPIOxCFG(7)
+#define STV090x_GPIO8CFG			STV090x_GPIOxCFG(8)
+#define STV090x_GPIO9CFG			STV090x_GPIOxCFG(9)
+#define STV090x_GPIO10CFG			STV090x_GPIOxCFG(10)
+#define STV090x_GPIO11CFG			STV090x_GPIOxCFG(11)
+#define STV090x_GPIO12CFG			STV090x_GPIOxCFG(12)
+#define STV090x_GPIO13CFG			STV090x_GPIOxCFG(13)
+#define STV090x_OFFST_GPIOx_OPD_FIELD		7
+#define STV090x_WIDTH_GPIOx_OPD_FIELD		1
+#define STV090x_OFFST_GPIOx_CONFIG_FIELD	1
+#define STV090x_WIDTH_GPIOx_CONFIG_FIELD	6
+#define STV090x_OFFST_GPIOx_XOR_FIELD		0
+#define STV090x_WIDTH_GPIOx_XOR_FIELD		1
+
+#define STV090x_CSxCFG(__x)			(0xf14e + __x * 0x1)
+#define STV090x_CS0CFG				STV090x_CSxCFG(0)
+#define STV090x_CS1CFG				STV090x_CSxCFG(1)
+#define STV090x_OFFST_CSX_OPD_FIELD		7
+#define STV090x_WIDTH_CSX_OPD_FIELD		1
+#define STV090x_OFFST_CSX_CONFIG_FIELD		1
+#define STV090x_WIDTH_CSX_CONFIG_FIELD		6
+#define STV090x_OFFST_CSX_XOR_FIELD		0
+#define STV090x_WIDTH_CSX_XOR_FIELD		1
+
+
+#define STV090x_STDBYCFG			0xf150
+#define STV090x_OFFST_STDBY_OPD_FIELD		7
+#define STV090x_WIDTH_STDBY_OPD_FIELD		1
+#define STV090x_OFFST_STDBY_CONFIG_FIELD	1
+#define STV090x_WIDTH_STDBY_CONFIG_FIELD	6
+#define STV090x_OFFST_STDBY_XOR_FIELD		0
+#define STV090x_WIDTH_STDBY_XOR_FIELD		1
+
+#define STV090x_DIRCLKCFG			0xf151
+#define STV090x_OFFST_DIRCLK_OPD_FIELD		7
+#define STV090x_WIDTH_DIRCLK_OPD_FIELD		1
+#define STV090x_OFFST_DIRCLK_CONFIG_FIELD	1
+#define STV090x_WIDTH_DIRCLK_CONFIG_FIELD	6
+#define STV090x_OFFST_DIRCLK_XOR_FIELD		0
+#define STV090x_WIDTH_DIRCLK_XOR_FIELD		1
+
+
+#define STV090x_AGCRFxCFG(__x)			(0xf152 + (__x - 1) * 0x4)
+#define STV090x_AGCRF1CFG			STV090x_AGCRFxCFG(1)
+#define STV090x_AGCRF2CFG			STV090x_AGCRFxCFG(2)
+#define STV090x_OFFST_AGCRFx_OPD_FIELD		7
+#define STV090x_WIDTH_AGCRFx_OPD_FIELD		1
+#define STV090x_OFFST_AGCRFx_CONFIG_FIELD	1
+#define STV090x_WIDTH_AGCRFx_CONFIG_FIELD	6
+#define STV090x_OFFST_AGCRFx_XOR_FIELD		0
+#define STV090x_WIDTH_AGCRFx_XOR_FIELD		1
+
+#define STV090x_SDATxCFG(__x)			(0xf153 + (__x - 1) * 0x4)
+#define STV090x_SDAT1CFG			STV090x_SDATxCFG(1)
+#define STV090x_SDAT2CFG			STV090x_SDATxCFG(2)
+#define STV090x_OFFST_SDATx_OPD_FIELD		7
+#define STV090x_WIDTH_SDATx_OPD_FIELD		1
+#define STV090x_OFFST_SDATx_CONFIG_FIELD	1
+#define STV090x_WIDTH_SDATx_CONFIG_FIELD	6
+#define STV090x_OFFST_SDATx_XOR_FIELD		0
+#define STV090x_WIDTH_SDATx_XOR_FIELD		1
+
+#define STV090x_SCLTxCFG(__x)			(0xf154 + (__x - 1) * 0x4)
+#define STV090x_SCLT1CFG			STV090x_SCLTxCFG(1)
+#define STV090x_SCLT2CFG			STV090x_SCLTxCFG(2)
+#define STV090x_OFFST_SCLTx_OPD_FIELD		7
+#define STV090x_WIDTH_SCLTx_OPD_FIELD		1
+#define STV090x_OFFST_SCLTx_CONFIG_FIELD	1
+#define STV090x_WIDTH_SCLTx_CONFIG_FIELD	6
+#define STV090x_OFFST_SCLTx_XOR_FIELD		0
+#define STV090x_WIDTH_SCLTx_XOR_FIELD		1
+
+#define STV090x_DISEQCOxCFG(__x)		(0xf155 + (__x - 1) * 0x4)
+#define STV090x_DISEQCO1CFG			STV090x_DISEQCOxCFG(1)
+#define STV090x_DISEQCO2CFG			STV090x_DISEQCOxCFG(2)
+#define STV090x_OFFST_DISEQCOx_OPD_FIELD	7
+#define STV090x_WIDTH_DISEQCOx_OPD_FIELD	1
+#define STV090x_OFFST_DISEQCOx_CONFIG_FIELD	1
+#define STV090x_WIDTH_DISEQCOx_CONFIG_FIELD	6
+#define STV090x_OFFST_DISEQCOx_XOR_FIELD	0
+#define STV090x_WIDTH_DISEQCOx_XOR_FIELD	1
+
+#define STV090x_CLKOUT27CFG			0xf15a
+#define STV090x_OFFST_CLKOUT27_OPD_FIELD	7
+#define STV090x_WIDTH_CLKOUT27_OPD_FIELD	1
+#define STV090x_OFFST_CLKOUT27_CONFIG_FIELD	1
+#define STV090x_WIDTH_CLKOUT27_CONFIG_FIELD	6
+#define STV090x_OFFST_CLKOUT27_XOR_FIELD	0
+#define STV090x_WIDTH_CLKOUT27_XOR_FIELD	1
+
+#define STV090x_ERRORxCFG(__x)			(0xf15b + (__x - 1) * 0x5)
+#define STV090x_ERROR1CFG			STV090x_ERRORxCFG(1)
+#define STV090x_ERROR2CFG			STV090x_ERRORxCFG(2)
+#define STV090x_ERROR3CFG			STV090x_ERRORxCFG(3)
+#define STV090x_OFFST_ERRORx_OPD_FIELD		7
+#define STV090x_WIDTH_ERRORx_OPD_FIELD		1
+#define STV090x_OFFST_ERRORx_CONFIG_FIELD	1
+#define STV090x_WIDTH_ERRORx_CONFIG_FIELD	6
+#define STV090x_OFFST_ERRORx_XOR_FIELD		0
+#define STV090x_WIDTH_ERRORx_XOR_FIELD		1
+
+#define STV090x_DPNxCFG(__x)			(0xf15c + (__x - 1) * 0x5)
+#define STV090x_DPN1CFG				STV090x_DPNxCFG(1)
+#define STV090x_DPN2CFG				STV090x_DPNxCFG(2)
+#define STV090x_DPN3CFG				STV090x_DPNxCFG(3)
+#define STV090x_OFFST_DPNx_OPD_FIELD		7
+#define STV090x_WIDTH_DPNx_OPD_FIELD		1
+#define STV090x_OFFST_DPNx_CONFIG_FIELD		1
+#define STV090x_WIDTH_DPNx_CONFIG_FIELD		6
+#define STV090x_OFFST_DPNx_XOR_FIELD		0
+#define STV090x_WIDTH_DPNx_XOR_FIELD		1
+
+#define STV090x_STROUTxCFG(__x)			(0xf15d + (__x - 1) * 0x5)
+#define STV090x_STROUT1CFG			STV090x_STROUTxCFG(1)
+#define STV090x_STROUT2CFG			STV090x_STROUTxCFG(2)
+#define STV090x_STROUT3CFG			STV090x_STROUTxCFG(3)
+#define STV090x_OFFST_STROUTx_OPD_FIELD		7
+#define STV090x_WIDTH_STROUTx_OPD_FIELD		1
+#define STV090x_OFFST_STROUTx_CONFIG_FIELD	1
+#define STV090x_WIDTH_STROUTx_CONFIG_FIELD	6
+#define STV090x_OFFST_STROUTx_XOR_FIELD		0
+#define STV090x_WIDTH_STROUTx_XOR_FIELD		1
+
+#define STV090x_CLKOUTxCFG(__x)			(0xf15e + (__x - 1) * 0x5)
+#define STV090x_CLKOUT1CFG			STV090x_CLKOUTxCFG(1)
+#define STV090x_CLKOUT2CFG			STV090x_CLKOUTxCFG(2)
+#define STV090x_CLKOUT3CFG			STV090x_CLKOUTxCFG(3)
+#define STV090x_OFFST_CLKOUTx_OPD_FIELD		7
+#define STV090x_WIDTH_CLKOUTx_OPD_FIELD		1
+#define STV090x_OFFST_CLKOUTx_CONFIG_FIELD	1
+#define STV090x_WIDTH_CLKOUTx_CONFIG_FIELD	6
+#define STV090x_OFFST_CLKOUTx_XOR_FIELD		0
+#define STV090x_WIDTH_CLKOUTx_XOR_FIELD		1
+
+#define STV090x_DATAxCFG(__x)			(0xf15f + (__x - 71) * 0x5)
+#define STV090x_DATA71CFG			STV090x_DATAxCFG(71)
+#define STV090x_DATA72CFG			STV090x_DATAxCFG(72)
+#define STV090x_DATA73CFG			STV090x_DATAxCFG(73)
+#define STV090x_OFFST_DATAx_OPD_FIELD		7
+#define STV090x_WIDTH_DATAx_OPD_FIELD		1
+#define STV090x_OFFST_DATAx_CONFIG_FIELD	1
+#define STV090x_WIDTH_DATAx_CONFIG_FIELD	6
+#define STV090x_OFFST_DATAx_XOR_FIELD		0
+#define STV090x_WIDTH_DATAx_XOR_FIELD		1
+
+#define STV090x_NCOARSE				0xf1b3
+#define STV090x_OFFST_M_DIV_FIELD		0
+#define STV090x_WIDTH_M_DIV_FIELD		8
+
+#define STV090x_SYNTCTRL			0xf1b6
+#define STV090x_OFFST_STANDBY_FIELD		7
+#define STV090x_WIDTH_STANDBY_FIELD		1
+#define STV090x_OFFST_BYPASSPLLCORE_FIELD	6
+#define STV090x_WIDTH_BYPASSPLLCORE_FIELD	1
+#define STV090x_OFFST_SELX1RATIO_FIELD		5
+#define STV090x_WIDTH_SELX1RATIO_FIELD		1
+#define STV090x_OFFST_STOP_PLL_FIELD		3
+#define STV090x_WIDTH_SELX1RATIO_FIELD		1
+#define STV090x_OFFST_BYPASSPLLFSK_FIELD	2
+#define STV090x_WIDTH_BYPASSPLLFSK_FIELD	1
+#define STV090x_OFFST_SELOSCI_FIELD		1
+#define STV090x_WIDTH_SELOSCI_FIELD		1
+#define STV090x_OFFST_BYPASSPLLADC_FIELD	0
+#define STV090x_WIDTH_BYPASSPLLADC_FIELD	1
+
+#define STV090x_FILTCTRL			0xf1b7
+#define STV090x_OFFST_INV_CLK135_FIELD		7
+#define STV090x_WIDTH_INV_CLK135_FIELD		1
+#define STV090x_OFFST_SEL_FSKCKDIV_FIELD	2
+#define STV090x_WIDTH_SEL_FSKCKDIV_FIELD	1
+#define STV090x_OFFST_INV_CLKFSK_FIELD		1
+#define STV090x_WIDTH_INV_CLKFSK_FIELD		1
+#define STV090x_OFFST_BYPASS_APPLI_FIELD	0
+#define STV090x_WIDTH_BYPASS_APPLI_FIELD	1
+
+#define STV090x_PLLSTAT				0xf1b8
+#define STV090x_OFFST_PLLLOCK_FIELD		0
+#define STV090x_WIDTH_PLLLOCK_FIELD		1
+
+#define STV090x_STOPCLK1			0xf1c2
+#define STV090x_OFFST_STOP_CLKPKDT2_FIELD	6
+#define STV090x_WIDTH_STOP_CLKPKDT2_FIELD	1
+#define STV090x_OFFST_STOP_CLKPKDT1_FIELD	5
+#define STV090x_WIDTH_STOP_CLKPKDT1_FIELD	1
+#define STV090x_OFFST_STOP_CLKFEC_FIELD		4
+#define STV090x_WIDTH_STOP_CLKFEC_FIELD		1
+#define STV090x_OFFST_STOP_CLKADCI2_FIELD	3
+#define STV090x_WIDTH_STOP_CLKADCI2_FIELD	1
+#define STV090x_OFFST_INV_CLKADCI2_FIELD	2
+#define STV090x_WIDTH_INV_CLKADCI2_FIELD	1
+#define STV090x_OFFST_STOP_CLKADCI1_FIELD	1
+#define STV090x_WIDTH_STOP_CLKADCI1_FIELD	1
+#define STV090x_OFFST_INV_CLKADCI1_FIELD	0
+#define STV090x_WIDTH_INV_CLKADCI1_FIELD	1
+
+#define STV090x_STOPCLK2			0xf1c3
+#define STV090x_OFFST_STOP_CLKSAMP2_FIELD	4
+#define STV090x_WIDTH_STOP_CLKSAMP2_FIELD	1
+#define STV090x_OFFST_STOP_CLKSAMP1_FIELD	3
+#define STV090x_WIDTH_STOP_CLKSAMP1_FIELD	1
+#define STV090x_OFFST_STOP_CLKVIT2_FIELD	2
+#define STV090x_WIDTH_STOP_CLKVIT2_FIELD	1
+#define STV090x_OFFST_STOP_CLKVIT1_FIELD	1
+#define STV090x_WIDTH_STOP_CLKVIT1_FIELD	1
+#define STV090x_OFFST_STOP_CLKTS_FIELD		0
+#define STV090x_WIDTH_STOP_CLKTS_FIELD		1
+
+#define STV090x_TSTTNR0				0xf1df
+#define STV090x_OFFST_SEL_FSK_FIELD		7
+#define STV090x_WIDTH_SEL_FSK_FIELD		1
+#define STV090x_OFFST_FSK_PON_FIELD		2
+#define STV090x_WIDTH_FSK_PON_FIELD		1
+
+#define STV090x_TSTTNR1				0xf1e0
+#define STV090x_OFFST_ADC1_PON_FIELD		1
+#define STV090x_WIDTH_ADC1_PON_FIELD		1
+#define STV090x_OFFST_ADC1_INMODE_FIELD		0
+#define STV090x_WIDTH_ADC1_INMODE_FIELD		1
+
+#define STV090x_TSTTNR2				0xf1e1
+#define STV090x_OFFST_DISEQC1_PON_FIELD		5
+#define STV090x_WIDTH_DISEQC1_PON_FIELD		1
+
+#define STV090x_TSTTNR3				0xf1e2
+#define STV090x_OFFST_ADC2_PON_FIELD		1
+#define STV090x_WIDTH_ADC2_PON_FIELD		1
+#define STV090x_OFFST_ADC2_INMODE_FIELD		0
+#define STV090x_WIDTH_ADC2_INMODE_FIELD		1
+
+#define STV090x_TSTTNR4				0xf1e3
+#define STV090x_OFFST_DISEQC2_PON_FIELD		5
+#define STV090x_WIDTH_DISEQC2_PON_FIELD		1
+
+#define STV090x_FSKTFC2				0xf170
+#define STV090x_OFFST_FSKT_KMOD_FIELD		2
+#define STV090x_WIDTH_FSKT_KMOD_FIELD		6
+#define STV090x_OFFST_FSKT_CAR_FIELD		0
+#define STV090x_WIDTH_FSKT_CAR_FIELD		2
+
+#define STV090x_FSKTFC1				0xf171
+#define STV090x_OFFST_FSKTC1_CAR_FIELD		0
+#define STV090x_WIDTH_FSKTC1_CAR_FIELD		8
+
+#define STV090x_FSKTFC0				0xf172
+#define STV090x_OFFST_FSKTC0_CAR_FIELD		0
+#define STV090x_WIDTH_FSKTC0_CAR_FIELD		8
+
+#define STV090x_FSKTDELTAF1			0xf173
+#define STV090x_OFFST_FSKTF1_DELTAF_FIELD	0
+#define STV090x_WIDTH_FSKTF1_DELTAF_FIELD	4
+
+#define STV090x_FSKTDELTAF0			0xf174
+#define STV090x_OFFST_FSKTF0_DELTAF_FIELD	0
+#define STV090x_WIDTH_FSKTF0_DELTAF_FIELD	8
+
+#define STV090x_FSKTCTRL			0xf175
+#define STV090x_OFFST_FSKT_EN_SGN_FIELD		6
+#define STV090x_WIDTH_FSKT_EN_SGN_FIELD		1
+#define STV090x_OFFST_FSKT_MOD_SGN_FIELD	5
+#define STV090x_WIDTH_FSKT_MOD_SGN_FIELD	1
+#define STV090x_OFFST_FSKT_MOD_EN_FIELD		2
+#define STV090x_WIDTH_FSKT_MOD_EN_FIELD		3
+#define STV090x_OFFST_FSKT_DACMODE_FIELD	0
+#define STV090x_WIDTH_FSKT_DACMODE_FIELD	2
+
+#define STV090x_FSKRFC2				0xf176
+#define STV090x_OFFST_FSKRC2_DETSGN_FIELD	6
+#define STV090x_WIDTH_FSKRC2_DETSGN_FIELD	1
+#define STV090x_OFFST_FSKRC2_OUTSGN_FIELD	5
+#define STV090x_WIDTH_FSKRC2_OUTSGN_FIELD	1
+#define STV090x_OFFST_FSKRC2_KAGC_FIELD		2
+#define STV090x_WIDTH_FSKRC2_KAGC_FIELD		3
+#define STV090x_OFFST_FSKRC2_CAR_FIELD		0
+#define STV090x_WIDTH_FSKRC2_CAR_FIELD		2
+
+#define STV090x_FSKRFC1				0xf177
+#define STV090x_OFFST_FSKRC1_CAR_FIELD		0
+#define STV090x_WIDTH_FSKRC1_CAR_FIELD		8
+
+#define STV090x_FSKRFC0				0xf178
+#define STV090x_OFFST_FSKRC0_CAR_FIELD		0
+#define STV090x_WIDTH_FSKRC0_CAR_FIELD		8
+
+#define STV090x_FSKRK1				0xf179
+#define STV090x_OFFST_FSKR_K1_EXP_FIELD		5
+#define STV090x_WIDTH_FSKR_K1_EXP_FIELD		3
+#define STV090x_OFFST_FSKR_K1_MANT_FIELD	0
+#define STV090x_WIDTH_FSKR_K1_MANT_FIELD	5
+
+#define STV090x_FSKRK2				0xf17a
+#define STV090x_OFFST_FSKR_K2_EXP_FIELD		5
+#define STV090x_WIDTH_FSKR_K2_EXP_FIELD		3
+#define STV090x_OFFST_FSKR_K2_MANT_FIELD	0
+#define STV090x_WIDTH_FSKR_K2_MANT_FIELD	5
+
+#define STV090x_FSKRAGCR			0xf17b
+#define STV090x_OFFST_FSKR_OUTCTL_FIELD		6
+#define STV090x_WIDTH_FSKR_OUTCTL_FIELD		2
+#define STV090x_OFFST_FSKR_AGC_REF_FIELD	0
+#define STV090x_WIDTH_FSKR_AGC_REF_FIELD	6
+
+#define STV090x_FSKRAGC				0xf17c
+#define STV090x_OFFST_FSKR_AGC_ACCU_FIELD	0
+#define STV090x_WIDTH_FSKR_AGC_ACCU_FIELD	8
+
+#define STV090x_FSKRALPHA			0xf17d
+#define STV090x_OFFST_FSKR_ALPHA_EXP_FIELD	2
+#define STV090x_WIDTH_FSKR_ALPHA_EXP_FIELD	3
+#define STV090x_OFFST_FSKR_ALPHA_M_FIELD	0
+#define STV090x_WIDTH_FSKR_ALPHA_M_FIELD	2
+
+#define STV090x_FSKRPLTH1			0xf17e
+#define STV090x_OFFST_FSKR_BETA_FIELD		4
+#define STV090x_WIDTH_FSKR_BETA_FIELD		4
+#define STV090x_OFFST_FSKR_PLL_TRESH1_FIELD	0
+#define STV090x_WIDTH_FSKR_PLL_TRESH1_FIELD	4
+
+#define STV090x_FSKRPLTH0			0xf17f
+#define STV090x_OFFST_FSKR_PLL_TRESH0_FIELD	0
+#define STV090x_WIDTH_FSKR_PLL_TRESH0_FIELD	8
+
+#define STV090x_FSKRDF1				0xf180
+#define STV090x_OFFST_FSKR_DELTAF1_FIELD	0
+#define STV090x_WIDTH_FSKR_DELTAF1_FIELD	5
+
+#define STV090x_FSKRDF0				0xf181
+#define STV090x_OFFST_FSKR_DELTAF0_FIELD	0
+#define STV090x_WIDTH_FSKR_DELTAF0_FIELD	8
+
+#define STV090x_FSKRSTEPP			0xf182
+#define STV090x_OFFST_FSKR_STEP_PLUS_FIELD	0
+#define STV090x_WIDTH_FSKR_STEP_PLUS_FIELD	8
+
+#define STV090x_FSKRSTEPM			0xf183
+#define STV090x_OFFST_FSKR_STEP_MINUS_FIELD	0
+#define STV090x_WIDTH_FSKR_STEP_MINUS_FIELD	8
+
+#define STV090x_FSKRDET1			0xf184
+#define STV090x_OFFST_FSKR_CARDET1_ACCU_FIELD	0
+#define STV090x_WIDTH_FSKR_CARDET1_ACCU_FIELD	4
+
+#define STV090x_FSKRDET0			0xf185
+#define STV090x_OFFST_FSKR_CARDET0_ACCU_FIELD	0
+#define STV090x_WIDTH_FSKR_CARDET0_ACCU_FIELD	8
+
+#define STV090x_FSKRDTH1				0xf186
+#define STV090x_OFFST_FSKR_CARLOSS_THRESH1_FIELD	4
+#define STV090x_WIDTH_FSKR_CARLOSS_THRESH1_FIELD	4
+#define STV090x_OFFST_FSKR_CARDET_THRESH1_FIELD		0
+#define STV090x_WIDTH_FSKR_CARDET_THRESH1_FIELD		4
+
+#define STV090x_FSKRDTH0			0xf187
+#define STV090x_OFFST_FSKR_CARDET_THRESH0_FIELD	0
+#define STV090x_WIDTH_FSKR_CARDET_THRESH0_FIELD	8
+
+#define STV090x_FSKRLOSS			0xf188
+#define STV090x_OFFST_FSKR_CARLOSS_THRESH_FIELD	0
+#define STV090x_WIDTH_FSKR_CARLOSS_THRESH_FIELD	8
+
+#define STV090x_Px_DISTXCTL(__x)		(0xF1A0 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXCTL			STV090x_Px_DISTXCTL(1)
+#define STV090x_P2_DISTXCTL			STV090x_Px_DISTXCTL(2)
+#define STV090x_OFFST_Px_TIM_OFF_FIELD		7
+#define STV090x_WIDTH_Px_TIM_OFF_FIELD		1
+#define STV090x_OFFST_Px_DISEQC_RESET_FIELD	6
+#define STV090x_WIDTH_Px_DISEQC_RESET_FIELD	1
+#define STV090x_OFFST_Px_TIM_CMD_FIELD		4
+#define STV090x_WIDTH_Px_TIM_CMD_FIELD		2
+#define STV090x_OFFST_Px_DIS_PRECHARGE_FIELD	3
+#define STV090x_WIDTH_Px_DIS_PRECHARGE_FIELD	1
+#define STV090x_OFFST_Px_DISTX_MODE_FIELD	0
+#define STV090x_WIDTH_Px_DISTX_MODE_FIELD	3
+
+#define STV090x_Px_DISRXCTL(__x)		(0xf1a1 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRXCTL			STV090x_Px_DISRXCTL(1)
+#define STV090x_P2_DISRXCTL			STV090x_Px_DISRXCTL(2)
+#define STV090x_OFFST_Px_RECEIVER_ON_FIELD	7
+#define STV090x_WIDTH_Px_RECEIVER_ON_FIELD	1
+#define STV090x_OFFST_Px_IGNO_SHORT22K_FIELD	6
+#define STV090x_WIDTH_Px_IGNO_SHORT22K_FIELD	1
+#define STV090x_OFFST_Px_ONECHIP_TRX_FIELD	5
+#define STV090x_WIDTH_Px_ONECHIP_TRX_FIELD	1
+#define STV090x_OFFST_Px_EXT_ENVELOP_FIELD	4
+#define STV090x_WIDTH_Px_EXT_ENVELOP_FIELD	1
+#define STV090x_OFFST_Px_PIN_SELECT_FIELD	2
+#define STV090x_WIDTH_Px_PIN_SELECT_FIELD	2
+#define STV090x_OFFST_Px_IRQ_RXEND_FIELD	1
+#define STV090x_WIDTH_Px_IRQ_RXEND_FIELD	1
+#define STV090x_OFFST_Px_IRQ_4NBYTES_FIELD	0
+#define STV090x_WIDTH_Px_IRQ_4NBYTES_FIELD	1
+
+#define STV090x_Px_DISRX_ST0(__x)		(0xf1a4 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRX_ST0			STV090x_Px_DISRX_ST0(1)
+#define STV090x_P2_DISRX_ST0			STV090x_Px_DISRX_ST0(2)
+#define STV090x_OFFST_Px_RX_END_FIELD		7
+#define STV090x_WIDTH_Px_RX_END_FIELD		1
+#define STV090x_OFFST_Px_RX_ACTIVE_FIELD	6
+#define STV090x_WIDTH_Px_RX_ACTIVE_FIELD	1
+#define STV090x_OFFST_Px_SHORT_22KHZ_FIELD	5
+#define STV090x_WIDTH_Px_SHORT_22KHZ_FIELD	1
+#define STV090x_OFFST_Px_CONT_TONE_FIELD	4
+#define STV090x_WIDTH_Px_CONT_TONE_FIELD	1
+#define STV090x_OFFST_Px_FIFO_4BREADY_FIELD	3
+#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD	2
+#define STV090x_OFFST_Px_FIFO_EMPTY_FIELD	2
+#define STV090x_WIDTH_Px_FIFO_EMPTY_FIELD	1
+#define STV090x_OFFST_Px_ABORT_DISRX_FIELD	0
+#define STV090x_WIDTH_Px_ABORT_DISRX_FIELD	1
+
+#define STV090x_Px_DISRX_ST1(__x)		(0xf1a5 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRX_ST1			STV090x_Px_DISRX_ST1(1)
+#define STV090x_P2_DISRX_ST1			STV090x_Px_DISRX_ST1(2)
+#define STV090x_OFFST_Px_RX_FAIL_FIELD		7
+#define STV090x_WIDTH_Px_RX_FAIL_FIELD		1
+#define STV090x_OFFST_Px_FIFO_PARITYFAIL_FIELD	6
+#define STV090x_WIDTH_Px_FIFO_PARITYFAIL_FIELD	1
+#define STV090x_OFFST_Px_RX_NONBYTE_FIELD	5
+#define STV090x_WIDTH_Px_RX_NONBYTE_FIELD	1
+#define STV090x_OFFST_Px_FIFO_OVERFLOW_FIELD	4
+#define STV090x_WIDTH_Px_FIFO_OVERFLOW_FIELD	1
+#define STV090x_OFFST_Px_FIFO_BYTENBR_FIELD	0
+#define STV090x_WIDTH_Px_FIFO_BYTENBR_FIELD	4
+
+#define STV090x_Px_DISRXDATA(__x)		(0xf1a6 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRXDATA			STV090x_Px_DISRXDATA(1)
+#define STV090x_P2_DISRXDATA			STV090x_Px_DISRXDATA(2)
+#define STV090x_OFFST_Px_DISRX_DATA_FIELD	0
+#define STV090x_WIDTH_Px_DISRX_DATA_FIELD	8
+
+#define STV090x_Px_DISTXDATA(__x)		(0xf1a7 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXDATA			STV090x_Px_DISTXDATA(1)
+#define STV090x_P2_DISTXDATA			STV090x_Px_DISTXDATA(2)
+#define STV090x_OFFST_Px_DISEQC_FIFO_FIELD	0
+#define STV090x_WIDTH_Px_DISEQC_FIFO_FIELD	8
+
+#define STV090x_Px_DISTXSTATUS(__x)		(0xf1a8 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXSTATUS			STV090x_Px_DISTXSTATUS(1)
+#define STV090x_P2_DISTXSTATUS			STV090x_Px_DISTXSTATUS(2)
+#define STV090x_OFFST_Px_TX_FAIL_FIELD		7
+#define STV090x_WIDTH_Px_TX_FAIL_FIELD		1
+#define STV090x_OFFST_Px_FIFO_FULL_FIELD	6
+#define STV090x_WIDTH_Px_FIFO_FULL_FIELD	1
+#define STV090x_OFFST_Px_TX_IDLE_FIELD		5
+#define STV090x_WIDTH_Px_TX_IDLE_FIELD		1
+#define STV090x_OFFST_Px_GAP_BURST_FIELD	4
+#define STV090x_WIDTH_Px_GAP_BURST_FIELD	1
+#define STV090x_OFFST_Px_TXFIFO_BYTES_FIELD	0
+#define STV090x_WIDTH_Px_TXFIFO_BYTES_FIELD	4
+
+#define STV090x_Px_F22TX(__x)			(0xf1a9 - (__x - 1) * 0x10)
+#define STV090x_P1_F22TX			STV090x_Px_F22TX(1)
+#define STV090x_P2_F22TX			STV090x_Px_F22TX(2)
+#define STV090x_OFFST_Px_F22_REG_FIELD		0
+#define STV090x_WIDTH_Px_F22_REG_FIELD		8
+
+#define STV090x_Px_F22RX(__x)			(0xf1aa - (__x - 1) * 0x10)
+#define STV090x_P1_F22RX			STV090x_Px_F22RX(1)
+#define STV090x_P2_F22RX			STV090x_Px_F22RX(2)
+#define STV090x_OFFST_Px_F22RX_REG_FIELD	0
+#define STV090x_WIDTH_Px_F22RX_REG_FIELD	8
+
+#define STV090x_Px_ACRPRESC(__x)		(0xf1ac - (__x - 1) * 0x10)
+#define STV090x_P1_ACRPRESC			STV090x_Px_ACRPRESC(1)
+#define STV090x_P2_ACRPRESC			STV090x_Px_ACRPRESC(2)
+#define STV090x_OFFST_Px_ACR_PRESC_FIELD	0
+#define STV090x_WIDTH_Px_ACR_PRESC_FIELD	3
+
+#define STV090x_Px_ACRDIV(__x)			(0xf1ad - (__x - 1) * 0x10)
+#define STV090x_P1_ACRDIV			STV090x_Px_ACRDIV(1)
+#define STV090x_P2_ACRDIV			STV090x_Px_ACRDIV(2)
+#define STV090x_OFFST_Px_ACR_DIV_FIELD		0
+#define STV090x_WIDTH_Px_ACR_DIV_FIELD		8
+
+#define STV090x_Px_IQCONST(__x)			(0xF400 - (__x - 1) * 0x200)
+#define STV090x_P1_IQCONST			STV090x_Px_IQCONST(1)
+#define STV090x_P2_IQCONST			STV090x_Px_IQCONST(2)
+#define STV090x_OFFST_Px_CONSTEL_SELECT_FIELD	5
+#define STV090x_WIDTH_Px_CONSTEL_SELECT_FIELD	2
+
+#define STV090x_Px_NOSCFG(__x)			(0xF401 - (__x - 1) * 0x200)
+#define STV090x_P1_NOSCFG			STV090x_Px_NOSCFG(1)
+#define STV090x_P2_NOSCFG			STV090x_Px_NOSCFG(2)
+#define STV090x_OFFST_Px_NOSPLH_BETA_FIELD	3
+#define STV090x_WIDTH_Px_NOSPLH_BETA_FIELD	2
+#define STV090x_OFFST_Px_NOSDATA_BETA_FIELD	0
+#define STV090x_WIDTH_Px_NOSDATA_BETA_FIELD	3
+
+#define STV090x_Px_ISYMB(__x)			(0xF402 - (__x - 1) * 0x200)
+#define STV090x_P1_ISYMB			STV090x_Px_ISYMB(1)
+#define STV090x_P2_ISYMB			STV090x_Px_ISYMB(2)
+#define STV090x_OFFST_Px_I_SYMBOL_FIELD		0
+#define STV090x_WIDTH_Px_I_SYMBOL_FIELD		8
+
+#define STV090x_Px_QSYMB(__x)			(0xF403 - (__x - 1) * 0x200)
+#define STV090x_P1_QSYMB			STV090x_Px_QSYMB(1)
+#define STV090x_P2_QSYMB			STV090x_Px_QSYMB(2)
+#define STV090x_OFFST_Px_Q_SYMBOL_FIELD		0
+#define STV090x_WIDTH_Px_Q_SYMBOL_FIELD		8
+
+#define STV090x_Px_AGC1CFG(__x)			(0xF404 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1CFG			STV090x_Px_AGC1CFG(1)
+#define STV090x_P2_AGC1CFG			STV090x_Px_AGC1CFG(2)
+#define STV090x_OFFST_Px_DC_FROZEN_FIELD	7
+#define STV090x_WIDTH_Px_DC_FROZEN_FIELD	1
+#define STV090x_OFFST_Px_DC_CORRECT_FIELD	6
+#define STV090x_WIDTH_Px_DC_CORRECT_FIELD	1
+#define STV090x_OFFST_Px_AMM_FROZEN_FIELD	5
+#define STV090x_WIDTH_Px_AMM_FROZEN_FIELD	1
+#define STV090x_OFFST_Px_AMM_CORRECT_FIELD	4
+#define STV090x_WIDTH_Px_AMM_CORRECT_FIELD	1
+#define STV090x_OFFST_Px_QUAD_FROZEN_FIELD	3
+#define STV090x_WIDTH_Px_QUAD_FROZEN_FIELD	1
+#define STV090x_OFFST_Px_QUAD_CORRECT_FIELD	2
+#define STV090x_WIDTH_Px_QUAD_CORRECT_FIELD	1
+
+#define STV090x_Px_AGC1CN(__x)			(0xF406 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1CN			STV090x_Px_AGC1CN(1)
+#define STV090x_P2_AGC1CN			STV090x_Px_AGC1CN(2)
+#define STV090x_WIDTH_Px_AGC1_LOCKED_FIELD	7
+#define STV090x_OFFST_Px_AGC1_LOCKED_FIELD	1
+#define STV090x_OFFST_Px_AGC1_MINPOWER_FIELD	4
+#define STV090x_WIDTH_Px_AGC1_MINPOWER_FIELD	1
+#define STV090x_OFFST_Px_AGCOUT_FAST_FIELD	3
+#define STV090x_WIDTH_Px_AGCOUT_FAST_FIELD	1
+#define STV090x_OFFST_Px_AGCIQ_BETA_FIELD	0
+#define STV090x_WIDTH_Px_AGCIQ_BETA_FIELD	3
+
+#define STV090x_Px_AGC1REF(__x)			(0xF407 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1REF			STV090x_Px_AGC1REF(1)
+#define STV090x_P2_AGC1REF			STV090x_Px_AGC1REF(2)
+#define STV090x_OFFST_Px_AGCIQ_REF_FIELD	0
+#define STV090x_WIDTH_Px_AGCIQ_REF_FIELD	8
+
+#define STV090x_Px_IDCCOMP(__x)			(0xF408 - (__x - 1) * 0x200)
+#define STV090x_P1_IDCCOMP			STV090x_Px_IDCCOMP(1)
+#define STV090x_P2_IDCCOMP			STV090x_Px_IDCCOMP(2)
+#define STV090x_OFFST_Px_IAVERAGE_ADJ_FIELD	0
+#define STV090x_WIDTH_Px_IAVERAGE_ADJ_FIELD	8
+
+#define STV090x_Px_QDCCOMP(__x)			(0xF409 - (__x - 1) * 0x200)
+#define STV090x_P1_QDCCOMP			STV090x_Px_QDCCOMP(1)
+#define STV090x_P2_QDCCOMP			STV090x_Px_QDCCOMP(2)
+#define STV090x_OFFST_Px_QAVERAGE_ADJ_FIELD	0
+#define STV090x_WIDTH_Px_QAVERAGE_ADJ_FIELD	8
+
+#define STV090x_Px_POWERI(__x)			(0xF40A - (__x - 1) * 0x200)
+#define STV090x_P1_POWERI			STV090x_Px_POWERI(1)
+#define STV090x_P2_POWERI			STV090x_Px_POWERI(2)
+#define STV090x_OFFST_Px_POWER_I_FIELD		0
+#define STV090x_WIDTH_Px_POWER_I_FIELD		8
+
+#define STV090x_Px_POWERQ(__x)			(0xF40B - (__x - 1) * 0x200)
+#define STV090x_P1_POWERQ			STV090x_Px_POWERQ(1)
+#define STV090x_P2_POWERQ			STV090x_Px_POWERQ(2)
+#define STV090x_OFFST_Px_POWER_Q_FIELD		0
+#define STV090x_WIDTH_Px_POWER_Q_FIELD		8
+
+#define STV090x_Px_AGC1AMM(__x)			(0xF40C - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1AMM			STV090x_Px_AGC1AMM(1)
+#define STV090x_P2_AGC1AMM			STV090x_Px_AGC1AMM(2)
+#define STV090x_OFFST_Px_AMM_VALUE_FIELD	0
+#define STV090x_WIDTH_Px_AMM_VALUE_FIELD	8
+
+#define STV090x_Px_AGC1QUAD(__x)		(0xF40D - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1QUAD			STV090x_Px_AGC1QUAD(1)
+#define STV090x_P2_AGC1QUAD			STV090x_Px_AGC1QUAD(2)
+#define STV090x_OFFST_Px_QUAD_VALUE_FIELD	0
+#define STV090x_WIDTH_Px_QUAD_VALUE_FIELD	8
+
+#define STV090x_Px_AGCIQINy(__x, __y)		(0xF40F - (__x-1) * 0x200 - __y * 0x1)
+#define STV090x_P1_AGCIQIN0			STV090x_Px_AGCIQINy(1, 0)
+#define STV090x_P1_AGCIQIN1			STV090x_Px_AGCIQINy(1, 1)
+#define STV090x_P2_AGCIQIN0			STV090x_Px_AGCIQINy(2, 0)
+#define STV090x_P2_AGCIQIN1			STV090x_Px_AGCIQINy(2, 1)
+#define STV090x_OFFST_Px_AGCIQ_VALUE_FIELD	0
+#define STV090x_WIDTH_Px_AGCIQ_VALUE_FIELD	8
+
+#define STV090x_Px_DEMOD(__x)			(0xF410 - (__x - 1) * 0x200)
+#define STV090x_P1_DEMOD			STV090x_Px_DEMOD(1)
+#define STV090x_P2_DEMOD			STV090x_Px_DEMOD(2)
+#define STV090x_OFFST_Px_MANUAL_S2ROLLOFF_FIELD	7
+#define STV090x_WIDTH_Px_MANUAL_S2ROLLOFF_FIELD	1
+#define STV090x_OFFST_Px_DEMOD_STOP_FIELD	6
+#define STV090x_WIDTH_Px_DEMOD_STOP_FIELD	1
+#define STV090x_OFFST_Px_SPECINV_CONTROL_FIELD	4
+#define STV090x_WIDTH_Px_SPECINV_CONTROL_FIELD	2
+#define STV090x_OFFST_Px_FORCE_ENASAMP_FIELD	3
+#define STV090x_WIDTH_Px_FORCE_ENASAMP_FIELD	1
+#define STV090x_OFFST_Px_MANUAL_SXROLLOFF_FIELD	2
+#define STV090x_WIDTH_Px_MANUAL_SXROLLOFF_FIELD	1
+#define STV090x_OFFST_Px_ROLLOFF_CONTROL_FIELD	0
+#define STV090x_WIDTH_Px_ROLLOFF_CONTROL_FIELD	2
+
+#define STV090x_Px_DMDMODCOD(__x)		(0xF411 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDMODCOD			STV090x_Px_DMDMODCOD(1)
+#define STV090x_P2_DMDMODCOD			STV090x_Px_DMDMODCOD(2)
+#define STV090x_OFFST_Px_MANUAL_MODCOD_FIELD	7
+#define STV090x_WIDTH_Px_MANUAL_MODCOD_FIELD	1
+#define STV090x_OFFST_Px_DEMOD_MODCOD_FIELD	2
+#define STV090x_WIDTH_Px_DEMOD_MODCOD_FIELD	5
+#define STV090x_OFFST_Px_DEMOD_TYPE_FIELD	0
+#define STV090x_WIDTH_Px_DEMOD_TYPE_FIELD	2
+
+#define STV090x_Px_DSTATUS(__x)			(0xF412 - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS			STV090x_Px_DSTATUS(1)
+#define STV090x_P2_DSTATUS			STV090x_Px_DSTATUS(2)
+#define STV090x_OFFST_Px_CAR_LOCK_FIELD		7
+#define STV090x_WIDTH_Px_CAR_LOCK_FIELD		1
+#define STV090x_OFFST_Px_TMGLOCK_QUALITY_FIELD	5
+#define STV090x_WIDTH_Px_TMGLOCK_QUALITY_FIELD	2
+#define STV090x_OFFST_Px_LOCK_DEFINITIF_FIELD	3
+#define STV090x_WIDTH_Px_LOCK_DEFINITIF_FIELD	1
+
+#define STV090x_Px_DSTATUS2(__x)		(0xF413 - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS2			STV090x_Px_DSTATUS2(1)
+#define STV090x_P2_DSTATUS2			STV090x_Px_DSTATUS2(2)
+#define STV090x_OFFST_Px_DEMOD_DELOCK_FIELD	7
+#define STV090x_WIDTH_Px_DEMOD_DELOCK_FIELD	1
+#define STV090x_OFFST_Px_AGC1_NOSIGNALACK_FIELD	3
+#define STV090x_WIDTH_Px_AGC1_NOSIGNALACK_FIELD	1
+#define STV090x_OFFST_Px_AGC2_OVERFLOW_FIELD	2
+#define STV090x_WIDTH_Px_AGC2_OVERFLOW_FIELD	1
+#define STV090x_OFFST_Px_CFR_OVERFLOW_FIELD	1
+#define STV090x_WIDTH_Px_CFR_OVERFLOW_FIELD	1
+#define STV090x_OFFST_Px_GAMMA_OVERUNDER_FIELD	0
+#define STV090x_WIDTH_Px_GAMMA_OVERUNDER_FIELD	1
+
+#define STV090x_Px_DMDCFGMD(__x)		(0xF414 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFGMD			STV090x_Px_DMDCFGMD(1)
+#define STV090x_P2_DMDCFGMD			STV090x_Px_DMDCFGMD(2)
+#define STV090x_OFFST_Px_DVBS2_ENABLE_FIELD	7
+#define STV090x_WIDTH_Px_DVBS2_ENABLE_FIELD	1
+#define STV090x_OFFST_Px_DVBS1_ENABLE_FIELD	6
+#define STV090x_WIDTH_Px_DVBS1_ENABLE_FIELD	1
+#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD	5 /* check */
+#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD	1
+#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD	4 /* check */
+#define STV090x_WIDTH_Px_SCAN_ENABLE_FIELD	1
+#define STV090x_OFFST_Px_TUN_AUTOSCAN_FIELD	3
+#define STV090x_WIDTH_Px_TUN_AUTOSCAN_FIELD	1
+#define STV090x_OFFST_Px_NOFORCE_RELOCK_FIELD	2
+#define STV090x_WIDTH_Px_NOFORCE_RELOCK_FIELD	1
+#define STV090x_OFFST_Px_TUN_RNG_FIELD		0
+#define STV090x_WIDTH_Px_TUN_RNG_FIELD		2
+
+#define STV090x_Px_DMDCFG2(__x)			(0xF415 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG2			STV090x_Px_DMDCFG2(1)
+#define STV090x_P2_DMDCFG2			STV090x_Px_DMDCFG2(2)
+#define STV090x_OFFST_Px_S1S2_SEQUENTIAL_FIELD	6
+#define STV090x_WIDTH_Px_S1S2_SEQUENTIAL_FIELD	1
+
+#define STV090x_Px_DMDISTATE(__x)		(0xF416 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDISTATE			STV090x_Px_DMDISTATE(1)
+#define STV090x_P2_DMDISTATE			STV090x_Px_DMDISTATE(2)
+#define STV090x_OFFST_Px_I2C_DEMOD_MODE_FIELD	0
+#define STV090x_WIDTH_Px_I2C_DEMOD_MODE_FIELD	5
+
+#define STV090x_Px_DMDTOM(__x)			(0xF417 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_DMDTOM			STV090x_Px_DMDTOM(1)
+#define STV090x_P2_DMDTOM			STV090x_Px_DMDTOM(2)
+
+#define STV090x_Px_DMDSTATE(__x)		(0xF41B - (__x - 1) * 0x200)
+#define STV090x_P1_DMDSTATE			STV090x_Px_DMDSTATE(1)
+#define STV090x_P2_DMDSTATE			STV090x_Px_DMDSTATE(2)
+#define STV090x_OFFST_Px_HEADER_MODE_FIELD	5
+#define STV090x_WIDTH_Px_HEADER_MODE_FIELD	2
+
+#define STV090x_Px_DMDFLYW(__x)			(0xF41C - (__x - 1) * 0x200)
+#define STV090x_P1_DMDFLYW			STV090x_Px_DMDFLYW(1)
+#define STV090x_P2_DMDFLYW			STV090x_Px_DMDFLYW(2)
+#define STV090x_OFFST_Px_I2C_IRQVAL_FIELD	4
+#define STV090x_WIDTH_Px_I2C_IRQVAL_FIELD	4
+#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD	0 /* check */
+#define STV090x_WIDTH_Px_FLYWHEEL_CPT_FIELD	4
+
+#define STV090x_Px_DSTATUS3(__x)		(0xF41D - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS3			STV090x_Px_DSTATUS3(1)
+#define STV090x_P2_DSTATUS3			STV090x_Px_DSTATUS3(2)
+#define STV090x_OFFST_Px_DEMOD_CFGMODE_FIELD	5
+#define STV090x_WIDTH_Px_DEMOD_CFGMODE_FIELD	2
+
+#define STV090x_Px_DMDCFG3(__x)			(0xF41E - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG3			STV090x_Px_DMDCFG3(1)
+#define STV090x_P2_DMDCFG3			STV090x_Px_DMDCFG3(2)
+#define STV090x_OFFST_Px_NOSTOP_FIFOFULL_FIELD	3
+#define STV090x_WIDTH_Px_NOSTOP_FIFOFULL_FIELD	1
+
+#define STV090x_Px_DMDCFG4(__x)			(0xf41f - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG4			STV090x_Px_DMDCFG4(1)
+#define STV090x_P2_DMDCFG4			STV090x_Px_DMDCFG4(2)
+
+#define STV090x_Px_CORRELMANT(__x)		(0xF420 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELMANT			STV090x_Px_CORRELMANT(1)
+#define STV090x_P2_CORRELMANT			STV090x_Px_CORRELMANT(2)
+#define STV090x_OFFST_Px_CORREL_MANT_FIELD	0
+#define STV090x_WIDTH_Px_CORREL_MANT_FIELD	8
+
+#define STV090x_Px_CORRELABS(__x)		(0xF421 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELABS			STV090x_Px_CORRELABS(1)
+#define STV090x_P2_CORRELABS			STV090x_Px_CORRELABS(2)
+#define STV090x_OFFST_Px_CORREL_ABS_FIELD	0
+#define STV090x_WIDTH_Px_CORREL_ABS_FIELD	8
+
+#define STV090x_Px_CORRELEXP(__x)		(0xF422 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELEXP			STV090x_Px_CORRELEXP(1)
+#define STV090x_P2_CORRELEXP			STV090x_Px_CORRELEXP(2)
+#define STV090x_OFFST_Px_CORREL_ABSEXP_FIELD	4
+#define STV090x_WIDTH_Px_CORREL_ABSEXP_FIELD	4
+#define STV090x_OFFST_Px_CORREL_EXP_FIELD	0
+#define STV090x_WIDTH_Px_CORREL_EXP_FIELD	4
+
+#define STV090x_Px_PLHMODCOD(__x)		(0xF424 - (__x - 1) * 0x200)
+#define STV090x_P1_PLHMODCOD			STV090x_Px_PLHMODCOD(1)
+#define STV090x_P2_PLHMODCOD			STV090x_Px_PLHMODCOD(2)
+#define STV090x_OFFST_Px_SPECINV_DEMOD_FIELD	7
+#define STV090x_WIDTH_Px_SPECINV_DEMOD_FIELD	1
+#define STV090x_OFFST_Px_PLH_MODCOD_FIELD	2
+#define STV090x_WIDTH_Px_PLH_MODCOD_FIELD	5
+#define STV090x_OFFST_Px_PLH_TYPE_FIELD		0
+#define STV090x_WIDTH_Px_PLH_TYPE_FIELD		2
+
+#define STV090x_Px_AGCK32(__x)			(0xf42b - (__x - 1) * 0x200)
+#define STV090x_P1_AGCK32			STV090x_Px_AGCK32(1)
+#define STV090x_P2_AGCK32			STV090x_Px_AGCK32(2)
+
+#define STV090x_Px_AGC2O(__x)			(0xF42C - (__x - 1) * 0x200)
+#define STV090x_P1_AGC2O			STV090x_Px_AGC2O(1)
+#define STV090x_P2_AGC2O			STV090x_Px_AGC2O(2)
+
+#define STV090x_Px_AGC2REF(__x)			(0xF42D - (__x - 1) * 0x200)
+#define STV090x_P1_AGC2REF			STV090x_Px_AGC2REF(1)
+#define STV090x_P2_AGC2REF			STV090x_Px_AGC2REF(2)
+#define STV090x_OFFST_Px_AGC2_REF_FIELD		0
+#define STV090x_WIDTH_Px_AGC2_REF_FIELD		8
+
+#define STV090x_Px_AGC1ADJ(__x)			(0xF42E - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1ADJ			STV090x_Px_AGC1ADJ(1)
+#define STV090x_P2_AGC1ADJ			STV090x_Px_AGC1ADJ(2)
+#define STV090x_OFFST_Px_AGC1_ADJUSTED_FIELD	0
+#define STV090x_WIDTH_Px_AGC1_ADJUSTED_FIELD	7
+
+#define STV090x_Px_AGC2Iy(__x, __y)		(0xF437 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_AGC2I0			STV090x_Px_AGC2Iy(1, 0)
+#define STV090x_P1_AGC2I1			STV090x_Px_AGC2Iy(1, 1)
+#define STV090x_P2_AGC2I0			STV090x_Px_AGC2Iy(2, 0)
+#define STV090x_P2_AGC2I1			STV090x_Px_AGC2Iy(2, 1)
+#define STV090x_OFFST_Px_AGC2_INTEGRATOR_FIELD	0
+#define STV090x_WIDTH_Px_AGC2_INTEGRATOR_FIELD	8
+
+#define STV090x_Px_CARCFG(__x)			(0xF438 - (__x - 1) * 0x200)
+#define STV090x_P1_CARCFG			STV090x_Px_CARCFG(1)
+#define STV090x_P2_CARCFG			STV090x_Px_CARCFG(2)
+#define STV090x_OFFST_Px_EN_CAR2CENTER_FIELD	5
+#define STV090x_WIDTH_Px_EN_CAR2CENTER_FIELD	1
+#define STV090x_OFFST_Px_ROTATON_FIELD		2
+#define STV090x_WIDTH_Px_ROTATON_FIELD		1
+#define STV090x_OFFST_Px_PH_DET_ALGO_FIELD	0
+#define STV090x_WIDTH_Px_PH_DET_ALGO_FIELD	2
+
+#define STV090x_Px_ACLC(__x)			(0xF439 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC				STV090x_Px_ACLC(1)
+#define STV090x_P2_ACLC				STV090x_Px_ACLC(2)
+#define STV090x_OFFST_Px_CAR_ALPHA_MANT_FIELD	4
+#define STV090x_WIDTH_Px_CAR_ALPHA_MANT_FIELD	2
+#define STV090x_OFFST_Px_CAR_ALPHA_EXP_FIELD	0
+#define STV090x_WIDTH_Px_CAR_ALPHA_EXP_FIELD	4
+
+#define STV090x_Px_BCLC(__x)			(0xF43A - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC				STV090x_Px_BCLC(1)
+#define STV090x_P2_BCLC				STV090x_Px_BCLC(2)
+#define STV090x_OFFST_Px_CAR_BETA_MANT_FIELD	4
+#define STV090x_WIDTH_Px_CAR_BETA_MANT_FIELD	2
+#define STV090x_OFFST_Px_CAR_BETA_EXP_FIELD	0
+#define STV090x_WIDTH_Px_CAR_BETA_EXP_FIELD	4
+
+#define STV090x_Px_CARFREQ(__x)			(0xF43D - (__x - 1) * 0x200)
+#define STV090x_P1_CARFREQ			STV090x_Px_CARFREQ(1)
+#define STV090x_P2_CARFREQ			STV090x_Px_CARFREQ(2)
+#define STV090x_OFFST_Px_KC_COARSE_EXP_FIELD	4
+#define STV090x_WIDTH_Px_KC_COARSE_EXP_FIELD	4
+#define STV090x_OFFST_Px_BETA_FREQ_FIELD	0
+#define STV090x_WIDTH_Px_BETA_FREQ_FIELD	4
+
+#define STV090x_Px_CARHDR(__x)			(0xF43E - (__x - 1) * 0x200)
+#define STV090x_P1_CARHDR			STV090x_Px_CARHDR(1)
+#define STV090x_P2_CARHDR			STV090x_Px_CARHDR(2)
+#define STV090x_OFFST_Px_FREQ_HDR_FIELD		0
+#define STV090x_WIDTH_Px_FREQ_HDR_FIELD		8
+
+#define STV090x_Px_LDT(__x)			(0xF43F - (__x - 1) * 0x200)
+#define STV090x_P1_LDT				STV090x_Px_LDT(1)
+#define STV090x_P2_LDT				STV090x_Px_LDT(2)
+#define STV090x_OFFST_Px_CARLOCK_THRES_FIELD	0
+#define STV090x_WIDTH_Px_CARLOCK_THRES_FIELD	8
+
+#define STV090x_Px_LDT2(__x)			(0xF440 - (__x - 1) * 0x200)
+#define STV090x_P1_LDT2				STV090x_Px_LDT2(1)
+#define STV090x_P2_LDT2				STV090x_Px_LDT2(2)
+#define STV090x_OFFST_Px_CARLOCK_THRES2_FIELD	0
+#define STV090x_WIDTH_Px_CARLOCK_THRES2_FIELD	8
+
+#define STV090x_Px_CFRICFG(__x)			(0xF441 - (__x - 1) * 0x200)
+#define STV090x_P1_CFRICFG			STV090x_Px_CFRICFG(1)
+#define STV090x_P2_CFRICFG			STV090x_Px_CFRICFG(2)
+#define STV090x_OFFST_Px_NEG_CFRSTEP_FIELD	0
+#define STV090x_WIDTH_Px_NEG_CFRSTEP_FIELD	1
+
+#define STV090x_Pn_CFRUPy(__x, __y)		(0xF443 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRUP0			STV090x_Pn_CFRUPy(1, 0)
+#define STV090x_P1_CFRUP1			STV090x_Pn_CFRUPy(1, 1)
+#define STV090x_P2_CFRUP0			STV090x_Pn_CFRUPy(2, 0)
+#define STV090x_P2_CFRUP1			STV090x_Pn_CFRUPy(2, 1)
+#define STV090x_OFFST_Px_CFR_UP_FIELD		0
+#define STV090x_WIDTH_Px_CFR_UP_FIELD		8
+
+#define STV090x_Pn_CFRLOWy(__x, __y)		(0xF447 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRLOW0			STV090x_Pn_CFRLOWy(1, 0)
+#define STV090x_P1_CFRLOW1			STV090x_Pn_CFRLOWy(1, 1)
+#define STV090x_P2_CFRLOW0			STV090x_Pn_CFRLOWy(2, 0)
+#define STV090x_P2_CFRLOW1			STV090x_Pn_CFRLOWy(2, 1)
+#define STV090x_OFFST_Px_CFR_LOW_FIELD		0
+#define STV090x_WIDTH_Px_CFR_LOW_FIELD		8
+
+#define STV090x_Pn_CFRINITy(__x, __y)		(0xF449 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRINIT0			STV090x_Pn_CFRINITy(1, 0)
+#define STV090x_P1_CFRINIT1			STV090x_Pn_CFRINITy(1, 1)
+#define STV090x_P2_CFRINIT0			STV090x_Pn_CFRINITy(2, 0)
+#define STV090x_P2_CFRINIT1			STV090x_Pn_CFRINITy(2, 1)
+#define STV090x_OFFST_Px_CFR_INIT_FIELD		0
+#define STV090x_WIDTH_Px_CFR_INIT_FIELD		8
+
+#define STV090x_Px_CFRINC1(__x)			(0xF44A - (__x - 1) * 0x200)
+#define STV090x_P1_CFRINC1			STV090x_Px_CFRINC1(1)
+#define STV090x_P2_CFRINC1			STV090x_Px_CFRINC1(2)
+#define STV090x_OFFST_Px_CFR_INC1_FIELD		0
+#define STV090x_WIDTH_Px_CFR_INC1_FIELD		7
+
+#define STV090x_Px_CFRINC0(__x)			(0xF44B - (__x - 1) * 0x200)
+#define STV090x_P1_CFRINC0			STV090x_Px_CFRINC0(1)
+#define STV090x_P2_CFRINC0			STV090x_Px_CFRINC0(2)
+#define STV090x_OFFST_Px_CFR_INC0_FIELD		4
+#define STV090x_WIDTH_Px_CFR_INC0_FIELD		4
+
+#define STV090x_Pn_CFRy(__x, __y)		(0xF44E - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFR0				STV090x_Pn_CFRy(1, 0)
+#define STV090x_P1_CFR1				STV090x_Pn_CFRy(1, 1)
+#define STV090x_P1_CFR2				STV090x_Pn_CFRy(1, 2)
+#define STV090x_P2_CFR0				STV090x_Pn_CFRy(2, 0)
+#define STV090x_P2_CFR1				STV090x_Pn_CFRy(2, 1)
+#define STV090x_P2_CFR2				STV090x_Pn_CFRy(2, 2)
+#define STV090x_OFFST_Px_CAR_FREQ_FIELD		0
+#define STV090x_WIDTH_Px_CAR_FREQ_FIELD		8
+
+#define STV090x_Px_LDI(__x)			(0xF44F - (__x - 1) * 0x200)
+#define STV090x_P1_LDI				STV090x_Px_LDI(1)
+#define STV090x_P2_LDI				STV090x_Px_LDI(2)
+#define STV090x_OFFST_Px_LOCK_DET_INTEGR_FIELD	0
+#define STV090x_WIDTH_Px_LOCK_DET_INTEGR_FIELD	8
+
+#define STV090x_Px_TMGCFG(__x)			(0xF450 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGCFG			STV090x_Px_TMGCFG(1)
+#define STV090x_P2_TMGCFG			STV090x_Px_TMGCFG(2)
+#define STV090x_OFFST_Px_TMGLOCK_BETA_FIELD	6
+#define STV090x_WIDTH_Px_TMGLOCK_BETA_FIELD	2
+#define STV090x_OFFST_Px_DO_TIMING_FIELD	4
+#define STV090x_WIDTH_Px_DO_TIMING_FIELD	1
+#define STV090x_OFFST_Px_TMG_MINFREQ_FIELD	0
+#define STV090x_WIDTH_Px_TMG_MINFREQ_FIELD	2
+
+#define STV090x_Px_RTC(__x)			(0xF451 - (__x - 1) * 0x200)
+#define STV090x_P1_RTC				STV090x_Px_RTC(1)
+#define STV090x_P2_RTC				STV090x_Px_RTC(2)
+#define STV090x_OFFST_Px_TMGALPHA_EXP_FIELD	4
+#define STV090x_WIDTH_Px_TMGALPHA_EXP_FIELD	4
+#define STV090x_OFFST_Px_TMGBETA_EXP_FIELD	0
+#define STV090x_WIDTH_Px_TMGBETA_EXP_FIELD	4
+
+#define STV090x_Px_RTCS2(__x)			(0xF452 - (__x - 1) * 0x200)
+#define STV090x_P1_RTCS2			STV090x_Px_RTCS2(1)
+#define STV090x_P2_RTCS2			STV090x_Px_RTCS2(2)
+#define STV090x_OFFST_Px_TMGALPHAS2_EXP_FIELD	4
+#define STV090x_WIDTH_Px_TMGALPHAS2_EXP_FIELD	4
+#define STV090x_OFFST_Px_TMGBETAS2_EXP_FIELD	0
+#define STV090x_WIDTH_Px_TMGBETAS2_EXP_FIELD	4
+
+#define STV090x_Px_TMGTHRISE(__x)		(0xF453 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGTHRISE			STV090x_Px_TMGTHRISE(1)
+#define STV090x_P2_TMGTHRISE			STV090x_Px_TMGTHRISE(2)
+#define STV090x_OFFST_Px_TMGLOCK_THRISE_FIELD	0
+#define STV090x_WIDTH_Px_TMGLOCK_THRISE_FIELD	8
+
+#define STV090x_Px_TMGTHFALL(__x)		(0xF454 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGTHFALL			STV090x_Px_TMGTHFALL(1)
+#define STV090x_P2_TMGTHFALL			STV090x_Px_TMGTHFALL(2)
+#define STV090x_OFFST_Px_TMGLOCK_THFALL_FIELD	0
+#define STV090x_WIDTH_Px_TMGLOCK_THFALL_FIELD	8
+
+#define STV090x_Px_SFRUPRATIO(__x)		(0xF455 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUPRATIO			STV090x_Px_SFRUPRATIO(1)
+#define STV090x_P2_SFRUPRATIO			STV090x_Px_SFRUPRATIO(2)
+#define STV090x_OFFST_Px_SFR_UPRATIO_FIELD	0
+#define STV090x_WIDTH_Px_SFR_UPRATIO_FIELD	8
+
+#define STV090x_Px_SFRLOWRATIO(__x)		(0xF456 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOWRATIO			STV090x_Px_SFRLOWRATIO(1)
+#define STV090x_P2_SFRLOWRATIO			STV090x_Px_SFRLOWRATIO(2)
+#define STV090x_OFFST_Px_SFR_LOWRATIO_FIELD	0
+#define STV090x_WIDTH_Px_SFR_LOWRATIO_FIELD	8
+
+#define STV090x_Px_KREFTMG(__x)			(0xF458 - (__x - 1) * 0x200)
+#define STV090x_P1_KREFTMG			STV090x_Px_KREFTMG(1)
+#define STV090x_P2_KREFTMG			STV090x_Px_KREFTMG(2)
+#define STV090x_OFFST_Px_KREF_TMG_FIELD		0
+#define STV090x_WIDTH_Px_KREF_TMG_FIELD		8
+
+#define STV090x_Px_SFRSTEP(__x)			(0xF459 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRSTEP			STV090x_Px_SFRSTEP(1)
+#define STV090x_P2_SFRSTEP			STV090x_Px_SFRSTEP(2)
+#define STV090x_OFFST_Px_SFR_SCANSTEP_FIELD	4
+#define STV090x_WIDTH_Px_SFR_SCANSTEP_FIELD	4
+#define STV090x_OFFST_Px_SFR_CENTERSTEP_FIELD	0
+#define STV090x_WIDTH_Px_SFR_CENTERSTEP_FIELD	4
+
+#define STV090x_Px_TMGCFG2(__x)			(0xF45A - (__x - 1) * 0x200)
+#define STV090x_P1_TMGCFG2			STV090x_Px_TMGCFG2(1)
+#define STV090x_P2_TMGCFG2			STV090x_Px_TMGCFG2(2)
+#define STV090x_OFFST_Px_SFRRATIO_FINE_FIELD	0
+#define STV090x_WIDTH_Px_SFRRATIO_FINE_FIELD	1
+
+#define STV090x_Px_SFRINIT1(__x)		(0xF45E - (__x - 1) * 0x200)
+#define STV090x_P1_SFRINIT1			STV090x_Px_SFRINIT1(1)
+#define STV090x_P2_SFRINIT1			STV090x_Px_SFRINIT1(2)
+#define STV090x_OFFST_Px_SFR_INIT_FIELD		0
+#define STV090x_WIDTH_Px_SFR_INIT_FIELD		8
+
+#define STV090x_Px_SFRINIT0(__x)		(0xF45F - (__x - 1) * 0x200)
+#define STV090x_P1_SFRINIT0			STV090x_Px_SFRINIT0(1)
+#define STV090x_P2_SFRINIT0			STV090x_Px_SFRINIT0(2)
+#define STV090x_OFFST_Px_SFR_INIT_FIELD		0
+#define STV090x_WIDTH_Px_SFR_INIT_FIELD		8
+
+#define STV090x_Px_SFRUP1(__x)			(0xF460 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUP1			STV090x_Px_SFRUP1(1)
+#define STV090x_P2_SFRUP1			STV090x_Px_SFRUP1(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_UP1_FIELD	0
+#define STV090x_WIDTH_Px_SYMB_FREQ_UP1_FIELD	7
+
+#define STV090x_Px_SFRUP0(__x)			(0xF461 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUP0			STV090x_Px_SFRUP0(1)
+#define STV090x_P2_SFRUP0			STV090x_Px_SFRUP0(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_UP0_FIELD	0
+#define STV090x_WIDTH_Px_SYMB_FREQ_UP0_FIELD	8
+
+#define STV090x_Px_SFRLOW1(__x)			(0xF462 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOW1			STV090x_Px_SFRLOW1(1)
+#define STV090x_P2_SFRLOW1			STV090x_Px_SFRLOW1(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_LOW1_FIELD	0
+#define STV090x_WIDTH_Px_SYMB_FREQ_LOW1_FIELD	7
+
+#define STV090x_Px_SFRLOW0(__x)			(0xF463 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOW0			STV090x_Px_SFRLOW0(1)
+#define STV090x_P2_SFRLOW0			STV090x_Px_SFRLOW0(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_LOW0_FIELD	0
+#define STV090x_WIDTH_Px_SYMB_FREQ_LOW0_FIELD	8
+
+#define STV090x_Px_SFRy(__x, __y)		(0xF464 - (__x-1) * 0x200 + (3 - __y))
+#define STV090x_P1_SFR0				STV090x_Px_SFRy(1, 0)
+#define STV090x_P1_SFR1				STV090x_Px_SFRy(1, 1)
+#define STV090x_P1_SFR2				STV090x_Px_SFRy(1, 2)
+#define STV090x_P1_SFR3				STV090x_Px_SFRy(1, 3)
+#define STV090x_P2_SFR0				STV090x_Px_SFRy(2, 0)
+#define STV090x_P2_SFR1				STV090x_Px_SFRy(2, 1)
+#define STV090x_P2_SFR2				STV090x_Px_SFRy(2, 2)
+#define STV090x_P2_SFR3				STV090x_Px_SFRy(2, 3)
+#define STV090x_OFFST_Px_SYMB_FREQ_FIELD	0
+#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD	32
+
+#define STV090x_Px_TMGREG2(__x)			(0xF468 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG2			STV090x_Px_TMGREG2(1)
+#define STV090x_P2_TMGREG2			STV090x_Px_TMGREG2(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD		0
+#define STV090x_WIDTH_Px_TMGREG_FIELD		8
+
+#define STV090x_Px_TMGREG1(__x)			(0xF469 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG1			STV090x_Px_TMGREG1(1)
+#define STV090x_P2_TMGREG1				STV090x_Px_TMGREG1(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD		0
+#define STV090x_WIDTH_Px_TMGREG_FIELD		8
+
+#define STV090x_Px_TMGREG0(__x)			(0xF46A - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG0			STV090x_Px_TMGREG0(1)
+#define STV090x_P2_TMGREG0			STV090x_Px_TMGREG0(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD		0
+#define STV090x_WIDTH_Px_TMGREG_FIELD		8
+
+#define STV090x_Px_TMGLOCKy(__x, __y)		(0xF46C - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_TMGLOCK0			STV090x_Px_TMGLOCKy(1, 0)
+#define STV090x_P1_TMGLOCK1			STV090x_Px_TMGLOCKy(1, 1)
+#define STV090x_P2_TMGLOCK0			STV090x_Px_TMGLOCKy(2, 0)
+#define STV090x_P2_TMGLOCK1			STV090x_Px_TMGLOCKy(2, 1)
+#define STV090x_OFFST_Px_TMGLOCK_LEVEL_FIELD	0
+#define STV090x_WIDTH_Px_TMGLOCK_LEVEL_FIELD	8
+
+#define STV090x_Px_TMGOBS(__x)			(0xF46D - (__x - 1) * 0x200)
+#define STV090x_P1_TMGOBS			STV090x_Px_TMGOBS(1)
+#define STV090x_P2_TMGOBS			STV090x_Px_TMGOBS(2)
+#define STV090x_OFFST_Px_ROLLOFF_STATUS_FIELD	6
+#define STV090x_WIDTH_Px_ROLLOFF_STATUS_FIELD	2
+
+#define STV090x_Px_EQUALCFG(__x)		(0xF46F - (__x - 1) * 0x200)
+#define STV090x_P1_EQUALCFG			STV090x_Px_EQUALCFG(1)
+#define STV090x_P2_EQUALCFG			STV090x_Px_EQUALCFG(2)
+#define STV090x_OFFST_Px_EQUAL_ON_FIELD		6
+#define STV090x_WIDTH_Px_EQUAL_ON_FIELD		1
+#define STV090x_OFFST_Px_MU_EQUALDFE_FIELD	0
+#define STV090x_WIDTH_Px_MU_EQUALDFE_FIELD	3
+
+#define STV090x_Px_EQUAIy(__x, __y)		(0xf470 - (__x - 1) * 0x200 + (__y - 1))
+#define STV090x_P1_EQUAI1			STV090x_Px_EQUAIy(1, 1)
+#define STV090x_P1_EQUAI2			STV090x_Px_EQUAIy(1, 2)
+#define STV090x_P1_EQUAI3			STV090x_Px_EQUAIy(1, 3)
+#define STV090x_P1_EQUAI4			STV090x_Px_EQUAIy(1, 4)
+#define STV090x_P1_EQUAI5			STV090x_Px_EQUAIy(1, 5)
+#define STV090x_P1_EQUAI6			STV090x_Px_EQUAIy(1, 6)
+#define STV090x_P1_EQUAI7			STV090x_Px_EQUAIy(1, 7)
+#define STV090x_P1_EQUAI8			STV090x_Px_EQUAIy(1, 8)
+
+#define STV090x_P2_EQUAI1			STV090x_Px_EQUAIy(2, 1)
+#define STV090x_P2_EQUAI2			STV090x_Px_EQUAIy(2, 2)
+#define STV090x_P2_EQUAI3			STV090x_Px_EQUAIy(2, 3)
+#define STV090x_P2_EQUAI4			STV090x_Px_EQUAIy(2, 4)
+#define STV090x_P2_EQUAI5			STV090x_Px_EQUAIy(2, 5)
+#define STV090x_P2_EQUAI6			STV090x_Px_EQUAIy(2, 6)
+#define STV090x_P2_EQUAI7			STV090x_Px_EQUAIy(2, 7)
+#define STV090x_P2_EQUAI8			STV090x_Px_EQUAIy(2, 8)
+#define STV090x_OFFST_Px_EQUA_ACCIy_FIELD	0
+#define STV090x_WIDTH_Px_EQUA_ACCIy_FIELD	8
+
+#define STV090x_Px_EQUAQy(__x, __y)		(0xf471 - (__x - 1) * 0x200 + (__y - 1))
+#define STV090x_P1_EQUAQ1			STV090x_Px_EQUAQy(1, 1)
+#define STV090x_P1_EQUAQ2			STV090x_Px_EQUAQy(1, 2)
+#define STV090x_P1_EQUAQ3			STV090x_Px_EQUAQy(1, 3)
+#define STV090x_P1_EQUAQ4			STV090x_Px_EQUAQy(1, 4)
+#define STV090x_P1_EQUAQ5			STV090x_Px_EQUAQy(1, 5)
+#define STV090x_P1_EQUAQ6			STV090x_Px_EQUAQy(1, 6)
+#define STV090x_P1_EQUAQ7			STV090x_Px_EQUAQy(1, 7)
+#define STV090x_P1_EQUAQ8			STV090x_Px_EQUAQy(1, 8)
+
+#define STV090x_P2_EQUAQ1			STV090x_Px_EQUAQy(2, 1)
+#define STV090x_P2_EQUAQ2			STV090x_Px_EQUAQy(2, 2)
+#define STV090x_P2_EQUAQ3			STV090x_Px_EQUAQy(2, 3)
+#define STV090x_P2_EQUAQ4			STV090x_Px_EQUAQy(2, 4)
+#define STV090x_P2_EQUAQ5			STV090x_Px_EQUAQy(2, 5)
+#define STV090x_P2_EQUAQ6			STV090x_Px_EQUAQy(2, 6)
+#define STV090x_P2_EQUAQ7			STV090x_Px_EQUAQy(2, 7)
+#define STV090x_P2_EQUAQ8			STV090x_Px_EQUAQy(2, 8)
+#define STV090x_OFFST_Px_EQUA_ACCQy_FIELD	0
+#define STV090x_WIDTH_Px_EQUA_ACCQy_FIELD	8
+
+#define STV090x_Px_NNOSDATATy(__x, __y)		(0xf481 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSDATAT0			STV090x_Px_NNOSDATATy(1, 0)
+#define STV090x_P1_NNOSDATAT1			STV090x_Px_NNOSDATATy(1, 1)
+#define STV090x_P2_NNOSDATAT0			STV090x_Px_NNOSDATATy(2, 0)
+#define STV090x_P2_NNOSDATAT1			STV090x_Px_NNOSDATATy(2, 1)
+#define STV090x_OFFST_Px_NOSDATAT_NORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSDATAT_NORMED_FIELD	8
+
+#define STV090x_Px_NNOSDATAy(__x, __y)		(0xf483 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSDATA0			STV090x_Px_NNOSDATAy(1, 0)
+#define STV090x_P1_NNOSDATA1			STV090x_Px_NNOSDATAy(1, 1)
+#define STV090x_P2_NNOSDATA0			STV090x_Px_NNOSDATAy(2, 0)
+#define STV090x_P2_NNOSDATA1			STV090x_Px_NNOSDATAy(2, 1)
+#define STV090x_OFFST_Px_NOSDATA_NORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSDATA_NORMED_FIELD	8
+
+#define STV090x_Px_NNOSPLHTy(__x, __y)		(0xf485 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSPLHT0			STV090x_Px_NNOSPLHTy(1, 0)
+#define STV090x_P1_NNOSPLHT1			STV090x_Px_NNOSPLHTy(1, 1)
+#define STV090x_P2_NNOSPLHT0			STV090x_Px_NNOSPLHTy(2, 0)
+#define STV090x_P2_NNOSPLHT1			STV090x_Px_NNOSPLHTy(2, 1)
+#define STV090x_OFFST_Px_NOSPLHT_NORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSPLHT_NORMED_FIELD	8
+
+#define STV090x_Px_NNOSPLHy(__x, __y)		(0xf487 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSPLH0			STV090x_Px_NNOSPLHy(1, 0)
+#define STV090x_P1_NNOSPLH1			STV090x_Px_NNOSPLHy(1, 1)
+#define STV090x_P2_NNOSPLH0			STV090x_Px_NNOSPLHy(2, 0)
+#define STV090x_P2_NNOSPLH1			STV090x_Px_NNOSPLHy(2, 1)
+#define STV090x_OFFST_Px_NOSPLH_NORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSPLH_NORMED_FIELD	8
+
+#define STV090x_Px_NOSDATATy(__x, __y)			(0xf489 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSDATAT0				STV090x_Px_NOSDATATy(1, 0)
+#define STV090x_P1_NOSDATAT1				STV090x_Px_NOSDATATy(1, 1)
+#define STV090x_P2_NOSDATAT0				STV090x_Px_NOSDATATy(2, 0)
+#define STV090x_P2_NOSDATAT1				STV090x_Px_NOSDATATy(2, 1)
+#define STV090x_OFFST_Px_NOSDATAT_UNNORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSDATAT_UNNORMED_FIELD	8
+
+#define STV090x_Px_NOSDATAy(__x, __y)		(0xf48b - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSDATA0			STV090x_Px_NOSDATAy(1, 0)
+#define STV090x_P1_NOSDATA1			STV090x_Px_NOSDATAy(1, 1)
+#define STV090x_P2_NOSDATA0			STV090x_Px_NOSDATAy(2, 0)
+#define STV090x_P2_NOSDATA1			STV090x_Px_NOSDATAy(2, 1)
+#define STV090x_OFFST_Px_NOSDATA_UNNORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSDATA_UNNORMED_FIELD	8
+
+#define STV090x_Px_NOSPLHTy(__x, __y)		(0xf48d - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSPLHT0			STV090x_Px_NOSPLHTy(1, 0)
+#define STV090x_P1_NOSPLHT1			STV090x_Px_NOSPLHTy(1, 1)
+#define STV090x_P2_NOSPLHT0			STV090x_Px_NOSPLHTy(2, 0)
+#define STV090x_P2_NOSPLHT1			STV090x_Px_NOSPLHTy(2, 1)
+#define STV090x_OFFST_Px_NOSPLHT_UNNORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSPLHT_UNNORMED_FIELD	8
+
+#define STV090x_Px_NOSPLHy(__x, __y)		(0xf48f - (__x - 1) * 0x200 - __y * 0x1)
+#define STv090x_P1_NOSPLH0			STV090x_Px_NOSPLHy(1, 0)
+#define STv090x_P1_NOSPLH1			STV090x_Px_NOSPLHy(1, 1)
+#define STv090x_P2_NOSPLH0			STV090x_Px_NOSPLHy(2, 0)
+#define STv090x_P2_NOSPLH1			STV090x_Px_NOSPLHy(2, 1)
+#define STV090x_OFFST_Px_NOSPLH_UNNORMED_FIELD	0
+#define STV090x_WIDTH_Px_NOSPLH_UNNORMED_FIELD	8
+
+#define STV090x_Px_CAR2CFG(__x)			(0xf490 - (__x - 1) * 0x200)
+#define STV090x_P1_CAR2CFG			STV090x_Px_CAR2CFG(1)
+#define STV090x_P2_CAR2CFG			STV090x_Px_CAR2CFG(2)
+#define STV090x_OFFST_Px_PN4_SELECT_FIELD	6
+#define STV090x_WIDTH_Px_PN4_SELECT_FIELD	1
+#define STV090x_OFFST_Px_CFR2_STOPDVBS1_FIELD	5
+#define STV090x_WIDTH_Px_CFR2_STOPDVBS1_FIELD	1
+#define STV090x_OFFST_Px_ROTA2ON_FIELD		2
+#define STV090x_WIDTH_Px_ROTA2ON_FIELD		1
+#define STV090x_OFFST_Px_PH_DET_ALGO2_FIELD	0
+#define STV090x_WIDTH_Px_PH_DET_ALGO2_FIELD	2
+
+#define STV090x_Px_ACLC2(__x)			(0xf491 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2			STV090x_Px_ACLC2(1)
+#define STV090x_P2_ACLC2			STV090x_Px_ACLC2(2)
+#define STV090x_OFFST_Px_CAR2_ALPHA_MANT_FIELD	4
+#define STV090x_WIDTH_Px_CAR2_ALPHA_MANT_FIELD	2
+#define STV090x_OFFST_Px_CAR2_ALPHA_EXP_FIELD	0
+#define STV090x_WIDTH_Px_CAR2_ALPHA_EXP_FIELD	4
+
+#define STV090x_Px_BCLC2(__x)			(0xf492 - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2			STV090x_Px_BCLC2(1)
+#define STV090x_P2_BCLC2			STV090x_Px_BCLC2(2)
+#define STV090x_OFFST_Px_CAR2_BETA_MANT_FIELD	4
+#define STV090x_WIDTH_Px_CAR2_BETA_MANT_FIELD	2
+#define STV090x_OFFST_Px_CAR2_BETA_EXP_FIELD	0
+#define STV090x_WIDTH_Px_CAR2_BETA_EXP_FIELD	4
+
+#define STV090x_Px_ACLC2S2Q(__x)		(0xf497 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S2Q			STV090x_Px_ACLC2S2Q(1)
+#define STV090x_P2_ACLC2S2Q			STV090x_Px_ACLC2S2Q(2)
+#define STV090x_OFFST_Px_ENAB_SPSKSYMB_FIELD	7
+#define STV090x_WIDTH_Px_ENAB_SPSKSYMB_FIELD	1
+#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_E_FIELD	4
+
+#define STV090x_Px_ACLC2S28(__x)		(0xf498 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S28			STV090x_Px_ACLC2S28(1)
+#define STV090x_P2_ACLC2S28			STV090x_Px_ACLC2S28(2)
+#define STV090x_OFFST_Px_CAR2S2_8_ALPH_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_8_ALPH_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_E_FIELD	4
+
+#define STV090x_Px_ACLC2S216A(__x)		(0xf499 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S216A			STV090x_Px_ACLC2S216A(1)
+#define STV090x_P2_ACLC2S216A			STV090x_Px_ACLC2S216A(2)
+#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_E_FIELD	4
+
+#define STV090x_Px_ACLC2S232A(__x)		(0xf499 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S232A			STV090x_Px_ACLC2S232A(1)
+#define STV090x_P2_ACLC2S232A			STV090x_Px_ACLC2S232A(2)
+#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_E_FIELD	4
+
+#define STV090x_Px_BCLC2S2Q(__x)		(0xf49c - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S2Q			STV090x_Px_BCLC2S2Q(1)
+#define STV090x_P2_BCLC2S2Q			STV090x_Px_BCLC2S2Q(2)
+#define STV090x_OFFST_Px_CAR2S2_Q_BETA_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_Q_BETA_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_E_FIELD	4
+
+#define STV090x_Px_BCLC2S28(__x)		(0xf49d - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S28			STV090x_Px_BCLC2S28(1)
+#define STV090x_P2_BCLC2S28			STV090x_Px_BCLC2S28(1)
+#define STV090x_OFFST_Px_CAR2S2_8_BETA_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_8_BETA_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_8_BETA_E_FIELD	4
+
+#define STV090x_Px_BCLC2S216A(__x)		(0xf49d - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S216A			STV090x_Px_BCLC2S216A(1)
+#define STV090x_P2_BCLC2S216A			STV090x_Px_BCLC2S216A(1)
+#define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_E_FIELD	4
+
+#define STV090x_Px_BCLC2S232A(__x)		(0xf49d - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S232A			STV090x_Px_BCLC2S232A(1)
+#define STV090x_P2_BCLC2S232A			STV090x_Px_BCLC2S232A(1)
+#define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD	4
+#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_M_FIELD	2
+#define STV090x_OFFST_Px_CAR2S2_32A_BETA_E_FIELD	0
+#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_E_FIELD	4
+
+#define STV090x_Px_PLROOT2(__x)			(0xf4ac - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT2			STV090x_Px_PLROOT2(1)
+#define STV090x_P2_PLROOT2			STV090x_Px_PLROOT2(2)
+#define STV090x_OFFST_Px_PLSCRAMB_MODE_FIELD	2
+#define STV090x_WIDTH_Px_PLSCRAMB_MODE_FIELD	2
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT_FIELD	0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT_FIELD	2
+
+#define STV090x_Px_PLROOT1(__x)			(0xf4ad - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT1			STV090x_Px_PLROOT1(1)
+#define STV090x_P2_PLROOT1			STV090x_Px_PLROOT1(2)
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT1_FIELD	0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT1_FIELD	8
+
+#define STV090x_Px_PLROOT0(__x)			(0xf4ae - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT0			STV090x_Px_PLROOT0(1)
+#define STV090x_P2_PLROOT0			STV090x_Px_PLROOT0(2)
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT0_FIELD	0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT0_FIELD	8
+
+#define STV090x_Px_MODCODLST0(__x)		(0xf4b0 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_MODCODLST0			STV090x_Px_MODCODLST0(1)
+#define STV090x_P2_MODCODLST0			STV090x_Px_MODCODLST0(2)
+
+#define STV090x_Px_MODCODLST1(__x)		(0xf4b1 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST1			STV090x_Px_MODCODLST1(1)
+#define STV090x_P2_MODCODLST1			STV090x_Px_MODCODLST1(2)
+#define STV090x_OFFST_Px_DIS_MODCOD29_FIELD	4
+#define STV090x_WIDTH_Px_DIS_MODCOD29T_FIELD	4
+#define STV090x_OFFST_Px_DIS_32PSK_9_10_FIELD	0
+#define STV090x_WIDTH_Px_DIS_32PSK_9_10_FIELD	4
+
+#define STV090x_Px_MODCODLST2(__x)		(0xf4b2 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST2			STV090x_Px_MODCODLST2(1)
+#define STV090x_P2_MODCODLST2			STV090x_Px_MODCODLST2(2)
+#define STV090x_OFFST_Px_DIS_32PSK_8_9_FIELD	4
+#define STV090x_WIDTH_Px_DIS_32PSK_8_9_FIELD	4
+#define STV090x_OFFST_Px_DIS_32PSK_5_6_FIELD	0
+#define STV090x_WIDTH_Px_DIS_32PSK_5_6_FIELD	4
+
+#define STV090x_Px_MODCODLST3(__x)		(0xf4b3 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST3			STV090x_Px_MODCODLST3(1)
+#define STV090x_P2_MODCODLST3			STV090x_Px_MODCODLST3(2)
+#define STV090x_OFFST_Px_DIS_32PSK_4_5_FIELD	4
+#define STV090x_WIDTH_Px_DIS_32PSK_4_5_FIELD	4
+#define STV090x_OFFST_Px_DIS_32PSK_3_4_FIELD	0
+#define STV090x_WIDTH_Px_DIS_32PSK_3_4_FIELD	4
+
+#define STV090x_Px_MODCODLST4(__x)		(0xf4b4 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST4			STV090x_Px_MODCODLST4(1)
+#define STV090x_P2_MODCODLST4			STV090x_Px_MODCODLST4(2)
+#define STV090x_OFFST_Px_DIS_16PSK_9_10_FIELD	4
+#define STV090x_WIDTH_Px_DIS_16PSK_9_10_FIELD	4
+#define STV090x_OFFST_Px_DIS_16PSK_8_9_FIELD	0
+#define STV090x_WIDTH_Px_DIS_16PSK_8_9_FIELD	4
+
+#define STV090x_Px_MODCODLST5(__x)		(0xf4b5 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST5			STV090x_Px_MODCODLST5(1)
+#define STV090x_P2_MODCODLST5			STV090x_Px_MODCODLST5(2)
+#define STV090x_OFFST_Px_DIS_16PSK_5_6_FIELD	4
+#define STV090x_WIDTH_Px_DIS_16PSK_5_6_FIELD	4
+#define STV090x_OFFST_Px_DIS_16PSK_4_5_FIELD	0
+#define STV090x_WIDTH_Px_DIS_16PSK_4_5_FIELD	4
+
+#define STV090x_Px_MODCODLST6(__x)		(0xf4b6 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST6			STV090x_Px_MODCODLST6(1)
+#define STV090x_P2_MODCODLST6			STV090x_Px_MODCODLST6(2)
+#define STV090x_OFFST_Px_DIS_16PSK_3_4_FIELD	4
+#define STV090x_WIDTH_Px_DIS_16PSK_3_4_FIELD	4
+#define STV090x_OFFST_Px_DIS_16PSK_2_3_FIELD	0
+#define STV090x_WIDTH_Px_DIS_16PSK_2_3_FIELD	4
+
+#define STV090x_Px_MODCODLST7(__x)		(0xf4b7 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST7			STV090x_Px_MODCODLST7(1)
+#define STV090x_P2_MODCODLST7			STV090x_Px_MODCODLST7(2)
+#define STV090x_OFFST_Px_DIS_8P_9_10_FIELD	4
+#define STV090x_WIDTH_Px_DIS_8P_9_10_FIELD	4
+#define STV090x_OFFST_Px_DIS_8P_8_9_FIELD	0
+#define STV090x_WIDTH_Px_DIS_8P_8_9_FIELD	4
+
+#define STV090x_Px_MODCODLST8(__x)		(0xf4b8 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST8			STV090x_Px_MODCODLST8(1)
+#define STV090x_P2_MODCODLST8			STV090x_Px_MODCODLST8(2)
+#define STV090x_OFFST_Px_DIS_8P_5_6_FIELD	4
+#define STV090x_WIDTH_Px_DIS_8P_5_6_FIELD	4
+#define STV090x_OFFST_Px_DIS_8P_3_4_FIELD	0
+#define STV090x_WIDTH_Px_DIS_8P_3_4_FIELD	4
+
+#define STV090x_Px_MODCODLST9(__x)		(0xf4b9 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST9			STV090x_Px_MODCODLST9(1)
+#define STV090x_P2_MODCODLST9			STV090x_Px_MODCODLST9(2)
+#define STV090x_OFFST_Px_DIS_8P_2_3_FIELD	4
+#define STV090x_WIDTH_Px_DIS_8P_2_3_FIELD	4
+#define STV090x_OFFST_Px_DIS_8P_3_5_FIELD	0
+#define STV090x_WIDTH_Px_DIS_8P_3_5_FIELD	4
+
+#define STV090x_Px_MODCODLSTA(__x)		(0xf4ba - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTA			STV090x_Px_MODCODLSTA(1)
+#define STV090x_P2_MODCODLSTA			STV090x_Px_MODCODLSTA(2)
+#define STV090x_OFFST_Px_DIS_QP_9_10_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_9_10_FIELD	4
+#define STV090x_OFFST_Px_DIS_QP_8_9_FIELD	0
+#define STV090x_WIDTH_Px_DIS_QP_8_9_FIELD	4
+
+#define STV090x_Px_MODCODLSTB(__x)		(0xf4bb - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTB			STV090x_Px_MODCODLSTB(1)
+#define STV090x_P2_MODCODLSTB			STV090x_Px_MODCODLSTB(2)
+#define STV090x_OFFST_Px_DIS_QP_5_6_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_5_6_FIELD	4
+#define STV090x_OFFST_Px_DIS_QP_4_5_FIELD	0
+#define STV090x_WIDTH_Px_DIS_QP_4_5_FIELD	4
+
+#define STV090x_Px_MODCODLSTC(__x)		(0xf4bc - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTC			STV090x_Px_MODCODLSTC(1)
+#define STV090x_P2_MODCODLSTC			STV090x_Px_MODCODLSTC(2)
+#define STV090x_OFFST_Px_DIS_QP_3_4_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_3_4_FIELD	4
+#define STV090x_OFFST_Px_DIS_QP_2_3_FIELD	0
+#define STV090x_WIDTH_Px_DIS_QP_2_3_FIELD	4
+
+#define STV090x_Px_MODCODLSTD(__x)		(0xf4bd - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTD			STV090x_Px_MODCODLSTD(1)
+#define STV090x_P2_MODCODLSTD			STV090x_Px_MODCODLSTD(2)
+#define STV090x_OFFST_Px_DIS_QP_3_5_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_3_5_FIELD	4
+#define STV090x_OFFST_Px_DIS_QP_1_2_FIELD	0
+#define STV090x_WIDTH_Px_DIS_QP_1_2_FIELD	4
+
+#define STV090x_Px_MODCODLSTE(__x)		(0xf4be - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTE			STV090x_Px_MODCODLSTE(1)
+#define STV090x_P2_MODCODLSTE			STV090x_Px_MODCODLSTE(2)
+#define STV090x_OFFST_Px_DIS_QP_2_5_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_2_5_FIELD	4
+#define STV090x_OFFST_Px_DIS_QP_1_3_FIELD	0
+#define STV090x_WIDTH_Px_DIS_QP_1_3_FIELD	4
+
+#define STV090x_Px_MODCODLSTF(__x)		(0xf4bf - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTF			STV090x_Px_MODCODLSTF(1)
+#define STV090x_P2_MODCODLSTF			STV090x_Px_MODCODLSTF(2)
+#define STV090x_OFFST_Px_DIS_QP_1_4_FIELD	4
+#define STV090x_WIDTH_Px_DIS_QP_1_4_FIELD	4
+
+#define STV090x_Px_GAUSSR0(__x)			(0xf4c0 - (__x - 1) * 0x200)
+#define STV090x_P1_GAUSSR0			STV090x_Px_GAUSSR0(1)
+#define STV090x_P2_GAUSSR0			STV090x_Px_GAUSSR0(2)
+#define STV090x_OFFST_Px_EN_CCIMODE_FIELD	7
+#define STV090x_WIDTH_Px_EN_CCIMODE_FIELD	1
+#define STV090x_OFFST_Px_R0_GAUSSIEN_FIELD	0
+#define STV090x_WIDTH_Px_R0_GAUSSIEN_FIELD	7
+
+#define STV090x_Px_CCIR0(__x)			(0xf4c1 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIR0			STV090x_Px_CCIR0(1)
+#define STV090x_P2_CCIR0			STV090x_Px_CCIR0(2)
+#define STV090x_OFFST_Px_CCIDETECT_PLH_FIELD	7
+#define STV090x_WIDTH_Px_CCIDETECT_PLH_FIELD	1
+#define STV090x_OFFST_Px_R0_CCI_FIELD		0
+#define STV090x_WIDTH_Px_R0_CCI_FIELD		7
+
+#define STV090x_Px_CCIQUANT(__x)		(0xf4c2 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIQUANT			STV090x_Px_CCIQUANT(1)
+#define STV090x_P2_CCIQUANT			STV090x_Px_CCIQUANT(2)
+#define STV090x_OFFST_Px_CCI_BETA_FIELD		5
+#define STV090x_WIDTH_Px_CCI_BETA_FIELD		3
+#define STV090x_OFFST_Px_CCI_QUANT_FIELD	0
+#define STV090x_WIDTH_Px_CCI_QUANT_FIELD	5
+
+#define STV090x_Px_CCITHRESH(__x)		(0xf4c3 - (__x - 1) * 0x200)
+#define STV090x_P1_CCITHRESH			STV090x_Px_CCITHRESH(1)
+#define STV090x_P2_CCITHRESH			STV090x_Px_CCITHRESH(2)
+#define STV090x_OFFST_Px_CCI_THRESHOLD_FIELD	0
+#define STV090x_WIDTH_Px_CCI_THRESHOLD_FIELD	8
+
+#define STV090x_Px_CCIACC(__x)			(0xf4c4 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIACC			STV090x_Px_CCIACC(1)
+#define STV090x_P2_CCIACC			STV090x_Px_CCIACC(1)
+#define STV090x_OFFST_Px_CCI_VALUE_FIELD	0
+#define STV090x_WIDTH_Px_CCI_VALUE_FIELD	8
+
+#define STV090x_Px_DMDRESCFG(__x)		(0xF4C6 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDRESCFG			STV090x_Px_DMDRESCFG(1)
+#define STV090x_P2_DMDRESCFG			STV090x_Px_DMDRESCFG(2)
+#define STV090x_OFFST_Px_DMDRES_RESET_FIELD	7
+#define STV090x_WIDTH_Px_DMDRES_RESET_FIELD	1
+
+#define STV090x_Px_DMDRESADR(__x)		(0xF4C7 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDRESADR			STV090x_Px_DMDRESADR(1)
+#define STV090x_P2_DMDRESADR			STV090x_Px_DMDRESADR(2)
+#define STV090x_OFFST_Px_DMDRES_RESNBR_FIELD	0
+#define STV090x_WIDTH_Px_DMDRES_RESNBR_FIELD	4
+
+#define STV090x_Px_DMDRESDATAy(__x, __y)	(0xF4C8 - (__x - 1) * 0x200 + (7 - __y))
+#define STV090x_P1_DMDRESDATA0			STV090x_Px_DMDRESDATAy(1, 0)
+#define STV090x_P1_DMDRESDATA1			STV090x_Px_DMDRESDATAy(1, 1)
+#define STV090x_P1_DMDRESDATA2			STV090x_Px_DMDRESDATAy(1, 2)
+#define STV090x_P1_DMDRESDATA3			STV090x_Px_DMDRESDATAy(1, 3)
+#define STV090x_P1_DMDRESDATA4			STV090x_Px_DMDRESDATAy(1, 4)
+#define STV090x_P1_DMDRESDATA5			STV090x_Px_DMDRESDATAy(1, 5)
+#define STV090x_P1_DMDRESDATA6			STV090x_Px_DMDRESDATAy(1, 6)
+#define STV090x_P1_DMDRESDATA7			STV090x_Px_DMDRESDATAy(1, 7)
+#define STV090x_P2_DMDRESDATA0			STV090x_Px_DMDRESDATAy(2, 0)
+#define STV090x_P2_DMDRESDATA1			STV090x_Px_DMDRESDATAy(2, 1)
+#define STV090x_P2_DMDRESDATA2			STV090x_Px_DMDRESDATAy(2, 2)
+#define STV090x_P2_DMDRESDATA3			STV090x_Px_DMDRESDATAy(2, 3)
+#define STV090x_P2_DMDRESDATA4			STV090x_Px_DMDRESDATAy(2, 4)
+#define STV090x_P2_DMDRESDATA5			STV090x_Px_DMDRESDATAy(2, 5)
+#define STV090x_P2_DMDRESDATA6			STV090x_Px_DMDRESDATAy(2, 6)
+#define STV090x_P2_DMDRESDATA7			STV090x_Px_DMDRESDATAy(2, 7)
+#define STV090x_OFFST_Px_DMDRES_DATA_FIELD	0
+#define STV090x_WIDTH_Px_DMDRES_DATA_FIELD	8
+
+#define STV090x_Px_FFEIy(__x, __y)		(0xf4d0 - (__x - 1) * 0x200 + 0x2 * (__y - 1))
+#define STV090x_P1_FFEI1			STV090x_Px_FFEIy(1, 1)
+#define STV090x_P1_FFEI2			STV090x_Px_FFEIy(1, 2)
+#define STV090x_P1_FFEI3			STV090x_Px_FFEIy(1, 3)
+#define STV090x_P1_FFEI4			STV090x_Px_FFEIy(1, 4)
+#define STV090x_P2_FFEI1			STV090x_Px_FFEIy(2, 1)
+#define STV090x_P2_FFEI2			STV090x_Px_FFEIy(2, 2)
+#define STV090x_P2_FFEI3			STV090x_Px_FFEIy(2, 3)
+#define STV090x_P2_FFEI4			STV090x_Px_FFEIy(2, 4)
+#define STV090x_OFFST_Px_FFE_ACCIy_FIELD	0
+#define STV090x_WIDTH_Px_FFE_ACCIy_FIELD	8
+
+#define STV090x_Px_FFEQy(__x, __y)		(0xf4d1 - (__x - 1) * 0x200 + 0x2 * (__y - 1))
+#define STV090x_P1_FFEQ1			STV090x_Px_FFEQy(1, 1)
+#define STV090x_P1_FFEQ2			STV090x_Px_FFEQy(1, 2)
+#define STV090x_P1_FFEQ3			STV090x_Px_FFEQy(1, 3)
+#define STV090x_P1_FFEQ4			STV090x_Px_FFEQy(1, 4)
+#define STV090x_P2_FFEQ1			STV090x_Px_FFEQy(2, 1)
+#define STV090x_P2_FFEQ2			STV090x_Px_FFEQy(2, 2)
+#define STV090x_P2_FFEQ3			STV090x_Px_FFEQy(2, 3)
+#define STV090x_P2_FFEQ4			STV090x_Px_FFEQy(2, 4)
+#define STV090x_OFFST_Px_FFE_ACCQy_FIELD	0
+#define STV090x_WIDTH_Px_FFE_ACCQy_FIELD	8
+
+#define STV090x_Px_FFECFG(__x)			(0xf4d8 - (__x - 1) * 0x200)
+#define STV090x_P1_FFECFG			STV090x_Px_FFECFG(1)
+#define STV090x_P2_FFECFG			STV090x_Px_FFECFG(2)
+#define STV090x_OFFST_Px_EQUALFFE_ON_FIELD	6
+#define STV090x_WIDTH_Px_EQUALFFE_ON_FIELD	1
+
+#define STV090x_Px_SMAPCOEF7(__x)		(0xf500 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF7			STV090x_Px_SMAPCOEF7(1)
+#define STV090x_P2_SMAPCOEF7			STV090x_Px_SMAPCOEF7(2)
+#define STV090x_OFFST_Px_DIS_QSCALE_FIELD	7
+#define STV090x_WIDTH_Px_DIS_QSCALE_FIELD	1
+#define STV090x_OFFST_Px_SMAPCOEF_Q_LLR12_FIELD	0
+#define STV090x_WIDTH_Px_SMAPCOEF_Q_LLR12_FIELD	7
+
+#define STV090x_Px_SMAPCOEF6(__x)		(0xf501 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF6			STV090x_Px_SMAPCOEF6(1)
+#define STV090x_P2_SMAPCOEF6			STV090x_Px_SMAPCOEF6(2)
+#define STV090x_OFFST_Px_ADJ_8PSKLLR1_FIELD	2
+#define STV090x_WIDTH_Px_ADJ_8PSKLLR1_FIELD	1
+#define STV090x_OFFST_Px_OLD_8PSKLLR1_FIELD	1
+#define STV090x_WIDTH_Px_OLD_8PSKLLR1_FIELD	1
+#define STV090x_OFFST_Px_DIS_AB8PSK_FIELD	0
+#define STV090x_WIDTH_Px_DIS_AB8PSK_FIELD	1
+
+#define STV090x_Px_SMAPCOEF5(__x)			(0xf502 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF5				STV090x_Px_SMAPCOEF5(1)
+#define STV090x_P2_SMAPCOEF5				STV090x_Px_SMAPCOEF5(2)
+#define STV090x_OFFST_Px_DIS_8SCALE_FIELD		7
+#define STV090x_WIDTH_Px_DIS_8SCALE_FIELD		1
+#define STV090x_OFFST_Px_SMAPCOEF_8P_LLR23_FIELD	0
+#define STV090x_WIDTH_Px_SMAPCOEF_8P_LLR23_FIELD	7
+
+#define STV090x_Px_DMDPLHSTAT(__x)		(0xF520 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDPLHSTAT			STV090x_Px_DMDPLHSTAT(1)
+#define STV090x_P2_DMDPLHSTAT			STV090x_Px_DMDPLHSTAT(2)
+#define STV090x_OFFST_Px_PLH_STATISTIC_FIELD	0
+#define STV090x_WIDTH_Px_PLH_STATISTIC_FIELD	8
+
+#define STV090x_Px_LOCKTIMEy(__x, __y)		(0xF525 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_LOCKTIME0			STV090x_Px_LOCKTIMEy(1, 0)
+#define STV090x_P1_LOCKTIME1			STV090x_Px_LOCKTIMEy(1, 1)
+#define STV090x_P1_LOCKTIME2			STV090x_Px_LOCKTIMEy(1, 2)
+#define STV090x_P1_LOCKTIME3			STV090x_Px_LOCKTIMEy(1, 3)
+#define STV090x_P2_LOCKTIME0			STV090x_Px_LOCKTIMEy(2, 0)
+#define STV090x_P2_LOCKTIME1			STV090x_Px_LOCKTIMEy(2, 1)
+#define STV090x_P2_LOCKTIME2			STV090x_Px_LOCKTIMEy(2, 2)
+#define STV090x_P2_LOCKTIME3			STV090x_Px_LOCKTIMEy(2, 3)
+#define STV090x_OFFST_Px_DEMOD_LOCKTIME_FIELD	0
+#define STV090x_WIDTH_Px_DEMOD_LOCKTIME_FIELD	8
+
+#define STV090x_Px_TNRCFG(__x)			(0xf4e0 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_TNRCFG			STV090x_Px_TNRCFG(1)
+#define STV090x_P2_TNRCFG			STV090x_Px_TNRCFG(2)
+
+#define STV090x_Px_TNRCFG2(__x)			(0xf4e1 - (__x - 1) * 0x200)
+#define STV090x_P1_TNRCFG2			STV090x_Px_TNRCFG2(1)
+#define STV090x_P2_TNRCFG2			STV090x_Px_TNRCFG2(2)
+#define STV090x_OFFST_Px_TUN_IQSWAP_FIELD	7
+#define STV090x_WIDTH_Px_TUN_IQSWAP_FIELD	1
+
+#define STV090x_Px_VITSCALE(__x)		(0xf532 - (__x - 1) * 0x200)
+#define STV090x_P1_VITSCALE			STV090x_Px_VITSCALE(1)
+#define STV090x_P2_VITSCALE			STV090x_Px_VITSCALE(2)
+#define STV090x_OFFST_Px_NVTH_NOSRANGE_FIELD	7
+#define STV090x_WIDTH_Px_NVTH_NOSRANGE_FIELD	1
+#define STV090x_OFFST_Px_VERROR_MAXMODE_FIELD	6
+#define STV090x_WIDTH_Px_VERROR_MAXMODE_FIELD	1
+#define STV090x_OFFST_Px_NSLOWSN_LOCKED_FIELD	3
+#define STV090x_WIDTH_Px_NSLOWSN_LOCKED_FIELD	1
+#define STV090x_OFFST_Px_DIS_RSFLOCK_FIELD	1
+#define STV090x_WIDTH_Px_DIS_RSFLOCK_FIELD	1
+
+#define STV090x_Px_FECM(__x)			(0xf533 - (__x - 1) * 0x200)
+#define STV090x_P1_FECM				STV090x_Px_FECM(1)
+#define STV090x_P2_FECM				STV090x_Px_FECM(2)
+#define STV090x_OFFST_Px_DSS_DVB_FIELD		7
+#define STV090x_WIDTH_Px_DSS_DVB_FIELD		1
+#define STV090x_OFFST_Px_DSS_SRCH_FIELD		4
+#define STV090x_WIDTH_Px_DSS_SRCH_FIELD		1
+#define STV090x_OFFST_Px_SYNCVIT_FIELD		1
+#define STV090x_WIDTH_Px_SYNCVIT_FIELD		1
+#define STV090x_OFFST_Px_IQINV_FIELD		0
+#define STV090x_WIDTH_Px_IQINV_FIELD		1
+
+#define STV090x_Px_VTH12(__x)			(0xf534 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH12			STV090x_Px_VTH12(1)
+#define STV090x_P2_VTH12			STV090x_Px_VTH12(2)
+#define STV090x_OFFST_Px_VTH12_FIELD		0
+#define STV090x_WIDTH_Px_VTH12_FIELD		8
+
+#define STV090x_Px_VTH23(__x)			(0xf535 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH23			STV090x_Px_VTH23(1)
+#define STV090x_P2_VTH23			STV090x_Px_VTH23(2)
+#define STV090x_OFFST_Px_VTH23_FIELD		0
+#define STV090x_WIDTH_Px_VTH23_FIELD		8
+
+#define STV090x_Px_VTH34(__x)			(0xf536 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH34			STV090x_Px_VTH34(1)
+#define STV090x_P2_VTH34			STV090x_Px_VTH34(2)
+#define STV090x_OFFST_Px_VTH34_FIELD		0
+#define STV090x_WIDTH_Px_VTH34_FIELD		8
+
+#define STV090x_Px_VTH56(__x)			(0xf537 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH56			STV090x_Px_VTH56(1)
+#define STV090x_P2_VTH56			STV090x_Px_VTH56(2)
+#define STV090x_OFFST_Px_VTH56_FIELD		0
+#define STV090x_WIDTH_Px_VTH56_FIELD		8
+
+#define STV090x_Px_VTH67(__x)			(0xf538 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH67			STV090x_Px_VTH67(1)
+#define STV090x_P2_VTH67			STV090x_Px_VTH67(2)
+#define STV090x_OFFST_Px_VTH67_FIELD		0
+#define STV090x_WIDTH_Px_VTH67_FIELD		8
+
+#define STV090x_Px_VTH78(__x)			(0xf539 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH78			STV090x_Px_VTH78(1)
+#define STV090x_P2_VTH78			STV090x_Px_VTH78(2)
+#define STV090x_OFFST_Px_VTH78_FIELD		0
+#define STV090x_WIDTH_Px_VTH78_FIELD		8
+
+#define STV090x_Px_VITCURPUN(__x)		(0xf53a - (__x - 1) * 0x200)
+#define STV090x_P1_VITCURPUN			STV090x_Px_VITCURPUN(1)
+#define STV090x_P2_VITCURPUN			STV090x_Px_VITCURPUN(2)
+#define STV090x_OFFST_Px_VIT_CURPUN_FIELD	0
+#define STV090x_WIDTH_Px_VIT_CURPUN_FIELD	5
+
+#define STV090x_Px_VERROR(__x)			(0xf53b - (__x - 1) * 0x200)
+#define STV090x_P1_VERROR			STV090x_Px_VERROR(1)
+#define STV090x_P2_VERROR			STV090x_Px_VERROR(2)
+#define STV090x_OFFST_Px_REGERR_VIT_FIELD	0
+#define STV090x_WIDTH_Px_REGERR_VIT_FIELD	8
+
+#define STV090x_Px_PRVIT(__x)			(0xf53c - (__x - 1) * 0x200)
+#define STV090x_P1_PRVIT			STV090x_Px_PRVIT(1)
+#define STV090x_P2_PRVIT			STV090x_Px_PRVIT(2)
+#define STV090x_OFFST_Px_DIS_VTHLOCK_FIELD	6
+#define STV090x_WIDTH_Px_DIS_VTHLOCK_FIELD	1
+#define STV090x_OFFST_Px_E7_8VIT_FIELD		5
+#define STV090x_WIDTH_Px_E7_8VIT_FIELD		1
+#define STV090x_OFFST_Px_E6_7VIT_FIELD		4
+#define STV090x_WIDTH_Px_E6_7VIT_FIELD		1
+#define STV090x_OFFST_Px_E5_6VIT_FIELD		3
+#define STV090x_WIDTH_Px_E5_6VIT_FIELD		1
+#define STV090x_OFFST_Px_E3_4VIT_FIELD		2
+#define STV090x_WIDTH_Px_E3_4VIT_FIELD		1
+#define STV090x_OFFST_Px_E2_3VIT_FIELD		1
+#define STV090x_WIDTH_Px_E2_3VIT_FIELD		1
+#define STV090x_OFFST_Px_E1_2VIT_FIELD		0
+#define STV090x_WIDTH_Px_E1_2VIT_FIELD		1
+
+#define STV090x_Px_VAVSRVIT(__x)		(0xf53d - (__x - 1) * 0x200)
+#define STV090x_P1_VAVSRVIT			STV090x_Px_VAVSRVIT(1)
+#define STV090x_P2_VAVSRVIT			STV090x_Px_VAVSRVIT(2)
+#define STV090x_OFFST_Px_SNVIT_FIELD		4
+#define STV090x_WIDTH_Px_SNVIT_FIELD		2
+#define STV090x_OFFST_Px_TOVVIT_FIELD		2
+#define STV090x_WIDTH_Px_TOVVIT_FIELD		2
+#define STV090x_OFFST_Px_HYPVIT_FIELD		0
+#define STV090x_WIDTH_Px_HYPVIT_FIELD		2
+
+#define STV090x_Px_VSTATUSVIT(__x)		(0xf53e - (__x - 1) * 0x200)
+#define STV090x_P1_VSTATUSVIT			STV090x_Px_VSTATUSVIT(1)
+#define STV090x_P2_VSTATUSVIT			STV090x_Px_VSTATUSVIT(2)
+#define STV090x_OFFST_Px_PRFVIT_FIELD		4
+#define STV090x_WIDTH_Px_PRFVIT_FIELD		1
+#define STV090x_OFFST_Px_LOCKEDVIT_FIELD	3
+#define STV090x_WIDTH_Px_LOCKEDVIT_FIELD	1
+
+#define STV090x_Px_VTHINUSE(__x)		(0xf53f - (__x - 1) * 0x200)
+#define STV090x_P1_VTHINUSE			STV090x_Px_VTHINUSE(1)
+#define STV090x_P2_VTHINUSE			STV090x_Px_VTHINUSE(2)
+#define STV090x_OFFST_Px_VIT_INUSE_FIELD	0
+#define STV090x_WIDTH_Px_VIT_INUSE_FIELD	8
+
+#define STV090x_Px_KDIV12(__x)			(0xf540 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV12			STV090x_Px_KDIV12(1)
+#define STV090x_P2_KDIV12			STV090x_Px_KDIV12(2)
+#define STV090x_OFFST_Px_K_DIVIDER_12_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_12_FIELD	7
+
+#define STV090x_Px_KDIV23(__x)			(0xf541 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV23			STV090x_Px_KDIV23(1)
+#define STV090x_P2_KDIV23			STV090x_Px_KDIV23(2)
+#define STV090x_OFFST_Px_K_DIVIDER_23_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_23_FIELD	7
+
+#define STV090x_Px_KDIV34(__x)			(0xf542 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV34			STV090x_Px_KDIV34(1)
+#define STV090x_P2_KDIV34			STV090x_Px_KDIV34(2)
+#define STV090x_OFFST_Px_K_DIVIDER_34_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_34_FIELD	7
+
+#define STV090x_Px_KDIV56(__x)			(0xf543 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV56			STV090x_Px_KDIV56(1)
+#define STV090x_P2_KDIV56			STV090x_Px_KDIV56(2)
+#define STV090x_OFFST_Px_K_DIVIDER_56_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_56_FIELD	7
+
+#define STV090x_Px_KDIV67(__x)			(0xf544 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV67			STV090x_Px_KDIV67(1)
+#define STV090x_P2_KDIV67			STV090x_Px_KDIV67(2)
+#define STV090x_OFFST_Px_K_DIVIDER_67_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_67_FIELD	7
+
+#define STV090x_Px_KDIV78(__x)			(0xf545 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV78			STV090x_Px_KDIV78(1)
+#define STV090x_P2_KDIV78			STV090x_Px_KDIV78(2)
+#define STV090x_OFFST_Px_K_DIVIDER_78_FIELD	0
+#define STV090x_WIDTH_Px_K_DIVIDER_78_FIELD	7
+
+#define STV090x_Px_PDELCTRL1(__x)		(0xf550 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELCTRL1			STV090x_Px_PDELCTRL1(1)
+#define STV090x_P2_PDELCTRL1			STV090x_Px_PDELCTRL1(2)
+#define STV090x_OFFST_Px_INV_MISMASK_FIELD	7
+#define STV090x_WIDTH_Px_INV_MISMASK_FIELD	1
+#define STV090x_OFFST_Px_FILTER_EN_FIELD	5
+#define STV090x_WIDTH_Px_FILTER_EN_FIELD	1
+#define STV090x_OFFST_Px_EN_MIS00_FIELD		1
+#define STV090x_WIDTH_Px_EN_MIS00_FIELD		1
+#define STV090x_OFFST_Px_ALGOSWRST_FIELD	0
+#define STV090x_WIDTH_Px_ALGOSWRST_FIELD	1
+
+#define STV090x_Px_PDELCTRL2(__x)		(0xf551 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELCTRL2			STV090x_Px_PDELCTRL2(1)
+#define STV090x_P2_PDELCTRL2			STV090x_Px_PDELCTRL2(2)
+#define STV090x_OFFST_Px_FORCE_CONTINUOUS	7
+#define STV090x_WIDTH_Px_FORCE_CONTINUOUS	1
+#define STV090x_OFFST_Px_RESET_UPKO_COUNT	6
+#define STV090x_WIDTH_Px_RESET_UPKO_COUNT	1
+#define STV090x_OFFST_Px_USER_PKTDELIN_NB	5
+#define STV090x_WIDTH_Px_USER_PKTDELIN_NB	1
+#define STV090x_OFFST_Px_FORCE_LOCKED		4
+#define STV090x_WIDTH_Px_FORCE_LOCKED		1
+#define STV090x_OFFST_Px_DATA_UNBBSCRAM		3
+#define STV090x_WIDTH_Px_DATA_UNBBSCRAM		1
+#define STV090x_OFFST_Px_FORCE_LONGPACKET	2
+#define STV090x_WIDTH_Px_FORCE_LONGPACKET	1
+#define STV090x_OFFST_Px_FRAME_MODE_FIELD	1
+#define STV090x_WIDTH_Px_FRAME_MODE_FIELD	1
+
+#define STV090x_Px_HYSTTHRESH(__x)		(0xf554 - (__x - 1) * 0x200)
+#define STV090x_P1_HYSTTHRESH			STV090x_Px_HYSTTHRESH(1)
+#define STV090x_P2_HYSTTHRESH			STV090x_Px_HYSTTHRESH(2)
+#define STV090x_OFFST_Px_UNLCK_THRESH_FIELD	4
+#define STV090x_WIDTH_Px_UNLCK_THRESH_FIELD	4
+#define STV090x_OFFST_Px_DELIN_LCK_THRESH_FIELD	0
+#define STV090x_WIDTH_Px_DELIN_LCK_THRESH_FIELD	4
+
+#define STV090x_Px_ISIENTRY(__x)		(0xf55e - (__x - 1) * 0x200)
+#define STV090x_P1_ISIENTRY			STV090x_Px_ISIENTRY(1)
+#define STV090x_P2_ISIENTRY			STV090x_Px_ISIENTRY(2)
+#define STV090x_OFFST_Px_ISI_ENTRY_FIELD	0
+#define STV090x_WIDTH_Px_ISI_ENTRY_FIELD	8
+
+#define STV090x_Px_ISIBITENA(__x)		(0xf55f - (__x - 1) * 0x200)
+#define STV090x_P1_ISIBITENA			STV090x_Px_ISIBITENA(1)
+#define STV090x_P2_ISIBITENA			STV090x_Px_ISIBITENA(2)
+#define STV090x_OFFST_Px_ISI_BIT_EN_FIELD	0
+#define STV090x_WIDTH_Px_ISI_BIT_EN_FIELD	8
+
+#define STV090x_Px_MATSTRy(__x, __y)		(0xf561 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_MATSTR0			STV090x_Px_MATSTRy(1, 0)
+#define STV090x_P1_MATSTR1			STV090x_Px_MATSTRy(1, 1)
+#define STV090x_P2_MATSTR0			STV090x_Px_MATSTRy(2, 0)
+#define STV090x_P2_MATSTR1			STV090x_Px_MATSTRy(2, 1)
+#define STV090x_OFFST_Px_MATYPE_CURRENT_FIELD	0
+#define STV090x_WIDTH_Px_MATYPE_CURRENT_FIELD	8
+
+#define STV090x_Px_UPLSTRy(__x, __y)		(0xf563 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_UPLSTR0			STV090x_Px_UPLSTRy(1, 0)
+#define STV090x_P1_UPLSTR1			STV090x_Px_UPLSTRy(1, 1)
+#define STV090x_P2_UPLSTR0			STV090x_Px_UPLSTRy(2, 0)
+#define STV090x_P2_UPLSTR1			STV090x_Px_UPLSTRy(2, 1)
+#define STV090x_OFFST_Px_UPL_CURRENT_FIELD	0
+#define STV090x_WIDTH_Px_UPL_CURRENT_FIELD	8
+
+#define STV090x_Px_DFLSTRy(__x, __y)		(0xf565 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_DFLSTR0			STV090x_Px_DFLSTRy(1, 0)
+#define STV090x_P1_DFLSTR1			STV090x_Px_DFLSTRy(1, 1)
+#define STV090x_P2_DFLSTR0			STV090x_Px_DFLSTRy(2, 0)
+#define STV090x_P2_DFLSTR1			STV090x_Px_DFLSTRy(2, 1)
+#define STV090x_OFFST_Px_DFL_CURRENT_FIELD	0
+#define STV090x_WIDTH_Px_DFL_CURRENT_FIELD	8
+
+#define STV090x_Px_SYNCSTR(__x)			(0xf566 - (__x - 1) * 0x200)
+#define STV090x_P1_SYNCSTR			STV090x_Px_SYNCSTR(1)
+#define STV090x_P2_SYNCSTR			STV090x_Px_SYNCSTR(2)
+#define STV090x_OFFST_Px_SYNC_CURRENT_FIELD	0
+#define STV090x_WIDTH_Px_SYNC_CURRENT_FIELD	8
+
+#define STV090x_Px_SYNCDSTRy(__x, __y)		(0xf568 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_SYNCDSTR0			STV090x_Px_SYNCDSTRy(1, 0)
+#define STV090x_P1_SYNCDSTR1			STV090x_Px_SYNCDSTRy(1, 1)
+#define STV090x_P2_SYNCDSTR0			STV090x_Px_SYNCDSTRy(2, 0)
+#define STV090x_P2_SYNCDSTR1			STV090x_Px_SYNCDSTRy(2, 1)
+#define STV090x_OFFST_Px_SYNCD_CURRENT_FIELD	0
+#define STV090x_WIDTH_Px_SYNCD_CURRENT_FIELD	8
+
+#define STV090x_Px_PDELSTATUS1(__x)		(0xf569 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELSTATUS1			STV090x_Px_PDELSTATUS1(1)
+#define STV090x_P2_PDELSTATUS1			STV090x_Px_PDELSTATUS1(2)
+#define STV090x_OFFST_Px_PKTDELIN_LOCK_FIELD	1
+#define STV090x_WIDTH_Px_PKTDELIN_LOCK_FIELD	1
+#define STV090x_OFFST_Px_FIRST_LOCK_FIELD	0
+#define STV090x_WIDTH_Px_FIRST_LOCK_FIELD	1
+
+#define STV090x_Px_PDELSTATUS2(__x)		(0xf56a - (__x - 1) * 0x200)
+#define STV090x_P1_PDELSTATUS2			STV090x_Px_PDELSTATUS2(1)
+#define STV090x_P2_PDELSTATUS2			STV090x_Px_PDELSTATUS2(2)
+#define STV090x_OFFST_Px_FRAME_MODCOD_FIELD	2
+#define STV090x_WIDTH_Px_FRAME_MODCOD_FIELD	5
+#define STV090x_OFFST_Px_FRAME_TYPE_FIELD	0
+#define STV090x_WIDTH_Px_FRAME_TYPE_FIELD	2
+
+#define STV090x_Px_BBFCRCKO1(__x)		(0xf56b - (__x - 1) * 0x200)
+#define STV090x_P1_BBFCRCKO1			STV090x_Px_BBFCRCKO1(1)
+#define STV090x_P2_BBFCRCKO1			STV090x_Px_BBFCRCKO1(2)
+#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD	0
+#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD	8
+
+#define STV090x_Px_BBFCRCKO0(__x)		(0xf56c - (__x - 1) * 0x200)
+#define STV090x_P1_BBFCRCKO0			STV090x_Px_BBFCRCKO0(1)
+#define STV090x_P2_BBFCRCKO0			STV090x_Px_BBFCRCKO0(2)
+#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD	0
+#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD	8
+
+#define STV090x_Px_UPCRCKO1(__x)		(0xf56d - (__x - 1) * 0x200)
+#define STV090x_P1_UPCRCKO1			STV090x_Px_UPCRCKO1(1)
+#define STV090x_P2_UPCRCKO1			STV090x_Px_UPCRCKO1(2)
+#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD	0
+#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD	8
+
+#define STV090x_Px_UPCRCKO0(__x)		(0xf56e - (__x - 1) * 0x200)
+#define STV090x_P1_UPCRCKO0			STV090x_Px_UPCRCKO0(1)
+#define STV090x_P2_UPCRCKO0			STV090x_Px_UPCRCKO0(2)
+#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD	0
+#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD	8
+
+#define STV090x_NBITER_NFx(__x)				(0xFA03 + (__x - 4) * 0x1)
+#define STV090x_NBITER_NF4				STV090x_NBITER_NFx(4)
+#define STV090x_NBITER_NF5				STV090x_NBITER_NFx(5)
+#define STV090x_NBITER_NF6				STV090x_NBITER_NFx(6)
+#define STV090x_NBITER_NF7				STV090x_NBITER_NFx(7)
+#define STV090x_NBITER_NF8				STV090x_NBITER_NFx(8)
+#define STV090x_NBITER_NF9				STV090x_NBITER_NFx(9)
+#define STV090x_NBITER_NF10				STV090x_NBITER_NFx(10)
+#define STV090x_NBITER_NF11				STV090x_NBITER_NFx(11)
+#define STV090x_NBITER_NF12				STV090x_NBITER_NFx(12)
+#define STV090x_NBITER_NF13				STV090x_NBITER_NFx(13)
+#define STV090x_NBITER_NF14				STV090x_NBITER_NFx(14)
+#define STV090x_NBITER_NF15				STV090x_NBITER_NFx(15)
+#define STV090x_NBITER_NF16				STV090x_NBITER_NFx(16)
+#define STV090x_NBITER_NF17				STV090x_NBITER_NFx(17)
+
+#define STV090x_NBITERNOERR				0xFA3F
+#define STV090x_OFFST_NBITER_STOP_CRIT_FIELD		0
+#define STV090x_WIDTH_NBITER_STOP_CRIT_FIELD		4
+
+#define STV090x_GAINLLR_NFx(__x)			(0xFA43 + (__x - 4) * 0x1)
+#define STV090x_GAINLLR_NF4				STV090x_GAINLLR_NFx(4)
+#define STV090x_OFFST_GAINLLR_NF_QP_1_2_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_1_2_FIELD		7
+
+#define STV090x_GAINLLR_NF5				STV090x_GAINLLR_NFx(5)
+#define STV090x_OFFST_GAINLLR_NF_QP_3_5_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_3_5_FIELD		7
+
+#define STV090x_GAINLLR_NF6				STV090x_GAINLLR_NFx(6)
+#define STV090x_OFFST_GAINLLR_NF_QP_2_3_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_2_3_FIELD		7
+
+#define STV090x_GAINLLR_NF7				STV090x_GAINLLR_NFx(7)
+#define STV090x_OFFST_GAINLLR_NF_QP_3_4_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_3_4_FIELD		7
+
+#define STV090x_GAINLLR_NF8				STV090x_GAINLLR_NFx(8)
+#define STV090x_OFFST_GAINLLR_NF_QP_4_5_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_4_5_FIELD		7
+
+#define STV090x_GAINLLR_NF9				STV090x_GAINLLR_NFx(9)
+#define STV090x_OFFST_GAINLLR_NF_QP_5_6_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_5_6_FIELD		7
+
+#define STV090x_GAINLLR_NF10				STV090x_GAINLLR_NFx(10)
+#define STV090x_OFFST_GAINLLR_NF_QP_8_9_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_8_9_FIELD		7
+
+#define STV090x_GAINLLR_NF11				STV090x_GAINLLR_NFx(11)
+#define STV090x_OFFST_GAINLLR_NF_QP_9_10_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_QP_9_10_FIELD		7
+
+#define STV090x_GAINLLR_NF12				STV090x_GAINLLR_NFx(12)
+#define STV090x_OFFST_GAINLLR_NF_8P_3_5_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_3_5_FIELD		7
+
+#define STV090x_GAINLLR_NF13				STV090x_GAINLLR_NFx(13)
+#define STV090x_OFFST_GAINLLR_NF_8P_2_3_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_2_3_FIELD		7
+
+#define STV090x_GAINLLR_NF14				STV090x_GAINLLR_NFx(14)
+#define STV090x_OFFST_GAINLLR_NF_8P_3_4_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_3_4_FIELD		7
+
+#define STV090x_GAINLLR_NF15				STV090x_GAINLLR_NFx(15)
+#define STV090x_OFFST_GAINLLR_NF_8P_5_6_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_5_6_FIELD		7
+
+#define STV090x_GAINLLR_NF16				STV090x_GAINLLR_NFx(16)
+#define STV090x_OFFST_GAINLLR_NF_8P_8_9_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_8_9_FIELD		7
+
+#define STV090x_GAINLLR_NF17				STV090x_GAINLLR_NFx(17)
+#define STV090x_OFFST_GAINLLR_NF_8P_9_10_FIELD		0
+#define STV090x_WIDTH_GAINLLR_NF_8P_9_10_FIELD		7
+
+#define STV090x_GENCFG					0xFA86
+#define STV090x_OFFST_BROADCAST_FIELD			4
+#define STV090x_WIDTH_BROADCAST_FIELD			1
+#define STV090x_OFFST_PRIORITY_FIELD			1
+#define STV090x_WIDTH_PRIORITY_FIELD			1
+#define STV090x_OFFST_DDEMOD_FIELD			0
+#define STV090x_WIDTH_DDEMOD_FIELD			1
+
+#define STV090x_LDPCERRx(__x)				(0xFA97 - (__x  * 0x1))
+#define STV090x_LDPCERR0				STV090x_LDPCERRx(0)
+#define STV090x_LDPCERR1				STV090x_LDPCERRx(1)
+#define STV090x_OFFST_Px_LDPC_ERRORS_COUNTER_FIELD	0
+#define STV090x_WIDTH_Px_LDPC_ERRORS_COUNTER_FIELD	8
+
+#define STV090x_BCHERR					0xFA98
+#define STV090x_OFFST_Px_ERRORFLAG_FIELD		4
+#define STV090x_WIDTH_Px_ERRORFLAG_FIELD		1
+#define STV090x_OFFST_Px_BCH_ERRORS_COUNTER_FIELD	0
+#define STV090x_WIDTH_Px_BCH_ERRORS_COUNTER_FIELD	4
+
+#define STV090x_Px_TSSTATEM(__x)			(0xF570 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATEM				STV090x_Px_TSSTATEM(1)
+#define STV090x_P2_TSSTATEM				STV090x_Px_TSSTATEM(2)
+#define STV090x_OFFST_Px_TSDIL_ON_FIELD			7
+#define STV090x_WIDTH_Px_TSDIL_ON_FIELD			1
+#define STV090x_OFFST_Px_TSRS_ON_FIELD			5
+#define STV090x_WIDTH_Px_TSRS_ON_FIELD			1
+
+#define STV090x_Px_TSCFGH(__x)				(0xF572 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGH				STV090x_Px_TSCFGH(1)
+#define STV090x_P2_TSCFGH				STV090x_Px_TSCFGH(2)
+#define STV090x_OFFST_Px_TSFIFO_DVBCI_FIELD		7
+#define STV090x_WIDTH_Px_TSFIFO_DVBCI_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_SERIAL_FIELD		6
+#define STV090x_WIDTH_Px_TSFIFO_SERIAL_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_TEIUPDATE_FIELD		5
+#define STV090x_WIDTH_Px_TSFIFO_TEIUPDATE_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_DUTY50_FIELD		4
+#define STV090x_WIDTH_Px_TSFIFO_DUTY50_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_HSGNLOUT_FIELD		3
+#define STV090x_WIDTH_Px_TSFIFO_HSGNLOUT_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_ERRORMODE_FIELD		1
+#define STV090x_WIDTH_Px_TSFIFO_ERRORMODE_FIELD		2
+#define STV090x_OFFST_Px_RST_HWARE_FIELD		0
+#define STV090x_WIDTH_Px_RST_HWARE_FIELD		1
+
+#define STV090x_Px_TSCFGM(__x)				(0xF573 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGM				STV090x_Px_TSCFGM(1)
+#define STV090x_P2_TSCFGM				STV090x_Px_TSCFGM(2)
+#define STV090x_OFFST_Px_TSFIFO_MANSPEED_FIELD		6
+#define STV090x_WIDTH_Px_TSFIFO_MANSPEED_FIELD		2
+#define STV090x_OFFST_Px_TSFIFO_PERMDATA_FIELD		5
+#define STV090x_WIDTH_Px_TSFIFO_PERMDATA_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_INVDATA_FIELD		0
+#define STV090x_WIDTH_Px_TSFIFO_INVDATA_FIELD		1
+
+#define STV090x_Px_TSCFGL(__x)				(0xF574 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGL				STV090x_Px_TSCFGL(1)
+#define STV090x_P2_TSCFGL				STV090x_Px_TSCFGL(2)
+#define STV090x_OFFST_Px_TSFIFO_BCLKDEL1CK_FIELD	6
+#define STV090x_WIDTH_Px_TSFIFO_BCLKDEL1CK_FIELD	2
+#define STV090x_OFFST_Px_BCHERROR_MODE_FIELD		4
+#define STV090x_WIDTH_Px_BCHERROR_MODE_FIELD		2
+#define STV090x_OFFST_Px_TSFIFO_NSGNL2DATA_FIELD	3
+#define STV090x_WIDTH_Px_TSFIFO_NSGNL2DATA_FIELD	1
+#define STV090x_OFFST_Px_TSFIFO_EMBINDVB_FIELD		2
+#define STV090x_WIDTH_Px_TSFIFO_EMBINDVB_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_DPUNACT_FIELD		1
+#define STV090x_WIDTH_Px_TSFIFO_DPUNACT_FIELD		1
+
+#define STV090x_Px_TSINSDELH(__x)			(0xF576 - (__x - 1) * 0x200)
+#define STV090x_P1_TSINSDELH				STV090x_Px_TSINSDELH(1)
+#define STV090x_P2_TSINSDELH				STV090x_Px_TSINSDELH(2)
+#define STV090x_OFFST_Px_TSDEL_SYNCBYTE_FIELD		7
+#define STV090x_WIDTH_Px_TSDEL_SYNCBYTE_FIELD		1
+#define STV090x_OFFST_Px_TSDEL_XXHEADER_FIELD		6
+#define STV090x_WIDTH_Px_TSDEL_XXHEADER_FIELD		1
+
+#define STV090x_Px_TSSPEED(__x)				(0xF580 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSPEED				STV090x_Px_TSSPEED(1)
+#define STV090x_P2_TSSPEED				STV090x_Px_TSSPEED(2)
+#define STV090x_OFFST_Px_TSFIFO_OUTSPEED_FIELD		0
+#define STV090x_WIDTH_Px_TSFIFO_OUTSPEED_FIELD		8
+
+#define STV090x_Px_TSSTATUS(__x)			(0xF581 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATUS				STV090x_Px_TSSTATUS(1)
+#define STV090x_P2_TSSTATUS				STV090x_Px_TSSTATUS(2)
+#define STV090x_OFFST_Px_TSFIFO_LINEOK_FIELD		7
+#define STV090x_WIDTH_Px_TSFIFO_LINEOK_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_ERROR_FIELD		6
+#define STV090x_WIDTH_Px_TSFIFO_ERROR_FIELD		1
+
+#define STV090x_Px_TSSTATUS2(__x)			(0xF582 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATUS2				STV090x_Px_TSSTATUS2(1)
+#define STV090x_P2_TSSTATUS2				STV090x_Px_TSSTATUS2(2)
+#define STV090x_OFFST_Px_TSFIFO_DEMODSEL_FIELD		7
+#define STV090x_WIDTH_Px_TSFIFO_DEMODSEL_FIELD		1
+#define STV090x_OFFST_Px_TSFIFOSPEED_STORE_FIELD	6
+#define STV090x_WIDTH_Px_TSFIFOSPEED_STORE_FIELD	1
+#define STV090x_OFFST_Px_DILXX_RESET_FIELD		5
+#define STV090x_WIDTH_Px_DILXX_RESET_FIELD		1
+#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD		5
+#define STV090x_WIDTH_Px_TSSERIAL_IMPOS_FIELD		1
+#define STV090x_OFFST_Px_SCRAMBDETECT_FIELD		1
+#define STV090x_WIDTH_Px_SCRAMBDETECT_FIELD		1
+
+#define STV090x_Px_TSBITRATEy(__x, __y)			(0xF584 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_TSBITRATE0				STV090x_Px_TSBITRATEy(1, 0)
+#define STV090x_P1_TSBITRATE1				STV090x_Px_TSBITRATEy(1, 1)
+#define STV090x_P2_TSBITRATE0				STV090x_Px_TSBITRATEy(2, 0)
+#define STV090x_P2_TSBITRATE1				STV090x_Px_TSBITRATEy(2, 1)
+#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD		7
+#define STV090x_WIDTH_Px_TSFIFO_BITRATE_FIELD		8
+
+#define STV090x_Px_ERRCTRL1(__x)			(0xF598 - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCTRL1				STV090x_Px_ERRCTRL1(1)
+#define STV090x_P2_ERRCTRL1				STV090x_Px_ERRCTRL1(2)
+#define STV090x_OFFST_Px_ERR_SOURCE_FIELD		4
+#define STV090x_WIDTH_Px_ERR_SOURCE_FIELD		4
+#define STV090x_OFFST_Px_NUM_EVENT_FIELD		0
+#define STV090x_WIDTH_Px_NUM_EVENT_FIELD		3
+
+#define STV090x_Px_ERRCNT12(__x)			(0xF599 - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT12				STV090x_Px_ERRCNT12(1)
+#define STV090x_P2_ERRCNT12				STV090x_Px_ERRCNT12(2)
+#define STV090x_OFFST_Px_ERRCNT1_OLDVALUE_FIELD		7
+#define STV090x_WIDTH_Px_ERRCNT1_OLDVALUE_FIELD		1
+#define STV090x_OFFST_Px_ERR_CNT12_FIELD		0
+#define STV090x_WIDTH_Px_ERR_CNT12_FIELD		7
+
+#define STV090x_Px_ERRCNT11(__x)			(0xF59A - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT11				STV090x_Px_ERRCNT11(1)
+#define STV090x_P2_ERRCNT11				STV090x_Px_ERRCNT11(2)
+#define STV090x_OFFST_Px_ERR_CNT11_FIELD		0
+#define STV090x_WIDTH_Px_ERR_CNT11_FIELD		8
+
+#define STV090x_Px_ERRCNT10(__x)			(0xF59B - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT10				STV090x_Px_ERRCNT10(1)
+#define STV090x_P2_ERRCNT10				STV090x_Px_ERRCNT10(2)
+#define STV090x_OFFST_Px_ERR_CNT10_FIELD		0
+#define STV090x_WIDTH_Px_ERR_CNT10_FIELD		8
+
+#define STV090x_Px_ERRCTRL2(__x)			(0xF59C - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCTRL2				STV090x_Px_ERRCTRL2(1)
+#define STV090x_P2_ERRCTRL2				STV090x_Px_ERRCTRL2(2)
+#define STV090x_OFFST_Px_ERR_SOURCE2_FIELD		4
+#define STV090x_WIDTH_Px_ERR_SOURCE2_FIELD		4
+#define STV090x_OFFST_Px_NUM_EVENT2_FIELD		0
+#define STV090x_WIDTH_Px_NUM_EVENT2_FIELD		3
+
+#define STV090x_Px_ERRCNT22(__x)			(0xF59D - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT22				STV090x_Px_ERRCNT22(1)
+#define STV090x_P2_ERRCNT22				STV090x_Px_ERRCNT22(2)
+#define STV090x_OFFST_Px_ERRCNT2_OLDVALUE_FIELD		7
+#define STV090x_WIDTH_Px_ERRCNT2_OLDVALUE_FIELD		1
+#define STV090x_OFFST_Px_ERR_CNT2_FIELD			0
+#define STV090x_WIDTH_Px_ERR_CNT2_FIELD			7
+
+#define STV090x_Px_ERRCNT21(__x)			(0xF59E - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT21				STV090x_Px_ERRCNT21(1)
+#define STV090x_P2_ERRCNT21				STV090x_Px_ERRCNT21(2)
+#define STV090x_OFFST_Px_ERR_CNT21_FIELD		0
+#define STV090x_WIDTH_Px_ERR_CNT21_FIELD		8
+
+#define STV090x_Px_ERRCNT20(__x)			(0xF59F - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT20				STV090x_Px_ERRCNT20(1)
+#define STV090x_P2_ERRCNT20				STV090x_Px_ERRCNT20(2)
+#define STV090x_OFFST_Px_ERR_CNT20_FIELD		0
+#define STV090x_WIDTH_Px_ERR_CNT20_FIELD		8
+
+#define STV090x_Px_FECSPY(__x)				(0xF5A0 - (__x - 1) * 0x200)
+#define STV090x_P1_FECSPY				STV090x_Px_FECSPY(1)
+#define STV090x_P2_FECSPY				STV090x_Px_FECSPY(2)
+#define STV090x_OFFST_Px_SPY_ENABLE_FIELD		7
+#define STV090x_WIDTH_Px_SPY_ENABLE_FIELD		1
+#define STV090x_OFFST_Px_BERMETER_DATAMAODE_FIELD	2
+#define STV090x_WIDTH_Px_BERMETER_DATAMAODE_FIELD	2
+
+#define STV090x_Px_FSPYCFG(__x)				(0xF5A1 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYCFG				STV090x_Px_FSPYCFG(1)
+#define STV090x_P2_FSPYCFG				STV090x_Px_FSPYCFG(2)
+#define STV090x_OFFST_Px_RST_ON_ERROR_FIELD		5
+#define STV090x_WIDTH_Px_RST_ON_ERROR_FIELD		1
+#define STV090x_OFFST_Px_ONE_SHOT_FIELD			4
+#define STV090x_WIDTH_Px_ONE_SHOT_FIELD			1
+#define STV090x_OFFST_Px_I2C_MODE_FIELD			2
+#define STV090x_WIDTH_Px_I2C_MODE_FIELD			2
+
+#define STV090x_Px_FSPYDATA(__x)			(0xF5A2 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYDATA				STV090x_Px_FSPYDATA(1)
+#define STV090x_P2_FSPYDATA				STV090x_Px_FSPYDATA(2)
+#define STV090x_OFFST_Px_SPY_STUFFING_FIELD		7
+#define STV090x_WIDTH_Px_SPY_STUFFING_FIELD		1
+#define STV090x_OFFST_Px_SPY_CNULLPKT_FIELD		5
+#define STV090x_WIDTH_Px_SPY_CNULLPKT_FIELD		1
+#define STV090x_OFFST_Px_SPY_OUTDATA_MODE_FIELD		0
+#define STV090x_WIDTH_Px_SPY_OUTDATA_MODE_FIELD		5
+
+#define STV090x_Px_FSPYOUT(__x)				(0xF5A3 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYOUT				STV090x_Px_FSPYOUT(1)
+#define STV090x_P2_FSPYOUT				STV090x_Px_FSPYOUT(2)
+#define STV090x_OFFST_Px_FSPY_DIRECT_FIELD		7
+#define STV090x_WIDTH_Px_FSPY_DIRECT_FIELD		1
+#define STV090x_OFFST_Px_STUFF_MODE_FIELD		0
+#define STV090x_WIDTH_Px_STUFF_MODE_FIELD		3
+
+#define STV090x_Px_FSTATUS(__x)				(0xF5A4 - (__x - 1) * 0x200)
+#define STV090x_P1_FSTATUS				STV090x_Px_FSTATUS(1)
+#define STV090x_P2_FSTATUS				STV090x_Px_FSTATUS(2)
+#define STV090x_OFFST_Px_SPY_ENDSIM_FIELD		7
+#define STV090x_WIDTH_Px_SPY_ENDSIM_FIELD		1
+#define STV090x_OFFST_Px_VALID_SIM_FIELD		6
+#define STV090x_WIDTH_Px_VALID_SIM_FIELD		1
+#define STV090x_OFFST_Px_FOUND_SIGNAL_FIELD		5
+#define STV090x_WIDTH_Px_FOUND_SIGNAL_FIELD		1
+#define STV090x_OFFST_Px_DSS_SYNCBYTE_FIELD		4
+#define STV090x_WIDTH_Px_DSS_SYNCBYTE_FIELD		1
+#define STV090x_OFFST_Px_RESULT_STATE_FIELD		0
+#define STV090x_WIDTH_Px_RESULT_STATE_FIELD		4
+
+#define STV090x_Px_FBERCPT4(__x)			(0xF5A8 - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT4				STV090x_Px_FBERCPT4(1)
+#define STV090x_P2_FBERCPT4				STV090x_Px_FBERCPT4(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
+
+#define STV090x_Px_FBERCPT3(__x)			(0xF5A9 - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT3				STV090x_Px_FBERCPT3(1)
+#define STV090x_P2_FBERCPT3				STV090x_Px_FBERCPT3(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
+
+#define STV090x_Px_FBERCPT2(__x)			(0xF5AA - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT2				STV090x_Px_FBERCPT2(1)
+#define STV090x_P2_FBERCPT2				STV090x_Px_FBERCPT2(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
+
+#define STV090x_Px_FBERCPT1(__x)			(0xF5AB - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT1				STV090x_Px_FBERCPT1(1)
+#define STV090x_P2_FBERCPT1				STV090x_Px_FBERCPT1(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
+
+#define STV090x_Px_FBERCPT0(__x)			(0xF5AC - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT0				STV090x_Px_FBERCPT0(1)
+#define STV090x_P2_FBERCPT0				STV090x_Px_FBERCPT0(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD		0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD		8
+
+#define STV090x_Px_FBERERRy(__x, __y)			(0xF5AF - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_FBERERR0				STV090x_Px_FBERERRy(1, 0)
+#define STV090x_P1_FBERERR1				STV090x_Px_FBERERRy(1, 1)
+#define STV090x_P1_FBERERR2				STV090x_Px_FBERERRy(1, 2)
+#define STV090x_P2_FBERERR0				STV090x_Px_FBERERRy(2, 0)
+#define STV090x_P2_FBERERR1				STV090x_Px_FBERERRy(2, 1)
+#define STV090x_P2_FBERERR2				STV090x_Px_FBERERRy(2, 2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_ERR_FIELD	0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_ERR_FIELD	8
+
+#define STV090x_Px_FSPYBER(__x)				(0xF5B2 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYBER				STV090x_Px_FSPYBER(1)
+#define STV090x_P2_FSPYBER				STV090x_Px_FSPYBER(2)
+#define STV090x_OFFST_Px_FSPYBER_SYNCBYTE_FIELD		4
+#define STV090x_WIDTH_Px_FSPYBER_SYNCBYTE_FIELD		1
+#define STV090x_OFFST_Px_FSPYBER_UNSYNC_FIELD		3
+#define STV090x_WIDTH_Px_FSPYBER_UNSYNC_FIELD		1
+#define STV090x_OFFST_Px_FSPYBER_CTIME_FIELD		0
+#define STV090x_WIDTH_Px_FSPYBER_CTIME_FIELD		3
+
+#define STV090x_RCCFGH					0xf600
+
+#define STV090x_TSGENERAL				0xF630
+#define STV090x_OFFST_Px_MUXSTREAM_OUT_FIELD		3
+#define STV090x_WIDTH_Px_MUXSTREAM_OUT_FIELD		1
+#define STV090x_OFFST_Px_TSFIFO_PERMPARAL_FIELD		1
+#define STV090x_WIDTH_Px_TSFIFO_PERMPARAL_FIELD		2
+
+#define STV090x_TSGENERAL1X				0xf670
+#define STV090x_CFGEXT					0xfa80
+
+#define STV090x_TSTRES0					0xFF11
+#define STV090x_OFFST_FRESFEC_FIELD			7
+#define STV090x_WIDTH_FRESFEC_FIELD			1
+
+#define STV090x_Px_TSTDISRX(__x)			(0xFF67 - (__x - 1) * 0x2)
+#define STV090x_P1_TSTDISRX				STV090x_Px_TSTDISRX(1)
+#define STV090x_P2_TSTDISRX				STV090x_Px_TSTDISRX(2)
+#define STV090x_OFFST_Px_TSTDISRX_SELECT_FIELD		3
+#define STV090x_WIDTH_Px_TSTDISRX_SELECT_FIELD		1
+
+#endif /* __STV090x_REG_H */

+ 373 - 0
drivers/media/dvb/frontends/stv6110x.c

@@ -0,0 +1,373 @@
+/*
+	STV6110(A) Silicon tuner driver
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include "dvb_frontend.h"
+
+#include "stv6110x_reg.h"
+#include "stv6110x.h"
+#include "stv6110x_priv.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+
+static u8 stv6110x_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
+
+static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
+{
+	int ret;
+	const struct stv6110x_config *config = stv6110x->config;
+	u8 b0[] = { reg };
+	u8 b1[] = { 0 };
+	struct i2c_msg msg[] = {
+		{ .addr = config->addr, .flags = 0, 	   .buf = b0, .len = 1 },
+		{ .addr = config->addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+	};
+
+	ret = i2c_transfer(stv6110x->i2c, msg, 2);
+	if (ret != 2) {
+		dprintk(FE_ERROR, 1, "I/O Error");
+		return -EREMOTEIO;
+	}
+	*data = b1[0];
+
+	return 0;
+}
+
+static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
+{
+	int ret;
+	const struct stv6110x_config *config = stv6110x->config;
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = config->addr, .flags = 0, . buf = buf, .len = 2 };
+
+	ret = i2c_transfer(stv6110x->i2c, &msg, 1);
+	if (ret != 1) {
+		dprintk(FE_ERROR, 1, "I/O Error");
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int stv6110x_init(struct dvb_frontend *fe)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+	int ret;
+	u8 i;
+
+	for (i = 0; i < ARRAY_SIZE(stv6110x_regs); i++) {
+		ret = stv6110x_write_reg(stv6110x, i, stv6110x_regs[i]);
+		if (ret < 0) {
+			dprintk(FE_ERROR, 1, "Initialization failed");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+	u32 rDiv, divider;
+	s32 pVal, pCalc, rDivOpt = 0;
+	u8 i;
+
+	STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
+
+	if (frequency <= 1023000) {
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+		pVal = 40;
+	} else if (frequency <= 1300000) {
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+		pVal = 40;
+	} else if (frequency <= 2046000) {
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+		pVal = 20;
+	} else {
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+		pVal = 20;
+	}
+
+	for (rDiv = 0; rDiv <= 3; rDiv++) {
+		pCalc = (REFCLOCK_kHz / 100) / R_DIV(rDiv);
+
+		if ((abs((s32)(pCalc - pVal))) < (abs((s32)(1000 - pVal))))
+			rDivOpt = rDiv;
+	}
+
+	divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz;
+	divider = (divider + 5) / 10;
+
+	STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
+	STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
+	STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
+
+	/* VCO Auto calibration */
+	STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
+
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
+	stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x_regs[STV6110x_TNG1]);
+	stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x_regs[STV6110x_TNG0]);
+	stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
+
+	for (i = 0; i < TRIALS; i++) {
+		stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
+		if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x_regs[STV6110x_STAT1]))
+				break;
+		msleep(1);
+	}
+
+	return 0;
+}
+
+static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x_regs[STV6110x_TNG1]);
+	stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x_regs[STV6110x_TNG0]);
+
+	*frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x_regs[STV6110x_TNG1]),
+				 STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x_regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
+
+	*frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x_regs[STV6110x_TNG1]) +
+			     STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x_regs[STV6110x_TNG1])));
+
+	*frequency >>= 2;
+
+	return 0;
+}
+
+static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+	u32 halfbw;
+	u8 i;
+
+	halfbw = bandwidth >> 1;
+
+	if (halfbw > 36000000)
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
+	else if (halfbw < 5000000)
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
+	else
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
+
+
+	STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
+	STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
+
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
+	stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
+
+	for (i = 0; i < TRIALS; i++) {
+		stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
+		if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x_regs[STV6110x_STAT1]))
+			break;
+		msleep(1);
+	}
+	STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
+
+	return 0;
+}
+
+static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x_regs[STV6110x_CTRL3]);
+	*bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x_regs[STV6110x_CTRL3]) + 5) * 2000000;
+
+	return 0;
+}
+
+static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	/* setup divider */
+	switch (refclock) {
+	default:
+	case 1:
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
+		break;
+	case 2:
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
+		break;
+	case 4:
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
+		break;
+	case 8:
+	case 0:
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
+		break;
+	}
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
+
+	return 0;
+}
+
+static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x_regs[STV6110x_CTRL2]);
+	*gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x_regs[STV6110x_CTRL2]);
+
+	return 0;
+}
+
+static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
+	stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
+
+	return 0;
+}
+
+static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+	int ret;
+
+	switch (mode) {
+	case TUNER_SLEEP:
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 0);
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 0);
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 0);
+		break;
+
+	case TUNER_WAKE:
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 1);
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 1);
+		STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 1);
+		break;
+	}
+
+	ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
+	if (ret < 0) {
+		dprintk(FE_ERROR, 1, "I/O Error");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int stv6110x_sleep(struct dvb_frontend *fe)
+{
+	return stv6110x_set_mode(fe, TUNER_SLEEP);
+}
+
+static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
+
+	if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x_regs[STV6110x_STAT1]))
+		*status = TUNER_PHASELOCKED;
+	else
+		*status = 0;
+
+	return 0;
+}
+
+
+static int stv6110x_release(struct dvb_frontend *fe)
+{
+	struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+	fe->tuner_priv = NULL;
+	kfree(stv6110x);
+
+	return 0;
+}
+
+static struct dvb_tuner_ops stv6110x_ops = {
+	.info = {
+		.name		= "STV6110(A) Silicon Tuner",
+		.frequency_min	=  950000,
+		.frequency_max	= 2150000,
+		.frequency_step	= 0,
+	},
+
+	.init			= stv6110x_init,
+	.sleep          	= stv6110x_sleep,
+	.release		= stv6110x_release
+};
+
+static struct stv6110x_devctl stv6110x_ctl = {
+	.tuner_init		= stv6110x_init,
+	.tuner_set_mode		= stv6110x_set_mode,
+	.tuner_set_frequency	= stv6110x_set_frequency,
+	.tuner_get_frequency	= stv6110x_get_frequency,
+	.tuner_set_bandwidth	= stv6110x_set_bandwidth,
+	.tuner_get_bandwidth	= stv6110x_get_bandwidth,
+	.tuner_set_bbgain	= stv6110x_set_bbgain,
+	.tuner_get_bbgain	= stv6110x_get_bbgain,
+	.tuner_set_refclk	= stv6110x_set_refclock,
+	.tuner_get_status	= stv6110x_get_status,
+};
+
+struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+					const struct stv6110x_config *config,
+					struct i2c_adapter *i2c)
+{
+	struct stv6110x_state *stv6110x;
+
+	stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL);
+	if (stv6110x == NULL)
+		goto error;
+
+	stv6110x->i2c		= i2c;
+	stv6110x->config	= config;
+	stv6110x->devctl	= &stv6110x_ctl;
+
+	fe->tuner_priv		= stv6110x;
+	fe->ops.tuner_ops	= stv6110x_ops;
+
+	printk("%s: Attaching STV6110x \n", __func__);
+	return stv6110x->devctl;
+
+error:
+	kfree(stv6110x);
+	return NULL;
+}
+EXPORT_SYMBOL(stv6110x_attach);
+
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STV6110x Silicon tuner");
+MODULE_LICENSE("GPL");

+ 71 - 0
drivers/media/dvb/frontends/stv6110x.h

@@ -0,0 +1,71 @@
+/*
+	STV6110(A) Silicon tuner driver
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV6110x_H
+#define __STV6110x_H
+
+struct stv6110x_config {
+	u8	addr;
+	u32	refclk;
+};
+
+enum tuner_mode {
+	TUNER_SLEEP = 1,
+	TUNER_WAKE,
+};
+
+enum tuner_status {
+	TUNER_PHASELOCKED = 1,
+};
+
+struct stv6110x_devctl {
+	int (*tuner_init) (struct dvb_frontend *fe);
+	int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
+	int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
+	int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
+	int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
+	int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
+	int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
+	int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
+	int (*tuner_set_refclk)  (struct dvb_frontend *fe, u32 refclk);
+	int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
+};
+
+
+#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE))
+
+extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+					       const struct stv6110x_config *config,
+					       struct i2c_adapter *i2c);
+
+#else
+static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+						      const struct stv6110x_config *config,
+						      struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+#endif /* CONFIG_DVB_STV6110x */
+
+#endif /* __STV6110x_H */

+ 75 - 0
drivers/media/dvb/frontends/stv6110x_priv.h

@@ -0,0 +1,75 @@
+/*
+	STV6110(A) Silicon tuner driver
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV6110x_PRIV_H
+#define __STV6110x_PRIV_H
+
+#define FE_ERROR				0
+#define FE_NOTICE				1
+#define FE_INFO					2
+#define FE_DEBUG				3
+#define FE_DEBUGREG				4
+
+#define dprintk(__y, __z, format, arg...) do {						\
+	if (__z) {									\
+		if	((verbose > FE_ERROR) && (verbose > __y))			\
+			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);		\
+		else if	((verbose > FE_NOTICE) && (verbose > __y))			\
+			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
+		else if ((verbose > FE_INFO) && (verbose > __y))			\
+			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);		\
+		else if ((verbose > FE_DEBUG) && (verbose > __y))			\
+			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
+	} else {									\
+		if (verbose > __y)							\
+			printk(format, ##arg);						\
+	}										\
+} while (0)
+
+
+#define STV6110x_SETFIELD(mask, bitf, val)				\
+	(mask = (mask & (~(((1 << STV6110x_WIDTH_##bitf) - 1) <<	\
+				  STV6110x_OFFST_##bitf))) | 		\
+			  (val << STV6110x_OFFST_##bitf))
+
+#define STV6110x_GETFIELD(bitf, val)					\
+	((val >> STV6110x_OFFST_##bitf) & 				\
+	((1 << STV6110x_WIDTH_##bitf) - 1))
+
+#define MAKEWORD16(a, b)			(((a) << 8) | (b))
+
+#define LSB(x)					((x & 0xff))
+#define MSB(y)					((y >> 8) & 0xff)
+
+#define TRIALS					10
+#define R_DIV(__div)				(1 << (__div + 1))
+#define REFCLOCK_kHz				(stv6110x->config->refclk /    1000)
+#define REFCLOCK_MHz				(stv6110x->config->refclk / 1000000)
+
+struct stv6110x_state {
+	struct i2c_adapter		*i2c;
+	const struct stv6110x_config	*config;
+
+	struct stv6110x_devctl		*devctl;
+};
+
+#endif /* __STV6110x_PRIV_H */

+ 82 - 0
drivers/media/dvb/frontends/stv6110x_reg.h

@@ -0,0 +1,82 @@
+/*
+	STV6110(A) Silicon tuner driver
+
+	Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+	Copyright (C) ST Microelectronics
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __STV6110x_REG_H
+#define __STV6110x_REG_H
+
+#define STV6110x_CTRL1				0x00
+#define STV6110x_OFFST_CTRL1_K			3
+#define STV6110x_WIDTH_CTRL1_K			5
+#define STV6110x_OFFST_CTRL1_LPT		2
+#define STV6110x_WIDTH_CTRL1_LPT		1
+#define STV6110x_OFFST_CTRL1_RX			1
+#define STV6110x_WIDTH_CTRL1_RX			1
+#define STV6110x_OFFST_CTRL1_SYN		0
+#define STV6110x_WIDTH_CTRL1_SYN		1
+
+#define STV6110x_CTRL2				0x01
+#define STV6110x_OFFST_CTRL2_CO_DIV		6
+#define STV6110x_WIDTH_CTRL2_CO_DIV		2
+#define STV6110x_OFFST_CTRL2_RSVD		5
+#define STV6110x_WIDTH_CTRL2_RSVD		1
+#define STV6110x_OFFST_CTRL2_REFOUT_SEL		4
+#define STV6110x_WIDTH_CTRL2_REFOUT_SEL		1
+#define STV6110x_OFFST_CTRL2_BBGAIN		0
+#define STV6110x_WIDTH_CTRL2_BBGAIN		4
+
+#define STV6110x_TNG0				0x02
+#define STV6110x_OFFST_TNG0_N_DIV_7_0		0
+#define STV6110x_WIDTH_TNG0_N_DIV_7_0		8
+
+#define STV6110x_TNG1				0x03
+#define STV6110x_OFFST_TNG1_R_DIV		6
+#define STV6110x_WIDTH_TNG1_R_DIV		2
+#define STV6110x_OFFST_TNG1_PRESC32_ON		5
+#define STV6110x_WIDTH_TNG1_PRESC32_ON		1
+#define STV6110x_OFFST_TNG1_DIV4SEL		4
+#define STV6110x_WIDTH_TNG1_DIV4SEL		1
+#define STV6110x_OFFST_TNG1_N_DIV_11_8		0
+#define STV6110x_WIDTH_TNG1_N_DIV_11_8		4
+
+
+#define STV6110x_CTRL3				0x04
+#define STV6110x_OFFST_CTRL3_DCLOOP_OFF		7
+#define STV6110x_WIDTH_CTRL3_DCLOOP_OFF		1
+#define STV6110x_OFFST_CTRL3_RCCLK_OFF		6
+#define STV6110x_WIDTH_CTRL3_RCCLK_OFF		1
+#define STV6110x_OFFST_CTRL3_ICP		5
+#define STV6110x_WIDTH_CTRL3_ICP		1
+#define STV6110x_OFFST_CTRL3_CF			0
+#define STV6110x_WIDTH_CTRL3_CF			5
+
+#define STV6110x_STAT1				0x05
+#define STV6110x_OFFST_STAT1_CALVCO_STRT	2
+#define STV6110x_WIDTH_STAT1_CALVCO_STRT	1
+#define STV6110x_OFFST_STAT1_CALRC_STRT		1
+#define STV6110x_WIDTH_STAT1_CALRC_STRT		1
+#define STV6110x_OFFST_STAT1_LOCK		0
+#define STV6110x_WIDTH_STAT1_LOCK		1
+
+#define STV6110x_STAT2				0x06
+#define STV6110x_STAT3				0x07
+
+#endif /* __STV6110x_REG_H */

+ 298 - 14
drivers/media/dvb/frontends/tda10048.c

@@ -1,7 +1,7 @@
 /*
 /*
     NXP TDA10048HN DVB OFDM demodulator driver
     NXP TDA10048HN DVB OFDM demodulator driver
 
 
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+    Copyright (C) 2009 Steven Toth <stoth@kernellabs.com>
 
 
     This program is free software; you can redistribute it and/or modify
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
 #include <linux/string.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
+#include <asm/div64.h>
 #include "dvb_frontend.h"
 #include "dvb_frontend.h"
 #include "dvb_math.h"
 #include "dvb_math.h"
 #include "tda10048.h"
 #include "tda10048.h"
@@ -138,11 +139,20 @@ struct tda10048_state {
 
 
 	struct i2c_adapter *i2c;
 	struct i2c_adapter *i2c;
 
 
-	/* configuration settings */
-	const struct tda10048_config *config;
+	/* We'll cache and update the attach config settings */
+	struct tda10048_config config;
 	struct dvb_frontend frontend;
 	struct dvb_frontend frontend;
 
 
 	int fwloaded;
 	int fwloaded;
+
+	u32 freq_if_hz;
+	u32 xtal_hz;
+	u32 pll_mfactor;
+	u32 pll_nfactor;
+	u32 pll_pfactor;
+	u32 sample_freq;
+
+	enum fe_bandwidth bandwidth;
 };
 };
 
 
 static struct init_tab {
 static struct init_tab {
@@ -192,12 +202,26 @@ static struct init_tab {
 	{ TDA10048_CONF_C4_2, 0x04 },
 	{ TDA10048_CONF_C4_2, 0x04 },
 };
 };
 
 
+static struct pll_tab {
+	u32	clk_freq_khz;
+	u32	if_freq_khz;
+	u8	m, n, p;
+} pll_tab[] = {
+	{ TDA10048_CLK_4000,  TDA10048_IF_36130, 10, 0, 0 },
+	{ TDA10048_CLK_16000, TDA10048_IF_3300,  10, 3, 0 },
+	{ TDA10048_CLK_16000, TDA10048_IF_3500,  10, 3, 0 },
+	{ TDA10048_CLK_16000, TDA10048_IF_4000,  10, 3, 0 },
+	{ TDA10048_CLK_16000, TDA10048_IF_4300,  10, 3, 0 },
+	{ TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 },
+};
+
 static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
 static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
 {
 {
+	struct tda10048_config *config = &state->config;
 	int ret;
 	int ret;
 	u8 buf[] = { reg, data };
 	u8 buf[] = { reg, data };
 	struct i2c_msg msg = {
 	struct i2c_msg msg = {
-		.addr = state->config->demod_address,
+		.addr = config->demod_address,
 		.flags = 0, .buf = buf, .len = 2 };
 		.flags = 0, .buf = buf, .len = 2 };
 
 
 	dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);
 	dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);
@@ -212,13 +236,14 @@ static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
 
 
 static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
 static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
 {
 {
+	struct tda10048_config *config = &state->config;
 	int ret;
 	int ret;
 	u8 b0[] = { reg };
 	u8 b0[] = { reg };
 	u8 b1[] = { 0 };
 	u8 b1[] = { 0 };
 	struct i2c_msg msg[] = {
 	struct i2c_msg msg[] = {
-		{ .addr = state->config->demod_address,
+		{ .addr = config->demod_address,
 			.flags = 0, .buf = b0, .len = 1 },
 			.flags = 0, .buf = b0, .len = 1 },
-		{ .addr = state->config->demod_address,
+		{ .addr = config->demod_address,
 			.flags = I2C_M_RD, .buf = b1, .len = 1 } };
 			.flags = I2C_M_RD, .buf = b1, .len = 1 } };
 
 
 	dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);
 	dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);
@@ -235,6 +260,7 @@ static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
 static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
 static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
 				 const u8 *data, u16 len)
 				 const u8 *data, u16 len)
 {
 {
+	struct tda10048_config *config = &state->config;
 	int ret = -EREMOTEIO;
 	int ret = -EREMOTEIO;
 	struct i2c_msg msg;
 	struct i2c_msg msg;
 	u8 *buf;
 	u8 *buf;
@@ -250,7 +276,7 @@ static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
 	*buf = reg;
 	*buf = reg;
 	memcpy(buf + 1, data, len);
 	memcpy(buf + 1, data, len);
 
 
-	msg.addr = state->config->demod_address;
+	msg.addr = config->demod_address;
 	msg.flags = 0;
 	msg.flags = 0;
 	msg.buf = buf;
 	msg.buf = buf;
 	msg.len = len + 1;
 	msg.len = len + 1;
@@ -271,14 +297,206 @@ error:
 	return ret;
 	return ret;
 }
 }
 
 
+static int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz,
+			     u32 if_hz)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u64 t;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (sample_freq_hz == 0)
+		return -EINVAL;
+
+	if (if_hz < (sample_freq_hz / 2)) {
+		/* PHY2 = (if2/fs) * 2^15 */
+		t = if_hz;
+		t *= 10;
+		t *= 32768;
+		do_div(t, sample_freq_hz);
+		t += 5;
+		do_div(t, 10);
+	} else {
+		/* PHY2 = ((IF1-fs)/fs) * 2^15 */
+		t = sample_freq_hz - if_hz;
+		t *= 10;
+		t *= 32768;
+		do_div(t, sample_freq_hz);
+		t += 5;
+		do_div(t, 10);
+		t = ~t + 1;
+	}
+
+	tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t);
+	tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8));
+
+	return 0;
+}
+
+static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz,
+			     u32 bw)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u64 t, z;
+	u32 b = 8000000;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (sample_freq_hz == 0)
+		return -EINVAL;
+
+	if (bw == BANDWIDTH_6_MHZ)
+		b = 6000000;
+	else
+	if (bw == BANDWIDTH_7_MHZ)
+		b = 7000000;
+
+	/* WREF = (B / (7 * fs)) * 2^31 */
+	t = b * 10;
+	/* avoid warning: this decimal constant is unsigned only in ISO C90 */
+	/* t *= 2147483648 on 32bit platforms */
+	t *= (2048 * 1024);
+	t *= 1024;
+	z = 7 * sample_freq_hz;
+	do_div(t, z);
+	t += 5;
+	do_div(t, 10);
+
+	tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t);
+	tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8));
+	tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16));
+	tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24));
+
+	return 0;
+}
+
+static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz,
+				u32 bw)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	u64 t;
+	u32 b = 8000000;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (sample_freq_hz == 0)
+		return -EINVAL;
+
+	if (bw == BANDWIDTH_6_MHZ)
+		b = 6000000;
+	else
+	if (bw == BANDWIDTH_7_MHZ)
+		b = 7000000;
+
+	/* INVWREF = ((7 * fs) / B) * 2^5 */
+	t = sample_freq_hz;
+	t *= 7;
+	t *= 32;
+	t *= 10;
+	do_div(t, b);
+	t += 5;
+	do_div(t, 10);
+
+	tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t);
+	tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8));
+
+	return 0;
+}
+
+static int tda10048_set_bandwidth(struct dvb_frontend *fe,
+	enum fe_bandwidth bw)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	dprintk(1, "%s(bw=%d)\n", __func__, bw);
+
+	/* Bandwidth setting may need to be adjusted */
+	switch (bw) {
+	case BANDWIDTH_6_MHZ:
+	case BANDWIDTH_7_MHZ:
+	case BANDWIDTH_8_MHZ:
+		tda10048_set_wref(fe, state->sample_freq, bw);
+		tda10048_set_invwref(fe, state->sample_freq, bw);
+		break;
+	default:
+		printk(KERN_ERR "%s() invalid bandwidth\n", __func__);
+		return -EINVAL;
+	}
+
+	state->bandwidth = bw;
+
+	return 0;
+}
+
+static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	struct tda10048_config *config = &state->config;
+	int i;
+	u32 if_freq_khz;
+
+	dprintk(1, "%s(bw = %d)\n", __func__, bw);
+
+	/* based on target bandwidth and clk we calculate pll factors */
+	switch (bw) {
+	case BANDWIDTH_6_MHZ:
+		if_freq_khz = config->dtv6_if_freq_khz;
+		break;
+	case BANDWIDTH_7_MHZ:
+		if_freq_khz = config->dtv7_if_freq_khz;
+		break;
+	case BANDWIDTH_8_MHZ:
+		if_freq_khz = config->dtv8_if_freq_khz;
+		break;
+	default:
+		printk(KERN_ERR "%s() no default\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pll_tab); i++) {
+		if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) &&
+			(pll_tab[i].if_freq_khz == if_freq_khz)) {
+
+			state->freq_if_hz = pll_tab[i].if_freq_khz * 1000;
+			state->xtal_hz = pll_tab[i].clk_freq_khz * 1000;
+			state->pll_mfactor = pll_tab[i].m;
+			state->pll_nfactor = pll_tab[i].n;
+			state->pll_pfactor = pll_tab[i].p;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(pll_tab)) {
+		printk(KERN_ERR "%s() Incorrect attach settings\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz);
+	dprintk(1, "- xtal_hz = %d\n", state->xtal_hz);
+	dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor);
+	dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor);
+	dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor);
+
+	/* Calculate the sample frequency */
+	state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45);
+	state->sample_freq /= (state->pll_nfactor + 1);
+	state->sample_freq /= (state->pll_pfactor + 4);
+	dprintk(1, "- sample_freq = %d\n", state->sample_freq);
+
+	/* Update the I/F */
+	tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz);
+
+	return 0;
+}
+
 static int tda10048_firmware_upload(struct dvb_frontend *fe)
 static int tda10048_firmware_upload(struct dvb_frontend *fe)
 {
 {
 	struct tda10048_state *state = fe->demodulator_priv;
 	struct tda10048_state *state = fe->demodulator_priv;
+	struct tda10048_config *config = &state->config;
 	const struct firmware *fw;
 	const struct firmware *fw;
 	int ret;
 	int ret;
 	int pos = 0;
 	int pos = 0;
 	int cnt;
 	int cnt;
-	u8 wlen = state->config->fwbulkwritelen;
+	u8 wlen = config->fwbulkwritelen;
 
 
 	if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))
 	if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))
 		wlen = TDA10048_BULKWRITE_200;
 		wlen = TDA10048_BULKWRITE_200;
@@ -289,7 +507,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe)
 		TDA10048_DEFAULT_FIRMWARE);
 		TDA10048_DEFAULT_FIRMWARE);
 
 
 	ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,
 	ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,
-		&state->i2c->dev);
+		state->i2c->dev.parent);
 	if (ret) {
 	if (ret) {
 		printk(KERN_ERR "%s: Upload failed. (file not found?)\n",
 		printk(KERN_ERR "%s: Upload failed. (file not found?)\n",
 			__func__);
 			__func__);
@@ -484,8 +702,12 @@ static int tda10048_get_tps(struct tda10048_state *state,
 static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
 {
 	struct tda10048_state *state = fe->demodulator_priv;
 	struct tda10048_state *state = fe->demodulator_priv;
+	struct tda10048_config *config = &state->config;
 	dprintk(1, "%s(%d)\n", __func__, enable);
 	dprintk(1, "%s(%d)\n", __func__, enable);
 
 
+	if (config->disable_gate_access)
+		return 0;
+
 	if (enable)
 	if (enable)
 		return tda10048_writereg(state, TDA10048_CONF_C4_1,
 		return tda10048_writereg(state, TDA10048_CONF_C4_1,
 			tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02);
 			tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02);
@@ -523,6 +745,12 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
 
 
 	dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
 	dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
 
 
+	/* Update the I/F pll's if the bandwidth changes */
+	if (p->u.ofdm.bandwidth != state->bandwidth) {
+		tda10048_set_if(fe, p->u.ofdm.bandwidth);
+		tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth);
+	}
+
 	if (fe->ops.tuner_ops.set_params) {
 	if (fe->ops.tuner_ops.set_params) {
 
 
 		if (fe->ops.i2c_gate_ctrl)
 		if (fe->ops.i2c_gate_ctrl)
@@ -544,6 +772,7 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
 static int tda10048_init(struct dvb_frontend *fe)
 static int tda10048_init(struct dvb_frontend *fe)
 {
 {
 	struct tda10048_state *state = fe->demodulator_priv;
 	struct tda10048_state *state = fe->demodulator_priv;
+	struct tda10048_config *config = &state->config;
 	int ret = 0, i;
 	int ret = 0, i;
 
 
 	dprintk(1, "%s()\n", __func__);
 	dprintk(1, "%s()\n", __func__);
@@ -556,10 +785,14 @@ static int tda10048_init(struct dvb_frontend *fe)
 		ret = tda10048_firmware_upload(fe);
 		ret = tda10048_firmware_upload(fe);
 
 
 	/* Set either serial or parallel */
 	/* Set either serial or parallel */
-	tda10048_output_mode(fe, state->config->output_mode);
+	tda10048_output_mode(fe, config->output_mode);
+
+	/* Set inversion */
+	tda10048_set_inversion(fe, config->inversion);
 
 
-	/* set inversion */
-	tda10048_set_inversion(fe, state->config->inversion);
+	/* Establish default RF values */
+	tda10048_set_if(fe, BANDWIDTH_8_MHZ);
+	tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ);
 
 
 	/* Ensure we leave the gate closed */
 	/* Ensure we leave the gate closed */
 	tda10048_i2c_gate_ctrl(fe, 0);
 	tda10048_i2c_gate_ctrl(fe, 0);
@@ -812,6 +1045,45 @@ static void tda10048_release(struct dvb_frontend *fe)
 	kfree(state);
 	kfree(state);
 }
 }
 
 
+static void tda10048_establish_defaults(struct dvb_frontend *fe)
+{
+	struct tda10048_state *state = fe->demodulator_priv;
+	struct tda10048_config *config = &state->config;
+
+	/* Validate/default the config */
+	if (config->dtv6_if_freq_khz == 0) {
+		config->dtv6_if_freq_khz = TDA10048_IF_4300;
+		printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz "
+			"is not set (defaulting to %d)\n",
+			__func__,
+			config->dtv6_if_freq_khz);
+	}
+
+	if (config->dtv7_if_freq_khz == 0) {
+		config->dtv7_if_freq_khz = TDA10048_IF_4300;
+		printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz "
+			"is not set (defaulting to %d)\n",
+			__func__,
+			config->dtv7_if_freq_khz);
+	}
+
+	if (config->dtv8_if_freq_khz == 0) {
+		config->dtv8_if_freq_khz = TDA10048_IF_4300;
+		printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz "
+			"is not set (defaulting to %d)\n",
+			__func__,
+			config->dtv8_if_freq_khz);
+	}
+
+	if (config->clk_freq_khz == 0) {
+		config->clk_freq_khz = TDA10048_CLK_16000;
+		printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz "
+			"is not set (defaulting to %d)\n",
+			__func__,
+			config->clk_freq_khz);
+	}
+}
+
 static struct dvb_frontend_ops tda10048_ops;
 static struct dvb_frontend_ops tda10048_ops;
 
 
 struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
 struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
@@ -826,10 +1098,11 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
 	if (state == NULL)
 	if (state == NULL)
 		goto error;
 		goto error;
 
 
-	/* setup the state */
-	state->config = config;
+	/* setup the state and clone the config */
+	memcpy(&state->config, config, sizeof(*config));
 	state->i2c = i2c;
 	state->i2c = i2c;
 	state->fwloaded = 0;
 	state->fwloaded = 0;
+	state->bandwidth = BANDWIDTH_8_MHZ;
 
 
 	/* check if the demod is present */
 	/* check if the demod is present */
 	if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
 	if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
@@ -840,6 +1113,17 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
 		sizeof(struct dvb_frontend_ops));
 		sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	state->frontend.demodulator_priv = state;
 
 
+	/* Establish any defaults the the user didn't pass */
+	tda10048_establish_defaults(&state->frontend);
+
+	/* Set the xtal and freq defaults */
+	if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0)
+		goto error;
+
+	/* Default bandwidth */
+	if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0)
+		goto error;
+
 	/* Leave the gate closed */
 	/* Leave the gate closed */
 	tda10048_i2c_gate_ctrl(&state->frontend, 0);
 	tda10048_i2c_gate_ctrl(&state->frontend, 0);
 
 

+ 20 - 1
drivers/media/dvb/frontends/tda10048.h

@@ -1,7 +1,7 @@
 /*
 /*
     NXP TDA10048HN DVB OFDM demodulator driver
     NXP TDA10048HN DVB OFDM demodulator driver
 
 
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+    Copyright (C) 2009 Steven Toth <stoth@kernellabs.com>
 
 
     This program is free software; you can redistribute it and/or modify
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     it under the terms of the GNU General Public License as published by
@@ -43,6 +43,25 @@ struct tda10048_config {
 #define TDA10048_INVERSION_OFF 0
 #define TDA10048_INVERSION_OFF 0
 #define TDA10048_INVERSION_ON  1
 #define TDA10048_INVERSION_ON  1
 	u8 inversion;
 	u8 inversion;
+
+#define TDA10048_IF_3300  3300
+#define TDA10048_IF_3500  3500
+#define TDA10048_IF_3800  3800
+#define TDA10048_IF_4000  4000
+#define TDA10048_IF_4300  4300
+#define TDA10048_IF_4500  4500
+#define TDA10048_IF_4750  4750
+#define TDA10048_IF_36130 36130
+	u16 dtv6_if_freq_khz;
+	u16 dtv7_if_freq_khz;
+	u16 dtv8_if_freq_khz;
+
+#define TDA10048_CLK_4000  4000
+#define TDA10048_CLK_16000 16000
+	u16 clk_freq_khz;
+
+	/* Disable I2C gate access */
+	u8 disable_gate_access;
 };
 };
 
 
 #if defined(CONFIG_DVB_TDA10048) || \
 #if defined(CONFIG_DVB_TDA10048) || \

+ 1 - 1
drivers/media/dvb/siano/Makefile

@@ -1,4 +1,4 @@
-sms1xxx-objs := smscoreapi.o sms-cards.o
+sms1xxx-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o
 
 
 obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
 obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
 obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsusb.o
 obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsusb.o

+ 184 - 4
drivers/media/dvb/siano/sms-cards.c

@@ -18,6 +18,7 @@
  */
  */
 
 
 #include "sms-cards.h"
 #include "sms-cards.h"
+#include "smsir.h"
 
 
 static int sms_dbg;
 static int sms_dbg;
 module_param_named(cards_dbg, sms_dbg, int, 0644);
 module_param_named(cards_dbg, sms_dbg, int, 0644);
@@ -30,17 +31,14 @@ static struct sms_board sms_boards[] = {
 	[SMS1XXX_BOARD_SIANO_STELLAR] = {
 	[SMS1XXX_BOARD_SIANO_STELLAR] = {
 		.name	= "Siano Stellar Digital Receiver",
 		.name	= "Siano Stellar Digital Receiver",
 		.type	= SMS_STELLAR,
 		.type	= SMS_STELLAR,
-		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
 	},
 	},
 	[SMS1XXX_BOARD_SIANO_NOVA_A] = {
 	[SMS1XXX_BOARD_SIANO_NOVA_A] = {
 		.name	= "Siano Nova A Digital Receiver",
 		.name	= "Siano Nova A Digital Receiver",
 		.type	= SMS_NOVA_A0,
 		.type	= SMS_NOVA_A0,
-		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
 	},
 	},
 	[SMS1XXX_BOARD_SIANO_NOVA_B] = {
 	[SMS1XXX_BOARD_SIANO_NOVA_B] = {
 		.name	= "Siano Nova B Digital Receiver",
 		.name	= "Siano Nova B Digital Receiver",
 		.type	= SMS_NOVA_B0,
 		.type	= SMS_NOVA_B0,
-		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
 	},
 	},
 	[SMS1XXX_BOARD_SIANO_VEGA] = {
 	[SMS1XXX_BOARD_SIANO_VEGA] = {
 		.name	= "Siano Vega Digital Receiver",
 		.name	= "Siano Vega Digital Receiver",
@@ -65,6 +63,9 @@ static struct sms_board sms_boards[] = {
 		.name	= "Hauppauge WinTV MiniStick",
 		.name	= "Hauppauge WinTV MiniStick",
 		.type	= SMS_NOVA_B0,
 		.type	= SMS_NOVA_B0,
 		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
 		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+		.board_cfg.leds_power = 26,
+		.board_cfg.led0 = 27,
+		.board_cfg.led1 = 28,
 		.led_power = 26,
 		.led_power = 26,
 		.led_lo    = 27,
 		.led_lo    = 27,
 		.led_hi    = 28,
 		.led_hi    = 28,
@@ -74,7 +75,9 @@ static struct sms_board sms_boards[] = {
 		.type	= SMS_NOVA_B0,
 		.type	= SMS_NOVA_B0,
 		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
 		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
 		.lna_ctrl  = 29,
 		.lna_ctrl  = 29,
+		.board_cfg.foreign_lna0_ctrl = 29,
 		.rf_switch = 17,
 		.rf_switch = 17,
+		.board_cfg.rf_switch_uhf = 17,
 	},
 	},
 	[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
 	[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
 		.name	= "Hauppauge WinTV MiniCard",
 		.name	= "Hauppauge WinTV MiniCard",
@@ -82,6 +85,16 @@ static struct sms_board sms_boards[] = {
 		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
 		.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
 		.lna_ctrl  = -1,
 		.lna_ctrl  = -1,
 	},
 	},
+	[SMS1XXX_BOARD_SIANO_NICE] = {
+	/* 11 */
+		.name = "Siano Nice Digital Receiver",
+		.type = SMS_NOVA_B0,
+	},
+	[SMS1XXX_BOARD_SIANO_VENICE] = {
+	/* 12 */
+		.name = "Siano Venice Digital Receiver",
+		.type = SMS_VEGA,
+	},
 };
 };
 
 
 struct sms_board *sms_get_board(int id)
 struct sms_board *sms_get_board(int id)
@@ -91,12 +104,179 @@ struct sms_board *sms_get_board(int id)
 	return &sms_boards[id];
 	return &sms_boards[id];
 }
 }
 EXPORT_SYMBOL_GPL(sms_get_board);
 EXPORT_SYMBOL_GPL(sms_get_board);
+static inline void sms_gpio_assign_11xx_default_led_config(
+		struct smscore_gpio_config *pGpioConfig) {
+	pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
+	pGpioConfig->InputCharacteristics =
+		SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL;
+	pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA;
+	pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
+	pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE;
+}
+
+int sms_board_event(struct smscore_device_t *coredev,
+		enum SMS_BOARD_EVENTS gevent) {
+	int board_id = smscore_get_board_id(coredev);
+	struct sms_board *board = sms_get_board(board_id);
+	struct smscore_gpio_config MyGpioConfig;
+
+	sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
+
+	switch (gevent) {
+	case BOARD_EVENT_POWER_INIT: /* including hotplug */
+		switch (board_id) {
+		case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+			/* set I/O and turn off all LEDs */
+			smscore_gpio_configure(coredev,
+					board->board_cfg.leds_power,
+					&MyGpioConfig);
+			smscore_gpio_set_level(coredev,
+					board->board_cfg.leds_power, 0);
+			smscore_gpio_configure(coredev, board->board_cfg.led0,
+					&MyGpioConfig);
+			smscore_gpio_set_level(coredev,
+					board->board_cfg.led0, 0);
+			smscore_gpio_configure(coredev, board->board_cfg.led1,
+					&MyGpioConfig);
+			smscore_gpio_set_level(coredev,
+					board->board_cfg.led1, 0);
+			break;
+		case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+		case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+			/* set I/O and turn off LNA */
+			smscore_gpio_configure(coredev,
+					board->board_cfg.foreign_lna0_ctrl,
+					&MyGpioConfig);
+			smscore_gpio_set_level(coredev,
+					board->board_cfg.foreign_lna0_ctrl,
+					0);
+			break;
+		}
+		break; /* BOARD_EVENT_BIND */
+
+	case BOARD_EVENT_POWER_SUSPEND:
+		switch (board_id) {
+		case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+			smscore_gpio_set_level(coredev,
+						board->board_cfg.leds_power, 0);
+			smscore_gpio_set_level(coredev,
+						board->board_cfg.led0, 0);
+			smscore_gpio_set_level(coredev,
+						board->board_cfg.led1, 0);
+			break;
+		case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+		case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+			smscore_gpio_set_level(coredev,
+					board->board_cfg.foreign_lna0_ctrl,
+					0);
+			break;
+		}
+		break; /* BOARD_EVENT_POWER_SUSPEND */
+
+	case BOARD_EVENT_POWER_RESUME:
+		switch (board_id) {
+		case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+			smscore_gpio_set_level(coredev,
+						board->board_cfg.leds_power, 1);
+			smscore_gpio_set_level(coredev,
+						board->board_cfg.led0, 1);
+			smscore_gpio_set_level(coredev,
+						board->board_cfg.led1, 0);
+			break;
+		case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+		case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+			smscore_gpio_set_level(coredev,
+					board->board_cfg.foreign_lna0_ctrl,
+					1);
+			break;
+		}
+		break; /* BOARD_EVENT_POWER_RESUME */
+
+	case BOARD_EVENT_BIND:
+		switch (board_id) {
+		case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+			smscore_gpio_set_level(coredev,
+				board->board_cfg.leds_power, 1);
+			smscore_gpio_set_level(coredev,
+				board->board_cfg.led0, 1);
+			smscore_gpio_set_level(coredev,
+				board->board_cfg.led1, 0);
+			break;
+		case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+		case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+			smscore_gpio_set_level(coredev,
+					board->board_cfg.foreign_lna0_ctrl,
+					1);
+			break;
+		}
+		break; /* BOARD_EVENT_BIND */
+
+	case BOARD_EVENT_SCAN_PROG:
+		break; /* BOARD_EVENT_SCAN_PROG */
+	case BOARD_EVENT_SCAN_COMP:
+		break; /* BOARD_EVENT_SCAN_COMP */
+	case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
+		break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
+	case BOARD_EVENT_FE_LOCK:
+		switch (board_id) {
+		case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+			smscore_gpio_set_level(coredev,
+			board->board_cfg.led1, 1);
+			break;
+		}
+		break; /* BOARD_EVENT_FE_LOCK */
+	case BOARD_EVENT_FE_UNLOCK:
+		switch (board_id) {
+		case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+			smscore_gpio_set_level(coredev,
+						board->board_cfg.led1, 0);
+			break;
+		}
+		break; /* BOARD_EVENT_FE_UNLOCK */
+	case BOARD_EVENT_DEMOD_LOCK:
+		break; /* BOARD_EVENT_DEMOD_LOCK */
+	case BOARD_EVENT_DEMOD_UNLOCK:
+		break; /* BOARD_EVENT_DEMOD_UNLOCK */
+	case BOARD_EVENT_RECEPTION_MAX_4:
+		break; /* BOARD_EVENT_RECEPTION_MAX_4 */
+	case BOARD_EVENT_RECEPTION_3:
+		break; /* BOARD_EVENT_RECEPTION_3 */
+	case BOARD_EVENT_RECEPTION_2:
+		break; /* BOARD_EVENT_RECEPTION_2 */
+	case BOARD_EVENT_RECEPTION_1:
+		break; /* BOARD_EVENT_RECEPTION_1 */
+	case BOARD_EVENT_RECEPTION_LOST_0:
+		break; /* BOARD_EVENT_RECEPTION_LOST_0 */
+	case BOARD_EVENT_MULTIPLEX_OK:
+		switch (board_id) {
+		case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+			smscore_gpio_set_level(coredev,
+						board->board_cfg.led1, 1);
+			break;
+		}
+		break; /* BOARD_EVENT_MULTIPLEX_OK */
+	case BOARD_EVENT_MULTIPLEX_ERRORS:
+		switch (board_id) {
+		case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+			smscore_gpio_set_level(coredev,
+						board->board_cfg.led1, 0);
+			break;
+		}
+		break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
+
+	default:
+		sms_err("Unknown SMS board event");
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sms_board_event);
 
 
 static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
 static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
 {
 {
 	int lvl, ret;
 	int lvl, ret;
 	u32 gpio;
 	u32 gpio;
-	struct smscore_gpio_config gpioconfig = {
+	struct smscore_config_gpio gpioconfig = {
 		.direction            = SMS_GPIO_DIRECTION_OUTPUT,
 		.direction            = SMS_GPIO_DIRECTION_OUTPUT,
 		.pullupdown           = SMS_GPIO_PULLUPDOWN_NONE,
 		.pullupdown           = SMS_GPIO_PULLUPDOWN_NONE,
 		.inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
 		.inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,

+ 64 - 0
drivers/media/dvb/siano/sms-cards.h

@@ -22,6 +22,7 @@
 
 
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include "smscoreapi.h"
 #include "smscoreapi.h"
+#include "smsir.h"
 
 
 #define SMS_BOARD_UNKNOWN 0
 #define SMS_BOARD_UNKNOWN 0
 #define SMS1XXX_BOARD_SIANO_STELLAR 1
 #define SMS1XXX_BOARD_SIANO_STELLAR 1
@@ -34,10 +35,47 @@
 #define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
 #define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
 #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
 #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
 #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
 #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
+#define SMS1XXX_BOARD_SIANO_NICE	11
+#define SMS1XXX_BOARD_SIANO_VENICE	12
+
+struct sms_board_gpio_cfg {
+	int lna_vhf_exist;
+	int lna_vhf_ctrl;
+	int lna_uhf_exist;
+	int lna_uhf_ctrl;
+	int lna_uhf_d_ctrl;
+	int lna_sband_exist;
+	int lna_sband_ctrl;
+	int lna_sband_d_ctrl;
+	int foreign_lna0_ctrl;
+	int foreign_lna1_ctrl;
+	int foreign_lna2_ctrl;
+	int rf_switch_vhf;
+	int rf_switch_uhf;
+	int rf_switch_sband;
+	int leds_power;
+	int led0;
+	int led1;
+	int led2;
+	int led3;
+	int led4;
+	int ir;
+	int eeprom_wp;
+	int mrc_sense;
+	int mrc_pdn_resetn;
+	int mrc_gp0; /* mrcs spi int */
+	int mrc_gp1;
+	int mrc_gp2;
+	int mrc_gp3;
+	int mrc_gp4;
+	int host_spi_gsp_ts_int;
+};
 
 
 struct sms_board {
 struct sms_board {
 	enum sms_device_type_st type;
 	enum sms_device_type_st type;
 	char *name, *fw[DEVICE_MODE_MAX];
 	char *name, *fw[DEVICE_MODE_MAX];
+	struct sms_board_gpio_cfg board_cfg;
+	enum ir_kb_type ir_kb_type;
 
 
 	/* gpios */
 	/* gpios */
 	int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
 	int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
@@ -45,6 +83,32 @@ struct sms_board {
 
 
 struct sms_board *sms_get_board(int id);
 struct sms_board *sms_get_board(int id);
 
 
+extern struct smscore_device_t *coredev;
+
+enum SMS_BOARD_EVENTS {
+	BOARD_EVENT_POWER_INIT,
+	BOARD_EVENT_POWER_SUSPEND,
+	BOARD_EVENT_POWER_RESUME,
+	BOARD_EVENT_BIND,
+	BOARD_EVENT_SCAN_PROG,
+	BOARD_EVENT_SCAN_COMP,
+	BOARD_EVENT_EMERGENCY_WARNING_SIGNAL,
+	BOARD_EVENT_FE_LOCK,
+	BOARD_EVENT_FE_UNLOCK,
+	BOARD_EVENT_DEMOD_LOCK,
+	BOARD_EVENT_DEMOD_UNLOCK,
+	BOARD_EVENT_RECEPTION_MAX_4,
+	BOARD_EVENT_RECEPTION_3,
+	BOARD_EVENT_RECEPTION_2,
+	BOARD_EVENT_RECEPTION_1,
+	BOARD_EVENT_RECEPTION_LOST_0,
+	BOARD_EVENT_MULTIPLEX_OK,
+	BOARD_EVENT_MULTIPLEX_ERRORS
+};
+
+int sms_board_event(struct smscore_device_t *coredev,
+		enum SMS_BOARD_EVENTS gevent);
+
 int sms_board_setup(struct smscore_device_t *coredev);
 int sms_board_setup(struct smscore_device_t *coredev);
 
 
 #define SMS_LED_OFF 0
 #define SMS_LED_OFF 0

+ 387 - 81
drivers/media/dvb/siano/smscoreapi.c

@@ -30,9 +30,13 @@
 #include <linux/io.h>
 #include <linux/io.h>
 
 
 #include <linux/firmware.h>
 #include <linux/firmware.h>
+#include <linux/wait.h>
+#include <asm/byteorder.h>
 
 
 #include "smscoreapi.h"
 #include "smscoreapi.h"
 #include "sms-cards.h"
 #include "sms-cards.h"
+#include "smsir.h"
+#include "smsendian.h"
 
 
 static int sms_dbg;
 static int sms_dbg;
 module_param_named(debug, sms_dbg, int, 0644);
 module_param_named(debug, sms_dbg, int, 0644);
@@ -58,42 +62,6 @@ struct smscore_client_t {
 	onremove_t		onremove_handler;
 	onremove_t		onremove_handler;
 };
 };
 
 
-struct smscore_device_t {
-	struct list_head entry;
-
-	struct list_head clients;
-	struct list_head subclients;
-	spinlock_t		clientslock;
-
-	struct list_head buffers;
-	spinlock_t		bufferslock;
-	int				num_buffers;
-
-	void			*common_buffer;
-	int				common_buffer_size;
-	dma_addr_t		common_buffer_phys;
-
-	void			*context;
-	struct device	*device;
-
-	char			devpath[32];
-	unsigned long	device_flags;
-
-	setmode_t		setmode_handler;
-	detectmode_t	detectmode_handler;
-	sendrequest_t	sendrequest_handler;
-	preload_t		preload_handler;
-	postload_t		postload_handler;
-
-	int				mode, modes_supported;
-
-	struct completion version_ex_done, data_download_done, trigger_done;
-	struct completion init_device_done, reload_start_done, resume_done;
-
-	int board_id;
-	int led_state;
-};
-
 void smscore_set_board_id(struct smscore_device_t *core, int id)
 void smscore_set_board_id(struct smscore_device_t *core, int id)
 {
 {
 	core->board_id = id;
 	core->board_id = id;
@@ -384,6 +352,13 @@ int smscore_register_device(struct smsdevice_params_t *params,
 	init_completion(&dev->init_device_done);
 	init_completion(&dev->init_device_done);
 	init_completion(&dev->reload_start_done);
 	init_completion(&dev->reload_start_done);
 	init_completion(&dev->resume_done);
 	init_completion(&dev->resume_done);
+	init_completion(&dev->gpio_configuration_done);
+	init_completion(&dev->gpio_set_level_done);
+	init_completion(&dev->gpio_get_level_done);
+	init_completion(&dev->ir_init_done);
+
+	/* Buffer management */
+	init_waitqueue_head(&dev->buffer_mng_waitq);
 
 
 	/* alloc common buffer */
 	/* alloc common buffer */
 	dev->common_buffer_size = params->buffer_size * params->num_buffers;
 	dev->common_buffer_size = params->buffer_size * params->num_buffers;
@@ -439,6 +414,71 @@ int smscore_register_device(struct smsdevice_params_t *params,
 }
 }
 EXPORT_SYMBOL_GPL(smscore_register_device);
 EXPORT_SYMBOL_GPL(smscore_register_device);
 
 
+
+static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
+		void *buffer, size_t size, struct completion *completion) {
+	int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+	if (rc < 0) {
+		sms_info("sendrequest returned error %d", rc);
+		return rc;
+	}
+
+	return wait_for_completion_timeout(completion,
+			msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
+			0 : -ETIME;
+}
+
+/**
+ * Starts & enables IR operations
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int smscore_init_ir(struct smscore_device_t *coredev)
+{
+	int ir_io;
+	int rc;
+	void *buffer;
+
+	coredev->ir.input_dev = NULL;
+	ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
+	if (ir_io) {/* only if IR port exist we use IR sub-module */
+		sms_info("IR loading");
+		rc = sms_ir_init(coredev);
+
+		if	(rc != 0)
+			sms_err("Error initialization DTV IR sub-module");
+		else {
+			buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
+						SMS_DMA_ALIGNMENT,
+						GFP_KERNEL | GFP_DMA);
+			if (buffer) {
+				struct SmsMsgData_ST2 *msg =
+				(struct SmsMsgData_ST2 *)
+				SMS_ALIGN_ADDRESS(buffer);
+
+				SMS_INIT_MSG(&msg->xMsgHeader,
+						MSG_SMS_START_IR_REQ,
+						sizeof(struct SmsMsgData_ST2));
+				msg->msgData[0] = coredev->ir.controller;
+				msg->msgData[1] = coredev->ir.timeout;
+
+				smsendian_handle_tx_message(
+					(struct SmsMsgHdr_ST2 *)msg);
+				rc = smscore_sendrequest_and_wait(coredev, msg,
+						msg->xMsgHeader. msgLength,
+						&coredev->ir_init_done);
+
+				kfree(buffer);
+			} else
+				sms_err
+				("Sending IR initialization message failed");
+		}
+	} else
+		sms_info("IR port has not been detected");
+
+	return 0;
+}
+
 /**
 /**
  * sets initial device mode and notifies client hotplugs that device is ready
  * sets initial device mode and notifies client hotplugs that device is ready
  *
  *
@@ -459,6 +499,7 @@ int smscore_start_device(struct smscore_device_t *coredev)
 	kmutex_lock(&g_smscore_deviceslock);
 	kmutex_lock(&g_smscore_deviceslock);
 
 
 	rc = smscore_notify_callbacks(coredev, coredev->device, 1);
 	rc = smscore_notify_callbacks(coredev, coredev->device, 1);
+	smscore_init_ir(coredev);
 
 
 	sms_info("device %p started, rc %d", coredev, rc);
 	sms_info("device %p started, rc %d", coredev, rc);
 
 
@@ -468,29 +509,19 @@ int smscore_start_device(struct smscore_device_t *coredev)
 }
 }
 EXPORT_SYMBOL_GPL(smscore_start_device);
 EXPORT_SYMBOL_GPL(smscore_start_device);
 
 
-static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
-					void *buffer, size_t size,
-					struct completion *completion)
-{
-	int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
-	if (rc < 0) {
-		sms_info("sendrequest returned error %d", rc);
-		return rc;
-	}
-
-	return wait_for_completion_timeout(completion,
-					   msecs_to_jiffies(10000)) ?
-						0 : -ETIME;
-}
 
 
 static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
 static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
 					 void *buffer, size_t size)
 					 void *buffer, size_t size)
 {
 {
 	struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
 	struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
 	struct SmsMsgHdr_ST *msg;
 	struct SmsMsgHdr_ST *msg;
-	u32 mem_address = firmware->StartAddress;
+	u32 mem_address;
 	u8 *payload = firmware->Payload;
 	u8 *payload = firmware->Payload;
 	int rc = 0;
 	int rc = 0;
+	firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
+	firmware->Length = le32_to_cpu(firmware->Length);
+
+	mem_address = firmware->StartAddress;
 
 
 	sms_info("loading FW to addr 0x%x size %d",
 	sms_info("loading FW to addr 0x%x size %d",
 		 mem_address, firmware->Length);
 		 mem_address, firmware->Length);
@@ -657,6 +688,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
 
 
 	kmutex_lock(&g_smscore_deviceslock);
 	kmutex_lock(&g_smscore_deviceslock);
 
 
+	/* Release input device (IR) resources */
+	sms_ir_exit(coredev);
+
 	smscore_notify_clients(coredev);
 	smscore_notify_clients(coredev);
 	smscore_notify_callbacks(coredev, NULL, 0);
 	smscore_notify_callbacks(coredev, NULL, 0);
 
 
@@ -664,7 +698,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
 	 * onresponse must no longer be called */
 	 * onresponse must no longer be called */
 
 
 	while (1) {
 	while (1) {
-		while ((cb = smscore_getbuffer(coredev))) {
+		while (!list_empty(&coredev->buffers)) {
+			cb = (struct smscore_buffer_t *) coredev->buffers.next;
+			list_del(&cb->entry);
 			kfree(cb);
 			kfree(cb);
 			num_buffers++;
 			num_buffers++;
 		}
 		}
@@ -685,8 +721,10 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
 
 
 	if (coredev->common_buffer)
 	if (coredev->common_buffer)
 		dma_free_coherent(NULL, coredev->common_buffer_size,
 		dma_free_coherent(NULL, coredev->common_buffer_size,
-				  coredev->common_buffer,
-				  coredev->common_buffer_phys);
+			coredev->common_buffer, coredev->common_buffer_phys);
+
+	if (coredev->fw_buf != NULL)
+		kfree(coredev->fw_buf);
 
 
 	list_del(&coredev->entry);
 	list_del(&coredev->entry);
 	kfree(coredev);
 	kfree(coredev);
@@ -746,7 +784,7 @@ static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
 	/*BDA*/
 	/*BDA*/
 	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
 	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
 	/*ISDBT*/
 	/*ISDBT*/
-	{"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
+	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
 	/*ISDBTBDA*/
 	/*ISDBTBDA*/
 	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
 	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
 	/*CMMB*/
 	/*CMMB*/
@@ -870,7 +908,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
 		coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
 		coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
 	}
 	}
 
 
-	if (rc != 0)
+	if (rc < 0)
 		sms_err("return error code %d.", rc);
 		sms_err("return error code %d.", rc);
 	return rc;
 	return rc;
 }
 }
@@ -940,14 +978,11 @@ smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
  *
  *
  */
  */
 void smscore_onresponse(struct smscore_device_t *coredev,
 void smscore_onresponse(struct smscore_device_t *coredev,
-			struct smscore_buffer_t *cb)
-{
-	struct SmsMsgHdr_ST *phdr =
-		(struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
-	struct smscore_client_t *client =
-		smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
+		struct smscore_buffer_t *cb) {
+	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
+			+ cb->offset);
+	struct smscore_client_t *client;
 	int rc = -EBUSY;
 	int rc = -EBUSY;
-
 	static unsigned long last_sample_time; /* = 0; */
 	static unsigned long last_sample_time; /* = 0; */
 	static int data_total; /* = 0; */
 	static int data_total; /* = 0; */
 	unsigned long time_now = jiffies_to_msecs(jiffies);
 	unsigned long time_now = jiffies_to_msecs(jiffies);
@@ -965,6 +1000,16 @@ void smscore_onresponse(struct smscore_device_t *coredev,
 	}
 	}
 
 
 	data_total += cb->size;
 	data_total += cb->size;
+	/* Do we need to re-route? */
+	if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
+			(phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
+		if (coredev->mode == DEVICE_MODE_DVBT_BDA)
+			phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
+	}
+
+
+	client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
+
 	/* If no client registered for type & id,
 	/* If no client registered for type & id,
 	 * check for control client where type is not registered */
 	 * check for control client where type is not registered */
 	if (client)
 	if (client)
@@ -1009,6 +1054,35 @@ void smscore_onresponse(struct smscore_device_t *coredev,
 		case MSG_SMS_SLEEP_RESUME_COMP_IND:
 		case MSG_SMS_SLEEP_RESUME_COMP_IND:
 			complete(&coredev->resume_done);
 			complete(&coredev->resume_done);
 			break;
 			break;
+		case MSG_SMS_GPIO_CONFIG_EX_RES:
+			sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
+			complete(&coredev->gpio_configuration_done);
+			break;
+		case MSG_SMS_GPIO_SET_LEVEL_RES:
+			sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
+			complete(&coredev->gpio_set_level_done);
+			break;
+		case MSG_SMS_GPIO_GET_LEVEL_RES:
+		{
+			u32 *msgdata = (u32 *) phdr;
+			coredev->gpio_get_res = msgdata[1];
+			sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
+					coredev->gpio_get_res);
+			complete(&coredev->gpio_get_level_done);
+			break;
+		}
+		case MSG_SMS_START_IR_RES:
+			complete(&coredev->ir_init_done);
+			break;
+		case MSG_SMS_IR_SAMPLES_IND:
+			sms_ir_event(coredev,
+				(const char *)
+				((char *)phdr
+				+ sizeof(struct SmsMsgHdr_ST)),
+				(int)phdr->msgLength
+				- sizeof(struct SmsMsgHdr_ST));
+			break;
+
 		default:
 		default:
 			break;
 			break;
 		}
 		}
@@ -1030,12 +1104,24 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
 	struct smscore_buffer_t *cb = NULL;
 	struct smscore_buffer_t *cb = NULL;
 	unsigned long flags;
 	unsigned long flags;
 
 
+	DEFINE_WAIT(wait);
+
 	spin_lock_irqsave(&coredev->bufferslock, flags);
 	spin_lock_irqsave(&coredev->bufferslock, flags);
 
 
-	if (!list_empty(&coredev->buffers)) {
-		cb = (struct smscore_buffer_t *) coredev->buffers.next;
-		list_del(&cb->entry);
-	}
+	/* This function must return a valid buffer, since the buffer list is
+	 * finite, we check that there is an available buffer, if not, we wait
+	 * until such buffer become available.
+	 */
+
+	prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
+
+	if (list_empty(&coredev->buffers))
+		schedule();
+
+	finish_wait(&coredev->buffer_mng_waitq, &wait);
+
+	cb = (struct smscore_buffer_t *) coredev->buffers.next;
+	list_del(&cb->entry);
 
 
 	spin_unlock_irqrestore(&coredev->bufferslock, flags);
 	spin_unlock_irqrestore(&coredev->bufferslock, flags);
 
 
@@ -1052,8 +1138,8 @@ EXPORT_SYMBOL_GPL(smscore_getbuffer);
  *
  *
  */
  */
 void smscore_putbuffer(struct smscore_device_t *coredev,
 void smscore_putbuffer(struct smscore_device_t *coredev,
-		       struct smscore_buffer_t *cb)
-{
+		struct smscore_buffer_t *cb) {
+	wake_up_interruptible(&coredev->buffer_mng_waitq);
 	list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
 	list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
 }
 }
 EXPORT_SYMBOL_GPL(smscore_putbuffer);
 EXPORT_SYMBOL_GPL(smscore_putbuffer);
@@ -1210,8 +1296,9 @@ int smsclient_sendrequest(struct smscore_client_t *client,
 EXPORT_SYMBOL_GPL(smsclient_sendrequest);
 EXPORT_SYMBOL_GPL(smsclient_sendrequest);
 
 
 
 
+/* old GPIO managments implementation */
 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
-			   struct smscore_gpio_config *pinconfig)
+			   struct smscore_config_gpio *pinconfig)
 {
 {
 	struct {
 	struct {
 		struct SmsMsgHdr_ST hdr;
 		struct SmsMsgHdr_ST hdr;
@@ -1280,35 +1367,254 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
 					    &msg, sizeof(msg));
 					    &msg, sizeof(msg));
 }
 }
 
 
-static int __init smscore_module_init(void)
-{
-	int rc = 0;
+/* new GPIO managment implementation */
+static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
+		u32 *pGroupNum, u32 *pGroupCfg) {
+
+	*pGroupCfg = 1;
+
+	if (PinNum >= 0 && PinNum <= 1)	{
+		*pTranslatedPinNum = 0;
+		*pGroupNum = 9;
+		*pGroupCfg = 2;
+	} else if (PinNum >= 2 && PinNum <= 6) {
+		*pTranslatedPinNum = 2;
+		*pGroupNum = 0;
+		*pGroupCfg = 2;
+	} else if (PinNum >= 7 && PinNum <= 11) {
+		*pTranslatedPinNum = 7;
+		*pGroupNum = 1;
+	} else if (PinNum >= 12 && PinNum <= 15) {
+		*pTranslatedPinNum = 12;
+		*pGroupNum = 2;
+		*pGroupCfg = 3;
+	} else if (PinNum == 16) {
+		*pTranslatedPinNum = 16;
+		*pGroupNum = 23;
+	} else if (PinNum >= 17 && PinNum <= 24) {
+		*pTranslatedPinNum = 17;
+		*pGroupNum = 3;
+	} else if (PinNum == 25) {
+		*pTranslatedPinNum = 25;
+		*pGroupNum = 6;
+	} else if (PinNum >= 26 && PinNum <= 28) {
+		*pTranslatedPinNum = 26;
+		*pGroupNum = 4;
+	} else if (PinNum == 29) {
+		*pTranslatedPinNum = 29;
+		*pGroupNum = 5;
+		*pGroupCfg = 2;
+	} else if (PinNum == 30) {
+		*pTranslatedPinNum = 30;
+		*pGroupNum = 8;
+	} else if (PinNum == 31) {
+		*pTranslatedPinNum = 31;
+		*pGroupNum = 17;
+	} else
+		return -1;
 
 
-	INIT_LIST_HEAD(&g_smscore_notifyees);
-	INIT_LIST_HEAD(&g_smscore_devices);
-	kmutex_init(&g_smscore_deviceslock);
+	*pGroupCfg <<= 24;
 
 
-	INIT_LIST_HEAD(&g_smscore_registry);
-	kmutex_init(&g_smscore_registrylock);
+	return 0;
+}
+
+int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+		struct smscore_gpio_config *pGpioConfig) {
+
+	u32 totalLen;
+	u32 TranslatedPinNum;
+	u32 GroupNum;
+	u32 ElectricChar;
+	u32 groupCfg;
+	void *buffer;
+	int rc;
+
+	struct SetGpioMsg {
+		struct SmsMsgHdr_ST xMsgHeader;
+		u32 msgData[6];
+	} *pMsg;
+
+
+	if (PinNum > MAX_GPIO_PIN_NUMBER)
+		return -EINVAL;
+
+	if (pGpioConfig == NULL)
+		return -EINVAL;
+
+	totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
+
+	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+			GFP_KERNEL | GFP_DMA);
+	if (!buffer)
+		return -ENOMEM;
+
+	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	pMsg->xMsgHeader.msgDstId = HIF_TASK;
+	pMsg->xMsgHeader.msgFlags = 0;
+	pMsg->xMsgHeader.msgLength = (u16) totalLen;
+	pMsg->msgData[0] = PinNum;
+
+	if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
+		pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
+		if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
+				&groupCfg) != 0)
+			return -EINVAL;
+
+		pMsg->msgData[1] = TranslatedPinNum;
+		pMsg->msgData[2] = GroupNum;
+		ElectricChar = (pGpioConfig->PullUpDown)
+				| (pGpioConfig->InputCharacteristics << 2)
+				| (pGpioConfig->OutputSlewRate << 3)
+				| (pGpioConfig->OutputDriving << 4);
+		pMsg->msgData[3] = ElectricChar;
+		pMsg->msgData[4] = pGpioConfig->Direction;
+		pMsg->msgData[5] = groupCfg;
+	} else {
+		pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
+		pMsg->msgData[1] = pGpioConfig->PullUpDown;
+		pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
+		pMsg->msgData[3] = pGpioConfig->OutputDriving;
+		pMsg->msgData[4] = pGpioConfig->Direction;
+		pMsg->msgData[5] = 0;
+	}
+
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+			&coredev->gpio_configuration_done);
+
+	if (rc != 0) {
+		if (rc == -ETIME)
+			sms_err("smscore_gpio_configure timeout");
+		else
+			sms_err("smscore_gpio_configure error");
+	}
+	kfree(buffer);
+
+	return rc;
+}
+
+int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+		u8 NewLevel) {
+
+	u32 totalLen;
+	int rc;
+	void *buffer;
+
+	struct SetGpioMsg {
+		struct SmsMsgHdr_ST xMsgHeader;
+		u32 msgData[3]; /* keep it 3 ! */
+	} *pMsg;
+
+	if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) ||
+			(PinNum > MAX_GPIO_PIN_NUMBER))
+		return -EINVAL;
 
 
+	totalLen = sizeof(struct SmsMsgHdr_ST) +
+			(3 * sizeof(u32)); /* keep it 3 ! */
 
 
+	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+			GFP_KERNEL | GFP_DMA);
+	if (!buffer)
+		return -ENOMEM;
 
 
+	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
 
 
+	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	pMsg->xMsgHeader.msgDstId = HIF_TASK;
+	pMsg->xMsgHeader.msgFlags = 0;
+	pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
+	pMsg->xMsgHeader.msgLength = (u16) totalLen;
+	pMsg->msgData[0] = PinNum;
+	pMsg->msgData[1] = NewLevel;
 
 
+	/* Send message to SMS */
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+			&coredev->gpio_set_level_done);
+
+	if (rc != 0) {
+		if (rc == -ETIME)
+			sms_err("smscore_gpio_set_level timeout");
+		else
+			sms_err("smscore_gpio_set_level error");
+	}
+	kfree(buffer);
 
 
 	return rc;
 	return rc;
-	sms_debug("rc %d", rc);
+}
+
+int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+		u8 *level) {
+
+	u32 totalLen;
+	int rc;
+	void *buffer;
+
+	struct SetGpioMsg {
+		struct SmsMsgHdr_ST xMsgHeader;
+		u32 msgData[2];
+	} *pMsg;
+
+
+	if (PinNum > MAX_GPIO_PIN_NUMBER)
+		return -EINVAL;
+
+	totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
+
+	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+			GFP_KERNEL | GFP_DMA);
+	if (!buffer)
+		return -ENOMEM;
+
+	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	pMsg->xMsgHeader.msgDstId = HIF_TASK;
+	pMsg->xMsgHeader.msgFlags = 0;
+	pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
+	pMsg->xMsgHeader.msgLength = (u16) totalLen;
+	pMsg->msgData[0] = PinNum;
+	pMsg->msgData[1] = 0;
+
+	/* Send message to SMS */
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+			&coredev->gpio_get_level_done);
+
+	if (rc != 0) {
+		if (rc == -ETIME)
+			sms_err("smscore_gpio_get_level timeout");
+		else
+			sms_err("smscore_gpio_get_level error");
+	}
+	kfree(buffer);
+
+	/* Its a race between other gpio_get_level() and the copy of the single
+	 * global 'coredev->gpio_get_res' to  the function's variable 'level'
+	 */
+	*level = coredev->gpio_get_res;
 
 
 	return rc;
 	return rc;
 }
 }
 
 
-static void __exit smscore_module_exit(void)
+static int __init smscore_module_init(void)
 {
 {
+	int rc = 0;
 
 
+	INIT_LIST_HEAD(&g_smscore_notifyees);
+	INIT_LIST_HEAD(&g_smscore_devices);
+	kmutex_init(&g_smscore_deviceslock);
 
 
+	INIT_LIST_HEAD(&g_smscore_registry);
+	kmutex_init(&g_smscore_registrylock);
 
 
+	return rc;
+}
 
 
-
+static void __exit smscore_module_exit(void)
+{
 	kmutex_lock(&g_smscore_deviceslock);
 	kmutex_lock(&g_smscore_deviceslock);
 	while (!list_empty(&g_smscore_notifyees)) {
 	while (!list_empty(&g_smscore_notifyees)) {
 		struct smscore_device_notifyee_t *notifyee =
 		struct smscore_device_notifyee_t *notifyee =

+ 372 - 116
drivers/media/dvb/siano/smscoreapi.h

@@ -1,26 +1,26 @@
-/*
- *  Driver for the Siano SMS1xxx USB dongle
- *
- *  author: Anatoly Greenblat
- *
- *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  See the GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __smscoreapi_h__
-#define __smscoreapi_h__
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_CORE_API_H__
+#define __SMS_CORE_API_H__
 
 
 #include <linux/version.h>
 #include <linux/version.h>
 #include <linux/device.h>
 #include <linux/device.h>
@@ -28,14 +28,13 @@
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
 #include <linux/types.h>
 #include <linux/types.h>
-#include <asm/page.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
 
 
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
+#include <asm/page.h>
 
 
+#include "smsir.h"
 
 
 #define kmutex_init(_p_) mutex_init(_p_)
 #define kmutex_init(_p_) mutex_init(_p_)
 #define kmutex_lock(_p_) mutex_lock(_p_)
 #define kmutex_lock(_p_) mutex_lock(_p_)
@@ -46,13 +45,14 @@
 #define min(a, b) (((a) < (b)) ? (a) : (b))
 #define min(a, b) (((a) < (b)) ? (a) : (b))
 #endif
 #endif
 
 
-#define SMS_ALLOC_ALIGNMENT					128
-#define SMS_DMA_ALIGNMENT					16
+#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS			(10000)
+#define SMS_ALLOC_ALIGNMENT				128
+#define SMS_DMA_ALIGNMENT				16
 #define SMS_ALIGN_ADDRESS(addr) \
 #define SMS_ALIGN_ADDRESS(addr) \
 	((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
 	((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
 
 
-#define SMS_DEVICE_FAMILY2					1
-#define SMS_ROM_NO_RESPONSE					2
+#define SMS_DEVICE_FAMILY2				1
+#define SMS_ROM_NO_RESPONSE				2
 #define SMS_DEVICE_NOT_READY				0x8000000
 #define SMS_DEVICE_NOT_READY				0x8000000
 
 
 enum sms_device_type_st {
 enum sms_device_type_st {
@@ -83,13 +83,13 @@ typedef void (*onremove_t)(void *context);
 struct smscore_buffer_t {
 struct smscore_buffer_t {
 	/* public members, once passed to clients can be changed freely */
 	/* public members, once passed to clients can be changed freely */
 	struct list_head entry;
 	struct list_head entry;
-	int				size;
-	int				offset;
+	int size;
+	int offset;
 
 
 	/* private members, read-only for clients */
 	/* private members, read-only for clients */
-	void			*p;
-	dma_addr_t		phys;
-	unsigned long	offset_in_common;
+	void *p;
+	dma_addr_t phys;
+	unsigned long offset_in_common;
 };
 };
 
 
 struct smsdevice_params_t {
 struct smsdevice_params_t {
@@ -116,10 +116,63 @@ struct smsclient_params_t {
 	int				data_type;
 	int				data_type;
 	onresponse_t	onresponse_handler;
 	onresponse_t	onresponse_handler;
 	onremove_t		onremove_handler;
 	onremove_t		onremove_handler;
-
 	void			*context;
 	void			*context;
 };
 };
 
 
+struct smscore_device_t {
+	struct list_head entry;
+
+	struct list_head clients;
+	struct list_head subclients;
+	spinlock_t clientslock;
+
+	struct list_head buffers;
+	spinlock_t bufferslock;
+	int num_buffers;
+
+	void *common_buffer;
+	int common_buffer_size;
+	dma_addr_t common_buffer_phys;
+
+	void *context;
+	struct device *device;
+
+	char devpath[32];
+	unsigned long device_flags;
+
+	setmode_t setmode_handler;
+	detectmode_t detectmode_handler;
+	sendrequest_t sendrequest_handler;
+	preload_t preload_handler;
+	postload_t postload_handler;
+
+	int mode, modes_supported;
+
+	/* host <--> device messages */
+	struct completion version_ex_done, data_download_done, trigger_done;
+	struct completion init_device_done, reload_start_done, resume_done;
+	struct completion gpio_configuration_done, gpio_set_level_done;
+	struct completion gpio_get_level_done, ir_init_done;
+
+	/* Buffer management */
+	wait_queue_head_t buffer_mng_waitq;
+
+	/* GPIO */
+	int gpio_get_res;
+
+	/* Target hardware board */
+	int board_id;
+
+	/* Firmware */
+	u8 *fw_buf;
+	u32 fw_buf_size;
+
+	/* Infrared (IR) */
+	struct ir_t ir;
+
+	int led_state;
+};
+
 /* GPIO definitions for antenna frequency domain control (SMS8021) */
 /* GPIO definitions for antenna frequency domain control (SMS8021) */
 #define SMS_ANTENNA_GPIO_0					1
 #define SMS_ANTENNA_GPIO_0					1
 #define SMS_ANTENNA_GPIO_1					0
 #define SMS_ANTENNA_GPIO_1					0
@@ -154,18 +207,15 @@ struct smsclient_params_t {
 #define MSG_SMS_INIT_DEVICE_RES				579
 #define MSG_SMS_INIT_DEVICE_RES				579
 #define MSG_SMS_ADD_PID_FILTER_REQ			601
 #define MSG_SMS_ADD_PID_FILTER_REQ			601
 #define MSG_SMS_ADD_PID_FILTER_RES			602
 #define MSG_SMS_ADD_PID_FILTER_RES			602
-#define MSG_SMS_REMOVE_PID_FILTER_REQ		603
-#define MSG_SMS_REMOVE_PID_FILTER_RES		604
-#define MSG_SMS_DAB_CHANNEL					607
-#define MSG_SMS_GET_PID_FILTER_LIST_REQ		608
-#define MSG_SMS_GET_PID_FILTER_LIST_RES		609
-#define MSG_SMS_GET_STATISTICS_REQ			615
-#define MSG_SMS_GET_STATISTICS_RES			616
-#define MSG_SMS_SET_ANTENNA_CONFIG_REQ		651
-#define MSG_SMS_SET_ANTENNA_CONFIG_RES		652
-#define MSG_SMS_GET_STATISTICS_EX_REQ		653
-#define MSG_SMS_GET_STATISTICS_EX_RES		654
-#define MSG_SMS_SLEEP_RESUME_COMP_IND		655
+#define MSG_SMS_REMOVE_PID_FILTER_REQ			603
+#define MSG_SMS_REMOVE_PID_FILTER_RES			604
+#define MSG_SMS_DAB_CHANNEL				607
+#define MSG_SMS_GET_PID_FILTER_LIST_REQ			608
+#define MSG_SMS_GET_PID_FILTER_LIST_RES			609
+#define MSG_SMS_HO_PER_SLICES_IND			630
+#define MSG_SMS_SET_ANTENNA_CONFIG_REQ			651
+#define MSG_SMS_SET_ANTENNA_CONFIG_RES			652
+#define MSG_SMS_SLEEP_RESUME_COMP_IND			655
 #define MSG_SMS_DATA_DOWNLOAD_REQ			660
 #define MSG_SMS_DATA_DOWNLOAD_REQ			660
 #define MSG_SMS_DATA_DOWNLOAD_RES			661
 #define MSG_SMS_DATA_DOWNLOAD_RES			661
 #define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ		664
 #define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ		664
@@ -190,14 +240,31 @@ struct smsclient_params_t {
 #define MSG_SMS_GPIO_CONFIG_EX_RES			713
 #define MSG_SMS_GPIO_CONFIG_EX_RES			713
 #define MSG_SMS_ISDBT_TUNE_REQ				776
 #define MSG_SMS_ISDBT_TUNE_REQ				776
 #define MSG_SMS_ISDBT_TUNE_RES				777
 #define MSG_SMS_ISDBT_TUNE_RES				777
+#define MSG_SMS_TRANSMISSION_IND			782
+#define MSG_SMS_START_IR_REQ				800
+#define MSG_SMS_START_IR_RES				801
+#define MSG_SMS_IR_SAMPLES_IND				802
+#define MSG_SMS_SIGNAL_DETECTED_IND			827
+#define MSG_SMS_NO_SIGNAL_IND				828
 
 
 #define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
 #define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
 	(ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
 	(ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
 	(ptr)->msgLength = len; (ptr)->msgFlags = 0; \
 	(ptr)->msgLength = len; (ptr)->msgFlags = 0; \
 } while (0)
 } while (0)
+
 #define SMS_INIT_MSG(ptr, type, len) \
 #define SMS_INIT_MSG(ptr, type, len) \
 	SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
 	SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
 
 
+enum SMS_DVB3_EVENTS {
+	DVB3_EVENT_INIT = 0,
+	DVB3_EVENT_SLEEP,
+	DVB3_EVENT_HOTPLUG,
+	DVB3_EVENT_FE_LOCK,
+	DVB3_EVENT_FE_UNLOCK,
+	DVB3_EVENT_UNC_OK,
+	DVB3_EVENT_UNC_ERR
+};
+
 enum SMS_DEVICE_MODE {
 enum SMS_DEVICE_MODE {
 	DEVICE_MODE_NONE = -1,
 	DEVICE_MODE_NONE = -1,
 	DEVICE_MODE_DVBT = 0,
 	DEVICE_MODE_DVBT = 0,
@@ -221,8 +288,13 @@ struct SmsMsgHdr_ST {
 };
 };
 
 
 struct SmsMsgData_ST {
 struct SmsMsgData_ST {
-	struct SmsMsgHdr_ST	xMsgHeader;
-	u32			msgData[1];
+	struct SmsMsgHdr_ST xMsgHeader;
+	u32 msgData[1];
+};
+
+struct SmsMsgData_ST2 {
+	struct SmsMsgHdr_ST xMsgHeader;
+	u32 msgData[2];
 };
 };
 
 
 struct SmsDataDownload_ST {
 struct SmsDataDownload_ST {
@@ -238,11 +310,12 @@ struct SmsVersionRes_ST {
 	u8		Step; /* 0 - Step A */
 	u8		Step; /* 0 - Step A */
 	u8		MetalFix; /* 0 - Metal 0 */
 	u8		MetalFix; /* 0 - Metal 0 */
 
 
-	u8		FirmwareId; /* 0xFF � ROM, otherwise the
-				     * value indicated by
-				     * SMSHOSTLIB_DEVICE_MODES_E */
-	u8		SupportedProtocols; /* Bitwise OR combination of
+	/* FirmwareId 0xFF if ROM, otherwise the
+	 * value indicated by SMSHOSTLIB_DEVICE_MODES_E */
+	u8 FirmwareId;
+	/* SupportedProtocols Bitwise OR combination of
 					     * supported protocols */
 					     * supported protocols */
+	u8 SupportedProtocols;
 
 
 	u8		VersionMajor;
 	u8		VersionMajor;
 	u8		VersionMinor;
 	u8		VersionMinor;
@@ -264,86 +337,219 @@ struct SmsFirmware_ST {
 	u8			Payload[1];
 	u8			Payload[1];
 };
 };
 
 
-struct SMSHOSTLIB_STATISTICS_ST {
-	u32 Reserved; /* Reserved */
+/* Statistics information returned as response for
+ * SmsHostApiGetStatistics_Req */
+struct SMSHOSTLIB_STATISTICS_S {
+	u32 Reserved;		/* Reserved */
 
 
 	/* Common parameters */
 	/* Common parameters */
-	u32 IsRfLocked; /* 0 - not locked, 1 - locked */
-	u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
-	u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+	u32 IsRfLocked;		/* 0 - not locked, 1 - locked */
+	u32 IsDemodLocked;	/* 0 - not locked, 1 - locked */
+	u32 IsExternalLNAOn;	/* 0 - external LNA off, 1 - external LNA on */
 
 
 	/* Reception quality */
 	/* Reception quality */
-	s32  SNR; /* dB */
-	u32 BER; /* Post Viterbi BER [1E-5] */
-	u32 FIB_CRC;	/* CRC errors percentage, valid only for DAB */
-	u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A,
-		     * valid only for DVB-T/H */
-	u32 MFER; /* DVB-H frame error rate in percentage,
-		   * 0xFFFFFFFF indicate N/A, valid only for DVB-H */
-	s32  RSSI; /* dBm */
-	s32  InBandPwr; /* In band power in dBM */
-	s32  CarrierOffset; /* Carrier Offset in bin/1024 */
-
-	/* Transmission parameters, valid only for DVB-T/H */
-	u32 Frequency; /* Frequency in Hz */
-	u32 Bandwidth; /* Bandwidth in MHz */
-	u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
-			       * for DVB-T/H FFT mode carriers in Kilos */
-	u32 ModemState; /* from SMS_DvbModemState_ET */
-	u32 GuardInterval; /* Guard Interval, 1 divided by value */
-	u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */
-	u32 LPCodeRate; /* Low Priority Code Rate from SMS_DvbModemState_ET */
-	u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */
-	u32 Constellation; /* Constellation from SMS_Constellation_ET */
+	s32 SNR;		/* dB */
+	u32 BER;		/* Post Viterbi BER [1E-5] */
+	u32 FIB_CRC;		/* CRC errors percentage, valid only for DAB */
+	u32 TS_PER;		/* Transport stream PER,
+	0xFFFFFFFF indicate N/A, valid only for DVB-T/H */
+	u32 MFER;		/* DVB-H frame error rate in percentage,
+	0xFFFFFFFF indicate N/A, valid only for DVB-H */
+	s32 RSSI;		/* dBm */
+	s32 InBandPwr;		/* In band power in dBM */
+	s32 CarrierOffset;	/* Carrier Offset in bin/1024 */
+
+	/* Transmission parameters */
+	u32 Frequency;		/* Frequency in Hz */
+	u32 Bandwidth;		/* Bandwidth in MHz, valid only for DVB-T/H */
+	u32 TransmissionMode;	/* Transmission Mode, for DAB modes 1-4,
+	for DVB-T/H FFT mode carriers in Kilos */
+	u32 ModemState;		/* from SMSHOSTLIB_DVB_MODEM_STATE_ET,
+	valid only for DVB-T/H */
+	u32 GuardInterval;	/* Guard Interval from
+	SMSHOSTLIB_GUARD_INTERVALS_ET, 	valid only for DVB-T/H */
+	u32 CodeRate;		/* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+	valid only for DVB-T/H */
+	u32 LPCodeRate;		/* Low Priority Code Rate from
+	SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */
+	u32 Hierarchy;		/* Hierarchy from SMSHOSTLIB_HIERARCHY_ET,
+	valid only for DVB-T/H */
+	u32 Constellation;	/* Constellation from
+	SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */
 
 
 	/* Burst parameters, valid only for DVB-H */
 	/* Burst parameters, valid only for DVB-H */
-	u32 BurstSize; /* Current burst size in bytes */
-	u32 BurstDuration; /* Current burst duration in mSec */
-	u32 BurstCycleTime; /* Current burst cycle time in mSec */
-	u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec,
-				       * as calculated by demodulator */
-	u32 NumOfRows; /* Number of rows in MPE table */
-	u32 NumOfPaddCols; /* Number of padding columns in MPE table */
-	u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */
-	/* Burst parameters */
-	u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
-	u32 TotalTSPackets; /* Total number of transport-stream packets */
-	u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
-				* errors after MPE RS decoding */
-	u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include errors
-				  * after MPE RS decoding */
-	u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected
-				    * by MPE RS decoding */
-
+	u32 BurstSize;		/* Current burst size in bytes,
+	valid only for DVB-H */
+	u32 BurstDuration;	/* Current burst duration in mSec,
+	valid only for DVB-H */
+	u32 BurstCycleTime;	/* Current burst cycle time in mSec,
+	valid only for DVB-H */
+	u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec,
+	as calculated by demodulator, valid only for DVB-H */
+	u32 NumOfRows;		/* Number of rows in MPE table,
+	valid only for DVB-H */
+	u32 NumOfPaddCols;	/* Number of padding columns in MPE table,
+	valid only for DVB-H */
+	u32 NumOfPunctCols;	/* Number of puncturing columns in MPE table,
+	valid only for DVB-H */
+	u32 ErrorTSPackets;	/* Number of erroneous
+	transport-stream packets */
+	u32 TotalTSPackets;	/* Total number of transport-stream packets */
+	u32 NumOfValidMpeTlbs;	/* Number of MPE tables which do not include
+	errors after MPE RS decoding */
+	u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors
+	after MPE RS decoding */
+	u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were
+	corrected by MPE RS decoding */
 	/* Common params */
 	/* Common params */
-	u32 BERErrorCount; /* Number of errornous SYNC bits. */
-	u32 BERBitCount; /* Total number of SYNC bits. */
+	u32 BERErrorCount;	/* Number of errornous SYNC bits. */
+	u32 BERBitCount;	/* Total number of SYNC bits. */
 
 
 	/* Interface information */
 	/* Interface information */
-	u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+	u32 SmsToHostTxErrors;	/* Total number of transmission errors. */
 
 
 	/* DAB/T-DMB */
 	/* DAB/T-DMB */
-	u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
+	u32 PreBER; 		/* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
 
 
 	/* DVB-H TPS parameters */
 	/* DVB-H TPS parameters */
-	u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
-		     * if set to 0xFFFFFFFF cell_id not yet recovered */
+	u32 CellId;		/* TPS Cell ID in bits 15..0, bits 31..16 zero;
+	 if set to 0xFFFFFFFF cell_id not yet recovered */
+	u32 DvbhSrvIndHP;	/* DVB-H service indication info, bit 1 -
+	Time Slicing indicator, bit 0 - MPE-FEC indicator */
+	u32 DvbhSrvIndLP;	/* DVB-H service indication info, bit 1 -
+	Time Slicing indicator, bit 0 - MPE-FEC indicator */
 
 
+	u32 NumMPEReceived;	/* DVB-H, Num MPE section received */
+
+	u32 ReservedFields[10];	/* Reserved */
 };
 };
 
 
-struct SmsMsgStatisticsInfo_ST {
-	u32 RequestResult;
+struct PID_STATISTICS_DATA_S {
+	struct PID_BURST_S {
+		u32 size;
+		u32 padding_cols;
+		u32 punct_cols;
+		u32 duration;
+		u32 cycle;
+		u32 calc_cycle;
+	} burst;
+
+	u32 tot_tbl_cnt;
+	u32 invalid_tbl_cnt;
+	u32 tot_cor_tbl;
+};
 
 
-	struct SMSHOSTLIB_STATISTICS_ST Stat;
+struct PID_DATA_S {
+	u32 pid;
+	u32 num_rows;
+	struct PID_STATISTICS_DATA_S pid_statistics;
+};
 
 
-	/* Split the calc of the SNR in DAB */
-	u32 Signal; /* dB */
-	u32 Noise; /* dB */
+#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1)
+#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth)
+#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \
+	if (_stat.TransmissionMode == 0) \
+		_stat.TransmissionMode = 2; \
+	else if (_stat.TransmissionMode == 1) \
+		_stat.TransmissionMode = 8; \
+		else \
+			_stat.TransmissionMode = 4;
+
+struct TRANSMISSION_STATISTICS_S {
+	u32 Frequency;		/* Frequency in Hz */
+	u32 Bandwidth;		/* Bandwidth in MHz */
+	u32 TransmissionMode;	/* FFT mode carriers in Kilos */
+	u32 GuardInterval;	/* Guard Interval from
+	SMSHOSTLIB_GUARD_INTERVALS_ET */
+	u32 CodeRate;		/* Code Rate from SMSHOSTLIB_CODE_RATE_ET */
+	u32 LPCodeRate;		/* Low Priority Code Rate from
+	SMSHOSTLIB_CODE_RATE_ET */
+	u32 Hierarchy;		/* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */
+	u32 Constellation;	/* Constellation from
+	SMSHOSTLIB_CONSTELLATION_ET */
 
 
+	/* DVB-H TPS parameters */
+	u32 CellId;		/* TPS Cell ID in bits 15..0, bits 31..16 zero;
+	 if set to 0xFFFFFFFF cell_id not yet recovered */
+	u32 DvbhSrvIndHP;	/* DVB-H service indication info, bit 1 -
+	 Time Slicing indicator, bit 0 - MPE-FEC indicator */
+	u32 DvbhSrvIndLP;	/* DVB-H service indication info, bit 1 -
+	 Time Slicing indicator, bit 0 - MPE-FEC indicator */
+	u32 IsDemodLocked;	/* 0 - not locked, 1 - locked */
 };
 };
 
 
+struct RECEPTION_STATISTICS_S {
+	u32 IsRfLocked;		/* 0 - not locked, 1 - locked */
+	u32 IsDemodLocked;	/* 0 - not locked, 1 - locked */
+	u32 IsExternalLNAOn;	/* 0 - external LNA off, 1 - external LNA on */
+
+	u32 ModemState;		/* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
+	s32 SNR;		/* dB */
+	u32 BER;		/* Post Viterbi BER [1E-5] */
+	u32 BERErrorCount;	/* Number of erronous SYNC bits. */
+	u32 BERBitCount;	/* Total number of SYNC bits. */
+	u32 TS_PER;		/* Transport stream PER,
+	0xFFFFFFFF indicate N/A */
+	u32 MFER;		/* DVB-H frame error rate in percentage,
+	0xFFFFFFFF indicate N/A, valid only for DVB-H */
+	s32 RSSI;		/* dBm */
+	s32 InBandPwr;		/* In band power in dBM */
+	s32 CarrierOffset;	/* Carrier Offset in bin/1024 */
+	u32 ErrorTSPackets;	/* Number of erroneous
+	transport-stream packets */
+	u32 TotalTSPackets;	/* Total number of transport-stream packets */
+
+	s32 MRC_SNR;		/* dB */
+	s32 MRC_RSSI;		/* dBm */
+	s32 MRC_InBandPwr;	/* In band power in dBM */
+};
 
 
-struct smscore_gpio_config {
+
+/* Statistics information returned as response for
+ * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */
+struct SMSHOSTLIB_STATISTICS_DVB_S {
+	/* Reception */
+	struct RECEPTION_STATISTICS_S ReceptionData;
+
+	/* Transmission parameters */
+	struct TRANSMISSION_STATISTICS_S TransmissionData;
+
+	/* Burst parameters, valid only for DVB-H */
+#define	SRVM_MAX_PID_FILTERS 8
+	struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS];
+};
+
+struct SRVM_SIGNAL_STATUS_S {
+	u32 result;
+	u32 snr;
+	u32 tsPackets;
+	u32 etsPackets;
+	u32 constellation;
+	u32 hpCode;
+	u32 tpsSrvIndLP;
+	u32 tpsSrvIndHP;
+	u32 cellId;
+	u32 reason;
+
+	s32 inBandPower;
+	u32 requestId;
+};
+
+struct SMSHOSTLIB_I2C_REQ_ST {
+	u32	DeviceAddress; /* I2c device address */
+	u32	WriteCount; /* number of bytes to write */
+	u32	ReadCount; /* number of bytes to read */
+	u8	Data[1];
+};
+
+struct SMSHOSTLIB_I2C_RES_ST {
+	u32	Status; /* non-zero value in case of failure */
+	u32	ReadCount; /* number of bytes read */
+	u8	Data[1];
+};
+
+
+struct smscore_config_gpio {
 #define SMS_GPIO_DIRECTION_INPUT  0
 #define SMS_GPIO_DIRECTION_INPUT  0
 #define SMS_GPIO_DIRECTION_OUTPUT 1
 #define SMS_GPIO_DIRECTION_OUTPUT 1
 	u8 direction;
 	u8 direction;
@@ -369,6 +575,47 @@ struct smscore_gpio_config {
 	u8 outputdriving;
 	u8 outputdriving;
 };
 };
 
 
+struct smscore_gpio_config {
+#define SMS_GPIO_DIRECTION_INPUT  0
+#define SMS_GPIO_DIRECTION_OUTPUT 1
+	u8 Direction;
+
+#define SMS_GPIO_PULL_UP_DOWN_NONE     0
+#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1
+#define SMS_GPIO_PULL_UP_DOWN_PULLUP   2
+#define SMS_GPIO_PULL_UP_DOWN_KEEPER   3
+	u8 PullUpDown;
+
+#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL  0
+#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1
+	u8 InputCharacteristics;
+
+#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW		1 /* 10xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST		0 /* 10xx */
+
+
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS	0 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS	1 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS	2 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS	3 /* 11xx */
+	u8 OutputSlewRate;
+
+#define SMS_GPIO_OUTPUT_DRIVING_S_4mA		0 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_8mA		1 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_12mA		2 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_16mA		3 /* 10xx */
+
+#define SMS_GPIO_OUTPUT_DRIVING_1_5mA		0 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_2_8mA		1 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_4mA		2 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_7mA		3 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_10mA		4 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_11mA		5 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_14mA		6 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_16mA		7 /* 11xx */
+	u8 OutputDriving;
+};
+
 extern void smscore_registry_setmode(char *devpath, int mode);
 extern void smscore_registry_setmode(char *devpath, int mode);
 extern int smscore_registry_getmode(char *devpath);
 extern int smscore_registry_getmode(char *devpath);
 
 
@@ -410,10 +657,19 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
 extern void smscore_putbuffer(struct smscore_device_t *coredev,
 extern void smscore_putbuffer(struct smscore_device_t *coredev,
 			      struct smscore_buffer_t *cb);
 			      struct smscore_buffer_t *cb);
 
 
+/* old GPIO managment */
 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
-			   struct smscore_gpio_config *pinconfig);
+			   struct smscore_config_gpio *pinconfig);
 int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
 int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
 
 
+/* new GPIO managment */
+extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+		struct smscore_gpio_config *pGpioConfig);
+extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+		u8 NewLevel);
+extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+		u8 *level);
+
 void smscore_set_board_id(struct smscore_device_t *core, int id);
 void smscore_set_board_id(struct smscore_device_t *core, int id);
 int smscore_get_board_id(struct smscore_device_t *core);
 int smscore_get_board_id(struct smscore_device_t *core);
 
 
@@ -442,4 +698,4 @@ int smscore_led_state(struct smscore_device_t *core, int led);
 	dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
 	dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
 
 
 
 
-#endif /* __smscoreapi_h__ */
+#endif /* __SMS_CORE_API_H__ */

+ 237 - 135
drivers/media/dvb/siano/smsdvb.c

@@ -1,28 +1,34 @@
-/*
- *  Driver for the Siano SMS1xxx USB dongle
- *
- *  Author: Uri Shkolni
- *
- *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  See the GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
 
 
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/init.h>
 
 
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
 #include "smscoreapi.h"
 #include "smscoreapi.h"
+#include "smsendian.h"
 #include "sms-cards.h"
 #include "sms-cards.h"
 
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -39,12 +45,15 @@ struct smsdvb_client_t {
 	struct dvb_frontend     frontend;
 	struct dvb_frontend     frontend;
 
 
 	fe_status_t             fe_status;
 	fe_status_t             fe_status;
-	int                     fe_ber, fe_snr, fe_unc, fe_signal_strength;
 
 
-	struct completion       tune_done, stat_done;
+	struct completion       tune_done;
 
 
 	/* todo: save freq/band instead whole struct */
 	/* todo: save freq/band instead whole struct */
 	struct dvb_frontend_parameters fe_params;
 	struct dvb_frontend_parameters fe_params;
+
+	struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
+	int event_fe_state;
+	int event_unc_state;
 };
 };
 
 
 static struct list_head g_smsdvb_clients;
 static struct list_head g_smsdvb_clients;
@@ -54,11 +63,69 @@ static int sms_dbg;
 module_param_named(debug, sms_dbg, int, 0644);
 module_param_named(debug, sms_dbg, int, 0644);
 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
 
 
+/* Events that may come from DVB v3 adapter */
+static void sms_board_dvb3_event(struct smsdvb_client_t *client,
+		enum SMS_DVB3_EVENTS event) {
+
+	struct smscore_device_t *coredev = client->coredev;
+	switch (event) {
+	case DVB3_EVENT_INIT:
+		sms_debug("DVB3_EVENT_INIT");
+		sms_board_event(coredev, BOARD_EVENT_BIND);
+		break;
+	case DVB3_EVENT_SLEEP:
+		sms_debug("DVB3_EVENT_SLEEP");
+		sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
+		break;
+	case DVB3_EVENT_HOTPLUG:
+		sms_debug("DVB3_EVENT_HOTPLUG");
+		sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
+		break;
+	case DVB3_EVENT_FE_LOCK:
+		if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
+			client->event_fe_state = DVB3_EVENT_FE_LOCK;
+			sms_debug("DVB3_EVENT_FE_LOCK");
+			sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
+		}
+		break;
+	case DVB3_EVENT_FE_UNLOCK:
+		if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
+			client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
+			sms_debug("DVB3_EVENT_FE_UNLOCK");
+			sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
+		}
+		break;
+	case DVB3_EVENT_UNC_OK:
+		if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
+			client->event_unc_state = DVB3_EVENT_UNC_OK;
+			sms_debug("DVB3_EVENT_UNC_OK");
+			sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
+		}
+		break;
+	case DVB3_EVENT_UNC_ERR:
+		if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
+			client->event_unc_state = DVB3_EVENT_UNC_ERR;
+			sms_debug("DVB3_EVENT_UNC_ERR");
+			sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
+		}
+		break;
+
+	default:
+		sms_err("Unknown dvb3 api event");
+		break;
+	}
+}
+
 static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 {
 {
 	struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
 	struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
-	struct SmsMsgHdr_ST *phdr =
-		(struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset);
+	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
+			+ cb->offset);
+	u32 *pMsgData = (u32 *) phdr + 1;
+	/*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
+	bool is_status_update = false;
+
+	smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
 
 
 	switch (phdr->msgType) {
 	switch (phdr->msgType) {
 	case MSG_SMS_DVBT_BDA_DATA:
 	case MSG_SMS_DVBT_BDA_DATA:
@@ -70,43 +137,110 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 		complete(&client->tune_done);
 		complete(&client->tune_done);
 		break;
 		break;
 
 
-	case MSG_SMS_GET_STATISTICS_RES:
-	{
-		struct SmsMsgStatisticsInfo_ST *p =
-			(struct SmsMsgStatisticsInfo_ST *)(phdr + 1);
-
-		if (p->Stat.IsDemodLocked) {
-			client->fe_status = FE_HAS_SIGNAL |
-					    FE_HAS_CARRIER |
-					    FE_HAS_VITERBI |
-					    FE_HAS_SYNC |
-					    FE_HAS_LOCK;
-
-			client->fe_snr = p->Stat.SNR;
-			client->fe_ber = p->Stat.BER;
-			client->fe_unc = p->Stat.BERErrorCount;
-
-			if (p->Stat.InBandPwr < -95)
-				client->fe_signal_strength = 0;
-			else if (p->Stat.InBandPwr > -29)
-				client->fe_signal_strength = 100;
-			else
-				client->fe_signal_strength =
-					(p->Stat.InBandPwr + 95) * 3 / 2;
+	case MSG_SMS_SIGNAL_DETECTED_IND:
+		sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
+		client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
+		is_status_update = true;
+		break;
+
+	case MSG_SMS_NO_SIGNAL_IND:
+		sms_info("MSG_SMS_NO_SIGNAL_IND");
+		client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
+		is_status_update = true;
+		break;
+
+	case MSG_SMS_TRANSMISSION_IND: {
+		sms_info("MSG_SMS_TRANSMISSION_IND");
+
+		pMsgData++;
+		memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
+				sizeof(struct TRANSMISSION_STATISTICS_S));
+
+		/* Mo need to correct guard interval
+		 * (as opposed to old statistics message).
+		 */
+		CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
+		CORRECT_STAT_TRANSMISSON_MODE(
+				client->sms_stat_dvb.TransmissionData);
+		is_status_update = true;
+		break;
+	}
+	case MSG_SMS_HO_PER_SLICES_IND: {
+		struct RECEPTION_STATISTICS_S *pReceptionData =
+				&client->sms_stat_dvb.ReceptionData;
+		struct SRVM_SIGNAL_STATUS_S SignalStatusData;
+
+		/*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
+		pMsgData++;
+		SignalStatusData.result = pMsgData[0];
+		SignalStatusData.snr = pMsgData[1];
+		SignalStatusData.inBandPower = (s32) pMsgData[2];
+		SignalStatusData.tsPackets = pMsgData[3];
+		SignalStatusData.etsPackets = pMsgData[4];
+		SignalStatusData.constellation = pMsgData[5];
+		SignalStatusData.hpCode = pMsgData[6];
+		SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
+		SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
+		SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
+		SignalStatusData.reason = pMsgData[10];
+		SignalStatusData.requestId = pMsgData[11];
+		pReceptionData->IsRfLocked = pMsgData[16];
+		pReceptionData->IsDemodLocked = pMsgData[17];
+		pReceptionData->ModemState = pMsgData[12];
+		pReceptionData->SNR = pMsgData[1];
+		pReceptionData->BER = pMsgData[13];
+		pReceptionData->RSSI = pMsgData[14];
+		CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
+
+		pReceptionData->InBandPwr = (s32) pMsgData[2];
+		pReceptionData->CarrierOffset = (s32) pMsgData[15];
+		pReceptionData->TotalTSPackets = pMsgData[3];
+		pReceptionData->ErrorTSPackets = pMsgData[4];
+
+		/* TS PER */
+		if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
+				> 0) {
+			pReceptionData->TS_PER = (SignalStatusData.etsPackets
+					* 100) / (SignalStatusData.tsPackets
+					+ SignalStatusData.etsPackets);
 		} else {
 		} else {
-			client->fe_status = 0;
-			client->fe_snr =
-			client->fe_ber =
-			client->fe_unc =
-			client->fe_signal_strength = 0;
+			pReceptionData->TS_PER = 0;
 		}
 		}
 
 
-		complete(&client->stat_done);
-		break;
-	} }
+		pReceptionData->BERBitCount = pMsgData[18];
+		pReceptionData->BERErrorCount = pMsgData[19];
 
 
+		pReceptionData->MRC_SNR = pMsgData[20];
+		pReceptionData->MRC_InBandPwr = pMsgData[21];
+		pReceptionData->MRC_RSSI = pMsgData[22];
+
+		is_status_update = true;
+		break;
+	}
+	}
 	smscore_putbuffer(client->coredev, cb);
 	smscore_putbuffer(client->coredev, cb);
 
 
+	if (is_status_update) {
+		if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
+			client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
+				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+			sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
+			if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
+					== 0)
+				sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
+			else
+				sms_board_dvb3_event(client,
+						DVB3_EVENT_UNC_ERR);
+
+		} else {
+			/*client->fe_status =
+				(phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ?
+				0 : FE_HAS_SIGNAL;*/
+			client->fe_status = 0;
+			sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
+		}
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -149,6 +283,7 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed)
 	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
 	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
 	PidMsg.msgData[0] = feed->pid;
 	PidMsg.msgData[0] = feed->pid;
 
 
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
 	return smsclient_sendrequest(client->smsclient,
 	return smsclient_sendrequest(client->smsclient,
 				     &PidMsg, sizeof(PidMsg));
 				     &PidMsg, sizeof(PidMsg));
 }
 }
@@ -169,6 +304,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
 	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
 	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
 	PidMsg.msgData[0] = feed->pid;
 	PidMsg.msgData[0] = feed->pid;
 
 
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
 	return smsclient_sendrequest(client->smsclient,
 	return smsclient_sendrequest(client->smsclient,
 				     &PidMsg, sizeof(PidMsg));
 				     &PidMsg, sizeof(PidMsg));
 }
 }
@@ -177,7 +313,10 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
 					void *buffer, size_t size,
 					void *buffer, size_t size,
 					struct completion *completion)
 					struct completion *completion)
 {
 {
-	int rc = smsclient_sendrequest(client->smsclient, buffer, size);
+	int rc;
+
+	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
+	rc = smsclient_sendrequest(client->smsclient, buffer, size);
 	if (rc < 0)
 	if (rc < 0)
 		return rc;
 		return rc;
 
 
@@ -186,83 +325,61 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
 						0 : -ETIME;
 						0 : -ETIME;
 }
 }
 
 
-static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
-{
-	struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
-			     DVBT_BDA_CONTROL_MSG_ID,
-			     HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
-	int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-					      &client->stat_done);
-	if (ret < 0)
-		return ret;
-
-	if (client->fe_status & FE_HAS_LOCK)
-		sms_board_led_feedback(client->coredev,
-				       (client->fe_unc == 0) ?
-				       SMS_LED_HI : SMS_LED_LO);
-	else
-		sms_board_led_feedback(client->coredev, SMS_LED_OFF);
-	return ret;
-}
-
 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
 {
 {
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	int rc = smsdvb_send_statistics_request(client);
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
 
 
-	if (!rc)
-		*stat = client->fe_status;
+	*stat = client->fe_status;
 
 
-	return rc;
+	return 0;
 }
 }
 
 
 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
 {
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	int rc = smsdvb_send_statistics_request(client);
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
 
 
-	if (!rc)
-		*ber = client->fe_ber;
+	*ber = client->sms_stat_dvb.ReceptionData.BER;
 
 
-	return rc;
+	return 0;
 }
 }
 
 
 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
 {
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	int rc = smsdvb_send_statistics_request(client);
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
 
 
-	if (!rc)
-		*strength = client->fe_signal_strength;
+	if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
+		*strength = 0;
+		else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
+			*strength = 100;
+		else
+			*strength =
+				(client->sms_stat_dvb.ReceptionData.InBandPwr
+				+ 95) * 3 / 2;
 
 
-	return rc;
+	return 0;
 }
 }
 
 
 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
 {
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	int rc = smsdvb_send_statistics_request(client);
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
 
 
-	if (!rc)
-		*snr = client->fe_snr;
+	*snr = client->sms_stat_dvb.ReceptionData.SNR;
 
 
-	return rc;
+	return 0;
 }
 }
 
 
 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
 {
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	int rc = smsdvb_send_statistics_request(client);
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
 
 
-	if (!rc)
-		*ucblocks = client->fe_unc;
+	*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
 
 
-	return rc;
+	return 0;
 }
 }
 
 
 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
@@ -286,12 +403,15 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
 		struct SmsMsgHdr_ST	Msg;
 		struct SmsMsgHdr_ST	Msg;
 		u32		Data[3];
 		u32		Data[3];
 	} Msg;
 	} Msg;
-	int ret;
 
 
-	Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
-	Msg.Msg.msgDstId  = HIF_TASK;
-	Msg.Msg.msgFlags  = 0;
-	Msg.Msg.msgType   = MSG_SMS_RF_TUNE_REQ;
+	client->fe_status = FE_HAS_SIGNAL;
+	client->event_fe_state = -1;
+	client->event_unc_state = -1;
+
+	Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	Msg.Msg.msgDstId = HIF_TASK;
+	Msg.Msg.msgFlags = 0;
+	Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
 	Msg.Msg.msgLength = sizeof(Msg);
 	Msg.Msg.msgLength = sizeof(Msg);
 	Msg.Data[0] = fep->frequency;
 	Msg.Data[0] = fep->frequency;
 	Msg.Data[2] = 12000000;
 	Msg.Data[2] = 12000000;
@@ -307,24 +427,6 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
 	default: return -EINVAL;
 	default: return -EINVAL;
 	}
 	}
 
 
-	/* Disable LNA, if any. An error is returned if no LNA is present */
-	ret = sms_board_lna_control(client->coredev, 0);
-	if (ret == 0) {
-		fe_status_t status;
-
-		/* tune with LNA off at first */
-		ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-						  &client->tune_done);
-
-		smsdvb_read_status(fe, &status);
-
-		if (status & FE_HAS_LOCK)
-			return ret;
-
-		/* previous tune didnt lock - enable LNA and tune again */
-		sms_board_lna_control(client->coredev, 1);
-	}
-
 	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
 	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
 					   &client->tune_done);
 					   &client->tune_done);
 }
 }
@@ -349,8 +451,7 @@ static int smsdvb_init(struct dvb_frontend *fe)
 	struct smsdvb_client_t *client =
 	struct smsdvb_client_t *client =
 		container_of(fe, struct smsdvb_client_t, frontend);
 		container_of(fe, struct smsdvb_client_t, frontend);
 
 
-	sms_board_power(client->coredev, 1);
-
+	sms_board_dvb3_event(client, DVB3_EVENT_INIT);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -359,8 +460,7 @@ static int smsdvb_sleep(struct dvb_frontend *fe)
 	struct smsdvb_client_t *client =
 	struct smsdvb_client_t *client =
 		container_of(fe, struct smsdvb_client_t, frontend);
 		container_of(fe, struct smsdvb_client_t, frontend);
 
 
-	sms_board_led_feedback(client->coredev, SMS_LED_OFF);
-	sms_board_power(client->coredev, 0);
+	sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -485,7 +585,6 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
 	client->coredev = coredev;
 	client->coredev = coredev;
 
 
 	init_completion(&client->tune_done);
 	init_completion(&client->tune_done);
-	init_completion(&client->stat_done);
 
 
 	kmutex_lock(&g_smsdvb_clientslock);
 	kmutex_lock(&g_smsdvb_clientslock);
 
 
@@ -493,8 +592,11 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
 
 
 	kmutex_unlock(&g_smsdvb_clientslock);
 	kmutex_unlock(&g_smsdvb_clientslock);
 
 
-	sms_info("success");
+	client->event_fe_state = -1;
+	client->event_unc_state = -1;
+	sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
 
 
+	sms_info("success");
 	sms_board_setup(coredev);
 	sms_board_setup(coredev);
 
 
 	return 0;
 	return 0;
@@ -547,5 +649,5 @@ module_init(smsdvb_module_init);
 module_exit(smsdvb_module_exit);
 module_exit(smsdvb_module_exit);
 
 
 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
-MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 102 - 0
drivers/media/dvb/siano/smsendian.c

@@ -0,0 +1,102 @@
+/****************************************************************
+
+ Siano Mobile Silicon, Inc.
+ MDTV receiver kernel modules.
+ Copyright (C) 2006-2009, Uri Shkolnik
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+ ****************************************************************/
+
+#include <asm/byteorder.h>
+
+#include "smsendian.h"
+#include "smscoreapi.h"
+
+void smsendian_handle_tx_message(void *buffer)
+{
+#ifdef __BIG_ENDIAN
+	struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+	int i;
+	int msgWords;
+
+	switch (msg->xMsgHeader.msgType) {
+	case MSG_SMS_DATA_DOWNLOAD_REQ:
+	{
+		msg->msgData[0] = le32_to_cpu(msg->msgData[0]);
+		break;
+	}
+
+	default:
+		msgWords = (msg->xMsgHeader.msgLength -
+				sizeof(struct SmsMsgHdr_ST))/4;
+
+		for (i = 0; i < msgWords; i++)
+			msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+
+		break;
+	}
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_tx_message);
+
+void smsendian_handle_rx_message(void *buffer)
+{
+#ifdef __BIG_ENDIAN
+	struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+	int i;
+	int msgWords;
+
+	switch (msg->xMsgHeader.msgType) {
+	case MSG_SMS_GET_VERSION_EX_RES:
+	{
+		struct SmsVersionRes_ST *ver =
+			(struct SmsVersionRes_ST *) msg;
+		ver->ChipModel = le16_to_cpu(ver->ChipModel);
+		break;
+	}
+
+	case MSG_SMS_DVBT_BDA_DATA:
+	case MSG_SMS_DAB_CHANNEL:
+	case MSG_SMS_DATA_MSG:
+	{
+		break;
+	}
+
+	default:
+	{
+		msgWords = (msg->xMsgHeader.msgLength -
+				sizeof(struct SmsMsgHdr_ST))/4;
+
+		for (i = 0; i < msgWords; i++)
+			msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+
+		break;
+	}
+	}
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_rx_message);
+
+void smsendian_handle_message_header(void *msg)
+{
+#ifdef __BIG_ENDIAN
+	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg;
+
+	phdr->msgType = le16_to_cpu(phdr->msgType);
+	phdr->msgLength = le16_to_cpu(phdr->msgLength);
+	phdr->msgFlags = le16_to_cpu(phdr->msgFlags);
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_message_header);

+ 32 - 0
drivers/media/dvb/siano/smsendian.h

@@ -0,0 +1,32 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2009, Uri Shkolnik
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_ENDIAN_H__
+#define __SMS_ENDIAN_H__
+
+#include <asm/byteorder.h>
+
+extern void smsendian_handle_tx_message(void *buffer);
+extern void smsendian_handle_rx_message(void *buffer);
+extern void smsendian_handle_message_header(void *msg);
+
+#endif /* __SMS_ENDIAN_H__ */
+

+ 301 - 0
drivers/media/dvb/siano/smsir.c

@@ -0,0 +1,301 @@
+/****************************************************************
+
+ Siano Mobile Silicon, Inc.
+ MDTV receiver kernel modules.
+ Copyright (C) 2006-2009, Uri Shkolnik
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+ ****************************************************************/
+
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+#include "smscoreapi.h"
+#include "smsir.h"
+#include "sms-cards.h"
+
+/* In order to add new IR remote control -
+ * 1) Add it to the <enum ir_kb_type> @ smsir,h,
+ * 2) Add its map to keyboard_layout_maps below
+ * 3) Set your board (sms-cards sub-module) to use it
+ */
+
+static struct keyboard_layout_map_t keyboard_layout_maps[] = {
+		[SMS_IR_KB_DEFAULT_TV] = {
+			.ir_protocol = IR_RC5,
+			.rc5_kbd_address = KEYBOARD_ADDRESS_TV1,
+			.keyboard_layout_map = {
+					KEY_0, KEY_1, KEY_2,
+					KEY_3, KEY_4, KEY_5,
+					KEY_6, KEY_7, KEY_8,
+					KEY_9, 0, 0, KEY_POWER,
+					KEY_MUTE, 0, 0,
+					KEY_VOLUMEUP, KEY_VOLUMEDOWN,
+					KEY_BRIGHTNESSUP,
+					KEY_BRIGHTNESSDOWN, KEY_CHANNELUP,
+					KEY_CHANNELDOWN,
+					0, 0, 0, 0, 0, 0, 0, 0,
+					0, 0, 0, 0, 0, 0, 0, 0,
+					0, 0, 0, 0, 0, 0, 0, 0,
+					0, 0, 0, 0, 0, 0, 0, 0,
+					0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+			}
+		},
+		[SMS_IR_KB_HCW_SILVER] = {
+			.ir_protocol = IR_RC5,
+			.rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1,
+			.keyboard_layout_map = {
+					KEY_0, KEY_1, KEY_2,
+					KEY_3, KEY_4, KEY_5,
+					KEY_6, KEY_7, KEY_8,
+					KEY_9, KEY_TEXT, KEY_RED,
+					KEY_RADIO, KEY_MENU,
+					KEY_SUBTITLE,
+					KEY_MUTE, KEY_VOLUMEUP,
+					KEY_VOLUMEDOWN, KEY_PREVIOUS, 0,
+					KEY_UP, KEY_DOWN, KEY_LEFT,
+					KEY_RIGHT, KEY_VIDEO, KEY_AUDIO,
+					KEY_MHP, KEY_EPG, KEY_TV,
+					0, KEY_NEXTSONG, KEY_EXIT,
+					KEY_CHANNELUP, 	KEY_CHANNELDOWN,
+					KEY_CHANNEL, 0,
+					KEY_PREVIOUSSONG, KEY_ENTER,
+					KEY_SLEEP, 0, 0, KEY_BLUE,
+					0, 0, 0, 0, KEY_GREEN, 0,
+					KEY_PAUSE, 0, KEY_REWIND,
+					0, KEY_FASTFORWARD, KEY_PLAY,
+					KEY_STOP, KEY_RECORD,
+					KEY_YELLOW, 0, 0, KEY_SELECT,
+					KEY_ZOOM, KEY_POWER, 0, 0
+			}
+		},
+		{ } /* Terminating entry */
+};
+
+u32 ir_pos;
+u32	ir_word;
+u32 ir_toggle;
+
+#define RC5_PUSH_BIT(dst, bit, pos)	\
+	{ dst <<= 1; dst |= bit; pos++; }
+
+
+static void sms_ir_rc5_event(struct smscore_device_t *coredev,
+				u32 toggle, u32 addr, u32 cmd)
+{
+	bool toggle_changed;
+	u16 keycode;
+
+	sms_log("IR RC5 word: address %d, command %d, toggle %d",
+				addr, cmd, toggle);
+
+	toggle_changed = ir_toggle != toggle;
+	/* keep toggle */
+	ir_toggle = toggle;
+
+	if (addr !=
+		keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address)
+		return; /* Check for valid address */
+
+	keycode =
+		keyboard_layout_maps
+		[coredev->ir.ir_kb_type].keyboard_layout_map[cmd];
+
+	if (!toggle_changed &&
+			(keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
+		return; /* accept only repeated volume, reject other keys */
+
+	sms_log("kernel input keycode (from ir) %d", keycode);
+	input_report_key(coredev->ir.input_dev, keycode, 1);
+	input_sync(coredev->ir.input_dev);
+
+}
+
+/* decode raw bit pattern to RC5 code */
+/* taken from ir-functions.c */
+static u32 ir_rc5_decode(unsigned int code)
+{
+/*	unsigned int org_code = code;*/
+	unsigned int pair;
+	unsigned int rc5 = 0;
+	int i;
+
+	for (i = 0; i < 14; ++i) {
+		pair = code & 0x3;
+		code >>= 2;
+
+		rc5 <<= 1;
+		switch (pair) {
+		case 0:
+		case 2:
+			break;
+		case 1:
+			rc5 |= 1;
+			break;
+		case 3:
+/*	dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
+			sms_log("bad code");
+			return 0;
+		}
+	}
+/*
+	dprintk(1, "ir-common: code=%x, rc5=%x, start=%x,
+		toggle=%x, address=%x, "
+		"instr=%x\n", rc5, org_code, RC5_START(rc5),
+		RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+*/
+	return rc5;
+}
+
+static void sms_rc5_parse_word(struct smscore_device_t *coredev)
+{
+	#define RC5_START(x)    (((x)>>12)&3)
+	#define RC5_TOGGLE(x)   (((x)>>11)&1)
+	#define RC5_ADDR(x)     (((x)>>6)&0x1F)
+	#define RC5_INSTR(x)    ((x)&0x3F)
+
+	int i, j;
+	u32 rc5_word = 0;
+
+	/* Reverse the IR word direction */
+	for (i = 0 ; i < 28 ; i++)
+		RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
+
+	rc5_word = ir_rc5_decode(rc5_word);
+	/* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
+
+	sms_ir_rc5_event(coredev,
+				RC5_TOGGLE(rc5_word),
+				RC5_ADDR(rc5_word),
+				RC5_INSTR(rc5_word));
+}
+
+
+static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
+		s32 ir_sample)
+{
+	#define RC5_TIME_GRANULARITY	200
+	#define RC5_DEF_BIT_TIME		889
+	#define RC5_MAX_SAME_BIT_CONT	4
+	#define RC5_WORD_LEN			27 /* 28 bit */
+
+	u32 i, j;
+	s32 delta_time;
+	u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample);
+	u32 level = (ir_sample < 0) ? 0 : 1;
+
+	for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) {
+		delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY;
+		if (delta_time < 0)
+			continue; /* not so many consecutive bits */
+		if (delta_time > (2 * RC5_TIME_GRANULARITY)) {
+			/* timeout */
+			if (ir_pos == (RC5_WORD_LEN-1))
+				/* complete last bit */
+				RC5_PUSH_BIT(ir_word, level, ir_pos)
+
+			if (ir_pos == RC5_WORD_LEN)
+				sms_rc5_parse_word(coredev);
+			else if (ir_pos) /* timeout within a word */
+				sms_log("IR error parsing a word");
+
+			ir_pos = 0;
+			ir_word = 0;
+			/* sms_log("timeout %d", time); */
+			break;
+		}
+		/* The time is within the range of this number of bits */
+		for (j = 0 ; j < i ; j++)
+			RC5_PUSH_BIT(ir_word, level, ir_pos)
+
+		break;
+	}
+}
+
+void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
+{
+	#define IR_DATA_RECEIVE_MAX_LEN	520 /* 128*4 + 4 + 4 */
+	u32 i;
+	enum ir_protocol ir_protocol =
+			keyboard_layout_maps[coredev->ir.ir_kb_type]
+					     .ir_protocol;
+	s32 *samples;
+	int count = len>>2;
+
+	samples = (s32 *)buf;
+/*	sms_log("IR buffer received, length = %d", count);*/
+
+	for (i = 0; i < count; i++)
+		if (ir_protocol == IR_RC5)
+			sms_rc5_accumulate_bits(coredev, samples[i]);
+	/*  IR_RCMM not implemented */
+}
+
+int sms_ir_init(struct smscore_device_t *coredev)
+{
+	struct input_dev *input_dev;
+
+	sms_log("Allocating input device");
+	input_dev = input_allocate_device();
+	if (!input_dev)	{
+		sms_err("Not enough memory");
+		return -ENOMEM;
+	}
+
+	coredev->ir.input_dev = input_dev;
+	coredev->ir.ir_kb_type =
+		sms_get_board(smscore_get_board_id(coredev))->ir_kb_type;
+	coredev->ir.keyboard_layout_map =
+		keyboard_layout_maps[coredev->ir.ir_kb_type].
+				keyboard_layout_map;
+	sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
+
+	coredev->ir.controller = 0;	/* Todo: vega/nova SPI number */
+	coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
+	sms_log("IR port %d, timeout %d ms",
+			coredev->ir.controller, coredev->ir.timeout);
+
+	snprintf(coredev->ir.name,
+				IR_DEV_NAME_MAX_LEN,
+				"SMS IR w/kbd type %d",
+				coredev->ir.ir_kb_type);
+	input_dev->name = coredev->ir.name;
+	input_dev->phys = coredev->ir.name;
+	input_dev->dev.parent = coredev->device;
+
+	/* Key press events only */
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
+	input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+
+	sms_log("Input device (IR) %s is set for key events", input_dev->name);
+
+	if (input_register_device(input_dev)) {
+		sms_err("Failed to register device");
+		input_free_device(input_dev);
+		return -EACCES;
+	}
+
+	return 0;
+}
+
+void sms_ir_exit(struct smscore_device_t *coredev)
+{
+	if (coredev->ir.input_dev)
+		input_unregister_device(coredev->ir.input_dev);
+
+	sms_log("");
+}
+

+ 93 - 0
drivers/media/dvb/siano/smsir.h

@@ -0,0 +1,93 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2009, Uri Shkolnik
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_IR_H__
+#define __SMS_IR_H__
+
+#include <linux/input.h>
+
+#define IR_DEV_NAME_MAX_LEN		23 /* "SMS IR kbd type nn\0" */
+#define IR_KEYBOARD_LAYOUT_SIZE	64
+#define IR_DEFAULT_TIMEOUT		100
+
+enum ir_kb_type {
+	SMS_IR_KB_DEFAULT_TV,
+	SMS_IR_KB_HCW_SILVER
+};
+
+enum rc5_keyboard_address {
+	KEYBOARD_ADDRESS_TV1 = 0,
+	KEYBOARD_ADDRESS_TV2 = 1,
+	KEYBOARD_ADDRESS_TELETEXT = 2,
+	KEYBOARD_ADDRESS_VIDEO = 3,
+	KEYBOARD_ADDRESS_LV1 = 4,
+	KEYBOARD_ADDRESS_VCR1 = 5,
+	KEYBOARD_ADDRESS_VCR2 = 6,
+	KEYBOARD_ADDRESS_EXPERIMENTAL = 7,
+	KEYBOARD_ADDRESS_SAT1 = 8,
+	KEYBOARD_ADDRESS_CAMERA = 9,
+	KEYBOARD_ADDRESS_SAT2 = 10,
+	KEYBOARD_ADDRESS_CDV = 12,
+	KEYBOARD_ADDRESS_CAMCORDER = 13,
+	KEYBOARD_ADDRESS_PRE_AMP = 16,
+	KEYBOARD_ADDRESS_TUNER = 17,
+	KEYBOARD_ADDRESS_RECORDER1 = 18,
+	KEYBOARD_ADDRESS_PRE_AMP1 = 19,
+	KEYBOARD_ADDRESS_CD_PLAYER = 20,
+	KEYBOARD_ADDRESS_PHONO = 21,
+	KEYBOARD_ADDRESS_SATA = 22,
+	KEYBOARD_ADDRESS_RECORDER2 = 23,
+	KEYBOARD_ADDRESS_CDR = 26,
+	KEYBOARD_ADDRESS_LIGHTING = 29,
+	KEYBOARD_ADDRESS_LIGHTING1 = 30, /* KEYBOARD_ADDRESS_HCW_SILVER */
+	KEYBOARD_ADDRESS_PHONE = 31,
+	KEYBOARD_ADDRESS_NOT_RC5 = 0xFFFF
+};
+
+enum ir_protocol {
+	IR_RC5,
+	IR_RCMM
+};
+
+struct keyboard_layout_map_t {
+	enum ir_protocol ir_protocol;
+	enum rc5_keyboard_address rc5_kbd_address;
+	u16 keyboard_layout_map[IR_KEYBOARD_LAYOUT_SIZE];
+};
+
+struct smscore_device_t;
+
+struct ir_t {
+	struct input_dev *input_dev;
+	enum ir_kb_type ir_kb_type;
+	char name[IR_DEV_NAME_MAX_LEN+1];
+	u16 *keyboard_layout_map;
+	u32 timeout;
+	u32 controller;
+};
+
+int sms_ir_init(struct smscore_device_t *coredev);
+void sms_ir_exit(struct smscore_device_t *coredev);
+void sms_ir_event(struct smscore_device_t *coredev,
+			const char *buf, int len);
+
+#endif /* __SMS_IR_H__ */
+

+ 357 - 0
drivers/media/dvb/siano/smssdio.c

@@ -0,0 +1,357 @@
+/*
+ *  smssdio.c - Siano 1xxx SDIO interface driver
+ *
+ *  Copyright 2008 Pierre Ossman
+ *
+ * Based on code by Siano Mobile Silicon, Inc.,
+ * Copyright (C) 2006-2008, Uri Shkolnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ *
+ * This hardware is a bit odd in that all transfers should be done
+ * to/from the SMSSDIO_DATA register, yet the "increase address" bit
+ * always needs to be set.
+ *
+ * Also, buffers from the card are always aligned to 128 byte
+ * boundaries.
+ */
+
+/*
+ * General cleanup notes:
+ *
+ * - only typedefs should be name *_t
+ *
+ * - use ERR_PTR and friends for smscore_register_device()
+ *
+ * - smscore_getbuffer should zero fields
+ *
+ * Fix stop command
+ */
+
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+/* Registers */
+
+#define SMSSDIO_DATA		0x00
+#define SMSSDIO_INT		0x04
+
+static const struct sdio_device_id smssdio_ids[] = {
+	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
+	 .driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
+	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
+	 .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A},
+	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0),
+	 .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B},
+	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0),
+	 .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
+	{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE),
+	 .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
+	{ /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, smssdio_ids);
+
+struct smssdio_device {
+	struct sdio_func *func;
+
+	struct smscore_device_t *coredev;
+
+	struct smscore_buffer_t *split_cb;
+};
+
+/*******************************************************************/
+/* Siano core callbacks                                            */
+/*******************************************************************/
+
+static int smssdio_sendrequest(void *context, void *buffer, size_t size)
+{
+	int ret;
+	struct smssdio_device *smsdev;
+
+	smsdev = context;
+
+	sdio_claim_host(smsdev->func);
+
+	while (size >= smsdev->func->cur_blksize) {
+		ret = sdio_write_blocks(smsdev->func, SMSSDIO_DATA, buffer, 1);
+		if (ret)
+			goto out;
+
+		buffer += smsdev->func->cur_blksize;
+		size -= smsdev->func->cur_blksize;
+	}
+
+	if (size) {
+		ret = sdio_write_bytes(smsdev->func, SMSSDIO_DATA,
+				       buffer, size);
+	}
+
+out:
+	sdio_release_host(smsdev->func);
+
+	return ret;
+}
+
+/*******************************************************************/
+/* SDIO callbacks                                                  */
+/*******************************************************************/
+
+static void smssdio_interrupt(struct sdio_func *func)
+{
+	int ret, isr;
+
+	struct smssdio_device *smsdev;
+	struct smscore_buffer_t *cb;
+	struct SmsMsgHdr_ST *hdr;
+	size_t size;
+
+	smsdev = sdio_get_drvdata(func);
+
+	/*
+	 * The interrupt register has no defined meaning. It is just
+	 * a way of turning of the level triggered interrupt.
+	 */
+	isr = sdio_readb(func, SMSSDIO_INT, &ret);
+	if (ret) {
+		dev_err(&smsdev->func->dev,
+			"Unable to read interrupt register!\n");
+		return;
+	}
+
+	if (smsdev->split_cb == NULL) {
+		cb = smscore_getbuffer(smsdev->coredev);
+		if (!cb) {
+			dev_err(&smsdev->func->dev,
+				"Unable to allocate data buffer!\n");
+			return;
+		}
+
+		ret = sdio_read_blocks(smsdev->func, cb->p, SMSSDIO_DATA, 1);
+		if (ret) {
+			dev_err(&smsdev->func->dev,
+				"Error %d reading initial block!\n", ret);
+			return;
+		}
+
+		hdr = cb->p;
+
+		if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) {
+			smsdev->split_cb = cb;
+			return;
+		}
+
+		size = hdr->msgLength - smsdev->func->cur_blksize;
+	} else {
+		cb = smsdev->split_cb;
+		hdr = cb->p;
+
+		size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST);
+
+		smsdev->split_cb = NULL;
+	}
+
+	if (hdr->msgLength > smsdev->func->cur_blksize) {
+		void *buffer;
+
+		size = ALIGN(size, 128);
+		buffer = cb->p + hdr->msgLength;
+
+		BUG_ON(smsdev->func->cur_blksize != 128);
+
+		/*
+		 * First attempt to transfer all of it in one go...
+		 */
+		ret = sdio_read_blocks(smsdev->func, buffer,
+				       SMSSDIO_DATA, size / 128);
+		if (ret && ret != -EINVAL) {
+			smscore_putbuffer(smsdev->coredev, cb);
+			dev_err(&smsdev->func->dev,
+				"Error %d reading data from card!\n", ret);
+			return;
+		}
+
+		/*
+		 * ..then fall back to one block at a time if that is
+		 * not possible...
+		 *
+		 * (we have to do this manually because of the
+		 * problem with the "increase address" bit)
+		 */
+		if (ret == -EINVAL) {
+			while (size) {
+				ret = sdio_read_blocks(smsdev->func,
+						       buffer, SMSSDIO_DATA, 1);
+				if (ret) {
+					smscore_putbuffer(smsdev->coredev, cb);
+					dev_err(&smsdev->func->dev,
+						"Error %d reading "
+						"data from card!\n", ret);
+					return;
+				}
+
+				buffer += smsdev->func->cur_blksize;
+				if (size > smsdev->func->cur_blksize)
+					size -= smsdev->func->cur_blksize;
+				else
+					size = 0;
+			}
+		}
+	}
+
+	cb->size = hdr->msgLength;
+	cb->offset = 0;
+
+	smscore_onresponse(smsdev->coredev, cb);
+}
+
+static int smssdio_probe(struct sdio_func *func,
+			 const struct sdio_device_id *id)
+{
+	int ret;
+
+	int board_id;
+	struct smssdio_device *smsdev;
+	struct smsdevice_params_t params;
+
+	board_id = id->driver_data;
+
+	smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL);
+	if (!smsdev)
+		return -ENOMEM;
+
+	smsdev->func = func;
+
+	memset(&params, 0, sizeof(struct smsdevice_params_t));
+
+	params.device = &func->dev;
+	params.buffer_size = 0x5000;	/* ?? */
+	params.num_buffers = 22;	/* ?? */
+	params.context = smsdev;
+
+	snprintf(params.devpath, sizeof(params.devpath),
+		 "sdio\\%s", sdio_func_id(func));
+
+	params.sendrequest_handler = smssdio_sendrequest;
+
+	params.device_type = sms_get_board(board_id)->type;
+
+	if (params.device_type != SMS_STELLAR)
+		params.flags |= SMS_DEVICE_FAMILY2;
+	else {
+		/*
+		 * FIXME: Stellar needs special handling...
+		 */
+		ret = -ENODEV;
+		goto free;
+	}
+
+	ret = smscore_register_device(&params, &smsdev->coredev);
+	if (ret < 0)
+		goto free;
+
+	smscore_set_board_id(smsdev->coredev, board_id);
+
+	sdio_claim_host(func);
+
+	ret = sdio_enable_func(func);
+	if (ret)
+		goto release;
+
+	ret = sdio_set_block_size(func, 128);
+	if (ret)
+		goto disable;
+
+	ret = sdio_claim_irq(func, smssdio_interrupt);
+	if (ret)
+		goto disable;
+
+	sdio_set_drvdata(func, smsdev);
+
+	sdio_release_host(func);
+
+	ret = smscore_start_device(smsdev->coredev);
+	if (ret < 0)
+		goto reclaim;
+
+	return 0;
+
+reclaim:
+	sdio_claim_host(func);
+	sdio_release_irq(func);
+disable:
+	sdio_disable_func(func);
+release:
+	sdio_release_host(func);
+	smscore_unregister_device(smsdev->coredev);
+free:
+	kfree(smsdev);
+
+	return ret;
+}
+
+static void smssdio_remove(struct sdio_func *func)
+{
+	struct smssdio_device *smsdev;
+
+	smsdev = sdio_get_drvdata(func);
+
+	/* FIXME: racy! */
+	if (smsdev->split_cb)
+		smscore_putbuffer(smsdev->coredev, smsdev->split_cb);
+
+	smscore_unregister_device(smsdev->coredev);
+
+	sdio_claim_host(func);
+	sdio_release_irq(func);
+	sdio_disable_func(func);
+	sdio_release_host(func);
+
+	kfree(smsdev);
+}
+
+static struct sdio_driver smssdio_driver = {
+	.name = "smssdio",
+	.id_table = smssdio_ids,
+	.probe = smssdio_probe,
+	.remove = smssdio_remove,
+};
+
+/*******************************************************************/
+/* Module functions                                                */
+/*******************************************************************/
+
+int smssdio_module_init(void)
+{
+	int ret = 0;
+
+	printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n");
+	printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n");
+
+	ret = sdio_register_driver(&smssdio_driver);
+
+	return ret;
+}
+
+void smssdio_module_exit(void)
+{
+	sdio_unregister_driver(&smssdio_driver);
+}
+
+module_init(smssdio_module_init);
+module_exit(smssdio_module_exit);
+
+MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
+MODULE_AUTHOR("Pierre Ossman");
+MODULE_LICENSE("GPL");

+ 42 - 33
drivers/media/dvb/siano/smsusb.c

@@ -1,23 +1,23 @@
-/*
- *  Driver for the Siano SMS1xxx USB dongle
- *
- *  author: Anatoly Greenblat
- *
- *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  See the GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
 
 
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/init.h>
@@ -26,6 +26,7 @@
 
 
 #include "smscoreapi.h"
 #include "smscoreapi.h"
 #include "sms-cards.h"
 #include "sms-cards.h"
+#include "smsendian.h"
 
 
 static int sms_dbg;
 static int sms_dbg;
 module_param_named(debug, sms_dbg, int, 0644);
 module_param_named(debug, sms_dbg, int, 0644);
@@ -64,15 +65,16 @@ static void smsusb_onresponse(struct urb *urb)
 	struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
 	struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
 	struct smsusb_device_t *dev = surb->dev;
 	struct smsusb_device_t *dev = surb->dev;
 
 
-	if (urb->status < 0) {
-		sms_err("error, urb status %d, %d bytes",
+	if (urb->status == -ESHUTDOWN) {
+		sms_err("error, urb status %d (-ESHUTDOWN), %d bytes",
 			urb->status, urb->actual_length);
 			urb->status, urb->actual_length);
 		return;
 		return;
 	}
 	}
 
 
-	if (urb->actual_length > 0) {
-		struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p;
+	if ((urb->actual_length > 0) && (urb->status == 0)) {
+		struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p;
 
 
+		smsendian_handle_message_header(phdr);
 		if (urb->actual_length >= phdr->msgLength) {
 		if (urb->actual_length >= phdr->msgLength) {
 			surb->cb->size = phdr->msgLength;
 			surb->cb->size = phdr->msgLength;
 
 
@@ -109,7 +111,10 @@ static void smsusb_onresponse(struct urb *urb)
 				"msglen %d actual %d",
 				"msglen %d actual %d",
 				phdr->msgLength, urb->actual_length);
 				phdr->msgLength, urb->actual_length);
 		}
 		}
-	}
+	} else
+		sms_err("error, urb status %d, %d bytes",
+			urb->status, urb->actual_length);
+
 
 
 exit_and_resubmit:
 exit_and_resubmit:
 	smsusb_submit_urb(dev, surb);
 	smsusb_submit_urb(dev, surb);
@@ -176,6 +181,7 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size)
 	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
 	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
 	int dummy;
 	int dummy;
 
 
+	smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer);
 	return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
 	return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
 			    buffer, size, &dummy, 1000);
 			    buffer, size, &dummy, 1000);
 }
 }
@@ -333,8 +339,8 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
 	case SMS_VEGA:
 	case SMS_VEGA:
 		dev->buffer_size = USB2_BUFFER_SIZE;
 		dev->buffer_size = USB2_BUFFER_SIZE;
 		dev->response_alignment =
 		dev->response_alignment =
-			dev->udev->ep_in[1]->desc.wMaxPacketSize -
-			sizeof(struct SmsMsgHdr_ST);
+		    le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
+		    sizeof(struct SmsMsgHdr_ST);
 
 
 		params.flags |= SMS_DEVICE_FAMILY2;
 		params.flags |= SMS_DEVICE_FAMILY2;
 		break;
 		break;
@@ -479,7 +485,6 @@ static int smsusb_resume(struct usb_interface *intf)
 }
 }
 
 
 struct usb_device_id smsusb_id_table[] = {
 struct usb_device_id smsusb_id_table[] = {
-#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
 	{ USB_DEVICE(0x187f, 0x0010),
 	{ USB_DEVICE(0x187f, 0x0010),
 		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
 		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
 	{ USB_DEVICE(0x187f, 0x0100),
 	{ USB_DEVICE(0x187f, 0x0100),
@@ -490,7 +495,6 @@ struct usb_device_id smsusb_id_table[] = {
 		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
 		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
 	{ USB_DEVICE(0x187f, 0x0300),
 	{ USB_DEVICE(0x187f, 0x0300),
 		.driver_info = SMS1XXX_BOARD_SIANO_VEGA },
 		.driver_info = SMS1XXX_BOARD_SIANO_VEGA },
-#endif
 	{ USB_DEVICE(0x2040, 0x1700),
 	{ USB_DEVICE(0x2040, 0x1700),
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
 	{ USB_DEVICE(0x2040, 0x1800),
 	{ USB_DEVICE(0x2040, 0x1800),
@@ -521,8 +525,13 @@ struct usb_device_id smsusb_id_table[] = {
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 	{ USB_DEVICE(0x2040, 0x5590),
 	{ USB_DEVICE(0x2040, 0x5590),
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-	{ }		/* Terminating entry */
-};
+	{ USB_DEVICE(0x187f, 0x0202),
+		.driver_info = SMS1XXX_BOARD_SIANO_NICE },
+	{ USB_DEVICE(0x187f, 0x0301),
+		.driver_info = SMS1XXX_BOARD_SIANO_VENICE },
+	{ } /* Terminating entry */
+	};
+
 MODULE_DEVICE_TABLE(usb, smsusb_id_table);
 MODULE_DEVICE_TABLE(usb, smsusb_id_table);
 
 
 static struct usb_driver smsusb_driver = {
 static struct usb_driver smsusb_driver = {
@@ -548,14 +557,14 @@ int smsusb_module_init(void)
 
 
 void smsusb_module_exit(void)
 void smsusb_module_exit(void)
 {
 {
-	sms_debug("");
 	/* Regular USB Cleanup */
 	/* Regular USB Cleanup */
 	usb_deregister(&smsusb_driver);
 	usb_deregister(&smsusb_driver);
+	sms_info("end");
 }
 }
 
 
 module_init(smsusb_module_init);
 module_init(smsusb_module_init);
 module_exit(smsusb_module_exit);
 module_exit(smsusb_module_exit);
 
 
-MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
+MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");
 MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
 MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 91 - 33
drivers/media/dvb/ttpci/av7110_av.c

@@ -89,6 +89,7 @@
 
 
 static void p_to_t(u8 const *buf, long int length, u16 pid,
 static void p_to_t(u8 const *buf, long int length, u16 pid,
 		   u8 *counter, struct dvb_demux_feed *feed);
 		   u8 *counter, struct dvb_demux_feed *feed);
+static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len);
 
 
 
 
 int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
 int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
@@ -192,8 +193,6 @@ int av7110_av_start_play(struct av7110 *av7110, int av)
 		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
 		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
 		break;
 		break;
 	}
 	}
-	if (!ret)
-		ret = av7110->playing;
 	return ret;
 	return ret;
 }
 }
 
 
@@ -437,6 +436,45 @@ static void play_audio_cb(u8 *buf, int count, void *priv)
 	aux_ring_buffer_write(&av7110->aout, buf, count);
 	aux_ring_buffer_write(&av7110->aout, buf, count);
 }
 }
 
 
+
+#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096)
+
+static ssize_t ts_play(struct av7110 *av7110, const char __user *buf,
+		       unsigned long count, int nonblock, int type)
+{
+	struct dvb_ringbuffer *rb;
+	u8 *kb;
+	unsigned long todo = count;
+
+	dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count);
+
+	rb = (type) ? &av7110->avout : &av7110->aout;
+	kb = av7110->kbuf[type];
+
+	if (!kb)
+		return -ENOBUFS;
+
+	if (nonblock && !FREE_COND_TS)
+		return -EWOULDBLOCK;
+
+	while (todo >= TS_SIZE) {
+		if (!FREE_COND_TS) {
+			if (nonblock)
+				return count - todo;
+			if (wait_event_interruptible(rb->queue, FREE_COND_TS))
+				return count - todo;
+		}
+		if (copy_from_user(kb, buf, TS_SIZE))
+			return -EFAULT;
+		write_ts_to_decoder(av7110, type, kb, TS_SIZE);
+		todo -= TS_SIZE;
+		buf += TS_SIZE;
+	}
+
+	return count - todo;
+}
+
+
 #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
 #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
 		   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
 		   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
 
 
@@ -780,11 +818,37 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
 }
 }
 
 
 
 
+static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len)
+{
+	struct ipack *ipack = &av7110->ipack[type];
+
+	if (buf[1] & TRANS_ERROR) {
+		av7110_ipack_reset(ipack);
+		return -1;
+	}
+
+	if (!(buf[3] & PAYLOAD))
+		return -1;
+
+	if (buf[1] & PAY_START)
+		av7110_ipack_flush(ipack);
+
+	if (buf[3] & ADAPT_FIELD) {
+		len -= buf[4] + 1;
+		buf += buf[4] + 1;
+		if (!len)
+			return 0;
+	}
+
+	av7110_ipack_instant_repack(buf + 4, len - 4, ipack);
+	return 0;
+}
+
+
 int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len)
 int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len)
 {
 {
 	struct dvb_demux *demux = feed->demux;
 	struct dvb_demux *demux = feed->demux;
 	struct av7110 *av7110 = (struct av7110 *) demux->priv;
 	struct av7110 *av7110 = (struct av7110 *) demux->priv;
-	struct ipack *ipack = &av7110->ipack[feed->pes_type];
 
 
 	dprintk(2, "av7110:%p, \n", av7110);
 	dprintk(2, "av7110:%p, \n", av7110);
 
 
@@ -804,20 +868,7 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (!(buf[3] & 0x10)) /* no payload? */
-		return -1;
-	if (buf[1] & 0x40)
-		av7110_ipack_flush(ipack);
-
-	if (buf[3] & 0x20) {  /* adaptation field? */
-		len -= buf[4] + 1;
-		buf += buf[4] + 1;
-		if (!len)
-			return 0;
-	}
-
-	av7110_ipack_instant_repack(buf + 4, len - 4, &av7110->ipack[feed->pes_type]);
-	return 0;
+	return write_ts_to_decoder(av7110, feed->pes_type, buf, len);
 }
 }
 
 
 
 
@@ -916,6 +967,7 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
 {
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_device *dvbdev = file->private_data;
 	struct av7110 *av7110 = dvbdev->priv;
 	struct av7110 *av7110 = dvbdev->priv;
+	unsigned char c;
 
 
 	dprintk(2, "av7110:%p, \n", av7110);
 	dprintk(2, "av7110:%p, \n", av7110);
 
 
@@ -925,7 +977,12 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
 	if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
 	if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
 		return -EPERM;
 		return -EPERM;
 
 
-	return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
+	if (get_user(c, buf))
+		return -EFAULT;
+	if (c == 0x47 && count % TS_SIZE == 0)
+		return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
+	else
+		return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
 }
 }
 
 
 static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
 static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
@@ -952,6 +1009,7 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
 {
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_device *dvbdev = file->private_data;
 	struct av7110 *av7110 = dvbdev->priv;
 	struct av7110 *av7110 = dvbdev->priv;
+	unsigned char c;
 
 
 	dprintk(2, "av7110:%p, \n", av7110);
 	dprintk(2, "av7110:%p, \n", av7110);
 
 
@@ -959,7 +1017,13 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
 		printk(KERN_ERR "not audio source memory\n");
 		printk(KERN_ERR "not audio source memory\n");
 		return -EPERM;
 		return -EPERM;
 	}
 	}
-	return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
+
+	if (get_user(c, buf))
+		return -EFAULT;
+	if (c == 0x47 && count % TS_SIZE == 0)
+		return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
+	else
+		return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
 }
 }
 
 
 static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };
 static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };
@@ -1062,7 +1126,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
 			if (ret)
 			if (ret)
 				break;
 				break;
 		}
 		}
-
 		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
 		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
 			if (av7110->playing == RP_AV) {
 			if (av7110->playing == RP_AV) {
 				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
 				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
@@ -1122,20 +1185,16 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
 	case VIDEO_SET_DISPLAY_FORMAT:
 	case VIDEO_SET_DISPLAY_FORMAT:
 	{
 	{
 		video_displayformat_t format = (video_displayformat_t) arg;
 		video_displayformat_t format = (video_displayformat_t) arg;
-
 		switch (format) {
 		switch (format) {
 		case VIDEO_PAN_SCAN:
 		case VIDEO_PAN_SCAN:
 			av7110->display_panscan = VID_PAN_SCAN_PREF;
 			av7110->display_panscan = VID_PAN_SCAN_PREF;
 			break;
 			break;
-
 		case VIDEO_LETTER_BOX:
 		case VIDEO_LETTER_BOX:
 			av7110->display_panscan = VID_VC_AND_PS_PREF;
 			av7110->display_panscan = VID_VC_AND_PS_PREF;
 			break;
 			break;
-
 		case VIDEO_CENTER_CUT_OUT:
 		case VIDEO_CENTER_CUT_OUT:
 			av7110->display_panscan = VID_CENTRE_CUT_PREF;
 			av7110->display_panscan = VID_CENTRE_CUT_PREF;
 			break;
 			break;
-
 		default:
 		default:
 			ret = -EINVAL;
 			ret = -EINVAL;
 		}
 		}
@@ -1183,7 +1242,8 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
 
 
 	case VIDEO_SLOWMOTION:
 	case VIDEO_SLOWMOTION:
 		if (av7110->playing&RP_VIDEO) {
 		if (av7110->playing&RP_VIDEO) {
-			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
+			if (av7110->trickmode != TRICK_SLOW)
+				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
 			if (!ret)
 			if (!ret)
 				ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
 				ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
 		} else {
 		} else {
@@ -1207,7 +1267,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
 	case VIDEO_CLEAR_BUFFER:
 	case VIDEO_CLEAR_BUFFER:
 		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
 		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
 		av7110_ipack_reset(&av7110->ipack[1]);
 		av7110_ipack_reset(&av7110->ipack[1]);
-
 		if (av7110->playing == RP_AV) {
 		if (av7110->playing == RP_AV) {
 			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
 			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
 					    __Play, 2, AV_PES, 0);
 					    __Play, 2, AV_PES, 0);
@@ -1228,13 +1287,13 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
 		break;
 		break;
 
 
 	case VIDEO_SET_STREAMTYPE:
 	case VIDEO_SET_STREAMTYPE:
-
 		break;
 		break;
 
 
 	default:
 	default:
 		ret = -ENOIOCTLCMD;
 		ret = -ENOIOCTLCMD;
 		break;
 		break;
 	}
 	}
+
 	return ret;
 	return ret;
 }
 }
 
 
@@ -1309,7 +1368,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
 
 
 	case AUDIO_CHANNEL_SELECT:
 	case AUDIO_CHANNEL_SELECT:
 		av7110->audiostate.channel_select = (audio_channel_select_t) arg;
 		av7110->audiostate.channel_select = (audio_channel_select_t) arg;
-
 		switch(av7110->audiostate.channel_select) {
 		switch(av7110->audiostate.channel_select) {
 		case AUDIO_STEREO:
 		case AUDIO_STEREO:
 			ret = audcom(av7110, AUDIO_CMD_STEREO);
 			ret = audcom(av7110, AUDIO_CMD_STEREO);
@@ -1320,7 +1378,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
 					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);
 					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);
 			}
 			}
 			break;
 			break;
-
 		case AUDIO_MONO_LEFT:
 		case AUDIO_MONO_LEFT:
 			ret = audcom(av7110, AUDIO_CMD_MONO_L);
 			ret = audcom(av7110, AUDIO_CMD_MONO_L);
 			if (!ret) {
 			if (!ret) {
@@ -1330,7 +1387,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
 					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);
 					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);
 			}
 			}
 			break;
 			break;
-
 		case AUDIO_MONO_RIGHT:
 		case AUDIO_MONO_RIGHT:
 			ret = audcom(av7110, AUDIO_CMD_MONO_R);
 			ret = audcom(av7110, AUDIO_CMD_MONO_R);
 			if (!ret) {
 			if (!ret) {
@@ -1340,7 +1396,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
 					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);
 					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);
 			}
 			}
 			break;
 			break;
-
 		default:
 		default:
 			ret = -EINVAL;
 			ret = -EINVAL;
 			break;
 			break;
@@ -1366,21 +1421,24 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
 			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
 			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
 					    __Play, 2, AV_PES, 0);
 					    __Play, 2, AV_PES, 0);
 		break;
 		break;
-	case AUDIO_SET_ID:
 
 
+	case AUDIO_SET_ID:
 		break;
 		break;
+
 	case AUDIO_SET_MIXER:
 	case AUDIO_SET_MIXER:
 	{
 	{
 		struct audio_mixer *amix = (struct audio_mixer *)parg;
 		struct audio_mixer *amix = (struct audio_mixer *)parg;
-
 		ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
 		ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
 		break;
 		break;
 	}
 	}
+
 	case AUDIO_SET_STREAMTYPE:
 	case AUDIO_SET_STREAMTYPE:
 		break;
 		break;
+
 	default:
 	default:
 		ret = -ENOIOCTLCMD;
 		ret = -ENOIOCTLCMD;
 	}
 	}
+
 	return ret;
 	return ret;
 }
 }
 
 

+ 1 - 1
drivers/media/dvb/ttpci/av7110_hw.c

@@ -1089,7 +1089,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
 		else {
 		else {
 			int i, len = dc->x0-dc->color+1;
 			int i, len = dc->x0-dc->color+1;
 			u8 __user *colors = (u8 __user *)dc->data;
 			u8 __user *colors = (u8 __user *)dc->data;
-			u8 r, g, b, blend;
+			u8 r, g = 0, b = 0, blend = 0;
 			ret = 0;
 			ret = 0;
 			for (i = 0; i<len; i++) {
 			for (i = 0; i<len; i++) {
 				if (get_user(r, colors + i * 4) ||
 				if (get_user(r, colors + i * 4) ||

+ 1 - 1
drivers/media/dvb/ttpci/av7110_v4l.c

@@ -458,7 +458,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 	dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
 	dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
 
 
 	if (av7110->analog_tuner_flags) {
 	if (av7110->analog_tuner_flags) {
-		if (i->index < 0 || i->index >= 4)
+		if (i->index >= 4)
 			return -EINVAL;
 			return -EINVAL;
 	} else {
 	} else {
 		if (i->index != 0)
 		if (i->index != 0)

+ 1 - 1
drivers/media/dvb/ttpci/budget-av.c

@@ -1413,7 +1413,7 @@ static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
 {
 	dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
 	dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
-	if (i->index < 0 || i->index >= KNC1_INPUTS)
+	if (i->index >= KNC1_INPUTS)
 		return -EINVAL;
 		return -EINVAL;
 	memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
 	memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
 	return 0;
 	return 0;

+ 85 - 0
drivers/media/dvb/ttpci/budget.c

@@ -47,6 +47,9 @@
 #include "bsru6.h"
 #include "bsru6.h"
 #include "bsbe1.h"
 #include "bsbe1.h"
 #include "tdhd1.h"
 #include "tdhd1.h"
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "isl6423.h"
 
 
 static int diseqc_method;
 static int diseqc_method;
 module_param(diseqc_method, int, 0444);
 module_param(diseqc_method, int, 0444);
@@ -425,6 +428,44 @@ static u8 read_pwm(struct budget* budget)
 	return pwm;
 	return pwm;
 }
 }
 
 
+static struct stv090x_config tt1600_stv090x_config = {
+	.device			= STV0903,
+	.demod_mode		= STV090x_SINGLE,
+	.clk_mode		= STV090x_CLK_EXT,
+
+	.xtal			= 27000000,
+	.address		= 0x68,
+	.ref_clk		= 27000000,
+
+	.ts1_mode		= STV090x_TSMODE_DVBCI,
+	.ts2_mode		= STV090x_TSMODE_SERIAL_CONTINUOUS,
+
+	.repeater_level		= STV090x_RPTLEVEL_16,
+
+	.tuner_init		= NULL,
+	.tuner_set_mode		= NULL,
+	.tuner_set_frequency	= NULL,
+	.tuner_get_frequency	= NULL,
+	.tuner_set_bandwidth	= NULL,
+	.tuner_get_bandwidth	= NULL,
+	.tuner_set_bbgain	= NULL,
+	.tuner_get_bbgain	= NULL,
+	.tuner_set_refclk	= NULL,
+	.tuner_get_status	= NULL,
+};
+
+static struct stv6110x_config tt1600_stv6110x_config = {
+	.addr			= 0x60,
+	.refclk			= 27000000,
+};
+
+static struct isl6423_config tt1600_isl6423_config = {
+	.current_max		= SEC_CURRENT_515m,
+	.curlim			= SEC_CURRENT_LIM_ON,
+	.mod_extern		= 1,
+	.addr			= 0x08,
+};
+
 static void frontend_init(struct budget *budget)
 static void frontend_init(struct budget *budget)
 {
 {
 	(void)alps_bsbe1_config; /* avoid warning */
 	(void)alps_bsbe1_config; /* avoid warning */
@@ -566,6 +607,48 @@ static void frontend_init(struct budget *budget)
 			}
 			}
 			break;
 			break;
 		}
 		}
+
+	case 0x101c: { /* TT S2-1600 */
+			struct stv6110x_devctl *ctl;
+			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+			msleep(50);
+			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+			msleep(250);
+
+			budget->dvb_frontend = dvb_attach(stv090x_attach,
+							  &tt1600_stv090x_config,
+							  &budget->i2c_adap,
+							  STV090x_DEMODULATOR_0);
+
+			if (budget->dvb_frontend) {
+
+				ctl = dvb_attach(stv6110x_attach,
+						 budget->dvb_frontend,
+						 &tt1600_stv6110x_config,
+						 &budget->i2c_adap);
+
+				tt1600_stv090x_config.tuner_init	  = ctl->tuner_init;
+				tt1600_stv090x_config.tuner_set_mode	  = ctl->tuner_set_mode;
+				tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+				tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+				tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+				tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+				tt1600_stv090x_config.tuner_set_bbgain	  = ctl->tuner_set_bbgain;
+				tt1600_stv090x_config.tuner_get_bbgain	  = ctl->tuner_get_bbgain;
+				tt1600_stv090x_config.tuner_set_refclk	  = ctl->tuner_set_refclk;
+				tt1600_stv090x_config.tuner_get_status	  = ctl->tuner_get_status;
+
+				dvb_attach(isl6423_attach,
+					budget->dvb_frontend,
+					&budget->i2c_adap,
+					&tt1600_isl6423_config);
+
+			} else {
+				dvb_frontend_detach(budget->dvb_frontend);
+				budget->dvb_frontend = NULL;
+			}
+		}
+		break;
 	}
 	}
 
 
 	if (budget->dvb_frontend == NULL) {
 	if (budget->dvb_frontend == NULL) {
@@ -641,6 +724,7 @@ MAKE_BUDGET_INFO(ttbc,	"TT-Budget/WinTV-NOVA-C  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);
 MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC);
 MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC);
 MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsact,	 "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsact,	 "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
@@ -653,6 +737,7 @@ static struct pci_device_id pci_tbl[] = {
 	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
 	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
 	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
 	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
 	MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
 	MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
+	MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c),
 	MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
 	MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
 	MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
 	MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
 	MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),
 	MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),

+ 38 - 71
drivers/media/radio/dsbr100.c

@@ -33,6 +33,10 @@
 
 
  History:
  History:
 
 
+ Version 0.46:
+	Removed usb_dsbr100_open/close calls and radio->users counter. Also,
+	radio->muted changed to radio->status and suspend/resume calls updated.
+
  Version 0.45:
  Version 0.45:
 	Converted to v4l2_device.
 	Converted to v4l2_device.
 
 
@@ -100,8 +104,8 @@
  */
  */
 #include <linux/version.h>	/* for KERNEL_VERSION MACRO	*/
 #include <linux/version.h>	/* for KERNEL_VERSION MACRO	*/
 
 
-#define DRIVER_VERSION "v0.45"
-#define RADIO_VERSION KERNEL_VERSION(0, 4, 5)
+#define DRIVER_VERSION "v0.46"
+#define RADIO_VERSION KERNEL_VERSION(0, 4, 6)
 
 
 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
@@ -121,13 +125,15 @@ devices, that would be 76 and 91.  */
 #define FREQ_MAX 108.0
 #define FREQ_MAX 108.0
 #define FREQ_MUL 16000
 #define FREQ_MUL 16000
 
 
+/* defines for radio->status */
+#define STARTED	0
+#define STOPPED	1
+
 #define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
 #define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
 
 
 static int usb_dsbr100_probe(struct usb_interface *intf,
 static int usb_dsbr100_probe(struct usb_interface *intf,
 			     const struct usb_device_id *id);
 			     const struct usb_device_id *id);
 static void usb_dsbr100_disconnect(struct usb_interface *intf);
 static void usb_dsbr100_disconnect(struct usb_interface *intf);
-static int usb_dsbr100_open(struct file *file);
-static int usb_dsbr100_close(struct file *file);
 static int usb_dsbr100_suspend(struct usb_interface *intf,
 static int usb_dsbr100_suspend(struct usb_interface *intf,
 						pm_message_t message);
 						pm_message_t message);
 static int usb_dsbr100_resume(struct usb_interface *intf);
 static int usb_dsbr100_resume(struct usb_interface *intf);
@@ -145,9 +151,8 @@ struct dsbr100_device {
 	struct mutex lock;	/* buffer locking */
 	struct mutex lock;	/* buffer locking */
 	int curfreq;
 	int curfreq;
 	int stereo;
 	int stereo;
-	int users;
 	int removed;
 	int removed;
-	int muted;
+	int status;
 };
 };
 
 
 static struct usb_device_id usb_dsbr100_device_table [] = {
 static struct usb_device_id usb_dsbr100_device_table [] = {
@@ -201,7 +206,7 @@ static int dsbr100_start(struct dsbr100_device *radio)
 		goto usb_control_msg_failed;
 		goto usb_control_msg_failed;
 	}
 	}
 
 
-	radio->muted = 0;
+	radio->status = STARTED;
 	mutex_unlock(&radio->lock);
 	mutex_unlock(&radio->lock);
 	return (radio->transfer_buffer)[0];
 	return (radio->transfer_buffer)[0];
 
 
@@ -244,7 +249,7 @@ static int dsbr100_stop(struct dsbr100_device *radio)
 		goto usb_control_msg_failed;
 		goto usb_control_msg_failed;
 	}
 	}
 
 
-	radio->muted = 1;
+	radio->status = STOPPED;
 	mutex_unlock(&radio->lock);
 	mutex_unlock(&radio->lock);
 	return (radio->transfer_buffer)[0];
 	return (radio->transfer_buffer)[0];
 
 
@@ -258,12 +263,12 @@ usb_control_msg_failed:
 }
 }
 
 
 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
+static int dsbr100_setfreq(struct dsbr100_device *radio)
 {
 {
 	int retval;
 	int retval;
 	int request;
 	int request;
+	int freq = (radio->curfreq / 16 * 80) / 1000 + 856;
 
 
-	freq = (freq / 16 * 80) / 1000 + 856;
 	mutex_lock(&radio->lock);
 	mutex_lock(&radio->lock);
 
 
 	retval = usb_control_msg(radio->usbdev,
 	retval = usb_control_msg(radio->usbdev,
@@ -431,7 +436,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 	radio->curfreq = f->frequency;
 	radio->curfreq = f->frequency;
 	mutex_unlock(&radio->lock);
 	mutex_unlock(&radio->lock);
 
 
-	retval = dsbr100_setfreq(radio, radio->curfreq);
+	retval = dsbr100_setfreq(radio);
 	if (retval < 0)
 	if (retval < 0)
 		dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
 		dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
 	return 0;
 	return 0;
@@ -473,7 +478,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 
 
 	switch (ctrl->id) {
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
 	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = radio->muted;
+		ctrl->value = radio->status;
 		return 0;
 		return 0;
 	}
 	}
 	return -EINVAL;
 	return -EINVAL;
@@ -543,65 +548,27 @@ static int vidioc_s_audio(struct file *file, void *priv,
 	return 0;
 	return 0;
 }
 }
 
 
-static int usb_dsbr100_open(struct file *file)
-{
-	struct dsbr100_device *radio = video_drvdata(file);
-	int retval;
-
-	lock_kernel();
-	radio->users = 1;
-	radio->muted = 1;
-
-	retval = dsbr100_start(radio);
-	if (retval < 0) {
-		dev_warn(&radio->usbdev->dev,
-			 "Radio did not start up properly\n");
-		radio->users = 0;
-		unlock_kernel();
-		return -EIO;
-	}
-
-	retval = dsbr100_setfreq(radio, radio->curfreq);
-	if (retval < 0)
-		dev_warn(&radio->usbdev->dev,
-			"set frequency failed\n");
-
-	unlock_kernel();
-	return 0;
-}
-
-static int usb_dsbr100_close(struct file *file)
-{
-	struct dsbr100_device *radio = video_drvdata(file);
-	int retval;
-
-	if (!radio)
-		return -ENODEV;
-
-	mutex_lock(&radio->lock);
-	radio->users = 0;
-	mutex_unlock(&radio->lock);
-
-	if (!radio->removed) {
-		retval = dsbr100_stop(radio);
-		if (retval < 0) {
-			dev_warn(&radio->usbdev->dev,
-				"dsbr100_stop failed\n");
-		}
-
-	}
-	return 0;
-}
-
 /* Suspend device - stop device. */
 /* Suspend device - stop device. */
 static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
 static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
 {
 {
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
 	int retval;
 	int retval;
 
 
-	retval = dsbr100_stop(radio);
-	if (retval < 0)
-		dev_warn(&intf->dev, "dsbr100_stop failed\n");
+	if (radio->status == STARTED) {
+		retval = dsbr100_stop(radio);
+		if (retval < 0)
+			dev_warn(&intf->dev, "dsbr100_stop failed\n");
+
+		/* After dsbr100_stop() status set to STOPPED.
+		 * If we want driver to start radio on resume
+		 * we set status equal to STARTED.
+		 * On resume we will check status and run radio if needed.
+		 */
+
+		mutex_lock(&radio->lock);
+		radio->status = STARTED;
+		mutex_unlock(&radio->lock);
+	}
 
 
 	dev_info(&intf->dev, "going into suspend..\n");
 	dev_info(&intf->dev, "going into suspend..\n");
 
 
@@ -614,9 +581,11 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
 	int retval;
 	int retval;
 
 
-	retval = dsbr100_start(radio);
-	if (retval < 0)
-		dev_warn(&intf->dev, "dsbr100_start failed\n");
+	if (radio->status == STARTED) {
+		retval = dsbr100_start(radio);
+		if (retval < 0)
+			dev_warn(&intf->dev, "dsbr100_start failed\n");
+	}
 
 
 	dev_info(&intf->dev, "coming out of suspend..\n");
 	dev_info(&intf->dev, "coming out of suspend..\n");
 
 
@@ -636,8 +605,6 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev)
 /* File system interface */
 /* File system interface */
 static const struct v4l2_file_operations usb_dsbr100_fops = {
 static const struct v4l2_file_operations usb_dsbr100_fops = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
-	.open		= usb_dsbr100_open,
-	.release	= usb_dsbr100_close,
 	.ioctl		= video_ioctl2,
 	.ioctl		= video_ioctl2,
 };
 };
 
 
@@ -695,9 +662,9 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
 	mutex_init(&radio->lock);
 	mutex_init(&radio->lock);
 
 
 	radio->removed = 0;
 	radio->removed = 0;
-	radio->users = 0;
 	radio->usbdev = interface_to_usbdev(intf);
 	radio->usbdev = interface_to_usbdev(intf);
 	radio->curfreq = FREQ_MIN * FREQ_MUL;
 	radio->curfreq = FREQ_MIN * FREQ_MUL;
+	radio->status = STOPPED;
 
 
 	video_set_drvdata(&radio->videodev, radio);
 	video_set_drvdata(&radio->videodev, radio);
 
 

+ 1 - 0
drivers/media/radio/radio-mr800.c

@@ -64,6 +64,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/version.h>	/* for KERNEL_VERSION MACRO */
 #include <linux/version.h>	/* for KERNEL_VERSION MACRO */
+#include <linux/mutex.h>
 
 
 /* driver and module definitions */
 /* driver and module definitions */
 #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
 #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"

+ 4 - 12
drivers/media/radio/radio-sf16fmi.c

@@ -49,7 +49,6 @@ struct fmi
 	int io;
 	int io;
 	int curvol; /* 1 or 0 */
 	int curvol; /* 1 or 0 */
 	unsigned long curfreq; /* freq in kHz */
 	unsigned long curfreq; /* freq in kHz */
-	__u32 flags;
 	struct mutex lock;
 	struct mutex lock;
 };
 };
 
 
@@ -57,7 +56,7 @@ static struct fmi fmi_card;
 static struct pnp_dev *dev;
 static struct pnp_dev *dev;
 
 
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
-/* It is only useful to give freq in intervall of 800 (=0.05Mhz),
+/* It is only useful to give freq in interval of 800 (=0.05Mhz),
  * other bits will be truncated, e.g 92.7400016 -> 92.7, but
  * other bits will be truncated, e.g 92.7400016 -> 92.7, but
  * 92.7400017 -> 92.75
  * 92.7400017 -> 92.75
  */
  */
@@ -142,7 +141,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
 					struct v4l2_tuner *v)
 					struct v4l2_tuner *v)
 {
 {
-	int mult;
 	struct fmi *fmi = video_drvdata(file);
 	struct fmi *fmi = video_drvdata(file);
 
 
 	if (v->index > 0)
 	if (v->index > 0)
@@ -150,11 +148,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 
 
 	strlcpy(v->name, "FM", sizeof(v->name));
 	strlcpy(v->name, "FM", sizeof(v->name));
 	v->type = V4L2_TUNER_RADIO;
 	v->type = V4L2_TUNER_RADIO;
-	mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
-	v->rangelow = RSF16_MINFREQ / mult;
-	v->rangehigh = RSF16_MAXFREQ / mult;
+	v->rangelow = RSF16_MINFREQ;
+	v->rangehigh = RSF16_MAXFREQ;
 	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
 	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-	v->capability = fmi->flags & V4L2_TUNER_CAP_LOW;
+	v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
 	v->audmode = V4L2_TUNER_MODE_STEREO;
 	v->audmode = V4L2_TUNER_MODE_STEREO;
 	v->signal = fmi_getsigstr(fmi);
 	v->signal = fmi_getsigstr(fmi);
 	return 0;
 	return 0;
@@ -171,8 +168,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 {
 	struct fmi *fmi = video_drvdata(file);
 	struct fmi *fmi = video_drvdata(file);
 
 
-	if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
-		f->frequency *= 1000;
 	if (f->frequency < RSF16_MINFREQ ||
 	if (f->frequency < RSF16_MINFREQ ||
 			f->frequency > RSF16_MAXFREQ)
 			f->frequency > RSF16_MAXFREQ)
 		return -EINVAL;
 		return -EINVAL;
@@ -189,8 +184,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 
 
 	f->type = V4L2_TUNER_RADIO;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = fmi->curfreq;
 	f->frequency = fmi->curfreq;
-	if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
-		f->frequency /= 1000;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -347,7 +340,6 @@ static int __init fmi_init(void)
 		return res;
 		return res;
 	}
 	}
 
 
-	fmi->flags = V4L2_TUNER_CAP_LOW;
 	strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
 	strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
 	fmi->vdev.v4l2_dev = v4l2_dev;
 	fmi->vdev.v4l2_dev = v4l2_dev;
 	fmi->vdev.fops = &fmi_fops;
 	fmi->vdev.fops = &fmi_fops;

+ 7 - 15
drivers/media/radio/radio-sf16fmr2.c

@@ -61,13 +61,12 @@ struct fmr2
 	int stereo; /* card is producing stereo audio */
 	int stereo; /* card is producing stereo audio */
 	unsigned long curfreq; /* freq in kHz */
 	unsigned long curfreq; /* freq in kHz */
 	int card_type;
 	int card_type;
-	u32 flags;
 };
 };
 
 
 static struct fmr2 fmr2_card;
 static struct fmr2 fmr2_card;
 
 
 /* hw precision is 12.5 kHz
 /* hw precision is 12.5 kHz
- * It is only useful to give freq in intervall of 200 (=0.0125Mhz),
+ * It is only useful to give freq in interval of 200 (=0.0125Mhz),
  * other bits will be truncated
  * other bits will be truncated
  */
  */
 #define RSF16_ENCODE(x)	((x) / 200 + 856)
 #define RSF16_ENCODE(x)	((x) / 200 + 856)
@@ -221,7 +220,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
 					struct v4l2_tuner *v)
 					struct v4l2_tuner *v)
 {
 {
-	int mult;
 	struct fmr2 *fmr2 = video_drvdata(file);
 	struct fmr2 *fmr2 = video_drvdata(file);
 
 
 	if (v->index > 0)
 	if (v->index > 0)
@@ -230,13 +228,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 	strlcpy(v->name, "FM", sizeof(v->name));
 	strlcpy(v->name, "FM", sizeof(v->name));
 	v->type = V4L2_TUNER_RADIO;
 	v->type = V4L2_TUNER_RADIO;
 
 
-	mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
-	v->rangelow = RSF16_MINFREQ / mult;
-	v->rangehigh = RSF16_MAXFREQ / mult;
-	v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-	v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW;
-	v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
-				V4L2_TUNER_MODE_MONO;
+	v->rangelow = RSF16_MINFREQ;
+	v->rangehigh = RSF16_MAXFREQ;
+	v->rxsubchans = fmr2->stereo ? V4L2_TUNER_SUB_STEREO :
+					V4L2_TUNER_SUB_MONO;
+	v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
+	v->audmode = V4L2_TUNER_MODE_STEREO;
 	mutex_lock(&fmr2->lock);
 	mutex_lock(&fmr2->lock);
 	v->signal = fmr2_getsigstr(fmr2);
 	v->signal = fmr2_getsigstr(fmr2);
 	mutex_unlock(&fmr2->lock);
 	mutex_unlock(&fmr2->lock);
@@ -254,8 +251,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
 {
 	struct fmr2 *fmr2 = video_drvdata(file);
 	struct fmr2 *fmr2 = video_drvdata(file);
 
 
-	if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
-		f->frequency *= 1000;
 	if (f->frequency < RSF16_MINFREQ ||
 	if (f->frequency < RSF16_MINFREQ ||
 			f->frequency > RSF16_MAXFREQ)
 			f->frequency > RSF16_MAXFREQ)
 		return -EINVAL;
 		return -EINVAL;
@@ -279,8 +274,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 
 
 	f->type = V4L2_TUNER_RADIO;
 	f->type = V4L2_TUNER_RADIO;
 	f->frequency = fmr2->curfreq;
 	f->frequency = fmr2->curfreq;
-	if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
-		f->frequency /= 1000;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -406,7 +399,6 @@ static int __init fmr2_init(void)
 	strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name));
 	strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name));
 	fmr2->io = io;
 	fmr2->io = io;
 	fmr2->stereo = 1;
 	fmr2->stereo = 1;
-	fmr2->flags = V4L2_TUNER_CAP_LOW;
 	mutex_init(&fmr2->lock);
 	mutex_init(&fmr2->lock);
 
 
 	if (!request_region(fmr2->io, 2, "sf16fmr2")) {
 	if (!request_region(fmr2->io, 2, "sf16fmr2")) {

+ 0 - 1
drivers/media/radio/radio-si470x.c

@@ -1214,7 +1214,6 @@ static int si470x_fops_release(struct file *file)
 		usb_autopm_put_interface(radio->intf);
 		usb_autopm_put_interface(radio->intf);
 	}
 	}
 
 
-unlock:
 	mutex_unlock(&radio->disconnect_lock);
 	mutex_unlock(&radio->disconnect_lock);
 
 
 done:
 done:

+ 19 - 1
drivers/media/video/Kconfig

@@ -440,6 +440,24 @@ config VIDEO_ADV7175
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called adv7175.
 	  module will be called adv7175.
 
 
+config VIDEO_THS7303
+	tristate "THS7303 Video Amplifier"
+	depends on I2C
+	help
+	  Support for TI THS7303 video amplifier
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ths7303.
+
+config VIDEO_ADV7343
+	tristate "ADV7343 video encoder"
+	depends on I2C
+	help
+	  Support for Analog Devices I2C bus based ADV7343 encoder.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adv7343.
+
 comment "Video improvement chips"
 comment "Video improvement chips"
 
 
 config VIDEO_UPD64031A
 config VIDEO_UPD64031A
@@ -694,7 +712,7 @@ config VIDEO_CAFE_CCIC
 
 
 config SOC_CAMERA
 config SOC_CAMERA
 	tristate "SoC camera support"
 	tristate "SoC camera support"
-	depends on VIDEO_V4L2 && HAS_DMA
+	depends on VIDEO_V4L2 && HAS_DMA && I2C
 	select VIDEOBUF_GEN
 	select VIDEOBUF_GEN
 	help
 	help
 	  SoC Camera is a common API to several cameras, not connecting
 	  SoC Camera is a common API to several cameras, not connecting

+ 43 - 36
drivers/media/video/Makefile

@@ -12,6 +12,8 @@ omap2cam-objs	:=	omap24xxcam.o omap24xxcam-dma.o
 
 
 videodev-objs	:=	v4l2-dev.o v4l2-ioctl.o v4l2-device.o
 videodev-objs	:=	v4l2-dev.o v4l2-ioctl.o v4l2-device.o
 
 
+# V4L2 core modules
+
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
 ifeq ($(CONFIG_COMPAT),y)
 ifeq ($(CONFIG_COMPAT),y)
   obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o
   obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o
@@ -23,21 +25,15 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
   obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
   obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
 endif
 endif
 
 
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+# All i2c modules must come first:
 
 
-obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
-
 obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
 obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
 obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
 obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
-obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
-obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
-obj-$(CONFIG_VIDEO_W9966) += w9966.o
-
 obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
 obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
 obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
 obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
 obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
 obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
@@ -49,16 +45,47 @@ obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
 obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
 obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
 obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
 obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
 obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
 obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
+obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
 obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
 obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
 obj-$(CONFIG_VIDEO_BT819) += bt819.o
 obj-$(CONFIG_VIDEO_BT819) += bt819.o
 obj-$(CONFIG_VIDEO_BT856) += bt856.o
 obj-$(CONFIG_VIDEO_BT856) += bt856.o
 obj-$(CONFIG_VIDEO_BT866) += bt866.o
 obj-$(CONFIG_VIDEO_BT866) += bt866.o
 obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
 obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
+obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
+obj-$(CONFIG_VIDEO_VINO) += indycam.o
+obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
+obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
+obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
+obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_M52790) += m52790.o
+obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
+obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
+obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
+obj-$(CONFIG_VIDEO_CX25840) += cx25840/
+obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
+obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_OV7670) 	+= ov7670.o
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 
 
-obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9M111)	+= mt9m111.o
+obj-$(CONFIG_SOC_CAMERA_MT9T031)	+= mt9t031.o
+obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV772X)		+= ov772x.o
+obj-$(CONFIG_SOC_CAMERA_TW9910)		+= tw9910.o
 
 
+# And now the v4l2 drivers:
+
+obj-$(CONFIG_VIDEO_BT848) += bt8xx/
+obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
+obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
+obj-$(CONFIG_VIDEO_W9966) += w9966.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
-obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
+obj-$(CONFIG_VIDEO_VINO) += vino.o
 obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
 obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
 obj-$(CONFIG_VIDEO_CPIA) += cpia.o
 obj-$(CONFIG_VIDEO_CPIA) += cpia.o
 obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
 obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
@@ -69,17 +96,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
 obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
-obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
-obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
-obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
-obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
-obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
-obj-$(CONFIG_VIDEO_M52790) += m52790.o
-obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
-obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
-obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
-obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
@@ -92,19 +109,12 @@ obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
 obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
 obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
 obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
-obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 
 
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 
 
-obj-$(CONFIG_VIDEO_CX25840) += cx25840/
-obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
-obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 
 
 obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
 obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
-obj-$(CONFIG_VIDEO_OV7670) 	+= ov7670.o
-
-obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 
 
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
@@ -134,24 +144,21 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
 
+obj-$(CONFIG_VIDEO_OMAP2)		+= omap2cam.o
+obj-$(CONFIG_SOC_CAMERA)		+= soc_camera.o
+obj-$(CONFIG_SOC_CAMERA_PLATFORM)	+= soc_camera_platform.o
+# soc-camera host drivers have to be linked after camera drivers
 obj-$(CONFIG_VIDEO_MX1)			+= mx1_camera.o
 obj-$(CONFIG_VIDEO_MX1)			+= mx1_camera.o
 obj-$(CONFIG_VIDEO_MX3)			+= mx3_camera.o
 obj-$(CONFIG_VIDEO_MX3)			+= mx3_camera.o
 obj-$(CONFIG_VIDEO_PXA27x)		+= pxa_camera.o
 obj-$(CONFIG_VIDEO_PXA27x)		+= pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
-obj-$(CONFIG_VIDEO_OMAP2)		+= omap2cam.o
-obj-$(CONFIG_SOC_CAMERA)		+= soc_camera.o
-obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
-obj-$(CONFIG_SOC_CAMERA_MT9M111)	+= mt9m111.o
-obj-$(CONFIG_SOC_CAMERA_MT9T031)	+= mt9t031.o
-obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
-obj-$(CONFIG_SOC_CAMERA_OV772X)		+= ov772x.o
-obj-$(CONFIG_SOC_CAMERA_PLATFORM)	+= soc_camera_platform.o
-obj-$(CONFIG_SOC_CAMERA_TW9910)		+= tw9910.o
 
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 
 
 obj-$(CONFIG_USB_VIDEO_CLASS)	+= uvc/
 obj-$(CONFIG_USB_VIDEO_CLASS)	+= uvc/
 
 
+obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
 EXTRA_CFLAGS += -Idrivers/media/common/tuners

+ 534 - 0
drivers/media/video/adv7343.c

@@ -0,0 +1,534 @@
+/*
+ * adv7343 - ADV7343 Video Encoder Driver
+ *
+ * The encoder hardware does not support SECAM.
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+
+#include <media/adv7343.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "adv7343_regs.h"
+
+MODULE_DESCRIPTION("ADV7343 video encoder driver");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+struct adv7343_state {
+	struct v4l2_subdev sd;
+	u8 reg00;
+	u8 reg01;
+	u8 reg02;
+	u8 reg35;
+	u8 reg80;
+	u8 reg82;
+	int bright;
+	int hue;
+	int gain;
+	u32 output;
+	v4l2_std_id std;
+};
+
+static inline struct adv7343_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7343_state, sd);
+}
+
+static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static const u8 adv7343_init_reg_val[] = {
+	ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT,
+	ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT,
+
+	ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT,
+	ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT,
+	ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT,
+	ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT,
+	ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT,
+	ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT,
+	ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT,
+
+	ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT,
+	ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT,
+	ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT,
+	ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT,
+	ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT,
+	ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT,
+	ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT,
+	ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT,
+
+	ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT,
+	ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT,
+	ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT,
+};
+
+/*
+ * 			    2^32
+ * FSC(reg) =  FSC (HZ) * --------
+ *			  27000000
+ */
+static const struct adv7343_std_info stdinfo[] = {
+	{
+		/* FSC(Hz) = 3,579,545.45 Hz */
+		SD_STD_NTSC, 569408542, V4L2_STD_NTSC,
+	}, {
+		/* FSC(Hz) = 3,575,611.00 Hz */
+		SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M,
+	}, {
+		/* FSC(Hz) = 3,582,056.00 */
+		SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc,
+	}, {
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N,
+	}, {
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL,
+	}, {
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443,
+	}, {
+		/* FSC(Hz) = 4,433,618.75 Hz */
+		SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60,
+	},
+};
+
+static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7343_state *state = to_state(sd);
+	struct adv7343_std_info *std_info;
+	int output_idx, num_std;
+	char *fsc_ptr;
+	u8 reg, val;
+	int err = 0;
+	int i = 0;
+
+	output_idx = state->output;
+
+	std_info = (struct adv7343_std_info *)stdinfo;
+	num_std = ARRAY_SIZE(stdinfo);
+
+	for (i = 0; i < num_std; i++) {
+		if (std_info[i].stdid & std)
+			break;
+	}
+
+	if (i == num_std) {
+		v4l2_dbg(1, debug, sd,
+				"Invalid std or std is not supported: %llx\n",
+						(unsigned long long)std);
+		return -EINVAL;
+	}
+
+	/* Set the standard */
+	val = state->reg80 & (~(SD_STD_MASK));
+	val |= std_info[i].standard_val3;
+	err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
+	if (err < 0)
+		goto setstd_exit;
+
+	state->reg80 = val;
+
+	/* Configure the input mode register */
+	val = state->reg01 & (~((u8) INPUT_MODE_MASK));
+	val |= SD_INPUT_MODE;
+	err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val);
+	if (err < 0)
+		goto setstd_exit;
+
+	state->reg01 = val;
+
+	/* Program the sub carrier frequency registers */
+	fsc_ptr = (unsigned char *)&std_info[i].fsc_val;
+	reg = ADV7343_FSC_REG0;
+	for (i = 0; i < 4; i++, reg++, fsc_ptr++) {
+		err = adv7343_write(sd, reg, *fsc_ptr);
+		if (err < 0)
+			goto setstd_exit;
+	}
+
+	val = state->reg80;
+
+	/* Filter settings */
+	if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443))
+		val &= 0x03;
+	else if (std & ~V4L2_STD_SECAM)
+		val |= 0x04;
+
+	err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
+	if (err < 0)
+		goto setstd_exit;
+
+	state->reg80 = val;
+
+setstd_exit:
+	if (err != 0)
+		v4l2_err(sd, "Error setting std, write failed\n");
+
+	return err;
+}
+
+static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
+{
+	struct adv7343_state *state = to_state(sd);
+	unsigned char val;
+	int err = 0;
+
+	if (output_type > ADV7343_SVIDEO_ID) {
+		v4l2_dbg(1, debug, sd,
+			"Invalid output type or output type not supported:%d\n",
+								output_type);
+		return -EINVAL;
+	}
+
+	/* Enable Appropriate DAC */
+	val = state->reg00 & 0x03;
+
+	if (output_type == ADV7343_COMPOSITE_ID)
+		val |= ADV7343_COMPOSITE_POWER_VALUE;
+	else if (output_type == ADV7343_COMPONENT_ID)
+		val |= ADV7343_COMPONENT_POWER_VALUE;
+	else
+		val |= ADV7343_SVIDEO_POWER_VALUE;
+
+	err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg00 = val;
+
+	/* Enable YUV output */
+	val = state->reg02 | YUV_OUTPUT_SELECT;
+	err = adv7343_write(sd, ADV7343_MODE_REG0, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg02 = val;
+
+	/* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */
+	val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI);
+	err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg82 = val;
+
+	/* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to
+	 * zero */
+	val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI);
+	err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val);
+	if (err < 0)
+		goto setoutput_exit;
+
+	state->reg35 = val;
+
+setoutput_exit:
+	if (err != 0)
+		v4l2_err(sd, "Error setting output, write failed\n");
+
+	return err;
+}
+
+static int adv7343_log_status(struct v4l2_subdev *sd)
+{
+	struct adv7343_state *state = to_state(sd);
+
+	v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std);
+	v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" :
+			((state->output == 1) ? "Component" : "S-Video"));
+	return 0;
+}
+
+static int adv7343_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+	switch (qc->id) {
+	case V4L2_CID_BRIGHTNESS:
+		return v4l2_ctrl_query_fill(qc, ADV7343_BRIGHTNESS_MIN,
+						ADV7343_BRIGHTNESS_MAX, 1,
+						ADV7343_BRIGHTNESS_DEF);
+	case V4L2_CID_HUE:
+		return v4l2_ctrl_query_fill(qc, ADV7343_HUE_MIN,
+						ADV7343_HUE_MAX, 1 ,
+						ADV7343_HUE_DEF);
+	case V4L2_CID_GAIN:
+		return v4l2_ctrl_query_fill(qc, ADV7343_GAIN_MIN,
+						ADV7343_GAIN_MAX, 1,
+						ADV7343_GAIN_DEF);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int adv7343_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct adv7343_state *state = to_state(sd);
+	int err = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		if (ctrl->value < ADV7343_BRIGHTNESS_MIN ||
+					ctrl->value > ADV7343_BRIGHTNESS_MAX) {
+			v4l2_dbg(1, debug, sd,
+					"invalid brightness settings %d\n",
+								ctrl->value);
+			return -ERANGE;
+		}
+
+		state->bright = ctrl->value;
+		err = adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,
+					state->bright);
+		break;
+
+	case V4L2_CID_HUE:
+		if (ctrl->value < ADV7343_HUE_MIN ||
+					ctrl->value > ADV7343_HUE_MAX) {
+			v4l2_dbg(1, debug, sd, "invalid hue settings %d\n",
+								ctrl->value);
+			return -ERANGE;
+		}
+
+		state->hue = ctrl->value;
+		err = adv7343_write(sd, ADV7343_SD_HUE_REG, state->hue);
+		break;
+
+	case V4L2_CID_GAIN:
+		if (ctrl->value < ADV7343_GAIN_MIN ||
+					ctrl->value > ADV7343_GAIN_MAX) {
+			v4l2_dbg(1, debug, sd, "invalid gain settings %d\n",
+								ctrl->value);
+			return -ERANGE;
+		}
+
+		if ((ctrl->value > POSITIVE_GAIN_MAX) &&
+			(ctrl->value < NEGATIVE_GAIN_MIN)) {
+			v4l2_dbg(1, debug, sd,
+				"gain settings not within the specified range\n");
+			return -ERANGE;
+		}
+
+		state->gain = ctrl->value;
+		err = adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, state->gain);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (err < 0)
+		v4l2_err(sd, "Failed to set the encoder controls\n");
+
+	return err;
+}
+
+static int adv7343_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+	struct adv7343_state *state = to_state(sd);
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		ctrl->value = state->bright;
+		break;
+
+	case V4L2_CID_HUE:
+		ctrl->value = state->hue;
+		break;
+
+	case V4L2_CID_GAIN:
+		ctrl->value = state->gain;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
+				struct v4l2_dbg_chip_ident *chip)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0);
+}
+
+static const struct v4l2_subdev_core_ops adv7343_core_ops = {
+	.log_status	= adv7343_log_status,
+	.g_chip_ident	= adv7343_g_chip_ident,
+	.g_ctrl		= adv7343_g_ctrl,
+	.s_ctrl		= adv7343_s_ctrl,
+	.queryctrl	= adv7343_queryctrl,
+};
+
+static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7343_state *state = to_state(sd);
+	int err = 0;
+
+	if (state->std == std)
+		return 0;
+
+	err = adv7343_setstd(sd, std);
+	if (!err)
+		state->std = std;
+
+	return err;
+}
+
+static int adv7343_s_routing(struct v4l2_subdev *sd,
+		u32 input, u32 output, u32 config)
+{
+	struct adv7343_state *state = to_state(sd);
+	int err = 0;
+
+	if (state->output == output)
+		return 0;
+
+	err = adv7343_setoutput(sd, output);
+	if (!err)
+		state->output = output;
+
+	return err;
+}
+
+static const struct v4l2_subdev_video_ops adv7343_video_ops = {
+	.s_std_output	= adv7343_s_std_output,
+	.s_routing	= adv7343_s_routing,
+};
+
+static const struct v4l2_subdev_ops adv7343_ops = {
+	.core	= &adv7343_core_ops,
+	.video	= &adv7343_video_ops,
+};
+
+static int adv7343_initialize(struct v4l2_subdev *sd)
+{
+	struct adv7343_state *state = to_state(sd);
+	int err = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) {
+
+		err = adv7343_write(sd, adv7343_init_reg_val[i],
+					adv7343_init_reg_val[i+1]);
+		if (err) {
+			v4l2_err(sd, "Error initializing\n");
+			return err;
+		}
+	}
+
+	/* Configure for default video standard */
+	err = adv7343_setoutput(sd, state->output);
+	if (err < 0) {
+		v4l2_err(sd, "Error setting output during init\n");
+		return -EINVAL;
+	}
+
+	err = adv7343_setstd(sd, state->std);
+	if (err < 0) {
+		v4l2_err(sd, "Error setting std during init\n");
+		return -EINVAL;
+	}
+
+	return err;
+}
+
+static int adv7343_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct adv7343_state *state;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+
+	state->reg00	= 0x80;
+	state->reg01	= 0x00;
+	state->reg02	= 0x20;
+	state->reg35	= 0x00;
+	state->reg80	= ADV7343_SD_MODE_REG1_DEFAULT;
+	state->reg82	= ADV7343_SD_MODE_REG2_DEFAULT;
+
+	state->output = ADV7343_COMPOSITE_ID;
+	state->std = V4L2_STD_NTSC;
+
+	v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops);
+	return adv7343_initialize(&state->sd);
+}
+
+static int adv7343_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+	v4l2_device_unregister_subdev(sd);
+	kfree(to_state(sd));
+
+	return 0;
+}
+
+static const struct i2c_device_id adv7343_id[] = {
+	{"adv7343", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, adv7343_id);
+
+static struct i2c_driver adv7343_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "adv7343",
+	},
+	.probe		= adv7343_probe,
+	.remove		= adv7343_remove,
+	.id_table	= adv7343_id,
+};
+
+static __init int init_adv7343(void)
+{
+	return i2c_add_driver(&adv7343_driver);
+}
+
+static __exit void exit_adv7343(void)
+{
+	i2c_del_driver(&adv7343_driver);
+}
+
+module_init(init_adv7343);
+module_exit(exit_adv7343);

+ 185 - 0
drivers/media/video/adv7343_regs.h

@@ -0,0 +1,185 @@
+/*
+ * ADV7343 encoder related structure and register definitions
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef ADV7343_REG_H
+#define ADV7343_REGS_H
+
+struct adv7343_std_info {
+	u32 standard_val3;
+	u32 fsc_val;
+	v4l2_std_id stdid;
+};
+
+/* Register offset macros */
+#define ADV7343_POWER_MODE_REG		(0x00)
+#define ADV7343_MODE_SELECT_REG		(0x01)
+#define ADV7343_MODE_REG0		(0x02)
+
+#define ADV7343_DAC2_OUTPUT_LEVEL	(0x0b)
+
+#define ADV7343_SOFT_RESET		(0x17)
+
+#define ADV7343_HD_MODE_REG1		(0x30)
+#define ADV7343_HD_MODE_REG2		(0x31)
+#define ADV7343_HD_MODE_REG3		(0x32)
+#define ADV7343_HD_MODE_REG4		(0x33)
+#define ADV7343_HD_MODE_REG5		(0x34)
+#define ADV7343_HD_MODE_REG6		(0x35)
+
+#define ADV7343_HD_MODE_REG7		(0x39)
+
+#define ADV7343_SD_MODE_REG1		(0x80)
+#define ADV7343_SD_MODE_REG2		(0x82)
+#define ADV7343_SD_MODE_REG3		(0x83)
+#define ADV7343_SD_MODE_REG4		(0x84)
+#define ADV7343_SD_MODE_REG5		(0x86)
+#define ADV7343_SD_MODE_REG6		(0x87)
+#define ADV7343_SD_MODE_REG7		(0x88)
+#define ADV7343_SD_MODE_REG8		(0x89)
+
+#define ADV7343_FSC_REG0		(0x8C)
+#define ADV7343_FSC_REG1		(0x8D)
+#define ADV7343_FSC_REG2		(0x8E)
+#define ADV7343_FSC_REG3		(0x8F)
+
+#define ADV7343_SD_CGMS_WSS0		(0x99)
+
+#define ADV7343_SD_HUE_REG		(0xA0)
+#define ADV7343_SD_BRIGHTNESS_WSS	(0xA1)
+
+/* Default values for the registers */
+#define ADV7343_POWER_MODE_REG_DEFAULT		(0x10)
+#define ADV7343_HD_MODE_REG1_DEFAULT		(0x3C)	/* Changed Default
+							   720p EAVSAV code*/
+#define ADV7343_HD_MODE_REG2_DEFAULT		(0x01)	/* Changed Pixel data
+							   valid */
+#define ADV7343_HD_MODE_REG3_DEFAULT		(0x00)	/* Color delay 0 clks */
+#define ADV7343_HD_MODE_REG4_DEFAULT		(0xE8)	/* Changed */
+#define ADV7343_HD_MODE_REG5_DEFAULT		(0x08)
+#define ADV7343_HD_MODE_REG6_DEFAULT		(0x00)
+#define ADV7343_HD_MODE_REG7_DEFAULT		(0x00)
+#define ADV7343_SD_MODE_REG8_DEFAULT		(0x00)
+#define ADV7343_SOFT_RESET_DEFAULT		(0x02)
+#define ADV7343_COMPOSITE_POWER_VALUE		(0x80)
+#define ADV7343_COMPONENT_POWER_VALUE		(0x1C)
+#define ADV7343_SVIDEO_POWER_VALUE		(0x60)
+#define ADV7343_SD_HUE_REG_DEFAULT		(127)
+#define ADV7343_SD_BRIGHTNESS_WSS_DEFAULT	(0x03)
+
+#define ADV7343_SD_CGMS_WSS0_DEFAULT		(0x10)
+
+#define ADV7343_SD_MODE_REG1_DEFAULT		(0x00)
+#define ADV7343_SD_MODE_REG2_DEFAULT		(0xC9)
+#define ADV7343_SD_MODE_REG3_DEFAULT		(0x10)
+#define ADV7343_SD_MODE_REG4_DEFAULT		(0x01)
+#define ADV7343_SD_MODE_REG5_DEFAULT		(0x02)
+#define ADV7343_SD_MODE_REG6_DEFAULT		(0x0C)
+#define ADV7343_SD_MODE_REG7_DEFAULT		(0x04)
+#define ADV7343_SD_MODE_REG8_DEFAULT		(0x00)
+
+/* Bit masks for Mode Select Register */
+#define INPUT_MODE_MASK			(0x70)
+#define SD_INPUT_MODE			(0x00)
+#define HD_720P_INPUT_MODE		(0x10)
+#define HD_1080I_INPUT_MODE		(0x10)
+
+/* Bit masks for Mode Register 0 */
+#define TEST_PATTERN_BLACK_BAR_EN	(0x04)
+#define YUV_OUTPUT_SELECT		(0x20)
+#define RGB_OUTPUT_SELECT		(0xDF)
+
+/* Bit masks for DAC output levels */
+#define DAC_OUTPUT_LEVEL_MASK		(0xFF)
+#define POSITIVE_GAIN_MAX		(0x40)
+#define POSITIVE_GAIN_MIN		(0x00)
+#define NEGATIVE_GAIN_MAX		(0xFF)
+#define NEGATIVE_GAIN_MIN		(0xC0)
+
+/* Bit masks for soft reset register */
+#define SOFT_RESET			(0x02)
+
+/* Bit masks for HD Mode Register 1 */
+#define OUTPUT_STD_MASK		(0x03)
+#define OUTPUT_STD_SHIFT	(0)
+#define OUTPUT_STD_EIA0_2	(0x00)
+#define OUTPUT_STD_EIA0_1	(0x01)
+#define OUTPUT_STD_FULL		(0x02)
+#define EMBEDDED_SYNC		(0x04)
+#define EXTERNAL_SYNC		(0xFB)
+#define STD_MODE_SHIFT		(3)
+#define STD_MODE_MASK		(0x1F)
+#define STD_MODE_720P		(0x05)
+#define STD_MODE_720P_25	(0x08)
+#define STD_MODE_720P_30	(0x07)
+#define STD_MODE_720P_50	(0x06)
+#define STD_MODE_1080I		(0x0D)
+#define STD_MODE_1080I_25fps	(0x0E)
+#define STD_MODE_1080P_24	(0x12)
+#define STD_MODE_1080P_25	(0x10)
+#define STD_MODE_1080P_30	(0x0F)
+#define STD_MODE_525P		(0x00)
+#define STD_MODE_625P		(0x03)
+
+/* Bit masks for SD Mode Register 1 */
+#define SD_STD_MASK		(0x03)
+#define SD_STD_NTSC		(0x00)
+#define SD_STD_PAL_BDGHI	(0x01)
+#define SD_STD_PAL_M		(0x02)
+#define SD_STD_PAL_N		(0x03)
+#define SD_LUMA_FLTR_MASK	(0x7)
+#define SD_LUMA_FLTR_SHIFT	(0x2)
+#define SD_CHROMA_FLTR_MASK	(0x7)
+#define SD_CHROMA_FLTR_SHIFT	(0x5)
+
+/* Bit masks for SD Mode Register 2 */
+#define SD_PBPR_SSAF_EN		(0x01)
+#define SD_PBPR_SSAF_DI		(0xFE)
+#define SD_DAC_1_DI		(0xFD)
+#define SD_DAC_2_DI		(0xFB)
+#define SD_PEDESTAL_EN		(0x08)
+#define SD_PEDESTAL_DI		(0xF7)
+#define SD_SQUARE_PIXEL_EN	(0x10)
+#define SD_SQUARE_PIXEL_DI	(0xEF)
+#define SD_PIXEL_DATA_VALID	(0x40)
+#define SD_ACTIVE_EDGE_EN	(0x80)
+#define SD_ACTIVE_EDGE_DI	(0x7F)
+
+/* Bit masks for HD Mode Register 6 */
+#define HD_RGB_INPUT_EN		(0x02)
+#define HD_RGB_INPUT_DI		(0xFD)
+#define HD_PBPR_SYNC_EN		(0x04)
+#define HD_PBPR_SYNC_DI		(0xFB)
+#define HD_DAC_SWAP_EN		(0x08)
+#define HD_DAC_SWAP_DI		(0xF7)
+#define HD_GAMMA_CURVE_A	(0xEF)
+#define HD_GAMMA_CURVE_B	(0x10)
+#define HD_GAMMA_EN		(0x20)
+#define HD_GAMMA_DI		(0xDF)
+#define HD_ADPT_FLTR_MODEB	(0x40)
+#define HD_ADPT_FLTR_MODEA	(0xBF)
+#define HD_ADPT_FLTR_EN		(0x80)
+#define HD_ADPT_FLTR_DI		(0x7F)
+
+#define ADV7343_BRIGHTNESS_MAX	(127)
+#define ADV7343_BRIGHTNESS_MIN	(0)
+#define ADV7343_BRIGHTNESS_DEF	(3)
+#define ADV7343_HUE_MAX		(255)
+#define ADV7343_HUE_MIN		(0)
+#define ADV7343_HUE_DEF		(127)
+#define ADV7343_GAIN_MAX	(255)
+#define ADV7343_GAIN_MIN	(0)
+#define ADV7343_GAIN_DEF	(0)
+
+#endif

+ 2 - 2
drivers/media/video/au0828/au0828-cards.c

@@ -136,9 +136,9 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg)
 			/* Tuner Reset Command from xc5000 */
 			/* Tuner Reset Command from xc5000 */
 			/* Drive the tuner into reset and out */
 			/* Drive the tuner into reset and out */
 			au0828_clear(dev, REG_001, 2);
 			au0828_clear(dev, REG_001, 2);
-			mdelay(200);
+			mdelay(10);
 			au0828_set(dev, REG_001, 2);
 			au0828_set(dev, REG_001, 2);
-			mdelay(50);
+			mdelay(10);
 			return 0;
 			return 0;
 		} else {
 		} else {
 			printk(KERN_ERR
 			printk(KERN_ERR

+ 17 - 0
drivers/media/video/au0828/au0828-core.c

@@ -36,6 +36,11 @@ int au0828_debug;
 module_param_named(debug, au0828_debug, int, 0644);
 module_param_named(debug, au0828_debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
 MODULE_PARM_DESC(debug, "enable debug messages");
 
 
+static unsigned int disable_usb_speed_check;
+module_param(disable_usb_speed_check, int, 0444);
+MODULE_PARM_DESC(disable_usb_speed_check,
+		 "override min bandwidth requirement of 480M bps");
+
 #define _AU0828_BULKPIPE 0x03
 #define _AU0828_BULKPIPE 0x03
 #define _BULKPIPESIZE 0xffff
 #define _BULKPIPESIZE 0xffff
 
 
@@ -181,6 +186,18 @@ static int au0828_usb_probe(struct usb_interface *interface,
 		le16_to_cpu(usbdev->descriptor.idProduct),
 		le16_to_cpu(usbdev->descriptor.idProduct),
 		ifnum);
 		ifnum);
 
 
+	/*
+	 * Make sure we have 480 Mbps of bandwidth, otherwise things like
+	 * video stream wouldn't likely work, since 12 Mbps is generally
+	 * not enough even for most Digital TV streams.
+	 */
+	if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
+		printk(KERN_ERR "au0828: Device initialization failed.\n");
+		printk(KERN_ERR "au0828: Device must be connected to a "
+		       "high-speed USB 2.0 port.\n");
+		return -ENODEV;
+	}
+
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL) {
 	if (dev == NULL) {
 		printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
 		printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);

+ 3 - 5
drivers/media/video/au0828/au0828-video.c

@@ -829,6 +829,9 @@ static int au0828_v4l2_close(struct file *filp)
 
 
 		au0828_uninit_isoc(dev);
 		au0828_uninit_isoc(dev);
 
 
+		/* Save some power by putting tuner to sleep */
+		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
+
 		/* When close the device, set the usb intf0 into alt0 to free
 		/* When close the device, set the usb intf0 into alt0 to free
 		   USB bandwidth */
 		   USB bandwidth */
 		ret = usb_set_interface(dev->usbdev, 0, 0);
 		ret = usb_set_interface(dev->usbdev, 0, 0);
@@ -910,11 +913,6 @@ static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
 
 
 	rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
 	rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
 
 
-	dprintk(2, "vma start=0x%08lx, size=%ld, ret=%d\n",
-		(unsigned long)vma->vm_start,
-		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
-		rc);
-
 	return rc;
 	return rc;
 }
 }
 
 

+ 8 - 6
drivers/media/video/bt8xx/bttv-driver.c

@@ -3152,6 +3152,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
 	struct bttv_fh *fh = file->private_data;
 	struct bttv_fh *fh = file->private_data;
 	struct bttv_buffer *buf;
 	struct bttv_buffer *buf;
 	enum v4l2_field field;
 	enum v4l2_field field;
+	unsigned int rc = POLLERR;
 
 
 	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
 	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
 		if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
 		if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
@@ -3160,9 +3161,10 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
 	}
 	}
 
 
 	if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
 	if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
+		mutex_lock(&fh->cap.vb_lock);
 		/* streaming capture */
 		/* streaming capture */
 		if (list_empty(&fh->cap.stream))
 		if (list_empty(&fh->cap.stream))
-			return POLLERR;
+			goto err;
 		buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
 		buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
 	} else {
 	} else {
 		/* read() capture */
 		/* read() capture */
@@ -3191,11 +3193,12 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
 	poll_wait(file, &buf->vb.done, wait);
 	poll_wait(file, &buf->vb.done, wait);
 	if (buf->vb.state == VIDEOBUF_DONE ||
 	if (buf->vb.state == VIDEOBUF_DONE ||
 	    buf->vb.state == VIDEOBUF_ERROR)
 	    buf->vb.state == VIDEOBUF_ERROR)
-		return POLLIN|POLLRDNORM;
-	return 0;
+		rc =  POLLIN|POLLRDNORM;
+	else
+		rc = 0;
 err:
 err:
 	mutex_unlock(&fh->cap.vb_lock);
 	mutex_unlock(&fh->cap.vb_lock);
-	return POLLERR;
+	return rc;
 }
 }
 
 
 static int bttv_open(struct file *file)
 static int bttv_open(struct file *file)
@@ -4166,7 +4169,6 @@ static struct video_device *vdev_init(struct bttv *btv,
 	if (NULL == vfd)
 	if (NULL == vfd)
 		return NULL;
 		return NULL;
 	*vfd = *template;
 	*vfd = *template;
-	vfd->minor   = -1;
 	vfd->v4l2_dev = &btv->c.v4l2_dev;
 	vfd->v4l2_dev = &btv->c.v4l2_dev;
 	vfd->release = video_device_release;
 	vfd->release = video_device_release;
 	vfd->debug   = bttv_debug;
 	vfd->debug   = bttv_debug;
@@ -4629,7 +4631,7 @@ static int __init bttv_init_module(void)
 #endif
 #endif
 	if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
 	if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
 		gbuffers = 2;
 		gbuffers = 2;
-	if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
+	if (gbufsize > BTTV_MAX_FBUF)
 		gbufsize = BTTV_MAX_FBUF;
 		gbufsize = BTTV_MAX_FBUF;
 	gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
 	gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
 	if (bttv_verbose)
 	if (bttv_verbose)

+ 21 - 0
drivers/media/video/bt8xx/bttv-i2c.c

@@ -389,6 +389,27 @@ int __devinit init_bttv_i2c(struct bttv *btv)
 	}
 	}
 	if (0 == btv->i2c_rc && i2c_scan)
 	if (0 == btv->i2c_rc && i2c_scan)
 		do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
 		do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
+
+	/* Instantiate the IR receiver device, if present */
+	if (0 == btv->i2c_rc) {
+		struct i2c_board_info info;
+		/* The external IR receiver is at i2c address 0x34 (0x35 for
+		   reads).  Future Hauppauge cards will have an internal
+		   receiver at 0x30 (0x31 for reads).  In theory, both can be
+		   fitted, and Hauppauge suggest an external overrides an
+		   internal.
+
+		   That's why we probe 0x1a (~0x34) first. CB
+		*/
+		const unsigned short addr_list[] = {
+			0x1a, 0x18, 0x4b, 0x64, 0x30,
+			I2C_CLIENT_END
+		};
+
+		memset(&info, 0, sizeof(struct i2c_board_info));
+		strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+		i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list);
+	}
 	return btv->i2c_rc;
 	return btv->i2c_rc;
 }
 }
 
 

+ 3 - 3
drivers/media/video/cpia2/cpia2_v4l.c

@@ -1064,7 +1064,7 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam)
 
 
 	switch(m->id) {
 	switch(m->id) {
 	case CPIA2_CID_FLICKER_MODE:
 	case CPIA2_CID_FLICKER_MODE:
-		if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS)
+		if (m->index >= NUM_FLICKER_CONTROLS)
 			return -EINVAL;
 			return -EINVAL;
 
 
 		strcpy(m->name, flicker_controls[m->index].name);
 		strcpy(m->name, flicker_controls[m->index].name);
@@ -1082,14 +1082,14 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam)
 					maximum = i;
 					maximum = i;
 			}
 			}
 		}
 		}
-		if(m->index < 0 || m->index > maximum)
+		if (m->index > maximum)
 			return -EINVAL;
 			return -EINVAL;
 
 
 		strcpy(m->name, framerate_controls[m->index].name);
 		strcpy(m->name, framerate_controls[m->index].name);
 		break;
 		break;
 	    }
 	    }
 	case CPIA2_CID_LIGHTS:
 	case CPIA2_CID_LIGHTS:
-		if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS)
+		if (m->index >= NUM_LIGHTS_CONTROLS)
 			return -EINVAL;
 			return -EINVAL;
 
 
 		strcpy(m->name, lights_controls[m->index].name);
 		strcpy(m->name, lights_controls[m->index].name);

+ 38 - 6
drivers/media/video/cx18/cx18-audio.c

@@ -26,14 +26,18 @@
 #include "cx18-cards.h"
 #include "cx18-cards.h"
 #include "cx18-audio.h"
 #include "cx18-audio.h"
 
 
-#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_AUDIO_ENABLE    0xc72014
+#define CX18_AI1_MUX_MASK    0x30
+#define CX18_AI1_MUX_I2S1    0x00
+#define CX18_AI1_MUX_I2S2    0x10
+#define CX18_AI1_MUX_843_I2S 0x20
 
 
 /* Selects the audio input and output according to the current
 /* Selects the audio input and output according to the current
    settings. */
    settings. */
 int cx18_audio_set_io(struct cx18 *cx)
 int cx18_audio_set_io(struct cx18 *cx)
 {
 {
 	const struct cx18_card_audio_input *in;
 	const struct cx18_card_audio_input *in;
-	u32 val;
+	u32 u, v;
 	int err;
 	int err;
 
 
 	/* Determine which input to use */
 	/* Determine which input to use */
@@ -52,9 +56,37 @@ int cx18_audio_set_io(struct cx18 *cx)
 		return err;
 		return err;
 
 
 	/* FIXME - this internal mux should be abstracted to a subdev */
 	/* FIXME - this internal mux should be abstracted to a subdev */
-	val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30;
-	val |= (in->audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
-					(in->audio_input << 4);
-	cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30);
+	u = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+	v = u & ~CX18_AI1_MUX_MASK;
+	switch (in->audio_input) {
+	case CX18_AV_AUDIO_SERIAL1:
+		v |= CX18_AI1_MUX_I2S1;
+		break;
+	case CX18_AV_AUDIO_SERIAL2:
+		v |= CX18_AI1_MUX_I2S2;
+		break;
+	default:
+		v |= CX18_AI1_MUX_843_I2S;
+		break;
+	}
+	if (v == u) {
+		/* force a toggle of some AI1 MUX control bits */
+		u &= ~CX18_AI1_MUX_MASK;
+		switch (in->audio_input) {
+		case CX18_AV_AUDIO_SERIAL1:
+			u |= CX18_AI1_MUX_843_I2S;
+			break;
+		case CX18_AV_AUDIO_SERIAL2:
+			u |= CX18_AI1_MUX_843_I2S;
+			break;
+		default:
+			u |= CX18_AI1_MUX_I2S1;
+			break;
+		}
+		cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE,
+				      u, CX18_AI1_MUX_MASK);
+	}
+	cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+			      v, CX18_AI1_MUX_MASK);
 	return 0;
 	return 0;
 }
 }

+ 273 - 101
drivers/media/video/cx18/cx18-av-core.c

@@ -99,9 +99,39 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
 			     or_value);
 			     or_value);
 }
 }
 
 
-static void cx18_av_initialize(struct cx18 *cx)
+static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
 {
 {
-	struct cx18_av_state *state = &cx->av_state;
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+	/*
+	 * The crystal freq used in calculations in this driver will be
+	 * 28.636360 MHz.
+	 * Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
+	 */
+
+	/*
+	 * VDCLK  Integer = 0x0f, Post Divider = 0x04
+	 * AIMCLK Integer = 0x0e, Post Divider = 0x16
+	 */
+	cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
+
+	/* VDCLK Fraction = 0x2be2fe */
+	/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
+	cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
+
+	/* AIMCLK Fraction = 0x05227ad */
+	/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
+	cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
+
+	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+	cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+	return 0;
+}
+
+static void cx18_av_initialize(struct v4l2_subdev *sd)
+{
+	struct cx18_av_state *state = to_cx18_av_state(sd);
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
 	u32 v;
 	u32 v;
 
 
 	cx18_av_loadfw(cx);
 	cx18_av_loadfw(cx);
@@ -150,6 +180,26 @@ static void cx18_av_initialize(struct cx18 *cx)
 	cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000);
 	cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000);
 	cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0);
 	cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0);
 
 
+	/*
+	 * Disable Video Auto-config of the Analog Front End and Video PLL.
+	 *
+	 * Since we only use BT.656 pixel mode, which works for both 525 and 625
+	 * line systems, it's just easier for us to set registers
+	 * 0x102 (CXADEC_CHIP_CTRL), 0x104-0x106 (CXADEC_AFE_CTRL),
+	 * 0x108-0x109 (CXADEC_PLL_CTRL1), and 0x10c-0x10f (CXADEC_VID_PLL_FRAC)
+	 * ourselves, than to run around cleaning up after the auto-config.
+	 *
+	 * (Note: my CX23418 chip doesn't seem to let the ACFG_DIS bit
+	 * get set to 1, but OTOH, it doesn't seem to do AFE and VID PLL
+	 * autoconfig either.)
+	 *
+	 * As a default, also turn off Dual mode for ADC2 and set ADC2 to CH3.
+	 */
+	cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000);
+
+	/* Setup the Video and and Aux/Audio PLLs */
+	cx18_av_init(sd, 0);
+
 	/* set video to auto-detect */
 	/* set video to auto-detect */
 	/* Clear bits 11-12 to enable slow locking mode.  Set autodetect mode */
 	/* Clear bits 11-12 to enable slow locking mode.  Set autodetect mode */
 	/* set the comb notch = 1 */
 	/* set the comb notch = 1 */
@@ -176,12 +226,23 @@ static void cx18_av_initialize(struct cx18 *cx)
 	/* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */
 	/* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */
 	/* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */
 	/* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */
 
 
-	v = cx18_av_read4(cx, CXADEC_AFE_CTRL);
-	v &= 0xFFFBFFFF;            /* turn OFF bit 18 for droop_comp_ch1 */
-	v &= 0xFFFF7FFF;            /* turn OFF bit 9 for clamp_sel_ch1 */
-	v &= 0xFFFFFFFE;            /* turn OFF bit 0 for 12db_ch1 */
-	/* v |= 0x00000001;*/            /* turn ON bit 0 for 12db_ch1 */
-	cx18_av_write4(cx, CXADEC_AFE_CTRL, v);
+	/*
+	 * Analog Front End (AFE)
+	 * Default to luma on ch1/ADC1, chroma on ch2/ADC2, SIF on ch3/ADC2
+	 *  bypass_ch[1-3]     use filter
+	 *  droop_comp_ch[1-3] disable
+	 *  clamp_en_ch[1-3]   disable
+	 *  aud_in_sel         ADC2
+	 *  luma_in_sel        ADC1
+	 *  chroma_in_sel      ADC2
+	 *  clamp_sel_ch[2-3]  midcode
+	 *  clamp_sel_ch1      video decoder
+	 *  vga_sel_ch3        audio decoder
+	 *  vga_sel_ch[1-2]    video decoder
+	 *  half_bw_ch[1-3]    disable
+	 *  +12db_ch[1-3]      disable
+	 */
+	cx18_av_and_or4(cx, CXADEC_AFE_CTRL, 0xFF000000, 0x00005D00);
 
 
 /* 	if(dwEnable && dw3DCombAvailable) { */
 /* 	if(dwEnable && dw3DCombAvailable) { */
 /*      	CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */
 /*      	CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */
@@ -195,50 +256,18 @@ static void cx18_av_initialize(struct cx18 *cx)
 
 
 static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
 static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
 {
 {
-	struct cx18 *cx = v4l2_get_subdevdata(sd);
-
-	cx18_av_initialize(cx);
-	return 0;
-}
-
-static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
-{
-	struct cx18 *cx = v4l2_get_subdevdata(sd);
-
-	/*
-	 * The crystal freq used in calculations in this driver will be
-	 * 28.636360 MHz.
-	 * Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
-	 */
-
-	/*
-	 * VDCLK  Integer = 0x0f, Post Divider = 0x04
-	 * AIMCLK Integer = 0x0e, Post Divider = 0x16
-	 */
-	cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
-
-	/* VDCLK Fraction = 0x2be2fe */
-	/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
-	cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
-
-	/* AIMCLK Fraction = 0x05227ad */
-	/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
-	cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
-
-	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
-	cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+	cx18_av_initialize(sd);
 	return 0;
 	return 0;
 }
 }
 
 
 static int cx18_av_load_fw(struct v4l2_subdev *sd)
 static int cx18_av_load_fw(struct v4l2_subdev *sd)
 {
 {
 	struct cx18_av_state *state = to_cx18_av_state(sd);
 	struct cx18_av_state *state = to_cx18_av_state(sd);
-	struct cx18 *cx = v4l2_get_subdevdata(sd);
 
 
 	if (!state->is_initialized) {
 	if (!state->is_initialized) {
 		/* initialize on first use */
 		/* initialize on first use */
 		state->is_initialized = 1;
 		state->is_initialized = 1;
-		cx18_av_initialize(cx);
+		cx18_av_initialize(sd);
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -248,8 +277,15 @@ void cx18_av_std_setup(struct cx18 *cx)
 	struct cx18_av_state *state = &cx->av_state;
 	struct cx18_av_state *state = &cx->av_state;
 	struct v4l2_subdev *sd = &state->sd;
 	struct v4l2_subdev *sd = &state->sd;
 	v4l2_std_id std = state->std;
 	v4l2_std_id std = state->std;
+
+	/*
+	 * Video ADC crystal clock to pixel clock SRC decimation ratio
+	 * 28.636360 MHz/13.5 Mpps * 256 = 0x21f.07b
+	 */
+	const int src_decimation = 0x21f;
+
 	int hblank, hactive, burst, vblank, vactive, sc;
 	int hblank, hactive, burst, vblank, vactive, sc;
-	int vblank656, src_decimation;
+	int vblank656;
 	int luma_lpf, uv_lpf, comb;
 	int luma_lpf, uv_lpf, comb;
 	u32 pll_int, pll_frac, pll_post;
 	u32 pll_int, pll_frac, pll_post;
 
 
@@ -259,40 +295,96 @@ void cx18_av_std_setup(struct cx18 *cx)
 	else
 	else
 		cx18_av_write(cx, 0x49f, 0x14);
 		cx18_av_write(cx, 0x49f, 0x14);
 
 
+	/*
+	 * Note: At the end of a field, there are 3 sets of half line duration
+	 * (double horizontal rate) pulses:
+	 *
+	 * 5 (625) or 6 (525) half-lines to blank for the vertical retrace
+	 * 5 (625) or 6 (525) vertical sync pulses of half line duration
+	 * 5 (625) or 6 (525) half-lines of equalization pulses
+	 */
 	if (std & V4L2_STD_625_50) {
 	if (std & V4L2_STD_625_50) {
-		/* FIXME - revisit these for Sliced VBI */
+		/*
+		 * The following relationships of half line counts should hold:
+		 * 625 = vblank656 + vactive
+		 * 10 = vblank656 - vblank = vsync pulses + equalization pulses
+		 *
+		 * vblank656: half lines after line 625/mid-313 of blanked video
+		 * vblank:    half lines, after line 5/317, of blanked video
+		 * vactive:   half lines of active video +
+		 * 		5 half lines after the end of active video
+		 *
+		 * As far as I can tell:
+		 * vblank656 starts counting from the falling edge of the first
+		 * 	vsync pulse (start of line 1 or mid-313)
+		 * vblank starts counting from the after the 5 vsync pulses and
+		 * 	5 or 4 equalization pulses (start of line 6 or 318)
+		 *
+		 * For 625 line systems the driver will extract VBI information
+		 * from lines 6-23 and lines 318-335 (but the slicer can only
+		 * handle 17 lines, not the 18 in the vblank region).
+		 * In addition, we need vblank656 and vblank to be one whole
+		 * line longer, to cover line 24 and 336, so the SAV/EAV RP
+		 * codes get generated such that the encoder can actually
+		 * extract line 23 & 335 (WSS).  We'll lose 1 line in each field
+		 * at the top of the screen.
+		 *
+		 * It appears the 5 half lines that happen after active
+		 * video must be included in vactive (579 instead of 574),
+		 * otherwise the colors get badly displayed in various regions
+		 * of the screen.  I guess the chroma comb filter gets confused
+		 * without them (at least when a PVR-350 is the PAL source).
+		 */
+		vblank656 = 48; /* lines  1 -  24  &  313 - 336 */
+		vblank = 38;    /* lines  6 -  24  &  318 - 336 */
+		vactive = 579;  /* lines 24 - 313  &  337 - 626 */
+
+		/*
+		 * For a 13.5 Mpps clock and 15,625 Hz line rate, a line is
+		 * is 864 pixels = 720 active + 144 blanking.  ITU-R BT.601
+		 * specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after
+		 * the end of active video to start a horizontal line, so that
+		 * leaves 132 pixels of hblank to ignore.
+		 */
 		hblank = 132;
 		hblank = 132;
 		hactive = 720;
 		hactive = 720;
-		burst = 93;
-		vblank = 36;
-		vactive = 580;
-		vblank656 = 40;
-		src_decimation = 0x21f;
 
 
+		/*
+		 * Burst gate delay (for 625 line systems)
+		 * Hsync leading edge to color burst rise = 5.6 us
+		 * Color burst width = 2.25 us
+		 * Gate width = 4 pixel clocks
+		 * (5.6 us + 2.25/2 us) * 13.5 Mpps + 4/2 clocks = 92.79 clocks
+		 */
+		burst = 93;
 		luma_lpf = 2;
 		luma_lpf = 2;
 		if (std & V4L2_STD_PAL) {
 		if (std & V4L2_STD_PAL) {
 			uv_lpf = 1;
 			uv_lpf = 1;
 			comb = 0x20;
 			comb = 0x20;
-			sc = 688739;
+			/* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
+			sc = 688700;
 		} else if (std == V4L2_STD_PAL_Nc) {
 		} else if (std == V4L2_STD_PAL_Nc) {
 			uv_lpf = 1;
 			uv_lpf = 1;
 			comb = 0x20;
 			comb = 0x20;
-			sc = 556453;
+			/* sc = 3582056.25 * src_decimation/28636360 * 2^13 */
+			sc = 556422;
 		} else { /* SECAM */
 		} else { /* SECAM */
 			uv_lpf = 0;
 			uv_lpf = 0;
 			comb = 0;
 			comb = 0;
-			sc = 672351;
+			/* (fr + fb)/2 = (4406260 + 4250000)/2 = 4328130 */
+			/* sc = 4328130 * src_decimation/28636360 * 2^13 */
+			sc = 672314;
 		}
 		}
 	} else {
 	} else {
 		/*
 		/*
 		 * The following relationships of half line counts should hold:
 		 * The following relationships of half line counts should hold:
-		 * 525 = vsync + vactive + vblank656
-		 * 12 = vblank656 - vblank
+		 * 525 = prevsync + vblank656 + vactive
+		 * 12 = vblank656 - vblank = vsync pulses + equalization pulses
 		 *
 		 *
-		 * vsync:     always 6 half-lines of vsync pulses
-		 * vactive:   half lines of active video
+		 * prevsync:  6 half-lines before the vsync pulses
 		 * vblank656: half lines, after line 3/mid-266, of blanked video
 		 * vblank656: half lines, after line 3/mid-266, of blanked video
 		 * vblank:    half lines, after line 9/272, of blanked video
 		 * vblank:    half lines, after line 9/272, of blanked video
+		 * vactive:   half lines of active video
 		 *
 		 *
 		 * As far as I can tell:
 		 * As far as I can tell:
 		 * vblank656 starts counting from the falling edge of the first
 		 * vblank656 starts counting from the falling edge of the first
@@ -319,20 +411,30 @@ void cx18_av_std_setup(struct cx18 *cx)
 		luma_lpf = 1;
 		luma_lpf = 1;
 		uv_lpf = 1;
 		uv_lpf = 1;
 
 
-		src_decimation = 0x21f;
+		/*
+		 * Burst gate delay (for 525 line systems)
+		 * Hsync leading edge to color burst rise = 5.3 us
+		 * Color burst width = 2.5 us
+		 * Gate width = 4 pixel clocks
+		 * (5.3 us + 2.5/2 us) * 13.5 Mpps + 4/2 clocks = 90.425 clocks
+		 */
 		if (std == V4L2_STD_PAL_60) {
 		if (std == V4L2_STD_PAL_60) {
-			burst = 0x5b;
+			burst = 90;
 			luma_lpf = 2;
 			luma_lpf = 2;
 			comb = 0x20;
 			comb = 0x20;
-			sc = 688739;
+			/* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
+			sc = 688700;
 		} else if (std == V4L2_STD_PAL_M) {
 		} else if (std == V4L2_STD_PAL_M) {
-			burst = 0x61;
+			/* The 97 needs to be verified against PAL-M timings */
+			burst = 97;
 			comb = 0x20;
 			comb = 0x20;
-			sc = 555452;
+			/* sc = 3575611.49 * src_decimation/28636360 * 2^13 */
+			sc = 555421;
 		} else {
 		} else {
-			burst = 0x5b;
+			burst = 90;
 			comb = 0x66;
 			comb = 0x66;
-			sc = 556063;
+			/* sc = 3579545.45.. * src_decimation/28636360 * 2^13 */
+			sc = 556032;
 		}
 		}
 	}
 	}
 
 
@@ -344,23 +446,26 @@ void cx18_av_std_setup(struct cx18 *cx)
 			    pll_int, pll_frac, pll_post);
 			    pll_int, pll_frac, pll_post);
 
 
 	if (pll_post) {
 	if (pll_post) {
-		int fin, fsc, pll;
+		int fsc, pll;
+		u64 tmp;
 
 
 		pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
 		pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
 		pll /= pll_post;
 		pll /= pll_post;
-		CX18_DEBUG_INFO_DEV(sd, "PLL = %d.%06d MHz\n",
+		CX18_DEBUG_INFO_DEV(sd, "Video PLL = %d.%06d MHz\n",
 				    pll / 1000000, pll % 1000000);
 				    pll / 1000000, pll % 1000000);
-		CX18_DEBUG_INFO_DEV(sd, "PLL/8 = %d.%06d MHz\n",
+		CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n",
 				    pll / 8000000, (pll / 8) % 1000000);
 				    pll / 8000000, (pll / 8) % 1000000);
 
 
-		fin = ((u64)src_decimation * pll) >> 12;
-		CX18_DEBUG_INFO_DEV(sd, "ADC Sampling freq = %d.%06d MHz\n",
-				    fin / 1000000, fin % 1000000);
+		CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio "
+				    "= %d.%03d\n", src_decimation / 256,
+				    ((src_decimation % 256) * 1000) / 256);
 
 
-		fsc = (((u64)sc) * pll) >> 24L;
+		tmp = 28636360 * (u64) sc;
+		do_div(tmp, src_decimation);
+		fsc = tmp >> 13;
 		CX18_DEBUG_INFO_DEV(sd,
 		CX18_DEBUG_INFO_DEV(sd,
-				    "Chroma sub-carrier freq = %d.%06d MHz\n",
-				    fsc / 1000000, fsc % 1000000);
+				    "Chroma sub-carrier initial freq = %d.%06d "
+				    "MHz\n", fsc / 1000000, fsc % 1000000);
 
 
 		CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, "
 		CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, "
 				    "vactive %i, vblank656 %i, src_dec %i, "
 				    "vactive %i, vblank656 %i, src_dec %i, "
@@ -470,16 +575,23 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
 {
 {
 	struct cx18_av_state *state = &cx->av_state;
 	struct cx18_av_state *state = &cx->av_state;
 	struct v4l2_subdev *sd = &state->sd;
 	struct v4l2_subdev *sd = &state->sd;
-	u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
-			   vid_input <= CX18_AV_COMPOSITE8);
-	u8 reg;
-	u8 v;
+
+	enum analog_signal_type {
+		NONE, CVBS, Y, C, SIF, Pb, Pr
+	} ch[3] = {NONE, NONE, NONE};
+
+	u8 afe_mux_cfg;
+	u8 adc2_cfg;
+	u32 afe_cfg;
+	int i;
 
 
 	CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n",
 	CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n",
 			    vid_input, aud_input);
 			    vid_input, aud_input);
 
 
-	if (is_composite) {
-		reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
+	if (vid_input >= CX18_AV_COMPOSITE1 &&
+	    vid_input <= CX18_AV_COMPOSITE8) {
+		afe_mux_cfg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
+		ch[0] = CVBS;
 	} else {
 	} else {
 		int luma = vid_input & 0xf0;
 		int luma = vid_input & 0xf0;
 		int chroma = vid_input & 0xf00;
 		int chroma = vid_input & 0xf00;
@@ -493,26 +605,45 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
 				     vid_input);
 				     vid_input);
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
-		reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
+		afe_mux_cfg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
+		ch[0] = Y;
 		if (chroma >= CX18_AV_SVIDEO_CHROMA7) {
 		if (chroma >= CX18_AV_SVIDEO_CHROMA7) {
-			reg &= 0x3f;
-			reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
+			afe_mux_cfg &= 0x3f;
+			afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
+			ch[2] = C;
 		} else {
 		} else {
-			reg &= 0xcf;
-			reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
+			afe_mux_cfg &= 0xcf;
+			afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
+			ch[1] = C;
 		}
 		}
 	}
 	}
+	/* TODO: LeadTek WinFast DVR3100 H & WinFast PVR2100 can do Y/Pb/Pr */
 
 
 	switch (aud_input) {
 	switch (aud_input) {
 	case CX18_AV_AUDIO_SERIAL1:
 	case CX18_AV_AUDIO_SERIAL1:
 	case CX18_AV_AUDIO_SERIAL2:
 	case CX18_AV_AUDIO_SERIAL2:
 		/* do nothing, use serial audio input */
 		/* do nothing, use serial audio input */
 		break;
 		break;
-	case CX18_AV_AUDIO4: reg &= ~0x30; break;
-	case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
-	case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
-	case CX18_AV_AUDIO7: reg &= ~0xc0; break;
-	case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
+	case CX18_AV_AUDIO4:
+		afe_mux_cfg &= ~0x30;
+		ch[1] = SIF;
+		break;
+	case CX18_AV_AUDIO5:
+		afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x10;
+		ch[1] = SIF;
+		break;
+	case CX18_AV_AUDIO6:
+		afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x20;
+		ch[1] = SIF;
+		break;
+	case CX18_AV_AUDIO7:
+		afe_mux_cfg &= ~0xc0;
+		ch[2] = SIF;
+		break;
+	case CX18_AV_AUDIO8:
+		afe_mux_cfg = (afe_mux_cfg & ~0xc0) | 0x40;
+		ch[2] = SIF;
+		break;
 
 
 	default:
 	default:
 		CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n",
 		CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n",
@@ -520,24 +651,65 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-	cx18_av_write_expect(cx, 0x103, reg, reg, 0xf7);
+	/* Set up analog front end multiplexers */
+	cx18_av_write_expect(cx, 0x103, afe_mux_cfg, afe_mux_cfg, 0xf7);
 	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
 	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
-	cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
+	cx18_av_and_or(cx, 0x401, ~0x6, ch[0] == CVBS ? 0 : 0x02);
 
 
 	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
 	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
-	v = cx18_av_read(cx, 0x102);
-	if (reg & 0x80)
-		v &= ~0x2;
+	adc2_cfg = cx18_av_read(cx, 0x102);
+	if (ch[2] == NONE)
+		adc2_cfg &= ~0x2; /* No sig on CH3, set ADC2 to CH2 for input */
 	else
 	else
-		v |= 0x2;
+		adc2_cfg |= 0x2;  /* Signal on CH3, set ADC2 to CH3 for input */
+
 	/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
 	/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
-	if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
-		v |= 0x4;
+	if (ch[1] != NONE && ch[2] != NONE)
+		adc2_cfg |= 0x4; /* Set dual mode */
 	else
 	else
-		v &= ~0x4;
-	cx18_av_write_expect(cx, 0x102, v, v, 0x17);
+		adc2_cfg &= ~0x4; /* Clear dual mode */
+	cx18_av_write_expect(cx, 0x102, adc2_cfg, adc2_cfg, 0x17);
+
+	/* Configure the analog front end */
+	afe_cfg = cx18_av_read4(cx, CXADEC_AFE_CTRL);
+	afe_cfg &= 0xff000000;
+	afe_cfg |= 0x00005000; /* CHROMA_IN, AUD_IN: ADC2; LUMA_IN: ADC1 */
+	if (ch[1] != NONE && ch[2] != NONE)
+		afe_cfg |= 0x00000030; /* half_bw_ch[2-3] since in dual mode */
+
+	for (i = 0; i < 3; i++) {
+		switch (ch[i]) {
+		default:
+		case NONE:
+			/* CLAMP_SEL = Fixed to midcode clamp level */
+			afe_cfg |= (0x00000200 << i);
+			break;
+		case CVBS:
+		case Y:
+			if (i > 0)
+				afe_cfg |= 0x00002000; /* LUMA_IN_SEL: ADC2 */
+			break;
+		case C:
+		case Pb:
+		case Pr:
+			/* CLAMP_SEL = Fixed to midcode clamp level */
+			afe_cfg |= (0x00000200 << i);
+			if (i == 0 && ch[i] == C)
+				afe_cfg &= ~0x00001000; /* CHROMA_IN_SEL ADC1 */
+			break;
+		case SIF:
+			/*
+			 * VGA_GAIN_SEL = Audio Decoder
+			 * CLAMP_SEL = Fixed to midcode clamp level
+			 */
+			afe_cfg |= (0x00000240 << i);
+			if (i == 0)
+				afe_cfg &= ~0x00004000; /* AUD_IN_SEL ADC1 */
+			break;
+		}
+	}
 
 
-	/*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/
+	cx18_av_write4(cx, CXADEC_AFE_CTRL, afe_cfg);
 
 
 	state->vid_input = vid_input;
 	state->vid_input = vid_input;
 	state->aud_input = aud_input;
 	state->aud_input = aud_input;
@@ -858,9 +1030,9 @@ static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 		 * cx18_av_std_setup(), above standard values:
 		 * cx18_av_std_setup(), above standard values:
 		 *
 		 *
 		 * 480 + 1 for 60 Hz systems
 		 * 480 + 1 for 60 Hz systems
-		 * 576 + 4 for 50 Hz systems
+		 * 576 + 3 for 50 Hz systems
 		 */
 		 */
-		Vlines = pix->height + (is_50Hz ? 4 : 1);
+		Vlines = pix->height + (is_50Hz ? 3 : 1);
 
 
 		/*
 		/*
 		 * Invalid height and width scaling requests are:
 		 * Invalid height and width scaling requests are:

+ 78 - 4
drivers/media/video/cx18/cx18-av-firmware.c

@@ -24,15 +24,63 @@
 #include "cx18-io.h"
 #include "cx18-io.h"
 #include <linux/firmware.h>
 #include <linux/firmware.h>
 
 
-#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_AUDIO_ENABLE    0xc72014
+#define CX18_AI1_MUX_MASK    0x30
+#define CX18_AI1_MUX_I2S1    0x00
+#define CX18_AI1_MUX_I2S2    0x10
+#define CX18_AI1_MUX_843_I2S 0x20
+#define CX18_AI1_MUX_INVALID 0x30
+
 #define FWFILE "v4l-cx23418-dig.fw"
 #define FWFILE "v4l-cx23418-dig.fw"
 
 
+static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw)
+{
+	struct v4l2_subdev *sd = &cx->av_state.sd;
+	int ret = 0;
+	const u8 *data;
+	u32 size;
+	int addr;
+	u32 expected, dl_control;
+
+	/* Ensure we put the 8051 in reset and enable firmware upload mode */
+	dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+	do {
+		dl_control &= 0x00ffffff;
+		dl_control |= 0x0f000000;
+		cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control);
+		dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+	} while ((dl_control & 0xff000000) != 0x0f000000);
+
+	/* Read and auto increment until at address 0x0000 */
+	while (dl_control & 0x3fff)
+		dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+
+	data = fw->data;
+	size = fw->size;
+	for (addr = 0; addr < size; addr++) {
+		dl_control &= 0xffff3fff; /* ignore top 2 bits of address */
+		expected = 0x0f000000 | ((u32)data[addr] << 16) | addr;
+		if (expected != dl_control) {
+			CX18_ERR_DEV(sd, "verification of %s firmware load "
+				     "failed: expected %#010x got %#010x\n",
+				     FWFILE, expected, dl_control);
+			ret = -EIO;
+			break;
+		}
+		dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+	}
+	if (ret == 0)
+		CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n",
+			      FWFILE, size);
+	return ret;
+}
+
 int cx18_av_loadfw(struct cx18 *cx)
 int cx18_av_loadfw(struct cx18 *cx)
 {
 {
 	struct v4l2_subdev *sd = &cx->av_state.sd;
 	struct v4l2_subdev *sd = &cx->av_state.sd;
 	const struct firmware *fw = NULL;
 	const struct firmware *fw = NULL;
 	u32 size;
 	u32 size;
-	u32 v;
+	u32 u, v;
 	const u8 *ptr;
 	const u8 *ptr;
 	int i;
 	int i;
 	int retries1 = 0;
 	int retries1 = 0;
@@ -95,6 +143,12 @@ int cx18_av_loadfw(struct cx18 *cx)
 	}
 	}
 
 
 	cx18_av_write4_expect(cx, CXADEC_DL_CTL,
 	cx18_av_write4_expect(cx, CXADEC_DL_CTL,
+				0x03000000 | fw->size, 0x03000000, 0x13000000);
+
+	CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
+
+	if (cx18_av_verifyfw(cx, fw) == 0)
+		cx18_av_write4_expect(cx, CXADEC_DL_CTL,
 				0x13000000 | fw->size, 0x13000000, 0x13000000);
 				0x13000000 | fw->size, 0x13000000, 0x13000000);
 
 
 	/* Output to the 416 */
 	/* Output to the 416 */
@@ -135,6 +189,28 @@ int cx18_av_loadfw(struct cx18 *cx)
 		cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
 		cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
 				      0, 0x400);
 				      0, 0x400);
 
 
+	/* Toggle the AI1 MUX */
+	v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+	u = v & CX18_AI1_MUX_MASK;
+	v &= ~CX18_AI1_MUX_MASK;
+	if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) {
+		/* Switch to I2S1 */
+		v |= CX18_AI1_MUX_I2S1;
+		cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+				      v, CX18_AI1_MUX_MASK);
+		/* Switch back to the A/V decoder core I2S output */
+		v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S;
+	} else {
+		/* Switch to the A/V decoder core I2S output */
+		v |= CX18_AI1_MUX_843_I2S;
+		cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+				      v, CX18_AI1_MUX_MASK);
+		/* Switch back to I2S1 or I2S2 */
+		v = (v & ~CX18_AI1_MUX_MASK) | u;
+	}
+	cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+			      v, CX18_AI1_MUX_MASK);
+
 	/* Enable WW auto audio standard detection */
 	/* Enable WW auto audio standard detection */
 	v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
 	v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
 	v |= 0xFF;   /* Auto by default */
 	v |= 0xFF;   /* Auto by default */
@@ -143,7 +219,5 @@ int cx18_av_loadfw(struct cx18 *cx)
 	cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF);
 	cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF);
 
 
 	release_firmware(fw);
 	release_firmware(fw);
-
-	CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
 	return 0;
 	return 0;
 }
 }

+ 2 - 2
drivers/media/video/cx18/cx18-av-vbi.c

@@ -255,8 +255,8 @@ int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt)
 	}
 	}
 
 
 	cx18_av_write(cx, 0x43c, 0x16);
 	cx18_av_write(cx, 0x43c, 0x16);
-	/* FIXME - should match vblank set in cx18_av_std_setup() */
-	cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26);
+	/* Should match vblank set in cx18_av_std_setup() */
+	cx18_av_write(cx, 0x474, is_pal ? 38 : 26);
 	return 0;
 	return 0;
 }
 }
 
 

+ 56 - 7
drivers/media/video/cx18/cx18-cards.c

@@ -340,13 +340,12 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
 
 
 static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = {
 static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = {
 	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100   */
 	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100   */
-	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
 	{ 0, 0, 0 }
 	{ 0, 0, 0 }
 };
 };
 
 
 static const struct cx18_card cx18_card_leadtek_pvr2100 = {
 static const struct cx18_card cx18_card_leadtek_pvr2100 = {
 	.type = CX18_CARD_LEADTEK_PVR2100,
 	.type = CX18_CARD_LEADTEK_PVR2100,
-	.name = "Leadtek WinFast PVR2100/DVR3100 H",
+	.name = "Leadtek WinFast PVR2100",
 	.comment = "Experimenters and photos needed for device to work well.\n"
 	.comment = "Experimenters and photos needed for device to work well.\n"
 		  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
 		  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
 	.v4l2_capabilities = CX18_CAP_ENCODER,
 	.v4l2_capabilities = CX18_CAP_ENCODER,
@@ -365,15 +364,12 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
 		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
 		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
 	},
 	},
 	.tuners = {
 	.tuners = {
-		/* XC3028 tuner */
+		/* XC2028 tuner */
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 	},
 	},
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
 	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
 	.ddr = {
 	.ddr = {
-		/*
-		 * Pointer to proper DDR config values provided by
-		 * Terry Wu <terrywu at leadtek.com.tw>
-		 */
+		/* Pointer to proper DDR config values provided by Terry Wu */
 		.chip_config = 0x303,
 		.chip_config = 0x303,
 		.refresh = 0x3bb,
 		.refresh = 0x3bb,
 		.timing1 = 0x24220e83,
 		.timing1 = 0x24220e83,
@@ -392,6 +388,58 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
 
 
 /* ------------------------------------------------------------------------- */
 /* ------------------------------------------------------------------------- */
 
 
+/* Leadtek WinFast DVR3100 H */
+
+static const struct cx18_card_pci_info cx18_pci_leadtek_dvr3100h[] = {
+	{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
+	{ 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_leadtek_dvr3100h = {
+	.type = CX18_CARD_LEADTEK_DVR3100H,
+	.name = "Leadtek WinFast DVR3100 H",
+	.comment = "Simultaneous DVB-T and Analog capture supported,\n"
+		  "\texcept when capturing Analog from the antenna input.\n",
+	.v4l2_capabilities = CX18_CAP_ENCODER,
+	.hw_audio_ctrl = CX18_HW_418_AV,
+	.hw_muxer = CX18_HW_GPIO_MUX,
+	.hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX |
+		  CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+	.video_inputs = {
+		{ CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+		{ CX18_CARD_INPUT_SVIDEO1,    1,
+			CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+		{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 },
+	},
+	.audio_inputs = {
+		{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 	    0 },
+		{ CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+	},
+	.tuners = {
+		/* XC3028 tuner */
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+	},
+	.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+	.ddr = {
+		/* Pointer to proper DDR config values provided by Terry Wu */
+		.chip_config = 0x303,
+		.refresh = 0x3bb,
+		.timing1 = 0x24220e83,
+		.timing2 = 0x1f,
+		.tune_lane = 0,
+		.initial_emrs = 0x2,
+	},
+	.gpio_init.initial_value = 0x6,
+	.gpio_init.direction = 0x7,
+	.gpio_audio_input = { .mask   = 0x7,
+			      .tuner  = 0x6, .linein = 0x2, .radio  = 0x2 },
+	.xceive_pin = 1,
+	.pci_list = cx18_pci_leadtek_dvr3100h,
+	.i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
 static const struct cx18_card *cx18_card_list[] = {
 static const struct cx18_card *cx18_card_list[] = {
 	&cx18_card_hvr1600_esmt,
 	&cx18_card_hvr1600_esmt,
 	&cx18_card_hvr1600_samsung,
 	&cx18_card_hvr1600_samsung,
@@ -400,6 +448,7 @@ static const struct cx18_card *cx18_card_list[] = {
 	&cx18_card_cnxt_raptor_pal,
 	&cx18_card_cnxt_raptor_pal,
 	&cx18_card_toshiba_qosmio_dvbt,
 	&cx18_card_toshiba_qosmio_dvbt,
 	&cx18_card_leadtek_pvr2100,
 	&cx18_card_leadtek_pvr2100,
+	&cx18_card_leadtek_dvr3100h,
 };
 };
 
 
 const struct cx18_card *cx18_get_card(u16 index)
 const struct cx18_card *cx18_get_card(u16 index)

+ 4 - 2
drivers/media/video/cx18/cx18-controls.c

@@ -176,8 +176,10 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx,
 		return -EBUSY;
 		return -EBUSY;
 
 
 	if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
 	if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
-	    type != V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
-		/* We don't do VBI insertion aside from IVTV format in a PS */
+	    !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS ||
+	      type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD ||
+	      type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) {
+		/* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */
 		cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
 		cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
 		CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
 		CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
 				"the MPEG stream\n");
 				"the MPEG stream\n");

+ 75 - 25
drivers/media/video/cx18/cx18-driver.c

@@ -30,6 +30,7 @@
 #include "cx18-irq.h"
 #include "cx18-irq.h"
 #include "cx18-gpio.h"
 #include "cx18-gpio.h"
 #include "cx18-firmware.h"
 #include "cx18-firmware.h"
+#include "cx18-queue.h"
 #include "cx18-streams.h"
 #include "cx18-streams.h"
 #include "cx18-av-core.h"
 #include "cx18-av-core.h"
 #include "cx18-scb.h"
 #include "cx18-scb.h"
@@ -151,7 +152,8 @@ MODULE_PARM_DESC(cardtype,
 		 "\t\t\t 4 = Yuan MPC718\n"
 		 "\t\t\t 4 = Yuan MPC718\n"
 		 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
 		 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
 		 "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
 		 "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
-		 "\t\t\t 7 = Leadtek WinFast PVR2100/DVR3100 H\n"
+		 "\t\t\t 7 = Leadtek WinFast PVR2100\n"
+		 "\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
 		 "\t\t\t 0 = Autodetect (default)\n"
 		 "\t\t\t 0 = Autodetect (default)\n"
 		 "\t\t\t-1 = Ignore this card\n\t\t");
 		 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -312,7 +314,7 @@ static void cx18_process_eeprom(struct cx18 *cx)
 	CX18_INFO("Autodetected %s\n", cx->card_name);
 	CX18_INFO("Autodetected %s\n", cx->card_name);
 
 
 	if (tv.tuner_type == TUNER_ABSENT)
 	if (tv.tuner_type == TUNER_ABSENT)
-		CX18_ERR("tveeprom cannot autodetect tuner!");
+		CX18_ERR("tveeprom cannot autodetect tuner!\n");
 
 
 	if (cx->options.tuner == -1)
 	if (cx->options.tuner == -1)
 		cx->options.tuner = tv.tuner_type;
 		cx->options.tuner = tv.tuner_type;
@@ -546,6 +548,40 @@ done:
 	cx->card_i2c = cx->card->i2c;
 	cx->card_i2c = cx->card->i2c;
 }
 }
 
 
+static int __devinit cx18_create_in_workq(struct cx18 *cx)
+{
+	snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
+		 cx->v4l2_dev.name);
+	cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name);
+	if (cx->in_work_queue == NULL) {
+		CX18_ERR("Unable to create incoming mailbox handler thread\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static int __devinit cx18_create_out_workq(struct cx18 *cx)
+{
+	snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out",
+		 cx->v4l2_dev.name);
+	cx->out_work_queue = create_workqueue(cx->out_workq_name);
+	if (cx->out_work_queue == NULL) {
+		CX18_ERR("Unable to create outgoing mailbox handler threads\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
+		cx->in_work_order[i].cx = cx;
+		cx->in_work_order[i].str = cx->epu_debug_str;
+		INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler);
+	}
+}
+
 /* Precondition: the cx18 structure has been memset to 0. Only
 /* Precondition: the cx18 structure has been memset to 0. Only
    the dev and instance fields have been filled in.
    the dev and instance fields have been filled in.
    No assumptions on the card type may be made here (see cx18_init_struct2
    No assumptions on the card type may be made here (see cx18_init_struct2
@@ -553,7 +589,7 @@ done:
  */
  */
 static int __devinit cx18_init_struct1(struct cx18 *cx)
 static int __devinit cx18_init_struct1(struct cx18 *cx)
 {
 {
-	int i;
+	int ret;
 
 
 	cx->base_addr = pci_resource_start(cx->pci_dev, 0);
 	cx->base_addr = pci_resource_start(cx->pci_dev, 0);
 
 
@@ -562,18 +598,18 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
 	mutex_init(&cx->epu2apu_mb_lock);
 	mutex_init(&cx->epu2apu_mb_lock);
 	mutex_init(&cx->epu2cpu_mb_lock);
 	mutex_init(&cx->epu2cpu_mb_lock);
 
 
-	cx->work_queue = create_singlethread_workqueue(cx->v4l2_dev.name);
-	if (cx->work_queue == NULL) {
-		CX18_ERR("Unable to create work hander thread\n");
-		return -ENOMEM;
-	}
+	ret = cx18_create_out_workq(cx);
+	if (ret)
+		return ret;
 
 
-	for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
-		cx->epu_work_order[i].cx = cx;
-		cx->epu_work_order[i].str = cx->epu_debug_str;
-		INIT_WORK(&cx->epu_work_order[i].work, cx18_epu_work_handler);
+	ret = cx18_create_in_workq(cx);
+	if (ret) {
+		destroy_workqueue(cx->out_work_queue);
+		return ret;
 	}
 	}
 
 
+	cx18_init_in_work_orders(cx);
+
 	/* start counting open_id at 1 */
 	/* start counting open_id at 1 */
 	cx->open_id = 1;
 	cx->open_id = 1;
 
 
@@ -759,17 +795,17 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
 		retval = -ENODEV;
 		retval = -ENODEV;
 		goto err;
 		goto err;
 	}
 	}
-	if (cx18_init_struct1(cx)) {
-		retval = -ENOMEM;
+
+	retval = cx18_init_struct1(cx);
+	if (retval)
 		goto err;
 		goto err;
-	}
 
 
 	CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
 	CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
 
 
 	/* PCI Device Setup */
 	/* PCI Device Setup */
 	retval = cx18_setup_pci(cx, pci_dev, pci_id);
 	retval = cx18_setup_pci(cx, pci_dev, pci_id);
 	if (retval != 0)
 	if (retval != 0)
-		goto free_workqueue;
+		goto free_workqueues;
 
 
 	/* map io memory */
 	/* map io memory */
 	CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
 	CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
@@ -943,8 +979,9 @@ free_map:
 	cx18_iounmap(cx);
 	cx18_iounmap(cx);
 free_mem:
 free_mem:
 	release_mem_region(cx->base_addr, CX18_MEM_SIZE);
 	release_mem_region(cx->base_addr, CX18_MEM_SIZE);
-free_workqueue:
-	destroy_workqueue(cx->work_queue);
+free_workqueues:
+	destroy_workqueue(cx->in_work_queue);
+	destroy_workqueue(cx->out_work_queue);
 err:
 err:
 	if (retval == 0)
 	if (retval == 0)
 		retval = -ENODEV;
 		retval = -ENODEV;
@@ -1053,11 +1090,19 @@ int cx18_init_on_first_open(struct cx18 *cx)
 	return 0;
 	return 0;
 }
 }
 
 
-static void cx18_cancel_epu_work_orders(struct cx18 *cx)
+static void cx18_cancel_in_work_orders(struct cx18 *cx)
 {
 {
 	int i;
 	int i;
-	for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++)
-		cancel_work_sync(&cx->epu_work_order[i].work);
+	for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++)
+		cancel_work_sync(&cx->in_work_order[i].work);
+}
+
+static void cx18_cancel_out_work_orders(struct cx18 *cx)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_STREAMS; i++)
+		if (&cx->streams[i].video_dev != NULL)
+			cancel_work_sync(&cx->streams[i].out_work_order);
 }
 }
 
 
 static void cx18_remove(struct pci_dev *pci_dev)
 static void cx18_remove(struct pci_dev *pci_dev)
@@ -1073,15 +1118,20 @@ static void cx18_remove(struct pci_dev *pci_dev)
 	if (atomic_read(&cx->tot_capturing) > 0)
 	if (atomic_read(&cx->tot_capturing) > 0)
 		cx18_stop_all_captures(cx);
 		cx18_stop_all_captures(cx);
 
 
-	/* Interrupts */
+	/* Stop interrupts that cause incoming work to be queued */
 	cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
 	cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+
+	/* Incoming work can cause outgoing work, so clean up incoming first */
+	cx18_cancel_in_work_orders(cx);
+	cx18_cancel_out_work_orders(cx);
+
+	/* Stop ack interrupts that may have been needed for work to finish */
 	cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 	cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 
 
 	cx18_halt_firmware(cx);
 	cx18_halt_firmware(cx);
 
 
-	cx18_cancel_epu_work_orders(cx);
-
-	destroy_workqueue(cx->work_queue);
+	destroy_workqueue(cx->in_work_queue);
+	destroy_workqueue(cx->out_work_queue);
 
 
 	cx18_streams_cleanup(cx, 1);
 	cx18_streams_cleanup(cx, 1);
 
 

+ 15 - 7
drivers/media/video/cx18/cx18-driver.h

@@ -80,8 +80,9 @@
 #define CX18_CARD_YUAN_MPC718 	      3	/* Yuan MPC718 */
 #define CX18_CARD_YUAN_MPC718 	      3	/* Yuan MPC718 */
 #define CX18_CARD_CNXT_RAPTOR_PAL     4	/* Conexant Raptor PAL */
 #define CX18_CARD_CNXT_RAPTOR_PAL     4	/* Conexant Raptor PAL */
 #define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
 #define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
-#define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100/DVR3100 H */
-#define CX18_CARD_LAST 		      6
+#define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100 */
+#define CX18_CARD_LEADTEK_DVR3100H    7 /* Leadtek WinFast DVR3100 H */
+#define CX18_CARD_LAST 		      7
 
 
 #define CX18_ENC_STREAM_TYPE_MPG  0
 #define CX18_ENC_STREAM_TYPE_MPG  0
 #define CX18_ENC_STREAM_TYPE_TS   1
 #define CX18_ENC_STREAM_TYPE_TS   1
@@ -254,6 +255,7 @@ struct cx18_options {
 #define CX18_F_S_INTERNAL_USE	5	/* this stream is used internally (sliced VBI processing) */
 #define CX18_F_S_INTERNAL_USE	5	/* this stream is used internally (sliced VBI processing) */
 #define CX18_F_S_STREAMOFF	7	/* signal end of stream EOS */
 #define CX18_F_S_STREAMOFF	7	/* signal end of stream EOS */
 #define CX18_F_S_APPL_IO        8	/* this stream is used read/written by an application */
 #define CX18_F_S_APPL_IO        8	/* this stream is used read/written by an application */
+#define CX18_F_S_STOPPING	9	/* telling the fw to stop capturing */
 
 
 /* per-cx18, i_flags */
 /* per-cx18, i_flags */
 #define CX18_F_I_LOADED_FW		0 	/* Loaded firmware 1st time */
 #define CX18_F_I_LOADED_FW		0 	/* Loaded firmware 1st time */
@@ -285,6 +287,7 @@ struct cx18_queue {
 	struct list_head list;
 	struct list_head list;
 	atomic_t buffers;
 	atomic_t buffers;
 	u32 bytesused;
 	u32 bytesused;
+	spinlock_t lock;
 };
 };
 
 
 struct cx18_dvb {
 struct cx18_dvb {
@@ -305,7 +308,7 @@ struct cx18_scb; /* forward reference */
 
 
 
 
 #define CX18_MAX_MDL_ACKS 2
 #define CX18_MAX_MDL_ACKS 2
-#define CX18_MAX_EPU_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7)
+#define CX18_MAX_IN_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7)
 /* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */
 /* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */
 
 
 #define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1
 #define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1
@@ -313,7 +316,7 @@ struct cx18_scb; /* forward reference */
 #define CX18_F_EWO_MB_STALE \
 #define CX18_F_EWO_MB_STALE \
 	     (CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC)
 	     (CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC)
 
 
-struct cx18_epu_work_order {
+struct cx18_in_work_order {
 	struct work_struct work;
 	struct work_struct work;
 	atomic_t pending;
 	atomic_t pending;
 	struct cx18 *cx;
 	struct cx18 *cx;
@@ -337,7 +340,6 @@ struct cx18_stream {
 	unsigned mdl_offset;
 	unsigned mdl_offset;
 
 
 	u32 id;
 	u32 id;
-	struct mutex qlock; 	/* locks access to the queues */
 	unsigned long s_flags;	/* status flags, see above */
 	unsigned long s_flags;	/* status flags, see above */
 	int dma;		/* can be PCI_DMA_TODEVICE,
 	int dma;		/* can be PCI_DMA_TODEVICE,
 				   PCI_DMA_FROMDEVICE or
 				   PCI_DMA_FROMDEVICE or
@@ -353,6 +355,8 @@ struct cx18_stream {
 	struct cx18_queue q_busy;	/* busy buffers - in use by firmware */
 	struct cx18_queue q_busy;	/* busy buffers - in use by firmware */
 	struct cx18_queue q_full;	/* full buffers - data for user apps */
 	struct cx18_queue q_full;	/* full buffers - data for user apps */
 
 
+	struct work_struct out_work_order;
+
 	/* DVB / Digital Transport */
 	/* DVB / Digital Transport */
 	struct cx18_dvb dvb;
 	struct cx18_dvb dvb;
 };
 };
@@ -568,10 +572,14 @@ struct cx18 {
 	u32 sw2_irq_mask;
 	u32 sw2_irq_mask;
 	u32 hw2_irq_mask;
 	u32 hw2_irq_mask;
 
 
-	struct workqueue_struct *work_queue;
-	struct cx18_epu_work_order epu_work_order[CX18_MAX_EPU_WORK_ORDERS];
+	struct workqueue_struct *in_work_queue;
+	char in_workq_name[11]; /* "cx18-NN-in" */
+	struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS];
 	char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
 	char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
 
 
+	struct workqueue_struct *out_work_queue;
+	char out_workq_name[12]; /* "cx18-NN-out" */
+
 	/* i2c */
 	/* i2c */
 	struct i2c_adapter i2c_adap[2];
 	struct i2c_adapter i2c_adap[2];
 	struct i2c_algo_bit_data i2c_algo[2];
 	struct i2c_algo_bit_data i2c_algo[2];

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini